pax_global_header00006660000000000000000000000064130367762330014524gustar00rootroot0000000000000052 comment=1123e0c05a5955501d108c10ddeae77867f01f2c uif-1.1.8/000077500000000000000000000000001303677623300123165ustar00rootroot00000000000000uif-1.1.8/COPYRIGHT000066400000000000000000000020511303677623300136070ustar00rootroot00000000000000Copyright (C) 2002-2015 Jörg Platte Copyright (C) 2002-2015 Cajus Pollmeier Copyright (C) 2013-2017 Mike Gabriel Copyright (C) 2013-2015 Alex Owen 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA On Debian GNU/Linux systems, a copy of the GNU General Public License may be found in the file /usr/share/common-licenses/GPL-2. uif-1.1.8/ChangeLog000066400000000000000000000330561303677623300140770ustar00rootroot000000000000002017-01-15 23:48:57 +0100 Mike Gabriel (204599c) * release 1.1.8 (HEAD, master) 2017-01-15 23:48:02 +0100 Mike Gabriel (d913b96) * validateData: Prevent from using networks with MAC addresses neither for outward bound nor for destination networks. 2017-01-15 23:24:33 +0100 Mike Gabriel (477c55b) * Better test and fix MAC address based source filtering. 2017-01-15 16:05:54 +0100 Mike Gabriel (9d20e8e) * release 1.1.7 (tag: 1.1.7, origin/master) 2017-01-15 16:05:07 +0100 Mike Gabriel (bd85804) * MAC-source filtering, regression fix: Re-add push of $ip to @netobjects if network object contains a MAC address. 2017-01-15 15:12:33 +0100 Mike Gabriel (36d6d86) * UIF: Allow MAC syntax in network items only with real IP addresses, not with DNS resolvable host names. 2017-01-15 14:54:24 +0100 Mike Gabriel (3435812) * release 1.1.6 (tag: 1.1.6) 2017-01-15 14:56:59 +0100 Mike Gabriel (0038831) * Makefile: Fix installation of uif.initscript. 2017-01-15 14:53:29 +0100 Mike Gabriel (9c01c91) * uif.conf.5: Add some hints and notes about IPv6 support. 2017-01-15 14:44:23 +0100 Mike Gabriel (6d01761) * doc files: consistently use UIF in capital letters. 2017-01-15 14:42:10 +0100 Mike Gabriel (868ac44) * services file: Add some more services (kerberos5 et al., ldaps, swat, openvpn, mysql, munin, cfenging, xmpp-client, xmpp-server, icinga2, webmin and puppet). 2017-01-15 14:26:03 +0100 Mike Gabriel (cfee841) * COPYRIGHT: Update copyright date for Mike Gabriel. 2017-01-15 14:23:26 +0100 Mike Gabriel (577cc6b) * ChangeLog: Convert to GNU ChangeLog style, generated from Git history. 2017-01-15 14:22:41 +0100 Mike Gabriel (d75e0ed) * INSTALL.md: Typo fix in Perl module name. 2017-01-15 14:21:55 +0100 Mike Gabriel (8766e7b) * Drop former uif initscript, replaced by new uif.initscript file. 2017-01-15 14:19:13 +0100 Mike Gabriel (26c5c19) * Revert "release 1.1.6" 2017-01-15 14:15:33 +0100 Mike Gabriel (465c6da) * Rename README.IPv6 -> README.IPv6.md 2017-01-15 14:13:04 +0100 Mike Gabriel (ed896f4) * release 1.1.6 2017-01-15 14:09:15 +0100 Mike Gabriel (f2f7bf2) * Update most documentation files and convert to markdown syntax. 2017-01-15 13:59:11 +0100 Mike Gabriel (13adace) * init script: Adopting Debian's init script as an example into upstream code. 2017-01-15 13:57:30 +0100 Mike Gabriel (402d8f5) * Add VERSION file (with last released version number). 2017-01-15 13:56:25 +0100 Mike Gabriel (6aae291) * Drop debian/ packaging folder, we are an upstream project. 2017-01-15 13:49:08 +0100 Mike Gabriel (91d3907) * IPv6 name resolution: Work around broken IPv6 name resolution in NetAddr::IP (see: CPAN issue #119858). 2017-01-13 16:16:54 +0100 Mike Gabriel (2baab0e) * IPv6 support: More locations in the code spotted, where we need to differentiate between IPv4 and IPv6 mode. 2016-04-18 11:52:59 +0200 Mike Gabriel (91cb12b) * Merge branch 'ka7-spelling_fix' 2016-04-16 14:33:51 +0200 klemens (ae13340) * spelling fix, as of lintian.debian.org (ka7-spelling_fix) 2015-03-11 10:00:49 +0100 Mike Gabriel (01892a9) * release 1.1.5 (tag: 1.1.5) 2015-03-11 10:00:16 +0100 Mike Gabriel (45b9141) * bump version and dates 2015-03-11 09:56:51 +0100 Mike Gabriel (d8c8700) * Fix severe flaw in IPv4-only/IPv6-only rule setup. Don't open IPv4 wholes when setting up IPv6-only rules and vice versa. 2014-12-09 13:52:24 +0100 Mike Gabriel (3ffeb89) * Fix another typo in same error message. 2014-12-09 13:13:29 +0100 Mike Gabriel (5cb7c81) * Fix spelling of Debian in error message. (Closes: Debian bug #772496). 2014-07-01 10:31:49 +0200 Mike Gabriel (2754565) * release 1.1.4 (tag: 1.1.4) 2014-07-01 10:27:32 +0200 Mike Gabriel (47e10a2) * debian/rules: Update from Debian package. 2014-07-01 10:27:21 +0200 Mike Gabriel (da54e44) * debian/copyright: Update from Debian package. 2014-07-01 10:08:23 +0200 Mike Gabriel (2a5b7ae) * Make sure that masq|snat|dnat|nat rules get ignored in IPv6 mode. 2014-06-13 21:24:00 +0200 Mike Gabriel (f6505c5) * release 1.1.3 (tag: 1.1.3) 2014-06-03 23:48:36 +0200 Mike Gabriel (23707ba) * uif.conf: Drop the fw+ filter for ICMPv6 rules. 2014-06-03 23:44:42 +0200 Mike Gabriel (244cbdd) * debian/uif.postinst: Provide a DebConf mediated workstation config that also protects from IPv6 attacks. 2014-06-03 23:40:34 +0200 Mike Gabriel (f888b00) * IPv6: make neighbor-solicitation (packet type 135) a must for the incoming filter 2014-06-03 23:39:52 +0200 Mike Gabriel (d318892) * examples: Provide an IPv4+6 config file example 2014-05-20 17:01:41 +0200 Mike Gabriel (76474e5) * uif.conf: Allow packet type 136 (neighbor-advertisement). Allow forwarding _and_ inbound ICMP messages. 2014-05-20 16:28:42 +0200 Mike Gabriel (a62ad68) * release 1.1.2 (tag: 1.1.2) 2014-05-20 16:28:08 +0200 Mike Gabriel (01513a7) * uif.spec: Update version+release field. 2014-05-20 16:26:06 +0200 Mike Gabriel (d91cdce) * debian/changelog: drop non-sense at EOF 2014-05-20 16:03:33 +0200 Mike Gabriel (f68c9e4) * uif.conf: Enable inclusion of services file by default. 2014-05-20 16:06:28 +0200 Mike Gabriel (2fdbae3) * services: Use more appropriate icmp packet type names. 2014-05-20 16:00:19 +0200 Mike Gabriel (4bf5f76) * debian/changelog: Use revison -0 in package version. 2014-01-28 23:33:51 +0100 Mike Gabriel (3c10099) * Add services "rdp" and "vnc-support" to services file. 2014-01-28 23:32:57 +0100 Mike Gabriel (5debe50) * Provide new protocol: ipv6-icmp. Rework ICMP types in services file. 2014-01-22 16:31:46 +0100 Mike Gabriel (e384b5b) * release 1.1.1 (tag: 1.1.1) 2014-01-22 16:29:48 +0100 Mike Gabriel (2084ea5) * Alioth-canonicalize Vcs-Git: field. 2014-01-22 16:27:49 +0100 Mike Gabriel (46b887e) * Install lintian overrides. Override issue false-positive issue maintainer-script-should-not-use-service. 2014-01-22 16:25:25 +0100 Mike Gabriel (3872ce4) * Make sure that hostnames resolve to IPv6 addresses when setting up the IPv6 filtering rules. 2014-01-22 16:04:42 +0100 Mike Gabriel (9bac303) * Default log level for iptables: crit (not debug). 2014-01-22 16:03:42 +0100 Mike Gabriel (f12a8bb) * debian/uif.init: Leave reporting startup failures to init-functions. Beautify init script when failures occur. 2014-01-22 15:24:50 +0100 Mike Gabriel (25cee2a) * Fix typos and mal-used minus signs in uif.conf.5 man page. 2014-01-22 15:06:47 +0100 Mike Gabriel (a3ce0ba) * Continue development... debian/rules: Add get-orig-source rule. 2014-01-22 14:37:06 +0100 Mike Gabriel (1a2ffc9) * release 1.1.0 (tag: 1.1.0) 2014-01-22 14:36:33 +0100 Mike Gabriel (43a6cdc) * Calls of update-rc.d are now handled by debhelper. Add #DEBHELPER# macro after the new uif configuration has been created. 2014-01-22 14:35:38 +0100 Mike Gabriel (cfc350b) * debian/uif.init: typo fix 2014-01-22 14:25:49 +0100 Mike Gabriel (2afe691) * Bump Standards: to 3.9.5. No changes needed. 2014-01-22 14:24:52 +0100 Mike Gabriel (e99b29f) * debian/rules: syntax fix 2014-01-22 14:24:07 +0100 Mike Gabriel (44f01b3) * debian/uif.init: Provide an LSB compliant init script for Debian. debian/uif.install: Don't install upstream's init script on Debian system. 2014-01-22 14:04:15 +0100 Mike Gabriel (2e5c2f0) * cosmetic removals of "/" before debian/ folder name 2014-01-22 14:03:34 +0100 Mike Gabriel (dc52d1b) * debian/uif.postinst: Adapt Debianic configuration of workstation profile to IPv6 capabilities. Enable IPv6 by default, as well, on Debian systems. 2014-01-22 14:02:02 +0100 Mike Gabriel (b7650fb) * add EOL at EOF 2014-01-22 14:01:40 +0100 Mike Gabriel (2ce5855) * Enable IPv6 support by default. 2014-01-22 14:00:11 +0100 Mike Gabriel (faf5264) * remove Debian specific comment in upstream uif.conf, hint to IPv4-only / IPv6-only network names usage in uif.conf 2014-01-22 13:52:45 +0100 Mike Gabriel (fff07b9) * Support filtering rules that apply to IPv4/IPv6 only. 2014-01-22 12:46:40 +0100 Mike Gabriel (3c31d9d) * Add /me and Alex Owen as copyright holders. 2014-01-22 12:45:53 +0100 Mike Gabriel (fdeef77) * uif.spec: update RPM build script 2014-01-22 12:37:32 +0100 Mike Gabriel (5638602) * service: fix author name (convert to UTF-8) 2014-01-22 12:36:15 +0100 Mike Gabriel (96ad6d6) * README.IPv6: typo fix 2014-01-22 12:34:42 +0100 Mike Gabriel (207e3cd) * Keep lines in README below 80 characters. 2014-01-22 12:32:55 +0100 Mike Gabriel (a665b56) * Drop deb: rule vom Makefile. 2014-01-22 12:32:00 +0100 Mike Gabriel (03b3a8f) * Update upstream download source in INSTALL file. Mark Net::LDAP as optional dependency. 2014-01-22 12:30:09 +0100 Mike Gabriel (3645e5e) * Update COPYRIGHT file. Add /me as copyright co-holder and update FSF address. 2013-10-31 09:29:31 +0100 Mike Gabriel (2fbf3e6) * Init script: be more explicit on whether init script actions are IPv4 or IPv6 actions. 2013-10-31 09:27:54 +0100 Mike Gabriel (4a7215c) * debian/rules: run dh_link during 2013-08-07 10:26:35 +0200 Mike Gabriel (16186ec) * debian scripts: whitespace/tab fixes 2013-08-07 10:23:56 +0200 Mike Gabriel (0be6dd8) * /debian/uif.config: whitespace/tab fixes 2013-08-07 10:21:35 +0200 Mike Gabriel (c7acd0b) * Makefile: fix installation of doc files 2013-08-07 10:18:28 +0200 Mike Gabriel (019c78e) * Provide IPv4/IPv6 capable set of default configuration files. Rename example files to denote that they show IPv4-only examples. 2013-08-07 10:10:40 +0200 Mike Gabriel (2b99d66) * fix encoding in copyright file 2013-08-06 21:30:33 +0200 Mike Gabriel (9f3554a) * /debian/control: Drop separate package uif-ldap again. Sync in packaging folder from Debian. 2013-06-11 23:02:20 +0200 Mike Gabriel (cd1fd5a) * /debian/rules: Run dh_link during install. 2013-06-11 22:54:01 +0200 Mike Gabriel (7fbbaad) * version fix, encoding fix, whitespace fix in Makefile 2013-06-11 22:52:24 +0200 Mike Gabriel (61a192d) * /debian/*.docs: Install README* files into bin:packages. 2013-06-11 22:47:35 +0200 Mike Gabriel (17225ff) * whitespace cleanup 2013-06-11 22:36:57 +0200 Mike Gabriel (9e77348) * coherent spelling of IPv4 and IPv6 in man page 2013-06-11 22:34:57 +0200 Mike Gabriel (2336ea3) * coherent spelling of IPv4 and IPv6 in init script 2013-06-11 22:33:23 +0200 Mike Gabriel (9f7f2bb) * propely tab'ify init script 2013-06-11 22:27:21 +0200 Mike Gabriel (341e532) * Create README.IPv6 as upstream file. 2013-06-11 22:26:29 +0200 Mike Gabriel (b51cf05) * /debian/rules: Leaving clean-up to dh_clean. 2013-06-11 22:25:23 +0200 Mike Gabriel (a4fd6bf) * Update README, mention issue trackers. 2013-06-11 01:12:08 +0200 Mike Gabriel (6b40a6e) * update changelog 2013-06-11 01:10:09 +0200 Alex Owen (0ffa361) * IPv6 patch 2013-06-11 01:08:27 +0200 Mike Gabriel (a374f15) * import packaging from Debian package 2013-06-11 01:03:24 +0200 Mike Gabriel (48c887d) * now really fix umlaut in uif.pl 2013-06-11 00:30:41 +0200 Mike Gabriel (d0b9dbf) * Continue development... 2013-06-11 00:29:02 +0200 Mike Gabriel (44a1201) * release 1.0.8 (tag: 1.0.8) 2013-06-11 00:28:45 +0200 Mike Gabriel (e694cb0) * update ChangeLog 2013-06-11 00:26:50 +0200 Mike Gabriel (2ee8df9) * convert Umlaut to UTF-8, fix FSF address 2013-06-11 00:25:07 +0200 Mike Gabriel (bc4d0f9) * fix hyphens and spelling errors in man pages 2013-06-11 00:24:37 +0200 Mike Gabriel (1cccc49) * import packaging files from Debian package 2013-06-11 00:12:25 +0200 Mike Gabriel (1d3bc90) * Continue development... 2013-06-11 00:09:47 +0200 Mike Gabriel (327a5ba) * add Description: keyword to LSB header 2013-06-10 23:39:10 +0200 Mike Gabriel (d1f04b6) * release 1.0.7 2013-06-10 23:38:42 +0200 Mike Gabriel (234f4f6) * add myself to the list of upstream people 2013-06-10 23:31:02 +0200 Mike Gabriel (f3f6a1a) * /debian/control: Add uif-ldap to Suggests: field 2013-06-10 23:17:04 +0200 Mike Gabriel (15ef174) * split uif into bin:packages uif and uif-ldap 2013-06-10 13:50:59 +0200 Mike Gabriel (c1d0f4d) * Provide a default (nothing-in/all-out) uif.conf. 2013-06-10 13:43:29 +0200 Mike Gabriel (c7606c1) * ChangeLog: moving credits over to Alex Owen 2013-06-10 13:40:52 +0200 Mike Gabriel (2573ad5) * abusing /debian/changelog as upstream changelog 2013-06-10 13:32:17 +0200 Mike Gabriel (252c79a) * Run dh_clean in clean stanza. 2013-06-10 13:31:43 +0200 Mike Gabriel (d86b092) * fix mailadress in changelog footer 2013-06-10 13:31:04 +0200 Mike Gabriel (3ba49af) * remove build cruft from /debian folder 2013-06-10 13:28:18 +0200 Mike Gabriel (7775ed3) * remove stray templates files: templates.de 2013-06-10 13:26:34 +0200 Mike Gabriel (7b14060) * upstream projects are easier to handle with source format 3.0 (native) 2013-06-10 13:24:52 +0200 Mike Gabriel (5907709) * Make LDAP dependency optional. 2013-06-10 13:23:57 +0200 Mike Gabriel (1a74530) * use my NWT address for this upstream project, set changelog to UNRELEASED 2013-06-10 13:22:05 +0200 Mike Gabriel (16f44c2) * rewrite /debian/changelog, use as upstream changelog from now on 2013-06-10 13:18:09 +0200 Mike Gabriel (369914e) * import all gains from the latest Debian package of uif (debian/1.0.6-3) 2011-08-24 08:25:53 +0200 Cajus Pollmeier (78811fa) * Fixed mail (tag: 1.0.6) 2011-08-24 08:24:59 +0200 Cajus Pollmeier (f97ce59) * Fixed encoding 2011-08-24 08:23:16 +0200 Cajus Pollmeier (d15aeda) * Initial checkin uif-1.1.8/INSTALL.md000066400000000000000000000015111303677623300137440ustar00rootroot00000000000000# Installation Guide for UIF 1.1.8 This file contains some quick installation hints for the UIF package. ## Download You can get the newest version at https://github.com/cajus/uif. ## Dependencies In order to use the script, you need iptables, ip6tables, Perl, NetAddr::IP (>=3.0), Socket, Data::Validate::IP and optionally Net::LDAP. ## Build Well - there's nothing to build. Just change the PREFIX on top of the Makefile and do a "make install". If you want to start UIF during bootup you should add the needed links in /etc/rc*. See file "uif.initscript" for a working init script. ## Debian The UIF package is regularly released via Debian. Use APT to retrieve this piece of software directly from the Debian archives: ``` # apt-get install uif ``` ## Documentation Use "man uif" and "man uif.conf" to see what's possible. uif-1.1.8/Makefile000066400000000000000000000040151303677623300137560ustar00rootroot00000000000000# uif-1.1.x Installer Makefile # # Cajus Pollmeier # Jörg Platte # Mike Gabriel # Change here to install to different location PREFIX = ${DESTDIR} VERS = `sed -n "s/[^ ]* (\([0-9.]*\)-[0-9]*).*/\1/p" debian/changelog | head -1` install: @echo "Installing uif script..." @# create directories install -o root -g root -m 700 -d ${PREFIX}/etc/uif install -o root -g root -m 755 -d ${PREFIX}/etc/default install -o root -g root -m 755 -d ${PREFIX}/etc/init.d install -o root -g root -m 755 -d ${PREFIX}/etc/ldap/schema install -o root -g root -m 755 -d ${PREFIX}/usr/sbin install -o root -g root -m 755 -d ${PREFIX}/usr/share/doc/uif install -o root -g root -m 755 -d ${PREFIX}/usr/share/man/man8 install -o root -g root -m 755 -d ${PREFIX}/usr/share/man/man5 @# install files install -o root -g root -m 700 uif.pl ${PREFIX}/usr/sbin/uif install -o root -g root -m 600 default ${PREFIX}/etc/default/uif install -o root -g root -m 600 services ${PREFIX}/etc/uif if [ ! -e ${PREFIX}/etc/uif/uif.conf ]; then install -o root -g root -m 600 uif.conf ${PREFIX}/etc/uif; fi if [ ! -e ${PREFIX}/etc/uif/uif-ipv4-networks.inc ]; then install -o root -g root -m 600 uif-ipv4-networks.inc ${PREFIX}/etc/uif; fi if [ ! -e ${PREFIX}/etc/uif/uif-ipv6-networks.inc ]; then install -o root -g root -m 600 uif-ipv6-networks.inc ${PREFIX}/etc/uif; fi install -o root -g root -m 755 uif.initscript ${PREFIX}/etc/init.d mv ${PREFIX}/etc/init.d/uif.initscript ${PREFIX}/etc/init.d/uif install -o root -g root -m 644 uif.schema ${PREFIX}/etc/ldap/schema @# install documentation install -o root -g root -m 644 docs/uif.conf.IPv4.tmpl ${PREFIX}/usr/share/doc/uif install -o root -g root -m 644 docs/uif.conf.IPv4+6.tmpl ${PREFIX}/usr/share/doc/uif install -o root -g root -m 644 docs/examples.IPv4.txt ${PREFIX}/usr/share/doc/uif install -o root -g root -m 644 uif.8 ${PREFIX}/usr/share/man/man8 install -o root -g root -m 644 uif.conf.5 ${PREFIX}/usr/share/man/man5 uif-1.1.8/README.IPv6.md000066400000000000000000000035331303677623300143640ustar00rootroot00000000000000# IPv6 support for UIF 1.1.8 Starting with version 1.1.0 UIF is able to handle IPv6 iptables as well as IPv4 iptables. The IPv6 support was originally provided by Alex Owen via a patch sent to the Debian bug tracker. Awesome thanks to Alex for this initial piece of work!!! With IPv6 support added, UIF can now also produce IPv6 firewall rules. The init script can, by setting IPV6MODE=1 in /etc/default/uif, be made to install the IPv4 rules from /etc/uif/uif.conf and the IPv6 rules from /etc/uif/uif6.conf. Judicious use of the include and include4 and include6 sections of the config files can mean that the ipv6 and ipv4 rules can be identical except for including a network section with IPv4 definitions and IPv6 definitions respectivly. ## Configuration Examples The file uif6.conf can be a sym-link to uif.conf or contain: ``` --uif6.conf-- include { "/etc/uif/uif.conf" } ------------- ``` The file uif.conf can then be used for a single set of rules but can include different network definitions as needed: ``` --uif.conf-- #include common services include { "/etc/uif/services" } # in IPv4 mode include IPv4 network definitions include4 { "/etc/uif/networks4" } #In IPv6 mode include IPv6 network defnintions include6 { "/etc/uif/networks6" } #common filter block for both ipv4 and ipv6 filter { #Put your firewall rules here } ------------ ``` As an addition it is possible to append "(4)" or "(6)" to network names in filtering rules (e.g.: "in+ s=trusted(4)"). This limits the application of this rule to the specified IP protocol version only. This can be especially helpful, if some of your network names only exist for one IP protocol version but not for the other. ## AUTHORS * Alex Owen , Sun, 15 Jul 2012 14:41:22 +0100 * Mike Gabriel , Wed, 22 Jan 2014 13:50:01 +0100 uif-1.1.8/README.LDAP.md000066400000000000000000000010351303677623300143130ustar00rootroot00000000000000# README.LDAP for UIF 1.1.8 ## Documentation / LDAP There is some LDAP support built into UIF, with that you can handle a big farm of diskles router configurations. Use uif(8) and information provided in the doc/ directory to configure the firewall fitting your needs. ## Call for help The LDAP support in UIF hasn't been tested for quite a while. Most users of UIF have use cases with local configuration files. If you feel like contributing, please dive into the LDAP functionality of UIF and test it, report bugs, give feedback, etc. uif-1.1.8/README.md000066400000000000000000000021031303677623300135710ustar00rootroot00000000000000# README for UIF 1.1.8 ## Documentation The UIF project has been developed for a diskless router system and provides a mechanism to create and simplify packet filter rules. It forces you to provide names for every value you use in order to make firewalls less confusing. Please have a look at the man pages for uif(8) and uif.conf(5). There are also example configurations in the docs/ directory. There is some LDAP support built-in, with that you can handle a big farm of diskles router configurations. Use uif(8) and information provided in the doc/ directory to configure the firewall fitting your needs. ## Bugs / Wishlist UIF is on Github. If you've found a bug, or have suggestions for future versions please report it via the project's issue tracker: https://github.com/cajus/uif/issues If you have installed UIF on Debian, you can also use the Debian BTS for reporting bugs. As the Debian maintainer of UIF is a member of the UIF upstream development team, the Debian bugs will also reach upstream quickly. Have fun, -Jörg Platte, Cajus Pollmeier, Mike Gabriel, Alex Owen uif-1.1.8/VERSION000066400000000000000000000000051303677623300133610ustar00rootroot000000000000001.1.8uif-1.1.8/default000066400000000000000000000012701303677623300136650ustar00rootroot00000000000000## Debian firewall package standard values # See "man 8 uif" for details. # the iptables loglevel LOGLEVEL="crit" # prefix for all logged incidents LOGPREFIX="FW" # iptables log specific options LOGLIMIT="20/minute" LOGBURST="5" # iptables limit specific options LIMIT="20/minute" BURST="5" # firewall testing timeout TIMEOUT=30 # specify modules to load before startup MODULES="ip_conntrack_ftp" # who should get the mails when the script fails MAILTO="root" # prefix for accounting rules ACCOUNTPREFIX="ACC_" # IPV6MODE can be set to 0 or 1. By default it is 0 # If set to 1 then both an IPv4 and an IPv6 firewall will be started # Uncomment below to enable the IPV6MODE IPV6MODE=1 uif-1.1.8/docs/000077500000000000000000000000001303677623300132465ustar00rootroot00000000000000uif-1.1.8/docs/examples.IPv4.txt000066400000000000000000000075531303677623300164200ustar00rootroot00000000000000EXAMPLES for UIF ================ These sample configurations are fully virtual setups but may contain valid ip addresses. 1) Simple router/proxy setup Imagine the following scenario with one packet filter and masquerading: ppp0 eth0 internet-----------filter-------------proxy---------intranet 193.174.71.23 192.168.0.1 192.168.0.2 192.168.0.0/24 The filter masquerades the proxy address and rejects all other internal traffic to the internet. Don't forget to enable forwarding (sysctl -w net.ipv4.ip_forward=1), respectivly adding it to /etc/sysctl.conf. 8<--------------------------------------------------------------------- include { # include the basic service definitions "/etc/uif/services" } service { # define all valid services from the proxy into the internet proxytraffic http https ntp pop3s imaps smtp ssh ftp } network { # define all networks and hosts proxy 192.168.0.2 intern 192.168.0.0/24 gonicus 21.8.6.9 ds 129.27.18.16 # accept external ssh connections from gonicus and ds sshok ds gonicus } interface { # define all local interfaces loop lo extern ppp0 intern eth0 } input { # permit all loopback traffic in+ i=loop # accept local ssh logins in+ i=intern s=intern p=ssh # accept external ssh connections from gonicus and ds in+ i=extern s=sshok p=ssh # accept pings in+ i=extern p=ping # reject and log all other incoming connentions in- f=log(incoming),reject } output { # permit all loopback traffic out+ o=loop # permit all outgoing traffic to the internal network out+ o=intern # permit outgoing ntp and ssh connections out+ o=extern p=ntp,ssh # reject all and log all other outgoing connentions out- f=log(outgoing),reject } forward { # in case of an pppoe dsl line the following line may be useful # it sets the mss of every forwarded packet to a smaller value fw> o=extern # forward previously defined proxy traffic to external hosts fw+ o=extern s=proxy p=proxytraffic # reject all and log all other outgoing connentions fw- f=log(forwarding),reject } masquerade { # masquerade proxy traffic masq+ o=extern s=proxy } --------------------------------------------------------------------->8 2) Router doing nat and transparent proxys Imagine the following (not really usable) scenario: eth0 eth1 Internet---------filter------------switch 80.67.1.53 10.10.0.1 | +--gatekeeper 10.10.0.15 | +--[intranet] Imagine "filter" is running squid as a transparent proxy and "gatekeeper" is your ssh gateway to the intranet. No other connections to the intranet are allowed. "filter" is acting as nameserver, no additional connections from the inside to the outside are allowed. 8<--------------------------------------------------------------------- include { # include the basic service definitions "/etc/uif/services" } network { # define all networks and hosts proxy 10.10.0.1 intern 10.10.0.0/16 gate 10.10.0.5 } interface { # define all local interfaces loop lo extern eth0 intern eth1 } filter { # permit all loopback traffic in+ i=loop out+ o=loop # permit all outgoing traffic for "filter" out+ o=intern,extern # accept pings in+ i=extern p=ping # accept local ssh logins, dns, http in+ i=intern s=intern p=ssh,dns,http # redirect port 80 to 10.10.0.1:3128 nat+ i=intern s=intern p=http D=proxy P=squid # redirect incomming ssh connections to gatekeeper nat+ i=extern p=ssh D=gatekeeper # reject and log all other connentions in- f=log(incoming),reject out- f=log(outgoing),reject fw- f=log(forward),reject } --------------------------------------------------------------------->8 uif-1.1.8/docs/uif.conf.IPv4+6.tmpl000066400000000000000000000115001303677623300165720ustar00rootroot00000000000000## Debian GNU Linux Firewall Package ## This file has been automatically generated by debconf. It will be overwritten ## the next time you configure firewall without choosing "don't touch". ## Sysconfig definitions # These entries define the global behaviour of the firewall package. Normally # they are preset in /etc/default/uif and may be overwritten by this # section. # # syntax: LogLevel : set the kernel loglevel for iptables rules # LogPrefix: prepend this string to all iptables logs # LogLimit: set packet log limit per time interval (times/interval) # LogBurst: set packet log burst # Limit: set packet limit per time interval (times/interval) # Burst: set packet burst # example: # sysconfig { # LogLevel debug # LogPrefix FW # LogLimit 20/minute # LogBurst 5 # Limit 20/minute # Burst 5 # AccountPrefix ACC_ # } ## Include predefined services # The include section takes a bunch of files and includes them into this # configuration file. # # syntax: "filename" #include { # "/etc/uif/services" #} ## Services needed for workstation setup # The service section provides the protocol definitions you're # using in the rules. You're forced to declare everything you # need for your setup. # # syntax: service_name [tcp([source:range]/[dest:range])] [udp([source:range]/[dest:range])] # [protocol_name([source:range][/][dest:range])] [service_name] ... # examples: http tcp(/80) # dns tcp(/53) udp(/53) # group http dns tcp(/443) # ipsec esp(/) udp(/500) service { traceroute udp(32769:65535/33434:33523) icmp(11) ping icmp(8) } ## Network definitions needed for simple workstation setup # In the network section you're asked to provide informations on all # hosts and/or networks running in your setup. # # syntax: net_name [ip-address[:mac-address]] [network] [net_name] # examples: webserver 192.168.1.5 # intranet 10.1.0.0/16 # dmz 10.5.0.0/255.255.0.0 # some intranet dmz 10.2.1.1 # router 10.1.0.1=0A:32:F2:C7:1A:31 network { localhost 127.0.0.1 all 0.0.0.0/0 trusted4 192.168.1.0/24 trusted6 fd00:1:2:3::/64 } ## Interface definitions # Since all definitions used in the filter section are symbolic, # you've to specify symbolic names for all your interfaces you're # going to use. # # syntax: interface_name [unix network interface] [interface_name] # examples: internal eth0 # external ippp0 ipsec0 # allppp ppp+ # group external allppp eth3 interface { loop lo } ## Filter definitions # The filter section defines the rules for in, out, forward, masquerading # and nat. All rules make use of the symbolic names defined above. This # section can be used multiple times in one config file. This makes more # senese when using one of these alias names: # filter, nat, input, output, forward, masquerade # # syntax: in[-/+] [i=interface] [s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # out[-/+] [o=interface] [s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # fw[>/-/+] [i/o=interface][s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # masq[-/+][i/o=interface][s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # nat[-/+] additionally allows [S=from source] [D=to destination] [P=to port:[range]] # additional: # All keys mentioned in the syntax section (in/out/...) can be prefixed with "sl", which # causes the creation of a stateless rule. # flags: limit([count/time[,burst]]) # reject([reject type]) # log([name]) # account(name) # examples: # masq+ o=extern s=intranet # nat+ s=intranet p=http D=relayintern P=squid # in+ s=trusted p=ssh,ping,traceroute,http # out- s=intranet p=smb f=reject # fw- d=microsoft f=reject,log(ms-alert) # slin+ s=testnet # slout- d=testnet # fw> o=extern # fw+ p=myhttp f=account(HTTP) # Take an attention about the protocol for your accounting rules. If you # want to count user http traffice, you may need a "myhttp tcp(80/)". filter { in+ i=loop s=localhost out+ o=loop d=localhost # allow incoming pings for IPv4 in+ s=all(4) p=ping # these IPv6-ICMP types are a MUST for IPv6 in+ s=all(6) p=ping,pong,noroute,packet-too-big,time-exceeded,parameter-problem,neighbor-advertisement,neighbor-solicitation in+ p=traceroute in+ s=trusted4(4) in+ s=trusted6(6) out+ d=all in- f=log(input),reject out- f=log(output),reject fw- f=log(forward),reject } uif-1.1.8/docs/uif.conf.IPv4.tmpl000066400000000000000000000110271303677623300164350ustar00rootroot00000000000000## Debian GNU Linux Firewall Package ## This file has been automatically generated by debconf. It will be overwritten ## the next time you configure firewall without choosing "don't touch". ## Sysconfig definitions # These entries define the global behaviour of the firewall package. Normally # they are preset in /etc/default/uif and may be overwritten by this # section. # # syntax: LogLevel : set the kernel loglevel for iptables rules # LogPrefix: prepend this string to all iptables logs # LogLimit: set packet log limit per time interval (times/interval) # LogBurst: set packet log burst # Limit: set packet limit per time interval (times/interval) # Burst: set packet burst # example: # sysconfig { # LogLevel debug # LogPrefix FW # LogLimit 20/minute # LogBurst 5 # Limit 20/minute # Burst 5 # AccountPrefix ACC_ # } ## Include predefined services # The include section takes a bunch of files and includes them into this # configuration file. # # syntax: "filename" #include { # "/etc/uif/services" #} ## Services needed for workstation setup # The service section provides the protocol definitions you're # using in the rules. You're forced to declare everything you # need for your setup. # # syntax: service_name [tcp([source:range]/[dest:range])] [udp([source:range]/[dest:range])] # [protocol_name([source:range][/][dest:range])] [service_name] ... # examples: http tcp(/80) # dns tcp(/53) udp(/53) # group http dns tcp(/443) # ipsec esp(/) udp(/500) service { traceroute udp(32769:65535/33434:33523) icmp(11) ping icmp(8) } ## Network definitions needed for simple workstation setup # In the network section you're asked to provide informations on all # hosts and/or networks running in your setup. # # syntax: net_name [ip-address[:mac-address]] [network] [net_name] # examples: webserver 192.168.1.5 # intranet 10.1.0.0/16 # dmz 10.5.0.0/255.255.0.0 # some intranet dmz 10.2.1.1 # router 10.1.0.1=0A:32:F2:C7:1A:31 network { localhost 127.0.0.1 all 0.0.0.0/0 trusted 192.168.1.0/24 } ## Interface definitions # Since all definitions used in the filter section are symbolic, # you've to specify symbolic names for all your interfaces you're # going to use. # # syntax: interface_name [unix network interface] [interface_name] # examples: internal eth0 # external ippp0 ipsec0 # allppp ppp+ # group external allppp eth3 interface { loop lo } ## Filter definitions # The filter section defines the rules for in, out, forward, masquerading # and nat. All rules make use of the symbolic names defined above. This # section can be used multiple times in one config file. This makes more # senese when using one of these alias names: # filter, nat, input, output, forward, masquerade # # syntax: in[-/+] [i=interface] [s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # out[-/+] [o=interface] [s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # fw[>/-/+] [i/o=interface][s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # masq[-/+][i/o=interface][s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # nat[-/+] additionally allows [S=from source] [D=to destination] [P=to port:[range]] # additional: # All keys mentioned in the syntax section (in/out/...) can be prefixed with "sl", which # causes the creation of a stateless rule. # flags: limit([count/time[,burst]]) # reject([reject type]) # log([name]) # account(name) # examples: # masq+ o=extern s=intranet # nat+ s=intranet p=http D=relayintern P=squid # in+ s=trusted p=ssh,ping,traceroute,http # out- s=intranet p=smb f=reject # fw- d=microsoft f=reject,log(ms-alert) # slin+ s=testnet # slout- d=testnet # fw> o=extern # fw+ p=myhttp f=account(HTTP) # Take an attention about the protocol for your accounting rules. If you # want to count user http traffice, you may need a "myhttp tcp(80/)". filter { in+ i=loop s=localhost out+ o=loop d=localhost in+ p=ping,traceroute in+ s=trusted out+ d=all in- f=log(input),reject out- f=log(output),reject fw- f=log(forward),reject } uif-1.1.8/services000066400000000000000000000052601303677623300140670ustar00rootroot00000000000000## UIF 1.0 sample services file # (C) 2002-2015, Cajus Pollmeier # (C) 2002-2015, Jörg Platte # (C) 2013-2015, Mike Gabriel # (C) 2013-2015, Alex Owen service { # ICMP & Routing traceroute udp(32769:65535/33434:33523) # ICMP protocol: IPv4 and IPv6 ICMP types ping icmp(echo-request) ipv6-icmp(echo-request) pong icmp(echo-reply) ipv6-icmp(echo-reply) noroute icmp(destination-unreachable) ipv6-icmp(destination-unreachable) router-advertisement icmp(router-advertisement) ipv6-icmp(router-advertisement) router-solicitation icmp(router-solicitation) ipv6-icmp(router-solicitation) # ICMP protocol: IPv4-only ICMP types host-unreachable icmp(host-unreachable) ttl-exceeded icmp(ttl-exceeded) source-quench icmp(source-quench) # ICMP protocol: IPv6-only ICMP types packet-too-big ipv6-icmp(packet-too-big) time-exceeded ipv6-icmp(time-exceeded) parameter-problem ipv6-icmp(parameter-problem) neighbor-advertisement ipv6-icmp(neighbor-advertisement) neighbor-solicitation ipv6-icmp(neighbor-solicitation) # Most common services you may want to filter ftp tcp(/21) ssh tcp(/22) telnet tcp(/23) smtp tcp(/25) whois tcp(/43) dns tcp(/53) udp(/53) bootp tcp(68/67) udp(68/67) http tcp(/80) kerberos5 tcp(/88) pop3 tcp(/110) sunrpc udp(/111) tcp(/111) ident tcp(/113) ntp udp(/123) nntp tcp(/119) smb tcp(/137:139) udp(/137:139) tcp(/445) udp(/445) imap tcp(/143) xdmcp udp(/177) ldap tcp(/389) https tcp(/443) ssmtp tcp(/465) syslog udp(/514) route udp(/520) icmp(9) uucp tcp(/540) real tcp(/554) ipp tcp(/631) udp(/631) mount udp(/635) ldaps tcp(/636) kerberos4 tcp(/750) kerberos-master tcp(/751) passwd-server tcp(/752) krb-prop tcp(/754) krbupdate tcp(/760) swat tcp(/901) imaps tcp(/993) pop3s tcp(/995) openvpn udp(/1194) tcp(/1194) nfs udp(/2049) tcp(/2049) cvspserver tcp(/2401) squid tcp(/3128) mysql tcp(/3306) rdp tcp(/3389) munin tcp(/4949) cfengine tcp(/5308) xmpp-client tcp(/5222) udp(/5222) xmpp-server tcp(/5223) udp(/5223) icinga2 tcp(/5665) vnc-support tcp(/5500:5509) x11 tcp(/6000:6063) proxy tcp(/8080) puppet tcp(/8140) webmin tcp(/10000) dhis udp(/58800) # ipsec ipsec esp(/) udp(/500) # some proprietary protocols arkeia tcp(/617) pcanywhere udp(/5632) tcp(/5631) msterminal tcp(/3389) udp(/3389) # some protocols igmp igmp() pim pim() tcp tcp(0:65535/0:65535) udp udp(0:65535/0:65535) # some useful definitions lowports udp(/1:1023) tcp(/1:1023) highports udp(/1024:65535) tcp(/1024:65535) } uif-1.1.8/uif-ipv4-networks.inc000066400000000000000000000010331303677623300163230ustar00rootroot00000000000000## IPv4 network name definitions for UIF # In the network section you're asked to provide informations on all # IPv4 hosts and/or networks running in your setup. # # syntax: net_name [ip-address[=mac-address]] [network] [net_name] # examples: webserver 192.168.1.5 # intranet 10.1.0.0/16 # dmz 10.5.0.0/255.255.0.0 # some intranet dmz 10.2.1.1 # router 10.1.0.1=0A:32:F2:C7:1A:31 network { localhost 127.0.0.1 all 0.0.0.0/0 # trusted 192.168.1.0/24 } uif-1.1.8/uif-ipv6-networks.inc000066400000000000000000000010511303677623300163250ustar00rootroot00000000000000## IPv6 network name definitions for UIF # In the network section you're asked to provide informations on all # IPv6 hosts and/or networks running in your setup. # # syntax: net_name [ip-address[=mac-address]] [network] [net_name] # examples: webserver 2001:610:1908:b000::148:14 # intranet fd00:0:0:1::/64 # dmz fd00:0:0:5::/64 # some intranet dmz fd00:0:2:1::1 # router fd00:0:0:1::1=0A:32:F2:C7:1A:31 network { localhost ::1 all ::/0 # trusted fd00:1:2:3::/64 } uif-1.1.8/uif.8000066400000000000000000000107701303677623300131770ustar00rootroot00000000000000.\" -*- nroff -*- .TH UIF 8 "Jan 15th, 2017" .\" Please adjust this date whenever revising the manpage. .Dd Jan 15th, 2017 .Dt UIF 8 .Os .ds operating-system UIF(8) .Sh NAME .Nm uif .Nd Tool for generating optimized packetfilter rules .Sh SYNOPSIS .Nm uif .Op Fl 6 .Op Fl dptW .Op Fl b Ar base .Op Fl c Ar config_file .Op Fl C Ar config_file .Op Fl D Ar bind_dn .Op Fl r Ar ruleset .Op Fl R Ar ruleset .Op Fl s Ar server .Op Fl T Ar time .Op Fl w Ar password .Sh DESCRIPTION .Pp This manual page documents the .Nm command. It is used to generate optimized .Xr iptables 8 packetfilter rules, using a simple description file specified by the user. Generated rules are provided in .Xr iptables\-save 8 style. .Nm can be used to read or write rulesets from or to LDAP servers in your network, which provides a global storing mechanism. (LDAP support is currently broken, note that you need to include the uif.schema to your slapd configuration in order to use it.) .Pp .Xr uif.conf 5 provides an easy way to specify rules, without exact knowledge of the iptables syntax. It provides groups and aliases to make your packetfilter human readable. .Pp Keep in mind that .Nm uif is intended to assist you when designing firewalls, but will not tell you what to filter. .Sh Options The options are as follows: .Bl -tag -width Ds .It Fl 6 Turn on IPv6 mode so as to manipulate ip6tables rules. Default configuration file is changed to .Ar /etc/uif/uif6.conf see .Ar \-c below. It should be noted that nat rules are silently ignored if .Ar \-6 is used. .It Fl b Ar base Specify the base to act on when using LDAP based firewall configuration. .Nm will look in the subtree .Ar ou=filter, ou=sysconfig, base for your rulesets. .It Fl c Ar config_file This option specifies the configuration file to be read by .Nm \. See .Xr uif.conf 5 for detailed information on the fileformat. It defaults to .Ar /etc/uif/uif.conf. .It Fl C Ar config_file When reading configuration data from other sources than specified with .Ar \-c you may want to convert this information into a textual configuration file. This options writes the parsed config back to the file specified by .Ar config_file. .It Fl d Clears all firewall rules immediately. .It Fl D Ar bind_dn If a special account is needed to bind to the LDAP database, the account dn can be specified at this point. Note: you should use this when writing an existing configuration to the LDAP. Reading the configuration may be done with an anonymous bind. .It Fl p Prints rules specified in the configuration to stdout. This option is mainly used for debugging the rule simplifier. .It Fl r Ar ruleset Specifies the name of the ruleset to load from the LDAP database. Remember to use the .Ar \-b option to set the base. Rulesets are stored using the following dn: .Ar cn=name, ou=rulesets, ou=filter, ou=sysconfig, base, where name will be replaced by the ruleset specified. .It Fl R Ar ruleset Specifies the name of the ruleset to write to the LDAP database. This option can be used to convert i.e. a textual configuration to a LDAP based ruleset. Like using .Ar \-r you've to specify the LDAP base to use. Target is .Ar cn=name, ou=rulesets, ou=filter, ou=sysconfig, base, where name will be replaced by the ruleset specified. .It Fl s Ar server This option specified the LDAP server to be used. .It Fl t This option is used to validate the packetfilter configuration without applying any rules. Mainly used for debugging. .It Fl T Ar time When changing your packetfiltering rules remotely, it is useful to have a test option. Specify this one to apply your rules for a period of time (in seconds). After that the original rules will be restored. .It Fl w Ar password When connecting to the LDAP server, you may need to authenticate via passwords. If you really need to specify a password, use this option, otherwise use .Ar \-W and enter it interactivly. .It Fl W Activate interactive password query for LDAP authentication. .El .Pp .Nm is meant to leave the packetfilter rules in a defined state, so if something went wrong during the initialisation, or .Nm is aborted by the user, the rules that were active before starting will be restored. .Pp Normally you will not need to call this binary directly. Use the init script instead, since it does the most common steps for you. .Sh FILES Configuration files are located in /etc/uif. .Sh SEE ALSO uif.conf(5) iptables(8) .Pp .Sh AUTHOR This manual page was written by Cajus Pollmeier and Jörg Platte , for the Debian GNU/Linux system (but may be used by others). uif-1.1.8/uif.conf000066400000000000000000000117331303677623300137550ustar00rootroot00000000000000## uif Firewall Configuration ## Sysconfig definitions # These entries define the global behaviour of the firewall package. Normally # they are preset in /etc/default/uif and may be overwritten by this # section. # # syntax: LogLevel : set the kernel loglevel for iptables rules # LogPrefix: prepend this string to all iptables logs # LogLimit: set packet log limit per time interval (times/interval) # LogBurst: set packet log burst # Limit: set packet limit per time interval (times/interval) # Burst: set packet burst # example: # sysconfig { # LogLevel debug # LogPrefix FW # LogLimit 20/minute # LogBurst 5 # Limit 20/minute # Burst 5 # AccountPrefix ACC_ # } ## Include predefined services # The include section takes a bunch of files and includes them into this # configuration file. # # syntax: "filename" include { "/etc/uif/services" } ## Services needed for workstation setup # The service section provides the protocol definitions you're # using in the rules. You're forced to declare everything you # need for your setup. # # syntax: service_name [tcp([source:range]/[dest:range])] [udp([source:range]/[dest:range])] # [protocol_name([source:range][/][dest:range])] [service_name] ... # examples: http tcp(/80) # dns tcp(/53) udp(/53) # group http dns tcp(/443) # ipsec esp(/) udp(/500) service { traceroute udp(32769:65535/33434:33523) icmp(11) ping icmp(8) } ## Network definitions needed for simple workstation setup # The network definitions are included from two separate files. # 1. /etc/uif/uif-ipv4-networks.inc # 2. /etc/uif/uif-ipv6-networks.inc # # If you want to setup IPv4 and IPv6 firewalling easily, # make sure that all network names you use in your ruleset # in both include files. # # Additionally make /etc/uif/uif6.conf a symlink that points to # /etc/uif/uif.conf. # # IPv4 network definitions # # If you update from a version of UIF that supported IPv4 only, then # you probably want to leave the uif.conf file untouched for now and # move your network definitions block from uif.conf to uif-ipv4-networks.inc # manually later. include4 { "/etc/uif/uif-ipv4-networks.inc" } # IPv6 network definitions # # Make sure IPV6MODE is set to 1 in /etc/default/uif if you want to use # IPv6 support on your UIF based firewall. include6 { "/etc/uif/uif-ipv6-networks.inc" } ## Interface definitions # Since all definitions used in the filter section are symbolic, # you've to specify symbolic names for all your interfaces you're # going to use. # # syntax: interface_name [unix network interface] [interface_name] # examples: internal eth0 # external ippp0 ipsec0 # allppp ppp+ # group external allppp eth3 interface { loop lo } ## Filter definitions # The filter section defines the rules for in, out, forward, masquerading # and nat. All rules make use of the symbolic names defined above. This # section can be used multiple times in one config file. This makes more # senese when using one of these alias names: # filter, nat, input, output, forward, masquerade # # syntax: in[-/+] [i=interface] [s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # out[-/+] [o=interface] [s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # fw[>/-/+] [i/o=interface][s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # masq[-/+][i/o=interface][s=source_net] [d=dest_net] [p=protocol] [f=flag_1,..,flag_n] # nat[-/+] additionally allows [S=from source] [D=to destination] [P=to port:[range]] # additional: # All keys mentioned in the syntax section (in/out/...) can be prefixed with "sl", which # causes the creation of a stateless rule. # flags: limit([count/time[,burst]]) # reject([reject type]) # log([name]) # account(name) # examples: # masq+ o=extern s=intranet # nat+ s=intranet p=http D=relayintern P=squid # in+ s=trusted p=ssh,ping,traceroute,http # out- s=intranet p=smb f=reject # fw- d=microsoft f=reject,log(ms-alert) # slin+ s=testnet # slout- d=testnet # fw> o=extern # fw+ p=myhttp f=account(HTTP) # Take an attention about the protocol for your accounting rules. If you # want to count user http traffice, you may need a "myhttp tcp(80/)". filter { in+ i=loop s=localhost out+ o=loop d=localhost in+ s=all(4) p=ping # these IPv6-ICMP types are a MUST for IPv6 in+ s=all(6) p=ping,pong,noroute,packet-too-big,time-exceeded,parameter-problem,neighbor-advertisement,neighbor-solicitation in+ p=traceroute # in+ s=trusted(4) # in+ s=trusted(6) out+ d=all in- f=log(input),reject out- f=log(output),reject fw- f=log(forward),reject } uif-1.1.8/uif.conf.5000066400000000000000000000210611303677623300141130ustar00rootroot00000000000000.\" -*- nroff -*- .TH UIF.CONF 5 "Jan 15th, 2017" .\" Please adjust this date whenever revising the manpage. .Dd Jan 15th, 2017 .Dt UIF.CONF 5 .Os .ds operating-system UIF.CONF(5) .Sh NAME .Nm uif.conf .Nd Tool for generating optimized packet filter rules .ds Default configuration file for uif .Sh DESCRIPTION First of all, the syntax of this configuration file is far from being perfect. If you've got some better ideas just drop me a line... .Ar /etc/uif/uif.conf is the default configuration file for .Xr uif 8 . This file may contain several sections and comments. Each section begins with the section name and the left curly brace and ends with the right curly brace in a single line. A comment starts with a hash mark .Cm (#) at the beginning of a line. .Pp Blank lines are silently ignored. The following sections are valid: .Cm include, include4, include6, sysconfig, service, network, interface, marker, filter, nat, input, output, forward, masquerade and .Cm stateless. .Pp The sections .Cm service, network, marker and .Cm interface have all a very similar syntax. Each line starts with an identifier followed by one or more blanks and one or more section specific entries or defined identifiers separated by blanks. A valid identifier is case sensitive and consists of letters, digits, underscores and hyphens. .Pp If two or more identifiers in one section are equal, the corresponding entries are merged to the first identifier. Hence, it's not possible to overwrite previously defined identifiers. As a result the order of the section entries is irrelevant and it's possible to define a section more than once. .Ss include section Include other configuration files. Each line in this section, enclosed in quotation marks ("), must be a valid filename. The contents of this file are added to the actual configuration file and each file should contain at least one section (a comment only file is not really useful...). .Ss include4 section Include other configuration files but ONLY in IPv4 mode (WITHOUT \-6 switch to uif). Otherwise equivalent to the include section above. .Ss include6 section Include other configuration files but ONLY in IPv6 mode (WITH \-6 switch to uif). Otherwise equivalent to the include section above. .Ss sysconfig section Set some global settings. Each line in this section starts with one of the following identifiers followed by one or more blanks and the desired value: .Cm LogLevel, LogPrefix, LogLimit, LogBurst, Limit, Burst and .Cm AccountPrefix. If there are multiple definitions of one entry the last definition is stored. .Bl -tag -width Ds .It Cm LogLevel A valid default log priority (see .Xr syslog.conf 5) .It Cm LogPrefix The default log prefix. Each iptables logmessage starts with this prefix. .It Cm LogLimit The default limit value for logmessages (see .Xr iptables 8) .It Cm LogBurst The default burst value for logmessages (see .Xr iptables 8) .It Cm Limit The default limit value (see .Xr iptables 8) .It Cm Burst The default burst value (see .Xr iptables 8) .It Cm AccountPrefix The default prefix for accounting chains. .Pp .El .Ss service section This section defines all needed services. A service description starts with the protocol (see .Xr protocols 5) followed by parameters in parenthesis. Most protocols don't need any parameters. The only exceptions are tcp, udp and icmp. The tcp and udp parameter defines the source and destionation port(\-range). The source and destination ports are separated by a slash (/) and portranges are separated by a colon (eg. tcp(123:333/99): tcp protocol, source\-portrange 123\-333, destination port 99). Empty source or destination ports are expanded to 1:65535. The icmp protocol parameter must be a valid icmp type (see iptables \-p icmp \-\-help). .Ss network section This section defines all needed networks and hosts. A network description starts with a valid IPv4 address (dotted quad), an optional netmask in cidr notation (number of bits) or an optional MAC\-address (with a prefixed equal sign (=). Some valid entries are: 127.0.0.1 127.0.0.0/8 192.168.0.1=00:00:00:00:00:FF. .Ss interface section This section defines all needed (physical and bridged) interfaces (eg. eth0, lo, ppp0). .Ss marker section This section defines all needed numerical (decimal) values for packet marking purposes. .Ss filter, nat, input, output, forward, masquerade and stateless sections Due to better partitioning of the packetfilter, rules can be split into these sections. Internally they are equivalent and contain all rules. As an exception to all other sections the order of entries in these sections is important. .Pp The default policy for the chains INPUT, OUTPUT and FORWARD is DROP (see .Xr iptables 8) and it's not possible to change this. .Pp Each line in in this section begins with .Cm in, out, fw, nat, masq, slin, slout or .Cm slfw followed by '+', '\-' or a mark identifier enclosed in curly braces (or, in case of fw followed by '>'). The identifiers .Cm in, out and .Cm fw define rules for incoming, outgoing and forwarded IP\-packets. Each packet with an INVALID state (see .Xr iptables 8) is matched by .Cm slin, slout and .Cm slfw. The lines starting with .Cm nat and .Cm masq define rules to modify the source or destination address or the destination port. .Pp \fBNote:\fR The identifiers nat and masq are non-operational in IPv6 mode. They simply get ignored as NAT and Masquerading are not supported by the IPv6 protocol. .Pp The plus and minus signs specify the type of the rule: '+' accepts matching packets and '\-' drops them. As a special case the identifier out and fw accept the greater than (>) sign to modify the MSS depending on the PMTU (see .Xr iptables 8) .Pp A very basic ruleset may look like this: .Cm out+ .Pp This allows every outgoing traffic and rejects all incoming connections (because of the default policy). .Pp To be more specific, each line may contain several parameters. Each parameter starts with a single character followed by an equal sign (=) and one or more previously defined identifiers (in the corresponding sections) separated by commas. The following parameters are valid: .Bl -tag -width Ds .It Cm s The source address or network. Append "(4)" or "(6)" to the network name to make this rule apply to IPv4 or IPv6 only. .It Cm d The destination address or network. Append "(4)" or "(6)" to the network name to make this rule apply to IPv4 or IPv6 only. .It Cm i The input interface. .It Cm o The output interface. .It Cm pi The physical input interface (only useful when used with bridged interfaces). .It Cm po The physical output interface (only useful when used with bridged interfaces). .It Cm p The service description (protocol). .It Cm m The mark field associated with a packet. .It Cm S The the new source address in nat rules. Supported in IPv4 mode only. Ignored in IPv6 mode. .It Cm D The the new destination address in nat rules. Supported in IPv4 mode only. Ignored in IPv6 mode. .It Cm P The the new service description in nat rules. This is only valid with tcp or udp packets. .It Cm f This parameter sets some 'flags'. A flag definition starts with the flag identifier and optional parameters in parenthesis. Valid flags are: .Pp .Cm log \- Logs matching packages to syslog. The given parameter is included in the log entry. The number of logged packets and the loglevel can be set in the sysconfig section. .Pp .Cm reject \- Only valid in DROP rules. This is used to send back an error packet in response to the matched packet. The default behaviour is a packet with set RST flag on tcp connections and a destination\-unreachable icmp packet in every other case. Valid parameters are listed in .Xr iptables 8 in the REJECT section. .Pp .Cm account \- Create an accounting chain for all matching packages and possible responses. The optional parameter is a part of the name of the chain. .Pp .Cm limit \- Limits the number of matching packets. The default values are set in the sysconfig section. Other values can be defined with the optional parameter. The first entry sets a new limit and the second parameter (separated by a comma (,)) sets the burst value (see Limit and Burst in sysconfig section). .El It's possible to invert the identifier of one of following parameters \- if it expands to ecactly one object \- by prepending a exclamation mark (!): .Cm s, d, i, o, p (eg.: s=!local p=!http). .Sh FILES Configuration files are located in /etc/uif. There is a sample configuration in .Ar /usr/share/doc/uif/uif.conf.tmpl.gz. .Sh SEE ALSO iptables(8) uif(8) .Sh AUTHOR This manual page was written by Jörg Platte and Cajus Pollmeier , for the Debian GNU/Linux system (but may be used by others). uif-1.1.8/uif.initscript000077500000000000000000000125471303677623300152270ustar00rootroot00000000000000#! /bin/bash ### BEGIN INIT INFO # Provides: uif # Required-Start: $network $syslog $remote_fs # Required-Stop: $network $syslog $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Universal Internet Firewall # Description: Start the firewall defined in /etc/uif/uif.conf. ### END INIT INFO # # Version: @(#)/etc/init.d/uif 1.1.8 January-2017 Mike Gabriel # # RedHat specific settings - ignore for real systems --------------------------- # chkconfig: - 60 95 # description: provides iptables packet filtering . /lib/lsb/init-functions PATH=/usr/sbin:/sbin:$PATH UIF=/usr/sbin/uif IPV6MODE=0 # Include firewall defaults if available if [ -f /etc/default/uif ] ; then . /etc/default/uif fi #THIS IS DEFAULT ANYWAY#[ -z "$OPTIONS" ] && OPTIONS="-c /etc/uif/uif.conf" # Binaries installed? if [ ! -f /sbin/iptables ]; then log_failure_msg "uif: iptables not found - aborting" exit 1 fi if [ $IPV6MODE = 1 -a ! -f /sbin/ip6tables ] ; then log_failure_msg "uif: ip6tables not found - aborting" exit 1 fi # uif installed? Without this script makes no sense... [ -f $UIF ] || exit 1 # As the name says. If the kernel supports modules, it'll try to load # the ones listed in "MODULES". load_modules() { [ -f /proc/modules ] || return LIST=`/sbin/lsmod|awk '!/Module/ {print $1}'` for mod in $MODULES; do echo $LIST | grep -q $mod || modprobe $mod || /bin/true done } case "$1" in start) log_daemon_msg "Starting uif" logger "Starting uif" [ -f /proc/modules ] && { log_progress_msg "modules"; load_modules; } log_progress_msg "IPv4-rules" EMSG=`$UIF $OPTIONS 2>&1` RET4=$? if [ $RET4 -ne 0 ]; then logger "Starting uif failed: $EMSG" [ -n "$MAILTO" ] && \ echo -e "Hi. This is your firewall script - which has failed" \ "to execute in a proper way.\nHere is the error message:\n" \ "\n$EMSG\n\nPlease fix to be sure..." | mail -s "Firewall script failure" $MAILTO log_end_msg $RET4 echo echo -e "Error message: $EMSG\n" exit 1 fi if [ $IPV6MODE = 1 ] ; then log_progress_msg "IPv6-rules" EMSG=`$UIF -6 $OPTIONS 2>&1` RET6=$? if [ $RET6 -ne 0 ]; then logger "Starting uif failed: $EMSG" [ -n "$MAILTO" ] && \ echo -e "Hi. This is your IPv6 firewall script - which has failed" \ "to execute in a proper way.\nHere is the error message:\n" \ "\n$EMSG\n\nPlease fix to be sure..." | mail -s "Firewall script failure" $MAILTO log_end_msg $RET6 echo echo -e "Error message: $EMSG\n" exit 1 fi else RET6=0; fi log_end_msg $(($RET4+$RET6)) ;; stop) log_daemon_msg "Stopping uif" logger "Stopping uif" if [ $IPV6MODE = 1 ] ; then log_progress_msg "IPv4" fi $UIF -d if [ $IPV6MODE = 1 ] ; then log_progress_msg "IPv6" $UIF -6 -d fi log_end_msg 0 ;; print) echo "Printing rules based on your current configuration" $UIF $OPTIONS -pt if [ $IPV6MODE = 1 ] ; then $UIF -6 $OPTIONS -pt fi ;; test|test4) if [ $IPV6MODE = 1 ] ; then echo -n "IPv4 Test: " fi echo -n "Activating IPv4 ruleset for $TIMEOUT seconds: modules, " trap 'echo "aborted, IPv4 rules restored"; exit 0' SIGINT load_modules echo -n "IPv4 rules - active, waiting - " EMSG=`$UIF -T $TIMEOUT $OPTIONS` if [ $? -eq 0 ]; then echo ok exit 0 fi echo failed echo -e "Error message: $EMSG\n" ;; test6) if [ $IPV6MODE = 1 ] ; then echo -n "IPv6 Test: " echo -n "Activating IPv6 ruleset for $TIMEOUT seconds: modules, " trap 'echo "aborted, IPv6 rules restored"; exit 0' SIGINT load_modules echo -n "IPv6 rules - active, waiting - " EMSG=`$UIF -6 -T $TIMEOUT $OPTIONS` if [ $? -eq 0 ]; then echo ok exit 0 fi echo failed echo -e "Error message: $EMSG\n" fi ;; status) if [ "`id -u`" != "0" ]; then echo "Can't retrieve status information. You need to be root." exit 1 fi if [ $IPV6MODE = 1 ] ; then echo "IPv4 STATUS:" fi # Simple rule listing echo -e "\nRule listing:\n" iptables-save | sed "/^#/d" # Show accounting data if [ -n "$ACCOUNTPREFIX" ]; then echo -e "\n\nCurrent accounting information:\n" iptables -vnx -L 2>&1 | sed "/pkts/d" | sed -ne "/^Chain $ACCOUNTPREFIX/N" -e "s/\n/ /p" | \ sed "s/[ ][ ]*/ /g" | awk '{ print $2"\t"$6" Bytes"; }' fi if [ $IPV6MODE = 1 ] ; then echo "IPv6 STATUS:" # Simple rule listing echo -e "\nRule listing:\n" ip6tables-save | sed "/^#/d" # Show accounting data if [ -n "$ACCOUNTPREFIX" ]; then echo -e "\n\nCurrent accounting information:\n" ip6tables -vnx -L 2>&1 | sed "/pkts/d" | sed -ne "/^Chain $ACCOUNTPREFIX/N" -e "s/\n/ /p" | \ sed "s/[ ][ ]*/ /g" | awk '{ print $2"\t"$6" Bytes"; }' fi fi # Show last 10 policy violations if [ -n "$LOGPREFIX" ]; then if [ $IPV6MODE = 1 ] ; then echo -e "\n\nLast 10 policy violations (IPv4 & IPv6 combined):" else echo -e "\n\nLast 10 policy violations (IPv4 only):" fi dmesg | grep "`hostname`.* $LOGPREFIX .*:" 2> /dev/null | tail -n 10 fi echo -e "\n\n" ;; restart|reload|force-reload) $0 start ;; flush) echo -n "Flushing IPv4 packet counters: " iptables -Z &> /dev/null if [ $? -eq 0 ]; then echo ok else echo failed fi if [ $IPV6MODE = 1 ] ; then echo -n "Flushing IPv6 packet counters: " ip6tables -Z &> /dev/null if [ $? -eq 0 ]; then echo ok else echo failed fi fi ;; *) echo "Usage: $0 {start|stop|status|restart|reload|flush|print}" exit 1 esac exit 0 uif-1.1.8/uif.pl000077500000000000000000001647371303677623300134630ustar00rootroot00000000000000#!/usr/bin/perl -w # Copyright (C) 2002-2015 Jörg Platte # Copyright (C) 2002-2015 Cajus Pollmeier # Copyright (C) 2013-2015 Mike Gabriel # Copyright (C) 2013-2015 Alex Owen # # 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # On Debian GNU/Linux systems, a copy of the GNU General Public License may be # found in the file /usr/share/common-licenses/GPL. use strict; my $LDAPENABLED = eval "use Net::LDAP; 1" ? '1' : '0'; use Getopt::Std; use NetAddr::IP; use Data::Validate::IP qw(is_ipv6 is_ipv4); use Socket qw(:addrinfo SOCK_RAW AF_INET AF_INET6); my $SignalCatched=0; my $configfile="/etc/uif/uif.conf"; my $configfile6="/etc/uif/uif6.conf"; my $ipv6=0; my @mapping = ( [ 'n', 'uifid', 'Name' ], [ 's', 'uifsource', 'Source'], [ 'i', 'uifindevice', 'InputInterface'], [ 'pi', 'uifpindevice', 'PhysicalInputInterface'], [ 'd', 'uifdest', 'Destination'], [ 'o', 'uifoutdevice', 'OutputInterface'], [ 'po', 'uifpoutdevice', 'PhysicalOutputInterface'], [ 'p', 'uifservice', 'Service'], [ 'm', 'uifmark', 'MarkMatch'], [ 'S', 'uiftranssource', 'TranslatedSource'], [ 'D', 'uiftransdest', 'TranslatedDestination'], [ 'P', 'uiftransservice', 'TranslatedService'], [ '', 'uiftype', 'Type'], [ 'f', 'uifflag', 'Flags']); my %charstringmap; my %ldapstringmap; my %ldapwritemap; my %stringcharmap; foreach (@mapping) { $charstringmap{${$_}[0]}=${$_}[2]; $stringcharmap{${$_}[2]}=${$_}[0]; if (${$_}[0]) { $ldapstringmap{${$_}[1]}=${$_}[2]; } $ldapwritemap{${$_}[2]}=${$_}[1]; } sub readConfig { my ($configfile, $Networks, $Services, $Interfaces, $Protocols, $Rules, $Id, $Sysconfig, $Marker) = @_; my @conflines; my @protlines; my $state='NONE'; my $line; unless (defined($$Protocols{'OK'})) { $$Protocols{'OK'}=1; open (PROT, '/etc/protocols') || die "Can't read '/etc/protocols'\n"; @protlines = ; close (PROT); foreach $line (@protlines) { if ($line =~ /^\s*(#|$)/) { next; } chomp($line); if ($line =~ /^([a-z0-9-.]+)\s+(\d+)\s+/) { $$Protocols{$1}=$2; $$Protocols{$2}=$1; } else { die "invalid line in '/etc/protocols': $line\n"; } } } open (CONF, $configfile) || die "Can't read configfile '$configfile'\n"; @conflines = ; close (CONF); foreach $line (@conflines) { $line =~ /^\s*(#|$)/ && next; chomp($line); if ($state eq 'NONE') { my $type; if ($line =~ /^\s*([^\s}]+)\s*{\s*$/) { $state="\U$1"; } else { die "invalid line: $line\n"; } } else { if ($line =~ /^\s*}\s*$/) { $state='NONE'; } elsif ($state eq 'SERVICE') { if ($line =~ /^\s*([a-zA-Z0-9_-]+)\s+(.*)$/) { $$Services{$1}.="$2 "; } else { die "invalid line in section service: $line\n"; } } elsif ($state eq 'INCLUDE') { if ($line =~ /^\s*\"(.+)\"$/) { my $file = $1; readConfig ($file, $Networks, $Services, $Interfaces, $Protocols, $Rules, $Id, $Sysconfig); } else { die "invalid line in section include: $line\n"; } } elsif ($state eq 'INCLUDE6') { if ($ipv6) { if ($line =~ /^\s*\"(.+)\"$/) { my $file = $1; readConfig ($file, $Networks, $Services, $Interfaces, $Protocols, $Rules, $Id, $Sysconfig); } else { die "invalid line in section include6: $line\n"; } } } elsif ($state eq 'INCLUDE4') { if ($ipv6) {} else { if ($line =~ /^\s*\"(.+)\"$/) { my $file = $1; readConfig ($file, $Networks, $Services, $Interfaces, $Protocols, $Rules, $Id, $Sysconfig); } else { die "invalid line in section include4: $line\n"; } } } elsif ($state eq 'NETWORK') { if ($line =~ /^\s*([a-zA-Z0-9_-]+)\s+(.*)$/) { $$Networks{$1}.="$2 "; } else { die "invalid line in section network: $line\n"; } } elsif ($state eq 'INTERFACE') { if ($line =~ /^\s*([a-zA-Z0-9_-]+(:\d+)?)\s+(.*)$/) { $$Interfaces{$1}.="$3 "; } else { die "invalid line in section interface: $line\n"; } } elsif ($state eq 'MARKER') { if ($line =~ /^\s*([a-zA-Z0-9_-]+)\s+(.*)$/) { $$Marker{$1}.="$2 "; } else { die "invalid line in section marker: $line\n"; } } elsif ($state eq 'SYSCONFIG') { if ($line =~ /^\s*([a-zA-Z0-9_-]+)\s+(.*)$/) { $$Sysconfig{$1}=$2; } else { die "invalid line in section sysconfig: $line\n"; } } elsif ($state =~ /^(FILTER|NAT|INPUT|OUTPUT|FORWARD|MASQUERADE|STATELESS)$/) { if ($line =~ /^\s*(\w+([-+|>]|{\w+}))\s*(.*)$/) { my $type = $1; my $parameter = $3; my %temphash; $temphash{'Type'}=$type; $temphash{'Rule'}=$line; $temphash{'Id'}=$$Id++; my $entry; foreach $entry (split(/\s+/, $parameter)) { $entry eq '' && next; if ($entry =~ /^([a-zA-Z]{1,2})=([^=]+)$/) { if (exists($charstringmap{$1})) { my $value = $2; $value =~ tr /,/ /; $temphash{$charstringmap{$1}}.="$value "; } else { die "invalid prefix: $1\n"; } } else { die "invalid parameter: $entry\n"; } } push (@$Rules, \%temphash); } else { die "invalid line in section filter/nat: $line\n" } } else { die "invalid section: \L$state\n"; } } } } sub resolveHashentries { my ($value, $Hash, $depth) = @_; unless (defined($depth)) { $depth=1; } elsif ($depth++ > 50) { die "possible loop in configfile: $value\n"; } my $newvalue; my $entry; foreach $entry (split (/\s+/, $value)) { $entry eq '' && next; if (exists($$Hash{$entry})) { $newvalue.=" ".resolveHashentries($$Hash{$entry}, $Hash, $depth); } else { $newvalue.=" ".$entry; } } return $newvalue; } sub expandRange { my ($range, $multi) = @_; if (@$range != 0) { unless (@$multi == 0 && @$range==1) { my %rangehash; my @rangearray; my $entry; foreach $entry (@$range) { $entry =~ /(\d+):(\d+)/; my $range=$2-$1+1; if (exists($rangehash{$range})) { push (@{$rangehash{$range}}, $1); } else { $rangehash{$range}=[$1]; } push (@rangearray, $range); } @rangearray=sort {$a <=> $b} (@rangearray); my $again=1; my $last=15; while ($again) { $again=0; while (@rangearray) { my $range=$rangearray[0]; if (@$multi+$range<=$last) { my $first=shift(@{$rangehash{$range}}); my $port; for ($port=$first+$range-1; $port>=$first; $port--) { push (@$multi, $port); } shift (@rangearray); } else { last; } } if (@rangearray>1) { $last+=15; if (@$multi+$rangearray[0]+$rangearray[1]<=$last) { $again=1; } } } my @temprange; foreach $range (@rangearray) { foreach (@{$rangehash{$range}}) { my $last=$_+$range-1; push(@temprange, "$_:$last"); } } @$range=@temprange; } } } sub simplifyNetworks { my (@networks) = @_; my @netobjects; my $netref; my %macs; my $mac; my $network; if (@networks) { my $ip; my $no_macs=1; foreach (@networks) { my $netaddr = ''; my $network = ''; my $macaddr = ''; if ( ($_ =~ /(^[^\/]+)\/([^\/^=]+)$/) || (($ipv6) && is_ipv6($_)) || ((!$ipv6) && is_ipv4($_)) ) { if ($ipv6) { $ip=NetAddr::IP->new6($_) || die "not a valid address or network: $_\n"; } else { $ip=NetAddr::IP->new($_) || die "not a valid address or network: $_\n"; } push(@netobjects, $ip); } elsif ( $_ =~ /(^[^=]+)=([^=]+)$/ ) { $netaddr = $1; $macaddr = $2; if ($netaddr =~ /(^[^\/]+)\/([^\/]+)$/) { $network = $1; # FIXME: netmask = $2; TODO: validate netmask } else { $network = $netaddr; } if ( (($ipv6) && is_ipv6($network)) || ((!$ipv6) && is_ipv4($network)) ) { if ($ipv6) { $ip=NetAddr::IP->new6($netaddr) || die "not a valid address or network: $netaddr\n"; } else { $ip=NetAddr::IP->new($netaddr) || die "not a valid address or network: $netaddr\n"; } if (!exists($macs{$ip})) { $macs{$ip}=[]; } $no_macs = 0; push (@{$macs{$ip}}, $macaddr); push (@netobjects, $ip); } else { die "Cannot use = syntax, must be =" } } else { # resolv "address" that actually is a DNS host name, not an IP address... my $err; my @res; if ($ipv6) { ( $err, @res ) = getaddrinfo( $_, "", { socktype => SOCK_RAW, family => AF_INET6 } ); } else { ( $err, @res ) = getaddrinfo( $_, "", { socktype => SOCK_RAW, family => AF_INET } ); } die "Cannot getaddrinfo for name '".$_."'- ".$err if $err; while ( my $ai = shift @res ) { my ( $err, $ipaddr ) = getnameinfo( $ai->{addr}, NI_NUMERICHOST, NIx_NOSERV ); die "Cannot getnameinfo - $err" if $err; if ($ipv6) { $ip=NetAddr::IP->new6($ipaddr) || die "not a valid address: $ipaddr\n"; } else { $ip=NetAddr::IP->new($ipaddr) || die "not a valid address: $ipaddr\n"; } push (@netobjects, $ip); } } } # if we don't handle individual MAC addresses on any of the networks, then # we can compact the list of networks if ($no_macs == 1) { @netobjects = NetAddr::IP::Compact(@netobjects); } @networks=(); foreach $network (@netobjects) { if (exists($macs{$network})) { foreach $mac (@{$macs{$network}}) { push (@networks, $network."=".$mac); } } else { push (@networks, $network); } } } return (@networks); } sub checkLimit { my ($limit) = @_; if ($limit =~/^\d+(\/second|\/minute|\/hour|\/day|)$/) { return 1; } else { return 0; } } sub validateSysconfig { my ($Sysconfig) = @_; my $syskey; foreach $syskey (keys (%$Sysconfig)) { if ("\L$syskey" eq "loglevel") { my $level=$$Sysconfig{$syskey}; delete $$Sysconfig{$syskey}; $level =~ s/\s+//g; if ($level =~/^(debug|info|notice|warning|err|crit|alert|emerg)$/) { $$Sysconfig{'LogLevel'}=$level; } else { die "unknown loglevel: $level\n"; } } elsif ("\L$syskey" eq "logprefix") { my $prefix=$$Sysconfig{$syskey}; delete $$Sysconfig{$syskey}; $$Sysconfig{'LogPrefix'}=$prefix; } elsif ("\L$syskey" eq "loglimit") { my $limit=$$Sysconfig{$syskey}; delete $$Sysconfig{$syskey}; $limit =~ s/\s+//g; if (checkLimit $limit) { $$Sysconfig{'LogLimit'}=$limit; } else { die "unknown loglimit: $limit:\n"; } } elsif ("\L$syskey" eq "logburst") { my $burst=$$Sysconfig{$syskey}; delete $$Sysconfig{$syskey}; $burst =~ s/\s+//g; if ($burst =~/^\d+$/) { $$Sysconfig{'LogBurst'}=$burst; } else { die "unknown logburst: $burst\n"; } } elsif ("\L$syskey" eq "limit") { my $limit=$$Sysconfig{$syskey}; delete $$Sysconfig{$syskey}; $limit =~ s/\s+//g; if (checkLimit $limit) { $$Sysconfig{'Limit'}=$limit; } else { die "unknown limit: $limit:\n"; } } elsif ("\L$syskey" eq "burst") { my $burst=$$Sysconfig{$syskey}; delete $$Sysconfig{$syskey}; $burst =~ s/\s+//g; if ($burst =~/^\d+$/) { $$Sysconfig{'Burst'}=$burst; } else { die "unknown burst: $burst\n"; } } elsif ("\L$syskey" eq "accountprefix") { my $prefix=$$Sysconfig{$syskey}; delete $$Sysconfig{$syskey}; $prefix =~ s/\s+//g; if ($prefix =~/^\w+$/) { $$Sysconfig{'AccountPrefix'}=$prefix; } else { die "invalid account prefix: $prefix\n"; } } else { die "unknown sysconfig parameter: $syskey\n"; } } } sub toRange { my ($range, $proto, $rule) = @_; if ($range =~ /^(\d*)(|:(\d*))$/) { if ($1 && $3) { return "$1:$3"; } elsif ($1 && $2) { return "$1:65535"; } elsif ($2 && $3) { return "0:$3"; } elsif ($1) { return "$1:$1"; } else { return "0:65535"; } } else { die "invalid $proto service: $range:\n$rule\n"; } } sub validateData { my ($Networks, $Services, $Interfaces, $Protocols, $Rules, $Sysconfig, $Marker) = @_; validateSysconfig $Sysconfig; my $key; foreach $key (keys (%$Networks)) { $$Networks{$key} = resolveHashentries($$Networks{$key}, $Networks); } foreach $key (keys (%$Services)) { $$Services{$key} = resolveHashentries($$Services{$key}, $Services); } foreach $key (keys (%$Interfaces)) { $$Interfaces{$key} = resolveHashentries($$Interfaces{$key}, $Interfaces); } foreach $key (keys (%$Interfaces)) { if (!($$Interfaces{$key} =~ /^[a-zA-Z0-9+ ]+(:\d+)?$/)) { die "invalid character in interface definition: $$Interfaces{$key}\n"; } } foreach $key (keys (%$Marker)) { $$Marker{$key} = resolveHashentries($$Marker{$key}, $Marker); } ## marken auf plausibilität prüfen my $rule; foreach $rule (@$Rules) { if (exists($$rule{'TranslatedSource'}) && exists($$rule{'TranslatedDestination'})) { die "can't modify source and destination address in one rule:\n$$rule{'Rule'}\n"; } my $ruletype=$$rule{'Type'}; if ($ruletype =~ /^\s*(masq|snat|dnat|nat)(\+|-)$/) { my $type = $1; my $action = $2; $$rule{'Table'}='nat'; if ($type eq 'masq') { if ($ipv6) { $$rule{'Type'}='IGNORE-IPV6-POSTROUTING'; } else { $$rule{'Type'}='POSTROUTING'; } $$rule{'Action'}='MASQUERADE'; } elsif ($type =~ /^(s|d|)nat$/) { if (exists($$rule{'TranslatedSource'})) { if ($ipv6) { $$rule{'Type'}='IGNORE-IPV6-POSTROUTING'; } else { $$rule{'Type'}='POSTROUTING'; } $$rule{'Action'}='SNAT'; } elsif (exists($$rule{'TranslatedDestination'})) { if ($ipv6) { $$rule{'Type'}='IGNORE-IPV6-PREROUTING'; } else { $$rule{'Type'}='PREROUTING'; } $$rule{'Action'}='DNAT'; } else { die "nat rule without address translation makes no sense:\n$$rule{'Rule'}\n"; } } if ($action eq '-') { $$rule{'Action'}='DROP'; } } elsif ($ruletype =~ /^\s*(in|out|fw|slin|slout|slfw)(\+|-|\||>|{\w+})$/) { my $type = $1; my $action = $2; $$rule{'Table'}='filter'; if ($type eq 'fw') { $$rule{'Type'}='FORWARD'; } elsif ($type eq 'in') { $$rule{'Type'}='INPUT'; } elsif ($type eq 'out') { $$rule{'Type'}='OUTPUT'; } elsif ($type eq 'slfw') { $$rule{'Type'}='STATELESSFORWARD'; } elsif ($type eq 'slin') { $$rule{'Type'}='STATELESSINPUT'; } else { $$rule{'Type'}='STATELESSOUTPUT'; } if ($action eq '+') { $$rule{'Action'}='ACCEPT'; } elsif ($action eq '-') { $$rule{'Action'}='DROP'; } elsif ($action eq '|') { if ($$rule{'Type'} =~ /OUTPUT/) { die "can't use mirror in OUTPUT chain\n"; } else { $$rule{'Action'}='MIRROR'; } } elsif ($action =~ /^{(\w+)}$/) { my $marker=$1; $$rule{'Action'}='MARK'; $$rule{'Table'}='mangle'; if (exists($$Marker{$marker})) { my @dummy = split(/\s+/, $$Marker{$marker}); if ($#dummy == 1) { $$rule{'Mark'}=$$Marker{$marker}; } else { die "can't mark packet with multiple mark values: $marker\n$$rule{'Rule'}\n"; } } else { die "invalid mark identifier: $marker\n$$rule{'Rule'}\n"; } } else { if ($$rule{'Type'} =~ /INPUT/) { die "can't use TCPMSS in INPUT chain\n"; } else { $$rule{'Action'}='TCPMSS'; } } if (exists($$rule{'TranslatedSource'}) || exists($$rule{'TranslatedDestination'}) || exists($$rule{'TranslatedService'})) { die "you can modify source or destination address only in nat rules:\n$$rule{'Rule'}\n"; } } else { die "unknown ruletype:\n$$rule{'Rule'}\n"; } my $hashentry; foreach $hashentry (qw(Source Destination TranslatedSource TranslatedDestination)) { my @simplenetwork; if (exists($$rule{$hashentry})) { my $position; foreach $position (split (/\s+/, $$rule{$hashentry})) { $position eq '' && next; $position =~ /^(!{0,1})(.*)/; if ($1) { $$rule{"${hashentry}-not"} = 1; } $position=$2; # support IPv4-only/IPv6-only rules if ($position =~ /^.*\((.+)\)$/) { my $only_proto = $1; $position =~ s/\((.+)\)$//; if (($ipv6) && ($only_proto eq "4")) { print "IPv6 setup: Skipping IPv4-only rule for network \"$position\"\n"; $$rule{'Type'} = 'IGNORE-IPV4-ONLY'; next; } elsif ((! $ipv6) && ($only_proto eq "6")) { print "IPv4 setup: Skipping IPv6-only rule for network \"$position\"\n"; $$rule{'Type'} = 'IGNORE-IPV6-ONLY'; next; } } if ($$rule{'Type'} =~ /^IGNORE\-IPV6\-.*$/) { next; } if (exists($$Networks{$position})) { my $network; foreach $network (split (/\s+/, $$Networks{$position})) { $network eq '' && next; push (@simplenetwork, $network); } } else { die "invalid network name: $position\n$$rule{'Rule'}\n"; } } @simplenetwork = simplifyNetworks (@simplenetwork); my $network; for $network (@simplenetwork) { if ( ( $network =~ /(^[^=]+)=([^=]+)$/ ) && ( ! ( $hashentry =~ /^.*Source$/ ) ) ) { die "MAC address sources don't make sense on destination networks"; } if ( ( $network =~ /(^[^=]+)=([^=]+)$/ ) && ( $$rule{'Type'} eq 'OUTPUT' ) ) { die "MAC address sources don't make sense for outward bound rules"; } } $$rule{$hashentry} = \@simplenetwork; } } foreach (qw(TranslatedSource TranslatedDestination)) { if (exists($$rule{$_}) && @{$$rule{$_}}>1) { die "you can specify only one source or destination network as nat target:\n$$rule{'Rule'}\n"; } if (exists($$rule{"$_-not"})) { die "inverting nat destinations is not possible\n$$rule{'Rule'}\n"; } } foreach (qw(Source Destination)) { if (exists($$rule{"${_}-not"}) && @{$$rule{$_}}>1) { die "you can specify only one source or destination network with not statement:\n$$rule{'Rule'}\n"; } } if (exists($$rule{'MarkMatch'})) { my $mark; my @array; foreach $mark (split (/\s+/, $$rule{'MarkMatch'})) { $mark eq '' && next; foreach (split(/\s+/, $$Marker{$mark})) { $_ eq '' && next; push (@array, $_); } } $$rule{'MarkMatch'}=\@array; } foreach $hashentry (qw(InputInterface OutputInterface PhysicalInputInterface PhysicalOutputInterface)) { if (exists($$rule{$hashentry})) { if (($hashentry eq 'InputInterface' || $hashentry eq 'PhysicalInputInterface') && $$rule{'Type'} =~ /(OUTPUT|POSTROUTING)/) { die "can't use input interface in output rule:\n$$rule{'Rule'}\n"; } elsif (($hashentry eq 'OutputInterface' || $hashentry eq 'PhysicalOutputInterface') && $$rule{'Type'} =~ /(INPUT|PREROUTING)/) { die "can't use output interface in input rule:\n$$rule{'Rule'}\n"; } my $position; my %interfacehash; foreach $position (split (/\s+/, $$rule{$hashentry})) { $position eq '' && next; $position =~ /^(!{0,1})(.*)/; if ($1) { $$rule{"${hashentry}-not"} = 1; } $position=$2; if (exists($$Interfaces{$position})) { my $interface; foreach $interface (split (/\s+/, $$Interfaces{$position})) { $interface eq '' && next; $interfacehash{$interface}=1; } } else { die "invalid interface entry: $position\n"; } } my @array = keys (%interfacehash); $$rule{$hashentry} = \@array; } if (exists($$rule{"${hashentry}-not"}) && @{$$rule{$hashentry}}>1) { die "you can specify only one input or output interface with not statement:\n$$rule{'Rule'}\n"; } } my $serviceentry; my $servicecounter=0; foreach $serviceentry (qw(Service TranslatedService)) { $servicecounter=0; if (exists($$rule{$serviceentry})) { my $serviceprefix=''; if ($serviceentry eq 'TranslatedService') { $serviceprefix='Translated'; } my @newservice; my $position; my %protocols; foreach $position (split (/\s+/, $$rule{$serviceentry})) { $position eq '' && next; $position =~ /^(!{0,1})(.*)/; if ($1) { if ($serviceprefix) { die "can't use not in nat destination service description: $position\n$$rule{'Rule'}\n"; } $$rule{"Service-not"}=1; } $position=$2; if (exists($$Services{$position})) { my $service; foreach $service (split (/\s+/, $$Services{$position})) { $service eq '' && next; if ($service =~ /^([\w-]+)\((.*)\)$/) { my $proto=$1; my $param=$2; if ($param eq '') { $param='all'; } if (exists($$Protocols{$proto})) { if ($proto =~ /^\d+$/) { $proto = $$Protocols{$proto}; } } else { die "unknown protocol: $service:\n$$rule{'Rule'}\n"; } $protocols{"$serviceprefix$proto"}.=" $param"; } else { die "invalid service entry: $service:\n$$rule{'Rule'}\n"; } } } else { die "invalid service entry: $position\n"; } } delete $$rule{$serviceentry}; my $proto; foreach $proto (qw(udp tcp)) { if (exists($protocols{"$serviceprefix$proto"})) { my @multisource; my @multidestination; my @sourcerange; my @destinationrange; my @sourcedestination; my %other; my $service; foreach $service (split (/\s+/, $protocols{"$serviceprefix$proto"})) { $service eq '' && next; if ($service =~ /^([^\/]*)\/([^\/]*)$/) { my $range=toRange ($1, $proto, $$rule{'Rule'}); $range.="/".toRange ($2, $proto, $$rule{'Rule'}); $other{$range}=1; } else { die "invalid $proto service: $service:\n$$rule{'Rule'}\n"; } } my $again=0; my $first=1; while ($first || $again) { $first=0; $again=0; LOOP: foreach $service (keys (%other)) { next unless exists($other{$service}); if ($service =~ /^(\d+):(\d+)\/(\d+):(\d+)$/) { my $ss=$1; my $se=$2; my $ds=$3; my $de=$4; if ($ss>$se || $ds>$de) { die "invalid port range: $service:\n$$rule{'Rule'}\n"; } my $test; foreach $test (keys (%other)) { $test eq $service && next; $test =~ /(\d+):(\d+)\/(\d+):(\d+)/; if ( $1 == $ss && $2 == $se ) { if ( $3 >= $ds && $4 <= $de) { delete $other{$test}; $again=1; last LOOP; } if ( $4 == $ds-1 || ($4 >= $ds && $4 <= $de)) { $ds=$3; $de=$4 if $4>$de; delete $other{$service}; delete $other{$test}; $other{"$ss:$se/$ds:$de"}=1; $again=1; last LOOP; } } elsif ( $3 == $ds && $4 == $de ) { if ( $1 >= $ss && $2 <= $se) { delete $other{$test}; $again=1; last LOOP; } if ( $2 == $ss-1 || ($2 >= $ss && $2 <= $se)) { $ss=$1; $se=$2 if $2>$se; delete $other{$service}; delete $other{$test}; $other{"$ss:$se/$ds:$de"}=1; $again=1; last LOOP; } } } } else { die "invalid service entry: $service:\n$$rule{'Rule'}\n"; } } } my $entry; foreach $entry (keys (%other)) { if ($entry =~ /(\d+):(\d+)\/0:65535/) { if ($1 != $2) { push (@sourcerange, "$1:$2"); } else { push (@multisource, $1); } } elsif ($entry =~ /0:65535\/(\d+):(\d+)/) { if ($1 != $2) { push (@destinationrange, "$1:$2"); } else { push (@multidestination, $1); } } else { push (@sourcedestination, $entry); } } if ($serviceprefix eq '') { expandRange (\@sourcerange, \@multisource); expandRange (\@destinationrange, \@multidestination); } $$rule{"$serviceprefix\u$proto"}= [\@multisource, \@multidestination, \@sourcerange, \@destinationrange, \@sourcedestination]; $servicecounter+=@multisource+@multidestination+@sourcerange+@destinationrange+@sourcedestination; delete $protocols{"$serviceprefix$proto"}; } } if ($serviceprefix ne '' && $servicecounter>1) { die "you can specify only one service or service range as nat target:\n$$rule{'Rule'}\n"; } if (exists($$rule{"Service-not"}) && $serviceprefix eq '' && $servicecounter>1) { die "you can specify only one service in not statement:\n$$rule{'Rule'}\n"; } if (exists($protocols{"${serviceprefix}icmp"})) { if ($serviceprefix ne '') { die "can't use icmp nat target:\n$$rule{'Rule'}\n"; } my %icmphash; my $message; foreach $message (split (/\s+/, $protocols{"${serviceprefix}icmp"})) { # message validation missing $message eq '' && next; $icmphash{$message}=1; } my @array = keys (%icmphash); $$rule{"${serviceprefix}ICMP"}=\@array; delete $protocols{"${serviceprefix}icmp"}; } if (exists($protocols{"${serviceprefix}ipv6-icmp"})) { if ($serviceprefix ne '') { die "can't use ipv6-icmp nat target:\n$$rule{'Rule'}\n"; } my %icmp6hash; my $message; foreach $message (split (/\s+/, $protocols{"${serviceprefix}ipv6-icmp"})) { # message validation missing $message eq '' && next; $icmp6hash{$message}=1; } my @array = keys (%icmp6hash); $$rule{"${serviceprefix}ICMP6"}=\@array; delete $protocols{"${serviceprefix}ipv6-icmp"}; } if (keys (%protocols)) { if ($serviceprefix ne '') { die "you can use tcp and udp based nat targets only:\n$$rule{'Rule'}\n"; } my @array = keys (%protocols); $$rule{"${serviceprefix}OtherProtocols"} = \@array; } } } if ( (exists($$rule{'TranslatedTcp'}) && exists($$rule{'Udp'})) || (exists($$rule{'TranslatedUdp'}) && exists($$rule{'Tcp'}))) { die "source protocol and translated protocol must be equal in nat rule:\n$$rule{'Rule'}\n"; } if (exists($$rule{'Flags'})) { my $flag; foreach $flag (split (/\s+/, $$rule{'Flags'})) { $flag eq '' && next; if ($flag =~ /^log(\((.+)\)|)$/) { $$rule{'Log'}=$2; } elsif ($flag =~ /^reject(\((.+)\)|)$/) { if ($$rule{'Table'} eq 'nat') { die "can't use reject with nat:\n$$rule{'Rule'}\n"; } if ($$rule{'Action'} ne 'DROP') { die "rejecting packets in allow rule makes no sense:\n$$rule{'Rule'}\n"; } if ($2) { my $param=$2; if ($param =~ /^(icmp-(net|host|port|proto)-unreachable|icmp-(net|host)-prohibited|tcp-reset)$/) { $$rule{'Reject'}=$param; } else { die "invalid reject parameter: $param:\n$$rule{'Rule'}\n"; } if ($param eq 'tcp-reset') { if (exists($$rule{'OtherProtocols'}) || exists($$rule{'ICMP'}) || exists($$rule{'ICMP6'}) || exists($$rule{'Udp'})) { die "can't use tcp-reset with other protocols than tcp:\n$$rule{'Rule'}\n"; } unless (exists($$rule{'Tcp'})) { die "need tcp protocol for tcp-reset:\n$$rule{'Rule'}\n"; } } } else { $$rule{'Reject'}=1; } } elsif ($flag =~ /^account(\((.+)\)|)$/) { if ($$rule{'Table'} eq 'nat') { die "can't use accounting with nat:\n$$rule{'Rule'}\n"; } if ($$rule{'Action'} eq 'DROP') { die "accounting packets in reject/drop rule makes no sense:\n$$rule{'Rule'}\n"; } if ($2) { my $param=$2; if ($param =~ /^[a-zA-Z0-9]+$/) { $$rule{'Accounting'}=$param; } else { die "invalid character in accountingname '$param':\n$$rule{'Rule'}\n"; } } else { $$rule{'Reject'}='default'; } } elsif ($flag =~ /^limit(\((.*)\)|)$/) { if ($$rule{'Action'} eq 'DROP') { die "limiting packets in reject/drop rule makes no sense:\n$$rule{'Rule'}\n"; } if (exists($$rule{'Accounting'})) { die "limiting packets does not work with accounting in current implementation:\n$$rule{'Rule'}\n"; } if ($2) { my $param=$2; if ($param =~ /^([^:]+)(:\d+|)$/) { if (checkLimit $1) { $$rule{'Limit'}=$1; if ($2) { # no need to check burst since it # is guaranteed to be either empty # or digits only (plus leading colon). # Empty results in other part of if # clause. my $burst=$2; $burst=~s/^://; $$rule{'Limit-burst'}=$burst; } else { $$rule{'Limit-burst'}=$$Sysconfig{'Burst'}; } } else { die "invalid limit '$param':\n$$rule{'Rule'}\n"; } } else { die "invalid limit descriptionb '$param':\n$$rule{'Rule'}\n"; } } else { $$rule{'Limit'}=$$Sysconfig{'Limit'}; $$rule{'Limit-burst'}=$$Sysconfig{'Burst'}; } } else { die "invalid flag: $flag -- $$rule{'Flags'}:\n$$rule{'Rule'}\n"; } } } } } sub genRuleDump { my ($Rules, $Listing, $Sysconfig) = @_; my @partial; my $rule; my %nat; my %filter; my %mangle; my @nat; my @filter; my @mangle; my $table; my $chains; foreach $rule (@$Rules) { if ( ($$rule{'Type'} eq "IGNORE-IPV4-ONLY") || ($$rule{'Type'} eq "IGNORE-IPV6-ONLY") ) { next; } my @protocol; my @source; my @destination; my @inputinterface; my @outputinterface; my @physicalinputinterface; my @physicaloutputinterface; my @mark; my $action; my $logaction; my $type; my $name; my $proto; my $id; my $not; if ($$rule{'Table'} eq 'filter') { $table=\@filter; $chains=\%filter; } elsif ($$rule{'Table'} eq 'nat') { $table=\@nat; $chains=\%nat; } elsif ($$rule{'Table'} eq 'mangle') { $table=\@mangle; $chains=\%mangle; } else { die "$$rule{'Table'} is not implemented!\n"; } $type="-A $$rule{'Type'}"; if (exists($$rule{'Name'})) { $name=$$rule{'Name'}; $name=~s/\s+//g; } else { $name="-"; } $id=$$rule{'Id'}; if (exists($$rule{'Reject'})) { if ($$rule{'Reject'} ne '1') { if ($$rule{'Reject'} =~ /tcp/) { $action="-p tcp -m tcp -j REJECT --reject-with $$rule{'Reject'}"; } else { $action="-j REJECT --reject-with $$rule{'Reject'}"; } } else { $action="-j MYREJECT"; } $logaction="REJECT"; } elsif ($$rule{'Action'} eq "TCPMSS") { $action="-p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu"; $logaction="TCPMSS"; } elsif ($$rule{'Action'} eq "MARK") { $action="-j MARK --set-mark $$rule{'Mark'}"; $logaction="MARK"; } else { $action="-j $$rule{'Action'}"; $logaction=$$rule{'Action'}; } if (exists($$rule{"Service-not"})) { $not='!'; } else { $not=''; } foreach $proto (qw(tcp udp)) { if (exists($$rule{"\u$proto"})) { my $string; my $entry; foreach $entry (qw(0 1)) { my $multiport; my $count=0; foreach $multiport (@{$$rule{"\u$proto"}[$entry]}) { if ($count==0) { $string=''; } $string.="$multiport,"; $count++; if ($count==15) { $string =~ s/,$//; $string="-p $proto -m multiport --".($entry==1?"d":"s")."port ".$string; push (@protocol, $string); $string=''; $count=0; } } if (defined($string) && $count) { $string =~ s/,$//; if ($count > 1) { $string="-p $proto -m multiport --".($entry==1?"d":"s")."port ".$string; } else { $string="-p $proto -m $proto --".($entry==1?"d":"s")."port ".$string; } push (@protocol, $string); } } my $range; foreach $range (@{$$rule{"\u$proto"}[2]}) { push (@protocol, "-p $proto -m $proto $not --sport $range"); } foreach $range (@{$$rule{"\u$proto"}[3]}) { push (@protocol, "-p $proto -m $proto $not --dport $range"); } foreach $range (@{$$rule{"\u$proto"}[4]}) { $range =~ /^(.+)\/(.+)$/; push (@protocol, "-p $proto -m $proto $not --sport $1 $not --dport $2"); } } } if (exists($$rule{'ICMP'}) && (! $ipv6)) { my $type; foreach $type (@{$$rule{'ICMP'}}) { if ($type eq 'all') { push (@protocol, "$not -p icmp"); } else { push (@protocol, "-p icmp -m icmp $not --icmp-type $type"); } } } if (exists($$rule{'ICMP6'}) and ($ipv6)) { my $type; foreach $type (@{$$rule{'ICMP6'}}) { if ($type eq 'all') { push (@protocol, "$not -p icmpv6"); } else { push (@protocol, "-p icmpv6 -m icmpv6 $not --icmpv6-type $type"); } } } if (exists($$rule{'OtherProtocols'})) { my $proto; foreach $proto (@{$$rule{'OtherProtocols'}}) { push (@protocol, "$not -p $proto"); } } if (exists($$rule{'Source'})) { if (exists($$rule{'Source-not'})) { $not='!'; } else { $not=''; } my $source; foreach $source (@{$$rule{'Source'}}) { if ($source =~ /(.+)=(.+)/ && ($$rule{'Table'} eq 'filter')) { push (@source, "$not -s $1 -m mac $not --mac-source $2"); } else { $source =~ /([^=]+)/; push (@source, "$not -s $1"); } } } if (exists($$rule{'Destination'})) { if (exists($$rule{'Destination-not'})) { $not='!'; } else { $not=''; } my $destination; foreach $destination (@{$$rule{'Destination'}}) { $destination =~ /([^=]+)/; push (@destination, "$not -d $1"); } } if (exists($$rule{'TranslatedSource'})) { my $source; $source=${$$rule{'TranslatedSource'}}[0]; $source =~ /([^=]+)/; $source=$1; my $ip = NetAddr::IP->new($source) || die "not a valid network: $source\n"; my $net=$ip->network(); my $bcast = $ip->broadcast(); if ($net ne $bcast) { $source="$net-$bcast"; } $source =~ s/\/[^-]+//g; # $action="-t nat ".$action; $action.=" --to-source $source"; } if (exists($$rule{'TranslatedDestination'})) { my $destination; $destination=${$$rule{'TranslatedDestination'}}[0]; $destination =~ /([^=]+)/; $destination=$1; my $ip = NetAddr::IP->new($destination) || die "not a valid network: $destination\n"; my $net=$ip->network(); my $bcast = $ip->broadcast(); if ($net ne $bcast) { $destination="$net-$bcast"; } $destination =~ s/\/[^-]+//g; # $action="-t nat ".$action; $action.=" --to-destination $destination"; } foreach $proto (qw(tcp udp)) { if (exists($$rule{"Translated\u$proto"})) { my $ref = $$rule{"Translated\u$proto"}; if (defined($$ref[1][0])) { $action.=":$$ref[1][0]"; $action="-p $proto -m $proto ".$action; } if (defined($$ref[3][0])) { $action.=":$$ref[3][0]"; $action="-p $proto -m $proto ".$action; } last; } } if (exists($$rule{'InputInterface'})) { if (exists($$rule{'InputInterface-not'})) { $not='!'; } else { $not=''; } my $input; foreach $input (@{$$rule{'InputInterface'}}) { push (@inputinterface, "$not -i $input"); } } if (exists($$rule{'OutputInterface'})) { if (exists($$rule{'OutputInterface-not'})) { $not='!'; } else { $not=''; } my $output; foreach $output (@{$$rule{'OutputInterface'}}) { push (@outputinterface, "$not -o $output"); } } if (exists($$rule{'PhysicalInputInterface'})) { if (exists($$rule{'PhysicalInputInterface-not'})) { $not='!'; } else { $not=''; } my $input; foreach $input (@{$$rule{'PhysicalInputInterface'}}) { push (@physicalinputinterface, "-m physdev $not --physdev-in $input"); } } if (exists($$rule{'PhysicalOutputInterface'})) { if (exists($$rule{'PhysicalOutputInterface-not'})) { $not='!'; } else { $not=''; } my $output; foreach $output (@{$$rule{'PhysicalOutputInterface'}}) { push (@physicaloutputinterface, "-m physdev $not --physdev-out $output"); } } if (exists($$rule{'MarkMatch'})) { my $mark; foreach $mark (@{$$rule{'MarkMatch'}}) { push (@mark, "-m mark --mark $mark"); } } if (exists($$rule{'Log'})) { my $chain = "${id}$$rule{'Action'}log"; $$chains{$chain}=1; my $logid; if ($$rule{'Log'}) { $logid=$$rule{'Log'}; } else { $logid=$name; } push (@$table, "-A $chain -m limit --limit $$Sysconfig{'LogLimit'} --limit-burst $$Sysconfig{'LogBurst'} -j LOG --log-prefix \"$$Sysconfig{'LogPrefix'} $logaction ($logid): \" --log-level $$Sysconfig{'LogLevel'} --log-tcp-options --log-ip-options"); push (@$table, "-A $chain $action"); $action="-j $chain"; } if (exists($$rule{'Accounting'})) { my $accountchain="$$Sysconfig{'AccountPrefix'}$$rule{'Accounting'}"; unless (exists($$chains{"$accountchain"})) { $$chains{"$accountchain"}=1; push (@$table, "-A $accountchain $action"); } my $accountrules="${id}_ACCOUNTING_$$rule{'Accounting'}"; $$chains{$accountrules}=1; push (@$table, "$type -j $accountrules"); push (@$table, "-A ACCOUNTING$$rule{'Type'} -j $accountrules"); $type="-A $accountrules "; $action=" -j $accountchain"; } if (exists($$rule{'Limit'})) { $action=" -m limit --limit $$rule{'Limit'} --limit-burst $$rule{'Limit-burst'} $action"; } my @rulearray = (\@inputinterface, \@outputinterface, \@physicalinputinterface, \@physicaloutputinterface, \@protocol, \@source, \@destination, \@mark); my $level=1; my $again=1; while ($again) { @partial = (); $again=0; my $array; # adjust if you have many entries... my $depth=0xFFFF; foreach $array (@rulearray) { if (@$array && $depth>@$array) { $depth=@$array; } } foreach $array (@rulearray) { if (@$array==$depth) { my $i; for ($i=0; $i<@$array; $i++) { $partial[$i].=" $$array[$i]"; } @$array = (); if ($depth != 1) { last; } } } foreach $array (@rulearray) { if (@$array) { $again=1; last; } } my $jumpto; if ($again) { $jumpto="-j ${id}_$level"; } else { $jumpto=$action; } if (@partial) { my $newjumpto; my $part; foreach $part (@partial) { $newjumpto=$jumpto; if ($part =~ /-p (udp|tcp)/ && $jumpto =~ /-p (udp|tcp)/) { $newjumpto =~ s/-p (udp|tcp) -m (udp|tcp)//; } push (@$table, $type." $part $newjumpto"); } } else { push (@$table, "$type $jumpto"); } if ($again) { $type="-A ${id}_$level"; $$chains{"${id}_$level"}=1; $level++; } } } my $entry; foreach $entry (qw(mangle filter nat)) { if ($entry eq "nat" && $ipv6 == 1) {next}; my $chain; push (@$Listing, "*$entry"); if ($entry eq 'filter') { $table=\@filter; $chains=\%filter; push (@$Listing, ":MYREJECT - [0:0]"); push (@$Listing, ":STATENOTNEW - [0:0]"); foreach (qw(INPUT OUTPUT FORWARD)) { push (@$Listing, ":ACCOUNTING$_ - [0:0]"); push (@$Listing, ":ACCOUNTINGSTATELESS$_ - [0:0]"); push (@$Listing, ":STATE$_ - [0:0]"); push (@$Listing, ":STATELESS$_ - [0:0]"); push (@$Listing, ":$_ DROP [0:0]"); push (@$Listing, "-A $_ -j STATE$_"); push (@$Listing, "-A STATE$_ -m state --state INVALID -j STATELESS$_"); push (@$Listing, "-A STATE$_ -j ACCOUNTING$_"); push (@$Listing, "-A STATE$_ -m state --state ESTABLISHED,RELATED -j ACCEPT"); if ($ipv6) { push (@$Listing, "-A STATE$_ ! -p ipv6-icmp -m state ! --state NEW -j STATENOTNEW"); } else { push (@$Listing, "-A STATE$_ -m state ! --state NEW -j STATENOTNEW"); } push (@$Listing, "-A STATELESS$_ -j ACCOUNTINGSTATELESS$_"); } push (@$Listing, "-A STATENOTNEW -m limit --limit $$Sysconfig{'LogLimit'} --limit-burst $$Sysconfig{'LogBurst'} -j LOG --log-prefix \"$$Sysconfig{'LogPrefix'} STATE NOT NEW: \" --log-level $$Sysconfig{'LogLevel'} --log-tcp-options --log-ip-options"); push (@$Listing, "-A STATENOTNEW -j DROP"); push (@$Listing, "-A MYREJECT -m tcp -p tcp -j REJECT --reject-with tcp-reset"); if ($ipv6) { push (@$Listing, "-A MYREJECT -j REJECT --reject-with icmp6-port-unreachable"); } else { push (@$Listing, "-A MYREJECT -j REJECT --reject-with icmp-port-unreachable"); } } elsif ($entry eq 'nat') { $table=\@nat; $chains=\%nat; foreach (qw(POSTROUTING PREROUTING OUTPUT)) { push (@$Listing, ":$_ ACCEPT [0:0]"); } } else { $table=\@mangle; $chains=\%mangle; foreach (qw(PREROUTING OUTPUT)) { push (@$Listing, ":$_ ACCEPT [0:0]"); } } foreach (keys(%$chains)) { push (@$Listing, ":$_ - [0:0]"); } push (@$Listing, "#"); push (@$Listing, "# beginning of user generated $entry rules"); push (@$Listing, "#"); foreach (@$table) { push (@$Listing, $_); } push (@$Listing, "#"); push (@$Listing, "# end of user generated $entry rules"); push (@$Listing, "#"); if ($entry eq 'filter') { foreach (qw(INPUT OUTPUT FORWARD)) { push (@$Listing, "-A STATELESS$_ -m limit --limit $$Sysconfig{'LogLimit'} --limit-burst $$Sysconfig{'LogBurst'} -j LOG --log-prefix \"$$Sysconfig{'LogPrefix'} INVALID STATE: \" --log-level $$Sysconfig{'LogLevel'} --log-tcp-options --log-ip-options"); push (@$Listing, "-A STATELESS$_ -j DROP"); } } push (@$Listing, "COMMIT"); } } sub printRules { my ($Listing) = @_; @$Listing=map { $_."\n" } @$Listing; print @$Listing; } sub signalCatcher { $SignalCatched=1; } sub applyRules { my ($timeout, $Listing) = @_; my @oldrules; my $error; @$Listing=map { $_."\n" } @$Listing; if ($ipv6) { open (IPT, '/sbin/ip6tables-save|'); } else { open (IPT, '/sbin/iptables-save|'); } @oldrules = ; close (IPT); $SIG{'INT'} = 'signalCatcher'; $SIG{'KILL'} = 'signalCatcher'; $SIG{'QUIT'} = 'signalCatcher'; $SIG{'TERM'} = 'signalCatcher'; if ($ipv6) { open (IPT, '|/sbin/ip6tables-restore'); } else { open (IPT, '|/sbin/iptables-restore'); } print IPT @$Listing; close (IPT); $error=$?; if ($timeout && !$error) { sleep $timeout; } if ($timeout || $SignalCatched || $error) { if ($ipv6) { open (IPT, '|/sbin/ip6tables-restore'); } else { open (IPT, '|/sbin/iptables-restore'); } print IPT @oldrules; close (IPT); if ($SignalCatched) { die "aborted. old rules restored.\n"; } elsif ($error) { die "error in generated rules\n"; } } } sub readCommandLine { my %Networks; my %Services; my %Protocols; my %Interfaces; my %Sysconfig; my %Marker; my @Rules; my @Listing; my $test=0; my $print=0; my $disable=0; my $writeconfigfile; my $writeldapruleset; my $ldap; my $readldap=0; my $writeldap=0; my $mesg; my $ldapbase='o=unconfigured'; my $ldapserver='localhost:389'; my $ldapruleset='std'; my $ldapbinddn; my $ldappassword; my $timeout=0; if (exists($ENV{'LOGLIMIT'})) { $Sysconfig{'LogLimit'}=$ENV{'LOGLIMIT'}; } else { $Sysconfig{'LogLimit'}='20/minute'; } if (exists($ENV{'LOGBURST'})) { $Sysconfig{'LogBurst'}=$ENV{'LOGBURST'}; } else { $Sysconfig{'LogBurst'}='5'; } if (exists($ENV{'LOGLEVEL'})) { $Sysconfig{'LogLevel'}=$ENV{'LOGLEVEL'}; } else { $Sysconfig{'LogLevel'}='debug'; } if (exists($ENV{'LOGPREFIX'})) { $Sysconfig{'LogPrefix'}=$ENV{'LOGPREFIX'}; } else { $Sysconfig{'LogPrefix'}='FW'; } if (exists($ENV{'LIMIT'})) { $Sysconfig{'Limit'}=$ENV{'LIMIT'}; } else { $Sysconfig{'Limit'}='20/minute'; } if (exists($ENV{'BURST'})) { $Sysconfig{'Burst'}=$ENV{'BURST'}; } else { $Sysconfig{'Burst'}='5'; } if (exists($ENV{'ACCOUNTPREFIX'})) { $Sysconfig{'AccountPrefix'}=$ENV{'ACCOUNTPREFIX'}; } else { $Sysconfig{'AccountPrefix'}='ACC_'; } my %opt; getopts('6c:tpds:b:r:T:C:R:D:w:W', \%opt) || uifUsg (); $ipv6 = 1 if $opt{'6'}; $configfile=$configfile6 if $opt{'6'}; $configfile = $opt{'c'} if $opt{'c'}; $test = 1 if $opt{'t'}; $print = 1 if $opt{'p'}; $disable = 1 if $opt{'d'}; if ($opt{'T'}) { if ($opt{'T'} =~ /^(\d+)$/) { $timeout=$1; } else { die "timeout must be numeric: $opt{'T'}\n"; uifUsg (); } } if ($opt{'s'}) { $ldapserver=$opt{'s'}; } if ($opt{'b'}) { $ldapbase=$opt{'b'}; } if ($opt{'r'}) { $readldap=1; $ldapruleset=$opt{'r'}; } if ($opt{'C'}) { $ldap=1; $writeconfigfile=$opt{'C'}; } if ($opt{'R'}) { $writeldap=1; $writeldapruleset=$opt{'R'}; } if ($opt{'D'}) { $ldapbinddn=$opt{'D'}; } if ($opt{'w'}) { $ldappassword=$opt{'w'}; } if ($opt{'W'}) { print "password: "; $ldappassword=; chomp($ldappassword); } if ($ipv6) { if (exists($ENV{'LOGPREFIX6'})) { $Sysconfig{'LogPrefix'}=$ENV{'LOGPREFIX6'}; } else { $Sysconfig{'LogPrefix'}='FW6'; } } if ($readldap || $writeldap) { if ($LDAPENABLED == 0) { die "To use LDAP features be sure to install Net::LDAP from the Debian package libnet-ldap-perl" } ; $ldap = Net::LDAP->new($ldapserver) or die "$@"; if ($ldapbinddn && ($ldappassword eq "")) { $mesg=$ldap->bind( $ldapbinddn); } elsif ($ldapbinddn && $ldappassword) { $mesg=$ldap->bind( $ldapbinddn, password => $ldappassword); } else { $mesg=$ldap->bind; } if ($mesg->is_error) { die "can't bind to ldap server: ".$mesg->error."\n"; uifUsg (); } } unless ($disable) { if ($readldap) { readLdap ($ldap, $ldapbase, $ldapruleset, \%Networks, \%Services, \%Interfaces, \%Protocols, \@Rules, \%Sysconfig, \%Marker); } else { my $Id=0; readConfig ($configfile, \%Networks, \%Services, \%Interfaces, \%Protocols, \@Rules, \$Id, \%Sysconfig, \%Marker); } if ($writeconfigfile) { writeConfig ($writeconfigfile, \%Networks, \%Services, \%Interfaces, \%Protocols, \@Rules, \%Sysconfig, \%Marker); exit 0; } elsif ($writeldap) { writeLdap ($ldap, $ldapbase, $writeldapruleset, \%Networks, \%Services, \%Interfaces, \%Protocols, \@Rules, \%Sysconfig, \%Marker); exit 0; } else { validateData (\%Networks, \%Services, \%Interfaces, \%Protocols, \@Rules, \%Sysconfig, \%Marker); genRuleDump (\@Rules, \@Listing, \%Sysconfig); } } else { clearAllRules (\@Listing); } if ($print) { printRules (\@Listing); } if ($test==0) { applyRules ($timeout, \@Listing); } } sub clearAllRules { my ($Listing) = @_; push (@$Listing,"*mangle"); push (@$Listing, ":PREROUTING ACCEPT [0:0]"); push (@$Listing, ":OUTPUT ACCEPT [0:0]"); push (@$Listing, "COMMIT"); if ($ipv6) {} else { push (@$Listing, "*nat"); push (@$Listing, ":PREROUTING ACCEPT [0:0]"); push (@$Listing, ":POSTROUTING ACCEPT [0:0]"); push (@$Listing, ":OUTPUT ACCEPT [0:0]"); push (@$Listing, "COMMIT"); } push (@$Listing, "*filter"); push (@$Listing, ":INPUT ACCEPT [0:0]"); push (@$Listing, ":OUTPUT ACCEPT [0:0]"); push (@$Listing, ":FORWARD ACCEPT [0:0]"); push (@$Listing, "COMMIT"); } sub uifUsg { print "usage: $0 [-6] [-c configfile] [-t] [-p] [-d] [-s server] [-b base] [-r ruleset] [-R ruleset] [-D ] [-W] [-w ] [-T time] [-C configfile]\n"; print "-6 ipv6 mode default config $configfile6\n"; print "-c read instead of $configfile (or in ipv6 mode $configfile6)\n"; print "-t test rules\n"; print "-p print rules to stdout\n"; print "-d disable firewall (clear all rules)\n"; print "-s LDAP-server (default: localhost)\n"; print "-b LDAP-base\n"; print "-r LDAP ruleset\n"; print "-T apply new rules and restore old rules after