github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/firewall/outgoing_firewall_iptables_test.go (about) 1 /* 2 * Copyright (C) 2019 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package firewall 19 20 import ( 21 "testing" 22 23 "github.com/mysteriumnetwork/node/firewall/iptables" 24 "github.com/stretchr/testify/assert" 25 ) 26 27 func Test_outgoingFirewallIptables_BlocksAllOutgoingTraffic(t *testing.T) { 28 mockedExec := iptablesExecMock{ 29 mocks: map[string]iptablesExecResult{}, 30 } 31 iptables.Exec = mockedExec.Exec 32 33 fw := &outgoingFirewallIptables{ 34 referenceTracker: make(map[string]refCount), 35 } 36 37 removeRuleFunc, err := fw.BlockOutgoingTraffic("test-scope", "1.1.1.1") 38 assert.NoError(t, err) 39 assert.True(t, mockedExec.VerifyCalledWithArgs("-A", "OUTPUT", "-s", "1.1.1.1", "-j", killswitchChain)) 40 41 removeRuleFunc() 42 assert.True(t, mockedExec.VerifyCalledWithArgs("-D", "OUTPUT", "-s", "1.1.1.1", "-j", killswitchChain)) 43 } 44 45 func Test_outgoingFirewallIptables_SessionTrafficBlockIsNoopWhenGlobalBlockWasCalled(t *testing.T) { 46 mockedExec := iptablesExecMock{ 47 mocks: map[string]iptablesExecResult{}, 48 } 49 iptables.Exec = mockedExec.Exec 50 51 fw := &outgoingFirewallIptables{ 52 referenceTracker: make(map[string]refCount), 53 } 54 55 removeGlobalBlock, err := fw.BlockOutgoingTraffic(Global, "1.1.1.1") 56 assert.NoError(t, err) 57 assert.Equal(t, 1, fw.referenceTracker["block-traffic"].count) 58 assert.True(t, mockedExec.VerifyCalledWithArgs("-A", "OUTPUT", "-s", "1.1.1.1", "-j", killswitchChain)) 59 60 removeSessionRule, _ := fw.BlockOutgoingTraffic(Session, "1.1.1.1") 61 assert.Equal(t, 1, fw.referenceTracker["block-traffic"].count) 62 63 removeSessionRule() 64 assert.Equal(t, 1, fw.referenceTracker["block-traffic"].count) 65 66 removeGlobalBlock() 67 assert.Equal(t, 0, fw.referenceTracker["block-traffic"].count) 68 } 69 70 func Test_outgoingFirewallIptables_AllowIPAccessIsAddedAndRemoved(t *testing.T) { 71 fw := &outgoingFirewallIptables{ 72 referenceTracker: make(map[string]refCount), 73 } 74 75 removeRule, _ := fw.AllowIPAccess("test-ip") 76 assert.Equal(t, 1, fw.referenceTracker["allow:test-ip"].count) 77 removeRule() 78 assert.Equal(t, 0, fw.referenceTracker["allow:test-ip"].count) 79 } 80 81 func Test_outgoingFirewallIptables_HostsFromMultipleURLsAreAllowed(t *testing.T) { 82 fw := &outgoingFirewallIptables{ 83 referenceTracker: make(map[string]refCount), 84 } 85 86 removeRules, _ := fw.AllowURLAccess("http://url1", "my-schema://url2:500/ignoredpath?ignoredQuery=true") 87 assert.Equal(t, 1, fw.referenceTracker["allow:url1"].count) 88 assert.Equal(t, 1, fw.referenceTracker["allow:url2"].count) 89 removeRules() 90 assert.Equal(t, 0, fw.referenceTracker["allow:url1"].count) 91 assert.Equal(t, 0, fw.referenceTracker["allow:url2"].count) 92 } 93 94 func Test_outgoingFirewallIptables_RuleIsRemovedOnlyAfterLastRemovalCall(t *testing.T) { 95 fw := &outgoingFirewallIptables{ 96 referenceTracker: make(map[string]refCount), 97 } 98 99 //two independent allow requests for the same service 100 removalRequest1, _ := fw.AllowIPAccess("service") 101 removalRequest2, _ := fw.AllowIPAccess("service") 102 //make sure allow ip was called once 103 assert.Equal(t, 1, fw.referenceTracker["allow:service"].count) 104 //first removal should have no effect 105 removalRequest1() 106 assert.Equal(t, 0, fw.referenceTracker["allow:service"].count) 107 //second removal removes added rule 108 removalRequest2() 109 assert.Equal(t, 0, fw.referenceTracker["allow:service"].count) 110 } 111 112 func Test_outgoingFirewallIptables_SetupIsSuccessful(t *testing.T) { 113 mockedExec := iptablesExecMock{ 114 mocks: map[string]iptablesExecResult{ 115 "--version": { 116 output: []string{"iptables v1.6.0"}, 117 }, 118 "-S OUTPUT": { 119 output: []string{ 120 "-P OUTPUT ACCEPT", 121 }, 122 }, 123 }, 124 } 125 iptables.Exec = mockedExec.Exec 126 127 fw := &outgoingFirewallIptables{ 128 referenceTracker: make(map[string]refCount), 129 } 130 assert.NoError(t, fw.Setup()) 131 assert.True(t, mockedExec.VerifyCalledWithArgs("-N", killswitchChain)) 132 assert.True(t, mockedExec.VerifyCalledWithArgs("-A", killswitchChain, "-m", "conntrack", "--ctstate", "NEW", "-j", "REJECT")) 133 } 134 135 func Test_outgoingFirewallIptables_SetupIsSucessfulIfPreviousCleanupFailed(t *testing.T) { 136 mockedExec := iptablesExecMock{ 137 mocks: map[string]iptablesExecResult{ 138 "--version": { 139 output: []string{"iptables v1.6.0"}, 140 }, 141 "-S OUTPUT": { 142 output: []string{ 143 "-P OUTPUT ACCEPT", 144 // leftover - kill switch is still enabled 145 "-A OUTPUT -s 5.5.5.5 -j MYST_CONSUMER_KILL_SWITCH", 146 }, 147 }, 148 // kill switch chain still exists 149 "-S MYST_CONSUMER_KILL_SWITCH": { 150 output: []string{ 151 // with some allowed ips 152 "-A MYST_CONSUMER_KILL_SWITCH -d 2.2.2.2 -j ACCEPT", 153 "-A MYST_CONSUMER_KILL_SWITCH -j REJECT", 154 }, 155 }, 156 }, 157 } 158 iptables.Exec = mockedExec.Exec 159 160 fw := &outgoingFirewallIptables{ 161 referenceTracker: make(map[string]refCount), 162 } 163 assert.NoError(t, fw.Setup()) 164 assert.True(t, mockedExec.VerifyCalledWithArgs("-D", "OUTPUT", "-s", "5.5.5.5", "-j", killswitchChain)) 165 assert.True(t, mockedExec.VerifyCalledWithArgs("-F", killswitchChain)) 166 assert.True(t, mockedExec.VerifyCalledWithArgs("-X", killswitchChain)) 167 assert.True(t, mockedExec.VerifyCalledWithArgs("-N", killswitchChain)) 168 assert.True(t, mockedExec.VerifyCalledWithArgs("-A", killswitchChain, "-m", "conntrack", "--ctstate", "NEW", "-j", "REJECT")) 169 170 } 171 172 func Test_outgoingFirewallIptables_ResetIsSuccessful(t *testing.T) { 173 mockedExec := iptablesExecMock{ 174 mocks: map[string]iptablesExecResult{ 175 "-S OUTPUT": { 176 output: []string{ 177 "-P OUTPUT ACCEPT", 178 // kill switch is enabled 179 "-A OUTPUT -s 1.1.1.1 -j MYST_CONSUMER_KILL_SWITCH", 180 }, 181 }, 182 "-S MYST_CONSUMER_KILL_SWITCH": { 183 output: []string{ 184 //first allowed address 185 "-A MYST_CONSUMER_KILL_SWITCH -d 2.2.2.2 -j ACCEPT", 186 //second allowed address 187 "-A MYST_CONSUMER_KILL_SWITCH -d 3.3.3.3 -j ACCEPT", 188 //drop everything else 189 "-A MYST_CONSUMER_KILL_SWITCH -j REJECT", 190 }, 191 }, 192 }, 193 } 194 iptables.Exec = mockedExec.Exec 195 196 fw := &outgoingFirewallIptables{ 197 referenceTracker: make(map[string]refCount), 198 } 199 fw.Teardown() 200 assert.True(t, mockedExec.VerifyCalledWithArgs("-D", "OUTPUT", "-s", "1.1.1.1", "-j", killswitchChain)) 201 assert.True(t, mockedExec.VerifyCalledWithArgs("-F", killswitchChain)) 202 assert.True(t, mockedExec.VerifyCalledWithArgs("-X", killswitchChain)) 203 } 204 205 func Test_outgoingFirewallIptables_AddsAllowedIP(t *testing.T) { 206 mockedExec := iptablesExecMock{ 207 mocks: map[string]iptablesExecResult{}, 208 } 209 iptables.Exec = mockedExec.Exec 210 211 fw := &outgoingFirewallIptables{ 212 referenceTracker: make(map[string]refCount), 213 } 214 215 removeRuleFunc, err := fw.AllowIPAccess("2.2.2.2") 216 assert.NoError(t, err) 217 assert.True(t, mockedExec.VerifyCalledWithArgs("-I", killswitchChain, "1", "-d", "2.2.2.2", "-j", "ACCEPT")) 218 219 removeRuleFunc() 220 assert.True(t, mockedExec.VerifyCalledWithArgs("-D", killswitchChain, "-d", "2.2.2.2", "-j", "ACCEPT")) 221 222 }