Browse Source

Merge pull request #1399 from Exchizz/feature/disable-nat-for-egress-gw

Add field to /api/nodes/wg-net/<network id>/creategateway for enabling/disabling NAT
dcarns 3 years ago
parent
commit
4bc8afd731
5 changed files with 89 additions and 45 deletions
  1. 34 0
      controllers/node_test.go
  2. 6 5
      go.mod
  3. 13 6
      logic/gateway.go
  4. 35 34
      models/node.go
  5. 1 0
      models/structs.go

+ 34 - 0
controllers/node_test.go

@@ -33,7 +33,39 @@ func TestCreateEgressGateway(t *testing.T) {
 		assert.Equal(t, models.Node{}, node)
 		assert.Equal(t, models.Node{}, node)
 		assert.EqualError(t, err, "windows is unsupported for egress gateways")
 		assert.EqualError(t, err, "windows is unsupported for egress gateways")
 	})
 	})
+	t.Run("Success-Nat-Enabled", func(t *testing.T) {
+		deleteAllNodes()
+		testnode := createTestNode()
+		gateway.NodeID = testnode.ID
+		gateway.NatEnabled = "yes"
+
+		node, err := logic.CreateEgressGateway(gateway)
+		t.Log(node.EgressGatewayNatEnabled)
+		t.Log(node.PostUp)
+		t.Log(node.PostDown)
+		assert.Nil(t, err)
+		assert.Contains(t, node.PostUp, "-j MASQUERADE")
+		assert.Contains(t, node.PostDown, "-j MASQUERADE")
+	})
+	t.Run("Success-Nat-Disabled", func(t *testing.T) {
+		deleteAllNodes()
+		testnode := createTestNode()
+		gateway.NodeID = testnode.ID
+		gateway.NatEnabled = "no"
+
+		node, err := logic.CreateEgressGateway(gateway)
+		t.Log(node.EgressGatewayNatEnabled)
+		t.Log(node.PostUp)
+		t.Log(node.PostDown)
+		assert.Nil(t, err)
+		assert.NotContains(t, node.PostUp, "-j MASUERADE")
+		assert.NotContains(t, node.PostDown, "-j MASUERADE")
+	})
 	t.Run("Success", func(t *testing.T) {
 	t.Run("Success", func(t *testing.T) {
+		var gateway models.EgressGatewayRequest
+		gateway.Interface = "eth0"
+		gateway.Ranges = []string{"10.100.100.0/24"}
+		gateway.NetID = "skynet"
 		deleteAllNodes()
 		deleteAllNodes()
 		testnode := createTestNode()
 		testnode := createTestNode()
 		gateway.NodeID = testnode.ID
 		gateway.NodeID = testnode.ID
@@ -41,6 +73,8 @@ func TestCreateEgressGateway(t *testing.T) {
 		node, err := logic.CreateEgressGateway(gateway)
 		node, err := logic.CreateEgressGateway(gateway)
 		t.Log(node)
 		t.Log(node)
 		assert.Nil(t, err)
 		assert.Nil(t, err)
+		assert.Contains(t, node.PostUp, "-j MASQUERADE")
+		assert.Contains(t, node.PostDown, "-j MASQUERADE")
 		assert.Equal(t, "yes", node.IsEgressGateway)
 		assert.Equal(t, "yes", node.IsEgressGateway)
 		assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges)
 		assert.Equal(t, gateway.Ranges, node.EgressGatewayRanges)
 	})
 	})

+ 6 - 5
go.mod

@@ -6,7 +6,6 @@ require (
 	github.com/eclipse/paho.mqtt.golang v1.4.1
 	github.com/eclipse/paho.mqtt.golang v1.4.1
 	github.com/go-playground/validator/v10 v10.11.0
 	github.com/go-playground/validator/v10 v10.11.0
 	github.com/golang-jwt/jwt/v4 v4.4.2
 	github.com/golang-jwt/jwt/v4 v4.4.2
-	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/google/uuid v1.3.0
 	github.com/google/uuid v1.3.0
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/handlers v1.5.1
 	github.com/gorilla/mux v1.8.0
 	github.com/gorilla/mux v1.8.0
@@ -18,10 +17,7 @@ require (
 	github.com/txn2/txeh v1.3.0
 	github.com/txn2/txeh v1.3.0
 	github.com/urfave/cli/v2 v2.10.3
 	github.com/urfave/cli/v2 v2.10.3
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
 	golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
-	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
 	golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
 	golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
-	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
-	golang.org/x/text v0.3.7 // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20220318042302-193cf8d6a5d6 // indirect
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220324164955-056925b7df31
 	google.golang.org/protobuf v1.28.0 // indirect
 	google.golang.org/protobuf v1.28.0 // indirect
@@ -39,11 +35,12 @@ require (
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 	github.com/posthog/posthog-go v0.0.0-20211028072449-93c17c49e2b0
 )
 )
 
 
+require github.com/coreos/go-oidc/v3 v3.2.0
+
 require (
 require (
 	cloud.google.com/go v0.81.0 // indirect
 	cloud.google.com/go v0.81.0 // indirect
 	fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 // indirect
 	fyne.io/systray v1.10.1-0.20220621085403-9a2652634e93 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
-	github.com/coreos/go-oidc/v3 v3.2.0
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/docker/distribution v2.7.1+incompatible // indirect
 	github.com/docker/distribution v2.7.1+incompatible // indirect
@@ -63,6 +60,7 @@ require (
 	github.com/godbus/dbus/v5 v5.1.0 // indirect
 	github.com/godbus/dbus/v5 v5.1.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
 	github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect
+	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/google/go-cmp v0.5.7 // indirect
 	github.com/google/go-cmp v0.5.7 // indirect
 	github.com/gopherjs/gopherjs v1.17.2 // indirect
 	github.com/gopherjs/gopherjs v1.17.2 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
 	github.com/gorilla/websocket v1.4.2 // indirect
@@ -88,7 +86,10 @@ require (
 	github.com/yuin/goldmark v1.4.0 // indirect
 	github.com/yuin/goldmark v1.4.0 // indirect
 	golang.org/x/image v0.0.0-20220601225756-64ec528b34cd // indirect
 	golang.org/x/image v0.0.0-20220601225756-64ec528b34cd // indirect
 	golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee // indirect
 	golang.org/x/mobile v0.0.0-20211207041440-4e6c2922fdee // indirect
+	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
+	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
+	golang.org/x/text v0.3.7 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
 	gopkg.in/square/go-jose.v2 v2.5.1 // indirect
 	gopkg.in/square/go-jose.v2 v2.5.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect

+ 13 - 6
logic/gateway.go

@@ -20,21 +20,28 @@ func CreateEgressGateway(gateway models.EgressGatewayRequest) (models.Node, erro
 	if node.OS != "linux" && node.OS != "freebsd" { // add in darwin later
 	if node.OS != "linux" && node.OS != "freebsd" { // add in darwin later
 		return models.Node{}, errors.New(node.OS + " is unsupported for egress gateways")
 		return models.Node{}, errors.New(node.OS + " is unsupported for egress gateways")
 	}
 	}
+	if gateway.NatEnabled == "" {
+		gateway.NatEnabled = "yes"
+	}
 	err = ValidateEgressGateway(gateway)
 	err = ValidateEgressGateway(gateway)
 	if err != nil {
 	if err != nil {
 		return models.Node{}, err
 		return models.Node{}, err
 	}
 	}
 	node.IsEgressGateway = "yes"
 	node.IsEgressGateway = "yes"
 	node.EgressGatewayRanges = gateway.Ranges
 	node.EgressGatewayRanges = gateway.Ranges
+	node.EgressGatewayNatEnabled = gateway.NatEnabled
 	postUpCmd := ""
 	postUpCmd := ""
 	postDownCmd := ""
 	postDownCmd := ""
 	if node.OS == "linux" {
 	if node.OS == "linux" {
-		postUpCmd = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT ; "
-		postUpCmd += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT ; "
-		postUpCmd += "iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
-		postDownCmd = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT ; "
-		postDownCmd += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT ; "
-		postDownCmd += "iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+		postUpCmd = "iptables -A FORWARD -i " + node.Interface + " -j ACCEPT; "
+		postUpCmd += "iptables -A FORWARD -o " + node.Interface + " -j ACCEPT"
+		postDownCmd = "iptables -D FORWARD -i " + node.Interface + " -j ACCEPT; "
+		postDownCmd += "iptables -D FORWARD -o " + node.Interface + " -j ACCEPT"
+
+		if node.EgressGatewayNatEnabled == "yes" {
+			postUpCmd += "; iptables -t nat -A POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+			postDownCmd += "; iptables -t nat -D POSTROUTING -o " + gateway.Interface + " -j MASQUERADE"
+		}
 	}
 	}
 	if node.OS == "freebsd" {
 	if node.OS == "freebsd" {
 		postUpCmd = "kldload ipfw ipfw_nat ; "
 		postUpCmd = "kldload ipfw ipfw_nat ; "

+ 35 - 34
models/node.go

@@ -35,40 +35,41 @@ var seededRand *rand.Rand = rand.New(
 
 
 // Node - struct for node model
 // Node - struct for node model
 type Node struct {
 type Node struct {
-	ID                  string   `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5" validate:"id_unique`
-	Address             string   `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
-	Address6            string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
-	LocalAddress        string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
-	Name                string   `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
-	NetworkSettings     Network  `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
-	ListenPort          int32    `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
-	LocalListenPort     int32    `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" validate:"numeric,min=0,max=65535"`
-	PublicKey           string   `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
-	Endpoint            string   `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
-	PostUp              string   `json:"postup" bson:"postup" yaml:"postup"`
-	PostDown            string   `json:"postdown" bson:"postdown" yaml:"postdown"`
-	AllowedIPs          []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
-	PersistentKeepalive int32    `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
-	IsHub               string   `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
-	AccessKey           string   `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
-	Interface           string   `json:"interface" bson:"interface" yaml:"interface"`
-	LastModified        int64    `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
-	ExpirationDateTime  int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
-	LastPeerUpdate      int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
-	LastCheckIn         int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
-	MacAddress          string   `json:"macaddress" bson:"macaddress" yaml:"macaddress"`
-	Password            string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
-	Network             string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
-	IsRelayed           string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
-	IsPending           string   `json:"ispending" bson:"ispending" yaml:"ispending"`
-	IsRelay             string   `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
-	IsDocker            string   `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
-	IsK8S               string   `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
-	IsEgressGateway     string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
-	IsIngressGateway    string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
-	EgressGatewayRanges []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
-	RelayAddrs          []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
-	IngressGatewayRange string   `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
+	ID                      string   `json:"id,omitempty" bson:"id,omitempty" yaml:"id,omitempty" validate:"required,min=5" validate:"id_unique`
+	Address                 string   `json:"address" bson:"address" yaml:"address" validate:"omitempty,ipv4"`
+	Address6                string   `json:"address6" bson:"address6" yaml:"address6" validate:"omitempty,ipv6"`
+	LocalAddress            string   `json:"localaddress" bson:"localaddress" yaml:"localaddress" validate:"omitempty,ip"`
+	Name                    string   `json:"name" bson:"name" yaml:"name" validate:"omitempty,max=62,in_charset"`
+	NetworkSettings         Network  `json:"networksettings" bson:"networksettings" yaml:"networksettings" validate:"-"`
+	ListenPort              int32    `json:"listenport" bson:"listenport" yaml:"listenport" validate:"omitempty,numeric,min=1024,max=65535"`
+	LocalListenPort         int32    `json:"locallistenport" bson:"locallistenport" yaml:"locallistenport" validate:"numeric,min=0,max=65535"`
+	PublicKey               string   `json:"publickey" bson:"publickey" yaml:"publickey" validate:"required,base64"`
+	Endpoint                string   `json:"endpoint" bson:"endpoint" yaml:"endpoint" validate:"required,ip"`
+	PostUp                  string   `json:"postup" bson:"postup" yaml:"postup"`
+	PostDown                string   `json:"postdown" bson:"postdown" yaml:"postdown"`
+	AllowedIPs              []string `json:"allowedips" bson:"allowedips" yaml:"allowedips"`
+	PersistentKeepalive     int32    `json:"persistentkeepalive" bson:"persistentkeepalive" yaml:"persistentkeepalive" validate:"omitempty,numeric,max=1000"`
+	IsHub                   string   `json:"ishub" bson:"ishub" yaml:"ishub" validate:"checkyesorno"`
+	AccessKey               string   `json:"accesskey" bson:"accesskey" yaml:"accesskey"`
+	Interface               string   `json:"interface" bson:"interface" yaml:"interface"`
+	LastModified            int64    `json:"lastmodified" bson:"lastmodified" yaml:"lastmodified"`
+	ExpirationDateTime      int64    `json:"expdatetime" bson:"expdatetime" yaml:"expdatetime"`
+	LastPeerUpdate          int64    `json:"lastpeerupdate" bson:"lastpeerupdate" yaml:"lastpeerupdate"`
+	LastCheckIn             int64    `json:"lastcheckin" bson:"lastcheckin" yaml:"lastcheckin"`
+	MacAddress              string   `json:"macaddress" bson:"macaddress" yaml:"macaddress"`
+	Password                string   `json:"password" bson:"password" yaml:"password" validate:"required,min=6"`
+	Network                 string   `json:"network" bson:"network" yaml:"network" validate:"network_exists"`
+	IsRelayed               string   `json:"isrelayed" bson:"isrelayed" yaml:"isrelayed"`
+	IsPending               string   `json:"ispending" bson:"ispending" yaml:"ispending"`
+	IsRelay                 string   `json:"isrelay" bson:"isrelay" yaml:"isrelay" validate:"checkyesorno"`
+	IsDocker                string   `json:"isdocker" bson:"isdocker" yaml:"isdocker" validate:"checkyesorno"`
+	IsK8S                   string   `json:"isk8s" bson:"isk8s" yaml:"isk8s" validate:"checkyesorno"`
+	IsEgressGateway         string   `json:"isegressgateway" bson:"isegressgateway" yaml:"isegressgateway"`
+	IsIngressGateway        string   `json:"isingressgateway" bson:"isingressgateway" yaml:"isingressgateway"`
+	EgressGatewayRanges     []string `json:"egressgatewayranges" bson:"egressgatewayranges" yaml:"egressgatewayranges"`
+	EgressGatewayNatEnabled string   `json:"egressgatewaynatenabled" bson:"egressgatewaynatenabled" yaml:"egressgatewaynatenabled"`
+	RelayAddrs              []string `json:"relayaddrs" bson:"relayaddrs" yaml:"relayaddrs"`
+	IngressGatewayRange     string   `json:"ingressgatewayrange" bson:"ingressgatewayrange" yaml:"ingressgatewayrange"`
 	// IsStatic - refers to if the Endpoint is set manually or dynamically
 	// IsStatic - refers to if the Endpoint is set manually or dynamically
 	IsStatic     string      `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
 	IsStatic     string      `json:"isstatic" bson:"isstatic" yaml:"isstatic" validate:"checkyesorno"`
 	UDPHolePunch string      `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`
 	UDPHolePunch string      `json:"udpholepunch" bson:"udpholepunch" yaml:"udpholepunch" validate:"checkyesorno"`

+ 1 - 0
models/structs.go

@@ -149,6 +149,7 @@ type EgressGatewayRequest struct {
 	NodeID      string   `json:"nodeid" bson:"nodeid"`
 	NodeID      string   `json:"nodeid" bson:"nodeid"`
 	NetID       string   `json:"netid" bson:"netid"`
 	NetID       string   `json:"netid" bson:"netid"`
 	RangeString string   `json:"rangestring" bson:"rangestring"`
 	RangeString string   `json:"rangestring" bson:"rangestring"`
+	NatEnabled  string   `json:"natenabled" bson:"natenabled"`
 	Ranges      []string `json:"ranges" bson:"ranges"`
 	Ranges      []string `json:"ranges" bson:"ranges"`
 	Interface   string   `json:"interface" bson:"interface"`
 	Interface   string   `json:"interface" bson:"interface"`
 	PostUp      string   `json:"postup" bson:"postup"`
 	PostUp      string   `json:"postup" bson:"postup"`