mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 19:31:44 +00:00
add ipv6 support to the image issue-74839
Co-authored-by: Dan Winship <danwinship@redhat.com>
This commit is contained in:
parent
e99df0e5a7
commit
a0887285f5
@ -1,4 +1,4 @@
|
|||||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
@ -29,3 +29,9 @@ filegroup(
|
|||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = ["tcp_test.go"],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
)
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
approvers:
|
approvers:
|
||||||
- anfernee
|
- anfernee
|
||||||
|
- aojea
|
||||||
|
@ -1 +1 @@
|
|||||||
1.1
|
1.2
|
||||||
|
@ -17,20 +17,33 @@ limitations under the License.
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TCP port to listen
|
||||||
|
const port = 9000
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ip := getIP().String()
|
ips := getIPs()
|
||||||
log.Printf("external ip: %v", ip)
|
if len(ips) == 0 {
|
||||||
|
panic("No valid IP found")
|
||||||
|
}
|
||||||
|
|
||||||
go probe(ip)
|
// listen TCP packets to inject the out of order TCP packets
|
||||||
|
for _, ip := range ips {
|
||||||
|
log.Printf("external ip: %v", ip.String())
|
||||||
|
go probe(ip.String())
|
||||||
|
}
|
||||||
|
|
||||||
log.Printf("listen on %v:9000", "0.0.0.0")
|
log.Printf("listen on %v:%d", "0.0.0.0", port)
|
||||||
|
|
||||||
listener, err := net.Listen("tcp", "0.0.0.0:9000")
|
// open a server listening to establish the TCP connections
|
||||||
|
listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%d", port))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -42,6 +55,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
go func(conn net.Conn) {
|
go func(conn net.Conn) {
|
||||||
|
// Close the connection after 10 secs
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
conn.Close()
|
conn.Close()
|
||||||
}(conn)
|
}(conn)
|
||||||
@ -51,12 +65,12 @@ func main() {
|
|||||||
func probe(ip string) {
|
func probe(ip string) {
|
||||||
log.Printf("probing %v", ip)
|
log.Printf("probing %v", ip)
|
||||||
|
|
||||||
ipAddr, err := net.ResolveIPAddr("ip4:tcp", ip)
|
ipAddr, err := net.ResolveIPAddr("ip:tcp", ip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := net.ListenIP("ip4:tcp", ipAddr)
|
conn, err := net.ListenIP("ip:tcp", ipAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -89,7 +103,7 @@ func probe(ip string) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if pkt.Flags&RST != 0 {
|
if pkt.Flags&RST != 0 {
|
||||||
panic("RST received")
|
log.Println("ERROR: RST received")
|
||||||
}
|
}
|
||||||
if pkt.Flags&ACK != 0 {
|
if pkt.Flags&ACK != 0 {
|
||||||
if seq, ok := pending[addr.String()]; ok {
|
if seq, ok := pending[addr.String()]; ok {
|
||||||
@ -111,20 +125,26 @@ func probe(ip string) {
|
|||||||
_, err := conn.WriteTo(badPkt.encode(localIP, remoteIP, data[:]), addr)
|
_, err := conn.WriteTo(badPkt.encode(localIP, remoteIP, data[:]), addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("conn.WriteTo() error: %v", err)
|
log.Printf("conn.WriteTo() error: %v", err)
|
||||||
|
} else {
|
||||||
|
log.Println("boom packet injected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIP() net.IP {
|
// getIPs gets the IPs from the downward API
|
||||||
conn, err := net.Dial("udp", "8.8.8.8:53")
|
// we don't have to validate the IPs because
|
||||||
if err != nil {
|
// they are validated previously by kubernetes/CNI
|
||||||
log.Fatal(err)
|
func getIPs() []net.IP {
|
||||||
|
var ips []net.IP
|
||||||
|
podIP, podIPs := os.Getenv("POD_IP"), os.Getenv("POD_IPS")
|
||||||
|
if podIPs != "" {
|
||||||
|
for _, ip := range strings.Split(podIPs, ",") {
|
||||||
|
ips = append(ips, net.ParseIP(ip))
|
||||||
|
}
|
||||||
|
} else if podIP != "" {
|
||||||
|
ips = append(ips, net.ParseIP(podIP))
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
return ips
|
||||||
|
|
||||||
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
|
||||||
|
|
||||||
return localAddr.IP
|
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// Control Bits. 6 bits.
|
||||||
|
// 00 01 02 03 04 05
|
||||||
|
// U A P R S F
|
||||||
|
|
||||||
// FIN is a TCP flag
|
// FIN is a TCP flag
|
||||||
FIN uint16 = 1 << iota
|
FIN uint16 = 1 << iota
|
||||||
// SYN is a TCP flag
|
// SYN is a TCP flag
|
||||||
@ -52,11 +56,16 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type tcpPacket struct {
|
type tcpPacket struct {
|
||||||
SrcPort uint16 // 0
|
SrcPort uint16 // 0
|
||||||
DestPort uint16 // 2
|
DestPort uint16 // 2
|
||||||
Seq uint32 // 4
|
Seq uint32 // 4
|
||||||
Ack uint32 // 8
|
Ack uint32 // 8
|
||||||
Flags uint16 // 13
|
// Flags bytes includes
|
||||||
|
// Data Offset. 4 bits.
|
||||||
|
// reserved. 3 bits. (must be zero)
|
||||||
|
// ECN, Explicit Congestion Notification. 3 bits.
|
||||||
|
// Control Bits (Real flags). 6 bits.
|
||||||
|
Flags uint16 // 12
|
||||||
WindowSize uint16 // 14
|
WindowSize uint16 // 14
|
||||||
Checksum uint16 // 16
|
Checksum uint16 // 16
|
||||||
UrgentPtr uint16 // 18
|
UrgentPtr uint16 // 18
|
||||||
@ -133,16 +142,29 @@ func (t *tcpPacket) encode(src, dest net.IP, data []byte) []byte {
|
|||||||
|
|
||||||
func checksumTCP(src, dest net.IP, tcpHeader, data []byte) uint16 {
|
func checksumTCP(src, dest net.IP, tcpHeader, data []byte) uint16 {
|
||||||
log.Printf("calling checksumTCP: %v %v %v %v", src, dest, tcpHeader, data)
|
log.Printf("calling checksumTCP: %v %v %v %v", src, dest, tcpHeader, data)
|
||||||
chk := &tcpChecksumer{}
|
chk := &tcpChecksummer{}
|
||||||
|
|
||||||
// Encode pseudoheader.
|
// Encode pseudoheader.
|
||||||
chk.add(src.To4())
|
if src.To4() != nil {
|
||||||
chk.add(dest.To4())
|
// IPv4 [ src (4) | dst (4) | rsv (1) | proto (1) | tcp length (2) ] ... | tcp header | data
|
||||||
|
chk.add(src.To4())
|
||||||
|
chk.add(dest.To4())
|
||||||
|
pseudoHeader := make([]byte, 4)
|
||||||
|
pseudoHeader[1] = tcpProtoNum
|
||||||
|
binary.BigEndian.PutUint16(pseudoHeader[2:], uint16(len(data)+len(tcpHeader)))
|
||||||
|
chk.add(pseudoHeader)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// https://tools.ietf.org/html/rfc2460 IPv6
|
||||||
|
// IPv6 [ src (16) | dst (16) | payload length (4) | Zero (3) | NH/proto (1) ] ... | tcp header | data
|
||||||
|
chk.add(src.To16())
|
||||||
|
chk.add(dest.To16())
|
||||||
|
pseudoHeader := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint32(pseudoHeader, uint32(len(data)+len(tcpHeader)))
|
||||||
|
pseudoHeader[7] = tcpProtoNum
|
||||||
|
chk.add(pseudoHeader)
|
||||||
|
}
|
||||||
|
|
||||||
var pseudoHeader [4]byte
|
|
||||||
pseudoHeader[1] = tcpProtoNum
|
|
||||||
binary.BigEndian.PutUint16(pseudoHeader[2:], uint16(len(data)+len(tcpHeader)))
|
|
||||||
chk.add(pseudoHeader[:])
|
|
||||||
chk.add(tcpHeader)
|
chk.add(tcpHeader)
|
||||||
chk.add(data)
|
chk.add(data)
|
||||||
|
|
||||||
@ -151,13 +173,13 @@ func checksumTCP(src, dest net.IP, tcpHeader, data []byte) uint16 {
|
|||||||
return chk.finalize()
|
return chk.finalize()
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcpChecksumer struct {
|
type tcpChecksummer struct {
|
||||||
sum uint32
|
sum uint32
|
||||||
oddByte byte
|
oddByte byte
|
||||||
length int
|
length int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *tcpChecksumer) finalize() uint16 {
|
func (c *tcpChecksummer) finalize() uint16 {
|
||||||
ret := c.sum
|
ret := c.sum
|
||||||
if c.length%2 > 0 {
|
if c.length%2 > 0 {
|
||||||
ret += uint32(c.oddByte)
|
ret += uint32(c.oddByte)
|
||||||
@ -171,7 +193,7 @@ func (c *tcpChecksumer) finalize() uint16 {
|
|||||||
return ^uint16(ret)
|
return ^uint16(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *tcpChecksumer) add(data []byte) {
|
func (c *tcpChecksummer) add(data []byte) {
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
91
test/images/regression-issue-74839/tcp_test.go
Normal file
91
test/images/regression-issue-74839/tcp_test.go
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2019 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Partially copied from https://github.com/bowei/lighthouse/blob/master/pkg/probe/tcp_test.go
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTCPChecksummer(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
desc string
|
||||||
|
data [][]byte
|
||||||
|
want uint16
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "empty",
|
||||||
|
data: [][]byte{},
|
||||||
|
want: 0xffff,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "1 byte",
|
||||||
|
data: [][]byte{{0x55}},
|
||||||
|
want: 0xffaa,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "2 bytes",
|
||||||
|
data: [][]byte{{0x55, 0x88}},
|
||||||
|
want: 0x77aa,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "3 bytes",
|
||||||
|
data: [][]byte{{0x55, 0x88, 0x99}},
|
||||||
|
want: 0x7711,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "3 bytes / 1 at a time",
|
||||||
|
data: [][]byte{{0x55}, {0x88}, {0x99}},
|
||||||
|
want: 0x7711,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "3 bytes / 2 1",
|
||||||
|
data: [][]byte{{0x55, 0x88}, {0x99}},
|
||||||
|
want: 0x7711,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "simple packet",
|
||||||
|
data: [][]byte{
|
||||||
|
{
|
||||||
|
0x7f, 0x00, 0x00, 0x01, // 127.0.0.1
|
||||||
|
0x7f, 0x00, 0x00, 0x01, // 127.0.0.1
|
||||||
|
0x00, 0x06, // TCP proto 6
|
||||||
|
0x00, 0x14, // Size = 20 bytes
|
||||||
|
0x00, 0x50, 0x1f, 0x90, 0x00,
|
||||||
|
0x00, 0x00, 0x01, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x50, 0x02, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: 0xff91,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.desc, func(t *testing.T) {
|
||||||
|
c := &tcpChecksummer{}
|
||||||
|
for _, b := range tc.data {
|
||||||
|
c.add(b)
|
||||||
|
}
|
||||||
|
got := c.finalize()
|
||||||
|
if got != tc.want {
|
||||||
|
t.Errorf("c.finalize() = %x, want %x; bytes: %v", got, tc.want, tc.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user