ferm-2.2/0000755000076400001440000000000012164352537011026 5ustar maxusersferm-2.2/ferm.service0000644000076400001440000000031412164352537013337 0ustar maxusers[Unit] Description=for Easy Rule Making [Service] Type=oneshot RemainAfterExit=yes ExecStart=/usr/sbin/ferm /etc/ferm.conf ExecStop=/usr/sbin/ferm -F /etc/ferm.conf [Install] WantedBy=multi-user.target ferm-2.2/README0000644000076400001440000000412112164352537011704 0ustar maxusersferm README =========== Max Kellermann Auke Kok Description ----------- ferm is a frontend for iptables. It reads the rules from a structured configuration file and calls iptables(8) to insert them into the running kernel. ferm's goal is to make firewall rules easy to write and easy to read. It tries to reduce the tedious task of writing down rules, thus enabling the firewall administrator to spend more time on developing good rules than the proper implementation of the rule. To achieve this, ferm uses a simple but powerful configuration language, which allows variables, functions, arrays, blocks. It also allows you to include other files, allowing you to create libraries of commonly used structures and functions. ferm, pronounced "firm", stands for "For Easy Rule Making". Installing ferm --------------- make install The package does not need to be compiled, just make sure you have perl (which is present in any base linux system) and iptables (including iptables-save and iptables-restore), and the a kernel supporting netfilter. Run the make install install script as root to install the package in it's best location, so it can be reached from the command line when called. The manual page will also be installed. That's all! Uninstalling ferm ----------------- make uninstall Ferm can now be quickly removed from the system by issuing a "make uninstall" command (as root, of course). This will not remove any configuration files of course! Getting started --------------- The ferm(1) manpage provides extensive documentation about the ferm syntax. To get started, try one of the example files, and modify it for your needs. If your machine is already firewalled and you wish to switch to ferm, the "import-ferm" script comes handy. It converts the current firewall rules to a ferm configuration file: import-ferm >/etc/ferm/ferm.conf After that, let ferm install the new ruleset: ferm /etc/ferm/ferm.conf Be careful, don't lock youself out of remote machines! Use the interactive mode (--interactive, -i) often! ferm-2.2/config.mk0000644000076400001440000000022212164352537012620 0ustar maxusersPERL = /usr/bin/perl PREFIX = /usr SERVICEDIR = $(PREFIX)/lib/systemd/system MANDIR = $(PREFIX)/share/man/man1 DOCDIR = $(PREFIX)/share/doc/ferm ferm-2.2/TODO0000644000076400001440000000012612164352537011515 0ustar maxusersTODO ==== Roadmap for ferm 3.0 -------------------- * support tc (traffic control) ferm-2.2/examples/0000755000076400001440000000000012164352537012644 5ustar maxusersferm-2.2/examples/ebtables.ferm0000644000076400001440000000035512164352537015303 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # ebtables demo. # # Author: Max Kellermann # domain eb chain FORWARD { policy DROP; logical-in br0 logical-out br0 { proto (IPv4 ARP) ACCEPT; } } ferm-2.2/examples/resolve.ferm0000644000076400001440000000072012164352537015175 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # Demo of the @resolve() function. # # Author: Max Kellermann # table filter chain OUTPUT { daddr @resolve(www.google.com) proto tcp dport http ACCEPT; daddr @resolve(yahoo.com, MX) proto tcp dport smtp ACCEPT; daddr @resolve(denic.de, NS) proto udp dport domain ACCEPT; } domain ip6 table filter chain OUTPUT { daddr @resolve(www.sixxs.net, AAAA) proto tcp dport http ACCEPT; } ferm-2.2/examples/fileserver.ferm0000644000076400001440000000167112164352537015672 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # Firewall configuration for a file server (NFSv4 and SMB). # # Author: Max Kellermann # table filter { chain INPUT { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # allow local connections interface lo ACCEPT; # respond to ping proto icmp icmp-type echo-request ACCEPT; # remote administration proto tcp dport ssh ACCEPT; # samba proto tcp dport (139 445) ACCEPT; #smbd proto udp dport (137:138) ACCEPT; #nmbd # NFSv4 proto tcp dport sunrpc ACCEPT; proto (tcp udp) dport 2049 ACCEPT; # reject the rest gracefully REJECT; } # outgoing connections are not limited chain OUTPUT policy ACCEPT; # this is not a router chain FORWARD policy DROP; } ferm-2.2/examples/ipv6.ferm0000644000076400001440000000145112164352537014404 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # IPv6 demo. # # Author: Max Kellermann # domain ip6 table filter { chain INPUT { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # allow local connections interface lo ACCEPT; # allow ICMP (for neighbor solicitation, like ARP for IPv4) proto ipv6-icmp ACCEPT; # allow SSH connections proto tcp dport ssh ACCEPT; # ident connections are also allowed proto tcp dport auth ACCEPT; # the rest is dropped by the above policy } # outgoing connections are not limited chain OUTPUT policy ACCEPT; # this is not a router chain FORWARD policy DROP; } ferm-2.2/examples/workstation.ferm0000644000076400001440000000150412164352537016103 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # Firewall configuration for a workstation which accepts remote ssh login. # # Author: Max Kellermann # table filter { chain INPUT { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # allow local connections interface lo ACCEPT; # respond to ping proto icmp icmp-type echo-request ACCEPT; # allow SSH connections proto tcp dport ssh ACCEPT; # ident connections are also allowed proto tcp dport auth ACCEPT; # the rest is dropped by the above policy } # outgoing connections are not limited chain OUTPUT policy ACCEPT; # this is not a router chain FORWARD policy DROP; } ferm-2.2/examples/arptables.ferm0000644000076400001440000000040412164352537015472 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # arptables demo. # # Author: Max Kellermann # domain arp chain INPUT { policy DROP; interface eth0 ACCEPT; interface eth1 { source-mac 00:00:de:ad:be:ef ACCEPT; } } ferm-2.2/examples/antiddos.ferm0000644000076400001440000000307012164352537015324 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # Firewall configuration to prevent basic tcp DoS/DDoS attacks # # Authors: Vlad Glagolev , Stepan Rogov # @def &ANTIDDOS($ports, $seconds, $hits, $time, $exceptions) = { proto tcp dport $ports @subchain "ddos_check" { # allow every exception as-is saddr $exceptions ACCEPT; # connection tracking mod conntrack ctstate (ESTABLISHED RELATED) ACCEPT; # check for IPs overloading $hits/$seconds rate and block them mod recent name "ddos_check" rcheck seconds $seconds hitcount $hits @subchain "ddos" { mod recent set name "ddos" NOP; DROP; } # register a packet in "ddos_check" list mod recent set name "ddos_check" NOP; # check IP in "ddos" list # if it exists and had been registered in the last $time seconds -- drop it mod recent name "ddos" rcheck seconds $time DROP; # remove packet from "ddos" list mod recent name "ddos" remove NOP; # allow ONLY new connections mod conntrack ctstate NEW ACCEPT; DROP; } } table filter { chain INPUT { policy DROP; # connection tracking mod state state INVALID REJECT; mod state state (ESTABLISHED RELATED) ACCEPT; # allow local connections interface lo ACCEPT; # ban ip addresses for 1 day which connect more than 50 times in 3 seconds, # exception is IP: 94.29.90.101 &ANTIDDOS((80, 443), 50, 3, 86400, 94.29.90.101); # the rest is dropped by the above policy } # outgoing connections are not limited chain OUTPUT policy ACCEPT; # this is not a router chain FORWARD policy DROP; } ferm-2.2/examples/mailserver.ferm0000644000076400001440000000176112164352537015675 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # Firewall configuration for a dedicated mail server. # # Author: Max Kellermann # @def $NET_TRUSTED = 195.135.144.144/28; table filter { chain INPUT { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # allow local connections interface lo ACCEPT; # respond to ping proto icmp icmp-type echo-request ACCEPT; # remote administration from the company network saddr $NET_TRUSTED proto tcp dport ssh ACCEPT; # our services to the world proto tcp dport (smtp ssmtp qmtp pop3 pop3s imap2 imap3 imaps) ACCEPT; # some SMTP servers use ident proto tcp dport auth REJECT; # the rest is dropped by the above policy } # outgoing connections are not limited chain OUTPUT policy ACCEPT; # this is not a router chain FORWARD policy DROP; } ferm-2.2/examples/dmz_router.ferm0000644000076400001440000000543212164352537015715 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # Firewall configuration for a router with a static IP and a demilitarized # zone on the third device. # # Author: Max Kellermann # @def $DEV_PRIVATE = eth0; @def $DEV_WORLD = eth1; @def $DEV_DMZ = eth2; @def $NET_PRIVATE = 192.168.0.0/24; @def $NET_DMZ = 192.168.1.0/24; # internal IPs of the admins @def $HOST_ADMIN = (192.168.0.4 192.168.0.10); # our static IP address @def $HOST_STATIC = 193.43.91.203; # convenience function which creates both the nat/DNAT and the filter/FORWARD # rule @def &FORWARD_TCP($proto, $port, $dest) = { table filter chain FORWARD interface $DEV_WORLD outerface $DEV_DMZ daddr $dest proto $proto dport $port ACCEPT; table nat chain PREROUTING interface $DEV_WORLD daddr $HOST_STATIC proto $proto dport $port DNAT to $dest; } table filter { chain INPUT { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # allow local connections interface lo ACCEPT; # respond to ping proto icmp icmp-type echo-request ACCEPT; # for IPsec interface $DEV_WORLD { proto udp dport 500 ACCEPT; proto (esp ah) ACCEPT; } # allow SSH connections from the administrator's workstation interface $DEV_PRIVATE saddr $HOST_ADMIN proto tcp dport ssh ACCEPT; # we provide DNS for the internal net interface ($DEV_PRIVATE $DEV_DMZ) { proto (udp tcp) dport domain ACCEPT; } # some IRC servers want that interface $DEV_WORLD { proto tcp dport auth ACCEPT; proto tcp dport (8080 3128) REJECT; } # the rest is dropped by the above policy (except additional # FORWARD rules added by the function &FORWARD_TCP) } # outgoing connections are not limited chain OUTPUT policy ACCEPT; chain FORWARD { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # the internal net may go everywhere interface $DEV_PRIVATE ACCEPT; # the DMZ may only access the internet interface $DEV_DMZ { outerface $DEV_WORLD ACCEPT; # report failure gracefully REJECT reject-with icmp-net-prohibited; } # the rest is dropped by the above policy } } table nat { chain POSTROUTING { # masquerade private IP addresses saddr ($NET_PRIVATE $NET_DMZ) outerface $DEV_WORLD SNAT to $HOST_STATIC; } } # forward connections to servers located in the DMZ &FORWARD_TCP(tcp, http, 192.168.1.2); &FORWARD_TCP(tcp, smtp, 192.168.1.3); &FORWARD_TCP((tcp udp), domain, 192.168.1.4); ferm-2.2/examples/dsl_router.ferm0000644000076400001440000000360012164352537015700 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # Firewall configuration for a router with a dynamic IP. # # Author: Max Kellermann # @def $DEV_PRIVATE = (eth0 eth1); @def $DEV_WORLD = ppp0; @def $NET_PRIVATE = 192.168.0.0/16; table filter { chain INPUT { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # allow local connections interface lo ACCEPT; # respond to ping proto icmp icmp-type echo-request ACCEPT; # for IPsec interface $DEV_WORLD { proto udp dport 500 ACCEPT; proto (esp ah) ACCEPT; } # allow SSH connections from the private network and from some # well-known internet hosts saddr ($NET_PRIVATE 81.209.165.42) proto tcp dport ssh ACCEPT; # we provide DNS and SMTP services for the internal net interface $DEV_PRIVATE saddr $NET_PRIVATE { proto (udp tcp) dport domain ACCEPT; proto tcp dport smtp ACCEPT; } # some IRC servers want that interface $DEV_WORLD { proto tcp dport auth ACCEPT; proto tcp dport (8080 3128) REJECT; } # the rest is dropped by the above policy } # outgoing connections are not limited chain OUTPUT policy ACCEPT; chain FORWARD { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # connections from the internal net to the internet or to other # internal nets are allowed interface $DEV_PRIVATE ACCEPT; # the rest is dropped by the above policy } } table nat { chain POSTROUTING { # masquerade private IP addresses saddr $NET_PRIVATE outerface $DEV_WORLD MASQUERADE; } } ferm-2.2/examples/webserver.ferm0000644000076400001440000000160612164352537015526 0ustar maxusers# -*- shell-script -*- # # Ferm example script # # Firewall configuration for a web and SMTP server. # # Author: Max Kellermann # @def $NET_TRUSTED = 195.135.144.144/28; table filter { chain INPUT { policy DROP; # connection tracking mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; # allow local connections interface lo ACCEPT; # respond to ping proto icmp icmp-type echo-request ACCEPT; # remote administration from the company network saddr $NET_TRUSTED proto tcp dport ssh ACCEPT; # our services to the world proto tcp dport (http https smtp) ACCEPT; # the rest is dropped by the above policy } # outgoing connections are not limited chain OUTPUT policy ACCEPT; # this is not a router chain FORWARD policy DROP; } ferm-2.2/Makefile0000644000076400001440000001100212164352537012460 0ustar maxusers# # Makefile for ferm # TOPDIR = . include $(TOPDIR)/config.mk VERSION := $(shell $(PERL) src/ferm --version | awk '{print $$2}' | head -1 | tr -d ',') DISTDIR = build/ferm-$(VERSION) .PHONY: all clean all: doc/ferm.txt doc/ferm.html doc/ferm.1 doc/import-ferm.1 clean: rm -rf build rm -f doc/ferm.txt doc/ferm.html doc/ferm.1 doc/import-ferm.1 *.tmp # # documentation # doc/ferm.txt: doc/ferm.pod pod2text $< > $@ doc/ferm.html: doc/ferm.pod pod2html $< --title="ferm - Firewall rules made easy" --flush > $@ doc/ferm.1: doc/ferm.pod pod2man --section=1 --release="ferm $(VERSION)" \ --center="FIREWALL RULES MADE EASY" \ --official $< > $@ doc/import-ferm.1: src/import-ferm pod2man --section=1 --release="ferm $(VERSION)" \ --center="FIREWALL RULES MADE EASY" \ --official $< > $@ # # test suite # STAMPDIR = $(TOPDIR)/build/test STAMPDIR_20 = $(TOPDIR)/build/test2 # a list of all ferm scripts which should be tested with iptables FERM_SCRIPTS = FERM_SCRIPTS += $(wildcard test/modules/*.ferm) $(wildcard test/targets/*.ferm) FERM_SCRIPTS += $(wildcard test/protocols/*.ferm) $(wildcard test/misc/*.ferm) FERM_SCRIPTS += $(wildcard test/ipv6/*.ferm) FERM_SCRIPTS += $(wildcard test/arptables/*.ferm) $(wildcard test/ebtables/*.ferm) EXCLUDE_IMPORT = test/misc/subchain-domains.ferm test/misc/ipfilter.ferm test/ipv6/mixed.ferm test/misc/address-magic.ferm IMPORT_SCRIPTS = $(filter-out $(EXCLUDE_IMPORT) test/arptables/% test/ebtables/%,$(FERM_SCRIPTS)) # just a hack RESULT_SED += -e 's,--protocol,-p,g' RESULT_SED += -e 's,--in-interface,-i,g' RESULT_SED += -e 's,--out-interface,-o,g' RESULT_SED += -e 's,--destination ,-d ,g' RESULT_SED += -e 's,--source ,-s ,g' RESULT_SED += -e 's,--match ,-m ,g' RESULT_SED += -e 's,--jump,-j,g' RESULT_SED += -e 's,--goto,-g,g' RESULT_SED += -e 's,--fragment,-f,g' EB_ARP_RESULT_SED = -e 's,--jump,-j,g' $(STAMPDIR)/test/arptables/%.result: test/arptables/%.ferm src/ferm @mkdir -p $(dir $@) $(PERL) src/ferm --test --slow $< |sed $(EB_ARP_RESULT_SED) >$@ $(STAMPDIR)/test/ebtables/%.result: test/ebtables/%.ferm src/ferm @mkdir -p $(dir $@) $(PERL) src/ferm --test --slow $< |sed $(EB_ARP_RESULT_SED) >$@ $(STAMPDIR)/%.result: %.ferm src/ferm @mkdir -p $(dir $@) $(PERL) src/ferm --test --slow --noflush $< |sed $(RESULT_SED) >$@ $(STAMPDIR)/%.SAVE: %.ferm src/ferm @mkdir -p $(dir $@) $(PERL) src/ferm --test $< >$@.tmp grep -v '^#' <$@.tmp >$@ $(STAMPDIR)/test/ipv6/%.IMPORT: export FERM_DOMAIN=ip6 $(STAMPDIR)/%.IMPORT: $(STAMPDIR)/%.SAVE src/import-ferm $(PERL) src/import-ferm $< >$@ $(STAMPDIR)/%.SAVE2: $(STAMPDIR)/%.IMPORT src/ferm $(PERL) src/ferm --test --fast $< |grep -v '^#' >$@ $(STAMPDIR)/%.check: %.result $(STAMPDIR)/%.result diff -u $^ @touch $@ $(STAMPDIR)/%.check-import: $(STAMPDIR)/%.SAVE $(STAMPDIR)/%.SAVE2 diff -u $^ @touch $@ .PHONY : check-ferm check-import check check-ferm: $(patsubst %.ferm,$(STAMPDIR)/%.check,$(FERM_SCRIPTS)) check-import: $(patsubst %.ferm,$(STAMPDIR)/%.check-import,$(IMPORT_SCRIPTS)) check: check-ferm check-import # # distribution # .PHONY: dist build/ferm-$(VERSION).tar.gz: all rm -rf $(DISTDIR) install -d -m 755 $(DISTDIR) $(DISTDIR)/src $(DISTDIR)/doc $(DISTDIR)/examples install -m 755 src/ferm src/import-ferm $(DISTDIR)/src install -m 644 ferm.service $(DISTDIR) install -m 644 doc/ferm.pod doc/ferm.txt doc/ferm.html doc/ferm.1 doc/import-ferm.1 $(DISTDIR)/doc install -m 644 config.mk Makefile AUTHORS COPYING NEWS README TODO $(DISTDIR) install -m 644 $(wildcard examples/*.ferm) $(DISTDIR)/examples cd build && tar czf ferm-$(VERSION).tar.gz ferm-$(VERSION) dist: build/ferm-$(VERSION).tar.gz # # installation # .PHONY: install uninstall install: all install -d -m 755 $(DOCDIR)/examples $(PREFIX)/sbin $(SERVICEDIR) install -m 644 AUTHORS COPYING NEWS README TODO $(DOCDIR) install -m 644 examples/*.ferm $(DOCDIR)/examples install -m 755 src/ferm src/import-ferm $(PREFIX)/sbin/ install -m 644 ferm.service $(SERVICEDIR) install -d -m 755 $(DOCDIR) $(MANDIR) install -m 644 doc/ferm.txt doc/ferm.html $(DOCDIR) install -m 644 doc/ferm.1 doc/import-ferm.1 $(MANDIR) gzip -f9 $(MANDIR)/ferm.1 $(MANDIR)/import-ferm.1 uninstall: rm -rf $(DOCDIR) rm -f $(MANDIR)/ferm.1 $(MANDIR)/import-ferm.1 rm -f $(SERVICEDIR)/ferm.service rm -f $(PREFIX)/sbin/ferm $(PREFIX)/sbin/import-ferm # # misc targets # .PHONY: upload upload: doc/ferm.html scp NEWS doc/ferm.html foo-projects.org:/var/www/ferm.foo-projects.org/download/2.2/ scp examples/*.ferm foo-projects.org:/var/www/ferm.foo-projects.org/download/examples/ ferm-2.2/COPYING0000644000076400001440000004310512164352537012064 0ustar maxusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ferm-2.2/doc/0000755000076400001440000000000012164352537011573 5ustar maxusersferm-2.2/doc/import-ferm.10000644000076400001440000001060612164352537014121 0ustar maxusers.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . nr % 0 . rr F .\} .el \{\ . de IX .. .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "IMPORT-FERM 1" .TH IMPORT-FERM 1 "2012-07-29" "ferm 2.2" "FIREWALL RULES MADE EASY" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" import\-ferm \- import existing firewall rules into ferm .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBimport-ferm\fR > ferm.conf .PP iptables-save | \fBimport-ferm\fR > ferm.conf .PP \&\fBimport-ferm\fR \fIinputfile\fR > ferm.conf .SH "DESCRIPTION" .IX Header "DESCRIPTION" This script helps you with porting an existing IPv4 firewall configuration to ferm. It reads a file generated with \&\fBiptables-save\fR, and tries to suggest a ferm configuration file. .PP If no input file was specified on the command line, \fBimport-ferm\fR runs \fIiptables-save\fR. .SH "BUGS" .IX Header "BUGS" iptables-save older than 1.3 is unable to write valid saves \- this is not a bug in \fBimport-ferm\fR. ferm-2.2/doc/ferm.pod0000644000076400001440000013560212164352537013237 0ustar maxusers# # ferm pod manual file # # # ferm, a firewall setup program that makes firewall rules easy! # # Copyright (C) 2001-2012 Max Kellermann, Auke Kok # # Comments, questions, greetings and additions to this program # may be sent to # # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # =head1 NAME B - a firewall rule parser for linux =head1 SYNOPSIS B I I =head1 DESCRIPTION B is a frontend for B. It reads the rules from a structured configuration file and calls iptables(8) to insert them into the running kernel. B's goal is to make firewall rules easy to write and easy to read. It tries to reduce the tedious task of writing down rules, thus enabling the firewall administrator to spend more time on developing good rules than the proper implementation of the rule. To achieve this, B uses a simple but powerful configuration language, which allows variables, functions, arrays, blocks. It also allows you to include other files, allowing you to create libraries of commonly used structures and functions. B, pronounced "firm", stands for "For Easy Rule Making". =head1 CAUTION This manual page does I indend to teach you how firewalling works and how to write good rules. There is already enough documentation on this topic. =head1 INTRODUCTION Let's start with a simple example: chain INPUT { proto tcp ACCEPT; } This will add a rule to the predefined input chain, matching and accepting all tcp packets. Ok, let's make it more complicated: chain (INPUT OUTPUT) { proto (udp tcp) ACCEPT; } This will insert 4 rules, namely 2 in chain input, and 2 in chain output, matching and accepting both udp and tcp packets. Normally you would type this: iptables -A INPUT -p tcp -j ACCEPT iptables -A OUTPUT -p tcp -j ACCEPT iptables -A INPUT -p udp -j ACCEPT iptables -A OUTPUT -p udp -j ACCEPT Note how much less typing we need to do? :-) Basically, this is all there is to it, although you can make it quite more complex. Something to look at: chain INPUT { policy ACCEPT; daddr 10.0.0.0/8 proto tcp dport ! ftp jump mychain sport :1023 TOS 4 settos 8 mark 2; daddr 10.0.0.0/8 proto tcp dport ftp REJECT; } My point here is, that *you* need to make nice rules, keep them readable to you and others, and not make it into a mess. It would aid the reader if the resulting firewall rules were placed here for reference. Also, you could include the nested version with better readability. Try using comments to show what you are doing: # this line enables transparent http-proxying for the internal network: proto tcp if eth0 daddr ! 192.168.0.0/255.255.255.0 dport http REDIRECT to-ports 3128; You will be thankful for it later! chain INPUT { policy ACCEPT; interface (eth0 ppp0) { # deny access to notorius hackers, return here if no match # was found to resume normal firewalling jump badguys; protocol tcp jump fw_tcp; protocol udp jump fw_udp; } } The more you nest, the better it looks. Make sure the order you specify is correct, you would not want to do this: chain FORWARD { proto ! udp DROP; proto tcp dport ftp ACCEPT; } because the second rule will never match. Best way is to specify first everyting that is allowed, and then deny everything else. Look at the examples for more good snapshots. Most people do something like this: proto tcp { dport ( ssh http ftp ) ACCEPT; dport 1024:65535 ! syn ACCEPT; DROP; } =head1 STRUCTURE OF A FIREWALL FILE The structure of a proper firewall file looks like simplified C-code. Only a few syntactic characters are used in ferm- configuration files. Besides these special caracters, ferm uses 'keys' and 'values', think of them as options and parameters, or as variables and values, whatever. With these words, you define the characteristics of your firewall. Every firewall consists of two things: First, look if network traffic matches certain conditions, and second, what to do with that traffic. You may specify conditions that are valid for the kernel interface program you are using, probably iptables(8). For instance, in iptables, when you are trying to match tcp packets, you would say: iptables --protocol tcp In ferm, this will become: protocol tcp; Just typing this in ferm doesn't do anything, you need to tell ferm (actually, you need to tell iptables(8) and the kernel) what to do with any traffic that matches this condition: iptables --protocol tcp -j ACCEPT Or, translated to B: protocol tcp ACCEPT; The B<;> character is at the end of every ferm rule. Ferm ignores line breaks, meaning the above example is identical to the following: protocol tcp ACCEPT; Here's a list of the special characters: =over 8 =item B<;> This character finalizes a rule. Separated by semicolons, you may write multiple rules in one line, although this decreases readability: protocol tcp ACCEPT; protocol udp DROP; =item B<{}> The nesting symbol defines a 'block' of rules. The curly brackets contain any number of nested rules. All matches before the block are carried forward to these. The closing curly bracket finalizes the rule set. You should not write a ';' after that, because that would be an empty rule. Example: chain INPUT proto icmp { icmp-type echo-request ACCEPT; DROP; } This block shows two rules inside a block, which will both be merged with anything in front of it, so you will get two rules: iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A INPUT -p icmp -j DROP There can be multiple nesting levels: chain INPUT { proto icmp { icmp-type echo-request ACCEPT; DROP; } daddr 172.16.0.0/12 REJECT; } Note that the 'REJECT' rule is not affected by 'proto icmp', although there is no ';' after the closing curly brace. Translated to iptables: iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A INPUT -p icmp -j DROP iptables -A INPUT -d 172.16.0.0/12 -j REJECT =item B<$> Variable expansion. Replaces '$FOO' by the value of the variable. See the section I for details. =item B<&> Function call. See the section I for details. =item B<()> The array symbol. Using the parentheses, you can define a 'list' of values that should be applied for the key to the left of it. Example: protocol ( tcp udp icmp ) this will result in three rules: ... -p tcp ... ... -p udp ... ... -p icmp ... Only values can be 'listed', so you cannot do something like this: proto tcp ( ACCEPT LOG ); but you can do this: chain (INPUT OUTPUT FORWARD) proto (icmp udp tcp) DROP; (which will result in nine rules!) Values are separated by spaces. The array symbol is both left- and right-associative, in contrast with the nesting block, which is left-associative only. =item C< # > The comment symbol. Anything that follows this symbol up to the end of line is ignored. =item C<`command`> Execute the command in a shell, and insert the process output. See the section I for details. =item C<'string'> Quote a string which may contain whitespaces, the dollar sign etc. LOG log-prefix ' hey, this is my log prefix!'; =item C<"string"> Quote a string (see above), but variable references with a dollar sign are evaluated: DNAT to "$myhost:$myport"; =back =head2 Keywords In the previous section, we already introduced some basic keywords like "chain", "protocol" and "ACCEPT". Let's explore their nature. There are three kinds of keywords: =over 8 =item B keywords define where a rule will be created. Example: "table", "chain". =item B keywords perform a test on all passing packets. The current rule is without effect if one (or more) of the matches does not pass. Example: "proto", "daddr". Most matches are followed by a parameter: "proto tcp", "daddr 172.16.0.0/12". =item B keywords state what to do with a packet. Example: "ACCEPT", "REJECT", "jump". Some targets define more keywords to specify details: "REJECT reject-with icmp-net-unreachable". =back Every rule consists of a B and a B, plus any number of B: table filter # location proto tcp dport (http https) # match ACCEPT; # target Strictly speaking, there is a fourth kind: B keywords (which control ferm's internal behaviour), but they will be explained later. =head2 Parameters Many keywords take parameters. These can be specified as literals, variable references or lists (arrays): proto udp saddr $TRUSTED_HOSTS; proto tcp dport (http https ssh); LOG log-prefix "funky wardriver alert: "; Some of them can be negated (lists cannot be negated): proto !esp; proto udp dport !domain; Keywords which take no parameters are negated by a prefixed '!': proto tcp !syn; Read iptables(8) to see where the B can be used. =head1 BASIC KEYWORDS =head2 Location keywords =over 8 =item B Set the domain. "ip" is default and means "IPv4" (iptables). "ip6" is for IPv6 support, using "ip6tables". =item B Specifies which netfilter table this rule will be inserted to: "filter" (default), "nat" or "mangle". =item B Specifies the netfilter chain (within the current table) this rule will be inserted to. Common predefined chain names are "INPUT", "OUTPUT", "FORWARD", "PREROUTING", "POSTROUTING", depending on the table. See the netfilter documentation for details. If you specify a non-existing chain here, ferm will add the rule to a custom chain with that name. =item B Specifies the default policy for the current chain (built-in only). Can be one of the built-in targets (ACCEPT, DROP, REJECT, ...). A packet that matches no rules in a chain will be treated as specified by the policy. To avoid ambiguity, always specify the policies of all predefined chains explicitly. =item B<@subchain ["CHAIN-NAME"] { ... }> Works like the normal block operators (i.e. without the I<@subchain> keyword), except that B moves rules within the curly braces into a new custom chain. The name for this chain is chosen automatically by ferm. In many cases, this is faster than just a block, because the kernel may skip a huge block of rules when a precondition is false. Imagine the following example: table filter chain INPUT { saddr (1.2.3.4 2.3.4.5 3.4.5.6 4.5.6.7 5.6.7.8) { proto tcp dport (http https ssh) ACCEPT; proto udp dport domain ACCEPT; } } This generates 20 rules. When a packet arrives which does not pass the B match, it nonetheless checks all 20 rules. With B<@subchain>, this check is done once, resulting in faster network filtering and less CPU load: table filter chain INPUT { saddr (1.2.3.4 2.3.4.5 3.4.5.6 4.5.6.7 5.6.7.8) @subchain { proto tcp dport (http https ssh) ACCEPT; proto udp dport domain ACCEPT; } } Optionally, you may define the name of the sub chain: saddr (1.2.3.4 2.3.4.5 3.4.5.6) @subchain "foobar" { proto tcp dport (http https ssh) ACCEPT; proto udp dport domain ACCEPT; } The name can either be a quoted string literal, or an expanded ferm expression such as @cat("interface_", $iface) or @substr($var,0,20). You can achieve the same by explicitly declaring a custom chain, but you may feel that using B<@subchain> requires less typing. =back =head2 Basic iptables match keywords =over 8 =item B Define the interface name, your outside network card, like eth0, or dialup like ppp1, or whatever device you want to match for passing packets. It is equivalent to the C<-i> switch in iptables(8). =item B Same as interface, only for matching the outgoing interface for a packet, as in iptables(8). =item B Currently supported by the kernel are tcp, udp and icmp, or their respective numbers. =item B Matches on packets originating from the specified address (saddr) or targeted at the address (daddr). Examples: saddr 192.168/8 ACCEPT; # (identical to the next one:) saddr 192.168.0.0/255.255.255.0 ACCEPT; daddr my.domain.com ACCEPT; =item B Specify that only fragmented IP packets should be matched. When packets are larger that the maximum packet size your system can handle (called Maximum Transmission Unit or MTU) they will be chopped into bits and sent one by one as single packets. See ifconfig(8) if you want to find the MTU for your system (the default is usually 1500 bytes). Fragments are frequently used in DOS attacks, because there is no way of finding out the origin of a fragment packet. =item B Matches on packets on the specified TCP or UDP port. "sport" matches the source port, and dport matches the destination port. This match can be used only after you specified "protocol tcp" or "protocol udp", because only these two protocols actually have ports. And some examples of valid ports/ranges: dport 80 ACCEPT; dport http ACCEPT; dport ssh:http ACCEPT; dport 0:1023 ACCEPT; # equivalent to :1023 dport 1023:65535 ACCEPT; =item B Specify that the SYN flag in a tcp package should be matched, which are used to build new tcp connections. You can identify incoming connections with this, and decide wether you want to allow it or not. Packets that do not have this flag are probably from an already established connection, so it's considered reasonably safe to let these through. =item B Load an iptables module. Most modules provide more match keywords. We'll get to that later. =back =head2 Basic target keywords =over 8 =item B Jumps to a custom chain. If no rule in the custom chain matched, netfilter returns to the next rule in the previous chain. =item B Go to a custom chain. Unlike the B option, B will not continue processing in this chain but instead in the chain that called us via B. The keyword B was chosen during the transition period, because B (already deprecated) used to be an alias for B. =item B Accepts matching packets. =item B Drop matching packets without further notice. =item B Rejects matching packets, i.e. send an ICMP packet to the sender, which is port-unreachable by default. You may specify another ICMP type. REJECT; # default to icmp-port-unreachable REJECT reject-with icmp-net-unreachable; Type "iptables -j REJECT -h" for details. =item B Finish the current chain and return to the calling chain (if "jump [custom-chain-name]" was used). =item B No action at all. =back =head1 ADDITIONAL KEYWORDS Netfilter is modular. Modules may provide additional targets and match keywords. The list of netfilter modules is constantly growing, and ferm tries to keep up with supporting them all. This chapter describes modules which are currently supported. =head2 iptables match modules =over 8 =item B Account traffic for all hosts in defined network/netmask. This is one of the match modules which behave like a target, i.e. you will mostly have to use the B target. mod account aname mynetwork aaddr 192.168.1.0/24 ashort NOP; =item B Check the address type; either source address or destination address. mod addrtype src-type BROADCAST; mod addrtype dst-type LOCAL; Type "iptables -m addrtype -h" for details. =item B Checks the SPI header in an AH packet. mod ah ahspi 0x101; mod ah ahspi ! 0x200:0x2ff; Additional arguments for IPv6: mod ah ahlen 32 ACCEPT; mod ah ahlen !32 ACCEPT; mod ah ahres ACCEPT; =item B Adds a comment of up to 256 characters to a rule, without an effect. Note that unlike ferm comments ('#'), this one will show up in "iptables -L". mod comment comment "This is my comment." ACCEPT; =item B Matches if a value in /proc/net/ipt_condition/NAME is 1 (path is /proc/net/ip6t_condition/NAME for the ip6 domain). mod condition condition (abc def) ACCEPT; mod condition condition !foo ACCEPT; =item B Match by how many bytes or packets a connection (or one of the two flows constituting the connection) have tranferred so far, or by average bytes per packet. mod connbytes connbytes 65536: connbytes-dir both connbytes-mode bytes ACCEPT; mod connbytes connbytes !1024:2048 connbytes-dir reply connbytes-mode packets ACCEPT; Valid values for I: I, I, I; for I: I, I, I. =item B Allows you to restrict the number of parallel TCP connections to a server per client IP address (or address block). mod connlimit connlimit-above 4 REJECT; mod connlimit connlimit-above !4 ACCEPT; mod connlimit connlimit-above 4 connlimit-mask 24 REJECT; =item B Check the mark field associated with the connection, set by the CONNMARK target. mod connmark mark 64; mod connmark mark 6/7; =item B Check connection tracking information. mod conntrack ctstate (ESTABLISHED RELATED); mod conntrack ctproto tcp; mod conntrack ctorigsrc 192.168.0.2; mod conntrack ctorigdst 1.2.3.0/24; mod conntrack ctorigsrcport 67; mod conntrack ctorigdstport 22; mod conntrack ctreplsrc 2.3.4.5; mod conntrack ctrepldst ! 3.4.5.6; mod conntrack ctstatus ASSURED; mod conntrack ctexpire 60; mod conntrack ctexpire 180:240; Type "iptables -m conntrack -h" for details. =item B Check DCCP (Datagram Congestion Control Protocol) specific attributes. This module is automatically loaded when you use "protocol dccp". proto dccp sport 1234 dport 2345 ACCEPT; proto dccp dccp-types (SYNCACK ACK) ACCEPT; proto dccp dccp-types !REQUEST DROP; proto dccp dccp-option 2 ACCEPT; =item B Match the 6 bit DSCP field within the TOS field. mod dscp dscp 11; mod dscp dscp-class AF41; =item B Match the ECN bits of an IPv4 TCP header. mod ecn ecn-tcp-cwr; mod ecn ecn-tcp-ece; mod ecn ecn-ip-ect 2; Type "iptables -m ecn -h" for details. =item B Checks the SPI header in an ESP packet. mod esp espspi 0x101; mod esp espspi ! 0x200:0x2ff; =item B "This module matches the EUI-64 part of a stateless autoconfigured IPv6 address. It compares the EUI-64 derived from the source MAC address in Ehternet frame with the lower 64 bits of the IPv6 source address. But "Universal/Local" bit is not compared. This module doesn't match other link layer frame, and is only valid in the PREROUTING, INPUT and FORWARD chains." mod eui64 ACCEPT; =item B "This module matches a rate limit based on a fuzzy logic controller [FLC]." mod fuzzy lower-limit 10 upper-limit 20 ACCEPT; =item B Matches the Hop-by-Hop Options header (ip6). mod hbh hbh-len 8 ACCEPT; mod hbh hbh-len !8 ACCEPT; mod hbh hbh-opts (1:4 2:8) ACCEPT; =item B Matches the Hop Limit field (ip6). mod hl hl-eq (8 10) ACCEPT; mod hl hl-eq !5 ACCEPT; mod hl hl-gt 15 ACCEPT; mod hl hl-lt 2 ACCEPT; =item B Checks which conntrack helper module tracks this connection. The port may be specified with "-portnr". mod helper helper irc ACCEPT; mod helper helper ftp-21 ACCEPT; =item B Check ICMP specific attributes. This module is automatically loaded when you use "protocol icmp". proto icmp icmp-type echo-request ACCEPT; This option can also be used in be I domain, although this is called B in F. Use "iptables -p icmp C<-h>" to obtain a list of valid ICMP types. =item B Match a range of IPv4 addresses. mod iprange src-range 192.168.2.0-192.168.3.255; mod iprange dst-range ! 192.168.6.0-192.168.6.255; =item B Match on IPv4 header options like source routing, record route, timestamp and router-alert. mod ipv4options ssrr ACCEPT; mod ipv4options lsrr ACCEPT; mod ipv4options no-srr ACCEPT; mod ipv4options !rr ACCEPT; mod ipv4options !ts ACCEPT; mod ipv4options !ra ACCEPT; mod ipv4options !any-opt ACCEPT; =item B Matches the IPv6 extension header (ip6). mod ipv6header header !(hop frag) ACCEPT; mod ipv6header header (auth dst) ACCEPT; =item B Similar to 'mod limit', but adds the ability to add per-destination or per-port limits managed in a hash table. mod hashlimit hashlimit 10/minute hashlimit-burst 30/minute hashlimit-mode dstip hashlimit-name foobar ACCEPT; Possible values for hashlimit-mode: dstip dstport srcip srcport (or a list with more than one of these). There are more possible settings, type "iptables -m hashlimit -h" for documentation. =item B Check the package length. mod length length 128; # exactly 128 bytes mod length length 512:768; # range mod length length ! 256; # negated =item B Limits the packet rate. mod limit limit 1/second; mod limit limit 15/minute limit-burst 10; Type "iptables -m limit -h" for details. =item B Match the source MAC address. mod mac mac-source 01:23:45:67:89; =item B Matches packets based on their netfilter mark field. This may be a 32 bit integer between 0 and 4294967295. mod mark mark 42; =item B Matches the mobility header (domain I). proto mh mh-type binding-update ACCEPT; =item B Match a set of source or destination ports (UDP and TCP only). mod multiport source-ports (https ftp); mod multiport destination-ports (mysql domain); This rule has a big advantage over "dport" and "sport": it generates only one rule for up to 15 ports instead of one rule for every port. =item B Match every 'n'th packet. mod nth every 3; mod nth counter 5 every 2; mod nth start 2 every 3; mod nth start 5 packet 2 every 6; Type "iptables -m nth -h" for details. =item B Match packets depending on the operating system of the sender. mod osf genre Linux; mod osf ! genre FreeBSD ttl 1 log 1; Type "iptables -m osf -h" for details. =item B Check information about the packet creator, namely user id, group id, process id, session id and command name. mod owner uid-owner 0; mod owner gid-owner 1000; mod owner pid-owner 5432; mod owner sid-owner 6543; mod owner cmd-owner "sendmail"; ("cmd-owner", "pid-owner" and "sid-owner" require special kernel patches not included in the vanilla Linux kernel) =item B Matches the physical device on which a packet entered or is about to leave the machine. This is useful for bridged interfaces. mod physdev physdev-in ppp1; mod physdev physdev-out eth2; mod physdev physdev-is-in; mod physdev physdev-is-out; mod physdev physdev-is-bridged; =item B Check the link-layer packet type. mod pkttype pkt-type unicast; mod pkttype pkt-type broadcase; mod pkttype pkt-type multicast; =item B Matches IPsec policy being applied to this packet. mod policy dir out pol ipsec ACCEPT; mod policy strict reqid 23 spi 0x10 proto ah ACCEPT; mod policy mode tunnel tunnel-src 192.168.1.2 ACCEPT; mod policy mode tunnel tunnel-dst 192.168.2.1 ACCEPT; mod policy strict next reqid 24 spi 0x11 ACCEPT; Note that the keyword I is also used as a shorthand version of I (built-in match module). You can fix this conflict by always using the long keyword I. =item B Detect TCP/UDP port scans. mod psd psd-weight-threshold 21 psd-delay-threshold 300 psd-lo-ports-weight 3 psd-hi-ports-weight 1 DROP; =item B Implements network quotas by decrementing a byte counter with each packet. mod quota quota 65536 ACCEPT; =item B Match a random percentage of all packets. mod random average 70; =item B Match the routing realm. Useful in environments using BGP. mod realm realm 3; =item B Temporarily mark source IP addresses. mod recent set; mod recent rcheck seconds 60; mod recent set rsource name "badguy"; mod recent set rdest; mod recent rcheck rsource name "badguy" seconds 60; mod recent update seconds 120 hitcount 3 rttl; This netfilter module has a design flaw: although it is implemented as a match module, it has target-like behaviour when using the "set" keyword. L =item B Match the IPv6 routing header (ip6 only). mod rt rt-type 2 rt-len 20 ACCEPT; mod rt rt-type !2 rt-len !20 ACCEPT; mod rt rt-segsleft 2:3 ACCEPT; mod rt rt-segsleft !4:5 ACCEPT; mod rt rt-0-res rt-0-addrs (::1 ::2) rt-0-not-strict ACCEPT; =item B Check SCTP (Stream Control Transmission Protocol) specific attributes. This module is automatically loaded when you use "protocol sctp". proto sctp sport 1234 dport 2345 ACCEPT; proto sctp chunk-types only DATA:Be ACCEPT; proto sctp chunk-types any (INIT INIT_ACK) ACCEPT; proto sctp chunk-types !all (HEARTBEAT) ACCEPT; Use "iptables -p sctp C<-h>" to obtain a list of valid chunk types. =item B Checks the source or destination IP/Port/MAC against a set. mod set set badguys src DROP; See L for more information. =item B Checks the connection tracking state. mod state state INVALID DROP; mod state state (ESTABLISHED RELATED) ACCEPT; Type "iptables -m state -h" for details. =item B Successor of B and B, currently undocumented in the iptables(8) man page. mod statistic mode random probability 0.8 ACCEPT; mod statistic mode nth every 5 packet 0 DROP; =item B Matches a string. mod string string "foo bar" ACCEPT; mod string algo kmp from 64 to 128 hex-string "deadbeef" ACCEPT; =item B Checks TCP specific attributes. This module is automatically loaded when you use "protocol tcp". proto tcp sport 1234; proto tcp dport 2345; proto tcp tcp-flags (SYN ACK) SYN; proto tcp tcp-flags ! (SYN ACK) SYN; proto tcp tcp-flags ALL (RST ACK); proto tcp syn; proto tcp tcp-option 2; proto tcp mss 512; Type "iptables -p tcp -h" for details. =item B Check the TCP MSS field of a SYN or SYN/ACK packet. mod tcpmss mss 123 ACCEPT; mod tcpmss mss 234:567 ACCEPT; =item B