istio.io/istio@v0.0.0-20240520182934-d79c90f27776/tools/istio-iptables/pkg/validation/vld_unix.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris 16 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 17 18 package validation 19 20 import ( 21 "errors" 22 "fmt" 23 "net" 24 "syscall" 25 26 "golang.org/x/sys/unix" 27 28 "istio.io/istio/pkg/log" 29 "istio.io/istio/tools/istio-iptables/pkg/constants" 30 ) 31 32 // Recover the original address from redirect socket. Supposed to work for tcp over ipv4 and ipv6. 33 func GetOriginalDestination(conn net.Conn) (daddr net.IP, dport uint16, err error) { 34 // obtain os fd from Conn 35 tcp, ok := conn.(*net.TCPConn) 36 if !ok { 37 err = errors.New("socket is not tcp") 38 return 39 } 40 file, err := tcp.File() 41 if err != nil { 42 return 43 } 44 defer file.Close() 45 fd := file.Fd() 46 47 // Detect underlying ip is v4 or v6 48 ip := conn.RemoteAddr().(*net.TCPAddr).IP 49 isIpv4 := false 50 if ip.To4() != nil { 51 isIpv4 = true 52 } else if ip.To16() != nil { 53 isIpv4 = false 54 } else { 55 err = fmt.Errorf("neither ipv6 nor ipv4 original addr: %s", ip) 56 return 57 } 58 59 // golang doesn't provide a struct sockaddr_storage 60 // IPv6MTUInfo is chosen because 61 // 1. it is no smaller than sockaddr_storage, 62 // 2. it is provide the port field value 63 var addr *unix.IPv6MTUInfo 64 if isIpv4 { 65 addr, err = unix.GetsockoptIPv6MTUInfo( 66 int(fd), 67 unix.IPPROTO_IP, 68 constants.SoOriginalDst) 69 if err != nil { 70 log.Errorf("Error ipv4 getsockopt: %v", err) 71 return 72 } 73 // See struct sockaddr_in 74 daddr = net.IPv4( 75 addr.Addr.Addr[0], addr.Addr.Addr[1], addr.Addr.Addr[2], addr.Addr.Addr[3]) 76 } else { 77 addr, err = unix.GetsockoptIPv6MTUInfo( 78 int(fd), unix.IPPROTO_IPV6, 79 constants.SoOriginalDst) 80 if err != nil { 81 log.Errorf("Error to ipv6 getsockopt: %v", err) 82 return 83 } 84 // See struct sockaddr_in6 85 daddr = addr.Addr.Addr[:] 86 } 87 // See sockaddr_in6 and sockaddr_in 88 dport = ntohs(addr.Addr.Port) 89 90 log.Infof("Local addr %s", conn.LocalAddr()) 91 log.Infof("Original addr %s: %d", ip, dport) 92 return 93 } 94 95 // Setup reuse address to run the validation server more robustly 96 func reuseAddr(network, address string, conn syscall.RawConn) error { 97 return conn.Control(func(descriptor uintptr) { 98 err := unix.SetsockoptInt(int(descriptor), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) 99 if err != nil { 100 log.Errorf("Fail to set fd %d SO_REUSEADDR with error %v", descriptor, err) 101 } 102 err = unix.SetsockoptInt(int(descriptor), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1) 103 if err != nil { 104 log.Errorf("Fail to set fd %d SO_REUSEPORT with error %v", descriptor, err) 105 } 106 }) 107 }