k8s.io/kubernetes@v1.29.3/test/images/regression-issue-74839/main.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  package main
    18  
    19  import (
    20  	"fmt"
    21  	"log"
    22  	"net"
    23  	"os"
    24  	"strings"
    25  	"time"
    26  
    27  	netutils "k8s.io/utils/net"
    28  )
    29  
    30  // TCP port to listen
    31  const port = 9000
    32  
    33  func main() {
    34  	ips := getIPs()
    35  	if len(ips) == 0 {
    36  		panic("No valid IP found")
    37  	}
    38  
    39  	// listen TCP packets to inject the out of order TCP packets
    40  	for _, ip := range ips {
    41  		log.Printf("external ip: %v", ip.String())
    42  		go probe(ip.String())
    43  	}
    44  
    45  	log.Printf("listen on %v:%d", "0.0.0.0", port)
    46  
    47  	// open a server listening to establish the TCP connections
    48  	listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
    49  	if err != nil {
    50  		panic(err)
    51  	}
    52  
    53  	for {
    54  		conn, err := listener.Accept()
    55  		if err != nil {
    56  			panic(err)
    57  		}
    58  
    59  		go func(conn net.Conn) {
    60  			// Close the connection after 10 secs
    61  			time.Sleep(10 * time.Second)
    62  			conn.Close()
    63  		}(conn)
    64  	}
    65  }
    66  
    67  func probe(ip string) {
    68  	log.Printf("probing %v", ip)
    69  
    70  	ipAddr, err := net.ResolveIPAddr("ip:tcp", ip)
    71  	if err != nil {
    72  		panic(err)
    73  	}
    74  
    75  	conn, err := net.ListenIP("ip:tcp", ipAddr)
    76  	if err != nil {
    77  		panic(err)
    78  	}
    79  
    80  	pending := make(map[string]uint32)
    81  
    82  	var buffer [4096]byte
    83  	for {
    84  		n, addr, err := conn.ReadFrom(buffer[:])
    85  		if err != nil {
    86  			log.Printf("conn.ReadFrom() error: %v", err)
    87  			continue
    88  		}
    89  
    90  		pkt := &tcpPacket{}
    91  		data, err := pkt.decode(buffer[:n])
    92  		if err != nil {
    93  			log.Printf("tcp packet parse error: %v", err)
    94  			continue
    95  		}
    96  
    97  		if pkt.DestPort != 9000 {
    98  			continue
    99  		}
   100  
   101  		log.Printf("tcp packet: %+v, flag: %v, data: %v, addr: %v", pkt, pkt.FlagString(), data, addr)
   102  
   103  		if pkt.Flags&SYN != 0 {
   104  			pending[addr.String()] = pkt.Seq + 1
   105  			continue
   106  		}
   107  		if pkt.Flags&RST != 0 {
   108  			log.Println("ERROR: RST received")
   109  		}
   110  		if pkt.Flags&ACK != 0 {
   111  			if seq, ok := pending[addr.String()]; ok {
   112  				log.Println("connection established")
   113  				delete(pending, addr.String())
   114  
   115  				badPkt := &tcpPacket{
   116  					SrcPort:    pkt.DestPort,
   117  					DestPort:   pkt.SrcPort,
   118  					Ack:        seq,
   119  					Seq:        pkt.Ack - 100000,      // Bad: seq out-of-window
   120  					Flags:      (5 << 12) | PSH | ACK, // Offset and Flags  oooo000F FFFFFFFF (o:offset, F:flags)
   121  					WindowSize: pkt.WindowSize,
   122  				}
   123  
   124  				data := []byte("boom!!!")
   125  				remoteIP := netutils.ParseIPSloppy(addr.String())
   126  				localIP := netutils.ParseIPSloppy(conn.LocalAddr().String())
   127  				_, err := conn.WriteTo(badPkt.encode(localIP, remoteIP, data[:]), addr)
   128  				if err != nil {
   129  					log.Printf("conn.WriteTo() error: %v", err)
   130  				} else {
   131  					log.Println("boom packet injected")
   132  				}
   133  			}
   134  		}
   135  	}
   136  }
   137  
   138  // getIPs gets the IPs from the downward API
   139  // we don't have to validate the IPs because
   140  // they are validated previously by kubernetes/CNI
   141  func getIPs() []net.IP {
   142  	var ips []net.IP
   143  	podIP, podIPs := os.Getenv("POD_IP"), os.Getenv("POD_IPS")
   144  	if podIPs != "" {
   145  		for _, ip := range strings.Split(podIPs, ",") {
   146  			ips = append(ips, netutils.ParseIPSloppy(ip))
   147  		}
   148  	} else if podIP != "" {
   149  		ips = append(ips, netutils.ParseIPSloppy(podIP))
   150  	}
   151  	return ips
   152  }