From 361b4f7f4f48fc399da149ffc2bf4b8d5e76c074 Mon Sep 17 00:00:00 2001
From: Adrien Raffin-Caboisse <adrien.raffin@sekoia.fr>
Date: Tue, 1 Mar 2022 22:43:25 +0100
Subject: [PATCH] fix(machine): allow to use * in ACL sources

---
 machine.go      |  20 ++++-
 machine_test.go | 205 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 223 insertions(+), 2 deletions(-)

diff --git a/machine.go b/machine.go
index 3106d0b..479380a 100644
--- a/machine.go
+++ b/machine.go
@@ -173,6 +173,12 @@ func getFilteredByACLPeers(
 				machine.IPAddresses.ToStringSlice(),
 				peer.IPAddresses.ToStringSlice(),
 			) || // match source and destination
+				matchSourceAndDestinationWithRule(
+					rule.SrcIPs,
+					dst,
+					peer.IPAddresses.ToStringSlice(),
+					machine.IPAddresses.ToStringSlice(),
+				) || // match return path
 				matchSourceAndDestinationWithRule(
 					rule.SrcIPs,
 					dst,
@@ -182,9 +188,21 @@ func getFilteredByACLPeers(
 				matchSourceAndDestinationWithRule(
 					rule.SrcIPs,
 					dst,
+					[]string{"*"},
+					[]string{"*"},
+				) || // match source and all destination
+				matchSourceAndDestinationWithRule(
+					rule.SrcIPs,
+					dst,
+					[]string{"*"},
 					peer.IPAddresses.ToStringSlice(),
+				) || // match source and all destination
+				matchSourceAndDestinationWithRule(
+					rule.SrcIPs,
+					dst,
+					[]string{"*"},
 					machine.IPAddresses.ToStringSlice(),
-				) { // match return path
+				) { // match all sources and source
 				peers[peer.ID] = peer
 			}
 		}
diff --git a/machine_test.go b/machine_test.go
index e9c91f8..ed95aaf 100644
--- a/machine_test.go
+++ b/machine_test.go
@@ -296,6 +296,7 @@ func (s *Suite) TestSerdeAddressStrignSlice(c *check.C) {
 	}
 }
 
+// nolint
 func Test_getFilteredByACLPeers(t *testing.T) {
 	type args struct {
 		machines []Machine
@@ -443,7 +444,7 @@ func Test_getFilteredByACLPeers(t *testing.T) {
 					},
 				},
 				machine: &Machine{ // current machine
-					ID:          1,
+					ID:          2,
 					IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")},
 					Namespace:   Namespace{Name: "marc"},
 				},
@@ -456,6 +457,208 @@ func Test_getFilteredByACLPeers(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "rules allows all hosts to reach one destination",
+			args: args{
+				machines: []Machine{ // list of all machines in the database
+					{
+						ID: 1,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.1"),
+						},
+						Namespace: Namespace{Name: "joe"},
+					},
+					{
+						ID: 2,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.2"),
+						},
+						Namespace: Namespace{Name: "marc"},
+					},
+					{
+						ID: 3,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.3"),
+						},
+						Namespace: Namespace{Name: "mickael"},
+					},
+				},
+				rules: []tailcfg.FilterRule{ // list of all ACLRules registered
+					{
+						SrcIPs: []string{"*"},
+						DstPorts: []tailcfg.NetPortRange{
+							{IP: "100.64.0.2"},
+						},
+					},
+				},
+				machine: &Machine{ // current machine
+					ID: 1,
+					IPAddresses: MachineAddresses{
+						netaddr.MustParseIP("100.64.0.1"),
+					},
+					Namespace: Namespace{Name: "joe"},
+				},
+			},
+			want: Machines{
+				{
+					ID: 2,
+					IPAddresses: MachineAddresses{
+						netaddr.MustParseIP("100.64.0.2"),
+					},
+					Namespace: Namespace{Name: "marc"},
+				},
+			},
+		},
+		{
+			name: "rules allows all hosts to reach one destination, destination can reach all hosts",
+			args: args{
+				machines: []Machine{ // list of all machines in the database
+					{
+						ID: 1,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.1"),
+						},
+						Namespace: Namespace{Name: "joe"},
+					},
+					{
+						ID: 2,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.2"),
+						},
+						Namespace: Namespace{Name: "marc"},
+					},
+					{
+						ID: 3,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.3"),
+						},
+						Namespace: Namespace{Name: "mickael"},
+					},
+				},
+				rules: []tailcfg.FilterRule{ // list of all ACLRules registered
+					{
+						SrcIPs: []string{"*"},
+						DstPorts: []tailcfg.NetPortRange{
+							{IP: "100.64.0.2"},
+						},
+					},
+				},
+				machine: &Machine{ // current machine
+					ID: 2,
+					IPAddresses: MachineAddresses{
+						netaddr.MustParseIP("100.64.0.2"),
+					},
+					Namespace: Namespace{Name: "marc"},
+				},
+			},
+			want: Machines{
+				{
+					ID: 1,
+					IPAddresses: MachineAddresses{
+						netaddr.MustParseIP("100.64.0.1"),
+					},
+					Namespace: Namespace{Name: "joe"},
+				},
+				{
+					ID: 3,
+					IPAddresses: MachineAddresses{
+						netaddr.MustParseIP("100.64.0.3"),
+					},
+					Namespace: Namespace{Name: "mickael"},
+				},
+			},
+		},
+		{
+			name: "rule allows all hosts to reach all destinations",
+			args: args{
+				machines: []Machine{ // list of all machines in the database
+					{
+						ID: 1,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.1"),
+						},
+						Namespace: Namespace{Name: "joe"},
+					},
+					{
+						ID: 2,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.2"),
+						},
+						Namespace: Namespace{Name: "marc"},
+					},
+					{
+						ID: 3,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.3"),
+						},
+						Namespace: Namespace{Name: "mickael"},
+					},
+				},
+				rules: []tailcfg.FilterRule{ // list of all ACLRules registered
+					{
+						SrcIPs: []string{"*"},
+						DstPorts: []tailcfg.NetPortRange{
+							{IP: "*"},
+						},
+					},
+				},
+				machine: &Machine{ // current machine
+					ID:          2,
+					IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")},
+					Namespace:   Namespace{Name: "marc"},
+				},
+			},
+			want: Machines{
+				{
+					ID: 1,
+					IPAddresses: MachineAddresses{
+						netaddr.MustParseIP("100.64.0.1"),
+					},
+					Namespace: Namespace{Name: "joe"},
+				},
+				{
+					ID:          3,
+					IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.3")},
+					Namespace:   Namespace{Name: "mickael"},
+				},
+			},
+		},
+		{
+			name: "without rule all communications are forbidden",
+			args: args{
+				machines: []Machine{ // list of all machines in the database
+					{
+						ID: 1,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.1"),
+						},
+						Namespace: Namespace{Name: "joe"},
+					},
+					{
+						ID: 2,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.2"),
+						},
+						Namespace: Namespace{Name: "marc"},
+					},
+					{
+						ID: 3,
+						IPAddresses: MachineAddresses{
+							netaddr.MustParseIP("100.64.0.3"),
+						},
+						Namespace: Namespace{Name: "mickael"},
+					},
+				},
+				rules: []tailcfg.FilterRule{ // list of all ACLRules registered
+				},
+				machine: &Machine{ // current machine
+					ID:          2,
+					IPAddresses: MachineAddresses{netaddr.MustParseIP("100.64.0.2")},
+					Namespace:   Namespace{Name: "marc"},
+				},
+			},
+			want: Machines{},
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {