github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/resolver_unix.go (about)

     1  //go:build !windows
     2  // +build !windows
     3  
     4  package libnetwork
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"os"
    10  	"os/exec"
    11  	"runtime"
    12  
    13  	"github.com/docker/docker/pkg/reexec"
    14  	"github.com/docker/libnetwork/iptables"
    15  	"github.com/sirupsen/logrus"
    16  	"github.com/vishvananda/netns"
    17  )
    18  
    19  func init() {
    20  	reexec.Register("setup-resolver", reexecSetupResolver)
    21  }
    22  
    23  const (
    24  	// outputChain used for docker embed dns
    25  	outputChain = "DOCKER_OUTPUT"
    26  	//postroutingchain used for docker embed dns
    27  	postroutingchain = "DOCKER_POSTROUTING"
    28  )
    29  
    30  func reexecSetupResolver() {
    31  	runtime.LockOSThread()
    32  	defer runtime.UnlockOSThread()
    33  
    34  	if len(os.Args) < 4 {
    35  		logrus.Error("invalid number of arguments..")
    36  		os.Exit(1)
    37  	}
    38  
    39  	resolverIP, ipPort, _ := net.SplitHostPort(os.Args[2])
    40  	_, tcpPort, _ := net.SplitHostPort(os.Args[3])
    41  	rules := [][]string{
    42  		{"-t", "nat", "-I", outputChain, "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[2]},
    43  		{"-t", "nat", "-I", postroutingchain, "-s", resolverIP, "-p", "udp", "--sport", ipPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
    44  		{"-t", "nat", "-I", outputChain, "-d", resolverIP, "-p", "tcp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[3]},
    45  		{"-t", "nat", "-I", postroutingchain, "-s", resolverIP, "-p", "tcp", "--sport", tcpPort, "-j", "SNAT", "--to-source", ":" + dnsPort},
    46  	}
    47  
    48  	f, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0)
    49  	if err != nil {
    50  		logrus.Errorf("failed get network namespace %q: %v", os.Args[1], err)
    51  		os.Exit(2)
    52  	}
    53  	defer f.Close()
    54  
    55  	nsFD := f.Fd()
    56  	if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
    57  		logrus.Errorf("setting into container net ns %v failed, %v", os.Args[1], err)
    58  		os.Exit(3)
    59  	}
    60  
    61  	// TODO IPv6 support
    62  	iptable := iptables.GetIptable(iptables.IPv4)
    63  
    64  	// insert outputChain and postroutingchain
    65  	err = iptable.RawCombinedOutputNative("-t", "nat", "-C", "OUTPUT", "-d", resolverIP, "-j", outputChain)
    66  	if err == nil {
    67  		iptable.RawCombinedOutputNative("-t", "nat", "-F", outputChain)
    68  	} else {
    69  		iptable.RawCombinedOutputNative("-t", "nat", "-N", outputChain)
    70  		iptable.RawCombinedOutputNative("-t", "nat", "-I", "OUTPUT", "-d", resolverIP, "-j", outputChain)
    71  	}
    72  
    73  	err = iptable.RawCombinedOutputNative("-t", "nat", "-C", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
    74  	if err == nil {
    75  		iptable.RawCombinedOutputNative("-t", "nat", "-F", postroutingchain)
    76  	} else {
    77  		iptable.RawCombinedOutputNative("-t", "nat", "-N", postroutingchain)
    78  		iptable.RawCombinedOutputNative("-t", "nat", "-I", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
    79  	}
    80  
    81  	for _, rule := range rules {
    82  		if iptable.RawCombinedOutputNative(rule...) != nil {
    83  			logrus.Errorf("set up rule failed, %v", rule)
    84  		}
    85  	}
    86  }
    87  
    88  func (r *resolver) setupIPTable() error {
    89  	if r.err != nil {
    90  		return r.err
    91  	}
    92  	laddr := r.conn.LocalAddr().String()
    93  	ltcpaddr := r.tcpListen.Addr().String()
    94  
    95  	cmd := &exec.Cmd{
    96  		Path:   reexec.Self(),
    97  		Args:   append([]string{"setup-resolver"}, r.resolverKey, laddr, ltcpaddr),
    98  		Stdout: os.Stdout,
    99  		Stderr: os.Stderr,
   100  	}
   101  	if err := cmd.Run(); err != nil {
   102  		return fmt.Errorf("reexec failed: %v", err)
   103  	}
   104  	return nil
   105  }