mecano
Version:
Common functions for system deployment.
335 lines (304 loc) • 16.6 kB
text/coffeescript
iptables = require "../src/misc/iptables"
test = require './test'
they = require 'ssh2-they'
fs = require 'ssh2-fs'
describe 'misc iptables', ->
describe 'normalize', ->
it 'normalize with shortcut for protocol', ->
iptables.normalize([ # Nothing to do
{ chain: 'INPUT', jump: 'ACCEPT', dport: 22, '-p': 'tcp' }
]).should.eql [
{ chain: 'INPUT', '--jump': 'ACCEPT', '--protocol': 'tcp', 'tcp|--dport': '22', 'after': {'-A': 'INPUT', '--jump': 'ACCEPT', 'chain': 'INPUT'} }
]
it 'normalize with full name for protocol', ->
iptables.normalize([
{ chain: 'INPUT', jump: 'ACCEPT', dport: 22, protocol: 'tcp' }
]).should.eql [
{ chain: 'INPUT', '--jump': 'ACCEPT', '--protocol': 'tcp', 'tcp|--dport': '22', 'after': {'-A': 'INPUT', '--jump': 'ACCEPT', 'chain': 'INPUT'} }
]
it 'normalize with full name for in-interface', ->
iptables.normalize([
{ chain: 'INPUT', jump: 'ACCEPT', 'in-interface': 'lo' }
]).should.eql [
{ chain: 'INPUT', '--jump': 'ACCEPT', '--in-interface': 'lo', 'after': {'-A': 'INPUT', '--jump': 'ACCEPT', 'chain': 'INPUT'} }
]
it 'normalize with full option for protocol', ->
iptables.normalize([
{ chain: 'INPUT', jump: 'ACCEPT', dport: 22, '--protocol': 'tcp' }
]).should.eql [
{ chain: 'INPUT', '--jump': 'ACCEPT', '--protocol': 'tcp', 'tcp|--dport': '22', 'after': {'-A': 'INPUT', '--jump': 'ACCEPT', 'chain': 'INPUT'} }
]
it 'normalize with full name without its module prefix (see state and comment)', ->
iptables.normalize([
{ chain: 'INPUT', jump: 'ACCEPT', dport: 88, '-p': 'udp', state: 'NEW', comment: 'krb5kdc daemon' }
]).should.eql [
{ chain: 'INPUT', '--jump': 'ACCEPT', '--protocol': 'udp', 'udp|--dport': '88', 'state|--state': 'NEW', 'comment|--comment': '"krb5kdc daemon"', 'after': {'-A': 'INPUT', '--jump': 'ACCEPT', 'chain': 'INPUT'} }
]
it 'normalize with full option without its module prefix (comment)', ->
iptables.normalize([
{ chain: 'INPUT', jump: 'ACCEPT', dport: 88, '-p': 'tcp', '--comment': 'My comment' }
]).should.eql [
{ chain: 'INPUT', '--jump': 'ACCEPT', '--protocol': 'tcp', 'tcp|--dport': '88', 'comment|--comment': '"My comment"', 'after': {'-A': 'INPUT', '--jump': 'ACCEPT', 'chain': 'INPUT'} }
]
it 'preserve input', ->
rules = [{ chain: 'INPUT', jump: 'ACCEPT', source: "10.10.10.0/24", comment: 'Local Network' }]
JSON.stringify(iptables.normalize rules).should.eql JSON.stringify(iptables.normalize rules)
it 'preserve command', ->
iptables.normalize([
{ chain: 'INPUT', command: '-A', jump: 'LOGGING' }
]).should.eql [
{ chain: 'INPUT', command: '-A', '--jump': 'LOGGING' }
]
it 'discard default log-level value', ->
iptables.normalize([
{ chain: 'LOGGING', command: '-A', '--limit': '2/min', jump: 'LOG', 'log-level': 4 }
]).should.eql [
{chain: 'LOGGING', command: '-A', 'limit|--limit': '2/min', '--jump': 'LOG' }
]
describe 'parse', ->
it 'parse', ->
iptables.parse("""
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 88 -m state --state NEW -m comment --comment "krb5kdc daemon" -j ACCEPT
-A INPUT -p udp -m udp --dport 88 -m state --state NEW -m comment --comment "krb5kdc daemon" -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
""").should.eql [
{ '-P': 'INPUT ACCEPT', command: '-P', chain: 'INPUT', target: 'ACCEPT' }
{ '-P': 'FORWARD ACCEPT', command: '-P', chain: 'FORWARD', target: 'ACCEPT' }
{ '-P': 'OUTPUT ACCEPT', command: '-P', chain: 'OUTPUT', target: 'ACCEPT' }
{ rulenum: 1, '-A': 'INPUT', command: '-A', chain: 'INPUT', 'state|--state': 'RELATED,ESTABLISHED', '--jump': 'ACCEPT' }
{ rulenum: 2, '-A': 'INPUT', command: '-A', chain: 'INPUT', '--protocol': 'icmp', '--jump': 'ACCEPT' }
{ rulenum: 3, '-A': 'INPUT', command: '-A', chain: 'INPUT', '--in-interface': 'lo', '--jump': 'ACCEPT' }
{ rulenum: 4, '-A': 'INPUT', command: '-A', chain: 'INPUT', '--protocol': 'tcp', 'tcp|--dport': '88', 'state|--state': 'NEW', 'comment|--comment': '"krb5kdc daemon"', '--jump': 'ACCEPT' }
{ rulenum: 5, '-A': 'INPUT', command: '-A', chain: 'INPUT', '--protocol': 'udp', 'udp|--dport': '88', 'state|--state': 'NEW', 'comment|--comment': '"krb5kdc daemon"', '--jump': 'ACCEPT' }
{ rulenum: 6, '-A': 'INPUT', command: '-A', chain: 'INPUT', '--protocol': 'tcp', 'state|--state': 'NEW', 'tcp|--dport': '22', '--jump': 'ACCEPT' }
{ rulenum: 7, '-A': 'INPUT', command: '-A', chain: 'INPUT', '--jump': 'REJECT', '--reject-with': 'icmp-host-prohibited' }
{ rulenum: 1, '-A': 'FORWARD', command: '-A', chain: 'FORWARD', '--jump': 'REJECT', '--reject-with': 'icmp-host-prohibited' }
]
it 'parse empty lines', ->
iptables.parse('\n-P INPUT ACCEPT\n').should.eql [ { '-P': 'INPUT ACCEPT', command: '-P', chain: 'INPUT', target: 'ACCEPT' } ]
it 'parse new chain (N)', ->
iptables.parse("""
-N LOGGING
""").should.eql [
{ '-N': 'LOGGING', command: '-N', chain: 'LOGGING' }
]
it 'parse logs', -> # --log-tcp-sequence --log-tcp-options --log-ip-options --log-uid
iptables.parse("""
-A LOGGING -j LOG --log-level 5 --log-prefix "IPTables-Dropped: "
""").should.eql [
{ rulenum: 1, '-A': 'LOGGING', command: '-A', chain: 'LOGGING', '--jump': 'LOG', '--log-level': '5', '--log-prefix': '"IPTables-Dropped: "' }
]
describe 'cmd', ->
it 'see change in protocol', ->
iptables.cmd([
{ rulenum: 5, '-A': 'INPUT', chain: 'INPUT', '--in-interface': 'eth1', '--protocol': 'tcp', 'tcp|--dport': '88', '-j': 'ACCEPT' }
], [
{ chain: 'INPUT', '-j': 'ACCEPT', '--in-interface': 'eth0', '--protocol': 'tcp', 'tcp|--dport': '88' }
]).should.eql [
"iptables -I INPUT 1 -j ACCEPT --in-interface eth0 --protocol tcp -m tcp --dport 88"
]
it 'see change in comment', ->
iptables.cmd([
{ rulenum: 5, '-A': 'INPUT', chain: 'INPUT', '--in-interface': 'eth1', 'comment|--comment': '"kadmin daemon"', '-j': 'ACCEPT' }
], [
{ chain: 'INPUT', '-j': 'ACCEPT', '--in-interface': 'eth1', 'comment|--comment': '"krb5kdc daemon"' }
]).should.eql [
"iptables -R INPUT 5 --in-interface eth1 -m comment --comment \"krb5kdc daemon\" -j ACCEPT"
]
it 'respect chain', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-N LOGGING
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j LOGGING
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 7
-A LOGGING -j DROP
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'LOGGING', command: '-A', '--limit': '2/min', jump: 'LOG', 'log-prefix': 'IPTables-Dropped: ', 'log-level': 5 }
]).should.eql [
'iptables -R LOGGING 1 -m limit --limit 2/min --jump LOG --log-prefix "IPTables-Dropped: " --log-level 5'
]
it 'parse and detect a change', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 88 -m state --state NEW -m comment --comment "krb5kdc daemon" -j ACCEPT
-A INPUT -p udp -m udp --dport 88 -m state --state NEW -m comment --comment "krb5kdc daemon" -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
"""
iptables.cmd(oldrules, iptables.normalize [
# Removing state
chain: 'INPUT', jump: 'ACCEPT', dport: 88, '-p': 'tcp', '--comment': 'krb5kdc daemon'
]).should.eql [ 'iptables -R INPUT 4 --protocol tcp -m tcp --dport 88 -m state --state NEW -m comment --comment "krb5kdc daemon" --jump ACCEPT' ]
it 'compare minus sign (IPTable silently remove minus sign)', ->
oldrules = iptables.parse """
-A INPUT -p tcp -m tcp --dport 389 -m state --state NEW -m comment --comment "LDAP (non-secured)" -j ACCEPT
-A INPUT -p tcp -m tcp --dport 636 -m state --state NEW -m comment --comment "LDAP (secured)" -j ACCEPT
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', jump: 'ACCEPT', dport: 389, protocol: 'tcp', state: 'NEW', comment: "LDAP (non-secured)" }
{ chain: 'INPUT', jump: 'ACCEPT', dport: 636, protocol: 'tcp', state: 'NEW', comment: "LDAP (secured)" }
]).should.eql []
it 'compare comment without any special char', ->
oldrules = iptables.parse """
-A INPUT -p udp -m udp --dport 53 -m state --state NEW -m comment --comment "Named" -j ACCEPT
-A INPUT -p tcp -m tcp --dport 53 -m state --state NEW -m comment --comment "Named" -j ACCEPT
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', jump: 'ACCEPT', dport: 53, protocol: 'tcp', state: 'NEW', comment: "Named" }
{ chain: 'INPUT', jump: 'ACCEPT', dport: 53, protocol: 'udp', state: 'NEW', comment: "Named" }
]).should.eql []
it 'create new chain (N)', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', command: '-A', jump: 'LOGGING' }
{ chain: 'LOGGING', command: '-A', '--limit': '2/min', jump: 'LOG', 'log-prefix': 'IPTables-Dropped: ', 'log-level': 5 }
{ chain: 'LOGGING', command: '-A', jump: 'DROP' }
]).should.eql [
'iptables -N LOGGING'
'iptables -A INPUT --jump LOGGING'
'iptables -A LOGGING --jump LOG --log-prefix "IPTables-Dropped: " --log-level 5 -m limit --limit 2/min'
'iptables -A LOGGING --jump DROP'
]
it 'discard existing rune in new chain (N)', ->
oldrules = iptables.parse """
-N LOGGING
-A INPUT -j LOGGING
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
-A LOGGING -m limit --limit 2/min -j LOG --log-level 5 --log-prefix "IPTables-Dropped: "
-A LOGGING -j DROP
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', command: '-A', jump: 'LOGGING' }
{ chain: 'LOGGING', command: '-A', '--limit': '2/min', jump: 'LOG', 'log-prefix': 'IPTables-Dropped: ', 'log-level': 5 }
{ chain: 'LOGGING', command: '-A', jump: 'DROP' }
]).should.eql []
describe 'position', ->
it 'default after "-i lo -j ACCEPT"', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', jump: 'ACCEPT', source: "10.10.10.0/24", comment: 'Local Network' }
]).should.eql ['iptables -I INPUT 5 --jump ACCEPT --source 10.10.10.0/24 -m comment --comment "Local Network"']
it 'after insert new rule', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', jump: 'ACCEPT', source: "10.10.10.0/24", comment: 'Local Network', after: {'in-interface': 'lo', jump: 'ACCEPT' } }
]).should.eql ['iptables -I INPUT 4 --jump ACCEPT --source 10.10.10.0/24 -m comment --comment "Local Network"']
it 'after shouldnt move when already after', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -s 10.10.10.0/24 -m comment --comment "Local Network" -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', jump: 'ACCEPT', source: "10.10.10.0/24", comment: 'Local Network', after: {'in-interface': 'lo', jump: 'ACCEPT' } }
]).should.eql []
it 'after insert and modify', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
"""
iptables.cmd(oldrules, iptables.normalize [
# Removing state
{chain: 'INPUT', jump: 'ACCEPT', dport: '22', '-p': 'tcp', '--comment': 'SSH'}
{chain: 'INPUT', jump: 'ACCEPT', dport: '88', '-p': 'tcp', '--comment': 'krb5kdc daemon'}
]).should.eql [
'iptables -R INPUT 4 --protocol tcp -m tcp --dport 22 --jump ACCEPT -m comment --comment "SSH"'
'iptables -I INPUT 5 --jump ACCEPT --protocol tcp -m tcp --dport 88 -m comment --comment "krb5kdc daemon"'
]
it 'before insert new rule', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', jump: 'ACCEPT', source: "10.10.10.0/24", comment: 'Local Network', before: {'in-interface': 'lo', jump: 'ACCEPT' } }
]).should.eql ['iptables -I INPUT 3 --jump ACCEPT --source 10.10.10.0/24 -m comment --comment "Local Network"']
it 'before shouldnt move when already before', ->
oldrules = iptables.parse """
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -s 10.10.10.0/24 -m comment --comment "Local Network" -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
"""
iptables.cmd(oldrules, iptables.normalize [
{ chain: 'INPUT', jump: 'ACCEPT', source: "10.10.10.0/24", comment: 'Local Network', before: {'in-interface': 'lo', jump: 'ACCEPT' } }
]).should.eql []