mirror of
https://github.com/soypat/lneto.git
synced 2026-08-11 02:13:44 +00:00
add IPv6, tcp packet, validation, IPProto
This commit is contained in:
@@ -7,9 +7,17 @@
|
||||
|
||||
Userspace networking primitives.
|
||||
|
||||
### Packages
|
||||
## Packages
|
||||
- `lneto`: Low-level Networking Operations, or "El Neto", the big networking package. Zero copy network frame marshalling and unmarshalling.
|
||||
- [`lneto/frames.go`](./lneto/frames.go): Ethernet, IPv4/IPv6, ARP, TCP, UDP packet marshalling/unmarshalling.
|
||||
|
||||
- [`lneto/tcp`](./lneto/ntp): TCP implementation and low level logic.
|
||||
- [`lneto/dhcp`](./lneto/dhcp): DHCP protocol implementation and low level logic.
|
||||
- [`lneto/dns`](./lneto/dns): DNS protocol implementation and low level logic.
|
||||
- [`lneto/ntp`](./lneto/ntp): NTP implementation and low level logic. Includes NTP time primitive manipulation and conversion to Go native types.
|
||||
|
||||
|
||||
## Install
|
||||
How to install package with newer versions of Go (+1.16):
|
||||
```sh
|
||||
go mod download github.com/soypat/tseq@latest
|
||||
|
||||
+185
-5
@@ -1,9 +1,13 @@
|
||||
package lneto
|
||||
|
||||
//go:generate stringer -type=EtherType -linecomment -output stringers.go .
|
||||
//go:generate stringer -type=EtherType,IPProto -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
|
||||
@@ -52,16 +56,192 @@ const (
|
||||
minEthPayload = 46
|
||||
)
|
||||
|
||||
// IPToS represents the Traffic Class (a.k.a Type of Service).
|
||||
type IPToS uint8
|
||||
|
||||
func (tos IPToS) DSCP() uint8 { return uint8(tos) >> 2 }
|
||||
// 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
|
||||
|
||||
func (f IPv4Flags) DontFragment() bool { return f&0x4000 != 0 }
|
||||
func (f IPv4Flags) MoreFragments() bool { return f&0x8000 != 0 }
|
||||
// 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 }
|
||||
|
||||
type TCPFlags uint8
|
||||
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 [RFC793]
|
||||
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
|
||||
)
|
||||
|
||||
+316
-169
@@ -3,39 +3,73 @@ package lneto
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/soypat/tseq"
|
||||
"github.com/soypat/tseq/lneto/tcp"
|
||||
)
|
||||
|
||||
func NewEthFrame(buf []byte) EthFrame { return EthFrame{buf: buf} }
|
||||
func NewARPv4Frame(buf []byte) ARPv4Frame { return ARPv4Frame{buf: buf} }
|
||||
func NewIPv4Frame(buf []byte) IPv4Frame { return IPv4Frame{buf: buf} }
|
||||
func NewTCPFrame(buf []byte) TCPFrame { return TCPFrame{buf: buf} }
|
||||
func NewUDPFrame(buf []byte) UDPFrame { return UDPFrame{buf: buf} }
|
||||
func NewEthFrame(buf []byte) EthFrame {
|
||||
return EthFrame{buf: mustBufferFrameLen(buf, sizeHeaderEthNoVLAN, "Ethernet")}
|
||||
}
|
||||
func NewARPv4Frame(buf []byte) ARPv4Frame {
|
||||
return ARPv4Frame{buf: mustBufferFrameLen(buf, sizeHeaderARPv4, "ARPv4")}
|
||||
}
|
||||
func NewIPv4Frame(buf []byte) IPv4Frame {
|
||||
return IPv4Frame{buf: mustBufferFrameLen(buf, sizeHeaderIPv4, "IPv4")}
|
||||
}
|
||||
func NewIPv6Frame(buf []byte) IPv6Frame {
|
||||
return IPv6Frame{buf: mustBufferFrameLen(buf, sizeHeaderIPv6, "IPv6")}
|
||||
}
|
||||
func NewTCPFrame(buf []byte) TCPFrame {
|
||||
return TCPFrame{buf: mustBufferFrameLen(buf, sizeHeaderIPv4, "TCP")}
|
||||
}
|
||||
func NewUDPFrame(buf []byte) UDPFrame {
|
||||
return UDPFrame{buf: mustBufferFrameLen(buf, sizeHeaderUDP, "UDP")}
|
||||
}
|
||||
|
||||
func mustBufferFrameLen(b []byte, minLen int, name string) []byte {
|
||||
if len(b) < minLen {
|
||||
panic(name + " frame too short")
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// EthFrame represents a Ethernet frame without including a preamble. The first byte is start of destination MAC address.
|
||||
type EthFrame struct {
|
||||
buf []byte
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (frm EthFrame) RawData() []byte { return frm.buf}
|
||||
func (efrm EthFrame) RawData() []byte { return efrm.buf }
|
||||
|
||||
func (frm EthFrame) Payload() []byte {
|
||||
if frm.IsVLAN() {
|
||||
return frm.buf[18:]
|
||||
// Payload returns the data portion of the ethernet packet with handling of VLAN packets.
|
||||
func (efrm EthFrame) Payload() []byte {
|
||||
if efrm.IsVLAN() {
|
||||
if len(efrm.buf) < 18 {
|
||||
return nil
|
||||
}
|
||||
return efrm.buf[18:]
|
||||
}
|
||||
return frm.buf[14:]
|
||||
return efrm.buf[sizeHeaderEthNoVLAN:]
|
||||
}
|
||||
|
||||
func (frm EthFrame) DstHardwareAddr6() (dst *[6]byte) {
|
||||
return (*[6]byte)(frm.buf[:6])
|
||||
// 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])
|
||||
}
|
||||
|
||||
func (frm EthFrame) SrcHardwareAddr6() (src *[6]byte) {
|
||||
return (*[6]byte)(frm.buf[6:12])
|
||||
// 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])
|
||||
}
|
||||
|
||||
func (frm EthFrame) EtherTypeOrSize() uint16 {
|
||||
return binary.BigEndian.Uint16(frm.buf[12:14])
|
||||
// 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))
|
||||
}
|
||||
|
||||
// IsVLAN returns true if the SizeOrEtherType is set to the VLAN tag 0x8100. This
|
||||
@@ -44,8 +78,8 @@ func (frm EthFrame) EtherTypeOrSize() uint16 {
|
||||
// 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 (frm EthFrame) IsVLAN() bool {
|
||||
return frm.EtherTypeOrSize() == uint16(EtherTypeVLAN)
|
||||
func (efrm EthFrame) IsVLAN() bool {
|
||||
return efrm.EtherTypeOrSize() == EtherTypeVLAN
|
||||
}
|
||||
|
||||
type ARPv4Frame struct {
|
||||
@@ -53,48 +87,48 @@ type ARPv4Frame struct {
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (frm ARPv4Frame) RawData() []byte { return frm.buf}
|
||||
func (afrm ARPv4Frame) RawData() []byte { return afrm.buf }
|
||||
|
||||
// HardwareType specifies the network link protocol type. Example: Ethernet is 1.
|
||||
func (arp ARPv4Frame) Hardware() (Type uint16, length uint8) {
|
||||
Type = binary.BigEndian.Uint16(arp.buf[0:2])
|
||||
length = arp.buf[4]
|
||||
func (afrm ARPv4Frame) Hardware() (Type uint16, length uint8) {
|
||||
Type = binary.BigEndian.Uint16(afrm.buf[0:2])
|
||||
length = afrm.buf[4]
|
||||
return Type, length
|
||||
}
|
||||
|
||||
func (arp ARPv4Frame) SetHardware(Type uint16, length uint8) {
|
||||
binary.BigEndian.PutUint16(arp.buf[0:2], Type)
|
||||
arp.buf[4] = length
|
||||
func (afrm ARPv4Frame) SetHardware(Type uint16, length uint8) {
|
||||
binary.BigEndian.PutUint16(afrm.buf[0:2], Type)
|
||||
afrm.buf[4] = length
|
||||
}
|
||||
|
||||
func (arp ARPv4Frame) Protocol() (Type uint16, length uint8) {
|
||||
Type = binary.BigEndian.Uint16(arp.buf[2:4])
|
||||
length = arp.buf[5]
|
||||
func (afrm ARPv4Frame) Protocol() (Type uint16, length uint8) {
|
||||
Type = binary.BigEndian.Uint16(afrm.buf[2:4])
|
||||
length = afrm.buf[5]
|
||||
return Type, length
|
||||
}
|
||||
|
||||
func (arp ARPv4Frame) SetProtocol(Type uint16, length uint8) {
|
||||
binary.BigEndian.PutUint16(arp.buf[2:4], Type)
|
||||
arp.buf[5] = length
|
||||
func (afrm ARPv4Frame) SetProtocol(Type uint16, length uint8) {
|
||||
binary.BigEndian.PutUint16(afrm.buf[2:4], Type)
|
||||
afrm.buf[5] = length
|
||||
}
|
||||
|
||||
func (arp ARPv4Frame) SetOperation(b uint8) { arp.buf[6] = b }
|
||||
func (afrm ARPv4Frame) SetOperation(b uint8) { afrm.buf[6] = b }
|
||||
|
||||
func (arp ARPv4Frame) IsOperationRequest() bool { return arp.buf[6] == 1 }
|
||||
func (arp ARPv4Frame) IsOperationReply() bool { return arp.buf[6] == 2 }
|
||||
func (afrm ARPv4Frame) IsOperationRequest() bool { return afrm.buf[6] == 1 }
|
||||
func (afrm ARPv4Frame) IsOperationReply() bool { return afrm.buf[6] == 2 }
|
||||
|
||||
// Sender returns the MAC (hardware) and IP (protocol) addresses of sender of ARP packet.
|
||||
// In an ARP request MAC is used to indicate
|
||||
// the address of the host sending the request. In an ARP reply MAC is
|
||||
// used to indicate the address of the host that the request was looking for.
|
||||
func (arp ARPv4Frame) Sender() (hardwareAddr *[6]byte, proto *[4]byte) {
|
||||
return (*[6]byte)(arp.buf[8:14]), (*[4]byte)(arp.buf[14:18])
|
||||
func (afrm ARPv4Frame) Sender() (hardwareAddr *[6]byte, proto *[4]byte) {
|
||||
return (*[6]byte)(afrm.buf[8:14]), (*[4]byte)(afrm.buf[14:18])
|
||||
}
|
||||
|
||||
// Target returns the MAC (hardware) and IP (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 (arp ARPv4Frame) Target() (hardwareAddr *[6]byte, proto *[4]byte) {
|
||||
return (*[6]byte)(arp.buf[18:24]), (*[4]byte)(arp.buf[24:28])
|
||||
func (afrm ARPv4Frame) Target() (hardwareAddr *[6]byte, proto *[4]byte) {
|
||||
return (*[6]byte)(afrm.buf[18:24]), (*[4]byte)(afrm.buf[24:28])
|
||||
}
|
||||
|
||||
type IPv4Frame struct {
|
||||
@@ -102,18 +136,17 @@ type IPv4Frame struct {
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (frm IPv4Frame) RawData() []byte { return frm.buf}
|
||||
func (ifrm IPv4Frame) RawData() []byte { return ifrm.buf }
|
||||
|
||||
|
||||
func (ip IPv4Frame) Version() uint8 { return ip.buf[0] & 0xf }
|
||||
func (ip IPv4Frame) IHL() uint8 { return ip.buf[0] >> 4 }
|
||||
func (ifrm IPv4Frame) Version() uint8 { return ifrm.buf[0] & 0xf }
|
||||
func (ifrm IPv4Frame) IHL() uint8 { return ifrm.buf[0] >> 4 }
|
||||
|
||||
// HeaderLength returns the length of the IPv4 header as calculated using IHL. It includes IP options.
|
||||
func (ip IPv4Frame) HeaderLength() int {
|
||||
return int(ip.IHL()) * 4
|
||||
func (ifrm IPv4Frame) HeaderLength() int {
|
||||
return int(ifrm.IHL()) * 4
|
||||
}
|
||||
|
||||
func (ip IPv4Frame) SetVersionAndIHL(version, IHL uint8) { ip.buf[0] = version&0xf | IHL<<4 }
|
||||
func (ifrm IPv4Frame) SetVersionAndIHL(version, IHL uint8) { ifrm.buf[0] = version&0xf | IHL<<4 }
|
||||
|
||||
// ToS (Type of Service) contains Differential Services Code Point (DSCP) and
|
||||
// Explicit Congestion Notification (ECN) union data.
|
||||
@@ -126,12 +159,12 @@ func (ip IPv4Frame) SetVersionAndIHL(version, IHL uint8) { ip.buf[0] = version&0
|
||||
// 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 (ip IPv4Frame) ToS() IPToS {
|
||||
return IPToS(ip.buf[1])
|
||||
func (ifrm IPv4Frame) ToS() IPToS {
|
||||
return IPToS(ifrm.buf[1])
|
||||
}
|
||||
|
||||
// SetToS sets ToS field. See [IPv4Frame.ToS].
|
||||
func (ip IPv4Frame) SetToS(tos IPToS) { ip.buf[1] = byte(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.
|
||||
@@ -141,90 +174,175 @@ func (ip IPv4Frame) SetToS(tos IPToS) { ip.buf[1] = byte(tos) }
|
||||
// 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 (ip IPv4Frame) TotalLength() uint16 {
|
||||
return binary.BigEndian.Uint16(ip.buf[2:4])
|
||||
func (ifrm IPv4Frame) TotalLength() uint16 {
|
||||
return binary.BigEndian.Uint16(ifrm.buf[2:4])
|
||||
}
|
||||
|
||||
// SetTotalLength sets TotalLength field. See [IPv4Frame.TotalLength].
|
||||
func (ip IPv4Frame) SetTotalLength(tl uint16) { binary.BigEndian.PutUint16(ip.buf[2:4], tl) }
|
||||
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 (ip IPv4Frame) ID() uint16 {
|
||||
return binary.BigEndian.Uint16(ip.buf[4:6])
|
||||
func (ifrm IPv4Frame) ID() uint16 {
|
||||
return binary.BigEndian.Uint16(ifrm.buf[4:6])
|
||||
}
|
||||
|
||||
// SetID sets ID field. See [IPv4Frame.ID].
|
||||
func (ip IPv4Frame) SetID(id uint16) { binary.BigEndian.PutUint16(ip.buf[4:6], id) }
|
||||
func (ifrm IPv4Frame) SetID(id uint16) { binary.BigEndian.PutUint16(ifrm.buf[4:6], id) }
|
||||
|
||||
// Flags returns the [IPv4Flags] of the IP packet.
|
||||
func (ip IPv4Frame) Flags() IPv4Flags {
|
||||
return IPv4Flags(binary.BigEndian.Uint16(ip.buf[6:8]))
|
||||
func (ifrm IPv4Frame) Flags() IPv4Flags {
|
||||
return IPv4Flags(binary.BigEndian.Uint16(ifrm.buf[6:8]))
|
||||
}
|
||||
|
||||
// SetFlags sets the IPv4 flags field. See [IPv4Flags].
|
||||
func (ip IPv4Frame) SetFlags(flags IPv4Flags) { binary.BigEndian.PutUint16(ip.buf[6:8], uint16(flags)) }
|
||||
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 (ip IPv4Frame) TTL() uint8 { return ip.buf[8] }
|
||||
func (ifrm IPv4Frame) TTL() uint8 { return ifrm.buf[8] }
|
||||
|
||||
// SetTTL sets the IP frame's TTL field. See [IPv4Frame.TTL].
|
||||
func (ip IPv4Frame) SetTTL(ttl uint8) { ip.buf[8] = 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.
|
||||
func (ip IPv4Frame) Protocol() uint8 { return ip.buf[9] }
|
||||
// See [IPProto].
|
||||
func (ifrm IPv4Frame) Protocol() IPProto { return IPProto(ifrm.buf[9]) }
|
||||
|
||||
// SetProtocol sets protocol field. See [IPv4Frame.Protocol].
|
||||
func (ip IPv4Frame) SetProtocol(proto uint8) { ip.buf[9] = proto }
|
||||
// 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 field of the IPv4 packet.
|
||||
func (ip IPv4Frame) CRC() uint16 {
|
||||
return binary.BigEndian.Uint16(ip.buf[10:12])
|
||||
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 (ip IPv4Frame) SetCRC(cs uint16) {
|
||||
binary.BigEndian.PutUint16(ip.buf[10:12], cs)
|
||||
func (ifrm IPv4Frame) SetCRC(cs uint16) {
|
||||
binary.BigEndian.PutUint16(ifrm.buf[10:12], cs)
|
||||
}
|
||||
|
||||
func (ip IPv4Frame) CalculateHeaderCRC() uint16 {
|
||||
// CalculateHeaderCRC calculates the CRC for this IPv4 frame.
|
||||
func (ifrm IPv4Frame) CalculateHeaderCRC() uint16 {
|
||||
var crc CRC791
|
||||
crc.Write(ip.buf[0:10])
|
||||
crc.Write(ip.buf[12:20])
|
||||
crc.Write(ifrm.buf[0:10])
|
||||
crc.Write(ifrm.buf[12:20])
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
func (ip IPv4Frame) writeTCPPseudoCRC(crc *CRC791) {
|
||||
crc.Write(ip.SourceAddr()[:])
|
||||
crc.Write(ip.DestinationAddr()[:])
|
||||
crc.AddUint16(ip.TotalLength() - 4*uint16(ip.IHL()))
|
||||
crc.AddUint16(uint16(ip.Protocol()))
|
||||
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 (ip IPv4Frame) writeUDPPseudoCRC(crc *CRC791) {
|
||||
crc.Write(ip.SourceAddr()[:])
|
||||
crc.Write(ip.DestinationAddr()[:])
|
||||
crc.AddUint16(uint16(ip.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 (ip IPv4Frame) SourceAddr() *[4]byte {
|
||||
return (*[4]byte)(ip.buf[12:16])
|
||||
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 (ip IPv4Frame) DestinationAddr() *[4]byte {
|
||||
return (*[4]byte)(ip.buf[16:20])
|
||||
func (ifrm IPv4Frame) DestinationAddr() *[4]byte {
|
||||
return (*[4]byte)(ifrm.buf[16:20])
|
||||
}
|
||||
|
||||
func (ip IPv4Frame) Payload() []byte {
|
||||
off := ip.HeaderLength()
|
||||
l := ip.TotalLength()
|
||||
return ip.buf[off:l]
|
||||
func (ifrm IPv4Frame) Payload() []byte {
|
||||
off := ifrm.HeaderLength()
|
||||
l := ifrm.TotalLength()
|
||||
return ifrm.buf[off:l]
|
||||
}
|
||||
|
||||
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.
|
||||
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()))
|
||||
}
|
||||
|
||||
type TCPFrame struct {
|
||||
@@ -232,104 +350,124 @@ type TCPFrame struct {
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (frm TCPFrame) RawData() []byte { return frm.buf}
|
||||
func (tfrm TCPFrame) RawData() []byte { return tfrm.buf }
|
||||
|
||||
|
||||
func (tcp TCPFrame) SourcePort() uint16 {
|
||||
return binary.BigEndian.Uint16(tcp.buf[0:2])
|
||||
// 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 (tcp TCPFrame) SetSourcePort(src uint16) {
|
||||
binary.BigEndian.PutUint16(tcp.buf[0:2], src)
|
||||
func (tfrm TCPFrame) SetSourcePort(src uint16) {
|
||||
binary.BigEndian.PutUint16(tfrm.buf[0:2], src)
|
||||
}
|
||||
|
||||
func (tcp TCPFrame) DestinationPort() uint16 {
|
||||
return binary.BigEndian.Uint16(tcp.buf[2:4])
|
||||
// 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 (tcp TCPFrame) SetDestinationPort(dst uint16) {
|
||||
binary.BigEndian.PutUint16(tcp.buf[2:4], dst)
|
||||
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 (tcp TCPFrame) Seq() tseq.Value {
|
||||
return tseq.Value(binary.BigEndian.Uint32(tcp.buf[4:8]))
|
||||
func (tfrm TCPFrame) Seq() tcp.Value {
|
||||
return tcp.Value(binary.BigEndian.Uint32(tfrm.buf[4:8]))
|
||||
}
|
||||
|
||||
// SetSeq sets Seq field. See [TCPFrame.Seq].
|
||||
func (tcp TCPFrame) SetSeq(v tseq.Value) {
|
||||
binary.BigEndian.PutUint32(tcp.buf[4:8], uint32(v))
|
||||
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 (tcp TCPFrame) Ack() tseq.Value {
|
||||
return tseq.Value(binary.BigEndian.Uint32(tcp.buf[8:12]))
|
||||
func (tfrm TCPFrame) Ack() tcp.Value {
|
||||
return tcp.Value(binary.BigEndian.Uint32(tfrm.buf[8:12]))
|
||||
}
|
||||
|
||||
// SetAck sets Ack field. See [TCPFrame.Ack].
|
||||
func (tcp TCPFrame) SetAck(v tseq.Value) {
|
||||
binary.BigEndian.PutUint32(tcp.buf[8:12], uint32(v))
|
||||
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 (tcp TCPFrame) HeaderLength() (tcpWords int) {
|
||||
return 4 * int(tcp.Offset())
|
||||
func (tfrm TCPFrame) HeaderLength() (tcpWords int) {
|
||||
offset, _ := tfrm.OffsetAndFlags()
|
||||
return 4 * int(offset)
|
||||
}
|
||||
|
||||
// Offset returns the number of 32 bit words used to represent the header. Is a TCP field.
|
||||
func (tcp TCPFrame) Offset() (tcpWords uint8) {
|
||||
return tcp.buf[12] & 0xf
|
||||
}
|
||||
|
||||
// SetOffset sets TCP offset field. See [TCPFrame.Offset].
|
||||
func (tcp TCPFrame) SetOffset() (tcpWords uint8) {
|
||||
return tcp.buf[12] & 0xf
|
||||
}
|
||||
|
||||
// Flags returns the TCP flags contained in TCP header. See [TCPFlags].
|
||||
func (tcp TCPFrame) Flags() TCPFlags { return TCPFlags(tcp.buf[13]) }
|
||||
|
||||
// SetFlags sets the TCP flags. See [TCPFlags].
|
||||
func (tcp TCPFrame) SetFlags(flags TCPFlags) { tcp.buf[13] = uint8(flags) }
|
||||
|
||||
func (tcp TCPFrame) CRC() uint16 {
|
||||
return binary.BigEndian.Uint16(tcp.buf[16:18])
|
||||
// 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 (tcp TCPFrame) SetCRC(checksum uint16) {
|
||||
binary.BigEndian.PutUint16(tcp.buf[16:18], checksum)
|
||||
func (tfrm TCPFrame) SetCRC(checksum uint16) {
|
||||
binary.BigEndian.PutUint16(tfrm.buf[16:18], checksum)
|
||||
}
|
||||
|
||||
func (tcp TCPFrame) CalculateCRC(ipPseudo IPv4Frame) uint16 {
|
||||
// CalculateIPv4CRC returns the CRC for the TCP header over an IPv4 protocol.
|
||||
func (tfrm TCPFrame) CalculateIPv4CRC(ifrm IPv4Frame) uint16 {
|
||||
var crc CRC791
|
||||
ipPseudo.writeTCPPseudoCRC(&crc)
|
||||
expectLen := int(ipPseudo.TotalLength()) - 4*int(ipPseudo.IHL())
|
||||
if expectLen != len(tcp.buf) {
|
||||
panic("unexpected TCP buffer length mismatches IPv4 header total length")
|
||||
ifrm.crcWriteTCPPseudo(&crc)
|
||||
expectLen := int(ifrm.TotalLength()) - 4*int(ifrm.IHL())
|
||||
if expectLen != len(tfrm.buf) {
|
||||
println("unexpected TCP buffer length mismatches IPv4 header total length", expectLen, len(tfrm.buf))
|
||||
}
|
||||
tcp.writeCRC(&crc)
|
||||
tfrm.crcWrite(&crc)
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
func (tcp TCPFrame) writeCRC(crc *CRC791) {
|
||||
// Write excluding
|
||||
crc.Write(tcp.buf[:16])
|
||||
crc.Write(tcp.buf[18:])
|
||||
// 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", expectLen, len(tfrm.buf))
|
||||
}
|
||||
tfrm.crcWrite(&crc)
|
||||
return crc.Sum16()
|
||||
}
|
||||
|
||||
func (tcp TCPFrame) SetUrgentPtr(up uint16) {
|
||||
binary.BigEndian.PutUint16(tcp.buf[18:20], up)
|
||||
func (tfrm TCPFrame) crcWrite(crc *CRC791) {
|
||||
// Write excluding CRC
|
||||
crc.Write(tfrm.buf[:16])
|
||||
crc.Write(tfrm.buf[18:])
|
||||
}
|
||||
|
||||
func (tcp TCPFrame) Payload() []byte {
|
||||
return tcp.buf[tcp.HeaderLength():]
|
||||
func (tfrm TCPFrame) SetUrgentPtr(up uint16) {
|
||||
binary.BigEndian.PutUint16(tfrm.buf[18:20], up)
|
||||
}
|
||||
|
||||
func (tfrm TCPFrame) UrgentPtr() uint16 {
|
||||
return binary.BigEndian.Uint16(tfrm.buf[18:20])
|
||||
}
|
||||
|
||||
func (tfrm TCPFrame) Payload() []byte {
|
||||
return tfrm.buf[tfrm.HeaderLength():]
|
||||
}
|
||||
|
||||
type UDPFrame struct {
|
||||
@@ -337,61 +475,70 @@ type UDPFrame struct {
|
||||
}
|
||||
|
||||
// RawData returns the underlying slice with which the frame was created.
|
||||
func (frm UDPFrame) RawData() []byte { return frm.buf}
|
||||
func (ufrm UDPFrame) RawData() []byte { return ufrm.buf }
|
||||
|
||||
|
||||
func (udp UDPFrame) SourcePort() uint16 {
|
||||
return binary.BigEndian.Uint16(udp.buf[0:2])
|
||||
func (ufrm UDPFrame) SourcePort() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[0:2])
|
||||
}
|
||||
|
||||
// SetSourcePort sets UDP source port. See [UDPFrame.SetSourcePort]
|
||||
func (udp UDPFrame) SetSourcePort(src uint16) {
|
||||
binary.BigEndian.PutUint16(udp.buf[0:2], src)
|
||||
func (ufrm UDPFrame) SetSourcePort(src uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[0:2], src)
|
||||
}
|
||||
|
||||
func (udp UDPFrame) DestinationPort() uint16 {
|
||||
return binary.BigEndian.Uint16(udp.buf[2:4])
|
||||
func (ufrm UDPFrame) DestinationPort() uint16 {
|
||||
return binary.BigEndian.Uint16(ufrm.buf[2:4])
|
||||
}
|
||||
|
||||
// SetDestinationPort sets UDP destination port. See [UDPFrame.DestinationPort]
|
||||
func (udp UDPFrame) SetDestinationPort(dst uint16) {
|
||||
binary.BigEndian.PutUint16(udp.buf[2:4], dst)
|
||||
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 (udp UDPFrame) Length() uint16 {
|
||||
return binary.BigEndian.Uint16(udp.buf[4:6])
|
||||
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 (udp UDPFrame) SetLength(length uint16) {
|
||||
binary.BigEndian.PutUint16(udp.buf[4:6], length)
|
||||
func (ufrm UDPFrame) SetLength(length uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[4:6], length)
|
||||
}
|
||||
|
||||
func (udp UDPFrame) CRC() uint16 {
|
||||
return binary.BigEndian.Uint16(udp.buf[6:8])
|
||||
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 (udp UDPFrame) SetCRC(checksum uint16) {
|
||||
binary.BigEndian.PutUint16(udp.buf[6:8], checksum)
|
||||
func (ufrm UDPFrame) SetCRC(checksum uint16) {
|
||||
binary.BigEndian.PutUint16(ufrm.buf[6:8], checksum)
|
||||
}
|
||||
|
||||
// Payload returns the data part of the UDP frame.
|
||||
func (udp UDPFrame) Payload() []byte {
|
||||
l := udp.Length()
|
||||
return udp.buf[8:l]
|
||||
func (ufrm UDPFrame) Payload() []byte {
|
||||
l := ufrm.Length()
|
||||
return ufrm.buf[sizeHeaderUDP:l]
|
||||
}
|
||||
|
||||
func (udp UDPFrame) CalculateChecksum(pseudoHeader IPv4Frame) uint16 {
|
||||
func (ufrm UDPFrame) CalculateIPv4Checksum(ifrm IPv4Frame) uint16 {
|
||||
var crc CRC791
|
||||
pseudoHeader.writeUDPPseudoCRC(&crc)
|
||||
crc.AddUint16(udp.Length())
|
||||
crc.AddUint16(udp.SourcePort())
|
||||
crc.AddUint16(udp.DestinationPort())
|
||||
crc.AddUint16(udp.Length())
|
||||
crc.Write(udp.Payload())
|
||||
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()
|
||||
}
|
||||
|
||||
+187
-1
@@ -1,4 +1,4 @@
|
||||
// Code generated by "stringer -type=EtherType -linecomment -output stringers.go ."; DO NOT EDIT.
|
||||
// Code generated by "stringer -type=EtherType,IPProto -linecomment -output stringers.go ."; DO NOT EDIT.
|
||||
|
||||
package lneto
|
||||
|
||||
@@ -103,3 +103,189 @@ func (i EtherType) String() string {
|
||||
}
|
||||
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 [RFC793]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, 209, 224, 258, 317, 335, 366, 369, 374, 379, 397, 402, 424, 436, 462, 486, 510, 522, 529, 536, 542, 548, 579, 617, 656, 692, 721, 746, 792, 820, 856, 859, 885, 921, 944, 965, 993, 1023, 1056, 1090, 1119, 1149, 1188, 1219, 1222, 1254, 1285, 1319, 1337, 1369, 1380, 1444, 1448, 1471, 1504, 1542}
|
||||
_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) + ")"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package tcp
|
||||
|
||||
import "log/slog"
|
||||
|
||||
// ControlBlock is a partial Transmission Control Block (TCB) implementation as
|
||||
// per RFC 9293 in section 3.3.1. In contrast with the description in RFC9293,
|
||||
// this implementation is limited to receiving only sequential segments.
|
||||
// This means buffer management is left up entirely to the user of the ControlBlock.
|
||||
// Use ControlBlock as the building block that solves Sequence Number calculation
|
||||
// and validation in a full TCP implementation.
|
||||
//
|
||||
// A ControlBlock's internal state is modified by the available "System Calls" as defined in
|
||||
// RFC9293, such as Close, Listen/Open, Send, and Receive.
|
||||
// Sent and received data is represented with the [Segment] struct type.
|
||||
type ControlBlock struct {
|
||||
// # Send Sequence Space
|
||||
//
|
||||
// 'Send' sequence numbers correspond to local data being sent.
|
||||
//
|
||||
// 1 2 3 4
|
||||
// ----------|----------|----------|----------
|
||||
// SND.UNA SND.NXT SND.UNA
|
||||
// +SND.WND
|
||||
// 1. old sequence numbers which have been acknowledged
|
||||
// 2. sequence numbers of unacknowledged data
|
||||
// 3. sequence numbers allowed for new data transmission
|
||||
// 4. future sequence numbers which are not yet allowed
|
||||
snd sendSpace
|
||||
// # Receive Sequence Space
|
||||
//
|
||||
// 'Receive' sequence numbers correspond to remote data being received.
|
||||
//
|
||||
// 1 2 3
|
||||
// ----------|----------|----------
|
||||
// RCV.NXT RCV.NXT
|
||||
// +RCV.WND
|
||||
// 1 - old sequence numbers which have been acknowledged
|
||||
// 2 - sequence numbers allowed for new reception
|
||||
// 3 - future sequence numbers which are not yet allowed
|
||||
rcv recvSpace
|
||||
// When FlagRST is set in pending flags rstPtr will contain the sequence number of the RST segment to make it "believable" (See RFC9293)
|
||||
rstPtr Value
|
||||
// pending is the queue of pending flags to be sent in the next 2 segments.
|
||||
// On a call to Send the queue is advanced and flags set in the segment are unset.
|
||||
// The second position of the queue is used for FIN segments.
|
||||
pending [2]Flags
|
||||
state State
|
||||
challengeAck bool
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
// sendSpace contains Send Sequence Space data. Its sequence numbers correspond to local data.
|
||||
type sendSpace struct {
|
||||
ISS Value // initial send sequence number, defined locally on connection start
|
||||
UNA Value // send unacknowledged. Seqs equal to UNA and above have NOT been acked by remote. Corresponds to local data.
|
||||
NXT Value // send next. This seq and up to UNA+WND-1 are allowed to be sent. Corresponds to local data.
|
||||
WND Size // send window defined by remote. Permitted number of local unacked octets in flight.
|
||||
// WL1 Value // segment sequence number used for last window update
|
||||
// WL2 Value // segment acknowledgment number used for last window update
|
||||
}
|
||||
|
||||
// inFlight returns amount of unacked bytes sent out.
|
||||
func (snd *sendSpace) inFlight() Size {
|
||||
return Sizeof(snd.UNA, snd.NXT)
|
||||
}
|
||||
|
||||
// maxSend returns maximum segment datalength receivable by remote peer.
|
||||
func (snd *sendSpace) maxSend() Size {
|
||||
return snd.WND - snd.inFlight()
|
||||
}
|
||||
|
||||
// recvSpace contains Receive Sequence Space data. Its sequence numbers correspond to remote data.
|
||||
type recvSpace struct {
|
||||
IRS Value // initial receive sequence number, defined by remote in SYN segment received.
|
||||
NXT Value // receive next. seqs before this have been acked. this seq and up to NXT+WND-1 are allowed to be sent. Corresponds to remote data.
|
||||
WND Size // receive window defined by local. Permitted number of remote unacked octets in flight.
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
"strconv"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=State -linecomment -output stringers.go .
|
||||
|
||||
// Segment represents an incoming/outgoing TCP segment in the sequence space.
|
||||
type Segment struct {
|
||||
SEQ Value // sequence number of first octet of segment. If SYN is set it is the initial sequence number (ISN) and the first data octet is ISN+1.
|
||||
ACK Value // acknowledgment number. If ACK is set it is sequence number of first octet the sender of the segment is expecting to receive next.
|
||||
DATALEN Size // The number of octets occupied by the data (payload) not counting SYN and FIN.
|
||||
WND Size // segment window
|
||||
Flags Flags // TCP flags.
|
||||
}
|
||||
|
||||
// LEN returns the length of the segment in octets including SYN and FIN flags.
|
||||
func (seg *Segment) LEN() Size {
|
||||
add := Size(seg.Flags>>0) & 1 // Add FIN bit.
|
||||
add += Size(seg.Flags>>1) & 1 // Add SYN bit.
|
||||
return seg.DATALEN + add
|
||||
}
|
||||
|
||||
// End returns the sequence number of the last octet of the segment.
|
||||
func (seg *Segment) Last() Value {
|
||||
seglen := seg.LEN()
|
||||
if seglen == 0 {
|
||||
return seg.SEQ
|
||||
}
|
||||
return Add(seg.SEQ, seglen) - 1
|
||||
}
|
||||
|
||||
// StringExchange returns a string representation of a segment exchange over
|
||||
// a network in RFC9293 styled visualization. invertDir inverts the arrow directions.
|
||||
// i.e:
|
||||
//
|
||||
// SynSent --> <SEQ=300><ACK=91>[SYN,ACK] --> SynRcvd
|
||||
func StringExchange(seg Segment, A, B State, invertDir bool) string {
|
||||
b := make([]byte, 0, 64)
|
||||
b = appendStringExchange(b, seg, A, B, invertDir)
|
||||
return unsafe.String(unsafe.SliceData(b), len(b))
|
||||
}
|
||||
|
||||
// appendStringExchange appends a RFC9293 styled visualization of exchange to buf.
|
||||
// i.e:
|
||||
//
|
||||
// SynSent --> <SEQ=300><ACK=91>[SYN,ACK] --> SynRcvd
|
||||
func appendStringExchange(buf []byte, seg Segment, A, B State, invertDir bool) []byte {
|
||||
const emptySpaces = " "
|
||||
const fill = len(emptySpaces) - 1
|
||||
appendVal := func(buf []byte, name string, i Value) []byte {
|
||||
buf = append(buf, '<')
|
||||
buf = append(buf, name...)
|
||||
buf = append(buf, '=')
|
||||
buf = strconv.AppendInt(buf, int64(i), 10)
|
||||
buf = append(buf, '>')
|
||||
return buf
|
||||
}
|
||||
startLen := len(buf)
|
||||
dirSep := []byte(" --> ")
|
||||
if invertDir {
|
||||
dirSep = []byte(" <-- ")
|
||||
}
|
||||
astr := A.String()
|
||||
buf = append(buf, astr...)
|
||||
if len(astr) < fill {
|
||||
// Space padding.
|
||||
buf = append(buf, emptySpaces[:fill-len(astr)]...)
|
||||
}
|
||||
buf = append(buf, dirSep...)
|
||||
buf = appendVal(buf, "SEQ", seg.SEQ)
|
||||
buf = appendVal(buf, "ACK", seg.ACK)
|
||||
if seg.DATALEN > 0 {
|
||||
buf = appendVal(buf, "DATA", Value(seg.DATALEN))
|
||||
}
|
||||
buf = append(buf, '[')
|
||||
buf = seg.Flags.AppendFormat(buf)
|
||||
buf = append(buf, ']')
|
||||
if len(buf)-startLen < 48 {
|
||||
// More space padding.
|
||||
buf = append(buf, emptySpaces[:48-len(buf)]...)
|
||||
}
|
||||
buf = append(buf, dirSep...)
|
||||
buf = append(buf, B.String()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Flags is a TCP flags bit-masked implementation i.e: SYN, FIN, ACK.
|
||||
type Flags uint16
|
||||
|
||||
const (
|
||||
FlagFIN Flags = 1 << iota // FlagFIN - No more data from sender.
|
||||
FlagSYN // FlagSYN - Synchronize sequence numbers.
|
||||
FlagRST // FlagRST - Reset the connection.
|
||||
FlagPSH // FlagPSH - Push function.
|
||||
FlagACK // FlagACK - Acknowledgment field significant.
|
||||
FlagURG // FlagURG - Urgent pointer field significant.
|
||||
FlagECE // FlagECE - ECN-Echo has a nonce-sum in the SYN/ACK.
|
||||
FlagCWR // FlagCWR - Congestion Window Reduced.
|
||||
FlagNS // FlagNS - Nonce Sum flag (see RFC 3540).
|
||||
)
|
||||
|
||||
const flagMask = 0x01ff
|
||||
|
||||
// The union of SYN|FIN|PSH and ACK flags is commonly found throughout the specification, so we define unexported shorthands.
|
||||
const (
|
||||
synack = FlagSYN | FlagACK
|
||||
finack = FlagFIN | FlagACK
|
||||
pshack = FlagPSH | FlagACK
|
||||
)
|
||||
|
||||
// HasAll checks if mask bits are all set in the receiver flags.
|
||||
func (flags Flags) HasAll(mask Flags) bool { return flags&mask == mask }
|
||||
|
||||
// HasAny checks if one or more mask bits are set in receiver flags.
|
||||
func (flags Flags) HasAny(mask Flags) bool { return flags&mask != 0 }
|
||||
|
||||
// Mask returns the flags with non-flag bits unset.
|
||||
func (flags Flags) Mask() Flags { return flags & flagMask }
|
||||
|
||||
// StringFlags returns human readable flag string. i.e:
|
||||
//
|
||||
// "[SYN,ACK]"
|
||||
//
|
||||
// Flags are printed in order from LSB (FIN) to MSB (NS).
|
||||
// All flags are printed with length of 3, so a NS flag will
|
||||
// end with a space i.e. [ACK,NS ]
|
||||
func (flags Flags) String() string {
|
||||
// Cover most common cases without heap allocating.
|
||||
switch flags {
|
||||
case 0:
|
||||
return "[]"
|
||||
case synack:
|
||||
return "[SYN,ACK]"
|
||||
case finack:
|
||||
return "[FIN,ACK]"
|
||||
case pshack:
|
||||
return "[PSH,ACK]"
|
||||
case FlagACK:
|
||||
return "[ACK]"
|
||||
case FlagSYN:
|
||||
return "[SYN]"
|
||||
case FlagFIN:
|
||||
return "[FIN]"
|
||||
case FlagRST:
|
||||
return "[RST]"
|
||||
}
|
||||
buf := make([]byte, 0, 2+3*bits.OnesCount16(uint16(flags)))
|
||||
buf = append(buf, '[')
|
||||
buf = flags.AppendFormat(buf)
|
||||
buf = append(buf, ']')
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// AppendFormat appends a human readable flag string to b returning the extended buffer.
|
||||
func (flags Flags) AppendFormat(b []byte) []byte {
|
||||
if flags == 0 {
|
||||
return b
|
||||
}
|
||||
// String Flag const
|
||||
const flaglen = 3
|
||||
const strflags = "FINSYNRSTPSHACKURGECECWRNS "
|
||||
var addcommas bool
|
||||
for flags != 0 { // written by Github Copilot- looks OK.
|
||||
i := bits.TrailingZeros16(uint16(flags))
|
||||
if addcommas {
|
||||
b = append(b, ',')
|
||||
} else {
|
||||
addcommas = true
|
||||
}
|
||||
b = append(b, strflags[i*flaglen:i*flaglen+flaglen]...)
|
||||
flags &= ^(1 << i)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// State enumerates states a TCP connection progresses through during its lifetime.
|
||||
type State uint8
|
||||
|
||||
const (
|
||||
// CLOSED - represents no connection state at all. Is not a valid state of the TCP state machine but rather a pseudo-state pre-initialization.
|
||||
StateClosed State = iota // CLOSED
|
||||
// LISTEN - represents waiting for a connection request from any remote TCP and port.
|
||||
StateListen // LISTEN
|
||||
// SYN-RECEIVED - represents waiting for a confirming connection request acknowledgment
|
||||
// after having both received and sent a connection request.
|
||||
StateSynRcvd // SYN-RECEIVED
|
||||
// SYN-SENT - represents waiting for a matching connection request after having sent a connection request.
|
||||
StateSynSent // SYN-SENT
|
||||
// ESTABLISHED - represents an open connection, data received can be delivered
|
||||
// to the user. The normal state for the data transfer phase of the connection.
|
||||
StateEstablished // ESTABLISHED
|
||||
// FIN-WAIT-1 - represents waiting for a connection termination request
|
||||
// from the remote TCP, or an acknowledgment of the connection
|
||||
// termination request previously sent.
|
||||
StateFinWait1 // FIN-WAIT-1
|
||||
// FIN-WAIT-2 - represents waiting for a connection termination request
|
||||
// from the remote TCP.
|
||||
StateFinWait2 // FIN-WAIT-2
|
||||
// CLOSING - represents waiting for a connection termination request
|
||||
// acknowledgment from the remote TCP.
|
||||
StateClosing // CLOSING
|
||||
// TIME-WAIT - represents waiting for enough time to pass to be sure the remote
|
||||
// TCP received the acknowledgment of its connection termination request.
|
||||
StateTimeWait // TIME-WAIT
|
||||
// CLOSE-WAIT - represents waiting for a connection termination request
|
||||
// from the local user.
|
||||
StateCloseWait // CLOSE-WAIT
|
||||
// LAST-ACK - represents waiting for an acknowledgment of the
|
||||
// connection termination request previously sent to the remote TCP
|
||||
// (which includes an acknowledgment of its connection termination request).
|
||||
StateLastAck // LAST-ACK
|
||||
)
|
||||
|
||||
// IsPreestablished returns true if the connection is in a state preceding the established state.
|
||||
// Returns false for Closed pseudo state.
|
||||
func (s State) IsPreestablished() bool {
|
||||
return s == StateSynRcvd || s == StateSynSent || s == StateListen
|
||||
}
|
||||
|
||||
// IsClosing returns true if the connection is in a closing state but not yet terminated (relieved of remote connection state).
|
||||
// Returns false for Closed pseudo state.
|
||||
func (s State) IsClosing() bool {
|
||||
return !(s <= StateEstablished)
|
||||
}
|
||||
|
||||
// IsClosed returns true if the connection closed and can possibly relieved of
|
||||
// all state related to the remote connection. It returns true if Closed or in TimeWait.
|
||||
func (s State) IsClosed() bool {
|
||||
return s == StateClosed || s == StateTimeWait
|
||||
}
|
||||
|
||||
// IsSynchronized returns true if the connection has gone through the Established state.
|
||||
func (s State) IsSynchronized() bool {
|
||||
return s >= StateEstablished
|
||||
}
|
||||
|
||||
// IsDataOpen returns true if the connection allows sending and receiving of data.
|
||||
func (s State) isOpen() bool {
|
||||
return s != StateClosed && s != StateTimeWait // TODO: is this api ok?
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Code generated by "stringer -type=State -linecomment -output stringers.go ."; DO NOT EDIT.
|
||||
|
||||
package tcp
|
||||
|
||||
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[StateClosed-0]
|
||||
_ = x[StateListen-1]
|
||||
_ = x[StateSynRcvd-2]
|
||||
_ = x[StateSynSent-3]
|
||||
_ = x[StateEstablished-4]
|
||||
_ = x[StateFinWait1-5]
|
||||
_ = x[StateFinWait2-6]
|
||||
_ = x[StateClosing-7]
|
||||
_ = x[StateTimeWait-8]
|
||||
_ = x[StateCloseWait-9]
|
||||
_ = x[StateLastAck-10]
|
||||
}
|
||||
|
||||
const _State_name = "CLOSEDLISTENSYN-RECEIVEDSYN-SENTESTABLISHEDFIN-WAIT-1FIN-WAIT-2CLOSINGTIME-WAITCLOSE-WAITLAST-ACK"
|
||||
|
||||
var _State_index = [...]uint8{0, 6, 12, 24, 32, 43, 53, 63, 70, 79, 89, 97}
|
||||
|
||||
func (i State) String() string {
|
||||
if i >= State(len(_State_index)-1) {
|
||||
return "State(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _State_name[_State_index[i]:_State_index[i+1]]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
package tseq implements TCP control flow.
|
||||
package ltcp implements TCP control flow.
|
||||
|
||||
# Transmission Control Block
|
||||
|
||||
@@ -13,7 +13,7 @@ pending control segment flags.
|
||||
All arithmetic dealing with sequence numbers must be performed modulo 2**32
|
||||
which brings with it subtleties to computer modulo arithmetic.
|
||||
*/
|
||||
package tseq
|
||||
package tcp
|
||||
|
||||
import "time"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package lneto
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
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")
|
||||
errShortIPv6 = errors.New("IPv6 payload length exceeds frame")
|
||||
|
||||
errShortTCP = errors.New("TCP offset exceeds frame")
|
||||
errBadTCPOff = errors.New("TCP offset invalid")
|
||||
)
|
||||
|
||||
// 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() error {
|
||||
ul := ufrm.Length()
|
||||
if ul < sizeHeaderUDP {
|
||||
return errBadUDPLen
|
||||
} else if int(ul) > len(ufrm.RawData()) {
|
||||
return errShortUDP
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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() error {
|
||||
tl := ifrm.TotalLength()
|
||||
if tl < sizeHeaderIPv4 {
|
||||
return errBadIPv4TL
|
||||
} else if int(tl) > len(ifrm.RawData()) {
|
||||
return errShortIPv4
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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() error {
|
||||
off := tfrm.HeaderLength()
|
||||
if off < sizeHeaderTCP {
|
||||
return errBadTCPOff
|
||||
} else if off > len(tfrm.RawData()) {
|
||||
return errShortTCP
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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() error {
|
||||
tl := i6frm.PayloadLength()
|
||||
if int(tl)+sizeHeaderIPv6 > len(i6frm.RawData()) {
|
||||
return errShortIPv6
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user