forked from xitongsys/ptcp
/
raw.go
96 lines (77 loc) · 1.84 KB
/
raw.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
package ptcp
import (
"net"
"syscall"
"github.com/audibleblink/ethernet-go/header"
"github.com/audibleblink/ptcp/util"
)
var RAWBUFSIZE = 65535
type Raw struct {
ifName string
iface *net.Interface
fd int
buf []byte
}
func NewRaw(interfaceName string) (*Raw, error) {
fd, err := syscall.Socket(syscall.AF_PACKET, syscall.SOCK_RAW, int(util.Htons(syscall.ETH_P_ALL)))
if err != nil {
return nil, err
}
iface, err := net.InterfaceByName(interfaceName)
if err != nil {
return nil, err
}
if err = syscall.BindToDevice(fd, interfaceName); err != nil {
return nil, err
}
if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
return nil, err
}
return &Raw{
ifName: interfaceName,
iface: iface,
fd: fd,
buf: make([]byte, RAWBUFSIZE),
}, nil
}
func (r *Raw) Read() ([]byte, error) {
n, _, err := syscall.Recvfrom(r.fd, r.buf, 0)
if err == nil {
eth := &header.Frame{}
err = eth.UnmarshalBinary(r.buf[:n])
return eth.Payload, err
}
return nil, err
}
func (r *Raw) Write(data []byte) error {
_, dstIp, err := header.GetIp(data)
if err != nil {
return err
}
eth := &header.Frame{}
eth.EtherType = header.EtherTypeIPv4
gatewayIp, err := route.GetGateway(dstIp)
if err != nil {
return err
} else if gatewayIp == 0 {
eth.Destination = r.iface.HardwareAddr
} else {
gateWayHwAddr, err := arp.GetHwAddr(gatewayIp)
if err != nil {
return err
}
eth.Destination = gateWayHwAddr
}
eth.Source = r.iface.HardwareAddr
eth.Payload = data
ethData, err := eth.MarshalBinary()
if err != nil {
return err
}
addr := syscall.SockaddrLinklayer{
Halen: 6,
Addr: [8]byte{eth.Source[0], eth.Source[1], eth.Source[2], eth.Source[3], eth.Source[4], eth.Source[5], 0xff, 0xff},
Ifindex: r.iface.Index,
}
return syscall.Sendto(r.fd, ethData, 0, &addr)
}