Home | History | Annotate | Download | only in net
      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 
      7 package net
      8 
      9 import (
     10 	"fmt"
     11 	"os"
     12 	"os/exec"
     13 	"runtime"
     14 	"testing"
     15 	"time"
     16 )
     17 
     18 type testInterface struct {
     19 	name         string
     20 	local        string
     21 	remote       string
     22 	setupCmds    []*exec.Cmd
     23 	teardownCmds []*exec.Cmd
     24 }
     25 
     26 func (ti *testInterface) setup() error {
     27 	for _, cmd := range ti.setupCmds {
     28 		if out, err := cmd.CombinedOutput(); err != nil {
     29 			return fmt.Errorf("args=%v out=%q err=%v", cmd.Args, string(out), err)
     30 		}
     31 	}
     32 	return nil
     33 }
     34 
     35 func (ti *testInterface) teardown() error {
     36 	for _, cmd := range ti.teardownCmds {
     37 		if out, err := cmd.CombinedOutput(); err != nil {
     38 			return fmt.Errorf("args=%v out=%q err=%v ", cmd.Args, string(out), err)
     39 		}
     40 	}
     41 	return nil
     42 }
     43 
     44 func TestPointToPointInterface(t *testing.T) {
     45 	if testing.Short() {
     46 		t.Skip("avoid external network")
     47 	}
     48 	if runtime.GOOS == "darwin" {
     49 		t.Skipf("not supported on %s", runtime.GOOS)
     50 	}
     51 	if os.Getuid() != 0 {
     52 		t.Skip("must be root")
     53 	}
     54 
     55 	// We suppose that using IPv4 link-local addresses doesn't
     56 	// harm anyone.
     57 	local, remote := "169.254.0.1", "169.254.0.254"
     58 	ip := ParseIP(remote)
     59 	for i := 0; i < 3; i++ {
     60 		ti := &testInterface{local: local, remote: remote}
     61 		if err := ti.setPointToPoint(5963 + i); err != nil {
     62 			t.Skipf("test requires external command: %v", err)
     63 		}
     64 		if err := ti.setup(); err != nil {
     65 			t.Fatal(err)
     66 		} else {
     67 			time.Sleep(3 * time.Millisecond)
     68 		}
     69 		ift, err := Interfaces()
     70 		if err != nil {
     71 			ti.teardown()
     72 			t.Fatal(err)
     73 		}
     74 		for _, ifi := range ift {
     75 			if ti.name != ifi.Name {
     76 				continue
     77 			}
     78 			ifat, err := ifi.Addrs()
     79 			if err != nil {
     80 				ti.teardown()
     81 				t.Fatal(err)
     82 			}
     83 			for _, ifa := range ifat {
     84 				if ip.Equal(ifa.(*IPNet).IP) {
     85 					ti.teardown()
     86 					t.Fatalf("got %v", ifa)
     87 				}
     88 			}
     89 		}
     90 		if err := ti.teardown(); err != nil {
     91 			t.Fatal(err)
     92 		} else {
     93 			time.Sleep(3 * time.Millisecond)
     94 		}
     95 	}
     96 }
     97 
     98 func TestInterfaceArrivalAndDeparture(t *testing.T) {
     99 	if testing.Short() {
    100 		t.Skip("avoid external network")
    101 	}
    102 	if os.Getuid() != 0 {
    103 		t.Skip("must be root")
    104 	}
    105 
    106 	// We suppose that using IPv4 link-local addresses and the
    107 	// dot1Q ID for Token Ring and FDDI doesn't harm anyone.
    108 	local, remote := "169.254.0.1", "169.254.0.254"
    109 	ip := ParseIP(remote)
    110 	for _, vid := range []int{1002, 1003, 1004, 1005} {
    111 		ift1, err := Interfaces()
    112 		if err != nil {
    113 			t.Fatal(err)
    114 		}
    115 		ti := &testInterface{local: local, remote: remote}
    116 		if err := ti.setBroadcast(vid); err != nil {
    117 			t.Skipf("test requires external command: %v", err)
    118 		}
    119 		if err := ti.setup(); err != nil {
    120 			t.Fatal(err)
    121 		} else {
    122 			time.Sleep(3 * time.Millisecond)
    123 		}
    124 		ift2, err := Interfaces()
    125 		if err != nil {
    126 			ti.teardown()
    127 			t.Fatal(err)
    128 		}
    129 		if len(ift2) <= len(ift1) {
    130 			for _, ifi := range ift1 {
    131 				t.Logf("before: %v", ifi)
    132 			}
    133 			for _, ifi := range ift2 {
    134 				t.Logf("after: %v", ifi)
    135 			}
    136 			ti.teardown()
    137 			t.Fatalf("got %v; want gt %v", len(ift2), len(ift1))
    138 		}
    139 		for _, ifi := range ift2 {
    140 			if ti.name != ifi.Name {
    141 				continue
    142 			}
    143 			ifat, err := ifi.Addrs()
    144 			if err != nil {
    145 				ti.teardown()
    146 				t.Fatal(err)
    147 			}
    148 			for _, ifa := range ifat {
    149 				if ip.Equal(ifa.(*IPNet).IP) {
    150 					ti.teardown()
    151 					t.Fatalf("got %v", ifa)
    152 				}
    153 			}
    154 		}
    155 		if err := ti.teardown(); err != nil {
    156 			t.Fatal(err)
    157 		} else {
    158 			time.Sleep(3 * time.Millisecond)
    159 		}
    160 		ift3, err := Interfaces()
    161 		if err != nil {
    162 			t.Fatal(err)
    163 		}
    164 		if len(ift3) >= len(ift2) {
    165 			for _, ifi := range ift2 {
    166 				t.Logf("before: %v", ifi)
    167 			}
    168 			for _, ifi := range ift3 {
    169 				t.Logf("after: %v", ifi)
    170 			}
    171 			t.Fatalf("got %v; want lt %v", len(ift3), len(ift2))
    172 		}
    173 	}
    174 }
    175