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 }