github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/libnetwork/iptables/conntrack.go (about)

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