From a2d5d31e8d0cec0e700d6a95e3b912e607bbf84f Mon Sep 17 00:00:00 2001 From: Adrian Likins Date: Fri, 28 Mar 2008 15:29:10 -0400 Subject: add iptables module from Krzysztof A. Adamski add some basic test cases to the unittests (needs expanded) add file info to setup.py add Makefiles to minion/modules/netapp/* and minion/modules/iptables/* to make make clean work --- func/minion/modules/Makefile | 2 +- func/minion/modules/iptables/Makefile | 17 ++++ func/minion/modules/iptables/__init__.py | 149 +++++++++++++++++++++++++++++++ func/minion/modules/iptables/common.py | 56 ++++++++++++ func/minion/modules/iptables/port.py | 137 ++++++++++++++++++++++++++++ func/minion/modules/netapp/Makefile | 17 ++++ 6 files changed, 377 insertions(+), 1 deletion(-) create mode 100755 func/minion/modules/iptables/Makefile create mode 100644 func/minion/modules/iptables/__init__.py create mode 100644 func/minion/modules/iptables/common.py create mode 100644 func/minion/modules/iptables/port.py create mode 100755 func/minion/modules/netapp/Makefile (limited to 'func/minion') diff --git a/func/minion/modules/Makefile b/func/minion/modules/Makefile index 64c9c5c..3af3333 100755 --- a/func/minion/modules/Makefile +++ b/func/minion/modules/Makefile @@ -1,5 +1,5 @@ - +DIRS = netapp iptables PYFILES = $(wildcard *.py) PYCHECKER = /usr/bin/pychecker diff --git a/func/minion/modules/iptables/Makefile b/func/minion/modules/iptables/Makefile new file mode 100755 index 0000000..15750f7 --- /dev/null +++ b/func/minion/modules/iptables/Makefile @@ -0,0 +1,17 @@ + +PYFILES = $(wildcard *.py) + +PYCHECKER = /usr/bin/pychecker +PYFLAKES = /usr/bin/pyflakes + +clean:: + @rm -fv *.pyc *~ .*~ *.pyo + @find . -name .\#\* -exec rm -fv {} \; + @rm -fv *.rpm + -for d in $(DIRS); do ($(MAKE) -C $$d clean ); done + +pychecker:: + @$(PYCHECKER) $(PYFILES) || exit 0 + +pyflakes:: + @$(PYFLAKES) $(PYFILES) || exit 0 diff --git a/func/minion/modules/iptables/__init__.py b/func/minion/modules/iptables/__init__.py new file mode 100644 index 0000000..11a9333 --- /dev/null +++ b/func/minion/modules/iptables/__init__.py @@ -0,0 +1,149 @@ +# +# Copyright 2008 +# Krzysztof A. Adamski +# +# This software may be freely redistributed under the terms of the GNU +# general public license. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# our modules +from func.minion.modules import func_module +from func.minion.modules.iptables.common import * + +IPTABLES_SAVE_FILE = "/etc/sysconfig/iptables" + +class Iptables(func_module.FuncModule): + + # Update these if need be. + version = "0.0.1" + api_version = "0.0.1" + description = "iptables module" + + def run(self, args): + """ + Run 'iptables' command with arguments given. For example: + > func '*' call iptables run "-L INPUT" + """ + return run_iptables(args) + + def policy(self, chain="INPUT", policy=None): + """ + Check/set default policy for the chain. Examples: + * Check default policy for INPUT chain: + > func '*' call iptables policy + or + > func '*' call iptables policy INPUT + * Set default policy for OUTPUT: + > func '*' call iptables policy OUTPUT DROP + """ + if policy==None: + return check_policy(chain) + else: + return set_policy(chain, policy) + + def flush(self, chain="INPUT"): + """ + Flush the selected chain (or INPUT if none given). + """ + return call_iptables("-F %s" % chain) + + def zero(self, chain="INPUT"): + """ + Zero counters in selected chain (or INPUT if none given). + """ + return call_iptables("-Z %s" % chain) + + def drop_from(self, ip): + """ + Drop all incomming traffic from IP. Example: + > func '*' call iptables drop_from 192.168.0.10 + """ + clear_all("-D INPUT -s %s -j ACCEPT" % ip) + clear_all("-D INPUT -s %s -j REJECT" % ip) + return call_if_policy("INPUT", "ACCEPT", "-I INPUT -s %s -j DROP" % ip) + + def reject_from(self, ip): + """ + Reject all incoming traffic from IP. Example: + > func '*' call iptables reject_from 192.168.0.10 + """ + clear_all("-D INPUT -s %s -j ACCEPT" % ip) + clear_all("-D INPUT -s %s -j DROP" % ip) + return call_iptables("-I INPUT -s %s -j REJECT" % ip) + + def accept_from(self, ip): + """ + Accept all incoming traffic from IP. Example: + > func '*' call iptables accept_from 192.168.0.10 + """ + clear_all("-D INPUT -s %s -j DROP" % ip) + clear_all("-D INPUT -s %s -j REJECT" % ip) + return call_if_policy("INPUT", "DROP", "-I INPUT -s %s -j ACCEPT" % ip) + + def drop_to(self, ip): + """ + Drop all outgoing traffic to IP. Example: + > func '*' call iptables drop_to 192.168.0.10 + """ + clear_all("-D OUTPUT -d %s -j ACCEPT" % ip) + clear_all("-D OUTPUT -d %s -j REJECT" % ip) + return call_if_policy("INPUT", "ACCEPT", "-I OUTPUT -d %s -j DROP" % ip) + + def reject_to(self, ip): + """ + Drop all outgoing traffic to IP. Example: + > func '*' call iptables reject_to 192.168.0.10 + """ + clear_all("-D OUTPUT -d %s -j ACCEPT" % ip) + clear_all("-D OUTPUT -d %s -j DROP" % ip) + return call_iptables("-I OUTPUT -d %s -j REJECT" % ip) + + def accept_to(self, ip): + """ + Accept all outgoing traffic to IP. Example: + > func '*' call iptables accept_to 192.168.0.10 + """ + clear_all("-D OUTPUT -d %s -j DROP" % ip) + clear_all("-D OUTPUT -d %s -j REJECT" % ip) + return call_if_policy("INPUT", "DROP", "-I OUTPUT -d %s -j ACCEPT" % ip) + + def inventory(self): + return self.dump() + + def dump(self, counters=False): + """ + Dump iptables configuration in iptables-save format. + """ + args = [] + if counters: + args.append("-c") + + cmd = sub_process.Popen(["/sbin/iptables-save"] + args, + executable="/sbin/iptables-save", + stdout=sub_process.PIPE, + stderr=sub_process.PIPE, + shell=False) + + data, error = cmd.communicate() + + return data + + def save(self, counters=False): + """ + Save iptables state using '/sbin/iptables-save'. If counters=True, + save counters too. + TODO: maybe some locking? + """ + f=open(IPTABLES_SAVE_FILE, 'w') + f.write(self.dump(counters)) + f.close + return True + + def panic(self): + self.flush("") + self.policy("INPUT", "DROP") + self.policy("OUTPUT", "DROP") + self.policy("FORWARD", "DROP") diff --git a/func/minion/modules/iptables/common.py b/func/minion/modules/iptables/common.py new file mode 100644 index 0000000..c5214f5 --- /dev/null +++ b/func/minion/modules/iptables/common.py @@ -0,0 +1,56 @@ +# +# Copyright 2008 +# Krzysztof A. Adamski +# +# This software may be freely redistributed under the terms of the GNU +# general public license. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# other modules +import sub_process + +def run_iptables(args): + cmd = sub_process.Popen(["/sbin/iptables"] + args.split(), + executable="/sbin/iptables", + stdout=sub_process.PIPE, + stderr=sub_process.PIPE, + shell=False) + + data, error = cmd.communicate() + + results = [] + for line in data.split("\n"): + tokens = line.split() + results.append(tokens) + + return results + +def call_iptables(args): + return sub_process.call(["/sbin/iptables"] + args.split(), + executable="/sbin/iptables", + shell=False) + +def check_policy(chain): + ret = run_iptables("-L %s" % chain) + try: + if ret[0][2] == "(policy": + return ret[0][3][:-1] + else: + return False + except: + return False + +def set_policy(chain, policy): + return call_iptables("-P %s %s" % (chain, policy) ) + +def clear_all(arg): + while not call_iptables(arg): pass + +def call_if_policy(chain, policy, arg): + if check_policy(chain) == policy: + return call_iptables(arg) + else: + return 0 diff --git a/func/minion/modules/iptables/port.py b/func/minion/modules/iptables/port.py new file mode 100644 index 0000000..49e5970 --- /dev/null +++ b/func/minion/modules/iptables/port.py @@ -0,0 +1,137 @@ +# +# Copyright 2008 +# Krzysztof A. Adamski +# +# This software may be freely redistributed under the terms of the GNU +# general public license. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# our modules +from func.minion.modules import func_module +from func.minion.modules.iptables.common import * + +class Port(func_module.FuncModule): + + # Update these if need be. + version = "0.0.1" + api_version = "0.0.1" + description = "iptables 'port' submodule" + + def drop_from(self, port, ip="0.0.0.0", prot="tcp", dir="dst"): + """ + Drop all traffic comming from/to PORT. Arguments: + * port - destination/source port + * ip - source IP + * prot - protocol (e.g. tcp/udp) + * dir - direction, "dst" for matching destination port or "src" for matching source port + Examples: + * Drop all incoming traffic to local TCP port 80: + > func '*' call iptables.port drop_from 80 + * Drop incomming traffic to local UDP port 53 from 192.168.0.0/24: + > func '*' call iptables.port drop_from 80 192.168.0.0/24 udp + """ + dir=parse_dir(dir) + clear_all("-D INPUT -p %s --%sport %s -s %s -j ACCEPT" % (prot, dir, port, ip) ) + clear_all("-D INPUT -p %s --%sport %s -s %s -j REJECT" % (prot, dir, port, ip) ) + return call_if_policy("INPUT", "ACCEPT", "-I INPUT -p %s --%sport %s -s %s -j DROP" % (prot, dir, port, ip) ) + + def reject_from(self, port, ip="0.0.0.0", prot="tcp", dir="dst"): + """ + Drop all traffic comming from/to PORT. Arguments: + * port - destination/source port + * ip - source IP + * prot - protocol (e.g. tcp/udp) + * dir - direction, "dst" for matching destination port or "src" for matching source port + Examples: + * Drop all incoming traffic to local TCP port 80: + > func '*' call iptables.port drop_from 80 + * Drop incomming traffic to local UDP port 53 from 192.168.0.0/24: + > func '*' call iptables.port drop_from 80 192.168.0.0/24 udp + """ + dir=parse_dir(dir) + clear_all("-D INPUT -p %s --%sport %s -s %s -j ACCEPT" % (prot, dir, port, ip) ) + clear_all("-D INPUT -p %s --%sport %s -s %s -j DROP" % (prot, dir, port, ip) ) + return call_iptables("-I INPUT -p %s --%sport %s -s %s -j REJECT" % (prot, dir, port, ip) ) + + def accept_from(self, port, ip="0.0.0.0", prot="tcp", dir="dst"): + """ + Accept all traffic comming from/to PORT. Arguments: + * port - destination/source port + * ip - source IP + * prot - protocol (e.g. tcp/udp) + * dir - direction, "dst" for matching destination port or "src" for matching source port + Examples: + * Accept all incoming traffic to local TCP port 80: + > func '*' call iptables.port accept_from 80 + * Accept incomming traffic to local UDP port 53 from 192.168.0.0/24: + > func '*' call iptables.port accept_from 80 192.168.0.0/24 udp + """ + dir=parse_dir(dir) + clear_all("-D INPUT -p %s --%sport %s -s %s -j DROP" % (prot, dir, port, ip) ) + clear_all("-D INPUT -p %s --%sport %s -s %s -j REJECT" % (prot, dir, port, ip) ) + return call_if_policy("INPUT", "DROP", "-I INPUT -p %s --%sport %s -s %s -j ACCEPT" % (prot, dir, port, ip) ) + + def drop_to(self, port, ip="0.0.0.0", prot="tcp", dir="dst"): + """ + Drop all outgoing traffic going from/to PORT. Arguments: + * port - destination/source port + * ip - destination IP + * prot - protocol (e.g. tcp/udp) + * dir - direction, "dst" for matching destination port or "src" for matching source port + Examples: + * Drop outgoing traffic to TCP port 80 on 192.168.0.1: + > func '*' call iptables.port drop_to 80 192.168.0.1 + * Drop outgoing traffic from UDP port 53 to 192.168.0.0/24: + > func '*' call iptables.port drop_to 53 192.168.0.0/24 udp src + """ + dir=parse_dir(dir) + clear_all("-D OUTPUT -p %s --%sport %s -d %s -j ACCEPT" % (prot, dir, port, ip) ) + clear_all("-D OUTPUT -p %s --%sport %s -d %s -j REJECT" % (prot, dir, port, ip) ) + return call_if_policy("OUTPUT", "ACCEPT", "-I OUTPUT -p %s --%sport %s -d %s -j DROP" % (prot, dir, port, ip) ) + + def reject_to(self, port, ip="0.0.0.0", prot="tcp", dir="dst"): + """ + Drop all outgoing traffic going from/to PORT. Arguments: + * port - destination/source port + * ip - destination IP + * prot - protocol (e.g. tcp/udp) + * dir - direction, "dst" for matching destination port or "src" for matching source port + Examples: + * Drop outgoing traffic to TCP port 80 on 192.168.0.1: + > func '*' call iptables.port drop_to 80 192.168.0.1 + * Drop outgoing traffic from UDP port 53 to 192.168.0.0/24: + > func '*' call iptables.port drop_to 53 192.168.0.0/24 udp src + """ + dir=parse_dir(dir) + clear_all("-D OUTPUT -p %s --%sport %s -d %s -j ACCEPT" % (prot, dir, port, ip) ) + clear_all("-D OUTPUT -p %s --%sport %s -d %s -j DROP" % (prot, dir, port, ip) ) + return call_iptables("-I OUTPUT -p %s --%sport %s -d %s -j REJECT" % (prot, dir, port, ip) ) + + def accept_to(self, port, ip="0.0.0.0", prot="tcp", dir="dst"): + """ + Accept all outgoing traffic going from/to PORT. Arguments: + * port - destination/source port + * ip - destination IP + * prot - protocol (e.g. tcp/udp) + * dir - direction, "dst" for matching destination port or "src" for matching source port + Examples: + * Accept outgoing traffic to TCP port 80 on 192.168.0.1: + > func '*' call iptables.port accept_to 80 192.168.0.1 + * Accept outgoing traffic from UDP port 53 to 192.168.0.0/24: + > func '*' call iptables.port accept_to 53 192.168.0.0/24 udp src + """ + dir=parse_dir(dir) + clear_all("-D OUTPUT -p %s --%sport %s -d %s -j DROP" % (prot, dir, port, ip) ) + clear_all("-D OUTPUT -p %s --%sport %s -d %s -j REJECT" % (prot, dir, port, ip) ) + return call_if_policy("OUTPUT", "DROP", "-I OUTPUT -p %s --%sport %s -d %s -j ACCEPT" % (prot, dir, port, ip) ) + +def parse_dir(dir): + if (dir == "dst"): + return "d" + elif (dir == "src"): + return "s" + else: + raise exceptions.Exception("Wrong direction!") diff --git a/func/minion/modules/netapp/Makefile b/func/minion/modules/netapp/Makefile new file mode 100755 index 0000000..15750f7 --- /dev/null +++ b/func/minion/modules/netapp/Makefile @@ -0,0 +1,17 @@ + +PYFILES = $(wildcard *.py) + +PYCHECKER = /usr/bin/pychecker +PYFLAKES = /usr/bin/pyflakes + +clean:: + @rm -fv *.pyc *~ .*~ *.pyo + @find . -name .\#\* -exec rm -fv {} \; + @rm -fv *.rpm + -for d in $(DIRS); do ($(MAKE) -C $$d clean ); done + +pychecker:: + @$(PYCHECKER) $(PYFILES) || exit 0 + +pyflakes:: + @$(PYFLAKES) $(PYFILES) || exit 0 -- cgit