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  }