mirror of
https://github.com/golang/net.git
synced 2026-03-31 02:17:08 +09:00
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>
This commit is contained in:
committed by
Mikio Hara
parent
58b2fb074e
commit
ef00b378c7
93
ipv6/bpf_test.go
Normal file
93
ipv6/bpf_test.go
Normal file
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
27
ipv6/bpfopt_linux.go
Normal file
27
ipv6/bpfopt_linux.go
Normal file
@@ -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))))
|
||||
}
|
||||
16
ipv6/bpfopt_stub.go
Normal file
16
ipv6/bpfopt_stub.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user