Add an ESTABLISHED flag to API iptables rules

This allows a response to an input with dport=`supevisor api port` and
is required when the host OS is doing stateful firewalling.

This should not affect things when stateful firewalling is not in
effect, as the standard OUTPUT chain policy is ACCEPT, so we're just
being explicit about it.

Change-type: patch
Backport-to: next, current, sunset
Signed-off-by: Cameron Diver <cameron@balena.io>
This commit is contained in:
Cameron Diver 2020-05-05 10:42:06 +01:00
parent d78d9712fe
commit 7b1f03ced5
2 changed files with 31 additions and 2 deletions

View File

@ -48,6 +48,11 @@ export function rejectOnAllInterfacesExcept(
`INPUT -p tcp --dport ${port} -i ${iface} -j ACCEPT`,
),
)
.then(() =>
clearAndAppendIptablesRule(
`OUTPUT -p tcp --sport ${port} -m state --state ESTABLISHED -j ACCEPT`,
),
)
.then(() =>
clearAndAppendIptablesRule(`INPUT -p tcp --dport ${port} -j REJECT`),
)

View File

@ -9,7 +9,7 @@ describe('iptables', async () => {
stub(iptables, 'execAsync').returns(Bluebird.resolve(''));
await iptables.rejectOnAllInterfacesExcept(['foo', 'bar'], 42);
expect((iptables.execAsync as sinon.SinonStub).callCount).to.equal(12);
expect((iptables.execAsync as sinon.SinonStub).callCount).to.equal(16);
expect(iptables.execAsync).to.be.calledWith(
'iptables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT',
);
@ -22,6 +22,12 @@ describe('iptables', async () => {
expect(iptables.execAsync).to.be.calledWith(
'iptables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -D OUTPUT -p tcp --sport 42 -m state --state ESTABLISHED -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -A OUTPUT -p tcp --sport 42 -m state --state ESTABLISHED -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -D INPUT -p tcp --dport 42 -j REJECT',
);
@ -40,6 +46,12 @@ describe('iptables', async () => {
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D OUTPUT -p tcp --sport 42 -m state --state ESTABLISHED -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -A OUTPUT -p tcp --sport 42 -m state --state ESTABLISHED -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D INPUT -p tcp --dport 42 -j REJECT',
);
@ -59,7 +71,7 @@ describe('iptables', async () => {
});
await iptables.rejectOnAllInterfacesExcept(['foo', 'bar'], 42);
expect((iptables.execAsync as sinon.SinonStub).callCount).to.equal(16);
expect((iptables.execAsync as sinon.SinonStub).callCount).to.equal(20);
expect(iptables.execAsync).to.be.calledWith(
'iptables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT',
);
@ -72,6 +84,12 @@ describe('iptables', async () => {
expect(iptables.execAsync).to.be.calledWith(
'iptables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -D OUTPUT -p tcp --sport 42 -m state --state ESTABLISHED -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -A OUTPUT -p tcp --sport 42 -m state --state ESTABLISHED -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -D INPUT -p tcp --dport 42 -j REJECT',
);
@ -96,6 +114,12 @@ describe('iptables', async () => {
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D OUTPUT -p tcp --sport 42 -m state --state ESTABLISHED -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -A OUTPUT -p tcp --sport 42 -m state --state ESTABLISHED -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D INPUT -p tcp --dport 42 -j REJECT',
);