From 99d303ac2739e65a02fbbc325b74ad6fcac63cc2 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 5 Jun 2015 15:58:00 +0200 Subject: Initial commit --- contrib/benchmarking/configs/other.conf | 8 ++ contrib/benchmarking/configs/thinkpad.conf | 8 ++ contrib/benchmarking/openvpn-config.txt | 2 + contrib/benchmarking/static.key | 21 ++++++ contrib/client-server-example/client.sh | 20 +++++ contrib/client-server-example/server.sh | 14 ++++ contrib/external-tests/go/main.go | 63 ++++++++++++++++ contrib/external-tests/haskell/Setup.hs | 2 + contrib/external-tests/haskell/cacophony-wg.cabal | 34 +++++++++ .../external-tests/haskell/src/Data/Time/TAI64.hs | 86 ++++++++++++++++++++++ contrib/external-tests/haskell/src/Main.hs | 81 ++++++++++++++++++++ contrib/external-tests/rust/.gitignore | 2 + contrib/external-tests/rust/Cargo.toml | 10 +++ contrib/external-tests/rust/src/main.rs | 74 +++++++++++++++++++ contrib/patch-kernel-builtin.sh | 12 +++ contrib/stress-testing/badpacket.c | 27 +++++++ contrib/stress-testing/peg.c | 50 +++++++++++++ contrib/stress-testing/self-send.sh | 48 ++++++++++++ contrib/stress-testing/threewayiperf.sh | 30 ++++++++ contrib/wgserver.service | 15 ++++ 20 files changed, 607 insertions(+) create mode 100644 contrib/benchmarking/configs/other.conf create mode 100644 contrib/benchmarking/configs/thinkpad.conf create mode 100644 contrib/benchmarking/openvpn-config.txt create mode 100644 contrib/benchmarking/static.key create mode 100755 contrib/client-server-example/client.sh create mode 100755 contrib/client-server-example/server.sh create mode 100644 contrib/external-tests/go/main.go create mode 100644 contrib/external-tests/haskell/Setup.hs create mode 100644 contrib/external-tests/haskell/cacophony-wg.cabal create mode 100644 contrib/external-tests/haskell/src/Data/Time/TAI64.hs create mode 100644 contrib/external-tests/haskell/src/Main.hs create mode 100644 contrib/external-tests/rust/.gitignore create mode 100644 contrib/external-tests/rust/Cargo.toml create mode 100644 contrib/external-tests/rust/src/main.rs create mode 100755 contrib/patch-kernel-builtin.sh create mode 100644 contrib/stress-testing/badpacket.c create mode 100644 contrib/stress-testing/peg.c create mode 100755 contrib/stress-testing/self-send.sh create mode 100755 contrib/stress-testing/threewayiperf.sh create mode 100644 contrib/wgserver.service (limited to 'contrib') diff --git a/contrib/benchmarking/configs/other.conf b/contrib/benchmarking/configs/other.conf new file mode 100644 index 0000000..4257914 --- /dev/null +++ b/contrib/benchmarking/configs/other.conf @@ -0,0 +1,8 @@ +[Interface] +ListenPort = 27183 +PrivateKey = oHilodMrwJSD1UUIkAkyCek2yqy1Frs5XuN47ShGFk0= + +[Peer] +PublicKey = S8hEvD+dam+PrwG4GrSPtE2Pl3ylO/oiUnUDXw3vnx0= +AllowedIPs = 192.168.2.2/32 +Endpoint = 10.10.10.100:38292 \ No newline at end of file diff --git a/contrib/benchmarking/configs/thinkpad.conf b/contrib/benchmarking/configs/thinkpad.conf new file mode 100644 index 0000000..df02b2b --- /dev/null +++ b/contrib/benchmarking/configs/thinkpad.conf @@ -0,0 +1,8 @@ +[Interface] +ListenPort = 38292 +PrivateKey = MPCo/WSBkm/DCkbEXUhtjc5u//IeD6wEeaw3Q2HxFGw= + +[Peer] +PublicKey = c5PwaIZcVZFDuoDdQJGnYe+fk+wt0qANARpnZDOvqhw= +AllowedIPs = 0.0.0.0/0 +Endpoint = 172.16.48.128:27183 diff --git a/contrib/benchmarking/openvpn-config.txt b/contrib/benchmarking/openvpn-config.txt new file mode 100644 index 0000000..f51eabd --- /dev/null +++ b/contrib/benchmarking/openvpn-config.txt @@ -0,0 +1,2 @@ +Server: openvpn --dev tun --ifconfig 192.168.3.1 192.168.3.2 --secret static.key --cipher AES-256-CBC --auth SHA256 --port 61721 +Client: openvpn --dev tun --ifconfig 192.168.3.2 192.168.3.1 --secret static.key --cipher AES-256-CBC --auth SHA256 --port 61721 --remote 10.10.10.1 diff --git a/contrib/benchmarking/static.key b/contrib/benchmarking/static.key new file mode 100644 index 0000000..53075fe --- /dev/null +++ b/contrib/benchmarking/static.key @@ -0,0 +1,21 @@ +# +# 2048 bit OpenVPN static key +# +-----BEGIN OpenVPN Static key V1----- +12abb34ac1cb716576642c7e4c9719af +b311929f6bb5a7b9082c9ac3a02dc77a +26fc65ba97e67d1dc5b273e72760caba +6c8a3321acdf89bfd0469528bfc9ed89 +1c9c3762d1e18786c8b6dd590456f158 +d1f625810da1225864c23d7e848ca5d7 +18a49c4b7e640f8e51001ace9222de75 +e05177fd01b32d702bd12b45b085678c +239e3927d98912174ac648d0e37a3247 +45cabcbea7cf70832f8800a8b863a35a +933c5921fd65882b050bd1096a0c6c60 +638fb22eafb9f49c13573236d0427441 +c98869ba8de30e597452237527e7dcc6 +519058a919de4432203dc1d7622fb4d0 +f8f20c5350256cdf17bb3b85c5c838fc +6ddeb4da9dae8b0b882cb043db483a9d +-----END OpenVPN Static key V1----- diff --git a/contrib/client-server-example/client.sh b/contrib/client-server-example/client.sh new file mode 100755 index 0000000..fbae46a --- /dev/null +++ b/contrib/client-server-example/client.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -e +[[ $UID == 0 ]] || { echo "You must be root to run this."; exit 1; } +umask 077 +trap 'rm -f /tmp/wg_private_key' EXIT INT TERM +exec 3<>/dev/tcp/demo.wireguard.io/42912 +wg genkey | tee /tmp/wg_private_key | wg pubkey >&3 +IFS=: read -r status server_pubkey server_port internal_ip <&3 +[[ $status == OK ]] +ip link del dev wg0 2>/dev/null || true +ip link add dev wg0 type wireguard +wg set wg0 private-key /tmp/wg_private_key peer "$server_pubkey" allowed-ips 0.0.0.0/0 endpoint "demo.wireguard.io:$server_port" +ip address add "$internal_ip"/24 dev wg0 +ip link set up dev wg0 +if [ "$1" == "default-route" ]; then + host="$(wg show wg0 endpoints | sed -n 's/.*\t\(.*\):.*/\1/p')" + ip route add $(ip route get $host | sed '/ via [0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/{s/^\(.* via [0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/}' | head -n 1) 2>/dev/null || true + ip route add 0/1 dev wg0 + ip route add 128/1 dev wg0 +fi diff --git a/contrib/client-server-example/server.sh b/contrib/client-server-example/server.sh new file mode 100755 index 0000000..e37861f --- /dev/null +++ b/contrib/client-server-example/server.sh @@ -0,0 +1,14 @@ +#!/bin/bash +if [[ -z $NCAT_REMOTE_ADDR ]]; then + ip link del dev wg0 2>/dev/null + set -e + ip link add dev wg0 type wireguard + ip address add 192.168.4.1/24 dev wg0 + wg set wg0 private-key <(wg genkey) listen-port 12912 + ip link set up dev wg0 + exec ncat -e "$(readlink -f "$0")" -k -l -p 42912 -v +fi +read -r public_key +[[ $(wg show wg0 | grep peer | wc -l) -ge 253 ]] && wg set wg0 peer $(wg show wg0 latest-handshakes | sort -k 2 -b -n | head -n 1 | cut -f 1) remove +next_ip=$(all="$(wg show wg0 allowed-ips)"; for ((i=2; i<=254; i++)); do ip="192.168.4.$i"; [[ $all != *$ip/32* ]] && echo $ip && break; done) +wg set wg0 peer "$public_key" allowed-ips $next_ip/32 2>/dev/null && echo "OK:$(wg show wg0 private-key | wg pubkey):$(wg show wg0 listen-port):$next_ip" || echo ERROR diff --git a/contrib/external-tests/go/main.go b/contrib/external-tests/go/main.go new file mode 100644 index 0000000..de7337b --- /dev/null +++ b/contrib/external-tests/go/main.go @@ -0,0 +1,63 @@ +/* Copyright 2015-2016 Jason A. Donenfeld . All Rights Reserved. */ + +package main + +import ( + "github.com/titanous/noise" + "net" + "time" + "bytes" + "crypto/rand" + "encoding/base64" + "encoding/binary" + "github.com/dchest/blake2s" +) + +func assert(exp bool) { + if !exp { + panic("Assertion failed.") + } +} + +func main() { + my_private, _ := base64.StdEncoding.DecodeString("WAmgVYXkbT2bCtdcDwolI88/iVi/aV3/PHcUBTQSYmo=") + my_public, _ := base64.StdEncoding.DecodeString("K5sF9yESrSBsOXPd6TcpKNgqoy1Ik3ZFKl4FolzrRyI=") + preshared, _ := base64.StdEncoding.DecodeString("FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE=") + their_public, _ := base64.StdEncoding.DecodeString("qRCwZSKInrMAq5sepfCdaCsRJaoLe5jhtzfiw7CjbwM=") + cs := noise.NewCipherSuite(noise.DH25519, noise.CipherChaChaPoly, noise.HashBLAKE2s) + hs := noise.NewHandshakeState(noise.Config{CipherSuite: cs, Random: rand.Reader, Pattern: noise.HandshakeIK, Initiator: true, Prologue: []byte("WireGuard v0 zx2c4 Jason@zx2c4.com"), PresharedKey: preshared, StaticKeypair: noise.DHKey{Private: my_private, Public: my_public}, PeerStatic: their_public}) + conn, _ := net.Dial("udp", "test.wireguard.io:51820") + + now := time.Now() + tai64n := make([]byte, 12) + binary.BigEndian.PutUint64(tai64n[:], uint64(now.Unix())) + binary.BigEndian.PutUint32(tai64n[8:], uint32(now.UnixNano())) + initiation_packet := make([]byte, 5) + initiation_packet[0] = 1 /* Type: Initiation */ + binary.LittleEndian.PutUint32(initiation_packet[1:], 28) /* Sender index: 28 (arbitrary) */ + initiation_packet, _, _ = hs.WriteMessage(initiation_packet, tai64n) + hasher, _ := blake2s.New(&blake2s.Config{Size: 16, Key: preshared}) + hasher.Write(their_public) + hasher.Write(initiation_packet) + initiation_packet = append(initiation_packet, hasher.Sum(nil)[:16]...) + initiation_packet = append(initiation_packet, bytes.Repeat([]byte{ 0 }, 16)...) + conn.Write(initiation_packet) + + response_packet := make([]byte, 89) + conn.Read(response_packet) + assert(response_packet[0] == 2 /* Type: Response */) + their_index := binary.LittleEndian.Uint32(response_packet[1:]) + our_index := binary.LittleEndian.Uint32(response_packet[5:]) + assert(our_index == 28) + payload, send_cs, _, err := hs.ReadMessage(nil, response_packet[9:57]) + assert(len(payload) == 0 && err == nil) + + keepalive_packet := make([]byte, 13) + keepalive_packet[0] = 4 /* Type: Data */ + binary.LittleEndian.PutUint32(keepalive_packet[1:], their_index) + binary.LittleEndian.PutUint64(keepalive_packet[3:], 0) /* Nonce */ + keepalive_packet = send_cs.Encrypt(keepalive_packet, nil, nil) + conn.Write(keepalive_packet) + + conn.Close() +} diff --git a/contrib/external-tests/haskell/Setup.hs b/contrib/external-tests/haskell/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/contrib/external-tests/haskell/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/contrib/external-tests/haskell/cacophony-wg.cabal b/contrib/external-tests/haskell/cacophony-wg.cabal new file mode 100644 index 0000000..62e2485 --- /dev/null +++ b/contrib/external-tests/haskell/cacophony-wg.cabal @@ -0,0 +1,34 @@ +-- Initial cacophony-wg.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: cacophony-wg +version: 0.1.0 +-- synopsis: +-- description: +license: PublicDomain +license-file: LICENSE +author: John Galt +maintainer: centromere@users.noreply.github.com +-- copyright: +-- category: +build-type: Simple +-- extra-source-files: +cabal-version: >=1.10 + +executable cacophony-wg + main-is: Main.hs + other-modules: + Data.Time.TAI64 + build-depends: + base >=4.8 && <4.9, + base16-bytestring, + base64-bytestring, + blake2, + bytestring, + cacophony, + cereal, + cryptonite, + network, + time + hs-source-dirs: src + default-language: Haskell2010 diff --git a/contrib/external-tests/haskell/src/Data/Time/TAI64.hs b/contrib/external-tests/haskell/src/Data/Time/TAI64.hs new file mode 100644 index 0000000..37a90e6 --- /dev/null +++ b/contrib/external-tests/haskell/src/Data/Time/TAI64.hs @@ -0,0 +1,86 @@ +module Data.Time.TAI64 ( + TAI64(..) + , TAI64N(..) + , TAI64NA(..) + , posixToTAI64 + , posixToTAI64N + , posixToTAI64NA + , getCurrentTAI64 + , getCurrentTAI64N + , getCurrentTAI64NA + , tAI64ToPosix + , tAI64NToPosix + , tAI64NAToPosix +) where + +import Data.Serialize +import Control.Monad +import Data.Word + +import Data.Time.Clock +import Data.Time.Clock.POSIX + +import Numeric + +data TAI64 = TAI64 + {-# UNPACK #-} !Word64 + deriving (Eq, Ord) + +data TAI64N = TAI64N + {-# UNPACK #-} !TAI64 + {-# UNPACK #-} !Word32 + deriving (Eq, Ord, Show) + +data TAI64NA = TAI64NA + {-# UNPACK #-} !TAI64N + {-# UNPACK #-} !Word32 + deriving (Eq, Ord, Show) + +instance Show TAI64 where + show (TAI64 t) = "TAI64 0x" ++ showHex t "" + +instance Serialize TAI64 where + put (TAI64 t) = putWord64be t + get = liftM TAI64 get + +instance Serialize TAI64N where + put (TAI64N t' nt) = put t' >> putWord32be nt + get = liftM2 TAI64N get get + +instance Serialize TAI64NA where + put (TAI64NA t' at) = put t' >> putWord32be at + get = liftM2 TAI64NA get get + + +posixToTAI64 :: POSIXTime -> TAI64 +posixToTAI64 = TAI64 . (2^62 +) . truncate . realToFrac + +posixToTAI64N :: POSIXTime -> TAI64N +posixToTAI64N pt = TAI64N t' ns where + t' = posixToTAI64 pt + ns = (`mod` 10^9) $ truncate (pts * 10**9) + pts = realToFrac pt + +posixToTAI64NA :: POSIXTime -> TAI64NA -- | PICOsecond precision +posixToTAI64NA pt = TAI64NA t' as where + t' = posixToTAI64N pt + as = (`mod` 10^9) $ truncate (pts * 10**18) + pts = realToFrac pt + +getCurrentTAI64 :: IO TAI64 +getCurrentTAI64N :: IO TAI64N +getCurrentTAI64NA :: IO TAI64NA +getCurrentTAI64 = liftM posixToTAI64 getPOSIXTime +getCurrentTAI64N = liftM posixToTAI64N getPOSIXTime +getCurrentTAI64NA = liftM posixToTAI64NA getPOSIXTime + +tAI64ToPosix :: TAI64 -> POSIXTime +tAI64ToPosix (TAI64 s) = fromRational . fromIntegral $ s - 2^62 + +tAI64NToPosix :: TAI64N -> POSIXTime +tAI64NToPosix (TAI64N t' n) = tAI64ToPosix t' + nanopart where + nanopart = fromRational $ (toRational $ 10**(-9)) * toRational n -- TODO: optimize? + +tAI64NAToPosix :: TAI64NA -> POSIXTime +tAI64NAToPosix (TAI64NA t' a) = tAI64NToPosix t' + attopart where + attopart = fromRational $ (toRational $ 10**(-18)) * toRational a diff --git a/contrib/external-tests/haskell/src/Main.hs b/contrib/external-tests/haskell/src/Main.hs new file mode 100644 index 0000000..f78305d --- /dev/null +++ b/contrib/external-tests/haskell/src/Main.hs @@ -0,0 +1,81 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Control.Applicative ((<$>)) +import Control.Concurrent.MVar +import Control.Monad (void) +import Data.ByteString.Char8 (pack, unpack, take, drop, replicate) +import Data.ByteString (ByteString) +import qualified Data.ByteString.Base16 as Hex +import qualified Data.ByteString.Base64 as B64 +import qualified Data.Serialize as S +import Prelude hiding (take, drop, replicate) +import System.Environment +import Network.Socket +import qualified Network.Socket.ByteString as NBS + +import Crypto.Hash.BLAKE2.BLAKE2s +import Crypto.Noise.Cipher +import Crypto.Noise.Cipher.ChaChaPoly1305 +import Crypto.Noise.Curve +import Crypto.Noise.Curve.Curve25519 +import Crypto.Noise.Handshake +import Crypto.Noise.HandshakePatterns +import Crypto.Noise.Hash.BLAKE2s +import Crypto.Noise.Types + +import Data.Time.TAI64 + +w :: PublicKey Curve25519 + -> Plaintext + -> Socket + -> SockAddr + -> ByteString + -> IO () +w theirPub (Plaintext myPSK) sock addr msg = do + let x = "\x01\x00\x00" `mappend` msg + mac = hash 16 myPSK (sbToBS' (curvePubToBytes theirPub) `mappend` sbToBS' x) + void $ NBS.sendTo sock (x `mappend` mac `mappend` replicate 16 '\0') addr + +r :: MVar ByteString -> Socket -> IO ByteString +r smv sock = do + (r, _) <- NBS.recvFrom sock 1024 + putMVar smv $ (take 2 . drop 1) r + return . take 48 . drop 5 $ r + +payload :: IO Plaintext +payload = do + tai64n <- getCurrentTAI64N + return . Plaintext . bsToSB' $ S.encode tai64n + +main :: IO () +main = do + let ip = "test.wireguard.io" + let port = "51820" + let mykey = "WAmgVYXkbT2bCtdcDwolI88/iVi/aV3/PHcUBTQSYmo=" + let serverkey = "qRCwZSKInrMAq5sepfCdaCsRJaoLe5jhtzfiw7CjbwM=" + let psk = "FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE=" + addrInfo <- head <$> getAddrInfo Nothing (Just ip) (Just port) + sock <- socket (addrFamily addrInfo) Datagram defaultProtocol + + let addr = addrAddress addrInfo + mykey' = curveBytesToPair . bsToSB' . either undefined id . B64.decode . pack $ mykey :: KeyPair Curve25519 + serverkey' = curveBytesToPub . bsToSB' . either undefined id . B64.decode . pack $ serverkey :: PublicKey Curve25519 + psk' = Plaintext . bsToSB' . either undefined id . B64.decode . pack $ psk + hs = handshakeState $ HandshakeStateParams + noiseIK + "WireGuard v0 zx2c4 Jason@zx2c4.com" + (Just psk') + (Just mykey') + Nothing + (Just serverkey') + Nothing + True :: HandshakeState ChaChaPoly1305 Curve25519 BLAKE2s + + senderindexmv <- newEmptyMVar + let hc = HandshakeCallbacks (w serverkey' psk' sock addr) (r senderindexmv sock) (\_ -> return ()) payload + (encryption, decryption) <- runHandshake hs hc + + let (keepAlive, encryption') = encryptPayload "" encryption + senderindex <- takeMVar senderindexmv + void $ NBS.sendTo sock ("\x04" `mappend` senderindex `mappend` replicate 8 '\0' `mappend` keepAlive) addr diff --git a/contrib/external-tests/rust/.gitignore b/contrib/external-tests/rust/.gitignore new file mode 100644 index 0000000..1e7caa9 --- /dev/null +++ b/contrib/external-tests/rust/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target/ diff --git a/contrib/external-tests/rust/Cargo.toml b/contrib/external-tests/rust/Cargo.toml new file mode 100644 index 0000000..c064905 --- /dev/null +++ b/contrib/external-tests/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "wireguard-keepalive" +version = "0.1.0" +authors = ["jason@zx2c4.com"] +[dependencies] +screech = { git = "https://github.com/trevp/screech" } +rust-crypto = "*" +byteorder = "*" +rustc-serialize = "*" +time = "*" diff --git a/contrib/external-tests/rust/src/main.rs b/contrib/external-tests/rust/src/main.rs new file mode 100644 index 0000000..fa468af --- /dev/null +++ b/contrib/external-tests/rust/src/main.rs @@ -0,0 +1,74 @@ +/* Copyright 2015-2016 Jason A. Donenfeld . All Rights Reserved. */ +extern crate screech; +extern crate crypto; +extern crate time; +extern crate rustc_serialize; +extern crate byteorder; + +use screech::*; +use byteorder::{ByteOrder, BigEndian, LittleEndian}; +use crypto::curve25519::curve25519_base; +use crypto::blake2s::Blake2s; +use rustc_serialize::base64::FromBase64; +use std::net::*; + +fn memcpy(out: &mut [u8], data: &[u8]) { + for count in 0..data.len() { + out[count] = data[count]; + } +} + +fn main() { + let send_addr = "test.wireguard.io:51820".to_socket_addrs().unwrap().next().unwrap(); + let listen_addr = "0.0.0.0:0".to_socket_addrs().unwrap().next().unwrap(); + let socket = UdpSocket::bind(listen_addr).unwrap(); + let mut empty_payload = [0; 0]; + + let mut their_public = [0; 32]; + memcpy(&mut their_public, &"qRCwZSKInrMAq5sepfCdaCsRJaoLe5jhtzfiw7CjbwM=".from_base64().unwrap()); + let mut my_private = [0; 32]; + memcpy(&mut my_private, &"WAmgVYXkbT2bCtdcDwolI88/iVi/aV3/PHcUBTQSYmo=".from_base64().unwrap()); + let mut my_preshared = [0; 32]; + memcpy(&mut my_preshared, &"FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE=".from_base64().unwrap()); + let my_public = curve25519_base(&my_private); + let mut my_keypair : Dh25519 = Default::default(); + my_keypair.set(&my_private, &my_public); + let mut owner : HandshakeCryptoOwner = Default::default(); + owner.set_s(my_keypair); + owner.set_rs(&their_public); + let mut cipherstate1 : CipherState = Default::default(); + let mut cipherstate2 : CipherState = Default::default(); + let mut handshake = HandshakeState::new_from_owner(&mut owner, true, HandshakePattern::IK, "WireGuard v0 zx2c4 Jason@zx2c4.com".as_bytes(), Some(&my_preshared[..]), &mut cipherstate1, &mut cipherstate2); + + let now = time::get_time(); + let mut tai64n = [0; 12]; + BigEndian::write_i64(&mut tai64n[0..], now.sec); + BigEndian::write_i32(&mut tai64n[8..], now.nsec); + let mut initiation_packet = [0; 145]; + initiation_packet[0] = 1; /* Type: Initiation */ + LittleEndian::write_u32(&mut initiation_packet[1..], 28); /* Sender index: 28 (arbitrary) */ + handshake.write_message(&tai64n, &mut initiation_packet[5..]); + let mut mac_material = [0; 143]; + memcpy(&mut mac_material, &their_public); + memcpy(&mut mac_material[32..], &initiation_packet[0..113]); + let mut mac = [0; 16]; + Blake2s::blake2s(&mut mac, &mac_material, &my_preshared); + memcpy(&mut initiation_packet[113..], &mac); + socket.send_to(&initiation_packet, &send_addr).unwrap(); + + let mut response_packet = [0; 89]; + socket.recv_from(&mut response_packet).unwrap(); + assert!(response_packet[0] == 2 /* Type: Response */); + let their_index = LittleEndian::read_u32(&response_packet[1..]); + let our_index = LittleEndian::read_u32(&response_packet[5..]); + assert!(our_index == 28); + let (payload_len, last) = handshake.read_message(&response_packet[9..57], &mut empty_payload).unwrap(); + assert!(payload_len == 0 && last); + + let mut keepalive_packet = [0; 29]; + keepalive_packet[0] = 4; /* Type: Data */ + LittleEndian::write_u32(&mut keepalive_packet[1..], their_index); + LittleEndian::write_u64(&mut keepalive_packet[5..], cipherstate1.n); + cipherstate1.encrypt(&empty_payload, &mut keepalive_packet[13..]); /* Empty payload means keepalive */ + socket.send_to(&keepalive_packet, &send_addr).unwrap(); +} diff --git a/contrib/patch-kernel-builtin.sh b/contrib/patch-kernel-builtin.sh new file mode 100755 index 0000000..8229762 --- /dev/null +++ b/contrib/patch-kernel-builtin.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +K="$1" +WG="$(readlink -f "$(dirname "$(readlink -f "$0")")/../src/")" + +if [[ ! -e $K/net/Kconfig ]]; then + echo "You must specify the location of kernel sources as the first argument." >&2 + exit 1 +fi + +sed -i "/^if NET/a source \"$WG/Kconfig\"" "$K/net/Kconfig" +echo "obj-y += ../../../../../../../../../../../../../../../../../../../../../..$WG/" >> "$K/net/Makefile" diff --git a/contrib/stress-testing/badpacket.c b/contrib/stress-testing/badpacket.c new file mode 100644 index 0000000..eee61fc --- /dev/null +++ b/contrib/stress-testing/badpacket.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + static const unsigned char handshake1[143] = { 1, 0 }; + int fd = socket(AF_INET, SOCK_DGRAM, 0); + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(atoi(argv[2])), + .sin_addr = inet_addr(argv[1]) + }; + connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + + for (;;) + send(fd, handshake1, sizeof(handshake1), 0); + + close(fd); + + return 0; +} diff --git a/contrib/stress-testing/peg.c b/contrib/stress-testing/peg.c new file mode 100644 index 0000000..6b539fa --- /dev/null +++ b/contrib/stress-testing/peg.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long long interface_tx_bytes(const char *interface) +{ + char buf[PATH_MAX]; + FILE *f; + unsigned long long ret; + snprintf(buf, PATH_MAX - 1, "/sys/class/net/%s/statistics/tx_bytes", interface); + f = fopen(buf, "r"); + fscanf(f, "%llu", &ret); + fclose(f); + return ret; +} + +int main(int argc, char *argv[]) +{ + char buf[1500] = { 0 }; + unsigned long long before, after, i; + struct timespec begin, end; + double elapsed; + struct ifreq req; + int fd = socket(AF_INET, SOCK_DGRAM, 0); + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(7271), + .sin_addr = inet_addr(argv[3]) + }; + strcpy(req.ifr_name, argv[1]); + ioctl(fd, SIOCGIFMTU, &req); + + connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + + before = interface_tx_bytes(argv[2]); + clock_gettime(CLOCK_MONOTONIC, &begin); + for (i = 0; i < 10000000; ++i) + send(fd, buf, req.ifr_mtu - 28, 0); + clock_gettime(CLOCK_MONOTONIC, &end); + after = interface_tx_bytes(argv[2]); + elapsed = end.tv_sec - begin.tv_sec + (end.tv_nsec - begin.tv_nsec) / 1000000000.0; + + printf("%.4f mbps\n", ((after - before) * 8) / elapsed / 1000000.0); + return 0; +} diff --git a/contrib/stress-testing/self-send.sh b/contrib/stress-testing/self-send.sh new file mode 100755 index 0000000..eb7947b --- /dev/null +++ b/contrib/stress-testing/self-send.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -e + +PRIVATE_KEYS=("") +PUBLIC_KEYS=("") + +resetwg() { + for i in {1..64}; do + ip link delete dev wg${i} 2>/dev/null >/dev/null || true + done +} + +for i in {1..64}; do + next_key="$(wg genkey)" + PRIVATE_KEYS+=("$next_key") + PUBLIC_KEYS+=($(wg pubkey <<<"$next_key")) +done + +resetwg +trap resetwg INT TERM EXIT + +for i in {1..64}; do + { echo "[Interface]" + echo "ListenPort = $(( $i + 31222 ))" + echo "PrivateKey = ${PRIVATE_KEYS[$i]}" + + for j in {1..64}; do + [[ $i == $j ]] && continue + echo "[Peer]" + echo "PublicKey = ${PUBLIC_KEYS[$j]}" + echo "AllowedIPs = 192.168.8.${j}/32" + echo "Endpoint = 127.0.0.1:$(( $j + 31222 ))" + done + } > "/tmp/deviceload.conf" + + ip link add dev wg${i} type wireguard + wg setconf wg${i} "/tmp/deviceload.conf" + ip link set up dev wg${i} + rm "/tmp/deviceload.conf" +done + +ip address add dev wg1 192.168.8.1/24 + +while true; do + for i in {2..64}; do + echo hello | ncat -u 192.168.8.${i} 1234 + done +done diff --git a/contrib/stress-testing/threewayiperf.sh b/contrib/stress-testing/threewayiperf.sh new file mode 100755 index 0000000..932d666 --- /dev/null +++ b/contrib/stress-testing/threewayiperf.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +if [[ $(hostname) == "thinkpad" ]]; then + make -C "$(dirname "$0")/../../src" remote-run + for i in 128 129 130; do + scp "$0" root@172.16.48.${i}: + done + for i in 128 129 130; do + konsole --new-tab -e ssh -t root@172.16.48.${i} "./$(basename "$0")" + done + exit +fi + +# perf top -U --dsos '[wireguard]' + +tmux new-session -s bigtest -d +tmux new-window -n "server 6000" -t bigtest "iperf3 -p 6000 -s" +tmux new-window -n "server 6001" -t bigtest "iperf3 -p 6001 -s" +sleep 5 +me=$(ip -o -4 address show dev wg0 | sed 's/.*inet \([^ ]*\)\/.*/\1/' | cut -d . -f 4) +for i in 1 2 3; do + [[ $i == $me ]] && continue + [[ $me == "1" ]] && port=6000 + [[ $me == "3" ]] && port=6001 + [[ $me == "2" && $i == "1" ]] && port=6000 + [[ $me == "2" && $i == "3" ]] && port=6001 + tmux new-window -n "client 192.168.2.${i}" -t bigtest "iperf3 -n 300000G -i 1 -p $port -c 192.168.2.${i}" +done +tmux attach -t bigtest diff --git a/contrib/wgserver.service b/contrib/wgserver.service new file mode 100644 index 0000000..dfce1e9 --- /dev/null +++ b/contrib/wgserver.service @@ -0,0 +1,15 @@ +[Unit] +Description=WireGuard Server + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/ip link add dev wgserver type wireguard +ExecStart=/bin/ip address add 192.168.177.1/24 dev wgserver +ExecStart=/usr/bin/wg setconf wgserver /etc/wireguard-server.conf +ExecStart=/bin/ip link set up dev wgserver +ExecStop=/bin/sh -c 'umask 077; /usr/bin/wg showconf wgserver > /etc/wireguard-server.conf.tmp && mv /etc/wireguard-server.conf.tmp /etc/wireguard-server.conf' +ExecStop=/bin/ip link del dev wgserver + +[Install] +WantedBy=multi-user.target -- cgit v1.2.3-59-g8ed1b