(linux) wireguard-control: migrate from `wireguard-control-sys` to `netlink` crates (#177)
also introduces a new `netlink-request` crate to help modularize the netlink code. this currently depends on a fork of the `netlink` project, but we should be able to use the official version soon.pull/186/head
parent
7ade68379f
commit
09e68c2c01
|
@ -24,18 +24,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.47"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d9ff5d688f1c13395289f67db01d4826b46dd694e7580accdc3e8430f2d98e"
|
||||
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
|
@ -60,43 +60,12 @@ version = "0.13.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "0.19.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium",
|
||||
"tap",
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
|
@ -115,15 +84,6 @@ version = "1.0.72"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -136,21 +96,11 @@ version = "1.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fff857943da45f546682664a79488be82e69e43c1a7a2307679ab9afb3a66d2e"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
|
@ -288,40 +238,33 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "funty"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.17"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888"
|
||||
checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.17"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d"
|
||||
checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.17"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99"
|
||||
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.17"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481"
|
||||
checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
|
@ -349,12 +292,6 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.11.2"
|
||||
|
@ -409,7 +346,7 @@ checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
|
|||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
"itoa 0.4.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -446,9 +383,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.15"
|
||||
version = "0.14.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c"
|
||||
checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
|
@ -458,7 +395,7 @@ dependencies = [
|
|||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"itoa 0.4.8",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
|
@ -510,29 +447,29 @@ version = "0.4.8"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.108"
|
||||
version = "0.2.112"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
|
||||
checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.23.1"
|
||||
version = "0.23.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abd5850c449b40bacb498b2bbdfaff648b1b055630073ba8db499caf2d0ea9f2"
|
||||
checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
|
@ -570,9 +507,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
|||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
|
||||
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
@ -601,9 +538,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "netlink-packet-core"
|
||||
version = "0.2.4"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac48279d5062bdf175bdbcb6b58ff1d6b0ecd54b951f7a0ff4bc0550fe903ccb"
|
||||
checksum = "8349128e95f5dabcb8a18587ad06b3ca7993e90c0c360b4a2abac0313ebce727"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
|
@ -612,10 +549,23 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "netlink-packet-route"
|
||||
version = "0.8.0"
|
||||
name = "netlink-packet-generic"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76aed5d3b6e3929713bf1e1334a11fd65180b6d9f5d7c8572664c48b122604f8"
|
||||
checksum = "8678ffbbfef3dd88acbe85ed31d32f0de0a100854ee7d47fe5b250f81857a23b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
"libc",
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "netlink-packet-route"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fb5d54077de7c0904111e1d19b661b8cfccbc23d9ce5b6dbcc7362721e6e552"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags",
|
||||
|
@ -627,9 +577,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "netlink-packet-utils"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fcfb6f758b66e964b2339596d94078218d96aad5b32003e8e2a1d23c27a6784"
|
||||
checksum = "0a008a56eceb0cab06739c7f37f15bda27f1147a14d0e7136e8c913b94f1441d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
|
@ -638,11 +588,36 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "netlink-sys"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f48ea34ea0678719815c3753155067212f853ad2d8ef4a49167bae7f7c254188"
|
||||
name = "netlink-packet-wireguard"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/mcginty/netlink?branch=wireguard-fixes#2b60e310ede5fa4c80c00874c19ee755b1bc8249"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"byteorder",
|
||||
"libc",
|
||||
"log",
|
||||
"netlink-packet-generic",
|
||||
"netlink-packet-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "netlink-request"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-generic",
|
||||
"netlink-packet-route",
|
||||
"netlink-packet-wireguard",
|
||||
"netlink-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "netlink-sys"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed51a4602bb956eefef0ebc15f478bf9732fa3cc706e0a37112e654f41c5b92c"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"log",
|
||||
]
|
||||
|
@ -660,18 +635,6 @@ dependencies = [
|
|||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "6.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"funty",
|
||||
"memchr",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
|
@ -728,12 +691,6 @@ version = "1.0.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
|
@ -754,9 +711,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.22"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
|
@ -800,9 +757,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.32"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
||||
checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
@ -826,12 +783,6 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.4"
|
||||
|
@ -909,9 +860,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.26.1"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a82b0b91fad72160c56bf8da7a549b25d7c31109f52cc1437eac4c0ad2550a7"
|
||||
checksum = "4ba4d3462c8b2e4d7f4fcfcf2b296dc6b65404fbbc7b63daa37fd485c149daf7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
|
@ -922,17 +873,11 @@ dependencies = [
|
|||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
|
@ -942,18 +887,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
version = "1.0.131"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
version = "1.0.131"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -962,11 +907,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.71"
|
||||
version = "1.0.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063bf466a64011ac24040a49009724ee60a57da1b437617ceb32e53ad61bfb19"
|
||||
checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"itoa 1.0.1",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
@ -1019,6 +964,7 @@ dependencies = [
|
|||
"log",
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-route",
|
||||
"netlink-request",
|
||||
"netlink-sys",
|
||||
"nix",
|
||||
"publicip",
|
||||
|
@ -1028,15 +974,8 @@ dependencies = [
|
|||
"toml",
|
||||
"url",
|
||||
"wireguard-control",
|
||||
"wireguard-control-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.7.0"
|
||||
|
@ -1091,21 +1030,15 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.81"
|
||||
version = "1.0.82"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
||||
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.2.0"
|
||||
|
@ -1395,25 +1328,15 @@ dependencies = [
|
|||
"curve25519-dalek",
|
||||
"hex",
|
||||
"libc",
|
||||
"netlink-packet-core",
|
||||
"netlink-packet-generic",
|
||||
"netlink-packet-route",
|
||||
"netlink-packet-wireguard",
|
||||
"netlink-request",
|
||||
"netlink-sys",
|
||||
"rand_core",
|
||||
"wireguard-control-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wireguard-control-sys"
|
||||
version = "1.5.2"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.4.3"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[workspace]
|
||||
members = ["server", "client", "hostsfile", "shared", "publicip"]
|
||||
members = ["server", "client", "hostsfile", "shared", "publicip", "netlink-request"]
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
|
|
@ -522,7 +522,10 @@ fn fetch(
|
|||
);
|
||||
}
|
||||
|
||||
log::info!("bringing up interface {}.", interface.as_str_lossy().yellow());
|
||||
log::info!(
|
||||
"bringing up interface {}.",
|
||||
interface.as_str_lossy().yellow()
|
||||
);
|
||||
let resolved_endpoint = config
|
||||
.server
|
||||
.external_endpoint
|
||||
|
@ -543,7 +546,10 @@ fn fetch(
|
|||
.with_str(interface.to_string())?;
|
||||
}
|
||||
|
||||
log::info!("fetching state for {} from server...", interface.as_str_lossy().yellow());
|
||||
log::info!(
|
||||
"fetching state for {} from server...",
|
||||
interface.as_str_lossy().yellow()
|
||||
);
|
||||
let mut store = DataStore::open_or_create(&opts.data_dir, interface)?;
|
||||
let api = Api::new(&config.server);
|
||||
let State { peers, cidrs } = api.http("GET", "/user/state")?;
|
||||
|
@ -978,11 +984,22 @@ fn show(opts: &Opts, short: bool, tree: bool, interface: Option<Interface>) -> R
|
|||
}
|
||||
|
||||
for (device_info, store) in devices {
|
||||
let public_key = match &device_info.public_key {
|
||||
Some(key) => key.to_base64(),
|
||||
None => {
|
||||
log::warn!(
|
||||
"network {} is missing public key.",
|
||||
device_info.name.to_string().yellow()
|
||||
);
|
||||
continue;
|
||||
},
|
||||
};
|
||||
|
||||
let peers = store.peers();
|
||||
let cidrs = store.cidrs();
|
||||
let me = peers
|
||||
.iter()
|
||||
.find(|p| p.public_key == device_info.public_key.as_ref().unwrap().to_base64())
|
||||
.find(|p| p.public_key == public_key)
|
||||
.ok_or_else(|| anyhow!("missing peer info"))?;
|
||||
|
||||
let mut peer_states = device_info
|
||||
|
|
|
@ -3,8 +3,8 @@ use colored::*;
|
|||
use indoc::eprintdoc;
|
||||
use log::{Level, LevelFilter};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use shared::{interface_config::ServerInfo, PeerDiff, INNERNET_PUBKEY_HEADER, Interface};
|
||||
use std::{io, path::Path, time::Duration, ffi::OsStr};
|
||||
use shared::{interface_config::ServerInfo, Interface, PeerDiff, INNERNET_PUBKEY_HEADER};
|
||||
use std::{ffi::OsStr, io, path::Path, time::Duration};
|
||||
use ureq::{Agent, AgentBuilder};
|
||||
|
||||
static LOGGER: Logger = Logger;
|
||||
|
@ -176,18 +176,19 @@ pub fn all_installed(config_dir: &Path) -> Result<Vec<Interface>, std::io::Error
|
|||
.into_iter()
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
let installed: Vec<_> = entries.into_iter()
|
||||
let installed: Vec<_> = entries
|
||||
.into_iter()
|
||||
.filter(|entry| match entry.file_type() {
|
||||
Ok(f) => f.is_file(),
|
||||
_ => false
|
||||
_ => false,
|
||||
})
|
||||
.filter_map(|entry| {
|
||||
let path = entry.path();
|
||||
match (path.extension(), path.file_stem()) {
|
||||
(Some(extension), Some(stem)) if extension == OsStr::new("conf") => {
|
||||
Some(stem.to_string_lossy().to_string())
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
.map(|name| name.parse())
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "netlink-request"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
netlink-sys = "0.8"
|
||||
netlink-packet-core = "0.4"
|
||||
netlink-packet-generic = "0.3"
|
||||
netlink-packet-route = "0.10"
|
||||
netlink-packet-wireguard = { git = "https://github.com/mcginty/netlink", branch = "wireguard-fixes" }
|
|
@ -0,0 +1,125 @@
|
|||
#[cfg(target_os = "linux")]
|
||||
mod linux {
|
||||
use netlink_packet_core::{
|
||||
NetlinkDeserializable, NetlinkMessage, NetlinkPayload, NetlinkSerializable, NLM_F_ACK,
|
||||
NLM_F_CREATE, NLM_F_EXCL, NLM_F_REQUEST,
|
||||
};
|
||||
use netlink_packet_generic::{
|
||||
ctrl::{nlas::GenlCtrlAttrs, GenlCtrl, GenlCtrlCmd},
|
||||
GenlFamily, GenlMessage,
|
||||
};
|
||||
use netlink_packet_route::RtnlMessage;
|
||||
use netlink_sys::{constants::NETLINK_GENERIC, protocols::NETLINK_ROUTE, Socket};
|
||||
use std::{fmt::Debug, io};
|
||||
|
||||
macro_rules! get_nla_value {
|
||||
($nlas:expr, $e:ident, $v:ident) => {
|
||||
$nlas.iter().find_map(|attr| match attr {
|
||||
$e::$v(value) => Some(value),
|
||||
_ => None,
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
pub fn netlink_request_genl<F>(
|
||||
mut message: GenlMessage<F>,
|
||||
flags: Option<u16>,
|
||||
) -> Result<Vec<NetlinkMessage<GenlMessage<F>>>, io::Error>
|
||||
where
|
||||
F: GenlFamily + Clone + Debug + Eq,
|
||||
GenlMessage<F>: Clone + Debug + Eq + NetlinkSerializable + NetlinkDeserializable,
|
||||
{
|
||||
if message.family_id() == 0 {
|
||||
let genlmsg: GenlMessage<GenlCtrl> = GenlMessage::from_payload(GenlCtrl {
|
||||
cmd: GenlCtrlCmd::GetFamily,
|
||||
nlas: vec![GenlCtrlAttrs::FamilyName(F::family_name().to_string())],
|
||||
});
|
||||
let responses =
|
||||
netlink_request_genl::<GenlCtrl>(genlmsg, Some(NLM_F_REQUEST | NLM_F_ACK))?;
|
||||
|
||||
match responses.get(0) {
|
||||
Some(NetlinkMessage {
|
||||
payload:
|
||||
NetlinkPayload::InnerMessage(GenlMessage {
|
||||
payload: GenlCtrl { nlas, .. },
|
||||
..
|
||||
}),
|
||||
..
|
||||
}) => {
|
||||
let family_id = get_nla_value!(nlas, GenlCtrlAttrs, FamilyId)
|
||||
.ok_or_else(|| io::ErrorKind::NotFound)?;
|
||||
message.set_resolved_family_id(*family_id);
|
||||
},
|
||||
_ => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"Unexpected netlink payload",
|
||||
))
|
||||
},
|
||||
};
|
||||
}
|
||||
netlink_request(message, flags, NETLINK_GENERIC)
|
||||
}
|
||||
|
||||
pub fn netlink_request_rtnl(
|
||||
message: RtnlMessage,
|
||||
flags: Option<u16>,
|
||||
) -> Result<Vec<NetlinkMessage<RtnlMessage>>, io::Error> {
|
||||
netlink_request(message, flags, NETLINK_ROUTE)
|
||||
}
|
||||
|
||||
pub fn netlink_request<I>(
|
||||
message: I,
|
||||
flags: Option<u16>,
|
||||
socket: isize,
|
||||
) -> Result<Vec<NetlinkMessage<I>>, io::Error>
|
||||
where
|
||||
NetlinkPayload<I>: From<I>,
|
||||
I: Clone + Debug + Eq + NetlinkSerializable + NetlinkDeserializable,
|
||||
{
|
||||
let mut req = NetlinkMessage::from(message);
|
||||
req.header.flags = flags.unwrap_or(NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
|
||||
req.finalize();
|
||||
let mut buf = [0; 4096];
|
||||
req.serialize(&mut buf);
|
||||
let len = req.buffer_len();
|
||||
|
||||
let socket = Socket::new(socket)?;
|
||||
let kernel_addr = netlink_sys::SocketAddr::new(0, 0);
|
||||
socket.connect(&kernel_addr)?;
|
||||
let n_sent = socket.send(&buf[..len], 0)?;
|
||||
if n_sent != len {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"failed to send netlink request",
|
||||
));
|
||||
}
|
||||
|
||||
let mut responses = vec![];
|
||||
loop {
|
||||
let n_received = socket.recv(&mut &mut buf[..], 0)?;
|
||||
let mut offset = 0;
|
||||
loop {
|
||||
let bytes = &buf[offset..];
|
||||
let response = NetlinkMessage::<I>::deserialize(bytes)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
responses.push(response.clone());
|
||||
match response.payload {
|
||||
// We've parsed all parts of the response and can leave the loop.
|
||||
NetlinkPayload::Ack(_) | NetlinkPayload::Done => return Ok(responses),
|
||||
NetlinkPayload::Error(e) => return Err(e.into()),
|
||||
_ => {},
|
||||
}
|
||||
offset += response.header.length as usize;
|
||||
if offset == n_received || response.header.length == 0 {
|
||||
// We've fully parsed the datagram, but there may be further datagrams
|
||||
// with additional netlink response parts.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use linux::{netlink_request, netlink_request_genl, netlink_request_rtnl};
|
|
@ -25,10 +25,10 @@ url = "2"
|
|||
wireguard-control = { path = "../wireguard-control" }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
netlink-sys = "0.7"
|
||||
netlink-packet-core = "0.2"
|
||||
netlink-packet-route = "0.8"
|
||||
wireguard-control-sys = { path = "../wireguard-control-sys" }
|
||||
netlink-sys = "0.8"
|
||||
netlink-packet-core = "0.4"
|
||||
netlink-packet-route = "0.10"
|
||||
netlink-request = { path = "../netlink-request" }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
nix = "0.23"
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use ipnetwork::IpNetwork;
|
||||
use netlink_packet_core::{
|
||||
NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REQUEST,
|
||||
};
|
||||
use netlink_packet_core::{NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_CREATE, NLM_F_REQUEST};
|
||||
use netlink_packet_route::{
|
||||
address,
|
||||
constants::*,
|
||||
|
@ -9,7 +7,7 @@ use netlink_packet_route::{
|
|||
route, AddressHeader, AddressMessage, LinkHeader, LinkMessage, RouteHeader, RouteMessage,
|
||||
RtnlMessage, RTN_UNICAST, RT_SCOPE_LINK, RT_TABLE_MAIN,
|
||||
};
|
||||
use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};
|
||||
use netlink_request::netlink_request_rtnl;
|
||||
use std::{io, net::IpAddr};
|
||||
use wireguard_control::InterfaceName;
|
||||
|
||||
|
@ -23,55 +21,6 @@ fn if_nametoindex(interface: &InterfaceName) -> Result<u32, io::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
fn netlink_call(
|
||||
message: RtnlMessage,
|
||||
flags: Option<u16>,
|
||||
) -> Result<Vec<NetlinkMessage<RtnlMessage>>, io::Error> {
|
||||
let mut req = NetlinkMessage::from(message);
|
||||
req.header.flags = flags.unwrap_or(NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE);
|
||||
req.finalize();
|
||||
let mut buf = [0; 4096];
|
||||
req.serialize(&mut buf);
|
||||
let len = req.buffer_len();
|
||||
|
||||
log::trace!("netlink request: {:?}", req);
|
||||
let socket = Socket::new(NETLINK_ROUTE)?;
|
||||
let kernel_addr = SocketAddr::new(0, 0);
|
||||
socket.connect(&kernel_addr)?;
|
||||
let n_sent = socket.send(&buf[..len], 0)?;
|
||||
if n_sent != len {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"failed to send netlink request",
|
||||
));
|
||||
}
|
||||
|
||||
let mut responses = vec![];
|
||||
loop {
|
||||
let n_received = socket.recv(&mut buf[..], 0)?;
|
||||
let mut offset = 0;
|
||||
loop {
|
||||
let bytes = &buf[offset..];
|
||||
let response = NetlinkMessage::<RtnlMessage>::deserialize(bytes)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
responses.push(response.clone());
|
||||
log::trace!("netlink response: {:?}", response);
|
||||
match response.payload {
|
||||
// We've parsed all parts of the response and can leave the loop.
|
||||
NetlinkPayload::Ack(_) | NetlinkPayload::Done => return Ok(responses),
|
||||
NetlinkPayload::Error(e) => return Err(e.into()),
|
||||
_ => {},
|
||||
}
|
||||
offset += response.header.length as usize;
|
||||
if offset == n_received || response.header.length == 0 {
|
||||
// We've fully parsed the datagram, but there may be further datagrams
|
||||
// with additional netlink response parts.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_up(interface: &InterfaceName, mtu: u32) -> Result<(), io::Error> {
|
||||
let index = if_nametoindex(interface)?;
|
||||
let message = LinkMessage {
|
||||
|
@ -82,7 +31,8 @@ pub fn set_up(interface: &InterfaceName, mtu: u32) -> Result<(), io::Error> {
|
|||
},
|
||||
nlas: vec![link::nlas::Nla::Mtu(mtu)],
|
||||
};
|
||||
netlink_call(RtnlMessage::SetLink(message), None)?;
|
||||
netlink_request_rtnl(RtnlMessage::SetLink(message), None)?;
|
||||
log::debug!("set interface {} up with mtu {}", interface, mtu);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -114,10 +64,11 @@ pub fn set_addr(interface: &InterfaceName, addr: IpNetwork) -> Result<(), io::Er
|
|||
},
|
||||
nlas,
|
||||
};
|
||||
netlink_call(
|
||||
netlink_request_rtnl(
|
||||
RtnlMessage::NewAddress(message),
|
||||
Some(NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE | NLM_F_CREATE),
|
||||
)?;
|
||||
log::debug!("set address {} on interface {}", addr, interface);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -140,15 +91,21 @@ pub fn add_route(interface: &InterfaceName, cidr: IpNetwork) -> Result<bool, io:
|
|||
nlas: vec![route::Nla::Destination(dst), route::Nla::Oif(if_index)],
|
||||
};
|
||||
|
||||
match netlink_call(RtnlMessage::NewRoute(message), None) {
|
||||
Ok(_) => Ok(true),
|
||||
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(false),
|
||||
match netlink_request_rtnl(RtnlMessage::NewRoute(message), None) {
|
||||
Ok(_) => {
|
||||
log::debug!("added route {} to interface {}", cidr, interface);
|
||||
Ok(true)
|
||||
},
|
||||
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => {
|
||||
log::debug!("route {} already existed.", cidr);
|
||||
Ok(false)
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_links() -> Result<Vec<String>, io::Error> {
|
||||
let link_responses = netlink_call(
|
||||
let link_responses = netlink_request_rtnl(
|
||||
RtnlMessage::GetLink(LinkMessage::default()),
|
||||
Some(NLM_F_DUMP | NLM_F_REQUEST),
|
||||
)?;
|
||||
|
@ -181,7 +138,7 @@ fn get_links() -> Result<Vec<String>, io::Error> {
|
|||
|
||||
pub fn get_local_addrs() -> Result<impl Iterator<Item = IpAddr>, io::Error> {
|
||||
let links = get_links()?;
|
||||
let addr_responses = netlink_call(
|
||||
let addr_responses = netlink_request_rtnl(
|
||||
RtnlMessage::GetAddress(AddressMessage::default()),
|
||||
Some(NLM_F_DUMP | NLM_F_REQUEST),
|
||||
)?;
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
|
@ -1,19 +0,0 @@
|
|||
[package]
|
||||
authors = ["K900 <me@0upti.me>", "Jake McGinty <jake@tonari.no>"]
|
||||
categories = ["external-ffi-bindings", "os::unix-apis"]
|
||||
description = "Raw bindings to the WireGuard embeddable C library"
|
||||
license = "LGPL-2.1-or-later"
|
||||
name = "wireguard-control-sys"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/tonarino/innernet"
|
||||
version = "1.5.2"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[features]
|
||||
buildtime_bindgen = ["bindgen"]
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = { version = "0", default-features = false, optional = true }
|
||||
cc = "1.0"
|
|
@ -1,5 +0,0 @@
|
|||
# `wireguard-control-sys`
|
||||
|
||||
A low-level FFI around the [`embaddable-wg-library`](https://git.zx2c4.com/wireguard-tools/tree/contrib/embeddable-wg-library) WireGuard C library, which in turn communicates with the Linux kernel WireGuard via Netlink.
|
||||
|
||||
You *probably* want to use the [`wireguard-control`](https://crates.io/crates/wireguard-control) crate instead.
|
|
@ -1,968 +0,0 @@
|
|||
/* automatically generated by rust-bindgen 0.59.1 */
|
||||
|
||||
pub type __uint8_t = ::std::os::raw::c_uchar;
|
||||
pub type __uint16_t = ::std::os::raw::c_ushort;
|
||||
pub type __uint32_t = ::std::os::raw::c_uint;
|
||||
pub type __int64_t = ::std::os::raw::c_long;
|
||||
pub type __uint64_t = ::std::os::raw::c_ulong;
|
||||
pub type sa_family_t = ::std::os::raw::c_ushort;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct sockaddr {
|
||||
pub sa_family: sa_family_t,
|
||||
pub sa_data: [::std::os::raw::c_char; 14usize],
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_sockaddr() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<sockaddr>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(sockaddr))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<sockaddr>(),
|
||||
2usize,
|
||||
concat!("Alignment of ", stringify!(sockaddr))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr>())).sa_family as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr),
|
||||
"::",
|
||||
stringify!(sa_family)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr>())).sa_data as *const _ as usize },
|
||||
2usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr),
|
||||
"::",
|
||||
stringify!(sa_data)
|
||||
)
|
||||
);
|
||||
}
|
||||
pub type in_addr_t = u32;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct in_addr {
|
||||
pub s_addr: in_addr_t,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_in_addr() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<in_addr>(),
|
||||
4usize,
|
||||
concat!("Size of: ", stringify!(in_addr))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<in_addr>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(in_addr))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<in_addr>())).s_addr as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(in_addr),
|
||||
"::",
|
||||
stringify!(s_addr)
|
||||
)
|
||||
);
|
||||
}
|
||||
pub type in_port_t = u16;
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct in6_addr {
|
||||
pub __in6_u: in6_addr__bindgen_ty_1,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union in6_addr__bindgen_ty_1 {
|
||||
pub __u6_addr8: [u8; 16usize],
|
||||
pub __u6_addr16: [u16; 8usize],
|
||||
pub __u6_addr32: [u32; 4usize],
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_in6_addr__bindgen_ty_1() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<in6_addr__bindgen_ty_1>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(in6_addr__bindgen_ty_1))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<in6_addr__bindgen_ty_1>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(in6_addr__bindgen_ty_1))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<in6_addr__bindgen_ty_1>())).__u6_addr8 as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(in6_addr__bindgen_ty_1),
|
||||
"::",
|
||||
stringify!(__u6_addr8)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<in6_addr__bindgen_ty_1>())).__u6_addr16 as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(in6_addr__bindgen_ty_1),
|
||||
"::",
|
||||
stringify!(__u6_addr16)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<in6_addr__bindgen_ty_1>())).__u6_addr32 as *const _ as usize
|
||||
},
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(in6_addr__bindgen_ty_1),
|
||||
"::",
|
||||
stringify!(__u6_addr32)
|
||||
)
|
||||
);
|
||||
}
|
||||
impl Default for in6_addr__bindgen_ty_1 {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Debug for in6_addr__bindgen_ty_1 {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write!(f, "in6_addr__bindgen_ty_1 {{ union }}")
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_in6_addr() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<in6_addr>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(in6_addr))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<in6_addr>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(in6_addr))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<in6_addr>())).__in6_u as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(in6_addr),
|
||||
"::",
|
||||
stringify!(__in6_u)
|
||||
)
|
||||
);
|
||||
}
|
||||
impl Default for in6_addr {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Debug for in6_addr {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write!(f, "in6_addr {{ __in6_u: {:?} }}", self.__in6_u)
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct sockaddr_in {
|
||||
pub sin_family: sa_family_t,
|
||||
pub sin_port: in_port_t,
|
||||
pub sin_addr: in_addr,
|
||||
pub sin_zero: [::std::os::raw::c_uchar; 8usize],
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_sockaddr_in() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<sockaddr_in>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(sockaddr_in))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<sockaddr_in>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(sockaddr_in))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in>())).sin_family as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in),
|
||||
"::",
|
||||
stringify!(sin_family)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in>())).sin_port as *const _ as usize },
|
||||
2usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in),
|
||||
"::",
|
||||
stringify!(sin_port)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in>())).sin_addr as *const _ as usize },
|
||||
4usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in),
|
||||
"::",
|
||||
stringify!(sin_addr)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in>())).sin_zero as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in),
|
||||
"::",
|
||||
stringify!(sin_zero)
|
||||
)
|
||||
);
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct sockaddr_in6 {
|
||||
pub sin6_family: sa_family_t,
|
||||
pub sin6_port: in_port_t,
|
||||
pub sin6_flowinfo: u32,
|
||||
pub sin6_addr: in6_addr,
|
||||
pub sin6_scope_id: u32,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_sockaddr_in6() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<sockaddr_in6>(),
|
||||
28usize,
|
||||
concat!("Size of: ", stringify!(sockaddr_in6))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<sockaddr_in6>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(sockaddr_in6))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in6>())).sin6_family as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in6),
|
||||
"::",
|
||||
stringify!(sin6_family)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in6>())).sin6_port as *const _ as usize },
|
||||
2usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in6),
|
||||
"::",
|
||||
stringify!(sin6_port)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in6>())).sin6_flowinfo as *const _ as usize },
|
||||
4usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in6),
|
||||
"::",
|
||||
stringify!(sin6_flowinfo)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in6>())).sin6_addr as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in6),
|
||||
"::",
|
||||
stringify!(sin6_addr)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<sockaddr_in6>())).sin6_scope_id as *const _ as usize },
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(sockaddr_in6),
|
||||
"::",
|
||||
stringify!(sin6_scope_id)
|
||||
)
|
||||
);
|
||||
}
|
||||
impl Default for sockaddr_in6 {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Debug for sockaddr_in6 {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write ! (f , "sockaddr_in6 {{ sin6_family: {:?}, sin6_port: {:?}, sin6_flowinfo: {:?}, sin6_addr: {:?}, sin6_scope_id: {:?} }}" , self . sin6_family , self . sin6_port , self . sin6_flowinfo , self . sin6_addr , self . sin6_scope_id)
|
||||
}
|
||||
}
|
||||
pub type wg_key = [u8; 32usize];
|
||||
pub type wg_key_b64_string = [::std::os::raw::c_char; 45usize];
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct timespec64 {
|
||||
pub tv_sec: i64,
|
||||
pub tv_nsec: i64,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_timespec64() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<timespec64>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(timespec64))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<timespec64>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(timespec64))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<timespec64>())).tv_sec as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(timespec64),
|
||||
"::",
|
||||
stringify!(tv_sec)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<timespec64>())).tv_nsec as *const _ as usize },
|
||||
8usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(timespec64),
|
||||
"::",
|
||||
stringify!(tv_nsec)
|
||||
)
|
||||
);
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct wg_allowedip {
|
||||
pub family: u16,
|
||||
pub __bindgen_anon_1: wg_allowedip__bindgen_ty_1,
|
||||
pub cidr: u8,
|
||||
pub next_allowedip: *mut wg_allowedip,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union wg_allowedip__bindgen_ty_1 {
|
||||
pub ip4: in_addr,
|
||||
pub ip6: in6_addr,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_wg_allowedip__bindgen_ty_1() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<wg_allowedip__bindgen_ty_1>(),
|
||||
16usize,
|
||||
concat!("Size of: ", stringify!(wg_allowedip__bindgen_ty_1))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<wg_allowedip__bindgen_ty_1>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(wg_allowedip__bindgen_ty_1))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_allowedip__bindgen_ty_1>())).ip4 as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_allowedip__bindgen_ty_1),
|
||||
"::",
|
||||
stringify!(ip4)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_allowedip__bindgen_ty_1>())).ip6 as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_allowedip__bindgen_ty_1),
|
||||
"::",
|
||||
stringify!(ip6)
|
||||
)
|
||||
);
|
||||
}
|
||||
impl Default for wg_allowedip__bindgen_ty_1 {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Debug for wg_allowedip__bindgen_ty_1 {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write!(f, "wg_allowedip__bindgen_ty_1 {{ union }}")
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_wg_allowedip() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<wg_allowedip>(),
|
||||
32usize,
|
||||
concat!("Size of: ", stringify!(wg_allowedip))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<wg_allowedip>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(wg_allowedip))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_allowedip>())).family as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_allowedip),
|
||||
"::",
|
||||
stringify!(family)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_allowedip>())).cidr as *const _ as usize },
|
||||
20usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_allowedip),
|
||||
"::",
|
||||
stringify!(cidr)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_allowedip>())).next_allowedip as *const _ as usize },
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_allowedip),
|
||||
"::",
|
||||
stringify!(next_allowedip)
|
||||
)
|
||||
);
|
||||
}
|
||||
impl Default for wg_allowedip {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Debug for wg_allowedip {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write ! (f , "wg_allowedip {{ family: {:?}, __bindgen_anon_1: {:?}, cidr: {:?}, next_allowedip: {:?} }}" , self . family , self . __bindgen_anon_1 , self . cidr , self . next_allowedip)
|
||||
}
|
||||
}
|
||||
impl wg_peer_flags {
|
||||
pub const WGPEER_REMOVE_ME: wg_peer_flags = wg_peer_flags(1);
|
||||
}
|
||||
impl wg_peer_flags {
|
||||
pub const WGPEER_REPLACE_ALLOWEDIPS: wg_peer_flags = wg_peer_flags(2);
|
||||
}
|
||||
impl wg_peer_flags {
|
||||
pub const WGPEER_HAS_PUBLIC_KEY: wg_peer_flags = wg_peer_flags(4);
|
||||
}
|
||||
impl wg_peer_flags {
|
||||
pub const WGPEER_HAS_PRESHARED_KEY: wg_peer_flags = wg_peer_flags(8);
|
||||
}
|
||||
impl wg_peer_flags {
|
||||
pub const WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL: wg_peer_flags = wg_peer_flags(16);
|
||||
}
|
||||
impl ::std::ops::BitOr<wg_peer_flags> for wg_peer_flags {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn bitor(self, other: Self) -> Self {
|
||||
wg_peer_flags(self.0 | other.0)
|
||||
}
|
||||
}
|
||||
impl ::std::ops::BitOrAssign for wg_peer_flags {
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, rhs: wg_peer_flags) {
|
||||
self.0 |= rhs.0;
|
||||
}
|
||||
}
|
||||
impl ::std::ops::BitAnd<wg_peer_flags> for wg_peer_flags {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn bitand(self, other: Self) -> Self {
|
||||
wg_peer_flags(self.0 & other.0)
|
||||
}
|
||||
}
|
||||
impl ::std::ops::BitAndAssign for wg_peer_flags {
|
||||
#[inline]
|
||||
fn bitand_assign(&mut self, rhs: wg_peer_flags) {
|
||||
self.0 &= rhs.0;
|
||||
}
|
||||
}
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct wg_peer_flags(pub ::std::os::raw::c_uint);
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union wg_endpoint {
|
||||
pub addr: sockaddr,
|
||||
pub addr4: sockaddr_in,
|
||||
pub addr6: sockaddr_in6,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_wg_endpoint() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<wg_endpoint>(),
|
||||
28usize,
|
||||
concat!("Size of: ", stringify!(wg_endpoint))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<wg_endpoint>(),
|
||||
4usize,
|
||||
concat!("Alignment of ", stringify!(wg_endpoint))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_endpoint>())).addr as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_endpoint),
|
||||
"::",
|
||||
stringify!(addr)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_endpoint>())).addr4 as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_endpoint),
|
||||
"::",
|
||||
stringify!(addr4)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_endpoint>())).addr6 as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_endpoint),
|
||||
"::",
|
||||
stringify!(addr6)
|
||||
)
|
||||
);
|
||||
}
|
||||
impl Default for wg_endpoint {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Debug for wg_endpoint {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write!(f, "wg_endpoint {{ union }}")
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct wg_peer {
|
||||
pub flags: wg_peer_flags,
|
||||
pub public_key: wg_key,
|
||||
pub preshared_key: wg_key,
|
||||
pub endpoint: wg_endpoint,
|
||||
pub last_handshake_time: timespec64,
|
||||
pub rx_bytes: u64,
|
||||
pub tx_bytes: u64,
|
||||
pub persistent_keepalive_interval: u16,
|
||||
pub first_allowedip: *mut wg_allowedip,
|
||||
pub last_allowedip: *mut wg_allowedip,
|
||||
pub next_peer: *mut wg_peer,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_wg_peer() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<wg_peer>(),
|
||||
160usize,
|
||||
concat!("Size of: ", stringify!(wg_peer))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<wg_peer>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(wg_peer))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).flags as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(flags)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).public_key as *const _ as usize },
|
||||
4usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(public_key)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).preshared_key as *const _ as usize },
|
||||
36usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(preshared_key)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).endpoint as *const _ as usize },
|
||||
68usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(endpoint)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).last_handshake_time as *const _ as usize },
|
||||
96usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(last_handshake_time)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).rx_bytes as *const _ as usize },
|
||||
112usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(rx_bytes)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).tx_bytes as *const _ as usize },
|
||||
120usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(tx_bytes)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe {
|
||||
&(*(::std::ptr::null::<wg_peer>())).persistent_keepalive_interval as *const _ as usize
|
||||
},
|
||||
128usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(persistent_keepalive_interval)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).first_allowedip as *const _ as usize },
|
||||
136usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(first_allowedip)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).last_allowedip as *const _ as usize },
|
||||
144usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(last_allowedip)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_peer>())).next_peer as *const _ as usize },
|
||||
152usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_peer),
|
||||
"::",
|
||||
stringify!(next_peer)
|
||||
)
|
||||
);
|
||||
}
|
||||
impl Default for wg_peer {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ::std::fmt::Debug for wg_peer {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write ! (f , "wg_peer {{ flags: {:?}, public_key: [{}], preshared_key: [{}], endpoint: {:?}, last_handshake_time: {:?}, rx_bytes: {:?}, tx_bytes: {:?}, persistent_keepalive_interval: {:?}, first_allowedip: {:?}, last_allowedip: {:?}, next_peer: {:?} }}" , self . flags , self . public_key . iter () . enumerate () . map (| (i , v) | format ! ("{}{:?}" , if i > 0 { ", " } else { "" } , v)) . collect :: < String > () , self . preshared_key . iter () . enumerate () . map (| (i , v) | format ! ("{}{:?}" , if i > 0 { ", " } else { "" } , v)) . collect :: < String > () , self . endpoint , self . last_handshake_time , self . rx_bytes , self . tx_bytes , self . persistent_keepalive_interval , self . first_allowedip , self . last_allowedip , self . next_peer)
|
||||
}
|
||||
}
|
||||
impl wg_device_flags {
|
||||
pub const WGDEVICE_REPLACE_PEERS: wg_device_flags = wg_device_flags(1);
|
||||
}
|
||||
impl wg_device_flags {
|
||||
pub const WGDEVICE_HAS_PRIVATE_KEY: wg_device_flags = wg_device_flags(2);
|
||||
}
|
||||
impl wg_device_flags {
|
||||
pub const WGDEVICE_HAS_PUBLIC_KEY: wg_device_flags = wg_device_flags(4);
|
||||
}
|
||||
impl wg_device_flags {
|
||||
pub const WGDEVICE_HAS_LISTEN_PORT: wg_device_flags = wg_device_flags(8);
|
||||
}
|
||||
impl wg_device_flags {
|
||||
pub const WGDEVICE_HAS_FWMARK: wg_device_flags = wg_device_flags(16);
|
||||
}
|
||||
impl ::std::ops::BitOr<wg_device_flags> for wg_device_flags {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn bitor(self, other: Self) -> Self {
|
||||
wg_device_flags(self.0 | other.0)
|
||||
}
|
||||
}
|
||||
impl ::std::ops::BitOrAssign for wg_device_flags {
|
||||
#[inline]
|
||||
fn bitor_assign(&mut self, rhs: wg_device_flags) {
|
||||
self.0 |= rhs.0;
|
||||
}
|
||||
}
|
||||
impl ::std::ops::BitAnd<wg_device_flags> for wg_device_flags {
|
||||
type Output = Self;
|
||||
#[inline]
|
||||
fn bitand(self, other: Self) -> Self {
|
||||
wg_device_flags(self.0 & other.0)
|
||||
}
|
||||
}
|
||||
impl ::std::ops::BitAndAssign for wg_device_flags {
|
||||
#[inline]
|
||||
fn bitand_assign(&mut self, rhs: wg_device_flags) {
|
||||
self.0 &= rhs.0;
|
||||
}
|
||||
}
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct wg_device_flags(pub ::std::os::raw::c_uint);
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct wg_device {
|
||||
pub name: [::std::os::raw::c_char; 16usize],
|
||||
pub ifindex: u32,
|
||||
pub flags: wg_device_flags,
|
||||
pub public_key: wg_key,
|
||||
pub private_key: wg_key,
|
||||
pub fwmark: u32,
|
||||
pub listen_port: u16,
|
||||
pub first_peer: *mut wg_peer,
|
||||
pub last_peer: *mut wg_peer,
|
||||
}
|
||||
#[test]
|
||||
fn bindgen_test_layout_wg_device() {
|
||||
assert_eq!(
|
||||
::std::mem::size_of::<wg_device>(),
|
||||
112usize,
|
||||
concat!("Size of: ", stringify!(wg_device))
|
||||
);
|
||||
assert_eq!(
|
||||
::std::mem::align_of::<wg_device>(),
|
||||
8usize,
|
||||
concat!("Alignment of ", stringify!(wg_device))
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).name as *const _ as usize },
|
||||
0usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(name)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).ifindex as *const _ as usize },
|
||||
16usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(ifindex)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).flags as *const _ as usize },
|
||||
20usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(flags)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).public_key as *const _ as usize },
|
||||
24usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(public_key)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).private_key as *const _ as usize },
|
||||
56usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(private_key)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).fwmark as *const _ as usize },
|
||||
88usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(fwmark)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).listen_port as *const _ as usize },
|
||||
92usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(listen_port)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).first_peer as *const _ as usize },
|
||||
96usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(first_peer)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
unsafe { &(*(::std::ptr::null::<wg_device>())).last_peer as *const _ as usize },
|
||||
104usize,
|
||||
concat!(
|
||||
"Offset of field: ",
|
||||
stringify!(wg_device),
|
||||
"::",
|
||||
stringify!(last_peer)
|
||||
)
|
||||
);
|
||||
}
|
||||
impl Default for wg_device {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_set_device(dev: *mut wg_device) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_get_device(
|
||||
dev: *mut *mut wg_device,
|
||||
device_name: *const ::std::os::raw::c_char,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_add_device(device_name: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_del_device(device_name: *const ::std::os::raw::c_char) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_free_device(dev: *mut wg_device);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_list_device_names() -> *mut ::std::os::raw::c_char;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_key_to_base64(base64: *mut ::std::os::raw::c_char, key: *mut u8);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_key_from_base64(
|
||||
key: *mut u8,
|
||||
base64: *mut ::std::os::raw::c_char,
|
||||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_key_is_zero(key: *mut u8) -> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_generate_public_key(public_key: *mut u8, private_key: *mut u8);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_generate_private_key(private_key: *mut u8);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn wg_generate_preshared_key(preshared_key: *mut u8);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
#[cfg(target_os = "linux")]
|
||||
mod linux {
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
pub fn build_bindings() {
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
|
||||
#[cfg(feature = "buildtime_bindgen")]
|
||||
{
|
||||
let bindings = bindgen::Builder::default()
|
||||
.rust_target(bindgen::RustTarget::Stable_1_40)
|
||||
.derive_default(true)
|
||||
.header("c/wireguard.h")
|
||||
.impl_debug(true)
|
||||
.allowlist_function("wg_.*")
|
||||
.bitfield_enum("wg_peer_flags")
|
||||
.bitfield_enum("wg_device_flags");
|
||||
|
||||
let bindings = bindings.generate().expect("Unable to generate bindings");
|
||||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
||||
#[cfg(not(feature = "buildtime_bindgen"))]
|
||||
{
|
||||
std::fs::copy("bindgen-bindings/bindings.rs", out_path.join("bindings.rs"))
|
||||
.expect("Could not copy bindings to output directory");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_library() {
|
||||
cc::Build::new()
|
||||
.file("c/wireguard.c")
|
||||
.warnings(true)
|
||||
.extra_warnings(true)
|
||||
.warnings_into_errors(true)
|
||||
.flag_if_supported("-Wno-unused-parameter")
|
||||
.compile("wireguard");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main() {
|
||||
linux::build_bindings();
|
||||
linux::build_library();
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
fn main() {}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,105 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
/*
|
||||
* Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#ifndef WIREGUARD_H
|
||||
#define WIREGUARD_H
|
||||
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef uint8_t wg_key[32];
|
||||
typedef char wg_key_b64_string[((sizeof(wg_key) + 2) / 3) * 4 + 1];
|
||||
|
||||
/* Cross platform __kernel_timespec */
|
||||
struct timespec64 {
|
||||
int64_t tv_sec;
|
||||
int64_t tv_nsec;
|
||||
};
|
||||
|
||||
typedef struct wg_allowedip {
|
||||
uint16_t family;
|
||||
union {
|
||||
struct in_addr ip4;
|
||||
struct in6_addr ip6;
|
||||
};
|
||||
uint8_t cidr;
|
||||
struct wg_allowedip *next_allowedip;
|
||||
} wg_allowedip;
|
||||
|
||||
enum wg_peer_flags {
|
||||
WGPEER_REMOVE_ME = 1U << 0,
|
||||
WGPEER_REPLACE_ALLOWEDIPS = 1U << 1,
|
||||
WGPEER_HAS_PUBLIC_KEY = 1U << 2,
|
||||
WGPEER_HAS_PRESHARED_KEY = 1U << 3,
|
||||
WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL = 1U << 4
|
||||
};
|
||||
|
||||
typedef union wg_endpoint {
|
||||
struct sockaddr addr;
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
} wg_endpoint;
|
||||
|
||||
typedef struct wg_peer {
|
||||
enum wg_peer_flags flags;
|
||||
|
||||
wg_key public_key;
|
||||
wg_key preshared_key;
|
||||
|
||||
wg_endpoint endpoint;
|
||||
|
||||
struct timespec64 last_handshake_time;
|
||||
uint64_t rx_bytes, tx_bytes;
|
||||
uint16_t persistent_keepalive_interval;
|
||||
|
||||
struct wg_allowedip *first_allowedip, *last_allowedip;
|
||||
struct wg_peer *next_peer;
|
||||
} wg_peer;
|
||||
|
||||
enum wg_device_flags {
|
||||
WGDEVICE_REPLACE_PEERS = 1U << 0,
|
||||
WGDEVICE_HAS_PRIVATE_KEY = 1U << 1,
|
||||
WGDEVICE_HAS_PUBLIC_KEY = 1U << 2,
|
||||
WGDEVICE_HAS_LISTEN_PORT = 1U << 3,
|
||||
WGDEVICE_HAS_FWMARK = 1U << 4
|
||||
};
|
||||
|
||||
typedef struct wg_device {
|
||||
char name[IFNAMSIZ];
|
||||
uint32_t ifindex;
|
||||
|
||||
enum wg_device_flags flags;
|
||||
|
||||
wg_key public_key;
|
||||
wg_key private_key;
|
||||
|
||||
uint32_t fwmark;
|
||||
uint16_t listen_port;
|
||||
|
||||
struct wg_peer *first_peer, *last_peer;
|
||||
} wg_device;
|
||||
|
||||
#define wg_for_each_device_name(__names, __name, __len) for ((__name) = (__names), (__len) = 0; ((__len) = strlen(__name)); (__name) += (__len) + 1)
|
||||
#define wg_for_each_peer(__dev, __peer) for ((__peer) = (__dev)->first_peer; (__peer); (__peer) = (__peer)->next_peer)
|
||||
#define wg_for_each_allowedip(__peer, __allowedip) for ((__allowedip) = (__peer)->first_allowedip; (__allowedip); (__allowedip) = (__allowedip)->next_allowedip)
|
||||
|
||||
int wg_set_device(wg_device *dev);
|
||||
int wg_get_device(wg_device **dev, const char *device_name);
|
||||
int wg_add_device(const char *device_name);
|
||||
int wg_del_device(const char *device_name);
|
||||
void wg_free_device(wg_device *dev);
|
||||
char *wg_list_device_names(void); /* first\0second\0third\0forth\0last\0\0 */
|
||||
void wg_key_to_base64(wg_key_b64_string base64, const wg_key key);
|
||||
int wg_key_from_base64(wg_key key, const wg_key_b64_string base64);
|
||||
bool wg_key_is_zero(const wg_key key);
|
||||
void wg_generate_public_key(wg_key public_key, const wg_key private_key);
|
||||
void wg_generate_private_key(wg_key private_key);
|
||||
void wg_generate_preshared_key(wg_key preshared_key);
|
||||
|
||||
#endif
|
|
@ -1,8 +0,0 @@
|
|||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
// https://github.com/rust-lang/rust-bindgen/issues/1651
|
||||
#![allow(deref_nullptr)]
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
|
@ -1,26 +0,0 @@
|
|||
#!/bin/bash -e
|
||||
# This script modified from https://github.com/rusqlite/rusqlite/blob/master/libsqlite3-sys/upgrade.sh
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
CUR_DIR=$(pwd -P)
|
||||
echo "$SCRIPT_DIR"
|
||||
cd "$SCRIPT_DIR" || { echo "fatal error" >&2; exit 1; }
|
||||
cargo clean
|
||||
mkdir -p "$SCRIPT_DIR/../target"
|
||||
|
||||
pushd "$SCRIPT_DIR/c"
|
||||
curl -O https://raw.githubusercontent.com/WireGuard/wireguard-tools/master/contrib/embeddable-wg-library/wireguard.c
|
||||
curl -O https://raw.githubusercontent.com/WireGuard/wireguard-tools/master/contrib/embeddable-wg-library/wireguard.h
|
||||
popd
|
||||
|
||||
# Regenerate bindgen file
|
||||
rm -f "bindgen-bindings/bindings.rs"
|
||||
# Just to make sure there is only one bindgen.rs file in target dir
|
||||
find "$SCRIPT_DIR/../target" -type f -name bindings.rs -exec rm {} \;
|
||||
cargo build --features "buildtime_bindgen"
|
||||
find "$SCRIPT_DIR/../target" -type f -name bindings.rs -exec mv {} "$SCRIPT_DIR/bindgen-bindings/bindings.rs" \;
|
||||
|
||||
# Sanity checks
|
||||
cd "$SCRIPT_DIR" || { echo "fatal error" >&2; exit 1; }
|
||||
cargo test
|
||||
echo 'You should increment the version in Cargo.toml'
|
|
@ -13,10 +13,13 @@ version = "1.5.2"
|
|||
base64 = "0.13"
|
||||
hex = "0.4"
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
wireguard-control-sys = { path = "../wireguard-control-sys", version = "1.5.2" }
|
||||
|
||||
[target.'cfg(not(target_os = "linux"))'.dependencies]
|
||||
rand_core = "0.6"
|
||||
curve25519-dalek = "4.0.0-pre.1"
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
netlink-request = { path = "../netlink-request" }
|
||||
netlink-sys = "0.8"
|
||||
netlink-packet-core = "0.4"
|
||||
netlink-packet-generic = "0.3"
|
||||
netlink-packet-route = "0.10"
|
||||
netlink-packet-wireguard = { git = "https://github.com/mcginty/netlink", branch = "wireguard-fixes" }
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
use wireguard_control::{Backend, Device};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
const BACKEND: Backend = Backend::Kernel;
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
const BACKEND: Backend = Backend::Userspace;
|
||||
|
||||
fn main() {
|
||||
let devices = Device::list(BACKEND).unwrap();
|
||||
println!("{:?}", devices);
|
||||
}
|
|
@ -1,536 +1,267 @@
|
|||
use crate::{
|
||||
device::AllowedIp, Backend, Device, DeviceUpdate, InterfaceName, InvalidInterfaceName,
|
||||
InvalidKey, PeerConfig, PeerConfigBuilder, PeerInfo, PeerStats,
|
||||
device::AllowedIp, Backend, Device, DeviceUpdate, InterfaceName, Key, PeerConfig,
|
||||
PeerConfigBuilder, PeerInfo, PeerStats,
|
||||
};
|
||||
use wireguard_control_sys::{timespec64, wg_device_flags as wgdf, wg_peer_flags as wgpf};
|
||||
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
io,
|
||||
net::{IpAddr, SocketAddr},
|
||||
os::raw::c_char,
|
||||
ptr, str,
|
||||
time::{Duration, SystemTime},
|
||||
use netlink_packet_core::{
|
||||
NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REQUEST,
|
||||
};
|
||||
use netlink_packet_generic::GenlMessage;
|
||||
use netlink_packet_route::{
|
||||
constants::*,
|
||||
link::{
|
||||
self,
|
||||
nlas::{Info, InfoKind},
|
||||
},
|
||||
LinkMessage, RtnlMessage,
|
||||
};
|
||||
use netlink_packet_wireguard::{
|
||||
self,
|
||||
constants::{WGDEVICE_F_REPLACE_PEERS, WGPEER_F_REMOVE_ME, WGPEER_F_REPLACE_ALLOWEDIPS},
|
||||
nlas::{WgAllowedIpAttrs, WgDeviceAttrs, WgPeerAttrs},
|
||||
Wireguard, WireguardCmd,
|
||||
};
|
||||
use netlink_request::{netlink_request_genl, netlink_request_rtnl};
|
||||
|
||||
impl<'a> From<&'a wireguard_control_sys::wg_allowedip> for AllowedIp {
|
||||
fn from(raw: &wireguard_control_sys::wg_allowedip) -> AllowedIp {
|
||||
let addr = match i32::from(raw.family) {
|
||||
libc::AF_INET => IpAddr::V4(unsafe { raw.__bindgen_anon_1.ip4.s_addr }.to_be().into()),
|
||||
libc::AF_INET6 => {
|
||||
IpAddr::V6(unsafe { raw.__bindgen_anon_1.ip6.__in6_u.__u6_addr8 }.into())
|
||||
},
|
||||
_ => unreachable!(format!("Unsupported socket family {}!", raw.family)),
|
||||
};
|
||||
use std::{convert::TryFrom, io};
|
||||
|
||||
AllowedIp {
|
||||
address: addr,
|
||||
cidr: raw.cidr,
|
||||
}
|
||||
macro_rules! get_nla_value {
|
||||
($nlas:expr, $e:ident, $v:ident) => {
|
||||
$nlas.iter().find_map(|attr| match attr {
|
||||
$e::$v(value) => Some(value),
|
||||
_ => None,
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<Vec<WgAllowedIpAttrs>> for AllowedIp {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(attrs: Vec<WgAllowedIpAttrs>) -> Result<Self, Self::Error> {
|
||||
let address = *get_nla_value!(attrs, WgAllowedIpAttrs, IpAddr)
|
||||
.ok_or_else(|| io::ErrorKind::NotFound)?;
|
||||
let cidr = *get_nla_value!(attrs, WgAllowedIpAttrs, Cidr)
|
||||
.ok_or_else(|| io::ErrorKind::NotFound)?;
|
||||
Ok(AllowedIp { address, cidr })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a wireguard_control_sys::wg_peer> for PeerInfo {
|
||||
fn from(raw: &wireguard_control_sys::wg_peer) -> PeerInfo {
|
||||
PeerInfo {
|
||||
impl AllowedIp {
|
||||
fn to_attrs(&self) -> Vec<WgAllowedIpAttrs> {
|
||||
vec![
|
||||
WgAllowedIpAttrs::Family(if self.address.is_ipv4() {
|
||||
AF_INET
|
||||
} else {
|
||||
AF_INET6
|
||||
}),
|
||||
WgAllowedIpAttrs::IpAddr(self.address),
|
||||
WgAllowedIpAttrs::Cidr(self.cidr),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl PeerConfigBuilder {
|
||||
fn to_attrs(&self) -> Vec<WgPeerAttrs> {
|
||||
let mut attrs = vec![WgPeerAttrs::PublicKey(self.public_key.0)];
|
||||
let mut flags = 0u32;
|
||||
if let Some(endpoint) = self.endpoint {
|
||||
attrs.push(WgPeerAttrs::Endpoint(endpoint));
|
||||
}
|
||||
if let Some(ref key) = self.preshared_key {
|
||||
attrs.push(WgPeerAttrs::PresharedKey(key.0));
|
||||
}
|
||||
if let Some(i) = self.persistent_keepalive_interval {
|
||||
attrs.push(WgPeerAttrs::PersistentKeepalive(i));
|
||||
}
|
||||
let allowed_ips: Vec<_> = self.allowed_ips.iter().map(AllowedIp::to_attrs).collect();
|
||||
attrs.push(WgPeerAttrs::AllowedIps(allowed_ips));
|
||||
if self.remove_me {
|
||||
flags |= WGPEER_F_REMOVE_ME;
|
||||
}
|
||||
if self.replace_allowed_ips {
|
||||
flags |= WGPEER_F_REPLACE_ALLOWEDIPS;
|
||||
}
|
||||
if flags != 0 {
|
||||
attrs.push(WgPeerAttrs::Flags(flags));
|
||||
}
|
||||
attrs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<Vec<WgPeerAttrs>> for PeerInfo {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(attrs: Vec<WgPeerAttrs>) -> Result<Self, Self::Error> {
|
||||
let public_key = get_nla_value!(attrs, WgPeerAttrs, PublicKey)
|
||||
.map(|key| Key(*key))
|
||||
.ok_or(io::ErrorKind::NotFound)?;
|
||||
let preshared_key = get_nla_value!(attrs, WgPeerAttrs, PresharedKey).map(|key| Key(*key));
|
||||
let endpoint = get_nla_value!(attrs, WgPeerAttrs, Endpoint).cloned();
|
||||
let persistent_keepalive_interval =
|
||||
get_nla_value!(attrs, WgPeerAttrs, PersistentKeepalive).cloned();
|
||||
let allowed_ips = get_nla_value!(attrs, WgPeerAttrs, AllowedIps)
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(AllowedIp::try_from)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let last_handshake_time = get_nla_value!(attrs, WgPeerAttrs, LastHandshake).cloned();
|
||||
let rx_bytes = get_nla_value!(attrs, WgPeerAttrs, RxBytes)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
let tx_bytes = get_nla_value!(attrs, WgPeerAttrs, TxBytes)
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
Ok(PeerInfo {
|
||||
config: PeerConfig {
|
||||
public_key: Key::from_raw(raw.public_key),
|
||||
preshared_key: if (raw.flags & wgpf::WGPEER_HAS_PRESHARED_KEY).0 > 0 {
|
||||
Some(Key::from_raw(raw.preshared_key))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
endpoint: parse_endpoint(&raw.endpoint),
|
||||
persistent_keepalive_interval: match raw.persistent_keepalive_interval {
|
||||
0 => None,
|
||||
x => Some(x),
|
||||
},
|
||||
allowed_ips: parse_allowed_ips(raw),
|
||||
public_key,
|
||||
preshared_key,
|
||||
endpoint,
|
||||
persistent_keepalive_interval,
|
||||
allowed_ips,
|
||||
__cant_construct_me: (),
|
||||
},
|
||||
stats: PeerStats {
|
||||
last_handshake_time: match (
|
||||
raw.last_handshake_time.tv_sec,
|
||||
raw.last_handshake_time.tv_nsec,
|
||||
) {
|
||||
(0, 0) => None,
|
||||
(s, ns) => Some(SystemTime::UNIX_EPOCH + Duration::new(s as u64, ns as u32)),
|
||||
},
|
||||
rx_bytes: raw.rx_bytes,
|
||||
tx_bytes: raw.tx_bytes,
|
||||
last_handshake_time,
|
||||
rx_bytes,
|
||||
tx_bytes,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a wireguard_control_sys::wg_device> for Device {
|
||||
fn from(raw: &wireguard_control_sys::wg_device) -> Device {
|
||||
// SAFETY: The name string buffer came directly from wgctrl so its NUL terminated.
|
||||
let name = unsafe { InterfaceName::from_wg(raw.name) };
|
||||
Device {
|
||||
impl<'a> TryFrom<&'a Wireguard> for Device {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(wg: &'a Wireguard) -> Result<Self, Self::Error> {
|
||||
let name = get_nla_value!(wg.nlas, WgDeviceAttrs, IfName)
|
||||
.ok_or_else(|| io::ErrorKind::NotFound)?
|
||||
.parse()?;
|
||||
let public_key = get_nla_value!(wg.nlas, WgDeviceAttrs, PublicKey).map(|key| Key(*key));
|
||||
let private_key = get_nla_value!(wg.nlas, WgDeviceAttrs, PrivateKey).map(|key| Key(*key));
|
||||
let listen_port = get_nla_value!(wg.nlas, WgDeviceAttrs, ListenPort).cloned();
|
||||
let fwmark = get_nla_value!(wg.nlas, WgDeviceAttrs, Fwmark).cloned();
|
||||
let peers = get_nla_value!(wg.nlas, WgDeviceAttrs, Peers)
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(PeerInfo::try_from)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
Ok(Device {
|
||||
name,
|
||||
public_key: if (raw.flags & wgdf::WGDEVICE_HAS_PUBLIC_KEY).0 > 0 {
|
||||
Some(Key::from_raw(raw.public_key))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
private_key: if (raw.flags & wgdf::WGDEVICE_HAS_PRIVATE_KEY).0 > 0 {
|
||||
Some(Key::from_raw(raw.private_key))
|
||||
} else {
|
||||
None
|
||||
},
|
||||
fwmark: match raw.fwmark {
|
||||
0 => None,
|
||||
x => Some(x),
|
||||
},
|
||||
listen_port: match raw.listen_port {
|
||||
0 => None,
|
||||
x => Some(x),
|
||||
},
|
||||
peers: parse_peers(raw),
|
||||
public_key,
|
||||
private_key,
|
||||
listen_port,
|
||||
fwmark,
|
||||
peers,
|
||||
linked_name: None,
|
||||
backend: Backend::Kernel,
|
||||
__cant_construct_me: (),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_peers(dev: &wireguard_control_sys::wg_device) -> Vec<PeerInfo> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
let mut current_peer = dev.first_peer;
|
||||
|
||||
if current_peer.is_null() {
|
||||
return result;
|
||||
}
|
||||
|
||||
loop {
|
||||
let peer = unsafe { &*current_peer };
|
||||
|
||||
result.push(PeerInfo::from(peer));
|
||||
|
||||
if current_peer == dev.last_peer {
|
||||
break;
|
||||
}
|
||||
current_peer = peer.next_peer;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn parse_allowed_ips(peer: &wireguard_control_sys::wg_peer) -> Vec<AllowedIp> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
let mut current_ip: *mut wireguard_control_sys::wg_allowedip = peer.first_allowedip;
|
||||
|
||||
if current_ip.is_null() {
|
||||
return result;
|
||||
}
|
||||
|
||||
loop {
|
||||
let ip = unsafe { &*current_ip };
|
||||
|
||||
result.push(AllowedIp::from(ip));
|
||||
|
||||
if current_ip == peer.last_allowedip {
|
||||
break;
|
||||
}
|
||||
current_ip = ip.next_allowedip;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn parse_endpoint(endpoint: &wireguard_control_sys::wg_endpoint) -> Option<SocketAddr> {
|
||||
let addr = unsafe { endpoint.addr };
|
||||
match i32::from(addr.sa_family) {
|
||||
libc::AF_INET => {
|
||||
let addr4 = unsafe { endpoint.addr4 };
|
||||
Some(SocketAddr::new(
|
||||
IpAddr::V4(u32::from_be(addr4.sin_addr.s_addr).into()),
|
||||
u16::from_be(addr4.sin_port),
|
||||
))
|
||||
},
|
||||
libc::AF_INET6 => {
|
||||
let addr6 = unsafe { endpoint.addr6 };
|
||||
let bytes = unsafe { addr6.sin6_addr.__in6_u.__u6_addr8 };
|
||||
Some(SocketAddr::new(
|
||||
IpAddr::V6(bytes.into()),
|
||||
u16::from_be(addr6.sin6_port),
|
||||
))
|
||||
},
|
||||
0 => None,
|
||||
_ => unreachable!(format!("Unsupported socket family: {}!", addr.sa_family)),
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_allowedips(
|
||||
allowed_ips: &[AllowedIp],
|
||||
) -> (
|
||||
*mut wireguard_control_sys::wg_allowedip,
|
||||
*mut wireguard_control_sys::wg_allowedip,
|
||||
) {
|
||||
if allowed_ips.is_empty() {
|
||||
return (ptr::null_mut(), ptr::null_mut());
|
||||
}
|
||||
|
||||
let mut first_ip = ptr::null_mut();
|
||||
let mut last_ip: *mut wireguard_control_sys::wg_allowedip = ptr::null_mut();
|
||||
|
||||
for ip in allowed_ips {
|
||||
let mut wg_allowedip = Box::new(wireguard_control_sys::wg_allowedip {
|
||||
family: 0,
|
||||
__bindgen_anon_1: Default::default(),
|
||||
cidr: ip.cidr,
|
||||
next_allowedip: first_ip,
|
||||
});
|
||||
|
||||
match ip.address {
|
||||
IpAddr::V4(a) => {
|
||||
wg_allowedip.family = libc::AF_INET as u16;
|
||||
wg_allowedip.__bindgen_anon_1.ip4.s_addr = u32::to_be(a.into());
|
||||
},
|
||||
IpAddr::V6(a) => {
|
||||
wg_allowedip.family = libc::AF_INET6 as u16;
|
||||
wg_allowedip.__bindgen_anon_1.ip6.__in6_u.__u6_addr8 = a.octets();
|
||||
},
|
||||
}
|
||||
|
||||
first_ip = Box::into_raw(wg_allowedip);
|
||||
if last_ip.is_null() {
|
||||
last_ip = first_ip;
|
||||
}
|
||||
}
|
||||
|
||||
(first_ip, last_ip)
|
||||
}
|
||||
|
||||
fn encode_endpoint(endpoint: Option<SocketAddr>) -> wireguard_control_sys::wg_endpoint {
|
||||
match endpoint {
|
||||
Some(SocketAddr::V4(s)) => {
|
||||
let mut peer = wireguard_control_sys::wg_endpoint::default();
|
||||
peer.addr4 = wireguard_control_sys::sockaddr_in {
|
||||
sin_family: libc::AF_INET as u16,
|
||||
sin_addr: wireguard_control_sys::in_addr {
|
||||
s_addr: u32::from_be((*s.ip()).into()),
|
||||
},
|
||||
sin_port: u16::to_be(s.port()),
|
||||
sin_zero: [0; 8],
|
||||
};
|
||||
peer
|
||||
},
|
||||
Some(SocketAddr::V6(s)) => {
|
||||
let mut peer = wireguard_control_sys::wg_endpoint::default();
|
||||
let in6_addr = wireguard_control_sys::in6_addr__bindgen_ty_1 {
|
||||
__u6_addr8: s.ip().octets(),
|
||||
};
|
||||
peer.addr6 = wireguard_control_sys::sockaddr_in6 {
|
||||
sin6_family: libc::AF_INET6 as u16,
|
||||
sin6_addr: wireguard_control_sys::in6_addr { __in6_u: in6_addr },
|
||||
sin6_port: u16::to_be(s.port()),
|
||||
sin6_flowinfo: 0,
|
||||
sin6_scope_id: 0,
|
||||
};
|
||||
peer
|
||||
},
|
||||
None => wireguard_control_sys::wg_endpoint::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_peers(
|
||||
peers: &[PeerConfigBuilder],
|
||||
) -> (
|
||||
*mut wireguard_control_sys::wg_peer,
|
||||
*mut wireguard_control_sys::wg_peer,
|
||||
) {
|
||||
let mut first_peer = ptr::null_mut();
|
||||
let mut last_peer: *mut wireguard_control_sys::wg_peer = ptr::null_mut();
|
||||
|
||||
for peer in peers {
|
||||
let (first_allowedip, last_allowedip) = encode_allowedips(&peer.allowed_ips);
|
||||
|
||||
let mut wg_peer = Box::new(wireguard_control_sys::wg_peer {
|
||||
public_key: peer.public_key.0,
|
||||
preshared_key: wireguard_control_sys::wg_key::default(),
|
||||
endpoint: encode_endpoint(peer.endpoint),
|
||||
last_handshake_time: timespec64 {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
},
|
||||
tx_bytes: 0,
|
||||
rx_bytes: 0,
|
||||
persistent_keepalive_interval: 0,
|
||||
first_allowedip,
|
||||
last_allowedip,
|
||||
next_peer: first_peer,
|
||||
flags: wgpf::WGPEER_HAS_PUBLIC_KEY,
|
||||
});
|
||||
|
||||
if let Some(Key(k)) = peer.preshared_key {
|
||||
wg_peer.flags |= wgpf::WGPEER_HAS_PRESHARED_KEY;
|
||||
wg_peer.preshared_key = k;
|
||||
}
|
||||
|
||||
if let Some(n) = peer.persistent_keepalive_interval {
|
||||
wg_peer.persistent_keepalive_interval = n;
|
||||
wg_peer.flags |= wgpf::WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
|
||||
}
|
||||
|
||||
if peer.replace_allowed_ips {
|
||||
wg_peer.flags |= wgpf::WGPEER_REPLACE_ALLOWEDIPS;
|
||||
}
|
||||
|
||||
if peer.remove_me {
|
||||
wg_peer.flags |= wgpf::WGPEER_REMOVE_ME;
|
||||
}
|
||||
|
||||
first_peer = Box::into_raw(wg_peer);
|
||||
if last_peer.is_null() {
|
||||
last_peer = first_peer;
|
||||
}
|
||||
}
|
||||
|
||||
(first_peer, last_peer)
|
||||
}
|
||||
|
||||
pub fn enumerate() -> Result<Vec<InterfaceName>, io::Error> {
|
||||
let base = unsafe { wireguard_control_sys::wg_list_device_names() };
|
||||
let link_responses = netlink_request_rtnl(
|
||||
RtnlMessage::GetLink(LinkMessage::default()),
|
||||
Some(NLM_F_DUMP | NLM_F_REQUEST),
|
||||
)?;
|
||||
let links = link_responses
|
||||
.into_iter()
|
||||
// Filter out non-link messages
|
||||
.filter_map(|response| match response {
|
||||
NetlinkMessage {
|
||||
payload: NetlinkPayload::InnerMessage(RtnlMessage::NewLink(link)),
|
||||
..
|
||||
} => Some(link),
|
||||
_ => None,
|
||||
})
|
||||
.filter(|link| {
|
||||
for nla in link.nlas.iter() {
|
||||
if let link::nlas::Nla::Info(infos) = nla {
|
||||
return infos.iter().any(|info| info == &Info::Kind(InfoKind::Wireguard))
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.filter_map(|link| link.nlas.iter().find_map(|nla| match nla {
|
||||
link::nlas::Nla::IfName(name) => Some(name.clone()),
|
||||
_ => None,
|
||||
}))
|
||||
.filter_map(|name| name.parse().ok())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if base.is_null() {
|
||||
return Err(io::Error::last_os_error());
|
||||
Ok(links)
|
||||
}
|
||||
|
||||
fn add_del(iface: &InterfaceName, add: bool) -> io::Result<()> {
|
||||
let mut message = LinkMessage::default();
|
||||
message
|
||||
.nlas
|
||||
.push(link::nlas::Nla::IfName(iface.as_str_lossy().to_string()));
|
||||
message.nlas.push(link::nlas::Nla::Info(vec![Info::Kind(
|
||||
link::nlas::InfoKind::Wireguard,
|
||||
)]));
|
||||
let extra_flags = if add { NLM_F_CREATE | NLM_F_EXCL } else { 0 };
|
||||
let rtnl_message = if add {
|
||||
RtnlMessage::NewLink(message)
|
||||
} else {
|
||||
RtnlMessage::DelLink(message)
|
||||
};
|
||||
let result = netlink_request_rtnl(rtnl_message, Some(NLM_F_REQUEST | NLM_F_ACK | extra_flags));
|
||||
match result {
|
||||
Err(e) if e.kind() != io::ErrorKind::AlreadyExists => Err(e),
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
||||
let mut current = base;
|
||||
let mut result = Vec::new();
|
||||
|
||||
loop {
|
||||
let next_dev = unsafe { CStr::from_ptr(current).to_bytes() };
|
||||
|
||||
let len = next_dev.len();
|
||||
|
||||
if len == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
current = unsafe { current.add(len + 1) };
|
||||
|
||||
let interface: InterfaceName = str::from_utf8(next_dev)
|
||||
.map_err(|_| InvalidInterfaceName::InvalidChars)?
|
||||
.parse()?;
|
||||
|
||||
result.push(interface);
|
||||
}
|
||||
|
||||
unsafe { libc::free(base as *mut libc::c_void) };
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn apply(builder: &DeviceUpdate, iface: &InterfaceName) -> io::Result<()> {
|
||||
let (first_peer, last_peer) = encode_peers(&builder.peers);
|
||||
|
||||
let result = unsafe { wireguard_control_sys::wg_add_device(iface.as_ptr()) };
|
||||
match result {
|
||||
0 | -17 => {},
|
||||
_ => return Err(io::Error::last_os_error()),
|
||||
};
|
||||
|
||||
let mut wg_device = Box::new(wireguard_control_sys::wg_device {
|
||||
name: iface.into_inner(),
|
||||
ifindex: 0,
|
||||
public_key: wireguard_control_sys::wg_key::default(),
|
||||
private_key: wireguard_control_sys::wg_key::default(),
|
||||
fwmark: 0,
|
||||
listen_port: 0,
|
||||
first_peer,
|
||||
last_peer,
|
||||
flags: wgdf(0),
|
||||
});
|
||||
|
||||
if let Some(Key(k)) = builder.public_key {
|
||||
wg_device.public_key = k;
|
||||
wg_device.flags |= wgdf::WGDEVICE_HAS_PUBLIC_KEY;
|
||||
}
|
||||
|
||||
add_del(iface, true)?;
|
||||
let mut nlas = vec![WgDeviceAttrs::IfName(iface.as_str_lossy().to_string())];
|
||||
if let Some(Key(k)) = builder.private_key {
|
||||
wg_device.private_key = k;
|
||||
wg_device.flags |= wgdf::WGDEVICE_HAS_PRIVATE_KEY;
|
||||
nlas.push(WgDeviceAttrs::PrivateKey(k));
|
||||
}
|
||||
|
||||
if let Some(f) = builder.fwmark {
|
||||
wg_device.fwmark = f;
|
||||
wg_device.flags |= wgdf::WGDEVICE_HAS_FWMARK;
|
||||
nlas.push(WgDeviceAttrs::Fwmark(f));
|
||||
}
|
||||
|
||||
if let Some(f) = builder.listen_port {
|
||||
wg_device.listen_port = f;
|
||||
wg_device.flags |= wgdf::WGDEVICE_HAS_LISTEN_PORT;
|
||||
nlas.push(WgDeviceAttrs::ListenPort(f));
|
||||
}
|
||||
|
||||
if builder.replace_peers {
|
||||
wg_device.flags |= wgdf::WGDEVICE_REPLACE_PEERS;
|
||||
}
|
||||
|
||||
let ptr = Box::into_raw(wg_device);
|
||||
let result = unsafe { wireguard_control_sys::wg_set_device(ptr) };
|
||||
|
||||
unsafe { wireguard_control_sys::wg_free_device(ptr) };
|
||||
|
||||
if result == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
nlas.push(WgDeviceAttrs::Flags(WGDEVICE_F_REPLACE_PEERS));
|
||||
}
|
||||
let peers: Vec<Vec<_>> = builder
|
||||
.peers
|
||||
.iter()
|
||||
.map(PeerConfigBuilder::to_attrs)
|
||||
.collect();
|
||||
nlas.push(WgDeviceAttrs::Peers(peers));
|
||||
let genlmsg: GenlMessage<Wireguard> = GenlMessage::from_payload(Wireguard {
|
||||
cmd: WireguardCmd::SetDevice,
|
||||
nlas,
|
||||
});
|
||||
netlink_request_genl(genlmsg, Some(NLM_F_REQUEST | NLM_F_ACK))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_by_name(name: &InterfaceName) -> Result<Device, io::Error> {
|
||||
let mut device: *mut wireguard_control_sys::wg_device = ptr::null_mut();
|
||||
let genlmsg: GenlMessage<Wireguard> = GenlMessage::from_payload(Wireguard {
|
||||
cmd: WireguardCmd::GetDevice,
|
||||
nlas: vec![WgDeviceAttrs::IfName(name.as_str_lossy().to_string())],
|
||||
});
|
||||
let responses = netlink_request_genl(genlmsg, Some(NLM_F_REQUEST | NLM_F_DUMP | NLM_F_ACK))?;
|
||||
|
||||
let result = unsafe {
|
||||
wireguard_control_sys::wg_get_device(
|
||||
(&mut device) as *mut _ as *mut *mut wireguard_control_sys::wg_device,
|
||||
name.as_ptr(),
|
||||
)
|
||||
};
|
||||
|
||||
let result = if result == 0 {
|
||||
Ok(Device::from(unsafe { &*device }))
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
};
|
||||
|
||||
unsafe { wireguard_control_sys::wg_free_device(device) };
|
||||
|
||||
result
|
||||
match responses.get(0) {
|
||||
Some(NetlinkMessage {
|
||||
payload: NetlinkPayload::InnerMessage(message),
|
||||
..
|
||||
}) => Device::try_from(&message.payload),
|
||||
_ => Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"Unexpected netlink payload",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_interface(iface: &InterfaceName) -> io::Result<()> {
|
||||
let result = unsafe { wireguard_control_sys::wg_del_device(iface.as_ptr()) };
|
||||
|
||||
if result == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a WireGuard encryption key.
|
||||
///
|
||||
/// WireGuard makes no meaningful distinction between public,
|
||||
/// private and preshared keys - any sequence of 32 bytes
|
||||
/// can be used as either of those.
|
||||
///
|
||||
/// This means that you need to be careful when working with
|
||||
/// `Key`s, especially ones created from external data.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub struct Key(wireguard_control_sys::wg_key);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl Key {
|
||||
/// Creates a new `Key` from raw bytes.
|
||||
pub fn from_raw(key: wireguard_control_sys::wg_key) -> Self {
|
||||
Self(key)
|
||||
}
|
||||
|
||||
/// Generates and returns a new private key.
|
||||
pub fn generate_private() -> Self {
|
||||
let mut private_key = wireguard_control_sys::wg_key::default();
|
||||
|
||||
unsafe {
|
||||
wireguard_control_sys::wg_generate_private_key(private_key.as_mut_ptr());
|
||||
}
|
||||
|
||||
Self(private_key)
|
||||
}
|
||||
|
||||
/// Generates and returns a new preshared key.
|
||||
pub fn generate_preshared() -> Self {
|
||||
let mut preshared_key = wireguard_control_sys::wg_key::default();
|
||||
|
||||
unsafe {
|
||||
wireguard_control_sys::wg_generate_preshared_key(preshared_key.as_mut_ptr());
|
||||
}
|
||||
|
||||
Self(preshared_key)
|
||||
}
|
||||
|
||||
/// Generates a public key for this private key.
|
||||
pub fn generate_public(&self) -> Self {
|
||||
let mut public_key = wireguard_control_sys::wg_key::default();
|
||||
|
||||
unsafe {
|
||||
wireguard_control_sys::wg_generate_public_key(
|
||||
public_key.as_mut_ptr(),
|
||||
&self.0 as *const u8 as *mut u8,
|
||||
);
|
||||
}
|
||||
|
||||
Self(public_key)
|
||||
}
|
||||
|
||||
/// Generates an all-zero key.
|
||||
pub fn zero() -> Self {
|
||||
Self(wireguard_control_sys::wg_key::default())
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Converts the key to a standardized base64 representation, as used by the `wg` utility and `wg-quick`.
|
||||
pub fn to_base64(&self) -> String {
|
||||
let mut key_b64: wireguard_control_sys::wg_key_b64_string = [0; 45];
|
||||
unsafe {
|
||||
wireguard_control_sys::wg_key_to_base64(
|
||||
key_b64.as_mut_ptr(),
|
||||
&self.0 as *const u8 as *mut u8,
|
||||
);
|
||||
|
||||
str::from_utf8_unchecked(&*(&key_b64[..44] as *const [c_char] as *const [u8])).into()
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a base64 representation of the key to the raw bytes.
|
||||
///
|
||||
/// This can fail, as not all text input is valid base64 - in this case
|
||||
/// `Err(InvalidKey)` is returned.
|
||||
pub fn from_base64(key: &str) -> Result<Self, InvalidKey> {
|
||||
let mut decoded = wireguard_control_sys::wg_key::default();
|
||||
|
||||
let key_str = CString::new(key)?;
|
||||
let result = unsafe {
|
||||
wireguard_control_sys::wg_key_from_base64(
|
||||
decoded.as_mut_ptr(),
|
||||
key_str.as_ptr() as *mut _,
|
||||
)
|
||||
};
|
||||
|
||||
if result == 0 {
|
||||
Ok(Self { 0: decoded })
|
||||
} else {
|
||||
Err(InvalidKey)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_hex(hex_str: &str) -> Result<Self, InvalidKey> {
|
||||
let bytes = hex::decode(hex_str).map_err(|_| InvalidKey)?;
|
||||
Self::from_base64(&base64::encode(&bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_encode_endpoint() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let endpoint = Some("1.2.3.4:51820".parse()?);
|
||||
let endpoint6: Option<SocketAddr> = Some("[2001:db8:1::1]:51820".parse()?);
|
||||
let encoded = encode_endpoint(endpoint);
|
||||
let encoded6 = encode_endpoint(endpoint6);
|
||||
assert_eq!(endpoint, parse_endpoint(&encoded));
|
||||
assert_eq!(endpoint6, parse_endpoint(&encoded6));
|
||||
Ok(())
|
||||
}
|
||||
add_del(iface, false)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{Backend, Device, DeviceUpdate, InterfaceName, PeerConfig, PeerInfo, PeerStats};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use crate::Key;
|
||||
|
||||
use std::{
|
||||
|
@ -382,131 +381,3 @@ pub fn apply(builder: &DeviceUpdate, iface: &InterfaceName) -> io::Result<()> {
|
|||
_ => Err(io::ErrorKind::Other.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a WireGuard encryption key.
|
||||
///
|
||||
/// WireGuard makes no meaningful distinction between public,
|
||||
/// private and preshared keys - any sequence of 32 bytes
|
||||
/// can be used as either of those.
|
||||
///
|
||||
/// This means that you need to be careful when working with
|
||||
/// `Key`s, especially ones created from external data.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub struct Key([u8; 32]);
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
impl Key {
|
||||
/// Generates and returns a new private key.
|
||||
pub fn generate_private() -> Self {
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
let mut bytes = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut bytes);
|
||||
|
||||
// Apply key clamping.
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
Self(bytes)
|
||||
}
|
||||
|
||||
/// Generates and returns a new preshared key.
|
||||
pub fn generate_preshared() -> Self {
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
let mut key = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut key);
|
||||
Self(key)
|
||||
}
|
||||
|
||||
/// Generates a public key for this private key.
|
||||
pub fn generate_public(&self) -> Self {
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
|
||||
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
|
||||
|
||||
// https://github.com/dalek-cryptography/x25519-dalek/blob/1c39ff92e0dfc0b24aa02d694f26f3b9539322a5/src/x25519.rs#L150
|
||||
let point = (&ED25519_BASEPOINT_TABLE * &Scalar::from_bits(self.0)).to_montgomery();
|
||||
|
||||
Self(point.to_bytes())
|
||||
}
|
||||
|
||||
/// Generates an all-zero key.
|
||||
pub fn zero() -> Self {
|
||||
Self([0u8; 32])
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Converts the key to a standardized base64 representation, as used by the `wg` utility and `wg-quick`.
|
||||
pub fn to_base64(&self) -> String {
|
||||
base64::encode(&self.0)
|
||||
}
|
||||
|
||||
/// Converts a base64 representation of the key to the raw bytes.
|
||||
///
|
||||
/// This can fail, as not all text input is valid base64 - in this case
|
||||
/// `Err(InvalidKey)` is returned.
|
||||
pub fn from_base64(key: &str) -> Result<Self, crate::InvalidKey> {
|
||||
use crate::InvalidKey;
|
||||
|
||||
let mut key_bytes = [0u8; 32];
|
||||
let decoded_bytes = base64::decode(key).map_err(|_| InvalidKey)?;
|
||||
|
||||
if decoded_bytes.len() != 32 {
|
||||
return Err(InvalidKey);
|
||||
}
|
||||
|
||||
key_bytes.copy_from_slice(&decoded_bytes[..]);
|
||||
Ok(Self(key_bytes))
|
||||
}
|
||||
|
||||
pub fn from_hex(hex_str: &str) -> Result<Self, crate::InvalidKey> {
|
||||
use crate::InvalidKey;
|
||||
|
||||
let mut sized_bytes = [0u8; 32];
|
||||
hex::decode_to_slice(hex_str, &mut sized_bytes).map_err(|_| InvalidKey)?;
|
||||
Ok(Self(sized_bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_pubkey_generation() {
|
||||
let privkey = "SGb+ojrRNDuMePufwtIYhXzA//k6wF3R21tEBgKlzlM=";
|
||||
let pubkey = "DD5yKRfzExcV5+kDnTroDgCU15latdMjiQ59j1hEuk8=";
|
||||
|
||||
let private = Key::from_base64(privkey).unwrap();
|
||||
let public = Key::generate_public(&private);
|
||||
|
||||
assert_eq!(public.to_base64(), pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_sanity_private() {
|
||||
let first = Key::generate_private();
|
||||
assert!(first.as_bytes() != [0u8; 32]);
|
||||
for _ in 0..100_000 {
|
||||
let key = Key::generate_private();
|
||||
assert!(first != key);
|
||||
assert!(key.as_bytes() != [0u8; 32]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_sanity_preshared() {
|
||||
let first = Key::generate_preshared();
|
||||
assert!(first.as_bytes() != [0u8; 32]);
|
||||
for _ in 0..100_000 {
|
||||
let key = Key::generate_preshared();
|
||||
assert!(first != key);
|
||||
assert!(key.as_bytes() != [0u8; 32]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,29 +102,34 @@ impl PeerConfigBuilder {
|
|||
}
|
||||
|
||||
/// Specifies a preshared key to be set for this peer.
|
||||
#[must_use]
|
||||
pub fn set_preshared_key(mut self, key: Key) -> Self {
|
||||
self.preshared_key = Some(key);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies that this peer's preshared key should be unset.
|
||||
#[must_use]
|
||||
pub fn unset_preshared_key(self) -> Self {
|
||||
self.set_preshared_key(Key::zero())
|
||||
}
|
||||
|
||||
/// Specifies an exact endpoint that this peer should be allowed to connect from.
|
||||
#[must_use]
|
||||
pub fn set_endpoint(mut self, address: SocketAddr) -> Self {
|
||||
self.endpoint = Some(address);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies the interval between keepalive packets to be sent to this peer.
|
||||
#[must_use]
|
||||
pub fn set_persistent_keepalive_interval(mut self, interval: u16) -> Self {
|
||||
self.persistent_keepalive_interval = Some(interval);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies that this peer does not require keepalive packets.
|
||||
#[must_use]
|
||||
pub fn unset_persistent_keepalive(self) -> Self {
|
||||
self.set_persistent_keepalive_interval(0)
|
||||
}
|
||||
|
@ -133,6 +138,7 @@ impl PeerConfigBuilder {
|
|||
///
|
||||
/// See [`AllowedIp`](AllowedIp) for details. This method can be called
|
||||
/// more than once, and all IP addresses will be added to the configuration.
|
||||
#[must_use]
|
||||
pub fn add_allowed_ip(mut self, address: IpAddr, cidr: u8) -> Self {
|
||||
self.allowed_ips.push(AllowedIp { address, cidr });
|
||||
self
|
||||
|
@ -142,6 +148,7 @@ impl PeerConfigBuilder {
|
|||
///
|
||||
/// See [`AllowedIp`](AllowedIp) for details. This method can be called
|
||||
/// more than once, and all IP addresses will be added to the configuration.
|
||||
#[must_use]
|
||||
pub fn add_allowed_ips(mut self, ips: &[AllowedIp]) -> Self {
|
||||
self.allowed_ips.extend_from_slice(ips);
|
||||
self
|
||||
|
@ -151,6 +158,7 @@ impl PeerConfigBuilder {
|
|||
///
|
||||
/// This is a convenience method for cases when you want to connect to a server
|
||||
/// that all traffic should be routed through.
|
||||
#[must_use]
|
||||
pub fn allow_all_ips(self) -> Self {
|
||||
self.add_allowed_ip(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
|
||||
.add_allowed_ip(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), 0)
|
||||
|
@ -158,12 +166,14 @@ impl PeerConfigBuilder {
|
|||
|
||||
/// Specifies that the allowed IP addresses in this configuration should replace
|
||||
/// the existing configuration of the interface, not be appended to it.
|
||||
#[must_use]
|
||||
pub fn replace_allowed_ips(mut self) -> Self {
|
||||
self.replace_allowed_ips = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Mark peer for removal from interface.
|
||||
#[must_use]
|
||||
pub fn remove(mut self) -> Self {
|
||||
self.remove_me = true;
|
||||
self
|
||||
|
|
|
@ -150,16 +150,6 @@ impl FromStr for InterfaceName {
|
|||
}
|
||||
|
||||
impl InterfaceName {
|
||||
#[cfg(target_os = "linux")]
|
||||
/// Creates a new [InterfaceName](Self).
|
||||
///
|
||||
/// ## Safety
|
||||
///
|
||||
/// The caller must ensure that `name` is a valid C string terminated by a NUL.
|
||||
pub(crate) unsafe fn from_wg(name: RawInterfaceName) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
|
||||
/// Returns a human-readable form of the device name.
|
||||
///
|
||||
/// Only use this when the interface name was constructed from a Rust string.
|
||||
|
@ -173,12 +163,6 @@ impl InterfaceName {
|
|||
pub fn as_ptr(&self) -> *const c_char {
|
||||
self.0.as_ptr()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
/// Consumes this interface name, returning its raw byte buffer.
|
||||
pub(crate) fn into_inner(self) -> RawInterfaceName {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for InterfaceName {
|
||||
|
@ -307,6 +291,7 @@ pub struct DeviceUpdate {
|
|||
|
||||
impl DeviceUpdate {
|
||||
/// Creates a new `DeviceConfigBuilder` that does nothing when applied.
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
DeviceUpdate {
|
||||
public_key: None,
|
||||
|
@ -323,40 +308,47 @@ impl DeviceUpdate {
|
|||
/// This is a convenience method that simply wraps
|
||||
/// [`set_public_key`](DeviceConfigBuilder::set_public_key)
|
||||
/// and [`set_private_key`](DeviceConfigBuilder::set_private_key).
|
||||
#[must_use]
|
||||
pub fn set_keypair(self, keypair: KeyPair) -> Self {
|
||||
self.set_public_key(keypair.public)
|
||||
.set_private_key(keypair.private)
|
||||
}
|
||||
|
||||
/// Specifies a new public key to be applied to the interface.
|
||||
#[must_use]
|
||||
pub fn set_public_key(mut self, key: Key) -> Self {
|
||||
self.public_key = Some(key);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies that the public key for this interface should be unset.
|
||||
#[must_use]
|
||||
pub fn unset_public_key(self) -> Self {
|
||||
self.set_public_key(Key::zero())
|
||||
}
|
||||
|
||||
/// Sets a new private key to be applied to the interface.
|
||||
#[must_use]
|
||||
pub fn set_private_key(mut self, key: Key) -> Self {
|
||||
self.private_key = Some(key);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies that the private key for this interface should be unset.
|
||||
#[must_use]
|
||||
pub fn unset_private_key(self) -> Self {
|
||||
self.set_private_key(Key::zero())
|
||||
}
|
||||
|
||||
/// Specifies the fwmark value that should be applied to packets coming from the interface.
|
||||
#[must_use]
|
||||
pub fn set_fwmark(mut self, fwmark: u32) -> Self {
|
||||
self.fwmark = Some(fwmark);
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies that fwmark should not be set on packets from the interface.
|
||||
#[must_use]
|
||||
pub fn unset_fwmark(self) -> Self {
|
||||
self.set_fwmark(0)
|
||||
}
|
||||
|
@ -364,6 +356,7 @@ impl DeviceUpdate {
|
|||
/// Specifies the port to listen for incoming packets on.
|
||||
///
|
||||
/// This is useful for a server configuration that listens on a fixed endpoint.
|
||||
#[must_use]
|
||||
pub fn set_listen_port(mut self, port: u16) -> Self {
|
||||
self.listen_port = Some(port);
|
||||
self
|
||||
|
@ -372,6 +365,7 @@ impl DeviceUpdate {
|
|||
/// Specifies that a random port should be used for incoming packets.
|
||||
///
|
||||
/// This is probably what you want in client configurations.
|
||||
#[must_use]
|
||||
pub fn randomize_listen_port(self) -> Self {
|
||||
self.set_listen_port(0)
|
||||
}
|
||||
|
@ -381,6 +375,7 @@ impl DeviceUpdate {
|
|||
/// See [`PeerConfigBuilder`](PeerConfigBuilder) for details on building
|
||||
/// peer configurations. This method can be called more than once, and all
|
||||
/// peers will be added to the configuration.
|
||||
#[must_use]
|
||||
pub fn add_peer(mut self, peer: PeerConfigBuilder) -> Self {
|
||||
self.peers.push(peer);
|
||||
self
|
||||
|
@ -391,6 +386,7 @@ impl DeviceUpdate {
|
|||
/// This is simply a convenience method to make adding peers more fluent.
|
||||
/// This method can be called more than once, and all peers will be added
|
||||
/// to the configuration.
|
||||
#[must_use]
|
||||
pub fn add_peer_with(
|
||||
self,
|
||||
pubkey: &Key,
|
||||
|
@ -400,6 +396,7 @@ impl DeviceUpdate {
|
|||
}
|
||||
|
||||
/// Specifies multiple peer configurations to be added to the interface.
|
||||
#[must_use]
|
||||
pub fn add_peers(mut self, peers: &[PeerConfigBuilder]) -> Self {
|
||||
self.peers.extend_from_slice(peers);
|
||||
self
|
||||
|
@ -407,12 +404,14 @@ impl DeviceUpdate {
|
|||
|
||||
/// Specifies that the peer configurations in this `DeviceConfigBuilder` should
|
||||
/// replace the existing configurations on the interface, not modify or append to them.
|
||||
#[must_use]
|
||||
pub fn replace_peers(mut self) -> Self {
|
||||
self.replace_peers = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Specifies that the peer with this public key should be removed from the interface.
|
||||
#[must_use]
|
||||
pub fn remove_peer_by_key(self, public_key: &Key) -> Self {
|
||||
let mut peer = PeerConfigBuilder::new(public_key);
|
||||
peer.remove_me = true;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::backends;
|
||||
use std::{ffi::NulError, fmt};
|
||||
|
||||
/// Represents an error in base64 key parsing.
|
||||
|
@ -27,11 +26,122 @@ impl From<NulError> for InvalidKey {
|
|||
///
|
||||
/// This means that you need to be careful when working with
|
||||
/// `Key`s, especially ones created from external data.
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub use backends::userspace::Key;
|
||||
#[derive(PartialEq, Eq, Clone)]
|
||||
pub struct Key(pub [u8; 32]);
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use backends::kernel::Key;
|
||||
impl Key {
|
||||
/// Generates and returns a new private key.
|
||||
pub fn generate_private() -> Self {
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
let mut bytes = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut bytes);
|
||||
|
||||
// Apply key clamping.
|
||||
bytes[0] &= 248;
|
||||
bytes[31] &= 127;
|
||||
bytes[31] |= 64;
|
||||
Self(bytes)
|
||||
}
|
||||
|
||||
/// Generates and returns a new preshared key.
|
||||
#[must_use]
|
||||
pub fn generate_preshared() -> Self {
|
||||
use rand_core::{OsRng, RngCore};
|
||||
|
||||
let mut key = [0u8; 32];
|
||||
OsRng.fill_bytes(&mut key);
|
||||
Self(key)
|
||||
}
|
||||
|
||||
/// Generates a public key for this private key.
|
||||
#[must_use]
|
||||
pub fn generate_public(&self) -> Self {
|
||||
use curve25519_dalek::scalar::Scalar;
|
||||
|
||||
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
|
||||
|
||||
// https://github.com/dalek-cryptography/x25519-dalek/blob/1c39ff92e0dfc0b24aa02d694f26f3b9539322a5/src/x25519.rs#L150
|
||||
let point = (&ED25519_BASEPOINT_TABLE * &Scalar::from_bits(self.0)).to_montgomery();
|
||||
|
||||
Self(point.to_bytes())
|
||||
}
|
||||
|
||||
/// Generates an all-zero key.
|
||||
#[must_use]
|
||||
pub fn zero() -> Self {
|
||||
Self([0u8; 32])
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Converts the key to a standardized base64 representation, as used by the `wg` utility and `wg-quick`.
|
||||
pub fn to_base64(&self) -> String {
|
||||
base64::encode(&self.0)
|
||||
}
|
||||
|
||||
/// Converts a base64 representation of the key to the raw bytes.
|
||||
///
|
||||
/// This can fail, as not all text input is valid base64 - in this case
|
||||
/// `Err(InvalidKey)` is returned.
|
||||
pub fn from_base64(key: &str) -> Result<Self, crate::InvalidKey> {
|
||||
let mut key_bytes = [0u8; 32];
|
||||
let decoded_bytes = base64::decode(key).map_err(|_| InvalidKey)?;
|
||||
|
||||
if decoded_bytes.len() != 32 {
|
||||
return Err(InvalidKey);
|
||||
}
|
||||
|
||||
key_bytes.copy_from_slice(&decoded_bytes[..]);
|
||||
Ok(Self(key_bytes))
|
||||
}
|
||||
|
||||
pub fn from_hex(hex_str: &str) -> Result<Self, crate::InvalidKey> {
|
||||
let mut sized_bytes = [0u8; 32];
|
||||
hex::decode_to_slice(hex_str, &mut sized_bytes).map_err(|_| InvalidKey)?;
|
||||
Ok(Self(sized_bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_pubkey_generation() {
|
||||
let privkey = "SGb+ojrRNDuMePufwtIYhXzA//k6wF3R21tEBgKlzlM=";
|
||||
let pubkey = "DD5yKRfzExcV5+kDnTroDgCU15latdMjiQ59j1hEuk8=";
|
||||
|
||||
let private = Key::from_base64(privkey).unwrap();
|
||||
let public = Key::generate_public(&private);
|
||||
|
||||
assert_eq!(public.to_base64(), pubkey);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_sanity_private() {
|
||||
let first = Key::generate_private();
|
||||
assert!(first.as_bytes() != [0u8; 32]);
|
||||
for _ in 0..100_000 {
|
||||
let key = Key::generate_private();
|
||||
assert!(first != key);
|
||||
assert!(key.as_bytes() != [0u8; 32]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rng_sanity_preshared() {
|
||||
let first = Key::generate_preshared();
|
||||
assert!(first.as_bytes() != [0u8; 32]);
|
||||
for _ in 0..100_000 {
|
||||
let key = Key::generate_preshared();
|
||||
assert!(first != key);
|
||||
assert!(key.as_bytes() != [0u8; 32]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a pair of private and public keys.
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue