mirror of
https://github.com/soypat/lneto.git
synced 2026-07-26 10:38:47 +00:00
remove legacy remnants and move ip,udp,ethernet logic into subpackages
This commit is contained in:
+7
-6
@@ -7,6 +7,7 @@ import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
)
|
||||
|
||||
@@ -49,16 +50,16 @@ func (afrm Frame) SetHardware(Type uint16, length uint8) {
|
||||
afrm.buf[4] = length
|
||||
}
|
||||
|
||||
// Protocol returns the internet protocol type and length. See [lneto2.EtherType].
|
||||
func (afrm Frame) Protocol() (Type lneto2.EtherType, length uint8) {
|
||||
Type = lneto2.EtherType(binary.BigEndian.Uint16(afrm.buf[2:4]))
|
||||
// Protocol returns the internet protocol type and length. See [ethernet.Type].
|
||||
func (afrm Frame) Protocol() (Type ethernet.Type, length uint8) {
|
||||
Type = ethernet.Type(binary.BigEndian.Uint16(afrm.buf[2:4]))
|
||||
return Type, afrm.protolen()
|
||||
}
|
||||
|
||||
func (afrm Frame) protolen() uint8 { return afrm.buf[5] }
|
||||
|
||||
// SetProtocol sets the protocol type and length fields of the ARP frame. See [Frame.Protocol] and [lneto2.EtherType].
|
||||
func (afrm Frame) SetProtocol(Type lneto2.EtherType, length uint8) {
|
||||
// SetProtocol sets the protocol type and length fields of the ARP frame. See [Frame.Protocol] and [ethernet.Type].
|
||||
func (afrm Frame) SetProtocol(Type ethernet.Type, length uint8) {
|
||||
binary.BigEndian.PutUint16(afrm.buf[2:4], uint16(Type))
|
||||
afrm.buf[5] = length
|
||||
}
|
||||
@@ -150,7 +151,7 @@ func (afrm Frame) String() string {
|
||||
sndhw, sndpt := afrm.Sender()
|
||||
tgthw, tgtpt := afrm.Target()
|
||||
var sndstr, tgtstr string
|
||||
if ptt == lneto2.EtherTypeIPv4 || ptt == lneto2.EtherTypeIPv6 {
|
||||
if ptt == ethernet.TypeIPv4 || ptt == ethernet.TypeIPv6 {
|
||||
sender, _ := netip.AddrFromSlice(sndpt)
|
||||
target, _ := netip.AddrFromSlice(tgtpt)
|
||||
sndstr = sender.String()
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
)
|
||||
|
||||
@@ -11,7 +12,7 @@ type Handler struct {
|
||||
ourHWAddr []byte
|
||||
ourProtoAddr []byte
|
||||
htype uint16
|
||||
protoType lneto2.EtherType
|
||||
protoType ethernet.Type
|
||||
pending [][sizeHeaderv6]byte
|
||||
queries []queryResult
|
||||
}
|
||||
@@ -22,7 +23,7 @@ type HandlerConfig struct {
|
||||
MaxQueries int
|
||||
MaxPending int
|
||||
HardwareType uint16
|
||||
ProtocolType lneto2.EtherType
|
||||
ProtocolType ethernet.Type
|
||||
}
|
||||
|
||||
func NewHandler(cfg HandlerConfig) (*Handler, error) {
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
)
|
||||
|
||||
func TestHandler(t *testing.T) {
|
||||
@@ -15,7 +15,7 @@ func TestHandler(t *testing.T) {
|
||||
MaxQueries: 1,
|
||||
MaxPending: 1,
|
||||
HardwareType: 1,
|
||||
ProtocolType: lneto2.EtherTypeIPv4,
|
||||
ProtocolType: ethernet.TypeIPv4,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -26,7 +26,7 @@ func TestHandler(t *testing.T) {
|
||||
MaxQueries: 1,
|
||||
MaxPending: 1,
|
||||
HardwareType: 1,
|
||||
ProtocolType: lneto2.EtherTypeIPv4,
|
||||
ProtocolType: ethernet.TypeIPv4,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package lneto
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// CRC791 function as defined by RFC 791. The Checksum field for TCP+IP
|
||||
// is the 16-bit ones' complement of the ones' complement sum of
|
||||
// all 16-bit words in the header. In case of uneven number of octet the
|
||||
// last word is LSB padded with zeros.
|
||||
//
|
||||
// The zero value of CRC791 is ready to use.
|
||||
type CRC791 struct {
|
||||
sum uint32
|
||||
excedent uint8
|
||||
needPad bool
|
||||
}
|
||||
|
||||
// Write adds the bytes in p to the running checksum.
|
||||
func (c *CRC791) Write(buff []byte) (n int, err error) {
|
||||
if len(buff) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if c.needPad {
|
||||
c.sum += uint32(c.excedent)<<8 + uint32(buff[0])
|
||||
buff = buff[1:]
|
||||
c.excedent = 0
|
||||
c.needPad = false
|
||||
if len(buff) == 0 {
|
||||
return 1, nil
|
||||
}
|
||||
}
|
||||
count := len(buff)
|
||||
for count > 1 {
|
||||
c.sum += uint32(binary.BigEndian.Uint16(buff[len(buff)-count:]))
|
||||
count -= 2
|
||||
}
|
||||
if count != 0 {
|
||||
c.excedent = buff[len(buff)-1]
|
||||
c.needPad = true
|
||||
}
|
||||
return len(buff), nil
|
||||
}
|
||||
|
||||
// AddUint32 adds a 32 bit value to the running checksum interpreted as BigEndian (network order).
|
||||
func (c *CRC791) AddUint32(value uint32) {
|
||||
c.AddUint16(uint16(value >> 16))
|
||||
c.AddUint16(uint16(value))
|
||||
}
|
||||
|
||||
// Add16 adds a 16 bit value to the running checksum interpreted as BigEndian (network order).
|
||||
func (c *CRC791) AddUint16(value uint16) {
|
||||
if c.needPad {
|
||||
c.sum += uint32(c.excedent)<<8 | uint32(value>>8)
|
||||
c.excedent = byte(value)
|
||||
} else {
|
||||
c.sum += uint32(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Add16 adds value to the running checksum interpreted as BigEndian (network order).
|
||||
func (c *CRC791) AddUint8(value uint8) {
|
||||
if c.needPad {
|
||||
c.sum += uint32(c.excedent)<<8 | uint32(value)
|
||||
} else {
|
||||
c.excedent = value
|
||||
}
|
||||
c.needPad = !c.needPad
|
||||
}
|
||||
|
||||
// Sum16 calculates the checksum with the data written to c thus far.
|
||||
func (c *CRC791) Sum16() uint16 {
|
||||
sum := c.sum
|
||||
if c.needPad {
|
||||
sum += uint32(c.excedent) << 8
|
||||
}
|
||||
for sum>>16 != 0 {
|
||||
sum = (sum & 0xffff) + (sum >> 16)
|
||||
}
|
||||
return uint16(^sum)
|
||||
}
|
||||
|
||||
// Reset zeros out the CRC791, resetting it to the initial state.
|
||||
func (c *CRC791) Reset() { *c = CRC791{} }
|
||||
-268
@@ -1,268 +0,0 @@
|
||||
package lneto
|
||||
|
||||
//go:generate stringer -type=EtherType,IPProto,ARPOp -linecomment -output stringers.go .
|
||||
|
||||
type EtherType uint16
|
||||
|
||||
// IsSize returns true if the EtherType is actually the size of the payload
|
||||
// and should NOT be interpreted as an EtherType.
|
||||
func (et EtherType) IsSize() bool { return et <= 1500 }
|
||||
|
||||
// Ethernet type flags
|
||||
const (
|
||||
EtherTypeIPv4 EtherType = 0x0800 // IPv4
|
||||
EtherTypeARP EtherType = 0x0806 // ARP
|
||||
EtherTypeWakeOnLAN EtherType = 0x0842 // wake on LAN
|
||||
EtherTypeTRILL EtherType = 0x22F3 // TRILL
|
||||
EtherTypeDECnetPhase4 EtherType = 0x6003 // DECnetPhase4
|
||||
EtherTypeRARP EtherType = 0x8035 // RARP
|
||||
EtherTypeAppleTalk EtherType = 0x809B // AppleTalk
|
||||
EtherTypeAARP EtherType = 0x80F3 // AARP
|
||||
EtherTypeIPX1 EtherType = 0x8137 // IPx1
|
||||
EtherTypeIPX2 EtherType = 0x8138 // IPx2
|
||||
EtherTypeQNXQnet EtherType = 0x8204 // QNXQnet
|
||||
EtherTypeIPv6 EtherType = 0x86DD // IPv6
|
||||
EtherTypeEthernetFlowControl EtherType = 0x8808 // EthernetFlowCtl
|
||||
EtherTypeIEEE802_3 EtherType = 0x8809 // IEEE802.3
|
||||
EtherTypeCobraNet EtherType = 0x8819 // CobraNet
|
||||
EtherTypeMPLSUnicast EtherType = 0x8847 // MPLS Unicast
|
||||
EtherTypeMPLSMulticast EtherType = 0x8848 // MPLS Multicast
|
||||
EtherTypePPPoEDiscovery EtherType = 0x8863 // PPPoE discovery
|
||||
EtherTypePPPoESession EtherType = 0x8864 // PPPoE session
|
||||
EtherTypeJumboFrames EtherType = 0x8870 // jumbo frames
|
||||
EtherTypeHomePlug1_0MME EtherType = 0x887B // home plug 1 0mme
|
||||
EtherTypeIEEE802_1X EtherType = 0x888E // IEEE 802.1x
|
||||
EtherTypePROFINET EtherType = 0x8892 // profinet
|
||||
EtherTypeHyperSCSI EtherType = 0x889A // hyper SCSI
|
||||
EtherTypeAoE EtherType = 0x88A2 // AoE
|
||||
EtherTypeEtherCAT EtherType = 0x88A4 // EtherCAT
|
||||
EtherTypeEthernetPowerlink EtherType = 0x88AB // Ethernet powerlink
|
||||
EtherTypeLLDP EtherType = 0x88CC // LLDP
|
||||
EtherTypeSERCOS3 EtherType = 0x88CD // SERCOS3
|
||||
EtherTypeHomePlugAVMME EtherType = 0x88E1 // home plug AVMME
|
||||
EtherTypeMRP EtherType = 0x88E3 // MRP
|
||||
EtherTypeIEEE802_1AE EtherType = 0x88E5 // IEEE 802.1ae
|
||||
EtherTypeIEEE1588 EtherType = 0x88F7 // IEEE 1588
|
||||
EtherTypeIEEE802_1ag EtherType = 0x8902 // IEEE 802.1ag
|
||||
EtherTypeFCoE EtherType = 0x8906 // FCoE
|
||||
EtherTypeFCoEInit EtherType = 0x8914 // FCoE init
|
||||
EtherTypeRoCE EtherType = 0x8915 // RoCE
|
||||
EtherTypeCTP EtherType = 0x9000 // CTP
|
||||
EtherTypeVeritasLLT EtherType = 0xCAFE // Veritas LLT
|
||||
EtherTypeVLAN EtherType = 0x8100 // VLAN
|
||||
EtherTypeServiceVLAN EtherType = 0x88a8 // service VLAN
|
||||
// minEthPayload is the minimum payload size for an Ethernet frame, assuming
|
||||
// that no 802.1Q VLAN tags are present.
|
||||
minEthPayload = 46
|
||||
)
|
||||
|
||||
// VLANTag holds priority (PCP) Drop indicator (DEI) and VLAN ID bits of the VLAN tag field.
|
||||
type VLANTag uint16
|
||||
|
||||
// DropEligibleIndicator returns true if the DEI bit is set.
|
||||
// DEI may be used separately or in conjunction with PCP to indicate frames eligible to be dropped in the presence of congestion.
|
||||
func (vt VLANTag) DropEligibleIndicator() bool { return vt&(1<<3) != 0 }
|
||||
|
||||
// PriorityCodePoint is 3-bit field which refers to the IEEE 802.1p class of service (CoS) and maps to the frame priority level. Different PCP values can be used to prioritize different classes of traffic
|
||||
func (vt VLANTag) PriorityCodePoint() uint8 { return uint8(vt & 0b111) }
|
||||
|
||||
// VLANIdentifier 12 bit field which specifies which VLAN the frame belongs to. Values of 0 and 4095 are reserved.
|
||||
func (vt VLANTag) VLANIdentifier() uint16 { return uint16(vt) >> 4 }
|
||||
|
||||
// IPToS represents the Traffic Class (a.k.a Type of Service).
|
||||
type IPToS uint8
|
||||
|
||||
// DS returns the top 6 bits of the IPv4 ToS holding the Differentiated Services field
|
||||
// which is used to classify packets.
|
||||
func (tos IPToS) DS() uint8 { return uint8(tos) >> 2 }
|
||||
|
||||
// ECN is the Explicit Congestion Notification which provides congestion control and non-congestion control traffic.
|
||||
func (tos IPToS) ECN() uint8 { return uint8(tos & 0b11) }
|
||||
|
||||
// IPv4Flags holds fragmentation field data of an IPv4 header.
|
||||
type IPv4Flags uint16
|
||||
|
||||
// IsEvil returns true if evil bit set as per [RFC3514].
|
||||
//
|
||||
// [RFC3514]: https://datatracker.ietf.org/doc/html/rfc3514
|
||||
func (f IPv4Flags) IsEvil() bool { return f&2000 != 0 }
|
||||
|
||||
// DontFragment specifies whether the datagram can not be fragmented.
|
||||
// This can be used when sending packets to a host that does not have resources to perform reassembly of fragments.
|
||||
// If the DontFragment(DF) flag is set, and fragmentation is required to route the packet, then the packet is dropped.
|
||||
func (f IPv4Flags) DontFragment() bool { return f&0x4000 != 0 }
|
||||
|
||||
// MoreFragments is cleared for unfragmented packets.
|
||||
// For fragmented packets, all fragments except the last have the MF flag set.
|
||||
// The last fragment has a non-zero Fragment Offset field, so it can still be differentiated from an unfragmented packet.
|
||||
func (f IPv4Flags) MoreFragments() bool { return f&0x8000 != 0 }
|
||||
|
||||
// FragmentOffset specifies the offset of a particular fragment relative to the beginning of the original unfragmented IP datagram.
|
||||
// Fragments are specified in units of 8 bytes, which is why fragment lengths are always a multiple of 8; except the last, which may be smaller.
|
||||
// The fragmentation offset value for the first fragment is always 0.
|
||||
func (f IPv4Flags) FragmentOffset() uint16 { return uint16(f) & 0x1fff }
|
||||
|
||||
const (
|
||||
sizeHeaderIPv4 = 20
|
||||
sizeHeaderTCP = 20
|
||||
sizeHeaderEthNoVLAN = 14
|
||||
sizeHeaderUDP = 8
|
||||
sizeHeaderARPv4 = 28
|
||||
sizeHeaderIPv6 = 40
|
||||
)
|
||||
|
||||
// IPProto represents the IP protocol number.
|
||||
type IPProto uint8
|
||||
|
||||
// IP protocol numbers.
|
||||
const (
|
||||
IPProtoHopByHop IPProto = 0 // IPv6 Hop-by-Hop Option [RFC8200]
|
||||
IPProtoICMP IPProto = 1 // Internet Control Message [RFC792]
|
||||
IPProtoIGMP IPProto = 2 // Internet Group Management [RFC1112]
|
||||
IPProtoGGP IPProto = 3 // Gateway-to-Gateway [RFC823]
|
||||
IPProtoIPv4 IPProto = 4 // IPv4 encapsulation [RFC2003]
|
||||
IPProtoST IPProto = 5 // Stream [RFC1190, RFC1819]
|
||||
IPProtoTCP IPProto = 6 // Transmission Control [RFC9293]
|
||||
IPProtoCBT IPProto = 7 // CBT [Ballardie]
|
||||
IPProtoEGP IPProto = 8 // Exterior Gateway Protocol [RFC888]
|
||||
IPProtoIGP IPProto = 9 // any private interior gateway (used by Cisco for their IGRP)
|
||||
IPProtoBBNRCCMON IPProto = 10 // BBN RCC Monitoring
|
||||
IPProtoNVP IPProto = 11 // Network Voice Protocol [RFC741]
|
||||
IPProtoPUP IPProto = 12 // PUP
|
||||
IPProtoARGUS IPProto = 13 // ARGUS
|
||||
IPProtoEMCON IPProto = 14 // EMCON
|
||||
IPProtoXNET IPProto = 15 // Cross Net Debugger
|
||||
IPProtoCHAOS IPProto = 16 // Chaos
|
||||
IPProtoUDP IPProto = 17 // User Datagram [RFC768]
|
||||
IPProtoMUX IPProto = 18 // Multiplexing
|
||||
IPProtoDCNMEAS IPProto = 19 // DCN Measurement Subsystems
|
||||
IPProtoHMP IPProto = 20 // Host Monitoring [RFC869]
|
||||
IPProtoPRM IPProto = 21 // Packet Radio Measurement
|
||||
IPProtoXNSIDP IPProto = 22 // XEROX NS IDP
|
||||
IPProtoTRUNK1 IPProto = 23 // Trunk-1
|
||||
IPProtoTRUNK2 IPProto = 24 // Trunk-2
|
||||
IPProtoLEAF1 IPProto = 25 // Leaf-1
|
||||
IPProtoLEAF2 IPProto = 26 // Leaf-2
|
||||
IPProtoRDP IPProto = 27 // Reliable Data Protocol [RFC908]
|
||||
IPProtoIRTP IPProto = 28 // Internet Reliable Transaction [RFC938]
|
||||
IPProtoISO_TP4 IPProto = 29 // ISO Transport Protocol Class 4 [RFC905]
|
||||
IPProtoNETBLT IPProto = 30 // Bulk Data Transfer Protocol [RFC998]
|
||||
IPProtoMFE_NSP IPProto = 31 // MFE Network Services Protocol
|
||||
IPProtoMERIT_INP IPProto = 32 // MERIT Internodal Protocol
|
||||
IPProtoDCCP IPProto = 33 // Datagram Congestion Control Protocol [RFC4340]
|
||||
IPProto3PC IPProto = 34 // Third Party Connect Protocol
|
||||
IPProtoIDPR IPProto = 35 // Inter-Domain Policy Routing Protocol
|
||||
IPProtoXTP IPProto = 36 // XTP
|
||||
IPProtoDDP IPProto = 37 // Datagram Delivery Protocol
|
||||
IPProtoIDPRCMTP IPProto = 38 // IDPR Control Message Transport Proto
|
||||
IPProtoTPPLUSPLUS IPProto = 39 // TP++ Transport Protocol
|
||||
IPProtoIL IPProto = 40 // IL Transport Protocol
|
||||
IPProtoIPv6 IPProto = 41 // IPv6 encapsulation [RFC2473]
|
||||
IPProtoSDRP IPProto = 42 // Source Demand Routing Protocol
|
||||
IPProtoIPv6Route IPProto = 43 // Routing Header for IPv6 [RFC8200]
|
||||
IPProtoIPv6Frag IPProto = 44 // Fragment Header for IPv6 [RFC8200]
|
||||
IPProtoIDRP IPProto = 45 // Inter-Domain Routing Protocol
|
||||
IPProtoRSVP IPProto = 46 // Reservation Protocol [RFC2205]
|
||||
IPProtoGRE IPProto = 47 // Generic Routing Encapsulation [RFC2784]
|
||||
IPProtoDSR IPProto = 48 // Dynamic Source Routing Protocol
|
||||
IPProtoBNA IPProto = 49 // BNA
|
||||
IPProtoESP IPProto = 50 // Encap Security Payload [RFC4303]
|
||||
IPProtoAH IPProto = 51 // Authentication Header [RFC4302]
|
||||
IPProtoINLSP IPProto = 52 // Integrated Net Layer Security TUBA
|
||||
IPProtoSWIPE IPProto = 53 // IP with Encryption
|
||||
IPProtoNARP IPProto = 54 // NBMA Address Resolution Protocol
|
||||
IPProtoMOBILE IPProto = 55 // IP Mobility
|
||||
IPProtoTLSP IPProto = 56 // Transport Layer Security Protocol using Kryptonet key management
|
||||
IPProtoSKIP IPProto = 57 // SKIP
|
||||
IPProtoIPv6ICMP IPProto = 58 // ICMP for IPv6 [RFC8200]
|
||||
IPProtoIPv6NoNxt IPProto = 59 // No Next Header for IPv6 [RFC8200]
|
||||
IPProtoIPv6Opts IPProto = 60 // Destination Options for IPv6 [RFC8200]
|
||||
IPProtoCFTP IPProto = 62 // CFTP
|
||||
IPProtoSATEXPAK IPProto = 64 // SATNET and Backroom EXPAK
|
||||
IPProtoKRYPTOLAN IPProto = 65 // Kryptolan
|
||||
IPProtoRVD IPProto = 66 // MIT Remote Virtual Disk Protocol
|
||||
IPProtoIPPC IPProto = 67 // Internet Pluribus Packet Core
|
||||
IPProtoSATMON IPProto = 69 // SATNET Monitoring
|
||||
IPProtoVISA IPProto = 70 // VISA Protocol
|
||||
IPProtoIPCV IPProto = 71 // Internet Packet Core Utility
|
||||
IPProtoCPNX IPProto = 72 // Computer Protocol Network Executive
|
||||
IPProtoCPHB IPProto = 73 // Computer Protocol Heart Beat
|
||||
IPProtoWSN IPProto = 74 // Wang Span Network
|
||||
IPProtoPVP IPProto = 75 // Packet Video Protocol
|
||||
IPProtoBRSATMON IPProto = 76 // Backroom SATNET Monitoring
|
||||
IPProtoSUNND IPProto = 77 // SUN ND PROTOCOL-Temporary
|
||||
IPProtoWBMON IPProto = 78 // WIDEBAND Monitoring
|
||||
IPProtoWBEXPAK IPProto = 79 // WIDEBAND EXPAK
|
||||
IPProtoISOIP IPProto = 80 // ISO Internet Protocol
|
||||
IPProtoVMTP IPProto = 81 // VMTP
|
||||
IPProtoSECUREVMTP IPProto = 82 // SECURE-VMTP
|
||||
IPProtoVINES IPProto = 83 // VINES
|
||||
IPProtoTTP IPProto = 84 // TTP
|
||||
IPProtoNSFNETIGP IPProto = 85 // NSFNET-IGP
|
||||
IPProtoDGP IPProto = 86 // Dissimilar Gateway Protocol
|
||||
IPProtoTCF IPProto = 87 // TCF
|
||||
IPProtoEIGRP IPProto = 88 // EIGRP
|
||||
IPProtoOSPFIGP IPProto = 89 // OSPFIGP
|
||||
IPProtoSpriteRPC IPProto = 90 // Sprite RPC Protocol
|
||||
IPProtoLARP IPProto = 91 // Locus Address Resolution Protocol
|
||||
IPProtoMTP IPProto = 92 // Multicast Transport Protocol
|
||||
IPProtoAX25 IPProto = 93 // AX.25 Frames
|
||||
IPProtoIPIP IPProto = 94 // IP-within-IP Encapsulation Protocol
|
||||
IPProtoMICP IPProto = 95 // Mobile Internetworking Control Pro.
|
||||
IPProtoSCCSP IPProto = 96 // Semaphore Communications Sec. Pro.
|
||||
IPProtoETHERIP IPProto = 97 // Ethernet-within-IP Encapsulation
|
||||
IPProtoENCAP IPProto = 98 // Encapsulation Header
|
||||
IPProtoGMTP IPProto = 100 // GMTP
|
||||
IPProtoIFMP IPProto = 101 // Ipsilon Flow Management Protocol
|
||||
IPProtoPNNI IPProto = 102 // PNNI over IP
|
||||
IPProtoPIM IPProto = 103 // Protocol Independent Multicast
|
||||
IPProtoARIS IPProto = 104 // ARIS
|
||||
IPProtoSCPS IPProto = 105 // SCPS
|
||||
IPProtoQNX IPProto = 106 // QNX
|
||||
IPProtoAN IPProto = 107 // Active Networks
|
||||
IPProtoIPComp IPProto = 108 // IP Payload Compression Protocol
|
||||
IPProtoSNP IPProto = 109 // Sitara Networks Protocol
|
||||
IPProtoCompaqPeer IPProto = 110 // Compaq Peer Protocol
|
||||
IPProtoIPXInIP IPProto = 111 // IPX in IP
|
||||
IPProtoVRRP IPProto = 112 // Virtual Router Redundancy Protocol
|
||||
IPProtoPGM IPProto = 113 // PGM Reliable Transport Protocol
|
||||
IPProtoL2TP IPProto = 115 // Layer Two Tunneling Protocol v3
|
||||
IPProtoDDX IPProto = 116 // D-II Data Exchange (DDX)
|
||||
IPProtoIATP IPProto = 117 // Interactive Agent Transfer Protocol
|
||||
IPProtoSTP IPProto = 118 // Schedule Transfer Protocol
|
||||
IPProtoSRP IPProto = 119 // SpectraLink Radio Protocol
|
||||
IPProtoUTI IPProto = 120 // UTI
|
||||
IPProtoSMP IPProto = 121 // Simple Message Protocol
|
||||
IPProtoSM IPProto = 122 // SM
|
||||
IPProtoPTP IPProto = 123 // Performance Transparency Protocol
|
||||
IPProtoISIS IPProto = 124 // ISIS over IPv4
|
||||
IPProtoFIRE IPProto = 125 // FIRE
|
||||
IPProtoCRTP IPProto = 126 // Combat Radio Transport Protocol
|
||||
IPProtoCRUDP IPProto = 127 // Combat Radio User Datagram
|
||||
IPProtoSSCOPMCE IPProto = 128 // SSCOPMCE
|
||||
IPProtoIPLT IPProto = 129 // IPLT
|
||||
IPProtoSPS IPProto = 130 // Secure Packet Shield
|
||||
IPProtoPIPE IPProto = 131 // Private IP Encapsulation within IP
|
||||
IPProtoSCTP IPProto = 132 // Stream Control Transmission Protocol
|
||||
IPProtoFC IPProto = 133 // Fibre Channel
|
||||
IPProtoRSVP_E2E_IGNORE IPProto = 134 // RSVP-E2E-IGNORE
|
||||
IPProtoMobilityHeader IPProto = 135 // Mobility Header
|
||||
IPProtoUDPLite IPProto = 136 // UDPLite
|
||||
IPProtoMPLSInIP IPProto = 137 // MPLS-in-IP
|
||||
IPProtoMANET IPProto = 138 // MANET Protocols
|
||||
IPProtoHIP IPProto = 139 // Host Identity Protocol
|
||||
IPProtoShim6 IPProto = 140 // Shim6 Protocol
|
||||
IPProtoWESP IPProto = 141 // Wrapped Encapsulating Security Payload
|
||||
IPProtoROHC IPProto = 142 // Robust Header Compression
|
||||
IPProtoEthernet IPProto = 143 // Ethernet
|
||||
IPProtoAGGFRAG IPProto = 144 // AGGFRAG Encapsulation payload for ESP
|
||||
IPProtoNSH IPProto = 145 // Network Service Header
|
||||
)
|
||||
|
||||
// ARPOp represents the type of ARP packet, either request or reply/response.
|
||||
type ARPOp uint8
|
||||
|
||||
const (
|
||||
ARPRequest ARPOp = 1 // request
|
||||
ARPReply ARPOp = 2 // reply
|
||||
)
|
||||
@@ -0,0 +1,74 @@
|
||||
package ethernet
|
||||
|
||||
const (
|
||||
sizeHeaderNoVLAN = 14
|
||||
)
|
||||
|
||||
//go:generate stringer -type=Type -linecomment -output stringers.go .
|
||||
|
||||
type Type uint16
|
||||
|
||||
// IsSize returns true if the EtherType is actually the size of the payload
|
||||
// and should NOT be interpreted as an EtherType.
|
||||
func (et Type) IsSize() bool { return et <= 1500 }
|
||||
|
||||
// Ethernet type flags
|
||||
const (
|
||||
TypeIPv4 Type = 0x0800 // IPv4
|
||||
TypeARP Type = 0x0806 // ARP
|
||||
TypeWakeOnLAN Type = 0x0842 // wake on LAN
|
||||
TypeTRILL Type = 0x22F3 // TRILL
|
||||
TypeDECnetPhase4 Type = 0x6003 // DECnetPhase4
|
||||
TypeRARP Type = 0x8035 // RARP
|
||||
TypeAppleTalk Type = 0x809B // AppleTalk
|
||||
TypeAARP Type = 0x80F3 // AARP
|
||||
TypeIPX1 Type = 0x8137 // IPx1
|
||||
TypeIPX2 Type = 0x8138 // IPx2
|
||||
TypeQNXQnet Type = 0x8204 // QNXQnet
|
||||
TypeIPv6 Type = 0x86DD // IPv6
|
||||
TypeEthernetFlowControl Type = 0x8808 // EthernetFlowCtl
|
||||
TypeIEEE802_3 Type = 0x8809 // IEEE802.3
|
||||
TypeCobraNet Type = 0x8819 // CobraNet
|
||||
TypeMPLSUnicast Type = 0x8847 // MPLS Unicast
|
||||
TypeMPLSMulticast Type = 0x8848 // MPLS Multicast
|
||||
TypePPPoEDiscovery Type = 0x8863 // PPPoE discovery
|
||||
TypePPPoESession Type = 0x8864 // PPPoE session
|
||||
TypeJumboFrames Type = 0x8870 // jumbo frames
|
||||
TypeHomePlug1_0MME Type = 0x887B // home plug 1 0mme
|
||||
TypeIEEE802_1X Type = 0x888E // IEEE 802.1x
|
||||
TypePROFINET Type = 0x8892 // profinet
|
||||
TypeHyperSCSI Type = 0x889A // hyper SCSI
|
||||
TypeAoE Type = 0x88A2 // AoE
|
||||
TypeEtherCAT Type = 0x88A4 // EtherCAT
|
||||
TypeEthernetPowerlink Type = 0x88AB // Ethernet powerlink
|
||||
TypeLLDP Type = 0x88CC // LLDP
|
||||
TypeSERCOS3 Type = 0x88CD // SERCOS3
|
||||
TypeHomePlugAVMME Type = 0x88E1 // home plug AVMME
|
||||
TypeMRP Type = 0x88E3 // MRP
|
||||
TypeIEEE802_1AE Type = 0x88E5 // IEEE 802.1ae
|
||||
TypeIEEE1588 Type = 0x88F7 // IEEE 1588
|
||||
TypeIEEE802_1ag Type = 0x8902 // IEEE 802.1ag
|
||||
TypeFCoE Type = 0x8906 // FCoE
|
||||
TypeFCoEInit Type = 0x8914 // FCoE init
|
||||
TypeRoCE Type = 0x8915 // RoCE
|
||||
TypeCTP Type = 0x9000 // CTP
|
||||
TypeVeritasLLT Type = 0xCAFE // Veritas LLT
|
||||
TypeVLAN Type = 0x8100 // VLAN
|
||||
TypeServiceVLAN Type = 0x88a8 // service VLAN
|
||||
// minEthPayload is the minimum payload size for an Ethernet frame, assuming
|
||||
// that no 802.1Q VLAN tags are present.
|
||||
minEthPayload = 46
|
||||
)
|
||||
|
||||
// VLANTag holds priority (PCP) Drop indicator (DEI) and VLAN ID bits of the VLAN tag field.
|
||||
type VLANTag uint16
|
||||
|
||||
// DropEligibleIndicator returns true if the DEI bit is set.
|
||||
// DEI may be used separately or in conjunction with PCP to indicate frames eligible to be dropped in the presence of congestion.
|
||||
func (vt VLANTag) DropEligibleIndicator() bool { return vt&(1<<3) != 0 }
|
||||
|
||||
// PriorityCodePoint is 3-bit field which refers to the IEEE 802.1p class of service (CoS) and maps to the frame priority level. Different PCP values can be used to prioritize different classes of traffic
|
||||
func (vt VLANTag) PriorityCodePoint() uint8 { return uint8(vt & 0b111) }
|
||||
|
||||
// VLANIdentifier 12 bit field which specifies which VLAN the frame belongs to. Values of 0 and 4095 are reserved.
|
||||
func (vt VLANTag) VLANIdentifier() uint16 { return uint16(vt) >> 4 }
|
||||
@@ -0,0 +1,131 @@
|
||||
package ethernet
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
)
|
||||
|
||||
// NewFrame returns a EthFrame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 14.
|
||||
// Users should still call [EthFrame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewFrame(buf []byte) (Frame, error) {
|
||||
if len(buf) < sizeHeaderNoVLAN {
|
||||
return Frame{buf: nil}, errShort
|
||||
}
|
||||
return Frame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// Frame encapsulates the raw data of an Ethernet frame
|
||||
// without including preamble (first byte is start of destination address)
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [IEEE 802.3].
|
||||
//
|
||||
// [IEEE 802.3]: https://standards.ieee.org/ieee/802.3/7071/
|
||||
type Frame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (efrm Frame) RawData() []byte { return efrm.buf }
|
||||
|
||||
// HeaderLength returns the length of the ethernet packet header. Nominally returns 14; or 18 for VLAN packets.
|
||||
func (efrm Frame) HeaderLength() int {
|
||||
if efrm.IsVLAN() {
|
||||
return 18
|
||||
}
|
||||
return sizeHeaderNoVLAN
|
||||
}
|
||||
|
||||
// Payload returns the data portion of the ethernet packet with handling of VLAN packets.
|
||||
func (efrm Frame) Payload() []byte {
|
||||
hl := efrm.HeaderLength()
|
||||
et := efrm.EtherTypeOrSize()
|
||||
if et.IsSize() {
|
||||
return efrm.buf[hl:et]
|
||||
}
|
||||
return efrm.buf[hl:]
|
||||
}
|
||||
|
||||
// DestinationHardwareAddr returns the target's MAC/hardware address for the ethernet packet.
|
||||
func (efrm Frame) DestinationHardwareAddr() (dst *[6]byte) {
|
||||
return (*[6]byte)(efrm.buf[0:6])
|
||||
}
|
||||
|
||||
// IsBroadcast returns true if the destination is the broadcast address ff:ff:ff:ff:ff:ff, false otherwise.
|
||||
func (efrm Frame) IsBroadcast() bool {
|
||||
return efrm.buf[0] == 0xff && efrm.buf[1] == 0xff && efrm.buf[2] == 0xff &&
|
||||
efrm.buf[3] == 0xff && efrm.buf[4] == 0xff && efrm.buf[5] == 0xff
|
||||
}
|
||||
|
||||
// SourceHardwareAddr returns the sender's MAC/hardware address of the ethernet packet.
|
||||
func (efrm Frame) SourceHardwareAddr() (src *[6]byte) {
|
||||
return (*[6]byte)(efrm.buf[6:12])
|
||||
}
|
||||
|
||||
// EtherTypeOrSize returns the EtherType/Size field of the ethernet packet.
|
||||
// Caller should check if the field is actually a valid EtherType or if it represents the Ethernet payload size with [EtherType.IsSize].
|
||||
func (efrm Frame) EtherTypeOrSize() Type {
|
||||
return Type(binary.BigEndian.Uint16(efrm.buf[12:14]))
|
||||
}
|
||||
|
||||
// SetEtherType sets the EtherType field of the ethernet packet. See [EtherType] and [Frame.EtherTypeOrSize].
|
||||
func (efrm Frame) SetEtherType(v Type) {
|
||||
binary.BigEndian.PutUint16(efrm.buf[12:14], uint16(v))
|
||||
}
|
||||
|
||||
// VLANTag returns the VLAN tag field following the TPID=0x8100. See [VLANTag]. Call [Frame.ValidateSize] to ensure this function does not panic.
|
||||
func (efrm Frame) VLANTag() VLANTag { return VLANTag(binary.BigEndian.Uint16(efrm.buf[14:16])) }
|
||||
|
||||
// SetVLANTag sets the VLAN tag field of the Ethernet Header. See [VLANTag]. Call [Frame.ValidateSize] to ensure this function does not panic.
|
||||
func (efrm Frame) SetVLANTag(vt VLANTag) { binary.BigEndian.PutUint16(efrm.buf[14:16], uint16(vt)) }
|
||||
|
||||
// VLANEtherType returns the [EtherType] for a VLAN ethernet frame (octet position 16). Call [Frame.ValidateSize] to ensure this function does not panic.
|
||||
func (efrm Frame) VLANEtherType() Type {
|
||||
return Type(binary.BigEndian.Uint16(efrm.buf[16:18]))
|
||||
}
|
||||
|
||||
// SetVLANEtherType sets the [EtherType] for a VLAN ethernet frame (octet position 16). Call [Frame.ValidateSize] to ensure this function does not panic.
|
||||
func (efrm Frame) SetVLANEtherType(vt Type) {
|
||||
binary.BigEndian.PutUint16(efrm.buf[16:18], uint16(vt))
|
||||
}
|
||||
|
||||
// IsVLAN returns true if the SizeOrEtherType is set to the VLAN tag 0x8100. This
|
||||
// indicates the EthernetHeader is invalid as-is and instead of EtherType the field
|
||||
// contains the first two octets of a 4 octet 802.1Q VLAN tag. In this case 4 more bytes
|
||||
// must be read from the wire, of which the last 2 of these bytes contain the actual
|
||||
// SizeOrEtherType field, which needs to be validated yet again in case the packet is
|
||||
// a VLAN double-tap packet.
|
||||
func (efrm Frame) IsVLAN() bool {
|
||||
return efrm.EtherTypeOrSize() == TypeVLAN
|
||||
}
|
||||
|
||||
// ClearHeader zeros out the fixed(non-variable) header contents.
|
||||
func (frm Frame) ClearHeader() {
|
||||
for i := range frm.buf[:sizeHeaderNoVLAN] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Validation API.
|
||||
//
|
||||
|
||||
var (
|
||||
errShort = errors.New("ethernet: too short")
|
||||
errShortVLAN = errors.New("ethernet: short VLAN")
|
||||
)
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (efrm Frame) ValidateSize(v *lneto2.Validator) {
|
||||
sz := efrm.EtherTypeOrSize()
|
||||
if sz.IsSize() && len(efrm.buf) < int(sz) {
|
||||
v.AddError(errShort)
|
||||
}
|
||||
if sz == TypeVLAN && len(efrm.buf) < 18 {
|
||||
v.AddError(errShortVLAN)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// Code generated by "stringer -type=Type -linecomment -output stringers.go ."; DO NOT EDIT.
|
||||
|
||||
package ethernet
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[TypeIPv4-2048]
|
||||
_ = x[TypeARP-2054]
|
||||
_ = x[TypeWakeOnLAN-2114]
|
||||
_ = x[TypeTRILL-8947]
|
||||
_ = x[TypeDECnetPhase4-24579]
|
||||
_ = x[TypeRARP-32821]
|
||||
_ = x[TypeAppleTalk-32923]
|
||||
_ = x[TypeAARP-33011]
|
||||
_ = x[TypeIPX1-33079]
|
||||
_ = x[TypeIPX2-33080]
|
||||
_ = x[TypeQNXQnet-33284]
|
||||
_ = x[TypeIPv6-34525]
|
||||
_ = x[TypeEthernetFlowControl-34824]
|
||||
_ = x[TypeIEEE802_3-34825]
|
||||
_ = x[TypeCobraNet-34841]
|
||||
_ = x[TypeMPLSUnicast-34887]
|
||||
_ = x[TypeMPLSMulticast-34888]
|
||||
_ = x[TypePPPoEDiscovery-34915]
|
||||
_ = x[TypePPPoESession-34916]
|
||||
_ = x[TypeJumboFrames-34928]
|
||||
_ = x[TypeHomePlug1_0MME-34939]
|
||||
_ = x[TypeIEEE802_1X-34958]
|
||||
_ = x[TypePROFINET-34962]
|
||||
_ = x[TypeHyperSCSI-34970]
|
||||
_ = x[TypeAoE-34978]
|
||||
_ = x[TypeEtherCAT-34980]
|
||||
_ = x[TypeEthernetPowerlink-34987]
|
||||
_ = x[TypeLLDP-35020]
|
||||
_ = x[TypeSERCOS3-35021]
|
||||
_ = x[TypeHomePlugAVMME-35041]
|
||||
_ = x[TypeMRP-35043]
|
||||
_ = x[TypeIEEE802_1AE-35045]
|
||||
_ = x[TypeIEEE1588-35063]
|
||||
_ = x[TypeIEEE802_1ag-35074]
|
||||
_ = x[TypeFCoE-35078]
|
||||
_ = x[TypeFCoEInit-35092]
|
||||
_ = x[TypeRoCE-35093]
|
||||
_ = x[TypeCTP-36864]
|
||||
_ = x[TypeVeritasLLT-51966]
|
||||
_ = x[TypeVLAN-33024]
|
||||
_ = x[TypeServiceVLAN-34984]
|
||||
}
|
||||
|
||||
const _Type_name = "IPv4ARPwake on LANTRILLDECnetPhase4RARPAppleTalkAARPVLANIPx1IPx2QNXQnetIPv6EthernetFlowCtlIEEE802.3CobraNetMPLS UnicastMPLS MulticastPPPoE discoveryPPPoE sessionjumbo frameshome plug 1 0mmeIEEE 802.1xprofinethyper SCSIAoEEtherCATservice VLANEthernet powerlinkLLDPSERCOS3home plug AVMMEMRPIEEE 802.1aeIEEE 1588IEEE 802.1agFCoEFCoE initRoCECTPVeritas LLT"
|
||||
|
||||
var _Type_map = map[Type]string{
|
||||
2048: _Type_name[0:4],
|
||||
2054: _Type_name[4:7],
|
||||
2114: _Type_name[7:18],
|
||||
8947: _Type_name[18:23],
|
||||
24579: _Type_name[23:35],
|
||||
32821: _Type_name[35:39],
|
||||
32923: _Type_name[39:48],
|
||||
33011: _Type_name[48:52],
|
||||
33024: _Type_name[52:56],
|
||||
33079: _Type_name[56:60],
|
||||
33080: _Type_name[60:64],
|
||||
33284: _Type_name[64:71],
|
||||
34525: _Type_name[71:75],
|
||||
34824: _Type_name[75:90],
|
||||
34825: _Type_name[90:99],
|
||||
34841: _Type_name[99:107],
|
||||
34887: _Type_name[107:119],
|
||||
34888: _Type_name[119:133],
|
||||
34915: _Type_name[133:148],
|
||||
34916: _Type_name[148:161],
|
||||
34928: _Type_name[161:173],
|
||||
34939: _Type_name[173:189],
|
||||
34958: _Type_name[189:200],
|
||||
34962: _Type_name[200:208],
|
||||
34970: _Type_name[208:218],
|
||||
34978: _Type_name[218:221],
|
||||
34980: _Type_name[221:229],
|
||||
34984: _Type_name[229:241],
|
||||
34987: _Type_name[241:259],
|
||||
35020: _Type_name[259:263],
|
||||
35021: _Type_name[263:270],
|
||||
35041: _Type_name[270:285],
|
||||
35043: _Type_name[285:288],
|
||||
35045: _Type_name[288:300],
|
||||
35063: _Type_name[300:309],
|
||||
35074: _Type_name[309:321],
|
||||
35078: _Type_name[321:325],
|
||||
35092: _Type_name[325:334],
|
||||
35093: _Type_name[334:338],
|
||||
36864: _Type_name[338:341],
|
||||
51966: _Type_name[341:352],
|
||||
}
|
||||
|
||||
func (i Type) String() string {
|
||||
if str, ok := _Type_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
+39
-31
@@ -9,9 +9,11 @@ import (
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/arp"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/internal"
|
||||
"github.com/soypat/lneto/ipv4"
|
||||
"github.com/soypat/lneto/ipv6"
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
"github.com/soypat/lneto/tcp"
|
||||
)
|
||||
@@ -92,9 +94,9 @@ func NewEthernetTCPStack(mac [6]byte, ip netip.AddrPort, slogger logger) (*LinkS
|
||||
tcpPortStack := &TCPPort{
|
||||
handler: tcp.Handler{},
|
||||
}
|
||||
proto := lneto2.EtherTypeIPv4
|
||||
proto := ethernet.TypeIPv4
|
||||
if ip.Addr().Is6() {
|
||||
proto = lneto2.EtherTypeIPv6
|
||||
proto = ethernet.TypeIPv6
|
||||
}
|
||||
arphandler, err := arp.NewHandler(arp.HandlerConfig{
|
||||
HardwareAddr: mac[:],
|
||||
@@ -177,7 +179,8 @@ func (ls *LinkStack) Register(h Handler, remoteHWAddr [6]byte) error {
|
||||
}
|
||||
|
||||
func (ls *LinkStack) RecvEth(ethFrame []byte) (err error) {
|
||||
efrm, err := lneto.NewEthFrame(ethFrame)
|
||||
|
||||
efrm, err := ethernet.NewFrame(ethFrame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -186,7 +189,7 @@ func (ls *LinkStack) RecvEth(ethFrame []byte) (err error) {
|
||||
if !efrm.IsBroadcast() && ls.mac != *dstaddr {
|
||||
return fmt.Errorf("incoming %s mismatch hwaddr %s", etype.String(), net.HardwareAddr(dstaddr[:]).String())
|
||||
}
|
||||
var vld lneto.Validator
|
||||
var vld lneto2.Validator
|
||||
efrm.ValidateSize(&vld)
|
||||
if err := vld.Err(); err != nil {
|
||||
return err
|
||||
@@ -210,15 +213,15 @@ func (ls *LinkStack) HandleEth(dst []byte) (n int, err error) {
|
||||
h := &ls.handlers[i]
|
||||
n, err = h.handle(dst[:ls.mtu], 14)
|
||||
if err != nil {
|
||||
ls.error("handling", slog.String("proto", lneto.EtherType(h.proto).String()), slog.String("err", err.Error()))
|
||||
ls.error("handling", slog.String("proto", ethernet.Type(h.proto).String()), slog.String("err", err.Error()))
|
||||
continue
|
||||
}
|
||||
if n > 0 {
|
||||
// Found packet
|
||||
efrm, _ := lneto.NewEthFrame(dst[:14])
|
||||
efrm, _ := ethernet.NewFrame(dst[:14])
|
||||
copy(efrm.DestinationHardwareAddr()[:], h.raddr)
|
||||
*efrm.SourceHardwareAddr() = ls.mac
|
||||
efrm.SetEtherType(lneto.EtherType(h.proto))
|
||||
efrm.SetEtherType(ethernet.Type(h.proto))
|
||||
|
||||
return n + 14, nil
|
||||
}
|
||||
@@ -228,12 +231,12 @@ func (ls *LinkStack) HandleEth(dst []byte) (n int, err error) {
|
||||
|
||||
type IPv4Stack struct {
|
||||
ip [4]byte
|
||||
validator lneto.Validator
|
||||
validator lneto2.Validator
|
||||
handlers []handler
|
||||
logger
|
||||
}
|
||||
|
||||
func (is *IPv4Stack) Protocol() uint32 { return uint32(lneto.EtherTypeIPv4) }
|
||||
func (is *IPv4Stack) Protocol() uint32 { return uint32(ethernet.TypeIPv4) }
|
||||
|
||||
func (is *IPv4Stack) Register(h Handler, remoteAddr *[4]byte) error {
|
||||
proto := h.Protocol()
|
||||
@@ -256,7 +259,8 @@ func (is *IPv4Stack) Register(h Handler, remoteAddr *[4]byte) error {
|
||||
}
|
||||
|
||||
func (is *IPv4Stack) Recv(ethFrame []byte, ipOff int) error {
|
||||
ifrm, err := lneto.NewIPv4Frame(ethFrame[ipOff:])
|
||||
|
||||
ifrm, err := ipv4.NewFrame(ethFrame[ipOff:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -289,7 +293,7 @@ func (is *IPv4Stack) Handle(ethFrame []byte, ipOff int) (int, error) {
|
||||
if len(ethFrame)-ipOff < 256 {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
ifrm, _ := lneto.NewIPv4Frame(ethFrame[ipOff:])
|
||||
ifrm, _ := ipv4.NewFrame(ethFrame[ipOff:])
|
||||
const ihl = 5
|
||||
const headerlen = ihl * 4
|
||||
ifrm.SetVersionAndIHL(4, 5)
|
||||
@@ -297,7 +301,7 @@ func (is *IPv4Stack) Handle(ethFrame []byte, ipOff int) (int, error) {
|
||||
ifrm.SetToS(0)
|
||||
for i := range is.handlers {
|
||||
h := &is.handlers[i]
|
||||
proto := lneto.IPProto(h.proto)
|
||||
proto := lneto2.IPProto(h.proto)
|
||||
ifrm.SetProtocol(proto)
|
||||
if len(h.raddr) == 4 {
|
||||
copy(ifrm.DestinationAddr()[:], h.raddr)
|
||||
@@ -325,12 +329,13 @@ func (is *IPv4Stack) Handle(ethFrame []byte, ipOff int) (int, error) {
|
||||
}
|
||||
|
||||
type TCPStack struct {
|
||||
validator lneto.Validator
|
||||
validator lneto2.Validator
|
||||
handlers []handler
|
||||
logger
|
||||
crc lneto2.CRC791
|
||||
}
|
||||
|
||||
func (ts *TCPStack) Protocol() uint32 { return uint32(lneto.IPProtoTCP) }
|
||||
func (ts *TCPStack) Protocol() uint32 { return uint32(lneto2.IPProtoTCP) }
|
||||
|
||||
func (ts *TCPStack) Register(h Handler, lport uint16) error {
|
||||
if lport == 0 {
|
||||
@@ -349,7 +354,7 @@ func (ts *TCPStack) Recv(ipFrame []byte, tcpOff int) error {
|
||||
if ipVersion != 4 && ipVersion != 6 {
|
||||
return errors.New("invalid IP version")
|
||||
}
|
||||
tfrm, err := lneto.NewTCPFrame(ipFrame[tcpOff:])
|
||||
tfrm, err := tcp.NewFrame(ipFrame[tcpOff:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -369,17 +374,19 @@ func (ts *TCPStack) Recv(ipFrame []byte, tcpOff int) error {
|
||||
if err = ts.validator.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
var crc uint16
|
||||
ts.crc.Reset()
|
||||
switch ipVersion {
|
||||
case 4:
|
||||
ifrm, _ := lneto.NewIPv4Frame(ipFrame)
|
||||
crc = tfrm.CalculateIPv4CRC(ifrm)
|
||||
ifrm, _ := ipv4.NewFrame(ipFrame)
|
||||
ifrm.CRCWriteTCPPseudo(&ts.crc)
|
||||
case 6:
|
||||
ifrm, _ := lneto.NewIPv6Frame(ipFrame)
|
||||
crc = tfrm.CalculateIPv6CRC(ifrm)
|
||||
i6frm, _ := ipv6.NewFrame(ipFrame)
|
||||
i6frm.CRCWritePseudo(&ts.crc)
|
||||
}
|
||||
tfrm.CRCWrite(&ts.crc)
|
||||
crc := ts.crc.Sum16()
|
||||
gotCRC := tfrm.CRC()
|
||||
if crc != gotCRC {
|
||||
if ts.crc.Sum16() != gotCRC {
|
||||
ts.error("TCPStack:Recv:crc-mismatch", slog.Uint64("lport", uint64(lport)), slog.Uint64("want", uint64(crc)), slog.Uint64("got", uint64(gotCRC)))
|
||||
return errors.New("TCP crc mismatch")
|
||||
}
|
||||
@@ -412,21 +419,22 @@ func (ts *TCPStack) Handle(ipFrame []byte, tcpOff int) (n int, err error) {
|
||||
return 0, err
|
||||
}
|
||||
// TCP packet written.
|
||||
tfrm, _ := lneto.NewTCPFrame(ipFrame[tcpOff : tcpOff+n])
|
||||
tfrm, _ := tcp.NewFrame(ipFrame[tcpOff : tcpOff+n])
|
||||
ts.validator.ResetErr()
|
||||
tfrm.ValidateSize(&ts.validator) // Perform basic validation.
|
||||
if err = ts.validator.Err(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
var crc uint16
|
||||
ts.crc.Reset()
|
||||
switch ipVersion {
|
||||
case 4:
|
||||
ifrm, _ := lneto.NewIPv4Frame(ipFrame)
|
||||
crc = tfrm.CalculateIPv4CRC(ifrm)
|
||||
ifrm, _ := ipv4.NewFrame(ipFrame)
|
||||
ifrm.CRCWriteTCPPseudo(&ts.crc)
|
||||
case 6:
|
||||
ifrm, _ := lneto.NewIPv6Frame(ipFrame)
|
||||
crc = tfrm.CalculateIPv6CRC(ifrm)
|
||||
i6frm, _ := ipv6.NewFrame(ipFrame)
|
||||
i6frm.CRCWritePseudo(&ts.crc)
|
||||
}
|
||||
crc := ts.crc.Sum16()
|
||||
tfrm.SetCRC(crc)
|
||||
return n, nil
|
||||
}
|
||||
@@ -435,7 +443,7 @@ type ARPStack struct {
|
||||
handler arp.Handler
|
||||
}
|
||||
|
||||
func (as *ARPStack) Protocol() uint32 { return uint32(lneto.EtherTypeARP) }
|
||||
func (as *ARPStack) Protocol() uint32 { return uint32(ethernet.TypeARP) }
|
||||
|
||||
func (as *ARPStack) Recv(EtherFrame []byte, arpOff int) error {
|
||||
afrm, _ := arp.NewFrame(EtherFrame[arpOff:])
|
||||
@@ -450,7 +458,7 @@ func (as *ARPStack) Handle(EtherFrame []byte, arpOff int) (int, error) {
|
||||
}
|
||||
afrm, _ := arp.NewFrame(EtherFrame[arpOff:])
|
||||
hwaddr, _ := afrm.Target()
|
||||
efrm, _ := lneto.NewEthFrame(EtherFrame)
|
||||
efrm, _ := ethernet.NewFrame(EtherFrame)
|
||||
copy(efrm.DestinationHardwareAddr()[:], hwaddr)
|
||||
slog.Info("handle", slog.String("out", afrm.String()))
|
||||
return n, err
|
||||
@@ -460,7 +468,7 @@ type TCPPort struct {
|
||||
handler tcp.Handler
|
||||
}
|
||||
|
||||
func (tp *TCPPort) Protocol() uint32 { return uint32(lneto.IPProtoTCP) }
|
||||
func (tp *TCPPort) Protocol() uint32 { return uint32(lneto2.IPProtoTCP) }
|
||||
|
||||
func (tp *TCPPort) Recv(tcpFrame []byte, off int) error {
|
||||
if off != 0 {
|
||||
|
||||
@@ -1,765 +0,0 @@
|
||||
package lneto
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/soypat/lneto/tcp"
|
||||
)
|
||||
|
||||
// NewEthFrame returns a EthFrame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 14.
|
||||
// Users should still call [EthFrame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewEthFrame(buf []byte) (EthFrame, error) {
|
||||
if len(buf) < sizeHeaderEthNoVLAN {
|
||||
return EthFrame{buf: nil}, errors.New("ethernet packet too short")
|
||||
}
|
||||
return EthFrame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// NewARPFrame returns a ARPFrame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 28 (IPv4 min size).
|
||||
// Users should still call [ARPFrame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewARPFrame(buf []byte) (ARPFrame, error) {
|
||||
if len(buf) < sizeHeaderARPv4 {
|
||||
return ARPFrame{buf: nil}, errors.New("ARP packet too short")
|
||||
}
|
||||
return ARPFrame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// NewIPv4Frame returns a new IPv4Frame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 20.
|
||||
// Users should still call [IPv4Frame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewIPv4Frame(buf []byte) (IPv4Frame, error) {
|
||||
if len(buf) < sizeHeaderIPv4 {
|
||||
return IPv4Frame{buf: nil}, errors.New("IPv4 packet too short")
|
||||
}
|
||||
return IPv4Frame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// NewIPv6Frame returns a new IPv6Frame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 40.
|
||||
// Users should still call [IPv6Frame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewIPv6Frame(buf []byte) (IPv6Frame, error) {
|
||||
if len(buf) < sizeHeaderIPv6 {
|
||||
return IPv6Frame{buf: nil}, errors.New("IPv6 packet too short")
|
||||
}
|
||||
return IPv6Frame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// NewTCPFrame returns a new TCPFrame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 20.
|
||||
// Users should still call [TCPFrame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewTCPFrame(buf []byte) (TCPFrame, error) {
|
||||
if len(buf) < sizeHeaderTCP {
|
||||
return TCPFrame{buf: nil}, errors.New("TCP packet too short")
|
||||
}
|
||||
return TCPFrame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// NewUDPFrame returns a new UDPFrame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 8.
|
||||
// Users should still call [UDPFrame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewUDPFrame(buf []byte) (UDPFrame, error) {
|
||||
if len(buf) < sizeHeaderUDP {
|
||||
return UDPFrame{buf: buf}, errors.New("UDP packet too short")
|
||||
}
|
||||
return UDPFrame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// EthFrame encapsulates the raw data of an Ethernet frame
|
||||
// without including preamble (first byte is start of destination address)
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [IEEE 802.3].
|
||||
//
|
||||
// [IEEE 802.3]: https://standards.ieee.org/ieee/802.3/7071/
|
||||
type EthFrame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (efrm EthFrame) RawData() []byte { return efrm.buf }
|
||||
|
||||
// HeaderLength returns the length of the ethernet packet header. Nominally returns 14; or 18 for VLAN packets.
|
||||
func (efrm EthFrame) HeaderLength() int {
|
||||
if efrm.IsVLAN() {
|
||||
return 18
|
||||
}
|
||||
return sizeHeaderEthNoVLAN
|
||||
}
|
||||
|
||||
// Payload returns the data portion of the ethernet packet with handling of VLAN packets.
|
||||
func (efrm EthFrame) Payload() []byte {
|
||||
hl := efrm.HeaderLength()
|
||||
et := efrm.EtherTypeOrSize()
|
||||
if et.IsSize() {
|
||||
return efrm.buf[hl:et]
|
||||
}
|
||||
return efrm.buf[hl:]
|
||||
}
|
||||
|
||||
// DestinationHardwareAddr returns the target's MAC/hardware address for the ethernet packet.
|
||||
func (efrm EthFrame) DestinationHardwareAddr() (dst *[6]byte) {
|
||||
return (*[6]byte)(efrm.buf[0:6])
|
||||
}
|
||||
|
||||
// IsBroadcast returns true if the destination is the broadcast address ff:ff:ff:ff:ff:ff, false otherwise.
|
||||
func (efrm EthFrame) IsBroadcast() bool {
|
||||
return efrm.buf[0] == 0xff && efrm.buf[1] == 0xff && efrm.buf[2] == 0xff &&
|
||||
efrm.buf[3] == 0xff && efrm.buf[4] == 0xff && efrm.buf[5] == 0xff
|
||||
}
|
||||
|
||||
// SourceHardwareAddr returns the sender's MAC/hardware address of the ethernet packet.
|
||||
func (efrm EthFrame) SourceHardwareAddr() (src *[6]byte) {
|
||||
return (*[6]byte)(efrm.buf[6:12])
|
||||
}
|
||||
|
||||
// EtherTypeOrSize returns the EtherType/Size field of the ethernet packet.
|
||||
// Caller should check if the field is actually a valid EtherType or if it represents the Ethernet payload size with [EtherType.IsSize].
|
||||
func (efrm EthFrame) EtherTypeOrSize() EtherType {
|
||||
return EtherType(binary.BigEndian.Uint16(efrm.buf[12:14]))
|
||||
}
|
||||
|
||||
// SetEtherType sets the EtherType field of the ethernet packet. See [EtherType] and [EthFrame.EtherTypeOrSize].
|
||||
func (efrm EthFrame) SetEtherType(v EtherType) {
|
||||
binary.BigEndian.PutUint16(efrm.buf[12:14], uint16(v))
|
||||
}
|
||||
|
||||
// VLANTag returns the VLAN tag field following the TPID=0x8100. See [VLANTag]. Call [EthFrame.ValidateSize] to ensure this function does not panic.
|
||||
func (efrm EthFrame) VLANTag() VLANTag { return VLANTag(binary.BigEndian.Uint16(efrm.buf[14:16])) }
|
||||
|
||||
// SetVLANTag sets the VLAN tag field of the Ethernet Header. See [VLANTag]. Call [EthFrame.ValidateSize] to ensure this function does not panic.
|
||||
func (efrm EthFrame) SetVLANTag(vt VLANTag) { binary.BigEndian.PutUint16(efrm.buf[14:16], uint16(vt)) }
|
||||
|
||||
// VLANEtherType returns the [EtherType] for a VLAN ethernet frame (octet position 16). Call [EthFrame.ValidateSize] to ensure this function does not panic.
|
||||
func (efrm EthFrame) VLANEtherType() EtherType {
|
||||
return EtherType(binary.BigEndian.Uint16(efrm.buf[16:18]))
|
||||
}
|
||||
|
||||
// SetVLANEtherType sets the [EtherType] for a VLAN ethernet frame (octet position 16). Call [EthFrame.ValidateSize] to ensure this function does not panic.
|
||||
func (efrm EthFrame) SetVLANEtherType(vt EtherType) {
|
||||
binary.BigEndian.PutUint16(efrm.buf[16:18], uint16(vt))
|
||||
}
|
||||
|
||||
// IsVLAN returns true if the SizeOrEtherType is set to the VLAN tag 0x8100. This
|
||||
// indicates the EthernetHeader is invalid as-is and instead of EtherType the field
|
||||
// contains the first two octets of a 4 octet 802.1Q VLAN tag. In this case 4 more bytes
|
||||
// must be read from the wire, of which the last 2 of these bytes contain the actual
|
||||
// SizeOrEtherType field, which needs to be validated yet again in case the packet is
|
||||
// a VLAN double-tap packet.
|
||||
func (efrm EthFrame) IsVLAN() bool {
|
||||
return efrm.EtherTypeOrSize() == EtherTypeVLAN
|
||||
}
|
||||
|
||||
// ClearHeader zeros out the fixed(non-variable) header contents.
|
||||
func (frm EthFrame) ClearHeader() {
|
||||
for i := range frm.buf[:sizeHeaderEthNoVLAN] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// ARPFrame encapsulates the raw data of an ARP packet
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [RFC826].
|
||||
//
|
||||
// [RFC826]: https://tools.ietf.org/html/rfc826
|
||||
type ARPFrame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (afrm ARPFrame) RawData() []byte { return afrm.buf }
|
||||
|
||||
// HardwareType specifies the network link protocol type. Example: Ethernet is 1.
|
||||
func (afrm ARPFrame) Hardware() (Type uint16, length uint8) {
|
||||
Type = binary.BigEndian.Uint16(afrm.buf[0:2])
|
||||
length = afrm.buf[4]
|
||||
return Type, length
|
||||
}
|
||||
|
||||
// SetHardware sets the networl link protocol type. See [ARPFrame.SetHardware].
|
||||
func (afrm ARPFrame) SetHardware(Type uint16, length uint8) {
|
||||
binary.BigEndian.PutUint16(afrm.buf[0:2], Type)
|
||||
afrm.buf[4] = length
|
||||
}
|
||||
|
||||
// Protocol returns the internet protocol type and length. See [EtherType].
|
||||
func (afrm ARPFrame) Protocol() (Type EtherType, length uint8) {
|
||||
Type = EtherType(binary.BigEndian.Uint16(afrm.buf[2:4]))
|
||||
length = afrm.buf[5]
|
||||
return Type, length
|
||||
}
|
||||
|
||||
// SetProtocol sets the protocol type and length fields of the ARP frame. See [ARPFrame.Protocol] and [EtherType].
|
||||
func (afrm ARPFrame) SetProtocol(Type EtherType, length uint8) {
|
||||
binary.BigEndian.PutUint16(afrm.buf[2:4], uint16(Type))
|
||||
afrm.buf[5] = length
|
||||
}
|
||||
|
||||
// Operation returns the ARP header operation field. See [ARPOp].
|
||||
func (afrm ARPFrame) Operation() ARPOp { return ARPOp(afrm.buf[6]) }
|
||||
|
||||
// SetOperation sets the ARP header operation field. See [ARPOp].
|
||||
func (afrm ARPFrame) SetOperation(b ARPOp) { afrm.buf[6] = uint8(b) }
|
||||
|
||||
// Sender returns the hardware (MAC) and protocol addresses of sender of ARP packet.
|
||||
// In an ARP request MAC address is used to indicate
|
||||
// the address of the host sending the request. In an ARP reply MAC address is
|
||||
// used to indicate the address of the host that the request was looking for.
|
||||
func (afrm ARPFrame) Sender() (hardwareAddr []byte, proto []byte) {
|
||||
_, hlen := afrm.Hardware()
|
||||
_, ilen := afrm.Protocol()
|
||||
return afrm.buf[8 : 8+hlen], afrm.buf[8+hlen : 8+hlen+ilen]
|
||||
}
|
||||
|
||||
// Target returns the hardware (MAC) and protocol addresses of target of ARP packet.
|
||||
// In an ARP request MAC target is ignored. In ARP reply MAC is used to indicate the address of host that originated request.
|
||||
func (afrm ARPFrame) Target() (hardwareAddr []byte, proto []byte) {
|
||||
_, hlen := afrm.Hardware()
|
||||
_, ilen := afrm.Protocol()
|
||||
toff := 8 + hlen + ilen
|
||||
return afrm.buf[toff : toff+hlen], afrm.buf[toff+hlen : toff+hlen+ilen]
|
||||
}
|
||||
|
||||
// Sender4 returns the IPv4 sender addresses. See [ARPFrame.Sender].
|
||||
func (afrm ARPFrame) Sender4() (hardwareAddr *[6]byte, proto *[4]byte) {
|
||||
return (*[6]byte)(afrm.buf[8:14]), (*[4]byte)(afrm.buf[14:18])
|
||||
}
|
||||
|
||||
// Target4 returns the IPv4 target addresses. See [ARPFrame.Sender].
|
||||
func (afrm ARPFrame) Target4() (hardwareAddr *[6]byte, proto *[4]byte) {
|
||||
return (*[6]byte)(afrm.buf[18:24]), (*[4]byte)(afrm.buf[24:28])
|
||||
}
|
||||
|
||||
// Sender6 returns the IPv6 sender addresses. See [ARPFrame.Sender].
|
||||
func (afrm ARPFrame) Sender16() (hardwareAddr *[6]byte, proto *[16]byte) {
|
||||
return (*[6]byte)(afrm.buf[8:14]), (*[16]byte)(afrm.buf[14:30])
|
||||
}
|
||||
|
||||
// Target6 returns the IPv6 target addresses. See [ARPFrame.Sender].
|
||||
func (afrm ARPFrame) Target16() (hardwareAddr *[6]byte, proto *[16]byte) {
|
||||
return (*[6]byte)(afrm.buf[30:36]), (*[16]byte)(afrm.buf[36:52])
|
||||
}
|
||||
|
||||
// ClearHeader zeros out the fixed(non-variable) header contents.
|
||||
func (frm ARPFrame) ClearHeader() {
|
||||
for i := range frm.buf[:8] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// IPv4Frame encapsulates the raw data of an IPv4 packet
|
||||
// and provides methods for manipulating, validating and
|
||||
// retreiving fields and payload data. See [RFC791].
|
||||
//
|
||||
// [RFC791]: https://tools.ietf.org/html/rfc791
|
||||
type IPv4Frame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (ifrm IPv4Frame) RawData() []byte { return ifrm.buf }
|
||||
|
||||
// HeaderLength returns the length of the IPv4 header as calculated using IHL. It includes IP options.
|
||||
func (ifrm IPv4Frame) HeaderLength() int {
|
||||
return int(ifrm.ihl()) * 4
|
||||
}
|
||||
|
||||
func (ifrm IPv4Frame) ihl() uint8 { return ifrm.buf[0] & 0xf }
|
||||
func (ifrm IPv4Frame) version() uint8 { return ifrm.buf[0] >> 4 }
|
||||
|
||||
// VersionAndIHL returns the version and IHL fields in the IPv4 header. Version should always be 4.
|
||||
func (ifrm IPv4Frame) VersionAndIHL() (version, IHL uint8) {
|
||||
v := ifrm.buf[0]
|
||||
return v >> 4, v & 0xf
|
||||
}
|
||||
|
||||
// SetVersionAndIHL sets the version and IHL fields in the IPv4 header. Version should always be 4.
|
||||
func (ifrm IPv4Frame) SetVersionAndIHL(version, IHL uint8) { ifrm.buf[0] = version<<4 | IHL&0xf }
|
||||
|
||||
// ToS (Type of Service) contains Differential Services Code Point (DSCP) and
|
||||
// Explicit Congestion Notification (ECN) union data.
|
||||
//
|
||||
// DSCP originally defined as the type of service (ToS), this field specifies
|
||||
// differentiated services (DiffServ) per RFC 2474. Real-time data streaming
|
||||
// makes use of the DSCP field. An example is Voice over IP (VoIP), which is
|
||||
// used for interactive voice services.
|
||||
//
|
||||
// ECN is defined in RFC 3168 and allows end-to-end notification of
|
||||
// network congestion without dropping packets. ECN is an optional feature available
|
||||
// when both endpoints support it and effective when also supported by the underlying network.
|
||||
func (ifrm IPv4Frame) ToS() IPToS {
|
||||
return IPToS(ifrm.buf[1])
|
||||
}
|
||||
|
||||
// SetToS sets ToS field. See [IPv4Frame.ToS].
|
||||
func (ifrm IPv4Frame) SetToS(tos IPToS) { ifrm.buf[1] = byte(tos) }
|
||||
|
||||
// TotalLength defines the entire packet size in bytes, including IP header and data.
|
||||
// The minimum size is 20 bytes (IPv4 header without data) and the maximum is 65,535 bytes.
|
||||
// All hosts are required to be able to reassemble datagrams of size up to 576 bytes,
|
||||
// but most modern hosts handle much larger packets.
|
||||
//
|
||||
// Links may impose further restrictions on the packet size, in which case datagrams
|
||||
// must be fragmented. Fragmentation in IPv4 is performed in either the
|
||||
// sending host or in routers. Reassembly is performed at the receiving host.
|
||||
func (ifrm IPv4Frame) TotalLength() uint16 {
|
||||
return binary.BigEndian.Uint16(ifrm.buf[2:4])
|
||||
}
|
||||
|
||||
// SetTotalLength sets TotalLength field. See [IPv4Frame.TotalLength].
|
||||
func (ifrm IPv4Frame) SetTotalLength(tl uint16) { binary.BigEndian.PutUint16(ifrm.buf[2:4], tl) }
|
||||
|
||||
// ID is an identification field and is primarily used for uniquely
|
||||
// identifying the group of fragments of a single IP datagram.
|
||||
func (ifrm IPv4Frame) ID() uint16 {
|
||||
return binary.BigEndian.Uint16(ifrm.buf[4:6])
|
||||
}
|
||||
|
||||
// SetID sets ID field. See [IPv4Frame.ID].
|
||||
func (ifrm IPv4Frame) SetID(id uint16) { binary.BigEndian.PutUint16(ifrm.buf[4:6], id) }
|
||||
|
||||
// Flags returns the [IPv4Flags] of the IP packet.
|
||||
func (ifrm IPv4Frame) Flags() IPv4Flags {
|
||||
return IPv4Flags(binary.BigEndian.Uint16(ifrm.buf[6:8]))
|
||||
}
|
||||
|
||||
// SetFlags sets the IPv4 flags field. See [IPv4Flags].
|
||||
func (ifrm IPv4Frame) SetFlags(flags IPv4Flags) {
|
||||
binary.BigEndian.PutUint16(ifrm.buf[6:8], uint16(flags))
|
||||
}
|
||||
|
||||
// TTL is an eight-bit time to live field limits a datagram's lifetime to prevent
|
||||
// network failure in the event of a routing loop. In practice, the field
|
||||
// is used as a hop count—when the datagram arrives at a router,
|
||||
// the router decrements the TTL field by one. When the TTL field hits zero,
|
||||
// the router discards the packet and typically sends an ICMP time exceeded message to the sender.
|
||||
func (ifrm IPv4Frame) TTL() uint8 { return ifrm.buf[8] }
|
||||
|
||||
// SetTTL sets the IP frame's TTL field. See [IPv4Frame.TTL].
|
||||
func (ifrm IPv4Frame) SetTTL(ttl uint8) { ifrm.buf[8] = ttl }
|
||||
|
||||
// Protocol field defines the protocol used in the data portion of the IP datagram. TCP is 6, UDP is 17.
|
||||
// See [IPProto].
|
||||
func (ifrm IPv4Frame) Protocol() IPProto { return IPProto(ifrm.buf[9]) }
|
||||
|
||||
// SetProtocol sets protocol field. See [IPv4Frame.Protocol] and [IPProto].
|
||||
func (ifrm IPv4Frame) SetProtocol(proto IPProto) { ifrm.buf[9] = uint8(proto) }
|
||||
|
||||
// CRC returns the cyclic-redundancy-check (checksum) field of the IPv4 header.
|
||||
func (ifrm IPv4Frame) CRC() uint16 {
|
||||
return binary.BigEndian.Uint16(ifrm.buf[10:12])
|
||||
}
|
||||
|
||||
// SetCRC sets the CRC field of the IP packet. See [IPv4Frame.CRC].
|
||||
func (ifrm IPv4Frame) SetCRC(cs uint16) {
|
||||
binary.BigEndian.PutUint16(ifrm.buf[10:12], cs)
|
||||
}
|
||||
|
||||
// CalculateHeaderCRC calculates the CRC for this IPv4 frame.
|
||||
func (ifrm IPv4Frame) CalculateHeaderCRC() uint16 {
|
||||
var crc CRC791
|
||||
crc.Write(ifrm.buf[0:10])
|
||||
crc.Write(ifrm.buf[12:20])
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
func (ifrm IPv4Frame) crcWriteTCPPseudo(crc *CRC791) {
|
||||
crc.Write(ifrm.SourceAddr()[:])
|
||||
crc.Write(ifrm.DestinationAddr()[:])
|
||||
crc.AddUint16(ifrm.TotalLength() - 4*uint16(ifrm.ihl()))
|
||||
crc.AddUint16(uint16(ifrm.Protocol()))
|
||||
}
|
||||
|
||||
func (ifrm IPv4Frame) crcWriteUDPPseudo(crc *CRC791) {
|
||||
crc.Write(ifrm.SourceAddr()[:])
|
||||
crc.Write(ifrm.DestinationAddr()[:])
|
||||
crc.AddUint16(uint16(ifrm.Protocol()))
|
||||
}
|
||||
|
||||
// SourceAddr returns pointer to the source IPv4 address in the IP header.
|
||||
func (ifrm IPv4Frame) SourceAddr() *[4]byte {
|
||||
return (*[4]byte)(ifrm.buf[12:16])
|
||||
}
|
||||
|
||||
// DestinationAddr returns pointer to the destination IPv4 address in the IP header.
|
||||
func (ifrm IPv4Frame) DestinationAddr() *[4]byte {
|
||||
return (*[4]byte)(ifrm.buf[16:20])
|
||||
}
|
||||
|
||||
// Payload returns the contents of the IPv4 packet, which may be zero sized.
|
||||
// Be sure to call [IPv4Frame.ValidateSize] beforehand to avoid panic.
|
||||
func (ifrm IPv4Frame) Payload() []byte {
|
||||
off := ifrm.HeaderLength()
|
||||
l := ifrm.TotalLength()
|
||||
return ifrm.buf[off:l]
|
||||
}
|
||||
|
||||
// Options returns the options portion of the IPv4 header. May be zero lengthed.
|
||||
// Be sure to call [IPv4Frame.ValidateSize] beforehand to avoid panic.
|
||||
func (ifrm IPv4Frame) Options() []byte {
|
||||
off := ifrm.HeaderLength()
|
||||
return ifrm.buf[sizeHeaderIPv4:off]
|
||||
}
|
||||
|
||||
// ClearHeader zeros out the fixed(non-variable) header contents.
|
||||
func (frm IPv4Frame) ClearHeader() {
|
||||
for i := range frm.buf[:sizeHeaderIPv4] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// IPv6Frame encapsulates the raw data of an IPv6 packet
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [RFC8200].
|
||||
//
|
||||
// [RFC8200]: https://tools.ietf.org/html/rfc8200
|
||||
type IPv6Frame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (i6frm IPv6Frame) RawData() []byte { return i6frm.buf }
|
||||
|
||||
// Payload returns the contents of the IPv6 packet, which may be zero sized.
|
||||
// Be sure to call [IPv6Frame.ValidateSize] beforehand to avoid panic.
|
||||
func (i6frm IPv6Frame) Payload() []byte {
|
||||
pl := i6frm.PayloadLength()
|
||||
return i6frm.buf[sizeHeaderIPv6 : sizeHeaderIPv6+pl]
|
||||
}
|
||||
|
||||
// VersionTrafficAndFlow returns the version, Traffic and Flow label fields of the IPv6 header.
|
||||
// See [IPToS] Traffic Class. Version should be 6 for IPv6.
|
||||
func (i6frm IPv6Frame) VersionTrafficAndFlow() (version uint8, tos IPToS, flow uint32) {
|
||||
v := binary.BigEndian.Uint32(i6frm.buf[0:4])
|
||||
version = uint8(v >> (32 - 4))
|
||||
tos = IPToS(v >> (32 - 12))
|
||||
flow = v & 0x000f_ffff
|
||||
return version, tos, flow
|
||||
}
|
||||
|
||||
// SetVersionTrafficAndFlow sets the version, ToS and Flow label in the IPv6 header. Version must be equal to 6.
|
||||
// See [IPv6Frame.VersionTrafficAndFlow].
|
||||
func (i6frm IPv6Frame) SetVersionTrafficAndFlow(version uint8, tos IPToS, flow uint32) {
|
||||
v := flow | uint32(tos)<<(32-12) | uint32(version)<<(32-4)
|
||||
binary.BigEndian.PutUint32(i6frm.buf[0:4], v)
|
||||
}
|
||||
|
||||
// PayloadLength returns the size of payload in octets(bytes) including any extension headers.
|
||||
// The length is set to zero when a Hop-by-Hop extension header carries a Jumbo Payload option.
|
||||
func (i6frm IPv6Frame) PayloadLength() uint16 {
|
||||
return binary.BigEndian.Uint16(i6frm.buf[4:6])
|
||||
}
|
||||
|
||||
// SetPayloadLength sets the payload length field of the IPv6 header. See [IPv6Frame.PayloadLength].
|
||||
func (i6frm IPv6Frame) SetPayloadLength(pl uint16) {
|
||||
binary.BigEndian.PutUint16(i6frm.buf[4:6], pl)
|
||||
}
|
||||
|
||||
// NextHeader returns the Next Header field of the IPv6 header which usually specifies the transport layer
|
||||
// protocol used by packet's payload.
|
||||
func (i6frm IPv6Frame) NextHeader() IPProto {
|
||||
return IPProto(i6frm.buf[6])
|
||||
}
|
||||
|
||||
// SetNextHeader sets the Next Header (protocol) field of the IPv6 header. See [IPv6Frame.NextHeader].
|
||||
func (i6frm IPv6Frame) SetNextHeader(proto IPProto) {
|
||||
i6frm.buf[6] = uint8(proto)
|
||||
}
|
||||
|
||||
// HopLimit returns the Hop Limit of the IPv6 header.
|
||||
// This value is decremented by one at each forwarding node and the packet is discarded if it becomes 0.
|
||||
// However, the destination node should process the packet normally even if received with a hop limit of 0.
|
||||
func (i6frm IPv6Frame) HopLimit() uint8 {
|
||||
return i6frm.buf[7]
|
||||
}
|
||||
|
||||
// SetHopLimit sets the Hop Limit field of the IPv6 header. See [IPv6Frame.HopLimiy].
|
||||
func (i6frm IPv6Frame) SetHopLimit(hop uint8) {
|
||||
i6frm.buf[7] = hop
|
||||
}
|
||||
|
||||
// SourceAddr returns pointer to the sending node unicast IPv6 address in the IP header.
|
||||
func (i6frm IPv6Frame) SourceAddr() *[16]byte {
|
||||
return (*[16]byte)(i6frm.buf[8:24])
|
||||
}
|
||||
|
||||
// DestinationAddr returns pointer to the destination node unicast or multicast IPv6 address in the IP header.
|
||||
func (i6frm IPv6Frame) DestinationAddr() *[16]byte {
|
||||
return (*[16]byte)(i6frm.buf[24:40])
|
||||
}
|
||||
|
||||
func (ifrm IPv6Frame) crcWritePseudo(crc *CRC791) {
|
||||
crc.Write(ifrm.SourceAddr()[:])
|
||||
crc.Write(ifrm.DestinationAddr()[:])
|
||||
crc.AddUint32(uint32(ifrm.PayloadLength()))
|
||||
crc.AddUint32(uint32(ifrm.NextHeader()))
|
||||
}
|
||||
|
||||
// ClearHeader zeros out the header contents.
|
||||
func (frm IPv6Frame) ClearHeader() {
|
||||
for i := range frm.buf[:sizeHeaderIPv6] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// TCPFrame encapsulates the raw data of a TCP segment
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [RFC9293].
|
||||
//
|
||||
// [RFC9293]: https://datatracker.ietf.org/doc/html/rfc9293
|
||||
type TCPFrame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (tfrm TCPFrame) RawData() []byte { return tfrm.buf }
|
||||
|
||||
// SourcePort identifies the sending port of the TCP packet. Must be non-zero.
|
||||
func (tfrm TCPFrame) SourcePort() uint16 {
|
||||
return binary.BigEndian.Uint16(tfrm.buf[0:2])
|
||||
}
|
||||
|
||||
// SetSourcePort sets TCP source port. See [TCPFrame.SetSourcePort]
|
||||
func (tfrm TCPFrame) SetSourcePort(src uint16) {
|
||||
binary.BigEndian.PutUint16(tfrm.buf[0:2], src)
|
||||
}
|
||||
|
||||
// DestinationPort identifies the receiving port for the TCP packet. Must be non-zero.
|
||||
func (tfrm TCPFrame) DestinationPort() uint16 {
|
||||
return binary.BigEndian.Uint16(tfrm.buf[2:4])
|
||||
}
|
||||
|
||||
// SetDestinationPort sets TCP destination port. See [TCPFrame.DestinationPort]
|
||||
func (tfrm TCPFrame) SetDestinationPort(dst uint16) {
|
||||
binary.BigEndian.PutUint16(tfrm.buf[2:4], dst)
|
||||
}
|
||||
|
||||
// Seq returns sequence number of the first data octet in this segment (except when SYN present)
|
||||
// If SYN present this is the Initial Sequence Number (ISN) and the first data octet would be ISN+1.
|
||||
func (tfrm TCPFrame) Seq() tcp.Value {
|
||||
return tcp.Value(binary.BigEndian.Uint32(tfrm.buf[4:8]))
|
||||
}
|
||||
|
||||
// SetSeq sets Seq field. See [TCPFrame.Seq].
|
||||
func (tfrm TCPFrame) SetSeq(v tcp.Value) {
|
||||
binary.BigEndian.PutUint32(tfrm.buf[4:8], uint32(v))
|
||||
}
|
||||
|
||||
// Ack is the next sequence number (Seq field) the sender is expecting to receive (when ACK is present).
|
||||
// In other words an Ack of X indicates all octets up to but not including X have been received.
|
||||
// Once a connection is established the ACK flag should always be set.
|
||||
func (tfrm TCPFrame) Ack() tcp.Value {
|
||||
return tcp.Value(binary.BigEndian.Uint32(tfrm.buf[8:12]))
|
||||
}
|
||||
|
||||
// SetAck sets Ack field. See [TCPFrame.Ack].
|
||||
func (tfrm TCPFrame) SetAck(v tcp.Value) {
|
||||
binary.BigEndian.PutUint32(tfrm.buf[8:12], uint32(v))
|
||||
}
|
||||
|
||||
// OffsetAndFlags returns the offset and flag fields of TCP header.
|
||||
// Offset is amount of 32-bit words used for TCP header including TCP options (see [TCPFrame.HeaderLength]).
|
||||
// See [tcp.Flags] for more information on TCP flags.
|
||||
func (tfrm TCPFrame) OffsetAndFlags() (offset uint8, flags tcp.Flags) {
|
||||
v := binary.BigEndian.Uint16(tfrm.buf[12:14])
|
||||
offset = uint8(v >> 12)
|
||||
flags = tcp.Flags(v).Mask()
|
||||
return offset, flags
|
||||
}
|
||||
|
||||
// SetOffsetAndFlags returns offset and flag fields of TCP header. See [TCPFrame.OffsetAndFlags].
|
||||
func (tfrm TCPFrame) SetOffsetAndFlags(offset uint8, flags tcp.Flags) {
|
||||
v := uint16(offset)<<12 | uint16(flags.Mask())
|
||||
binary.BigEndian.PutUint16(tfrm.buf[12:14], v)
|
||||
}
|
||||
|
||||
// HeaderLength uses Offset field to calculate the total length of
|
||||
// the TCP header including options. Performs no validation.
|
||||
func (tfrm TCPFrame) HeaderLength() (tcpWords int) {
|
||||
offset, _ := tfrm.OffsetAndFlags()
|
||||
return 4 * int(offset)
|
||||
}
|
||||
|
||||
func (tfrm TCPFrame) WindowSize() uint16 { return binary.BigEndian.Uint16(tfrm.buf[14:16]) }
|
||||
func (tfrm TCPFrame) SetWindowSize(v uint16) {
|
||||
binary.BigEndian.PutUint16(tfrm.buf[14:16], v)
|
||||
}
|
||||
|
||||
// CRC returns the checksum field in the TCP header.
|
||||
func (tfrm TCPFrame) CRC() uint16 {
|
||||
return binary.BigEndian.Uint16(tfrm.buf[16:18])
|
||||
}
|
||||
|
||||
// SetCRC sets the checksum field of the TCP header. See [TCPFrame.CRC].
|
||||
func (tfrm TCPFrame) SetCRC(checksum uint16) {
|
||||
binary.BigEndian.PutUint16(tfrm.buf[16:18], checksum)
|
||||
}
|
||||
|
||||
// CalculateIPv4CRC returns the CRC for the TCP header over an IPv4 protocol.
|
||||
func (tfrm TCPFrame) CalculateIPv4CRC(ifrm IPv4Frame) uint16 {
|
||||
var crc CRC791
|
||||
ifrm.crcWriteTCPPseudo(&crc)
|
||||
expectLen := int(ifrm.TotalLength()) - ifrm.HeaderLength()
|
||||
if expectLen != len(tfrm.buf) {
|
||||
println("unexpected TCP buffer length mismatches IPv4 header total length", len(tfrm.buf), expectLen)
|
||||
}
|
||||
tfrm.crcWrite(&crc)
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
// CalculateIPv4CRC returns the CRC for the TCP header over an IPv4 protocol.
|
||||
func (tfrm TCPFrame) CalculateIPv6CRC(ifrm IPv6Frame) uint16 {
|
||||
var crc CRC791
|
||||
ifrm.crcWritePseudo(&crc)
|
||||
expectLen := int(ifrm.PayloadLength())
|
||||
if expectLen != len(tfrm.buf) {
|
||||
println("unexpected TCP buffer length mismatches IPv4 header total length", len(tfrm.buf), expectLen)
|
||||
}
|
||||
tfrm.crcWrite(&crc)
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
func (tfrm TCPFrame) crcWrite(crc *CRC791) {
|
||||
// Write excluding CRC
|
||||
crc.Write(tfrm.buf[:16])
|
||||
crc.Write(tfrm.buf[18:])
|
||||
}
|
||||
|
||||
func (tfrm TCPFrame) UrgentPtr() uint16 { return binary.BigEndian.Uint16(tfrm.buf[18:20]) }
|
||||
func (tfrm TCPFrame) SetUrgentPtr(up uint16) { binary.BigEndian.PutUint16(tfrm.buf[18:20], up) }
|
||||
|
||||
// Payload returns the payload content section of the TCP packet (not including TCP options).
|
||||
// Be sure to call [TCPFrame.ValidateSize] beforehand to avoid panic.
|
||||
func (tfrm TCPFrame) Payload() []byte {
|
||||
return tfrm.buf[tfrm.HeaderLength():]
|
||||
}
|
||||
|
||||
// Segment returns the [tcp.Segment] representation of the TCP header and data length.
|
||||
func (tfrm TCPFrame) Segment(payloadSize int) tcp.Segment {
|
||||
if payloadSize > math.MaxUint32 {
|
||||
panic("TCP overflow payload size")
|
||||
}
|
||||
return tcp.Segment{
|
||||
SEQ: tfrm.Seq(),
|
||||
ACK: tfrm.Ack(),
|
||||
WND: tcp.Size(tfrm.WindowSize()),
|
||||
DATALEN: tcp.Size(payloadSize),
|
||||
Flags: tcp.Flags(binary.BigEndian.Uint16(tfrm.buf[12:14])).Mask(),
|
||||
}
|
||||
}
|
||||
|
||||
// Options returns the TCP option buffer portion of the frame. The returned slice may be zero length.
|
||||
// Be sure to call [TCPFrame.ValidateSize] beforehand to avoid panic.
|
||||
func (tfrm TCPFrame) Options() []byte {
|
||||
return tfrm.buf[sizeHeaderTCP:tfrm.HeaderLength()]
|
||||
}
|
||||
|
||||
// ClearHeader zeros out the fixed(non-variable) header contents.
|
||||
func (frm TCPFrame) ClearHeader() {
|
||||
for i := range frm.buf[:sizeHeaderTCP] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (tfrm TCPFrame) String() string {
|
||||
seg := tfrm.Segment(len(tfrm.Payload()))
|
||||
return fmt.Sprintf("%+v", seg)
|
||||
}
|
||||
|
||||
// UDPFrame encapsulates the raw data of a UDP datagram
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [RFC768].
|
||||
//
|
||||
// [RFC768]: https://tools.ietf.org/html/rfc768
|
||||
type UDPFrame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (ufrm UDPFrame) RawData() []byte { return ufrm.buf }
|
||||
|
||||
// SourcePort identifies the sending port for the UDP packet. Must be non-zero.
|
||||
func (ufrm UDPFrame) SourcePort() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[0:2])
|
||||
}
|
||||
|
||||
// SetSourcePort sets UDP source port. See [UDPFrame.SourcePort]
|
||||
func (ufrm UDPFrame) SetSourcePort(src uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[0:2], src)
|
||||
}
|
||||
|
||||
// DestinationPort identifies the receiving port for the UDP packet. Must be non-zero.
|
||||
func (ufrm UDPFrame) DestinationPort() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[2:4])
|
||||
}
|
||||
|
||||
// SetDestinationPort sets UDP destination port. See [UDPFrame.DestinationPort]
|
||||
func (ufrm UDPFrame) SetDestinationPort(dst uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[2:4], dst)
|
||||
}
|
||||
|
||||
// Length specifies length in bytes of UDP header and UDP payload. The minimum length
|
||||
// is 8 bytes (UDP header length). This field should match the result of the IP header
|
||||
// TotalLength field minus the IP header size: udp.Length == ip.TotalLength - 4*ip.IHL
|
||||
func (ufrm UDPFrame) Length() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[4:6])
|
||||
}
|
||||
|
||||
// SetLength sets the UDP header's length field. See [UDPFrame.Length].
|
||||
func (ufrm UDPFrame) SetLength(length uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[4:6], length)
|
||||
}
|
||||
|
||||
// CRC returns the checksum field in the UDP header.
|
||||
func (ufrm UDPFrame) CRC() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[6:8])
|
||||
}
|
||||
|
||||
// SetCRC sets the UDP header's CRC field. See [UDPFrame.CRC].
|
||||
func (ufrm UDPFrame) SetCRC(checksum uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[6:8], checksum)
|
||||
}
|
||||
|
||||
// Payload returns the payload content section of the UDP packet.
|
||||
// Be sure to call [UDPFrame.ValidateSize] beforehand to avoid panic.
|
||||
func (ufrm UDPFrame) Payload() []byte {
|
||||
l := ufrm.Length()
|
||||
return ufrm.buf[sizeHeaderUDP:l]
|
||||
}
|
||||
|
||||
func (ufrm UDPFrame) CalculateIPv4Checksum(ifrm IPv4Frame) uint16 {
|
||||
var crc CRC791
|
||||
ifrm.crcWriteUDPPseudo(&crc)
|
||||
crc.AddUint16(ufrm.Length())
|
||||
crc.AddUint16(ufrm.SourcePort())
|
||||
crc.AddUint16(ufrm.DestinationPort())
|
||||
crc.AddUint16(ufrm.Length()) // Length double tap.
|
||||
crc.Write(ufrm.Payload())
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
func (ufrm UDPFrame) CalculateIPv6Checksum(ifrm IPv6Frame) uint16 {
|
||||
var crc CRC791
|
||||
ifrm.crcWritePseudo(&crc)
|
||||
crc.AddUint16(ufrm.SourcePort())
|
||||
crc.AddUint16(ufrm.DestinationPort())
|
||||
crc.AddUint16(ufrm.Length()) // Length double tap.
|
||||
crc.Write(ufrm.Payload())
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
// ClearHeader zeros out the header contents.
|
||||
func (frm UDPFrame) ClearHeader() {
|
||||
for i := range frm.buf[:sizeHeaderUDP] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
+16
-11
@@ -5,7 +5,9 @@ import (
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/ipv4"
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
"github.com/soypat/lneto/tcp"
|
||||
)
|
||||
|
||||
@@ -47,14 +49,14 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
|
||||
hasIPOpt = ri&(1<<1) != 0
|
||||
hasTCPOpt = ri&(1<<2) != 0
|
||||
)
|
||||
var etherType lneto.EtherType = lneto.EtherTypeIPv4
|
||||
var etherType ethernet.Type = ethernet.TypeIPv4
|
||||
var ipOpts []byte
|
||||
if hasIPOpt {
|
||||
ipOpts = []byte{1, 2, 3, 4}
|
||||
}
|
||||
ethsize := 14
|
||||
if gen.EnableVLAN && isVLAN {
|
||||
etherType = lneto.EtherTypeVLAN
|
||||
etherType = ethernet.TypeVLAN
|
||||
ethsize = 18
|
||||
}
|
||||
var tcpOpts []byte
|
||||
@@ -66,7 +68,7 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
|
||||
tcpOptWlen := sizeWord(len(tcpOpts))
|
||||
off := len(dst)
|
||||
dst = append(dst, make([]byte, ethsize+sizeHeaderIPv4+4*int(ipOptWLen)+sizeHeaderTCP+4*int(tcpOptWlen)+int(seg.DATALEN))...)
|
||||
efrm, err := lneto.NewEthFrame(dst[off:])
|
||||
efrm, err := ethernet.NewFrame(dst[off:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -75,11 +77,11 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
|
||||
|
||||
efrm.SetEtherType(etherType)
|
||||
if isVLAN {
|
||||
efrm.SetVLANEtherType(lneto.EtherTypeIPv4)
|
||||
efrm.SetVLANEtherType(ethernet.TypeIPv4)
|
||||
efrm.SetVLANTag(1 << 4)
|
||||
}
|
||||
ethernetPayload := efrm.Payload()
|
||||
ifrm, err := lneto.NewIPv4Frame(ethernetPayload)
|
||||
ifrm, err := ipv4.NewFrame(ethernetPayload)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -89,13 +91,13 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
|
||||
ifrm.SetID(uint16(rng.Uint32()))
|
||||
ifrm.SetFlags(0x4001) // Don't fragment.
|
||||
ifrm.SetTTL(64)
|
||||
ifrm.SetProtocol(lneto.IPProtoTCP)
|
||||
ifrm.SetProtocol(lneto2.IPProtoTCP)
|
||||
*ifrm.SourceAddr() = gen.SrcIPv4
|
||||
*ifrm.DestinationAddr() = gen.DstIPv4
|
||||
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
|
||||
|
||||
ipPayload := ifrm.Payload()
|
||||
tfrm, err := lneto.NewTCPFrame(ipPayload)
|
||||
tfrm, err := tcp.NewFrame(ipPayload)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -120,8 +122,11 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
|
||||
// Set Variable section of data.
|
||||
copy(ifrm.Options(), ipOpts)
|
||||
copy(tfrm.Options(), tcpOpts)
|
||||
tcpCRC := tfrm.CalculateIPv4CRC(ifrm)
|
||||
tfrm.SetCRC(tcpCRC)
|
||||
var crc lneto2.CRC791
|
||||
ifrm.CRCWriteTCPPseudo(&crc)
|
||||
tfrm.CRCWrite(&crc)
|
||||
|
||||
tfrm.SetCRC(crc.Sum16())
|
||||
switch {
|
||||
case gen.SrcTCP != tfrm.SourcePort():
|
||||
panic("IP options overwrite TCP header")
|
||||
@@ -136,7 +141,7 @@ func (gen *PacketGen) AppendRandomIPv4TCPPacket(dst []byte, rng *rand.Rand, seg
|
||||
case len(tcpPayload) > 0 && firstPayloadByte != tcpPayload[0]:
|
||||
panic("TCP options overwrite payload")
|
||||
}
|
||||
var vld lneto.Validator
|
||||
var vld lneto2.Validator
|
||||
efrm.ValidateSize(&vld)
|
||||
if err = vld.Err(); err != nil {
|
||||
panic(err)
|
||||
|
||||
+13
-2
@@ -7,6 +7,17 @@ import (
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
)
|
||||
|
||||
// NewIPv4Frame returns a new IPv4Frame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 20.
|
||||
// Users should still call [IPv4Frame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewFrame(buf []byte) (Frame, error) {
|
||||
if len(buf) < sizeHeader {
|
||||
return Frame{buf: nil}, errors.New("ipv4: short buffer")
|
||||
}
|
||||
return Frame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// Frame encapsulates the raw data of an IPv4 packet
|
||||
// and provides methods for manipulating, validating and
|
||||
// retreiving fields and payload data. See [RFC791].
|
||||
@@ -123,14 +134,14 @@ func (ifrm Frame) CalculateHeaderCRC() uint16 {
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
func (ifrm Frame) crcWriteTCPPseudo(crc *lneto2.CRC791) {
|
||||
func (ifrm Frame) CRCWriteTCPPseudo(crc *lneto2.CRC791) {
|
||||
crc.Write(ifrm.SourceAddr()[:])
|
||||
crc.Write(ifrm.DestinationAddr()[:])
|
||||
crc.AddUint16(ifrm.TotalLength() - 4*uint16(ifrm.ihl()))
|
||||
crc.AddUint16(uint16(ifrm.Protocol()))
|
||||
}
|
||||
|
||||
func (ifrm Frame) crcWriteUDPPseudo(crc *lneto2.CRC791) {
|
||||
func (ifrm Frame) CRCWriteUDPPseudo(crc *lneto2.CRC791) {
|
||||
crc.Write(ifrm.SourceAddr()[:])
|
||||
crc.Write(ifrm.DestinationAddr()[:])
|
||||
crc.AddUint16(uint16(ifrm.Protocol()))
|
||||
|
||||
+31
-1
@@ -2,10 +2,22 @@ package ipv6
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
)
|
||||
|
||||
// NewIPv6Frame returns a new IPv6Frame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 40.
|
||||
// Users should still call [IPv6Frame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewFrame(buf []byte) (Frame, error) {
|
||||
if len(buf) < sizeHeader {
|
||||
return Frame{buf: nil}, errShortBuf
|
||||
}
|
||||
return Frame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// Frame encapsulates the raw data of an IPv6 packet
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [RFC8200].
|
||||
@@ -86,7 +98,7 @@ func (i6frm Frame) DestinationAddr() *[16]byte {
|
||||
return (*[16]byte)(i6frm.buf[24:40])
|
||||
}
|
||||
|
||||
func (i6frm Frame) crcWritePseudo(crc *lneto2.CRC791) {
|
||||
func (i6frm Frame) CRCWritePseudo(crc *lneto2.CRC791) {
|
||||
crc.Write(i6frm.SourceAddr()[:])
|
||||
crc.Write(i6frm.DestinationAddr()[:])
|
||||
crc.AddUint32(uint32(i6frm.PayloadLength()))
|
||||
@@ -99,3 +111,21 @@ func (i6frm Frame) ClearHeader() {
|
||||
i6frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Validate API.
|
||||
//
|
||||
|
||||
var (
|
||||
errShortFrame = errors.New("ipv6: short frame")
|
||||
errShortBuf = errors.New("ipv6: short buffer for frame")
|
||||
)
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (i6frm Frame) ValidateSize(v *lneto2.Validator) {
|
||||
tl := i6frm.PayloadLength()
|
||||
if int(tl)+sizeHeader > len(i6frm.RawData()) {
|
||||
v.AddError(errShortFrame)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-118
@@ -1,115 +1,6 @@
|
||||
package lneto2
|
||||
|
||||
//go:generate stringer -type=EtherType,IPProto,ARPOp -linecomment -output stringers.go .
|
||||
|
||||
type EtherType uint16
|
||||
|
||||
// IsSize returns true if the EtherType is actually the size of the payload
|
||||
// and should NOT be interpreted as an EtherType.
|
||||
func (et EtherType) IsSize() bool { return et <= 1500 }
|
||||
|
||||
// Ethernet type flags
|
||||
const (
|
||||
EtherTypeIPv4 EtherType = 0x0800 // IPv4
|
||||
EtherTypeARP EtherType = 0x0806 // ARP
|
||||
EtherTypeWakeOnLAN EtherType = 0x0842 // wake on LAN
|
||||
EtherTypeTRILL EtherType = 0x22F3 // TRILL
|
||||
EtherTypeDECnetPhase4 EtherType = 0x6003 // DECnetPhase4
|
||||
EtherTypeRARP EtherType = 0x8035 // RARP
|
||||
EtherTypeAppleTalk EtherType = 0x809B // AppleTalk
|
||||
EtherTypeAARP EtherType = 0x80F3 // AARP
|
||||
EtherTypeIPX1 EtherType = 0x8137 // IPx1
|
||||
EtherTypeIPX2 EtherType = 0x8138 // IPx2
|
||||
EtherTypeQNXQnet EtherType = 0x8204 // QNXQnet
|
||||
EtherTypeIPv6 EtherType = 0x86DD // IPv6
|
||||
EtherTypeEthernetFlowControl EtherType = 0x8808 // EthernetFlowCtl
|
||||
EtherTypeIEEE802_3 EtherType = 0x8809 // IEEE802.3
|
||||
EtherTypeCobraNet EtherType = 0x8819 // CobraNet
|
||||
EtherTypeMPLSUnicast EtherType = 0x8847 // MPLS Unicast
|
||||
EtherTypeMPLSMulticast EtherType = 0x8848 // MPLS Multicast
|
||||
EtherTypePPPoEDiscovery EtherType = 0x8863 // PPPoE discovery
|
||||
EtherTypePPPoESession EtherType = 0x8864 // PPPoE session
|
||||
EtherTypeJumboFrames EtherType = 0x8870 // jumbo frames
|
||||
EtherTypeHomePlug1_0MME EtherType = 0x887B // home plug 1 0mme
|
||||
EtherTypeIEEE802_1X EtherType = 0x888E // IEEE 802.1x
|
||||
EtherTypePROFINET EtherType = 0x8892 // profinet
|
||||
EtherTypeHyperSCSI EtherType = 0x889A // hyper SCSI
|
||||
EtherTypeAoE EtherType = 0x88A2 // AoE
|
||||
EtherTypeEtherCAT EtherType = 0x88A4 // EtherCAT
|
||||
EtherTypeEthernetPowerlink EtherType = 0x88AB // Ethernet powerlink
|
||||
EtherTypeLLDP EtherType = 0x88CC // LLDP
|
||||
EtherTypeSERCOS3 EtherType = 0x88CD // SERCOS3
|
||||
EtherTypeHomePlugAVMME EtherType = 0x88E1 // home plug AVMME
|
||||
EtherTypeMRP EtherType = 0x88E3 // MRP
|
||||
EtherTypeIEEE802_1AE EtherType = 0x88E5 // IEEE 802.1ae
|
||||
EtherTypeIEEE1588 EtherType = 0x88F7 // IEEE 1588
|
||||
EtherTypeIEEE802_1ag EtherType = 0x8902 // IEEE 802.1ag
|
||||
EtherTypeFCoE EtherType = 0x8906 // FCoE
|
||||
EtherTypeFCoEInit EtherType = 0x8914 // FCoE init
|
||||
EtherTypeRoCE EtherType = 0x8915 // RoCE
|
||||
EtherTypeCTP EtherType = 0x9000 // CTP
|
||||
EtherTypeVeritasLLT EtherType = 0xCAFE // Veritas LLT
|
||||
EtherTypeVLAN EtherType = 0x8100 // VLAN
|
||||
EtherTypeServiceVLAN EtherType = 0x88a8 // service VLAN
|
||||
// minEthPayload is the minimum payload size for an Ethernet frame, assuming
|
||||
// that no 802.1Q VLAN tags are present.
|
||||
minEthPayload = 46
|
||||
)
|
||||
|
||||
// VLANTag holds priority (PCP) Drop indicator (DEI) and VLAN ID bits of the VLAN tag field.
|
||||
type VLANTag uint16
|
||||
|
||||
// DropEligibleIndicator returns true if the DEI bit is set.
|
||||
// DEI may be used separately or in conjunction with PCP to indicate frames eligible to be dropped in the presence of congestion.
|
||||
func (vt VLANTag) DropEligibleIndicator() bool { return vt&(1<<3) != 0 }
|
||||
|
||||
// PriorityCodePoint is 3-bit field which refers to the IEEE 802.1p class of service (CoS) and maps to the frame priority level. Different PCP values can be used to prioritize different classes of traffic
|
||||
func (vt VLANTag) PriorityCodePoint() uint8 { return uint8(vt & 0b111) }
|
||||
|
||||
// VLANIdentifier 12 bit field which specifies which VLAN the frame belongs to. Values of 0 and 4095 are reserved.
|
||||
func (vt VLANTag) VLANIdentifier() uint16 { return uint16(vt) >> 4 }
|
||||
|
||||
// IPToS represents the Traffic Class (a.k.a Type of Service).
|
||||
type IPToS uint8
|
||||
|
||||
// DS returns the top 6 bits of the IPv4 ToS holding the Differentiated Services field
|
||||
// which is used to classify packets.
|
||||
func (tos IPToS) DS() uint8 { return uint8(tos) >> 2 }
|
||||
|
||||
// ECN is the Explicit Congestion Notification which provides congestion control and non-congestion control traffic.
|
||||
func (tos IPToS) ECN() uint8 { return uint8(tos & 0b11) }
|
||||
|
||||
// IPv4Flags holds fragmentation field data of an IPv4 header.
|
||||
type IPv4Flags uint16
|
||||
|
||||
// IsEvil returns true if evil bit set as per [RFC3514].
|
||||
//
|
||||
// [RFC3514]: https://datatracker.ietf.org/doc/html/rfc3514
|
||||
func (f IPv4Flags) IsEvil() bool { return f&2000 != 0 }
|
||||
|
||||
// DontFragment specifies whether the datagram can not be fragmented.
|
||||
// This can be used when sending packets to a host that does not have resources to perform reassembly of fragments.
|
||||
// If the DontFragment(DF) flag is set, and fragmentation is required to route the packet, then the packet is dropped.
|
||||
func (f IPv4Flags) DontFragment() bool { return f&0x4000 != 0 }
|
||||
|
||||
// MoreFragments is cleared for unfragmented packets.
|
||||
// For fragmented packets, all fragments except the last have the MF flag set.
|
||||
// The last fragment has a non-zero Fragment Offset field, so it can still be differentiated from an unfragmented packet.
|
||||
func (f IPv4Flags) MoreFragments() bool { return f&0x8000 != 0 }
|
||||
|
||||
// FragmentOffset specifies the offset of a particular fragment relative to the beginning of the original unfragmented IP datagram.
|
||||
// Fragments are specified in units of 8 bytes, which is why fragment lengths are always a multiple of 8; except the last, which may be smaller.
|
||||
// The fragmentation offset value for the first fragment is always 0.
|
||||
func (f IPv4Flags) FragmentOffset() uint16 { return uint16(f) & 0x1fff }
|
||||
|
||||
const (
|
||||
sizeHeaderIPv4 = 20
|
||||
sizeHeaderTCP = 20
|
||||
sizeHeaderEthNoVLAN = 14
|
||||
sizeHeaderUDP = 8
|
||||
sizeHeaderARPv4 = 28
|
||||
sizeHeaderIPv6 = 40
|
||||
)
|
||||
//go:generate stringer -type=IPProto -linecomment -output stringers.go .
|
||||
|
||||
// IPProto represents the IP protocol number.
|
||||
type IPProto uint8
|
||||
@@ -258,11 +149,3 @@ const (
|
||||
IPProtoAGGFRAG IPProto = 144 // AGGFRAG Encapsulation payload for ESP
|
||||
IPProtoNSH IPProto = 145 // Network Service Header
|
||||
)
|
||||
|
||||
// ARPOp represents the type of ARP packet, either request or reply/response.
|
||||
type ARPOp uint8
|
||||
|
||||
const (
|
||||
ARPRequest ARPOp = 1 // request
|
||||
ARPReply ARPOp = 2 // reply
|
||||
)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package lneto_test
|
||||
package lneto2_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/internal/ltesto"
|
||||
"github.com/soypat/lneto/ipv4"
|
||||
"github.com/soypat/lneto/tcp"
|
||||
)
|
||||
|
||||
@@ -37,31 +38,31 @@ func testMoveTCPPacket(t *testing.T, src, dst []byte) {
|
||||
if len(src) != len(dst) {
|
||||
panic("expect src and dst same length")
|
||||
}
|
||||
efrm, err := lneto.NewEthFrame(src)
|
||||
efrm, err := ethernet.NewFrame(src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
epl := efrm.Payload()
|
||||
ifrm, err := lneto.NewIPv4Frame(epl)
|
||||
ifrm, err := ipv4.NewFrame(epl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ipl := ifrm.Payload()
|
||||
tfrm, err := lneto.NewTCPFrame(ipl)
|
||||
tfrm, err := tcp.NewFrame(ipl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
efrm2, _ := lneto.NewEthFrame(dst)
|
||||
efrm2, _ := ethernet.NewFrame(dst)
|
||||
*efrm2.DestinationHardwareAddr() = *efrm.DestinationHardwareAddr()
|
||||
*efrm2.SourceHardwareAddr() = *efrm.SourceHardwareAddr()
|
||||
efrm2.SetEtherType(efrm.EtherTypeOrSize())
|
||||
if efrm.EtherTypeOrSize() == lneto.EtherTypeVLAN {
|
||||
if efrm.EtherTypeOrSize() == ethernet.TypeVLAN {
|
||||
efrm2.SetVLANTag(efrm.VLANTag())
|
||||
efrm2.SetVLANEtherType(efrm.VLANEtherType())
|
||||
}
|
||||
|
||||
ifrm2, _ := lneto.NewIPv4Frame(efrm2.Payload())
|
||||
ifrm2, _ := ipv4.NewFrame(efrm2.Payload())
|
||||
ifrm2.SetVersionAndIHL(ifrm.VersionAndIHL())
|
||||
ifrm2.SetToS(ifrm.ToS())
|
||||
ifrm2.SetFlags(ifrm.Flags())
|
||||
@@ -73,7 +74,7 @@ func testMoveTCPPacket(t *testing.T, src, dst []byte) {
|
||||
*ifrm2.SourceAddr() = *ifrm.SourceAddr()
|
||||
*ifrm2.DestinationAddr() = *ifrm.DestinationAddr()
|
||||
|
||||
tfrm2, _ := lneto.NewTCPFrame(ifrm2.Payload())
|
||||
tfrm2, _ := tcp.NewFrame(ifrm2.Payload())
|
||||
tfrm2.SetSourcePort(tfrm.SourcePort())
|
||||
tfrm2.SetDestinationPort(tfrm.DestinationPort())
|
||||
tfrm2.SetSeq(tfrm.Seq())
|
||||
+1
-119
@@ -1,108 +1,9 @@
|
||||
// Code generated by "stringer -type=EtherType,IPProto,ARPOp -linecomment -output stringers.go ."; DO NOT EDIT.
|
||||
// Code generated by "stringer -type=IPProto -linecomment -output stringers.go ."; DO NOT EDIT.
|
||||
|
||||
package lneto2
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[EtherTypeIPv4-2048]
|
||||
_ = x[EtherTypeARP-2054]
|
||||
_ = x[EtherTypeWakeOnLAN-2114]
|
||||
_ = x[EtherTypeTRILL-8947]
|
||||
_ = x[EtherTypeDECnetPhase4-24579]
|
||||
_ = x[EtherTypeRARP-32821]
|
||||
_ = x[EtherTypeAppleTalk-32923]
|
||||
_ = x[EtherTypeAARP-33011]
|
||||
_ = x[EtherTypeIPX1-33079]
|
||||
_ = x[EtherTypeIPX2-33080]
|
||||
_ = x[EtherTypeQNXQnet-33284]
|
||||
_ = x[EtherTypeIPv6-34525]
|
||||
_ = x[EtherTypeEthernetFlowControl-34824]
|
||||
_ = x[EtherTypeIEEE802_3-34825]
|
||||
_ = x[EtherTypeCobraNet-34841]
|
||||
_ = x[EtherTypeMPLSUnicast-34887]
|
||||
_ = x[EtherTypeMPLSMulticast-34888]
|
||||
_ = x[EtherTypePPPoEDiscovery-34915]
|
||||
_ = x[EtherTypePPPoESession-34916]
|
||||
_ = x[EtherTypeJumboFrames-34928]
|
||||
_ = x[EtherTypeHomePlug1_0MME-34939]
|
||||
_ = x[EtherTypeIEEE802_1X-34958]
|
||||
_ = x[EtherTypePROFINET-34962]
|
||||
_ = x[EtherTypeHyperSCSI-34970]
|
||||
_ = x[EtherTypeAoE-34978]
|
||||
_ = x[EtherTypeEtherCAT-34980]
|
||||
_ = x[EtherTypeEthernetPowerlink-34987]
|
||||
_ = x[EtherTypeLLDP-35020]
|
||||
_ = x[EtherTypeSERCOS3-35021]
|
||||
_ = x[EtherTypeHomePlugAVMME-35041]
|
||||
_ = x[EtherTypeMRP-35043]
|
||||
_ = x[EtherTypeIEEE802_1AE-35045]
|
||||
_ = x[EtherTypeIEEE1588-35063]
|
||||
_ = x[EtherTypeIEEE802_1ag-35074]
|
||||
_ = x[EtherTypeFCoE-35078]
|
||||
_ = x[EtherTypeFCoEInit-35092]
|
||||
_ = x[EtherTypeRoCE-35093]
|
||||
_ = x[EtherTypeCTP-36864]
|
||||
_ = x[EtherTypeVeritasLLT-51966]
|
||||
_ = x[EtherTypeVLAN-33024]
|
||||
_ = x[EtherTypeServiceVLAN-34984]
|
||||
}
|
||||
|
||||
const _EtherType_name = "IPv4ARPwake on LANTRILLDECnetPhase4RARPAppleTalkAARPVLANIPx1IPx2QNXQnetIPv6EthernetFlowCtlIEEE802.3CobraNetMPLS UnicastMPLS MulticastPPPoE discoveryPPPoE sessionjumbo frameshome plug 1 0mmeIEEE 802.1xprofinethyper SCSIAoEEtherCATservice VLANEthernet powerlinkLLDPSERCOS3home plug AVMMEMRPIEEE 802.1aeIEEE 1588IEEE 802.1agFCoEFCoE initRoCECTPVeritas LLT"
|
||||
|
||||
var _EtherType_map = map[EtherType]string{
|
||||
2048: _EtherType_name[0:4],
|
||||
2054: _EtherType_name[4:7],
|
||||
2114: _EtherType_name[7:18],
|
||||
8947: _EtherType_name[18:23],
|
||||
24579: _EtherType_name[23:35],
|
||||
32821: _EtherType_name[35:39],
|
||||
32923: _EtherType_name[39:48],
|
||||
33011: _EtherType_name[48:52],
|
||||
33024: _EtherType_name[52:56],
|
||||
33079: _EtherType_name[56:60],
|
||||
33080: _EtherType_name[60:64],
|
||||
33284: _EtherType_name[64:71],
|
||||
34525: _EtherType_name[71:75],
|
||||
34824: _EtherType_name[75:90],
|
||||
34825: _EtherType_name[90:99],
|
||||
34841: _EtherType_name[99:107],
|
||||
34887: _EtherType_name[107:119],
|
||||
34888: _EtherType_name[119:133],
|
||||
34915: _EtherType_name[133:148],
|
||||
34916: _EtherType_name[148:161],
|
||||
34928: _EtherType_name[161:173],
|
||||
34939: _EtherType_name[173:189],
|
||||
34958: _EtherType_name[189:200],
|
||||
34962: _EtherType_name[200:208],
|
||||
34970: _EtherType_name[208:218],
|
||||
34978: _EtherType_name[218:221],
|
||||
34980: _EtherType_name[221:229],
|
||||
34984: _EtherType_name[229:241],
|
||||
34987: _EtherType_name[241:259],
|
||||
35020: _EtherType_name[259:263],
|
||||
35021: _EtherType_name[263:270],
|
||||
35041: _EtherType_name[270:285],
|
||||
35043: _EtherType_name[285:288],
|
||||
35045: _EtherType_name[288:300],
|
||||
35063: _EtherType_name[300:309],
|
||||
35074: _EtherType_name[309:321],
|
||||
35078: _EtherType_name[321:325],
|
||||
35092: _EtherType_name[325:334],
|
||||
35093: _EtherType_name[334:338],
|
||||
36864: _EtherType_name[338:341],
|
||||
51966: _EtherType_name[341:352],
|
||||
}
|
||||
|
||||
func (i EtherType) String() string {
|
||||
if str, ok := _EtherType_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return "EtherType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
@@ -289,22 +190,3 @@ func (i IPProto) String() string {
|
||||
return "IPProto(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ARPRequest-1]
|
||||
_ = x[ARPReply-2]
|
||||
}
|
||||
|
||||
const _ARPOp_name = "requestreply"
|
||||
|
||||
var _ARPOp_index = [...]uint8{0, 7, 12}
|
||||
|
||||
func (i ARPOp) String() string {
|
||||
i -= 1
|
||||
if i >= ARPOp(len(_ARPOp_index)-1) {
|
||||
return "ARPOp(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||
}
|
||||
return _ARPOp_name[_ARPOp_index[i]:_ARPOp_index[i+1]]
|
||||
}
|
||||
|
||||
-310
@@ -1,310 +0,0 @@
|
||||
// Code generated by "stringer -type=EtherType,IPProto,ARPOp -linecomment -output stringers.go ."; DO NOT EDIT.
|
||||
|
||||
package lneto
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[EtherTypeIPv4-2048]
|
||||
_ = x[EtherTypeARP-2054]
|
||||
_ = x[EtherTypeWakeOnLAN-2114]
|
||||
_ = x[EtherTypeTRILL-8947]
|
||||
_ = x[EtherTypeDECnetPhase4-24579]
|
||||
_ = x[EtherTypeRARP-32821]
|
||||
_ = x[EtherTypeAppleTalk-32923]
|
||||
_ = x[EtherTypeAARP-33011]
|
||||
_ = x[EtherTypeIPX1-33079]
|
||||
_ = x[EtherTypeIPX2-33080]
|
||||
_ = x[EtherTypeQNXQnet-33284]
|
||||
_ = x[EtherTypeIPv6-34525]
|
||||
_ = x[EtherTypeEthernetFlowControl-34824]
|
||||
_ = x[EtherTypeIEEE802_3-34825]
|
||||
_ = x[EtherTypeCobraNet-34841]
|
||||
_ = x[EtherTypeMPLSUnicast-34887]
|
||||
_ = x[EtherTypeMPLSMulticast-34888]
|
||||
_ = x[EtherTypePPPoEDiscovery-34915]
|
||||
_ = x[EtherTypePPPoESession-34916]
|
||||
_ = x[EtherTypeJumboFrames-34928]
|
||||
_ = x[EtherTypeHomePlug1_0MME-34939]
|
||||
_ = x[EtherTypeIEEE802_1X-34958]
|
||||
_ = x[EtherTypePROFINET-34962]
|
||||
_ = x[EtherTypeHyperSCSI-34970]
|
||||
_ = x[EtherTypeAoE-34978]
|
||||
_ = x[EtherTypeEtherCAT-34980]
|
||||
_ = x[EtherTypeEthernetPowerlink-34987]
|
||||
_ = x[EtherTypeLLDP-35020]
|
||||
_ = x[EtherTypeSERCOS3-35021]
|
||||
_ = x[EtherTypeHomePlugAVMME-35041]
|
||||
_ = x[EtherTypeMRP-35043]
|
||||
_ = x[EtherTypeIEEE802_1AE-35045]
|
||||
_ = x[EtherTypeIEEE1588-35063]
|
||||
_ = x[EtherTypeIEEE802_1ag-35074]
|
||||
_ = x[EtherTypeFCoE-35078]
|
||||
_ = x[EtherTypeFCoEInit-35092]
|
||||
_ = x[EtherTypeRoCE-35093]
|
||||
_ = x[EtherTypeCTP-36864]
|
||||
_ = x[EtherTypeVeritasLLT-51966]
|
||||
_ = x[EtherTypeVLAN-33024]
|
||||
_ = x[EtherTypeServiceVLAN-34984]
|
||||
}
|
||||
|
||||
const _EtherType_name = "IPv4ARPwake on LANTRILLDECnetPhase4RARPAppleTalkAARPVLANIPx1IPx2QNXQnetIPv6EthernetFlowCtlIEEE802.3CobraNetMPLS UnicastMPLS MulticastPPPoE discoveryPPPoE sessionjumbo frameshome plug 1 0mmeIEEE 802.1xprofinethyper SCSIAoEEtherCATservice VLANEthernet powerlinkLLDPSERCOS3home plug AVMMEMRPIEEE 802.1aeIEEE 1588IEEE 802.1agFCoEFCoE initRoCECTPVeritas LLT"
|
||||
|
||||
var _EtherType_map = map[EtherType]string{
|
||||
2048: _EtherType_name[0:4],
|
||||
2054: _EtherType_name[4:7],
|
||||
2114: _EtherType_name[7:18],
|
||||
8947: _EtherType_name[18:23],
|
||||
24579: _EtherType_name[23:35],
|
||||
32821: _EtherType_name[35:39],
|
||||
32923: _EtherType_name[39:48],
|
||||
33011: _EtherType_name[48:52],
|
||||
33024: _EtherType_name[52:56],
|
||||
33079: _EtherType_name[56:60],
|
||||
33080: _EtherType_name[60:64],
|
||||
33284: _EtherType_name[64:71],
|
||||
34525: _EtherType_name[71:75],
|
||||
34824: _EtherType_name[75:90],
|
||||
34825: _EtherType_name[90:99],
|
||||
34841: _EtherType_name[99:107],
|
||||
34887: _EtherType_name[107:119],
|
||||
34888: _EtherType_name[119:133],
|
||||
34915: _EtherType_name[133:148],
|
||||
34916: _EtherType_name[148:161],
|
||||
34928: _EtherType_name[161:173],
|
||||
34939: _EtherType_name[173:189],
|
||||
34958: _EtherType_name[189:200],
|
||||
34962: _EtherType_name[200:208],
|
||||
34970: _EtherType_name[208:218],
|
||||
34978: _EtherType_name[218:221],
|
||||
34980: _EtherType_name[221:229],
|
||||
34984: _EtherType_name[229:241],
|
||||
34987: _EtherType_name[241:259],
|
||||
35020: _EtherType_name[259:263],
|
||||
35021: _EtherType_name[263:270],
|
||||
35041: _EtherType_name[270:285],
|
||||
35043: _EtherType_name[285:288],
|
||||
35045: _EtherType_name[288:300],
|
||||
35063: _EtherType_name[300:309],
|
||||
35074: _EtherType_name[309:321],
|
||||
35078: _EtherType_name[321:325],
|
||||
35092: _EtherType_name[325:334],
|
||||
35093: _EtherType_name[334:338],
|
||||
36864: _EtherType_name[338:341],
|
||||
51966: _EtherType_name[341:352],
|
||||
}
|
||||
|
||||
func (i EtherType) String() string {
|
||||
if str, ok := _EtherType_map[i]; ok {
|
||||
return str
|
||||
}
|
||||
return "EtherType(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[IPProtoHopByHop-0]
|
||||
_ = x[IPProtoICMP-1]
|
||||
_ = x[IPProtoIGMP-2]
|
||||
_ = x[IPProtoGGP-3]
|
||||
_ = x[IPProtoIPv4-4]
|
||||
_ = x[IPProtoST-5]
|
||||
_ = x[IPProtoTCP-6]
|
||||
_ = x[IPProtoCBT-7]
|
||||
_ = x[IPProtoEGP-8]
|
||||
_ = x[IPProtoIGP-9]
|
||||
_ = x[IPProtoBBNRCCMON-10]
|
||||
_ = x[IPProtoNVP-11]
|
||||
_ = x[IPProtoPUP-12]
|
||||
_ = x[IPProtoARGUS-13]
|
||||
_ = x[IPProtoEMCON-14]
|
||||
_ = x[IPProtoXNET-15]
|
||||
_ = x[IPProtoCHAOS-16]
|
||||
_ = x[IPProtoUDP-17]
|
||||
_ = x[IPProtoMUX-18]
|
||||
_ = x[IPProtoDCNMEAS-19]
|
||||
_ = x[IPProtoHMP-20]
|
||||
_ = x[IPProtoPRM-21]
|
||||
_ = x[IPProtoXNSIDP-22]
|
||||
_ = x[IPProtoTRUNK1-23]
|
||||
_ = x[IPProtoTRUNK2-24]
|
||||
_ = x[IPProtoLEAF1-25]
|
||||
_ = x[IPProtoLEAF2-26]
|
||||
_ = x[IPProtoRDP-27]
|
||||
_ = x[IPProtoIRTP-28]
|
||||
_ = x[IPProtoISO_TP4-29]
|
||||
_ = x[IPProtoNETBLT-30]
|
||||
_ = x[IPProtoMFE_NSP-31]
|
||||
_ = x[IPProtoMERIT_INP-32]
|
||||
_ = x[IPProtoDCCP-33]
|
||||
_ = x[IPProto3PC-34]
|
||||
_ = x[IPProtoIDPR-35]
|
||||
_ = x[IPProtoXTP-36]
|
||||
_ = x[IPProtoDDP-37]
|
||||
_ = x[IPProtoIDPRCMTP-38]
|
||||
_ = x[IPProtoTPPLUSPLUS-39]
|
||||
_ = x[IPProtoIL-40]
|
||||
_ = x[IPProtoIPv6-41]
|
||||
_ = x[IPProtoSDRP-42]
|
||||
_ = x[IPProtoIPv6Route-43]
|
||||
_ = x[IPProtoIPv6Frag-44]
|
||||
_ = x[IPProtoIDRP-45]
|
||||
_ = x[IPProtoRSVP-46]
|
||||
_ = x[IPProtoGRE-47]
|
||||
_ = x[IPProtoDSR-48]
|
||||
_ = x[IPProtoBNA-49]
|
||||
_ = x[IPProtoESP-50]
|
||||
_ = x[IPProtoAH-51]
|
||||
_ = x[IPProtoINLSP-52]
|
||||
_ = x[IPProtoSWIPE-53]
|
||||
_ = x[IPProtoNARP-54]
|
||||
_ = x[IPProtoMOBILE-55]
|
||||
_ = x[IPProtoTLSP-56]
|
||||
_ = x[IPProtoSKIP-57]
|
||||
_ = x[IPProtoIPv6ICMP-58]
|
||||
_ = x[IPProtoIPv6NoNxt-59]
|
||||
_ = x[IPProtoIPv6Opts-60]
|
||||
_ = x[IPProtoCFTP-62]
|
||||
_ = x[IPProtoSATEXPAK-64]
|
||||
_ = x[IPProtoKRYPTOLAN-65]
|
||||
_ = x[IPProtoRVD-66]
|
||||
_ = x[IPProtoIPPC-67]
|
||||
_ = x[IPProtoSATMON-69]
|
||||
_ = x[IPProtoVISA-70]
|
||||
_ = x[IPProtoIPCV-71]
|
||||
_ = x[IPProtoCPNX-72]
|
||||
_ = x[IPProtoCPHB-73]
|
||||
_ = x[IPProtoWSN-74]
|
||||
_ = x[IPProtoPVP-75]
|
||||
_ = x[IPProtoBRSATMON-76]
|
||||
_ = x[IPProtoSUNND-77]
|
||||
_ = x[IPProtoWBMON-78]
|
||||
_ = x[IPProtoWBEXPAK-79]
|
||||
_ = x[IPProtoISOIP-80]
|
||||
_ = x[IPProtoVMTP-81]
|
||||
_ = x[IPProtoSECUREVMTP-82]
|
||||
_ = x[IPProtoVINES-83]
|
||||
_ = x[IPProtoTTP-84]
|
||||
_ = x[IPProtoNSFNETIGP-85]
|
||||
_ = x[IPProtoDGP-86]
|
||||
_ = x[IPProtoTCF-87]
|
||||
_ = x[IPProtoEIGRP-88]
|
||||
_ = x[IPProtoOSPFIGP-89]
|
||||
_ = x[IPProtoSpriteRPC-90]
|
||||
_ = x[IPProtoLARP-91]
|
||||
_ = x[IPProtoMTP-92]
|
||||
_ = x[IPProtoAX25-93]
|
||||
_ = x[IPProtoIPIP-94]
|
||||
_ = x[IPProtoMICP-95]
|
||||
_ = x[IPProtoSCCSP-96]
|
||||
_ = x[IPProtoETHERIP-97]
|
||||
_ = x[IPProtoENCAP-98]
|
||||
_ = x[IPProtoGMTP-100]
|
||||
_ = x[IPProtoIFMP-101]
|
||||
_ = x[IPProtoPNNI-102]
|
||||
_ = x[IPProtoPIM-103]
|
||||
_ = x[IPProtoARIS-104]
|
||||
_ = x[IPProtoSCPS-105]
|
||||
_ = x[IPProtoQNX-106]
|
||||
_ = x[IPProtoAN-107]
|
||||
_ = x[IPProtoIPComp-108]
|
||||
_ = x[IPProtoSNP-109]
|
||||
_ = x[IPProtoCompaqPeer-110]
|
||||
_ = x[IPProtoIPXInIP-111]
|
||||
_ = x[IPProtoVRRP-112]
|
||||
_ = x[IPProtoPGM-113]
|
||||
_ = x[IPProtoL2TP-115]
|
||||
_ = x[IPProtoDDX-116]
|
||||
_ = x[IPProtoIATP-117]
|
||||
_ = x[IPProtoSTP-118]
|
||||
_ = x[IPProtoSRP-119]
|
||||
_ = x[IPProtoUTI-120]
|
||||
_ = x[IPProtoSMP-121]
|
||||
_ = x[IPProtoSM-122]
|
||||
_ = x[IPProtoPTP-123]
|
||||
_ = x[IPProtoISIS-124]
|
||||
_ = x[IPProtoFIRE-125]
|
||||
_ = x[IPProtoCRTP-126]
|
||||
_ = x[IPProtoCRUDP-127]
|
||||
_ = x[IPProtoSSCOPMCE-128]
|
||||
_ = x[IPProtoIPLT-129]
|
||||
_ = x[IPProtoSPS-130]
|
||||
_ = x[IPProtoPIPE-131]
|
||||
_ = x[IPProtoSCTP-132]
|
||||
_ = x[IPProtoFC-133]
|
||||
_ = x[IPProtoRSVP_E2E_IGNORE-134]
|
||||
_ = x[IPProtoMobilityHeader-135]
|
||||
_ = x[IPProtoUDPLite-136]
|
||||
_ = x[IPProtoMPLSInIP-137]
|
||||
_ = x[IPProtoMANET-138]
|
||||
_ = x[IPProtoHIP-139]
|
||||
_ = x[IPProtoShim6-140]
|
||||
_ = x[IPProtoWESP-141]
|
||||
_ = x[IPProtoROHC-142]
|
||||
_ = x[IPProtoEthernet-143]
|
||||
_ = x[IPProtoAGGFRAG-144]
|
||||
_ = x[IPProtoNSH-145]
|
||||
}
|
||||
|
||||
const (
|
||||
_IPProto_name_0 = "IPv6 Hop-by-Hop Option [RFC8200]Internet Control Message [RFC792]Internet Group Management [RFC1112]Gateway-to-Gateway [RFC823]IPv4 encapsulation [RFC2003]Stream [RFC1190, RFC1819]Transmission Control [RFC9293]CBT [Ballardie]Exterior Gateway Protocol [RFC888]any private interior gateway (used by Cisco for their IGRP)BBN RCC MonitoringNetwork Voice Protocol [RFC741]PUPARGUSEMCONCross Net DebuggerChaosUser Datagram [RFC768]MultiplexingDCN Measurement SubsystemsHost Monitoring [RFC869]Packet Radio MeasurementXEROX NS IDPTrunk-1Trunk-2Leaf-1Leaf-2Reliable Data Protocol [RFC908]Internet Reliable Transaction [RFC938]ISO Transport Protocol Class 4 [RFC905]Bulk Data Transfer Protocol [RFC998]MFE Network Services ProtocolMERIT Internodal ProtocolDatagram Congestion Control Protocol [RFC4340]Third Party Connect ProtocolInter-Domain Policy Routing ProtocolXTPDatagram Delivery ProtocolIDPR Control Message Transport ProtoTP++ Transport ProtocolIL Transport ProtocolIPv6 encapsulation [RFC2473]Source Demand Routing ProtocolRouting Header for IPv6 [RFC8200]Fragment Header for IPv6 [RFC8200]Inter-Domain Routing ProtocolReservation Protocol [RFC2205]Generic Routing Encapsulation [RFC2784]Dynamic Source Routing ProtocolBNAEncap Security Payload [RFC4303]Authentication Header [RFC4302]Integrated Net Layer Security TUBAIP with EncryptionNBMA Address Resolution ProtocolIP MobilityTransport Layer Security Protocol using Kryptonet key managementSKIPICMP for IPv6 [RFC8200]No Next Header for IPv6 [RFC8200]Destination Options for IPv6 [RFC8200]"
|
||||
_IPProto_name_1 = "CFTP"
|
||||
_IPProto_name_2 = "SATNET and Backroom EXPAKKryptolanMIT Remote Virtual Disk ProtocolInternet Pluribus Packet Core"
|
||||
_IPProto_name_3 = "SATNET MonitoringVISA ProtocolInternet Packet Core UtilityComputer Protocol Network ExecutiveComputer Protocol Heart BeatWang Span NetworkPacket Video ProtocolBackroom SATNET MonitoringSUN ND PROTOCOL-TemporaryWIDEBAND MonitoringWIDEBAND EXPAKISO Internet ProtocolVMTPSECURE-VMTPVINESTTPNSFNET-IGPDissimilar Gateway ProtocolTCFEIGRPOSPFIGPSprite RPC ProtocolLocus Address Resolution ProtocolMulticast Transport ProtocolAX.25 FramesIP-within-IP Encapsulation ProtocolMobile Internetworking Control Pro.Semaphore Communications Sec. Pro.Ethernet-within-IP EncapsulationEncapsulation Header"
|
||||
_IPProto_name_4 = "GMTPIpsilon Flow Management ProtocolPNNI over IPProtocol Independent MulticastARISSCPSQNXActive NetworksIP Payload Compression ProtocolSitara Networks ProtocolCompaq Peer ProtocolIPX in IPVirtual Router Redundancy ProtocolPGM Reliable Transport Protocol"
|
||||
_IPProto_name_5 = "Layer Two Tunneling Protocol v3D-II Data Exchange (DDX)Interactive Agent Transfer ProtocolSchedule Transfer ProtocolSpectraLink Radio ProtocolUTISimple Message ProtocolSMPerformance Transparency ProtocolISIS over IPv4FIRECombat Radio Transport ProtocolCombat Radio User DatagramSSCOPMCEIPLTSecure Packet ShieldPrivate IP Encapsulation within IPStream Control Transmission ProtocolFibre ChannelRSVP-E2E-IGNOREMobility HeaderUDPLiteMPLS-in-IPMANET ProtocolsHost Identity ProtocolShim6 ProtocolWrapped Encapsulating Security PayloadRobust Header CompressionEthernetAGGFRAG Encapsulation payload for ESPNetwork Service Header"
|
||||
)
|
||||
|
||||
var (
|
||||
_IPProto_index_0 = [...]uint16{0, 32, 65, 100, 127, 155, 180, 210, 225, 259, 318, 336, 367, 370, 375, 380, 398, 403, 425, 437, 463, 487, 511, 523, 530, 537, 543, 549, 580, 618, 657, 693, 722, 747, 793, 821, 857, 860, 886, 922, 945, 966, 994, 1024, 1057, 1091, 1120, 1150, 1189, 1220, 1223, 1255, 1286, 1320, 1338, 1370, 1381, 1445, 1449, 1472, 1505, 1543}
|
||||
_IPProto_index_2 = [...]uint8{0, 25, 34, 66, 95}
|
||||
_IPProto_index_3 = [...]uint16{0, 17, 30, 58, 93, 121, 138, 159, 185, 210, 229, 243, 264, 268, 279, 284, 287, 297, 324, 327, 332, 339, 358, 391, 419, 431, 466, 501, 535, 567, 587}
|
||||
_IPProto_index_4 = [...]uint8{0, 4, 36, 48, 78, 82, 86, 89, 104, 135, 159, 179, 188, 222, 253}
|
||||
_IPProto_index_5 = [...]uint16{0, 31, 55, 90, 116, 142, 145, 168, 170, 203, 217, 221, 252, 278, 286, 290, 310, 344, 380, 393, 408, 423, 430, 440, 455, 477, 491, 529, 554, 562, 599, 621}
|
||||
)
|
||||
|
||||
func (i IPProto) String() string {
|
||||
switch {
|
||||
case i <= 60:
|
||||
return _IPProto_name_0[_IPProto_index_0[i]:_IPProto_index_0[i+1]]
|
||||
case i == 62:
|
||||
return _IPProto_name_1
|
||||
case 64 <= i && i <= 67:
|
||||
i -= 64
|
||||
return _IPProto_name_2[_IPProto_index_2[i]:_IPProto_index_2[i+1]]
|
||||
case 69 <= i && i <= 98:
|
||||
i -= 69
|
||||
return _IPProto_name_3[_IPProto_index_3[i]:_IPProto_index_3[i+1]]
|
||||
case 100 <= i && i <= 113:
|
||||
i -= 100
|
||||
return _IPProto_name_4[_IPProto_index_4[i]:_IPProto_index_4[i+1]]
|
||||
case 115 <= i && i <= 145:
|
||||
i -= 115
|
||||
return _IPProto_name_5[_IPProto_index_5[i]:_IPProto_index_5[i+1]]
|
||||
default:
|
||||
return "IPProto(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ARPRequest-1]
|
||||
_ = x[ARPReply-2]
|
||||
}
|
||||
|
||||
const _ARPOp_name = "requestreply"
|
||||
|
||||
var _ARPOp_index = [...]uint8{0, 7, 12}
|
||||
|
||||
func (i ARPOp) String() string {
|
||||
i -= 1
|
||||
if i >= ARPOp(len(_ARPOp_index)-1) {
|
||||
return "ARPOp(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||
}
|
||||
return _ARPOp_name[_ARPOp_index[i]:_ARPOp_index[i+1]]
|
||||
}
|
||||
+14
-8
@@ -9,14 +9,6 @@ import (
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
)
|
||||
|
||||
var (
|
||||
errShortTCP = errors.New("TCP offset exceeds frame")
|
||||
errBadTCPOff = errors.New("TCP offset invalid")
|
||||
errEvilPacket = errors.New("evil packet")
|
||||
errZeroDstPort = errors.New("TCP zero destination port")
|
||||
errZeroSrcPort = errors.New("TCP zero source port")
|
||||
)
|
||||
|
||||
const (
|
||||
sizeHeaderTCP = 20
|
||||
)
|
||||
@@ -148,6 +140,12 @@ func (tfrm Frame) Segment(payloadSize int) Segment {
|
||||
}
|
||||
}
|
||||
|
||||
func (tfrm Frame) CRCWrite(crc *lneto2.CRC791) {
|
||||
// Write excluding CRC
|
||||
crc.Write(tfrm.buf[:16])
|
||||
crc.Write(tfrm.buf[18:])
|
||||
}
|
||||
|
||||
// SetSegment sets the sequence, acknowledgment, offset, window and flag fields of the TCP header from the the [Segment].
|
||||
// Offset, like in [Frame.SetOffset], is expressed in words with minimum being 5.
|
||||
func (tfrm Frame) SetSegment(seg Segment, offset uint8) {
|
||||
@@ -184,6 +182,14 @@ func (tfrm Frame) String() string {
|
||||
// Validation API
|
||||
//
|
||||
|
||||
var (
|
||||
errShortTCP = errors.New("TCP offset exceeds frame")
|
||||
errBadTCPOff = errors.New("TCP offset invalid")
|
||||
errEvilPacket = errors.New("evil packet")
|
||||
errZeroDstPort = errors.New("TCP zero destination port")
|
||||
errZeroSrcPort = errors.New("TCP zero source port")
|
||||
)
|
||||
|
||||
// func (tfrm Frame) Validate(v *lneto2.Validator) {
|
||||
// tfrm.ValidateSize(v)
|
||||
// tfrm.ValidateExceptCRC(v)
|
||||
|
||||
+8
-6
@@ -5,7 +5,9 @@ import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/ipv4"
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
"github.com/soypat/lneto/tcp"
|
||||
)
|
||||
|
||||
@@ -584,20 +586,20 @@ func TestExchange_helloworld_client(t *testing.T) {
|
||||
}
|
||||
|
||||
func parseSegment(t *testing.T, b []byte) (tcp.Segment, []byte) {
|
||||
var vld lneto.Validator
|
||||
var vld lneto2.Validator
|
||||
t.Helper()
|
||||
efrm, err := lneto.NewEthFrame(b)
|
||||
efrm, err := ethernet.NewFrame(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if efrm.EtherTypeOrSize() != lneto.EtherTypeIPv4 {
|
||||
if efrm.EtherTypeOrSize() != ethernet.TypeIPv4 {
|
||||
t.Fatalf("not IPv4")
|
||||
}
|
||||
efrm.ValidateSize(&vld)
|
||||
if err := vld.Err(); err != nil {
|
||||
t.Fatal(vld.Err())
|
||||
}
|
||||
ifrm, err := lneto.NewIPv4Frame(efrm.Payload())
|
||||
ifrm, err := ipv4.NewFrame(efrm.Payload())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -614,7 +616,7 @@ func parseSegment(t *testing.T, b []byte) (tcp.Segment, []byte) {
|
||||
}
|
||||
|
||||
ipl := ifrm.Payload()
|
||||
tfrm, err := lneto.NewTCPFrame(ipl)
|
||||
tfrm, err := tcp.NewFrame(ipl)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package udp
|
||||
|
||||
const (
|
||||
sizeHeader = 8
|
||||
)
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package udp
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
|
||||
"github.com/soypat/lneto/lneto2"
|
||||
)
|
||||
|
||||
// NewUDPFrame returns a new UDPFrame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 8.
|
||||
// Users should still call [Frame.ValidateSize] before working
|
||||
// with payload/options of frames to avoid panics.
|
||||
func NewFrame(buf []byte) (Frame, error) {
|
||||
if len(buf) < sizeHeader {
|
||||
return Frame{buf: buf}, errors.New("UDP packet too short")
|
||||
}
|
||||
return Frame{buf: buf}, nil
|
||||
}
|
||||
|
||||
// Frame encapsulates the raw data of a UDP datagram
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [RFC768].
|
||||
//
|
||||
// [RFC768]: https://tools.ietf.org/html/rfc768
|
||||
type Frame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (ufrm Frame) RawData() []byte { return ufrm.buf }
|
||||
|
||||
// SourcePort identifies the sending port for the UDP packet. Must be non-zero.
|
||||
func (ufrm Frame) SourcePort() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[0:2])
|
||||
}
|
||||
|
||||
// SetSourcePort sets UDP source port. See [Frame.SourcePort]
|
||||
func (ufrm Frame) SetSourcePort(src uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[0:2], src)
|
||||
}
|
||||
|
||||
// DestinationPort identifies the receiving port for the UDP packet. Must be non-zero.
|
||||
func (ufrm Frame) DestinationPort() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[2:4])
|
||||
}
|
||||
|
||||
// SetDestinationPort sets UDP destination port. See [Frame.DestinationPort]
|
||||
func (ufrm Frame) SetDestinationPort(dst uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[2:4], dst)
|
||||
}
|
||||
|
||||
// Length specifies length in bytes of UDP header and UDP payload. The minimum length
|
||||
// is 8 bytes (UDP header length). This field should match the result of the IP header
|
||||
// TotalLength field minus the IP header size: udp.Length == ip.TotalLength - 4*ip.IHL
|
||||
func (ufrm Frame) Length() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[4:6])
|
||||
}
|
||||
|
||||
// SetLength sets the UDP header's length field. See [Frame.Length].
|
||||
func (ufrm Frame) SetLength(length uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[4:6], length)
|
||||
}
|
||||
|
||||
// CRC returns the checksum field in the UDP header.
|
||||
func (ufrm Frame) CRC() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[6:8])
|
||||
}
|
||||
|
||||
// SetCRC sets the UDP header's CRC field. See [Frame.CRC].
|
||||
func (ufrm Frame) SetCRC(checksum uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[6:8], checksum)
|
||||
}
|
||||
|
||||
// Payload returns the payload content section of the UDP packet.
|
||||
// Be sure to call [Frame.ValidateSize] beforehand to avoid panic.
|
||||
func (ufrm Frame) Payload() []byte {
|
||||
l := ufrm.Length()
|
||||
return ufrm.buf[sizeHeader:l]
|
||||
}
|
||||
|
||||
// func (ufrm Frame) CalculateIPv4Checksum(ifrm IPv4Frame) uint16 {
|
||||
// var crc lneto2.CRC791
|
||||
// ifrm.crcWriteUDPPseudo(&crc)
|
||||
// crc.AddUint16(ufrm.Length())
|
||||
// crc.AddUint16(ufrm.SourcePort())
|
||||
// crc.AddUint16(ufrm.DestinationPort())
|
||||
// crc.AddUint16(ufrm.Length()) // Length double tap.
|
||||
// crc.Write(ufrm.Payload())
|
||||
// return crc.Sum16()
|
||||
// }
|
||||
|
||||
// func (ufrm Frame) CalculateIPv6Checksum(ifrm IPv6Frame) uint16 {
|
||||
// var crc lneto2.CRC791
|
||||
// ifrm.crcWritePseudo(&crc)
|
||||
// crc.AddUint16(ufrm.SourcePort())
|
||||
// crc.AddUint16(ufrm.DestinationPort())
|
||||
// crc.AddUint16(ufrm.Length()) // Length double tap.
|
||||
// crc.Write(ufrm.Payload())
|
||||
// return crc.Sum16()
|
||||
// }
|
||||
|
||||
// ClearHeader zeros out the header contents.
|
||||
func (frm Frame) ClearHeader() {
|
||||
for i := range frm.buf[:sizeHeader] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Validation API.
|
||||
//
|
||||
|
||||
var (
|
||||
errBadLen = errors.New("udp: bad UDP length")
|
||||
errShort = errors.New("udp: short buffer")
|
||||
)
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (ufrm Frame) ValidateSize(v *lneto2.Validator) {
|
||||
ul := ufrm.Length()
|
||||
if ul < sizeHeader {
|
||||
v.AddError(errBadLen)
|
||||
}
|
||||
if int(ul) > len(ufrm.RawData()) {
|
||||
v.AddError(errShort)
|
||||
}
|
||||
}
|
||||
-142
@@ -1,142 +0,0 @@
|
||||
package lneto
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
errShortEth = errors.New("ethernet length exceeds frame")
|
||||
errShortVLAN = errors.New("ethernet length too short for VLAN")
|
||||
errShortUDP = errors.New("UDP length exceeds frame")
|
||||
errBadUDPLen = errors.New("UDP length invalid")
|
||||
errShortIPv4 = errors.New("IPv4 total length exceeds frame")
|
||||
errBadIPv4TL = errors.New("IPv4 short total length")
|
||||
errBadIPv4IHL = errors.New("IPv4 bad IHL (<5)")
|
||||
errShortIPv6 = errors.New("IPv6 payload length exceeds frame")
|
||||
errShortARP = errors.New("bad ARP size")
|
||||
errShortTCP = errors.New("TCP offset exceeds frame")
|
||||
errBadTCPOff = errors.New("TCP offset invalid")
|
||||
|
||||
errBadIPVersion = errors.New("bad IP version field")
|
||||
errEvilPacket = errors.New("evil packet")
|
||||
errZeroDstPort = errors.New("TCP zero destination port")
|
||||
errZeroSrcPort = errors.New("TCP zero source port")
|
||||
)
|
||||
|
||||
type Validator struct {
|
||||
checkEvil bool
|
||||
allowMultiErrs bool
|
||||
accum []error
|
||||
}
|
||||
|
||||
func (v *Validator) ResetErr() {
|
||||
v.accum = v.accum[:0]
|
||||
}
|
||||
|
||||
func (v *Validator) Err() error {
|
||||
if len(v.accum) == 1 {
|
||||
return v.accum[0]
|
||||
} else if len(v.accum) == 0 {
|
||||
return nil
|
||||
}
|
||||
return errors.Join(v.accum...)
|
||||
}
|
||||
|
||||
func (v *Validator) gotErr(err error) {
|
||||
if len(v.accum) != 0 && !v.allowMultiErrs {
|
||||
return
|
||||
}
|
||||
v.accum = append(v.accum, err)
|
||||
}
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (efrm EthFrame) ValidateSize(v *Validator) {
|
||||
sz := efrm.EtherTypeOrSize()
|
||||
if sz.IsSize() && len(efrm.buf) < int(sz) {
|
||||
v.gotErr(errShortEth)
|
||||
}
|
||||
if sz == EtherTypeVLAN && len(efrm.buf) < 18 {
|
||||
v.gotErr(errShortVLAN)
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (afrm ARPFrame) ValidateSize(v *Validator) {
|
||||
_, hlen := afrm.Hardware()
|
||||
_, ilen := afrm.Protocol()
|
||||
minLen := 8 + 2*(hlen+ilen)
|
||||
if len(afrm.buf) < int(minLen) {
|
||||
v.gotErr(errShortARP)
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (ifrm IPv4Frame) ValidateSize(v *Validator) {
|
||||
ihl := ifrm.ihl()
|
||||
tl := ifrm.TotalLength()
|
||||
if tl < sizeHeaderIPv4 {
|
||||
v.gotErr(errBadIPv4TL)
|
||||
}
|
||||
if int(tl) > len(ifrm.RawData()) {
|
||||
v.gotErr(errShortIPv4)
|
||||
}
|
||||
if ihl < 5 {
|
||||
v.gotErr(errBadIPv4IHL)
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateExceptCRC checks for invalid frame values but does not check CRC.
|
||||
func (ifrm IPv4Frame) ValidateExceptCRC(v *Validator) {
|
||||
ifrm.ValidateSize(v)
|
||||
flags := ifrm.Flags()
|
||||
if ifrm.version() != 4 {
|
||||
v.gotErr(errBadIPVersion)
|
||||
}
|
||||
if v.checkEvil && flags.IsEvil() {
|
||||
v.gotErr(errEvilPacket)
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (i6frm IPv6Frame) ValidateSize(v *Validator) {
|
||||
tl := i6frm.PayloadLength()
|
||||
if int(tl)+sizeHeaderIPv6 > len(i6frm.RawData()) {
|
||||
v.gotErr(errShortIPv6)
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (tfrm TCPFrame) ValidateSize(v *Validator) {
|
||||
off := tfrm.HeaderLength()
|
||||
if off < sizeHeaderTCP {
|
||||
v.gotErr(errBadTCPOff)
|
||||
}
|
||||
if off > len(tfrm.RawData()) {
|
||||
v.gotErr(errShortTCP)
|
||||
}
|
||||
}
|
||||
|
||||
func (tfrm TCPFrame) ValidateExceptCRC(v *Validator) {
|
||||
tfrm.ValidateSize(v)
|
||||
if tfrm.DestinationPort() == 0 {
|
||||
v.gotErr(errZeroDstPort)
|
||||
}
|
||||
if tfrm.SourcePort() == 0 {
|
||||
v.gotErr(errZeroSrcPort)
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||
func (ufrm UDPFrame) ValidateSize(v *Validator) {
|
||||
ul := ufrm.Length()
|
||||
if ul < sizeHeaderUDP {
|
||||
v.gotErr(errBadUDPLen)
|
||||
}
|
||||
if int(ul) > len(ufrm.RawData()) {
|
||||
v.gotErr(errShortUDP)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user