1// Copyright 2013 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// +build darwin dragonfly freebsd linux netbsd openbsd 6 7package net 8 9import ( 10 "fmt" 11 "os" 12 "os/exec" 13 "runtime" 14 "strings" 15 "testing" 16 "time" 17) 18 19type testInterface struct { 20 name string 21 local string 22 remote string 23 setupCmds []*exec.Cmd 24 teardownCmds []*exec.Cmd 25} 26 27func (ti *testInterface) setup() error { 28 for _, cmd := range ti.setupCmds { 29 if out, err := cmd.CombinedOutput(); err != nil { 30 return fmt.Errorf("args=%v out=%q err=%v", cmd.Args, string(out), err) 31 } 32 } 33 return nil 34} 35 36func (ti *testInterface) teardown() error { 37 for _, cmd := range ti.teardownCmds { 38 if out, err := cmd.CombinedOutput(); err != nil { 39 return fmt.Errorf("args=%v out=%q err=%v ", cmd.Args, string(out), err) 40 } 41 } 42 return nil 43} 44 45func TestPointToPointInterface(t *testing.T) { 46 if testing.Short() { 47 t.Skip("avoid external network") 48 } 49 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { 50 t.Skipf("not supported on %s", runtime.GOOS) 51 } 52 if os.Getuid() != 0 { 53 t.Skip("must be root") 54 } 55 56 // We suppose that using IPv4 link-local addresses doesn't 57 // harm anyone. 58 local, remote := "169.254.0.1", "169.254.0.254" 59 ip := ParseIP(remote) 60 for i := 0; i < 3; i++ { 61 ti := &testInterface{local: local, remote: remote} 62 if err := ti.setPointToPoint(5963 + i); err != nil { 63 t.Skipf("test requires external command: %v", err) 64 } 65 if err := ti.setup(); err != nil { 66 if e := err.Error(); strings.Contains(e, "No such device") && strings.Contains(e, "gre0") { 67 t.Skip("skipping test; no gre0 device. likely running in container?") 68 } 69 t.Fatal(err) 70 } else { 71 time.Sleep(3 * time.Millisecond) 72 } 73 ift, err := Interfaces() 74 if err != nil { 75 ti.teardown() 76 t.Fatal(err) 77 } 78 for _, ifi := range ift { 79 if ti.name != ifi.Name { 80 continue 81 } 82 ifat, err := ifi.Addrs() 83 if err != nil { 84 ti.teardown() 85 t.Fatal(err) 86 } 87 for _, ifa := range ifat { 88 if ip.Equal(ifa.(*IPNet).IP) { 89 ti.teardown() 90 t.Fatalf("got %v", ifa) 91 } 92 } 93 } 94 if err := ti.teardown(); err != nil { 95 t.Fatal(err) 96 } else { 97 time.Sleep(3 * time.Millisecond) 98 } 99 } 100} 101 102func TestInterfaceArrivalAndDeparture(t *testing.T) { 103 if testing.Short() { 104 t.Skip("avoid external network") 105 } 106 if os.Getuid() != 0 { 107 t.Skip("must be root") 108 } 109 110 // We suppose that using IPv4 link-local addresses and the 111 // dot1Q ID for Token Ring and FDDI doesn't harm anyone. 112 local, remote := "169.254.0.1", "169.254.0.254" 113 ip := ParseIP(remote) 114 for _, vid := range []int{1002, 1003, 1004, 1005} { 115 ift1, err := Interfaces() 116 if err != nil { 117 t.Fatal(err) 118 } 119 ti := &testInterface{local: local, remote: remote} 120 if err := ti.setBroadcast(vid); err != nil { 121 t.Skipf("test requires external command: %v", err) 122 } 123 if err := ti.setup(); err != nil { 124 t.Fatal(err) 125 } else { 126 time.Sleep(3 * time.Millisecond) 127 } 128 ift2, err := Interfaces() 129 if err != nil { 130 ti.teardown() 131 t.Fatal(err) 132 } 133 if len(ift2) <= len(ift1) { 134 for _, ifi := range ift1 { 135 t.Logf("before: %v", ifi) 136 } 137 for _, ifi := range ift2 { 138 t.Logf("after: %v", ifi) 139 } 140 ti.teardown() 141 t.Fatalf("got %v; want gt %v", len(ift2), len(ift1)) 142 } 143 for _, ifi := range ift2 { 144 if ti.name != ifi.Name { 145 continue 146 } 147 ifat, err := ifi.Addrs() 148 if err != nil { 149 ti.teardown() 150 t.Fatal(err) 151 } 152 for _, ifa := range ifat { 153 if ip.Equal(ifa.(*IPNet).IP) { 154 ti.teardown() 155 t.Fatalf("got %v", ifa) 156 } 157 } 158 } 159 if err := ti.teardown(); err != nil { 160 t.Fatal(err) 161 } else { 162 time.Sleep(3 * time.Millisecond) 163 } 164 ift3, err := Interfaces() 165 if err != nil { 166 t.Fatal(err) 167 } 168 if len(ift3) >= len(ift2) { 169 for _, ifi := range ift2 { 170 t.Logf("before: %v", ifi) 171 } 172 for _, ifi := range ift3 { 173 t.Logf("after: %v", ifi) 174 } 175 t.Fatalf("got %v; want lt %v", len(ift3), len(ift2)) 176 } 177 } 178} 179 180func TestInterfaceArrivalAndDepartureZoneCache(t *testing.T) { 181 if testing.Short() { 182 t.Skip("avoid external network") 183 } 184 if os.Getuid() != 0 { 185 t.Skip("must be root") 186 } 187 188 // Ensure zoneCache is filled: 189 _, _ = Listen("tcp", "[fe80::1%nonexistent]:0") 190 191 ti := &testInterface{local: "fe80::1"} 192 if err := ti.setLinkLocal(0); err != nil { 193 t.Skipf("test requires external command: %v", err) 194 } 195 if err := ti.setup(); err != nil { 196 t.Fatal(err) 197 } 198 defer ti.teardown() 199 200 time.Sleep(3 * time.Millisecond) 201 202 // If Listen fails (on Linux with “bind: invalid argument”), zoneCache was 203 // not updated when encountering a nonexistent interface: 204 ln, err := Listen("tcp", "[fe80::1%"+ti.name+"]:0") 205 if err != nil { 206 t.Fatal(err) 207 } 208 ln.Close() 209 if err := ti.teardown(); err != nil { 210 t.Fatal(err) 211 } 212} 213