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 }