diff --git a/ipv4_test.go b/ipv4_test.go new file mode 100644 index 0000000..f855521 --- /dev/null +++ b/ipv4_test.go @@ -0,0 +1,81 @@ +package water + +import ( + "net" + "os/exec" + "testing" + "time" + + "github.com/songgao/water/waterutil" +) + +const BUFFERSIZE = 1522 + +func startRead(ch chan<- []byte, ifce *Interface) { + go func() { + for { + buffer := make([]byte, BUFFERSIZE) + _, err := ifce.Read(buffer) + if err == nil { + ch <- buffer + } + } + }() +} + +func startBroadcast(t *testing.T, dst net.IP) { + if err := exec.Command("ping", "-b", "-c", "2", dst.String()).Start(); err != nil { + t.Fatal(err) + } +} + +func TestBroadcast(t *testing.T) { + var ( + self = net.IPv4(10, 0, 42, 1) + mask = net.IPv4Mask(255, 255, 255, 0) + brd = net.IPv4(10, 0, 42, 255) + ) + + ifce, err := NewTAP("test") + if err != nil { + t.Fatalf("creating TAP error: %v\n", err) + } + + setupIfce(t, net.IPNet{IP: self, Mask: mask}, ifce.Name()) + startBroadcast(t, brd) + + dataCh := make(chan []byte, 8) + startRead(dataCh, ifce) + + timeout := time.NewTimer(8 * time.Second).C + +readFrame: + for { + select { + case buffer := <-dataCh: + ethertype := waterutil.MACEthertype(buffer) + if ethertype != waterutil.IPv4 { + continue readFrame + } + if !waterutil.IsBroadcast(waterutil.MACDestination(buffer)) { + continue readFrame + } + packet := waterutil.MACPayload(buffer) + if !waterutil.IsIPv4(packet) { + continue readFrame + } + if !waterutil.IPv4Source(packet).Equal(self) { + continue readFrame + } + if !waterutil.IPv4Destination(packet).Equal(brd) { + continue readFrame + } + if waterutil.IPv4Protocol(packet) != waterutil.ICMP { + continue readFrame + } + break readFrame + case <-timeout: + t.Fatal("Waiting for broadcast packet timeout") + } + } +} diff --git a/ipv4_test_linux.go b/ipv4_test_linux.go new file mode 100644 index 0000000..b5b680c --- /dev/null +++ b/ipv4_test_linux.go @@ -0,0 +1,16 @@ +package water + +import ( + "net" + "os/exec" + "testing" +) + +func setupIfce(t *testing.T, ipNet net.IPNet, dev string) { + if err := exec.Command("ip", "link", "set", dev, "up").Run(); err != nil { + t.Fatal(err) + } + if err := exec.Command("ip", "addr", "add", ipNet.String(), "dev", dev).Run(); err != nil { + t.Fatal(err) + } +} diff --git a/ipv4_test_other.go b/ipv4_test_other.go new file mode 100644 index 0000000..d70a50f --- /dev/null +++ b/ipv4_test_other.go @@ -0,0 +1,12 @@ +// +build !linux + +package water + +import ( + "net" + "testing" +) + +func setupIfce(t *testing.T, ipNet net.IPNet, dev string) { + t.Fatal("unsupported platform") +} diff --git a/syscalls_other.go b/syscalls_other.go index a38ce85..ace8c3c 100644 --- a/syscalls_other.go +++ b/syscalls_other.go @@ -2,10 +2,12 @@ package water +import "errors" + func newTAP(ifName string) (ifce *Interface, err error) { - panic("water: tap interface not implemented on this platform") + return nil, errors.New("tap interface not implemented on this platform") } func newTUN(ifName string) (ifce *Interface, err error) { - panic("water: tap interface not implemented on this platform") + return nil, errors.New("tap interface not implemented on this platform") }