github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/pkg/packet/packet.go (about)

     1  // Package packet support for TCP/IP packet manipulations
     2  // needed by the Aporeto infrastructure.
     3  package packet
     4  
     5  import (
     6  	"encoding/binary"
     7  	"encoding/hex"
     8  	"errors"
     9  	"fmt"
    10  	"net"
    11  	"strconv"
    12  
    13  	"go.uber.org/zap"
    14  )
    15  
    16  // printCount prints the debug header for packets every few lines that it prints
    17  var printCount int
    18  
    19  var errIPPacketCorrupt = errors.New("IP packet is smaller than min IP size of 20")
    20  var errTCPAuthOption = errors.New("tcp authentication option not found")
    21  
    22  //NewPacket is a method called on Packet which decodes the packet into the struct
    23  func (p *Packet) NewPacket(context uint64, bytes []byte, mark string, lengthValidate bool) (err error) {
    24  
    25  	// Get the mark value
    26  	p.Mark = mark
    27  
    28  	// Set the context
    29  	p.context = context
    30  	if len(bytes) < ipv4HdrLenPos {
    31  		return fmt.Errorf("invalid packet length %d", len(bytes))
    32  	}
    33  	if bytes[ipv4HdrLenPos]&ipv4ProtoMask == 0x40 {
    34  		p.ipHdr.version = V4
    35  		return p.parseIPv4Packet(bytes, lengthValidate)
    36  	}
    37  
    38  	p.ipHdr.version = V6
    39  	return p.parseIPv6Packet(bytes, lengthValidate)
    40  }
    41  
    42  // New returns a pointer to Packet structure built from the
    43  // provided bytes buffer which is expected to contain valid TCP/IP
    44  // packet bytes.
    45  // WARNING: This package takes control of the bytes buffer passed. The caller has
    46  // to be aware calling any function that returns a slice will NOT be a copy rather
    47  // a sub-slice of the bytes buffer passed. It is the responsibility of the caller
    48  // to copy the slice If and when necessary.
    49  func New(context uint64, bytes []byte, mark string, lengthValidate bool) (packet *Packet, err error) {
    50  
    51  	var p Packet
    52  
    53  	// Get the mark value
    54  	p.Mark = mark
    55  
    56  	// Set the context
    57  	p.context = context
    58  	if len(bytes) < ipv4HdrLenPos {
    59  		return nil, fmt.Errorf("invalid packet length %d", len(bytes))
    60  	}
    61  	if bytes[ipv4HdrLenPos]&ipv4ProtoMask == 0x40 {
    62  		p.ipHdr.version = V4
    63  		return &p, p.parseIPv4Packet(bytes, lengthValidate)
    64  	}
    65  
    66  	p.ipHdr.version = V6
    67  	return &p, p.parseIPv6Packet(bytes, lengthValidate)
    68  }
    69  
    70  func (p *Packet) parseTCP(bytes []byte) {
    71  	// TCP Header Processing
    72  	tcpBuffer := bytes[p.ipHdr.ipHeaderLen:]
    73  
    74  	p.tcpHdr.tcpChecksum = binary.BigEndian.Uint16(tcpBuffer[tcpChecksumPos : tcpChecksumPos+2])
    75  	p.tcpHdr.sourcePort = binary.BigEndian.Uint16(tcpBuffer[tcpSourcePortPos : tcpSourcePortPos+2])
    76  	p.tcpHdr.destinationPort = binary.BigEndian.Uint16(tcpBuffer[tcpDestPortPos : tcpDestPortPos+2])
    77  	p.tcpHdr.tcpAck = binary.BigEndian.Uint32(tcpBuffer[tcpAckPos : tcpAckPos+4])
    78  	p.tcpHdr.tcpSeq = binary.BigEndian.Uint32(tcpBuffer[tcpSeqPos : tcpSeqPos+4])
    79  	p.tcpHdr.tcpDataOffset = (tcpBuffer[tcpDataOffsetPos] & tcpDataOffsetMask) >> 4
    80  	p.tcpHdr.tcpTotalLength = uint16(len(p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]))
    81  
    82  	p.SetTCPFlags(tcpBuffer[tcpFlagsOffsetPos])
    83  }
    84  
    85  func parseIP(s string, ipv4 bool) (net.IP, error) {
    86  	ip := net.ParseIP(s)
    87  	if ip == nil {
    88  		return nil, fmt.Errorf("invalid IP address : %s", s)
    89  	}
    90  	if ipv4 {
    91  		ip = ip.To4()
    92  		if ip == nil {
    93  			return nil, fmt.Errorf("not a valid IPv4 address : %s", s)
    94  		}
    95  	} else {
    96  		ip = ip.To16()
    97  		if ip == nil {
    98  			return nil, fmt.Errorf("not a valid IPv6 address : %s", s)
    99  		}
   100  	}
   101  	return ip, nil
   102  }
   103  
   104  // NewIpv4TCPPacket creates an Ipv4/TCP packet
   105  func NewIpv4TCPPacket(context uint64, tcpFlags uint8, src, dst string, srcPort, desPort uint16) (*Packet, error) {
   106  
   107  	var p Packet
   108  	p.context = context
   109  	p.ipHdr.version = V4
   110  
   111  	srcIP, err := parseIP(src, true)
   112  	if err != nil {
   113  		return nil, fmt.Errorf("source address : %s", err)
   114  	}
   115  	dstIP, err := parseIP(dst, true)
   116  	if err != nil {
   117  		return nil, fmt.Errorf("destination address : %s", err)
   118  	}
   119  
   120  	buffer := make([]byte, minIPv4HdrSize+minTCPHeaderLen)
   121  	buffer[ipv4HdrLenPos] = 0x45
   122  	copy(buffer[ipv4SourceAddrPos:ipv4SourceAddrPos+4], srcIP)
   123  	copy(buffer[ipv4DestAddrPos:ipv4DestAddrPos+4], dstIP)
   124  
   125  	buffer[ipv4ProtoPos] = uint8(IPProtocolTCP)
   126  	binary.BigEndian.PutUint16(buffer[ipv4LengthPos:ipv4LengthPos+2], uint16(minIPv4HdrSize+minTCPHeaderLen))
   127  
   128  	// TCP data
   129  	tcpBuffer := buffer[minIPv4HdrSize:]
   130  	tcpBuffer[tcpFlagsOffsetPos] = tcpFlags
   131  	binary.BigEndian.PutUint16(tcpBuffer[tcpSourcePortPos:tcpSourcePortPos+2], srcPort)
   132  	binary.BigEndian.PutUint16(tcpBuffer[tcpDestPortPos:tcpDestPortPos+2], desPort)
   133  	tcpBuffer[tcpDataOffsetPos] = 5 << 4
   134  
   135  	if err := p.parseIPv4Packet(buffer, true); err != nil {
   136  		return nil, err
   137  	}
   138  
   139  	p.UpdateIPv4Checksum()
   140  	p.UpdateTCPChecksum()
   141  
   142  	return &p, nil
   143  }
   144  
   145  // NewIpv6TCPPacket creates an Ipv6/TCP packet
   146  func NewIpv6TCPPacket(context uint64, tcpFlags uint8, src, dst string, srcPort, desPort uint16) (*Packet, error) {
   147  
   148  	var p Packet
   149  	p.context = context
   150  	p.ipHdr.version = V6
   151  
   152  	srcIP, err := parseIP(src, false)
   153  	if err != nil {
   154  		return nil, fmt.Errorf("source address : %s", err)
   155  	}
   156  	dstIP, err := parseIP(dst, false)
   157  	if err != nil {
   158  		return nil, fmt.Errorf("destination address : %s", err)
   159  	}
   160  
   161  	buffer := make([]byte, ipv6HeaderLen+minTCPHeaderLen)
   162  
   163  	buffer[ipv6VersionPos] = 6
   164  	binary.BigEndian.PutUint16(buffer[ipv6PayloadLenPos:ipv6PayloadLenPos+2], minTCPHeaderLen)
   165  	copy(buffer[ipv6SourceAddrPos:ipv6SourceAddrPos+16], srcIP.To16())
   166  	copy(buffer[ipv6DestAddrPos:ipv6DestAddrPos+16], dstIP.To16())
   167  
   168  	buffer[ipv6ProtoPos] = uint8(IPProtocolTCP)
   169  
   170  	// TCP data
   171  	tcpBuffer := buffer[ipv6HeaderLen:]
   172  	tcpBuffer[tcpFlagsOffsetPos] = tcpFlags
   173  	binary.BigEndian.PutUint16(tcpBuffer[tcpSourcePortPos:tcpSourcePortPos+2], srcPort)
   174  	binary.BigEndian.PutUint16(tcpBuffer[tcpDestPortPos:tcpDestPortPos+2], desPort)
   175  	tcpBuffer[tcpDataOffsetPos] = 5 << 4
   176  
   177  	if err := p.parseIPv6Packet(buffer, true); err != nil {
   178  		return nil, err
   179  	}
   180  
   181  	p.UpdateTCPChecksum()
   182  
   183  	return &p, nil
   184  }
   185  
   186  func (p *Packet) parseICMP(bytes []byte) {
   187  
   188  	icmpBuffer := bytes[p.ipHdr.ipHeaderLen:]
   189  	p.icmpHdr.icmpType = int8(icmpBuffer[0])
   190  	p.icmpHdr.icmpCode = int8(icmpBuffer[1])
   191  }
   192  
   193  func (p *Packet) parseUDP(bytes []byte) {
   194  	// UDP Header Processing
   195  	udpBuffer := bytes[p.ipHdr.ipHeaderLen:]
   196  
   197  	p.udpHdr.udpChecksum = binary.BigEndian.Uint16(udpBuffer[udpChecksumPos : udpChecksumPos+2])
   198  	p.udpHdr.udpLength = binary.BigEndian.Uint16(udpBuffer[udpLengthPos : udpLengthPos+2])
   199  	p.udpHdr.udpData = []byte{}
   200  
   201  	p.udpHdr.sourcePort = binary.BigEndian.Uint16(udpBuffer[udpSourcePortPos : udpSourcePortPos+2])
   202  	p.udpHdr.destinationPort = binary.BigEndian.Uint16(udpBuffer[udpDestPortPos : udpDestPortPos+2])
   203  }
   204  
   205  func (p *Packet) parseIPv4Packet(bytes []byte, lengthValidate bool) (err error) {
   206  
   207  	// IP Header Processing
   208  	if len(bytes) < minIPv4HdrSize {
   209  		return errIPPacketCorrupt
   210  	}
   211  
   212  	p.ipHdr.ipHeaderLen = (bytes[ipv4HdrLenPos] & ipv4HdrLenMask) * 4
   213  	p.ipHdr.ipProto = bytes[ipv4ProtoPos]
   214  	p.ipHdr.ipTotalLength = binary.BigEndian.Uint16(bytes[ipv4LengthPos : ipv4LengthPos+2])
   215  	p.ipHdr.ipID = binary.BigEndian.Uint16(bytes[ipv4IDPos : ipv4IDPos+2])
   216  	p.ipHdr.ipChecksum = binary.BigEndian.Uint16(bytes[ipv4ChecksumPos : ipv4ChecksumPos+2])
   217  	p.ipHdr.sourceAddress = append([]byte{}, bytes[ipv4SourceAddrPos:ipv4SourceAddrPos+4]...)
   218  	p.ipHdr.destinationAddress = append([]byte{}, bytes[ipv4DestAddrPos:ipv4DestAddrPos+4]...)
   219  
   220  	if p.ipHdr.ipHeaderLen != minIPv4HdrSize {
   221  		return fmt.Errorf("packets with ip options not supported: hdrlen=%d", p.ipHdr.ipHeaderLen)
   222  	}
   223  
   224  	p.ipHdr.Buffer = bytes
   225  
   226  	if lengthValidate && p.ipHdr.ipTotalLength != uint16(len(p.ipHdr.Buffer)) {
   227  		if p.ipHdr.ipTotalLength < uint16(len(p.ipHdr.Buffer)) {
   228  			p.ipHdr.Buffer = p.ipHdr.Buffer[:p.ipHdr.ipTotalLength]
   229  		} else {
   230  			return fmt.Errorf("stated ip packet length %d differs from bytes available %d", p.ipHdr.ipTotalLength, len(p.ipHdr.Buffer))
   231  		}
   232  	}
   233  
   234  	// Some sanity checking for TCP.
   235  	if p.ipHdr.ipProto == IPProtocolTCP {
   236  		if p.ipHdr.ipTotalLength-uint16(p.ipHdr.ipHeaderLen) < minTCPIPPacketLen {
   237  			return fmt.Errorf("tcp ip packet too small: hdrlen=%d", p.ipHdr.ipHeaderLen)
   238  		}
   239  
   240  		p.parseTCP(bytes)
   241  	}
   242  
   243  	// Some sanity checking for UDP.
   244  	if p.ipHdr.ipProto == IPProtocolUDP {
   245  		if p.ipHdr.ipTotalLength-uint16(p.ipHdr.ipHeaderLen) < minUDPIPPacketLen {
   246  			return fmt.Errorf("udp ip packet too small: hdrlen=%d", p.ipHdr.ipHeaderLen)
   247  		}
   248  
   249  		p.parseUDP(bytes)
   250  	}
   251  
   252  	if p.ipHdr.ipProto == IPProtocolICMP {
   253  		if p.ipHdr.ipTotalLength-uint16(p.ipHdr.ipHeaderLen) < minICMPIPPacketLen {
   254  			return fmt.Errorf("tcp ip packet too small: hdrlen=%d", p.ipHdr.ipHeaderLen)
   255  		}
   256  
   257  		p.parseICMP(bytes)
   258  	}
   259  
   260  	// Chaching the result of the flow hash for performance optimization.
   261  	// It is called in multiple places.
   262  	p.l4flowhash = p.l4FlowHash()
   263  
   264  	return nil
   265  }
   266  
   267  func (p *Packet) parseIPv6Packet(bytes []byte, lengthValidate bool) (err error) {
   268  	// IP Header Processing
   269  	p.ipHdr.ipHeaderLen = ipv6HeaderLen
   270  	p.ipHdr.ipProto = bytes[ipv6ProtoPos]
   271  	p.ipHdr.ipTotalLength = ipv6HeaderLen + binary.BigEndian.Uint16(bytes[ipv6PayloadLenPos:ipv6PayloadLenPos+2])
   272  	p.ipHdr.sourceAddress = append([]byte{}, bytes[ipv6SourceAddrPos:ipv6SourceAddrPos+16]...)
   273  	p.ipHdr.destinationAddress = append([]byte{}, bytes[ipv6DestAddrPos:ipv6DestAddrPos+16]...)
   274  
   275  	p.ipHdr.Buffer = bytes
   276  
   277  	if lengthValidate && p.ipHdr.ipTotalLength != uint16(len(p.ipHdr.Buffer)) {
   278  		if p.ipHdr.ipTotalLength < uint16(len(p.ipHdr.Buffer)) {
   279  			p.ipHdr.Buffer = p.ipHdr.Buffer[:p.ipHdr.ipTotalLength]
   280  		} else {
   281  			return fmt.Errorf("stated ip packet length %d differs from bytes available %d", p.ipHdr.ipTotalLength, len(p.ipHdr.Buffer))
   282  		}
   283  
   284  		p.parseTCP(bytes)
   285  	}
   286  
   287  	// Some sanity checking for TCP.
   288  	if p.ipHdr.ipProto == IPProtocolTCP {
   289  		if p.ipHdr.ipTotalLength-uint16(p.ipHdr.ipHeaderLen) < minTCPIPPacketLen {
   290  			return fmt.Errorf("tcp ip packet too small: hdrlen=%d", p.ipHdr.ipHeaderLen)
   291  		}
   292  
   293  		p.parseTCP(bytes)
   294  	}
   295  
   296  	// Some sanity checking for UDP.
   297  	if p.ipHdr.ipProto == IPProtocolUDP {
   298  		if p.ipHdr.ipTotalLength-uint16(p.ipHdr.ipHeaderLen) < minUDPIPPacketLen {
   299  			return fmt.Errorf("udp ip packet too small: hdrlen=%d", p.ipHdr.ipHeaderLen)
   300  		}
   301  		p.parseUDP(bytes)
   302  	}
   303  
   304  	// Chaching the result of the flow hash for performance optimization.
   305  	// It is called in multiple places.
   306  	p.l4flowhash = p.l4FlowHash()
   307  
   308  	return nil
   309  }
   310  
   311  // IsEmptyTCPPayload returns the TCP data offset
   312  func (p *Packet) IsEmptyTCPPayload() bool {
   313  	return p.TCPDataStartBytes() == p.tcpHdr.tcpTotalLength
   314  }
   315  
   316  // GetUDPData return additional data in packet
   317  func (p *Packet) GetUDPData() []byte {
   318  	return p.ipHdr.Buffer[p.ipHdr.ipHeaderLen+UDPDataPos:]
   319  }
   320  
   321  // GetUDPDataStartBytes return start of UDP data
   322  func (p *Packet) GetUDPDataStartBytes() uint16 {
   323  	return UDPDataPos
   324  }
   325  
   326  // TCPDataStartBytes provides the tcp data start offset in bytes
   327  func (p *Packet) TCPDataStartBytes() uint16 {
   328  	return uint16(p.tcpHdr.tcpDataOffset) * 4
   329  }
   330  
   331  // GetIPLength returns the IP length
   332  func (p *Packet) GetIPLength() uint16 {
   333  	return p.ipHdr.ipTotalLength
   334  }
   335  
   336  // Print is a print helper function
   337  func (p *Packet) Print(context uint64, packetLogLevel bool) {
   338  
   339  	if p.ipHdr.ipProto != IPProtocolTCP {
   340  		return
   341  	}
   342  
   343  	logPkt := false
   344  	detailed := false
   345  
   346  	if packetLogLevel || context == 0 {
   347  		logPkt = true
   348  		detailed = true
   349  	}
   350  
   351  	var buf string
   352  	print := false
   353  
   354  	if logPkt {
   355  		if printCount%200 == 0 {
   356  			buf += fmt.Sprintf("Packet: %5s %5s %25s %15s %5s %15s %5s %6s %20s %20s %6s %20s %20s %2s %5s %5s\n",
   357  				"IPID", "Dir", "Comment", "SIP", "SP", "DIP", "DP", "Flags", "TCPSeq", "TCPAck", "TCPLen", "ExpAck", "ExpSeq", "DO", "Acsum", "Ccsum")
   358  		}
   359  		printCount++
   360  		offset := 0
   361  
   362  		if (p.GetTCPFlags() & TCPSynMask) == TCPSynMask {
   363  			offset = 1
   364  		}
   365  
   366  		expAck := p.tcpHdr.tcpSeq + uint32(uint16(len(p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]))-p.TCPDataStartBytes()) + uint32(offset)
   367  		ccsum := p.computeTCPChecksum()
   368  		csumValidationStr := ""
   369  
   370  		if p.tcpHdr.tcpChecksum != ccsum {
   371  			csumValidationStr = "Bad Checksum"
   372  		}
   373  
   374  		buf += fmt.Sprintf("Packet: %5d %5s %25s %15s %5d %15s %5d %6s %20d %20d %6d %20d %20d %2d %5d %5d %12s\n",
   375  			p.ipHdr.ipID,
   376  			flagsToDir(p.context|context),
   377  			flagsToStr(p.context|context),
   378  			p.ipHdr.sourceAddress.String(), p.tcpHdr.sourcePort,
   379  			p.ipHdr.destinationAddress.String(), p.tcpHdr.destinationPort,
   380  			tcpFlagsToStr(p.GetTCPFlags()),
   381  			p.tcpHdr.tcpSeq, p.tcpHdr.tcpAck, uint16(len(p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]))-p.TCPDataStartBytes(),
   382  			expAck, expAck, p.tcpHdr.tcpDataOffset,
   383  			p.tcpHdr.tcpChecksum, ccsum, csumValidationStr)
   384  		print = true
   385  	}
   386  
   387  	if detailed {
   388  		pktBytes := []byte{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 8, 0}
   389  		pktBytes = append(pktBytes, p.ipHdr.Buffer...)
   390  		buf += fmt.Sprintf("%s\n", hex.Dump(pktBytes))
   391  		print = true
   392  	}
   393  
   394  	if print {
   395  		zap.L().Debug(buf)
   396  	}
   397  }
   398  
   399  //UpdatePacketBuffer updates the packet with the new updates buffer.
   400  func (p *Packet) UpdatePacketBuffer(buffer []byte, tcpOptionsLen uint16) error {
   401  
   402  	if tcpOptionsLen != 0 {
   403  		// If the packet has a payload then we can't insert options
   404  		if p.TCPDataStartBytes() != uint16(len(p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:])) {
   405  			return fmt.Errorf("cannot insert options with existing data: optionlength=%d, iptotallength=%d", tcpOptionsLen, p.ipHdr.ipTotalLength)
   406  		}
   407  	} else {
   408  		// This case is for adding a payload to a packet which may or may not have options
   409  		tcpOptionsLen := p.TCPDataStartBytes() - minTCPHeaderLen
   410  		// Working with unsigned numbers so make sure we didn't go negative basically
   411  		if p.TCPDataStartBytes() < tcpOptionsLen {
   412  			return fmt.Errorf("cannot payload: bad options length: optionlength=%d", tcpOptionsLen)
   413  		}
   414  	}
   415  
   416  	packetLenIncrease := uint16(len(buffer) - len(p.ipHdr.Buffer))
   417  	p.ipHdr.Buffer = buffer
   418  
   419  	// IP Header Processing
   420  	p.FixupIPHdrOnDataModify(p.ipHdr.ipTotalLength, p.ipHdr.ipTotalLength+packetLenIncrease)
   421  
   422  	// TCP Header Processing
   423  	p.FixuptcpHdrOnTCPDataAttach(tcpOptionsLen)
   424  
   425  	p.UpdateTCPChecksum()
   426  	return nil
   427  }
   428  
   429  //GetTCPBytes returns the bytes in the packet. It consolidates in case of changes as well
   430  func (p *Packet) GetTCPBytes() []byte {
   431  
   432  	pktBytes := []byte{}
   433  	pktBytes = append(pktBytes, p.ipHdr.Buffer...)
   434  	return pktBytes
   435  }
   436  
   437  // ReadTCPDataString returns ths payload in a string variable
   438  // It does not remove the payload from the packet
   439  func (p *Packet) ReadTCPDataString() string {
   440  	return string(p.ReadTCPData())
   441  }
   442  
   443  // ReadTCPData returns ths payload in a string variable
   444  // It does not remove the payload from the packet
   445  func (p *Packet) ReadTCPData() []byte {
   446  	return p.ipHdr.Buffer[uint16(p.ipHdr.ipHeaderLen)+p.TCPDataStartBytes():]
   447  }
   448  
   449  // CheckTCPAuthenticationOption ensures authentication option exists at the offset provided
   450  func (p *Packet) CheckTCPAuthenticationOption(iOptionLength int) (err error) {
   451  	tcpDataStart := p.TCPDataStartBytes()
   452  
   453  	if tcpDataStart <= minTCPIPPacketLen {
   454  		return errTCPAuthOption
   455  	}
   456  	if len(p.ipHdr.Buffer) < int(p.ipHdr.ipHeaderLen)+20 {
   457  		return errors.New("Invalid IP Packet")
   458  	}
   459  	if int(p.ipHdr.ipHeaderLen)+int(p.tcpHdr.tcpDataOffset*4) > len(p.ipHdr.Buffer) {
   460  		return errors.New("Invalid TCP Packet")
   461  	}
   462  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen+20 : int(p.ipHdr.ipHeaderLen)+int(p.tcpHdr.tcpDataOffset*4)]
   463  
   464  	for i := 0; i < len(buffer); {
   465  		if buffer[i] == 0 || buffer[i] == 1 {
   466  			i++
   467  			continue
   468  		}
   469  
   470  		if buffer[i] != TCPAuthenticationOption {
   471  			if len(buffer) <= i+1 {
   472  				return errTCPAuthOption
   473  			}
   474  			if int(buffer[i+1]) == 0 {
   475  				zap.L().Debug("Bad Packet Option", zap.String("Buffer", hex.Dump(buffer)))
   476  				return errors.New("Invalid TCP Option Packet")
   477  			}
   478  			i = i + int(buffer[i+1])
   479  			continue
   480  		}
   481  
   482  		if buffer[i] == TCPAuthenticationOption {
   483  			return nil
   484  		}
   485  		return errTCPAuthOption
   486  
   487  	}
   488  	return errTCPAuthOption
   489  }
   490  
   491  // FixupIPHdrOnDataModify modifies the IP header fields and checksum
   492  func (p *Packet) FixupIPHdrOnDataModify(old, new uint16) {
   493  	// IP Header Processing
   494  	// IP chekcsum fixup.
   495  	p.ipHdr.ipChecksum = incCsum16(p.ipHdr.ipChecksum, old, new)
   496  	// Update IP Total Length.
   497  	p.ipHdr.ipTotalLength = p.ipHdr.ipTotalLength + new - old
   498  
   499  	if p.ipHdr.version == V6 {
   500  		binary.BigEndian.PutUint16(p.ipHdr.Buffer[ipv6PayloadLenPos:ipv6PayloadLenPos+2], p.ipHdr.ipTotalLength-uint16(p.ipHdr.ipHeaderLen))
   501  	} else {
   502  		binary.BigEndian.PutUint16(p.ipHdr.Buffer[ipv4LengthPos:ipv4LengthPos+2], p.ipHdr.ipTotalLength)
   503  		binary.BigEndian.PutUint16(p.ipHdr.Buffer[ipv4ChecksumPos:ipv4ChecksumPos+2], p.ipHdr.ipChecksum)
   504  	}
   505  }
   506  
   507  // TCPSequenceNumber return the initial sequence number
   508  func (p *Packet) TCPSequenceNumber() uint32 {
   509  	if p.ipHdr.ipProto != IPProtocolTCP {
   510  		return 0
   511  	}
   512  	return p.tcpHdr.tcpSeq
   513  }
   514  
   515  // SetTCPSeq sets the TCP seq number
   516  func (p *Packet) SetTCPSeq(seq uint32) {
   517  	p.tcpHdr.tcpSeq = seq
   518  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
   519  	binary.BigEndian.PutUint32(buffer[tcpSeqPos:tcpSeqPos+4], p.tcpHdr.tcpSeq)
   520  }
   521  
   522  // IncreaseTCPSeq increases TCP seq number by incr
   523  func (p *Packet) IncreaseTCPSeq(incr uint32) {
   524  	p.SetTCPSeq(p.tcpHdr.tcpSeq + incr)
   525  }
   526  
   527  // DecreaseTCPSeq decreases TCP seq number by decr
   528  func (p *Packet) DecreaseTCPSeq(decr uint32) {
   529  	p.SetTCPSeq(p.tcpHdr.tcpSeq - decr)
   530  }
   531  
   532  // SetTCPAck sets the TCP ack number
   533  func (p *Packet) SetTCPAck(ack uint32) {
   534  	p.tcpHdr.tcpAck = ack
   535  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
   536  	binary.BigEndian.PutUint32(buffer[tcpAckPos:tcpAckPos+4], p.tcpHdr.tcpAck)
   537  }
   538  
   539  // IncreaseTCPAck increases TCP ack number by incr
   540  func (p *Packet) IncreaseTCPAck(incr uint32) {
   541  	p.SetTCPAck(p.tcpHdr.tcpAck + incr)
   542  }
   543  
   544  // DecreaseTCPAck decreases TCP ack number by decr
   545  func (p *Packet) DecreaseTCPAck(decr uint32) {
   546  	p.SetTCPAck(p.tcpHdr.tcpAck - decr)
   547  }
   548  
   549  // FixuptcpHdrOnTCPDataDetach modifies the TCP header fields and checksum
   550  func (p *Packet) FixuptcpHdrOnTCPDataDetach(optionLength uint16) {
   551  
   552  	// Update DataOffset
   553  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
   554  	p.tcpHdr.tcpDataOffset = p.tcpHdr.tcpDataOffset - uint8(optionLength/4)
   555  	buffer[tcpDataOffsetPos] = p.tcpHdr.tcpDataOffset << 4
   556  }
   557  
   558  // tcpDataDetach splits the p.Buffer into p.Buffer (header + some options), p.tcpOptions (optionLength) and p.TCPData (dataLength)
   559  func (p *Packet) tcpDataDetach(optionLength uint16, dataLength uint16) { //nolint
   560  	p.ipHdr.Buffer = p.ipHdr.Buffer[:uint16(p.ipHdr.ipHeaderLen)+p.TCPDataStartBytes()-optionLength]
   561  }
   562  
   563  // TCPDataDetach performs the following:
   564  //   - Removes all TCP data from Buffer to TCPData.
   565  //   - Removes "optionLength" bytes of options from TCP header to tcpOptions
   566  //   - Updates IP Hdr (lengths, checksums)
   567  //   - Updates TCP header (checksums)
   568  func (p *Packet) TCPDataDetach(optionLength uint16) {
   569  	// Length
   570  	dataLength := uint16(len(p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:])) - p.TCPDataStartBytes()
   571  
   572  	// detach TCP data
   573  	p.tcpDataDetach(optionLength, dataLength)
   574  
   575  	// Process TCP Header fields and metadata
   576  	p.FixuptcpHdrOnTCPDataDetach(optionLength)
   577  
   578  	// Process IP Header fields
   579  	p.FixupIPHdrOnDataModify(p.ipHdr.ipTotalLength, p.ipHdr.ipTotalLength-(dataLength+optionLength))
   580  
   581  	p.UpdateTCPChecksum()
   582  }
   583  
   584  // FixuptcpHdrOnTCPDataAttach modifies the TCP header fields and checksum
   585  func (p *Packet) FixuptcpHdrOnTCPDataAttach(tcpOptionsLen uint16) {
   586  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
   587  	numberOfOptions := tcpOptionsLen / 4
   588  
   589  	// Modify the fields
   590  	p.tcpHdr.tcpDataOffset = p.tcpHdr.tcpDataOffset + uint8(numberOfOptions)
   591  	buffer[tcpDataOffsetPos] = p.tcpHdr.tcpDataOffset << 4
   592  
   593  	// Modify the tcp header length
   594  	p.tcpHdr.tcpTotalLength = uint16(len(p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]))
   595  }
   596  
   597  // L4FlowHash calculate a hash string based on the 4-tuple. It returns the cached
   598  // value and does not re-calculate it. This leads to performance gains.
   599  func (p *Packet) L4FlowHash() string {
   600  	return p.l4flowhash
   601  }
   602  
   603  func (p *Packet) l4FlowHash() string {
   604  	return p.ipHdr.sourceAddress.String() + ":" + p.ipHdr.destinationAddress.String() + ":" + strconv.Itoa(int(p.SourcePort())) + ":" + strconv.Itoa(int(p.DestPort()))
   605  }
   606  
   607  // L4ReverseFlowHash calculate a hash string based on the 4-tuple by reversing source and destination information
   608  func (p *Packet) L4ReverseFlowHash() string {
   609  	return p.ipHdr.destinationAddress.String() + ":" + p.ipHdr.sourceAddress.String() + ":" + strconv.Itoa(int(p.DestPort())) + ":" + strconv.Itoa(int(p.SourcePort()))
   610  }
   611  
   612  // SourcePortHash calculates a hash based on dest ip/port for net packet and src ip/port for app packet.
   613  func (p *Packet) SourcePortHash(stage uint64) string {
   614  	if stage == PacketTypeNetwork {
   615  		return p.L4ReverseFlowHash()
   616  	}
   617  
   618  	return p.L4FlowHash()
   619  }
   620  
   621  // ID returns the IP ID of the packet
   622  func (p *Packet) ID() string {
   623  	return strconv.Itoa(int(p.ipHdr.ipID))
   624  }
   625  
   626  //SourcePort -- returns the appropriate source port
   627  func (p *Packet) SourcePort() uint16 {
   628  	if p.ipHdr.ipProto == IPProtocolTCP {
   629  		return p.tcpHdr.sourcePort
   630  	}
   631  
   632  	return p.udpHdr.sourcePort
   633  }
   634  
   635  //DestPort -- returns the appropriate destination port
   636  func (p *Packet) DestPort() uint16 {
   637  	if p.ipHdr.ipProto == IPProtocolTCP {
   638  		return p.tcpHdr.destinationPort
   639  	}
   640  
   641  	return p.udpHdr.destinationPort
   642  }
   643  
   644  //SourceAddress returns the source IP
   645  func (p *Packet) SourceAddress() net.IP {
   646  	return p.ipHdr.sourceAddress
   647  }
   648  
   649  //DestinationAddress returns the destination address
   650  func (p *Packet) DestinationAddress() net.IP {
   651  	return p.ipHdr.destinationAddress
   652  }
   653  
   654  //TCPSeqNum returns tcp sequence number
   655  func (p *Packet) TCPSeqNum() uint32 {
   656  	return p.tcpHdr.tcpSeq
   657  }
   658  
   659  //TCPAckNum returns tcp ack number
   660  func (p *Packet) TCPAckNum() uint32 {
   661  	return p.tcpHdr.tcpAck
   662  }
   663  
   664  //IPProto returns the L4 protocol
   665  func (p *Packet) IPProto() uint8 {
   666  	return p.ipHdr.ipProto
   667  }
   668  
   669  //IPTotalLen returns the total length of the packet
   670  func (p *Packet) IPTotalLen() uint16 {
   671  	return p.ipHdr.ipTotalLength
   672  }
   673  
   674  //IPHeaderLen returns the ip header length
   675  func (p *Packet) IPHeaderLen() uint8 {
   676  	return p.ipHdr.ipHeaderLen
   677  }
   678  
   679  //GetBuffer returns the slice representing the buffer at offset specified
   680  func (p *Packet) GetBuffer(offset int) []byte {
   681  	return p.ipHdr.Buffer[offset:]
   682  }
   683  
   684  // IPversion returns the version of ip packet
   685  func (p *Packet) IPversion() IPver {
   686  	return p.ipHdr.version
   687  }
   688  
   689  //TestGetTCPPacket is used by other test code when they need to create a packet
   690  func TestGetTCPPacket(srcIP, dstIP net.IP, srcPort, dstPort uint16) *Packet {
   691  	p := &Packet{}
   692  
   693  	p.ipHdr.destinationAddress = dstIP
   694  	p.tcpHdr.destinationPort = dstPort
   695  	p.ipHdr.sourceAddress = srcIP
   696  	p.tcpHdr.sourcePort = srcPort
   697  	p.ipHdr.ipProto = IPProtocolTCP
   698  
   699  	return p
   700  }