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 }