diff options
Diffstat (limited to 'share/examples/ipfilter')
54 files changed, 6631 insertions, 0 deletions
diff --git a/share/examples/ipfilter/BNF b/share/examples/ipfilter/BNF new file mode 100644 index 000000000000..ef35d25e9f8a --- /dev/null +++ b/share/examples/ipfilter/BNF @@ -0,0 +1,81 @@ +filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] + [ proto ] [ ip ] [ group ] [ tag ] [ pps ] . + +insert = "@" decnumber . +action = block | "pass" | log | "count" | auth | call . +in-out = "in" | "out" . +options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] . +tos = "tos" decnumber | "tos" hexnumber . +ttl = "ttl" decnumber . +proto = "proto" protocol . +ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . +group = [ "head" decnumber ] [ "group" decnumber ] . +pps = "pps" decnumber . + +onif = "on" interface-name [ "out-via" interface-name ] . +block = "block" [ return-icmp[return-code] | "return-rst" ] . +auth = "auth" | "preauth" . +log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . +tag = "tag" tagid . +call = "call" [ "now" ] function-name "/" decnumber. +dup = "dup-to" interface-name[":"ipaddr] . +froute = "fastroute" | "to" interface-name . +replyto = "reply-to" interface-name [ ":" ipaddr ] . +protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . +srcdst = "all" | fromto . +fromto = "from" object "to" object . + +return-icmp = "return-icmp" | "return-icmp-as-dest" . +loglevel = facility"."priority | priority . +object = addr [ port-comp | port-range ] . +addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +port-comp = "port" compare port-num . +port-range = "port" port-num range port-num . +flags = "flags" flag { flag } [ "/" flag { flag } ] . +with = "with" | "and" . +icmp = "icmp-type" icmp-type [ "code" decnumber ] . +return-code = "("icmp-code")" . +keep = "keep" "state" [ "limit" number ] | "keep" "frags" . + +nummask = host-name [ "/" decnumber ] . +host-name = ipaddr | hostname | "any" . +ipaddr = host-num "." host-num "." host-num "." host-num . +host-num = digit [ digit [ digit ] ] . +port-num = service-name | decnumber . + +withopt = [ "not" | "no" ] opttype [ [ "," ] withopt ] . +opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" | + "mbcast" | "opt" ipopts . +optname = ipopts [ "," optname ] . +ipopts = optlist | "sec-class" [ secname ] . +secname = seclvl [ "," secname ] . +seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" | + "reserv-4" | "secret" | "topsecret" . +icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" | + "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" | + "inforep" | "maskreq" | "maskrep" | "routerad" | + "routersol" | decnumber . +icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" | + "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" | + "net-prohib" | "host-prohib" | "net-tos" | "host-tos" | + "filter-prohib" | "host-preced" | "cutoff-preced" . +optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" | + "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" | + "visa" | "imitd" | "eip" | "finn" . +facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" | + "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" | + "audit" | "logalert" | "local0" | "local1" | "local2" | + "local3" | "local4" | "local5" | "local6" | "local7" . +priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" | + "info" | "debug" . + +hexnumber = "0" "x" hexstring . +hexstring = hexdigit [ hexstring ] . +decnumber = digit [ decnumber ] . + +compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" | + "le" | "ge" . +range = "<>" | "><" . +hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" . +digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . +flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" . diff --git a/share/examples/ipfilter/Makefile b/share/examples/ipfilter/Makefile new file mode 100644 index 000000000000..ec4d4be3dd2f --- /dev/null +++ b/share/examples/ipfilter/Makefile @@ -0,0 +1,30 @@ +PACKAGE=ipf +FILES= README + +# dist sample files +.PATH: ${.CURDIR}/rules +FILES+= BASIC.NAT BASIC_1.FW BASIC_2.FW \ + example.1 example.2 example.3 example.4 example.5 \ + example.6 example.7 example.8 example.9 example.10 \ + example.11 example.12 example.13 example.sr firewall \ + ftp-proxy ftppxy nat-setup nat.eg server tcpstate + +# ftp://ftp.OpenBSD.org/pub/OpenBSD/src/share/ipf/ sample files. +FILES+= example.14 firewall.1 firewall.2 \ + ipf.conf.permissive ipf.conf.restrictive \ + ipf.conf.sample ipnat.conf.sample + +# http://www.obfuscation.org/ipf/ how-to +FILES+= ipf-howto.txt + +# http://coombs.anu.edu.au/~avalon/ sample files +FILES+= examples.txt rules.txt + +BINMODE=0755 +SCRIPTS= mkfilters +MAN= mkfilters.1 + +SCRIPTSDIR= ${SHAREDIR}/examples/ipfilter +FILESDIR= ${SHAREDIR}/examples/ipfilter + +.include <bsd.prog.mk> diff --git a/share/examples/ipfilter/Makefile.depend b/share/examples/ipfilter/Makefile.depend new file mode 100644 index 000000000000..11aba52f82cf --- /dev/null +++ b/share/examples/ipfilter/Makefile.depend @@ -0,0 +1,10 @@ +# Autogenerated - do NOT edit! + +DIRDEPS = \ + + +.include <dirdeps.mk> + +.if ${DEP_RELDIR} == ${_DEP_RELDIR} +# local dependencies - needed for -jN in clean tree +.endif diff --git a/share/examples/ipfilter/README b/share/examples/ipfilter/README new file mode 100644 index 000000000000..aa4df9786702 --- /dev/null +++ b/share/examples/ipfilter/README @@ -0,0 +1,14 @@ + +This directory contains various files related to ipfilter. + +For information on building ipf based firewalls, read the ipf-howto.txt. + +a more up to date version of this file may be found at: + + http://www.obfuscation.org/ipf/ + +Additional help may be found at the ipf home page: + + http://coombs.anu.edu.au/~avalon/ + +examples.txt and rules.txt come from this site. diff --git a/share/examples/ipfilter/example.14 b/share/examples/ipfilter/example.14 new file mode 100644 index 000000000000..c4c1994030ba --- /dev/null +++ b/share/examples/ipfilter/example.14 @@ -0,0 +1,61 @@ +# +# log all inbound packet on le0 which has IP options present +# +log in on le0 from any to any with ipopts +# +# block any inbound packets on le0 which are fragmented and "too short" to +# do any meaningful comparison on. This actually only applies to TCP +# packets which can be missing the flags/ports (depending on which part +# of the fragment you see). +# +block in log quick on le0 from any to any with short frag +# +# log all inbound TCP packets with the SYN flag (only) set +# (NOTE: if it were an inbound TCP packet with the SYN flag set and it +# had IP options present, this rule and the above would cause it +# to be logged twice). +# +log in on le0 proto tcp from any to any flags S/SA +# +# block and log any inbound ICMP unreachables +# +block in log on le0 proto icmp from any to any icmp-type unreach +# +# block and log any inbound UDP packets on le0 which are going to port 2049 +# (the NFS port). +# +block in log on le0 proto udp from any to any port = 2049 +# +# quickly allow any packets to/from a particular pair of hosts +# +pass in quick from any to 10.1.3.2/32 +pass in quick from any to 10.1.0.13/32 +pass in quick from 10.1.3.2/32 to any +pass in quick from 10.1.0.13/32 to any +# +# block (and stop matching) any packet with IP options present. +# +block in quick on le0 from any to any with ipopts +# +# allow any packet through +# +pass in from any to any +# +# block any inbound UDP packets destined for these subnets. +# +block in on le0 proto udp from any to 10.1.3.0/24 +block in on le0 proto udp from any to 10.1.1.0/24 +block in on le0 proto udp from any to 10.1.2.0/24 +# +# block any inbound TCP packets with only the SYN flag set that are +# destined for these subnets. +# +block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA +# +# block any inbound ICMP packets destined for these subnets. +# +block in on le0 proto icmp from any to 10.1.3.0/24 +block in on le0 proto icmp from any to 10.1.1.0/24 +block in on le0 proto icmp from any to 10.1.2.0/24 diff --git a/share/examples/ipfilter/examples.txt b/share/examples/ipfilter/examples.txt new file mode 100644 index 000000000000..2faf50a16a0b --- /dev/null +++ b/share/examples/ipfilter/examples.txt @@ -0,0 +1,514 @@ +IP Filter Examples + + [Image] Permissions + [Image] Interface + [Image] Netmasks and hosts + [Image] IP Protocols + [Image] IP Options + [Image] IP Fragments + [Image] TCP/UDP Ports + [Image] ICMP type/code + [Image] TCP Flags (established) + [Image] Responding to a BAD packet + [Image] IP Security Classes + [Image] Packet state filtering + [Image] Network Address Translation (NAT) + [Image] Transparent Proxy Support + [Image] Transparent routing + [Image] Logging packets to network devices + [Image] Rule groups + Authenticating packets + Pre-authenticating packets + + ------------------------------------------------------------------------ + +Permission Specifying. + +To specify where to pass through or to block a packet, either block or pass +is used. In and out are used to describe the direction in which the packet +is travelling through a network interface. Eg: + +# setup default to block all packets. +block in all +block out all +# pass packets from host firewall to any destination +pass in from firewall to any + + ------------------------------------------------------------------------ + +Select network Interfaces + +To select which interface a packet is currently associated with, either its +destination as a result of route processing or where it has been received +from, the on keyword is used. Whilst not compulsory, it is recommended that +each rule include it for clarity. Eg: + +# drop all inbound packets from localhost coming from ethernet +block in on le0 from localhost to any + + ------------------------------------------------------------------------ + +Netmasks and hosts + +As not all networks are formed with classical network boundaries, it is +necessary to provide a mechanism to support VLSM (Variable Length Subnet +Masks). This package provides several ways to do this. Eg: + +# +block in on le0 from mynet/26 to any +# +block in on le0 from mynet/255.255.255.192 to any +# +block in on le0 from mynet mask 255.255.255.192 to any +# +block in on le0 from mynet mask 0xffffffc0 to any + +Are all valid and legal syntax with this package. However, when regenerating +rules (ie using ipfstat), this package will prefer to use the shortest valid +notation (top down). + +The default netmask, when none is given is 255.255.255.255 or "/32". + +To invert the match on a hostname or network, include an ! before the name +or number with no space between them. + ------------------------------------------------------------------------ + +Protocol + +To filter on an individual protocol, it is possible to specify the protocol +in a filter rule. Eg: + +# block all incoming ICMP packets +block in on le0 proto icmp all + +The name of the protocol can be any valid name from /etc/protocols or a +number. + +# allow all IP packets in which are protocol 4 +pass in on le0 proto 4 all + +There is one exception to this rule, being "tcp/udp". If given in a ruleset, +it will match either of the two protocols. This is useful when setting up +port restrictions. Eg: + +# prevent any packets destined for NFS from coming in +block in on le0 proto tcp/udp from any to any port = 2049 + + ------------------------------------------------------------------------ + +Filtering IP fragments + +IP fragments are bad news, in general. Recent study has shown that IP +fragments can pose a large threat to IP packet filtering, IF there are rules +used which rely on data which may be distributed across fragments. To this +package, the threat is that the TCP flags field of the TCP packet may be in +the 2nd or 3rd fragment or possibly be believed to be in the first when +actually in the 2nd or 3rd. + +To filter out these nasties, it is possible to select fragmented packets out +as follows: + +# +# get rid of all IP fragments +# +block in all with frag + +The problem arises that fragments can actually be a non-malicious. The +really malicious ones can be grouped under the term "short fragments" and +can be filtered out as follows: + +# +# get rid of all short IP fragments (too small for valid comparison) +# +block in proto tcp all with short + + ------------------------------------------------------------------------ + +IP Options + +IP options have a bad name for being a general security threat. They can be +of some use, however, to programs such as traceroute but many find this +usefulness not worth the risk. + +Filtering on IP options can be achieved two ways. The first is by naming +them collectively and is done as follows: + +# +# drop and log any IP packets with options set in them. +# +block in log all with ipopts +# + +The second way is to actually list the names of the options you wish to +filter. + +# +# drop any source routing options +# +block in quick all with opt lsrr +block in quick all with opt ssrr + +[Image] NOTE that options are matched explicitly, so if I had lsrr,ssrr it +would only match packets with both options set. + +It is also possible to select packets which DON'T have various options +present in the packet header. For example, to allow telnet connections +without any IP options present, the following would be done: + +# +# Allow anyone to telnet in so long as they don't use IP options. +# +pass in proto tcp from any to any port = 23 with no ipopts +# +# Allow packets with strict source routing and no loose source routing +# +pass in from any to any with opt ssrr not opt lsrr + + ------------------------------------------------------------------------ + +Filtering by ports + +Filtering by port number only works with the TCP and UDP IP protocols. When +specifying port numbers, either the number or the service name from +/etc/services may be used. If the proto field is used in a filter rule, it +will be used in conjunction with the port name in determining the port +number. + +The possible operands available for use with port numbers are: + +Operand Alias Parameters Result +< lt port# true if port is less than given value +> gt port# true if port is greater than given value += eq port# true if port is equal to than given value +!= ne port# true if port is not equal to than given value +<= le port# true if port is less than or equal to given value +=> ge port# true if port is greater than or equal to given value + +Eg: + +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass in proto tcp from fubar/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass in proto udp from fubar port != 53 to localhost + +Two range comparisons are also possible: + +Expression Syntax: +port1# <> port2# true if port is less than port1 or greater than port2 +port1# >< port2# true if port is greater than port1 and less than port2 + +[Image] NOTE that in neither case, when the port number is equal to one of +those given, does it match. Eg: + +# +# block anything trying to get to X terminal ports, X:0 to X:9 +# +block in proto tcp from any to any port 5999 >< 6010 +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +block in proto tcp/udp all +pass in proto tcp/udp from any to any port 512 <> 515 + +Note that the last one above could just as easily be done in the reverse +fashion: allowing everything through and blocking only a small range. Note +that the port numbers are different, however, due to the difference in the +way they are compared. + +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +pass in proto tcp/udp all +block in proto tcp/udp from any to any port 511 >< 516 + + ------------------------------------------------------------------------ + +TCP Flags (established) + +Filtering on TCP flags is useful, but fraught with danger. I'd recommend +that before using TCP flags in your IP filtering, you become at least a +little bit acquainted with what the role of each of them is and when they're +used. This package will compare the flags present in each TCP packet, if +asked, and match if those present in the TCP packet are the same as in the +IP filter rule. + +Some IP filtering/firewall packages allow you to filter out TCP packets +which belong to an "established" connection. This is, simply put, filtering +on packets which have the ACK bit set. The ACK bit is only set in packets +transmitted during the lifecycle of a TCP connection. It is necessary for +this flag to be present from either end for data to be transferred. If you +were using a rule which as worded something like: + +allow proto tcp 10.1.0.0 255.255.0.0 port = 23 10.2.0.0 255.255.0.0 established + +It could be rewritten as: + +pass in proto tcp 10.1.0.0/16 port = 23 10.2.0.0/16 flags A/A +pass out proto tcp 10.1.0.0/16 port = 23 10.2.0.0/16 flags A/A + +A more useful flag to filter on, for TCP connections, I find, is the SYN +flag. This is only set during the initial stages of connection negotiation, +and for the very first packet of a new TCP connection, it is the only flag +set. At all other times, an ACK or maybe even an URG/PUSH flag may be set. +So, if I want to stop connections being made to my internal network +(10.1.0.0) from the outside network, I might do something like: + +# +# block incoming connection requests to my internal network from the big bad +# internet. +# +block in on le0 proto tcp from any to 10.1.0.0/16 flags S/SA + +If you wanted to block the replies to this (the SYN-ACK's), then you might +do: + +block out on le0 proto tcp from 10.1.0.0 to any flags SA/SA + +where SA represents the SYN-ACK flags both being set. + +The flags after the / represent the TCP flag mask, indicating which bits of +the TCP flags you are interested in checking. When using the SYN bit in a +check, you SHOULD specify a mask to ensure that your filter CANNOT be +defeated by a packet with SYN and URG flags, for example, set (to Unix, this +is the same as a plain SYN). + ------------------------------------------------------------------------ + +ICMP Type/Code + +ICMP can be a source of a lot of trouble for Internet Connected networks. +Blocking out all ICMP packets can be useful, but it will disable some +otherwise useful programs, such as "ping". Filtering on ICMP type allows for +pings (for example) to work. Eg: + +# block all ICMP packets. +# +block in proto icmp all +# +# allow in ICMP echos and echo-replies. +# +pass in on le1 proto icmp from any to any icmp-type echo +pass in on le1 proto icmp from any to any icmp-type echorep + +To specify an ICMP code, the numeric value must be used. So, if we wanted to +block all port-unreachables, we would do: + +# +# block all ICMP destination unreachable packets which are port-unreachables +# +block in on le1 proto icmp from any to any icmp-type unreach code 3 + + ------------------------------------------------------------------------ + +Responding to a BAD packet + +To provide feedback to people trying to send packets through your filter +which you wish to disallow, you can send back either an ICMP error +(Destination Unreachable) or, if they're sending a TCP packet, a TCP RST +(Reset). + +What's the difference ? TCP/IP stacks take longer to pass the ICMP errors +back, through to the application, as they can often be due to temporary +problems (network was unplugged for a second) and it is `incorrect' to shut +down a connection for this reason. Others go to the other extreme and will +shut down all connections between the two hosts for which the ICMP error is +received. The TCP RST, however, is for only *one* connection (cannot be used +for more than one) and will cause the connection to immediately shut down. +So, for example, if you're blocking port 113, and setup a rule to return a +TCP RST rather than nothing or an ICMP packet, you won't experience any +delay if the other end was attempting to make a connection to an identd +service. + +Some examples are as follows: + +# +# block all incoming TCP connections but send back a TCP-RST for ones to +# the ident port +# +block in proto tcp from any to any flags S/SA +block return-rst in quick proto tcp from any to any port = 113 flags S/SA +# +# block all inbound UDP packets and send back an ICMP error. +# +block return-icmp in proto udp from any to any + +When returning ICMP packets, it is also possible to specify the type of ICMP +error return. This was requested so that traceroute traces could be forced +to end elegantly. To do this, the requested ICMP Unreachable code is placed +in brackets following the "return-icmp" directive: + +# +# block all inbound UDP packets and send back an ICMP error. +# +block return-icmp (3) in proto udp from any to any port > 30000 +block return-icmp (port-unr) in proto udp from any to any port > 30000 + +Those two examples are equivalent, and return an ICMP port unreachable error +packet to in response to any UDP packet received destined for a port greater +than 30,000. + ------------------------------------------------------------------------ + +Filtering IP Security Classes + +For users who have packets which contain IP security bits, filtering on the +defined classes and authority levels is supported. Currently, filtering on +16bit authority flags is not supported. + +As with ipopts and other IP options, it is possible to say that the packet +only matches if a certain class isn't present. + +Some examples of filtering on IP security options: + +# +# drop all packets without IP security options +# +block in all with no opt sec +# +# only allow packets in and out on le0 which are top secret +# +block out on le1 all +pass out on le1 all with opt sec-class topsecret +block in on le1 all +pass in on le1 all with opt sec-class topsecret + + ------------------------------------------------------------------------ + +Packet state filtering + +Packet state filtering can be used for any TCP flow to short-cut later +filtering. The "short-cuts" are kept in a table, with no alterations to the +packet filter list made. Subsequent packets, if a matching packet is found +in the table, are not passed through the list. For TCP flows, the filter +will follow the ack/sequence numbers of packets and only allow packets +through which fall inside the correct window. + +# +# Keep state for all outgoing telnet connections +# and disallow all other TCP traffic. +# +pass out on le1 proto tcp from any to any port = telnet keep state +block out on le1 all + +For UDP packets, packet exchanges are effectively stateless. However, if a +packet is first sent out from a given port, a reply is usually expected in +answer, in the `reverse' direction. + +# +# allow UDP replies back from name servers +# +pass out on le1 proto udp from any to any port = domain keep state + +Held UDP state is timed out, as is TCP state for entries added which do not +have the SYN flag set. If an entry is created with the SYN flag set, any +subsequent matching packet which doesn't have this flag set (ie a SYN-ACK) +will cause it to be "timeless" (actually, the timeout defaults to 5 days), +until either a FIN or RST is seen. + + ------------------------------------------------------------------------ + +Network Address Translation (NAT) + +Network address translation is used to remap IP #'s from one address range +to another range of network addresses. For TCP and UDP, this also can +include the port numbers. The IP#'s/port #'s are changed when a packet is +going out through an interface and IP Filter matches it against a NAT rules. + +Packets coming back in the same interface are remapped, as a matter of +course, to their original address information. + +# map all tcp connections from 10.1.0.0/16 to 240.1.0.1, changing the source +# port number to something between 10,000 and 20,000 inclusive. For all other +# IP packets, allocate an IP # between 240.1.0.0 and 240.1.0.255, temporarily +# for each new user. In this example, ed1 is the external interface. +# Use ipnat, not ipf to load these rules. +# +map ed1 10.1.0.0/16 -> 240.1.0.1/32 portmap tcp 10000:20000 +map ed1 10.1.0.0/16 -> 240.1.0.0/24 + + ------------------------------------------------------------------------ + +Transparent Proxy Suppoer + +Transparent proxies are supported through redirection, which works in a +similar way to NAT, except that rules are triggered by input packets. To +effect redirection rules, ipnat must be used (same as for NAT) rather than +ipf. + +# Redirection is triggered for input packets. +# For example, to redirect FTP connections through this box (in this case ed0 +# is the interface on the "inside" where default routes point), to the local +# ftp port, forcing them to connect through a proxy, you would use: +# +rdr ed0 0.0.0.0/0 port ftp -> 127.0.0.1 port ftp + + ------------------------------------------------------------------------ + +Transparent routing + +Transparent routing can be performed in two ways using IP Filter. The first +is to use the keyword "fastroute" in a rule, using the normal route lookup +to occur or using a fixed route with "to". Both effect transparent routing +by not causing any decrement in the TTL to occur as it passes through the +kernel. + +# Route all UDP packets through transparently. +# +pass in quick fastroute proto udp all +# +# Route all ICMP packets to network 10 (on le0) out through le1, to "router" +# +pass in quick on le0 to le1:router proto icmp all + + ------------------------------------------------------------------------ + +Logging packets to the network + +Logging packets to the network devices is supported for both packets being +passed through the filter and those being blocked. For packets being passed +on, the "dup-to" keyword must be used, but for packets being blocked, either +"to" (more efficient) or "dup-to" can be used. + +To log packets to the interface without requiring ARP to work, create a +static arp cache for a meaningless IP# (say 10.0.0.1) and log packets to +this IP#. + +# Log all short TCP packets to qe3, with "packetlog" as the intended +# destination for the packet. +# +block in quick to qe3:packetlog proto tcp all with short +# +# Log all connection attempts for TCP +# +pass in quick on ppp0 dup-to le1:packetlog proto tcp all flags S/SA + + ------------------------------------------------------------------------ + +Rule groups + +To aide in making rule processing more efficient, it is possible to setup +rule `groups'. By default, all rules are in group 0 and all other groups +have it as their ultimate parent. To start a new group, a rule includes a +`head' statement, such as this: + +# Process all incoming ppp packets on ppp0 with group 100, with the default for +# this interface to block all incoming. +# +block in quick on ppp0 all head 100 + +If we then wanted to allow people to connect to our WWW server, via ppp0, we +could then just add a rule about WWW. NOTE: only packets which match the +above rule are processed by any group 100 rules. + +# Allow connections to the WWW server via ppp0. +# +pass in quick proto tcp from any to any port = WWW keep state group 100 + + ------------------------------------------------------------------------ +Return to the IP Filter home page diff --git a/share/examples/ipfilter/firewall.1 b/share/examples/ipfilter/firewall.1 new file mode 100644 index 000000000000..077a4607b192 --- /dev/null +++ b/share/examples/ipfilter/firewall.1 @@ -0,0 +1,35 @@ +# +# This is an example of a very light firewall used to guard against +# some of the most easily exploited common security holes. +# +# The example assumes it is running on a gateway with interface ppp0 +# attached to the outside world, and interface ed0 attached to +# network 192.168.4.0 which needs to be protected. +# +# +# Pass any packets not explicitly mentioned by subsequent rules +# +pass out from any to any +pass in from any to any +# +# Block any inherently bad packets coming in from the outside world. +# These include ICMP redirect packets and IP fragments so short the +# filtering rules won't be able to examine the whole UDP/TCP header. +# +block in log quick on ppp0 proto icmp from any to any icmp-type redir +block in log quick on ppp0 proto tcp/udp all with short +# +# Block any IP spoofing attempts. (Packets "from" our network +# shouldn't be coming in from outside). +# +block in log quick on ppp0 from 192.168.4.0/24 to any +block in log quick on ppp0 from localhost to any +block in log quick on ppp0 from 0.0.0.0/32 to any +block in log quick on ppp0 from 255.255.255.255/32 to any +# +# Block any incoming traffic to NFS ports, to the RPC portmapper, and +# to X servers. +# +block in log on ppp0 proto tcp/udp from any to any port = sunrpc +block in log on ppp0 proto tcp/udp from any to any port = 2049 +block in log on ppp0 proto tcp from any to any port = 6000 diff --git a/share/examples/ipfilter/firewall.2 b/share/examples/ipfilter/firewall.2 new file mode 100644 index 000000000000..d87721088afc --- /dev/null +++ b/share/examples/ipfilter/firewall.2 @@ -0,0 +1,69 @@ +# +# This is an example of a fairly heavy firewall used to keep everyone +# out of a particular network while still allowing people within that +# network to get outside. +# +# The example assumes it is running on a gateway with interface ppp0 +# attached to the outside world, and interface ed0 attached to +# network 192.168.4.0 which needs to be protected. +# +# +# Pass any packets not explicitly mentioned by subsequent rules +# +pass out from any to any +pass in from any to any +# +# Block any inherently bad packets coming in from the outside world. +# These include ICMP redirect packets, IP fragments so short the +# filtering rules won't be able to examine the whole UDP/TCP header, +# and anything with IP options. +# +block in log quick on ppp0 proto icmp from any to any icmp-type redir +block in log quick on ppp0 proto tcp/udp all with short +block in log quick on ppp0 from any to any with ipopts +# +# Block any IP spoofing attempts. (Packets "from" our network +# shouldn't be coming in from outside). +# +block in log quick on ppp0 from 192.168.4.0/24 to any +block in log quick on ppp0 from localhost to any +block in log quick on ppp0 from 0.0.0.0/32 to any +block in log quick on ppp0 from 255.255.255.255/32 to any +# +# Block all incoming UDP traffic except talk and DNS traffic. NFS +# and portmap are special-cased and logged. +# +block in on ppp0 proto udp from any to any +block in log on ppp0 proto udp from any to any port = sunrpc +block in log on ppp0 proto udp from any to any port = 2049 +pass in on ppp0 proto udp from any to any port = domain +pass in on ppp0 proto udp from any to any port = talk +pass in on ppp0 proto udp from any to any port = ntalk +# +# Block all incoming TCP traffic connections to known services, +# returning a connection reset so things like ident don't take +# forever timing out. Don't log ident (auth port) as it's so common. +# +block return-rst in log on ppp0 proto tcp from any to any flags S/SA +block return-rst in on ppp0 proto tcp from any to any port = auth flags S/SA +# +# Allow incoming TCP connections to ports between 1024 and 5000, as +# these don't have daemons listening but are used by outgoing +# services like ftp and talk. For slightly more obscurity (though +# not much more security), the second commented out rule can chosen +# instead. +# +pass in on ppp0 proto tcp from any to any port 1024 >< 5000 +#pass in on ppp0 proto tcp from any port = ftp-data to any port 1024 >< 5000 +# +# Now allow various incoming TCP connections to particular hosts, TCP +# to the main nameserver so secondaries can do zone transfers, SMTP +# to the mail host, www to the web server (which really should be +# outside the firewall if you care about security), and ssh to a +# hypothetical machine caled 'gatekeeper' that can be used to gain +# access to the protected network from the outside world. +# +pass in on ppp0 proto tcp from any to ns1 port = domain +pass in on ppp0 proto tcp from any to mail port = smtp +pass in on ppp0 proto tcp from any to www port = www +pass in on ppp0 proto tcp from any to gatekeeper port = ssh diff --git a/share/examples/ipfilter/ipf-howto.txt b/share/examples/ipfilter/ipf-howto.txt new file mode 100644 index 000000000000..66f67bd96bf1 --- /dev/null +++ b/share/examples/ipfilter/ipf-howto.txt @@ -0,0 +1,3167 @@ + + + + + + + IP Filter Based Firewalls HOWTO + + Brendan Conoboy <synk@swcp.com> + Erik Fichtner <emf@obfuscation.org> + + Fri Apr 20 09:31:14 EDT 2001 + + + + + + + Abstract: This document is intended to introduce a new + user to the IP Filter firewalling package and, at the + same time, teach the user some basic fundamentals of + good firewall design. + + + + + + + + + + + + +1. Introduction + + IP Filter is a great little firewall package. It does +just about everything other free firewalls (ipfwadm, +ipchains, ipfw) do, but it's also portable and does neat +stuff the others don't. This document is intended to make +some cohesive sense of the sparse documentation presently +available for ipfilter. Some prior familiarity with packet +filtering will be useful, however too much familiarity may +make this document a waste of your time. For greater under- +standing of firewalls, the authors recommend reading Build- +ing Internet Firewalls, Chapman & Zwicky, O'Reilly and Asso- +ciates; and TCP/IP Illustrated, Volume 1, Stevens, Addison- +Wesley. + + + + + +1.1. Disclaimer + + The authors of this document are not responsible for +any damages incurred due to actions taken based on this doc- +ument. This document is meant as an introduction to building +a firewall based on IP-Filter. If you do not feel + + + + + + + + + + -2- + + +comfortable taking responsibility for your own actions, you +should stop reading this document and hire a qualified secu- +rity professional to install your firewall for you. + + +1.2. Copyright + + Unless otherwise stated, HOWTO documents are copy- +righted by their respective authors. HOWTO documents may be +reproduced and distributed in whole or in part, in any +medium physical or electronic, as long as this copyright +notice is retained on all copies. Commercial redistribution +is allowed and encouraged; however, the authors would like +to be notified of any such distributions. + + All translations, derivative works, or aggregate works +incorporating any HOWTO documents must be covered under this +copyright notice. That is, you may not produce a derivative +work from a HOWTO and impose additional restrictions on its +distribution. Exceptions to these rules may be granted under +certain conditions; please contact the HOWTO coordinator. + + In short, we wish to promote dissemination of this +information through as many channels as possible. However, +we do wish to retain copyright on the HOWTO documents, and +would like to be notified of any plans to redistribute the +HOWTOs. + + +1.3. Where to obtain the important pieces + + The official IPF homepage is at: +<http://coombs.anu.edu.au/~avalon/ip-filter.html> + + The most up-to-date version of this document can be +found at: <http://www.obfuscation.org/ipf/> + + + + +2. Basic Firewalling + + This section is designed to familiarize you with ipfil- +ter's syntax, and firewall theory in general. The features +discussed here are features you'll find in any good firewall +package. This section will give you a good foundation to +make reading and understanding the advanced section very +easy. It must be emphasized that this section alone is not +enough to build a good firewall, and that the advanced sec- +tion really is required reading for anybody who wants to +build an effective security system. + + + + + + + + + + + + + -3- + + +2.1. Config File Dynamics, Order and Precedence + + IPF (IP Filter) has a config file (as opposed to say, +running some command again and again for each new rule). +The config file drips with Unix: There's one rule per line, +the "#" mark denotes a comment, and you can have a rule and +a comment on the same line. Extraneous whitespace is +allowed, and is encouraged to keep the rules readable. + + +2.2. Basic Rule Processing + + The rules are processed from top to bottom, each one +appended after another. This quite simply means that if the +entirety of your config file is: + + block in all + pass in all + +The computer sees it as: + + block in all + pass in all + +Which is to say that when a packet comes in, the first thing +IPF applies is: + + block in all + +Should IPF deem it necessary to move on to the next rule, it +would then apply the second rule: + + pass in all + + At this point, you might want to ask yourself "would +IPF move on to the second rule?" If you're familiar with +ipfwadm or ipfw, you probably won't ask yourself this. +Shortly after, you will become bewildered at the weird way +packets are always getting denied or passed when they +shouldn't. Many packet filters stop comparing packets to +rulesets the moment the first match is made; IPF is not one +of them. + + Unlike the other packet filters, IPF keeps a flag on +whether or not it's going to pass the packet. Unless you +interrupt the flow, IPF will go through the entire ruleset, +making its decision on whether or not to pass or drop the +packet based on the last matching rule. The scene: IP Fil- +ter's on duty. It's been been scheduled a slice of CPU +time. It has a checkpoint clipboard that reads: + + block in all + pass in all + + + + + + + + + + + -4- + + +A packet comes in the interface and it's time to go to work. +It takes a look at the packet, it takes a look at the first +rule: + + block in all + +"So far I think I will block this packet" says IPF. It +takes a look at the second rule: + + pass in all + +"So far I think I will pass this packet" says IPF. It takes +a look at a third rule. There is no third rule, so it goes +with what its last motivation was, to pass the packet +onward. + +It's a good time to point out that even if the ruleset had +been + + block in all + block in all + block in all + block in all + pass in all + +that the packet would still have gone through. There is no +cumulative effect. The last matching rule always takes +precedence. + +2.3. Controlling Rule Processing + + If you have experience with other packet filters, you +may find this layout to be confusing, and you may be specu- +lating that there are problems with portability with other +filters and speed of rule matching. Imagine if you had 100 +rules and most of the applicable ones were the first 10. +There would be a terrible overhead for every packet coming +in to go through 100 rules every time. Fortunately, there +is a simple keyword you can add to any rule that makes it +take action at that match. That keyword is quick. + +Here's a modified copy of the original ruleset using the +quick keyword: + + block in quick all + pass in all + +In this case, IPF looks at the first rule: + + block in quick all + +The packet matches and the search is over. The packet is +expunged without a peep. There are no notices, no logs, no +memorial service. Cake will not be served. So what about + + + + + + + + + + -5- + + +the next rule? + + pass in all + + This rule is never encountered. It could just as eas- +ily not be in the config file at all. The sweeping match of +all and the terminal keyword quick from the previous rule +make certain that no rules are followed afterward. + + Having half a config file laid to waste is rarely a +desirable state. On the other hand, IPF is here to block +packets and as configured, it's doing a very good job. +Nonetheless, IPF is also here to let some packets through, +so a change to the ruleset to make this possible is called +for. + +2.4. Basic filtering by IP address + + IPF will match packets on many criteria. The one that +we most commonly think of is the IP address. There are some +blocks of address space from which we should never get traf- +fic. One such block is from the unroutable networks, +192.168.0.0/16 (/16 is the CIDR notation for a netmask. You +may be more familiar with the dotted decimal format, +255.255.0.0. IPF accepts both). If you wanted to block +192.168.0.0/16, this is one way to do it: + + block in quick from 192.168.0.0/16 to any + pass in all + +Now we have a less stringent ruleset that actually does +something for us. Let's imagine a packet comes in from +1.2.3.4. The first rule is applied: + + block in quick from 192.168.0.0/16 to any + +The packet is from 1.2.3.4, not 192.168.*.*, so there is no +match. The second rule is applied: + + pass in all + +The packet from 1.2.3.4 is definitely a part of all, so the +packet is sent to whatever it's destination happened to be. + + On the other hand, suppose we have a packet that comes +in from 192.168.1.2. The first rule is applied: + + block in quick from 192.168.0.0/16 to any + +There's a match, the packet is dropped, and that's the end. +Again, it doesn't move to the second rule because the first +rule matches and contains the quick keyword. + + + + + + + + + + + + -6- + + + At this point you can build a fairly extensive set of +definitive addresses which are passed or blocked. Since +we've already started blocking private address space from +entering our firewall, let's take care of the rest of it: + + block in quick from 192.168.0.0/16 to any + block in quick from 172.16.0.0/12 to any + block in quick from 10.0.0.0/8 to any + pass in all + +The first three address blocks are some of the private IP +space. + +2.5. Controlling Your Interfaces + + It seems very frequent that companies have internal +networks before they want a link to the outside world. In +fact, it's probably reasonable to say that's the main reason +people consider firewalls in the first place. The machine +that bridges the outside world to the inside world and vice +versa is the router. What separates the router from any +other machine is simple: It has more than one interface. + + Every packet you receive comes from a network inter- +face; every packet you transmit goes out a network inter- +face. Say your machine has 3 interfaces, lo0 (loopback), +xl0 (3com ethernet), and tun0 (FreeBSD's generic tunnel +interface that PPP uses), but you don't want packets coming +in on the tun0 interface? + + block in quick on tun0 all + pass in all + +In this case, the on keyword means that the data is coming +in on the named interface. If a packet comes in on tun0, +the first rule will block it. If a packet comes in on lo0 +or in on xl0, the first rule will not match, the second rule +will, the packet will be passed. + +2.6. Using IP Address and Interface Together + + It's an odd state of affairs when one decides it best +to have the tun0 interface up, but not allow any data to be +received from it. The more criteria the firewall matches +against, the tighter (or looser) the firewall can become. +Maybe you want data from tun0, but not from 192.168.0.0/16? +This is the start of a powerful firewall. + + block in quick on tun0 from 192.168.0.0/16 to any +----------- + See rfc1918 at +<http://www.faqs.org/rfcs/rfc1918.html> and +<http://www.ietf.org/internet-drafts/draft-man- +ning-dsua-06.txt> + + + + + + + + + + -7- + + + pass in all + +Compare this to our previous rule: + + block in quick from 192.168.0.0/16 to any + pass in all + +The old way, all traffic from 192.168.0.0/16, regardless of +interface, was completely blocked. The new way, using on +tun0 means that it's only blocked if it comes in on the tun0 +interface. If a packet arrived on the xl0 interface from +192.168.0.0/16, it would be passed. + + At this point you can build a fairly extensive set of +definitive addresses which are passed or blocked. Since +we've already started blocking private address space from +entering tun0, let's take care of the rest of it: + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + pass in all + +You've already seen the first three blocks, but not the +rest. The fourth is a largely wasted class-A network used +for loopback. Much software communicates with itself on +127.0.0.1 so blocking it from an external source is a good +idea. The fifth, 0.0.0.0/8, should never be seen on the +internet. Most IP stacks treat "0.0.0.0/32" as the default +gateway, and the rest of the 0.*.*.* network gets handled +strangely by various systems as a byproduct of how routing +decisions are made. You should treat 0.0.0.0/8 just like +127.0.0.0/8. 169.254.0.0/16 has been assigned by the IANA +for use in auto-configuration when systems have not yet been +able to obtain an IP address via DHCP or the like. Most +notably, Microsoft Windows will use addresses in this range +if they are set to DHCP and cannot find a DHCP server. +192.0.2.0/24 has also been reserved for use as an example IP +netblock for documentation authors. We specifically do not +use this range as it would cause confusion when we tell you +to block it, and thus all our examples come from +20.20.20.0/24. 204.152.64.0/23 is an odd netblock reserved +by Sun Microsystems for private cluster interconnects, and +blocking this is up to your own judgement. Lastly, +224.0.0.0/3 wipes out the "Class D and E" networks which is +used mostly for multicast traffic, although further defini- +tion of "Class E" space can be found in RFC 1166. + + + + + + + + + + + -8- + + + There's a very important principle in packet filtering +which has only been alluded to with the private network +blocking and that is this: When you know there's certain +types of data that only comes from certain places, you setup +the system to only allow that kind of data from those +places. In the case of the unroutable addresses, you know +that nothing from 10.0.0.0/8 should be arriving on tun0 +because you have no way to reply to it. It's an illegiti- +mate packet. The same goes for the other unroutables as +well as 127.0.0.0/8. + + Many pieces of software do all their authentication +based upon the packet's originating IP address. When you +have an internal network, say 20.20.20.0/24, you know that +the only traffic for that internal network is going to come +off the local ethernet. Should a packet from 20.20.20.0/24 +arrive over a PPP dialup, it's perfectly reasonable to drop +it on the floor, or put it in a dark room for interrogation. +It should by no means be allowed to get to its final desti- +nation. You can accomplish this particularly easily with +what you already know of IPF. The new ruleset would be: + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in quick on tun0 from 20.20.20.0/24 to any + pass in all + +2.7. Bi-Directional Filtering; The "out" Keyword + + Up until now, we've been passing or blocking inbound +traffic. To clarify, inbound traffic is all traffic that +enters the firewall on any interface. Conversely, outbound +traffic is all traffic that leaves on any interface (whether +locally generated or simply passing through). This means +that all packets coming in are not only filtered as they +enter the firewall, they're also filtered as they exit. +Thusfar there's been an implied pass out all that may or may +not be desirable. Just as you may pass and block incoming +traffic, you may do the same with outgoing traffic. + + Now that we know there's a way to filter outbound pack- +ets just like inbound, it's up to us to find a conceivable +use for such a thing. One possible use of this idea is to +keep spoofed packets from exiting your own network. Instead +of passing any traffic out the router, you could instead +limit permitted traffic to packets originating at + + + + + + + + + + + -9- + + +20.20.20.0/24. You might do it like this: + + pass out quick on tun0 from 20.20.20.0/24 to any + block out quick on tun0 from any to any + +If a packet comes from 20.20.20.1/32, it gets sent out by +the first rule. If a packet comes from 1.2.3.4/32 it gets +blocked by the second. + + You can also make similar rules for the unroutable +addresses. If some machine tries to route a packet through +IPF with a destination in 192.168.0.0/16, why not drop it? +The worst that can happen is that you'll spare yourself some +bandwidth: + + block out quick on tun0 from any to 192.168.0.0/16 + block out quick on tun0 from any to 172.16.0.0/12 + block out quick on tun0 from any to 10.0.0.0/8 + block out quick on tun0 from any to 0.0.0.0/8 + block out quick on tun0 from any to 127.0.0.0/8 + block out quick on tun0 from any to 169.254.0.0/16 + block out quick on tun0 from any to 192.0.2.0/24 + block out quick on tun0 from any to 204.152.64.0/23 + block out quick on tun0 from any to 224.0.0.0/3 + block out quick on tun0 from !20.20.20.0/24 to any + +In the narrowest viewpoint, this doesn't enhance your secu- +rity. It enhances everybody else's security, and that's a +nice thing to do. As another viewpoint, one might suppose +that because nobody can send spoofed packets from your site, +that your site has less value as a relay for crackers, and +as such is less of a target. + + You'll likely find a number of uses for blocking out- +bound packets. One thing to always keep in mind is that in +and out directions are in reference to your firewall, never +any other machine. + +2.8. Logging What Happens; The "log" Keyword + + Up to this point, all blocked and passed packets have +been silently blocked and silently passed. Usually you want +to know if you're being attacked rather than wonder if that +firewall is really buying you any added benefits. While I +wouldn't want to log every passed packet, and in some cases +every blocked packet, I would want to know about the blocked +packets from 20.20.20.0/24. To do this, we add the log key- +word: + + block in quick on tun0 from 192.168.0.0/16 to any +----------- + This can, of course, be changed by using -DIPFIL- +TER_DEFAULT_BLOCK when compiling ipfilter on your +system. + + + + + + + + + + -10- + + + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + pass in all + +So far, our firewall is pretty good at blocking packets com- +ing to it from suspect places, but there's still more to be +done. For one thing, we're accepting packets destined any- +where. One thing we ought to do is make sure packets to +20.20.20.0/32 and 20.20.20.255/32 get dropped on the floor. +To do otherwise opens the internal network for a smurf +attack. These two lines would prevent our hypothetical net- +work from being used as a smurf relay: + + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + +This brings our total ruleset to look something like this: + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass in all + +2.9. Complete Bi-Directional Filtering By Interface + + So far we have only presented fragments of a complete +ruleset. When you're actually creating your ruleset, you +should setup rules for every direction and every interface. +The default state of ipfilter is to pass packets. It is as +though there were an invisible rule at the beginning which +states pass in all and pass out all. Rather than rely on +some default behaviour, make everything as specific as pos- +sible, interface by interface, until every base is covered. + + First we'll start with the lo0 interface, which wants +to run wild and free. Since these are programs talking to +others on the local system, go ahead and keep it unre- +stricted: + + + + + + + + + + -11- + + + pass out quick on lo0 + pass in quick on lo0 + +Next, there's the xl0 interface. Later on we'll begin plac- +ing restrictions on the xl0 interface, but to start with, +we'll act as though everything on our local network is +trustworthy and give it much the same treatment as lo0: + + pass out quick on xl0 + pass in quick on xl0 + +Finally, there's the tun0 interface, which we've been half- +filtering with up until now: + + block out quick on tun0 from any to 192.168.0.0/16 + block out quick on tun0 from any to 172.16.0.0/12 + block out quick on tun0 from any to 127.0.0.0/8 + block out quick on tun0 from any to 10.0.0.0/8 + block out quick on tun0 from any to 0.0.0.0/8 + block out quick on tun0 from any to 169.254.0.0/16 + block out quick on tun0 from any to 192.0.2.0/24 + block out quick on tun0 from any to 204.152.64.0/23 + block out quick on tun0 from any to 224.0.0.0/3 + pass out quick on tun0 from 20.20.20.0/24 to any + block out quick on tun0 from any to any + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass in all + +This is a pretty significant amount of filtering already, +protecting 20.20.20.0/24 from being spoofed or being used +for spoofing. Future examples will continue to show one- +sideness, but keep in mind that it's for brevity's sake, and +when setting up your own ruleset, adding rules for every +direction and every interface is necessary. + + +2.10. Controlling Specific Protocols; The "proto" Keyword + + Denial of Service attacks are as rampant as buffer +overflow exploits. Many denial of service attacks rely on +glitches in the OS's TCP/IP stack. Frequently, this has +come in the form of ICMP packets. Why not block them + + + + + + + + + + -12- + + +entirely? + + block in log quick on tun0 proto icmp from any to any + +Now any ICMP traffic coming in from tun0 will be logged and +discarded. + +2.11. Filtering ICMP with the "icmp-type" Keyword; Merging +Rulesets + + Of course, dropping all ICMP isn't really an ideal sit- +uation. Why not drop all ICMP? Well, because it's useful +to have partially enabled. So maybe you want to keep some +types of ICMP traffic and drop other kinds. If you want +ping and traceroute to work, you need to let in ICMP types 0 +and 11. Strictly speaking, this might not be a good idea, +but if you need to weigh security against convenience, IPF +lets you do it. + + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + +Remember that ruleset order is important. Since we're doing +everything quick we must have our passes before our blocks, +so we really want the last three rules in this order: + + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + block in log quick on tun0 proto icmp from any to any + +Adding these 3 rules to the anti-spoofing rules is a bit +tricky. One error might be to put the new ICMP rules at the +beginning: + + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + block in log quick on tun0 proto icmp from any to any + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass in all + +The problem with this is that an ICMP type 0 packet from +192.168.0.0/16 will get passed by the first rule, and never +blocked by the fourth rule. Also, since we quickly pass an + + + + + + + + + + -13- + + +ICMP ECHO_REPLY (type 0) to 20.20.20.0/24, we've just opened +ourselves back up to a nasty smurf attack and nullified +those last two block rules. Oops. To avoid this, we place +the ICMP rules after the anti-spoofing rules: + + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + block in log quick on tun0 proto icmp from any to any + pass in all + +Because we block spoofed traffic before the ICMP rules are +processed, a spoofed packet never makes it to the ICMP rule- +set. It's very important to keep such situations in mind +when merging rules. + +2.12. TCP and UDP Ports; The "port" Keyword + + Now that we've started blocking packets based on proto- +col, we can start blocking packets based on specific aspects +of each protocol. The most frequently used of these aspects +is the port number. Services such as rsh, rlogin, and tel- +net are all very convenient to have, but also hideously +insecure against network sniffing and spoofing. One great +compromise is to only allow the services to run internally, +then block them externally. This is easy to do because +rlogin, rsh, and telnet use specific TCP ports (513, 514, +and 23 respectively). As such, creating rules to block them +is easy: + + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 513 + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 514 + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 23 + +Make sure all 3 are before the pass in all and they'll be +closed off from the outside (leaving out spoofing for +brevity's sake): + + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0 + pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11 + block in log quick on tun0 proto icmp from any to any + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 513 + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 514 + + + + + + + + + + -14- + + + block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 23 + pass in all + +You might also want to block 514/udp (syslog), 111/tcp & +111/udp (portmap), 515/tcp (lpd), 2049/tcp and 2049/udp +(NFS), 6000/tcp (X11) and so on and so forth. You can get a +complete listing of the ports being listened to by using +netstat -a (or lsof -i, if you have it installed). + + Blocking UDP instead of TCP only requires replacing +proto tcp with proto udp. The rule for syslog would be: + + block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 514 + +IPF also has a shorthand way to write rules that apply to +both proto tcp and proto udp at the same time, such as +portmap or NFS. The rule for portmap would be: + + block in log quick on tun0 proto tcp/udp from any to 20.20.20.0/24 port = 111 + + + + +3. Advanced Firewalling Introduction + + This section is designed as an immediate followup to +the basic section. Contained below are both concepts for +advanced firewall design, and advanced features contained +only within ipfilter. Once you are comfortable with this +section, you should be able to build a very strong firewall. + +3.1. Rampant Paranoia; or The Default-Deny Stance + + There's a big problem with blocking services by the +port: sometimes they move. RPC based programs are terrible +about this, lockd, statd, even nfsd listens places other +than 2049. It's awfully hard to predict, and even worse to +automate adjusting all the time. What if you miss a ser- +vice? Instead of dealing with all that hassle, let's start +over with a clean slate. The current ruleset looks like +this: + + + + + Yes, we really are starting over. The first rule we're +going to use is this: + + block in all + +No network traffic gets through. None. Not a peep. You're +rather secure with this setup. Not terribly useful, but +quite secure. The great thing is that it doesn't take much +more to make your box rather secure, yet useful too. Let's + + + + + + + + + + -15- + + +say the machine this is running on is a web server, nothing +more, nothing less. It doesn't even do DNS lookups. It +just wants to take connections on 80/tcp and that's it. We +can do that. We can do that with a second rule, and you +already know how: + + block in on tun0 all + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80 + +This machine will pass in port 80 traffic for 20.20.20.1, +and deny everything else. For basic firewalling, this is +all one needs. + +3.2. Implicit Allow; The "keep state" Rule + + The job of your firewall is to prevent unwanted traffic +getting to point B from point A. We have general rules +which say "as long as this packet is to port 23, it's okay." +We have general rules which say "as long as this packet has +its FIN flag set, it's okay." Our firewalls don't know the +beginning, middle, or end of any TCP/UDP/ICMP session. They +merely have vague rules that are applied to all packets. +We're left to hope that the packet with its FIN flag set +isn't really a FIN scan, mapping our services. We hope that +the packet to port 23 isn't an attempted hijack of our tel- +net session. What if there was a way to identify and autho- +rize individual TCP/UDP/ICMP sessions and distinguish them +from port scanners and DoS attacks? There is a way, it's +called keeping state. + + We want convenience and security in one. Lots of peo- +ple do, that's why Ciscos have an "established" clause that +lets established tcp sessions go through. Ipfw has estab- +lished. Ipfwadm has setup/established. They all have this +feature, but the name is very misleading. When we first saw +it, we thought it meant our packet filter was keeping track +of what was going on, that it knew if a connection was +really established or not. The fact is, they're all taking +the packet's word for it from a part of the packet anybody +can lie about. They read the TCP packet's flags section and +there's the reason UDP/ICMP don't work with it, they have no +such thing. Anybody who can create a packet with bogus +flags can get by a firewall with this setup. + + Where does IPF come in to play here, you ask? Well, +unlike the other firewalls, IPF really can keep track of +whether or not a connection is established. And it'll do it +with TCP, UDP and ICMP, not just TCP. Ipf calls it keeping +state. The keyword for the ruleset is keep state. + + Up until now, we've told you that packets come in, then +the ruleset gets checked; packets go out, then the ruleset +gets checked. Actually, what happens is packets come in, +the state table gets checked, then *maybe* the inbound + + + + + + + + + + -16- + + +ruleset gets checked; packets go out, the state table gets +checked, then *maybe* the outbound ruleset gets checked. +The state table is a list of TCP/UDP/ICMP sessions that are +unquestionadely passed through the firewall, circumventing +the entire ruleset. Sound like a serious security hole? +Hang on, it's the best thing that ever happened to your +firewall. + + All TCP/IP sessions have a start, a middle, and an end +(even though they're sometimes all in the same packet). You +can't have an end without a middle and you can't have a mid- +dle without a start. This means that all you really need to +filter on is the beginning of a TCP/UDP/ICMP session. If +the beginning of the session is allowed by your firewall +rules, you really want the middle and end to be allowed too +(lest your IP stack should overflow and your machines become +useless). Keeping state allows you to ignore the middle and +end and simply focus on blocking/passing new sessions. If +the new session is passed, all its subsequent packets will +be allowed through. If it's blocked, none of its subsequent +packets will be allowed through. Here's an example for run- +ning an ssh server (and nothing but an ssh server): + + block out quick on tun0 all + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 22 keep state + +The first thing you might notice is that there's no "pass +out" provision. In fact, there's only an all-inclusive +"block out" rule. Despite this, the ruleset is complete. +This is because by keeping state, the entire ruleset is cir- +cumvented. Once the first SYN packet hits the ssh server, +state is created and the remainder of the ssh session is +allowed to take place without interference from the fire- +wall. Here's another example: + + block in quick on tun0 all + pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state + +In this case, the server is running no services. Infact, +it's not a server, it's a client. And this client doesn't +want unauthorized packets entering its IP stack at all. +However, the client wants full access to the internet and +the reply packets that such privilege entails. This simple +ruleset creates state entries for every new outgoing TCP +session. Again, since a state entry is created, these new +TCP sessions are free to talk back and forth as they please +without the hindrance or inspection of the firewall rule- +set. We mentioned that this also works for UDP and ICMP: + + block in quick on tun0 all + pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state + pass out quick on tun0 proto udp from 20.20.20.1/32 to any keep state + pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state + + + + + + + + + + + -17- + + +Yes Virginia, we can ping. Now we're keeping state on TCP, +UDP, ICMP. Now we can make outgoing connections as though +there's no firewall at all, yet would-be attackers can't get +back in. This is very handy because there's no need to +track down what ports we're listening to, only the ports we +want people to be able to get to. + + State is pretty handy, but it's also a bit tricky. You +can shoot yourself in the foot in strange and mysterious +ways. Consider the following ruleset: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 + pass out quick on tun0 proto tcp from any to any keep state + block in quick all + block out quick all + +At first glance, this seems to be a good setup. We allow +incoming sessions to port 23, and outgoing sessions any- +where. Naturally packets going to port 23 will have reply +packets, but the ruleset is setup in such a way that the +pass out rule will generate a state entry and everything +will work perfectly. At least, you'd think so. + + The unfortunate truth is that after 60 seconds of idle +time the state entry will be closed (as opposed to the nor- +mal 5 days). This is because the state tracker never saw +the original SYN packet destined to port 23, it only saw the +SYN ACK. IPF is very good about following TCP sessions from +start to finish, but it's not very good about coming into +the middle of a connection, so rewrite the rule to look like +this: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state + pass out quick on tun0 proto tcp from any to any keep state + block in quick all + block out quick all + +The additional of this rule will enter the very first packet +into the state table and everything will work as expected. +Once the 3-way handshake has been witness by the state +engine, it is marked in 4/4 mode, which means it's setup for +long-term data exchange until such time as the connection is +torn down (wherein the mode changes again. You can see the +current modes of your state table with ipfstat -s. + +3.3. Stateful UDP + + UDP is stateless so naturally it's a bit harder to do a +reliable job of keeping state on it. Nonetheless, ipf does +a pretty good job. When machine A sends a UDP packet to +machine B with source port X and destination port Y, ipf +will allow a reply from machine B to machine A with source +port Y and destination port X. This is a short term state +entry, a mere 60 seconds. + + + + + + + + + + -18- + + + Here's an example of what happens if we use nslookup to +get the IP address of www.3com.com: + + $ nslookup www.3com.com + + A DNS packet is generated: + + 17:54:25.499852 20.20.20.1.2111 > 198.41.0.5.53: 51979+ + +The packet is from 20.20.20.1, port 2111, destined for +198.41.0.5, port 53. A 60 second state entry is created. +If a packet comes back from 198.41.0.5 port 53 destined for +20.20.20.1 port 2111 within that period of time, the reply +packet will be let through. As you can see, milliseconds +later: + + 17:54:25.501209 198.41.0.5.53 > 20.20.20.1.2111: 51979 q: www.3com.com + +The reply packet matches the state criteria and is let +through. At that same moment that packet is let through, +the state gateway is closed and no new incoming packets will +be allowed in, even if they claim to be from the same place. + +3.4. Stateful ICMP + + IPFilter handles ICMP states in the manner that one +would expect from understanding how ICMP is used with TCP +and UDP, and with your understanding of how keep state +works. There are two general types of ICMP messages; +requests and replies. When you write a rule such as: + + pass out on tun0 proto icmp from any to any icmp-type 8 keep state + +to allow outbound echo requests (a typical ping), the resul- +tant icmp-type 0 packet that comes back will be allowed in. +This state entry has a default timeout of an incomplete 0/0 +state of 60 seconds. Thus, if you are keeping state on any +outbound icmp message that will elicit an icmp message in +reply, you need a proto icmp [...] keep state rule. + + However, the majority of ICMP messages are status mes- +sages generated by some failure in UDP (and sometimes TCP), +and in 3.4.x and greater IPFilters, any ICMP error status +message (say icmp-type 3 code 3 port unreachable, or icmp- +type 11 time exceeded) that matches an active state table +entry that could have generated that message, the ICMP +packet is let in. For example, in older IPFilters, if you +wanted traceroute to work, you needed to use: + + pass out on tun0 proto udp from any to any port 33434><33690 keep state + pass in on tun0 proto icmp from any to any icmp-type timex + +whereas now you can do the right thing and just keep state +on udp with: + + + + + + + + + + -19- + + + pass out on tun0 proto udp from any to any port 33434><33690 keep state + +To provide some protection against a third-party sneaking +ICMP messages through your firewall when an active connec- +tion is known to be in your state table, the incoming ICMP +packet is checked not only for matching source and destina- +tion addresses (and ports, when applicable) but a tiny part +of the payload of the packet that the ICMP message is claim- +ing it was generated by. + +3.5. FIN Scan Detection; "flags" Keyword, "keep frags" Key- +word + +Let's go back to the 4 rule set from the previous section: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state + pass out quick on tun0 proto tcp from any to any keep state + block in quick all + block out quick all + +This is almost, but not quite, satisfactory. The problem is +that it's not just SYN packets that're allowed to go to port +23, any old packet can get through. We can change this by +using the flags option: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state + pass out quick on tun0 proto tcp from any to any flags S keep state + block in quick all + block out quick all + +Now only TCP packets, destined for 20.20.20.1, at port 23, +with a lone SYN flag will be allowed in and entered into the +state table. A lone SYN flag is only present as the very +first packet in a TCP session (called the TCP handshake) and +that's really what we wanted all along. There's at least +two advantages to this: No arbitrary packets can come in +and make a mess of your state table. Also, FIN and XMAS +scans will fail since they set flags other than the SYN +flag. Now all incoming packets must either be handshakes or +have state already. If anything else comes in, it's proba- +bly a port scan or a forged packet. There's one exception +to that, which is when a packet comes in that's fragmented +from its journey. IPF has provisions for this as well, the +----------- + Some examples use flags S/SA instead of flags S. +flags S actually equates to flags S/AUPRFS and +matches against only the SYN packet out of all six +possible flags, while flags S/SA will allow pack- +ets that may or may not have the URG, PSH, FIN, or +RST flags set. Some protocols demand the URG or +PSH flags, and S/SAFR would be a better choice for +these, however we feel that it is less secure to +blindly use S/SA when it isn't required. But it's +your firewall. + + + + + + + + + + -20- + + +keep frags keyword. With it, IPF will notice and keep track +of packets that are fragmented, allowing the expected frag- +ments to go through. Let's rewrite the 3 rules to log +forgeries and allow fragments: + + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state keep frags + pass out quick on tun0 proto tcp from any to any keep state flags S keep frags + block in log quick all + block out log quick all + +This works because every packet that should be allowed +through makes it into the state table before the blocking +rules are reached. The only scan this won't detect is a SYN +scan itself. If you're truly worried about that, you might +even want to log all initial SYN packets. + +3.6. Responding To a Blocked Packet + + So far, all of our blocked packets have been dumped on +the floor, logged or not, we've never sent anything back to +the originating host. Sometimes this isn't the most desir- +able of responses because in doing so, we actually tell the +attacker that a packet filter is present. It seems a far +better thing to misguide the attacker into believing that, +while there's no packet filter running, there's likewise no +services to break into. This is where fancier blocking +comes into play. + + When a service isn't running on a Unix system, it nor- +mally lets the remote host know with some sort of return +packet. In TCP, this is done with an RST (Reset) packet. +When blocking a TCP packet, IPF can actually return an RST +to the origin by using the return-rst keyword. + +Where once we did: + + block in log on tun0 proto tcp from any to 20.20.20.0/24 port = 23 + pass in all + +We might now do: + + block return-rst in log proto tcp from any to 20.20.20.0/24 port = 23 + block in log quick on tun0 + pass in all + +We need two block statements since return-rst only works +with TCP, and we still want to block protocols such as UDP, +ICMP, and others. Now that this is done, the remote side +will get "connection refused" instead of "connection timed +out". + + It's also possible to send an error message when some- +body sends a packet to a UDP port on your system. Whereas +once you might have used: + + + + + + + + + + -21- + + + block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111 + +You could instead use the return-icmp keyword to send a +reply: + + block return-icmp(port-unr) in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111 + +According to TCP/IP Illustrated, port-unreachable is the +correct ICMP type to return when no service is listening on +the port in question. You can use any ICMP type you like, +but port-unreachable is probably your best bet. It's also +the default ICMP type for return-icmp. + + However, when using return-icmp, you'll notice that +it's not very stealthy, and it returns the ICMP packet with +the IP address of the firewall, not the original destination +of the packet. This was fixed in ipfilter 3.3, and a new +keyword; return-icmp-as-dest, has been added. The new for- +mat is: + + block return-icmp-as-dest(port-unr) in log on tun0 proto udp from any to 20.20.20.0/24 port = 111 + +3.7. Fancy Logging Techniques + + It is important to note that the presence of the log +keyword only ensures that the packet will be available to +the ipfilter logging device; /dev/ipl. In order to actu- +ally see this log information, one must be running the ipmon +utility (or some other utility that reads from /dev/ipl). +The typical usage of log is coupled with ipmon -s to log the +information to syslog. As of ipfilter 3.3, one can now even +control the logging behavior of syslog by using log level +keywords, as in rules such as this: + + block in log level auth.info quick on tun0 from 20.20.20.0/24 to any + block in log level auth.alert quick on tun0 proto tcp from any to 20.20.20.0/24 port = 21 + +In addition to this, you can tailor what information is +being logged. For example, you may not be interested that +someone attempted to probe your telnet port 500 times, but +you are interested that they probed you once. You can use +the log first keyword to only log the first example of a +packet. Of course, the notion of "first-ness" only applies +to packets in a specific session, and for the typical +blocked packet, you will be hard pressed to encounter situa- +tions where this does what you expect. However, if used in +conjunction with pass and keep state, this can be a valuable +keyword for keeping tabs on traffic. + + Another useful thing you can do with the logs is to +keep track of interesting pieces of the packet in addition +to the header information normally being logged. Ipfilter +will give you the first 128 bytes of the packet if you use +the log body keyword. You should limit the use of body + + + + + + + + + + -22- + + +logging, as it makes your logs very verbose, but for certain +applications, it is often handy to be able to go back and +take a look at the packet, or to send this data to another +application that can examine it further. + +3.8. Putting It All Together + + So now we have a pretty tight firewall, but it can +still be tighter. Some of the original ruleset we wiped +clean is actually very useful. I'd suggest bringing back +all the anti-spoofing stuff. This leaves us with: + + block in on tun0 + block in quick on tun0 from 192.168.0.0/16 to any + block in quick on tun0 from 172.16.0.0/12 to any + block in quick on tun0 from 10.0.0.0/8 to any + block in quick on tun0 from 127.0.0.0/8 to any + block in quick on tun0 from 0.0.0.0/8 to any + block in quick on tun0 from 169.254.0.0/16 to any + block in quick on tun0 from 192.0.2.0/24 to any + block in quick on tun0 from 204.152.64.0/23 to any + block in quick on tun0 from 224.0.0.0/3 to any + block in log quick on tun0 from 20.20.20.0/24 to any + block in log quick on tun0 from any to 20.20.20.0/32 + block in log quick on tun0 from any to 20.20.20.255/32 + pass out quick on tun0 proto tcp/udp from 20.20.20.1/32 to any keep state + pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state + pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80 flags S keep state + +3.9. Improving Performance With Rule Groups + + Let's extend our use of our firewall by creating a much +more complicated, and we hope more applicable to the real +world, example configuration For this example, we're going +to change the interface names, and network numbers. Let's +assume that we have three interfaces in our firewall with +interfaces xl0, xl1, and xl2. + +xl0 is connected to our external network 20.20.20.0/26 +xl1 is connected to our "DMZ" network 20.20.20.64/26 +xl2 is connected to our protected network 20.20.20.128/25 + +We'll define the entire ruleset in one swoop, since we fig- +ure that you can read these rules by now: + + block in quick on xl0 from 192.168.0.0/16 to any + block in quick on xl0 from 172.16.0.0/12 to any + block in quick on xl0 from 10.0.0.0/8 to any + block in quick on xl0 from 127.0.0.0/8 to any + block in quick on xl0 from 0.0.0.0/8 to any + block in quick on xl0 from 169.254.0.0/16 to any + block in quick on xl0 from 192.0.2.0/24 to any + block in quick on xl0 from 204.152.64.0/23 to any + block in quick on xl0 from 224.0.0.0/3 to any + + + + + + + + + + -23- + + + block in log quick on xl0 from 20.20.20.0/24 to any + block in log quick on xl0 from any to 20.20.20.0/32 + block in log quick on xl0 from any to 20.20.20.63/32 + block in log quick on xl0 from any to 20.20.20.64/32 + block in log quick on xl0 from any to 20.20.20.127/32 + block in log quick on xl0 from any to 20.20.20.128/32 + block in log quick on xl0 from any to 20.20.20.255/32 + pass out on xl0 all + + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state + pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state + pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state + pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state + pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state + block out on xl1 all + pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state + + block out on xl2 all + pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state + +From this arbitarary example, we can already see that our +ruleset is becoming unwieldy. To make matters worse, as we +add more specific rules to our DMZ network, we add addi- +tional tests that must be parsed for every packet, which +affects the performance of the xl0 <-> xl2 connections. If +you set up a firewall with a ruleset like this, and you have +lots of bandwidth and a moderate amount of cpu, everyone +that has a workstation on the xl2 network is going to come +looking for your head to place on a platter. So, to keep +your head <-> torso network intact, you can speed things +along by creating rule groups. Rule groups allow you to +write your ruleset in a tree fashion, instead of as a linear +list, so that if your packet has nothing to do with the set +of tests (say, all those xl1 rules) those rules will never +be consulted. It's somewhat like having multiple firewalls +all on the same machine. + +Here's a simple example to get us started: + + block out quick on xl1 all head 10 + pass out quick proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state group 10 + block out on xl2 all + +In this simplistic example, we can see a small hint of the +power of the rule group. If the packet is not destined for +xl1, the head of rule group 10 will not match, and we will +go on with our tests. If the packet does match for xl1, the +quick keyword will short-circuit all further processing at +the root level (rule group 0), and focus the testing on +rules which belong to group 10; namely, the SYN check for +80/tcp. In this way, we can re-write the above rules so +that we can maximize performance of our firewall. + + + + + + + + + + -24- + + + block in quick on xl0 all head 1 + block in quick on xl0 from 192.168.0.0/16 to any group 1 + block in quick on xl0 from 172.16.0.0/12 to any group 1 + block in quick on xl0 from 10.0.0.0/8 to any group 1 + block in quick on xl0 from 127.0.0.0/8 to any group 1 + block in quick on xl0 from 0.0.0.0/8 to any group 1 + block in quick on xl0 from 169.254.0.0/16 to any group 1 + block in quick on xl0 from 192.0.2.0/24 to any group 1 + block in quick on xl0 from 204.152.64.0/23 to any group 1 + block in quick on xl0 from 224.0.0.0/3 to any group 1 + block in log quick on xl0 from 20.20.20.0/24 to any group 1 + block in log quick on xl0 from any to 20.20.20.0/32 group 1 + block in log quick on xl0 from any to 20.20.20.63/32 group 1 + block in log quick on xl0 from any to 20.20.20.64/32 group 1 + block in log quick on xl0 from any to 20.20.20.127/32 group 1 + block in log quick on xl0 from any to 20.20.20.128/32 group 1 + block in log quick on xl0 from any to 20.20.20.255/32 group 1 + pass in on xl0 all group 1 + + pass out on xl0 all + + block out quick on xl1 all head 10 + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state group 10 + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state group 10 + pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state group 10 + pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state group 10 + pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state group 10 + pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state + pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state group 10 + + pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state + + block out on xl2 all + + pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state + +Now you can see the rule groups in action. For a host on +the xl2 network, we can completely bypass all the checks in +group 10 when we're not communicating with hosts on that +network. + + Depending on your situation, it may be prudent to group +your rules by protocol, or various machines, or netblocks, +or whatever makes it flow smoothly. + +3.10. "Fastroute"; The Keyword of Stealthiness + + Even though we're forwarding some packets, and blocking +other packets, we're typically behaving like a well behaved +router should by decrementing the TTL on the packet and +acknowledging to the entire world that yes, there is a hop +here. But we can hide our presence from inquisitive appli- +cations like unix traceroute which uses UDP packets with +various TTL values to map the hops between two sites. If we + + + + + + + + + + -25- + + +want incoming traceroutes to work, but we do not want to +announce the presence of our firewall as a hop, we can do so +with a rule like this: + + block in quick on xl0 fastroute proto udp from any to any port 33434 >< 33465 + +The presence of the fastroute keyword will signal ipfilter +to not pass the packet into the Unix IP stack for routing +which results in a TTL decrement. The packet will be placed +gently on the output interface by ipfilter itself and no +such decrement will happen. Ipfilter will of course use the +system's routing table to figure out what the appropriate +output interface really is, but it will take care of the +actual task of routing itself. + + There's a reason we used block quick in our example, +too. If we had used pass, and if we had IP Forwarding +enabled in our kernel, we would end up having two paths for +a packet to come out of, and we would probably panic our +kernel. + + It should be noted, however, that most Unix kernels +(and certainly the ones underlying the systems that ipfilter +usually runs on) have far more efficient routing code than +what exists in ipfilter, and this keyword should not be +thought of as a way to improve the operating speed of your +firewall, and should only be used in places where stealth is +an issue. + + + + +4. NAT and Proxies + + Outside of the corporate environment, one of the +biggest enticements of firewall technology to the end user +is the ability to connect several computers through a common +external interface, often without the approval, knowledge, +or even consent of their service provider. To those famil- +iar with Linux, this concept is called IP Masquerading, but +to the rest of the world it is known by the more obscure +name of Network Address Translation, or NAT for short. + +4.1. Mapping Many Addresses Into One Address + + The basic use of NAT accomplishes much the same thing +that Linux's IP Masquerading function does, and it does it +----------- + To be pedantic, what IPFilter provides is really +called NPAT, for Network and Port Address Transla- +tion, which means we can change any of the source +and destination IP Addresses and their source and +destination ports. True NAT only allows one to +change the addresses. + + + + + + + + + + -26- + + +with one simple rule: + + map tun0 192.168.1.0/24 -> 20.20.20.1/32 + +Very simple. Whenever a packet goes out the tun0 interface +with a source address matching the CIDR network mask of +192.168.1.0/24 this packet will be rewritten within the IP +stack such that its source address is 20.20.20.1, and it +will be sent on to its original destination. The system +also keeps a list of what translated connections are in +progress so that it can perform the reverse and remap the +response (which will be directed to 20.20.20.1) to the +internal host that really generated the packet. + + There is a drawback to the rule we have just written, +though. In a large number of cases, we do not happen to +know what the IP address of our outside link is (if we're +using tun0 or ppp0 and a typical ISP) so it makes setting up +our NAT tables a chore. Luckily, NAT is smart enough to +accept an address of 0/32 as a signal that it needs to go +look at what the address of that interface really is and we +can rewrite our rule as follows: + + map tun0 192.168.1.0/24 -> 0/32 + +Now we can load our ipnat rules with impunity and connect to +the outside world without having to edit anything. You do +have to run ipf -y to refresh the address if you get discon- +nected and redial or if your DHCP lease changes, though. + + Some of you may be wondering what happens to the source +port when the mapping happens. With our current rule, the +packet's source port is unchanged from the original source +port. There can be instances where we do not desire this +behavior; maybe we have another firewall further upstream we +have to pass through, or perhaps many hosts are trying to +use the same source port, causing a collision where the rule +doesn't match and the packet is passed untranslated. ipnat +helps us here with the portmap keyword: + + map tun0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:30000 + +Our rule now shoehorns all the translated connections (which +can be tcp, udp, or tcp/udp) into the port range of 20000 to +30000. + + + +----------- + This is a typical internal address space, since +it's non-routable on the Real Internet it is often +used for internal networks. You should still +block these packets coming in from the outside +world as discussed earlier. + + + + + + + + + + -27- + + +4.2. Mapping Many Addresses Into a Pool of Addresses + + Another use common use of NAT is to take a small stati- +cally allocated block of addresses and map many computers +into this smaller address space. This is easy to accom- +plish using what you already know about the map and portmap +keywords by writing a rule like so: + + map tun0 192.168.0.0/16 -> 20.20.20.0/24 portmap tcp/udp 20000:60000 + +Also, there may be instances where a remote application +requires that multiple connections all come from the same IP +address. We can help with these situations by telling NAT +to statically map sessions from a host into the pool of +addresses and work some magic to choose a port. This uses a +the keyword map-block as follows: + + map-block tun0 192.168.1.0/24 -> 20.20.20.0/24 + +4.3. One to One Mappings + + Occasionally it is desirable to have a system with one +IP address behind the firewall to appear to have a com- +pletely different IP address. One example of how this would +work would be a lab of computers which are then attached to +various networks that are to be put under some kind of test. +In this example, you would not want to have to reconfigure +the entire lab when you could place a NAT system in front +and change the addresses in one simple place. We can do +that with the bimap keyword, for bidirectional mapping. +Bimap has some additional protections on it to ensure a +known state for the connection, whereas the map keyword is +designed to allocate an address and a source port and +rewrite the packet and go on with life. + + bimap tun0 192.168.1.1/32 -> 20.20.20.1/32 + +will accomplish the mapping for one host. + +4.4. Spoofing Services + + Spoofing services? What does that have to do with any- +thing? Plenty. Let's pretend that we have a web server +running on 20.20.20.5, and since we've gotten increasingly +suspicious of our network security, we desire to not run +this server on port 80 since that requires a brief lifespan +as the root user. But how do we run it on a less +privledged port of 8000 in this world of "anything dot com"? +How will anyone find our server? We can use the redirection +facilities of NAT to solve this problem by instructing it to +remap any connections destined for 20.20.20.5:80 to really +point to 20.20.20.5:8000. This uses the rdr keyword: + + rdr tun0 20.20.20.5/32 port 80 -> 192.168.0.5 port 8000 + + + + + + + + + + -28- + + +We can also specify the protocol here, if we wanted to redi- +rect a UDP service, instead of a TCP service (which is the +default). For example, if we had a honeypot on our firewall +to impersonate the popular Back Orifice for Windows, we +could shovel our entire network into this one place with a +simple rule: + + rdr tun0 20.20.20.0/24 port 31337 -> 127.0.0.1 port 31337 udp + +An extremely important point must be made about rdr: You +cannot easily use this feature as a "reflector". E.g: + + rdr tun0 20.20.20.5/32 port 80 -> 20.20.20.6 port 80 tcp + +will not work in the situation where .5 and .6 are on the +same LAN segment. The rdr function is applied to packets +that enter the firewall on the specified interface. When a +packet comes in that matches a rdr rule, its destination +address is then rewritten, it is pushed into ipf for filter- +ing, and should it successfully run the gauntlet of filter +rules, it is then sent to the unix routing code. Since this +packet is still inbound on the same interface that it will +need to leave the system on to reach a host, the system gets +confused. Reflectors don't work. Neither does specifying +the address of the interface the packet just came in on. +Always remember that rdr destinations must exit out of the +firewall host on a different interface. + +4.5. Transparent Proxy Support; Redirection Made Useful + + Since you're installing a firewall, you may have +decided that it is prudent to use a proxy for many of your +outgoing connections so that you can further tighten your +filter rules protecting your internal network, or you may +have run into a situation that the NAT mapping process does +not currently handle properly. This can also be accom- +plished with a redirection statement: + + rdr xl0 0.0.0.0/0 port 21 -> 127.0.0.1 port 21 + +This statement says that any packet coming in on the xl0 +interface destined for any address (0.0.0.0/0) on the ftp +port should be rewritten to connect it with a proxy that is +running on the NAT system on port 21. + +----------- + Yes. There is a way to do this. It's so convo- +luted that I refuse to use it, though. Smart peo- +ple who require this functionality will transpar- +ently redirect into something like TIS plug-gw on +127.0.0.1. Stupid people will set up a dummy loop +interface pair and double rewrite. + This includes 127.0.0.1, by the way. That's on +lo0. Neat, huh? + + + + + + + + + + -29- + + + This specific example of FTP proxying does lead to some +complications when used with web browsers or other auto- +matic-login type clients that are unaware of the require- +ments of communicating with the proxy. There are patches +for TIS Firewall Toolkit'sftp-gw to mate it with the nat +process so that it can determine where you were trying to go +and automatically send you there. Many proxy packages now +work in a transparent proxy environment (Squid for example, +located at http://squid.nlanr.net, works fine.) + + This application of the rdr keyword is often more use- +ful when you wish to force users to authenticate themselves +with the proxy. (For example, you desire your engineers to +be able to surf the web, but you would rather not have your +call-center staff doing so.) + +4.6. Magic Hidden Within NAT; Application Proxies + + Since ipnat provides a method to rewrite packets as +they traverse the firewall, it becomes a convenient place to +build in some application level proxies to make up for well +known deficiencies of that application and typical fire- +walls. For example; FTP. We can make our firewall pay +attention to the packets going across it and when it notices +that it's dealing with an Active FTP session, it can write +itself some temporary rules, much like what happens with +keep state, so that the FTP data connection works. To do +this, we use a rule like so: + + map tun0 192.168.1.0/24 -> 20.20.20.1/32 proxy port ftp ftp/tcp + +You must always remember to place this proxy rule before any +portmap rules, otherwise when portmap comes along and +matches the packet and rewrites it before the proxy gets a +chance to work on it. Remember that ipnat rules are first- +match. + + There also exist proxies for "rcmd" (which we suspect +is berkeley r-* commands which should be forbidden anyway, +thus we haven't looked at what this proxy does) and "raudio" +for Real Audio PNM streams. Likewise, both of these rules +should be put before any portmap rules, if you're doing NAT. + + + +5. Loading and Manipulating Filter Rules; The ipf Utility + + IP Filter rules are loaded by using the ipf utility. +The filter rules can be stored in any file on the system, +but typically these rules are stored in /etc/ipf.rules, +/usr/local/etc/ipf.rules, or /etc/opt/ipf/ipf.rules. + + IP Filter has two sets of rules, the active set and the +inactive set. By default, all operations are performed on + + + + + + + + + + -30- + + +the active set. You can manipulate the inactive set by +adding -I to the ipf command line. The two sets can be +toggled by using the -s command line option. This is very +useful for testing new rule sets without wiping out the old +rule set. + + Rules can also be removed from the list instead of +added by using the -r command line option, but it is gener- +ally a safer idea to flush the rule set that you're working +on with -F and completely reload it when making changes. + + In summary, the easiest way to load a rule set is ipf +-Fa -f /etc/ipf.rules. For more complicated manipulations +of the rule set, please see the ipf(1) man page. + +6. Loading and Manipulating NAT Rules; The ipnat Utility + + NAT rules are loaded by using the ipnat utility. The +NAT rules can be stored in any file on the system, but typi- +cally these rules are stored in /etc/ipnat.rules, +/usr/local/etc/ipnat.rules, or /etc/opt/ipf/ipnat.rules. + + Rules can also be removed from the list instead of +added by using the -r command line option, but it is gener- +ally a safer idea to flush the rule set that you're working +on with -C and completely reload it when making changes. +Any active mappings are not affected by -C, and can be +removed with -F. + + NAT rules and active mappings can be examined with the +-l command line option. + + In summary, the easiest way to load a NAT rule set is +ipnat -CF -f /etc/ipnat.rules. + +7. Monitoring and Debugging + + There will come a time when you are interested in what +your firewall is actually doing, and ipfilter would be +incomplete if it didn't have a full suite of status monitor- +ing tools. + +7.1. The ipfstat utility + + In its simplest form, ipfstat displays a table of +interesting data about how your firewall is performing, such +as how many packets have been passed or blocked, if they +were logged or not, how many state entries have been made, +and so on. Here's an example of something you might see +from running the tool: + + # ipfstat + input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0 + output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0 + + + + + + + + + + -31- + + + input packets logged: blocked 99286 passed 0 + output packets logged: blocked 0 passed 0 + packets logged: input 0 output 0 + log failures: input 3898 output 0 + fragment state(in): kept 0 lost 0 + fragment state(out): kept 0 lost 0 + packet state(in): kept 169364 lost 0 + packet state(out): kept 431395 lost 0 + ICMP replies: 0 TCP RSTs sent: 0 + Result cache hits(in): 1215208 (out): 1098963 + IN Pullups succeeded: 2 failed: 0 + OUT Pullups succeeded: 0 failed: 0 + Fastroute successes: 0 failures: 0 + TCP cksum fails(in): 0 (out): 0 + Packet log flags set: (0) + none + +ipfstat is also capable of showing you your current rule +list. Using the -i or the -o flag will show the currently +loaded rules for in or out, respectively. Adding a -h to +this will provide more useful information at the same time +by showing you a "hit count" on each rule. For example: + + # ipfstat -ho + 2451423 pass out on xl0 from any to any + 354727 block out on ppp0 from any to any + 430918 pass out quick on ppp0 proto tcp/udp from 20.20.20.0/24 to any keep state keep frags + +From this, we can see that perhaps there's something abnor- +mal going on, since we've got a lot of blocked packets out- +bound, even with a very permissive pass out rule. Something +here may warrant further investigation, or it may be func- +tioning perfectly by design. ipfstat can't tell you if your +rules are right or wrong, it can only tell you what is hap- +pening because of your rules. + +To further debug your rules, you may want to use the -n +flag, which will show the rule number next to each rule. + + # ipfstat -on + @1 pass out on xl0 from any to any + @2 block out on ppp0 from any to any + @3 pass out quick on ppp0 proto tcp/udp from 20.20.20.0/24 to any keep state keep frags + +The final piece of really interesting information that ipfs- +tat can provide us is a dump of the state table. This is +done with the -s flag: + + # ipfstat -s + 281458 TCP + 319349 UDP + 0 ICMP + 19780145 hits + 5723648 misses + + + + + + + + + + -32- + + + 0 maximum + 0 no memory + 1 active + 319349 expired + 281419 closed + 100.100.100.1 -> 20.20.20.1 ttl 864000 pass 20490 pr 6 state 4/4 + pkts 196 bytes 17394 987 -> 22 585538471:2213225493 16592:16500 + pass in log quick keep state + pkt_flags & b = 2, pkt_options & ffffffff = 0 + pkt_security & ffff = 0, pkt_auth & ffff = 0 + +Here we see that we have one state entry for a TCP connec- +tion. The output will vary slightly from version to ver- +sion, but the basic information is the same. We can see in +this connection that we have a fully established connection +(represented by the 4/4 state. Other states are incomplete +and will be documented fully later.) We can see that the +state entry has a time to live of 240 hours, which is an +absurdly long time, but is the default for an established +TCP connection. This TTL counter is decremented every sec- +ond that the state entry is not used, and will finally +result in the connection being purged if it has been left +idle. The TTL is also reset to 864000 whenever the state +IS used, ensuring that the entry will not time out while it +is being actively used. We can also see that we have passed +196 packets consisting of about 17kB worth of data over this +connection. We can see the ports for both endpoints, in +this case 987 and 22; which means that this state entry rep- +resents a connection from 100.100.100.1 port 987 to +20.20.20.1 port 22. The really big numbers in the second +line are the TCP sequence numbers for this connection, which +helps to ensure that someone isn't easily able to inject a +forged packet into your session. The TCP window is also +shown. The third line is a synopsis of the implicit rule +that was generated by the keep state code, showing that this +connection is an inbound connection. + +7.2. The ipmon utility + + ipfstat is great for collecting snapshots of what's +going on on the system, but it's often handy to have some +kind of log to look at and watch events as they happen in +time. ipmon is this tool. ipmon is capable of watching +the packet log (as created with the log keyword in your +rules), the state log, or the nat log, or any combination of +the three. This tool can either be run in the foreground, +or as a daemon which logs to syslog or a file. If we wanted +to watch the state table in action, ipmon -o S would show +this: + + # ipmon -o S + 01/08/1999 15:58:57.836053 STATE:NEW 100.100.100.1,53 -> 20.20.20.15,53 PR udp + 01/08/1999 15:58:58.030815 STATE:NEW 20.20.20.15,123 -> 128.167.1.69,123 PR udp + 01/08/1999 15:59:18.032174 STATE:NEW 20.20.20.15,123 -> 128.173.14.71,123 PR udp + + + + + + + + + + -33- + + + 01/08/1999 15:59:24.570107 STATE:EXPIRE 100.100.100.1,53 -> 20.20.20.15,53 PR udp Pkts 4 Bytes 356 + 01/08/1999 16:03:51.754867 STATE:NEW 20.20.20.13,1019 -> 100.100.100.10,22 PR tcp + 01/08/1999 16:04:03.070127 STATE:EXPIRE 20.20.20.13,1019 -> 100.100.100.10,22 PR tcp Pkts 63 Bytes 4604 + +Here we see a state entry for an external dns request off +our nameserver, two xntp pings to well-known time servers, +and a very short lived outbound ssh connection. + + ipmon is also capable of showing us what packets have +been logged. For example, when using state, you'll often +run into packets like this: + + # ipmon -o I + 15:57:33.803147 ppp0 @0:2 b 100.100.100.103,443 -> 20.20.20.10,4923 PR tcp len 20 1488 -A + +What does this mean? The first field is obvious, it's a +timestamp. The second field is also pretty obvious, it's +the interface that this event happened on. The third field +@0:2 is something most people miss. This is the rule that +caused the event to happen. Remember ipfstat -in? If you +wanted to know where this came from, you could look there +for rule 2 in rule group 0. The fourth field, the little +"b" says that this packet was blocked, and you'll generally +ignore this unless you're logging passed packets as well, +which would be a little "p" instead. The fifth and sixth +fields are pretty self-explanatory, they say where this +packet came from and where it was going. The seventh ("PR") +and eighth fields tell you the protocol and the ninth field +tells you the size of the packet. The last part, the "-A" +in this case, tells you the flags that were on the packet; +This one was an ACK packet. Why did I mention state ear- +lier? Due to the often laggy nature of the Internet, some- +times packets will be regenerated. Sometimes, you'll get +two copies of the same packet, and your state rule which +keeps track of sequence numbers will have already seen this +packet, so it will assume that the packet is part of a dif- +ferent connection. Eventually this packet will run into a +real rule and have to be dealt with. You'll often see the +last packet of a session being closed get logged because the +keep state code has already torn down the connection before +the last packet has had a chance to make it to your fire- +wall. This is normal, do not be alarmed. Another example +packet that might be logged: + + 12:46:12.470951 xl0 @0:1 S 20.20.20.254 -> 255.255.255.255 PR icmp len 20 9216 icmp 9/0 + +----------- + For a technical presentation of the IP Filter +stateful inspection engine, please see the white +paper Real Stateful TCP Packet Filtering in IP +Filter, by Guido van Rooij. This paper may be +found at +<http://www.iae.nl/users/guido/papers/tcp_filter- +ing.ps.gz> + + + + + + + + + + -34- + + +This is an ICMP router discovery broadcast. We can tell by +the ICMP type 9/0. + +Finally, ipmon also lets us look at the NAT table in action. + + # ipmon -o N + 01/08/1999 05:30:02.466114 @2 NAT:RDR 20.20.20.253,113 <- -> 20.20.20.253,113 [100.100.100.13,45816] + 01/08/1999 05:30:31.990037 @2 NAT:EXPIRE 20.20.20.253,113 <- -> 20.20.20.253,113 [100.100.100.13,45816] Pkts 10 Bytes 455 + +This would be a redirection to an identd that lies to pro- +vide ident service for the hosts behind our NAT, since they +are typically unable to provide this service for themselves +with ordinary natting. + + + + +8. Specific Applications of IP Filter - Things that don't +fit, but should be mentioned anyway. + +8.1. Keep State With Servers and Flags. + + Keeping state is a good thing, but it's quite easy to +make a mistake in the direction that you want to keep state +in. Generally, you want to have a keep state keyword on +the first rule that interacts with a packet for the connec- +tion. One common mistake that is made when mixing state +tracking with filtering on flags is this: + + block in all + pass in quick proto tcp from any to 20.20.20.20/32 port = 23 flags S + pass out all keep state + +That certainly appears to allow a connection to be created +to the telnet server on 20.20.20.20, and the replies to go +back. If you try using this rule, you'll see that it does +work--Momentarily. Since we're filtering for the SYN flag, +the state entry never fully gets completed, and the default +time to live for an incomplete state is 60 seconds. + +We can solve this by rewriting the rules in one of two ways: + +1) + + block in all + pass in quick proto tcp from any to 20.20.20.20/32 port = 23 keep state + block out all + +or: + +2) + + block in all + pass in quick proto tcp from any to 20.20.20.20/32 port = 23 flags S keep state + + + + + + + + + + -35- + + + pass out all keep state + +Either of these sets of rules will result in a fully estab- +lished state entry for a connection to your server. + +8.2. Coping With FTP + + FTP is one of those protocols that you just have to sit +back and ask "What the heck were they thinking?" FTP has +many problems that the firewall administrator needs to deal +with. What's worse, the problems the administrator must +face are different between making ftp clients work and mak- +ing ftp servers work. + + Within the FTP protocol, there are two forms of data +transfer, called active and passive. Active transfers are +those where the server connects to an open port on the +client to send data. Conversely, passive transfers are +those where the client connects to the server to receive +data. + +8.2.1. Running an FTP Server + + In running an FTP server, handling Active FTP sessions +is easy to setup. At the same time, handling Passive FTP +sessions is a big problem. First we'll cover how to handle +Active FTP, then move on to Passive. Generally, we can han- +dle Active FTP sessions like we would an incoming HTTP or +SMTP connection; just open the ftp port and let keep state +do the rest: + + pass in quick proto tcp from any to 20.20.20.20/32 port = 21 flags S keep state + pass out proto tcp all keep state + +These rules will allow Active FTP sessions, the most common +type, to your ftp server on 20.20.20.20. + + The next challenge becomes handling Passive FTP connec- +tions. Web browsers default to this mode, so it's becoming +quite popular and as such it should be supported. The prob- +lem with passive connections are that for every passive con- +nection, the server starts listening on a new port (usually +above 1023). This is essentially like creating a new +unknown service on the server. Assuming we have a good +firewall with a default-deny policy, that new service will +be blocked, and thus Active FTP sessions are broken. Don't +despair! There's hope yet to be had. + + A person's first inclination to solving this problem +might be to just open up all ports above 1023. In truth, +this will work: + + pass in quick proto tcp from any to 20.20.20.20/32 port > 1023 flags S keep state + pass out proto tcp all keep state + + + + + + + + + + -36- + + +This is somewhat unsatisfactory, though. By letting every- +thing above 1023 in, we actually open ourselves up for a +number of potential problems. While 1-1023 is the desig- +nated area for server services to run, numerous programs +decided to use numbers higher than 1023, such as nfsd and X. + + The good news is that your FTP server gets to decide +which ports get assigned to passive sessions. This means +that instead of opening all ports above 1023, you can allo- +cate ports 15001-19999 as ftp ports and only open that range +of your firewall up. In wu-ftpd, this is done with the pas- +sive ports option in ftpaccess. Please see the man page on +ftpaccess for details in wu-ftpd configuration. On the +ipfilter side, all we need do is setup corresponding rules: + + pass in quick proto tcp from any to 20.20.20.20/32 port 15000 >< 20000 flags S keep state + pass out proto tcp all keep state + +If even this solution doesn't satisfy you, you can always +hack IPF support into your FTP server, or FTP server support +into IPF. + +8.2.2. Running an FTP Client + + While FTP server support is still less than perfect in +IPF, FTP client support has been working well since 3.3.3. +As with FTP servers, there are two types of ftp client +transfers: passive and active. + + The simplest type of client transfer from the fire- +wall's standpoint is the passive transfer. Assuming you're +keeping state on all outbound tcp sessions, passive trans- +fers will work already. If you're not doing this already, +please consider the following: + + pass out proto tcp all keep state + +The second type of client transfer, active, is a bit more +troublesome, but nonetheless a solved problem. Active +transfers cause the server to open up a second connection +back to the client for data to flow through. This is nor- +mally a problem when there's a firewall in the middle, stop- +ping outside connections from coming back in. To solve +this, ipfilter includes an ipnat proxy which temporarily +opens up a hole in the firewall just for the FTP server to +get back to the client. Even if you're not using ipnat to +do nat, the proxy is still effective. The following rules +is the bare minimum to add to the ipnat configuration file +(ep0 should be the interface name of the outbound network +connection): + + map ep0 0/0 -> 0/32 proxy port 21 ftp/tcp + + + + + + + + + + + + -37- + + +For more details on ipfilter's internal proxies, see section +3.6 + +8.3. Assorted Kernel Variables + + There are some useful kernel tunes that either need to +be set for ipf to function, or are just generally handy to +know about for building firewalls. The first major one you +must set is to enable IP Forwarding, otherwise ipf will do +very little, as the underlying ip stack won't actually route +packets. + +IP Forwarding: + +openbsd: + net.inet.ip.forwarding=1 + + +freebsd: + net.inet.ip.forwarding=1 + + +netbsd: + net.inet.ip.forwarding=1 + + +solaris: + ndd -set /dev/ip ip_forwarding 1 + +Ephemeral Port Adjustment: + +openbsd: + net.inet.ip.portfirst = 25000 + + +freebsd: + net.inet.ip.portrange.first = 25000 net.inet.ip.por- + trange.last = 49151 + + +netbsd: + net.inet.ip.anonportmin = 25000 net.inet.ip.anonportmax + = 49151 + + +solaris: + ndd -set /dev/tcp tcp_smallest_anon_port 25000 + ndd -set /dev/tcp tcp_largest_anon_port 65535 + +Other Useful Values: + +openbsd: + net.inet.ip.sourceroute = 0 + net.inet.ip.directed-broadcast = 0 + + + + + + + + + + -38- + + +freebsd: + net.inet.ip.sourceroute=0 + net.ip.accept_sourceroute=0 + + +netbsd: + net.inet.ip.allowsrcrt=0 + net.inet.ip.forwsrcrt=0 + net.inet.ip.directed-broadcast=0 + net.inet.ip.redirect=0 + + +solaris: + ndd -set /dev/ip ip_forward_directed_broadcasts 0 + ndd -set /dev/ip ip_forward_src_routed 0 + ndd -set /dev/ip ip_respond_to_echo_broadcast 0 + +In addition, freebsd has some ipf specific sysctl variables. + + net.inet.ipf.fr_flags: 0 + net.inet.ipf.fr_pass: 514 + net.inet.ipf.fr_active: 0 + net.inet.ipf.fr_tcpidletimeout: 864000 + net.inet.ipf.fr_tcpclosewait: 60 + net.inet.ipf.fr_tcplastack: 20 + net.inet.ipf.fr_tcptimeout: 120 + net.inet.ipf.fr_tcpclosed: 1 + net.inet.ipf.fr_udptimeout: 120 + net.inet.ipf.fr_icmptimeout: 120 + net.inet.ipf.fr_defnatage: 1200 + net.inet.ipf.fr_ipfrttl: 120 + net.inet.ipf.ipl_unreach: 13 + net.inet.ipf.ipl_inited: 1 + net.inet.ipf.fr_authsize: 32 + net.inet.ipf.fr_authused: 0 + net.inet.ipf.fr_defaultauthage: 600 + + + + +9. Fun with ipf! + + This section doesn't necessarily teach you anything new +about ipf, but it may raise an issue or two that you haven't +yet thought up on your own, or tickle your brain in a way +that you invent something interesting that we haven't +thought of. + +9.1. Localhost Filtering + + A long time ago at a university far, far away, Wietse +Venema created the tcp-wrapper package, and ever since, it's +been used to add a layer of protection to network services +all over the world. This is good. But, tcp-wrappers have + + + + + + + + + + -39- + + +flaws. For starters, they only protect TCP services, as the +name suggests. Also, unless you run your service from +inetd, or you have specifically compiled it with libwrap and +the appropriate hooks, your service isn't protected. This +leaves gigantic holes in your host security. We can plug +these up by using ipf on the local host. For example, my +laptop often gets plugged into or dialed into networks that +I don't specifically trust, and so, I use the following rule +set: + + pass in quick on lo0 all + pass out quick on lo0 all + + block in log all + block out all + + pass in quick proto tcp from any to any port = 113 flags S keep state + pass in quick proto tcp from any to any port = 22 flags S keep state + pass in quick proto tcp from any port = 20 to any port 39999 >< 45000 flags S keep state + + pass out quick proto icmp from any to any keep state + pass out quick proto tcp/udp from any to any keep state keep frags + +It's been like that for quite a while, and I haven't suf- +fered any pain or anguish as a result of having ipf loaded +up all the time. If I wanted to tighten it up more, I could +switch to using the NAT ftp proxy and I could add in some +rules to prevent spoofing. But even as it stands now, this +box is far more restrictive about what it presents to the +local network and beyond than the typical host does. This +is a good thing if you happen to run a machine that allows a +lot of users on it, and you want to make sure one of them +doesn't happen to start up a service they wern't supposed +to. It won't stop a malicious hacker with root access from +adjusting your ipf rules and starting a service anyway, but +it will keep the "honest" folks honest, and your weird ser- +vices safe, cozy and warm even on a malicious LAN. A big +win, in my opinion. Using local host filtering in addition +to a somewhat less-restrictive "main firewall" machine can +solve many performance issues as well as political night- +mares like "Why doesn't ICQ work?" and "Why can't I put a +web server on my own workstation! It's MY WORKSTATION!!" +Another very big win. Who says you can't have security and +convienence at the same time? + +9.2. What Firewall? Transparent filtering. + + One major concern in setting up a firewall is the +integrity of the firewall itself. Can somebody break into +your firewall, thereby subverting its ruleset? This is a +common problem administrators must face, particularly when +they're using firewall solutions on top of their Unix/NT +machines. Some use it as an argument for blackbox hardware +solutions, under the flawed notion that inherent obscurity + + + + + + + + + + -40- + + +of their closed system increases their security. We have a +better way. + + Many network admins are familiar with the common ether- +net bridge. This is a device that connects two separate +ethernet segments to make them one. An ethernet bridge is +typically used to connect separate buildings, switch network +speeds, and extend maximum wire lengths. Hubs and switches +are common bridges, sometimes they're just 2 ported devices +called repeaters. Recent versions of Linux, OpenBSD, +NetBSD, and FreeBSD include code to convert $1000 PCs into +$10 bridges, too! What all bridges tend to have in common +is that though they sit in the middle of a connection +between two machines, the two machines don't know the bridge +is there. Enter ipfilter and OpenBSD. + + Ethernet bridging takes place at Layer2 on the ISO +stack. IP takes place on Layer3. IP Filter in primarily +concerned with Layer3, but dabbles in Layer2 by working with +interfaces. By mixing IP filter with OpenBSD's bridge +device, we can create a firewall that is both invisible and +unreachable. The system needs no IP address, it doesn't +even need to reveal its ethernet address. The only telltale +sign that the filter might be there is that latency is some- +what higher than a piece of cat5 would normally make it, and +that packets don't seem to make it to their final destina- +tion. + + The setup for this sort of ruleset is surprisingly sim- +ple, too. In OpenBSD, the first bridge device is named +bridge0. Say we have two ethernet cards in our machine as +well, xl0 and xl1. To turn this machine into a bridge, all +one need do is enter the following three commands: + + brconfig bridge0 add xl0 add xl1 up + ifconfig xl0 up + ifconfig xl1 up + +At ths point, all traffic ariving on xl0 is sent out xl1 and +all traffic on xl1 is sent out xl0. You'll note that nei- +ther interface has been assigned an IP address, nor do we +need assign one. All things considered, it's likely best we +not add one at all. + + Rulesets behave essentially the as the always have. +Though there is a bridge0 interface, we don't filter based +on it. Rules continue to be based upon the particular +interface we're using, making it important which network +cable is plugged into which network card in the back of the +machine. Let's start with some basic filtering to illis- +trate what's happened. Assume the network used to look like +this: + + + + + + + + + + + + -41- + + + 20.20.20.1 <---------------------------------> 20.20.20.0/24 network hub + +That is, we have a router at 20.20.20.1 connected to the +20.20.20.0/24 network. All packets from the 20.20.20.0/24 +network go through 20.20.20.1 to get to the outside world +and vice versa. Now we add the Ipf Bridge: + + 20.20.20.1 <-------/xl0 IpfBridge xl1/-------> 20.20.20.0/24 network hub + +We also have the following ruleset loaded on the IpfBridge +host: + + pass in quick all + pass out quick all + +With this ruleset loaded, the network is functionally iden- +tical. As far as the 20.20.20.1 router is concerned, and as +far as the 20.20.20.0/24 hosts are concerned, the two net- +work diagrams are identical. Now let's change the ruleset +some: + + block in quick on xl0 proto icmp + pass in quick all + pass out quick all + +Still, 20.20.20.1 and 20.20.20.0/24 think the network is +identical, but if 20.20.20.1 attempts to ping 20.20.20.2, it +will never get a reply. What's more, 20.20.20.2 won't even +get the packet in the first place. IPfilter will intercept +the packet before it even gets to the other end of the vir- +tual wire. We can put a bridged filter anywhere. Using +this method we can shrink the network trust circle down an +individual host level (given enough ethernet cards:-) + + Blocking icmp from the world seems kind of silly, espe- +cially if you're a sysadmin and like pinging the world, to +traceroute, or to resize your MTU. Let's construct a better +ruleset and take advantage of the original key feature of +ipf: stateful inspection. + + pass in quick on xl1 proto tcp keep state + pass in quick on xl1 proto udp keep state + pass in quick on xl1 proto icmp keep state + block in quick on xl0 + +In this situation, the 20.20.20.0/24 network (perhaps more +aptly called the xl1 network) can now reach the outside +world, but the outside world can't reach it, and it can't +figure out why, either. The router is accessible, the hosts +are active, but the outside world just can't get in. Even +if the router itself were compromised, the firewall would +still be active and successful. + + + + + + + + + + + + -42- + + + So far, we've been filtering by interface and protocol +only. Even though bridging is concerned layer2, we can +still discriminate based on IP address. Normally we have a +few services running, so our ruleset may look like this: + + pass in quick on xl1 proto tcp keep state + pass in quick on xl1 proto udp keep state + pass in quick on xl1 proto icmp keep state + block in quick on xl1 # nuh-uh, we're only passing tcp/udp/icmp sir. + pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state + pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state + block in quick on xl0 + +Now we have a network where 20.20.20.2 is a zone serving +name server, 20.20.20.3 is an incoming mail server, and +20.20.20.7 is a web server. + + Bridged IP Filter is not yet perfect, we must confess. + + First, You'll note that all the rules are setup using +the in direction instead of a combination of in and out. +This is because the out direction is presently unimplemented +with bridging in OpenBSD. This was originally done to pre- +vent vast performance drops using multiple interfaces. Work +has been done in speeding it up, but it remains unimple- +mented. If you really want this feature, you might try your +hand at working on the code or asking the OpenBSD people how +you can help. + + Second, using IP Filter with bridging makes the use of +IPF's NAT features inadvisable, if not downright dangerous. +The first problem is that it would give away that there's a +filtering bridge. The second problem would be that the +bridge has no IP address to masquerade with, which will most +assuredly lead to confusion and perhaps a kernel panic to +boot. You can, of course, put an IP address on the outbound +interface to make NAT work, but part of the glee of bridging +is thus diminished. + +9.2.1. Using Transparent Filtering to Fix Network Design +Mistakes + + Many organizations started using IP well before they +thought a firewall or a subnet would be a good idea. Now +they have class-C sized networks or larger that include all +their servers, their workstations, their routers, coffee +makers, everything. The horror! Renumbering with proper +subnets, trust levels, filters, and so are in both time con- +suming and expensive. The expense in hardware and man hours +alone is enough to make most organizations unwilling to +really solve the problem, not to mention the downtime +involved. The typical problem network looks like this: + + + + + + + + + + -43- + + + 20.20.20.1 router 20.20.20.6 unix server + 20.20.20.2 unix server 20.20.20.7 nt workstation + 20.20.20.3 unix server 20.20.20.8 nt server + 20.20.20.4 win98 workstation 20.20.20.9 unix workstation + 20.20.20.5 intelligent switch 20.20.20.10 win95 workstation + +Only it's about 20 times larger and messier and frequently +undocumented. Ideally, you'd have all the trusting servers +in one subnet, all the work- stations in another, and the +network switches in a third. Then the router would filter +packets between the subnets, giving the workstations limited +access to the servers, nothing access to the switches, and +only the sysadmin's workstation access to the coffee pot. +I've never seen a class-C sized network with such coherence. +IP Filter can help. + + To start with, we're going to separate the router, the +workstations, and the servers. To do this we're going to +need 2 hubs (or switches) which we probably already have, +and an IPF machine with 3 ethernet cards. We're going to +put all the servers on one hub and all the workstations on +the other. Normally we'd then connect the hubs to each +other, then to the router. Instead, we're going to plug the +router into IPF's xl0 interface, the servers into IPF's xl1 +interface, and the workstations into IPF's xl2 interface. +Our network diagram looks something like this: + + | 20.20.20.2 unix server + router (20.20.20.1) ____________| 20.20.20.3 unix server + | / | 20.20.20.6 unix server + | /xl1 | 20.20.20.7 nt server + ------------/xl0 IPF Bridge < + xl2 | 20.20.20.4 win98 workstation + ____________| 20.20.20.8 nt workstation + | 20.20.20.9 unix workstation + | 20.20.20.10 win95 workstation + +Where once there was nothing but interconnecting wires, now +there's a filtering bridge that not a single host needs to +be modified to take advantage of. Presumably we've already +enabled bridging so the network is behaving perfectly nor- +mally. Further, we're starting off with a ruleset much like +our last ruleset: + + pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state + pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state + block in quick on xl0 + pass in quick on xl1 proto tcp keep state + pass in quick on xl1 proto udp keep state + pass in quick on xl1 proto icmp keep state + block in quick on xl1 # nuh-uh, we're only passing tcp/udp/icmp sir. + pass in quick on xl2 proto tcp keep state + + + + + + + + + + -44- + + + pass in quick on xl2 proto udp keep state + pass in quick on xl2 proto icmp keep state + block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir. + +Once again, traffic coming from the router is restricted to +DNS, SMTP, and HTTP. At the moment, the servers and the +workstations can exchange traffic freely. Depending on what +kind of organization you are, there might be something about +this network dynamic you don't like. Perhaps you don't want +your workstations getting access to your servers at all? +Take the xl2 ruleset of: + + pass in quick on xl2 proto tcp keep state + pass in quick on xl2 proto udp keep state + pass in quick on xl2 proto icmp keep state + block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir. + +And change it to: + + block in quick on xl2 from any to 20.20.20.0/24 + pass in quick on xl2 proto tcp keep state + pass in quick on xl2 proto udp keep state + pass in quick on xl2 proto icmp keep state + block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir. + +Perhaps you want them to just get to the servers to get and +send their mail with IMAP? Easily done: + + pass in quick on xl2 proto tcp from any to 20.20.20.3/32 port=25 + pass in quick on xl2 proto tcp from any to 20.20.20.3/32 port=143 + block in quick on xl2 from any to 20.20.20.0/24 + pass in quick on xl2 proto tcp keep state + pass in quick on xl2 proto udp keep state + pass in quick on xl2 proto icmp keep state + block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir. + +Now your workstations and servers are protected from the +outside world, and the servers are protected from your work- +stations. + + Perhaps the opposite is true, maybe you want your work- +stations to be able to get to the servers, but not the out- +side world. After all, the next generation of exploits is +breaking the clients, not the servers. In this case, you'd +change the xl2 rules to look more like this: + + pass in quick on xl2 from any to 20.20.20.0/24 + block in quick on xl2 + +Now the servers have free reign, but the clients can only +connect to the servers. We might want to batten down the +hatches on the servers, too: + + pass in quick on xl1 from any to 20.20.20.0/24 + + + + + + + + + + -45- + + + block in quick on xl1 + +With the combination of these two, the clients and servers +can talk to each other, but neither can access the outside +world (though the outside world can get to the few services +from earlier). The whole ruleset would look something like +this: + + pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state + pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state + pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state + block in quick on xl0 + pass in quick on xl1 from any to 20.20.20.0/24 + block in quick on xl1 + pass in quick on xl2 from any to 20.20.20.0/24 + block in quick on xl2 + +So remember, when your network is a mess of twisty IP +addresses and machine classes, transparent filtered bridges +can solve a problem that would otherwise be lived with and +perhaps someday exploited. + +9.3. Drop-Safe Logging With dup-to and to. + + Until now, we've been using the filter to drop packets. +Instead of dropping them, let's consider passing them on to +another system that can do something useful with this infor- +mation beyond the logging we can perform with ipmon. Our +firewall system, be it a bridge or a router, can have as +many interfaces as we can cram into the system. We can use +this information to create a "drop-safe" for our packets. A +good example of a use for this would be to implement an +intrusion detection network. For starters, it might be +desirable to hide the presence of our intrusion detection +systems from our real network so that we can keep them from +being detected. + + Before we get started, there are some operational char- +acteristics that we need to make note of. If we are only +going to deal with blocked packets, we can use either the to +keyword or the fastroute keyword. (We'll cover the differ- +ences between these two later) If we're going to pass the +packets like we normally would, we need to make a copy of +the packet for our drop-safe log with the dup-to keyword. + +9.3.1. The dup-to Method + + If, for example, we wanted to send a copy of everything +going out the xl3 interface off to our drop-safe network on +ed0, we would use this rule in our filter list: + + pass out on xl3 dup-to ed0 from any to any + + + + + + + + + + + -46- + + +You might also have a need to send the packet directly to a +specific IP address on your drop-safe network instead of +just making a copy of the packet out there and hoping for +the best. To do this, we modify our rule slightly: + + pass out on xl3 dup-to ed0:192.168.254.2 from any to any + +But be warned that this method will alter the copied +packet's destination address, and may thus destroy the use- +fulness of the log. For this reason, we recommend only +using the known address method of logging when you can be +certain that the address that you're logging to corresponds +in some way to what you're logging for (e.g.: don't use +"192.168.254.2" for logging for both your web server and +your mail server, since you'll have a hard time later trying +to figure out which system was the target of a specific set +of packets.) + + This technique can be used quite effectively if you +treat an IP Address on your drop-safe network in much the +same way that you would treat a Multicast Group on the real +internet. (e.g.: "192.168.254.2" could be the channel for +your http traffic analysis system, "23.23.23.23" could be +your channel for telnet sessions, and so on.) You don't +even need to actually have this address set as an address or +alias on any of your analysis systems. Normally, your +ipfilter machine would need to ARP for the new destination +address (using dup-to ed0:192.168.254.2 style, of course) +but we can avoid that issue by creating a static arp entry +for this "channel" on our ipfilter system. + + In general, though, dup-to ed0 is all that is required +to get a new copy of the packet over to our drop-safe net- +work for logging and examination. + +9.3.2. The to Method + + The dup-to method does have an immediate drawback, +though. Since it has to make a copy of the packet and +optionally modify it for its new destination, it's going to +take a while to complete all this work and be ready to deal +with the next packet coming in to the ipfilter system. + + If we don't care about passing the packet to its normal +destination and we were going to block it anyway, we can +just use the to keyword to push this packet past the normal +routing table and force it to go out a different interface +than it would normally go out. + + block in quick on xl0 to ed0 proto tcp from any to any port < 1024 + +we use block quick for to interface routing, because like +fastroute, the to interface code will generate two packet +paths through ipfilter when used with pass, and likely cause + + + + + + + + + + -47- + + +your system to panic. + + + +10. Bogus Network Filtering, the ultimate in current anti- +spoofing technology. + + We've spent a little bit of time tracking down the cur- +rent vast tracts of IP address space that have been reserved +by the IANA for various reasons, or are otherwise not cur- +rently in use at the time this document was written. Since +none of these address ranges should be in use currently, +there should be no legitimate reason to ever see them as a +source address, or to send them traffic as a destination +address, right? Right! + + So without further ado, the complete list of bogus net- +works: + + # + # s/OUTSIDE/outside-interface (eg: fxp0) + # s/MYNET/network-cidr-address (eg: 1.2.3.0/24) + # + block in on OUTSIDE all + block in quick on OUTSIDE from 0.0.0.0/7 to any + block in quick on OUTSIDE from 2.0.0.0/8 to any + block in quick on OUTSIDE from 5.0.0.0/8 to any + block in quick on OUTSIDE from 10.0.0.0/8 to any + block in quick on OUTSIDE from 23.0.0.0/8 to any + block in quick on OUTSIDE from 27.0.0.0/8 to any + block in quick on OUTSIDE from 31.0.0.0/8 to any + block in quick on OUTSIDE from 67.0.0.0/8 to any + block in quick on OUTSIDE from 68.0.0.0/6 to any + block in quick on OUTSIDE from 72.0.0.0/5 to any + block in quick on OUTSIDE from 80.0.0.0/4 to any + block in quick on OUTSIDE from 96.0.0.0/3 to any + block in quick on OUTSIDE from 127.0.0.0/8 to any + block in quick on OUTSIDE from 128.0.0.0/16 to any + block in quick on OUTSIDE from 128.66.0.0/16 to any + block in quick on OUTSIDE from 169.254.0.0/16 to any + block in quick on OUTSIDE from 172.16.0.0/12 to any + block in quick on OUTSIDE from 191.255.0.0/16 to any + block in quick on OUTSIDE from 192.0.0.0/16 to any + block in quick on OUTSIDE from 192.168.0.0/16 to any + block in quick on OUTSIDE from 197.0.0.0/8 to any + block in quick on OUTSIDE from 201.0.0.0/8 to any + block in quick on OUTSIDE from 204.152.64.0/23 to any + block in quick on OUTSIDE from 224.0.0.0/3 to any + block in quick on OUTSIDE from MYNET to any + # Your pass rules come here... + + block out on OUTSIDE all + block out quick on OUTSIDE from !MYNET to any + block out quick on OUTSIDE from MYNET to 0.0.0.0/7 + + + + + + + + + + -48- + + + block out quick on OUTSIDE from MYNET to 2.0.0.0/8 + block out quick on OUTSIDE from MYNET to 5.0.0.0/8 + block out quick on OUTSIDE from MYNET to 10.0.0.0/8 + block out quick on OUTSIDE from MYNET to 23.0.0.0/8 + block out quick on OUTSIDE from MYNET to 27.0.0.0/8 + block out quick on OUTSIDE from MYNET to 31.0.0.0/8 + block out quick on OUTSIDE from MYNET to 67.0.0.0/8 + block out quick on OUTSIDE from MYNET to 68.0.0.0/6 + block out quick on OUTSIDE from MYNET to 72.0.0.0/5 + block out quick on OUTSIDE from MYNET to 80.0.0.0/4 + block out quick on OUTSIDE from MYNET to 96.0.0.0/3 + block out quick on OUTSIDE from MYNET to 127.0.0.0/8 + block out quick on OUTSIDE from MYNET to 128.0.0.0/16 + block out quick on OUTSIDE from MYNET to 128.66.0.0/16 + block out quick on OUTSIDE from MYNET to 169.254.0.0/16 + block out quick on OUTSIDE from MYNET to 172.16.0.0/12 + block out quick on OUTSIDE from MYNET to 191.255.0.0/16 + block out quick on OUTSIDE from MYNET to 192.0.0.0/16 + block out quick on OUTSIDE from MYNET to 192.168.0.0/16 + block out quick on OUTSIDE from MYNET to 197.0.0.0/8 + block out quick on OUTSIDE from MYNET to 201.0.0.0/8 + block out quick on OUTSIDE from MYNET to 204.152.64.0/23 + block out quick on OUTSIDE from MYNET to 224.0.0.0/3 + # Your pass rules come here... + +If you're going to use these, we suggest that you become +familiar with whois.arin.net and keep an occasional eye on +these, as the IANA isn't going to notify you when they allo- +cate one of these to a new corporation or something. You +have been warned. + + We'd also like to thank Frank DiGennaro <fsd@server- +vault.com> for greatly contributing to this filter list. + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/share/examples/ipfilter/ipf.conf.permissive b/share/examples/ipfilter/ipf.conf.permissive new file mode 100644 index 000000000000..016c59cadff2 --- /dev/null +++ b/share/examples/ipfilter/ipf.conf.permissive @@ -0,0 +1,29 @@ +# augmented rules generated by mkfilters +block in log quick from any with ipopts +block in log quick proto tcp from any to any with short +block in log quick all with opt lsrr +block in log quick all with opt ssrr +#------------------------------------------------------- +# loopback pakets left unmolested +pass in quick on lo0 all +pass out quick on lo0 all +#------------------------------------------------------- +pass out on ed1 all head 150 +block out from 127.0.0.0/8 to any group 150 +block out from any to 127.0.0.0/8 group 150 +block out from any to 192.168.1.110/32 group 150 +#------------------------------------------------------- +pass in on ed1 all head 100 +block in from 127.0.0.0/8 to any group 100 +block in from 192.168.1.110/32 to any group 100 +block in from 192.168.0.1/24 to any group 100 +#------------------------------------------------------- +pass out on fxp0 all head 250 +block out from 127.0.0.0/8 to any group 250 +block out from any to 127.0.0.0/8 group 250 +block out from any to 192.168.0.1/32 group 250 +#------------------------------------------------------- +pass in on fxp0 all head 200 +block in from 127.0.0.0/8 to any group 200 +block in from 192.168.0.1/32 to any group 200 +block in from 192.168.1.110/24 to any group 200 diff --git a/share/examples/ipfilter/ipf.conf.restrictive b/share/examples/ipfilter/ipf.conf.restrictive new file mode 100644 index 000000000000..b1b449c8fd77 --- /dev/null +++ b/share/examples/ipfilter/ipf.conf.restrictive @@ -0,0 +1,76 @@ +#-------------------------------------------------------------------------- +# ed1 - external interface +# fxp0 - internal interface +#-------------------------------------------------------------------------- +# First, nasty packets which we don't want near us at all +# packets which are too short to be real except echo replies on lo0 +pass in log quick on lo0 proto icmp from 127.0.0.1/8 to 127.0.0.1/8 with short +block in log quick all with short +block in log quick all with opt lsrr +block in log quick all with opt ssrr +#-------------------------------------------------------------------------- +# loopback packets left unmolested +pass in log quick on lo0 all +pass out log quick on lo0 all +#-------------------------------------------------------------------------- +# Group setup: +# 100 incoming ed1 +# 150 outgoing ed1 +# 200 incoming fxp0 +# 250 outgoing fxp0 +#-------------------------------------------------------------------------- +block in log body on ed1 all head 100 +block out log body on ed1 all head 150 +#-------------------------------------------------------------------------- +block in log on fxp0 all head 200 +block out log on fxp0 all head 250 +#-------------------------------------------------------------------------- +# incoming ed1 traffic - group 100 +# 1) prevent localhost spoofing +block in log quick from 127.0.0.1/32 to 192.168.0.0/24 group 100 +block in log quick from 127.0.0.1/32 to 192.168.1.0/24 group 100 +block in log quick from any to 127.0.0.1/8 group 100 +#-------------------------------------------------------------------------- +# 2) deny pakets which should not be seen on th internet (paranoid) +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from any to 10.0.0.0/8 group 100 +block in log quick from 172.16.0.0/16 to any group 100 +block in log quick from any to 172.16.0.0/16 group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log from any to 192.168.0.0/16 group 100 +# 3) implement policy +# allow incoming ftp-data +pass in log quick proto tcp/udp from any to 192.168.1.1/24 keep state group 100 +# if nothing applies, block and return icmp-replies (unreachable and rst) +block return-icmp(net-unr) in proto udp from any to any group 100 +block return-rst in log proto tcp from any to any group 100 +#-------------------------------------------------------------------------- +# outgoing ed1 traffic - group 150 +# Setup outgoing DNS +pass out log quick proto tcp/udp from any to 212.40.0.10 port = 53 keep state group 150 +pass out log quick proto tcp/udp from any to 212.40.5.50 port = 53 keep state group 150 +# allow outgoing http-service +pass out log quick proto tcp from any to any port = 80 flags S/SA keep state keep frags group 150 +# allow outgoing smtp traffic +pass out log quick proto tcp from 192.168.1.1/24 to any port = 25 flags S/SA keep state group 150 +# allow outgoing pop3 traffic +pass out log quick proto tcp from 192.168.1.1/24 to any port = 110 flags S/SA keep state group 150 +# allow outgoing ftp traffic +pass out log quick proto tcp/udp from 192.168.1.1/24 to any port = ftp keep state group 150 +pass out log quick proto icmp from any to any keep state keep frags group 150 +#-------------------------------------------------------------------------- +# incoming traffic on fxp0 - group 200 +#-------------------------------------------------------------------------- +# 1) prevent localhost spoofing +block in log quick from 127.0.0.0/8 to any group 200 +block in log quick from 192.168.0.1/32 to any group 200 +block in log quick from 192.168.1.110/24 to any group 200 +pass in log quick from any to any group 200 +#-------------------------------------------------------------------------- +# outgoing traffic on fxp0 - group 250 +#-------------------------------------------------------------------------- +block out log quick from 127.0.0.0/8 to any group 250 +block out quick from any to 127.0.0.0/8 group 250 +block out log quick from any to 192.168.0.1/32 group 250 +pass out log quick from any to nay group 250 +#-------------------------------------------------------------------------- diff --git a/share/examples/ipfilter/ipf.conf.sample b/share/examples/ipfilter/ipf.conf.sample new file mode 100644 index 000000000000..cb47107f88c5 --- /dev/null +++ b/share/examples/ipfilter/ipf.conf.sample @@ -0,0 +1,18 @@ +block in log quick from any with ipopts +block in log quick proto tcp from any to any with short +pass out on ed1 all head 150 +block out from 127.0.0.0/8 to any group 150 +block out from any to 127.0.0.0/8 group 150 +block out from any to 192.168.1.110/32 group 150 +pass in on ed1 all head 100 +block in from 127.0.0.0/8 to any group 100 +block in from 192.168.1.110/32 to any group 100 +block in from 192.168.0.1/0xffffff00 to any group 100 +pass out on fxp0 all head 250 +block out from 127.0.0.0/8 to any group 250 +block out from any to 127.0.0.0/8 group 250 +block out from any to 192.168.0.1/32 group 250 +pass in on fxp0 all head 200 +block in from 127.0.0.0/8 to any group 200 +block in from 192.168.0.1 to any group 200 +block in from 192.168.1.110/0xffffff00 to any group 200 diff --git a/share/examples/ipfilter/ipnat.conf.sample b/share/examples/ipfilter/ipnat.conf.sample new file mode 100644 index 000000000000..f20d895936ef --- /dev/null +++ b/share/examples/ipfilter/ipnat.conf.sample @@ -0,0 +1,2 @@ +map ed1 192.168.0.0/24 -> 192.168.1.110/32 portmap tcp/udp 40000:65000 +map ed1 192.168.0.0/24 -> 192.168.1.110/32 diff --git a/share/examples/ipfilter/l4check/Makefile b/share/examples/ipfilter/l4check/Makefile new file mode 100644 index 000000000000..e7366b63ad6a --- /dev/null +++ b/share/examples/ipfilter/l4check/Makefile @@ -0,0 +1,10 @@ +# For Solaris +#LIBS=-lsocket -lnsl + +all: l4check + +l4check: l4check.c + $(CC) -g -I.. $(CFLAGS) $(LIBS) l4check.c -o $@ + +clean: + /bin/rm -f l4check diff --git a/share/examples/ipfilter/l4check/http.check b/share/examples/ipfilter/l4check/http.check new file mode 100644 index 000000000000..56d93d9281a6 --- /dev/null +++ b/share/examples/ipfilter/l4check/http.check @@ -0,0 +1,2 @@ +GET / + diff --git a/share/examples/ipfilter/l4check/http.ok b/share/examples/ipfilter/l4check/http.ok new file mode 100644 index 000000000000..2b5d2c15266d --- /dev/null +++ b/share/examples/ipfilter/l4check/http.ok @@ -0,0 +1 @@ +<HTML>
\ No newline at end of file diff --git a/share/examples/ipfilter/l4check/l4check.c b/share/examples/ipfilter/l4check/l4check.c new file mode 100644 index 000000000000..2e80b7531b4e --- /dev/null +++ b/share/examples/ipfilter/l4check/l4check.c @@ -0,0 +1,800 @@ + +/* + * (C)Copyright (C) 2012 by Darren Reed. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> + +#include <net/if.h> + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> + +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_nat.h" + +#include "ipf.h" + +extern char *optarg; + + +typedef struct l4cfg { + struct l4cfg *l4_next; + struct ipnat l4_nat; /* NAT rule */ + struct sockaddr_in l4_sin; /* remote socket to connect */ + time_t l4_last; /* when we last connected */ + int l4_alive; /* 1 = remote alive */ + int l4_fd; + int l4_rw; /* 0 = reading, 1 = writing */ + char *l4_rbuf; /* read buffer */ + int l4_rsize; /* size of buffer */ + int l4_rlen; /* how much used */ + char *l4_wptr; /* next byte to write */ + int l4_wlen; /* length yet to be written */ +} l4cfg_t; + + +l4cfg_t *l4list = NULL; +char *response = NULL; +char *probe = NULL; +l4cfg_t template; +int frequency = 20; +int ctimeout = 1; +int rtimeout = 1; +size_t plen = 0; +size_t rlen = 0; +int natfd = -1; +int opts = 0; + +#if defined(sun) && !defined(__svr4__) && !defined(__SVR4) +# define strerror(x) sys_errlist[x] +#endif + + +char * +copystr(char *dst, char *src) +{ + register char *s, *t, c; + register int esc = 0; + + for (s = src, t = dst; s && t && (c = *s++); ) + if (esc) { + esc = 0; + switch (c) + { + case 'n' : + *t++ = '\n'; + break; + case 'r' : + *t++ = '\r'; + break; + case 't' : + *t++ = '\t'; + break; + } + } else if (c != '\\') + *t++ = c; + else + esc = 1; + *t = '\0'; + return(dst); +} + +void +addnat(l4cfg_t *l4) +{ + ipnat_t *ipn = &l4->l4_nat; + + printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]), + ipn->in_outmsk, ntohs(ipn->in_pmin)); + printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext)); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(natfd, SIOCADNAT, &ipn) == -1) + perror("ioctl(SIOCADNAT)"); + } +} + + +void +delnat(l4cfg_t *l4) +{ + ipnat_t *ipn = &l4->l4_nat; + + printf("Remove NAT rule for %s/%#x,%u -> ", + inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin); + printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(natfd, SIOCRMNAT, &ipn) == -1) + perror("ioctl(SIOCRMNAT)"); + } +} + + +void +connectl4(l4cfg_t *l4) +{ + l4->l4_rw = 1; + l4->l4_rlen = 0; + l4->l4_wlen = plen; + if (!l4->l4_wlen) { + l4->l4_alive = 1; + addnat(l4); + } else + l4->l4_wptr = probe; +} + + +void +closel4(l4cfg_t *l4, int dead) +{ + close(l4->l4_fd); + l4->l4_fd = -1; + l4->l4_rw = -1; + if (dead && l4->l4_alive) { + l4->l4_alive = 0; + delnat(l4); + } +} + + +void +connectfd(l4cfg_t *l4) +{ + if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin, + sizeof(l4->l4_sin)) == -1) { + if (errno == EISCONN) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Connected fd %d\n", + l4->l4_fd); + connectl4(l4); + return; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Connect failed fd %d: %s\n", + l4->l4_fd, strerror(errno)); + closel4(l4, 1); + return; + } + l4->l4_rw = 1; +} + + +void +writefd(l4cfg_t *l4) +{ + char buf[80], *ptr; + int n, i, fd; + + fd = l4->l4_fd; + + if (l4->l4_rw == -2) { + connectfd(l4); + return; + } + + n = l4->l4_wlen; + + i = send(fd, l4->l4_wptr, n, 0); + if (i == 0 || i == -1) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Send on fd %d failed: %s\n", + fd, strerror(errno)); + closel4(l4, 1); + } else { + l4->l4_wptr += i; + l4->l4_wlen -= i; + if (l4->l4_wlen == 0) + l4->l4_rw = 0; + if (opts & OPT_VERBOSE) + fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd); + } +} + + +void readfd(l4cfg_t *l4) +{ + char buf[80], *ptr; + int n, i, fd; + + fd = l4->l4_fd; + + if (l4->l4_rw == -2) { + connectfd(l4); + return; + } + + if (l4->l4_rsize) { + n = l4->l4_rsize - l4->l4_rlen; + ptr = l4->l4_rbuf + l4->l4_rlen; + } else { + n = sizeof(buf) - 1; + ptr = buf; + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Read %d bytes on fd %d to %p\n", + n, fd, ptr); + i = recv(fd, ptr, n, 0); + if (i == 0 || i == -1) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Read error on fd %d: %s\n", + fd, (i == 0) ? "EOF" : strerror(errno)); + closel4(l4, 1); + } else { + if (ptr == buf) + ptr[i] = '\0'; + if (opts & OPT_VERBOSE) + fprintf(stderr, "%d: Read %d bytes [%*.*s]\n", + fd, i, i, i, ptr); + if (ptr != buf) { + l4->l4_rlen += i; + if (l4->l4_rlen >= l4->l4_rsize) { + if (!strncmp(response, l4->l4_rbuf, + l4->l4_rsize)) { + printf("%d: Good response\n", + fd); + if (!l4->l4_alive) { + l4->l4_alive = 1; + addnat(l4); + } + closel4(l4, 0); + } else { + if (opts & OPT_VERBOSE) + printf("%d: Bad response\n", + fd); + closel4(l4, 1); + } + } + } else if (!l4->l4_alive) { + l4->l4_alive = 1; + addnat(l4); + closel4(l4, 0); + } + } +} + + +int +runconfig(void) +{ + int fd, opt, res, mfd, i; + struct timeval tv; + time_t now, now1; + fd_set rfd, wfd; + l4cfg_t *l4; + + mfd = 0; + opt = 1; + now = time(NULL); + + /* + * First, initiate connections that are closed, as required. + */ + for (l4 = l4list; l4; l4 = l4->l4_next) { + if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) { + l4->l4_last = now; + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + continue; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, + sizeof(opt)); +#ifdef O_NONBLOCK + if ((res = fcntl(fd, F_GETFL, 0)) != -1) + fcntl(fd, F_SETFL, res | O_NONBLOCK); +#endif + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Connecting to %s,%d (fd %d)...", + inet_ntoa(l4->l4_sin.sin_addr), + ntohs(l4->l4_sin.sin_port), fd); + if (connect(fd, (struct sockaddr *)&l4->l4_sin, + sizeof(l4->l4_sin)) == -1) { + if (errno != EINPROGRESS) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "failed\n"); + perror("connect"); + close(fd); + fd = -1; + } else { + if (opts & OPT_VERBOSE) + fprintf(stderr, "waiting\n"); + l4->l4_rw = -2; + } + } else { + if (opts & OPT_VERBOSE) + fprintf(stderr, "connected\n"); + connectl4(l4); + } + l4->l4_fd = fd; + } + } + + /* + * Now look for fd's which we're expecting to read/write from. + */ + FD_ZERO(&rfd); + FD_ZERO(&wfd); + tv.tv_sec = MIN(rtimeout, ctimeout); + tv.tv_usec = 0; + + for (l4 = l4list; l4; l4 = l4->l4_next) + if (l4->l4_rw == 0) { + if (now - l4->l4_last > rtimeout) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "%d: Read timeout\n", + l4->l4_fd); + closel4(l4, 1); + continue; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Wait for read on fd %d\n", + l4->l4_fd); + FD_SET(l4->l4_fd, &rfd); + if (l4->l4_fd > mfd) + mfd = l4->l4_fd; + } else if ((l4->l4_rw == 1 && l4->l4_wlen) || + l4->l4_rw == -2) { + if ((l4->l4_rw == -2) && + (now - l4->l4_last > ctimeout)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, + "%d: connect timeout\n", + l4->l4_fd); + closel4(l4); + continue; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Wait for write on fd %d\n", + l4->l4_fd); + FD_SET(l4->l4_fd, &wfd); + if (l4->l4_fd > mfd) + mfd = l4->l4_fd; + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1, + tv.tv_sec); + i = select(mfd + 1, &rfd, &wfd, NULL, &tv); + if (i == -1) { + perror("select"); + return(-1); + } + + now1 = time(NULL); + + for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) { + if (l4->l4_fd < 0) + continue; + if (FD_ISSET(l4->l4_fd, &rfd)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Ready to read on fd %d\n", + l4->l4_fd); + readfd(l4); + i--; + } + + if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Ready to write on fd %d\n", + l4->l4_fd); + writefd(l4); + i--; + } + } + return(0); +} + + +int +gethostport(char *str, int lnum, u_32_t *ipp, u_short *portp) +{ + struct servent *sp; + struct hostent *hp; + char *host, *port; + struct in_addr ip; + + host = str; + port = strchr(host, ','); + if (port) + *port++ = '\0'; + +#ifdef HAVE_INET_ATON + if (ISDIGIT(*host) && inet_aton(host, &ip)) + *ipp = ip.s_addr; +#else + if (ISDIGIT(*host)) + *ipp = inet_addr(host); +#endif + else { + if (!(hp = gethostbyname(host))) { + fprintf(stderr, "%d: can't resolve hostname: %s\n", + lnum, host); + return(0); + } + *ipp = *(u_32_t *)hp->h_addr; + } + + if (port) { + if (ISDIGIT(*port)) + *portp = htons(atoi(port)); + else { + sp = getservbyname(port, "tcp"); + if (sp) + *portp = sp->s_port; + else { + fprintf(stderr, "%d: unknown service %s\n", + lnum, port); + return(0); + } + } + } else + *portp = 0; + return(1); +} + + +char * +mapfile(char *file, size_t *sizep) +{ + struct stat sb; + caddr_t addr; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) { + perror("open(mapfile)"); + return(NULL); + } + + if (fstat(fd, &sb) == -1) { + perror("fstat(mapfile)"); + close(fd); + return(NULL); + } + + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (addr == (caddr_t)-1) { + perror("mmap(mapfile)"); + close(fd); + return(NULL); + } + close(fd); + *sizep = sb.st_size; + return(char *)addr; +} + + +int +readconfig(char *filename) +{ + char c, buf[512], *s, *t, *errtxt = NULL, *line; + int num, err = 0; + ipnat_t *ipn; + l4cfg_t *l4; + FILE *fp; + + fp = fopen(filename, "r"); + if (!fp) { + perror("open(configfile)"); + return(-1); + } + + bzero((char *)&template, sizeof(template)); + template.l4_fd = -1; + template.l4_rw = -1; + template.l4_sin.sin_family = AF_INET; + ipn = &template.l4_nat; + ipn->in_flags = IPN_TCP|IPN_ROUNDR; + ipn->in_redir = NAT_REDIRECT; + + for (num = 1; fgets(buf, sizeof(buf), fp); num++) { + s = strchr(buf, '\n'); + if (!s) { + fprintf(stderr, "%d: line too long\n", num); + fclose(fp); + return(-1); + } + + *s = '\0'; + + /* + * lines which are comments + */ + s = strchr(buf, '#'); + if (s) + *s = '\0'; + + /* + * Skip leading whitespace + */ + for (line = buf; (c = *line) && ISSPACE(c); line++) + ; + if (!*line) + continue; + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Parsing: [%s]\n", line); + t = strtok(line, " \t"); + if (!t) + continue; + if (!strcasecmp(t, "interface")) { + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, "\t"); + if (!s || !t) { + errtxt = line; + err = -1; + break; + } + + if (!strchr(t, ',')) { + fprintf(stderr, + "%d: local address,port missing\n", + num); + err = -1; + break; + } + + strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname)); + if (!gethostport(t, num, &ipn->in_outip, + &ipn->in_pmin)) { + errtxt = line; + err = -1; + break; + } + ipn->in_outmsk = 0xffffffff; + ipn->in_pmax = ipn->in_pmin; + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Interface %s %s/%#x port %u\n", + ipn->in_ifname, + inet_ntoa(ipn->in_out[0]), + ipn->in_outmsk, ipn->in_pmin); + } else if (!strcasecmp(t, "remote")) { + if (!*ipn->in_ifname) { + fprintf(stderr, + "%d: ifname not set prior to remote\n", + num); + err = -1; + break; + } + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, ""); + if (!s || !t || strcasecmp(s, "server")) { + errtxt = line; + err = -1; + break; + } + + ipn->in_pnext = 0; + if (!gethostport(t, num, &ipn->in_inip, + &ipn->in_pnext)) { + errtxt = line; + err = -1; + break; + } + ipn->in_inmsk = 0xffffffff; + if (ipn->in_pnext == 0) + ipn->in_pnext = ipn->in_pmin; + + l4 = (l4cfg_t *)malloc(sizeof(*l4)); + if (!l4) { + fprintf(stderr, "%d: out of memory (%d)\n", + num, sizeof(*l4)); + err = -1; + break; + } + bcopy((char *)&template, (char *)l4, sizeof(*l4)); + l4->l4_sin.sin_addr = ipn->in_in[0]; + l4->l4_sin.sin_port = ipn->in_pnext; + l4->l4_next = l4list; + l4list = l4; + } else if (!strcasecmp(t, "connect")) { + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, "\t"); + if (!s || !t) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "timeout")) { + ctimeout = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, "connect timeout %d\n", + ctimeout); + } else if (!strcasecmp(s, "frequency")) { + frequency = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "connect frequency %d\n", + frequency); + } else { + errtxt = line; + err = -1; + break; + } + } else if (!strcasecmp(t, "probe")) { + s = strtok(NULL, " \t"); + if (!s) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "string")) { + if (probe) { + fprintf(stderr, + "%d: probe already set\n", + num); + err = -1; + break; + } + t = strtok(NULL, ""); + if (!t) { + fprintf(stderr, + "%d: No probe string\n", num); + err = -1; + break; + } + + probe = malloc(strlen(t)); + copystr(probe, t); + plen = strlen(probe); + if (opts & OPT_VERBOSE) + fprintf(stderr, "Probe string [%s]\n", + probe); + } else if (!strcasecmp(s, "file")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + if (probe) { + fprintf(stderr, + "%d: probe already set\n", + num); + err = -1; + break; + } + probe = mapfile(t, &plen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Probe file %s len %u@%p\n", + t, plen, probe); + } + } else if (!strcasecmp(t, "response")) { + s = strtok(NULL, " \t"); + if (!s) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "timeout")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + rtimeout = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "response timeout %d\n", + rtimeout); + } else if (!strcasecmp(s, "string")) { + if (response) { + fprintf(stderr, + "%d: response already set\n", + num); + err = -1; + break; + } + response = strdup(strtok(NULL, "")); + rlen = strlen(response); + template.l4_rsize = rlen; + template.l4_rbuf = malloc(rlen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Response string [%s]\n", + response); + } else if (!strcasecmp(s, "file")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + if (response) { + fprintf(stderr, + "%d: response already set\n", + num); + err = -1; + break; + } + response = mapfile(t, &rlen); + template.l4_rsize = rlen; + template.l4_rbuf = malloc(rlen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Response file %s len %u@%p\n", + t, rlen, response); + } + } else { + errtxt = line; + err = -1; + break; + } + } + + if (errtxt) + fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt); + fclose(fp); + return(err); +} + + +void +usage(char *prog) +{ + fprintf(stderr, "Usage: %s -f <configfile>\n", prog); + exit(1); +} + + +int +main(int argc, char *argv[]) +{ + char *config = NULL; + int c; + + while ((c = getopt(argc, argv, "f:nv")) != -1) + switch (c) + { + case 'f' : + config = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (config == NULL) + usage(argv[0]); + + if (readconfig(config)) + exit(1); + + if (!l4list) { + fprintf(stderr, "No remote servers, exiting."); + exit(1); + } + + if (!(opts & OPT_DONOTHING)) { + natfd = open(IPL_NAT, O_RDWR); + if (natfd == -1) { + perror("open(IPL_NAT)"); + exit(1); + } + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Starting...\n"); + while (runconfig() == 0) + ; +} diff --git a/share/examples/ipfilter/l4check/l4check.conf b/share/examples/ipfilter/l4check/l4check.conf new file mode 100644 index 000000000000..d000e9fc5b48 --- /dev/null +++ b/share/examples/ipfilter/l4check/l4check.conf @@ -0,0 +1,31 @@ +# +# NOTE: ORDER IS IMPORTANT IN THIS FILE +# +# Interface to do the redirections on and the IP address which will be +# targeted. +# +interface nf0 192.168.1.1,2100 +# +connect timeout 1 +connect frequency 20 +# +# If no probe string is specified, a successful connection implies the +# server is still alive. +# +probe string GET /\n\n +#probe file http.check +# +response timeout 4 +response string <HTML> +#response file http.ok +# +# Here we have multiple servers, listed because that's what happens to be +# used for testing of connect timeoutes, read timeouts, success and things +# which don't connect. +# +remote server 192.168.1.2,23 +remote server 192.168.1.2,2101 +remote server 192.168.1.3,25 +remote server 192.168.1.254,8000 +remote server 192.168.1.1,9 +# diff --git a/share/examples/ipfilter/mkfilters b/share/examples/ipfilter/mkfilters new file mode 100644 index 000000000000..fe15c55563ab --- /dev/null +++ b/share/examples/ipfilter/mkfilters @@ -0,0 +1,116 @@ +#!/usr/local/bin/perl +# for best results, bring up all your interfaces before running this + +if ($^O =~ m/^irix/i) +{ + &irix_mkfilters || regular_mkfilters || die $!; +} +else +{ + ®ular_mkfilters || irix_mkfilters || die $!; +} + +foreach $i (keys %ifaces) { + $net{$i} = $inet{$i}."/".$netmask{$i} if (defined($inet{$i})); +} +# +# print out route suggestions +# +print "#\n"; +print "# The following routes should be configured, if not already:\n"; +print "#\n"; +foreach $i (keys %ifaces) { + next if (($i =~ /lo/) || !defined($net{$i}) || defined($ppp{$i})); + print "# route add $inet{$i} localhost 0\n"; +} +print "#\n"; + +# +# print out some generic filters which people should use somewhere near the top +# +print "block in log quick from any to any with ipopts\n"; +print "block in log quick proto tcp from any to any with short\n"; + +$grpi = 0; + +foreach $i (keys %ifaces) { + if (!defined($inet{$i})) { + next; + } + + $grpi += 100; + $grpo = $grpi + 50; + + if ($i !~ /lo/) { + print "pass out on $i all head $grpo\n"; + print "block out from 127.0.0.0/8 to any group $grpo\n"; + print "block out from any to 127.0.0.0/8 group $grpo\n"; + print "block out from any to $inet{$i}/32 group $grpo\n"; + print "pass in on $i all head $grpi\n"; + print "block in from 127.0.0.0/8 to any group $grpi\n"; + print "block in from $inet{$i}/32 to any group $grpi\n"; + foreach $j (keys %ifaces) { + if ($i ne $j && $j !~ /^lo/ && defined($net{$j})) { + print "block in from $net{$j} to any group $grpi\n"; + } + } + } +} + +sub irix_mkfilters +{ + open(NETSTAT, "/usr/etc/netstat -i|") || return 0; + + while (defined($line = <NETSTAT>)) + { + if ($line =~ m/^Name/) + { + next; + } + elsif ($line =~ m/^(\S+)/) + { + open(I, "/usr/etc/ifconfig $1|") || return 0; + &scan_ifconfig; + close I; # being neat... - Allen + } + } + close NETSTAT; # again, being neat... - Allen + return 1; +} + +sub regular_mkfilters +{ + open(I, "ifconfig -a|") || return 0; + &scan_ifconfig; + close I; # being neat... - Allen + return 1; +} + +sub scan_ifconfig +{ + while (<I>) { + chop; + if (/^[a-zA-Z]+\d+:/) { + ($iface = $_) =~ s/^([a-zA-Z]+\d+).*/$1/; + $ifaces{$iface} = $iface; + next; + } + if (/inet/) { + if (/\-\-\>/) { # PPP, (SLIP?) + ($inet{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$1/; + ($ppp{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$2/; + } else { + ($inet{$iface} = $_) =~ s/.*inet ([^ ]+).*/$1/; + } + } + if (/netmask/) { + ($mask = $_) =~ s/.*netmask ([^ ]+).*/$1/; + $mask =~ s/^/0x/ if ($mask =~ /^[0-9a-f]*$/); + $netmask{$iface} = $mask; + } + if (/broadcast/) { + ($bcast{$iface} = $_) =~ s/.*broadcast ([^ ]+).*/$1/; + } + } +} + diff --git a/share/examples/ipfilter/mkfilters.1 b/share/examples/ipfilter/mkfilters.1 new file mode 100644 index 000000000000..65afaec4019e --- /dev/null +++ b/share/examples/ipfilter/mkfilters.1 @@ -0,0 +1,15 @@ +.\" +.TH MKFILTERS 1 +.SH NAME +mkfilters \- generate a minimal firewall ruleset for ipfilter +.SH SYNOPSIS +.B mkfilters +.SH FILES +/usr/share/examples/ipfilter/mkfilters +.SH DESCRIPTION +.PP +\fBmkfilters\fP is a perl script that generates a minimal filter rule set for +use with \fBipfilter\fP by parsing the output of \fBifconfig\fP. +.DT +.SH SEE ALSO +ipf(8), ipf(5), ipfilter(5), ifconfig(8) diff --git a/share/examples/ipfilter/mlfk_rule.c b/share/examples/ipfilter/mlfk_rule.c new file mode 100644 index 000000000000..9126e4d97281 --- /dev/null +++ b/share/examples/ipfilter/mlfk_rule.c @@ -0,0 +1,69 @@ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> + +#include <netinet/ipl.h> +#include <netinet/ip_compat.h> +#include <netinet/ip_fil.h> +#include <netinet/ip_state.h> +#include <netinet/ip_nat.h> +#include <netinet/ip_auth.h> +#include <netinet/ip_frag.h> + +#include "ip_rules.h" + +extern ipf_main_softc_t ipfmain; + +static int +ipfrule_modevent(module_t mod, int type, void *unused) +{ + int error = 0; + + switch (type) + { + case MOD_LOAD : + error = ipfrule_add(); + if (!error) + ipfmain.ipf_refcnt++; + break; + case MOD_UNLOAD : + error = ipfrule_remove(); + if (!error) + ipfmain.ipf_refcnt--; + break; + default: + error = EINVAL; + break; + } + return(error); +} + +static moduledata_t ipfrulemod = { + "ipfrule", + ipfrule_modevent, + 0 +}; +DECLARE_MODULE(ipfrule, ipfrulemod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); +#ifdef MODULE_DEPEND +MODULE_DEPEND(ipfrule, ipfilter, 1, 1, 1); +#endif +#ifdef MODULE_VERSION +MODULE_VERSION(ipfrule, 1); +#endif diff --git a/share/examples/ipfilter/rules.txt b/share/examples/ipfilter/rules.txt new file mode 100644 index 000000000000..f8ceb8a4352c --- /dev/null +++ b/share/examples/ipfilter/rules.txt @@ -0,0 +1,181 @@ +# +# block all incoming TCP packets on le0 from host "foo" to any destination. +# +block in on le0 proto tcp from foo/32 to any + + ------------------------------------------------------------------------ + +# +# block all outgoing TCP packets on le0 from any host to port 23 of host bar. +# +block out on le0 proto tcp from any to bar/32 port != 23 + + ------------------------------------------------------------------------ + +# +# block all inbound packets. +# +block in from any to any +# +# pass through packets to and from localhost. +# +pass in from 127.0.0.1/32 to 127.0.0.1/32 +# +# allow a variety of individual hosts to send any type of IP packet to any +# other host. +# +pass in from 10.1.3.1 to any +pass in from 10.1.3.2 to any +pass in from 10.1.3.3 to any +pass in from 10.1.3.4 to any +pass in from 10.1.3.5 to any +pass in from 10.1.0.13/32 to any +pass in from 10.1.1.1/32 to any +pass in from 10.1.2.1/32 to any +# +# +# block all outbound packets. +# +block out from any to any +# +# allow any packets destined for localhost out. +# +pass out from any to 127.0.0.1/32 +# +# allow any host to send any IP packet out to a limited number of hosts. +# +pass out from any to 10.1.3.1/32 +pass out from any to 10.1.3.2/32 +pass out from any to 10.1.3.3/32 +pass out from any to 10.1.3.4/32 +pass out from any to 10.1.3.5/32 +pass out from any to 10.1.0.13/32 +pass out from any to 10.1.1.1/32 +pass out from any to 10.1.2.1/32 + + ------------------------------------------------------------------------ + +# +# block all ICMP packets. +# +block in proto icmp from any to any + + ------------------------------------------------------------------------ + +# +# test ruleset +# +# allow packets coming from foo to bar through. +# +pass from foo to bar +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass proto tcp from fubar/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass proto udp from fubar port != 53 to localhost +# +# block all ICMP unreachables. +# +block from any to any icmp unreach +# +# allow packets through which have a non-standard IP header length (ie there +# are IP options such as source-routing present). +# +pass from any to any with ipopts + + ------------------------------------------------------------------------ + +# +# block all TCP packets with only the SYN flag set (this is the first +# packet sent to establish a connection). +# +block in proto tcp from any to any flags S/SA + + ------------------------------------------------------------------------ + +# +# log all inbound packet on le0 which has IP options present +# +log in on le0 from any to any with ipopts +# +# block any inbound packets on le0 which are fragmented and "too short" to +# do any meaningful comparison on. This actually only applies to TCP +# packets which can be missing the flags/ports (depending on which part +# of the fragment you see). +# +block in log quick on le0 from any to any with short frag +# +# log all inbound TCP packets with the SYN flag (only) set +# (NOTE: if it were an inbound TCP packet with the SYN flag set and it +# had IP options present, this rule and the above would cause it +# to be logged twice). +# +log in on le0 proto tcp from any to any flags S/SA +# +# block and log any inbound ICMP unreachables +# +block in log on le0 proto icmp from any to any icmp-type unreach +# +# block and log any inbound UDP packets on le0 which are going to port 2049 +# (the NFS port). +# +block in log on le0 proto udp from any to any port = 2049 +# +# quickly allow any packets to/from a particular pair of hosts +# +pass in quick from any to 10.1.3.2/32 +pass in quick from any to 10.1.0.13/32 +pass in quick from 10.1.3.2/32 to any +pass in quick from 10.1.0.13/32 to any +# +# block (and stop matching) any packet with IP options present. +# +block in quick on le0 from any to any with ipopts +# +# allow any packet through +# +pass in from any to any +# +# block any inbound UDP packets destined for these subnets. +# +block in on le0 proto udp from any to 10.1.3.0/24 +block in on le0 proto udp from any to 10.1.1.0/24 +block in on le0 proto udp from any to 10.1.2.0/24 +# +# block any inbound TCP packets with only the SYN flag set that are +# destined for these subnets. +# +block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA +# +# block any inbound ICMP packets destined for these subnets. +# +block in on le0 proto icmp from any to 10.1.3.0/24 +block in on le0 proto icmp from any to 10.1.1.0/24 +block in on le0 proto icmp from any to 10.1.2.0/24 +# +# Log all short TCP packets to qe3, with "packetlog" as the intended +# destination for the packet. +# +block in to qe3:packetlog proto tcp all with short +# +# Log all connection attempts for TCP +# +pass in dup-to le0:packetlog proto tcp all flags S/SA +# +# Route all UDP packets through transparently. +# +pass in fastroute proto udp all +# +# Route all ICMP packets to network 10 out through le1, to "router" +# +pass in to le1:router proto icmp all + + ------------------------------------------------------------------------ +Return to the IP Filter home page diff --git a/share/examples/ipfilter/rules/BASIC.NAT b/share/examples/ipfilter/rules/BASIC.NAT new file mode 100644 index 000000000000..213e33815c19 --- /dev/null +++ b/share/examples/ipfilter/rules/BASIC.NAT @@ -0,0 +1,46 @@ +#!/sbin/ipnat -f - +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# If we have only 1 valid IP address from our ISP, then we do this: +# +# To make ftp work, using the internal ftp proxy, use: +# +map ppp0 w.x.y.z/24 -> a.b.c.d/32 proxy port ftp ftp/tcp +# +# For normal TCP/UDP and other IP protocols +# +map ppp0 w.x.y.z/24 -> a.b.c.d/32 portmap tcp/udp 40000:60000 +map ppp0 w.x.y.z/24 -> a.b.c.d/32 +# +# if we get a different dialup IP address each time, then we would use: +# +#map ppp0 w.x.y.z/24 -> 0/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.z/24 -> 0/32 +# +# If we have a class C address space of valid IP#'s from our ISP, then we can +# do this: +# +#map ppp0 w.x.y.z/24 -> a.b.c.d/24 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.z/24 -> a.b.c.d/24 +# +# or, if we only have a small number of PC's, this: +# +#map ppp0 w.x.y.v/32 -> a.b.c.E/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.v/32 -> a.b.c.E/32 +#map ppp0 w.x.y.u/32 -> a.b.c.F/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.u/32 -> a.b.c.F/32 +#map ppp0 w.x.y.t/32 -> a.b.c.G/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.t/32 -> a.b.c.G/32 +#map ppp0 w.x.y.s/32 -> a.b.c.H/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.s/32 -> a.b.c.H/32 +#map ppp0 w.x.y.r/32 -> a.b.c.I/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.r/32 -> a.b.c.I/32 +#map ppp0 w.x.y.q/32 -> a.b.c.J/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.q/32 -> a.b.c.J/32 +#map ppp0 w.x.y.p/32 -> a.b.c.K/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.p/32 -> a.b.c.K/32 diff --git a/share/examples/ipfilter/rules/BASIC_1.FW b/share/examples/ipfilter/rules/BASIC_1.FW new file mode 100644 index 000000000000..642dde061efd --- /dev/null +++ b/share/examples/ipfilter/rules/BASIC_1.FW @@ -0,0 +1,99 @@ +#!/sbin/ipf -f - +# +# SAMPLE: RESTRICTIVE FILTER RULES +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# This file contains the basic rules needed to construct a firewall for the +# above situation. +# +#------------------------------------------------------- +# *Nasty* packets we don't want to allow near us at all! +# short packets which are packets fragmented too short to be real. +block in log quick all with short +#------------------------------------------------------- +# Group setup. +# ============ +# By default, block and log everything. This maybe too much logging +# (especially for ed0) and needs to be further refined. +# +block in log on ppp0 all head 100 +block in log proto tcp all flags S/SA head 101 group 100 +block out log on ppp0 all head 150 +block in log on ed0 from w.x.y.z/24 to any head 200 +block in log proto tcp all flags S/SA head 201 group 200 +block in log proto udp all head 202 group 200 +block out log on ed0 all head 250 +#------------------------------------------------------- +# Localhost packets. +# ================== +# packets going in/out of network interfaces that aren't on the loopback +# interface should *NOT* exist. +block in log quick from 127.0.0.0/8 to any group 100 +block in log quick from any to 127.0.0.0/8 group 100 +block in log quick from 127.0.0.0/8 to any group 200 +block in log quick from any to 127.0.0.0/8 group 200 +# And of course, make sure the loopback allows packets to traverse it. +pass in quick on lo0 all +pass out quick on lo0 all +#------------------------------------------------------- +# Invalid Internet packets. +# ========================= +# +# Deny reserved addresses. +# +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log quick from 172.16.0.0/12 to any group 100 +# +# Prevent IP spoofing. +# +block in log quick from a.b.c.d/24 to any group 100 +# +#------------------------------------------------------- +# Allow outgoing DNS requests (no named on firewall) +# +pass in quick proto udp from any to any port = 53 keep state group 202 +# +# If we were running named on the firewall and all internal hosts talked to +# it, we'd use the following: +# +#pass in quick proto udp from any to w.x.y.z/32 port = 53 keep state group 202 +#pass out quick on ppp0 proto udp from a.b.c.d/32 to any port = 53 keep state +# +# Allow outgoing FTP from any internal host to any external FTP server. +# +pass in quick proto tcp from any to any port = ftp keep state group 201 +pass in quick proto tcp from any to any port = ftp-data keep state group 201 +pass in quick proto tcp from any port = ftp-data to any port > 1023 keep state group 101 +# +# Allow NTP from any internal host to any external NTP server. +# +pass in quick proto udp from any to any port = ntp keep state group 202 +# +# Allow outgoing connections: SSH, TELNET, WWW +# +pass in quick proto tcp from any to any port = 22 keep state group 201 +pass in quick proto tcp from any to any port = telnet keep state group 201 +pass in quick proto tcp from any to any port = www keep state group 201 +# +#------------------------------------------------------- +block in log proto tcp from any to a.b.c.d/32 flags S/SA head 110 group 100 +# +# Allow incoming to the external firewall interface: mail, WWW, DNS +# +pass in log quick proto tcp from any to any port = smtp keep state group 110 +pass in log quick proto tcp from any to any port = www keep state group 110 +pass in log quick proto tcp from any to any port = 53 keep state group 110 +pass in log quick proto udp from any to any port = 53 keep state group 100 +#------------------------------------------------------- +# Log these: +# ========== +# * return RST packets for invalid SYN packets to help the other end close +block return-rst in log proto tcp from any to any flags S/SA group 100 +# * return ICMP error packets for invalid UDP packets +block return-icmp(net-unr) in proto udp all group 100 diff --git a/share/examples/ipfilter/rules/BASIC_2.FW b/share/examples/ipfilter/rules/BASIC_2.FW new file mode 100644 index 000000000000..1d4fd7317673 --- /dev/null +++ b/share/examples/ipfilter/rules/BASIC_2.FW @@ -0,0 +1,72 @@ +#!/sbin/ipf -f - +# +# SAMPLE: PERMISSIVE FILTER RULES +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# This file contains the basic rules needed to construct a firewall for the +# above situation. +# +#------------------------------------------------------- +# *Nasty* packets we don't want to allow near us at all! +# short packets which are packets fragmented too short to be real. +block in log quick all with short +#------------------------------------------------------- +# Group setup. +# ============ +# By default, block and log everything. This maybe too much logging +# (especially for ed0) and needs to be further refined. +# +block in log on ppp0 all head 100 +block out log on ppp0 all head 150 +block in log on ed0 from w.x.y.z/24 to any head 200 +block out log on ed0 all head 250 +#------------------------------------------------------- +# Invalid Internet packets. +# ========================= +# +# Deny reserved addresses. +# +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log quick from 172.16.0.0/12 to any group 100 +# +# Prevent IP spoofing. +# +block in log quick from a.b.c.d/24 to any group 100 +# +#------------------------------------------------------- +# Localhost packets. +# ================== +# packets going in/out of network interfaces that aren't on the loopback +# interface should *NOT* exist. +block in log quick from 127.0.0.0/8 to any group 100 +block in log quick from any to 127.0.0.0/8 group 100 +block in log quick from 127.0.0.0/8 to any group 200 +block in log quick from any to 127.0.0.0/8 group 200 +# And of course, make sure the loopback allows packets to traverse it. +pass in quick on lo0 all +pass out quick on lo0 all +#------------------------------------------------------- +# Allow any communication between the inside network and the outside only. +# +# Allow all outgoing connections (SSH, TELNET, FTP, WWW, gopher, etc) +# +pass in log quick proto tcp all flags S/SA keep state group 200 +# +# Support all UDP `connections' initiated from inside. +# +# Allow ping out +# +pass in log quick proto icmp all keep state group 200 +#------------------------------------------------------- +# Log these: +# ========== +# * return RST packets for invalid SYN packets to help the other end close +block return-rst in log proto tcp from any to any flags S/SA group 100 +# * return ICMP error packets for invalid UDP packets +block return-icmp(net-unr) in proto udp all group 100 diff --git a/share/examples/ipfilter/rules/example.1 b/share/examples/ipfilter/rules/example.1 new file mode 100644 index 000000000000..ff93f492cafe --- /dev/null +++ b/share/examples/ipfilter/rules/example.1 @@ -0,0 +1,4 @@ +# +# block all incoming TCP packets on le0 from host 10.1.1.1 to any destination. +# +block in on le0 proto tcp from 10.1.1.1/32 to any diff --git a/share/examples/ipfilter/rules/example.10 b/share/examples/ipfilter/rules/example.10 new file mode 100644 index 000000000000..560d1e670f61 --- /dev/null +++ b/share/examples/ipfilter/rules/example.10 @@ -0,0 +1,12 @@ +# +# pass ack packets (ie established connection) +# +pass in proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A +pass out proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A +# +# block incoming connection requests to my internal network from the big bad +# internet. +# +block in on le0 proto tcp from any to 10.1.0.0/16 flags S/SA +# to block the replies: +block out on le0 proto tcp from 10.1.0.0 to any flags SA/SA diff --git a/share/examples/ipfilter/rules/example.11 b/share/examples/ipfilter/rules/example.11 new file mode 100644 index 000000000000..c6b4e7ff0d73 --- /dev/null +++ b/share/examples/ipfilter/rules/example.11 @@ -0,0 +1,26 @@ +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass in proto tcp from 10.2.2.2/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass in proto udp from 10.2.2.2 port != 53 to localhost +# +# block anything trying to get to X terminal ports, X:0 to X:9 +# +block in proto tcp from any to any port 5999 >< 6010 +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +block in proto tcp/udp all +pass in proto tcp/udp from any to any port 512 <> 515 +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +pass in proto tcp/udp all +block in proto tcp/udp from any to any port 511 >< 516 diff --git a/share/examples/ipfilter/rules/example.12 b/share/examples/ipfilter/rules/example.12 new file mode 100644 index 000000000000..c0ba1d3cdda1 --- /dev/null +++ b/share/examples/ipfilter/rules/example.12 @@ -0,0 +1,17 @@ +# +# get rid of all short IP fragments (too small for valid comparison) +# +block in proto tcp all with short +# +# drop and log any IP packets with options set in them. +# +block in log all with ipopts +# +# log packets with BOTH ssrr and lsrr set +# +log in all with opt lsrr,ssrr +# +# drop any source routing options +# +block in quick all with opt lsrr +block in quick all with opt ssrr diff --git a/share/examples/ipfilter/rules/example.13 b/share/examples/ipfilter/rules/example.13 new file mode 100644 index 000000000000..854f07f1694f --- /dev/null +++ b/share/examples/ipfilter/rules/example.13 @@ -0,0 +1,17 @@ +# +# Log all short TCP packets to qe3, with 10.3.3.3 as the intended +# destination for the packet. +# +block in on qe0 to qe3:10.3.3.3 proto tcp all with short +# +# Log all connection attempts for TCP +# +pass in on le0 dup-to le1:10.3.3.3 proto tcp all flags S/SA +# +# Route all UDP packets through transparently. +# +pass in on ppp0 fastroute proto udp all +# +# Route all ICMP packets to network 10 out through le1, to 10.3.3.1 +# +pass in on le0 to le1:10.3.3.1 proto icmp all diff --git a/share/examples/ipfilter/rules/example.2 b/share/examples/ipfilter/rules/example.2 new file mode 100644 index 000000000000..4f81725eeb0c --- /dev/null +++ b/share/examples/ipfilter/rules/example.2 @@ -0,0 +1,5 @@ +# +# block all outgoing TCP packets on le0 from any host to port 23 of +# host 10.1.1.2 +# +block out on le0 proto tcp from any to 10.1.1.3/32 port = 23 diff --git a/share/examples/ipfilter/rules/example.3 b/share/examples/ipfilter/rules/example.3 new file mode 100644 index 000000000000..cd31f73e7c2b --- /dev/null +++ b/share/examples/ipfilter/rules/example.3 @@ -0,0 +1,40 @@ +# +# block all inbound packets. +# +block in from any to any +# +# pass through packets to and from localhost. +# +pass in from 127.0.0.1/32 to 127.0.0.1/32 +# +# allow a variety of individual hosts to send any type of IP packet to any +# other host. +# +pass in from 10.1.3.1/32 to any +pass in from 10.1.3.2/32 to any +pass in from 10.1.3.3/32 to any +pass in from 10.1.3.4/32 to any +pass in from 10.1.3.5/32 to any +pass in from 10.1.0.13/32 to any +pass in from 10.1.1.1/32 to any +pass in from 10.1.2.1/32 to any +# +# +# block all outbound packets. +# +block out from any to any +# +# allow any packets destined for localhost out. +# +pass out from any to 127.0.0.1/32 +# +# allow any host to send any IP packet out to a limited number of hosts. +# +pass out from any to 10.1.3.1/32 +pass out from any to 10.1.3.2/32 +pass out from any to 10.1.3.3/32 +pass out from any to 10.1.3.4/32 +pass out from any to 10.1.3.5/32 +pass out from any to 10.1.0.13/32 +pass out from any to 10.1.1.1/32 +pass out from any to 10.1.2.1/32 diff --git a/share/examples/ipfilter/rules/example.4 b/share/examples/ipfilter/rules/example.4 new file mode 100644 index 000000000000..7918ec2fbd99 --- /dev/null +++ b/share/examples/ipfilter/rules/example.4 @@ -0,0 +1,4 @@ +# +# block all ICMP packets. +# +block in proto icmp from any to any diff --git a/share/examples/ipfilter/rules/example.5 b/share/examples/ipfilter/rules/example.5 new file mode 100644 index 000000000000..6d688b5eab80 --- /dev/null +++ b/share/examples/ipfilter/rules/example.5 @@ -0,0 +1,25 @@ +# +# test ruleset +# +# allow packets coming from foo to bar through. +# +pass in from 10.1.1.2 to 10.2.1.1 +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass in proto tcp from 10.2.2.2/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass in proto udp from 10.2.2.2 port != 53 to localhost +# +# block all ICMP unreachables. +# +block in proto icmp from any to any icmp-type unreach +# +# allow packets through which have a non-standard IP header length (ie there +# are IP options such as source-routing present). +# +pass in from any to any with ipopts diff --git a/share/examples/ipfilter/rules/example.6 b/share/examples/ipfilter/rules/example.6 new file mode 100644 index 000000000000..d40f0f3d2a18 --- /dev/null +++ b/share/examples/ipfilter/rules/example.6 @@ -0,0 +1,5 @@ +# +# block all TCP packets with only the SYN flag set (this is the first +# packet sent to establish a connection) out of the SYN-ACK pair. +# +block in proto tcp from any to any flags S/SA diff --git a/share/examples/ipfilter/rules/example.7 b/share/examples/ipfilter/rules/example.7 new file mode 100644 index 000000000000..062de9811935 --- /dev/null +++ b/share/examples/ipfilter/rules/example.7 @@ -0,0 +1,12 @@ +# block all ICMP packets. +# +block in proto icmp all +# +# allow in ICMP echos and echo-replies. +# +pass in on le1 proto icmp from any to any icmp-type echo +pass in on le1 proto icmp from any to any icmp-type echorep +# +# block all ICMP destination unreachable packets which are port-unreachables +# +block in on le1 proto icmp from any to any icmp-type unreach code 3 diff --git a/share/examples/ipfilter/rules/example.8 b/share/examples/ipfilter/rules/example.8 new file mode 100644 index 000000000000..baa02581256e --- /dev/null +++ b/share/examples/ipfilter/rules/example.8 @@ -0,0 +1,10 @@ +# +# block all incoming TCP connections but send back a TCP-RST for ones to +# the ident port +# +block in proto tcp from any to any flags S/SA +block return-rst in quick proto tcp from any to any port = 113 flags S/SA +# +# block all inbound UDP packets and send back an ICMP error. +# +block return-icmp in proto udp from any to any diff --git a/share/examples/ipfilter/rules/example.9 b/share/examples/ipfilter/rules/example.9 new file mode 100644 index 000000000000..daff2031db8e --- /dev/null +++ b/share/examples/ipfilter/rules/example.9 @@ -0,0 +1,12 @@ +# +# drop all packets without IP security options +# +block in all +pass in all with opt sec +# +# only allow packets in and out on le1 which are top secret +# +block out on le1 all +pass out on le1 all with opt sec-class topsecret +block in on le1 all +pass in on le1 all with opt sec-class topsecret diff --git a/share/examples/ipfilter/rules/example.sr b/share/examples/ipfilter/rules/example.sr new file mode 100644 index 000000000000..c4c1994030ba --- /dev/null +++ b/share/examples/ipfilter/rules/example.sr @@ -0,0 +1,61 @@ +# +# log all inbound packet on le0 which has IP options present +# +log in on le0 from any to any with ipopts +# +# block any inbound packets on le0 which are fragmented and "too short" to +# do any meaningful comparison on. This actually only applies to TCP +# packets which can be missing the flags/ports (depending on which part +# of the fragment you see). +# +block in log quick on le0 from any to any with short frag +# +# log all inbound TCP packets with the SYN flag (only) set +# (NOTE: if it were an inbound TCP packet with the SYN flag set and it +# had IP options present, this rule and the above would cause it +# to be logged twice). +# +log in on le0 proto tcp from any to any flags S/SA +# +# block and log any inbound ICMP unreachables +# +block in log on le0 proto icmp from any to any icmp-type unreach +# +# block and log any inbound UDP packets on le0 which are going to port 2049 +# (the NFS port). +# +block in log on le0 proto udp from any to any port = 2049 +# +# quickly allow any packets to/from a particular pair of hosts +# +pass in quick from any to 10.1.3.2/32 +pass in quick from any to 10.1.0.13/32 +pass in quick from 10.1.3.2/32 to any +pass in quick from 10.1.0.13/32 to any +# +# block (and stop matching) any packet with IP options present. +# +block in quick on le0 from any to any with ipopts +# +# allow any packet through +# +pass in from any to any +# +# block any inbound UDP packets destined for these subnets. +# +block in on le0 proto udp from any to 10.1.3.0/24 +block in on le0 proto udp from any to 10.1.1.0/24 +block in on le0 proto udp from any to 10.1.2.0/24 +# +# block any inbound TCP packets with only the SYN flag set that are +# destined for these subnets. +# +block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA +# +# block any inbound ICMP packets destined for these subnets. +# +block in on le0 proto icmp from any to 10.1.3.0/24 +block in on le0 proto icmp from any to 10.1.1.0/24 +block in on le0 proto icmp from any to 10.1.2.0/24 diff --git a/share/examples/ipfilter/rules/firewall b/share/examples/ipfilter/rules/firewall new file mode 100644 index 000000000000..f26b7150b98c --- /dev/null +++ b/share/examples/ipfilter/rules/firewall @@ -0,0 +1,39 @@ +Configuring IP Filter for firewall usage. +========================================= + +Step 1 - Block out "bad" IP packets. +------------------------------------ + +Run the perl script "mkfilters". This will generate a list of blocking +rules which: + a) blocks all packets which might belong to an IP Spoofing attack; + b) blocks all packets with IP options; + c) blocks all packets which have a length which is too short for + any legal packet; + +Step 2 - Convert Network Security Policy to filter rules. +--------------------------------------------------------- + +Draw up a list of which services you want to allow users to use on the +Internet (e.g. WWW, ftp, etc). Draw up a separate list for what you +want each host that is part of your firewall to be allowed to do, including +communication with internal hosts. + +Step 3 - Create TCP "keep state" rules. +--------------------------------------- + +For each service that uses TCP, create a rule as follows: + +pass in on <int-a> proto tcp from <int-net> to any port <ext-service> flags S/SA keep state + +where +* "int-a" is the internal interface of the firewall. That is, it is the + closest to your internal network in terms of network hops. + +* "int-net" is the internal network IP# subnet address range. This might + be something like 10.1.0.0/16, or 128.33.1.0/24 + +* "ext-service" is the service to which you wish to connect or if it doesn't + have a proper name, a number can be used. The translation of "ext-service" + as a name to a number is controlled with the /etc/services file. + diff --git a/share/examples/ipfilter/rules/ftp-proxy b/share/examples/ipfilter/rules/ftp-proxy new file mode 100644 index 000000000000..ad2f7171e85a --- /dev/null +++ b/share/examples/ipfilter/rules/ftp-proxy @@ -0,0 +1,45 @@ +How to setup FTP proxying using the built in proxy code. +======================================================== + +NOTE: Currently, the built-in FTP proxy is only available for use with NAT + (i.e. only if you're already using "map" rules with ipnat). It does + support null-NAT mappings, that is, using the proxy without changing + the addresses. + +Lets assume your network diagram looks something like this: + + +[host A] + |a +---+-------------+---------- + |b + [host B] + |c +---+-------------+---------- + |d +[host C] + +and IP Filter is running on host B. If you want to proxy FTP from A to C +then you would do: + +map int-c ipaddr-a/32 -> ip-addr-c-net/32 proxy port ftp ftp/tcp + +int-c = name of "interface c" +ipaddr-a = ip# of interface a +ipaddr-c-net = another ip# on the C-network (usually not the same as the +interface). + +e.g., if host A was 10.1.1.1, host B had two network interfaces ed0 and vx0 +which had IP#'s 10.1.1.2 and 203.45.67.89 respectively, and host C was +203.45.67.90, you would do: + +map vx0 10.1.1.1/32 -> 203.45.67.91/32 proxy port ftp ftp/tcp + +where: +ipaddr-a = 10.1.1.1 +int-c = vx0 +ipaddr-c-net = 203.45.67.91 + +The "map" rule for this proxy should precede any other NAT rules you are +using. + diff --git a/share/examples/ipfilter/rules/ftppxy b/share/examples/ipfilter/rules/ftppxy new file mode 100755 index 000000000000..2c42c527fa1e --- /dev/null +++ b/share/examples/ipfilter/rules/ftppxy @@ -0,0 +1,6 @@ +#!/bin/sh +# The proxy bit is as follows: +# proxy [port <portname>] <tag>/<protocol> +# the <tag> should match a tagname in the proxy table, as does the protocol. +# this format isn't finalised yet +echo "map ed0 0/0 -> 192.1.1.1/32 proxy port ftp ftp/tcp" | /sbin/ipnat -f - diff --git a/share/examples/ipfilter/rules/ip_rules b/share/examples/ipfilter/rules/ip_rules new file mode 100644 index 000000000000..9850f16b9306 --- /dev/null +++ b/share/examples/ipfilter/rules/ip_rules @@ -0,0 +1,3 @@ +# Used to generate ../ip_rules.c and ../ip_rules.h +pass in all +pass out all diff --git a/share/examples/ipfilter/rules/ipmon.conf b/share/examples/ipfilter/rules/ipmon.conf new file mode 100644 index 000000000000..652afceb3ea1 --- /dev/null +++ b/share/examples/ipfilter/rules/ipmon.conf @@ -0,0 +1,25 @@ +# +# +# +# +match { logtag = 10000; } +do { execute("/usr/bin/mail -s 'logtag 10000' root"); }; +# +match { logtag = 2000, every 10 seconds; } +do { execute("echo 'XXXXXXXX tag 2000 packet XXXXXXXX'"); }; +# +match { protocol = udp, result = block; } +do { file("file:///var/log/udp-block"); }; +# +match { protocol = tcp, result = block, dstport = 25; } +do { syslog("local0.info"), syslog("local1."), syslog(".warn"); }; +# +match { srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; } +do { execute("/usr/bin/mail -s 'from 10.1 to 192.168.1' root"); }; + +# +match { + rule = 12, logtag = 101, direction = in, result = block, + protocol = udp, srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; } +do { nothing; }; +# diff --git a/share/examples/ipfilter/rules/nat-setup b/share/examples/ipfilter/rules/nat-setup new file mode 100644 index 000000000000..b10e8f113e0c --- /dev/null +++ b/share/examples/ipfilter/rules/nat-setup @@ -0,0 +1,77 @@ +Configuring NAT on your network. +================================ + +To start setting up NAT, we need to define which is your "internal" interface +and which is your "external" interface. The "internal" interface is the +network adapter connected to the network with private IP addresses which +you need to change for communicating on the Internet. The "external" +interface is configured with a valid internet address. + +For example, your internal interface might have an IP# of 10.1.1.1 and be +connected to your ethernet, whilst your external interface might be a PPP +connection with an IP number of 204.51.62.176. + +Thus your network might look like this: + +<Internal Network> + [pc] [pc] + | | ++-+---------+------+ + | + [firewall] + | + | + Internet +<External Network> + + +Writing the map-rule. +--------------------- +When you're connected to the Internet, you will either have a block of IP +addresses assigned to you, maybe several different blocks, or you use a +single IP address, i.e. with dialup PPP. If you have a block of addresses +assigned, these can be used to create either a 1:1 mapping (if you have +only a few internal IP addresses) or N:1 mappings, where groups of internal +addresses map to a single IP address and unless you have enough Internet +addresses for a 1:1 mapping, you will want to do "portmapping" for TCP and +UDP port numbers. + +For an N:1 situation, you might have: + +map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap + +where if you had 16 addresses available, you could do: + +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap + +Or if you wanted to allocate subnets to each IP#, you might do: + +map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap +map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap +map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap + +*** NOTE: NAT rules are used on a first-match basis only! + + +Filtering with NAT. +------------------- +IP Filter will always translate addresses in a packet _BEFORE_ it checks its +access list for inbound packets and translates addresses _AFTER_ it has +checked the access control lists for outbound packets. + +For example (using the above NAT rules), if you wanted to prevent all hosts +in the 10.1.2.0/24 subnet from using NAT, you might use the following rule +with ipf: + +block out on ppp0 from 10.1.2.0/24 to any +block in on ppp0 from any to 10.1.2.0/24 + +and use these with ipnat: + +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap diff --git a/share/examples/ipfilter/rules/nat.eg b/share/examples/ipfilter/rules/nat.eg new file mode 100644 index 000000000000..9c26754a57fa --- /dev/null +++ b/share/examples/ipfilter/rules/nat.eg @@ -0,0 +1,14 @@ +# map all tcp connections from 10.1.0.0/16 to 240.1.0.1, changing the source +# port number to something between 10,000 and 20,000 inclusive. For all other +# IP packets, allocate an IP # between 240.1.0.0 and 240.1.0.255, temporarily +# for each new user. +# +map ed1 10.1.0.0/16 -> 240.1.0.1/32 portmap tcp 10000:20000 +map ed1 10.1.0.0/16 -> 240.1.0.0/24 +# +# Redirection is triggered for input packets. +# For example, to redirect FTP connections through this box, to the local ftp +# port, forcing them to connect through a proxy, you would use: +# +rdr ed0 0.0.0.0/0 port ftp -> 127.0.0.1 port ftp +# diff --git a/share/examples/ipfilter/rules/pool.conf b/share/examples/ipfilter/rules/pool.conf new file mode 100644 index 000000000000..285398ddf3b1 --- /dev/null +++ b/share/examples/ipfilter/rules/pool.conf @@ -0,0 +1,4 @@ +# +pool 0 = { !10.0.0.0 - 10.255.255.255, 10.1.0.0 - 10.1.255.255, + 10.1.1.0 - 10.1.1.255, !10.1.2.0 - 10.2.2.255, + 10.1.2.3 - 10.1.2.3, 10.1.2.15 - 10.1.2.15 }; diff --git a/share/examples/ipfilter/rules/server b/share/examples/ipfilter/rules/server new file mode 100644 index 000000000000..de0e9bbd06d8 --- /dev/null +++ b/share/examples/ipfilter/rules/server @@ -0,0 +1,11 @@ +# +# For a network server, which has two interfaces, 128.1.40.1 (le0) and +# 128.1.2.1 (le1), we want to block all IP spoofing attacks. le1 is +# connected to the majority of the network, whilst le0 is connected to a +# leaf subnet. We're not concerned about filtering individual services +# or +# +pass in quick on le0 from 128.1.40.0/24 to any +block in log quick on le0 from any to any +block in log quick on le1 from 128.1.1.0/24 to any +pass in quick on le1 from any to any diff --git a/share/examples/ipfilter/rules/tcpstate b/share/examples/ipfilter/rules/tcpstate new file mode 100644 index 000000000000..339a25f963fc --- /dev/null +++ b/share/examples/ipfilter/rules/tcpstate @@ -0,0 +1,13 @@ +# +# Only allow TCP packets in/out of le0 if there is an outgoing connection setup +# somewhere, waiting for it. +# +pass out quick on le0 proto tcp from any to any flags S/SAFR keep state +block out on le0 proto tcp all +block in on le0 proto tcp all +# +# allow nameserver queries and replies to pass through, but no other UDP +# +pass out quick on le0 proto udp from any to any port = 53 keep state +block out on le0 proto udp all +block in on le0 proto udp all diff --git a/share/examples/ipfilter/samples/Makefile b/share/examples/ipfilter/samples/Makefile new file mode 100644 index 000000000000..47ab4a26d5c0 --- /dev/null +++ b/share/examples/ipfilter/samples/Makefile @@ -0,0 +1,24 @@ +CC=gcc +all: + @echo "Please do one of the following:" + @echo "make bsd" + @echo "make bsdi" + @echo "make freebsd" + @echo "make freebsd22" + @echo "make netbsd" + @echo "make openbsd" + @echo "make sunos4" + @echo "make sunos5" + +sunos5: + $(CC) -I.. userauth.c -o userauth -lsocket -lnsl + $(CC) -I.. proxy.c -o proxy -lsocket -lnsl + $(CC) -I.. relay.c -o relay -lsocket -lnsl + +freebsd freebsd22 netbsd bsd bsdi sunos4 openbsd: + $(CC) -I.. userauth.c -o userauth + $(CC) -I.. proxy.c -o proxy + $(CC) -I.. relay.c -o relay + +clean: + /bin/rm -f userauth proxy relay diff --git a/share/examples/ipfilter/samples/ipfilter-pb.gif b/share/examples/ipfilter/samples/ipfilter-pb.gif Binary files differnew file mode 100644 index 000000000000..afaefa866541 --- /dev/null +++ b/share/examples/ipfilter/samples/ipfilter-pb.gif diff --git a/share/examples/ipfilter/samples/proxy.c b/share/examples/ipfilter/samples/proxy.c new file mode 100644 index 000000000000..7f5949b519be --- /dev/null +++ b/share/examples/ipfilter/samples/proxy.c @@ -0,0 +1,316 @@ + +/* + * Sample transparent proxy program. + * + * Sample implementation of a program which intercepts a TCP connectiona and + * just echos all data back to the origin. Written to work via inetd as a + * "nonwait" program running as root; ie. + * tcpmux stream tcp nowait root /usr/local/bin/proxy proxy + * with a NAT rue like this: + * rdr smc0 0/0 port 80 -> 127.0.0.1/32 port 1 + */ +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <syslog.h> +#if !defined(__SVR4) && !defined(__svr4__) +#include <strings.h> +#else +#include <sys/byteorder.h> +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# include <sys/ioccom.h> +# include <sys/sysmacros.h> +#endif +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <net/if.h> +#include <netdb.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <ctype.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ipl.h" + + +main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin, sloc, sout; + ipfobj_t obj; + natlookup_t natlook; + char buffer[512]; + int namelen, fd, n; + + /* + * get IP# and port # of the remote end of the connection (at the + * origin). + */ + namelen = sizeof(sin); + if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) { + perror("getpeername"); + exit(-1); + } + + /* + * get IP# and port # of the local end of the connection (at the + * man-in-the-middle). + */ + namelen = sizeof(sin); + if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) { + perror("getsockname"); + exit(-1); + } + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(natlook); + obj.ipfo_ptr = &natlook; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + + /* + * Build up the NAT natlookup structure. + */ + bzero((char *)&natlook, sizeof(natlook)); + natlook.nl_outip = sin.sin_addr; + natlook.nl_inip = sloc.sin_addr; + natlook.nl_flags = IPN_TCP; + natlook.nl_outport = sin.sin_port; + natlook.nl_inport = sloc.sin_port; + + /* + * Open the NAT device and lookup the mapping pair. + */ + fd = open(IPNAT_NAME, O_RDONLY); + if (ioctl(fd, SIOCGNATL, &obj) == -1) { + perror("ioctl(SIOCGNATL)"); + exit(-1); + } + +#define DO_NAT_OUT +#ifdef DO_NAT_OUT + if (argc > 1) + do_nat_out(0, 1, fd, &natlook, argv[1]); +#else + + /* + * Log it + */ + syslog(LOG_DAEMON|LOG_INFO, "connect to %s,%d", + inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); + printf("connect to %s,%d\n", + inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); + + /* + * Just echo data read in from stdin to stdout + */ + while ((n = read(0, buffer, sizeof(buffer))) > 0) + if (write(1, buffer, n) != n) + break; + close(0); +#endif +} + + +#ifdef DO_NAT_OUT +do_nat_out(in, out, fd, nlp, extif) + int fd; + natlookup_t *nlp; + char *extif; +{ + nat_save_t ns, *nsp = &ns; + struct sockaddr_in usin; + u_32_t sum1, sum2, sumd; + int onoff, ofd, slen; + ipfobj_t obj; + ipnat_t *ipn; + nat_t *nat; + + bzero((char *)&ns, sizeof(ns)); + + nat = &ns.ipn_nat; + nat->nat_p = IPPROTO_TCP; + nat->nat_dir = NAT_OUTBOUND; + if ((extif != NULL) && (*extif != '\0')) { + strncpy(nat->nat_ifnames[0], extif, + sizeof(nat->nat_ifnames[0])); + strncpy(nat->nat_ifnames[1], extif, + sizeof(nat->nat_ifnames[1])); + nat->nat_ifnames[0][sizeof(nat->nat_ifnames[0]) - 1] = '\0'; + nat->nat_ifnames[1][sizeof(nat->nat_ifnames[1]) - 1] = '\0'; + } + + ofd = socket(AF_INET, SOCK_DGRAM, 0); + bzero((char *)&usin, sizeof(usin)); + usin.sin_family = AF_INET; + usin.sin_addr = nlp->nl_realip; + usin.sin_port = nlp->nl_realport; + (void) connect(ofd, (struct sockaddr *)&usin, sizeof(usin)); + slen = sizeof(usin); + (void) getsockname(ofd, (struct sockaddr *)&usin, &slen); + close(ofd); +printf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr)); + + if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + perror("socket"); + usin.sin_port = 0; + if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin))) + perror("bind"); + slen = sizeof(usin); + if (getsockname(ofd, (struct sockaddr *)&usin, &slen)) + perror("getsockname"); +printf("local port# to use: %d\n", ntohs(usin.sin_port)); + + nat->nat_inip = usin.sin_addr; + nat->nat_outip = nlp->nl_outip; + nat->nat_oip = nlp->nl_realip; + + sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) + ntohs(usin.sin_port); + sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) + ntohs(nlp->nl_outport); + CALC_SUMD(sum1, sum2, sumd); + nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); + nat->nat_sumd[1] = nat->nat_sumd[0]; + + sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)); + sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); + CALC_SUMD(sum1, sum2, sumd); + nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); + + nat->nat_inport = usin.sin_port; + nat->nat_outport = nlp->nl_outport; + nat->nat_oport = nlp->nl_realport; + + nat->nat_flags = IPN_TCPUDP; + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*nsp); + obj.ipfo_ptr = nsp; + obj.ipfo_type = IPFOBJ_NATSAVE; + + onoff = 1; + if (ioctl(fd, SIOCSTLCK, &onoff) == 0) { + if (ioctl(fd, SIOCSTPUT, &obj) != 0) + perror("SIOCSTPUT"); + onoff = 0; + if (ioctl(fd, SIOCSTLCK, &onoff) != 0) + perror("SIOCSTLCK"); + } + + usin.sin_addr = nlp->nl_realip; + usin.sin_port = nlp->nl_realport; +printf("remote end for connection: %s,%d\n", inet_ntoa(usin.sin_addr), +ntohs(usin.sin_port)); +fflush(stdout); + if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin))) + perror("connect"); + + relay(in, out, ofd); +} + + +relay(in, out, net) + int in, out, net; +{ + char netbuf[1024], outbuf[1024]; + char *nwptr, *nrptr, *owptr, *orptr; + size_t nsz, osz; + fd_set rd, wr; + int i, n, maxfd; + + n = 0; + maxfd = in; + if (out > maxfd) + maxfd = out; + if (net > maxfd) + maxfd = net; + + nrptr = netbuf; + nwptr = netbuf; + nsz = sizeof(netbuf); + orptr = outbuf; + owptr = outbuf; + osz = sizeof(outbuf); + + while (n >= 0) { + FD_ZERO(&rd); + FD_ZERO(&wr); + + if (nrptr - netbuf < sizeof(netbuf)) + FD_SET(in, &rd); + if (orptr - outbuf < sizeof(outbuf)) + FD_SET(net, &rd); + + if (nsz < sizeof(netbuf)) + FD_SET(net, &wr); + if (osz < sizeof(outbuf)) + FD_SET(out, &wr); + + n = select(maxfd + 1, &rd, &wr, NULL, NULL); + + if ((n > 0) && FD_ISSET(in, &rd)) { + i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf)); + if (i <= 0) + break; + nsz -= i; + nrptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(net, &rd)) { + i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf)); + if (i <= 0) + break; + osz -= i; + orptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(out, &wr)) { + i = write(out, owptr, orptr - owptr); + if (i <= 0) + break; + osz += i; + if (osz == sizeof(outbuf) || owptr == orptr) { + orptr = outbuf; + owptr = outbuf; + } else + owptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(net, &wr)) { + i = write(net, nwptr, nrptr - nwptr); + if (i <= 0) + break; + nsz += i; + if (nsz == sizeof(netbuf) || nwptr == nrptr) { + nrptr = netbuf; + nwptr = netbuf; + } else + nwptr += i; + } + } + + close(net); + close(out); + close(in); +} +#endif diff --git a/share/examples/ipfilter/samples/relay.c b/share/examples/ipfilter/samples/relay.c new file mode 100644 index 000000000000..88d5fd968805 --- /dev/null +++ b/share/examples/ipfilter/samples/relay.c @@ -0,0 +1,195 @@ + +/* + * Sample program to be used as a transparent proxy. + * + * Must be executed with permission enough to do an ioctl on /dev/ipl + * or equivalent. This is just a sample and is only alpha quality. + * - Darren Reed (8 April 1996) + */ +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/syslog.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <net/if.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ipl.h" + +#define RELAY_BUFSZ 8192 + +char ibuff[RELAY_BUFSZ]; +char obuff[RELAY_BUFSZ]; + +int relay(ifd, ofd, rfd) + int ifd, ofd, rfd; +{ + fd_set rfds, wfds; + char *irh, *irt, *rrh, *rrt; + char *iwh, *iwt, *rwh, *rwt; + int nfd, n, rw; + + irh = irt = ibuff; + iwh = iwt = obuff; + nfd = ifd; + if (nfd < ofd) + nfd = ofd; + if (nfd < rfd) + nfd = rfd; + + while (1) { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + if (irh > irt) + FD_SET(rfd, &wfds); + if (irh < (ibuff + RELAY_BUFSZ)) + FD_SET(ifd, &rfds); + if (iwh > iwt) + FD_SET(ofd, &wfds); + if (iwh < (obuff + RELAY_BUFSZ)) + FD_SET(rfd, &rfds); + + switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL))) + { + case -1 : + case 0 : + return(-1); + default : + if (FD_ISSET(ifd, &rfds)) { + rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh); + if (rw == -1) + return(-1); + if (rw == 0) + return(0); + irh += rw; + n--; + } + if (n && FD_ISSET(ofd, &wfds)) { + rw = write(ofd, iwt, iwh - iwt); + if (rw == -1) + return(-1); + iwt += rw; + n--; + } + if (n && FD_ISSET(rfd, &rfds)) { + rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh); + if (rw == -1) + return(-1); + if (rw == 0) + return(0); + iwh += rw; + n--; + } + if (n && FD_ISSET(rfd, &wfds)) { + rw = write(rfd, irt, irh - irt); + if (rw == -1) + return(-1); + irt += rw; + n--; + } + if (irh == irt) + irh = irt = ibuff; + if (iwh == iwt) + iwh = iwt = obuff; + } + } +} + +main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin; + ipfobj_t obj; + natlookup_t nl; + natlookup_t *nlp = &nl; + int fd, sl = sizeof(sl), se; + + openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON); + if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) { + se = errno; + perror("open"); + errno = se; + syslog(LOG_ERR, "open: %m\n"); + exit(-1); + } + + bzero(&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(nl); + obj.ipfo_ptr = &nl; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + + bzero(&nl, sizeof(nl)); + nl.nl_flags = IPN_TCP; + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sl = sizeof(sin); + if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) { + se = errno; + perror("getsockname"); + errno = se; + syslog(LOG_ERR, "getsockname: %m\n"); + exit(-1); + } else { + nl.nl_inip.s_addr = sin.sin_addr.s_addr; + nl.nl_inport = sin.sin_port; + } + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sl = sizeof(sin); + if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) { + se = errno; + perror("getpeername"); + errno = se; + syslog(LOG_ERR, "getpeername: %m\n"); + exit(-1); + } else { + nl.nl_outip.s_addr = sin.sin_addr.s_addr; + nl.nl_outport = sin.sin_port; + } + + if (ioctl(fd, SIOCGNATL, &obj) == -1) { + se = errno; + perror("ioctl"); + errno = se; + syslog(LOG_ERR, "ioctl: %m\n"); + exit(-1); + } + + sin.sin_port = nl.nl_realport; + sin.sin_addr = nl.nl_realip; + sl = sizeof(sin); + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (connect(fd, (struct sockaddr *)&sin, sl) == -1) { + se = errno; + perror("connect"); + errno = se; + syslog(LOG_ERR, "connect: %m\n"); + exit(-1); + } + + (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + + syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr), + ntohs(sin.sin_port)); + if (relay(0, 1, fd) == -1) { + se = errno; + perror("relay"); + errno = se; + syslog(LOG_ERR, "relay: %m\n"); + exit(-1); + } + exit(0); +} diff --git a/share/examples/ipfilter/samples/userauth.c b/share/examples/ipfilter/samples/userauth.c new file mode 100644 index 000000000000..cc733a715322 --- /dev/null +++ b/share/examples/ipfilter/samples/userauth.c @@ -0,0 +1,61 @@ + +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <net/if.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_auth.h" + +extern int errno; + +main() +{ + struct frauth fra; + struct frauth *frap = &fra; + fr_info_t *fin = &fra.fra_info; + fr_ip_t *fi = &fin->fin_fi; + char yn[16]; + int fd; + + fd = open(IPL_NAME, O_RDWR); + fra.fra_len = 0; + fra.fra_buf = NULL; + while (ioctl(fd, SIOCAUTHW, &frap) == 0) { + if (fra.fra_info.fin_out) + fra.fra_pass = FR_OUTQUE; + else + fra.fra_pass = FR_INQUE; + + printf("%s ", inet_ntoa(fi->fi_src)); + if (fi->fi_flx & FI_TCPUDP) + printf("port %d ", fin->fin_data[0]); + printf("-> %s ", inet_ntoa(fi->fi_dst)); + if (fi->fi_flx & FI_TCPUDP) + printf("port %d ", fin->fin_data[1]); + printf("\n"); + printf("Allow packet through ? [y/n]"); + fflush(stdout); + if (!fgets(yn, sizeof(yn), stdin)) + break; + fflush(stdin); + if (yn[0] == 'n' || yn[0] == 'N') + fra.fra_pass |= FR_BLOCK; + else if (yn[0] == 'y' || yn[0] == 'Y') { + fra.fra_pass |= FR_PASS; + if (fra.fra_info.fin_fi.fi_flx & FI_TCPUDP) + fra.fra_pass |= FR_KEEPSTATE; + } else + fra.fra_pass |= FR_NOMATCH; + printf("answer = %c (%x), id %d idx %d\n", yn[0], + fra.fra_pass, fra.fra_info.fin_id, fra.fra_index); + if (ioctl(fd, SIOCAUTHR, &frap) != 0) + perror("SIOCAUTHR"); + } + fprintf(stderr, "errno=%d \n", errno); + perror("frauth-SIOCAUTHW"); +} |