-
Notifications
You must be signed in to change notification settings - Fork 2
/
afconn_linux.go
130 lines (114 loc) · 3.47 KB
/
afconn_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package etherconn
import (
"context"
"errors"
"fmt"
"net"
"github.com/google/gopacket"
"github.com/google/gopacket/afpacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"golang.org/x/net/bpf"
"golang.org/x/sys/unix"
)
type afConn struct {
*afpacket.TPacket
maxFrameSize int
}
func newAfConn(maxEtherFrameSize int, others ...any) (*afConn, error) {
r := &afConn{maxFrameSize: maxEtherFrameSize}
var err error
r.TPacket, err = afpacket.NewTPacket(others...)
return r, err
}
func (afconn *afConn) CloseMe() {
afconn.Close()
}
func (afconn *afConn) ReadPacketData() ([]byte, gopacket.CaptureInfo, error) {
buf := make([]byte, afconn.maxFrameSize)
ci, err := afconn.ReadPacketDataTo(buf)
return buf, ci, err
}
func (afconn *afConn) setBPFFilter(filter string) error {
pcapBPF, err := pcap.CompileBPFFilter(layers.LinkTypeEthernet, afconn.maxFrameSize, filter)
if err != nil {
return err
}
bpfIns := []bpf.RawInstruction{}
for _, ins := range pcapBPF {
bpfIns2 := bpf.RawInstruction{
Op: ins.Code,
Jt: ins.Jt,
Jf: ins.Jf,
K: ins.K,
}
bpfIns = append(bpfIns, bpfIns2)
}
// if relay.conn.SetBPF(bpfIns); err != nil {
// return err
// }
return afconn.SetBPF(bpfIns)
}
func (afconn *afConn) isTimeout(err error) bool {
return errors.Is(err, afpacket.ErrTimeout)
}
func (afconn *afConn) relayType() RelayType {
return RelayTypeAFP
}
func (afconn *afConn) getRawStats() any {
_, rawstat, err := afconn.SocketStats()
if err != nil {
return nil
}
return rawstat
}
func getVLANsFromAncDataAFPkt(existList []uint16, auxdata []interface{}) []uint16 {
var r []uint16
for _, adata := range auxdata {
if v, ok := adata.(afpacket.AncillaryVLAN); ok {
r = append([]uint16{uint16(v.VLAN)}, existList...)
}
}
return r
}
// NewRawSocketRelayPcap creates a new RawSocketRelay instance using AF_PACKET socket , bound to the interface ifname,
// optionally with RelayOption functions.
// This function will put the interface in promisc mode, which means it requires root privilage.
func NewRawSocketRelay(parentctx context.Context, ifname string, options ...RelayOption) (*RawSocketRelay, error) {
//NOTE:interface must be put in promisc mode, otherwise only pkt with real mac will be received
err := SetPromisc(ifname)
if err != nil {
return nil, fmt.Errorf("failed to set %v to Promisc mode,%w", ifname, err)
}
conn, err := newAfConn(
afpacket.DefaultFrameSize,
afpacket.OptInterface(ifname),
afpacket.OptBlockSize(afpacket.DefaultBlockSize),
afpacket.OptNumBlocks(afpacket.DefaultNumBlocks),
afpacket.OptAddVLANHeader(false),
afpacket.OptPollTimeout(DefaultRelayRecvTimeout),
afpacket.SocketRaw,
afpacket.TPacketVersionHighestAvailable)
if err != nil {
return nil, fmt.Errorf("failed to create rawsocketrelay,%w", err)
}
return newRawSocketRelayWithRelayConn(parentctx, ifname, conn, options...)
}
// SetPromisc put the interface in Promisc mode
func SetPromisc(ifname string) error {
intf, err := net.InterfaceByName(ifname)
if err != nil {
return fmt.Errorf("couldn't query interface %s: %s", ifname, err)
}
htons := func(data uint16) uint16 { return data<<8 | data>>8 }
fd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW, int(htons(unix.ETH_P_ALL)))
if err != nil {
return fmt.Errorf("couldn't open packet socket: %s", err)
}
mreq := unix.PacketMreq{
Ifindex: int32(intf.Index),
Type: unix.PACKET_MR_PROMISC,
}
opt := unix.PACKET_ADD_MEMBERSHIP
return unix.SetsockoptPacketMreq(fd, unix.SOL_PACKET, opt, &mreq)
}