.TH IPF 1
.SH NAME
-ipf - alters packet filtering lists for IP packet input and ouput
+ipf \- alters packet filtering lists for IP packet input and ouput
.SH SYNOPSIS
-ipf [-AEDIsnovdrzZ] [-l <block|pass|nomatch>] [-F <i|o|a>]
--f <\fIfilename\fP> [ -f <\fIfilename\fP> [...]]
+.B ipf
+[
+.B \-AdDEInorsUvyzZ
+] [
+.B \-l
+<block|pass|nomatch>
+] [
+.B \-F
+<i|o|a>
+]
+.B \-f
+<\fIfilename\fP>
+[
+.B \-f
+<\fIfilename\fP>
+[...]]
.SH DESCRIPTION
.PP
-\fBipf\fP opens the filenames listed (treating "-" as stdin) and parses the
+\fBipf\fP opens the filenames listed (treating "\-" as stdin) and parses the
file for a set of rules which are to be added or removed from the packet
filter rule set.
.PP
Each rule processed by \fBipf\fP
-is added to the kernels internal lists if there are no parsing problems.
+is added to the kernel's internal lists if there are no parsing problems.
Rules are added to the end of the internal lists, matching the order in
which they appear when given to \fBipf\fP.
.SH OPTIONS
-.IP -A
-set the list to make changes to the active list (default).
-.IP -E
-Enable the filter (if disabled). Not effective for loadable kernel versions.
-.IP -D
+.TP
+.B \-A
+Set the list to make changes to the active list (default).
+.TP
+.B \-d
+Turn debug mode on. Causes a hexdump of filter rules to be generated as
+it processes each one.
+.TP
+.B \-D
Disable the filter (if enabled). Not effective for loadable kernel versions.
-.IP -F
-this option specifies which filter list to flush. The parameter should
+.TP
+.B \-E
+Enable the filter (if disabled). Not effective for loadable kernel versions.
+.TP
+.BR \-F \0<param>
+This option specifies which filter list to flush. The parameter should
either be "i" (input), "o" (output) or "a" (remove all filter rules).
Either a single letter or an entire word starting with the appropriate
letter maybe used. This option maybe before, or after, any other with
the order on the command line being that used to execute options.
-.IP -d
-turn debug mode on. Causes a hexdump of filter rules to be generated as
-it processes each one.
-.IP -f
-this option specifies which files
-\fBipf\fP should use to get input from for modifying the pack filter rule
+.TP
+.BR \-f \0<filename>
+This option specifies which files
+\fBipf\fP should use to get input from for modifying the packet filter rule
lists.
-.IP -I
-set the list to make changes to the inactive list.
-.IP -l
+.TP
+.B \-I
+Set the list to make changes to the inactive list.
+.TP
+.B \-l \0<param>
Use of the \fB-l\fP flag toggles default logging of packets. Valid
arguments to this option are \fBpass\fP, \fBblock\fP and \fBnomatch\fP.
When an option is set, any packet which exits filtering and matches the
set category is logged. This is most useful for causing all packets
which don't match any of the loaded rules to be logged.
-.IP -n
+.TP
+.B \-n
This flag (no-change) prevents \fBipf\fP from actually making any ioctl
calls or doing anything which would alter the currently running kernel.
-.IP -o
+.TP
+.B \-o
Force rules by default to be added/deleted to/from the output list, rather
than the (default) input list.
-.IP -s
-swap the active filter list in use to be the "other" one.
-.IP -r
-remove matching filter rules rather than add them to the internal lists
-.IP -v
-turn verbose mode on. Displays information relating to rule processing.
-.IP -z
-for each rule in the input file, reset the statistics for it to zero and
+.TP
+.B \-r
+Remove matching filter rules rather than add them to the internal lists
+.TP
+.B \-s
+Swap the active filter list in use to be the "other" one.
+.TP
+.B \-U
+(SOLARIS 2 ONLY) Block packets travelling along the data stream which aren't
+recognised as IP packets. They will be printed out on the console.
+.TP
+.B \-v
+Turn verbose mode on. Displays information relating to rule processing.
+.TP
+.B \-y
+(SOLARIS 2 ONLY) Manually resync the in-kernel interface list maintained
+by IP Filter with the current interface status list.
+.TP
+.B \-z
+For each rule in the input file, reset the statistics for it to zero and
display the statistics prior to them being zero'd.
-.IP -Z
-zero global statistics held in the kernel for filtering only (this doesn't
+.TP
+.B \-Z
+Zero global statistics held in the kernel for filtering only (this doesn't
affect fragment or state statistics).
.DT
.SH SEE ALSO
.TH IPF 4
.SH NAME
-ipf - packet filtering kernel interface
+ipf \- packet filtering kernel interface
.SH SYNOPSIS
#include <sys/ip_fil.h>
.SH IOCTLS
ioctl(fd, SIOCIPFFL, int *)
.fi
.PP
-The variations, SIOCADAFR vs SIOCADIFR, allow operation on the two lists,
+The variations, SIOCADAFR vs. SIOCADIFR, allow operation on the two lists,
active and inactive, respectively. All of these ioctl's are implemented
as being routing ioctls and thus the same rules for the various routing
ioctls and the file descriptor are employed, mainly being that the fd must
-be that of the device associated with the module (ie /dev/ipl).
+be that of the device associated with the module (i.e., /dev/ipl).
.LP
.PP
The three groups of ioctls above perform adding rules to the end of the
-.LP
.TH IPF 5
.SH NAME
-ipf - IP packet filtering format.
+ipf \- IP packet filter rule syntax
.SH DESCRIPTION
.PP
A rule file for \fBipf\fP may have any name or even be stdin. As
could be done:
.nf
-\fC# ipfstat -i | ipf -rf -\fP
+\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 ] .
+filter-rule = [ insert ] action in-out [ options ] [ match ] [ keep ]
+
+insert = "@" decnumber .
+action = block | "pass" | log | "count" | call .
+in-out = "in" | "out" .
+options = [ log ] [ "quick" ] [ "on" interface-name [ dup ] [ froute ] ] .
+match = [ tos ] [ ttl ] [ proto ] [ ip ] .
+keep = "keep state" | "keep frags" .
+
+block = "block" [ "return-icmp"[return-code] | "return-rst" ] .
+log = "log" [ "body" ] [ "first" ] [ "or-block" ] .
+call = "call" [ "now" ] function-name .
+
+dup = "dup-to" interface-name[":"ipaddr] .
+froute = "fastroute" | "to" interface-name .
-insert = "@" decnumber .
-action = block | "pass" | log | "count" | 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 ] .
+tos = "tos" decnumber | "tos" hexnumber .
+ttl = "ttl" decnumber .
+proto = "proto" protocol .
+ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] .
-block = "block" [ "return-icmp"[return-code] | "return-rst" ] .
-log = "log" [ "body" ] [ "first" ] .
-call = "call" [ "now" ] function-name .
-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 .
+srcdst = "all" | fromto .
+fromto = "from" object "to" object .
-object = addr [ port-comp | port-range ] .
-addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] .
+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 ] .
+
+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" .
-nummask = host-name [ "/" decnumber ] .
+nummask = host-name [ "/" decnumber ] .
host-name = ipaddr | hostname | "any" .
-ipaddr = host-num "." host-num "." host-num "." host-num .
+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 ] .
+optname = ipopts [ "," optname ] .
ipopts = optlist | "sec-class" [ secname ] .
-secname = seclvl [ "," secname ] .
+secname = seclvl [ "," secname ] .
seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" |
- "reserv-4" | "secret" | "topsecret" .
+ "reserv-4" | "secret" | "topsecret" .
icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" |
- "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" |
- "inforep" | "maskreq" | "maskrep" | decnumber .
+ "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" .
-optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" |
- "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" |
- "visa" | "imitd" | "eip" | "finn" .
+ "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" |
+ "net-prohib" | "host-prohib" | "net-tos" | "host-tos" .
+optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" |
+ "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" |
+ "visa" | "imitd" | "eip" | "finn" .
hexnumber = "0" "x" hexstring .
hexstring = hexdigit [ hexstring ] .
decnumber = digit [ decnumber ] .
compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" |
- "le" | "ge" .
-range = "<>" | "><" .
+ "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" .
+digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .
+flag = "F" | "S" | "R" | "P" | "A" | "U" .
.fi
.PP
-The "briefest" valid rule is of the form:
+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
pass in
log in
+ count in
.fi
.PP
-These can also be written like:
-.nf
- block in all pass in from any to any
-.fi
-.PP
-The action, one of either block, log or pass, indicates what to do with
-the packet if it matches the rest of the filter rule. Block indicates that
-the packet should be dropped here and not let through, log write the packet
-header to the \fBipl\fP packet logging psuedo-device (and has no further
-effect on validity of packet to be allowed through the filter) and pass which
-will allow the packet through. Each rule MUST have one of these three
-keywords.
-.PP
-In response to blocking a packet, the filter may be instructed to send a
-reply packet, either an ICMP unreachable (\fBreturn-icmp\fP)or a TCP
-"reset" (\fBreturn-rst\fP). An ICMP packet may be generated in response
-to any IP packet but a TCP reset may only be used with a rule which is
-being applied to TCP packets.
-.PP
-When a packet header is logged with the \fBlog\fP keyword, the optional
-\fBbody\fP keyword indicates that the first 128 bytes of the packet contents
-will be logged to the \fBipl\fP packet logging psuedo-device after the
-headers.
-.PP
-The next word must be either \fBin\fP or \fBout\fP. As each packet moving
-through the kernel is either an inbound packet or outbound, there is a
-requirement that each filter rule be explicitly stated as to which side of
-the IO it is to be used on.
-.PP
-The list of options is brief, and indeed all are optional. The presence
-of the \fBlog\fP option indicates, that should this be the last matching
-rule, the packet header will be written to the \fBipl\fP log. The \fBquick\fP
-option allows "short-cut" rules in order to speed up the filter. If a
-packet header matches a filter rule which is marked as \fBquick\fP, it will
-result in a quick-match and stop processing at this point. This is good for
-rules such as "block in quick from any to any with ipopts" which will match
-any packet with a non-standard header length (IP options present) and abort
-further processing, recording a match and also that the packet should be
-blocked. If this command is missing, the rule is taken to be a
-"fall-through" rule, meaning that the result of the match is used
-(block/pass) and that it will continue processing to see if there are any
-more matches. This 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 port > 6003
-.fi
-.PP
-which sets up the range 6000-6003 as being permitted and all others being
-denied. Another (easier) way to do the same is:
-.LP
+These are supposed to be the same as, but currently differ from:
+.\" XXX How, why do they differ??
.nf
- block in from any to any port 6000 <> 6003
- pass in from any to any port 5999 >< 6004
+ block in all
+ pass in from any to any
+ log in all
+ count in all
.fi
.PP
-Note that both the "block" and "pass" are needed here to affect a result
-as a failed "block" 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
+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
-would be needed before the first block. Expect to see a "between" operator
-as soon as I can work out how to fit in in.
+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 \fBon\fP command allows an interface name to be incorporated into the
-matching procedure. That it is a match and not actually associated with
-the interface itself is a result of the way this was implemented. Indeed,
-there is nothing to stop you using this with every rule if you so wish.
-If it is absent, the rule is taken to be applied to a packet regardless of
-the interface it is present on.
+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) 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.
+.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.
.PP
-The \fBall\fP command is essentially an alias for "from any to any" with
-no other commands.
+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
-Using \fBtos\fP, packets with different service capabilities can be filtered
-upon. Individual service levels or combinations can be filtered upon. The
+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.
-.PP
-Packets may also be selected by their \fBttl\fP value. The value given in
+.\" XXX TOS mask?? not in grammar!
+.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 \fBproto\fP command allows a specific protocol to be matched against.
-All protocol names found in \fB/etc/protocols\fP are recognised and maybe
-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.
-.PP
-To match against BOTH source and destination addresses, the \fBfrom\fP and
-\fBto\fP commands are used. They both support a large variety of valid
-syntaxes, including the "x/y" format. There is a special case for the
-hostname \fBany\fP which is taken to be 0.0.0.0/0 and matches all IP numbers.
-If a \fBport\fP match is included, then it is only applied to TCP/UDP
-packets. If the \fBproto\fP command is left out, packets from both protocols
-are compared. 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.
-.PP
-"x/y" indicates that a mask of y consecutive bits set is generated, starting
-with the MSB, so a value of 16 would give 0xffff0000.
+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
-"x mask y" indicates that the mask y is in dotted IP notation or a hexadecimal
-number of the form 0x12345678.
+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
-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.
+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
-When composing
-\fBport\fP comparisons, either the service name may be used or an integer
-port number.
+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. See the examples for more information.
.PP
-The \fBwith\fP command is used to nominate irregular attributes that some
-packets ma have associated with them. Alternatively, the keyword \fBand\fP
-maybe used in place of \fBwith\fP. This is provided to make the rules more
-readable and serves no other purpose. To filter IP options, in general,
-use \fBipopts\fP. For more specific filtering on IP options, individual
-options can be listed. When listed, all those listed must be found in a
-packet to cause a match.
+The \fBall\fP keyword is essentially a synonym for "from any to any"
+with no other match parameters.
.PP
-Before any option used after the \fBwith\fP keyword, the word \fBnot\fp
-maybe inserted to cause the filter rule to only match if the option(s) is
-not present.
-.PP
-The \fBflags\fP command 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:
+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
A - ACK
U - URG
.fi
-.PP
-The various flag symbols maybe used in combination, so that "SA" would
-represent a SYN-ACK combination present in a packet. There is nothing
-preventing combinations, such as "SFR". However, to guard against weird
-abberations, 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
-wich to compare (ie those you deem significant). This is done by appending
-"/<flags>" to the set of TCP flags you wish to match against. eg:
+.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 a
- # packet with ONLY the SYN flag set.
+ # becomes "flags S/AUPRFS" and will match
+ # packets with ONLY the SYN flag set.
... flags SA
# becomes "flags SA/AUPRFS" and will match any
# keyword action. "S/SA" will NOT match a packet
# with BOTH SYN and ACK set, but WILL match "SFP".
.fi
-.PP
-The next parameter set for the filter rule is the optional \fBicmp-type\fP.
-It is only effective when used with \fB"proto icmp"\fP and must NOT be used
-in conjuction with \fBflags\fP. There are a number of types which can be
-refered to by an abbreviation recognised by this language or the numbers
-with which they are associated can be used.
+.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 last parameter which can be set for a filter rule is whether on not to
-record state information for that packet, and what sort to keep. Either
-information relating to the packet's `flow' or if fragment details can be
-kept, allowing packets which match these to flow straight through, rather
+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 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
+??
+.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.
+.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 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.
.SH FILES
/etc/services
+.br
/etc/hosts
.SH SEE ALSO
ipf(1), ipftest(1)
* to the original author and the contributors.
*
* @(#)ipf.h 1.12 6/5/96
- * $Id: ipf.h,v 1.5 1996/07/18 05:11:02 dm Exp $
+ * $Id: ipf.h,v 1.6 1997/02/11 22:23:39 kstailey Exp $
*/
+#ifndef SOLARIS
+#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
+#endif
#define OPT_REMOVE 0x00001
#define OPT_DEBUG 0x00002
#define OPT_OUTQUE FR_OUTQUE /* 0x0004 */
extern u_long hostnum(), optname();
extern void printpacket();
+#if SOLARIS
+extern int inet_aton();
+#endif
#ifdef sun
#define STRERROR(x) sys_errlist[x]
#define STRERROR(x) strerror(x)
#endif
+#ifndef MIN
+#define MIN(a,b) ((a) > (b) ? (b) : (a))
+#endif
+
#include <paths.h>
#endif
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-1996 Darren Reed";
-static char rcsid[] = "$Id: fils.c,v 1.7 1996/10/08 07:33:33 niklas Exp $";
+static char rcsid[] = "$Id: fils.c,v 1.8 1997/02/11 22:23:41 kstailey Exp $";
#endif
#ifdef _PATH_UNIX
#define VMUNIX _PATH_UNIX
opts |= OPT_VERBOSE;
break;
default :
- Usage();
+ Usage(argv[0]);
break;
}
}
fp->f_st[0].fr_bpkl, fp->f_st[0].fr_ppkl);
PRINTF("output packets logged:\tblocked %lu passed %lu\n",
fp->f_st[1].fr_bpkl, fp->f_st[1].fr_ppkl);
- PRINTF(" packets logged:\tinput %lu-%lu output %lu-%lu\n",
- fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip,
- fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip);
+ PRINTF(" packets logged:\tinput %lu output %lu\n",
+ fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl);
+ PRINTF(" log failures:\t\tinput %lu output %lu\n",
+ fp->f_st[0].fr_skip, fp->f_st[1].fr_skip);
PRINTF("fragment state(in):\tkept %lu\tlost %lu\n",
fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr);
PRINTF("fragment state(out):\tkept %lu\tlost %lu\n",
fp->f_st[0].fr_ret, fp->f_st[1].fr_ret);
PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n",
fp->f_st[0].fr_chit, fp->f_st[1].fr_chit);
+ PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n",
+ fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]);
+ PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n",
+ fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]);
PRINTF("Packet log flags set: (%#x)\n", frf);
if (frf & FF_LOGPASS)
set = 1 - set;
if (opts & OPT_ACCNT) {
i = F_AC;
- if (opts & OPT_INQUE)
- fp = (struct frentry *)fiop->f_acctin[set];
- else {
+ if (opts & OPT_OUTQUE) {
fp = (struct frentry *)fiop->f_acctout[set];
i++;
- }
+ } else if (opts & OPT_INQUE)
+ fp = (struct frentry *)fiop->f_acctin[set];
} else if (opts & OPT_OUTQUE) {
i = F_OUT;
fp = (struct frentry *)fiop->f_fout[set];
if (kmemcpy(&ips, istab[i], sizeof(ips)) == -1)
break;
PRINTF("%s -> ", inet_ntoa(ips.is_src));
- PRINTF("%s age %d pass %d pr %d\n",
+ PRINTF("%s age %d pass %d pr %d state %d/%d\n",
inet_ntoa(ips.is_dst), ips.is_age,
- ips.is_pass, ips.is_p);
+ ips.is_pass, ips.is_p, ips.is_state[0],
+ ips.is_state[1]);
if (ips.is_p == IPPROTO_TCP)
- PRINTF("\t%hu -> %hu %lu:%lu %hu\n",
+ PRINTF("\t%hu -> %hu %lu:%lu %hu:%hu\n",
ntohs(ips.is_sport),
ntohs(ips.is_dport),
- ips.is_seq, ips.is_ack, ips.is_win);
+ ips.is_seq, ips.is_ack,
+ ips.is_swin, ips.is_dwin);
else if (ips.is_p == IPPROTO_UDP)
PRINTF("\t%hu -> %hu\n", ntohs(ips.is_sport),
ntohs(ips.is_dport));
-.LP
.TH ipfstat 8
.SH NAME
-ipfstat - reports on packet filter statistics and filter list
+ipfstat \- reports on packet filter statistics and filter list
.SH SYNOPSIS
-ipfstat [-hIiovd:]
+.B ipfstat
+[
+.B \-hIinov
+] [
+.B \-d
+<device>
+]
.SH DESCRIPTION
-.LP
.PP
-\fBipfstat examines /dev/kmem using the symbols \fB_fr_flags\fP,
+\fBipfstat\fP examines /dev/kmem using the symbols \fB_fr_flags\fP,
\fB_frstats\fP, \fB_filterin\fP, and \fB_filterout\fP.
To run and work, it needs to be able to read both /dev/kmem and the
kernel itself. The kernel name defaults to \fB/vmunix\fP.
is to retrieve and display the accumulated statistics which have been
accumulated over time as the kernel has put packets through the filter.
.SH OPTIONS
-.IP -a
-display the accounting filter list and show bytes counted against each rule.
-.IP -d <device>
-use a device other than \fB/dev/ipl\fP for interfacing with the kernel.
-.IP -f
-show fragment state information (statistics) and held state information (in
+.TP
+.B \-a
+Display the accounting filter list and show bytes counted against each rule.
+.TP
+.BR \-d \0<device>
+Use a device other than \fB/dev/ipl\fP for interfacing with the kernel.
+.TP
+.B \-f
+Show fragment state information (statistics) and held state information (in
the kernel) if any is present.
-.IP -h
-show per-rule the number of times each one scores a "hit". For use in
-combination with \fB-i\fP.
-.IP -i
-display the filter list used for the input side of the kernel IP processing.
-.IP -I
-swap between retrieving "inactive"/"active" filter list details. For use
-in combination with \fB-i\fP.
-.IP -o
-display the filter list used for the output side of the kernel IP processing.
-.IP -s
-show packet/flow state information (statistics) and held state information (in
+.TP
+.B \-h
+Show per-rule the number of times each one scores a "hit". For use in
+combination with \fB\-i\fP.
+.TP
+.B \-i
+Display the filter list used for the input side of the kernel IP processing.
+.TP
+.B \-I
+Swap between retrieving "inactive"/"active" filter list details. For use
+in combination with \fB\-i\fP.
+.TP
+.B \-n
+Show the "rule number" for each rule as it is printed.
+.TP
+.B \-o
+Display the filter list used for the output side of the kernel IP processing.
+.TP
+.B \-s
+Show packet/flow state information (statistics) and held state information (in
the kernel) if any is present.
-.IP -v
-turn verbose mode on. Displays more debugging information.
+.TP
+.B \-v
+Turn verbose mode on. Displays more debugging information.
.SH SYNOPSIS
The role of \fBipfstat\fP is to display current kernel statistics gathered
as a result of applying the filters in place (if any) to packets going in and
out of the kernel. This is the default operation when no command line
parameters are present.
.PP
-When supplied with either \fB-i\fP or \fB-o\fP, it will retrieve and display
+When supplied with either \fB\-i\fP or \fB\-o\fP, it will retrieve and display
the appropriate list of filter rules currently installed and in use by the
kernel.
.SH FILES
/dev/kmem
+.br
/vmunix
.SH SEE ALSO
ipf(1), ipfstat(1)
#define KMEM "/dev/kmem"
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed";
-static char rcsid[] = "$Id: kmem.c,v 1.5 1996/12/17 23:50:51 niklas Exp $";
+static char rcsid[] = "$Id: kmem.c,v 1.6 1997/02/11 22:23:44 kstailey Exp $";
#endif
static int kmemfd = -1;
int kmemcpy(buf, pos, n)
register char *buf;
-u_long pos;
+long pos;
register int n;
{
register int r;
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
- * $Id: kmem.h,v 1.3 1996/07/18 05:08:10 dm Exp $
+ * $Id: kmem.h,v 1.4 1997/02/11 22:23:46 kstailey Exp $
*/
extern int openkmem();
-.TH IPFNAT 1
+.TH IPNAT 1
.SH NAME
-ipnat - user interface to the NAT
+ipnat \- user interface to the NAT
.SH SYNOPSIS
-ipnat [-lnrsv] -f <\fIfilename\fP>
+.B ipnat
+[
+.B \-lnrsvCF
+]
+.B \-f <\fIfilename\fP>
.SH DESCRIPTION
.PP
-\fBipnat\fP opens the filename given (treating "-" as stdin) and parses the
+\fBipnat\fP opens the filename given (treating "\-" as stdin) and parses the
file for a set of rules which are to be added or removed from the IP NAT.
.PP
Each rule processed by \fBipnat\fP
Rules are added to the end of the internal lists, matching the order in
which they appear when given to \fBipnat\fP.
.SH OPTIONS
-.IP -l
+.TP
+.B \-C
+delete all entries in the current NAT listing (NAT rules)
+.TP
+.B \-F
+delete all active entries in the current NAT table (currently active
+NAT mappings)
+.TP
+.B \-l
Show the list of current NAT table entry mappings.
-.IP -n
+.TP
+.B \-n
This flag (no-change) prevents \fBipf\fP from actually making any ioctl
calls or doing anything which would alter the currently running kernel.
-.IP -s
-retrieve and display NAT statistics
-.IP -r
-remove matching NAT rules rather than add them to the internal lists
-.IP -v
-turn verbose mode on. Displays information relating to rule processing.
+.TP
+.B \-s
+Retrieve and display NAT statistics
+.TP
+.B \-r
+Remove matching NAT rules rather than add them to the internal lists
+.TP
+.B \-v
+Turn verbose mode on. Displays information relating to rule processing.
.DT
.SH SEE ALSO
ipfstat(1), ipftest(1), ipf(1), ipnat(4), ipnat(5)
.TH IPNAT 4
.SH NAME
-ipnat - Network Address Translation kernel interface
+ipnat \- Network Address Translation kernel interface
.SH SYNOPSIS
#include <sys/ip_fil.h>
.SH IOCTLS
These ioctl's are implemented as being routing ioctls and thus the same rules
for the various routing ioctls and the file descriptor are employed, mainly
being that the fd must be that of the device associated with the module
-(ie /dev/ipl).
+(i.e., /dev/ipl).
.LP
.PP
The strcture used with the NAT interface is described below:
It would be nice if there were more flexibility when adding and deleting
filter rules.
.SH SEE ALSO
-ipnat(1), ipfstat(1), ipf(1), ipf(4), ipnat(5)
+ipfstat(1), ipf(1), ipnat(1), ipf(4), ipnat(5)
-.LP
.TH IPNAT 5
.SH NAME
-ipnat - IP NAT file format
+ipnat \- IP NAT file format
.SH DESCRIPTION
The format for files accepted by ipnat is described by the following grammar:
.LP
ICMP, only have their IP# changed.
.SH FILES
/etc/services
+.br
/etc/hosts
.SH SEE ALSO
-ipnat(1), ipf(5), ipnat(4)
+ipnat(1), ipf(5), ipnat(4), ipnat(5)
-/* $OpenBSD: ipnat.c,v 1.9 1997/02/07 20:06:44 kstailey Exp $ */
+/* $OpenBSD: ipnat.c,v 1.10 1997/02/11 22:24:20 kstailey Exp $ */
/*
* (C)opyright 1993,1994,1995 by Darren Reed.
*
#include <netinet/tcp.h>
#include <net/if.h>
#include "ip_fil_compat.h"
-#include "ip_fil.h"
+#include "ip_fil.h" /* XXX needed? */
#include <netdb.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include "ip_nat.h"
#include <ctype.h>
-#if 0
-#ifndef lint
+
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed";
-#endif
+static char rcsid[] = "Id: ipnat.c,v 2.0.1.7 1997/01/30 12:02:32 darrenr Exp";
#endif
#if SOLARIS
extern char *optarg;
extern int kmemcpy();
-void dostats(), printnat(), parsefile();
+void dostats(), printnat(), parsefile(), flushtable();
+
+#define OPT_REM 1
+#define OPT_NODO 2
+#define OPT_STAT 4
+#define OPT_LIST 8
+#define OPT_VERBOSE 16
+#define OPT_FLUSH 32
+#define OPT_CLEAR 64
void usage(name)
char *name;
{
- fprintf(stderr, "%s: [-lnrsv] [-f filename]\n", name);
+ fprintf(stderr, "%s: [-CFlnrsv] [-f filename]\n", name);
exit(1);
}
char *file = NULL, c;
int fd, opts = 1;
- while ((c = getopt(argc, argv, "f:lnrsv")) != -1)
+ while ((c = getopt(argc, argv, "CFf:lnrsv")) != -1)
switch (c)
{
+ case 'C' :
+ opts |= OPT_CLEAR;
+ break;
case 'f' :
file = optarg;
break;
+ case 'F' :
+ opts |= OPT_FLUSH;
+ break;
case 'l' :
- opts |= 8;
+ opts |= OPT_LIST;
break;
case 'n' :
- opts |= 2;
+ opts |= OPT_NODO;
break;
case 'r' :
- opts &= ~1;
+ opts &= ~OPT_REM;
break;
case 's' :
- opts |= 4;
+ opts |= OPT_STAT;
break;
case 'v' :
- opts |= 16;
+ opts |= OPT_VERBOSE;
break;
default :
usage(argv[0]);
}
- if (((fd = open(IPL_NAME, O_RDWR)) == -1) &&
+ if (!(opts & OPT_NODO) && ((fd = open(IPL_NAME, O_RDWR)) == -1) &&
((fd = open(IPL_NAME, O_RDONLY)) == -1)) {
perror("open");
exit(-1);
}
+ if (opts & (OPT_FLUSH|OPT_CLEAR))
+ flushtable(fd, opts);
if (file)
parsefile(fd, file, opts);
- if (opts & 12)
+ if (opts & (OPT_LIST|OPT_STAT))
dostats(fd, opts);
return 0;
}
}
-void printnat(np, verbose)
+void printnat(np, verbose, ptr)
ipnat_t *np;
int verbose;
+void *ptr;
{
int bits;
printf("/%s ", inet_ntoa(np->in_out[1]));
if (np->in_pmin)
printf("port %d ", ntohs(np->in_pmin));
- printf("-> %s", inet_ntoa(np->in_in[0]),
- ntohs(np->in_pnext));
- if (np->in_pmax)
- printf(" port %d", ntohs(np->in_pmax));
+ printf("-> %s", inet_ntoa(np->in_in[0]));
+ if (np->in_pnext)
+ printf(" port %d", ntohs(np->in_pnext));
+ if (np->in_flags & IPN_TCPUDP)
+ printf(" tcp/udp");
+ else if (np->in_flags & IPN_TCP)
+ printf(" tcp");
+ else if (np->in_flags & IPN_UDP)
+ printf(" udp");
printf("\n");
if (verbose)
- printf("\t%x %u %x %u", (u_int)np->in_ifp,
- np->in_space, np->in_flags, np->in_pnext);
+ printf("\t%x %u %x %u %x %d\n", (u_int)np->in_ifp,
+ np->in_space, np->in_flags, np->in_pnext, np,
+ np->in_use);
} else {
np->in_nextip.s_addr = htonl(np->in_nextip.s_addr);
printf("map %s %s/", np->in_ifname, inet_ntoa(np->in_in[0]));
printf("%d ", bits);
else
printf("%s", inet_ntoa(np->in_out[1]));
- if (np->in_port[0] || np->in_port[1]) {
+ if (np->in_pmin || np->in_pmax) {
printf(" portmap");
- if (np->in_flags & IPN_TCPUDP)
+ if ((np->in_flags & IPN_TCPUDP) == IPN_TCPUDP)
printf(" tcp/udp");
else if (np->in_flags & IPN_TCP)
printf(" tcp");
else if (np->in_flags & IPN_UDP)
printf(" udp");
- printf(" %d:%d", ntohs(np->in_port[0]),
- ntohs(np->in_port[1]));
+ printf(" %d:%d", ntohs(np->in_pmin),
+ ntohs(np->in_pmax));
}
printf("\n");
if (verbose)
}
+/*
+ * Get a nat filter type given its kernel address.
+ */
+char *getnattype(ipnat)
+ipnat_t *ipnat;
+{
+ ipnat_t ipnatbuff;
+
+ if (ipnat && kmemcpy(&ipnatbuff, ipnat, sizeof(ipnatbuff)))
+ return "???";
+
+ return (ipnatbuff.in_redir == NAT_MAP) ? "MAP" : "RDR";
+}
+
+
void dostats(fd, opts)
int fd, opts;
{
natstat_t ns;
ipnat_t ipn;
- nat_t **nt, *np, nat;
- int i;
+ nat_t **nt[2], *np, nat;
+ int i = 0;
- if (ioctl(fd, SIOCGNATS, &ns) == -1) {
+ bzero((char *)&ns, sizeof(ns));
+
+ if (!(opts & OPT_NODO) && ioctl(fd, SIOCGNATS, &ns) == -1) {
perror("ioctl(SIOCGNATS)");
return;
}
- if (opts & 4) {
+
+ if (opts & OPT_STAT) {
printf("mapped\tin\t%lu\tout\t%lu\n",
ns.ns_mapped[0], ns.ns_mapped[1]);
printf("added\t%lu\texpired\t%lu\n",
ns.ns_added, ns.ns_expire);
printf("inuse\t%lu\n", ns.ns_inuse);
- if (opts & 16)
+ if (opts & OPT_VERBOSE)
printf("table %#x list %#x\n",
(u_int)ns.ns_table, (u_int)ns.ns_list);
}
- if (opts & 8) {
+ if (opts & OPT_LIST) {
+ printf("List of active MAP/Redirect filters:\n");
while (ns.ns_list) {
if (kmemcpy(&ipn, ns.ns_list, sizeof(ipn))) {
perror("kmemcpy");
break;
}
- printnat(&ipn, opts & 16);
+ printnat(&ipn, opts & OPT_VERBOSE, (void *)ns.ns_list);
ns.ns_list = ipn.in_next;
}
- nt = (nat_t **)malloc(sizeof(*nt) * NAT_SIZE);
- if (kmemcpy(nt, ns.ns_table, sizeof(*nt) * NAT_SIZE)) {
+ nt[0] = (nat_t **)malloc(sizeof(*nt) * NAT_SIZE);
+ if (kmemcpy(nt[0], ns.ns_table[0], sizeof(**nt) * NAT_SIZE)) {
perror("kmemcpy");
return;
}
+
+ printf("\nList of active sessions:\n");
+
for (i = 0; i < NAT_SIZE; i++)
- for (np = nt[i]; np; np = nat.nat_next) {
+ for (np = nt[0][i]; np; np = nat.nat_hnext[0]) {
if (kmemcpy(&nat, np, sizeof(nat)))
break;
- printf("%s %hu <- -> ",
+
+ printf("%s %-15s %-5hu <- ->",
+ getnattype(nat.nat_ptr),
inet_ntoa(nat.nat_inip),
ntohs(nat.nat_inport));
- printf("%s %hu %hu %hu %lx [",
+ printf(" %-15s %-5hu",
inet_ntoa(nat.nat_outip),
- ntohs(nat.nat_outport),
- nat.nat_age, nat.nat_use,
- nat.nat_sumd);
- printf("%s %hu]\n", inet_ntoa(nat.nat_oip),
+ ntohs(nat.nat_outport));
+ printf(" [%s %hu]", inet_ntoa(nat.nat_oip),
ntohs(nat.nat_oport));
+ printf(" %d %hu %lx", nat.nat_age,
+ nat.nat_use, nat.nat_sumd);
+#if SOLARIS
+ printf(" %lx", nat.nat_ipsumd);
+#endif
+ putchar('\n');
}
+ free(nt[0]);
}
}
{
static ipnat_t ipn;
char *s, *t;
- char *shost, *snetm, *dhost, *dnetm, *proto, *dport, *tport;
+ char *shost, *snetm, *dhost, *proto;
+ char *dnetm = NULL, *dport = NULL, *tport = NULL;
int resolved;
bzero((char *)&ipn, sizeof(ipn));
if (ipn.in_redir == NAT_MAP) {
ipn.in_inip = hostnum(shost, &resolved);
+ if (resolved == -1)
+ return NULL;
ipn.in_inmsk = hostmask(snetm);
ipn.in_outip = hostnum(dhost, &resolved);
+ if (resolved == -1)
+ return NULL;
ipn.in_outmsk = hostmask(dnetm);
} else {
ipn.in_inip = hostnum(dhost, &resolved); /* Inside is target */
+ if (resolved == -1)
+ return NULL;
ipn.in_inmsk = hostmask("255.255.255.255");
ipn.in_outip = hostnum(shost, &resolved);
+ if (resolved == -1)
+ return NULL;
ipn.in_outmsk = hostmask(snetm);
if (!(s = strtok(NULL, " \t"))) {
ipn.in_flags = IPN_TCP; /* XXX- TCP only by default */
ipn.in_flags = IPN_UDP;
else if (!strcasecmp(s, "tcp/udp"))
ipn.in_flags = IPN_TCPUDP;
+ else if (!strcasecmp(s, "tcpudp"))
+ ipn.in_flags = IPN_TCPUDP;
else {
fprintf(stderr,
"expected protocol - got \"%s\"\n", s);
return NULL;
}
proto = s;
+ if ((s = strtok(NULL, " \t"))) {
+ fprintf(stderr,
+ "extra junk at the end of rdr: %s\n",
+ s);
+ return NULL;
+ }
}
ipn.in_pmin = portnum(dport, proto); /* dest port */
ipn.in_pmax = ipn.in_pmin; /* NECESSARY of removing nats */
ipn.in_flags = IPN_TCP;
else if (!strcasecmp(s, "udp"))
ipn.in_flags = IPN_UDP;
+ else if (!strcasecmp(s, "tcpudp"))
+ ipn.in_flags = IPN_TCPUDP;
else if (!strcasecmp(s, "tcp/udp"))
ipn.in_flags = IPN_TCPUDP;
else {
if (*line)
fprintf(stderr, "%d: syntax error in \"%s\"\n",
linenum, line);
- } else if (!(opts & 2)) {
- if ((opts &16) && np)
- printnat(np, opts & 16);
- if (opts & 1) {
+ } else if (!(opts & OPT_NODO)) {
+ if ((opts & OPT_VERBOSE) && np)
+ printnat(np, opts & OPT_VERBOSE, NULL);
+ if (opts & OPT_REM) {
if (ioctl(fd, SIOCADNAT, np) == -1)
perror("ioctl(SIOCADNAT)");
} else if (ioctl(fd, SIOCRMNAT, np) == -1)
}
fclose(stdin);
}
+
+
+void flushtable(fd, opts)
+int fd, opts;
+{
+ int n = 0;
+
+ if (opts & OPT_FLUSH) {
+ n = 0;
+ if (!(opts & OPT_NODO) && ioctl(fd, SIOCFLNAT, &n) == -1)
+ perror("ioctl(SIOCFLNAT)");
+ else
+ printf("%d entries flushed from NAT table\n", n);
+ }
+
+ if (opts & OPT_CLEAR) {
+ n = 0;
+ if (!(opts & OPT_NODO) && ioctl(fd, SIOCCNATL, &n) == -1)
+ perror("ioctl(SIOCCNATL)");
+ else
+ printf("%d entries flushed from NAT list\n", n);
+ }
+}
+/* $OpenBSD: fil.c,v 1.8 1997/02/11 22:23:08 kstailey Exp $ */
/*
* (C)opyright 1993-1996 by Darren Reed.
*
* to the original author and the contributors.
*/
#if 0
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed";
-static char rcsid[] = "$OpenBSD: fil.c,v 1.7 1996/10/24 17:56:20 tholo Exp $";
+static char rcsid[] = "Id: fil.c,v 2.0.1.3 1997/01/29 13:38:54 darrenr Exp";
#endif
#endif
#endif
#include <sys/uio.h>
#if !defined(__SVR4) && !defined(__svr4__)
-# if defined(__OpenBSD__)
-# include <sys/dirent.h>
-# else
-# include <sys/dir.h>
-# endif
# include <sys/mbuf.h>
#else
# include <sys/byteorder.h>
#define FR_IFDEBUG(ex,second,verb_pr) if (ex) { debug verb_pr; second; }
#define FR_VERBOSE(verb_pr) verbose verb_pr
#define FR_DEBUG(verb_pr) debug verb_pr
-#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi)
+#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, NULL)
# if SOLARIS
# define bcmp memcmp
# endif
#define FR_IFDEBUG(ex,second,verb_pr) ;
#define FR_VERBOSE(verb_pr)
#define FR_DEBUG(verb_pr)
+#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m)
+extern int send_reset __P((struct tcpiphdr *));
# if SOLARIS
-extern int icmp_error();
-extern kmutex_t ipf_mutex;
-# define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi)
+extern int icmp_error(), ipfr_fastroute();
+extern kmutex_t ipf_mutex, ipl_mutex;
# else
-# define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m)
+extern void ipfr_fastroute __P((struct mbuf *, fr_info_t *, frdest_t *));
# endif
extern int ipl_unreach;
+extern int ipllog __P((u_int, ip_t *, register fr_info_t *,
+ struct mbuf *));
#endif
#if SOLARIS
-# define IPLLOG(fl, ip, fi, m) ipllog(fl, ip, fi)
# define SEND_RESET(ip, if, q) send_reset(ip, qif, q)
# define ICMP_ERROR(b, ip, t, c, if, src) \
icmp_error(b, ip, t, c, if, src)
#else
-# define IPLLOG(fl, ip, fi, m) ipllog(fl, ip, fi, m)
# define SEND_RESET(ip, if, q) send_reset( \
(struct tcpiphdr *)ip)
# if BSD < 199103
int fr_flags = 0, fr_active = 0;
fr_info_t frcache[2];
-
+
void fr_makefrip __P((int, ip_t *, fr_info_t *));
int fr_tcpudpchk __P((frentry_t *, fr_info_t *));
-#if (defined(_KERNEL) || defined(KERNEL)) && !SOLARIS
-int fr_scanlist __P((int, ip_t *, fr_info_t *, void *));
-#else
-int fr_scanlist __P((int, ip_t *, fr_info_t *));
-#endif
+int fr_scanlist __P((int, ip_t *, fr_info_t *, void *m));
/*
* bit values for identifying presence of individual IP options
*/
void
fr_makefrip(hlen, ip, fin)
- int hlen;
- ip_t *ip;
- fr_info_t *fin;
+ int hlen;
+ ip_t *ip;
+ fr_info_t *fin;
{
struct optlist *op;
tcphdr_t *tcp;
*/
int
fr_tcpudpchk(fr, fin)
- frentry_t *fr;
- fr_info_t *fin;
+ frentry_t *fr;
+ fr_info_t *fin;
{
register u_short po, tup;
register char i;
* kernel sauce.
*/
int
-fr_scanlist(pass, ip, fin
-#if (defined(_KERNEL) || defined(KERNEL)) && !SOLARIS
- , m)
- void *m;
-#else
- )
-#endif
- int pass;
- ip_t *ip;
- register fr_info_t *fin;
+fr_scanlist(pass, ip, fin, m)
+ int pass;
+ ip_t *ip;
+ register fr_info_t *fin;
+ void *m;
{
register struct frentry *fr;
register fr_ip_t *fi = &fin->fin_fi;
int rulen, portcmp = 0, off;
+ fr = fin->fin_fr;
+ fin->fin_fr = NULL;
fin->fin_rule = 0;
off = ip->ip_off & 0x1fff;
pass |= (fi->fi_fl << 20);
if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
portcmp = 1;
- for (rulen = 0, fr = fin->fin_fr; fr; fr = fr->fr_next, rulen++) {
+ for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
/*
* In all checks below, a null (zero) value in the
* filter struture is taken to mean a wildcard.
if (portcmp) {
if (!fr_tcpudpchk(fr, fin))
continue;
- } else if (fr->fr_dcmp || fr->fr_scmp)
+ } else if (fr->fr_dcmp || fr->fr_scmp || fr->fr_tcpf ||
+ fr->fr_tcpfm)
continue;
} else if (fi->fi_p == IPPROTO_ICMP) {
if (!off && (fin->fin_dlen > 1)) {
fr->fr_icmpm, fr->fr_icmp));
continue;
}
- } else if (fr->fr_icmpm || fr->fr_tcpfm)
+ } else if (fr->fr_icmpm || fr->fr_icmp)
continue;
}
FR_VERBOSE(("*"));
- /*
- * Just log this packet...
- */
+ /*
+ * Just log this packet...
+ */
pass = fr->fr_flags;
if ((pass & FR_CALLNOW) && fr->fr_func)
pass = (*fr->fr_func)(pass, ip, fin);
#ifdef IPFILTER_LOG
if ((pass & FR_LOGMASK) == FR_LOG) {
- if (!IPLLOG(fr->fr_flags, ip, fin, m))
+ if (!ipllog(fr->fr_flags, ip, fin, m))
frstats[fin->fin_out].fr_skip++;
frstats[fin->fin_out].fr_pkl++;
}
fr->fr_bytes += ip->ip_len;
else
fin->fin_icode = fr->fr_icode;
+ fin->fin_rule = rulen;
+ fin->fin_fr = fr;
if (pass & FR_QUICK)
break;
}
- fin->fin_rule = rulen;
- fin->fin_fr = fr;
return pass;
}
/*
* frcheck - filter check
- * check using source and destination addresses/pors in a packet whether
+ * check using source and destination addresses/ports in a packet whether
* or not to pass it on or not.
*/
int
fr_check(ip, hlen, ifp, out
#ifdef _KERNEL
# if SOLARIS
- , qif, q, mb)
+ , qif, q, mp)
qif_t *qif;
queue_t *q;
- mblk_t *mb;
+ mblk_t **mp;
# else
, mp)
struct mbuf **mp;
#else
)
#endif
- ip_t *ip;
- int hlen;
- struct ifnet *ifp;
- int out;
+ ip_t *ip;
+ int hlen;
+ struct ifnet *ifp;
+ int out;
{
/*
* The above really sucks, but short of writing a diff
*/
fr_info_t frinfo, *fc;
register fr_info_t *fin = &frinfo;
- frentry_t *fr;
- int pass;
+ frentry_t *fr = NULL;
+ int pass, changed;
#if !defined(__SVR4) && !defined(__svr4__) && defined(_KERNEL)
register struct mbuf *m = *mp;
register int up = MIN(hlen + 8, ip->ip_len);
if (up > m->m_len) {
- if ((*mp = m_pullup(m, up)) == 0)
+ if ((*mp = m_pullup(m, up)) == 0) {
+ frstats[out].fr_pull[1]++;
return -1;
- else {
+ } else {
+ frstats[out].fr_pull[0]++;
m = *mp;
ip = mtod(m, struct ip *);
}
}
}
#endif
-#if SOLARIS
- mblk_t *mc = NULL;
+#if SOLARIS && defined(_KERNEL)
+ mblk_t *mc = NULL, *m = qif->qf_m;
#endif
fr_makefrip(hlen, ip, fin);
fin->fin_ifp = ifp;
MUTEX_ENTER(&ipf_mutex);
if (!out) {
- ip_natin(ip, hlen, fin);
+ changed = ip_natin(ip, hlen, fin);
if ((fin->fin_fr = ipacct[0][fr_active]) &&
(FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
frstats[0].fr_acct++;
if ((pass = ipfr_knownfrag(ip, fin))) {
if ((pass & FR_KEEPSTATE)) {
- /*
- * XXX I don't know if changing hlen to fin is right,
- * but at least that is typesafe. //niklas@appli.se
- *
- * old code was:
- * if (fr_addstate(ip, hlen, pass) == -1)
- */
if (fr_addstate(ip, fin, pass) == -1)
frstats[out].fr_bads++;
else
#endif
}
}
+ fr = fin->fin_fr;
if ((pass & FR_KEEPFRAG)) {
if (fin->fin_fi.fi_fl & FI_FRAG) {
}
}
- fr = fin->fin_fr;
-
if (fr && fr->fr_func)
pass = (*fr->fr_func)(pass, ip, fin);
if ((fin->fin_fr = ipacct[1][fr_active]) &&
(FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
frstats[1].fr_acct++;
- ip_natout(ip, hlen, fin);
+ fin->fin_fr = NULL;
+ changed = ip_natout(ip, hlen, fin);
}
+ fin->fin_fr = fr;
MUTEX_EXIT(&ipf_mutex);
#ifdef IPFILTER_LOG
pass |= FF_LOGBLOCK;
frstats[out].fr_bpkl++;
logit:
- if (!IPLLOG(pass, ip, fin, m))
+ if (!ipllog(pass, ip, fin, m)) {
frstats[out].fr_skip++;
+ if ((pass & (FR_PASS|FR_LOGORBLOCK)) ==
+ (FR_PASS|FR_LOGORBLOCK))
+ pass ^= FR_PASS|FR_BLOCK;
+ }
}
}
#endif /* IPFILTER_LOG */
frdest_t *fdp = &fr->fr_tif;
if ((pass & FR_FASTROUTE) ||
- (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1))
+ (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
ipfr_fastroute(m, fin, fdp);
+ m = *mp = NULL;
+ pass = 0;
+ }
if (mc)
ipfr_fastroute(mc, fin, &fr->fr_dif);
}
if (!(pass & FR_PASS) && m)
m_freem(m);
+ return (pass & FR_PASS) ? 0 : -1;
# else
- /*
if (pass & FR_DUP)
- mc = dupmsg(mb);
+ mc = dupmsg(m);
if (fr) {
frdest_t *fdp = &fr->fr_tif;
if ((pass & FR_FASTROUTE) ||
- (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1))
- ipfr_fastroute(mb, fin, fdp);
+ (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) {
+ ipfr_fastroute(qif, ip, m, mp, fin, fdp);
+ m = *mp = NULL;
+ }
if (mc)
- ipfr_fastroute(mc, fin, &fr->fr_dif);
+ ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif);
}
- */
+ return (pass & FR_PASS) ? changed : -1;
# endif
- return (pass & FR_PASS) ? 0 : -1;
#else
if (pass & FR_NOMATCH)
return 1;
}
-#ifndef _KERNEL
+#ifdef IPFILTER_LOG
+# if !(defined(_KERNEL))
static void ipllog()
{
verbose("l");
}
+# endif
+
+
+int fr_copytolog(buf, len)
+char *buf;
+int len;
+{
+ int clen, tail;
+
+ tail = (iplh >= iplt) ? (iplbuf + IPLLOGSIZE - iplh) : (iplt - iplh);
+ clen = MIN(tail, len);
+ bcopy(buf, iplh, clen);
+ len -= clen;
+ tail -= clen;
+ iplh += clen;
+ buf += clen;
+ if (iplh == iplbuf + IPLLOGSIZE) {
+ iplh = iplbuf;
+ tail = iplt - iplh;
+ }
+ if (len && tail) {
+ clen = MIN(tail, len);
+ bcopy(buf, iplh, clen);
+ len -= clen;
+ iplh += clen;
+ }
+ return len;
+}
#endif
-/* $OpenBSD: if_ether.c,v 1.7 1996/05/22 11:48:45 deraadt Exp $ */
+/* $OpenBSD: if_ether.c,v 1.8 1997/02/11 22:23:14 kstailey Exp $ */
/* $NetBSD: if_ether.c,v 1.31 1996/05/11 12:59:58 mycroft Exp $ */
/*
+/* $OpenBSD: ip_fil.c,v 1.10 1997/02/11 22:23:12 kstailey Exp $ */
/*
* (C)opyright 1993,1994,1995 by Darren Reed.
*
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*/
-#if 0
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed";
-static char rcsid[] = "$OpenBSD: ip_fil.c,v 1.9 1997/02/05 00:53:11 kstailey Exp $";
-#endif
+static char rcsid[] = "Id: ip_fil.c,v 2.0.1.5 1997/01/29 13:41:45 darrenr Exp ";
#endif
-#ifndef linux
-#include <sys/errno.h>
-#include <sys/types.h>
#include <sys/param.h>
+#include <sys/errno.h>
#include <sys/file.h>
-#if defined(__OpenBSD__)
-# include <sys/dirent.h>
-#else
-# include <sys/dir.h>
-#endif
#include <sys/ioctl.h>
-#include <sys/systm.h>
-#include <sys/uio.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
#include <net/if.h>
#ifdef sun
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include <sys/syslog.h>
-#endif
+
#include "ip_fil_compat.h"
#include "ip_fil.h"
#include "ip_frag.h"
extern fr_flags, fr_active;
extern struct protosw inetsw[];
extern int (*fr_checkp) __P((ip_t *, int, struct ifnet *, int,
- struct mbuf **));
+ struct mbuf **));
#if BSD < 199306
extern int ipfr_slowtimer __P((void));
static int (*fr_saveslowtimo) __P((void));
static void (*fr_saveslowtimo) __P((void));
#endif
+static void frzerostats __P((caddr_t));
+
int ipl_inited = 0;
int ipl_unreach = ICMP_UNREACH_FILTER_PROHIB;
+int send_reset __P((struct tcpiphdr *));
#ifdef IPFILTER_LOG
# define LOGSIZE 8192
-static char iplbuf[LOGSIZE];
-static caddr_t iplh = iplbuf, iplt = iplbuf;
+int ipllog __P((u_int, ip_t *, register fr_info_t *, struct mbuf *));
+char iplbuf[LOGSIZE];
+caddr_t iplh = iplbuf, iplt = iplbuf;
static int iplused = 0;
#endif /* IPFILTER_LOG */
-static int iplbusy = 0;
static int (*fr_savep) __P((ip_t *, int, struct ifnet *, int,
- struct mbuf **));
+ struct mbuf **));
+static void frflush __P((caddr_t));
+static int frrequest __P((int, caddr_t, int));
-#if _BSDI_VERSION >= 199510
+#if _BSDI_VERSION >= 199501
# include <sys/device.h>
# include <sys/conf.h>
int iplioctl __P((dev_t, int, caddr_t, int, struct proc *));
-int iplclose __P((dev_t, int, int, struct proc *));
int iplopen __P((dev_t, int, int, struct proc *));
+int iplclose __P((dev_t, int, int, struct proc *));
+# ifdef IPFILTER_LOG
+int iplread __P((dev_t, struct uio *, int));
+# else
+# define iplread noread
+# endif
struct cfdriver iplcd = {
NULL, "ipl", NULL, NULL, DV_DULL, 0
nostrat, nodump, nopsize, 0,
nostop
};
-#else /* _BSDI_VERSION >= 199510 */
+#else /* _BSDI_VERSION >= 199501 */
-# ifndef linux
-# ifdef IPFILTER_LOG
-# if BSD >= 199306
+# ifdef IPFILTER_LOG
+# if BSD >= 199306
int iplread __P((dev_t, struct uio *, int));
-# else
-int iplread __P((dev_t, struct uio *));
-# endif
# else
-# define iplread noread
+int iplread __P((dev_t, struct uio *));
# endif
-int iplclose __P((dev_t, int));
-int iplopen __P((dev_t, int));
-# endif /* linux */
+# else
+# define iplread noread
+# endif
int iplioctl __P((dev_t, int, caddr_t, int));
-
-#endif /* _BSDI_VERSION >= 199510 */
+int iplopen __P((dev_t, int));
+int iplclose __P((dev_t, int));
+#endif /* _BSDI_VERSION >= 199501 */
int iplattach __P((void));
int ipldetach __P((void));
-void frzerostats __P((caddr_t));
-void frflush __P((caddr_t));
-int frrequest __P((int, caddr_t, int));
-
-#ifndef IPFILTER_LKM
-void iplinit __P((void));
-#endif /* !IPFILTER_LKM */
#ifdef IPFILTER_LKM
int iplidentify __P((char *));
int
iplidentify(s)
- char *s;
+ char *s;
{
if (strcmp(s, "ipl") == 0)
return 1;
return 0;
}
+#else
+void iplinit __P((void));
#endif /* IPFILTER_LKM */
+void ipfr_fastroute __P((struct mbuf *, fr_info_t *, frdest_t *));
int
iplattach()
SPLNET(s);
if (ipl_inited || (fr_checkp == fr_check)) {
- printf("ipl: already initialized (%d)\n", iplbusy);
+ printf("IP Filter: already initialized\n");
SPLX(s);
return EBUSY;
}
ipl_inited = 1;
+ bzero((char *)nat_table, sizeof(nat_t *) * NAT_SIZE * 2);
fr_savep = fr_checkp;
fr_checkp = fr_check;
fr_saveslowtimo = inetsw[0].pr_slowtimo;
{
int s, i = FR_INQUE|FR_OUTQUE;
- if (iplbusy > 1) {
- printf("iplbusy: %d\n", iplbusy);
- return EBUSY;
- }
SPLNET(s);
if (!ipl_inited)
{
- printf("ipl: not initialized\n");
+ printf("IP Filter: not initialized\n");
SPLX(s);
return EBUSY;
}
}
-void
+static void
frzerostats(data)
- caddr_t data;
+ caddr_t data;
{
struct friostat fio;
fio.f_acctout[1] = ipacct[1][1];
fio.f_active = fr_active;
IWCOPY((caddr_t)&fio, data, sizeof(fio));
- bzero((char *)frstats, sizeof(*frstats));
+ bzero((char *)frstats, sizeof(*frstats) * 2);
}
-void
+static void
frflush(data)
- caddr_t data;
+ caddr_t data;
{
struct frentry *f, **fp;
int flags = *(int *)data, flushed = 0, set = fr_active;
*/
int
iplioctl(dev, cmd, data, mode
-#if _BSDI_VERSION >= 199510
- , p)
+#if _BSDI_VERSION >= 199501
+ , p)
struct proc *p;
#else
- )
+ )
#endif
- dev_t dev;
- int cmd;
- caddr_t data;
- int mode;
+ dev_t dev;
+ int cmd;
+ caddr_t data;
+ int mode;
{
int error = 0, s, unit;
}
-int
+static int
frrequest(req, data, set)
- int req, set;
- caddr_t data;
+ int req, set;
+ caddr_t data;
{
register frentry_t *fp, *f, **fprev;
register frentry_t **ftail;
*/
int
iplopen(dev, flags
-#if _BSDI_VERSION >= 199510
+#if _BSDI_VERSION >= 199501
, devtype, p)
int devtype;
struct proc *p;
#else
)
#endif
- dev_t dev;
- int flags;
+ dev_t dev;
+ int flags;
{
u_int min = minor(dev);
int
iplclose(dev, flags
-#if _BSDI_VERSION >= 199510
+#if _BSDI_VERSION >= 199501
, devtype, p)
int devtype;
struct proc *p;
#else
)
#endif
- dev_t dev;
- int flags;
+ dev_t dev;
+ int flags;
{
u_int min = minor(dev);
# if BSD >= 199306
int
iplread(dev, uio, ioflag)
- int ioflag;
+ int ioflag;
# else
int
iplread(dev, uio)
# endif
- dev_t dev;
- register struct uio *uio;
+ dev_t dev;
+ register struct uio *uio;
{
register int ret, s;
register size_t sz, sx;
if (!uio->uio_resid)
return 0;
- iplbusy++;
while (!iplused) {
error = SLEEP(iplbuf, "ipl sleep");
- if (error) {
- iplbusy--;
+ if (error)
return error;
- }
}
SPLNET(s);
iplh = iplt = iplbuf;
}
SPLX(s);
- iplbusy--;
return ret;
}
# endif /* IPFILTER_LOG */
#ifdef IPFILTER_LOG
int
ipllog(flags, ip, fin, m)
- u_int flags;
- ip_t *ip;
- register fr_info_t *fin;
- struct mbuf *m;
+ u_int flags;
+ ip_t *ip;
+ register fr_info_t *fin;
+ struct mbuf *m;
{
struct ipl_ci iplci;
- register size_t tail = 0;
register int len, mlen, hlen;
struct ifnet *ifp = fin->fin_ifp;
}
}
- mlen = (flags & FR_LOGBODY) ? (MIN(m->m_len, 128) & 0xfa) : 0;
+ mlen = (flags & FR_LOGBODY) ? MIN(ip->ip_len - hlen, 128) : 0;
len = hlen + sizeof(iplci) + mlen;
if (iplused + len > LOGSIZE)
return 0;
# endif
iplci.flags = flags;
iplci.hlen = (u_char)hlen;
- iplci.plen = (flags & FR_LOGBODY) ? (u_char)mlen : 0 ;
+ iplci.plen = (u_char)mlen;
iplci.rule = fin->fin_rule;
-# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
- (defined(OpenBSD) && (OpenBSD >= 199606))
- strcpy(iplci.ifname, ifp->if_xname);
+# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
+ (defined(OpenBSD) && (OpenBSD >= 199603))
+ strncpy(iplci.ifname, ifp->if_xname, IFNAMSIZ);
# else
iplci.unit = (u_char)ifp->if_unit;
if ((iplci.ifname[0] = ifp->if_name[0]))
if ((iplci.ifname[2] = ifp->if_name[2]))
iplci.ifname[3] = ifp->if_name[3];
# endif
- if (iplh == iplbuf + LOGSIZE)
- iplh = iplbuf;
- tail = (iplh >= iplt) ? (iplbuf + LOGSIZE - iplh) : (iplt - iplh);
-
- len = MIN(tail, sizeof(iplci));
-
- /*
- * check in both cases where we add stuff to the buffer to see if we
- * are going to wrap around at the end.
- */
- bcopy((char *)&iplci, iplh, len);
- iplh += len;
- if (len < sizeof(iplci)) {
- bcopy((char *)&iplci + len, iplbuf, sizeof(iplci) - len);
- iplh = iplbuf + sizeof(iplci) - len;
- tail = iplt - iplh;
- } else
- tail -= len;
-
- len = MIN(tail, hlen);
- bcopy((char *)ip, iplh, len);
- iplh += len;
- if (len < hlen) {
- iplh = iplbuf;
- bcopy((char *)ip + len, iplh, hlen - len);
- iplh += hlen - len;
- tail = iplt - iplh;
- } else
- tail -= len;
-
- if (mlen) {
- len = MIN(tail, mlen);
-#if BSD < 199103
- bcopy((char *)m->m_un.mun_dat, iplh, len);
-#else
- bcopy((char *)m->M_dat.M_databuf, iplh, len);
-#endif
- iplh += len;
- if (len < mlen) {
- iplh = iplbuf;
-#if BSD < 199103
- bcopy((char *)m->m_un.mun_dat + len, iplh,
- mlen - len);
-#else
- bcopy((char *)m->M_dat.M_databuf + len, iplh,
- mlen - len);
-#endif
- iplh += mlen - len;
- }
+ /*
+ * Guaranteed to succeed from above
+ */
+ (void) fr_copytolog((char *)&iplci, sizeof(iplci));
+
+ for (len -= sizeof(iplci); m && len > 0; m = m->m_next, len -= hlen) {
+ hlen = MIN(len, m->m_len);
+ if (fr_copytolog(mtod(m, char *), hlen))
+ break;
}
+
wakeup(iplbuf);
return 1;
}
*/
int
send_reset(ti)
- struct tcpiphdr *ti;
+ struct tcpiphdr *ti;
{
struct tcpiphdr *tp;
struct ip *ip;
void
iplinit()
{
- /* (void) iplattach(); */
+ (void) iplattach();
ip_init();
+ (void) ipldetach(); /* XXX */
}
#endif
void
ipfr_fastroute(m0, fin, fdp)
- struct mbuf *m0;
- fr_info_t *fin;
- frdest_t *fdp;
+ struct mbuf *m0;
+ fr_info_t *fin;
+ frdest_t *fdp;
{
register struct ip *ip, *mhip;
register struct mbuf *m = m0;
dst = (struct sockaddr_in *)&ro->ro_dst;
dst->sin_family = AF_INET;
dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst;
-#if BSD >= 199306 && !(defined(__NetBSD__) || defined(__OpenBSD__))
+#if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) \
+ && !defined(__OpenBSD__)
# ifdef RTF_CLONING
rtalloc_ign(ro, RTF_CLONING);
# else
}
ro->ro_rt->rt_use++;
- /*
+ /*
+ * For input packets which are being "fastrouted", they won't
+ * go back through output filtering and miss their chance to get
+ * NAT'd.
+ */
+ (void) ip_natout(ip, hlen, fin);
+ if (fin->fin_out)
+ ip->ip_sum = 0;
+ /*
* If small enough for interface, can just send directly.
*/
if (ip->ip_len <= ifp->if_mtu) {
+/* $OpenBSD: ip_fil.h,v 1.8 1997/02/11 22:23:16 kstailey Exp $ */
/*
* (C)opyright 1993-1996 by Darren Reed.
*
* to the original author and the contributors.
*
* @(#)ip_fil.h 1.35 6/5/96
- * $OpenBSD: ip_fil.h,v 1.7 1997/02/05 00:53:12 kstailey Exp $
+ * Id: ip_fil.h,v 2.0.1.2 1997/01/10 00:28:15 darrenr Exp
*/
#ifndef __IP_FIL_H__
#define __IP_FIL_H__
-#ifdef _KERNEL
-#define IPFILTER_LOG
-#endif /* _KERNEL */
-
#ifndef SOLARIS
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
#endif
#define SIOCFRENB _IOW('r', 72, u_int)
#define SIOCFRSYN _IOW('r', 73, u_int)
#define SIOCFRZST _IOWR('r', 74, struct friostat)
-#define SIOCFLNAT _IOWR('r', 75, int)
-#define SIOCCNATL _IOWR('r', 76, int)
-#define SIOCZRLST _IOWR('r', 77, struct frentry)
+#define SIOCZRLST _IOWR('r', 75, struct frentry)
#else
#define SIOCADAFR _IOW(r, 60, struct frentry)
#define SIOCRMAFR _IOW(r, 61, struct frentry)
#define SIOCFRENB _IOW(r, 72, u_int)
#define SIOCFRSYN _IOW(r, 73, u_int)
#define SIOCFRZST _IOWR(r, 74, struct friostat)
-#define SIOCFLNAT _IOWR(r, 75, int)
-#define SIOCCNATL _IOWR(r, 76, int)
-#define SIOCZRLST _IOWR(r, 77, struct frentry)
+#define SIOCZRLST _IOWR(r, 75, struct frentry)
#endif
#define SIOCADDFR SIOCADAFR
#define SIOCDELFR SIOCRMAFR
#define SIOCINSFR SIOCINAFR
typedef struct fr_ip {
- u_char fi_v:4;
- u_char fi_fl:4;
+ u_char fi_v:4; /* IP version */
+ u_char fi_fl:4; /* packet flags */
u_char fi_tos;
u_char fi_ttl;
u_char fi_p;
struct in_addr fi_src;
struct in_addr fi_dst;
- u_long fi_optmsk;
- u_short fi_secmsk;
+ u_long fi_optmsk; /* bitmask composed from IP options */
+ u_short fi_secmsk; /* bitmask composed from IP security options */
u_short fi_auth;
} fr_ip_t;
u_short fin_rule;
u_short fin_hlen;
u_short fin_dlen;
- char *fin_dp;
+ char *fin_dp; /* start of data past IP header */
struct frentry *fin_fr;
} fr_info_t;
struct ifnet *fr_ifa;
u_long fr_hits;
u_long fr_bytes; /* this is only incremented when a packet */
- /* stops matching on this rule */
+ /* matches this rule and it is the last match*/
/*
* Fields after this may not change whilst in the kernel.
*/
struct fr_ip fr_ip;
- struct fr_ip fr_mip;
+ struct fr_ip fr_mip; /* mask structure */
u_char fr_tcpfm; /* tcp flags mask */
u_char fr_tcpf; /* tcp flags */
#define FR_LOGB 0x00011 /* Log-fail */
#define FR_LOGP 0x00012 /* Log-pass */
#define FR_LOGBODY 0x00020 /* Log the body */
-#define FR_LOGFIRST 0x00040
-#define FR_RETRST 0x00080
-#define FR_RETICMP 0x00100
+#define FR_LOGFIRST 0x00040 /* Log the first byte if state held */
+#define FR_RETRST 0x00080 /* Return TCP RST packet - reset connection */
+#define FR_RETICMP 0x00100 /* Return ICMP unreachable packet */
#define FR_NOMATCH 0x00200
#define FR_ACCOUNT 0x00400 /* count packet bytes */
-#define FR_KEEPFRAG 0x00800
-#define FR_KEEPSTATE 0x01000
+#define FR_KEEPFRAG 0x00800 /* keep fragment information */
+#define FR_KEEPSTATE 0x01000 /* keep `connection' state information */
#define FR_INACTIVE 0x02000
-#define FR_QUICK 0x04000
-#define FR_FASTROUTE 0x08000
-#define FR_CALLNOW 0x10000
-#define FR_DUP 0x20000
+#define FR_QUICK 0x04000 /* match & stop processing list */
+#define FR_FASTROUTE 0x08000 /* bypass normal routing */
+#define FR_CALLNOW 0x10000 /* call another function (fr_func) if matches */
+#define FR_DUP 0x20000 /* duplicate packet */
+#define FR_LOGORBLOCK 0x40000 /* block the packet if it can't be logged */
#define FR_LOGMASK (FR_LOG|FR_LOGP|FR_LOGB)
/*
#define FF_LOGBLOCK 0x200000
#define FF_LOGNOMATCH 0x400000
#define FF_LOGGING (FF_LOGPASS|FF_LOGBLOCK|FF_LOGNOMATCH)
+#define FF_BLOCKNONIP 0x800000 /* Solaris2 Only */
#define FR_NONE 0
#define FR_EQUAL 1
u_long fr_bads; /* bad attempts to allocate packet state */
u_long fr_ads; /* new packet state kept */
u_long fr_chit; /* cached hit */
+ u_long fr_pull[2]; /* good and bad pullup attempts */
#if SOLARIS
u_long fr_bad; /* bad IP packets to the filter */
u_long fr_notip; /* packets passed through no on ip queue */
int ol_bit;
} optlist_t;
+/*
+ * Log structure. Each packet header logged is prepended by one of these,
+ * minimize size to make most effective use of log space which should
+ * (ideally) be a muliple of the most common log entry size.
+ */
typedef struct ipl_ci {
u_long sec;
u_long usec;
u_char hlen;
u_char plen;
- u_short rule;
- u_long flags:24; /* XXX FIXME do we care about the extra bytes? */
-#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
- (defined(OpenBSD) && (OpenBSD >= 199606))
- u_long filler:8; /* XXX FIXME do we care? */
- u_char ifname[IFNAMSIZ];
+ u_short rule; /* assume never more than 64k rules, total */
+#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
+ (defined(OpenBSD) && (OpenBSD >= 199603))
+ u_long flags;
+ u_char ifname[IFNAMSIZ]; /* = 32 bytes */
#else
+ u_long flags:24;
u_long unit:8;
- u_char ifname[4];
+ u_char ifname[4]; /* = 20 bytes */
#endif
} ipl_ci_t;
#ifndef ICMP_UNREACH_FILTER_PROHIB
#define ICMP_UNREACH_FILTER_PROHIB 13
#endif
-/*
- * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108.
- *
- * Basic Option
- *
- * 00000001 - (Reserved 4)
- * 00111101 - Top Secret
- * 01011010 - Secret
- * 10010110 - Confidential
- * 01100110 - (Reserved 3)
- * 11001100 - (Reserved 2)
- * 10101011 - Unclassified
- * 11110001 - (Reserved 1)
- */
-#define IPSO_CLASS_RES4 0x01
-#define IPSO_CLASS_TOPS 0x3d
-#define IPSO_CLASS_SECR 0x5a
-#define IPSO_CLASS_CONF 0x96
-#define IPSO_CLASS_RES3 0x66
-#define IPSO_CLASS_RES2 0xcc
-#define IPSO_CLASS_UNCL 0xab
-#define IPSO_CLASS_RES1 0xf1
-
-#define IPSO_AUTH_GENSER 0x80
-#define IPSO_AUTH_ESI 0x40
-#define IPSO_AUTH_SCI 0x20
-#define IPSO_AUTH_NSA 0x10
-#define IPSO_AUTH_DOE 0x08
-#define IPSO_AUTH_UN 0x06
-#define IPSO_AUTH_FTE 0x01
-
-/*#define IPOPT_RR 7 */
-#define IPOPT_ZSU 10 /* ZSU */
-#define IPOPT_MTUP 11 /* MTUP */
-#define IPOPT_MTUR 12 /* MTUR */
-#define IPOPT_ENCODE 15 /* ENCODE */
-/*#define IPOPT_TS 68 */
-#define IPOPT_TR 82 /* TR */
-/*#define IPOPT_SECURITY 130 */
-/*#define IPOPT_LSRR 131 */
-#define IPOPT_E_SEC 133 /* E-SEC */
-#define IPOPT_CIPSO 134 /* CIPSO */
-/*#define IPOPT_SATID 136 */
-#ifndef IPOPT_SID
-# define IPOPT_SID IPOPT_SATID
-#endif
-/*#define IPOPT_SSRR 137 */
-#define IPOPT_ADDEXT 147 /* ADDEXT */
-#define IPOPT_VISA 142 /* VISA */
-#define IPOPT_IMITD 144 /* IMITD */
-#define IPOPT_EIP 145 /* EIP */
-#define IPOPT_FINN 205 /* FINN */
#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
+#define IPLLOGSIZE 8192
+#ifdef _KERNEL
+extern int fr_check __P((ip_t *, int, struct ifnet *, int,
+ struct mbuf **));
+#else
+extern int fr_check __P((ip_t *, int, struct ifnet *, int));
+#endif
+extern int fr_copytolog(char *, int);
extern fr_info_t frcache[];
+extern char *iplh, *iplt;
+extern char iplbuf[IPLLOGSIZE];
#ifdef _KERNEL
extern struct frentry *ipfilter[2][2], *ipacct[2][2];
extern struct filterstats frstats[];
-
-#ifdef IPFILTER_LOG
-extern int ipllog __P((u_int, ip_t *, fr_info_t *, struct mbuf *));
-#endif
-extern int send_reset __P((struct tcpiphdr *));
-extern void ipfr_fastroute __P((struct mbuf *, fr_info_t *, frdest_t *));
# if SOLARIS
-extern int fr_check();
extern int ipfsync();
-# else /* SOLARIS */
-extern int fr_check __P((ip_t *, int, struct ifnet *, int,
- struct mbuf **));
-# endif /* SOLARIS */
-#else /* _KERNEL */
-extern int fr_check __P((ip_t *, int, struct ifnet *, int));
+# endif
#endif /* _KERNEL */
#endif /* __IP_FIL_H__ */
+/* $OpenBSD: ip_fil_compat.h,v 1.3 1997/02/11 22:23:18 kstailey Exp $ */
/*
* (C)opyright 1993, 1994, 1995 by Darren Reed.
*
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*
- * @(#)ip_fil_compat.h 1.8 1/14/96
- * $OpenBSD: ip_fil_compat.h,v 1.2 1996/10/08 07:33:26 niklas Exp $
+ * @(#)ip_compat.h 1.8 1/14/96
+ * Id: ip_compat.h,v 2.0.1.4 1997/02/04 14:24:25 darrenr Exp
*/
-#ifndef __IP_COMPAT_H_
-#define __IP_COMPAT_H__
+#ifndef __IP_FIL_COMPAT_H_
+#define __IP_FIL_COMPAT_H__
+
+#ifdef _KERNEL /* XXX */
+#define IPFILTER_LOG
+#endif /* _KERNEL */
#ifndef SOLARIS
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
#endif
+#if SOLARIS
+#define MTYPE(m) ((m)->b_datap->db_type)
+#endif
#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
#ifndef IP_OFFMASK
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
+/*
+ * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108.
+ *
+ * Basic Option
+ *
+ * 00000001 - (Reserved 4)
+ * 00111101 - Top Secret
+ * 01011010 - Secret
+ * 10010110 - Confidential
+ * 01100110 - (Reserved 3)
+ * 11001100 - (Reserved 2)
+ * 10101011 - Unclassified
+ * 11110001 - (Reserved 1)
+ */
+#define IPSO_CLASS_RES4 0x01
+#define IPSO_CLASS_TOPS 0x3d
+#define IPSO_CLASS_SECR 0x5a
+#define IPSO_CLASS_CONF 0x96
+#define IPSO_CLASS_RES3 0x66
+#define IPSO_CLASS_RES2 0xcc
+#define IPSO_CLASS_UNCL 0xab
+#define IPSO_CLASS_RES1 0xf1
+
+#define IPSO_AUTH_GENSER 0x80
+#define IPSO_AUTH_ESI 0x40
+#define IPSO_AUTH_SCI 0x20
+#define IPSO_AUTH_NSA 0x10
+#define IPSO_AUTH_DOE 0x08
+#define IPSO_AUTH_UN 0x06
+#define IPSO_AUTH_FTE 0x01
+
+/*
+ * IP option #defines
+ */
+/*#define IPOPT_RR 7 */
+#define IPOPT_ZSU 10 /* ZSU */
+#define IPOPT_MTUP 11 /* MTUP */
+#define IPOPT_MTUR 12 /* MTUR */
+#define IPOPT_ENCODE 15 /* ENCODE */
+/*#define IPOPT_TS 68 */
+#define IPOPT_TR 82 /* TR */
+/*#define IPOPT_SECURITY 130 */
+/*#define IPOPT_LSRR 131 */
+#define IPOPT_E_SEC 133 /* E-SEC */
+#define IPOPT_CIPSO 134 /* CIPSO */
+/*#define IPOPT_SATID 136 */
+#ifndef IPOPT_SID
+# define IPOPT_SID IPOPT_SATID
+#endif
+/*#define IPOPT_SSRR 137 */
+#define IPOPT_ADDEXT 147 /* ADDEXT */
+#define IPOPT_VISA 142 /* VISA */
+#define IPOPT_IMITD 144 /* IMITD */
+#define IPOPT_EIP 145 /* EIP */
+#define IPOPT_FINN 205 /* FINN */
+
+
+/*
+ * Build some macros and #defines to enable the same code to compile anywhere
+ * Well, that's the idea, anyway :-)
+ */
#ifdef _KERNEL
# if SOLARIS
# define MUTEX_ENTER(x) mutex_enter(x)
queue_t *qf_out;
void *qf_wqinfo;
void *qf_rqinfo;
- char qf_name[8];
int (*qf_inp)();
int (*qf_outp)();
+ mblk_t *qf_m;
+ int qf_len;
+ char qf_name[8];
/*
* in case the ILL has disappeared...
*/
# define htons(x) (x)
# define htonl(x) (x)
# endif
-# define KMALLOC(x) kmem_alloc((x), KM_SLEEP)
+# define KMALLOC(x) kmem_alloc((x), KM_NOSLEEP)
# define GET_MINOR(x) getminor(x)
# else
-# define KMALLOC(x) new_kmem_alloc((x), KMEM_SLEEP)
+# define KMALLOC(x) new_kmem_alloc((x), KMEM_NOSLEEP)
# endif /* __svr4__ */
# endif /* sun && !linux */
# ifndef GET_MINOR
# else
# include <vm/vm_kern.h>
# endif /* __FreeBSD__ */
-# define KMALLOC(x) kmem_alloc(kmem_map, (x))
-# define KFREE(x) kmem_free(kmem_map, (vm_offset_t)(x), \
+/*
+** # define KMALLOC(x) kmem_alloc(kmem_map, (x))
+** # define KFREE(x) kmem_free(kmem_map, (vm_offset_t)(x), \
sizeof(*(x)))
+*/
+# ifdef M_PFIL
+# define KMALLOC(x) malloc((x), M_PFIL, M_NOWAIT)
+# define KFREE(x) FREE((x), M_PFIL)
+# else
+# define KMALLOC(x) malloc((x), M_TEMP, M_NOWAIT)
+# define KFREE(x) FREE((x), M_TEMP)
+# endif
# define UIOMOVE(a,b,c,d) uiomove(a,b,d)
# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0)
# endif /* BSD */
# endif
# endif
#else
-# define MUTEX_ENTER(x) ;
-# define MUTEX_EXIT(x) ;
-# define SPLNET(x) ;
-# define SPLX(x) ;
-# define KMALLOC(x) malloc(x)
-# define KFREE(x) free(x)
-# define GETUNIT(x) (x)
-# define IRCOPY(a,b,c) bcopy((a), (b), (c))
-# define IWCOPY(a,b,c) bcopy((a), (b), (c))
+# ifndef linux
+# define MUTEX_ENTER(x) ;
+# define MUTEX_EXIT(x) ;
+# define SPLNET(x) ;
+# define SPLX(x) ;
+# define KMALLOC(x) malloc(x)
+# define KFREE(x) free(x)
+# define GETUNIT(x) (x)
+# define IRCOPY(a,b,c) bcopy((a), (b), (c))
+# define IWCOPY(a,b,c) bcopy((a), (b), (c))
+# endif
#endif /* KERNEL */
#ifdef linux
# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH
# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED
# define ICMP_PARAMPROB ICMP_PARAMETERPROB
-# define icmp icmphdr
-# define icmp_type type
-# define icmp_code code
# define TH_FIN 0x01
# define TH_SYN 0x02
__u8 ip_ttl;
__u8 ip_p;
__u16 ip_sum;
- __u32 ip_src;
- __u32 ip_dst;
+ struct in_addr ip_src;
+ struct in_addr ip_dst;
} ip_t;
+/*
+ * Structure of an icmp header.
+ */
+struct icmp {
+ u_char icmp_type; /* type of message, see below */
+ u_char icmp_code; /* type sub code */
+ u_short icmp_cksum; /* ones complement cksum of struct */
+ union {
+ u_char ih_pptr; /* ICMP_PARAMPROB */
+ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
+ struct ih_idseq {
+ n_short icd_id;
+ n_short icd_seq;
+ } ih_idseq;
+ int ih_void;
+ } icmp_hun;
+# define icmp_pptr icmp_hun.ih_pptr
+# define icmp_gwaddr icmp_hun.ih_gwaddr
+# define icmp_id icmp_hun.ih_idseq.icd_id
+# define icmp_seq icmp_hun.ih_idseq.icd_seq
+# define icmp_void icmp_hun.ih_void
+ union {
+ struct id_ts {
+ n_time its_otime;
+ n_time its_rtime;
+ n_time its_ttime;
+ } id_ts;
+ struct id_ip {
+ ip_t idi_ip;
+ /* options and then 64 bits of data */
+ } id_ip;
+ u_long id_mask;
+ char id_data[1];
+ } icmp_dun;
+# define icmp_otime icmp_dun.id_ts.its_otime
+# define icmp_rtime icmp_dun.id_ts.its_rtime
+# define icmp_ttime icmp_dun.id_ts.its_ttime
+# define icmp_ip icmp_dun.id_ip.idi_ip
+# define icmp_mask icmp_dun.id_mask
+# define icmp_data icmp_dun.id_data
+};
+
+struct ipovly {
+ caddr_t ih_next, ih_prev; /* for protocol sequence q's */
+ u_char ih_x1; /* (unused) */
+ u_char ih_pr; /* protocol */
+ short ih_len; /* protocol length */
+ struct in_addr ih_src; /* source internet address */
+ struct in_addr ih_dst; /* destination internet address */
+};
+
# define SPLX(x) (void)
# define SPLNET(x) (void)
#else
typedef struct tcphdr tcphdr_t;
typedef struct udphdr udphdr_t;
+typedef struct icmp icmphdr_t;
typedef struct ip ip_t;
#endif /* linux */
-#endif /* __IP_COMPAT_H__ */
+#endif /* __IP__FIL_COMPAT_H__ */
+/* $OpenBSD: ip_frag.c,v 1.7 1997/02/11 22:23:20 kstailey Exp $ */
/*
* (C)opyright 1993,1994,1995 by Darren Reed.
*
* to the original author and the contributors.
*/
#if 0
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed";
-static char rcsid[] = "$OpenBSD: ip_frag.c,v 1.6 1997/01/18 08:29:20 downsj Exp $";
+static char rcsid[] = "Id: ip_frag.c,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp";
#endif
#endif
#endif
#include <sys/errno.h>
#include <sys/types.h>
-#if defined(_KERNEL) || defined(KERNEL)
-#include <sys/systm.h>
-#endif
#include <sys/param.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/protosw.h>
#include <sys/socket.h>
+#ifdef _KERNEL
+# include <sys/systm.h>
+#endif
#if !defined(__SVR4) && !defined(__svr4__)
-# if defined(__OpenBSD__)
-# include <sys/dirent.h>
-# else
-# include <sys/dir.h>
-# endif
# include <sys/mbuf.h>
#else
# include <sys/byteorder.h>
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include <sys/syslog.h>
#include "ip_fil_compat.h"
#include "ip_fil.h"
#include "ip_frag.h"
ipfr_t *ipfr_heads[IPFT_SIZE];
ipfrstat_t ipfr_stats;
u_long ipfr_inuse = 0;
+u_long fr_ipfrttl = 120; /* 60 seconds */
#ifdef _KERNEL
extern int ipfr_timer_id;
#endif
fr->ipfr_prev = NULL;
ipfr_heads[idx] = fr;
bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ);
- fr->ipfr_ttl = 120; /* 60 seconds */
+ fr->ipfr_ttl = fr_ipfrttl;
fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG);
fr->ipfr_off = (ip->ip_off & 0x1fff) + (fin->fin_dlen >> 3);
*fp = fr;
for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
for (fp = &ipfr_heads[idx]; (fr = *fp); ) {
*fp = fr->ipfr_next;
- KFREE(fp);
+ KFREE(fr);
}
SPLX(s);
MUTEX_EXIT(&ipf_frag);
*/
# if BSD < 199306
int
-#else
+# else
void
-#endif
+# endif
ipfr_slowtimer()
{
ipfr_t **fp, *fr;
*fp = fr->ipfr_next;
ipfr_stats.ifs_expire++;
ipfr_inuse--;
- KFREE(fp);
+ KFREE(fr);
} else
fp = &fr->ipfr_next;
}
SPLX(s);
-#if SOLARIS
+# if SOLARIS
MUTEX_EXIT(&ipf_frag);
fr_timeoutstate();
ip_natexpire();
ipfr_timer_id = timeout(ipfr_slowtimer, NULL, HZ/2);
-#else
+# else
fr_timeoutstate();
ip_natexpire();
ip_slowtimo();
-#endif
-# if BSD < 199306
+# if BSD < 199306
return 0;
+# endif
# endif
}
#endif /* defined(_KERNEL) */
+/* $OpenBSD: ip_frag.h,v 1.5 1997/02/11 22:23:22 kstailey Exp $ */
/*
* (C)opyright 1993, 1994, 1995 by Darren Reed.
*
* to the original author and the contributors.
*
* @(#)ip_frag.h 1.5 3/24/96
- * $OpenBSD: ip_frag.h,v 1.4 1996/10/08 07:33:27 niklas Exp $
+ * Id: ip_frag.h,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp
*/
#ifndef __IP_FRAG_H_
-/* $OpenBSD: ip_icmp.c,v 1.5 1996/05/09 14:33:32 mickey Exp $ */
+/* $OpenBSD: ip_icmp.c,v 1.6 1997/02/11 22:23:23 kstailey Exp $ */
/* $NetBSD: ip_icmp.c,v 1.19 1996/02/13 23:42:22 christos Exp $ */
/*
case ICMP_UNREACH_ISOLATED:
case ICMP_UNREACH_HOST_PROHIB:
case ICMP_UNREACH_TOSHOST:
+ case ICMP_UNREACH_FILTER_PROHIB:
+ case ICMP_UNREACH_HOST_PRECEDENCE:
+ case ICMP_UNREACH_PRECEDENCE_CUTOFF:
code = PRC_UNREACH_HOST;
break;
+/* $OpenBSD: ip_nat.c,v 1.8 1997/02/11 22:23:25 kstailey Exp $ */
/*
- * (C)opyright 1995 by Darren Reed.
+ * (C)opyright 1995-1996 by Darren Reed.
*
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*
- * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com)
- *
- * Things still screwed:
- * 1) You can't specify a mapping to a class D address. By default, it
- * always adds 1 to that address. As a result, when a packet comes back,
- * the rule won't be matched. (e.g. outgoing address = 199.165.219.2,
- * whereas the rule says outgoing address = 199.165.219.1/32. Because
- * ADNATS always adds one, and there really isn't any provision for
- * only using 1 address (the in_space stuff is broke), there isn't any
- * easy solution)
- * 2) There needs to be a way to flush the NATs table completely. Either
- * an ioctl, or an easy way of doing it from ipnat.c.
- *
- * Missing from RFC 1631: ICMP header checksum recalculations.
+ * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com)
*
*/
#if 0
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
-static char rcsid[] = "$OpenBSD: ip_nat.c,v 1.7 1997/01/18 08:29:21 downsj Exp $";
+static char rcsid[] = "Id: ip_nat.c,v 2.0.1.10 1997/02/08 06:38:49 darrenr Exp";
#endif
#endif
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
-#if defined(_KERNEL) || defined(KERNEL)
-#include <sys/systm.h>
-#endif
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/protosw.h>
#include <sys/socket.h>
+#ifdef _KERNEL
+# include <sys/systm.h>
+#endif
#if !defined(__SVR4) && !defined(__svr4__)
-# if defined(__OpenBSD__)
-# include <sys/dirent.h>
-# else
-# include <sys/dir.h>
-# endif
# include <sys/mbuf.h>
#else
# include <sys/byteorder.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
+
+#ifdef RFC1825
+#include <vpn/md5.h>
+#include <vpn/ipsec.h>
+extern struct ifnet vpnif;
+#endif
+
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include <sys/syslog.h>
#include "ip_fil_compat.h"
#include "ip_fil.h"
#include "ip_nat.h"
+#include "ip_state.h"
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
-nat_t *nat_table[2][NAT_SIZE];
+nat_t *nat_table[2][NAT_SIZE], *nat_instances = NULL;
ipnat_t *nat_list = NULL;
-u_long nat_inuse = 0;
+u_long nat_inuse = 0,
+ fr_defnatage = 1200;
natstat_t nat_stats;
#if SOLARIS
# ifndef _KERNEL
+#define bzero(a,b) memset(a,0,b)
#define bcmp(a,b,c) memcpy(a,b,c)
#define bcopy(a,b,c) memmove(b,a,c)
# else
# endif
#endif
-int flush_nattable __P((void));
-int clear_natlist __P((void));
-nat_t *nat_new __P((ipnat_t *, ip_t *, int, u_short, int));
+static int flush_nattable __P((void)), clear_natlist __P((void));
+static void nattable_sync __P((void)), nat_delete __P((struct nat *));
+void fix_incksum __P((u_short *, u_long));
+void fix_outcksum __P((u_short *, u_long));
+nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_short, int));
+nat_t *nat_lookupmapip __P((register int, struct in_addr, u_short,
+ struct in_addr, u_short));
+
+void
+fix_outcksum(sp, n)
+ u_short *sp;
+ u_long n;
+{
+ register u_short sumshort;
+ register u_long sum1;
+
+#ifdef sparc
+ sum1 = (~(*sp)) & 0xffff;
+#else
+ sum1 = (~ntohs(*sp)) & 0xffff;
+#endif
+ sum1 += (n);
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ /* Again */
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ sumshort = ~(u_short)sum1;
+ *(sp) = htons(sumshort);
+}
+
+
+void
+fix_incksum(sp, n)
+ u_short *sp;
+ u_long n;
+{
+ register u_short sumshort;
+ register u_long sum1;
+
+#ifdef sparc
+ sum1 = (~(*sp)) & 0xffff;
+#else
+ sum1 = (~ntohs(*sp)) & 0xffff;
+#endif
+ sum1 += ~(n) & 0xffff;
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ /* Again */
+ sum1 = (sum1 >> 16) + (sum1 & 0xffff);
+ sumshort = ~(u_short)sum1;
+ *(sp) = htons(sumshort);
+}
+
/*
* How the NAT is organised and works.
caddr_t data;
int cmd, mode;
{
- register ipnat_t *nat, *n, **np;
+ register ipnat_t *nat, *n = NULL, **np = NULL;
ipnat_t natd;
int error = 0, ret;
*/
MUTEX_ENTER(&ipf_nat);
if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
- IRCOPY(data, &natd, sizeof(natd));
+ IRCOPY(data, (char *)&natd, sizeof(natd));
nat = &natd;
for (np = &nat_list; (n = *np); np = &n->in_next)
- if (!bcmp((char *)&nat->in_port, (char *)&n->in_port,
+ if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
IPN_CMPSIZ))
break;
}
IRCOPY((char *)data, (char *)n, sizeof(*n));
n->in_ifp = (void *)GETUNIT(n->in_ifname);
n->in_next = *np;
+ n->in_use = 0;
n->in_space = ~(0xffffffff & ntohl(n->in_outmsk));
- n->in_space -= 2; /* lose 2: broadcast + network address */
- if (n->in_inmsk != 0xffffffff)
+ if (n->in_space) /* lose 2: broadcast + network address */
+ n->in_space -= 2;
+ else
+ n->in_space = 1; /* single IP# mapping */
+ if (n->in_outmsk != 0xffffffff)
n->in_nip = ntohl(n->in_outip) + 1;
else
n->in_nip = ntohl(n->in_outip);
- if (n->in_redir == NAT_MAP)
+ if (n->in_redir == NAT_MAP) {
n->in_pnext = ntohs(n->in_pmin);
+ /*
+ * Multiply by the number of ports made available.
+ */
+ if (ntohs(n->in_pmax) > ntohs(n->in_pmin))
+ n->in_space *= (ntohs(n->in_pmax) -
+ ntohs(n->in_pmin));
+ }
/* Otherwise, these fields are preset */
*np = n;
break;
break;
}
*np = n->in_next;
+
KFREE(n);
+ nattable_sync();
break;
case SIOCGNATS :
- nat_stats.ns_table = (nat_t ***)nat_table;
+ nat_stats.ns_table[0] = nat_table[0];
+ nat_stats.ns_table[1] = nat_table[1];
nat_stats.ns_list = nat_list;
nat_stats.ns_inuse = nat_inuse;
IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats));
case SIOCGNATL :
{
natlookup_t nl;
- nat_t *na;
IRCOPY((char *)data, (char *)&nl, sizeof(nl));
- if ((na = nat_lookupredir(&nl))) {
- nl.nl_inip = na->nat_outip;
- nl.nl_inport = na->nat_outport;
+
+ if (nat_lookupredir(&nl))
IWCOPY((char *)&nl, (char *)data, sizeof(nl));
- } else
+ else
error = ESRCH;
break;
}
}
+static void
+nat_delete(natd)
+ struct nat *natd;
+{
+ register struct nat **natp, *nat;
+
+ for (natp = natd->nat_hstart[0]; (nat = *natp);
+ natp = &nat->nat_hnext[0])
+ if (nat == natd) {
+ *natp = nat->nat_hnext[0];
+ break;
+ }
+
+ for (natp = natd->nat_hstart[1]; (nat = *natp);
+ natp = &nat->nat_hnext[1])
+ if (nat == natd) {
+ *natp = nat->nat_hnext[1];
+ break;
+ }
+
+ if (natd->nat_ptr) {
+ natd->nat_ptr->in_space++;
+ natd->nat_ptr->in_use--;
+ }
+ KFREE(natd);
+ nat_inuse--;
+}
+
+
/*
* flush_nattable - clear the NAT table of all mapping entries.
*/
-int
+static int
flush_nattable()
{
- nat_t *nat, **natp;
- int i, j = 0;
+ register nat_t *nat, **natp;
+ register int j = 0;
+
+ /*
+ * Everything will be deleted, so lets just make it the deletions
+ * quicker.
+ */
+ bzero((char *)nat_table[0], sizeof(nat_table[0]));
+ bzero((char *)nat_table[1], sizeof(nat_table[1]));
- for (natp = &nat_table[0][0], i = NAT_SIZE - 1; i >= 0; i--, natp++)
- while ((nat = *natp)) {
- *natp = nat->nat_next;
- KFREE((caddr_t)nat);
- j++;
- }
+ for (natp = &nat_instances; (nat = *natp); ) {
+ *natp = nat->nat_next;
+ nat_delete(nat);
+ j++;
+ }
- for (natp = &nat_table[1][0], i = NAT_SIZE - 1; i >= 0; i--, natp++)
- while ((nat = *natp)) {
- *natp = nat->nat_next;
- KFREE((caddr_t)nat);
- j++;
- }
return j;
}
+/*
+ * I know this is O(N*M), but it can't be avoided.
+ */
+static void
+nattable_sync()
+{
+ register nat_t *nat;
+ register ipnat_t *np;
+ int i;
+
+ for (i = NAT_SIZE - 1; i >= 0; i--)
+ for (nat = nat_instances; nat; nat = nat->nat_next) {
+ for (np = nat_list; np; np = np->in_next)
+ if (nat->nat_ptr == np)
+ break;
+ /*
+ * XXX - is it better to remove this if ? works the
+ * same if it is just "nat->nat_ptr = np".
+ */
+ if (!np)
+ nat->nat_ptr = NULL;
+ }
+}
+
+
/*
* clear_natlist - delete all entries in the active NAT mapping list.
*/
-int
+static int
clear_natlist()
{
register ipnat_t *n, **np;
*np = n->in_next;
KFREE(n);
}
+
+ nattable_sync();
return i;
}
* Create a new NAT table entry.
*/
nat_t *
-nat_new(np, ip, hlen, flags, direction)
+nat_new(np, ip, fin, flags, direction)
ipnat_t *np;
ip_t *ip;
- int hlen;
+ fr_info_t *fin;
u_short flags;
int direction;
{
register u_long sum1, sum2, sumd;
u_short port = 0, sport = 0, dport = 0, nport = 0;
struct in_addr in;
- tcphdr_t *tcp;
+ tcphdr_t *tcp = NULL;
nat_t *nat, **natp;
+ u_short nflags;
- if (flags) {
- tcp = (tcphdr_t *)((char *)ip + hlen);
+ nflags = flags & np->in_flags;
+ if (flags & IPN_TCPUDP) {
+ tcp = (tcphdr_t *)fin->fin_dp;
sport = tcp->th_sport;
dport = tcp->th_dport;
}
if (!(nat = (nat_t *)KMALLOC(sizeof(*nat))))
return NULL;
+ bzero((char *)nat, sizeof(*nat));
+
/*
* Search the current table for a match.
*/
* record, then create a new port
*/
do {
+ port = 0;
in.s_addr = np->in_nip;
- if (np->in_flags & IPN_TCPUDP) {
+ if (nflags & IPN_TCPUDP) {
port = htons(np->in_pnext++);
if (np->in_pnext >= ntohs(np->in_pmax)) {
np->in_pnext = ntohs(np->in_pmin);
if (np->in_outmsk != 0xffffffff)
np->in_nip++;
}
- } else {
+ } else if (np->in_outmsk != 0xffffffff) {
np->in_space--;
- if (np->in_outmsk != 0xffffffff)
- np->in_nip++;
+ np->in_nip++;
}
+
+ if (!port && (flags & IPN_TCPUDP))
+ port = sport;
if ((np->in_nip & ntohl(np->in_outmsk)) >
- ntohl(np->in_outip))
+ ntohl(np->in_outip))
np->in_nip = ntohl(np->in_outip) + 1;
- } while (nat_lookupinip(in, sport));
+ } while (nat_inlookup(flags, ip->ip_dst, dport, in, port));
/* Setup the NAT table */
- nat->nat_use = 0;
nat->nat_inip = ip->ip_src;
nat->nat_outip.s_addr = htonl(in.s_addr);
+ nat->nat_oip = ip->ip_dst;
sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) +
(ntohl(ip->ip_src.s_addr) >> 16) + ntohs(sport);
- /* Do it twice */
- sum1 = (sum1 & 0xffff) + (sum1 >> 16);
- sum1 = (sum1 & 0xffff) + (sum1 >> 16);
-
sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(port);
- /* Do it twice */
- sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- sum2 = (sum2 & 0xffff) + (sum2 >> 16);
-
- if (sum1 > sum2)
- sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
- sumd = sum2 - sum1;
- sumd = (sumd & 0xffff) + (sumd >> 16);
- nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16);
-
- if (sport) {
+ if (flags & IPN_TCPUDP) {
nat->nat_inport = sport;
nat->nat_outport = port;
- } else {
- nat->nat_inport = 0;
- nat->nat_outport = 0;
+ nat->nat_oport = dport;
}
} else {
* internal port.
*/
in.s_addr = ntohl(np->in_inip);
- nport = np->in_pnext;
+ if (!(nport = np->in_pnext))
+ nport = dport;
- nat->nat_use = 0;
nat->nat_inip.s_addr = htonl(in.s_addr);
nat->nat_outip = ip->ip_dst;
nat->nat_oip = ip->ip_src;
sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) +
(ntohl(ip->ip_dst.s_addr) >> 16) + ntohs(dport);
+ sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(nport);
+
+ if (flags & IPN_TCPUDP) {
+ nat->nat_inport = nport;
+ nat->nat_outport = dport;
+ nat->nat_oport = sport;
+ }
+ }
+
+ /* Do it twice */
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+
+ /* Do it twice */
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16);
+
+ if (sum1 > sum2)
+ sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
+ sumd = sum2 - sum1;
+ sumd = (sumd & 0xffff) + (sumd >> 16);
+ nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16);
+
+ if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) {
+ if (direction == NAT_OUTBOUND)
+ sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) +
+ (ntohl(ip->ip_src.s_addr) >> 16);
+ else
+ sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) +
+ (ntohl(ip->ip_dst.s_addr) >> 16);
+
+ sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16);
+
/* Do it twice */
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
sum1 = (sum1 & 0xffff) + (sum1 >> 16);
- sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(nport);
-
/* Do it twice */
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- if (sum2 > sum1)
- sum1--; /* Because ~1 == -2, We really need ~1 == -1 */
- sumd = (sum1 - sum2);
+ if (sum1 > sum2)
+ sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
+ sumd = sum2 - sum1;
sumd = (sumd & 0xffff) + (sumd >> 16);
- nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16);
-
- if (dport) {
- nat->nat_inport = nport;
- nat->nat_outport = dport;
- nat->nat_oport = sport;
- } else {
- nat->nat_inport = 0;
- nat->nat_outport = 0;
- }
- }
+ nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
+ } else
+ nat->nat_ipsumd = nat->nat_sumd;
in.s_addr = htonl(in.s_addr);
+ nat->nat_next = nat_instances;
+ nat_instances = nat;
natp = &nat_table[0][nat->nat_inip.s_addr % NAT_SIZE];
- nat->nat_next = *natp;
+ nat->nat_hstart[0] = natp;
+ nat->nat_hnext[0] = *natp;
*natp = nat;
- nat->nat_use++;
natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE];
- nat->nat_next = *natp;
+ nat->nat_hstart[1] = natp;
+ nat->nat_hnext[1] = *natp;
*natp = nat;
- nat->nat_use++;
- if (direction == NAT_REDIRECT) {
- ip->ip_src = in;
- if (flags)
+ nat->nat_ptr = np;
+ np->in_use++;
+ if (direction == NAT_OUTBOUND) {
+ if (flags & IPN_TCPUDP)
tcp->th_sport = htons(port);
} else {
- ip->ip_dst = in;
- if (flags)
+ if (flags & IPN_TCPUDP)
tcp->th_dport = htons(nport);
}
-
nat_stats.ns_added++;
nat_inuse++;
return nat;
* NB: these lookups don't lock access to the list, it assume it has already
* been done!
*/
+/*
+ * Lookup a nat entry based on the mapped destination ip address/port and
+ * real source address/port. We use this lookup when receiving a packet,
+ * we're looking for a table entry, based on the destination address.
+ * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
+ */
nat_t *
-nat_lookupredir(np)
- natlookup_t *np;
+nat_inlookup(flags, src, sport, mapdst, mapdport)
+ register int flags;
+ struct in_addr src, mapdst;
+ u_short sport, mapdport;
{
- nat_t *nat;
+ register nat_t *nat;
- nat = nat_table[0][np->nl_inip.s_addr % NAT_SIZE];
- for (; nat; nat = nat->nat_next)
- if ((nat->nat_inip.s_addr == np->nl_inip.s_addr) &&
- (nat->nat_oip.s_addr == np->nl_outip.s_addr) &&
- (np->nl_inport == nat->nat_inport) &&
- (np->nl_outport == nat->nat_oport))
+ flags &= IPN_TCPUDP;
+
+ nat = nat_table[1][mapdst.s_addr % NAT_SIZE];
+ for (; nat; nat = nat->nat_hnext[1])
+ if (nat->nat_oip.s_addr == src.s_addr &&
+ nat->nat_outip.s_addr == mapdst.s_addr &&
+ (!flags || (nat->nat_oport == sport &&
+ nat->nat_outport == mapdport)))
return nat;
return NULL;
}
+/*
+ * Lookup a nat entry based on the source 'real' ip address/port and
+ * destination address/port. We use this lookup when sending a packet out,
+ * we're looking for a table entry, based on the source address.
+ * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
+ */
nat_t *
-nat_lookupinip(ipaddr, sport)
- struct in_addr ipaddr;
- u_short sport;
+nat_outlookup(flags, src, sport, dst, dport)
+ register int flags;
+ struct in_addr src, dst;
+ u_short sport, dport;
{
- nat_t *nat;
+ register nat_t *nat;
- nat = nat_table[0][ipaddr.s_addr % NAT_SIZE];
+ flags &= IPN_TCPUDP;
- for (; nat; nat = nat->nat_next)
- if (nat->nat_inip.s_addr == ipaddr.s_addr) {
- if (nat->nat_inport && (sport != nat->nat_inport))
- continue;
+ nat = nat_table[0][src.s_addr % NAT_SIZE];
+ for (; nat; nat = nat->nat_hnext[0])
+ if (nat->nat_inip.s_addr == src.s_addr &&
+ nat->nat_oip.s_addr == dst.s_addr &&
+ (!flags || (nat->nat_inport == sport &&
+ nat->nat_oport == dport)))
return nat;
- }
return NULL;
}
+/*
+ * Lookup a nat entry based on the mapped source ip address/port and
+ * real destination address/port. We use this lookup when sending a packet
+ * out, we're looking for a table entry, based on the source address.
+ */
nat_t *
-nat_lookupoutip(np, ip, tcp)
- register ipnat_t *np;
- ip_t *ip;
- tcphdr_t *tcp;
+nat_lookupmapip(flags, mapsrc, mapsport, dst, dport)
+ register int flags;
+ struct in_addr mapsrc, dst;
+ u_short mapsport, dport;
{
- struct in_addr ipaddr;
- u_short port = tcp->th_dport;
- nat_t *nat;
+ register nat_t *nat;
- ipaddr.s_addr = ip->ip_dst.s_addr;
- nat = nat_table[1][ipaddr.s_addr % NAT_SIZE];
+ flags &= IPN_TCPUDP;
- if (np->in_redir == NAT_MAP) {
- for (; nat; nat = nat->nat_next)
- if (nat->nat_outip.s_addr == ipaddr.s_addr &&
- (!nat->nat_outport || (port == nat->nat_outport)))
- return nat;
- } else
- for (; nat; nat = nat->nat_next)
- if (nat->nat_outip.s_addr == ipaddr.s_addr &&
- nat->nat_oip.s_addr == ip->ip_src.s_addr &&
- port == nat->nat_outport &&
- tcp->th_sport == nat->nat_oport)
- return nat;
+ nat = nat_table[1][mapsrc.s_addr % NAT_SIZE];
+ for (; nat; nat = nat->nat_hnext[0])
+ if (nat->nat_outip.s_addr == mapsrc.s_addr &&
+ nat->nat_oip.s_addr == dst.s_addr &&
+ (!flags || (nat->nat_outport == mapsport &&
+ nat->nat_oport == dport)))
+ return nat;
return NULL;
}
+/*
+ * Lookup the NAT tables to search for a matching redirect
+ */
+nat_t *
+nat_lookupredir(np)
+ register natlookup_t *np;
+{
+ nat_t *nat;
+
+ /*
+ * If nl_inip is non null, this is a lookup based on the real
+ * ip address. Else, we use the fake.
+ */
+ if ((nat = nat_outlookup(IPN_TCPUDP, np->nl_inip, np->nl_inport,
+ np->nl_outip, np->nl_outport))) {
+ np->nl_inip = nat->nat_outip;
+ np->nl_inport = nat->nat_outport;
+ }
+ return nat;
+}
+
+
/*
* Packets going out on the external interface go through this.
* Here, the source address requires alteration, if anything.
*/
-void
+int
ip_natout(ip, hlen, fin)
ip_t *ip;
int hlen;
{
register ipnat_t *np;
register u_long ipa;
- register u_long sum1;
- tcphdr_t *tcp;
+ tcphdr_t *tcp = NULL;
nat_t *nat;
- u_short nflags = 0, sport = 0;
- struct ifnet *ifp = fin->fin_ifp;
+ u_short nflags = 0, sport = 0, dport = 0, *csump = NULL;
+ struct ifnet *ifp;
+ frentry_t *fr;
+
+ if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
+ fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
+ ifp = fr->fr_tif.fd_ifp;
+ else
+ ifp = fin->fin_ifp;
if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
if (ip->ip_p == IPPROTO_TCP)
nflags = IPN_TCP;
else if (ip->ip_p == IPPROTO_UDP)
nflags = IPN_UDP;
- }
- if (nflags) {
- tcp = (tcphdr_t *)fin->fin_dp;
- sport = tcp->th_sport;
+ if (nflags) {
+ tcp = (tcphdr_t *)fin->fin_dp;
+ sport = tcp->th_sport;
+ dport = tcp->th_dport;
+ }
}
ipa = ip->ip_src.s_addr;
if ((np->in_ifp == ifp) && np->in_space &&
(!np->in_flags || (np->in_flags & nflags)) &&
((ipa & np->in_inmsk) == np->in_inip) &&
- (np->in_redir == NAT_MAP ||
- np->in_pnext == sport)) {
+ ((np->in_redir == NAT_MAP) ||
+ (np->in_pnext == sport))) {
/*
* If there is no current entry in the nat table for
* this IP#, create one for it.
*/
- if (!(nat = nat_lookupinip(ip->ip_src, sport))) {
+ if (!(nat = nat_outlookup(nflags, ip->ip_src, sport,
+ ip->ip_dst, dport))) {
if (np->in_redir == NAT_REDIRECT)
continue;
/*
* Redirections are only for incoming
* connections.
*/
- if (!(nat = nat_new(np, ip, hlen,
- nflags & np->in_flags,
+ if (!(nat = nat_new(np, ip, fin, nflags,
NAT_OUTBOUND)))
break;
- } else
- ip->ip_src = nat->nat_outip;
+ }
+ ip->ip_src = nat->nat_outip;
- nat->nat_age = 1200; /* 5 mins */
+ nat->nat_age = fr_defnatage; /* 5 mins */
/*
* Fix up checksums, not by recalculating them, but
* simply computing adjustments.
*/
+#if SOLARIS
+ if (np->in_redir == NAT_MAP)
+ fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
+ else
+ fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
+#endif
+
if (nflags && !(ip->ip_off & 0x1fff) &&
!(fin->fin_fi.fi_fl & FI_SHORT)) {
- u_short *sp;
- u_short sumshort;
if (nat->nat_outport)
tcp->th_sport = nat->nat_outport;
if (ip->ip_p == IPPROTO_TCP) {
- sp = &tcp->th_sum;
-
- sum1 = (~ntohs(*sp)) & 0xffff;
-
- sum1 += nat->nat_sumd;
-
- sum1 = (sum1 >> 16) + (sum1 & 0xffff);
- /* Again */
- sum1 = (sum1 >> 16) + (sum1 & 0xffff);
- sumshort = ~(u_short)sum1;
- *sp = htons(sumshort);
-
+ csump = &tcp->th_sum;
+ set_tcp_age(&nat->nat_age,
+ nat->nat_state, ip, fin,1);
} else if (ip->ip_p == IPPROTO_UDP) {
udphdr_t *udp = (udphdr_t *)tcp;
- sp = &udp->uh_sum;
-
- if (udp->uh_sum) {
- sum1 = (~ntohs(*sp)) & 0xffff;
- sum1 += nat->nat_sumd;
- sum1 = (sum1 >> 16) +
- (sum1 & 0xffff);
- /* Again */
- sum1 = (sum1 >> 16) +
- (sum1 & 0xffff);
- sumshort = ~(u_short)sum1;
- *sp = htons(sumshort);
- }
+ if (udp->uh_sum)
+ csump = &udp->uh_sum;
+ } else if (ip->ip_p == IPPROTO_ICMP) {
+ icmphdr_t *ic = (icmphdr_t *)tcp;
+
+ csump = &ic->icmp_cksum;
+ }
+ if (csump) {
+ if (np->in_redir == NAT_MAP)
+ fix_outcksum(csump,
+ nat->nat_sumd);
+ else
+ fix_incksum(csump,
+ nat->nat_sumd);
}
}
nat_stats.ns_mapped[1]++;
MUTEX_EXIT(&ipf_nat);
- return;
+ return 1;
}
MUTEX_EXIT(&ipf_nat);
- return;
+ return 0;
}
* Packets coming in from the external interface go through this.
* Here, the destination address requires alteration, if anything.
*/
-void
+int
ip_natin(ip, hlen, fin)
ip_t *ip;
int hlen;
{
register ipnat_t *np;
register struct in_addr in;
- register u_long sum1;
struct ifnet *ifp = fin->fin_ifp;
- tcphdr_t *tcp;
- u_short port = 0, nflags;
+ tcphdr_t *tcp = NULL;
+ u_short sport = 0, dport = 0, nflags = 0, *csump = NULL;
nat_t *nat;
if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
nflags = IPN_TCP;
else if (ip->ip_p == IPPROTO_UDP)
nflags = IPN_UDP;
- }
- if (nflags) {
- tcp = (tcphdr_t *)((char *)ip + hlen);
- port = tcp->th_dport;
+ if (nflags) {
+ tcp = (tcphdr_t *)((char *)ip + hlen);
+ dport = tcp->th_dport;
+ sport = tcp->th_sport;
+ }
}
in = ip->ip_dst;
if ((np->in_ifp == ifp) &&
(!np->in_flags || (nflags & np->in_flags)) &&
((in.s_addr & np->in_outmsk) == np->in_outip) &&
- (np->in_redir == NAT_MAP || np->in_pmin == port)) {
- if (!(nat = nat_lookupoutip(np, ip, tcp))) {
+ (np->in_redir == NAT_MAP || np->in_pmin == dport)) {
+ if (!(nat = nat_inlookup(nflags, ip->ip_src, sport,
+ ip->ip_dst, dport))) {
if (np->in_redir == NAT_MAP)
continue;
else {
* nat_new. Otherwise, if it's just a
* mapping, do a continue;
*/
- nflags &= np->in_flags;
- if (!(nat = nat_new(np, ip, hlen,
+ if (!(nat = nat_new(np, ip, fin,
nflags,
NAT_INBOUND)))
break;
}
}
- nat->nat_age = 1200;
-
ip->ip_dst = nat->nat_inip;
+ nat->nat_age = fr_defnatage;
+
/*
* Fix up checksums, not by recalculating them, but
* simply computing adjustments.
*/
+#if SOLARIS
+ if (np->in_redir == NAT_MAP)
+ fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
+ else
+ fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
+#endif
if (nflags && !(ip->ip_off & 0x1fff) &&
!(fin->fin_fi.fi_fl & FI_SHORT)) {
- u_short *sp;
- u_short sumshort;
if (nat->nat_inport)
tcp->th_dport = nat->nat_inport;
if (ip->ip_p == IPPROTO_TCP) {
- sp = &tcp->th_sum;
-
- sum1 = (~ntohs(*sp)) & 0xffff;
- sum1 += ~nat->nat_sumd & 0xffff;
- sum1 = (sum1 >> 16) + (sum1 & 0xffff);
- /* Again */
- sum1 = (sum1 >> 16) + (sum1 & 0xffff);
- sumshort = ~(u_short)sum1;
- *sp = htons(sumshort);
+ csump = &tcp->th_sum;
+ set_tcp_age(&nat->nat_age,
+ nat->nat_state, ip, fin,0);
} else if (ip->ip_p == IPPROTO_UDP) {
udphdr_t *udp = (udphdr_t *)tcp;
- sp = &udp->uh_sum;
-
- if (udp->uh_sum) {
- sum1 = (~ntohs(*sp)) & 0xffff;
- sum1+= ~nat->nat_sumd & 0xffff;
- sum1 = (sum1 >> 16) +
- (sum1 & 0xffff);
- /* Again */
- sum1 = (sum1 >> 16) +
- (sum1 & 0xffff);
- sumshort = ~(u_short)sum1;
- *sp = htons(sumshort);
- }
+ if (udp->uh_sum)
+ csump = &udp->uh_sum;
+ } else if (ip->ip_p == IPPROTO_ICMP) {
+ icmphdr_t *ic = (icmphdr_t *)tcp;
+
+ csump = &ic->icmp_cksum;
+ }
+ if (csump) {
+ if (np->in_redir == NAT_MAP)
+ fix_incksum(csump,
+ nat->nat_sumd);
+ else
+ fix_outcksum(csump,
+ nat->nat_sumd);
}
}
nat_stats.ns_mapped[0]++;
MUTEX_EXIT(&ipf_nat);
- return;
+ return 1;
}
MUTEX_EXIT(&ipf_nat);
- return;
+ return 0;
}
void
ip_natunload()
{
- register struct nat *nat, **natp;
- register struct ipnat *ipn, **ipnp;
- register int i;
MUTEX_ENTER(&ipf_nat);
- for (i = 0; i < NAT_SIZE; i++)
- for (natp = &nat_table[0][i]; (nat = *natp); ) {
- *natp = nat->nat_next;
- if (!--nat->nat_use)
- KFREE(nat);
- }
- for (i = 0; i < NAT_SIZE; i++)
- for (natp = &nat_table[1][i]; (nat = *natp); ) {
- *natp = nat->nat_next;
- if (!--nat->nat_use)
- KFREE(nat);
- }
- for (ipnp = &nat_list; (ipn = *ipnp); ) {
- *ipnp = ipn->in_next;
- KFREE(ipn);
- }
+ (void) clear_natlist();
+ (void) flush_nattable();
+
MUTEX_EXIT(&ipf_nat);
}
ip_natexpire()
{
register struct nat *nat, **natp;
- register int i;
MUTEX_ENTER(&ipf_nat);
- for (i = 0; i < NAT_SIZE; i++)
- for (natp = &nat_table[0][i]; (nat = *natp); ) {
- if (nat->nat_age > 0)
- nat->nat_age--;
- if (!nat->nat_use || !nat->nat_age) {
- *natp = nat->nat_next;
- if (nat->nat_use)
- nat->nat_use--;
- if (!nat->nat_use) {
- KFREE(nat);
- nat_stats.ns_expire++;
- nat_inuse--;
- }
- } else
- natp = &nat->nat_next;
- }
-
- for (i = 0; i < NAT_SIZE; i++)
- for (natp = &nat_table[1][i]; (nat = *natp); ) {
- if (nat->nat_age > 0)
- nat->nat_age--;
- if (!nat->nat_use || !nat->nat_age) {
- *natp = nat->nat_next;
- if (nat->nat_use)
- nat->nat_use--;
- if (!nat->nat_use) {
- KFREE(nat);
- nat_stats.ns_expire++;
- nat_inuse--;
- }
- } else
- natp = &nat->nat_next;
- }
+ for (natp = &nat_instances; (nat = *natp); natp = &nat->nat_next) {
+ if (--nat->nat_age)
+ continue;
+ *natp = nat->nat_next;
+ nat_delete(nat);
+ nat_stats.ns_expire++;
+ }
MUTEX_EXIT(&ipf_nat);
}
+/* $OpenBSD: ip_nat.h,v 1.5 1997/02/11 22:23:27 kstailey Exp $ */
/*
* (C)opyright 1995 by Darren Reed.
*
* to the original author and the contributors.
*
* @(#)ip_nat.h 1.5 2/4/96
- * $Id: ip_nat.h,v 1.4 1996/10/08 07:33:29 niklas Exp $
+ * Id: ip_nat.h,v 2.0.1.7 1997/01/30 12:39:41 darrenr Exp
*/
#ifndef __IP_NAT_H_
#define SIOCGNATL _IOWR('r', 83, struct natlookup)
#define SIOCGFRST _IOR('r', 84, struct ipfrstat)
#define SIOCGIPST _IOR('r', 85, struct ips_stat)
+#define SIOCFLNAT _IOWR('r', 86, int)
+#define SIOCCNATL _IOWR('r', 87, int)
+
#else
#define SIOCADNAT _IOW(r, 80, struct ipnat)
#define SIOCRMNAT _IOW(r, 81, struct ipnat)
#define SIOCGNATL _IOWR(r, 83, struct natlookup)
#define SIOCGFRST _IOR(r, 84, struct ipfrstat)
#define SIOCGIPST _IOR(r, 85, struct ips_stat)
+#define SIOCFLNAT _IOWR(r, 86, int)
+#define SIOCCNATL _IOWR(r, 87, int)
#endif
#define NAT_SIZE 367
typedef struct nat {
- struct nat *nat_next;
- u_short nat_use;
- short nat_age;
+ int nat_age;
u_long nat_sumd;
+ u_long nat_ipsumd;
struct in_addr nat_inip;
struct in_addr nat_outip;
struct in_addr nat_oip; /* other ip */
u_short nat_oport; /* other port */
u_short nat_inport;
u_short nat_outport;
+ u_short nat_use;
+ u_char nat_state[2];
+ struct ipnat *nat_ptr;
+ struct nat *nat_next;
+ struct nat *nat_hnext[2];
+ struct nat **nat_hstart[2];
} nat_t;
typedef struct ipnat {
struct ipnat *in_next;
void *in_ifp;
- u_short in_flags;
+ u_int in_space;
+ u_int in_use;
+ struct in_addr in_nextip;
u_short in_pnext;
+ u_short in_flags;
u_short in_port[2];
struct in_addr in_in[2];
struct in_addr in_out[2];
- struct in_addr in_nextip;
- int in_space;
int in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */
char in_ifname[IFNAMSIZ];
} ipnat_t;
#define NAT_MAP 0
#define NAT_REDIRECT 1
-#define IPN_CMPSIZ (sizeof(struct in_addr) * 4 + sizeof(u_short) * 2)
+#define IPN_CMPSIZ (sizeof(struct in_addr) * 4 + sizeof(u_short) * 3 + \
+ sizeof(int))
typedef struct natlookup {
struct in_addr nl_inip;
u_long ns_added;
u_long ns_expire;
u_long ns_inuse;
- nat_t ***ns_table;
+ nat_t **ns_table[2];
ipnat_t *ns_list;
} natstat_t;
#define IPN_UDP 2
#define IPN_TCPUDP 3
+extern nat_t *nat_table[2][NAT_SIZE];
extern int nat_ioctl __P((caddr_t, int, int));
-extern nat_t *nat_lookupoutip __P((ipnat_t *, ip_t *, tcphdr_t *));
-extern nat_t *nat_lookupinip __P((struct in_addr, u_short));
+extern nat_t *nat_outlookup __P((int, struct in_addr, u_short, struct in_addr,
+ u_short));
+extern nat_t *nat_inlookup __P((int, struct in_addr, u_short, struct in_addr,
+ u_short));
extern nat_t *nat_lookupredir __P((natlookup_t *));
-extern void ip_natout __P((ip_t *, int, fr_info_t *));
-extern void ip_natin __P((ip_t *, int, fr_info_t *));
+extern int ip_natout __P((ip_t *, int, fr_info_t *));
+extern int ip_natin __P((ip_t *, int, fr_info_t *));
extern void ip_natunload __P((void));
extern void ip_natexpire __P((void));
#endif /* __IP_NAT_H__ */
+/* $OpenBSD: ip_state.c,v 1.7 1997/02/11 22:23:28 kstailey Exp $ */
/*
* (C)opyright 1995 by Darren Reed.
*
* to the original author and the contributors.
*/
#if 0
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed";
-static char rcsid[] = "$OpenBSD: ip_state.c,v 1.6 1997/01/18 08:29:21 downsj Exp $";
+static char rcsid[] = "Id: ip_state.c,v 2.0.1.2 1997/01/09 15:22:45 darrenr Exp ";
#endif
#endif
# include <stdlib.h>
# include <string.h>
#endif
-#ifndef linux
#include <sys/errno.h>
#include <sys/types.h>
-#if defined(_KERNEL) || defined(KERNEL)
-#include <sys/systm.h>
-#endif
#include <sys/param.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/protosw.h>
#include <sys/socket.h>
+#ifdef _KERNEL
+# include <sys/systm.h>
+#endif
#if !defined(__SVR4) && !defined(__svr4__)
-# if defined(__OpenBSD__)
-# include <sys/dirent.h>
-# else
-# include <sys/dir.h>
-# endif
# include <sys/mbuf.h>
#else
# include <sys/byteorder.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
+#include <netinet/tcp_fsm.h>
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#include <sys/syslog.h>
-#endif
#include "ip_fil_compat.h"
#include "ip_fil.h"
#include "ip_state.h"
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
+void set_tcp_age __P((int *, u_char *, ip_t *, fr_info_t *, int));
+#ifndef _KERNEL
+int fr_tcpstate __P((register ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *,
+ u_short, ipstate_t **));
+#else
+int fr_tcpstate __P((register ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *,
+ u_short));
+#endif
+
#define TCP_CLOSE (TH_FIN|TH_RST)
ipstate_t *ips_table[IPSTATE_SIZE];
#endif
+#define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */
+
+u_long fr_tcpidletimeout = FIVE_DAYS,
+ fr_tcpclosewait = 60,
+ fr_tcplastack = 20,
+ fr_tcptimeout = 120,
+ fr_tcpclosed = 1,
+ fr_udptimeout = 120,
+ fr_icmptimeout = 120;
+
+
ips_stat_t *
fr_statetstats()
{
register ipstate_t *is = &ips;
register u_int hv;
+ if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
+ return -1;
if (ips_num == IPSTATE_MAX) {
ips_stats.iss_max++;
return -1;
}
+ ips.is_age = 1;
+ ips.is_state[0] = 0;
+ ips.is_state[1] = 0;
/*
* Copy and calculate...
*/
return -1;
}
ips_stats.iss_icmp++;
- is->is_age = 120;
+ is->is_age = fr_icmptimeout;
break;
}
case IPPROTO_TCP :
hv += (is->is_sport = tcp->th_sport);
is->is_seq = ntohl(tcp->th_seq);
is->is_ack = ntohl(tcp->th_ack);
- is->is_win = ntohs(tcp->th_win);
+ is->is_swin = ntohs(tcp->th_win);
+ is->is_dwin = is->is_swin; /* start them the same */
ips_stats.iss_tcp++;
/*
* If we're creating state for a starting connectoin, start the
* connect.
*/
if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN)
- is->is_age = 120;
- else
- is->is_age = 0;
+ is->is_ack = 0; /* Trumpet WinSock 'ism */
+ set_tcp_age(&is->is_age, is->is_state, ip, fin,
+ tcp->th_sport == is->is_sport);
break;
}
case IPPROTO_UDP :
hv += (is->is_dport = tcp->th_dport);
hv += (is->is_sport = tcp->th_sport);
ips_stats.iss_udp++;
- is->is_age = 120;
+ is->is_age = fr_udptimeout;
break;
}
default :
}
+/*
+ * check to see if a packet with TCP headers fits within the TCP window.
+ * change timeout depending on whether new packet is a SYN-ACK returning for a
+ * SYN or a RST or FIN which indicate time to close up shop.
+ */
+int
+fr_tcpstate(is, fin, ip, tcp, sport
+#ifndef _KERNEL
+ ,isp)
+ ipstate_t **isp;
+#else
+ )
+#endif
+ register ipstate_t *is;
+ fr_info_t *fin;
+ ip_t *ip;
+ tcphdr_t *tcp;
+ u_short sport;
+{
+ register int seqskew, ackskew;
+ register u_short swin, dwin;
+ register tcp_seq seq, ack;
+ int source;
+
+ /*
+ * Find difference between last checked packet and this packet.
+ */
+ seq = ntohl(tcp->th_seq);
+ ack = ntohl(tcp->th_ack);
+ if (sport == is->is_sport) {
+ seqskew = seq - is->is_seq;
+ ackskew = ack - is->is_ack;
+ } else {
+ seqskew = ack - is->is_seq;
+ if (!is->is_ack)
+ /*
+ * Must be a SYN-ACK in reply to a SYN.
+ */
+ is->is_ack = seq;
+ ackskew = seq - is->is_ack;
+ }
+
+ /*
+ * Make skew values absolute
+ */
+ if (seqskew < 0)
+ seqskew = -seqskew;
+ if (ackskew < 0)
+ ackskew = -ackskew;
+
+ /*
+ * If the difference in sequence and ack numbers is within the
+ * window size of the connection, store these values and match
+ * the packet.
+ */
+ if ((source = (sport == is->is_sport))) {
+ swin = is->is_swin;
+ dwin = is->is_dwin;
+ } else {
+ dwin = is->is_swin;
+ swin = is->is_dwin;
+ }
+
+ if ((seqskew <= swin) && (ackskew <= dwin)) {
+ if (source) {
+ is->is_seq = seq;
+ is->is_ack = ack;
+ is->is_swin = ntohs(tcp->th_win);
+ } else {
+ is->is_seq = ack;
+ is->is_ack = seq;
+ is->is_dwin = ntohs(tcp->th_win);
+ }
+ ips_stats.iss_hits++;
+ /*
+ * Nearing end of connection, start timeout.
+ */
+ set_tcp_age(&is->is_age, is->is_state, ip, fin,
+ tcp->th_sport == is->is_sport);
+ return 1;
+ }
+ return 0;
+}
+
+
/*
* Check if a packet has a registered state.
*/
tcphdr_t *tcp;
u_int hv, hlen;
- if ((ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT))
+ if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT))
return 0;
hlen = fin->fin_hlen;
if (is->is_icmp.ics_type &&
is->is_icmp.ics_type != ic->icmp_type)
continue;
- is->is_age = 120;
+ is->is_age = fr_icmptimeout;
ips_stats.iss_hits++;
MUTEX_EXIT(&ipf_state);
return is->is_pass;
case IPPROTO_TCP :
{
register u_short dport = tcp->th_dport, sport = tcp->th_sport;
- register u_short win = ntohs(tcp->th_win);
- tcp_seq seq, ack;
hv += dport;
hv += sport;
hv %= IPSTATE_SIZE;
MUTEX_ENTER(&ipf_state);
for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) {
- register int dl, seqskew, ackskew;
-
if ((is->is_p == pr) &&
PAIRS(sport, dport, is->is_sport, is->is_dport) &&
- IPPAIR(src, dst, is->is_src, is->is_dst)) {
- dl = ip->ip_len - hlen - sizeof(tcphdr_t);
- /*
- * Find difference between last checked packet
- * and this packet.
- */
- seq = ntohl(tcp->th_seq);
- ack = ntohl(tcp->th_ack);
- if (sport == is->is_sport) {
- seqskew = seq - is->is_seq;
- ackskew = ack - is->is_ack;
- } else {
- seqskew = ack - is->is_seq;
- if (!is->is_ack) {
- /*
- * Must be a SYN-ACK in reply
- * to a SYN. Set age timeout
- * to 0 to stop deletion.
- */
- is->is_ack = seq;
- is->is_age = 0;
- }
- ackskew = seq - is->is_ack;
- }
-
- /*
- * Make skew values absolute
- */
- if (seqskew < 0)
- seqskew = -seqskew;
- if (ackskew < 0)
- ackskew = -ackskew;
- /*
- * If the difference in sequence and ack
- * numbers is within the window size of the
- * connection, store these values and match
- * the packet.
- */
- if ((seqskew <= win) && (ackskew <= win)) {
- is->is_win = win;
- if (sport == is->is_sport) {
- is->is_seq = seq;
- is->is_ack = ack;
- } else {
- is->is_seq = ack;
- is->is_ack = seq;
- }
- ips_stats.iss_hits++;
- /*
- * Nearing end of connection, start
- * timeout.
- */
+ IPPAIR(src, dst, is->is_src, is->is_dst))
+ if (fr_tcpstate(is, fin, ip, tcp, sport
+#ifndef _KERNEL
+ , NULL
+#endif
+ )) {
#ifdef _KERNEL
- if (!is->is_age) {
- if (tcp->th_flags & TH_FIN)
- is->is_age = 120;
- if (tcp->th_flags & TH_RST)
- is->is_age = 1;
- }
MUTEX_EXIT(&ipf_state);
return is->is_pass;
#else
- if (tcp->th_flags & TCP_CLOSE) {
- int pass = is->is_pass;
+ int pass = is->is_pass;
+ if (tcp->th_flags & TCP_CLOSE) {
*isp = is->is_next;
isp = &ips_table[hv];
KFREE(is);
- return pass;
}
- return is->is_pass;
+ return pass;
#endif
}
- }
}
MUTEX_EXIT(&ipf_state);
break;
PAIRS(sport, dport, is->is_sport, is->is_dport) &&
IPPAIR(src, dst, is->is_src, is->is_dst)) {
ips_stats.iss_hits++;
- is->is_age = 120;
+ is->is_age = fr_udptimeout;
MUTEX_EXIT(&ipf_state);
return is->is_pass;
}
/*
- * Slowly expire held state for thingslike UDP and ICMP. Timeouts are set
+ * Slowly expire held state for things like UDP and ICMP. Timeouts are set
* in expectation of this being called twice per second.
*/
void
isp = &is->is_next;
MUTEX_EXIT(&ipf_state);
}
+
+
+/*
+ * Original idea freom Pradeep Krishnan for use primarily with NAT code.
+ * (pkrishna@netcom.com)
+ */
+void
+set_tcp_age(age, state, ip, fin, dir)
+ int *age;
+ u_char *state;
+ ip_t *ip;
+ fr_info_t *fin;
+ int dir;
+{
+ tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
+ u_char flags = tcp->th_flags;
+ int dlen, ostate;
+
+ ostate = state[1 - dir];
+
+ dlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2);
+
+ if (flags & TH_RST) {
+ if (!(tcp->th_flags & TH_PUSH) && !dlen) {
+ *age = fr_tcpclosed;
+ state[dir] = TCPS_CLOSED;
+ } else {
+ *age = fr_tcpclosewait;
+ state[dir] = TCPS_CLOSE_WAIT;
+ }
+ return;
+ }
+
+ *age = fr_tcptimeout; /* 1 min */
+
+ switch(state[dir])
+ {
+ case TCPS_FIN_WAIT_2:
+ case TCPS_CLOSED:
+ if ((flags & TH_OPENING) == TH_OPENING)
+ state[dir] = TCPS_SYN_RECEIVED;
+ else if (flags & TH_SYN)
+ state[dir] = TCPS_SYN_SENT;
+ break;
+ case TCPS_SYN_RECEIVED:
+ if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
+ state[dir] = TCPS_ESTABLISHED;
+ *age = fr_tcpidletimeout;
+ }
+ break;
+ case TCPS_SYN_SENT:
+ if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
+ state[dir] = TCPS_ESTABLISHED;
+ *age = fr_tcpidletimeout;
+ }
+ break;
+ case TCPS_ESTABLISHED:
+ if (flags & TH_FIN) {
+ state[dir] = TCPS_CLOSE_WAIT;
+ if (!(flags & TH_PUSH) && !dlen &&
+ ostate > TCPS_ESTABLISHED)
+ *age = fr_tcplastack;
+ else
+ *age = fr_tcpclosewait;
+ } else
+ *age = fr_tcpidletimeout;
+ break;
+ case TCPS_CLOSE_WAIT:
+ if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen &&
+ ostate > TCPS_ESTABLISHED) {
+ *age = fr_tcplastack;
+ state[dir] = TCPS_LAST_ACK;
+ } else
+ *age = fr_tcpclosewait;
+ break;
+ case TCPS_LAST_ACK:
+ if (flags & TH_ACK) {
+ state[dir] = TCPS_FIN_WAIT_2;
+ if (!(flags & TH_PUSH) && !dlen &&
+ ostate > TCPS_ESTABLISHED)
+ *age = fr_tcplastack;
+ else {
+ *age = fr_tcpclosewait;
+ state[dir] = TCPS_CLOSE_WAIT;
+ }
+ }
+ break;
+ }
+}
+/* $OpenBSD: ip_state.h,v 1.4 1997/02/11 22:23:30 kstailey Exp $ */
/*
* (C)opyright 1995 by Darren Reed.
*
* to the original author and the contributors.
*
* @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed
- * $OpenBSD: ip_state.h,v 1.3 1996/10/08 07:33:30 niklas Exp $
+ * Id: ip_state.h,v 2.0.1.1 1997/01/09 15:14:43 darrenr Exp
*/
#ifndef __IP_STATE_H__
#define __IP_STATE_H__
u_short ts_dport;
u_long ts_seq;
u_long ts_ack;
- u_short ts_win;
+ u_short ts_swin;
+ u_short ts_dwin;
+ u_char ts_state[2];
} tcpstate_t;
typedef struct ipstate {
struct in_addr is_src;
struct in_addr is_dst;
u_char is_p;
+ u_char is_flags;
union {
icmpstate_t is_ics;
tcpstate_t is_ts;
#define is_udp is_ps.is_us
#define is_seq is_tcp.ts_seq
#define is_ack is_tcp.ts_ack
-#define is_win is_tcp.ts_win
+#define is_dwin is_tcp.ts_dwin
+#define is_swin is_tcp.ts_swin
#define is_sport is_tcp.ts_sport
#define is_dport is_tcp.ts_dport
+#define is_state is_tcp.ts_state
+#define TH_OPENING (TH_SYN|TH_ACK)
typedef struct ips_stat {
u_long iss_hits;
} ips_stat_t;
extern ips_stat_t *fr_statetstats __P((void));
-extern int fr_addstate __P((ip_t *, fr_info_t *, u_int));
-extern int fr_checkstate __P((ip_t *, fr_info_t *));
-extern void fr_timeoutstate __P((void));
+extern int fr_addstate __P((ip_t *, fr_info_t *, u_int));
+extern int fr_checkstate __P((ip_t *, fr_info_t *));
+extern void fr_timeoutstate __P((void));
+extern void set_tcp_age __P((int *, u_char *, ip_t *, fr_info_t *, int));
# ifdef _KERNEL
-extern void fr_stateunload __P((void));
+extern void fr_stateunload __P((void));
# endif
#endif /* __IP_STATE_H__ */
#include <sys/ioctl.h>
#include <sys/param.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip_var.h>
#include <netinet/ip.h>
#include <netinet/tcpip.h>
#include <net/if.h>
#include <netdb.h>
-#include "ip_fil_compat.h"
-#include "ip_fil.h"
#include "ipf.h"
#include "ipt.h"
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ipft_ef.c 1.6 2/4/96 (C)1995 Darren Reed";
-static char rcsid[] = "$Id: ipft_ef.c,v 1.5 1996/10/08 07:33:34 niklas Exp $";
+static char rcsid[] = "$Id: ipft_ef.c,v 1.6 1997/02/11 22:23:48 kstailey Exp $";
#endif
static int etherf_open(), etherf_close(), etherf_readip();
static FILE *efp = NULL;
static int efd = -1;
-#ifdef NEED_INET_ATON
-extern u_long inet_aton();
-#else
-#include <arpa/inet.h>
-#endif
static int etherf_open(fname)
char *fname;
#include <netinet/ip_icmp.h>
#include <netinet/tcpip.h>
#include <net/if.h>
-#include "ip_fil_compat.h"
#include <netdb.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include "ipf.h"
#include "ipt.h"
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ipft_hx.c 1.1 3/9/96 (C) 1996 Darren Reed";
-static char rcsid[] = "$Id: ipft_hx.c,v 1.3 1997/01/17 07:14:06 millert Exp $";
+static char rcsid[] = "$Id: ipft_hx.c,v 1.4 1997/02/11 22:23:50 kstailey Exp $";
#endif
extern int opts;
char line[513];
ip = (struct ip *)buf;
- *ifn = NULL;
while (fgets(line, sizeof(line)-1, tfp)) {
- if ((s = strchr(line, '\n'))) {
+ if ((s = index(line, '\n'))) {
if (s == line)
return (char *)ip - buf;
*s = '\0';
}
- if ((s = strchr(line, '\r')))
- *s = '\0';
- if ((s = strchr(line, '#')))
+ if ((s = index(line, '#')))
*s = '\0';
if (!*line)
continue;
printf("input: %s\n", line);
fflush(stdout);
}
- *ifn = NULL;
- *dir = 0;
ip = (struct ip *)readhex(line, (char *)ip);
}
return -1;
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
#include <net/if.h>
-#include "ip_fil_compat.h"
-#include "ip_fil.h"
#include "ipf.h"
#include "ipt.h"
#include "pcap.h"
-#ifndef lint
-static char rcsid[] = "$Id: ipft_pc.c,v 1.5 1996/10/08 07:33:35 niklas Exp $";
+#if !defined(lint) && defined(LIBC_SCCS)
+static char rcsid[] = "$Id: ipft_pc.c,v 1.6 1997/02/11 22:23:51 kstailey Exp $";
#endif
struct llc {
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
#include <net/if.h>
-#include "ip_fil_compat.h"
-#include "ip_fil.h"
#include "ipf.h"
#include "ipt.h"
#include "snoop.h"
-#ifndef lint
-static char rcsid[] = "$Id: ipft_sn.c,v 1.4 1996/10/08 07:33:35 niklas Exp $";
+#if !defined(lint) && defined(LIBC_SCCS)
+static char rcsid[] = "$Id: ipft_sn.c,v 1.5 1997/02/11 22:23:52 kstailey Exp $";
#endif
struct llc {
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip_var.h>
#include <netinet/ip.h>
#include <netinet/tcpip.h>
#include <net/if.h>
#include <netdb.h>
-#include "ip_fil_compat.h"
-#include "ip_fil.h"
#include "ipf.h"
#include "ipt.h"
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ipft_td.c 1.8 2/4/96 (C)1995 Darren Reed";
-static char rcsid[] = "$Id: ipft_td.c,v 1.5 1996/10/08 07:33:36 niklas Exp $";
+static char rcsid[] = "$Id: ipft_td.c,v 1.6 1997/02/11 22:23:54 kstailey Exp $";
#endif
static int tcpd_open(), tcpd_close(), tcpd_readip();
-#ifdef NEED_INET_ATON
-extern u_long inet_aton();
-#else
-#include <arpa/inet.h>
-#endif
struct ipread tcpd = { tcpd_open, tcpd_close, tcpd_readip };
#include <netinet/tcp.h>
#include <netinet/ip_icmp.h>
#include <netinet/tcpip.h>
+#include <arpa/inet.h>
#include <net/if.h>
-#include "ip_fil_compat.h"
#include <netdb.h>
#include <arpa/nameser.h>
#include <resolv.h>
+#include "ip_fil_compat.h"
#include "ipf.h"
#include "ipt.h"
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed";
-static char rcsid[] = "$Id: ipft_tx.c,v 1.5 1997/01/17 07:14:07 millert Exp $";
+static char rcsid[] = "$Id: ipft_tx.c,v 1.6 1997/02/11 22:23:55 kstailey Exp $";
#endif
extern int opts;
* returns an ip address as a long var as a result of either a DNS lookup or
* straight inet_addr() call
*/
-u_long tx_hostnum(host, resolved)
+static u_long tx_hostnum(host, resolved)
char *host;
int *resolved;
{
* find the port number given by the name, either from getservbyname() or
* straight atoi()
*/
-u_short tx_portnum(name)
+static u_short tx_portnum(name)
char *name;
{
struct servent *sp, *sp2;
ip = (struct ip *)buf;
*ifn = NULL;
while (fgets(line, sizeof(line)-1, tfp)) {
- if ((s = strchr(line, '\n')))
+ if ((s = index(line, '\n')))
*s = '\0';
- if ((s = strchr(line, '\r')))
+ if ((s = index(line, '\r')))
*s = '\0';
- if ((s = strchr(line, '#')))
+ if ((s = index(line, '#')))
*s = '\0';
if (!*line)
continue;
if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
char *last;
- last = strchr(*cpp, ',');
+ last = index(*cpp, ',');
if (!last) {
fprintf(stderr, "tcp/udp with no source port\n");
return 1;
if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
char *last;
- last = strchr(*cpp, ',');
+ last = index(*cpp, ',');
if (!last) {
fprintf(stderr, "tcp/udp with no destination port\n");
return 1;
char *s, *t;
for (s = *cpp; *s; s++)
- if ((t = strchr(tcp_flagset, *s)))
+ if ((t = index(tcp_flagset, *s)))
tcp->th_flags |= tcp_flags[t - tcp_flagset];
if (tcp->th_flags)
cpp++;
s++, i++)
if (*s && !strncasecmp(*cpp, *s, strlen(*s))) {
ic->icmp_type = i;
- if ((t = strchr(*cpp, ',')))
+ if ((t = index(*cpp, ',')))
ic->icmp_code = atoi(t+1);
cpp++;
break;
-.LP
.TH ipftest 8
.SH NAME
-ipftest - test packet filter rules with arbitary input.
+ipftest \- test packet filter rules with arbitary input.
.SH SYNOPSIS
-ipftest [-vbdPSTEHX] [-I interface] -r <filename> [-i <filename>]
+.B ipftest
+[
+.B \-vbdPSTEHX
+] [
+.B \-I
+interface
+]
+.B \-r
+<filename>
+[
+.B \-i
+<filename>
+]
.SH DESCRIPTION
-.LP
.PP
\fBipftest\fP is provided for the purpose of being able to test a set of
-filter rules without having to put them in place, in operation and procede
+filter rules without having to put them in place, in operation and proceed
to test their effectiveness. The hope is that this minimises disruptions
in providing a secure IP environment.
.PP
idea of what is happening with packets passing through their filter
ruleset.
.PP
-When used without eiether of \fB-S\fP, \fB-T\fP or \fB-E\fP,
+When used without either of \fB\-S\fP, \fB\-T\fP or \fB\-E\fP,
\fBipftest\fP uses its own text input format to generate "fake" IP packets.
The format used is as follows:
.nf
out on le0 tcp 10.4.12.1,2245 10.1.1.1,23 S
.fi
.SH OPTIONS
-.IP -v
+.TP
+.B \-v
Verbose mode. This provides more information about which parts of rule
matching the input packet passes and fails.
-.IP -d
+.TP
+.B \-d
Turn on filter rule debugging. Currently, this only shows you what caused
the rule to not match in the IP header checking (addresses/netmasks, etc).
-.IP -b
+.TP
+.B \-b
Cause the output to be a brief summary (one-word) of the result of passing
the packet through the filter; either "pass", "block" or "nomatch".
This is used in the regression testing.
-.IP -I <interface>
+.TP
+.BR \-I \0<interface>
Set the interface name (used in rule matching) to be the name supplied.
-This is useful with the \fB-P, -S, -T\fP and \fB-E\fP options, where it is
+This is useful with the \fB\-P, \-S, \-T\fP and \fB\-E\fP options, where it is
not otherwise possible to associate a packet with an interface. Normal
"text packets" can override this setting.
-.IP -P
-The input file specified by \fB-i\fP is a binary file produced using libpcap
-(ie tcpdump version 3). Packets are read from this file as being input
-(for rule purposes). An interface maybe specified using \fB-I\fP.
-.IP -S
+.TP
+.B \-P
+The input file specified by \fB\-i\fP is a binary file produced using libpcap
+(i.e., tcpdump version 3). Packets are read from this file as being input
+(for rule purposes). An interface maybe specified using \fB\-I\fP.
+.TP
+.B \-S
The input file is to be in "snoop" format (see RFC 1761). Packets are read
from this file and used as input from any interface. This is perhaps the
most useful input type, currently.
-.IP -T
+.TP
+.B \-T
The input file is to be text output from tcpdump. The text formats which
are currently supported are those which result from the following tcpdump
option combinations:
tcpdump -nqte
.fi
.LP
-.IP -H
+.TP
+.B \-H
The input file is to be hex digits, representing the binary makeup of the
packet. No length correction is made, if an incorrect length is put in
the IP header.
-.IP -X
+.TP
+.B \-X
The input file is composed of text descriptions of IP packets.
-.IP -E
+.TP
+.B \-E
The input file is to be text output from etherfind. The text formats which
are currently supported are those which result from the following etherfind
option combinations:
etherfind -n -t
.fi
.LP
-.IP -i <filename>
-Specify the filename to take input from. Default is stdin.
-.IP -r <filename>
+.TP
+.BR \-i \0<filename>
+Specify the filename from which to take input. Default is stdin.
+.TP
+.BR \-r \0<filename>
Specify the filename from which to read filter rules.
.SH FILES
.SH SEE ALSO
#include "ipt.h"
#include <ctype.h>
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-1996 Darren Reed";
-static char rcsid[] = "$Id: ipt.c,v 1.7 1997/01/17 07:14:08 millert Exp $";
+static char rcsid[] = "$Id: ipt.c,v 1.8 1997/02/11 22:23:58 kstailey Exp $";
#endif
extern int fr_check();
/*
* treat both CR and LF as EOL
*/
- if ((s = strchr(line, '\n')))
+ if ((s = index(line, '\n')))
*s = '\0';
- if ((s = strchr(line, '\r')))
+ if ((s = index(line, '\r')))
*s = '\0';
/*
* # is comment marker, everything after is a ignored
*/
- if ((s = strchr(line, '#')))
+ if ((s = index(line, '#')))
*s = '\0';
if (!*line)
while ((i = (*r->r_readip)(buf, sizeof(buf), &iface, &dir)) > 0) {
ip->ip_off = ntohs(ip->ip_off);
ip->ip_len = ntohs(ip->ip_len);
- switch (fr_check(ip, ip->ip_hl << 2, iface, dir))
+ switch (fr_check(ip, ip->ip_hl << 2, iface, dir)) /* XXX */
{
case -1 :
(void)printf("block");
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
- * $Id: ipt.h,v 1.2 1996/07/18 04:59:25 dm Exp $
+ * $Id: ipt.h,v 1.3 1997/02/11 22:24:00 kstailey Exp $
*/
#include <fcntl.h>
#include "ipf.h"
#include "ipt.h"
-#ifndef lint
+#if !defined(lint) && defined(LIBC_SCCS)
static char sccsid[] = "@(#)misc.c 1.3 2/4/96 (C) 1995 Darren Reed";
+static char rcsid[] = "$Id: misc.c,v 1.5 1997/02/11 22:24:01 kstailey Exp $";
#endif
void debug(), verbose();
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
- * $Id: pcap.h,v 1.3 1996/07/18 04:59:26 dm Exp $
+ * $Id: pcap.h,v 1.4 1997/02/11 22:24:03 kstailey Exp $
*/
/*
* This header file is constructed to match the version described by
/*
* written to comply with the RFC (1761) from Sun.
- * $Id: snoop.h,v 1.2 1996/07/18 04:59:26 dm Exp $
+ * $Id: snoop.h,v 1.3 1997/02/11 22:24:04 kstailey Exp $
*/
struct snoophdr {
char s_id[8];
-.LP
.TH ipmon 8
.SH NAME
-ipmon - monitors /dev/ipl for logged packets
+ipmon \- monitors /dev/ipl for logged packets
.SH SYNOPSIS
-ipmon [-sfN] [<filename>]
+.B ipmon
+[
+.B \-sfN
+] [
+<filename>
+]
.SH DESCRIPTION
.LP
\fBipmon\fP opens \fB/dev/ipl\fP for reading and awaits data to be saved from
the packet filter. The binary data read from the device is reprinted in
human readable for, however, IP#'s are not mapped back to hostnames, nor are
ports mapped back to service names. The output goes to standard output by
-default or a filename, if given on the command line. Should the \fB-s\fP
+default or a filename, if given on the command line. Should the \fB\-s\fP
option be used, output is instead sent to \fBsyslogd(8)\fP. Messages sent
via syslog have the day, month and year removed from the message, but the
time (including microseconds), as recorded in the log, is still included.
.SH OPTIONS
.TP
-.B -s
+.B \-s
Packet information read in will be sent through syslogd rather than
saved to a file. The following levels are used:
-.TP
.IP
-.RS
-.B LOG_INFO - packets logged using the "log" keyword as the action rather
+.B LOG_INFO
+\- packets logged using the "log" keyword as the action rather
than pass or block.
-.TP 3
-.B LOG_NOTICE - packets logged which are also passed
-.TP 3
-.B LOG_WARNING - packets logged which are also blocked
-.TP 3
-.B LOG_ERR - packets which have been logged and which can be considered
+.IP
+.B LOG_NOTICE
+\- packets logged which are also passed
+.IP
+.B LOG_WARNING
+\- packets logged which are also blocked
+.IP
+.B LOG_ERR
+\- packets which have been logged and which can be considered
"short".
-.RE
.TP
-.B -f
+.B \-f
Flush the current packet log buffer. The number of bytes flushed is displayed,
even should the result be zero.
.TP
-.B -N
+.B \-N
IP addresses and port numbers will be mapped, where possible, back into
hostnames and service names.
.SH DIAGNOSTICS
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
-#include <sys/syslog.h>
+#include <stdlib.h>
+#include <syslog.h>
#include <sys/errno.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <arpa/inet.h>
+#include <ctype.h>
-#ifndef lint
-static char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-1996 Darren Reed";
-static char rcsid[] = "$Id: ipmon.c,v 1.6 1996/10/08 07:33:38 niklas Exp $";
+#if !defined(lint) && defined(LIBC_SCCS)
+static char rcsid[] = "$Id: ipmon.c,v 1.7 1997/02/11 22:24:10 kstailey Exp $";
#endif
#include "ip_fil_compat.h"
#include "ip_fil.h"
+
struct flags {
int value;
char flag;
{ 0, '\0' }
};
+
static char line[2048];
-static void printpacket();
+static void printpacket(), dumphex();
+static int opts = 0;
+
+#define OPT_SYSLOG 0x01
+#define OPT_RESOLVE 0x02
+#define OPT_HEXBODY 0x04
+#define OPT_VERBOSE 0x08
+#define OPT_HEXHDR 0x10
+
+#ifndef LOGFAC
+#define LOGFAC LOG_LOCAL0
+#endif
+
+void printiplci(icp)
+struct ipl_ci *icp;
+{
+ printf("sec %ld usec %ld hlen %d plen %d\n", icp->sec, icp->usec,
+ icp->hlen, icp->plen);
+}
+
+
+void resynclog(fd, iplcp, log)
+int fd;
+struct ipl_ci *iplcp;
+FILE *log;
+{
+ time_t now;
+ char *s = NULL;
+ int len, nr = 0;
+
+ do {
+ if (s) {
+ s = (char *)&iplcp->sec;
+ if (opts & OPT_SYSLOG) {
+ syslog(LOG_INFO, "Sync bytes:");
+ syslog(LOG_INFO, " %02x %02x %02x %02x",
+ *s, *(s+1), *(s+2), *(s+3));
+ syslog(LOG_INFO, " %02x %02x %02x %02x\n",
+ *(s+4), *(s+5), *(s+6), *(s+7));
+ } else {
+ fprintf(log, "Sync bytes:");
+ fprintf(log, " %02x %02x %02x %02x",
+ *s, *(s+1), *(s+2), *(s+3));
+ fprintf(log, " %02x %02x %02x %02x\n",
+ *(s+4), *(s+5), *(s+6), *(s+7));
+ }
+ }
+ do {
+ s = (char *)&iplcp->sec;
+ len = sizeof(iplcp->sec);
+ while (len) {
+ switch ((nr = read(fd, s, len)))
+ {
+ case -1:
+ case 0:
+ return;
+ default :
+ s += nr;
+ len -= nr;
+ now = time(NULL);
+ break;
+ }
+ }
+ } while ((now < iplcp->sec) ||
+ ((iplcp->sec - now) > (86400*5)));
+
+ len = sizeof(iplcp->usec);
+ while (len) {
+ switch ((nr = read(fd, s, len)))
+ {
+ case -1:
+ case 0:
+ return;
+ default :
+ s += nr;
+ len -= nr;
+ break;
+ }
+ }
+ } while (iplcp->usec > 1000000);
+
+ len = sizeof(*iplcp) - sizeof(iplcp->sec) - sizeof(iplcp->usec);
+ while (len) {
+ switch ((nr = read(fd, s, len)))
+ {
+ case -1:
+ case 0:
+ return;
+ default :
+ s += nr;
+ len -= nr;
+ break;
+ }
+ }
+}
+
+
+int readlogentry(fd, lenp, buf, bufsize, log)
+int fd, bufsize, *lenp;
+char *buf;
+FILE *log;
+{
+ struct ipl_ci *icp = (struct ipl_ci *)buf;
+ time_t now;
+ char *s;
+ int len, n = bufsize, tr = sizeof(struct ipl_ci), nr;
+
+ if (bufsize < tr)
+ return 1;
+ for (s = buf; (n > 0) && (tr > 0); s += nr, n -= nr) {
+ nr = read(fd, s, tr);
+ if (nr > 0)
+ tr -= nr;
+ else
+ return -1;
+ }
+
+ now = time(NULL);
+ if ((icp->hlen > 92) || (now < icp->sec) ||
+ ((now - icp->sec) > (86400*5))) {
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_INFO, "Out of sync! (1,%x)\n", now);
+ else
+ fprintf(log, "Out of sync! (1,%x)\n", now);
+ dumphex(log, buf, sizeof(struct ipl_ci));
+ resynclog(fd, icp, log);
+ }
+
+
+ len = (int)((u_int)icp->plen);
+ if (len > 128 || len < 0) {
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_INFO, "Out of sync! (2,%d)\n", len);
+ else
+ fprintf(log, "Out of sync! (2,%d)\n", len);
+ dumphex(log, buf, sizeof(struct ipl_ci));
+ resynclog(fd, icp, log);
+ }
+
+
+ tr = icp->hlen + icp->plen;
+ if (n < tr)
+ return 1;
+
+ for (; (n > 0) && (tr > 0); s += nr, n-= nr) {
+ nr = read(fd, s, tr);
+ if (nr > 0)
+ tr -= nr;
+ else
+ return -1;
+ }
+ *lenp = s - buf;
+ return 0;
+}
char *hostname(res, ip)
}
-static void dumphex(log, ip, lp)
+static void dumphex(log, buf, len)
FILE *log;
-struct ip *ip;
-struct ipl_ci *lp;
+u_char *buf;
+int len;
{
+ char line[80];
int i, j, k;
- u_char *s = (u_char *)ip;
+ u_char *s = buf, *t = (u_char *)line;
- for (i = lp->plen + lp->hlen, j = 0; i; i--, j++, s++) {
- if (j && !(j & 0xf))
- putchar('\n');
- printf("%02x", *s);
+ for (i = len, j = 0; i; i--, j++, s++) {
+ if (j && !(j & 0xf)) {
+ *t++ = '\n';
+ *t = '\0';
+ fputs(line, stdout);
+ t = (u_char *)line;
+ *t = '\0';
+ }
+ sprintf(t, "%02x", *s & 0xff);
+ t += 2;
if (!((j + 1) & 0xf)) {
- s -= 16;
- printf(" ");
+ s -= 15;
+ sprintf(t, " ");
+ t += 8;
for (k = 16; k; k--, s++)
- putchar(isprint(*s) ? *s : '.');
+ *t++ = (isprint(*s) ? *s : '.');
+ s--;
}
if ((j + 1) & 0xf)
- putchar(' ');
+ *t++ = ' ';;
}
- if ((j - 1) & 0xf)
- putchar('\n');
+ if (j & 0xf) {
+ for (k = 16 - (j & 0xf); k; k--) {
+ *t++ = ' ';
+ *t++ = ' ';
+ *t++ = ' ';
+ }
+ sprintf(t, " ");
+ t += 7;
+ s -= j & 0xf;
+ for (k = j & 0xf; k; k--, s++)
+ *t++ = (isprint(*s) ? *s : '.');
+ *t++ = '\n';
+ *t = '\0';
+ }
+ fputs(line, stdout);
+ fflush(stdout);
}
-static void printpacket(log, ip, lp, opts)
+static void printpacket(log, buf, blen)
FILE *log;
-struct ip *ip;
-struct ipl_ci *lp;
-int opts;
+char *buf;
+int blen;
{
struct protoent *pr;
struct tcphdr *tp;
struct tm *tm;
char c[3], pname[8], *t, *proto;
u_short hl, p;
- int i, lvl, res, len;
+ int i, lvl, res;
+#if !SOLARIS && !(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603))\
+ && !(defined(OpenBSD) && (OpenBSD <= 1991011) && (OpenBSD >= 199603))
+ int len;
+#endif
+ struct ip *ip;
+ struct ipl_ci *lp;
- res = (opts & 2) ? 1 : 0;
+ lp = (struct ipl_ci *)buf;
+ ip = (struct ip *)(buf + sizeof(*lp));
+ res = (opts & OPT_RESOLVE) ? 1 : 0;
t = line;
*t = '\0';
hl = (ip->ip_hl << 2);
p = (u_short)ip->ip_p;
tm = localtime((time_t *)&lp->sec);
- if (!(opts & 1)) {
+ if (!(opts & OPT_SYSLOG)) {
(void) sprintf(t, "%2d/%02d/%4d ",
tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900);
t += strlen(t);
}
-#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \
- (defined(OpenBSD) && (OpenBSD >= 199606))
- (void) sprintf(t, "%02d:%02d:%02d.%-.6ld %s @%hd ",
+#if SOLARIS || (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) \
+ || (defined(OpenBSD) && (OpenBSD <= 1991011) && (OpenBSD >= 199603))
+ (void) sprintf(t, "%02d:%02d:%02d.%-.6ld %.*s @%hd ",
tm->tm_hour, tm->tm_min, tm->tm_sec, lp->usec,
- lp->ifname, lp->rule);
+ (int)sizeof(lp->ifname), lp->ifname, lp->rule);
#else
for (len = 0; len < 3; len++)
if (!lp->ifname[len])
if (tp->th_flags & tcpfl[i].value)
*t++ = tcpfl[i].flag;
}
+ if (opts & OPT_VERBOSE) {
+ (void) sprintf(t, " %lu %lu %hu",
+ (u_long)tp->th_seq,
+ (u_long)tp->th_ack, tp->th_win);
+ t += strlen(t);
+ }
*t = '\0';
} else {
(void) sprintf(t, "%s -> ", hostname(res, ip->ip_src));
*t++ = '\n';
*t++ = '\0';
- if (opts & 1)
+ if (opts & OPT_SYSLOG)
syslog(lvl, "%s", line);
else
(void) fprintf(log, "%s", line);
+ if (opts & OPT_HEXHDR)
+ dumphex(log, buf, sizeof(struct ipl_ci));
+ if (opts & OPT_HEXBODY)
+ dumphex(log, ip, lp->plen + lp->hlen);
fflush(log);
- if (opts & 4)
- dumphex(log, ip, lp);
}
int main(argc, argv)
int argc;
char *argv[];
{
- FILE *log;
- int fd, flushed = 0, opts = 0;
- u_int len;
- char buf[512], c;
- struct ipl_ci iplci;
+ FILE *log = NULL;
+ int fd = -1, flushed = 0, doread, n;
+ char buf[512], c, *iplfile = IPL_NAME;
extern int optind;
+ extern char *optarg;
- if ((fd = open(IPL_NAME, O_RDONLY)) == -1) {
- (void) fprintf(stderr, "%s: ", IPL_NAME);
- perror("open");
- exit(-1);
- }
-
- while ((c = getopt(argc, argv, "Nfsx")) != -1)
+ while ((c = getopt(argc, argv, "Nf:FsvxX")) != -1)
switch (c)
{
case 'f' :
+ iplfile = optarg;
+ break;
+ case 'F' :
+ if ((fd == -1) &&
+ (fd = open(iplfile, O_RDWR)) == -1) {
+ (void) fprintf(stderr, "%s: ", IPL_NAME);
+ perror("open");
+ exit(-1);
+ }
if (ioctl(fd, SIOCIPFFB, &flushed) == 0) {
printf("%d bytes flushed from log buffer\n",
flushed);
fflush(stdout);
- }
+ } else
+ perror("SIOCIPFFB");
break;
case 'N' :
- opts |= 2;
- break;
- case 'x' :
- opts |= 4;
+ opts |= OPT_RESOLVE;
break;
case 's' :
openlog(argv[0], LOG_NDELAY|LOG_PID, LOGFAC);
- opts |= 1;
+ opts |= OPT_SYSLOG;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ case 'x' :
+ opts |= OPT_HEXBODY;
+ break;
+ case 'X' :
+ opts |= OPT_HEXHDR;
break;
}
- log = argv[optind] ? fopen(argv[1], "a") : stdout;
- setvbuf(log, NULL, _IONBF, 0);
- if (flushed)
- fprintf(log, "%d bytes flushed from log\n", flushed);
-
- while (1) {
- assert(read(fd, &iplci, sizeof(struct ipl_ci)) ==
- sizeof(struct ipl_ci));
- assert(iplci.hlen > 0 && iplci.hlen <= 92);
- len = (u_int)iplci.plen;
- assert(len <= 128);
- assert(read(fd, buf, iplci.hlen + iplci.plen) ==
- (iplci.hlen + iplci.plen));
- printpacket(log, buf, &iplci, opts);
+ if ((fd == -1) && (fd = open(iplfile, O_RDONLY)) == -1) {
+ (void) fprintf(stderr, "%s: ", IPL_NAME);
+ perror("open");
+ exit(-1);
+ }
+
+ if (!(opts & OPT_SYSLOG)) {
+ log = argv[optind] ? fopen(argv[optind], "a") : stdout;
+ setvbuf(log, NULL, _IONBF, 0);
}
- /* NOTREACHED */
+
+ if (flushed) {
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_INFO, "%d bytes flushed from log\n",
+ flushed);
+ else
+ fprintf(log, "%d bytes flushed from log\n", flushed);
+ }
+
+ for (doread = 1; doread; )
+ switch (readlogentry(fd, &n, buf, sizeof(buf), log))
+ {
+ case -1 :
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_ERR, "read: %m\n");
+ else
+ perror("read");
+ doread = 0;
+ break;
+ case 1 :
+ if (opts & OPT_SYSLOG)
+ syslog(LOG_ERR, "aborting logging\n");
+ else
+ fprintf(log, "aborting logging\n");
+ doread = 0;
+ break;
+ case 2 :
+ break;
+ case 0 :
+ printpacket(log, buf, n, opts);
+ break;
+ }
exit(0);
/* NOTREACHED */
}