Переглянути джерело

add support ip masquerade of non-overlay addresses; cleanup

Eugene Yakubovich 10 роки тому
батько
коміт
cd0003665f
15 змінених файлів з 193 додано та 83 видалено
  1. 2 2
      backend/common.go
  2. 15 15
      main.go
  3. 1 1
      pkg/ip/endianess.go
  4. 1 1
      pkg/ip/iface.go
  5. 1 1
      pkg/ip/ipnet.go
  6. 1 1
      pkg/ip/ipnet_test.go
  7. 69 0
      pkg/ip/iptables.go
  8. 1 1
      pkg/ip/tun.go
  9. 7 7
      subnet/config.go
  10. 2 2
      subnet/rand.go
  11. 22 22
      subnet/subnet.go
  12. 3 3
      subnet/subnet_test.go
  13. 3 3
      udp/cproxy.go
  14. 5 5
      udp/proxy.go
  15. 60 19
      udp/run.go

+ 2 - 2
backend/common.go

@@ -1,7 +1,7 @@
 package backend
 
 import (
-	"github.com/coreos-inc/rudder/pkg"
+	"github.com/coreos-inc/rudder/pkg/ip"
 )
 
-type ReadyFunc func(sn pkg.IP4Net, mtu int)
+type ReadyFunc func(sn ip.IP4Net, mtu int)

+ 15 - 15
main.go

@@ -12,7 +12,7 @@ import (
 	"github.com/coreos-inc/rudder/Godeps/_workspace/src/github.com/coreos/go-systemd/daemon"
 	log "github.com/coreos-inc/rudder/Godeps/_workspace/src/github.com/golang/glog"
 
-	"github.com/coreos-inc/rudder/pkg"
+	"github.com/coreos-inc/rudder/pkg/ip"
 	"github.com/coreos-inc/rudder/subnet"
 	"github.com/coreos-inc/rudder/udp"
 )
@@ -26,7 +26,7 @@ type CmdLineOpts struct {
 	etcdPrefix   string
 	help         bool
 	version      bool
-	slowProxy    bool
+	ipMasq       bool
 	port         int
 	subnetFile   string
 	iface        string
@@ -40,12 +40,12 @@ func init() {
 	flag.IntVar(&opts.port, "port", defaultPort, "port to use for inter-node communications")
 	flag.StringVar(&opts.subnetFile, "subnet-file", "/run/rudder/subnet.env", "filename where env variables (subnet and MTU values) will be written to")
 	flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
-	flag.BoolVar(&opts.slowProxy, "no-fast-proxy", false, "disable accelerated proxy")
+	flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
 	flag.BoolVar(&opts.help, "help", false, "print this message")
 	flag.BoolVar(&opts.version, "version", false, "print version and exit")
 }
 
-func writeSubnet(sn pkg.IP4Net, mtu int) error {
+func writeSubnet(sn ip.IP4Net, mtu int) error {
 	// Write out the first usable IP by incrementing
 	// sn.IP by one
 	sn.IP += 1
@@ -66,12 +66,12 @@ func writeSubnet(sn pkg.IP4Net, mtu int) error {
 
 func lookupIface() (*net.Interface, net.IP) {
 	var iface *net.Interface
-	var ip net.IP
+	var tep net.IP
 	var err error
 
 	if len(opts.iface) > 0 {
-		if ip = net.ParseIP(opts.iface); ip != nil {
-			iface, err = pkg.GetInterfaceByIP(ip)
+		if tep = net.ParseIP(opts.iface); tep != nil {
+			iface, err = ip.GetInterfaceByIP(tep)
 			if err != nil {
 				log.Errorf("Error looking up interface %s: %s", opts.iface, err)
 				return nil, nil
@@ -86,7 +86,7 @@ func lookupIface() (*net.Interface, net.IP) {
 	} else {
 		log.Info("Determining IP address of default interface")
 		for {
-			if iface, err = pkg.GetDefaultGatewayIface(); err == nil {
+			if iface, err = ip.GetDefaultGatewayIface(); err == nil {
 				break
 			}
 			log.Error("Failed to get default interface: ", err)
@@ -94,14 +94,14 @@ func lookupIface() (*net.Interface, net.IP) {
 		}
 	}
 
-	if ip == nil {
-		ip, err = pkg.GetIfaceIP4Addr(iface)
+	if tep == nil {
+		tep, err = ip.GetIfaceIP4Addr(iface)
 		if err != nil {
 			log.Error("Failed to find IPv4 address for interface ", iface.Name)
 		}
 	}
 
-	return iface, ip
+	return iface, tep
 }
 
 func makeSubnetManager() *subnet.SubnetManager {
@@ -137,16 +137,16 @@ func main() {
 		os.Exit(0)
 	}
 
-	iface, ip := lookupIface()
-	if iface == nil || ip == nil {
+	iface, tep := lookupIface()
+	if iface == nil || tep == nil {
 		return
 	}
 
-	log.Infof("Using %s to tunnel", ip)
+	log.Infof("Using %s to tunnel", tep)
 
 	sm := makeSubnetManager()
 
-	udp.Run(sm, iface, ip, opts.port, !opts.slowProxy, func(sn pkg.IP4Net, mtu int) {
+	udp.Run(sm, iface, tep, opts.port, opts.ipMasq, func(sn ip.IP4Net, mtu int) {
 		writeSubnet(sn, mtu)
 		daemon.SdNotify("READY=1")
 	})

+ 1 - 1
pkg/endianess.go → pkg/ip/endianess.go

@@ -1,4 +1,4 @@
-package pkg
+package ip
 
 // Taken from a patch by David Anderson who submitted it
 // but got rejected by the golang team

+ 1 - 1
pkg/iface.go → pkg/ip/iface.go

@@ -1,4 +1,4 @@
-package pkg
+package ip
 
 import (
 	"errors"

+ 1 - 1
pkg/ipnet.go → pkg/ip/ipnet.go

@@ -1,4 +1,4 @@
-package pkg
+package ip
 
 import (
 	"bytes"

+ 1 - 1
pkg/ipnet_test.go → pkg/ip/ipnet_test.go

@@ -1,4 +1,4 @@
-package pkg
+package ip
 
 import (
 	"encoding/json"

+ 69 - 0
pkg/ip/iptables.go

@@ -0,0 +1,69 @@
+package ip
+
+import (
+	"os/exec"
+	"syscall"
+)
+
+type IPTables struct {
+	path string
+}
+
+func NewIPTables() (*IPTables, error) {
+	path, err := exec.LookPath("iptables")
+	if err != nil {
+		return nil, err
+	}
+
+	return &IPTables{path}, nil
+}
+
+func (ipt *IPTables) Exists(table string, args... string) (bool, error) {
+	cmd := append([]string{"-t", table, "-C"}, args...)
+	err := exec.Command(ipt.path, cmd...).Run()
+
+	switch {
+	case err == nil:
+		return true, nil
+	case err.(*exec.ExitError).Sys().(syscall.WaitStatus).ExitStatus() == 1:
+		return false, nil
+	default:
+		return false, err
+	}
+}
+
+func (ipt *IPTables) Append(table string, args... string) error {
+	cmd := append([]string{"-t", table, "-A"}, args...)
+	return exec.Command(ipt.path, cmd...).Run()
+}
+
+// AppendUnique acts like Append except that it won't add a duplicate
+func (ipt *IPTables) AppendUnique(table string, args... string) error {
+	exists, err := ipt.Exists(table, args...)
+	if err != nil {
+		return err
+	}
+
+	if !exists {
+		return ipt.Append(table, args...)
+	}
+
+	return nil
+}
+
+func (ipt *IPTables) ClearChain(table, chain string) error {
+	cmd := append([]string{"-t", table, "-N", chain})
+	err := exec.Command(ipt.path, cmd...).Run()
+
+	switch {
+	case err == nil:
+		return nil
+	case err.(*exec.ExitError).Sys().(syscall.WaitStatus).ExitStatus() == 1:
+		// chain already exists. Flush (clear) it.
+		cmd := append([]string{"-t", table, "-F", chain})
+		return exec.Command(ipt.path, cmd...).Run()
+	default:
+		return err
+	}
+}
+

+ 1 - 1
pkg/tun.go → pkg/ip/tun.go

@@ -1,4 +1,4 @@
-package pkg
+package ip
 
 import (
 	"bytes"

+ 7 - 7
subnet/config.go

@@ -4,13 +4,13 @@ import (
 	"encoding/json"
 	"errors"
 
-	"github.com/coreos-inc/rudder/pkg"
+	"github.com/coreos-inc/rudder/pkg/ip"
 )
 
 type Config struct {
-	Network   pkg.IP4Net
-	SubnetMin pkg.IP4
-	SubnetMax pkg.IP4
+	Network   ip.IP4Net
+	SubnetMin ip.IP4
+	SubnetMax ip.IP4
 	SubnetLen uint
 }
 
@@ -35,9 +35,9 @@ func ParseConfig(s string) (*Config, error) {
 		}
 	}
 
-	subnetSize := pkg.IP4(1 << (32 - cfg.SubnetLen))
+	subnetSize := ip.IP4(1 << (32 - cfg.SubnetLen))
 
-	if cfg.SubnetMin == pkg.IP4(0) {
+	if cfg.SubnetMin == ip.IP4(0) {
 		// skip over the first subnet otherwise it causes problems. e.g.
 		// if Network is 10.100.0.0/16, having an interface with 10.0.0.0
 		// makes ping think it's a broadcast address (not sure why)
@@ -46,7 +46,7 @@ func ParseConfig(s string) (*Config, error) {
 		return nil, errors.New("SubnetMin is not in the range of the Network")
 	}
 
-	if cfg.SubnetMax == pkg.IP4(0) {
+	if cfg.SubnetMax == ip.IP4(0) {
 		cfg.SubnetMax = cfg.Network.Next().IP - subnetSize
 	} else if !cfg.Network.Contains(cfg.SubnetMax) {
 		return nil, errors.New("SubnetMax is not in the range of the Network")

+ 2 - 2
pkg/rand.go → subnet/rand.go

@@ -1,4 +1,4 @@
-package pkg
+package subnet
 
 import (
 	"math/rand"
@@ -12,6 +12,6 @@ func init() {
 	rnd = rand.New(rand.NewSource(seed))
 }
 
-func RandInt(lo, hi int) int {
+func randInt(lo, hi int) int {
 	return lo + int(rnd.Int31n(int32(hi-lo)))
 }

+ 22 - 22
subnet/subnet.go

@@ -12,7 +12,7 @@ import (
 	"github.com/coreos-inc/rudder/Godeps/_workspace/src/github.com/coreos/go-etcd/etcd"
 	log "github.com/coreos-inc/rudder/Godeps/_workspace/src/github.com/golang/glog"
 
-	"github.com/coreos-inc/rudder/pkg"
+	"github.com/coreos-inc/rudder/pkg/ip"
 )
 
 const (
@@ -38,7 +38,7 @@ var (
 )
 
 type SubnetLease struct {
-	Network pkg.IP4Net
+	Network ip.IP4Net
 	Data    string
 }
 
@@ -66,12 +66,12 @@ func NewSubnetManager(etcdCli *etcd.Client, prefix string) (*SubnetManager, erro
 	return newSubnetManager(&esr)
 }
 
-func (sm *SubnetManager) AcquireLease(ip pkg.IP4, data string) (pkg.IP4Net, error) {
+func (sm *SubnetManager) AcquireLease(tep ip.IP4, data string) (ip.IP4Net, error) {
 	for i := 0; i < registerRetries; i++ {
 		var err error
 		sm.leases, err = sm.getLeases()
 		if err != nil {
-			return pkg.IP4Net{}, err
+			return ip.IP4Net{}, err
 		}
 
 		// try to reuse a subnet if there's one that match our IP
@@ -81,10 +81,10 @@ func (sm *SubnetManager) AcquireLease(ip pkg.IP4, data string) (pkg.IP4Net, erro
 			if err != nil {
 				log.Error("Error parsing subnet lease JSON: ", err)
 			} else {
-				if ip == ba.PublicIP {
+				if tep == ba.PublicIP {
 					resp, err := sm.registry.updateSubnet(l.Network.StringSep(".", "-"), data, subnetTTL)
 					if err != nil {
-						return pkg.IP4Net{}, nil
+						return ip.IP4Net{}, nil
 					}
 
 					sm.myLease.Network = l.Network
@@ -97,7 +97,7 @@ func (sm *SubnetManager) AcquireLease(ip pkg.IP4, data string) (pkg.IP4Net, erro
 		// no existing match, grab a new one
 		sn, err := sm.allocateSubnet()
 		if err != nil {
-			return pkg.IP4Net{}, err
+			return ip.IP4Net{}, err
 		}
 
 		resp, err := sm.registry.createSubnet(sn.StringSep(".", "-"), data, subnetTTL)
@@ -112,11 +112,11 @@ func (sm *SubnetManager) AcquireLease(ip pkg.IP4, data string) (pkg.IP4Net, erro
 			continue
 
 		default:
-			return pkg.IP4Net{}, err
+			return ip.IP4Net{}, err
 		}
 	}
 
-	return pkg.IP4Net{}, errors.New("Max retries reached trying to acquire a subnet")
+	return ip.IP4Net{}, errors.New("Max retries reached trying to acquire a subnet")
 }
 
 func (sm *SubnetManager) UpdateSubnet(data string) error {
@@ -142,16 +142,16 @@ func (sm *SubnetManager) GetConfig() *Config {
 
 /// Implementation
 
-func parseSubnetKey(s string) (pkg.IP4Net, error) {
+func parseSubnetKey(s string) (ip.IP4Net, error) {
 	if parts := subnetRegex.FindStringSubmatch(s); len(parts) == 3 {
-		ip := net.ParseIP(parts[1]).To4()
+		snIp := net.ParseIP(parts[1]).To4()
 		prefixLen, err := strconv.ParseUint(parts[2], 10, 5)
-		if ip != nil && err == nil {
-			return pkg.IP4Net{pkg.FromIP(ip), uint(prefixLen)}, nil
+		if snIp != nil && err == nil {
+			return ip.IP4Net{ip.FromIP(snIp), uint(prefixLen)}, nil
 		}
 	}
 
-	return pkg.IP4Net{}, errors.New("Error parsing IP Subnet")
+	return ip.IP4Net{}, errors.New("Error parsing IP Subnet")
 }
 
 type subnetRegistry interface {
@@ -274,7 +274,7 @@ func (sm *SubnetManager) applyLeases(newLeases []SubnetLease) EventBatch {
 	return batch
 }
 
-func (sm *SubnetManager) applySubnetChange(action string, ipn pkg.IP4Net, data string) Event {
+func (sm *SubnetManager) applySubnetChange(action string, ipn ip.IP4Net, data string) Event {
 	switch action {
 	case "delete", "expire":
 		for i, l := range sm.leases {
@@ -304,14 +304,14 @@ func (sm *SubnetManager) applySubnetChange(action string, ipn pkg.IP4Net, data s
 }
 
 type BaseAttrs struct {
-	PublicIP pkg.IP4
+	PublicIP ip.IP4
 }
 
-func (sm *SubnetManager) allocateSubnet() (pkg.IP4Net, error) {
+func (sm *SubnetManager) allocateSubnet() (ip.IP4Net, error) {
 	log.Infof("Picking subnet in range %s ... %s", sm.config.SubnetMin, sm.config.SubnetMax)
 
-	var bag []pkg.IP4
-	sn := pkg.IP4Net{sm.config.SubnetMin, sm.config.SubnetLen}
+	var bag []ip.IP4
+	sn := ip.IP4Net{sm.config.SubnetMin, sm.config.SubnetLen}
 
 OuterLoop:
 	for ; sn.IP <= sm.config.SubnetMax && len(bag) < 100; sn = sn.Next() {
@@ -324,10 +324,10 @@ OuterLoop:
 	}
 
 	if len(bag) == 0 {
-		return pkg.IP4Net{}, errors.New("out of subnets")
+		return ip.IP4Net{}, errors.New("out of subnets")
 	} else {
-		i := pkg.RandInt(0, len(bag))
-		return pkg.IP4Net{bag[i], sm.config.SubnetLen}, nil
+		i := randInt(0, len(bag))
+		return ip.IP4Net{bag[i], sm.config.SubnetLen}, nil
 	}
 }
 

+ 3 - 3
subnet/subnet_test.go

@@ -7,7 +7,7 @@ import (
 
 	"github.com/coreos-inc/rudder/Godeps/_workspace/src/github.com/coreos/go-etcd/etcd"
 
-	"github.com/coreos-inc/rudder/pkg"
+	"github.com/coreos-inc/rudder/pkg/ip"
 )
 
 type mockSubnetRegistry struct {
@@ -151,7 +151,7 @@ func TestAcquireLease(t *testing.T) {
 		t.Fatalf("Failed to create subnet manager: %s", err)
 	}
 
-	ip, _ := pkg.ParseIP4("1.2.3.4")
+	ip, _ := ip.ParseIP4("1.2.3.4")
 	data := `{ "PublicIP": "1.2.3.4" }`
 
 	sn, err := sm.AcquireLease(ip, data)
@@ -252,7 +252,7 @@ func TestRenewLease(t *testing.T) {
 		t.Fatalf("Failed to create subnet manager: %s", err)
 	}
 
-	ip, _ := pkg.ParseIP4("1.2.3.4")
+	ip, _ := ip.ParseIP4("1.2.3.4")
 	data := `{ "PublicIP": "1.2.3.4" }`
 
 	sn, err := sm.AcquireLease(ip, data)

+ 3 - 3
udp/cproxy.go

@@ -13,11 +13,11 @@ import (
 
 	log "github.com/coreos-inc/rudder/Godeps/_workspace/src/github.com/golang/glog"
 
-	"github.com/coreos-inc/rudder/pkg"
+	"github.com/coreos-inc/rudder/pkg/ip"
 	"github.com/coreos-inc/rudder/subnet"
 )
 
-func runCProxy(tun *os.File, conn *os.File, ctl *os.File, tunIP pkg.IP4, tunMTU uint) {
+func runCProxy(tun *os.File, conn *os.File, ctl *os.File, tunIP ip.IP4, tunMTU uint) {
 	var log_errors int
 	if log.V(1) {
 		log_errors = 1
@@ -55,7 +55,7 @@ func newCtlSockets() (*os.File, *os.File, error) {
 	return f1, f2, nil
 }
 
-func fastProxy(sm *subnet.SubnetManager, tun *os.File, conn *net.UDPConn, tunIP pkg.IP4, tunMTU uint, port int) {
+func fastProxy(sm *subnet.SubnetManager, tun *os.File, conn *net.UDPConn, tunIP ip.IP4, tunMTU uint, port int) {
 	log.Info("Running fast proxy loop")
 
 	c, err := conn.File()

+ 5 - 5
udp/proxy.go

@@ -8,7 +8,7 @@ import (
 
 	log "github.com/coreos-inc/rudder/Godeps/_workspace/src/github.com/golang/glog"
 
-	"github.com/coreos-inc/rudder/pkg"
+	"github.com/coreos-inc/rudder/pkg/ip"
 	"github.com/coreos-inc/rudder/subnet"
 )
 
@@ -17,7 +17,7 @@ const (
 )
 
 type routeEntry struct {
-	sn   pkg.IP4Net
+	sn   ip.IP4Net
 	addr *net.UDPAddr
 }
 
@@ -33,7 +33,7 @@ func NewRouter(port int) *Router {
 	}
 }
 
-func (r *Router) SetRoute(sn pkg.IP4Net, dst pkg.IP4) {
+func (r *Router) SetRoute(sn ip.IP4Net, dst ip.IP4) {
 	r.mux.Lock()
 	defer r.mux.Unlock()
 
@@ -58,7 +58,7 @@ func (r *Router) SetRoute(sn pkg.IP4Net, dst pkg.IP4) {
 	r.routes = append(r.routes, re)
 }
 
-func (r *Router) DelRoute(sn pkg.IP4Net) {
+func (r *Router) DelRoute(sn ip.IP4Net) {
 	r.mux.Lock()
 	defer r.mux.Unlock()
 
@@ -80,7 +80,7 @@ func (r *Router) routePacket(pkt []byte, conn *net.UDPConn) {
 	r.mux.Lock()
 	defer r.mux.Unlock()
 
-	dstIP := pkg.FromBytes(pkt[16:20])
+	dstIP := ip.FromBytes(pkt[16:20])
 
 	for i, re := range r.routes {
 		if re.sn.Contains(dstIP) {

+ 60 - 19
udp/run.go

@@ -3,6 +3,7 @@ package udp
 import (
 	"encoding/json"
 	"net"
+	"strings"
 	"syscall"
 	"time"
 
@@ -10,7 +11,7 @@ import (
 	log "github.com/coreos-inc/rudder/Godeps/_workspace/src/github.com/golang/glog"
 
 	"github.com/coreos-inc/rudder/backend"
-	"github.com/coreos-inc/rudder/pkg"
+	"github.com/coreos-inc/rudder/pkg/ip"
 	"github.com/coreos-inc/rudder/subnet"
 )
 
@@ -18,7 +19,7 @@ const (
 	encapOverhead = 28 // 20 bytes IP hdr + 8 bytes UDP hdr
 )
 
-func configureIface(ifname string, ipn pkg.IP4Net, mtu int) error {
+func configureIface(ifname string, ipn ip.IP4Net, mtu int) error {
 	iface, err := net.InterfaceByName(ifname)
 	if err != nil {
 		log.Error("Failed to lookup interface ", ifname)
@@ -55,16 +56,53 @@ func configureIface(ifname string, ipn pkg.IP4Net, mtu int) error {
 	return nil
 }
 
-func acquireLease(sm *subnet.SubnetManager, pubIP net.IP) (pkg.IP4Net, error) {
+func setupIpMasq(ipn ip.IP4Net, iface string) error {
+	ipt, err := ip.NewIPTables()
+	if err != nil {
+		log.Error("Failed to setup IP Masquerade. iptables was not found")
+		return err
+	}
+
+	err = ipt.ClearChain("nat", "RUDDER")
+	if err != nil {
+		log.Error("Failed to create/clear RUDDER chain in NAT table: ", err)
+		return err
+	}
+
+	rules := [][]string{
+		// This rule makes sure we don't NAT traffic within overlay network (e.g. coming out of docker0)
+		[]string{ "RUDDER", "-d", ipn.String(), "-j", "ACCEPT" },
+		// This rule makes sure we don't NAT multicast traffic within overlay network
+		[]string{ "RUDDER", "-d", "224.0.0.0/4", "-j", "ACCEPT" },
+		// This rule will NAT everything originating from our overlay network and 
+		[]string{ "RUDDER", "!", "-o", iface, "-j", "MASQUERADE" },
+		// This rule will take everything coming from overlay and sent it to RUDDER chain
+		[]string{ "POSTROUTING", "-s", ipn.String(), "-j", "RUDDER" },
+	}
+
+	for _, args := range rules {
+		log.Info("Adding iptables rule: ", strings.Join(args, " "))
+
+		err = ipt.AppendUnique("nat", args...)
+		if err != nil {
+			log.Error("Failed to insert IP masquerade rule: ", err)
+			return err
+		}
+	}
+
+	return nil
+}
+
+func acquireLease(sm *subnet.SubnetManager, pubIP net.IP) (ip.IP4Net, error) {
 	attrs := subnet.BaseAttrs{
-		PublicIP: pkg.FromIP(pubIP),
+		PublicIP: ip.FromIP(pubIP),
 	}
 	data, err := json.Marshal(&attrs)
 	if err != nil {
-		return pkg.IP4Net{}, err
+		return ip.IP4Net{}, err
 	}
 
-	var sn pkg.IP4Net
+	var sn ip.IP4Net
 	for {
 		sn, err = sm.AcquireLease(attrs.PublicIP, string(data))
 		if err == nil {
@@ -78,14 +116,14 @@ func acquireLease(sm *subnet.SubnetManager, pubIP net.IP) (pkg.IP4Net, error) {
 	return sn, nil
 }
 
-func Run(sm *subnet.SubnetManager, iface *net.Interface, ip net.IP, port int, fast bool, ready backend.ReadyFunc) {
-	sn, err := acquireLease(sm, ip)
+func Run(sm *subnet.SubnetManager, tepIface *net.Interface, tepIP net.IP, port int, ipMasq bool, ready backend.ReadyFunc) {
+	sn, err := acquireLease(sm, tepIP)
 	if err != nil {
 		log.Error("Failed to acquire lease: ", err)
 		return
 	}
 
-	tun, tunName, err := pkg.OpenTun("rudder%d")
+	tun, tunName, err := ip.OpenTun("rudder%d")
 	if err != nil {
 		log.Error("Failed to open TUN device: ", err)
 		return
@@ -103,32 +141,35 @@ func Run(sm *subnet.SubnetManager, iface *net.Interface, ip net.IP, port int, fa
 
 	// Interface's subnet is that of the whole overlay network (e.g. /16)
 	// and not that of the individual host (e.g. /24)
-	ipn := pkg.IP4Net{
+	tunNet := ip.IP4Net{
 		IP:        sn.IP,
 		PrefixLen: sm.GetConfig().Network.PrefixLen,
 	}
 
 	// TUN MTU will be smaller b/c of encap (IP+UDP hdrs)
 	var mtu int
-	if iface.MTU > 0 {
-		mtu = iface.MTU - encapOverhead
+	if tepIface.MTU > 0 {
+		mtu = tepIface.MTU - encapOverhead
 	} else {
-		log.Errorf("Failed to determine MTU for %s interface", ip)
+		log.Errorf("Failed to determine MTU for %s interface", tepIP)
 		return
 	}
 
-	err = configureIface(tunName, ipn, mtu)
+	err = configureIface(tunName, tunNet, mtu)
 	if err != nil {
 		return
 	}
 
+	if ipMasq {
+		err = setupIpMasq(tunNet.Network(), tunName)
+		if err != nil {
+			return
+		}
+	}
+
 	// all initialized and ready for business
 	log.Info("UDP encapsulation initialized")
 	ready(sn, mtu)
 
-	if fast {
-		fastProxy(sm, tun, conn, ipn.IP, uint(mtu), port)
-	} else {
-		proxy(sm, tun, conn, uint(mtu), port)
-	}
+	fastProxy(sm, tun, conn, tunNet.IP, uint(mtu), port)
 }