59 lines
1.4 KiB
Go
59 lines
1.4 KiB
Go
package inet
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
"pcap-web-tools/internal/pcap"
|
|
)
|
|
|
|
const (
|
|
etherTypeIPv4 = 0x0800
|
|
etherTypeIPv6 = 0x86dd
|
|
etherTypeVLAN = 0x8100
|
|
etherTypeQinQ = 0x88a8
|
|
)
|
|
|
|
// FindIP returns the offset of the IP header within a link-layer frame of the
|
|
// given pcap link type, by parsing the link-layer header.
|
|
func FindIP(frame []byte, linkType uint32) (int, error) {
|
|
switch linkType {
|
|
case pcap.LinkTypeRaw:
|
|
return 0, nil
|
|
|
|
case pcap.LinkTypeEthernet:
|
|
off := 12
|
|
for {
|
|
if off+2 > len(frame) {
|
|
return 0, fmt.Errorf("Ethernet header truncated")
|
|
}
|
|
et := binary.BigEndian.Uint16(frame[off:])
|
|
if et == etherTypeVLAN || et == etherTypeQinQ {
|
|
off += 4
|
|
continue
|
|
}
|
|
return etherIP(et, off+2)
|
|
}
|
|
|
|
case pcap.LinkTypeLinuxSLL:
|
|
if len(frame) < 16 {
|
|
return 0, fmt.Errorf("Linux cooked (SLL) header truncated")
|
|
}
|
|
return etherIP(binary.BigEndian.Uint16(frame[14:]), 16)
|
|
|
|
case pcap.LinkTypeLinuxSLL2:
|
|
if len(frame) < 20 {
|
|
return 0, fmt.Errorf("Linux cooked v2 (SLL2) header truncated")
|
|
}
|
|
return etherIP(binary.BigEndian.Uint16(frame[0:]), 20)
|
|
}
|
|
return 0, fmt.Errorf("cannot locate the IP header for link type %s", pcap.LinkTypeName(linkType))
|
|
}
|
|
|
|
func etherIP(etherType uint16, off int) (int, error) {
|
|
if etherType != etherTypeIPv4 && etherType != etherTypeIPv6 {
|
|
return 0, fmt.Errorf("link-layer payload is not IP (EtherType 0x%04x)", etherType)
|
|
}
|
|
return off, nil
|
|
}
|