|
| 1 | +package protocols |
| 2 | + |
| 3 | +import ( |
| 4 | + "encoding/binary" |
| 5 | + "errors" |
| 6 | + "fmt" |
| 7 | + "net" |
| 8 | +) |
| 9 | + |
| 10 | +var HardwareTypeValues = map[uint16]string{ |
| 11 | + 1: "Ethernet", |
| 12 | + 6: "IEE 802 (Token Ring)", |
| 13 | + 11: "ATM", |
| 14 | + 12: "HDLC", |
| 15 | +} |
| 16 | + |
| 17 | +type ARPPacket struct { |
| 18 | + EthFrame EthernetFrame |
| 19 | + HardwareType uint16 |
| 20 | + ProtocolType uint16 |
| 21 | + HardwareAddrLen uint8 |
| 22 | + ProtocolAddrLen uint8 |
| 23 | + Operation uint16 |
| 24 | + SenderHWAddr net.HardwareAddr |
| 25 | + SenderProtoAddr net.IP // only IPv4 - IPv6 should rely on NDP |
| 26 | + TargetHWAddr net.HardwareAddr |
| 27 | + TargetProtoAddr net.IP // only IPv4 - IPv6 should rely on NDP |
| 28 | +} |
| 29 | + |
| 30 | +var errInvalidARPPacket = errors.New("ARP packet must be 28 bytes") |
| 31 | + |
| 32 | +// ARPPacketFromBytes parses an array of bytes to the corresponding ARP packet and returns a pointer to it. |
| 33 | +// Returns an error if the number of bytes is less than 28 |
| 34 | +func ARPPacketFromBytes(raw []byte) (*ARPPacket, error) { |
| 35 | + frame, err := EthFrameFromBytes(raw) |
| 36 | + if err != nil { |
| 37 | + return nil, err |
| 38 | + } |
| 39 | + |
| 40 | + if len(frame.Payload) < 28 { |
| 41 | + return nil, errInvalidARPPacket |
| 42 | + } |
| 43 | + payload := frame.Payload |
| 44 | + |
| 45 | + return &ARPPacket{ |
| 46 | + EthFrame: *frame, |
| 47 | + HardwareType: binary.BigEndian.Uint16(payload[0:2]), |
| 48 | + ProtocolType: binary.BigEndian.Uint16(payload[2:4]), |
| 49 | + HardwareAddrLen: payload[4], |
| 50 | + ProtocolAddrLen: payload[5], |
| 51 | + Operation: binary.BigEndian.Uint16(payload[6:8]), |
| 52 | + SenderHWAddr: payload[8:14], |
| 53 | + SenderProtoAddr: payload[14:18], |
| 54 | + TargetHWAddr: payload[18:24], |
| 55 | + TargetProtoAddr: payload[24:28], |
| 56 | + }, nil |
| 57 | +} |
| 58 | + |
| 59 | +func (p ARPPacket) Destination() string { |
| 60 | + return fmt.Sprintf("%s|%s", p.TargetHWAddr.String(), p.TargetProtoAddr.String()) |
| 61 | +} |
| 62 | + |
| 63 | +func (p ARPPacket) Source() string { |
| 64 | + return fmt.Sprintf("%s|%s", p.SenderHWAddr.String(), p.SenderProtoAddr.String()) |
| 65 | +} |
| 66 | + |
| 67 | +func (p ARPPacket) Info() string { |
| 68 | + return fmt.Sprintf("%s ARP packet from %s to %s", HardwareTypeValues[p.HardwareType], p.Source(), p.Destination()) |
| 69 | +} |
0 commit comments