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

     1  package packet
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"encoding/hex"
     7  	"fmt"
     8  	"strconv"
     9  
    10  	"go.uber.org/zap"
    11  	"golang.org/x/net/ipv4"
    12  )
    13  
    14  // Helpher functions for the package, mainly for debugging and validation
    15  // They are not used by the main package
    16  
    17  // VerifyIPv4Checksum returns true if the IP header checksum is correct
    18  // for this packet, false otherwise. Note that the checksum is not
    19  // modified.
    20  func (p *Packet) VerifyIPv4Checksum() bool {
    21  
    22  	sum := p.computeIPv4Checksum()
    23  
    24  	return sum == p.ipHdr.ipChecksum
    25  }
    26  
    27  // UpdateIPv4Checksum computes the IP header checksum and updates the
    28  // packet with the value.
    29  func (p *Packet) UpdateIPv4Checksum() {
    30  
    31  	p.ipHdr.ipChecksum = p.computeIPv4Checksum()
    32  
    33  	binary.BigEndian.PutUint16(p.ipHdr.Buffer[ipv4ChecksumPos:ipv4ChecksumPos+2], p.ipHdr.ipChecksum)
    34  }
    35  
    36  // VerifyTCPChecksum returns true if the TCP header checksum is correct
    37  // for this packet, false otherwise. Note that the checksum is not
    38  // modified.
    39  func (p *Packet) VerifyTCPChecksum() bool {
    40  
    41  	sum := p.computeTCPChecksum()
    42  
    43  	return sum == p.tcpHdr.tcpChecksum
    44  }
    45  
    46  // UpdateTCPChecksum computes the TCP header checksum and updates the
    47  // packet with the value.
    48  func (p *Packet) UpdateTCPChecksum() {
    49  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
    50  	p.tcpHdr.tcpChecksum = p.computeTCPChecksum()
    51  	binary.BigEndian.PutUint16(buffer[tcpChecksumPos:tcpChecksumPos+2], p.tcpHdr.tcpChecksum)
    52  }
    53  
    54  // UpdateTCPFlags
    55  func (p *Packet) updateTCPFlags(tcpFlags uint8) {
    56  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
    57  	buffer[tcpFlagsOffsetPos] = tcpFlags
    58  }
    59  
    60  // ConvertAcktoFinAck function removes the data from the packet
    61  // It is called only if the packet is Ack or Psh/Ack
    62  // converts psh/ack to fin/ack packet.
    63  func (p *Packet) ConvertAcktoFinAck() error {
    64  	var tcpFlags uint8
    65  
    66  	tcpFlags = tcpFlags | TCPFinMask
    67  	tcpFlags = tcpFlags | TCPAckMask
    68  
    69  	p.updateTCPFlags(tcpFlags)
    70  	p.tcpHdr.tcpFlags = tcpFlags
    71  
    72  	p.TCPDataDetach(0)
    73  
    74  	return nil
    75  }
    76  
    77  // ConvertToRst function converts the packet to
    78  // a RST packet
    79  func (p *Packet) ConvertToRst() {
    80  	var tcpFlags uint8
    81  
    82  	tcpFlags = tcpFlags | TCPRstMask
    83  
    84  	p.updateTCPFlags(tcpFlags)
    85  	p.tcpHdr.tcpFlags = tcpFlags
    86  
    87  	p.TCPDataDetach(0)
    88  }
    89  
    90  //PacketToStringTCP returns a string representation of fields contained in this packet.
    91  func (p *Packet) PacketToStringTCP() string {
    92  
    93  	var buf bytes.Buffer
    94  	buf.WriteString("(error)")
    95  
    96  	header, err := ipv4.ParseHeader(p.ipHdr.Buffer)
    97  
    98  	if err == nil {
    99  		buf.Reset()
   100  		buf.WriteString(header.String())
   101  		buf.WriteString(" srcport=")
   102  		buf.WriteString(strconv.Itoa(int(p.SourcePort())))
   103  		buf.WriteString(" dstport=")
   104  		buf.WriteString(strconv.Itoa(int(p.DestPort())))
   105  		buf.WriteString(" tcpcksum=")
   106  		buf.WriteString(fmt.Sprintf("0x%0x", p.tcpHdr.tcpChecksum))
   107  		buf.WriteString(" data")
   108  		buf.WriteString(hex.EncodeToString(p.GetTCPBytes()))
   109  	}
   110  	return buf.String()
   111  }
   112  
   113  // Computes the IP header checksum. The packet is not modified.
   114  func (p *Packet) computeIPv4Checksum() uint16 {
   115  
   116  	// IP packet checksum is computed with the checksum value set to zero
   117  	p.ipHdr.Buffer[ipv4ChecksumPos] = 0
   118  	p.ipHdr.Buffer[ipv4ChecksumPos+1] = 0
   119  
   120  	// Compute checksum, over IP header only
   121  	sum := checksum(p.ipHdr.Buffer[:p.ipHdr.ipHeaderLen])
   122  
   123  	// Restore the previous checksum (whether correct or not, as this function doesn't change it)
   124  	binary.BigEndian.PutUint16(p.ipHdr.Buffer[ipv4ChecksumPos:ipv4ChecksumPos+2], p.ipHdr.ipChecksum)
   125  
   126  	return sum
   127  }
   128  
   129  // Computes the TCP header checksum. The packet is not modified.
   130  func (p *Packet) computeTCPChecksum() uint16 {
   131  	var csum uint32
   132  	var buf [2]byte
   133  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
   134  	tcpBufSize := uint16(len(buffer))
   135  
   136  	oldCsumLow := buffer[tcpChecksumPos]
   137  	oldCsumHigh := buffer[tcpChecksumPos+1]
   138  
   139  	// Put 0 to calculate the checksum. We will reset it back after the checksum
   140  	buffer[tcpChecksumPos] = 0
   141  	buffer[tcpChecksumPos+1] = 0
   142  
   143  	if p.ipHdr.version == V4 {
   144  		csum = partialChecksum(0, p.ipHdr.Buffer[ipv4SourceAddrPos:ipv4SourceAddrPos+4])
   145  		csum = partialChecksum(csum, p.ipHdr.Buffer[ipv4DestAddrPos:ipv4DestAddrPos+4])
   146  	} else {
   147  		csum = partialChecksum(0, p.ipHdr.Buffer[ipv6SourceAddrPos:ipv6SourceAddrPos+16])
   148  		csum = partialChecksum(csum, p.ipHdr.Buffer[ipv6DestAddrPos:ipv6DestAddrPos+16])
   149  	}
   150  
   151  	// reserved 0 byte
   152  	buf[0] = 0
   153  	// tcp option 6
   154  	buf[1] = 6
   155  
   156  	csum = partialChecksum(csum, buf[:])
   157  	binary.BigEndian.PutUint16(buf[:], tcpBufSize)
   158  	csum = partialChecksum(csum, buf[:])
   159  
   160  	csum = partialChecksum(csum, buffer)
   161  
   162  	csum16 := finalizeChecksum(csum)
   163  
   164  	// restore the checksum
   165  	buffer[tcpChecksumPos] = oldCsumLow
   166  	buffer[tcpChecksumPos+1] = oldCsumHigh
   167  
   168  	return csum16
   169  }
   170  
   171  // incCsum16 implements rfc1624, equation 3.
   172  func incCsum16(start, old, new uint16) uint16 {
   173  
   174  	start = start ^ 0xffff
   175  	old = old ^ 0xffff
   176  
   177  	csum := uint32(start) + uint32(old) + uint32(new)
   178  	for (csum >> 16) > 0 {
   179  		csum = (csum & 0xffff) + ((csum >> 16) & 0xffff)
   180  	}
   181  	csum = csum ^ 0xffff
   182  	return uint16(csum)
   183  }
   184  
   185  func csumConvert32To16bit(sum uint32) uint16 {
   186  	for sum > 0xffff {
   187  		sum = (sum >> 16) + (sum & 0xffff)
   188  	}
   189  
   190  	return uint16(sum)
   191  }
   192  
   193  // Computes a sum of 16 bit numbers
   194  func checksumDelta(init uint32, buf []byte) uint32 {
   195  
   196  	sum := init
   197  
   198  	for ; len(buf) >= 2; buf = buf[2:] {
   199  		sum += uint32(buf[0])<<8 | uint32(buf[1])
   200  	}
   201  
   202  	if len(buf) > 0 {
   203  		sum += uint32(buf[0]) << 8
   204  	}
   205  
   206  	return sum
   207  }
   208  
   209  // Computes a checksum over the given slice.
   210  func checksum(buf []byte) uint16 {
   211  	sum32 := checksumDelta(0, buf)
   212  	sum16 := csumConvert32To16bit(sum32)
   213  
   214  	csum := ^sum16
   215  	return csum
   216  }
   217  
   218  func partialChecksum(csum uint32, buf []byte) uint32 {
   219  	return checksumDelta(csum, buf)
   220  }
   221  
   222  func finalizeChecksum(csum32 uint32) uint16 {
   223  	csum16 := csumConvert32To16bit(csum32)
   224  	csum := ^csum16
   225  
   226  	return csum
   227  }
   228  
   229  func (p *Packet) updateUDPv6Checksum() {
   230  	var csum uint32
   231  	var tmp [4]byte
   232  
   233  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
   234  
   235  	csum = partialChecksum(0, p.ipHdr.sourceAddress)
   236  	csum = partialChecksum(csum, p.ipHdr.destinationAddress)
   237  
   238  	binary.BigEndian.PutUint32(tmp[:], uint32(len(buffer)))
   239  	csum = partialChecksum(csum, tmp[:])
   240  
   241  	tmp = [4]byte{0, 0, 0, 17}
   242  	csum = partialChecksum(csum, tmp[:])
   243  
   244  	buffer[udpChecksumPos] = 0
   245  	buffer[udpChecksumPos+1] = 0
   246  	csum = partialChecksum(csum, buffer[:])
   247  
   248  	p.udpHdr.udpChecksum = finalizeChecksum(csum)
   249  	// update checksum
   250  	binary.BigEndian.PutUint16(buffer[udpChecksumPos:udpChecksumPos+2], p.udpHdr.udpChecksum)
   251  }
   252  
   253  func (p *Packet) fixupUDPHdr() {
   254  	// checksum set to 0, ignored by the stack
   255  	buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
   256  	//binary.BigEndian.PutUint16(buffer[udpLengthPos:udpLengthPos+2], uint16(len(buffer)))
   257  	binary.BigEndian.PutUint16(buffer[udpLengthPos:udpLengthPos+2], 8)
   258  }
   259  
   260  func (p *Packet) fixupUDPChecksum() {
   261  	if p.ipHdr.version == V4 {
   262  		buffer := p.ipHdr.Buffer[p.ipHdr.ipHeaderLen:]
   263  
   264  		buffer[udpChecksumPos] = 0
   265  		buffer[udpChecksumPos+1] = 0
   266  	} else {
   267  		p.updateUDPv6Checksum()
   268  	}
   269  }
   270  
   271  // ReadUDPToken Parsing using format specified in https://tools.ietf.org/html/draft-ietf-tsvwg-udp-options-08
   272  // ReadUDPToken return the UDP token. Gets called only during the handshake process.
   273  func (p *Packet) ReadUDPToken() []byte {
   274  	// length of options .. skip udp data
   275  	udpOptions := p.ipHdr.Buffer[uint16(p.ipHdr.ipHeaderLen)+8 : p.ipHdr.ipTotalLength]
   276  	// zap.L().Error("Received Packet", zap.String("IP\n", hex.Dump(p.ipHdr.Buffer)))
   277  	// zap.L().Error("UDP Options", zap.String("UDP\n", hex.Dump(udpOptions)))
   278  	for i := 0; i < len(udpOptions); i++ {
   279  		if udpOptions[i] == 0 || udpOptions[i] == 1 {
   280  			i++
   281  			continue
   282  		}
   283  		if udpOptions[i] != UDPAporetoOption {
   284  			if len(udpOptions) < i+2 {
   285  				return []byte{}
   286  			}
   287  			if udpOptions[i+1] != 0xff {
   288  				i = i + int(udpOptions[i+1])
   289  				continue
   290  			} else {
   291  				i = i + int(binary.LittleEndian.Uint16(udpOptions[i+2:]))
   292  				continue
   293  			}
   294  		} else {
   295  			if len(udpOptions) < i+2 {
   296  				return []byte{}
   297  			}
   298  			if udpOptions[i+1] != 0xff {
   299  
   300  				if len(udpOptions[i:]) >= int(udpOptions[i+1]) {
   301  					return udpOptions[i+UDPSignatureLen+2:]
   302  				}
   303  			} else {
   304  				if len(udpOptions[i:]) >= int(binary.LittleEndian.Uint16(udpOptions[i+2:])) {
   305  					return udpOptions[i+4+UDPSignatureLen:]
   306  				}
   307  
   308  			}
   309  		}
   310  	}
   311  	return []byte{}
   312  }
   313  
   314  // UDPTokenAttach attached udp packet signature and tokens.
   315  func (p *Packet) UDPTokenAttach(udpdata []byte, udptoken []byte) {
   316  	if udpdata[0] == 0x22 && udpdata[1] == 0xff {
   317  		copy(udpdata[4+UDPSignatureLen:], udptoken)
   318  	} else {
   319  		copy(udpdata[2+UDPSignatureLen:], udptoken)
   320  	}
   321  	//p.udpHdr.udpData = append([]byte("APORETO!"), udpdata...)
   322  
   323  	p.udpHdr.udpLength = 0
   324  	packetLenIncrease := uint16(len(udpdata))
   325  	// IP Header Processing
   326  	p.FixupIPHdrOnDataModify(p.ipHdr.ipTotalLength, p.ipHdr.ipTotalLength+packetLenIncrease)
   327  
   328  	// Attach Data @ the end of current buffer
   329  	p.ipHdr.Buffer = append(p.ipHdr.Buffer, udpdata...)
   330  
   331  	p.fixupUDPHdr()
   332  	p.fixupUDPChecksum()
   333  
   334  }
   335  
   336  // UDPDataAttach Attaches UDP data post encryption.
   337  func (p *Packet) UDPDataAttach(header, udpdata []byte) {
   338  
   339  	// Attach Data @ the end of current buffer
   340  	p.ipHdr.Buffer = append(p.ipHdr.Buffer, header...)
   341  	p.ipHdr.Buffer = append(p.ipHdr.Buffer, udpdata...)
   342  	// IP Header Processing
   343  	p.FixupIPHdrOnDataModify(p.ipHdr.ipTotalLength, uint16(len(p.ipHdr.Buffer)))
   344  
   345  	p.fixupUDPHdr()
   346  	p.fixupUDPChecksum()
   347  }
   348  
   349  // UDPDataDetach detaches UDP payload from the Buffer. Called only during Encrypt/Decrypt.
   350  func (p *Packet) UDPDataDetach() {
   351  	// Create constants for IP header + UDP header. copy ?
   352  	p.ipHdr.Buffer = p.ipHdr.Buffer[:p.ipHdr.ipHeaderLen+UDPDataPos]
   353  }
   354  
   355  // CreateReverseFlowPacket modifies the packet for reverse flow.
   356  func (p *Packet) CreateReverseFlowPacket() {
   357  
   358  	buffer := p.ipHdr.Buffer
   359  
   360  	// reverse ip addresses
   361  	if p.ipHdr.version == V4 {
   362  		copy(buffer[ipv4SourceAddrPos:ipv4SourceAddrPos+4], p.ipHdr.destinationAddress)
   363  		copy(buffer[ipv4DestAddrPos:ipv4DestAddrPos+4], p.ipHdr.sourceAddress)
   364  	} else {
   365  		copy(buffer[ipv6SourceAddrPos:ipv6SourceAddrPos+16], p.ipHdr.destinationAddress)
   366  		copy(buffer[ipv6DestAddrPos:ipv6DestAddrPos+16], p.ipHdr.sourceAddress)
   367  	}
   368  
   369  	buffer = buffer[p.ipHdr.ipHeaderLen:]
   370  
   371  	// reverse ports
   372  	binary.BigEndian.PutUint16(buffer[udpSourcePortPos:udpSourcePortPos+2], p.udpHdr.destinationPort)
   373  	binary.BigEndian.PutUint16(buffer[udpDestPortPos:udpDestPortPos+2], p.udpHdr.sourcePort)
   374  
   375  	// swap in our packet structures
   376  	p.ipHdr.sourceAddress, p.ipHdr.destinationAddress = p.ipHdr.destinationAddress, p.ipHdr.sourceAddress
   377  	p.udpHdr.sourcePort, p.udpHdr.destinationPort = p.udpHdr.destinationPort, p.udpHdr.sourcePort
   378  
   379  	// Just get the IP/UDP header. Ignore the rest. No need for packet
   380  	p.ipHdr.Buffer = p.ipHdr.Buffer[:p.ipHdr.ipHeaderLen+UDPDataPos]
   381  
   382  	p.FixupIPHdrOnDataModify(p.ipHdr.ipTotalLength, uint16(p.ipHdr.ipHeaderLen+UDPDataPos))
   383  
   384  	if p.ipHdr.version == V4 {
   385  		p.UpdateIPv4Checksum()
   386  	}
   387  
   388  	p.fixupUDPHdr()
   389  	p.fixupUDPChecksum()
   390  }
   391  
   392  // GetUDPType returns udp type of packet.
   393  func (p *Packet) GetUDPType() byte {
   394  	var offset uint8
   395  	// Every UDP control packet has a 20 byte packet signature. The
   396  	// first 2 bytes represent the following control information.
   397  	// Byte 0 : Bits 0,1 are reserved fields.
   398  	//          Bits 2,3,4 represent version information.
   399  	//          Bits 5,6 represent udp packet type,
   400  	//          Bit 7 represents encryption. (currently unused).
   401  	// Byte 1: reserved for future use.
   402  	// Bytes [2:20]: Packet signature.
   403  	//zap.L().Error("Packet", zap.String("P/n", hex.Dump(p.ipHdr.Buffer)))
   404  	if p.ipHdr.ipTotalLength > uint16(p.IPHeaderLen())+8+255 {
   405  		offset = 4
   406  	} else {
   407  		offset = 2
   408  	}
   409  
   410  	return GetUDPTypeFromBuffer(p.ipHdr.Buffer[p.ipHdr.ipHeaderLen+offset:])
   411  }
   412  
   413  // GetUDPTypeFromBuffer gets the UDP packet from a raw buffer.,
   414  func GetUDPTypeFromBuffer(buffer []byte) byte {
   415  	if len(buffer) < (UDPDataPos + UDPSignatureLen) {
   416  		return 0
   417  	}
   418  
   419  	marker := buffer[UDPDataPos:udpSignatureEnd]
   420  
   421  	// check for packet signature.
   422  	if !bytes.Equal(buffer[udpAuthMarkerOffset:udpSignatureEnd], []byte(UDPAuthMarker)) {
   423  		zap.L().Debug("Not an Aporeto control Packet")
   424  		return 0
   425  	}
   426  	// control packet. byte 0 has packet type information.
   427  	return marker[0] & UDPPacketMask
   428  }
   429  
   430  //GetTCPFlags returns the tcp flags from the packet
   431  func (p *Packet) GetTCPFlags() uint8 {
   432  	return p.tcpHdr.tcpFlags
   433  }
   434  
   435  //SetTCPFlags allows to set the tcp flags on the packet
   436  func (p *Packet) SetTCPFlags(flags uint8) {
   437  	p.tcpHdr.tcpFlags = flags
   438  }
   439  
   440  // CreateUDPAuthMarker creates a UDP auth marker.
   441  func CreateUDPAuthMarker(packetType uint8, payloadLength uint16) []byte {
   442  	var options []byte
   443  	// Every UDP control packet has a 20 byte packet signature. The
   444  	// first 2 bytes represent the following control information.
   445  	// Byte 0 : Bits 0,1 are reserved fields.
   446  	//          Bits 2,3,4 represent version information.
   447  	//          Bits 5, 6, 7 represent udp packet type,
   448  	// Byte 1: reserved for future use.
   449  	// Bytes [2:20]: Packet signature.
   450  
   451  	//marker := make([]byte, UDPSignatureLen)
   452  	// ignore version info as of now.
   453  	if payloadLength < uint16(UDPAporetoOptionLengthFirstByte) {
   454  		options = make([]byte, int(payloadLength)+UDPAporetoOptionShortLength+UDPSignatureLen)
   455  		options[0] = UDPAporetoOption
   456  		options[1] = uint8(payloadLength) + UDPAporetoOptionShortLength + UDPSignatureLen
   457  
   458  		options[2] |= packetType // byte 0
   459  		options[3] = 0           // byte 1
   460  		copy(options[4:], []byte(UDPAuthMarker))
   461  	} else {
   462  		options = make([]byte, int(payloadLength)+UDPAporetoOptionLongLength+len(UDPAuthMarker))
   463  		options[0] = UDPAporetoOption
   464  		options[1] = UDPAporetoOptionLengthFirstByte
   465  		binary.LittleEndian.PutUint16(options[2:], payloadLength+20)
   466  		options[4] |= packetType // byte 0
   467  		options[5] = 0           // byte 1
   468  		copy(options[UDPAporetoOptionLongLength:], []byte(UDPAuthMarker))
   469  
   470  	}
   471  
   472  	return options
   473  }
   474  
   475  // GetICMPTypeCode returns the icmp type and icmp code
   476  func (p *Packet) GetICMPTypeCode() (int8, int8) {
   477  	return p.icmpHdr.icmpType, p.icmpHdr.icmpCode
   478  }