github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/nfqdatapath/datapath_linux.go (about) 1 // +build linux 2 3 package nfqdatapath 4 5 import ( 6 "context" 7 "fmt" 8 "net" 9 "os" 10 "strconv" 11 "syscall" 12 "time" 13 14 "github.com/ghedo/go.pkt/layers" 15 gpacket "github.com/ghedo/go.pkt/packet" 16 "github.com/ghedo/go.pkt/packet/ipv4" 17 "go.aporeto.io/enforcerd/internal/utils" 18 "go.aporeto.io/enforcerd/trireme-lib/buildflags" 19 "go.aporeto.io/enforcerd/trireme-lib/controller/constants" 20 "go.aporeto.io/enforcerd/trireme-lib/controller/internal/enforcer/applicationproxy/markedconn" 21 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/connection" 22 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/packet" 23 "go.uber.org/zap" 24 "golang.org/x/sys/unix" 25 ) 26 27 func procSetValue(procName string, value int) error { 28 file, err := os.OpenFile(procName, os.O_RDWR|os.O_TRUNC, 0644) 29 if err != nil { 30 return err 31 } 32 defer file.Close() // nolint: errcheck 33 _, err = file.WriteString(strconv.Itoa(value)) 34 if err != nil { 35 return err 36 } 37 return nil 38 } 39 40 // Declare function pointer so that it can be overridden by unit test 41 var procSetValuePtr func(procName string, value int) error = procSetValue 42 43 func adjustConntrack(mode constants.ModeType) { 44 // As the pods in k8s is RO, we need to use the Host Proc to write into the proc FS. 45 err := procSetValuePtr(utils.GetPathOnHostViaProcRoot("/proc/sys/net/netfilter/nf_conntrack_tcp_be_liberal"), 1) 46 if err != nil { 47 zap.L().Fatal("Failed to set conntrack options", zap.Error(err)) 48 } 49 50 if mode == constants.LocalServer && !buildflags.IsLegacyKernel() { 51 err := procSetValuePtr(utils.GetPathOnHostViaProcRoot("/proc/sys/net/ipv4/ip_early_demux"), 0) 52 if err != nil { 53 zap.L().Fatal("Failed to set early demux options", zap.Error(err)) 54 } 55 } 56 } 57 58 func (d *Datapath) setMark(pkt *packet.Packet, mark uint32) error { 59 return nil 60 } 61 62 func (d *Datapath) reverseFlow(pkt *packet.Packet) error { 63 return nil 64 } 65 66 func (d *Datapath) drop(pkt *packet.Packet) error { 67 return nil 68 } 69 70 func (d *Datapath) dropFlow(pkt *packet.Packet) error { 71 return nil 72 } 73 74 func (d *Datapath) ignoreFlow(pkt *packet.Packet) error { 75 return nil 76 } 77 78 func (d *Datapath) setFlowState(pkt *packet.Packet, accepted bool) error { 79 return nil 80 } 81 82 func (d *Datapath) startInterceptors(ctx context.Context) { 83 d.startInterceptor(ctx) 84 } 85 86 type pingConn struct { 87 conn net.Conn 88 } 89 90 func dialIP(srcIP, dstIP net.IP) (PingConn, error) { 91 92 d := net.Dialer{ 93 Timeout: 5 * time.Second, 94 KeepAlive: -1, // keepalive disabled. 95 LocalAddr: &net.IPAddr{IP: srcIP}, 96 Control: markedconn.ControlFunc(constants.ProxyMarkInt, false, nil), 97 } 98 99 conn, err := d.Dial("ip4:tcp", dstIP.String()) 100 if err != nil { 101 return nil, err 102 } 103 104 return &pingConn{conn: conn}, nil 105 } 106 107 // Close closes the connection. 108 func (p *pingConn) Close() error { 109 return p.conn.Close() 110 } 111 112 // Write writes to the connection. 113 func (p *pingConn) Write(data []byte) (int, error) { 114 115 n, err := p.conn.Write(data) 116 if err != nil { 117 return n, err 118 } 119 120 if n != len(data) { 121 return n, fmt.Errorf("partial data written, total: %v, written: %v", len(data), n) 122 } 123 124 return n, nil 125 } 126 127 // ConstructWirePacket returns TCP packet with the given payload in wire format. 128 func (p *pingConn) ConstructWirePacket(srcIP, dstIP net.IP, transport gpacket.Packet, payload gpacket.Packet) ([]byte, error) { 129 return packLayers(srcIP, dstIP, transport, payload) 130 } 131 132 func bindRandomPort(tcpConn *connection.TCPConnection) (uint16, error) { 133 134 fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, unix.IPPROTO_TCP) 135 if err != nil || fd <= -1 { 136 return 0, fmt.Errorf("unable to open socket, fd: %d : %s", fd, err) 137 } 138 139 addr := unix.SockaddrInet4{Port: 0} 140 copy(addr.Addr[:], net.ParseIP("127.0.0.1").To4()) 141 if err = unix.Bind(fd, &addr); err != nil { 142 unix.Close(fd) // nolint: errcheck 143 return 0, fmt.Errorf("unable to bind socket: %s", err) 144 } 145 146 sockAddr, err := unix.Getsockname(fd) 147 if err != nil { 148 unix.Close(fd) // nolint: errcheck 149 return 0, fmt.Errorf("unable to get socket address: %s", err) 150 } 151 152 ip4Addr, ok := sockAddr.(*unix.SockaddrInet4) 153 if !ok { 154 unix.Close(fd) // nolint: errcheck 155 return 0, fmt.Errorf("invalid socket address: %T", sockAddr) 156 } 157 158 tcpConn.PingConfig.SetSocketFd(uintptr(fd)) 159 return uint16(ip4Addr.Port), nil 160 } 161 162 func closeRandomPort(tcpConn *connection.TCPConnection) error { 163 164 fd := tcpConn.PingConfig.SocketFd() 165 tcpConn.PingConfig.SetSocketClosed(true) 166 167 return unix.Close(int(fd)) 168 } 169 170 func packLayers(srcIP, dstIP net.IP, transport gpacket.Packet, payload gpacket.Packet) ([]byte, error) { 171 172 // pseudo header. 173 ipPacket := ipv4.Make() 174 ipPacket.SrcAddr = srcIP 175 ipPacket.DstAddr = dstIP 176 ipPacket.Protocol = ipv4.TCP 177 178 transport.SetPayload(payload) // nolint:errcheck 179 ipPacket.SetPayload(transport) // nolint:errcheck 180 181 // pack the layers together. 182 buf, err := layers.Pack(transport, payload) 183 if err != nil { 184 return nil, fmt.Errorf("unable to encode packet to wire format: %v", err) 185 } 186 187 return buf, nil 188 } 189 190 func isAddrInUseErrno(errNo syscall.Errno) bool { 191 return errNo == unix.EADDRINUSE 192 }