blob: b44da90549a42ef057f55fce4bf5daa39f03a4cc [file] [log] [blame]
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ipv4_test
import (
"net"
"runtime"
"testing"
"time"
"golang.org/x/net/bpf"
"golang.org/x/net/ipv4"
)
func TestBPF(t *testing.T) {
if runtime.GOOS != "linux" {
t.Skipf("not supported on %s", runtime.GOOS)
}
l, err := net.ListenPacket("udp4", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
defer l.Close()
p := ipv4.NewPacketConn(l)
// This filter accepts UDP packets whose first payload byte is
// even.
prog, err := bpf.Assemble([]bpf.Instruction{
// Load the first byte of the payload (skipping UDP header).
bpf.LoadAbsolute{Off: 8, Size: 1},
// Select LSB of the byte.
bpf.ALUOpConstant{Op: bpf.ALUOpAnd, Val: 1},
// Byte is even?
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 0, SkipFalse: 1},
// Accept.
bpf.RetConstant{Val: 4096},
// Ignore.
bpf.RetConstant{Val: 0},
})
if err != nil {
t.Fatalf("compiling BPF: %s", err)
}
if err = p.SetBPF(prog); err != nil {
t.Fatalf("attaching filter to Conn: %s", err)
}
s, err := net.Dial("udp4", l.LocalAddr().String())
if err != nil {
t.Fatal(err)
}
defer s.Close()
go func() {
for i := byte(0); i < 10; i++ {
s.Write([]byte{i})
}
}()
l.SetDeadline(time.Now().Add(2 * time.Second))
seen := make([]bool, 5)
for {
var b [512]byte
n, _, err := l.ReadFrom(b[:])
if err != nil {
t.Fatalf("reading from listener: %s", err)
}
if n != 1 {
t.Fatalf("unexpected packet length, want 1, got %d", n)
}
if b[0] >= 10 {
t.Fatalf("unexpected byte, want 0-9, got %d", b[0])
}
if b[0]%2 != 0 {
t.Fatalf("got odd byte %d, wanted only even bytes", b[0])
}
seen[b[0]/2] = true
seenAll := true
for _, v := range seen {
if !v {
seenAll = false
break
}
}
if seenAll {
break
}
}
}