From ddef81d88c257fb34cdc869efbdced1fc503ce3b Mon Sep 17 00:00:00 2001 From: Santhosh Manohar Date: Wed, 13 Apr 2016 01:28:18 -0700 Subject: [PATCH] Move the iptables setup for embedded DNS into a reexec process Signed-off-by: Santhosh Manohar --- resolver.go | 23 +++----------- resolver_unix.go | 77 +++++++++++++++++++++++++++++++++++++++++++++ resolver_windows.go | 7 +++++ 3 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 resolver_unix.go create mode 100644 resolver_windows.go diff --git a/resolver.go b/resolver.go index d4dec8e4..becee883 100644 --- a/resolver.go +++ b/resolver.go @@ -9,7 +9,6 @@ import ( "time" log "github.com/Sirupsen/logrus" - "github.com/docker/libnetwork/iptables" "github.com/docker/libnetwork/types" "github.com/miekg/dns" ) @@ -105,8 +104,6 @@ func (r *resolver) SetupFunc() func() { r.err = fmt.Errorf("error in opening name server socket %v", err) return } - laddr := r.conn.LocalAddr() - _, ipPort, _ := net.SplitHostPort(laddr.String()) // Listen on a TCP as well tcpaddr := &net.TCPAddr{ @@ -118,21 +115,6 @@ func (r *resolver) SetupFunc() func() { r.err = fmt.Errorf("error in opening name TCP server socket %v", err) return } - ltcpaddr := r.tcpListen.Addr() - _, tcpPort, _ := net.SplitHostPort(ltcpaddr.String()) - rules := [][]string{ - {"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", laddr.String()}, - {"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "udp", "--sport", ipPort, "-j", "SNAT", "--to-source", ":" + dnsPort}, - {"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "tcp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", ltcpaddr.String()}, - {"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "tcp", "--sport", tcpPort, "-j", "SNAT", "--to-source", ":" + dnsPort}, - } - - for _, rule := range rules { - r.err = iptables.RawCombinedOutputNative(rule...) - if r.err != nil { - return - } - } r.err = nil }) } @@ -142,6 +124,11 @@ func (r *resolver) Start() error { if r.err != nil { return r.err } + + if err := r.setupIPTable(); err != nil { + return fmt.Errorf("setting up IP table rules failed: %v", err) + } + s := &dns.Server{Handler: r, PacketConn: r.conn} r.server = s go func() { diff --git a/resolver_unix.go b/resolver_unix.go new file mode 100644 index 00000000..2b3734fb --- /dev/null +++ b/resolver_unix.go @@ -0,0 +1,77 @@ +// +build !windows + +package libnetwork + +import ( + "fmt" + "net" + "os" + "os/exec" + "runtime" + + log "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/reexec" + "github.com/docker/libnetwork/iptables" + "github.com/vishvananda/netns" +) + +func init() { + reexec.Register("setup-resolver", reexecSetupResolver) +} + +func reexecSetupResolver() { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + if len(os.Args) < 4 { + log.Error("invalid number of arguments..") + os.Exit(1) + } + + _, ipPort, _ := net.SplitHostPort(os.Args[2]) + _, tcpPort, _ := net.SplitHostPort(os.Args[3]) + rules := [][]string{ + {"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "udp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[2]}, + {"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "udp", "--sport", ipPort, "-j", "SNAT", "--to-source", ":" + dnsPort}, + {"-t", "nat", "-A", "OUTPUT", "-d", resolverIP, "-p", "tcp", "--dport", dnsPort, "-j", "DNAT", "--to-destination", os.Args[3]}, + {"-t", "nat", "-A", "POSTROUTING", "-s", resolverIP, "-p", "tcp", "--sport", tcpPort, "-j", "SNAT", "--to-source", ":" + dnsPort}, + } + + f, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0) + if err != nil { + log.Errorf("failed get network namespace %q: %v", os.Args[1], err) + os.Exit(2) + } + defer f.Close() + + nsFD := f.Fd() + if err = netns.Set(netns.NsHandle(nsFD)); err != nil { + log.Errorf("setting into container net ns %v failed, %v", os.Args[1], err) + os.Exit(3) + } + + for _, rule := range rules { + if iptables.RawCombinedOutputNative(rule...) != nil { + log.Errorf("setting up rule failed, %v", rule) + } + } +} + +func (r *resolver) setupIPTable() error { + if r.err != nil { + return r.err + } + laddr := r.conn.LocalAddr().String() + ltcpaddr := r.tcpListen.Addr().String() + + cmd := &exec.Cmd{ + Path: reexec.Self(), + Args: append([]string{"setup-resolver"}, r.sb.Key(), laddr, ltcpaddr), + Stdout: os.Stdout, + Stderr: os.Stderr, + } + if err := cmd.Run(); err != nil { + return fmt.Errorf("reexec failed: %v", err) + } + return nil +} diff --git a/resolver_windows.go b/resolver_windows.go new file mode 100644 index 00000000..aa33b1a2 --- /dev/null +++ b/resolver_windows.go @@ -0,0 +1,7 @@ +// +build windows + +package libnetwork + +func (r *resolver) setupIPTable() error { + return nil +}