1// +build !windows
2
3package libnetwork
4
5import (
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
18func init() {
19	reexec.Register("setup-resolver", reexecSetupResolver)
20}
21
22const (
23	// outputChain used for docker embed dns
24	outputChain = "DOCKER_OUTPUT"
25	//postroutingchain used for docker embed dns
26	postroutingchain = "DOCKER_POSTROUTING"
27)
28
29func 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	// insert outputChain and postroutingchain
61	err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "OUTPUT", "-d", resolverIP, "-j", outputChain)
62	if err == nil {
63		iptables.RawCombinedOutputNative("-t", "nat", "-F", outputChain)
64	} else {
65		iptables.RawCombinedOutputNative("-t", "nat", "-N", outputChain)
66		iptables.RawCombinedOutputNative("-t", "nat", "-I", "OUTPUT", "-d", resolverIP, "-j", outputChain)
67	}
68
69	err = iptables.RawCombinedOutputNative("-t", "nat", "-C", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
70	if err == nil {
71		iptables.RawCombinedOutputNative("-t", "nat", "-F", postroutingchain)
72	} else {
73		iptables.RawCombinedOutputNative("-t", "nat", "-N", postroutingchain)
74		iptables.RawCombinedOutputNative("-t", "nat", "-I", "POSTROUTING", "-d", resolverIP, "-j", postroutingchain)
75	}
76
77	for _, rule := range rules {
78		if iptables.RawCombinedOutputNative(rule...) != nil {
79			logrus.Errorf("setting up rule failed, %v", rule)
80		}
81	}
82}
83
84func (r *resolver) setupIPTable() error {
85	if r.err != nil {
86		return r.err
87	}
88	laddr := r.conn.LocalAddr().String()
89	ltcpaddr := r.tcpListen.Addr().String()
90
91	cmd := &exec.Cmd{
92		Path:   reexec.Self(),
93		Args:   append([]string{"setup-resolver"}, r.resolverKey, laddr, ltcpaddr),
94		Stdout: os.Stdout,
95		Stderr: os.Stderr,
96	}
97	if err := cmd.Run(); err != nil {
98		return fmt.Errorf("reexec failed: %v", err)
99	}
100	return nil
101}
102