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

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