1// +build linux,!appengine 2 3package dns 4 5import ( 6 "bytes" 7 "net" 8 "runtime" 9 "strings" 10 "testing" 11 "time" 12 13 "golang.org/x/net/ipv4" 14 "golang.org/x/net/ipv6" 15) 16 17func TestSetUDPSocketOptions(t *testing.T) { 18 // returns an error if we cannot resolve that address 19 testFamily := func(n, addr string) error { 20 a, err := net.ResolveUDPAddr(n, addr) 21 if err != nil { 22 return err 23 } 24 c, err := net.ListenUDP(n, a) 25 if err != nil { 26 return err 27 } 28 if err := setUDPSocketOptions(c); err != nil { 29 t.Fatalf("failed to set socket options: %v", err) 30 } 31 ch := make(chan *SessionUDP) 32 go func() { 33 // Set some deadline so this goroutine doesn't hang forever 34 c.SetReadDeadline(time.Now().Add(time.Minute)) 35 b := make([]byte, 1) 36 _, sess, err := ReadFromSessionUDP(c, b) 37 if err != nil { 38 t.Errorf("failed to read from conn: %v", err) 39 // fallthrough to chan send below 40 } 41 ch <- sess 42 }() 43 44 c2, err := net.Dial("udp", c.LocalAddr().String()) 45 if err != nil { 46 t.Fatalf("failed to dial udp: %v", err) 47 } 48 if _, err := c2.Write([]byte{1}); err != nil { 49 t.Fatalf("failed to write to conn: %v", err) 50 } 51 sess := <-ch 52 if sess == nil { 53 // t.Error was already called in the goroutine above. 54 t.FailNow() 55 } 56 if len(sess.context) == 0 { 57 t.Fatalf("empty session context: %v", sess) 58 } 59 ip := parseDstFromOOB(sess.context) 60 if ip == nil { 61 t.Fatalf("failed to parse dst: %v", sess) 62 } 63 if !strings.Contains(c.LocalAddr().String(), ip.String()) { 64 t.Fatalf("dst was different than listen addr: %v != %v", ip.String(), c.LocalAddr().String()) 65 } 66 return nil 67 } 68 69 // we require that ipv4 be supported 70 if err := testFamily("udp4", "127.0.0.1:0"); err != nil { 71 t.Fatalf("failed to test socket options on IPv4: %v", err) 72 } 73 // IPv6 might not be supported so these will just log 74 if err := testFamily("udp6", "[::1]:0"); err != nil { 75 t.Logf("failed to test socket options on IPv6-only: %v", err) 76 } 77 if err := testFamily("udp", "[::1]:0"); err != nil { 78 t.Logf("failed to test socket options on IPv6/IPv4: %v", err) 79 } 80} 81 82func TestParseDstFromOOB(t *testing.T) { 83 if runtime.GOARCH != "amd64" { 84 // The cmsghdr struct differs in the width (32/64-bit) of 85 // lengths and the struct padding between architectures. 86 // The data below was only written with amd64 in mind, and 87 // thus the test must be skipped on other architectures. 88 t.Skip("skipping test on unsupported architecture") 89 } 90 91 // dst is :ffff:100.100.100.100 92 oob := []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 100, 100, 100, 2, 0, 0, 0} 93 dst := parseDstFromOOB(oob) 94 dst4 := dst.To4() 95 if dst4 == nil { 96 t.Errorf("failed to parse IPv4 in IPv6: %v", dst) 97 } else if dst4.String() != "100.100.100.100" { 98 t.Errorf("unexpected IPv4: %v", dst4) 99 } 100 101 // dst is 2001:db8::1 102 oob = []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0} 103 dst = parseDstFromOOB(oob) 104 dst6 := dst.To16() 105 if dst6 == nil { 106 t.Errorf("failed to parse IPv6: %v", dst) 107 } else if dst6.String() != "2001:db8::1" { 108 t.Errorf("unexpected IPv6: %v", dst4) 109 } 110 111 // dst is 100.100.100.100 but was received on 10.10.10.10 112 oob = []byte{28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 10, 10, 10, 10, 100, 100, 100, 100, 0, 0, 0, 0} 113 dst = parseDstFromOOB(oob) 114 dst4 = dst.To4() 115 if dst4 == nil { 116 t.Errorf("failed to parse IPv4: %v", dst) 117 } else if dst4.String() != "100.100.100.100" { 118 t.Errorf("unexpected IPv4: %v", dst4) 119 } 120} 121 122func TestCorrectSource(t *testing.T) { 123 if runtime.GOARCH != "amd64" { 124 // See comment above in TestParseDstFromOOB. 125 t.Skip("skipping test on unsupported architecture") 126 } 127 128 // dst is :ffff:100.100.100.100 which should be counted as IPv4 129 oob := []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 100, 100, 100, 100, 2, 0, 0, 0} 130 soob := correctSource(oob) 131 cm4 := new(ipv4.ControlMessage) 132 cm4.Src = net.ParseIP("100.100.100.100") 133 if !bytes.Equal(soob, cm4.Marshal()) { 134 t.Errorf("unexpected oob for ipv4 address: %v", soob) 135 } 136 137 // dst is 2001:db8::1 138 oob = []byte{36, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 50, 0, 0, 0, 32, 1, 13, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0} 139 soob = correctSource(oob) 140 cm6 := new(ipv6.ControlMessage) 141 cm6.Src = net.ParseIP("2001:db8::1") 142 if !bytes.Equal(soob, cm6.Marshal()) { 143 t.Errorf("unexpected oob for IPv6 address: %v", soob) 144 } 145} 146