├── .gitignore ├── src ├── message.rs ├── dht.rs ├── crypto.rs ├── api.rs ├── config.rs ├── fake.rs ├── wg_device.rs ├── utils.rs ├── stun │ ├── mod.rs │ └── codec.rs └── main.rs ├── README.md ├── Cargo.toml ├── test.sh └── LICENSE.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /src/message.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Serialize, Deserialize, Debug)] 4 | pub struct Message { 5 | pub timestamp: std::time::SystemTime, 6 | pub ip_addr_list: Vec, 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Exchanges your IP via a OpenDHT. 2 | 3 | Just run `wg-quick up wg0` and then `sudo wireguard-p2p` on both peers. 4 | wireguard-p2p will determine your current public IP, exchange it via OpenDHT, set the endpoint to a localhost port and proxy packages between both peers. 5 | 6 | 7 | ## Install 8 | ```bash 9 | cargo install wireguard-p2p 10 | ``` 11 | 12 | ## Dependencies 13 | 14 | ### OpenDHT 15 | OpenDHT will have to be discoverable by pkgconfig 16 | 17 | Follow the build/install instructions [here](https://github.com/savoirfairelinux/opendht/wiki/Build-the-library#using-cmake) 18 | 19 | ### Fedora 20 | ```bash 21 | sudo dnf install -y jsoncpp-devel http-parser-devel 22 | ``` 23 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wireguard-p2p" 3 | version = "0.3.0" 4 | description = "A WireGuard peer-to-peer client" 5 | license = "LGPL-2.1+" 6 | authors = ["Manuel Schölling "] 7 | edition = "2018" 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [dependencies] 12 | serde = { version = "1.0", features = ["derive"] } 13 | serde_json = "1.0" 14 | async-std = { version = "1.8", features = ["attributes", "unstable"] } 15 | async-trait = "0.1.4" 16 | anyhow = "1.0" 17 | bytes = "0.6" 18 | slog = "2.7.0" 19 | slog-async = "2.5.0" 20 | slog-term = "2.6.0" 21 | base64 = "0.13.0" 22 | async-stream = "0.3.0" 23 | futures = "0.3.8" 24 | sodiumoxide = "0.2.6" 25 | wireguard-uapi = "1.0.5" 26 | byteorder = "1.3.4" 27 | rand = { version = "0.8.0", features = ["small_rng"] } 28 | lazy_static = "1.4.0" 29 | opendht = "0.5.2" 30 | clap = "2.33.3" 31 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -v 4 | 5 | # First we create the network namespace called "container": 6 | 7 | ip netns delete ns1 8 | ip netns delete ns2 9 | 10 | ip netns add ns1 11 | ip netns add ns2 12 | 13 | # Next, we create a WireGuard interface in the "init" (original) namespace: 14 | 15 | # Finally, we move that interface into the new namespace: 16 | 17 | # Now we can configure wg0 as usual, except we specify its new namespace in doing so: 18 | 19 | ip link delete test1 20 | ip link delete test2 21 | 22 | ip link add test1 type wireguard 23 | ip link add test2 type wireguard 24 | 25 | ip link set test1 netns ns1 26 | ip link set test2 netns ns2 27 | 28 | ip -n ns1 addr add 10.9.9.1/32 dev test1 29 | ip -n ns2 addr add 10.9.9.2/32 dev test2 30 | 31 | ip netns exec ns1 wg setconf test1 /etc/wireguard/test1.conf 32 | ip netns exec ns2 wg setconf test2 /etc/wireguard/test2.conf 33 | #ip netns exec ns1 wg-quick up test1 34 | #ip netns exec ns2 wg-quick up test2 35 | 36 | ip -n ns1 link set test1 up 37 | ip -n ns2 link set test2 up 38 | 39 | ip -n ns1 route add default dev test1 40 | ip -n ns2 route add default dev test2 41 | 42 | ip netns exec ns1 wg set test1 peer g912ZZMQB0REuA7brLYumd0VQS2/J/8odv7LYSm+cw0= endpoint 192.168.178.21:9991 43 | 44 | sleep 2 45 | 46 | ip netns exec ns1 wg 47 | ip netns exec ns1 ping 10.9.9.2 48 | -------------------------------------------------------------------------------- /src/dht.rs: -------------------------------------------------------------------------------- 1 | use opendht; 2 | use std::sync::Arc; 3 | use async_std::prelude::*; 4 | use async_std::net::ToSocketAddrs; 5 | use std::net::SocketAddr; 6 | 7 | use crate::api::DhtApi; 8 | 9 | #[derive(Clone)] 10 | pub struct OpenDht { 11 | dht: Arc 12 | } 13 | 14 | impl OpenDht { 15 | pub async fn new(log: slog::Logger, listen_port: u16, bootstrap_servers: impl ToSocketAddrs) -> anyhow::Result { 16 | let dht = opendht::OpenDht::new(listen_port)?; 17 | let dht = Arc::new(dht); 18 | 19 | let servers: Vec = bootstrap_servers.to_socket_addrs().await?.collect(); 20 | slog::debug!(log, "OpenDHT bootstrapping..."); 21 | if dht.bootstrap(&servers).await.is_err() { 22 | anyhow::bail!("Failed to bootstrap using {:?}", servers); 23 | } 24 | slog::info!(log, "OpenDHT bootstrapping done"); 25 | 26 | let dht2 = dht.clone(); 27 | async_std::task::spawn(async move { 28 | while let Some(next) = dht2.tick() { 29 | async_std::task::sleep(next).await; 30 | } 31 | slog::crit!(log, "OpenDHT loop ended!"); 32 | }); 33 | 34 | Ok(OpenDht { dht }) 35 | } 36 | } 37 | 38 | #[async_trait::async_trait] 39 | impl DhtApi for OpenDht { 40 | fn listen(&self, key: Vec) -> Box> + Send + Unpin> { 41 | Box::new(self.dht.listen(&key[..])) 42 | } 43 | 44 | async fn put(&self, key: &[u8], value: &[u8]) -> anyhow::Result<()> { 45 | self.dht.put(key, value).await?; 46 | Ok(()) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/crypto.rs: -------------------------------------------------------------------------------- 1 | use crate::api::PublicKeyCrypto; 2 | 3 | use sodiumoxide::crypto::box_; 4 | use sodiumoxide::crypto::box_::NONCEBYTES; 5 | 6 | use base64; 7 | use bytes::BufMut; 8 | 9 | #[derive(Clone)] 10 | pub struct PublicKey(pub box_::PublicKey); 11 | pub struct SecretKey(pub box_::SecretKey); 12 | 13 | pub struct Sodiumoxide(box_::PrecomputedKey); 14 | 15 | impl Sodiumoxide { 16 | pub fn new(their_pk: &PublicKey, our_sk: &SecretKey) -> Self { 17 | let precomputed_key = box_::precompute(&their_pk.0, &our_sk.0); 18 | Self(precomputed_key) 19 | } 20 | } 21 | 22 | impl PublicKeyCrypto for Sodiumoxide { 23 | fn encrypt(&self, plaintext: &[u8]) -> anyhow::Result { 24 | let nonce = box_::gen_nonce(); 25 | 26 | let ciphertext = box_::seal_precomputed(plaintext, &nonce, &self.0); 27 | 28 | let mut buf = bytes::BytesMut::new(); 29 | buf.put(&nonce.0[..]); 30 | buf.put(&ciphertext[..]); 31 | 32 | return Ok(buf.freeze()); 33 | } 34 | 35 | fn decrypt(&self, ciphertext: &[u8]) -> Option> { 36 | if ciphertext.len() < NONCEBYTES { 37 | dbg!("Decryption failed"); 38 | return None; 39 | } 40 | let (nonce, ciphertext) = ciphertext.split_at(NONCEBYTES); 41 | 42 | if let Some(nonce) = box_::Nonce::from_slice(&nonce[..]) { 43 | let r = box_::open_precomputed(&ciphertext, &nonce, &self.0); 44 | if r.is_err() { 45 | dbg!("Decryption failed"); 46 | } 47 | r.ok() 48 | } else { 49 | None 50 | } 51 | } 52 | } 53 | 54 | impl PublicKey { 55 | pub fn new(buf: [u8; 32]) -> Self { 56 | Self(box_::PublicKey(buf)) 57 | } 58 | } 59 | 60 | impl std::fmt::Display for PublicKey { 61 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { 62 | write!(fmt, "{}", base64::encode(self.0.0)) 63 | } 64 | } 65 | 66 | impl SecretKey { 67 | pub fn new(buf: [u8; 32]) -> Self { 68 | Self(box_::SecretKey(buf)) 69 | } 70 | 71 | pub fn public_key(&self) -> PublicKey { 72 | PublicKey(self.0.public_key()) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/api.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use async_std::prelude::*; 4 | use async_trait::async_trait; 5 | 6 | use crate::PublicKey; 7 | use crate::SecretKey; 8 | use crate::stun; 9 | use crate::utils::UdpSender; 10 | use crate::utils::UdpReceiver; 11 | 12 | 13 | pub struct DeviceConfig {} 14 | 15 | impl DeviceConfig { 16 | pub async fn get_peers(&self, dev: &dyn WireguardDevice) -> anyhow::Result> + Unpin>> { 17 | dev.get_peers().await 18 | } 19 | } 20 | 21 | #[async_trait] 22 | pub trait Peer { 23 | fn get_public_key(&self) -> PublicKey; 24 | } 25 | 26 | #[async_trait] 27 | pub trait Stun { 28 | // return not just SocketAddr but also stun state type 29 | async fn lookup_public_address(&self, stun_log: &slog::Logger, 30 | to_inet_tx: &mut UdpSender, 31 | from_inet_rx: &mut UdpReceiver, 32 | stun_server: SocketAddr, ) -> anyhow::Result; 33 | } 34 | 35 | #[async_trait] 36 | pub trait ConfigApi { 37 | fn get_wireguard_devices(&self) -> anyhow::Result, DeviceConfig)> + Unpin>>; 38 | async fn get_peers(&self, dev: &dyn WireguardDevice) -> anyhow::Result> + Unpin>>; 39 | } 40 | 41 | #[async_trait] 42 | pub trait SecretKeyCrypto { 43 | async fn encrypt(buf: dyn AsRef) -> dyn AsRef; 44 | async fn decrypt(buf: dyn AsRef) -> dyn AsRef; 45 | } 46 | 47 | pub trait PublicKeyCrypto { 48 | fn encrypt(&self, buf: &[u8]) -> anyhow::Result; 49 | fn decrypt(&self, ciphertext: &[u8]) -> Option>; 50 | } 51 | 52 | #[async_trait] 53 | pub trait DhtApi { 54 | fn listen(&self, key: Vec) -> Box> + Send + Unpin>; 55 | async fn put(&self, key: &[u8], value: &[u8]) -> anyhow::Result<()>; 56 | } 57 | 58 | #[async_trait] 59 | pub trait WireguardDevice: Send + Sync { 60 | async fn get_name(&self) -> anyhow::Result; 61 | async fn get_listen_port(&self) -> anyhow::Result; 62 | async fn get_public_key(&self) -> anyhow::Result>; 63 | async fn get_secret_key(&self) -> anyhow::Result>; 64 | async fn set_endpoint(&self, remote_pkey: &PublicKey, remote_addr: &SocketAddr) -> anyhow::Result<()>; 65 | async fn get_peers(&self) -> anyhow::Result> + Unpin>>; 66 | } 67 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use slog::debug; 2 | use async_trait::async_trait; 3 | use async_std::prelude::*; 4 | use wireguard_uapi::RouteSocket; 5 | 6 | use crate::api; 7 | use crate::api::*; 8 | use crate::wg_device::WireguardDev; 9 | 10 | pub struct Config { 11 | log: slog::Logger, 12 | pub opendht_port: u16, 13 | interfaces: Option>, 14 | } 15 | 16 | impl Config { 17 | pub fn new(log: slog::Logger) -> anyhow::Result { 18 | let matches = clap::App::new("wiregurad-p2p") 19 | .arg(clap::Arg::with_name("interfaces") 20 | .short("i") 21 | .long("ifnames") 22 | .takes_value(true) 23 | .help("Restrict to these devices [default: all]")) 24 | .arg(clap::Arg::with_name("opendht_port") 25 | .short("P") 26 | .default_value("4222") 27 | .help("OpenDHt listen port")) 28 | .get_matches(); 29 | 30 | let interfaces = matches.value_of("interfaces").map(|ifnames| { 31 | ifnames.split(',').map(String::from).collect() 32 | }); 33 | 34 | let opendht_port = matches.value_of("opendht_port").unwrap(); 35 | let opendht_port = str::parse(opendht_port)?; 36 | 37 | Ok(Config { 38 | opendht_port, 39 | interfaces, 40 | log 41 | }) 42 | } 43 | } 44 | 45 | #[async_trait] 46 | impl api::ConfigApi for Config { 47 | fn get_wireguard_devices(&self) -> anyhow::Result, DeviceConfig)> + Unpin>> { 48 | if let Some(ref ifnames) = self.interfaces { 49 | let vec: Result, _> = ifnames.into_iter().map(|ifname| WireguardDev::new(ifname.to_string()).map(|d| d.as_trait())).collect(); 50 | let it = vec?.into_iter().map(|dev| (dev, DeviceConfig {})); 51 | let s = futures::stream::iter(it); 52 | return Ok(Box::new(s)); 53 | } 54 | 55 | debug!(self.log, "RouteSocket::connect()..."); 56 | let mut c = RouteSocket::connect()?; 57 | debug!(self.log, "RouteSocket::connect() done."); 58 | 59 | let vec: anyhow::Result>>; 60 | vec = c.list_device_names()? 61 | .into_iter() 62 | .map(|ifname| WireguardDev::new(ifname).map(|d| d.as_trait())) 63 | .collect(); 64 | debug!(self.log, "Found {:?} devices.", vec.as_ref().map(|v| v.len())); 65 | 66 | let it = vec?.into_iter().map(|dev| (dev, DeviceConfig {})); 67 | 68 | let stream = futures::stream::iter(it); 69 | Ok(Box::new(stream)) 70 | } 71 | 72 | async fn get_peers(&self, dev: &dyn WireguardDevice) -> anyhow::Result> + Unpin>> { 73 | Ok(Box::new(dev.get_peers().await?)) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/fake.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | use async_trait::async_trait; 4 | use async_std::prelude::*; 5 | 6 | use crate::PublicKey; 7 | use crate::SecretKey; 8 | use crate::api::*; 9 | use crate::WireguardDevice; 10 | use crate::stun; 11 | use crate::utils::UdpSender; 12 | use crate::utils::UdpReceiver; 13 | 14 | pub struct Cfg; 15 | 16 | /* 17 | impl Cfg { 18 | pub fn new() -> Self { 19 | Cfg 20 | } 21 | } 22 | */ 23 | 24 | #[async_trait] 25 | impl ConfigApi for Cfg { 26 | fn get_wireguard_devices(&self) -> anyhow::Result, DeviceConfig)> + Unpin>> { 27 | unimplemented!() 28 | } 29 | 30 | async fn get_peers(&self, dev: &dyn WireguardDevice) -> anyhow::Result> + Unpin>> { 31 | unimplemented!() 32 | } 33 | } 34 | 35 | pub struct FakeDht; 36 | 37 | /* 38 | impl FakeDht { 39 | pub fn new() -> Self { 40 | FakeDht 41 | } 42 | } 43 | */ 44 | 45 | #[async_trait] 46 | impl DhtApi for FakeDht { 47 | fn listen(&self, key: Vec) -> Box> + Send + Unpin> { 48 | unimplemented!() 49 | } 50 | 51 | async fn put(&self, key: &[u8], value: &[u8]) -> anyhow::Result<()> { 52 | todo!() 53 | } 54 | } 55 | 56 | pub struct FakeStun; 57 | 58 | #[async_trait] 59 | impl Stun for FakeStun { 60 | // return not just SocketAddr but also stun state type 61 | async fn lookup_public_address(&self, stun_log: &slog::Logger, 62 | to_inet_tx: &mut UdpSender, 63 | from_inet_rx: &mut UdpReceiver, 64 | stun_server: SocketAddr) -> anyhow::Result { 65 | todo!() 66 | } 67 | } 68 | 69 | pub struct FakeWireguardDevice; 70 | 71 | #[async_trait] 72 | impl WireguardDevice for FakeWireguardDevice { 73 | async fn get_listen_port(&self) -> anyhow::Result { 74 | return Ok(9999); 75 | } 76 | 77 | async fn set_endpoint(&self, remote_pkey: &PublicKey, remote_addr: &SocketAddr) -> anyhow::Result<()> { 78 | unimplemented!() 79 | } 80 | 81 | async fn get_name(&self) -> anyhow::Result { 82 | unimplemented!() 83 | } 84 | 85 | async fn get_public_key(&self) -> anyhow::Result> { 86 | unimplemented!() 87 | } 88 | 89 | async fn get_secret_key(&self) -> anyhow::Result> { 90 | unimplemented!() 91 | } 92 | 93 | async fn get_peers(&self) -> anyhow::Result> + Unpin>> { 94 | unimplemented!() 95 | } 96 | } 97 | 98 | pub struct NoopPublicKeyCrypto; 99 | 100 | impl PublicKeyCrypto for NoopPublicKeyCrypto { 101 | fn encrypt(&self, buf: &[u8]) -> anyhow::Result { 102 | return Ok(bytes::Bytes::from(buf.to_vec())); 103 | } 104 | 105 | fn decrypt(&self, buf: &[u8]) -> Option> { 106 | return Some(buf.to_vec()); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/wg_device.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | use std::sync::Arc; 3 | 4 | use anyhow::anyhow; 5 | use async_std::prelude::*; 6 | use async_std::sync::Mutex; 7 | use wireguard_uapi::{DeviceInterface, WgSocket}; 8 | 9 | use crate::api; 10 | use crate::WireguardDevice; 11 | use crate::PublicKey; 12 | use crate::SecretKey; 13 | 14 | #[allow(dead_code)] 15 | pub struct WireguardDev { 16 | socket: Arc>, 17 | ifindex: u32, 18 | ifname: String, 19 | } 20 | 21 | impl WireguardDev { 22 | pub fn new(ifname: String) -> anyhow::Result { 23 | let mut socket = WgSocket::connect()?; 24 | let dev = socket.get_device(DeviceInterface::from_name(&ifname))?; 25 | let ifindex = dev.ifindex; 26 | 27 | Ok(WireguardDev { 28 | ifindex, ifname, 29 | socket: Arc::new(Mutex::new(socket)), 30 | }) 31 | } 32 | 33 | async fn get_device(&self) -> anyhow::Result { 34 | let mut sock = self.socket.lock().await; 35 | 36 | let dev = sock.get_device(DeviceInterface::from_index(self.ifindex))?; 37 | Ok(dev) 38 | } 39 | 40 | pub fn as_trait(self) -> Box { 41 | Box::new(self) 42 | } 43 | } 44 | 45 | #[async_trait::async_trait] 46 | impl WireguardDevice for WireguardDev { 47 | async fn get_listen_port(&self) -> anyhow::Result { 48 | let dev = self.get_device().await?; 49 | return Ok(dev.listen_port); 50 | } 51 | 52 | async fn set_endpoint(&self, remote_pkey: &PublicKey, remote_addr: &SocketAddr) -> anyhow::Result<()> { 53 | let dev = self.get_device().await?; 54 | let peer = dev.peers.iter().filter(|p| p.public_key.eq(&remote_pkey.0.0)).next(); 55 | if let Some(peer) = peer { 56 | let peer = wireguard_uapi::set::Peer { 57 | public_key: &peer.public_key, 58 | flags: Vec::new(), 59 | preshared_key: Some(&peer.preshared_key), 60 | endpoint: Some(&remote_addr), 61 | persistent_keepalive_interval: if peer.persistent_keepalive_interval == 0 { None } else { Some(peer.persistent_keepalive_interval) }, 62 | allowed_ips: Vec::new(), 63 | protocol_version: if peer.protocol_version == 0 { None } else { Some(peer.protocol_version) }, 64 | }; 65 | 66 | let dev = wireguard_uapi::set::Device { 67 | interface: DeviceInterface::from_index(self.ifindex), 68 | flags: Vec::new(), 69 | private_key: dev.private_key.as_ref(), 70 | listen_port: if dev.listen_port == 0 { None } else { Some(dev.listen_port) }, 71 | fwmark: Some(dev.fwmark), 72 | peers: vec!(peer) 73 | }; 74 | 75 | let mut sock = self.socket.lock().await; 76 | sock.set_device(dev)?; 77 | Ok(()) 78 | } else { 79 | Err(anyhow!("Failed to find peer {} for wireguard device {} ({})", remote_pkey, self.ifname, self.ifindex)) 80 | } 81 | } 82 | 83 | async fn get_name(&self) -> anyhow::Result { 84 | let dev = self.get_device().await?; 85 | return Ok(dev.ifname); 86 | } 87 | 88 | async fn get_public_key(&self) -> anyhow::Result> { 89 | let dev = self.get_device().await?; 90 | let pkey = dev.public_key.map(PublicKey::new); 91 | return Ok(pkey); 92 | } 93 | 94 | async fn get_secret_key(&self) -> anyhow::Result> { 95 | let dev = self.get_device().await?; 96 | let skey = dev.private_key.map(SecretKey::new); 97 | return Ok(skey); 98 | } 99 | 100 | async fn get_peers(&self) -> anyhow::Result> + Unpin>> { 101 | let dev = self.get_device().await?; 102 | let vec: Vec> = dev.peers.into_iter().map(|p| Peer(p).as_trait()).collect(); 103 | let stream = futures::stream::iter(vec.into_iter()); 104 | Ok(Box::new(stream)) 105 | } 106 | } 107 | 108 | struct Peer(wireguard_uapi::get::Peer); 109 | 110 | impl Peer { 111 | fn as_trait(self) -> Box { 112 | Box::new(self) 113 | } 114 | } 115 | 116 | #[async_trait::async_trait] 117 | impl api::Peer for Peer { 118 | fn get_public_key(&self) -> PublicKey { 119 | PublicKey::new(self.0.public_key) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use std::future::Future; 2 | use std::collections::hash_map::Entry; 3 | use std::collections::hash_map::VacantEntry; 4 | use std::net::SocketAddr; 5 | use std::sync::Arc; 6 | use std::result::Result; 7 | 8 | use async_std::prelude::*; 9 | use async_std::channel::{Sender, Receiver}; 10 | 11 | #[async_trait::async_trait] 12 | pub trait TryInsertWithAsync<'a, V: Send> { 13 | async fn try_insert_with_async(self, default: F) -> Result<&'a mut V, E> 14 | where F: Send + Future>; 15 | } 16 | 17 | #[async_trait::async_trait] 18 | impl<'a, K: Send, V: Send> TryInsertWithAsync<'a, V> for VacantEntry<'a, K, V> { 19 | async fn try_insert_with_async(self, default: F) -> Result<&'a mut V, E> 20 | where F: Send + Future> 21 | { 22 | let v = default.await?; 23 | let v = self.insert(v); 24 | Ok(v) 25 | } 26 | } 27 | 28 | #[async_trait::async_trait] 29 | pub trait OrTryInsertWithAsync<'a, V: Send> { 30 | async fn or_try_insert_with_async(self, default: F) -> Result<&'a mut V, E> 31 | where F: Send + Future>; 32 | } 33 | 34 | #[async_trait::async_trait] 35 | impl<'a, K: Send, V: Send> OrTryInsertWithAsync<'a, V> for Entry<'a, K, V> { 36 | async fn or_try_insert_with_async(self, default: F) -> Result<&'a mut V, E> 37 | where F: Send + Future> 38 | { 39 | match self { 40 | Entry::Occupied(v) => Ok(v.into_mut()), 41 | Entry::Vacant(o) => Ok(o.try_insert_with_async(default).await?) 42 | } 43 | } 44 | } 45 | 46 | pub fn spawn(future: F) where 47 | F: Future> + Send + 'static, 48 | { 49 | let handle = async_std::task::spawn(async { 50 | if let Err(e) = future.await { 51 | unimplemented!("Task failed: {:?}", e); 52 | // todo!() //error!("Task failed: {:?}", e); 53 | } 54 | }); 55 | // TODO: what to do with handle? 56 | } 57 | 58 | pub fn batches + Unpin>(mut stream: S) 59 | -> impl futures::Stream> { 60 | async_stream::stream! { 61 | loop { 62 | while let Some(res) = stream.next().await { 63 | yield vec![res].into_iter(); 64 | } 65 | } 66 | } 67 | } 68 | 69 | /* 70 | TODO: 71 | pub fn batches + Unpin>(mut stream: S) 72 | -> impl futures::Stream> 73 | { 74 | async_stream::stream! { 75 | loop { 76 | let mut items = vec![]; 77 | while let Ok(res) = stream.next().timeout(Duration::from_secs(0)).await { 78 | if let Some(item) = res { 79 | items.push(item) 80 | } else { 81 | yield items.into_iter(); 82 | return; 83 | } 84 | } 85 | if !items.is_empty() { 86 | yield items.into_iter(); 87 | } 88 | } 89 | } 90 | } 91 | */ 92 | 93 | pub type UdpSender = Sender<(Vec, SocketAddr)>; 94 | pub type UdpReceiver = Receiver<(bytes::Bytes, SocketAddr)>; 95 | 96 | pub fn split_udp_socket(sock: async_std::net::UdpSocket) -> (UdpSender, UdpReceiver) { 97 | let (tx1, rx2) = async_std::channel::unbounded(); 98 | let (tx2, rx1) = async_std::channel::unbounded(); 99 | 100 | let sock = Arc::new(sock); 101 | let sock1 = sock.clone(); 102 | 103 | spawn(async move { 104 | let mut buf = vec![0u8; 64 * 1024]; 105 | loop { 106 | let (n, peer) = sock.recv_from(&mut buf).await?; 107 | let b = bytes::Bytes::copy_from_slice(&buf[..n]); 108 | tx2.send((b, peer)).await? 109 | } 110 | }); 111 | 112 | spawn(async move { 113 | loop { 114 | let (buf, dst): (Vec, SocketAddr) = rx2.recv().await?; 115 | let n = sock1.send_to(&buf[..], dst).await?; 116 | assert_eq!(buf.len(), n); 117 | } 118 | }); 119 | 120 | 121 | (tx1, rx1) 122 | } 123 | 124 | pub fn cloned_rx(rx: UdpReceiver) -> (UdpReceiver, UdpReceiver) { 125 | let (tx1, rx1) = async_std::channel::unbounded(); 126 | let (tx2, rx2) = async_std::channel::unbounded(); 127 | 128 | spawn(async move { 129 | loop { 130 | let (buf, dst) = rx.recv().await?; 131 | tx1.send((buf.clone(), dst.clone())).await?; 132 | tx2.send((buf, dst)).await?; 133 | } 134 | }); 135 | 136 | (rx1, rx2) 137 | } 138 | -------------------------------------------------------------------------------- /src/stun/mod.rs: -------------------------------------------------------------------------------- 1 | mod codec; 2 | 3 | use slog::{info, debug}; 4 | 5 | use std::net::SocketAddr; 6 | use std::time::Instant; 7 | use std::time::Duration; 8 | use std::net::IpAddr; 9 | use std::net::Ipv4Addr; 10 | 11 | use rand::Rng; 12 | use rand::SeedableRng; 13 | 14 | use async_std::prelude::*; 15 | use async_std::sync::Mutex; 16 | 17 | //pub const NETWORK_UNREACHABLE: i32 = 101; 18 | 19 | use crate::stun::codec::*; 20 | use crate::utils::UdpSender; 21 | use crate::utils::UdpReceiver; 22 | 23 | lazy_static::lazy_static! { 24 | static ref RNG: Mutex = Mutex::new(rand::rngs::SmallRng::from_entropy()); 25 | } 26 | 27 | #[derive(Copy, Clone, Debug, PartialEq)] 28 | pub enum Connectivity { 29 | OpenInternet(SocketAddr), 30 | FullConeNat(SocketAddr), 31 | SymmetricNat, 32 | RestrictedPortNat(SocketAddr), 33 | RestrictedConeNat(SocketAddr), 34 | SymmetricFirewall(SocketAddr), 35 | } 36 | 37 | impl Into> for Connectivity { 38 | fn into(self) -> Option { 39 | match self { 40 | Connectivity::OpenInternet(addr) => Some(addr), 41 | Connectivity::FullConeNat(addr) => Some(addr), 42 | Connectivity::SymmetricNat => None, 43 | Connectivity::RestrictedPortNat(addr) => Some(addr), 44 | Connectivity::RestrictedConeNat(addr) => Some(addr), 45 | Connectivity::SymmetricFirewall(addr) => Some(addr), 46 | } 47 | } 48 | } 49 | 50 | pub struct Stun; 51 | 52 | #[async_trait::async_trait] 53 | impl crate::api::Stun for Stun { 54 | async fn lookup_public_address(&self, stun_log: &slog::Logger, 55 | mut to_inet_tx: &mut UdpSender, 56 | mut from_inet_rx: &mut UdpReceiver, 57 | stun_server: SocketAddr) -> anyhow::Result { 58 | let bind_addr = IpAddr::V4(Ipv4Addr::UNSPECIFIED); 59 | let addr: Option; 60 | let conn = check(stun_log, &mut to_inet_tx, &mut from_inet_rx, bind_addr, stun_server).await?; 61 | Ok(conn) 62 | } 63 | } 64 | 65 | 66 | async fn check(stun_log: &slog::Logger, 67 | mut to_inet_tx: &mut UdpSender, 68 | mut from_inet_rx: &mut UdpReceiver, 69 | bind_addr: IpAddr, 70 | stun_server: SocketAddr, 71 | ) -> Result { 72 | let resp = change_request(&mut to_inet_tx, &mut from_inet_rx, stun_server, ChangeRequest::None).await?; 73 | if let Some(Response::Bind(resp)) = resp { 74 | let public_addr = resp.mapped_address; 75 | 76 | if bind_addr == public_addr.ip() { 77 | debug!(stun_log, 78 | "No NAT. Public IP ({}) == Bind IP ({})", 79 | bind_addr, 80 | public_addr.ip() 81 | ); 82 | let resp = change_request(&mut to_inet_tx, &mut from_inet_rx, stun_server, ChangeRequest::IpAndPort).await?; 83 | if resp.is_some() { 84 | info!(stun_log, "OpenInternet: {}", public_addr); 85 | return Ok(Connectivity::OpenInternet(public_addr)); 86 | } else { 87 | info!(stun_log, "SymmetricFirewall: {}", public_addr); 88 | return Ok(Connectivity::SymmetricFirewall(public_addr)); 89 | } 90 | } 91 | debug!(stun_log, "Public IP ({}) != Bind IP ({})", bind_addr, public_addr.ip()); 92 | 93 | // NAT detected 94 | let resp = change_request(&mut to_inet_tx, &mut from_inet_rx, stun_server, ChangeRequest::IpAndPort).await?; 95 | if resp.is_some() { 96 | info!(stun_log, "FullConeNat: {}", public_addr); 97 | return Ok(Connectivity::FullConeNat(public_addr)); 98 | } 99 | 100 | debug!(stun_log, "No respone from different IP and Port"); 101 | let resp = change_request(&mut to_inet_tx, &mut from_inet_rx, stun_server, ChangeRequest::Port).await?; 102 | if let Some(Response::Bind(resp)) = resp { 103 | if resp.mapped_address.ip() != public_addr.ip() { 104 | info!(stun_log, "SymmetricNat"); 105 | return Ok(Connectivity::SymmetricNat); 106 | } 107 | 108 | let resp = change_request(&mut to_inet_tx, &mut from_inet_rx, stun_server, ChangeRequest::Port).await?; 109 | if resp.is_some() { 110 | info!(stun_log, "RestrictedConeNat: {}", public_addr); 111 | Ok(Connectivity::RestrictedConeNat(public_addr)) 112 | } else { 113 | info!(stun_log, "RestrictedPortNat: {}", public_addr); 114 | Ok(Connectivity::RestrictedPortNat(public_addr)) 115 | } 116 | } else { 117 | let msg = format!("Expected Some(BindResponse) but got {:?} instead!", resp); 118 | todo!() 119 | //Err(std::io::Error::new(ErrorKind::InvalidData, msg)) 120 | } 121 | } else { 122 | todo!() 123 | // Err(std::io::Error::from_raw_os_error(NETWORK_UNREACHABLE)) 124 | } 125 | } 126 | 127 | async fn change_request( 128 | to_inet_tx: &mut UdpSender, 129 | from_inet_rx: &mut UdpReceiver, 130 | stun_server: SocketAddr, 131 | req: ChangeRequest, 132 | ) -> Result, anyhow::Error> { 133 | let req = codec::Request::Bind(BindRequest { 134 | change_request: req, 135 | ..Default::default() 136 | }); 137 | 138 | send_request(to_inet_tx, from_inet_rx, stun_server, req).await 139 | } 140 | 141 | async fn send_request( 142 | to_inet_tx: &mut UdpSender, 143 | from_inet_rx: &mut UdpReceiver, 144 | stun_server: SocketAddr, 145 | req: Request, 146 | ) -> Result, anyhow::Error> { 147 | let mut lock = RNG.lock().await; 148 | let id: u64 = lock.gen(); 149 | 150 | let mut buf = bytes::BytesMut::new(); 151 | StunCodec::encode((id, req), &mut buf)?; 152 | to_inet_tx.send((buf.to_vec(), stun_server)).await?; 153 | 154 | let start = Instant::now(); 155 | 156 | loop { 157 | let dur = Duration::from_secs(10).checked_sub(Instant::now() - start); 158 | let dur = dur.unwrap_or(Duration::from_secs(0)); 159 | match async_std::future::timeout(dur, from_inet_rx.next()).await { 160 | Err(e) => return Ok(None), 161 | Ok(None) => return Ok(None), 162 | Ok(Some((buf, src))) => { 163 | if let Some((actual_id, resp)) = StunCodec::decode_const(&buf)? { 164 | if actual_id == id { 165 | return Ok(Some(resp)); 166 | } 167 | } else { 168 | continue 169 | } 170 | } 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(unreachable_code)] 2 | #![allow(unused_variables)] 3 | 4 | mod api; 5 | mod fake; 6 | mod utils; 7 | mod message; 8 | mod wg_device; 9 | mod crypto; 10 | mod stun; 11 | mod config; 12 | mod dht; 13 | 14 | use std::sync::Arc; 15 | use std::net::SocketAddr; 16 | use std::net::IpAddr; 17 | use std::net::Ipv4Addr; 18 | use std::collections::HashMap; 19 | use std::collections::hash_map::Entry; 20 | use std::time::Duration; 21 | use std::time::SystemTime; 22 | 23 | use async_std::sync::RwLock; 24 | use async_std::sync::Mutex; 25 | use async_std::sync::Condvar; 26 | use async_std::net::UdpSocket; 27 | use async_std::net::ToSocketAddrs; 28 | use anyhow::{bail, anyhow, Context}; 29 | 30 | use slog::Drain; 31 | use slog::{debug, info, error, crit}; 32 | 33 | use api::*; 34 | use utils::*; 35 | use crypto::*; 36 | use dht::OpenDht; 37 | use message::Message; 38 | use utils::{UdpSender, UdpReceiver}; 39 | use config::Config; 40 | use futures::stream::StreamExt; 41 | 42 | type RwConnectionsMap = RwLock>>; 43 | 44 | /// Creates a new local socket and forwards all incoming data (outbound wireguard traffic) to the internet 45 | /// The returned local socket can be used to forward inbound wireguard traffic from this peer_addr 46 | /// to the wireguard interface at wg_lo_port (typically done in forward_incoming_traffic() via the connections map) 47 | /// 48 | /// public_socket: public internet socket 49 | async fn new_local_socket(parent_log: &slog::Logger, 50 | to_inet_tx: UdpSender, 51 | remote_peer_addr: SocketAddr) -> anyhow::Result> { 52 | info!(parent_log, "Setting up new local address"; slog::o!("remote_addr" => remote_peer_addr)); 53 | let lo_socket = UdpSocket::bind("127.0.0.1:0").await?; 54 | let lo_socket = Arc::new(lo_socket); 55 | 56 | let lo_sock = lo_socket.clone(); 57 | let local_addr = lo_socket.local_addr()?; 58 | let mut buf = vec![0u8; 64 * 1024]; 59 | 60 | let log_out = parent_log.new(slog::o!("direction" => "outbound")); 61 | let handle = spawn(async move { 62 | // forward data from local socket (outbound wireguard) to the internet 63 | loop { 64 | let (n, lo_peer_addr) = lo_sock.recv_from(&mut buf).await?; 65 | debug!(log_out, "Forwarding outbound packet..."; slog::o!("src" => lo_peer_addr, "via_lo" => local_addr, "dst" => remote_peer_addr, "bytes" => n)); 66 | // lo_peer_addr must be wireguard on localhost 67 | to_inet_tx.send((buf[..n].to_vec(), remote_peer_addr)).await?; 68 | debug!(log_out, "Outbound packet forwarded"; slog::o!("src" => lo_peer_addr, "via_lo" => local_addr, "dst" => remote_peer_addr, "bytes" => n)); 69 | } 70 | Ok(()) 71 | }); 72 | 73 | Ok(lo_socket) 74 | } 75 | 76 | async fn dht_get(log_get: slog::Logger, 77 | dht: OpenDht, 78 | wg_dev: Arc>, 79 | remote_pkey: PublicKey, 80 | to_inet_tx: UdpSender, 81 | connections: Arc) -> anyhow::Result<()> { 82 | let secret_key = wg_dev.get_secret_key().await?; 83 | let secret_key = secret_key.ok_or(anyhow!("Wireguard device {:?} has no secret key!", wg_dev.get_name().await))?; 84 | let local_pkey = secret_key.public_key(); 85 | let crypto = Sodiumoxide::new(&remote_pkey, &secret_key); 86 | 87 | let key = [remote_pkey.0.0, local_pkey.0.0].concat(); 88 | debug!(log_get, "Waiting for remote peer to publish IP in DHT..."; slog::o!("dht_key" => base64::encode(&key))); 89 | 90 | // TODO: if not found within X seconds, repeat 91 | 92 | let mut last_timestamp: Option = None; 93 | 94 | let listen = batches(dht.listen(key.clone())); 95 | futures::pin_mut!(listen); 96 | while let Some(batch) = listen.next().await { 97 | // TODO: need secret key for PublicKeyCrypto 98 | let batch: Vec<_> = batch.collect(); 99 | dbg!(batch.len()); 100 | let batch = batch.into_iter(); 101 | 102 | let batch = batch.map(|value| crypto.decrypt(&value[..])) 103 | .filter_map(|value| {if value.is_none() { debug!(log_get, "Decryption failed") }; value }); 104 | 105 | let batch: Vec<_> = batch.collect(); 106 | dbg!(batch.len()); 107 | let batch = batch.into_iter(); 108 | 109 | let batch = batch.map(|value| serde_json::from_slice::(&value[..])) 110 | .filter_map(|value| {if value.is_err() { info!(log_get, "Deserialization failed") }; value.ok() }); 111 | let batch: Vec<_> = batch.collect(); 112 | dbg!(batch.len()); 113 | let batch = batch.into_iter(); 114 | 115 | let msg = batch.max_by_key(|m| m.timestamp); 116 | 117 | dbg!(&msg); 118 | 119 | let a = msg.as_ref().and_then(|m| m.timestamp.duration_since(SystemTime::UNIX_EPOCH).map(|d| d.as_secs()).ok()); 120 | let b = last_timestamp.as_ref().and_then(|t| t.duration_since(SystemTime::UNIX_EPOCH).map(|d| d.as_secs()).ok()); 121 | debug!(log_get, "msg_ts < last_ts?"; slog::o!("msg_ts" => a, "last_ts" => b)); 122 | if msg.as_ref().map(|m| m.timestamp) < last_timestamp { 123 | debug!(log_get, "skipping"; slog::o!("msg_ts" => a, "last_ts" => b)); 124 | continue 125 | } 126 | last_timestamp = msg.as_ref().map(|m| m.timestamp); 127 | let ip_addr_list = msg.map(|m| m.ip_addr_list).unwrap_or(vec![]); 128 | 129 | for remote_peer_addr in ip_addr_list { 130 | // TODO: check remote_peer_addr ip type 131 | info!(log_get, "Found new remote peer address"; slog::o!("addr" => remote_peer_addr, "dht_key" => base64::encode(&key))); 132 | 133 | let mut write_map = connections.write().await; 134 | 135 | let insertion = new_local_socket(&log_get, to_inet_tx.clone(), remote_peer_addr); 136 | let local_peer_addr = match write_map.entry(remote_peer_addr) { 137 | Entry::Vacant(vacant) => vacant.try_insert_with_async(insertion).await?.local_addr()?, 138 | Entry::Occupied(value) => value.get().local_addr()?, 139 | }; 140 | 141 | wg_dev.set_endpoint(&remote_pkey, &local_peer_addr).await?; 142 | debug!(log_get, "Wireguard endpoint set"; slog::o!("fwd_addr" => local_peer_addr, "remote_addr" => remote_peer_addr)); 143 | // TODO: sleep for a short time 144 | } 145 | debug!(log_get, "Waiting for remote peer to publish a new IP in DHT..."; slog::o!("dht_key" => base64::encode(&key))); 146 | } 147 | 148 | Ok(()) 149 | } 150 | 151 | async fn dht_put(log_put: slog::Logger, 152 | dht: OpenDht, 153 | wg_dev: Arc>, 154 | remote_pkey: PublicKey, 155 | public_address: Arc<(Mutex, Condvar)>) -> anyhow::Result<()> { 156 | let (lock, cvar) = &*public_address; 157 | 158 | let secret_key = wg_dev.get_secret_key().await?; 159 | let secret_key = secret_key.ok_or(anyhow!("Wireguard device {:?} has no secret key!", wg_dev.get_name().await))?; 160 | let local_pkey = secret_key.public_key(); 161 | let crypto = Sodiumoxide::new(&remote_pkey, &secret_key); 162 | 163 | let mut guard = cvar.wait_until(lock.lock().await, |addr| { 164 | let addr = Into::>::into(*addr); 165 | addr.map(|a| !a.ip().is_unspecified()).unwrap_or(false) 166 | }).await; 167 | 168 | loop { 169 | let public_addr: Option = (*guard).into(); 170 | debug!(log_put, "Got myown a new public address"; slog::o!("addr" => format!("{:?}", public_addr))); 171 | drop(guard); 172 | 173 | let msg = Message { 174 | timestamp: std::time::SystemTime::now(), 175 | ip_addr_list: public_addr.map(|a| vec![a]).unwrap_or(vec![]), 176 | }; 177 | 178 | let value = serde_json::to_vec(&msg)?; 179 | let value = crypto.encrypt(&value[..])?; 180 | let key = if let Some(local_pkey) = wg_dev.get_public_key().await? { 181 | [local_pkey.0.0, remote_pkey.0.0].concat() 182 | } else { 183 | bail!("Wireguard device {:?} has no public key!", wg_dev.get_name().await); 184 | }; 185 | 186 | 187 | let res = dht.put(&key[..], &value[..]).await; 188 | info!(log_put, "Published own public address on DHT"; slog::o!("dht_key" => base64::encode(key), "addr" => public_addr)); 189 | 190 | let (g, res) = cvar.wait_timeout(lock.lock().await, Duration::from_secs(60)).await; 191 | guard = g; 192 | 193 | if res.timed_out() { 194 | debug!(log_put, "Republishing old address..."; slog::o!("addr" => public_addr)); 195 | } 196 | } 197 | Ok(()) 198 | } 199 | 200 | async fn forward_inbound_traffic(log_fwd: slog::Logger, 201 | to_inet_tx: UdpSender, 202 | mut from_inet_rx: UdpReceiver, 203 | connections: Arc, wg_lo_port: u16) -> anyhow::Result<()> { 204 | let wg_lo_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), wg_lo_port); 205 | 206 | while let Some((buf, remote_peer_addr)) = from_inet_rx.next().await { 207 | debug!(log_fwd, "Received inbound packet"; slog::o!("src" => remote_peer_addr, "dst" => wg_lo_addr, "bytes" => buf.len())); 208 | 209 | // TODO: if remote_peer_addr is the same as in previous iteration, just cache lo_socket 210 | 211 | let lo_socket = { 212 | let read_map = connections.read().await; 213 | if let Some(lo_sock) = read_map.get(&remote_peer_addr) { 214 | lo_sock.clone() 215 | } else { 216 | drop(read_map); 217 | let mut write_map = connections.write().await; 218 | let insertion = new_local_socket(&log_fwd, to_inet_tx.clone(), remote_peer_addr); 219 | write_map.entry(remote_peer_addr).or_try_insert_with_async(insertion).await?.clone() 220 | } 221 | }; 222 | 223 | lo_socket.send_to(&buf, &wg_lo_addr).await?; 224 | debug!(log_fwd, "Forwarded inbound packet"; slog::o!("remote_addr" => remote_peer_addr, "bytes" => buf.len(), "wg_addr" => wg_lo_addr)); 225 | } 226 | 227 | Ok(()) 228 | } 229 | 230 | async fn lookup_public_address(log: slog::Logger, 231 | stun_server: SocketAddr, 232 | mut to_inet_tx: UdpSender, 233 | mut from_inet_rx: UdpReceiver, 234 | public_address: Arc<(Mutex, Condvar)>) -> anyhow::Result<()> { 235 | let stun = stun::Stun; 236 | loop { 237 | match stun.lookup_public_address(&log, &mut to_inet_tx, &mut from_inet_rx, stun_server).await { 238 | Ok(new_address) => { 239 | let addr: Option = new_address.into(); 240 | debug!(log, "STUN succeeded"; slog::o!("addr" => addr)); 241 | let old_address = *public_address.0.lock().await; 242 | if new_address != old_address { 243 | info!(log, "STUN found new address"; slog::o!("addr" => addr)); 244 | let mut lock = public_address.0.lock().await; 245 | *lock = new_address; 246 | public_address.1.notify_all(); 247 | debug!(log, "STUN all tasks notified"; slog::o!("addr" => addr)); 248 | } 249 | async_std::task::sleep(Duration::from_secs(60)).await; 250 | } 251 | Err(err) => { 252 | error!(log, "STUN failed"; slog::o!("error" => format!("{:?}", err))); 253 | async_std::task::sleep(Duration::from_secs(15)).await; 254 | } 255 | } 256 | } 257 | } 258 | 259 | async fn handle_device(log_dev: slog::Logger, 260 | dht: OpenDht, 261 | cfg: Arc, wg_dev: Box) -> anyhow::Result<()> { 262 | let wg_lo_port = wg_dev.get_listen_port().await?; 263 | debug!(log_dev, "Wireguard device port found"; "port" => wg_lo_port); 264 | 265 | let connections: Arc; 266 | connections = Arc::new(RwLock::new(HashMap::new())); 267 | 268 | let public_socket = UdpSocket::bind("[::]:0").await?; 269 | info!(log_dev, "Listening on public address"; "address" => public_socket.local_addr()?); 270 | 271 | let (to_inet_tx, from_inet_rx) = split_udp_socket(public_socket); 272 | let (from_inet_rx1, from_inet_rx2) = cloned_rx(from_inet_rx); 273 | 274 | let log_fwd = log_dev.new(slog::o!("traffic" => "inbound")); 275 | spawn(forward_inbound_traffic(log_fwd, to_inet_tx.clone(), from_inet_rx1, connections.clone(), wg_lo_port)); 276 | 277 | let log_stun = log_dev.new(slog::o!("traffic" => "stun")); 278 | // TODO: resolve ip later 279 | let stun_server = "stun.wtfismyip.com:3478".to_socket_addrs().await?.next().unwrap(); 280 | let public_address = Arc::new((Mutex::new(stun::Connectivity::SymmetricNat), Condvar::new())); 281 | spawn(lookup_public_address(log_stun, stun_server, to_inet_tx.clone(), from_inet_rx2, public_address.clone())); 282 | 283 | // TODO: drop last public_socket 284 | // todo!(); 285 | 286 | let mut peers = cfg.get_peers(wg_dev.as_ref()).await?; 287 | let wg_dev = Arc::new(wg_dev); 288 | 289 | while let Some(peer) = peers.next().await { 290 | let remote_pkey = peer.get_public_key(); 291 | 292 | let log_peer = log_dev.new(slog::o!("peer" => format!("{:}", remote_pkey))); 293 | let log_put = log_peer.new(slog::o!("dht" => "put")); 294 | let log_get = log_peer.new(slog::o!("dht" => "get")); 295 | 296 | spawn(dht_put(log_put, dht.clone(), wg_dev.clone(), remote_pkey.clone(), public_address.clone().into())); 297 | spawn(dht_get(log_get, dht.clone(), wg_dev.clone(), remote_pkey, to_inet_tx.clone(), connections.clone())); 298 | } 299 | 300 | Ok(()) 301 | } 302 | 303 | #[async_std::main] 304 | async fn main() -> anyhow::Result<()> { 305 | if let Err(()) = sodiumoxide::init() { 306 | bail!("Initializing sodiumoxide failed"); 307 | } 308 | 309 | let decorator = slog_term::TermDecorator::new().build(); 310 | let drain = slog_term::FullFormat::new(decorator).build().fuse(); 311 | let drain = slog_async::Async::new(drain).build().fuse(); 312 | 313 | let log = slog::Logger::root(drain, slog::o!()); 314 | 315 | let cfg = Arc::new(Config::new(log.clone())?); 316 | 317 | // [x] stun 318 | // [ ] cli 319 | // [ ] config 320 | // [ ] dynamic config 321 | 322 | let mut stream = cfg.get_wireguard_devices()?; 323 | 324 | // TODO: use another port or the same opendht instance for all wg devices 325 | let dht_log = log.new(slog::o!("task" => "dht")); 326 | let dht = OpenDht::new(dht_log, cfg.opendht_port, "bootstrap.ring.cx:4222").await.context("Initializing DHT failed")?; 327 | 328 | let mut futures = vec![]; 329 | while let Some((wg_dev, dev_cfg)) = stream.next().await { 330 | debug!(log, "Getting device name..."); 331 | let dev_name = wg_dev.get_name().await?; 332 | let log_dev = log.new(slog::o!("dev" => dev_name.to_string())); 333 | debug!(log_dev, "Handling device"); 334 | futures.push(handle_device(log_dev, dht.clone(), Arc::new(dev_cfg), wg_dev)); 335 | } 336 | 337 | let results = futures::future::join_all(futures).await; 338 | if results.len() == 0 { 339 | crit!(log, "No wireguard devices found!"); 340 | } else { 341 | results.into_iter().collect::>()?; 342 | async_std::future::pending::<()>().await; 343 | } 344 | 345 | Ok(()) 346 | } 347 | -------------------------------------------------------------------------------- /src/stun/codec.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use std::io::Cursor; 4 | use std::io::Error; 5 | use std::io::ErrorKind; 6 | use std::io::Read; 7 | use std::io::Result; 8 | use std::io::Seek; 9 | use std::io::SeekFrom; 10 | use std::io::Write; 11 | use std::net::IpAddr; 12 | use std::net::Ipv4Addr; 13 | use std::net::SocketAddr; 14 | 15 | use futures::Sink; 16 | use futures::SinkExt; 17 | use futures::Stream; 18 | use futures::TryStream; 19 | use futures::StreamExt; 20 | 21 | use byteorder::NetworkEndian; 22 | use byteorder::ReadBytesExt; 23 | use byteorder::WriteBytesExt; 24 | use bytes::BufMut; 25 | //use ring::constant_time::verify_slices_are_equal; 26 | //use ring::digest; 27 | 28 | #[derive(Debug, Clone)] 29 | pub enum Request { 30 | Bind(BindRequest), 31 | SharedSecret, //(SharedSecretRequestMsg), 32 | } 33 | 34 | #[derive(Debug, Clone, PartialEq)] 35 | pub enum ChangeRequest { 36 | None, 37 | Ip, 38 | Port, 39 | IpAndPort, 40 | } 41 | 42 | impl Default for ChangeRequest { 43 | fn default() -> Self { 44 | ChangeRequest::None 45 | } 46 | } 47 | 48 | #[derive(Debug, Default, Clone)] 49 | pub struct BindRequest { 50 | pub response_address: Option, 51 | pub change_request: ChangeRequest, 52 | pub username: Option>, 53 | } 54 | 55 | impl BindRequest { 56 | fn encode(&self) -> Result> { 57 | let mut buf = Vec::new(); 58 | 59 | if let Some(a) = self.response_address { 60 | Attribute::ResponseAddress(a).encode(&mut buf)?; 61 | } 62 | 63 | if self.change_request != ChangeRequest::None { 64 | let r = self.change_request.clone(); 65 | Attribute::ChangeRequest(r).encode(&mut buf)?; 66 | } 67 | 68 | if let Some(ref u) = self.username { 69 | Attribute::Username(u.clone()).encode(&mut buf)?; 70 | } 71 | 72 | Ok(buf) 73 | } 74 | } 75 | 76 | #[derive(Debug)] 77 | pub enum Response { 78 | Bind(BindResponse), 79 | // 'BindErrorResponseMsg': BindErrorResponseMsg, 80 | // 'SharedSecretResponseMsg': SharedSecretResponseMsg, 81 | // 'SharedSecretErrorResponseMsg': SharedSecretErrorResponseMsg} 82 | } 83 | 84 | #[derive(Debug)] 85 | pub struct BindResponse { 86 | pub mapped_address: SocketAddr, 87 | pub source_address: SocketAddr, 88 | pub changed_address: SocketAddr, 89 | pub reflected_from: Option, 90 | } 91 | 92 | #[derive(Default)] 93 | pub struct StunCodec; 94 | 95 | pub enum Attribute { 96 | MappedAddress(SocketAddr), 97 | ResponseAddress(SocketAddr), 98 | ChangedAddress(SocketAddr), 99 | SourceAddress(SocketAddr), 100 | ReflectedFrom(SocketAddr), 101 | ChangeRequest(ChangeRequest), 102 | MessageIntegrity([u8; 20]), 103 | Username(Vec), 104 | UnknownOptional, 105 | } 106 | 107 | impl StunCodec { 108 | pub fn new() -> StunCodec { 109 | StunCodec 110 | } 111 | 112 | pub fn encode(msg: (u64, Request), buf: &mut bytes::BytesMut) -> Result<()> { 113 | let (trans_id, req) = msg; 114 | 115 | let (typ, m) = match req { 116 | Request::Bind(bind) => (BINDING_REQUEST, bind.encode()?), 117 | _ => unimplemented!(), 118 | }; 119 | 120 | buf.put_u16(typ); 121 | // buf.write_u16::(m.len() as u16 + 24).unwrap(); 122 | buf.put_u16(m.len() as u16); 123 | buf.put_u64(0); 124 | buf.put_u64(trans_id); 125 | buf.put_slice(&m); 126 | 127 | Ok(()) 128 | /* 129 | TODO sha1 130 | 131 | let mut copy = buf.clone(); 132 | while copy.len() % 64 != 0 { 133 | copy.write_u8(0).unwrap(); 134 | } 135 | println!("{}", copy.len()); 136 | 137 | let mut hash = [0; 20]; 138 | let digest = digest::digest(&digest::SHA1, ©[..]); 139 | hash.copy_from_slice(digest.as_ref()); 140 | let message_integrity = Attribute::MessageIntegrity(hash); 141 | message_integrity.encode(buf).unwrap(); 142 | */ 143 | } 144 | 145 | 146 | fn read_binding_response(_msg: &[u8], c: &mut Cursor<&[u8]>) -> Result { 147 | let mut mapped_address = None; 148 | let mut source_address = None; 149 | let mut changed_address = None; 150 | let mut message_integrity = None; 151 | let mut reflected_from = None; 152 | 153 | let error = |reason| Error::new(ErrorKind::InvalidData, reason); 154 | 155 | loop { 156 | let attr = Attribute::read(c); 157 | match attr { 158 | Ok(Attribute::MappedAddress(s)) => { 159 | mapped_address.get_or_insert(s); 160 | } 161 | Ok(Attribute::SourceAddress(s)) => { 162 | source_address.get_or_insert(s); 163 | } 164 | Ok(Attribute::ChangedAddress(s)) => { 165 | changed_address.get_or_insert(s); 166 | } 167 | Ok(Attribute::ReflectedFrom(s)) => { 168 | reflected_from.get_or_insert(s); 169 | } 170 | Ok(Attribute::MessageIntegrity(s)) => { 171 | message_integrity.get_or_insert(s); 172 | } 173 | Ok(Attribute::UnknownOptional) => continue, 174 | Err(ref e) if e.kind() == ErrorKind::UnexpectedEof => break, 175 | _ => return Err(error("Unknown mandatory attribute!")), 176 | }; 177 | } 178 | 179 | /* 180 | if let Some(expected) = message_integrity { 181 | let actual = digest::digest(&digest::SHA1, &msg[..msg.len() - 24]); 182 | 183 | if verify_slices_are_equal(actual.as_ref(), &expected).is_err() { 184 | return Err(error("Message integrity violated!")); 185 | } 186 | } 187 | */ 188 | 189 | Ok(BindResponse { 190 | mapped_address: mapped_address.ok_or_else(|| error("MappedAddress missing!"))?, 191 | source_address: source_address.ok_or_else(|| error("SourceAddress missing!"))?, 192 | changed_address: changed_address.ok_or_else(|| error("ChangedAddress missing!"))?, 193 | reflected_from, 194 | }) 195 | } 196 | 197 | pub fn decode_stream(stream: impl Stream, SocketAddr)>) -> impl TryStream { 198 | stream.filter_map(|(buf, peer)| { 199 | let pkt = StunCodec::decode_const(buf.as_ref()).ok().flatten(); 200 | futures::future::ready(pkt.map(|pkt| Ok((pkt, peer)))) 201 | }) 202 | } 203 | 204 | pub fn encode_sink(sink: impl Sink<(bytes::Bytes, SocketAddr), Error=Error> + Unpin) -> impl Sink<((u64, Request), SocketAddr), Error=Error> + Unpin 205 | { 206 | sink.with(|((id, req), peer): ((u64, Request), SocketAddr)| { 207 | let mut buf = bytes::BytesMut::with_capacity(4096); 208 | let res = StunCodec::encode((id, req), &mut buf); 209 | futures::future::ready(res.map(|_| (buf.freeze(), peer))) 210 | }) 211 | } 212 | 213 | 214 | pub fn decode_const(msg: &[u8]) -> Result> { 215 | let mut c = Cursor::new(msg); 216 | 217 | let msg_type = c.read_u16::()?; 218 | let _msg_len = c.read_u16::()?; 219 | let trans_id1 = c.read_u64::()?; 220 | let trans_id2 = c.read_u64::()?; 221 | 222 | if trans_id1 != 0 { 223 | return Ok(None)/* 224 | return Err(Error::new( 225 | ErrorKind::InvalidData, 226 | "Invalid transaction ID!", 227 | ));*/ 228 | } 229 | 230 | let res = match msg_type { 231 | BINDING_RESPONSE => StunCodec::read_binding_response(msg, &mut c).map(Response::Bind), 232 | BINDING_ERROR => Err(Error::new( 233 | ErrorKind::InvalidData, 234 | "BINDING_ERROR unimplemented", 235 | )), 236 | SHARED_SECRET_RESPONSE => Err(Error::new( 237 | ErrorKind::InvalidData, 238 | "SHARED_SECRET_RESPONSE unimplemented", 239 | )), 240 | SHARED_SECRET_ERROR => Err(Error::new( 241 | ErrorKind::InvalidData, 242 | "SHARED_SECRET_ERROR unimplemented", 243 | )), 244 | _ => return Err(Error::new(ErrorKind::InvalidData, "Unknown message type!")), 245 | }; 246 | 247 | res.map(|v| Some((trans_id2, v))) 248 | } 249 | } 250 | 251 | impl Attribute { 252 | fn read(mut c: &mut Cursor<&[u8]>) -> Result { 253 | let typ = c.read_u16::()?; 254 | let len = c.read_u16::()?; 255 | 256 | match typ { 257 | MAPPED_ADDRESS => Ok(Attribute::MappedAddress(Self::read_address(&mut c)?)), 258 | RESPONSE_ADDRESS => Ok(Attribute::ResponseAddress(Self::read_address(&mut c)?)), 259 | CHANGED_ADDRESS => Ok(Attribute::ChangedAddress(Self::read_address(&mut c)?)), 260 | SOURCE_ADDRESS => Ok(Attribute::SourceAddress(Self::read_address(&mut c)?)), 261 | REFLECTED_FROM => Ok(Attribute::ReflectedFrom(Self::read_address(&mut c)?)), 262 | MESSAGE_INTEGRITY => { 263 | let mut hash = [0; 20]; 264 | c.read_exact(&mut hash)?; 265 | Ok(Attribute::MessageIntegrity(hash)) 266 | } 267 | CHANGE_REQUEST => match c.read_u32::()? { 268 | CHANGE_REQUEST_IP => Ok(Attribute::ChangeRequest(ChangeRequest::Ip)), 269 | CHANGE_REQUEST_PORT => Ok(Attribute::ChangeRequest(ChangeRequest::Port)), 270 | CHANGE_REQUEST_IP_AND_PORT => { 271 | Ok(Attribute::ChangeRequest(ChangeRequest::IpAndPort)) 272 | } 273 | _ => Err(Error::new( 274 | ErrorKind::InvalidData, 275 | "CHANGE_REQUEST not understood", 276 | )), 277 | }, 278 | _ if typ <= 0x7fff => Err(Error::new( 279 | ErrorKind::InvalidData, 280 | "Unknown mandatory field", 281 | )), 282 | _ => { 283 | c.seek(SeekFrom::Current(i64::from(len)))?; 284 | Ok(Attribute::UnknownOptional) 285 | } 286 | } 287 | } 288 | 289 | fn read_address(c: &mut Cursor<&[u8]>) -> Result { 290 | let _ = c.read_u8()?; 291 | let typ = c.read_u8()?; 292 | let port = c.read_u16::()?; 293 | let addr = c.read_u32::()?; 294 | 295 | if typ != 0x01 { 296 | return Err(Error::new(ErrorKind::InvalidData, "Invalid address family")); 297 | } 298 | 299 | let b0 = ((addr & 0xff00_0000) >> 24) as u8; 300 | let b1 = ((addr & 0x00ff_0000) >> 16) as u8; 301 | let b2 = ((addr & 0x0000_ff00) >> 8) as u8; 302 | let b3 = (addr & 0x0000_00ff) as u8; 303 | let ip = IpAddr::V4(Ipv4Addr::new(b0, b1, b2, b3)); 304 | 305 | Ok(SocketAddr::new(ip, port)) 306 | } 307 | 308 | fn encode(&self, buf: &mut Vec) -> Result<()> { 309 | let (typ, opaque) = match *self { 310 | Attribute::MappedAddress(ref s) => (MAPPED_ADDRESS, Self::encode_address(s)?), 311 | Attribute::ResponseAddress(ref s) => (RESPONSE_ADDRESS, Self::encode_address(s)?), 312 | Attribute::ChangedAddress(ref s) => (CHANGED_ADDRESS, Self::encode_address(s)?), 313 | Attribute::SourceAddress(ref s) => (SOURCE_ADDRESS, Self::encode_address(s)?), 314 | Attribute::ReflectedFrom(ref s) => (REFLECTED_FROM, Self::encode_address(s)?), 315 | Attribute::MessageIntegrity(ref h) => (MESSAGE_INTEGRITY, h.to_vec()), 316 | Attribute::Username(ref u) => { 317 | let total_len = (4.0 * (u.len() as f64 / 4.0).ceil()) as usize; 318 | let padding_len = total_len - u.len(); 319 | 320 | let mut buf = Vec::with_capacity(total_len); 321 | buf.write_all(&u[..])?; 322 | for _ in 0..padding_len { 323 | buf.write_u8(0x00)?; 324 | } 325 | assert_eq!(buf.len(), total_len); 326 | 327 | (USERNAME, buf) 328 | } 329 | Attribute::ChangeRequest(ref c) => (CHANGE_REQUEST, Self::encode_change_request(c)?), 330 | Attribute::UnknownOptional => unreachable!(), 331 | }; 332 | 333 | buf.write_u16::(typ)?; 334 | buf.write_u16::(opaque.len() as u16)?; 335 | buf.write_all(&opaque[..])?; 336 | 337 | Ok(()) 338 | } 339 | 340 | fn encode_change_request(c: &ChangeRequest) -> Result> { 341 | let mut buf = Vec::with_capacity(4); 342 | 343 | match *c { 344 | ChangeRequest::None => (), 345 | ChangeRequest::Ip => buf.write_u32::(CHANGE_REQUEST_IP)?, 346 | ChangeRequest::Port => buf.write_u32::(CHANGE_REQUEST_PORT)?, 347 | ChangeRequest::IpAndPort => { 348 | buf.write_u32::(CHANGE_REQUEST_IP_AND_PORT)? 349 | } 350 | }; 351 | 352 | Ok(buf) 353 | } 354 | 355 | fn encode_address(addr: &SocketAddr) -> Result> { 356 | let mut buf = Vec::with_capacity(8); 357 | buf.write_u8(0x00)?; 358 | buf.write_u8(0x01)?; 359 | 360 | if let SocketAddr::V4(ref addr) = *addr { 361 | buf.write_u16::(addr.port())?; 362 | buf.write_all(&addr.ip().octets()[..])?; 363 | 364 | Ok(buf) 365 | } else { 366 | Err(Error::new( 367 | ErrorKind::InvalidInput, 368 | "STUN does not support IPv6", 369 | )) 370 | } 371 | } 372 | } 373 | 374 | const BINDING_REQUEST: u16 = 0x0001; 375 | const BINDING_RESPONSE: u16 = 0x0101; 376 | const BINDING_ERROR: u16 = 0x0111; 377 | const SHARED_SECRET_REQUEST: u16 = 0x0002; 378 | const SHARED_SECRET_RESPONSE: u16 = 0x0102; 379 | const SHARED_SECRET_ERROR: u16 = 0x0112; 380 | 381 | const MAPPED_ADDRESS: u16 = 0x0001; 382 | const RESPONSE_ADDRESS: u16 = 0x0002; 383 | const CHANGE_REQUEST: u16 = 0x0003; 384 | const SOURCE_ADDRESS: u16 = 0x0004; 385 | const CHANGED_ADDRESS: u16 = 0x0005; 386 | const USERNAME: u16 = 0x0006; 387 | const PASSWORD: u16 = 0x0007; 388 | const MESSAGE_INTEGRITY: u16 = 0x0008; 389 | const ERROR_CODE: u16 = 0x0009; 390 | const UNKNOWN_ATTRIBUTES: u16 = 0x000a; 391 | const REFLECTED_FROM: u16 = 0x000b; 392 | 393 | const CHANGE_REQUEST_IP: u32 = 0x20; 394 | const CHANGE_REQUEST_PORT: u32 = 0x40; 395 | const CHANGE_REQUEST_IP_AND_PORT: u32 = 0x60; 396 | 397 | #[cfg(test)] 398 | mod tests { 399 | use super::*; 400 | 401 | #[test] 402 | fn encode_address() { 403 | let mut buf = Vec::new(); 404 | 405 | let attr = Attribute::ChangedAddress("127.0.1.2:54321".parse().unwrap()); 406 | attr.encode(&mut buf).unwrap(); 407 | 408 | let expected = vec![ 409 | 0x00, 0x05, 0x00, 0x08, 0x00, 0x01, 0xd4, 0x31, 0x7f, 0x00, 0x01, 0x02, 410 | ]; 411 | 412 | assert_eq!(expected, buf); 413 | } 414 | 415 | #[test] 416 | fn encode_binding_request() { 417 | let req = BindRequest { 418 | response_address: None, 419 | change_request: ChangeRequest::IpAndPort, 420 | username: Some(b"foo".to_vec()), 421 | }; 422 | 423 | let mut actual = bytes::BytesMut::with_capacity(1024); 424 | let _ = StunCodec::encode((0x123456789, Request::Bind(req)), &mut actual); // dst 425 | 426 | // TODO: sha1 427 | let expected = vec![ 428 | // 0x00, 0x01, 0x00, 0x14, // type, len 429 | 0x00, 0x01, 0x00, 0x10, // type, len 430 | 0x00, 0x00, 0x00, 0x00, // transaction id 431 | 0x00, 0x00, 0x00, 0x00, // ... 432 | 0x00, 0x00, 0x00, 0x01, // ... 433 | 0x23, 0x45, 0x67, 0x89, // ... 434 | 0x00, 0x03, 0x00, 0x04, // changed_address, len 435 | 0x00, 0x00, 0x00, 0x60, // ip and port 436 | 0x00, 0x06, 0x00, 0x04, // username 437 | 0x66, 0x6f, 0x6f, 438 | 0x00, // "foo" 439 | 440 | /*0x00, 0x08, 0x00, 0x14, // message integrity 441 | 0x89, 0x4f, 0xef, 0x24, // sha1 442 | 0xd5, 0x81, 0x45, 0x66, // ... 443 | 0x8b, 0xa8, 0x27, 0xf0, // ... 444 | 0xf8, 0x1e, 0x54, 0x98, // ... 445 | 0xf7, 0x19, 0x52, 0x04, // ... 446 | */ 447 | ]; 448 | 449 | assert_eq!(expected, actual); 450 | } 451 | } 452 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of th 379 | --------------------------------------------------------------------------------