package packet import ( "encoding/binary" "iter" "net/netip" "golang.org/x/sys/unix" ) const Size = 0xffff type Packet struct { Payload []byte Control []byte Name []byte SegSize int //todo should this hold out as well? OutLen int wasSegmented bool isV4 bool //Addr netip.AddrPort } func New(isV4 bool) *Packet { return &Packet{ Payload: make([]byte, Size), Control: make([]byte, unix.CmsgSpace(2)), Name: make([]byte, unix.SizeofSockaddrInet6), isV4: isV4, } } func (p *Packet) AddrPort() netip.AddrPort { var ip netip.Addr // Its ok to skip the ok check here, the slicing is the only error that can occur and it will panic if p.isV4 { ip, _ = netip.AddrFromSlice(p.Name[4:8]) } else { ip, _ = netip.AddrFromSlice(p.Name[8:24]) } return netip.AddrPortFrom(ip.Unmap(), binary.BigEndian.Uint16(p.Name[2:4])) } func (p *Packet) updateCtrl(ctrlLen int) { p.SegSize = len(p.Payload) p.wasSegmented = false if ctrlLen == 0 { return } if len(p.Control) == 0 { return } cmsgs, err := unix.ParseSocketControlMessage(p.Control) if err != nil { return // oh well } for _, c := range cmsgs { if c.Header.Level == unix.SOL_UDP && c.Header.Type == unix.UDP_GRO && len(c.Data) >= 2 { p.wasSegmented = true p.SegSize = int(binary.LittleEndian.Uint16(c.Data[:2])) return } } } // Update sets a Packet into "just received, not processed" state func (p *Packet) Update(ctrlLen int) { p.OutLen = -1 p.updateCtrl(ctrlLen) } func (p *Packet) Segments() iter.Seq[[]byte] { return func(yield func([]byte) bool) { //cursor := 0 for offset := 0; offset < len(p.Payload); offset += p.SegSize { end := offset + p.SegSize if end > len(p.Payload) { end = len(p.Payload) } if !yield(p.Payload[offset:end]) { return } } //if p.SegSize > 0 && p.SegSize < len(p.Payload) { // //} else { // f.readOutsidePackets(p.Addr, nil, result2[:0], p.Payload, h, fwPacket2, lhh, nb2, i, conntrackCache.Get(f.l)) //} } } //type Pool struct { // pool sync.Pool //} // //var bigPool = &Pool{ // pool: sync.Pool{New: func() any { return New() }}, //} // //func GetPool() *Pool { // return bigPool //} // //func (p *Pool) Get() *Packet { // return p.pool.Get().(*Packet) //} // //func (p *Pool) Put(x *Packet) { // x.Payload = x.Payload[:Size] // p.pool.Put(x) //}