Files
pcap-web-tools/internal/inet/locate.go
T
2026-10-05 20:07:31 +02:00

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
}