Skip to content

Commit ef00b37

Browse files
David Andersoncixtor
David Anderson
authored andcommitted
ipv6: support attaching packet filters to PacketConn.
Fixes golang/go#14974 Change-Id: I58c41acf29329aedf61b9ca59eb271e4536c80ea Reviewed-on: https://go-review.googlesource.com/23107 Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com>
1 parent 58b2fb0 commit ef00b37

12 files changed

+273
-0
lines changed

ipv6/bpf_test.go

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2016 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+
package ipv6_test
6+
7+
import (
8+
"net"
9+
"runtime"
10+
"testing"
11+
"time"
12+
13+
"golang.org/x/net/bpf"
14+
"golang.org/x/net/ipv6"
15+
)
16+
17+
func TestBPF(t *testing.T) {
18+
if runtime.GOOS != "linux" {
19+
t.Skipf("not supported on %s", runtime.GOOS)
20+
}
21+
22+
l, err := net.ListenPacket("udp6", "[::1]:0")
23+
if err != nil {
24+
t.Fatal(err)
25+
}
26+
defer l.Close()
27+
28+
p := ipv6.NewPacketConn(l)
29+
30+
// This filter accepts UDP packets whose first payload byte is
31+
// even.
32+
prog, err := bpf.Assemble([]bpf.Instruction{
33+
// Load the first byte of the payload (skipping UDP header).
34+
bpf.LoadAbsolute{Off: 8, Size: 1},
35+
// Select LSB of the byte.
36+
bpf.ALUOpConstant{Op: bpf.ALUOpAnd, Val: 1},
37+
// Byte is even?
38+
bpf.JumpIf{Cond: bpf.JumpEqual, Val: 0, SkipFalse: 1},
39+
// Accept.
40+
bpf.RetConstant{Val: 4096},
41+
// Ignore.
42+
bpf.RetConstant{Val: 0},
43+
})
44+
if err != nil {
45+
t.Fatalf("compiling BPF: %s", err)
46+
}
47+
48+
if err = p.SetBPF(prog); err != nil {
49+
t.Fatalf("attaching filter to Conn: %s", err)
50+
}
51+
52+
s, err := net.Dial("udp6", l.LocalAddr().String())
53+
if err != nil {
54+
t.Fatal(err)
55+
}
56+
defer s.Close()
57+
go func() {
58+
for i := byte(0); i < 10; i++ {
59+
s.Write([]byte{i})
60+
}
61+
}()
62+
63+
l.SetDeadline(time.Now().Add(2 * time.Second))
64+
seen := make([]bool, 5)
65+
for {
66+
var b [512]byte
67+
n, _, err := l.ReadFrom(b[:])
68+
if err != nil {
69+
t.Fatalf("reading from listener: %s", err)
70+
}
71+
if n != 1 {
72+
t.Fatalf("unexpected packet length, want 1, got %d", n)
73+
}
74+
if b[0] >= 10 {
75+
t.Fatalf("unexpected byte, want 0-9, got %d", b[0])
76+
}
77+
if b[0]%2 != 0 {
78+
t.Fatalf("got odd byte %d, wanted only even bytes", b[0])
79+
}
80+
seen[b[0]/2] = true
81+
82+
seenAll := true
83+
for _, v := range seen {
84+
if !v {
85+
seenAll = false
86+
break
87+
}
88+
}
89+
if seenAll {
90+
break
91+
}
92+
}
93+
}

ipv6/bpfopt_linux.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2016 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+
package ipv6
6+
7+
import (
8+
"os"
9+
"unsafe"
10+
11+
"golang.org/x/net/bpf"
12+
)
13+
14+
// SetBPF attaches a BPF program to the connection.
15+
//
16+
// Only supported on Linux.
17+
func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
18+
fd, err := c.sysfd()
19+
if err != nil {
20+
return err
21+
}
22+
prog := sysSockFProg{
23+
Len: uint16(len(filter)),
24+
Filter: (*sysSockFilter)(unsafe.Pointer(&filter[0])),
25+
}
26+
return os.NewSyscallError("setsockopt", setsockopt(fd, sysSOL_SOCKET, sysSO_ATTACH_FILTER, unsafe.Pointer(&prog), uint32(unsafe.Sizeof(prog))))
27+
}

ipv6/bpfopt_stub.go

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2016 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 !linux
6+
7+
package ipv6
8+
9+
import "golang.org/x/net/bpf"
10+
11+
// SetBPF attaches a BPF program to the connection.
12+
//
13+
// Only supported on Linux.
14+
func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
15+
return errOpNoSupport
16+
}

ipv6/defs_linux.go

+9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ package ipv6
1313
#include <linux/in6.h>
1414
#include <linux/ipv6.h>
1515
#include <linux/icmpv6.h>
16+
#include <linux/filter.h>
17+
#include <sys/socket.h>
1618
*/
1719
import "C"
1820

@@ -104,6 +106,9 @@ const (
104106
sysICMPV6_FILTER_BLOCKOTHERS = C.ICMPV6_FILTER_BLOCKOTHERS
105107
sysICMPV6_FILTER_PASSONLY = C.ICMPV6_FILTER_PASSONLY
106108

109+
sysSOL_SOCKET = C.SOL_SOCKET
110+
sysSO_ATTACH_FILTER = C.SO_ATTACH_FILTER
111+
107112
sysSizeofKernelSockaddrStorage = C.sizeof_struct___kernel_sockaddr_storage
108113
sysSizeofSockaddrInet6 = C.sizeof_struct_sockaddr_in6
109114
sysSizeofInet6Pktinfo = C.sizeof_struct_in6_pktinfo
@@ -134,3 +139,7 @@ type sysGroupReq C.struct_group_req
134139
type sysGroupSourceReq C.struct_group_source_req
135140

136141
type sysICMPv6Filter C.struct_icmp6_filter
142+
143+
type sysSockFProg C.struct_sock_fprog
144+
145+
type sysSockFilter C.struct_sock_filter

ipv6/zsys_linux_386.go

+16
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ const (
8484
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
8585
sysICMPV6_FILTER_PASSONLY = 0x4
8686

87+
sysSOL_SOCKET = 0x1
88+
sysSO_ATTACH_FILTER = 0x1a
89+
8790
sysSizeofKernelSockaddrStorage = 0x80
8891
sysSizeofSockaddrInet6 = 0x1c
8992
sysSizeofInet6Pktinfo = 0x14
@@ -150,3 +153,16 @@ type sysGroupSourceReq struct {
150153
type sysICMPv6Filter struct {
151154
Data [8]uint32
152155
}
156+
157+
type sysSockFProg struct {
158+
Len uint16
159+
Pad_cgo_0 [2]byte
160+
Filter *sysSockFilter
161+
}
162+
163+
type sysSockFilter struct {
164+
Code uint16
165+
Jt uint8
166+
Jf uint8
167+
K uint32
168+
}

ipv6/zsys_linux_amd64.go

+16
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ const (
8484
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
8585
sysICMPV6_FILTER_PASSONLY = 0x4
8686

87+
sysSOL_SOCKET = 0x1
88+
sysSO_ATTACH_FILTER = 0x1a
89+
8790
sysSizeofKernelSockaddrStorage = 0x80
8891
sysSizeofSockaddrInet6 = 0x1c
8992
sysSizeofInet6Pktinfo = 0x14
@@ -152,3 +155,16 @@ type sysGroupSourceReq struct {
152155
type sysICMPv6Filter struct {
153156
Data [8]uint32
154157
}
158+
159+
type sysSockFProg struct {
160+
Len uint16
161+
Pad_cgo_0 [6]byte
162+
Filter *sysSockFilter
163+
}
164+
165+
type sysSockFilter struct {
166+
Code uint16
167+
Jt uint8
168+
Jf uint8
169+
K uint32
170+
}

ipv6/zsys_linux_arm.go

+16
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ const (
8484
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
8585
sysICMPV6_FILTER_PASSONLY = 0x4
8686

87+
sysSOL_SOCKET = 0x1
88+
sysSO_ATTACH_FILTER = 0x1a
89+
8790
sysSizeofKernelSockaddrStorage = 0x80
8891
sysSizeofSockaddrInet6 = 0x1c
8992
sysSizeofInet6Pktinfo = 0x14
@@ -150,3 +153,16 @@ type sysGroupSourceReq struct {
150153
type sysICMPv6Filter struct {
151154
Data [8]uint32
152155
}
156+
157+
type sysSockFProg struct {
158+
Len uint16
159+
Pad_cgo_0 [2]byte
160+
Filter *sysSockFilter
161+
}
162+
163+
type sysSockFilter struct {
164+
Code uint16
165+
Jt uint8
166+
Jf uint8
167+
K uint32
168+
}

ipv6/zsys_linux_arm64.go

+16
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ const (
8686
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
8787
sysICMPV6_FILTER_PASSONLY = 0x4
8888

89+
sysSOL_SOCKET = 0x1
90+
sysSO_ATTACH_FILTER = 0x1a
91+
8992
sysSizeofKernelSockaddrStorage = 0x80
9093
sysSizeofSockaddrInet6 = 0x1c
9194
sysSizeofInet6Pktinfo = 0x14
@@ -154,3 +157,16 @@ type sysGroupSourceReq struct {
154157
type sysICMPv6Filter struct {
155158
Data [8]uint32
156159
}
160+
161+
type sysSockFProg struct {
162+
Len uint16
163+
Pad_cgo_0 [6]byte
164+
Filter *sysSockFilter
165+
}
166+
167+
type sysSockFilter struct {
168+
Code uint16
169+
Jt uint8
170+
Jf uint8
171+
K uint32
172+
}

ipv6/zsys_linux_mips64.go

+16
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ const (
8686
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
8787
sysICMPV6_FILTER_PASSONLY = 0x4
8888

89+
sysSOL_SOCKET = 0x1
90+
sysSO_ATTACH_FILTER = 0x1a
91+
8992
sysSizeofKernelSockaddrStorage = 0x80
9093
sysSizeofSockaddrInet6 = 0x1c
9194
sysSizeofInet6Pktinfo = 0x14
@@ -154,3 +157,16 @@ type sysGroupSourceReq struct {
154157
type sysICMPv6Filter struct {
155158
Data [8]uint32
156159
}
160+
161+
type sysSockFProg struct {
162+
Len uint16
163+
Pad_cgo_0 [6]byte
164+
Filter *sysSockFilter
165+
}
166+
167+
type sysSockFilter struct {
168+
Code uint16
169+
Jt uint8
170+
Jf uint8
171+
K uint32
172+
}

ipv6/zsys_linux_mips64le.go

+16
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ const (
8686
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
8787
sysICMPV6_FILTER_PASSONLY = 0x4
8888

89+
sysSOL_SOCKET = 0x1
90+
sysSO_ATTACH_FILTER = 0x1a
91+
8992
sysSizeofKernelSockaddrStorage = 0x80
9093
sysSizeofSockaddrInet6 = 0x1c
9194
sysSizeofInet6Pktinfo = 0x14
@@ -154,3 +157,16 @@ type sysGroupSourceReq struct {
154157
type sysICMPv6Filter struct {
155158
Data [8]uint32
156159
}
160+
161+
type sysSockFProg struct {
162+
Len uint16
163+
Pad_cgo_0 [6]byte
164+
Filter *sysSockFilter
165+
}
166+
167+
type sysSockFilter struct {
168+
Code uint16
169+
Jt uint8
170+
Jf uint8
171+
K uint32
172+
}

ipv6/zsys_linux_ppc64.go

+16
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ const (
8686
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
8787
sysICMPV6_FILTER_PASSONLY = 0x4
8888

89+
sysSOL_SOCKET = 0x1
90+
sysSO_ATTACH_FILTER = 0x1a
91+
8992
sysSizeofKernelSockaddrStorage = 0x80
9093
sysSizeofSockaddrInet6 = 0x1c
9194
sysSizeofInet6Pktinfo = 0x14
@@ -154,3 +157,16 @@ type sysGroupSourceReq struct {
154157
type sysICMPv6Filter struct {
155158
Data [8]uint32
156159
}
160+
161+
type sysSockFProg struct {
162+
Len uint16
163+
Pad_cgo_0 [6]byte
164+
Filter *sysSockFilter
165+
}
166+
167+
type sysSockFilter struct {
168+
Code uint16
169+
Jt uint8
170+
Jf uint8
171+
K uint32
172+
}

ipv6/zsys_linux_ppc64le.go

+16
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ const (
8686
sysICMPV6_FILTER_BLOCKOTHERS = 0x3
8787
sysICMPV6_FILTER_PASSONLY = 0x4
8888

89+
sysSOL_SOCKET = 0x1
90+
sysSO_ATTACH_FILTER = 0x1a
91+
8992
sysSizeofKernelSockaddrStorage = 0x80
9093
sysSizeofSockaddrInet6 = 0x1c
9194
sysSizeofInet6Pktinfo = 0x14
@@ -154,3 +157,16 @@ type sysGroupSourceReq struct {
154157
type sysICMPv6Filter struct {
155158
Data [8]uint32
156159
}
160+
161+
type sysSockFProg struct {
162+
Len uint16
163+
Pad_cgo_0 [6]byte
164+
Filter *sysSockFilter
165+
}
166+
167+
type sysSockFilter struct {
168+
Code uint16
169+
Jt uint8
170+
Jf uint8
171+
K uint32
172+
}

0 commit comments

Comments
 (0)