Skip to content

Commit 5245b66

Browse files
added creation of ARP packets and marshaling to bytes
1 parent f468b2e commit 5245b66

File tree

5 files changed

+106
-31
lines changed

5 files changed

+106
-31
lines changed

arpspoof/arpspoof.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package arpspoof
2+
package arpspoof

layers/arp.go

Lines changed: 97 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,33 @@ import (
99

1010
const headerSizeARP = 28
1111

12+
type Operation uint16
13+
14+
const (
15+
OperationRequest Operation = 1
16+
OperationReply Operation = 2
17+
)
18+
19+
type ARPOperation struct {
20+
Val Operation
21+
Desc string
22+
}
23+
24+
func (ao *ARPOperation) String() string {
25+
return fmt.Sprintf("%s (%d)", ao.Desc, ao.Val)
26+
}
27+
1228
// The Address Resolution Protocol (ARP) is a communication protocol
1329
// used for discovering the link layer address, such as a MAC address,
1430
// associated with a given internet layer address, typically an IPv4 address.
1531
// Defined in RFC 826.
1632
type ARPPacket struct {
17-
HardwareType uint16 // Network link protocol type.
18-
ProtocolType uint16 // Internetwork protocol for which the ARP request is intended.
19-
ProtocolTypeDesc string // Internetwork protocol description.
20-
Hlen uint8 // Length (in octets) of a hardware address.
21-
Plen uint8 // Length (in octets) of internetwork addresses.
22-
Op uint16 // Specifies the operation that the sender is performing.
23-
OpDesc string // Operation description.
33+
HardwareType uint16 // Network link protocol type.
34+
ProtocolType uint16 // Internetwork protocol for which the ARP request is intended.
35+
ProtocolTypeDesc string // Internetwork protocol description.
36+
Hlen uint8 // Length (in octets) of a hardware address.
37+
Plen uint8 // Length (in octets) of internetwork addresses.
38+
Op *ARPOperation // Specifies the operation that the sender is performing.
2439
// Media address of the sender. In an ARP request this field is used to indicate
2540
// the address of the host sending the request. In an ARP reply this field is used
2641
// to indicate the address of the host that the request was looking for.
@@ -32,13 +47,40 @@ type ARPPacket struct {
3247
TargetIP netip.Addr // Internetwork address of the intended receiver.
3348
}
3449

50+
func New(
51+
op Operation,
52+
senderMAC net.HardwareAddr,
53+
senderIP netip.Addr,
54+
targetMAC net.HardwareAddr,
55+
targetIP netip.Addr,
56+
) (*ARPPacket, error) {
57+
if len(senderMAC) < 6 || len(targetMAC) < 6 || len(senderMAC) != len(targetMAC) {
58+
return nil, fmt.Errorf("malformed hardware address")
59+
}
60+
if !senderIP.IsValid() || !senderIP.Is4() || !targetIP.IsValid() || !targetIP.Is4() {
61+
return nil, fmt.Errorf("malformed protocol address")
62+
}
63+
return &ARPPacket{
64+
HardwareType: 1,
65+
ProtocolType: 0x0800,
66+
ProtocolTypeDesc: "IPv4",
67+
Hlen: uint8(len(senderMAC)),
68+
Plen: 4,
69+
Op: &ARPOperation{Val: op, Desc: opdesc(op)},
70+
SenderMAC: senderMAC,
71+
SenderIP: senderIP,
72+
TargetMAC: targetMAC,
73+
TargetIP: targetIP,
74+
}, nil
75+
}
76+
3577
func (ap *ARPPacket) String() string {
3678
return fmt.Sprintf(`%s
3779
- Hardware Type: %d
3880
- Protocol Type: %s (%#04x)
3981
- HLen: %d
40-
- PLen: %d
41-
- Operation: %s (%d)
82+
- PLen: %d
83+
- Operation: %s
4284
- Sender MAC Address: %s
4385
- Sender IP Address: %s
4486
- Target MAC Address: %s
@@ -50,7 +92,6 @@ func (ap *ARPPacket) String() string {
5092
ap.ProtocolType,
5193
ap.Hlen,
5294
ap.Plen,
53-
ap.OpDesc,
5495
ap.Op,
5596
ap.SenderMAC,
5697
ap.SenderIP,
@@ -61,29 +102,57 @@ func (ap *ARPPacket) String() string {
61102

62103
func (ap *ARPPacket) Summary() string {
63104
var message string
64-
switch ap.OpDesc {
65-
case "request":
66-
message = fmt.Sprintf("ARP Packet: (%s) Who has %s? Tell %s", ap.OpDesc, ap.TargetIP, ap.SenderIP)
67-
case "reply":
68-
message = fmt.Sprintf("ARP Packet: (%s) %s at %s", ap.OpDesc, ap.SenderIP, ap.SenderMAC)
105+
switch ap.Op.Val {
106+
case OperationRequest:
107+
message = fmt.Sprintf("ARP Packet: (%s) Who has %s? Tell %s", ap.Op.Desc, ap.TargetIP, ap.SenderIP)
108+
case OperationReply:
109+
message = fmt.Sprintf("ARP Packet: (%s) %s at %s", ap.Op.Desc, ap.SenderIP, ap.SenderMAC)
69110
default:
70-
message = fmt.Sprintf("ARP Packet: (%s)", ap.OpDesc)
111+
message = fmt.Sprintf("ARP Packet: (%s)", ap.Op.Desc)
71112
}
72113
return message
73114
}
74115

75-
// Parse parses the given ARP packet data into the ARPPacket struct.
76-
func (ap *ARPPacket) Parse(data []byte) error {
116+
// MarshalBinary implements encoding.BinaryMarshaler interface
117+
func (ap *ARPPacket) MarshalBinary() ([]byte, error) {
118+
buf := make([]byte, 2+2+1+1+2+(ap.Plen*2)+(ap.Hlen*2))
119+
binary.BigEndian.PutUint16(buf[0:2], ap.HardwareType)
120+
binary.BigEndian.PutUint16(buf[2:4], ap.ProtocolType)
121+
buf[4] = ap.Hlen
122+
buf[5] = ap.Plen
123+
binary.BigEndian.PutUint16(buf[6:8], uint16(ap.Op.Val))
124+
hoffset := 8 + ap.Hlen
125+
poffset := hoffset + ap.Plen
126+
copy(buf[8:hoffset], ap.SenderMAC)
127+
copy(buf[hoffset:poffset], ap.SenderIP.AsSlice())
128+
copy(buf[poffset:poffset+ap.Hlen], ap.TargetMAC)
129+
copy(buf[poffset+ap.Hlen:poffset+ap.Hlen+ap.Plen], ap.TargetIP.AsSlice())
130+
return buf, nil
131+
}
132+
133+
func (ap *ARPPacket) ToBytes() ([]byte, error) {
134+
return ap.MarshalBinary()
135+
}
136+
137+
// UnmarshalBinary implements encoding.BinaryUnmarshaler interface
138+
func (ap *ARPPacket) UnmarshalBinary(data []byte) error {
77139
if len(data) < headerSizeARP {
78140
return fmt.Errorf("minimum header size for ARP is %d bytes, got %d bytes", headerSizeARP, len(data))
79141
}
80142
ap.HardwareType = binary.BigEndian.Uint16(data[0:2])
81143
ap.ProtocolType = binary.BigEndian.Uint16(data[2:4])
82144
ap.ProtocolTypeDesc = ptypedesc(ap.ProtocolType)
145+
if ap.ProtocolTypeDesc == "Unknown" {
146+
return fmt.Errorf("unknown protocol type")
147+
}
83148
ap.Hlen = data[4]
84149
ap.Plen = data[5]
85-
ap.Op = binary.BigEndian.Uint16(data[6:8])
86-
ap.OpDesc = opdesc(ap.Op)
150+
op := Operation(binary.BigEndian.Uint16(data[6:8]))
151+
opdesc := opdesc(op)
152+
if opdesc == "Unknown" {
153+
return fmt.Errorf("unknown operation")
154+
}
155+
ap.Op = &ARPOperation{Val: op, Desc: opdesc}
87156
hoffset := 8 + ap.Hlen
88157
ap.SenderMAC = net.HardwareAddr(data[8:hoffset])
89158
poffset := hoffset + ap.Plen
@@ -100,6 +169,11 @@ func (ap *ARPPacket) Parse(data []byte) error {
100169
return nil
101170
}
102171

172+
// Parse parses the given ARP packet data into the ARPPacket struct.
173+
func (ap *ARPPacket) Parse(data []byte) error {
174+
return ap.UnmarshalBinary(data)
175+
}
176+
103177
func (ap *ARPPacket) NextLayer() (layer string, payload []byte) { return }
104178

105179
func ptypedesc(pt uint16) string {
@@ -115,12 +189,12 @@ func ptypedesc(pt uint16) string {
115189
return proto
116190
}
117191

118-
func opdesc(op uint16) string {
192+
func opdesc(op Operation) string {
119193
var opdesc string
120194
switch op {
121-
case 1:
195+
case OperationRequest:
122196
opdesc = "request"
123-
case 2:
197+
case OperationReply:
124198
opdesc = "reply"
125199
default:
126200
opdesc = "Unknown"

mpcapng/write.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ const (
2828
ifNameCode uint16 = 0x0002
2929
ifDescCode uint16 = 0x0003
3030
ifMACCode uint16 = 0x0006
31-
ifTsResCode uint16 = 0x0009
31+
ifTSResCode uint16 = 0x0009
3232
ifFilterCode uint16 = 0x000b
3333
ifOSCode uint16 = 0x000c
3434
epbBlockType uint32 = 0x00000006
35-
interfaceId uint32 = 0x00000000 // only support one IDB
35+
interfaceID uint32 = 0x00000000 // only support one IDB
3636
)
3737

3838
var (
@@ -223,7 +223,7 @@ func (pw *Writer) writeIdbOptions(in *net.Interface, expr string) ([]byte, error
223223
binary.Write(buf, nativeEndian, in.HardwareAddr)
224224
}
225225
buf.Write(bytes.Repeat(zero, 2))
226-
binary.Write(buf, nativeEndian, ifTsResCode)
226+
binary.Write(buf, nativeEndian, ifTSResCode)
227227
binary.Write(buf, nativeEndian, uint16(1))
228228
binary.Write(buf, nativeEndian, timeRes)
229229
buf.Write(bytes.Repeat(zero, 3))
@@ -248,7 +248,7 @@ func (pw *Writer) WritePacket(timestamp time.Time, data []byte) error {
248248
blockLen := 4 + 4 + 4 + 4 + 4 + 4 + 4 + packetLen + 4
249249
binary.Write(pw.w, nativeEndian, epbBlockType)
250250
binary.Write(pw.w, nativeEndian, uint32(blockLen))
251-
binary.Write(pw.w, nativeEndian, interfaceId)
251+
binary.Write(pw.w, nativeEndian, interfaceID)
252252
msecs := uint64(timestamp.UnixMilli())
253253
binary.Write(pw.w, nativeEndian, uint32(msecs>>32))
254254
binary.Write(pw.w, nativeEndian, uint32(msecs&(1<<32-1)))

mshark.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package mshark is a simple packet capture tool
12
package mshark
23

34
import (
@@ -220,10 +221,7 @@ func OpenLive(conf *Config, pw ...PacketWriter) error {
220221
}()
221222

222223
// number of packets
223-
count := conf.PacketCount
224-
if count < 0 {
225-
count = 0
226-
}
224+
count := max(0, conf.PacketCount)
227225
infinity := count == 0
228226

229227
b := make([]byte, conf.Snaplen)

native/native.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// Package native determines host machine endianness
12
package native
23

34
import (

0 commit comments

Comments
 (0)