| .TH IPF 5 |
| .SH NAME |
| ipf, ipf.conf \- IP packet filter rule syntax |
| .SH DESCRIPTION |
| .PP |
| A rule file for \fBipf\fP may have any name or even be stdin. As |
| \fBipfstat\fP produces parseable rules as output when displaying the internal |
| kernel filter lists, it is quite plausible to use its output to feed back |
| into \fBipf\fP. Thus, to remove all filters on input packets, the following |
| could be done: |
| .nf |
| |
| \fC# ipfstat \-i | ipf \-rf \-\fP |
| .fi |
| .SH GRAMMAR |
| .PP |
| The format used by \fBipf\fP for construction of filtering rules can be |
| described using the following grammar in BNF: |
| \fC |
| .nf |
| filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] |
| [ proto ] [ ip ] [ group ]. |
| |
| insert = "@" decnumber . |
| action = block | "pass" | log | "count" | skip | auth | call . |
| in-out = "in" | "out" . |
| options = [ log ] [ "quick" ] [ "on" interface-name [ 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 ] . |
| |
| block = "block" [ icmp[return-code] | "return-rst" ] . |
| auth = "auth" | "preauth" . |
| log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . |
| call = "call" [ "now" ] function-name . |
| skip = "skip" decnumber . |
| dup = "dup-to" interface-name[":"ipaddr] . |
| froute = "fastroute" | "to" interface-name . |
| protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . |
| srcdst = "all" | fromto . |
| fromto = "from" [ "!" ] object "to" [ "!" ] object . |
| |
| icmp = "return-icmp" | "return-icmp-as-dest" . |
| 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" | "keep" "frags" . |
| loglevel = facility"."priority | priority . |
| |
| 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" | "frag" | "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" | 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" . |
| .fi |
| .PP |
| This syntax is somewhat simplified for readability, some combinations |
| that match this grammar are disallowed by the software because they do |
| not make sense (such as tcp \fBflags\fP for non-TCP packets). |
| .SH FILTER RULES |
| .PP |
| The "briefest" valid rules are (currently) no-ops and are of the form: |
| .nf |
| block in all |
| pass in all |
| log out all |
| count in all |
| .fi |
| .PP |
| Filter rules are checked in order, with the last matching rule |
| determining the fate of the packet (but see the \fBquick\fP option, |
| below). |
| .PP |
| Filters are installed by default at the end of the kernel's filter |
| lists, prepending the rule with \fB@n\fP will cause it to be inserted |
| as the n'th entry in the current list. This is especially useful when |
| modifying and testing active filter rulesets. See ipf(1) for more |
| information. |
| .SH ACTIONS |
| .PP |
| The action indicates what to do with the packet if it matches the rest |
| of the filter rule. Each rule MUST have an action. The following |
| actions are recognised: |
| .TP |
| .B block |
| indicates that the packet should be flagged to be dropped. In response |
| to blocking a packet, the filter may be instructed to send a reply |
| packet, either an ICMP packet (\fBreturn-icmp\fP), an ICMP packet |
| masquerading as being from the original packet's destination |
| (\fBreturn-icmp-as-dest\fP), or a TCP "reset" (\fBreturn-rst\fP). An |
| ICMP packet may be generated in response to any IP packet, and its |
| type may optionally be specified, but a TCP reset may only be used |
| with a rule which is being applied to TCP packets. When using |
| \fBreturn-icmp\fP or \fBreturn-icmp-as-dest\fP, it is possible to specify |
| the actual unreachable `type'. That is, whether it is a network |
| unreachable, port unreachable or even administratively |
| prohibitied. This is done by enclosing the ICMP code associated with |
| it in parenthesis directly following \fBreturn-icmp\fP or |
| \fBreturn-icmp-as-dest\fP as follows: |
| .nf |
| block return-icmp(11) ... |
| .fi |
| .PP |
| Would return a Type-Of-Service (TOS) ICMP unreachable error. |
| .TP |
| .B pass |
| will flag the packet to be let through the filter. |
| .TP |
| .B log |
| causes the packet to be logged (as described in the LOGGING section |
| below) and has no effect on whether the packet will be allowed through |
| the filter. |
| .TP |
| .B count |
| causes the packet to be included in the accounting statistics kept by |
| the filter, and has no effect on whether the packet will be allowed through |
| the filter. These statistics are viewable with ipfstat(8). |
| .TP |
| .B call |
| this action is used to invoke the named function in the kernel, which |
| must conform to a specific calling interface. Customised actions and |
| semantics can thus be implemented to supplement those available. This |
| feature is for use by knowledgeable hackers, and is not currently |
| documented. |
| .TP |
| .B "skip <n>" |
| causes the filter to skip over the next \fIn\fP filter rules. If a rule is |
| inserted or deleted inside the region being skipped over, then the value of |
| \fIn\fP is adjusted appropriately. |
| .TP |
| .B auth |
| this allows authentication to be performed by a user-space program running |
| and waiting for packet information to validate. The packet is held for a |
| period of time in an internal buffer whilst it waits for the program to return |
| to the kernel the \fIreal\fP flags for whether it should be allowed through |
| or not. Such a program might look at the source address and request some sort |
| of authentication from the user (such as a password) before allowing the |
| packet through or telling the kernel to drop it if from an unrecognised source. |
| .TP |
| .B preauth |
| tells the filter that for packets of this class, it should look in the |
| pre-authenticated list for further clarification. If no further matching |
| rule is found, the packet will be dropped (the FR_PREAUTH is not the same |
| as FR_PASS). If a further matching rule is found, the result from that is |
| used in its instead. This might be used in a situation where a person |
| \fIlogs in\fP to the firewall and it sets up some temporary rules defining |
| the access for that person. |
| .PP |
| The next word must be either \fBin\fP or \fBout\fP. Each packet |
| moving through the kernel is either inbound (just been received on an |
| interface, and moving towards the kernel's protocol processing) or |
| outbound (transmitted or forwarded by the stack, and on its way to an |
| interface). There is a requirement that each filter rule explicitly |
| state which side of the I/O it is to be used on. |
| .SH OPTIONS |
| .PP |
| The list of options is brief, and all are indeed optional. Where |
| options are used, they must be present in the order shown here. These |
| are the currently supported options: |
| .TP |
| .B log |
| indicates that, should this be the last matching rule, the packet |
| header will be written to the \fBipl\fP log (as described in the |
| LOGGING section below). |
| .TP |
| .B quick |
| allows "short-cut" rules in order to speed up the filter or override |
| later rules. If a packet matches a filter rule which is marked as |
| \fBquick\fP, this rule will be the last rule checked, allowing a |
| "short-circuit" path to avoid processing later rules for this |
| packet. The current status of the packet (after any effects of the |
| current rule) will determine whether it is passed or blocked. |
| .IP |
| If this option is missing, the rule is taken to be a "fall-through" |
| rule, meaning that the result of the match (block/pass) is saved and |
| that processing will continue to see if there are any more matches. |
| .TP |
| .B on |
| allows an interface name to be incorporated into the matching |
| procedure. Interface names are as printed by "netstat \-i". If this |
| option is used, the rule will only match if the packet is going |
| through that interface in the specified direction (in/out). If this |
| option is absent, the rule is taken to be applied to a packet |
| regardless of the interface it is present on (i.e. on all interfaces). |
| Filter rulesets are common to all interfaces, rather than having a |
| filter list for each interface. |
| .IP |
| This option is especially useful for simple IP-spoofing protection: |
| packets should only be allowed to pass inbound on the interface from |
| which the specified source address would be expected, others may be |
| logged and/or dropped. |
| .TP |
| .B dup-to |
| causes the packet to be copied, and the duplicate packet to be sent |
| outbound on the specified interface, optionally with the destination |
| IP address changed to that specified. This is useful for off-host |
| logging, using a network sniffer. |
| .TP |
| .B to |
| causes the packet to be moved to the outbound queue on the |
| specified interface. This can be used to circumvent kernel routing |
| decisions, and even to bypass the rest of the kernel processing of the |
| packet (if applied to an inbound rule). It is thus possible to |
| construct a firewall that behaves transparently, like a filtering hub |
| or switch, rather than a router. The \fBfastroute\fP keyword is a |
| synonym for this option. |
| .SH MATCHING PARAMETERS |
| .PP |
| The keywords described in this section are used to describe attributes |
| of the packet to be used when determining whether rules match or don't |
| match. The following general-purpose attributes are provided for |
| matching, and must be used in this order: |
| .TP |
| .B tos |
| packets with different Type-Of-Service values can be filtered. |
| Individual service levels or combinations can be filtered upon. The |
| value for the TOS mask can either be represented as a hex number or a |
| decimal integer value. |
| .TP |
| .B ttl |
| packets may also be selected by their Time-To-Live value. The value given in |
| the filter rule must exactly match that in the packet for a match to occur. |
| This value can only be given as a decimal integer value. |
| .TP |
| .B proto |
| allows a specific protocol to be matched against. All protocol names |
| found in \fB/etc/protocols\fP are recognised and may be used. |
| However, the protocol may also be given as a DECIMAL number, allowing |
| for rules to match your own protocols, or new ones which would |
| out-date any attempted listing. |
| .IP |
| The special protocol keyword \fBtcp/udp\fP may be used to match either |
| a TCP or a UDP packet, and has been added as a convenience to save |
| duplication of otherwise-identical rules. |
| .\" XXX grammar should reflect this (/etc/protocols) |
| .PP |
| The \fBfrom\fP and \fBto\fP keywords are used to match against IP |
| addresses (and optionally port numbers). Rules must specify BOTH |
| source and destination parameters. |
| .PP |
| IP addresses may be specified in one of two ways: as a numerical |
| address\fB/\fPmask, or as a hostname \fBmask\fP netmask. The hostname |
| may either be a valid hostname, from either the hosts file or DNS |
| (depending on your configuration and library) or of the dotted numeric |
| form. There is no special designation for networks but network names |
| are recognised. Note that having your filter rules depend on DNS |
| results can introduce an avenue of attack, and is discouraged. |
| .PP |
| There is a special case for the hostname \fBany\fP which is taken to |
| be 0.0.0.0/0 (see below for mask syntax) and matches all IP addresses. |
| Only the presence of "any" has an implied mask, in all other |
| situations, a hostname MUST be accompanied by a mask. It is possible |
| to give "any" a hostmask, but in the context of this language, it is |
| non-sensical. |
| .PP |
| The numerical format "x\fB/\fPy" indicates that a mask of y |
| consecutive 1 bits set is generated, starting with the MSB, so a y value |
| of 16 would give 0xffff0000. The symbolic "x \fBmask\fP y" indicates |
| that the mask y is in dotted IP notation or a hexadecimal number of |
| the form 0x12345678. Note that all the bits of the IP address |
| indicated by the bitmask must match the address on the packet exactly; |
| there isn't currently a way to invert the sense of the match, or to |
| match ranges of IP addresses which do not express themselves easily as |
| bitmasks (anthropomorphization; it's not just for breakfast anymore). |
| .PP |
| If a \fBport\fP match is included, for either or both of source and |
| destination, then it is only applied to |
| .\" XXX - "may only be" ? how does this apply to other protocols? will it not match, or will it be ignored? |
| TCP and UDP packets. If there is no \fBproto\fP match parameter, |
| packets from both protocols are compared. This is equivalent to "proto |
| tcp/udp". When composing \fBport\fP comparisons, either the service |
| name or an integer port number may be used. Port comparisons may be |
| done in a number of forms, with a number of comparison operators, or |
| port ranges may be specified. When the port appears as part of the |
| \fBfrom\fP object, it matches the source port number, when it appears |
| as part of the \fBto\fP object, it matches the destination port number. |
| See the examples for more information. |
| .PP |
| The \fBall\fP keyword is essentially a synonym for "from any to any" |
| with no other match parameters. |
| .PP |
| Following the source and destination matching parameters, the |
| following additional parameters may be used: |
| .TP |
| .B with |
| is used to match irregular attributes that some packets may have |
| associated with them. To match the presence of IP options in general, |
| use \fBwith ipopts\fP. To match packets that are too short to contain |
| a complete header, use \fBwith short\fP. To match fragmented packets, |
| use \fBwith frag\fP. For more specific filtering on IP options, |
| individual options can be listed. |
| .IP |
| Before any parameter used after the \fBwith\fP keyword, the word |
| \fBnot\fP or \fBno\fP may be inserted to cause the filter rule to only |
| match if the option(s) is not present. |
| .IP |
| Multiple consecutive \fBwith\fP clauses are allowed. Alternatively, |
| the keyword \fBand\fP may be used in place of \fBwith\fP, this is |
| provided purely to make the rules more readable ("with ... and ..."). |
| When multiple clauses are listed, all those must match to cause a |
| match of the rule. |
| .\" XXX describe the options more specifically in a separate section |
| .TP |
| .B flags |
| is only effective for TCP filtering. Each of the letters possible |
| represents one of the possible flags that can be set in the TCP |
| header. The association is as follows: |
| .LP |
| .nf |
| F - FIN |
| S - SYN |
| R - RST |
| P - PUSH |
| A - ACK |
| U - URG |
| .fi |
| .IP |
| The various flag symbols may be used in combination, so that "SA" |
| would represent a SYN-ACK combination present in a packet. There is |
| nothing preventing the specification of combinations, such as "SFR", |
| that would not normally be generated by law-abiding TCP |
| implementations. However, to guard against weird aberrations, it is |
| necessary to state which flags you are filtering against. To allow |
| this, it is possible to set a mask indicating which TCP flags you wish |
| to compare (i.e., those you deem significant). This is done by |
| appending "/<flags>" to the set of TCP flags you wish to match |
| against, e.g.: |
| .LP |
| .nf |
| ... flags S |
| # becomes "flags S/AUPRFS" and will match |
| # packets with ONLY the SYN flag set. |
| |
| ... flags SA |
| # becomes "flags SA/AUPRFS" and will match any |
| # packet with only the SYN and ACK flags set. |
| |
| ... flags S/SA |
| # will match any packet with just the SYN flag set |
| # out of the SYN-ACK pair; the common "establish" |
| # keyword action. "S/SA" will NOT match a packet |
| # with BOTH SYN and ACK set, but WILL match "SFP". |
| .fi |
| .TP |
| .B icmp-type |
| is only effective when used with \fBproto icmp\fP and must NOT be used |
| in conjuction with \fBflags\fP. There are a number of types, which can be |
| referred to by an abbreviation recognised by this language, or the numbers |
| with which they are associated can be used. The most important from |
| a security point of view is the ICMP redirect. |
| .SH KEEP HISTORY |
| .PP |
| The second last parameter which can be set for a filter rule is whether or not |
| to record historical information for that packet, and what sort to keep. The |
| following information can be kept: |
| .TP |
| .B state |
| keeps information about the flow of a communication session. State can |
| be kept for TCP, UDP, and ICMP packets. |
| .TP |
| .B frags |
| keeps information on fragmented packets, to be applied to later |
| fragments. |
| .PP |
| allowing packets which match these to flow straight through, rather |
| than going through the access control list. |
| .SH GROUPS |
| The last pair of parameters control filter rule "grouping". By default, all |
| filter rules are placed in group 0 if no other group is specified. To add a |
| rule to a non-default group, the group must first be started by creating a |
| group \fIhead\fP. If a packet matches a rule which is the \fIhead\fP of a |
| group, the filter processing then switches to the group, using that rule as |
| the default for the group. If \fBquick\fP is used with a \fBhead\fP rule, rule |
| processing isn't stopped until it has returned from processing the group. |
| .PP |
| A rule may be both the head for a new group and a member of a non-default |
| group (\fBhead\fP and \fBgroup\fP may be used together in a rule). |
| .TP |
| .B "head <n>" |
| indicates that a new group (number n) should be created. |
| .TP |
| .B "group <n>" |
| indicates that the rule should be put in group (number n) rather than group 0. |
| .SH LOGGING |
| .PP |
| When a packet is logged, with either the \fBlog\fP action or option, |
| the headers of the packet are written to the \fBipl\fP packet logging |
| psuedo-device. Immediately following the \fBlog\fP keyword, the |
| following qualifiers may be used (in order): |
| .TP |
| .B body |
| indicates that the first 128 bytes of the packet contents will be |
| logged after the headers. |
| .TP |
| .B first |
| If log is being used in conjunction with a "keep" option, it is recommended |
| that this option is also applied so that only the triggering packet is logged |
| and not every packet which thereafter matches state information. |
| .TP |
| .B or-block |
| indicates that, if for some reason the filter is unable to log the |
| packet (such as the log reader being too slow) then the rule should be |
| interpreted as if the action was \fBblock\fP for this packet. |
| .TP |
| .B "level <loglevel>" |
| indicates what logging facility and priority, or just priority with |
| the default facility being used, will be used to log information about |
| this packet using ipmon's -s option. |
| .PP |
| See ipl(4) for the format of records written |
| to this device. The ipmon(8) program can be used to read and format |
| this log. |
| .SH EXAMPLES |
| .PP |
| The \fBquick\fP option is good for rules such as: |
| \fC |
| .nf |
| block in quick from any to any with ipopts |
| .fi |
| .PP |
| which will match any packet with a non-standard header length (IP |
| options present) and abort further processing of later rules, |
| recording a match and also that the packet should be blocked. |
| .PP |
| The "fall-through" rule parsing allows for effects such as this: |
| .LP |
| .nf |
| block in from any to any port < 6000 |
| pass in from any to any port >= 6000 |
| block in from any to any port > 6003 |
| .fi |
| .PP |
| which sets up the range 6000-6003 as being permitted and all others being |
| denied. Note that the effect of the first rule is overridden by subsequent |
| rules. Another (easier) way to do the same is: |
| .LP |
| .nf |
| block in from any to any port 6000 <> 6003 |
| pass in from any to any port 5999 >< 6004 |
| .fi |
| .PP |
| Note that both the "block" and "pass" are needed here to effect a |
| result as a failed match on the "block" action does not imply a pass, |
| only that the rule hasn't taken effect. To then allow ports < 1024, a |
| rule such as: |
| .LP |
| .nf |
| pass in quick from any to any port < 1024 |
| .fi |
| .PP |
| would be needed before the first block. To create a new group for |
| processing all inbound packets on le0/le1/lo0, with the default being to block |
| all inbound packets, we would do something like: |
| .LP |
| .nf |
| block in all |
| block in quick on le0 all head 100 |
| block in quick on le1 all head 200 |
| block in quick on lo0 all head 300 |
| .fi |
| .PP |
| |
| and to then allow ICMP packets in on le0, only, we would do: |
| .LP |
| .nf |
| pass in proto icmp all group 100 |
| .fi |
| .PP |
| Note that because only inbound packets on le0 are used processed by group 100, |
| there is no need to respecify the interface name. Likewise, we could further |
| breakup processing of TCP, etc, as follows: |
| .LP |
| .nf |
| block in proto tcp all head 110 group 100 |
| pass in from any to any port = 23 group 110 |
| .fi |
| .PP |
| and so on. The last line, if written without the groups would be: |
| .LP |
| .nf |
| pass in on le0 proto tcp from any to any port = telnet |
| .fi |
| .PP |
| Note, that if we wanted to say "port = telnet", "proto tcp" would |
| need to be specified as the parser interprets each rule on its own and |
| qualifies all service/port names with the protocol specified. |
| .SH FILES |
| /dev/ipauth |
| .br |
| /dev/ipl |
| .br |
| /dev/ipstate |
| .br |
| /etc/hosts |
| .br |
| /etc/services |
| .SH SEE ALSO |
| ipftest(1), iptest(1), mkfilters(1), ipf(4), ipnat(5), ipf(8), ipfstat(8) |