k8s.io/kubernetes@v1.29.3/test/images/regression-issue-74839/tcp.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Partially copied from https://github.com/bowei/lighthouse/blob/master/pkg/probe/tcp.go
    18  
    19  package main
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/binary"
    24  	"log"
    25  	"net"
    26  )
    27  
    28  const (
    29  	tcpHeaderSize = 20
    30  	tcpProtoNum   = 6
    31  )
    32  
    33  const (
    34  	// Control Bits. 6 bits.
    35  	// 00    01    02    03    04    05
    36  	// U     A     P     R     S     F
    37  
    38  	// FIN is a TCP flag
    39  	FIN uint16 = 1 << iota
    40  	// SYN is a TCP flag
    41  	SYN
    42  	// RST is a TCP flag
    43  	RST
    44  	// PSH is a TCP flag
    45  	PSH
    46  	// ACK is a TCP flag
    47  	ACK
    48  	// URG is a TCP flag
    49  	URG
    50  	// ECE is a TCP flag
    51  	ECE
    52  	// CWR is a TCP flag
    53  	CWR
    54  	// NS is a TCP flag
    55  	NS
    56  )
    57  
    58  type tcpPacket struct {
    59  	SrcPort  uint16 // 0
    60  	DestPort uint16 // 2
    61  	Seq      uint32 // 4
    62  	Ack      uint32 // 8
    63  	// Flags bytes includes
    64  	// Data Offset. 4 bits.
    65  	// reserved. 3 bits. (must be zero)
    66  	// ECN, Explicit Congestion Notification. 3 bits.
    67  	// Control Bits (Real flags). 6 bits.
    68  	Flags      uint16 // 12
    69  	WindowSize uint16 // 14
    70  	Checksum   uint16 // 16
    71  	UrgentPtr  uint16 // 18
    72  	// 20
    73  }
    74  
    75  func (t *tcpPacket) decode(pkt []byte) ([]byte, error) {
    76  	err := binary.Read(bytes.NewReader(pkt), binary.BigEndian, t)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	return pkt[t.DataOffset():], nil
    82  }
    83  
    84  func (t *tcpPacket) DataOffset() int {
    85  	return int((t.Flags >> 12) * 4)
    86  }
    87  
    88  func (t *tcpPacket) FlagString() string {
    89  	out := ""
    90  
    91  	if t.Flags&FIN != 0 {
    92  		out += "FIN "
    93  	}
    94  	if t.Flags&SYN != 0 {
    95  		out += "SYN "
    96  	}
    97  	if t.Flags&RST != 0 {
    98  		out += "RST "
    99  	}
   100  	if t.Flags&PSH != 0 {
   101  		out += "PSH "
   102  	}
   103  	if t.Flags&ACK != 0 {
   104  		out += "ACK "
   105  	}
   106  	if t.Flags&URG != 0 {
   107  		out += "URG "
   108  	}
   109  	if t.Flags&ECE != 0 {
   110  		out += "ECE "
   111  	}
   112  	if t.Flags&CWR != 0 {
   113  		out += "CWR "
   114  	}
   115  	if t.Flags&NS != 0 {
   116  		out += "NS "
   117  	}
   118  
   119  	return out
   120  }
   121  
   122  func (t *tcpPacket) encode(src, dest net.IP, data []byte) []byte {
   123  	pkt := make([]byte, 20, 20+len(data))
   124  
   125  	encoder := binary.BigEndian
   126  	encoder.PutUint16(pkt, t.SrcPort)
   127  	encoder.PutUint16(pkt[2:], t.DestPort)
   128  	encoder.PutUint32(pkt[4:], t.Seq)
   129  	encoder.PutUint32(pkt[8:], t.Ack)
   130  	encoder.PutUint16(pkt[12:], t.Flags)
   131  	encoder.PutUint16(pkt[14:], t.WindowSize)
   132  	encoder.PutUint16(pkt[18:], t.UrgentPtr)
   133  
   134  	checksum := checksumTCP(src, dest, pkt[:tcpHeaderSize], data)
   135  	pkt[16] = uint8(checksum & 0xff)
   136  	pkt[17] = uint8(checksum >> 8)
   137  
   138  	pkt = append(pkt, data...)
   139  
   140  	return pkt
   141  }
   142  
   143  func checksumTCP(src, dest net.IP, tcpHeader, data []byte) uint16 {
   144  	log.Printf("calling checksumTCP: %v %v %v %v", src, dest, tcpHeader, data)
   145  	chk := &tcpChecksummer{}
   146  
   147  	// Encode pseudoheader.
   148  	if src.To4() != nil {
   149  		// IPv4 [ src (4) | dst (4) | rsv (1) | proto (1) | tcp length (2) ] ... | tcp header | data
   150  		chk.add(src.To4())
   151  		chk.add(dest.To4())
   152  		pseudoHeader := make([]byte, 4)
   153  		pseudoHeader[1] = tcpProtoNum
   154  		binary.BigEndian.PutUint16(pseudoHeader[2:], uint16(len(data)+len(tcpHeader)))
   155  		chk.add(pseudoHeader)
   156  
   157  	} else {
   158  		// https://tools.ietf.org/html/rfc2460 IPv6
   159  		// IPv6 [ src (16) | dst (16) | payload length (4) | Zero (3) | NH/proto (1) ] ... | tcp header | data
   160  		chk.add(src.To16())
   161  		chk.add(dest.To16())
   162  		pseudoHeader := make([]byte, 8)
   163  		binary.BigEndian.PutUint32(pseudoHeader, uint32(len(data)+len(tcpHeader)))
   164  		pseudoHeader[7] = tcpProtoNum
   165  		chk.add(pseudoHeader)
   166  	}
   167  
   168  	chk.add(tcpHeader)
   169  	chk.add(data)
   170  
   171  	log.Printf("checksumer: %+v", chk)
   172  
   173  	return chk.finalize()
   174  }
   175  
   176  type tcpChecksummer struct {
   177  	sum     uint32
   178  	oddByte byte
   179  	length  int
   180  }
   181  
   182  func (c *tcpChecksummer) finalize() uint16 {
   183  	ret := c.sum
   184  	if c.length%2 > 0 {
   185  		ret += uint32(c.oddByte)
   186  	}
   187  	log.Println("ret: ", ret)
   188  	for ret>>16 > 0 {
   189  		ret = ret&0xffff + ret>>16
   190  		log.Println("ret: ", ret)
   191  	}
   192  	log.Println("ret: ", ret)
   193  	return ^uint16(ret)
   194  }
   195  
   196  func (c *tcpChecksummer) add(data []byte) {
   197  	if len(data) == 0 {
   198  		return
   199  	}
   200  	haveOddByte := c.length%2 > 0
   201  	c.length += len(data)
   202  	if haveOddByte {
   203  		data = append([]byte{c.oddByte}, data...)
   204  	}
   205  	for i := 0; i < len(data)-1; i += 2 {
   206  		c.sum += uint32(data[i]) + uint32(data[i+1])<<8
   207  	}
   208  	if c.length%2 > 0 {
   209  		c.oddByte = data[len(data)-1]
   210  	}
   211  }