summaryrefslogtreecommitdiffhomepage
path: root/src/ping-test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/ping-test.go')
-rw-r--r--src/ping-test.go175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/ping-test.go b/src/ping-test.go
new file mode 100644
index 0000000..4b58891
--- /dev/null
+++ b/src/ping-test.go
@@ -0,0 +1,175 @@
+/* Copyright (C) 2015-2017 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. */
+
+package main
+
+import (
+ "crypto/rand"
+ "encoding/base64"
+ "encoding/binary"
+ "log"
+ "net"
+ "time"
+
+ "github.com/dchest/blake2s"
+ "github.com/titanous/noise"
+ "golang.org/x/net/icmp"
+ "golang.org/x/net/ipv4"
+)
+
+func ipChecksum(buf []byte) uint16 {
+ sum := uint32(0)
+ for ; len(buf) >= 2; buf = buf[2:] {
+ sum += uint32(buf[0])<<8 | uint32(buf[1])
+ }
+ if len(buf) > 0 {
+ sum += uint32(buf[0]) << 8
+ }
+ for sum > 0xffff {
+ sum = (sum >> 16) + (sum & 0xffff)
+ }
+ csum := ^uint16(sum)
+ if csum == 0 {
+ csum = 0xffff
+ }
+ return csum
+}
+
+func main() {
+ ourPrivate, _ := base64.StdEncoding.DecodeString("WAmgVYXkbT2bCtdcDwolI88/iVi/aV3/PHcUBTQSYmo=")
+ ourPublic, _ := base64.StdEncoding.DecodeString("K5sF9yESrSBsOXPd6TcpKNgqoy1Ik3ZFKl4FolzrRyI=")
+ theirPublic, _ := base64.StdEncoding.DecodeString("qRCwZSKInrMAq5sepfCdaCsRJaoLe5jhtzfiw7CjbwM=")
+ preshared, _ := base64.StdEncoding.DecodeString("FpCyhws9cxwWoV4xELtfJvjJN+zQVRPISllRWgeopVE=")
+ 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 v1 zx2c4 Jason@zx2c4.com"),
+ PresharedKey: preshared,
+ PresharedKeyPlacement: 2,
+ StaticKeypair: noise.DHKey{Private: ourPrivate, Public: ourPublic},
+ PeerStatic: theirPublic,
+ })
+ conn, err := net.Dial("udp", "demo.wireguard.io:12913")
+ if err != nil {
+ log.Fatalf("error dialing udp socket: %s", err)
+ }
+ defer conn.Close()
+
+ // write handshake initiation packet
+ now := time.Now()
+ tai64n := make([]byte, 12)
+ binary.BigEndian.PutUint64(tai64n[:], 4611686018427387914+uint64(now.Unix()))
+ binary.BigEndian.PutUint32(tai64n[8:], uint32(now.UnixNano()))
+ initiationPacket := make([]byte, 8)
+ initiationPacket[0] = 1 // Type: Initiation
+ initiationPacket[1] = 0 // Reserved
+ initiationPacket[2] = 0 // Reserved
+ initiationPacket[3] = 0 // Reserved
+ binary.LittleEndian.PutUint32(initiationPacket[4:], 28) // Sender index: 28 (arbitrary)
+ initiationPacket, _, _ = hs.WriteMessage(initiationPacket, tai64n)
+ hasher, _ := blake2s.New(&blake2s.Config{Size: 32})
+ hasher.Write([]byte("mac1----"))
+ hasher.Write(theirPublic)
+ hasher, _ = blake2s.New(&blake2s.Config{Size: 16, Key: hasher.Sum(nil)})
+ hasher.Write(initiationPacket)
+ initiationPacket = append(initiationPacket, hasher.Sum(nil)[:16]...)
+ initiationPacket = append(initiationPacket, make([]byte, 16)...)
+ if _, err := conn.Write(initiationPacket); err != nil {
+ log.Fatalf("error writing initiation packet: %s", err)
+ }
+
+ // read handshake response packet
+ responsePacket := make([]byte, 92)
+ n, err := conn.Read(responsePacket)
+ if err != nil {
+ log.Fatalf("error reading response packet: %s", err)
+ }
+ if n != len(responsePacket) {
+ log.Fatalf("response packet too short: want %d, got %d", len(responsePacket), n)
+ }
+ if responsePacket[0] != 2 { // Type: Response
+ log.Fatalf("response packet type wrong: want %d, got %d", 2, responsePacket[0])
+ }
+ if responsePacket[1] != 0 || responsePacket[2] != 0 || responsePacket[3] != 0 {
+ log.Fatalf("response packet has non-zero reserved fields")
+ }
+ theirIndex := binary.LittleEndian.Uint32(responsePacket[4:])
+ ourIndex := binary.LittleEndian.Uint32(responsePacket[8:])
+ if ourIndex != 28 {
+ log.Fatalf("response packet index wrong: want %d, got %d", 28, ourIndex)
+ }
+ payload, sendCipher, receiveCipher, err := hs.ReadMessage(nil, responsePacket[12:60])
+ if err != nil {
+ log.Fatalf("error reading handshake message: %s", err)
+ }
+ if len(payload) > 0 {
+ log.Fatalf("unexpected payload: %x", payload)
+ }
+
+ // write ICMP Echo packet
+ pingMessage, _ := (&icmp.Message{
+ Type: ipv4.ICMPTypeEcho,
+ Body: &icmp.Echo{
+ ID: 921,
+ Seq: 438,
+ Data: []byte("WireGuard"),
+ },
+ }).Marshal(nil)
+ pingHeader, err := (&ipv4.Header{
+ Version: ipv4.Version,
+ Len: ipv4.HeaderLen,
+ TotalLen: ipv4.HeaderLen + len(pingMessage),
+ Protocol: 1, // ICMP
+ TTL: 20,
+ Src: net.IPv4(10, 189, 129, 2),
+ Dst: net.IPv4(10, 189, 129, 1),
+ }).Marshal()
+ binary.BigEndian.PutUint16(pingHeader[2:], uint16(ipv4.HeaderLen+len(pingMessage))) // fix the length endianness on BSDs
+ pingData := append(pingHeader, pingMessage...)
+ binary.BigEndian.PutUint16(pingData[10:], ipChecksum(pingData))
+ pingPacket := make([]byte, 16)
+ pingPacket[0] = 4 // Type: Data
+ pingPacket[1] = 0 // Reserved
+ pingPacket[2] = 0 // Reserved
+ pingPacket[3] = 0 // Reserved
+ binary.LittleEndian.PutUint32(pingPacket[4:], theirIndex)
+ binary.LittleEndian.PutUint64(pingPacket[8:], 0) // Nonce
+ pingPacket = sendCipher.Encrypt(pingPacket, nil, pingData)
+ if _, err := conn.Write(pingPacket); err != nil {
+ log.Fatalf("error writing ping message: %s", err)
+ }
+
+ // read ICMP Echo Reply packet
+ replyPacket := make([]byte, 128)
+ n, err = conn.Read(replyPacket)
+ if err != nil {
+ log.Fatalf("error reading ping reply message: %s", err)
+ }
+ replyPacket = replyPacket[:n]
+ if replyPacket[0] != 4 { // Type: Data
+ log.Fatalf("unexpected reply packet type: %d", replyPacket[0])
+ }
+ if replyPacket[1] != 0 || replyPacket[2] != 0 || replyPacket[3] != 0 {
+ log.Fatalf("reply packet has non-zero reserved fields")
+ }
+ replyPacket, err = receiveCipher.Decrypt(nil, nil, replyPacket[16:])
+ if err != nil {
+ log.Fatalf("error decrypting reply packet: %s", err)
+ }
+ replyHeaderLen := int(replyPacket[0]&0x0f) << 2
+ replyLen := binary.BigEndian.Uint16(replyPacket[2:])
+ replyMessage, err := icmp.ParseMessage(1, replyPacket[replyHeaderLen:replyLen])
+ if err != nil {
+ log.Fatalf("error parsing echo: %s", err)
+ }
+ echo, ok := replyMessage.Body.(*icmp.Echo)
+ if !ok {
+ log.Fatalf("unexpected reply body type %T", replyMessage.Body)
+ }
+
+ if echo.ID != 921 || echo.Seq != 438 || string(echo.Data) != "WireGuard" {
+ log.Fatalf("incorrect echo response: %#v", echo)
+ }
+}