github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/libnetwork/ns/init_linux.go (about)

     1  package ns
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"strings"
     8  	"sync"
     9  	"syscall"
    10  	"time"
    11  
    12  	"github.com/sirupsen/logrus"
    13  	"github.com/vishvananda/netlink"
    14  	"github.com/vishvananda/netns"
    15  )
    16  
    17  var (
    18  	initNs   netns.NsHandle
    19  	initNl   *netlink.Handle
    20  	initOnce sync.Once
    21  	// NetlinkSocketsTimeout represents the default timeout duration for the sockets
    22  	NetlinkSocketsTimeout = 3 * time.Second
    23  )
    24  
    25  // Init initializes a new network namespace
    26  func Init() {
    27  	var err error
    28  	initNs, err = netns.Get()
    29  	if err != nil {
    30  		logrus.Errorf("could not get initial namespace: %v", err)
    31  	}
    32  	initNl, err = netlink.NewHandle(getSupportedNlFamilies()...)
    33  	if err != nil {
    34  		logrus.Errorf("could not create netlink handle on initial namespace: %v", err)
    35  	}
    36  	err = initNl.SetSocketTimeout(NetlinkSocketsTimeout)
    37  	if err != nil {
    38  		logrus.Warnf("Failed to set the timeout on the default netlink handle sockets: %v", err)
    39  	}
    40  }
    41  
    42  // SetNamespace sets the initial namespace handler
    43  func SetNamespace() error {
    44  	initOnce.Do(Init)
    45  	if err := netns.Set(initNs); err != nil {
    46  		linkInfo, linkErr := getLink()
    47  		if linkErr != nil {
    48  			linkInfo = linkErr.Error()
    49  		}
    50  		return fmt.Errorf("failed to set to initial namespace, %v, initns fd %d: %v", linkInfo, initNs, err)
    51  	}
    52  	return nil
    53  }
    54  
    55  // ParseHandlerInt transforms the namespace handler into an integer
    56  func ParseHandlerInt() int {
    57  	return int(getHandler())
    58  }
    59  
    60  // GetHandler returns the namespace handler
    61  func getHandler() netns.NsHandle {
    62  	initOnce.Do(Init)
    63  	return initNs
    64  }
    65  
    66  func getLink() (string, error) {
    67  	return os.Readlink(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
    68  }
    69  
    70  // NlHandle returns the netlink handler
    71  func NlHandle() *netlink.Handle {
    72  	initOnce.Do(Init)
    73  	return initNl
    74  }
    75  
    76  func getSupportedNlFamilies() []int {
    77  	fams := []int{syscall.NETLINK_ROUTE}
    78  	// NETLINK_XFRM test
    79  	if err := checkXfrmSocket(); err != nil {
    80  		logrus.Warnf("Could not load necessary modules for IPSEC rules: %v", err)
    81  	} else {
    82  		fams = append(fams, syscall.NETLINK_XFRM)
    83  	}
    84  	// NETLINK_NETFILTER test
    85  	if err := loadNfConntrackModules(); err != nil {
    86  		if checkNfSocket() != nil {
    87  			logrus.Warnf("Could not load necessary modules for Conntrack: %v", err)
    88  		} else {
    89  			fams = append(fams, syscall.NETLINK_NETFILTER)
    90  		}
    91  	} else {
    92  		fams = append(fams, syscall.NETLINK_NETFILTER)
    93  	}
    94  
    95  	return fams
    96  }
    97  
    98  // API check on required xfrm modules (xfrm_user, xfrm_algo)
    99  func checkXfrmSocket() error {
   100  	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_XFRM)
   101  	if err != nil {
   102  		return err
   103  	}
   104  	syscall.Close(fd)
   105  	return nil
   106  }
   107  
   108  func loadNfConntrackModules() error {
   109  	if out, err := exec.Command("modprobe", "-va", "nf_conntrack").CombinedOutput(); err != nil {
   110  		return fmt.Errorf("Running modprobe nf_conntrack failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
   111  	}
   112  	if out, err := exec.Command("modprobe", "-va", "nf_conntrack_netlink").CombinedOutput(); err != nil {
   113  		return fmt.Errorf("Running modprobe nf_conntrack_netlink failed with message: `%s`, error: %v", strings.TrimSpace(string(out)), err)
   114  	}
   115  	return nil
   116  }
   117  
   118  // API check on required nf_conntrack* modules (nf_conntrack, nf_conntrack_netlink)
   119  func checkNfSocket() error {
   120  	fd, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW, syscall.NETLINK_NETFILTER)
   121  	if err != nil {
   122  		return err
   123  	}
   124  	syscall.Close(fd)
   125  	return nil
   126  }