github.com/rish1988/moby@v25.0.2+incompatible/libnetwork/iptables/conntrack.go (about) 1 //go:build linux 2 3 package iptables 4 5 import ( 6 "context" 7 "errors" 8 "net" 9 "syscall" 10 11 "github.com/containerd/log" 12 "github.com/docker/docker/libnetwork/types" 13 "github.com/vishvananda/netlink" 14 ) 15 16 // checkConntrackProgrammable checks if the handle supports the 17 // NETLINK_NETFILTER and the base modules are loaded. 18 func checkConntrackProgrammable(nlh *netlink.Handle) error { 19 if !nlh.SupportsNetlinkFamily(syscall.NETLINK_NETFILTER) { 20 return errors.New("conntrack is not available") 21 } 22 return nil 23 } 24 25 // DeleteConntrackEntries deletes all the conntrack connections on the host for the specified IP 26 // Returns the number of flows deleted for IPv4, IPv6 else error 27 func DeleteConntrackEntries(nlh *netlink.Handle, ipv4List []net.IP, ipv6List []net.IP) error { 28 if err := checkConntrackProgrammable(nlh); err != nil { 29 return err 30 } 31 32 var totalIPv4FlowPurged uint 33 for _, ipAddress := range ipv4List { 34 flowPurged, err := purgeConntrackState(nlh, syscall.AF_INET, ipAddress) 35 if err != nil { 36 log.G(context.TODO()).Warnf("Failed to delete conntrack state for %s: %v", ipAddress, err) 37 continue 38 } 39 totalIPv4FlowPurged += flowPurged 40 } 41 42 var totalIPv6FlowPurged uint 43 for _, ipAddress := range ipv6List { 44 flowPurged, err := purgeConntrackState(nlh, syscall.AF_INET6, ipAddress) 45 if err != nil { 46 log.G(context.TODO()).Warnf("Failed to delete conntrack state for %s: %v", ipAddress, err) 47 continue 48 } 49 totalIPv6FlowPurged += flowPurged 50 } 51 52 if totalIPv4FlowPurged > 0 || totalIPv6FlowPurged > 0 { 53 log.G(context.TODO()).Debugf("DeleteConntrackEntries purged ipv4:%d, ipv6:%d", totalIPv4FlowPurged, totalIPv6FlowPurged) 54 } 55 56 return nil 57 } 58 59 func DeleteConntrackEntriesByPort(nlh *netlink.Handle, proto types.Protocol, ports []uint16) error { 60 if err := checkConntrackProgrammable(nlh); err != nil { 61 return err 62 } 63 64 var totalIPv4FlowPurged uint 65 var totalIPv6FlowPurged uint 66 67 for _, port := range ports { 68 filter := &netlink.ConntrackFilter{} 69 if err := filter.AddProtocol(uint8(proto)); err != nil { 70 log.G(context.TODO()).Warnf("Failed to delete conntrack state for %s port %d: %v", proto.String(), port, err) 71 continue 72 } 73 if err := filter.AddPort(netlink.ConntrackOrigDstPort, port); err != nil { 74 log.G(context.TODO()).Warnf("Failed to delete conntrack state for %s port %d: %v", proto.String(), port, err) 75 continue 76 } 77 78 v4FlowPurged, err := nlh.ConntrackDeleteFilter(netlink.ConntrackTable, syscall.AF_INET, filter) 79 if err != nil { 80 log.G(context.TODO()).Warnf("Failed to delete conntrack state for IPv4 %s port %d: %v", proto.String(), port, err) 81 } 82 totalIPv4FlowPurged += v4FlowPurged 83 84 v6FlowPurged, err := nlh.ConntrackDeleteFilter(netlink.ConntrackTable, syscall.AF_INET6, filter) 85 if err != nil { 86 log.G(context.TODO()).Warnf("Failed to delete conntrack state for IPv6 %s port %d: %v", proto.String(), port, err) 87 } 88 totalIPv6FlowPurged += v6FlowPurged 89 } 90 91 if totalIPv4FlowPurged > 0 || totalIPv6FlowPurged > 0 { 92 log.G(context.TODO()).Debugf("DeleteConntrackEntriesByPort for %s ports purged ipv4:%d, ipv6:%d", proto.String(), totalIPv4FlowPurged, totalIPv6FlowPurged) 93 } 94 95 return nil 96 } 97 98 func purgeConntrackState(nlh *netlink.Handle, family netlink.InetFamily, ipAddress net.IP) (uint, error) { 99 filter := &netlink.ConntrackFilter{} 100 // NOTE: doing the flush using the ipAddress is safe because today there cannot be multiple networks with the same subnet 101 // so it will not be possible to flush flows that are of other containers 102 if err := filter.AddIP(netlink.ConntrackNatAnyIP, ipAddress); err != nil { 103 return 0, err 104 } 105 return nlh.ConntrackDeleteFilter(netlink.ConntrackTable, family, filter) 106 }