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 }