github.com/castai/kvisor@v1.7.1-0.20240516114728-b3572a2607b5/cmd/agent/daemon/conntrack/conntrack_nf.go (about)

     1  package conntrack
     2  
     3  import (
     4  	"net"
     5  	"net/netip"
     6  	"strings"
     7  	"syscall"
     8  
     9  	"github.com/castai/kvisor/pkg/logging"
    10  	"github.com/florianl/go-conntrack"
    11  	"github.com/samber/lo"
    12  )
    13  
    14  type NetfilterConntrackClient struct {
    15  	log  *logging.Logger
    16  	nfct *conntrack.Nfct
    17  }
    18  
    19  func (n *NetfilterConntrackClient) GetDestination(src, dst netip.AddrPort) (netip.AddrPort, bool) {
    20  	// TODO(Kvisor): Track metrics and consider adding LRU hashmap cache if we make to many syscalls.
    21  
    22  	req := conntrack.Con{
    23  		Origin: &conntrack.IPTuple{
    24  			Src: lo.ToPtr(net.IP(src.Addr().AsSlice())),
    25  			Dst: lo.ToPtr(net.IP(dst.Addr().AsSlice())),
    26  			Proto: &conntrack.ProtoTuple{
    27  				Number:  lo.ToPtr(uint8(syscall.IPPROTO_TCP)),
    28  				SrcPort: lo.ToPtr(src.Port()),
    29  				DstPort: lo.ToPtr(dst.Port()),
    30  			},
    31  		},
    32  	}
    33  	family := conntrack.IPv4
    34  	if dst.Addr().Is6() {
    35  		family = conntrack.IPv6
    36  	}
    37  	sessions, err := n.nfct.Get(conntrack.Conntrack, family, req)
    38  	if err != nil {
    39  		if !strings.Contains(err.Error(), "no such file or directory") {
    40  			n.log.Errorf("getting conntrack records: %v", err)
    41  		}
    42  		return netip.AddrPort{}, false
    43  	}
    44  	for _, sess := range sessions {
    45  		if !isTupleValid(sess.Reply) {
    46  			continue
    47  		}
    48  		ip, ok := netip.AddrFromSlice(*sess.Reply.Src)
    49  		if !ok {
    50  			continue
    51  		}
    52  		res := netip.AddrPortFrom(ip, *sess.Reply.Proto.SrcPort)
    53  		return res, true
    54  	}
    55  	return netip.AddrPort{}, false
    56  }
    57  
    58  func (n *NetfilterConntrackClient) Close() error {
    59  	return n.nfct.Close()
    60  }
    61  
    62  func isTupleValid(t *conntrack.IPTuple) bool {
    63  	if t == nil {
    64  		return false
    65  	}
    66  	if t.Src == nil || t.Dst == nil || t.Proto == nil {
    67  		return false
    68  	}
    69  	if t.Proto.SrcPort == nil || t.Proto.DstPort == nil {
    70  		return false
    71  	}
    72  	return true
    73  }