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  }