Skip to content

Commit 12165c6

Browse files
fixed tests, added marshalbinary to ethernet ans arp, fixed graceful shutdown, small improvements
1 parent 5245b66 commit 12165c6

File tree

10 files changed

+170
-148
lines changed

10 files changed

+170
-148
lines changed

layers/arp.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func (ao *ARPOperation) String() string {
2525
return fmt.Sprintf("%s (%d)", ao.Desc, ao.Val)
2626
}
2727

28-
// The Address Resolution Protocol (ARP) is a communication protocol
28+
// ARPPacket represents The Address Resolution Protocol (ARP) that is a communication protocol
2929
// used for discovering the link layer address, such as a MAC address,
3030
// associated with a given internet layer address, typically an IPv4 address.
3131
// Defined in RFC 826.
@@ -47,7 +47,7 @@ type ARPPacket struct {
4747
TargetIP netip.Addr // Internetwork address of the intended receiver.
4848
}
4949

50-
func New(
50+
func NewARPPacket(
5151
op Operation,
5252
senderMAC net.HardwareAddr,
5353
senderIP netip.Addr,
@@ -106,7 +106,7 @@ func (ap *ARPPacket) Summary() string {
106106
case OperationRequest:
107107
message = fmt.Sprintf("ARP Packet: (%s) Who has %s? Tell %s", ap.Op.Desc, ap.TargetIP, ap.SenderIP)
108108
case OperationReply:
109-
message = fmt.Sprintf("ARP Packet: (%s) %s at %s", ap.Op.Desc, ap.SenderIP, ap.SenderMAC)
109+
message = fmt.Sprintf("ARP Packet: (%s) %s is at %s", ap.Op.Desc, ap.SenderIP, ap.SenderMAC)
110110
default:
111111
message = fmt.Sprintf("ARP Packet: (%s)", ap.Op.Desc)
112112
}
@@ -115,23 +115,24 @@ func (ap *ARPPacket) Summary() string {
115115

116116
// MarshalBinary implements encoding.BinaryMarshaler interface
117117
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))
118+
b := make([]byte, 2+2+1+1+2+(ap.Plen*2)+(ap.Hlen*2))
119+
binary.BigEndian.PutUint16(b[0:2], ap.HardwareType)
120+
binary.BigEndian.PutUint16(b[2:4], ap.ProtocolType)
121+
b[4] = ap.Hlen
122+
b[5] = ap.Plen
123+
binary.BigEndian.PutUint16(b[6:8], uint16(ap.Op.Val))
124124
hoffset := 8 + ap.Hlen
125125
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
126+
copy(b[8:hoffset], ap.SenderMAC)
127+
copy(b[hoffset:poffset], ap.SenderIP.AsSlice())
128+
copy(b[poffset:poffset+ap.Hlen], ap.TargetMAC)
129+
copy(b[poffset+ap.Hlen:poffset+ap.Hlen+ap.Plen], ap.TargetIP.AsSlice())
130+
return b, nil
131131
}
132132

133-
func (ap *ARPPacket) ToBytes() ([]byte, error) {
134-
return ap.MarshalBinary()
133+
func (ap *ARPPacket) ToBytes() []byte {
134+
b, _ := ap.MarshalBinary()
135+
return b
135136
}
136137

137138
// UnmarshalBinary implements encoding.BinaryUnmarshaler interface

layers/arp_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ func TestParseARP(t *testing.T) {
6060
ProtocolTypeDesc: "IPv4",
6161
Hlen: 0x06,
6262
Plen: 0x04,
63-
Op: 0x0001,
64-
OpDesc: "request",
63+
Op: &ARPOperation{Val: 1, Desc: "request"},
6564
SenderMAC: net.HardwareAddr{0x7b, 0x13, 0x0b, 0x87, 0xea, 0x51},
6665
SenderIP: netip.AddrFrom4([4]byte{0x7F, 0x00, 0x00, 0x01}),
6766
TargetMAC: net.HardwareAddr{0x43, 0x40, 0x8d, 0x28, 0xca, 0x0b},

layers/ethernet.go

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,60 +9,111 @@ import (
99

1010
const headerSizeEthernet = 14
1111

12+
type EtherType uint16
13+
14+
const (
15+
EtherTypeIPv4 EtherType = 0x0800
16+
EtherTypeARP EtherType = 0x0806
17+
EtherTypeIPv6 EtherType = 0x86dd
18+
)
19+
20+
type EthernetType struct {
21+
Val EtherType
22+
Desc string // Protocol description
23+
}
24+
25+
func (et *EthernetType) String() string {
26+
return fmt.Sprintf("%s (%#04x)", et.Desc, et.Val)
27+
}
28+
29+
// EthernetFrame represents Ethernet Frame
1230
// An Ethernet frame is a data link layer protocol data unit.
1331
type EthernetFrame struct {
14-
DstMAC net.HardwareAddr // MAC address of the destination device.
15-
SrcMAC net.HardwareAddr // MAC address of the source device.
16-
EtherType uint16 // The protocol of the upper layer.
17-
EtherTypeDesc string // Protocol description
18-
payload []byte
32+
DstMAC net.HardwareAddr // MAC address of the destination device.
33+
SrcMAC net.HardwareAddr // MAC address of the source device.
34+
EtherType *EthernetType // The protocol of the upper layer.
35+
Payload []byte
36+
}
37+
38+
func NewEthernetFrame(dstMAC, srcMAC net.HardwareAddr, et EtherType, payload []byte) (*EthernetFrame, error) {
39+
if len(dstMAC) != 6 || len(srcMAC) != 6 {
40+
return nil, fmt.Errorf("malformed hardware address")
41+
}
42+
return &EthernetFrame{
43+
DstMAC: dstMAC,
44+
SrcMAC: srcMAC,
45+
EtherType: &EthernetType{Val: et, Desc: ethertypedesc(et)},
46+
Payload: payload,
47+
}, nil
1948
}
2049

2150
func (ef *EthernetFrame) String() string {
2251
return fmt.Sprintf(`%s
2352
- DstMAC: %s
2453
- SrcMAC: %s
25-
- EtherType: %s (%#04x)
26-
- Payload: %d bytes
54+
- EtherType: %s
55+
- Payload: %d bytes
2756
%s`,
2857
ef.Summary(),
2958
ef.DstMAC,
3059
ef.SrcMAC,
31-
ef.EtherTypeDesc,
3260
ef.EtherType,
33-
len(ef.payload),
34-
hex.Dump(ef.payload))
61+
len(ef.Payload),
62+
hex.Dump(ef.ToBytes()))
3563
}
3664

3765
func (ef *EthernetFrame) Summary() string {
3866
return fmt.Sprintf("Ethernet Frame: Src MAC: %s -> Dst MAC: %s", ef.SrcMAC, ef.DstMAC)
3967
}
4068

41-
// Parse parses the given byte data into an Ethernet frame.
42-
func (ef *EthernetFrame) Parse(data []byte) error {
69+
func (ef *EthernetFrame) MarshalBinary() ([]byte, error) {
70+
b := make([]byte, 6+6+2+len(ef.Payload))
71+
copy(b[0:6], ef.DstMAC)
72+
copy(b[6:12], ef.SrcMAC)
73+
binary.BigEndian.PutUint16(b[12:14], uint16(ef.EtherType.Val))
74+
copy(b[14:], ef.Payload)
75+
return b, nil
76+
}
77+
78+
func (ef *EthernetFrame) ToBytes() []byte {
79+
b, _ := ef.MarshalBinary()
80+
return b
81+
}
82+
83+
func (ef *EthernetFrame) UnmarshalBinary(data []byte) error {
4384
if len(data) < headerSizeEthernet {
4485
return fmt.Errorf("did not read a complete Ethernet frame, only %d bytes read", len(data))
4586
}
4687
ef.DstMAC = net.HardwareAddr(data[0:6])
4788
ef.SrcMAC = net.HardwareAddr(data[6:12])
48-
ef.EtherType = binary.BigEndian.Uint16(data[12:14])
49-
ef.payload = data[headerSizeEthernet:]
50-
ef.EtherTypeDesc, _ = ef.NextLayer()
89+
et := EtherType(binary.BigEndian.Uint16(data[12:14]))
90+
etdesc := ethertypedesc(et)
91+
ef.EtherType = &EthernetType{Val: et, Desc: etdesc}
92+
ef.Payload = data[headerSizeEthernet:]
5193
return nil
5294
}
5395

96+
// Parse parses the given byte data into an Ethernet frame.
97+
func (ef *EthernetFrame) Parse(data []byte) error {
98+
return ef.UnmarshalBinary(data)
99+
}
100+
54101
// NextLayer returns the name and payload of the next layer protocol based on the EtherType field of the EthernetFrame.
55102
func (ef *EthernetFrame) NextLayer() (string, []byte) {
56-
var layer string
57-
switch ef.EtherType {
58-
case 0x0800:
59-
layer = "IPv4"
60-
case 0x0806:
61-
layer = "ARP"
62-
case 0x86dd:
63-
layer = "IPv6"
103+
return ef.EtherType.Desc, ef.Payload
104+
}
105+
106+
func ethertypedesc(et EtherType) string {
107+
var etdesc string
108+
switch et {
109+
case EtherTypeIPv4:
110+
etdesc = "IPv4"
111+
case EtherTypeARP:
112+
etdesc = "ARP"
113+
case EtherTypeIPv6:
114+
etdesc = "IPv6"
64115
default:
65-
layer = ""
116+
etdesc = ""
66117
}
67-
return layer, ef.payload
118+
return etdesc
68119
}

layers/ethernet_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ func BenchmarkParseEthernet(b *testing.B) {
2222

2323
func TestParseEthernet(t *testing.T) {
2424
expected := &EthernetFrame{
25-
DstMAC: net.HardwareAddr{0x7b, 0x13, 0x0b, 0x87, 0xea, 0x51},
26-
SrcMAC: net.HardwareAddr{0x43, 0x40, 0x8d, 0x28, 0xca, 0x0b},
27-
EtherType: 0x0800,
28-
EtherTypeDesc: "IPv4",
29-
payload: []byte{},
25+
DstMAC: net.HardwareAddr{0x7b, 0x13, 0x0b, 0x87, 0xea, 0x51},
26+
SrcMAC: net.HardwareAddr{0x43, 0x40, 0x8d, 0x28, 0xca, 0x0b},
27+
EtherType: &EthernetType{Val: 0x0800, Desc: "IPv4"},
28+
Payload: []byte{},
3029
}
3130
eth := &EthernetFrame{}
3231
packet, close := testPacket(t, "ethernet")

layers/http.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,23 @@ func (h *HTTPMessage) String() string {
4242
func (h *HTTPMessage) Summary() string {
4343
m := fmt.Sprintf("HTTP Message: %s", contdata)
4444
if h.Request != nil {
45-
m = fmt.Sprintf("HTTP Request: %s %s%s%s %s Content-Length: %d",
46-
h.Request.Method, h.Request.Host, h.Request.URL.Path, h.Request.URL.RawQuery, h.Request.Proto, h.Request.ContentLength)
45+
m = fmt.Sprintf(
46+
"HTTP Request: %s %s%s%s %s Content-Length: %d",
47+
h.Request.Method,
48+
h.Request.Host,
49+
h.Request.URL.Path,
50+
h.Request.URL.RawQuery,
51+
h.Request.Proto,
52+
h.Request.ContentLength,
53+
)
4754
} else if h.Response != nil {
4855
m = fmt.Sprintf("HTTP Response: %s %s Content-Length: %d",
4956
h.Response.Proto, h.Response.Status, h.Response.ContentLength)
5057
}
51-
return fmt.Sprintf("%s", m)
58+
return m
5259
}
5360

5461
func (h *HTTPMessage) Parse(data []byte) error {
55-
5662
if !bytes.Contains(data, protohttp10) && !bytes.Contains(data, protohttp11) {
5763
h.Request = nil
5864
h.Response = nil
@@ -119,7 +125,8 @@ func (h *HTTPMessage) MarshalJSON() ([]byte, error) {
119125
Proto: h.Response.Proto,
120126
Status: h.Response.Status,
121127
ContentLength: int(h.Response.ContentLength),
122-
Header: h.Response.Header}})
128+
Header: h.Response.Header,
129+
}})
123130
}
124131
return nil, fmt.Errorf("both request and response are empty")
125132
}

layers/http_test.go

Lines changed: 0 additions & 57 deletions
This file was deleted.

layers/layers.go

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

34
import (

0 commit comments

Comments
 (0)