first commit

This commit is contained in:
soypat
2024-12-23 18:56:52 -03:00
parent 53f3296e99
commit 4ea0a782cf
15 changed files with 1362 additions and 78 deletions
+10 -35
View File
@@ -1,44 +1,19 @@
# go-module-template
[![go.dev reference](https://pkg.go.dev/badge/github.com/soypat/go-module-template)](https://pkg.go.dev/github.com/soypat/go-module-template)
[![Go Report Card](https://goreportcard.com/badge/github.com/soypat/go-module-template)](https://goreportcard.com/report/github.com/soypat/go-module-template)
[![codecov](https://codecov.io/gh/soypat/go-module-template/branch/main/graph/badge.svg)](https://codecov.io/gh/soypat/go-module-template)
[![Go](https://github.com/soypat/go-module-template/actions/workflows/go.yml/badge.svg)](https://github.com/soypat/go-module-template/actions/workflows/go.yml)
[![sourcegraph](https://sourcegraph.com/github.com/soypat/go-module-template/-/badge.svg)](https://sourcegraph.com/github.com/soypat/go-module-template?badge)
<!--
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
# tseq
[![go.dev reference](https://pkg.go.dev/badge/github.com/soypat/tseq)](https://pkg.go.dev/github.com/soypat/tseq)
[![Go Report Card](https://goreportcard.com/badge/github.com/soypat/tseq)](https://goreportcard.com/report/github.com/soypat/tseq)
[![codecov](https://codecov.io/gh/soypat/tseq/branch/main/graph/badge.svg)](https://codecov.io/gh/soypat/tseq)
[![Go](https://github.com/soypat/tseq/actions/workflows/go.yml/badge.svg)](https://github.com/soypat/tseq/actions/workflows/go.yml)
[![sourcegraph](https://sourcegraph.com/github.com/soypat/tseq/-/badge.svg)](https://sourcegraph.com/github.com/soypat/tseq?badge)
[![stability-experimental](https://img.shields.io/badge/stability-experimental-orange.svg)](https://github.com/emersion/stability-badges#experimental)
Userspace networking primitives.
See https://github.com/emersion/stability-badges#unstable for more stability badges.
-->
Go module template with instructions on how to make your code importable and setting up codecov CI.
### Packages
- `lneto`: Low-level Networking Operations, or "El Neto", the big networking package. Zero copy network frame marshalling and unmarshalling.
How to install package with newer versions of Go (+1.16):
```sh
go mod download github.com/soypat/go-module-template@latest
go mod download github.com/soypat/tseq@latest
```
## First steps
0. Replace LICENSE with your desired license. BSD 3 clause is included by default.
1. Fix `go.mod` file by replacing `github.com/YOURUSER/YOURREPONAME` with your corresponding project repository link.
2. Replace `soypat/go-module-template` in the badge URLs. Make sure you've replaced all of them by performing text search in the readme for `soypat` and `template`.
3. Rename `module.go` and `module_test.go` to fit your own repository needs. Below are some exemplary modules that abide by what's generally considered "good practices":
- [`mu8` minimal machine learning library](https://github.com/soypat/mu8). Note how most interfaces and interface algorithms are defined at the root package level and how the concrete implementations live in the subdirectories.
- Similarily [`sdf`](https://github.com/soypat/sdf) also does the same with defining interfaces top level.
## Setting up codecov CI
This instructive will allow for tests to run on pull requests and pushes to your repository.
1. Create an account on [codecov.io](https://app.codecov.io/)
2. Setup repository on codecov and obtain the CODECOV_TOKEN token, which is a string of base64 characters.
3. Open up the github repository for this project and go to `Settings -> Secrets and variables -> Actions`. Once there create a New Repository Secret. Name it `CODECOV_TOKEN` and copy paste the token obtained in the previous step in the `secret` input box. Click "Add secret".
-9
View File
@@ -1,9 +0,0 @@
package main
import (
"os"
)
func main() {
os.Stdout.WriteString("Hello world!\n")
}
+1 -1
View File
@@ -1,3 +1,3 @@
module github.com/YOURUSER/YOURREPONAME
module github.com/soypat/tseq
go 1.20
+84
View File
@@ -0,0 +1,84 @@
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{} }
+67
View File
@@ -0,0 +1,67 @@
package lneto
//go:generate stringer -type=EtherType -linecomment -output stringers.go .
type EtherType uint16
// 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
)
type IPToS uint8
func (tos IPToS) DSCP() uint8 { return uint8(tos) >> 2 }
func (tos IPToS) ECN() uint8 { return uint8(tos & 0b11) }
type IPv4Flags uint16
func (f IPv4Flags) DontFragment() bool { return f&0x4000 != 0 }
func (f IPv4Flags) MoreFragments() bool { return f&0x8000 != 0 }
func (f IPv4Flags) FragmentOffset() uint16 { return uint16(f) & 0x1fff }
type TCPFlags uint8
+120
View File
@@ -0,0 +1,120 @@
package dhcp
import (
"errors"
"fmt"
)
//go:generate stringer -type=OptNum,Op,MessageType -linecomment -output stringers.go
type Option struct {
Num OptNum
Data []byte
}
func (opt *Option) String() string {
return opt.Num.String() + ":" + fmt.Sprint(opt.Data)
}
func (opt *Option) Encode(dst []byte) (int, error) {
if len(opt.Data) > 255 {
return 0, errors.New("DHCP option data too long")
} else if len(dst) < 2+len(opt.Data) {
return 0, errors.New("DHCP option buffer too short")
}
_ = dst[2+len(opt.Data)]
dst[0] = byte(opt.Num)
dst[1] = byte(len(opt.Data))
copy(dst[2:], opt.Data)
return 2 + len(opt.Data), nil
}
type OptNum uint8
// DHCP options. Taken from https://help.sonicwall.com/help/sw/eng/6800/26/2/3/content/Network_DHCP_Server.042.12.htm.
const (
OptWordAligned OptNum = 0 // word-aligned
OptSubnetMask OptNum = 1 // subnet mask
OptTimeOffset OptNum = 2 // Time offset in seconds from UTC
OptRouter OptNum = 3 // N/4 router addresses
OptTimeServers OptNum = 4 // N/4 time server addresses
OptNameServers OptNum = 5 // N/4 IEN-116 server addresses
OptDNSServers OptNum = 6 // N/4 DNS server addresses
OptLogServers OptNum = 7 // N/4 logging server addresses
OptCookieServers OptNum = 8 // N/4 quote server addresses
OptLPRServers OptNum = 9 // N/4 printer server addresses
OptImpressServers OptNum = 10 // N/4 impress server addresses
OptRLPServers OptNum = 11 // N/4 RLP server addresses
OptHostName OptNum = 12 // Hostname string
OptBootFileSize OptNum = 13 // Size of boot file in 512 byte chunks
OptMeritDumpFile OptNum = 14 // Client to dump and name of file to dump to
OptDomainName OptNum = 15 // The DNS domain name of the client
OptSwapServer OptNum = 16 // Swap server addresses
OptRootPath OptNum = 17 // Path name for root disk
OptExtensionFile OptNum = 18 // Patch name for more BOOTP info
OptIPLayerForwarding OptNum = 19 // Enable or disable IP forwarding
OptSrcrouteenabler OptNum = 20 // Enable or disable source routing
OptPolicyFilter OptNum = 21 // Routing policy filters
OptMaximumDGReassemblySize OptNum = 22 // Maximum datagram reassembly size
OptDefaultIPTTL OptNum = 23 // Default IP time-to-live
OptPathMTUAgingTimeout OptNum = 24 // Path MTU aging timeout
OptMTUPlateau OptNum = 25 // Path MTU plateau table
OptInterfaceMTUSize OptNum = 26 // Interface MTU size
OptAllSubnetsAreLocal OptNum = 27 // All subnets are local
OptBroadcastAddress OptNum = 28 // Broadcast address
OptPerformMaskDiscovery OptNum = 29 // Perform mask discovery
OptProvideMasktoOthers OptNum = 30 // Provide mask to others
OptPerformRouterDiscovery OptNum = 31 // Perform router discovery
OptRouterSolicitationAddress OptNum = 32 // Router solicitation address
OptStaticRoutingTable OptNum = 33 // Static routing table
OptTrailerEncapsulation OptNum = 34 // Trailer encapsulation
OptARPCacheTimeout OptNum = 35 // ARP cache timeout
OptEthernetEncapsulation OptNum = 36 // Ethernet encapsulation
OptDefaultTCPTimetoLive OptNum = 37 // Default TCP time to live
OptTCPKeepaliveInterval OptNum = 38 // TCP keepalive interval
OptTCPKeepaliveGarbage OptNum = 39 // TCP keepalive garbage
OptNISDomainName OptNum = 40 // NIS domain name
OptNISServerAddresses OptNum = 41 // NIS server addresses
OptNTPServersAddresses OptNum = 42 // NTP servers addresses
OptVendorSpecificInformation OptNum = 43 // Vendor specific information
OptNetBIOSNameServer OptNum = 44 // NetBIOS name server
OptNetBIOSDatagramDistribution OptNum = 45 // NetBIOS datagram distribution
OptNetBIOSNodeType OptNum = 46 // NetBIOS node type
OptNetBIOSScope OptNum = 47 // NetBIOS scope
OptXWindowFontServer OptNum = 48 // X window font server
OptXWindowDisplayManager OptNum = 49 // X window display manager
OptRequestedIPaddress OptNum = 50 // Requested IP address
OptIPAddressLeaseTime OptNum = 51 // IP address lease time
OptOptionOverload OptNum = 52 // Overload “sname” or “file”
OptMessageType OptNum = 53 // DHCP message type.
OptServerIdentification OptNum = 54 // DHCP server identification
OptParameterRequestList OptNum = 55 // Parameter request list
OptMessage OptNum = 56 // DHCP error message
OptMaximumMessageSize OptNum = 57 // DHCP maximum message size
OptRenewTimeValue OptNum = 58 // DHCP renewal (T1) time
OptRebindingTimeValue OptNum = 59 // DHCP rebinding (T2) time
OptClientIdentifier OptNum = 60 // Client identifier
OptClientIdentifier1 OptNum = 61 // Client identifier(1)
)
type Op byte
const (
opUndefined Op = iota // undefined
OpRequest // request
OpReply // reply
)
type MessageType uint8
const (
msg MessageType = iota // undefined
MsgDiscover // discover
MsgOffer // offer
MsgRequest // request
MsgDecline // decline
MsgAck // ack
MsgNak // nak
MsgRelease // release
MsgInform // inform
)
+120
View File
@@ -0,0 +1,120 @@
package dhcp
import (
"encoding/binary"
"errors"
)
const (
sizeSName = 64 // Server name, part of BOOTP too.
sizeBootFile = 128 // Boot file name, Legacy.
sizeHeader = 44
// Magic Cookie offset measured from the start of the UDP payload.
magicCookieOffset = sizeHeader + sizeSName + sizeBootFile
// Expected Magic Cookie value.
MagicCookie uint32 = 0x63825363
// DHCP Options offset measured from the start of the UDP payload.
optionsOffset = magicCookieOffset + 4
DefaultClientPort = 68
DefaultServerPort = 67
)
func NewFrameV4(buf []byte) FrameV4 {
return FrameV4{buf: buf}
}
type FrameV4 struct {
buf []byte
}
func (frm FrameV4) Op() Op {
return Op(frm.buf[0])
}
func (frm FrameV4) Hardware() (Type, Len, Ops uint8) {
return frm.buf[1], frm.buf[2], frm.buf[3]
}
func (frm FrameV4) SetHardware(Type, Len, Ops uint8) {
frm.buf[1], frm.buf[2], frm.buf[3] = Type, Len, Ops
}
func (frm FrameV4) XID() uint32 {
return binary.BigEndian.Uint32(frm.buf[4:8])
}
func (frm FrameV4) Secs() uint16 {
return binary.BigEndian.Uint16(frm.buf[8:10])
}
func (frm FrameV4) Flags() uint16 {
return binary.BigEndian.Uint16(frm.buf[10:12])
}
// CIAddr is the client IP address. If the client has not obtained an IP
// address yet, this field is set to 0.
func (frm FrameV4) CIAddr() *[4]byte {
return (*[4]byte)(frm.buf[12:16])
}
// YIAddr is the IP address offered by the server to the client.
func (frm FrameV4) YIAddr() *[4]byte {
return (*[4]byte)(frm.buf[16:20])
}
// SIAddr is the IP address of the next server to use in bootstrap. This
// field is used in DHCPOFFER and DHCPACK messages.
func (frm FrameV4) SIAddr() *[4]byte {
return (*[4]byte)(frm.buf[20:24])
}
// GIAddr is the gateway IP address.
func (frm FrameV4) GIAddr() *[4]byte {
return (*[4]byte)(frm.buf[24:28])
}
// CHAddrAs6 returns [FrameV4.CHAddr] but limited to first 6 bytes.
func (frm FrameV4) CHAddrAs6() *[6]byte {
return (*[6]byte)(frm.buf[28 : 28+6])
}
// CHAddr is the client hardware address. Can be up to 16 bytes in length but
// is usually 6 bytes for Ethernet.
func (frm FrameV4) CHAddr() *[16]byte {
return (*[16]byte)(frm.buf[28:44])
}
func (frm FrameV4) MagicCookie() uint32 {
return binary.BigEndian.Uint32(frm.buf[magicCookieOffset:])
}
func (frm FrameV4) ForEachOption(fn func(opt Option) error) error {
if fn == nil {
return errors.New("nil function to parse DHCP")
}
// Parse DHCP options.
ptr := optionsOffset
if ptr >= len(frm.buf) {
return errors.New("short payload to parse DHCP options")
}
for ptr+1 < len(frm.buf) {
if int(frm.buf[ptr+1]) >= len(frm.buf) {
return errors.New("DHCP option length exceeds payload")
}
optnum := OptNum(frm.buf[ptr])
if optnum == 0xff {
break
} else if optnum == OptWordAligned {
ptr++
continue
}
optlen := frm.buf[ptr+1]
optionData := frm.buf[ptr+2 : ptr+2+int(optlen)]
if err := fn(Option{optnum, optionData}); err != nil {
return err
}
ptr += int(optlen) + 2
}
return nil
}
+84
View File
@@ -0,0 +1,84 @@
// Code generated by "stringer -type=OptNum -linecomment -output stringers.go"; DO NOT EDIT.
package dhcp
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[OptWordAligned-0]
_ = x[OptSubnetMask-1]
_ = x[OptTimeOffset-2]
_ = x[OptRouter-3]
_ = x[OptTimeServers-4]
_ = x[OptNameServers-5]
_ = x[OptDNSServers-6]
_ = x[OptLogServers-7]
_ = x[OptCookieServers-8]
_ = x[OptLPRServers-9]
_ = x[OptImpressServers-10]
_ = x[OptRLPServers-11]
_ = x[OptHostName-12]
_ = x[OptBootFileSize-13]
_ = x[OptMeritDumpFile-14]
_ = x[OptDomainName-15]
_ = x[OptSwapServer-16]
_ = x[OptRootPath-17]
_ = x[OptExtensionFile-18]
_ = x[OptIPLayerForwarding-19]
_ = x[OptSrcrouteenabler-20]
_ = x[OptPolicyFilter-21]
_ = x[OptMaximumDGReassemblySize-22]
_ = x[OptDefaultIPTTL-23]
_ = x[OptPathMTUAgingTimeout-24]
_ = x[OptMTUPlateau-25]
_ = x[OptInterfaceMTUSize-26]
_ = x[OptAllSubnetsAreLocal-27]
_ = x[OptBroadcastAddress-28]
_ = x[OptPerformMaskDiscovery-29]
_ = x[OptProvideMasktoOthers-30]
_ = x[OptPerformRouterDiscovery-31]
_ = x[OptRouterSolicitationAddress-32]
_ = x[OptStaticRoutingTable-33]
_ = x[OptTrailerEncapsulation-34]
_ = x[OptARPCacheTimeout-35]
_ = x[OptEthernetEncapsulation-36]
_ = x[OptDefaultTCPTimetoLive-37]
_ = x[OptTCPKeepaliveInterval-38]
_ = x[OptTCPKeepaliveGarbage-39]
_ = x[OptNISDomainName-40]
_ = x[OptNISServerAddresses-41]
_ = x[OptNTPServersAddresses-42]
_ = x[OptVendorSpecificInformation-43]
_ = x[OptNetBIOSNameServer-44]
_ = x[OptNetBIOSDatagramDistribution-45]
_ = x[OptNetBIOSNodeType-46]
_ = x[OptNetBIOSScope-47]
_ = x[OptXWindowFontServer-48]
_ = x[OptXWindowDisplayManager-49]
_ = x[OptRequestedIPaddress-50]
_ = x[OptIPAddressLeaseTime-51]
_ = x[OptOptionOverload-52]
_ = x[OptMessageType-53]
_ = x[OptServerIdentification-54]
_ = x[OptParameterRequestList-55]
_ = x[OptMessage-56]
_ = x[OptMaximumMessageSize-57]
_ = x[OptRenewTimeValue-58]
_ = x[OptRebindingTimeValue-59]
_ = x[OptClientIdentifier-60]
_ = x[OptClientIdentifier1-61]
}
const _OptNum_name = "OptWordAlignedOptSubnetMaskTime offset in seconds from UTCN/4 router addressesN/4 time server addressesN/4 IEN-116 server addressesN/4 DNS server addressesN/4 logging server addressesN/4 quote server addressesN/4 printer server addressesN/4 impress server addressesN/4 RLP server addressesHostname stringSize of boot file in 512 byte chunksClient to dump and name of file to dump toThe DNS domain name of the clientSwap server addressesPath name for root diskPatch name for more BOOTP infoEnable or disable IP forwardingEnable or disable source routingRouting policy filtersMaximum datagram reassembly sizeDefault IP time-to-livePath MTU aging timeoutPath MTU plateau tableInterface MTU sizeAll subnets are localBroadcast addressPerform mask discoveryProvide mask to othersPerform router discoveryRouter solicitation addressStatic routing tableTrailer encapsulationARP cache timeoutEthernet encapsulationDefault TCP time to liveTCP keepalive intervalTCP keepalive garbageNIS domain nameNIS server addressesNTP servers addressesVendor specific informationNetBIOS name serverNetBIOS datagram distributionNetBIOS node typeNetBIOS scopeX window font serverX window display managerRequested IP addressIP address lease timeOverload “sname” or “file”DHCP message type.DHCP server identificationParameter request listDHCP error messageDHCP maximum message sizeDHCP renewal (T1) timeDHCP rebinding (T2) timeClient identifierClient identifier"
var _OptNum_index = [...]uint16{0, 14, 27, 58, 78, 103, 131, 155, 183, 209, 237, 265, 289, 304, 340, 382, 415, 436, 459, 489, 520, 552, 574, 606, 629, 651, 673, 691, 712, 729, 751, 773, 797, 824, 844, 865, 882, 904, 928, 950, 971, 986, 1006, 1027, 1054, 1073, 1102, 1119, 1132, 1152, 1176, 1196, 1217, 1251, 1269, 1295, 1317, 1335, 1360, 1382, 1406, 1423, 1440}
func (i OptNum) String() string {
if i >= OptNum(len(_OptNum_index)-1) {
return "OptNum(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _OptNum_name[_OptNum_index[i]:_OptNum_index[i+1]]
}
+397
View File
@@ -0,0 +1,397 @@
package lneto
import (
"encoding/binary"
"github.com/soypat/tseq"
)
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} }
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 (frm EthFrame) Payload() []byte {
if frm.IsVLAN() {
return frm.buf[18:]
}
return frm.buf[14:]
}
func (frm EthFrame) DstHardwareAddr6() (dst *[6]byte) {
return (*[6]byte)(frm.buf[:6])
}
func (frm EthFrame) SrcHardwareAddr6() (src *[6]byte) {
return (*[6]byte)(frm.buf[6:12])
}
func (frm EthFrame) EtherTypeOrSize() uint16 {
return binary.BigEndian.Uint16(frm.buf[12:14])
}
// 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 (frm EthFrame) IsVLAN() bool {
return frm.EtherTypeOrSize() == uint16(EtherTypeVLAN)
}
type ARPv4Frame struct {
buf []byte
}
// RawData returns the underlying slice with which the frame was created.
func (frm ARPv4Frame) RawData() []byte { return frm.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]
return Type, length
}
func (arp ARPv4Frame) SetHardware(Type uint16, length uint8) {
binary.BigEndian.PutUint16(arp.buf[0:2], Type)
arp.buf[4] = length
}
func (arp ARPv4Frame) Protocol() (Type uint16, length uint8) {
Type = binary.BigEndian.Uint16(arp.buf[2:4])
length = arp.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 (arp ARPv4Frame) SetOperation(b uint8) { arp.buf[6] = b }
func (arp ARPv4Frame) IsOperationRequest() bool { return arp.buf[6] == 1 }
func (arp ARPv4Frame) IsOperationReply() bool { return arp.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])
}
// 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])
}
type IPv4Frame struct {
buf []byte
}
// RawData returns the underlying slice with which the frame was created.
func (frm IPv4Frame) RawData() []byte { return frm.buf}
func (ip IPv4Frame) Version() uint8 { return ip.buf[0] & 0xf }
func (ip IPv4Frame) IHL() uint8 { return ip.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 (ip IPv4Frame) SetVersionAndIHL(version, IHL uint8) { ip.buf[0] = version&0xf | IHL<<4 }
// 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 (ip IPv4Frame) ToS() IPToS {
return IPToS(ip.buf[1])
}
// SetToS sets ToS field. See [IPv4Frame.ToS].
func (ip IPv4Frame) SetToS(tos IPToS) { ip.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 (ip IPv4Frame) TotalLength() uint16 {
return binary.BigEndian.Uint16(ip.buf[2:4])
}
// SetTotalLength sets TotalLength field. See [IPv4Frame.TotalLength].
func (ip IPv4Frame) SetTotalLength(tl uint16) { binary.BigEndian.PutUint16(ip.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])
}
// SetID sets ID field. See [IPv4Frame.ID].
func (ip IPv4Frame) SetID(id uint16) { binary.BigEndian.PutUint16(ip.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]))
}
// SetFlags sets the IPv4 flags field. See [IPv4Flags].
func (ip IPv4Frame) SetFlags(flags IPv4Flags) { binary.BigEndian.PutUint16(ip.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] }
// SetTTL sets the IP frame's TTL field. See [IPv4Frame.TTL].
func (ip IPv4Frame) SetTTL(ttl uint8) { ip.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] }
// SetProtocol sets protocol field. See [IPv4Frame.Protocol].
func (ip IPv4Frame) SetProtocol(proto uint8) { ip.buf[9] = 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])
}
// 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 (ip IPv4Frame) CalculateHeaderCRC() uint16 {
var crc CRC791
crc.Write(ip.buf[0:10])
crc.Write(ip.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 (ip IPv4Frame) writeUDPPseudoCRC(crc *CRC791) {
crc.Write(ip.SourceAddr()[:])
crc.Write(ip.DestinationAddr()[:])
crc.AddUint16(uint16(ip.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])
}
// 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 (ip IPv4Frame) Payload() []byte {
off := ip.HeaderLength()
l := ip.TotalLength()
return ip.buf[off:l]
}
type TCPFrame struct {
buf []byte
}
// RawData returns the underlying slice with which the frame was created.
func (frm TCPFrame) RawData() []byte { return frm.buf}
func (tcp TCPFrame) SourcePort() uint16 {
return binary.BigEndian.Uint16(tcp.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 (tcp TCPFrame) DestinationPort() uint16 {
return binary.BigEndian.Uint16(tcp.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)
}
// 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]))
}
// SetSeq sets Seq field. See [TCPFrame.Seq].
func (tcp TCPFrame) SetSeq(v tseq.Value) {
binary.BigEndian.PutUint32(tcp.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]))
}
// SetAck sets Ack field. See [TCPFrame.Ack].
func (tcp TCPFrame) SetAck(v tseq.Value) {
binary.BigEndian.PutUint32(tcp.buf[8:12], uint32(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())
}
// 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])
}
// 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 (tcp TCPFrame) CalculateCRC(ipPseudo 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")
}
tcp.writeCRC(&crc)
return crc.Sum16()
}
func (tcp TCPFrame) writeCRC(crc *CRC791) {
// Write excluding
crc.Write(tcp.buf[:16])
crc.Write(tcp.buf[18:])
}
func (tcp TCPFrame) SetUrgentPtr(up uint16) {
binary.BigEndian.PutUint16(tcp.buf[18:20], up)
}
func (tcp TCPFrame) Payload() []byte {
return tcp.buf[tcp.HeaderLength():]
}
type UDPFrame struct {
buf []byte
}
// RawData returns the underlying slice with which the frame was created.
func (frm UDPFrame) RawData() []byte { return frm.buf}
func (udp UDPFrame) SourcePort() uint16 {
return binary.BigEndian.Uint16(udp.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 (udp UDPFrame) DestinationPort() uint16 {
return binary.BigEndian.Uint16(udp.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)
}
// 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])
}
// 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 (udp UDPFrame) CRC() uint16 {
return binary.BigEndian.Uint16(udp.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)
}
// Payload returns the data part of the UDP frame.
func (udp UDPFrame) Payload() []byte {
l := udp.Length()
return udp.buf[8:l]
}
func (udp UDPFrame) CalculateChecksum(pseudoHeader 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())
return crc.Sum16()
}
+36
View File
@@ -0,0 +1,36 @@
package ntp
type LeapIndicator uint8
const (
LeapNoWarning LeapIndicator = iota // no warning
LeapLastMinute61 // last minute 61
LeapLastMinute59 // last minute 59
)
const (
// If the Stratum field is 0, which implies unspecified or invalid, the
// Reference Identifier field can be used to convey messages useful for
// status reporting and access control. These are called Kiss-o'-Death
// (KoD) packets and the ASCII messages they convey are called kiss codes.
StratumUnspecified = 0
StratumPrimary = 1
StratumUnsync = 16
)
func IsStratumSecondary(stratum uint8) bool {
return stratum > 1 && stratum < 16
}
type Mode uint8
const (
modeUndef Mode = iota // undefined
ModeSymmetricActive // symmetric active
ModeSymmetricPassive // symmetric passive
ModeClient // client
ModeServer // server
ModeBroadcast // broadcast
ModeNTPControlMessage // control message
ModePrivateUse // private use
)
+272
View File
@@ -0,0 +1,272 @@
// package ntp implements the NTP protocol as described in RFC 5905.
package ntp
import (
"encoding/binary"
"errors"
"math"
"math/bits"
"sync"
"time"
)
// NTP Global Parameters.
const (
SizeHeader = 48
ClientPort = 1023 // Typical Client port number.
ServerPort = 123 // NTP server port number
Version4 = 4 // Current NTP Version Number
MinPoll = 4 // Minimum poll exponent (16s)
MaxPoll = 17 // Maximum poll exponent (~36h)
MaxDisp = 16 // Maximum dispersion (16s)
MaxDist = 1 // Distance threshold (1s)
MaxStratum = 16 // Maximum stratum
MinDispDiv = 200 // Minimum dispersion divisor 1/(200) == 0.005
)
func NewFrame(buf []byte) Frame {
return Frame{buf: buf}
}
type Frame struct {
buf []byte
}
func (frm Frame) Flags() (mode Mode, version uint8, lp LeapIndicator) {
b := frm.buf[0]
mode = Mode(b & 0b111)
version = (b << 3) & 0b11
lp = LeapIndicator(b >> 5)
return mode, version, lp
}
func (frm Frame) SetFlags(mode Mode, version uint8, lp LeapIndicator) {
b := uint8(mode)&0b111 | (Version4&0b11)<<3 | uint8(lp&0b111)<<5
frm.buf[0] = b
}
func (frm Frame) Stratum() uint8 { return frm.buf[1] }
func (frm Frame) SetStratum(stratum uint8) { frm.buf[1] = stratum }
// Poll is 8-bit signed integer representing the maximum interval between
// successive messages, in log2 seconds. Suggested default limits for
// minimum and maximum poll intervals are 6 and 10, respectively.
func (frm Frame) Poll() int8 { return int8(frm.buf[2]) }
func (frm Frame) SetPoll(Poll int8) { frm.buf[2] = uint8(Poll) }
// Precision is 8-bit signed integer representing the precision of the
// system clock, in log2 seconds. For instance, a value of -18
// corresponds to a precision of about one microsecond. The precision
// can be determined when the service first starts up as the minimum
// time of several iterations to read the system clock.
func (frm Frame) Precision() int8 { return int8(frm.buf[3]) }
func (frm Frame) SetPrecision(Precision int8) { frm.buf[3] = uint8(Precision) }
// Total round-trip delay to the reference clock, in NTP short format.
func (frm Frame) RootDelay() Short {
return Short(binary.BigEndian.Uint32(frm.buf[4:8]))
}
func (frm Frame) SetRootDelay(rd Short) {
binary.BigEndian.PutUint32(frm.buf[4:8], uint32(rd))
}
// Total dispersion to the reference clock, in NTP short format.
func (frm Frame) RootDispersion() Short {
return Short(binary.BigEndian.Uint32(frm.buf[8:12]))
}
func (frm Frame) SetRootDispersion(rd Short) {
binary.BigEndian.PutUint32(frm.buf[8:12], uint32(rd))
}
// 32-bit code identifying the particular server or reference clock.
// The interpretation depends on the value in the stratum field.
// For packet stratum 0 (unspecified or invalid), this is a four-character
// ASCII [RFC1345] string, called the "kiss code", used for debugging and monitoring purposes.
// For stratum 1 (reference clock), this is a four-octet, left-justified,
// zero-padded ASCII string assigned to the reference clock.
// The authoritative list of Reference Identifiers is maintained by IANA; however, any string
// beginning with the ASCII character "X" is reserved for unregistered
// experimentation and development.
func (frm Frame) ReferenceID() *[4]byte {
return (*[4]byte)(frm.buf[12:16])
}
// ReferenceTime is when the system clock was last set or corrected, in NTP timestamp format.
func (frm Frame) ReferenceTime() Timestamp {
return TimestampFromUint64(binary.BigEndian.Uint64(frm.buf[16:24]))
}
func (frm Frame) SetReferenceTime(rt Timestamp) {
rt.Put(frm.buf[16:24])
}
// OriginTime is time at the client when the request departed for the server, in NTP timestamp format.
func (frm Frame) OriginTime() Timestamp {
return TimestampFromUint64(binary.BigEndian.Uint64(frm.buf[24:32]))
}
func (frm Frame) SetOriginTime(ot Timestamp) {
ot.Put(frm.buf[24:32])
}
// ReceiveTime time at the server when the request arrived from the client, in NTP timestamp format.
func (frm Frame) ReceiveTime() Timestamp {
return TimestampFromUint64(binary.BigEndian.Uint64(frm.buf[32:40]))
}
func (frm Frame) SetReceiveTime(rt Timestamp) {
rt.Put(frm.buf[32:40])
}
// TransmitTime at the server when the response left for the client, in NTP timestamp format.
func (frm Frame) TransmitTime() Timestamp {
return TimestampFromUint64(binary.BigEndian.Uint64(frm.buf[40:48]))
}
func (frm Frame) SetTransmitTime(rt Timestamp) {
rt.Put(frm.buf[40:48])
}
type Short uint32
var baseTime = time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
// BaseTime returnsS the time that corresponds to the NTP base time.
// The zero value for [Timestamp] and [Date] types corresponds to this time.
func BaseTime() time.Time {
return baseTime
}
// In the date and timestamp formats, the prime epoch, or base date of
// era 0, is 0 h 1 January 1900 UTC, when all bits are zero. It should
// be noted that strictly speaking, UTC did not exist prior to 1 January
// 1972, but it is convenient to assume it has existed for all eternity,
// even if all knowledge of historic leap seconds has been lost. Dates
// are relative to the prime epoch; values greater than zero represent
// times after that date; values less than zero represent times before
// it. Note that the Era Offset field of the date format and the
// Seconds field of the timestamp format have the same interpretation.
// Timestamp format is used in packet headers and other
// places with limited word size. It includes a 32-bit unsigned seconds
// field spanning 136 years and a 32-bit fraction field resolving 232
// picoseconds. The 32-bit short format is used in delay and dispersion
// header fields where the full resolution and range of the other
// formats are not justified. It includes a 16-bit unsigned seconds
// field and a 16-bit fraction field.
type Timestamp struct {
sec uint32
fra uint32
}
func (t Timestamp) Put(b []byte) {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
binary.BigEndian.PutUint32(b[:4], t.sec)
binary.BigEndian.PutUint32(b[4:], t.fra)
}
// IsZero reports whether t represents the zero time instant.
func (t Timestamp) IsZero() bool { return t.sec == 0 && t.fra == 0 }
func TimestampFromUint64(ts uint64) Timestamp {
return Timestamp{
sec: uint32(ts >> 32),
fra: uint32(ts),
}
}
func TimestampFromTime(t time.Time) (Timestamp, error) {
t = t.UTC()
if t.Before(baseTime) {
return Timestamp{}, errors.New("ntp.TimestampFromTime: time is before baseTime")
}
off := t.Sub(baseTime)
sec := uint64(off / time.Second)
if sec > math.MaxUint32 {
return Timestamp{}, errors.New("ntp.TimestampFromTime: time is too large")
}
fra := uint64(off%time.Second) * math.MaxUint32 / uint64(time.Second)
return Timestamp{
sec: uint32(sec),
fra: uint32(fra),
}, nil
}
// The 128-bit date format is used where sufficient storage and word
// size are available. It includes a 64-bit signed seconds field
// spanning 584 billion years and a 64-bit fraction field resolving .05
// attosecond (i.e., 0.5e-18).
type Date struct {
sec int64
frac uint64
}
func (t Timestamp) Seconds() uint32 { return t.sec }
func (t Timestamp) Fractions() uint32 { return t.fra }
func (t Short) Seconds() uint16 { return uint16(t >> 16) }
func (t Short) Fractions() uint16 { return uint16(t) }
func (t Timestamp) Time() time.Time {
off := time.Second*time.Duration(t.Seconds()) + time.Second*time.Duration(t.Fractions())/math.MaxUint32
return baseTime.Add(off)
}
func (t Timestamp) Sub(v Timestamp) time.Duration {
dsec := time.Duration(t.sec) - time.Duration(v.sec)
dfra := time.Duration(t.fra) - time.Duration(v.fra)
// Work in uint64 to avoid overflow since fra is possibly MaxUint32-1
// which means the result of dfra*MaxUint32 would be MaxUint64-MaxUint32, overflowing time.Duration's
// underlying int64 representation by *a lot*.
dfraneg := dfra < 0
dfra = time.Duration(uint64(dfra.Abs()) * uint64(time.Second) / math.MaxUint32)
if dfraneg {
dfra = -dfra
}
return dsec*time.Second + dfra
}
func (t Timestamp) Add(d time.Duration) Timestamp {
add := uint32(uint64(d%time.Second) * math.MaxUint32 / uint64(time.Second))
add, carry := bits.Add32(t.fra, add, 0)
t.sec += uint32(d/time.Second) + carry
t.fra = add
return t
}
func (d Date) Time() (time.Time, error) {
sec := d.sec
neg := sec < 0
if neg {
sec = -sec
}
hi, seclo := bits.Mul64(uint64(sec), uint64(time.Second))
if hi != 0 || seclo > math.MaxInt64-uint64(time.Second)-1 {
return time.Time{}, errors.New("ntp.Date.Time overflow")
}
off := time.Duration(seclo)
off += time.Second * time.Duration(d.frac>>32) / math.MaxUint32
if neg {
off = -off
}
return baseTime.Add(off), nil
}
var (
ntpOnceSystemClock sync.Once
sysPrec int8
)
// SystemPrecision calculates the Precision field value for the NTP header once
// and reuses it for all future calls.
func SystemPrecision() int8 {
ntpOnceSystemClock.Do(recalculateSystemPrecision)
return sysPrec
}
func recalculateSystemPrecision() {
const maxIter = 16
var times [maxIter]time.Time
for i := 0; i < maxIter; i++ {
times[i] = time.Now()
}
avg := times[maxIter-1].Sub(times[0]) / maxIter
sysPrec = int8(math.Log2(avg.Seconds()))
}
+105
View File
@@ -0,0 +1,105 @@
// Code generated by "stringer -type=EtherType -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) + ")"
}
-12
View File
@@ -1,12 +0,0 @@
// package gomoduletemplate is a template repository
// for creating new Go modules with basic CI instrumentation.
package gomoduletemplate
// Fibonacci returns the nth number in the Fibonacci sequence.
func Fibonacci(n int) int {
a, b := 0, 1
for i := 0; i < n; i++ {
a, b = b, a+b
}
return a
}
-21
View File
@@ -1,21 +0,0 @@
package gomoduletemplate_test
import (
"testing"
gomoduletemplate "github.com/YOURUSER/YOURREPONAME"
)
func TestWorkingGoInstall(t *testing.T) {
t.Log("Your go installation works!")
}
func TestFibonacci(t *testing.T) {
var sequence = []int{0, 1, 1, 2, 3, 5, 8, 13, 21, 34}
for nth, expected := range sequence {
got := gomoduletemplate.Fibonacci(nth)
if got != expected {
t.Errorf("Fibonacci(%d) = %d, expected %d", nth, got, expected)
}
}
}
+66
View File
@@ -0,0 +1,66 @@
/*
package tseq implements TCP control flow.
# Transmission Control Block
The Transmission Control Block (TCB) is the core data structure of TCP.
It stores core state of the TCP connection such as the send and receive
sequence number spaces, the current state of the connection, and the
pending control segment flags.
# Values and Sizes
All arithmetic dealing with sequence numbers must be performed modulo 2**32
which brings with it subtleties to computer modulo arithmetic.
*/
package tseq
import "time"
// Value represents the value of a sequence number.
type Value uint32
// Size represents the size (length) of a sequence number window.
type Size uint32
// LessThan checks if v is before w (modulo 32) i.e., v < w.
func LessThan(v, w Value) bool {
return int32(v-w) < 0
}
// LessThanEq returns true if v==w or v is before (modulo 32) i.e., v < w.
func LessThanEq(v, w Value) bool {
return v == w || LessThan(v, w)
}
// InRange checks if v is in the range [a,b) (modulo 32), i.e., a <= v < b.
func InRange(v, a, b Value) bool {
return v-a < b-a
}
// InWindow checks if v is in the window that starts at 'first' and spans 'size'
// sequence numbers (modulo 32).
func InWindow(v, first Value, size Size) bool {
return InRange(v, first, Add(first, size))
}
// Add calculates the sequence number following the [v, v+s) window.
func Add(v Value, s Size) Value {
return v + Value(s)
}
// Size calculates the size of the window defined by [v, w).
func Sizeof(v, w Value) Size {
return Size(w - v)
}
// UpdateForward updates v such that it becomes v + s.
func (v *Value) UpdateForward(s Size) {
*v += Value(s)
}
// DefaultNewISS returns a new initial send sequence number.
// It's implementation is suggested by RFC9293.
func DefaultNewISS(t time.Time) Value {
return Value(t.UnixMicro() / 4)
}