-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathndproxy.go
87 lines (78 loc) · 2.28 KB
/
ndproxy.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
// ndproxy
package main
import (
// "context"
// "fmt"
"log"
"net"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/hujun-open/etherconn"
)
type L2Encap struct {
HwAddr net.HardwareAddr
Vlans etherconn.VLANs
}
type NDPProxy struct {
targets map[string]L2Encap //key is stringify IP
relay etherconn.PacketRelay
econn *etherconn.EtherConn
}
func NewNDPProxyFromRelay(targets map[string]L2Encap, relay etherconn.PacketRelay) *NDPProxy {
r := new(NDPProxy)
r.relay = relay
r.targets = targets
r.econn = etherconn.NewEtherConn(net.HardwareAddr{0, 0, 0, 0, 0, 0},
r.relay, etherconn.WithDefault())
go r.recv()
return r
}
func (proxy *NDPProxy) processReq(pbuf []byte, peermac net.HardwareAddr) {
gpkt := gopacket.NewPacket(pbuf, layers.LayerTypeIPv6, gopacket.DecodeOptions{Lazy: true, NoCopy: true})
if icmp6Layer := gpkt.Layer(layers.LayerTypeICMPv6NeighborSolicitation); icmp6Layer != nil {
req := icmp6Layer.(*layers.ICMPv6NeighborSolicitation)
if l2ep, ok := proxy.targets[req.TargetAddress.String()]; ok {
peerIPlayer := gpkt.Layer(layers.LayerTypeIPv6)
resp := &layers.ICMPv6NeighborAdvertisement{
TargetAddress: req.TargetAddress,
Flags: 0b01000000,
Options: []layers.ICMPv6Option{
{
Type: layers.ICMPv6OptTargetAddress,
Data: []byte(l2ep.HwAddr),
},
},
}
respicmp6Layer := &layers.ICMPv6{
TypeCode: layers.CreateICMPv6TypeCode(136, 0),
}
buf := gopacket.NewSerializeBuffer()
iplayer := &layers.IPv6{
Version: 6,
SrcIP: req.TargetAddress,
DstIP: peerIPlayer.(*layers.IPv6).SrcIP,
NextHeader: layers.IPProtocol(58),
HopLimit: 255, //must be 255, otherwise won't be acceptedz
}
respicmp6Layer.SetNetworkLayerForChecksum(iplayer)
opts := gopacket.SerializeOptions{FixLengths: true, ComputeChecksums: true}
gopacket.SerializeLayers(buf, opts,
iplayer,
respicmp6Layer,
resp)
_, err := proxy.econn.WriteIPPktToFrom(buf.Bytes(), l2ep.HwAddr, peermac, l2ep.Vlans)
if err != nil {
log.Printf("failed to send resp, %v", err)
}
}
}
}
func (proxy *NDPProxy) recv() {
for {
pkt, remote, err := proxy.econn.ReadPkt()
if err != nil {
log.Fatalf("failed from recv, %v", err)
}
go proxy.processReq(pkt, remote.HwAddr)
}
}