-
Notifications
You must be signed in to change notification settings - Fork 0
/
arp.go
122 lines (98 loc) · 3.05 KB
/
arp.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
package arp
import (
"fmt"
"net"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/google/gopacket/pcap"
"github.com/lucheng0127/kube-eip/pkg/utils/ctx"
logger "github.com/lucheng0127/kube-eip/pkg/utils/log"
)
type ArpCracker struct {
handle *pcap.Handle
targets map[string]int
iface *net.Interface
}
func NewArpCracker(dev string) (*ArpCracker, error) {
ctx := ctx.NewTraceContext()
cracker := new(ArpCracker)
cracker.targets = make(map[string]int)
iface, err := net.InterfaceByName(dev)
if err != nil {
logger.Error(ctx, fmt.Sprintf("get interface %s %s", dev, err.Error()))
return nil, err
}
cracker.iface = iface
handle, err := pcap.OpenLive(dev, 1600, true, pcap.BlockForever)
if err != nil {
logger.Error(ctx, fmt.Sprintf("monitor interface %s traffic %s", dev, err.Error()))
return nil, err
} else if err := handle.SetBPFFilter("arp"); err != nil {
logger.Error(ctx, fmt.Sprintf("set bpf filter %s", err.Error()))
return nil, err
}
cracker.handle = handle
return cracker, nil
}
func (cracker *ArpCracker) doArpReply(dstHwAddr, dstProtAddr, srcprotAdPr []byte) {
ctx := ctx.NewTraceContext()
ether := layers.Ethernet{
EthernetType: layers.EthernetTypeARP,
SrcMAC: cracker.iface.HardwareAddr,
DstMAC: dstHwAddr,
}
arpReply := layers.ARP{
AddrType: layers.LinkTypeEthernet,
Protocol: layers.EthernetTypeIPv4,
Operation: layers.ARPReply,
HwAddressSize: 6,
ProtAddressSize: 4,
SourceHwAddress: cracker.iface.HardwareAddr,
SourceProtAddress: srcprotAdPr,
DstHwAddress: dstHwAddr,
DstProtAddress: dstProtAddr,
}
buf := gopacket.NewSerializeBuffer()
err := gopacket.SerializeLayers(buf, gopacket.SerializeOptions{
FixLengths: true,
ComputeChecksums: true,
}, ðer, &arpReply)
if err != nil {
logger.Error(ctx, fmt.Sprintf("build arp reply %s", err.Error()))
}
if err = cracker.handle.WritePacketData(buf.Bytes()); err != nil {
logger.Error(ctx, fmt.Sprintf("send arp reply %s", err.Error()))
}
}
func (cracker *ArpCracker) handleArp(pkt gopacket.Packet) {
arpLayer := pkt.Layer(layers.LayerTypeARP)
if arpLayer == nil {
return
}
arpPkt := arpLayer.(*layers.ARP)
if arpPkt.Operation == layers.ARPReply {
return
}
target := net.IP(arpPkt.DstProtAddress).String()
if _, ok := cracker.targets[target]; !ok {
// Arp request dst not in eip targets, do nothing
return
}
cracker.doArpReply(arpPkt.SourceHwAddress, arpPkt.SourceProtAddress, arpPkt.DstProtAddress)
}
func (cracker *ArpCracker) AddTarget(target string) {
ctx := ctx.NewTraceContext()
logger.Info(ctx, fmt.Sprintf("add %s to arp poisoning targets", target))
cracker.targets[target] = 0
}
func (cracker *ArpCracker) DeleteTarget(target string) {
ctx := ctx.NewTraceContext()
logger.Info(ctx, fmt.Sprintf("remove %s from arp poisoning targets", target))
delete(cracker.targets, target)
}
func (cracker *ArpCracker) Poisoning() {
packetSource := gopacket.NewPacketSource(cracker.handle, cracker.handle.LinkType())
for pkt := range packetSource.Packets() {
cracker.handleArp(pkt)
}
}