author | David Anderson
<danderson@google.com> 2016-05-15 03:16:23 UTC |
committer | Mikio Hara
<mikioh.mikioh@gmail.com> 2016-05-15 06:10:11 UTC |
parent | 58b2fb074ec0cc06e95f2409a11ff51dd11798e2 |
ipv6/bpf_test.go | +93 | -0 |
ipv6/bpfopt_linux.go | +27 | -0 |
ipv6/bpfopt_stub.go | +16 | -0 |
ipv6/defs_linux.go | +9 | -0 |
ipv6/zsys_linux_386.go | +16 | -0 |
ipv6/zsys_linux_amd64.go | +16 | -0 |
ipv6/zsys_linux_arm.go | +16 | -0 |
ipv6/zsys_linux_arm64.go | +16 | -0 |
ipv6/zsys_linux_mips64.go | +16 | -0 |
ipv6/zsys_linux_mips64le.go | +16 | -0 |
ipv6/zsys_linux_ppc64.go | +16 | -0 |
ipv6/zsys_linux_ppc64le.go | +16 | -0 |
diff --git a/ipv6/bpf_test.go b/ipv6/bpf_test.go new file mode 100644 index 0000000..03d478d --- /dev/null +++ b/ipv6/bpf_test.go @@ -0,0 +1,93 @@ +// 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 ipv6_test + +import ( + "net" + "runtime" + "testing" + "time" + + "golang.org/x/net/bpf" + "golang.org/x/net/ipv6" +) + +func TestBPF(t *testing.T) { + if runtime.GOOS != "linux" { + t.Skipf("not supported on %s", runtime.GOOS) + } + + l, err := net.ListenPacket("udp6", "[::1]:0") + if err != nil { + t.Fatal(err) + } + defer l.Close() + + p := ipv6.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("udp6", 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 + } + } +} diff --git a/ipv6/bpfopt_linux.go b/ipv6/bpfopt_linux.go new file mode 100644 index 0000000..066ef20 --- /dev/null +++ b/ipv6/bpfopt_linux.go @@ -0,0 +1,27 @@ +// 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 ipv6 + +import ( + "os" + "unsafe" + + "golang.org/x/net/bpf" +) + +// SetBPF attaches a BPF program to the connection. +// +// Only supported on Linux. +func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error { + fd, err := c.sysfd() + if err != nil { + return err + } + prog := sysSockFProg{ + Len: uint16(len(filter)), + Filter: (*sysSockFilter)(unsafe.Pointer(&filter[0])), + } + return os.NewSyscallError("setsockopt", setsockopt(fd, sysSOL_SOCKET, sysSO_ATTACH_FILTER, unsafe.Pointer(&prog), uint32(unsafe.Sizeof(prog)))) +} diff --git a/ipv6/bpfopt_stub.go b/ipv6/bpfopt_stub.go new file mode 100644 index 0000000..2e4de5f --- /dev/null +++ b/ipv6/bpfopt_stub.go @@ -0,0 +1,16 @@ +// 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. + +// +build !linux + +package ipv6 + +import "golang.org/x/net/bpf" + +// SetBPF attaches a BPF program to the connection. +// +// Only supported on Linux. +func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error { + return errOpNoSupport +} diff --git a/ipv6/defs_linux.go b/ipv6/defs_linux.go index d83abce..664305d 100644 --- a/ipv6/defs_linux.go +++ b/ipv6/defs_linux.go @@ -13,6 +13,8 @@ package ipv6 #include <linux/in6.h> #include <linux/ipv6.h> #include <linux/icmpv6.h> +#include <linux/filter.h> +#include <sys/socket.h> */ import "C" @@ -104,6 +106,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = C.ICMPV6_FILTER_BLOCKOTHERS sysICMPV6_FILTER_PASSONLY = C.ICMPV6_FILTER_PASSONLY + sysSOL_SOCKET = C.SOL_SOCKET + sysSO_ATTACH_FILTER = C.SO_ATTACH_FILTER + sysSizeofKernelSockaddrStorage = C.sizeof_struct___kernel_sockaddr_storage sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6 sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo @@ -134,3 +139,7 @@ type sysGroupReq C.struct_group_req type sysGroupSourceReq C.struct_group_source_req type sysICMPv6Filter C.struct_icmp6_filter + +type sysSockFProg C.struct_sock_fprog + +type sysSockFilter C.struct_sock_filter diff --git a/ipv6/zsys_linux_386.go b/ipv6/zsys_linux_386.go index 2727929..36fccbb 100644 --- a/ipv6/zsys_linux_386.go +++ b/ipv6/zsys_linux_386.go @@ -84,6 +84,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 + sysSOL_SOCKET = 0x1 + sysSO_ATTACH_FILTER = 0x1a + sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 @@ -150,3 +153,16 @@ type sysGroupSourceReq struct { type sysICMPv6Filter struct { Data [8]uint32 } + +type sysSockFProg struct { + Len uint16 + Pad_cgo_0 [2]byte + Filter *sysSockFilter +} + +type sysSockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} diff --git a/ipv6/zsys_linux_amd64.go b/ipv6/zsys_linux_amd64.go index 2f742e9..7461e7e 100644 --- a/ipv6/zsys_linux_amd64.go +++ b/ipv6/zsys_linux_amd64.go @@ -84,6 +84,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 + sysSOL_SOCKET = 0x1 + sysSO_ATTACH_FILTER = 0x1a + sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 @@ -152,3 +155,16 @@ type sysGroupSourceReq struct { type sysICMPv6Filter struct { Data [8]uint32 } + +type sysSockFProg struct { + Len uint16 + Pad_cgo_0 [6]byte + Filter *sysSockFilter +} + +type sysSockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} diff --git a/ipv6/zsys_linux_arm.go b/ipv6/zsys_linux_arm.go index 2727929..36fccbb 100644 --- a/ipv6/zsys_linux_arm.go +++ b/ipv6/zsys_linux_arm.go @@ -84,6 +84,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 + sysSOL_SOCKET = 0x1 + sysSO_ATTACH_FILTER = 0x1a + sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 @@ -150,3 +153,16 @@ type sysGroupSourceReq struct { type sysICMPv6Filter struct { Data [8]uint32 } + +type sysSockFProg struct { + Len uint16 + Pad_cgo_0 [2]byte + Filter *sysSockFilter +} + +type sysSockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} diff --git a/ipv6/zsys_linux_arm64.go b/ipv6/zsys_linux_arm64.go index ab10464..ed35f60 100644 --- a/ipv6/zsys_linux_arm64.go +++ b/ipv6/zsys_linux_arm64.go @@ -86,6 +86,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 + sysSOL_SOCKET = 0x1 + sysSO_ATTACH_FILTER = 0x1a + sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 @@ -154,3 +157,16 @@ type sysGroupSourceReq struct { type sysICMPv6Filter struct { Data [8]uint32 } + +type sysSockFProg struct { + Len uint16 + Pad_cgo_0 [6]byte + Filter *sysSockFilter +} + +type sysSockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} diff --git a/ipv6/zsys_linux_mips64.go b/ipv6/zsys_linux_mips64.go index ec8ce15..141c869 100644 --- a/ipv6/zsys_linux_mips64.go +++ b/ipv6/zsys_linux_mips64.go @@ -86,6 +86,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 + sysSOL_SOCKET = 0x1 + sysSO_ATTACH_FILTER = 0x1a + sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 @@ -154,3 +157,16 @@ type sysGroupSourceReq struct { type sysICMPv6Filter struct { Data [8]uint32 } + +type sysSockFProg struct { + Len uint16 + Pad_cgo_0 [6]byte + Filter *sysSockFilter +} + +type sysSockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} diff --git a/ipv6/zsys_linux_mips64le.go b/ipv6/zsys_linux_mips64le.go index 2341ae6..d50eb63 100644 --- a/ipv6/zsys_linux_mips64le.go +++ b/ipv6/zsys_linux_mips64le.go @@ -86,6 +86,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 + sysSOL_SOCKET = 0x1 + sysSO_ATTACH_FILTER = 0x1a + sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 @@ -154,3 +157,16 @@ type sysGroupSourceReq struct { type sysICMPv6Filter struct { Data [8]uint32 } + +type sysSockFProg struct { + Len uint16 + Pad_cgo_0 [6]byte + Filter *sysSockFilter +} + +type sysSockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} diff --git a/ipv6/zsys_linux_ppc64.go b/ipv6/zsys_linux_ppc64.go index b99b8a5..c1d775f 100644 --- a/ipv6/zsys_linux_ppc64.go +++ b/ipv6/zsys_linux_ppc64.go @@ -86,6 +86,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 + sysSOL_SOCKET = 0x1 + sysSO_ATTACH_FILTER = 0x1a + sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 @@ -154,3 +157,16 @@ type sysGroupSourceReq struct { type sysICMPv6Filter struct { Data [8]uint32 } + +type sysSockFProg struct { + Len uint16 + Pad_cgo_0 [6]byte + Filter *sysSockFilter +} + +type sysSockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +} diff --git a/ipv6/zsys_linux_ppc64le.go b/ipv6/zsys_linux_ppc64le.go index 992b56e..e385fb7 100644 --- a/ipv6/zsys_linux_ppc64le.go +++ b/ipv6/zsys_linux_ppc64le.go @@ -86,6 +86,9 @@ const ( sysICMPV6_FILTER_BLOCKOTHERS = 0x3 sysICMPV6_FILTER_PASSONLY = 0x4 + sysSOL_SOCKET = 0x1 + sysSO_ATTACH_FILTER = 0x1a + sysSizeofKernelSockaddrStorage = 0x80 sysSizeofSockaddrInet6 = 0x1c sysSizeofInet6Pktinfo = 0x14 @@ -154,3 +157,16 @@ type sysGroupSourceReq struct { type sysICMPv6Filter struct { Data [8]uint32 } + +type sysSockFProg struct { + Len uint16 + Pad_cgo_0 [6]byte + Filter *sysSockFilter +} + +type sysSockFilter struct { + Code uint16 + Jt uint8 + Jf uint8 + K uint32 +}