Merge pull request #1288 from balena-io/add-established-iptables-rule

Add an ESTABLISHED flag to API iptables rules
This commit is contained in:
CameronDiver 2020-05-05 12:23:52 +01:00 committed by GitHub
commit 2186097a63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 75 deletions

View File

@ -42,20 +42,19 @@ export function rejectOnAllInterfacesExcept(
): Bluebird<void> { ): Bluebird<void> {
// We delete each rule and create it again to ensure ordering (all ACCEPTs before the REJECT/DROP). // We delete each rule and create it again to ensure ordering (all ACCEPTs before the REJECT/DROP).
// This is especially important after a supervisor update. // This is especially important after a supervisor update.
return ( return Bluebird.each(allowedInterfaces, iface =>
Bluebird.each(allowedInterfaces, iface => clearAndInsertIptablesRule(
clearAndInsertIptablesRule( `INPUT -p tcp --dport ${port} -i ${iface} -j ACCEPT`,
`INPUT -p tcp --dport ${port} -i ${iface} -j ACCEPT`, ),
)
.then(() =>
clearAndAppendIptablesRule(
`OUTPUT -p tcp --sport ${port} -m state --state ESTABLISHED -j ACCEPT`,
), ),
) )
.then(() => .then(() =>
clearAndAppendIptablesRule(`INPUT -p tcp --dport ${port} -j REJECT`), clearAndAppendIptablesRule(`INPUT -p tcp --dport ${port} -j REJECT`),
) );
// On systems without REJECT support, fall back to DROP
.catch(() =>
clearAndAppendIptablesRule(`INPUT -p tcp --dport ${port} -j DROP`),
)
);
} }
export function removeRejections(port: number): Bluebird<void> { export function removeRejections(port: number): Bluebird<void> {

View File

@ -8,56 +8,6 @@ describe('iptables', async () => {
it('calls iptables to delete and recreate rules to block a port', async () => { it('calls iptables to delete and recreate rules to block a port', async () => {
stub(iptables, 'execAsync').returns(Bluebird.resolve('')); 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).to.be.calledWith(
'iptables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -I INPUT -p tcp --dport 42 -i foo -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -D INPUT -p tcp --dport 42 -i bar -j ACCEPT',
);
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 INPUT -p tcp --dport 42 -j REJECT',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -A INPUT -p tcp --dport 42 -j REJECT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -I INPUT -p tcp --dport 42 -i foo -j ACCEPT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D INPUT -p tcp --dport 42 -i bar -j ACCEPT',
);
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 INPUT -p tcp --dport 42 -j REJECT',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -A INPUT -p tcp --dport 42 -j REJECT',
);
(iptables.execAsync as sinon.SinonStub).restore();
});
it("falls back to blocking the port with DROP if there's no REJECT support", async () => {
stub(iptables, 'execAsync').callsFake(cmd => {
if (/REJECT$/.test(cmd)) {
return Bluebird.reject(new Error());
} else {
return Bluebird.resolve('');
}
});
await iptables.rejectOnAllInterfacesExcept(['foo', 'bar'], 42); 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(16);
expect(iptables.execAsync).to.be.calledWith( expect(iptables.execAsync).to.be.calledWith(
@ -72,18 +22,18 @@ describe('iptables', async () => {
expect(iptables.execAsync).to.be.calledWith( expect(iptables.execAsync).to.be.calledWith(
'iptables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT', '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( expect(iptables.execAsync).to.be.calledWith(
'iptables -D INPUT -p tcp --dport 42 -j REJECT', 'iptables -D INPUT -p tcp --dport 42 -j REJECT',
); );
expect(iptables.execAsync).to.be.calledWith( expect(iptables.execAsync).to.be.calledWith(
'iptables -A INPUT -p tcp --dport 42 -j REJECT', 'iptables -A INPUT -p tcp --dport 42 -j REJECT',
); );
expect(iptables.execAsync).to.be.calledWith(
'iptables -D INPUT -p tcp --dport 42 -j DROP',
);
expect(iptables.execAsync).to.be.calledWith(
'iptables -A INPUT -p tcp --dport 42 -j DROP',
);
expect(iptables.execAsync).to.be.calledWith( expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT', 'ip6tables -D INPUT -p tcp --dport 42 -i foo -j ACCEPT',
); );
@ -96,19 +46,18 @@ describe('iptables', async () => {
expect(iptables.execAsync).to.be.calledWith( expect(iptables.execAsync).to.be.calledWith(
'ip6tables -I INPUT -p tcp --dport 42 -i bar -j ACCEPT', '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( expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D INPUT -p tcp --dport 42 -j REJECT', 'ip6tables -D INPUT -p tcp --dport 42 -j REJECT',
); );
expect(iptables.execAsync).to.be.calledWith( expect(iptables.execAsync).to.be.calledWith(
'ip6tables -A INPUT -p tcp --dport 42 -j REJECT', 'ip6tables -A INPUT -p tcp --dport 42 -j REJECT',
); );
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -D INPUT -p tcp --dport 42 -j DROP',
);
expect(iptables.execAsync).to.be.calledWith(
'ip6tables -A INPUT -p tcp --dport 42 -j DROP',
);
(iptables.execAsync as sinon.SinonStub).restore(); (iptables.execAsync as sinon.SinonStub).restore();
}); });
}); });