istio
107 строк · 3.0 Кб
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
18package validation
19
20import (
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.
33func GetOriginalDestination(conn net.Conn) (daddr net.IP, dport uint16, err error) {
34// obtain os fd from Conn
35tcp, ok := conn.(*net.TCPConn)
36if !ok {
37err = errors.New("socket is not tcp")
38return
39}
40file, err := tcp.File()
41if err != nil {
42return
43}
44defer file.Close()
45fd := file.Fd()
46
47// Detect underlying ip is v4 or v6
48ip := conn.RemoteAddr().(*net.TCPAddr).IP
49isIpv4 := false
50if ip.To4() != nil {
51isIpv4 = true
52} else if ip.To16() != nil {
53isIpv4 = false
54} else {
55err = fmt.Errorf("neither ipv6 nor ipv4 original addr: %s", ip)
56return
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
63var addr *unix.IPv6MTUInfo
64if isIpv4 {
65addr, err = unix.GetsockoptIPv6MTUInfo(
66int(fd),
67unix.IPPROTO_IP,
68constants.SoOriginalDst)
69if err != nil {
70log.Errorf("Error ipv4 getsockopt: %v", err)
71return
72}
73// See struct sockaddr_in
74daddr = net.IPv4(
75addr.Addr.Addr[0], addr.Addr.Addr[1], addr.Addr.Addr[2], addr.Addr.Addr[3])
76} else {
77addr, err = unix.GetsockoptIPv6MTUInfo(
78int(fd), unix.IPPROTO_IPV6,
79constants.SoOriginalDst)
80if err != nil {
81log.Errorf("Error to ipv6 getsockopt: %v", err)
82return
83}
84// See struct sockaddr_in6
85daddr = addr.Addr.Addr[:]
86}
87// See sockaddr_in6 and sockaddr_in
88dport = ntohs(addr.Addr.Port)
89
90log.Infof("Local addr %s", conn.LocalAddr())
91log.Infof("Original addr %s: %d", ip, dport)
92return
93}
94
95// Setup reuse address to run the validation server more robustly
96func reuseAddr(network, address string, conn syscall.RawConn) error {
97return conn.Control(func(descriptor uintptr) {
98err := unix.SetsockoptInt(int(descriptor), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
99if err != nil {
100log.Errorf("Fail to set fd %d SO_REUSEADDR with error %v", descriptor, err)
101}
102err = unix.SetsockoptInt(int(descriptor), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
103if err != nil {
104log.Errorf("Fail to set fd %d SO_REUSEPORT with error %v", descriptor, err)
105}
106})
107}
108