diff options
author | ngie <ngie@FreeBSD.org> | 2015-10-05 03:26:51 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2015-10-05 03:26:51 +0000 |
commit | e1dd16d965b177f109afb771e59432e36f335d0a (patch) | |
tree | 15db092a5401cf329f1bff9d3bf700d1fde0f121 /contrib/ipfilter | |
parent | 115d008392113efc6f844baa7cc407e9eaae63db (diff) | |
download | FreeBSD-src-e1dd16d965b177f109afb771e59432e36f335d0a.zip FreeBSD-src-e1dd16d965b177f109afb771e59432e36f335d0a.tar.gz |
Revert r288682
I meant to do this on ^/user/ngie/more-tests
Pointyhat to: ngie (use svn info next time...)
Diffstat (limited to 'contrib/ipfilter')
319 files changed, 70759 insertions, 0 deletions
diff --git a/contrib/ipfilter/BNF b/contrib/ipfilter/BNF new file mode 100644 index 0000000..ef35d25 --- /dev/null +++ b/contrib/ipfilter/BNF @@ -0,0 +1,81 @@ +filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] + [ proto ] [ ip ] [ group ] [ tag ] [ pps ] . + +insert = "@" decnumber . +action = block | "pass" | log | "count" | auth | call . +in-out = "in" | "out" . +options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] . +tos = "tos" decnumber | "tos" hexnumber . +ttl = "ttl" decnumber . +proto = "proto" protocol . +ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . +group = [ "head" decnumber ] [ "group" decnumber ] . +pps = "pps" decnumber . + +onif = "on" interface-name [ "out-via" interface-name ] . +block = "block" [ return-icmp[return-code] | "return-rst" ] . +auth = "auth" | "preauth" . +log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . +tag = "tag" tagid . +call = "call" [ "now" ] function-name "/" decnumber. +dup = "dup-to" interface-name[":"ipaddr] . +froute = "fastroute" | "to" interface-name . +replyto = "reply-to" interface-name [ ":" ipaddr ] . +protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber . +srcdst = "all" | fromto . +fromto = "from" object "to" object . + +return-icmp = "return-icmp" | "return-icmp-as-dest" . +loglevel = facility"."priority | priority . +object = addr [ port-comp | port-range ] . +addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +port-comp = "port" compare port-num . +port-range = "port" port-num range port-num . +flags = "flags" flag { flag } [ "/" flag { flag } ] . +with = "with" | "and" . +icmp = "icmp-type" icmp-type [ "code" decnumber ] . +return-code = "("icmp-code")" . +keep = "keep" "state" [ "limit" number ] | "keep" "frags" . + +nummask = host-name [ "/" decnumber ] . +host-name = ipaddr | hostname | "any" . +ipaddr = host-num "." host-num "." host-num "." host-num . +host-num = digit [ digit [ digit ] ] . +port-num = service-name | decnumber . + +withopt = [ "not" | "no" ] opttype [ [ "," ] withopt ] . +opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" | + "mbcast" | "opt" ipopts . +optname = ipopts [ "," optname ] . +ipopts = optlist | "sec-class" [ secname ] . +secname = seclvl [ "," secname ] . +seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" | + "reserv-4" | "secret" | "topsecret" . +icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" | + "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" | + "inforep" | "maskreq" | "maskrep" | "routerad" | + "routersol" | decnumber . +icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" | + "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" | + "net-prohib" | "host-prohib" | "net-tos" | "host-tos" | + "filter-prohib" | "host-preced" | "cutoff-preced" . +optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" | + "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" | + "visa" | "imitd" | "eip" | "finn" . +facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" | + "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" | + "audit" | "logalert" | "local0" | "local1" | "local2" | + "local3" | "local4" | "local5" | "local6" | "local7" . +priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" | + "info" | "debug" . + +hexnumber = "0" "x" hexstring . +hexstring = hexdigit [ hexstring ] . +decnumber = digit [ decnumber ] . + +compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" | + "le" | "ge" . +range = "<>" | "><" . +hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" . +digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . +flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" . diff --git a/contrib/ipfilter/BugReport b/contrib/ipfilter/BugReport new file mode 100644 index 0000000..6994831 --- /dev/null +++ b/contrib/ipfilter/BugReport @@ -0,0 +1,12 @@ +Please submit this information at SourceForge using this URL: +http://sourceforge.net/tracker/?func=add&group_id=169098&atid=849053 + +Please also send an email to darrenr@reed.wattle.id.au. + +Some information that I generally find important: +-------------------------- +* IP Filter Version +* Operating System and its Version +* Configuration: (LKM or compiled-into-kernel) +* Description of problem +* How to repeat diff --git a/contrib/ipfilter/HISTORY b/contrib/ipfilter/HISTORY new file mode 100644 index 0000000..8b67de7 --- /dev/null +++ b/contrib/ipfilter/HISTORY @@ -0,0 +1,1830 @@ +# +# NOTE: Quite a few patches and suggestions come from other sources, to whom +# I'm greatly indebted, even if no names are mentioned. +# +# Thanks to the Coombs Computing Unit at the ANU for their continued support +# in providing a very available location for the IP Filter home page and +# distribution center. +# +# Thanks also to all those who have contributed patches and other code, +# and especially those who have found the time to port IP Filter to new +# platforms. +# +5.1.2 - RELEASED - 22 Jul 2012 + +3546266 macro letters could be more consistent +3546265 not all of the state statistics are displayed +3546261 scripts for updating BSD environment out of date +3546260 compiler warnings about non-integer array subscript +3546259 asserting numdereflists == 0 is not correct +3546258 expression matching does not see IPF_EXP_END +3544317 ipnat/ipfstat are not using ipfexp_t +3545324 proxy checksum calculation is not hardware aware +3545321 FTP sequence number adjustment incorrectly applied +3545320 EPSV is not recognised +3545319 move nat rule creation to ip_proxy.c +3545317 better feedback of checksum requirements for proxies +3545314 ftp proxy levels do not make sense +3545312 EPRT is not supported by ftp proxy +3544318 ipnat.conf parsing ignores LHS address family +3545309 non-ipv6 safe proxies do not fail with ipv6 +3545323 NAT updates the source port twice +3545322 ipv6 nat rules cannot start proxies +3544314 bucket copyout tries to copy too much data +3544313 remove nat encap feature +3546248 compat rule pointer type mismatch +3546247 UDP hardware checksum offload not recognised +3545311 ifp_ifaddr does not find the first set address +3545310 ipmon needs ipl_sec on 64bit boundary +3545326 reference count changes made without lock +3544315 stateful matching does not use ipfexp_t +3543493 tokens are not flushed when disabled +3543487 NAT rules do not always release lookup objects +3543491 function comments in ip_state.c are old +3543404 ipnat.conf parsing uses family/ip version badly +3543403 incorrect line number printed in ipnat parsing errors +3543402 Not all NAT statistics are printed +3542979 NAT session list management is too simple +3542978 ipv4 and ipv6 nat insert have common hash insertion +3542977 ipnat_t refence tracking incomplete +3542975 proxies must use ipnat_t separately +3542980 printing ipv6 expressions is wrong +3542983 ippool cannot handle more than one ipv6 address +3543018 mask array shifted incorrectly. +3542974 reason for dropping packet is lost +3542982 line numbers not recorded/displayed correctly by ipf +3542981 exclamation mark cuases trouble with pools +3541655 test suite checksums incorrect +3541653 display proxy fail status correctly +3540993 IP header offset excluded in pullup calculations +3540994 pullupmsg does not work as required +3540992 pointer to ipv6 frag header not updated on pullup +3541645 netmask management adds /32 for /0 +3541637 ipnat parser does not zero port fields for non-port protocol +3541635 pool names cannot by numbers +3540995 IPv6 fragment tracking does not always work +3540996 printing of nextip for ipv6 nat rules is wrong +3540999 ipnat.conf parsing has trouble with icmpidmap for ipv6 +3540825 whois output parsing error for ipv6 +3540814 ipfd_lock serves no purpose +3540810 lookup objects need tail pointers +3540809 refactor hash table lookups for nat +3540819 radix tree does not work with ipv6 +3540820 mutex emulation should be logged +3540828 ipfstat filtering with -m fails tests +3536480 ippool could be more like the others +3536477 pool printing not uniform +3536483 flushing empty destination lists causes panic +3536481 more use of bzero after KMALLOC required +3536479 ipnat.conf line numbers not stored +3536484 Makefile missing dependency for ippool +3536199 TFTP proxy requires something extra +3536198 ICMP checksum out by one +3536203 ipnat does not return an error +3536201 ipf.conf parsing too address friendly +3536200 printing of bytes/packets not indented +3497941 ipv4 multicast detection incorrect on little endian +3535361 to interfaces printed out of order +3535363 ipf parser is inconsistent +3532306 deleting ipnat rules does not work +3532054 new error required for ipf_rx_create +3532053 icmp6 checksums wrong +3532052 icmpv6 state check with incorrect length +3531871 checksum verification wants too many icmp6 bytes +3531870 ipnat.conf parsing needs to support inet6 +3532048 error in ipf group parsing +3531868 ICMPV6 checksum not validated +3531893 ipftest exits without error for bad input +3531890 whois pool parsing builds bad structures +3531891 icmpv6 text parsing ignorant of icmp types +3531653 rewrite with icmp does not work +3530563 NAT operations fail with EPERM +3530544 first pass at gcc -Wextra cleanup +3530540 lookup create functions do not set error properly +3530539 ipf_main_soft_destroy doesn't need 2nd arg +3530541 reorder structure for better packing +3530543 ipnat purge needs documentation +3530515 BSD upgrade script required +3528029 ipmon bad-mutex panic +3530247 loading address pools light on input validation +3530255 radix tree delete uses wrong lookup +3530254 radix tree allocation support wrong +3530264 ipmon prints qd for some 64bit numbers +3530260 decapsulate rules not printed correctly. +3530266 ipfstat -v/-d flags confused +2939220 why a packet is blocked is not discernable +2939218 output interface not recorded +2941850 use of destination lists with to/dup-to beneficial +3457747 build errors introduced with radix change +3535360 timeout groups leak +3535359 memory leak with tokens +3535358 listing rules in groups requires tracking groups +3535357 rule head removal is problematic +3530259 not all ioctl error checked wth SIOCIPFINTERROR +3530258 error routine that uses fd required +3530253 inadequate function comment blocks +3530249 walking lookup tables leaks memory +3530241 extra lock padding required for freebsd +3529901 ipf returns 0 when rules fail to load +3529491 checksum validation could be better +3529486 tcp checksum wrong for ipv6 +3533779 ipv6 nat rules missing inet6 keyword +3532693 ipnat.conf rejects some ipv6 addresses +3532691 ipv4 should not be forced for icmp +3532689 ipv6 nat rules do not print inet6 +3532688 ipv6 address always printed with "to <if>" +3532687 with v6hdrs not supported like with ipopts +3532686 ipf expressions do not work with ipv6 +3540825 whois output parsing error for ipv6 +3540818 NAT for certain IPv6 ICMP packets should not be allowed +3540815 memory leak with destination lists +3540814 ipfd_lock serves no purpose +3540810 lookup objects need tail pointers +3540809 refactor hash table lookups for nat +3540808 completed tokens do not stop iteration +3530492 address hash table name not used +3528029 ipmon bad-mutex panic +3530256 hook memory leaked +3530271 pools parsing produces badly formed address structures +3488061 cleanup for illumos build +3484434 SIOCIPFINTERROR must work for all devices +3484067 mandoc -Tlint warnings to be fixed +3483343 compile warning in ipfcomp.c +3482893 building without IPFILTER_LOG fails +3482765 building netbsd kernel without inet6 fails +3482116 ipf_check frees packet from ipftest +3481663 does not compile on solaris 11 + +5.1.1 - RELEASED - 9 May 2012 + +3481322 ip_fil_compat.c needs a cleanup +3481211 add user errors to dtrace +3481152 compatibility for 4.1 needs more work +3481153 PRIu64 problems on FreeBSD +3481155 ipnat listing incorrect +3480543 change leads to compat problems +3480538 compiler errors from earlier patch +3480537 ipf_instance_destroy is incomplete +3480536 _fini order leads to panic +3479991 compiler warnings about size mismatches +3479974 copyright dates are wrong (fix) +3479464 add support for leaks testing +3479457 %qu is not the prefered way +3479451 iterators leak memory +3479453 nat rules with pools leak +3479454 memory leak in hostmap table +3479461 load_hash uses memory after free +3479462 printpool leaks memory +3479452 missing FREE_MB_T to freembt leaks +3479450 ipfdetach is called when detached +3479448 group mapping rules memory leak +3479455 memory leak from tuning +3479458 ipf must be running in global zone +3479460 driver replace is wrong +3479459 radix tree tries to free null pointer +3479463 rwlock emulation does not free memory +3479465 parser leaks memory +3475959 hardware checksum not correctly used +3475426 ip pseudo checksum wrong +3473566 radix tree does not delete dups right +3472987 compile is not clean +3472337 not everything is zero'd +3472344 interface setup needs to be after insert +3472340 wildcard counter drops twice +3472338 change fastroute interface +3472335 kernel lock defines not placed correctly +3472324 ICMP INFOREQ/REPLY not handled +3472330 multicast packets tagged by address +3472333 ipf_deliverlocal called incorrectly +3472345 mutex debug could be more granular +3472761 building i19 regression is flawed +3456457 use of bsd tree.h needs to be removed +3460522 code cleanup required for building on freebsd +3459734 trade some cpu for memory +3457747 build errors introduced with radix change +3457804 build errors from removal of pcap-int,h +3440163 rewrite radix tree +3428004 snoop, tcpdump, etherfind readers are unused +3439495 ipf_rand_push never called (fix brackets) +3437732 getnattype does not need to use ipnat_t (fix variable name) +3437696 fr_cksum is a nightmare +3439061 ipf_send_ip doesn't need 3rd arg +3439059 ipid needs to be file local +3437740 complete buildout of fnew +3438575 add dtrace probes to block events +3438347 comment blocks missing softc +3437687 description of ipf_makefrip wrong +3438340 more stats as dtrace probes +3438316 free on nat structure uses fixed size +3437745 nat iterator using the wrong size +3437710 fail checksum verification if packet is short +3437696 fr_cksum is a nightmare +3437732 getnattype does not need to use ipnat_t +3437735 rename ipf_allocmbt to allocmbt +3437697 fr_family to version assignment is wrong +3437746 ap_session_t has unused fields +3437747 move softc structure to .h file (ip_state.c) +3437704 there is no DTRACE_PROBE5 +3437748 wrong interface in qpktinfo_t +3437729 create function to hexdump mb_t +3438273 msgdsize should be easier to read +3437683 object direction not set for 32bit +3433767 calling ip_cksum could be easier +3433764 left over locking +3428015 printing proxy data size is useless +3428013 add M_ADJ to hide adjmsg/m_adj +3428012 interface name is not always returned correctly +3428002 ip_ttl is too low +3427997 ipft readers do not set buffer length +3426558 resistence is futile +3424495 various copy-paste errors +1826936 shall we allow ipf to be as dumb as its admin +3424477 specfuncs needs to go +3424484 missing fr_checkv6sum +3424478 one entry at a time +2998760 auth rules do not mix well with to/dup-to/fastroute +3424195 add ctfmerge to sunos5 makefile +3424132 some dtrace probes to start with +3423812 makefile needs ip_frag.h for some files +3423817 reference count useful in verbose output +3423800 walking lists does not drop reference +3423805 fragmentation stats not reported correclty +3423808 ip addresses reportied incorrectly with ipfstat -f +3423821 track packets and bytes for fragmentation +3423803 attempt to double free rule +3423805 fragmentation stats not reported correctly +3422712 system panic with ipfstat -f +3422619 pullup counter bumped for every packet +3422608 dummy rtentry required to build +3422018 frflush next to ipf_fini_all is redundant +3422012 instance cleanup is not clean +3421845 instance name not set +3005622 ip_fil5.1.0 does not load on Solaris 10 U8 +2976332 stateful filtering is incompatible with ipv4 options +3387509 ipftest needs help construction ip packets with options +2998746 passp can never be null +3064034 mbuf clobbering problem with ipv6 +3105725 ipnat divide by zero panic +2998750 ipf_htent_insert can leak memory +3064034 mbuf clobbering problem with ipv6 +3105725 ipnat divie by zero panic + +5.1 - RELEASED - 9 May 2010 + +* See WhatsNew50.txt + +4.1 - RELEASED - 12 February 2004 + +4.0-BETA1 20 August 2003 + +support 0/32 and 0/0 on the RHS in redirect rules + +where LHS and RHS netmasks are the same size for redirect, do 1:1 mapping +for bimap rules. + +allow NAT rule to match 'all' interfaces with * as interface name + +do mapping of ICMP sequence id#'s in pings + +allow default age for NAT entries to be set per NAT rule + +provide round robin selection of destination addresses for redirect + +ipmon can load a configuration file with instructions on actions +to take when a matching log entry is received + +now requires pfil to work on Solaris & HP-UX + +supports mapping outbound connections to a specific address/port + +support toggling of logging per ipfilter 'device' + +use queues to expire data rather than lists + +add MSN RPC proxy + +add IRC proxy + +support rules with dynamic ip addresses + +add ability to define a pool of addresses & networks which can then +be placed in a single rule + +support passing entire packet back to user program for authentication + +support master/slave for state information sharing + +reorganise generic code into a lib directory and make libipf.a + +user programs enforce version matching with the kernel + +supports window scaling if seen at TCP session setup + +generates C code from filter rules to compile in or load as native +machine code. + +supports loading rules comprised of BPF bytecode statements + +HP-UX 11 port completed + +and packets-per-second filtering + +add numerical tags to rules for filtering and display in ipmon output + +3.4.4 23/05/2000 - Released + +don't add TCP state if it is an RST packet and (attempt) to send out +RST/ICMP packets in a manner that bypasses IP Filter. + +add patch to work with 4.0_STABLE delayed checksums + +3.4.3 20/05/2000 - Released + +fix ipmon -F + +don't truncate IPv6 packets on Solaris + +fix keep state for ICMP ECHO + +add some NAT stats and use def_nat_age rather than DEF_NAT_AGE + +don't make ftp proxy drop packets + +use MCLISREFERENCED() in tandem with M_EXT to check if IP fields need to be +swapped back. + +fix up RST generation for non-Solaris + +get "short" flag right for IPv6 + +3.4.2 - 10/5/2000 - Released + +Fix bug in dealing with "hlen == 1 and opt > 1" - Itojun + +ignore previous NAT mappings for 0/0 and 0/32 rules + +bring in a completely new ftp proxy + +allow NAT to cause packets to be dropped. + +add NetBSD callout support for 1.4-current + +3.4.1 - 30/4/2000 - Released + +add ratoui() and fix parsing of group numbers to allow 0 - UINT_MAX + +don't include opt_inet6.h for FreeBSD if KLD_MODULE is defined + +Solaris must use copyin() for all types of ioctl() args + +fix up screen/tty when leaving "top mode" of ipfstat + +linked list for maptable not setup correctly in nat_hostmap() + +check for maptable rather than nat_table[1] to see if malloc for maptable +succeeded in nat_init + +fix handling of map NAT rules with "from/to" host specs + +fix printout out of source address when using "from/to" with map rules + +convert ip_len back to network byte order, not plen, for solaris as ip_len +may have been changed by NAT and plen won't reflect this + +3.4 - 27/4/2000 - Released + +source address spoofing can be turned on (fr_chksrc) without using +filter rules + +group numbers are now 32bits in size, up from 16bits + +IPv6 filtering available + +add frank volf's state-top patches + +add load splitting and round-robin attribute to redirect rules + +FreeBSD-4.0 support (including KLD) + +add top-style operation mode for ipfstat (-t) + +add save/restore of IP Filter state/NAT information (ipfs) + +further ftp proxy security checks + +support for adding and removing proxies at runtime + +3.3.13 26/04/2000 - Released + +Fix parsing of "range" with "portmap" + +Relax checking of ftp replies, slightly. + +Fix NAT timeouts for ICMP packets + +SunOS4 patches for ICMP redirects from Jurgen Keil (jk@tools.de) + +3.3.12 16/03/2000 - Released + +tighten up ftp proxy behaviour. sigh. yuck. hate. + +fix bug in range check for NAT where the last IP# was not used. + +fix problem with icmp codes > 127 in filter rules caused bad things to +happen and in particular, where #18 caused the rule to be printed +erroneously. + +fix bug with the spl level not being reset when returning EIO from +iplioctl due to ipfilter not being initialized yet. + +3.3.11 04/03/2000 - Released + +make "or-block" work with lines that start with "log" + +fix up parsing and printing of rules with syslog levels in them + +fix from Cy Schubert for calling of apr_fini only if non-null + + +3.3.10 24/02/2000 - Released + +* fix back from guido for state tracking interfaces + +* update for NetBSD pfil interface changes + +* if attaching fails and we can abort, then cleanup when doing so. + +julian@computer.org: +* solaris.c (fr_precheck): After calling freemsg on mt, set it point to *mp. +* ipf.c (packetlogon): use flag to store the return value from get_flags. +* ipmon.c (init_tabs): General cleanup so we do not have to cast + an int s->s_port to u_int port and try to check if the u_int port + is less than zero. + +3.3.9 15/02/2000 - Released + +fix scheduling of bad locking in fr_addstate() used when we attach onto +a filter rule. + +fix up ip_statesync() with storing interface names in ipstate_t + +fix fr_running for LKM's - Eugene Polovnikov + +junk using pullupmsg() for solaris - it's next to useless for what we +need to do here anyway - and implement what we require. + +don't call fr_delstate() in fr_checkstate(), when compiled for a user +program, early but when we're finished with it (got fr & pass) + +ipnat(5) fix from Guido + +on solaris2, copy message and use that with filter if there is another +copy if it being used (db_ref > 1). bad for performance, but better +than causing a crash. + +patch for solaris8-fcs compile from Casper Dik + +3.3.8 01/02/2000 - Released + +fix state handling of SYN packets. + +add parsing recognition of extra icmp types/codes and fix handling of +icmp time stamps and mask requests - Frank volf + +3.3.7 25/01/2000 - Released + +sync on state information as well as NAT information when required + +record nat protocol in all nat log records + +don't reuse the IP# from an active NAT session if the IP# in the rule +has changed dynamically. + +lookup the protocol for NAT log information in ipmon and pass that to +portname. + +fix the bug with changing the outbound interface of a packet where it +would lead to a panic. + +use fr_running instead of ipl_inited. (sysctl name change on freebsd) + +return EIO if someone attempts an ioctl on state/nat if ipfilter is not +enabled. + +fix rule insertion bug + +make state flushing clean anything that's not fully established (4/4) + +call fr_state_flush() after we've released ipf_state so we don't generate +a recursive mutex acquisition panic + +fix parsing of icmp code after return-icmp/return-icmp-as-dest and add +some patches to enhance parsing strength + +3.3.6 28/12/1999 - Released + +add in missing rwlock release in fr_checkicmpmatchingstate() and fix check +for ICMP_ECHO to only be for packet, not state entry which we don't have yet. + +handle SIOCIPFFB in nat_ioctl() and fr_state_ioctl() + +fix size of friostat for SunOS4 + +fix bug in running off the end of a buffer in real audio proxy + +3.3.5 11/12/1999 - Released + +fix parsing of "log level" and printing it back out too + +<net/if_types.h> is only present on Solaris2.6/7/8 + +use send_icmp_err rather than icmp_error to send back a frag-needed error +when doing PMTU + +do not use -b with add_drv on Solaris unless $BASEDIR is set. + +fix problem where source address in icmp replies is reversed + +fix yet another problem with real audio. + +3.3.4 4/12/1999 - Released + +fix up the real audio proxy to properly setup state information and NAT +entries, thanks to Laine Stump for testing/advice/fixes. + +fix ipfr_fastroute to set dst->sin_addr (Sean Farley - appears to prevent +FreeBSD 3.3 from panic'ing) as this had been removed in prior hacks to this +routine. + +fix kinstall for BSDI + +support ICMP errors being allowed through for ICMP packets going out with +keep state enabled + +support hardware checksumming (gigabit ethernet cards) on Solaris thanks to +Tel.Net Media for providing hardware for testing. + +patched from Frank Volf for ipmon (ICMP & fragmented packets) and allowing +ICMP responses to ICMP packets in the keep state table. + +add in patches for hardware checksumming under solaris + +Solaris install scripts now use $BASEDIR as appropriate. + +add Solaris8 support + +fix "ipf -y" on solaris so that it rescans rules also for changes in +interface pointers + +let ipmon become a daemon with -D if it is using syslog + +fix parsing of return-icmp-as-dest(foo) + +add reference to ipfstat -g to ipfstat.8 + +ipf_mutex needs to be declared for irix in ip_fil.c + +3.3.3 22/10/1999 - Released + +add -g command line option to ipfstat to show groups still define. + +fix problem with fragment table not recording rule pointer when called +from state functions (fin_fr not set). + +fixup fastroute problems with keep state rules. + +load rules into inactive set first, so we don't disable things like NIS +lookups half way through processing - found by Kevin Littlejohn + +fix handling of unaligned ip pointer for solaris + +patch for fr_newauth from Rudi Sluijtman + +fixed htons() bug in fr_tcpsum() where ip_p wasn't cast to u_short + +3.3.2 23/09/1999 - Released + +patches from Scott Presnell to fix rcmd proxy + +patches from Greg to fix Solaris detachment of interfaces + +add openbsd compatibility fixes + +fix free'ing already freed memory in ipfr_slowtimer() + +fix for deferencing invalid memory in cleaning up after a device disappears + +3.3.1 14/8/1999 - Released + +remove include file sys/user.h for irix + +prevent people from running buildsunos directly + +fix up some problems with the saving of rule pointers so that NAT saves +that information in case it should need to call fr_addstate() from a proxy. + +fix up scanning for the end of FTP messages + +don't remove /etc/opt/ipf in postremove + +attempt to prevent people running buildsolaris script without doing a +"make solaris" + +fix timeout losing on freebsd3 + +3.3 7/8/1999 - Released + +NAT: information (rules, mappings) are stored in hash tables; setup some +basic NAT regression testing. + +display version name of installed kernel code when initializing. + +add -V command line option to ipf, showing version (program and kernel +module) as well as the run-status of the kernel code. + +fix problem with "log" rules actually affecting result of filtering. + +automatically use SUNWspro if available and on a 64bit Solaris system for +compiling. + +add kernel proxies for rcmd(3) and RealAudio (PNA) + +use timeout/untimeout on SunOS4/BSD platforms too rather than hijacking +ip_slowtimo + +fix IP headers generated through parsing of text information + +fix NAT rules to be in the correct order again. + +make keep-state work with to/fastroute keywords and enforce usage of those +interfaces. + +update keep-state code with new algorithm from Guido + +add FreeBSD-3 support + +add return-icmp-as-dest option to retrun an ICMP packet using the original +destination as the source rather than a local IP address + +add "level [facility.]<priority>" option to filter language + +add changes from Guido to state code. + +add code to return EPERM if the device is opened for writing and we're +in securelevel 2 or greater. + +authentication code patches from Guido + +fix real audio proxy + +fix ipmon rule printing of interfaces and add IN/OUT to the end of ipmon +log output. + +fix bimap rules with hash tables + +update addresses used in NAT mappings for 0/32 rules for any protocol but TCP +if it changes on the interface - check every ip_natexpire() + +add redirect regression test + +count buckets used in the state hash table. + +fix sending of RST's with return-rst to use the ack number provided in +the packet being replied to in addition to the sequence number. + +fix to compile as a 64bit application on solaris7-64bit + +add NAT IP mapping to ranges of IP addresses that aren't CIDR specified + +fix calculation of in_space parameter for NAT + +fix `wrapping' when incrementing the next ip address for use in NAT + +fix free'ing of kernel memory in ip_natunload on solaris + +fix -l/-U command line options from interfering with each other + +fix fastroute under solaris2 and cleanup compilation for solaris7 + +add install scripts and compile cleanly on BSD/OS 4.0 + +safely open files in /tmp for writing device output when testing. + +fix uninitialized pointer bug in NAT + +fix SIOCZRLST (zero list rule stats) bug with groups + +change some usage of u_short to u_int in function calling + +fix compilation for Solaris7 (SUNWspro) + +change solaris makefiles to build for either sparc or i386 rather than +per-cpu (sun4u, etc). + +fixed bug in ipllog + +add patches from George Michaelson for FreeBSD 3.0 + +add patch from Guido to provide ICMP checking for known state in the same +manner as is done for NAT. + +enable FTP PASV proxying and enable wildcarding in NAT/state code for ports +for better PORT/PASV support with FTP. + +bring into main tree static nat features: map-block and "auto" portmapping. + +add in source host filtering for redirects (alan jones) + +3.2.10 22/11/98 - Released + +3.2.10beta9 17/11/98 - Released + +fix fr_tcpsum problems in handling mbufs with an odd number of bytes +and/or split across an mbuf boundary + +fix NAT list entry comparisons and allow multiple entries for the same +proxy (but on different ports). + +don't create duplicate NAT entries for repeated PORT commands. + +3.2.10beta8 14/11/98 - Released + +always exit an rwlock before expecting to enter it again on solaris + +fix loop in nat_new for pre-existing nat + +don't setup state for an ftp connection if creating nat fails. + +3.2.10beta7 05/11/98 - Released + +set fake window in ipft_tx.c to ensure code passes tests. + +cleaned up/enhanced ipnat -l/ipnat -lv output + +fixed NAT handling of non-TCP/UDP packets, esp. for ICMP errors returned. + +Solaris recusive mutex on icmp-error/tcp-reset - requires rwlock's rather +than mutexes. + +3.2.10beta6 03/11/98 - Released + +fix mixed use of krwlock_t and kmutex_t on Solaris2 + +fix FTP proxy back up, splitting pasv code out of port code. + +3.2.10beta5 02/11/98 - Released + +fixed port translation in ICMP reply handling + +3.2.10beta4 01/11/98 - Released + +increase useful statistic collection on solaris + +filter DL_UNITDATA_REQ as well as DL_UNITDATA_IND on solaris + +disable PASV reply translation for now + +fail with an error if we try to load a NAT rule with a non-existant + proxy name - Guido + +fix portmap usage with 0/0 and 0/32 map rules + +remove ap_unload/ap_expire - automatically done when NAT is cleaned up + +print "STATE:CLOSED" from ipmon if the connection progresses past established + rather than "STATE:EXPIRED" + +3.2.10beta3 26/10/98 - Released + +fixed traceroute/nat problem + +rewrote nat/proxy interface + +ipnat now lists associated proxy sessions for each NAT where applicable + +3.2.10beta2 13/10/98 - Released + +use KRWLOCK_T in place of krwlock_t for solaris as well as irix + +disable use of read-write lock acquisition by default + +add in mb_t for linux, non-kernel + +some changes to progress compilation on linux with glibc + +change PASV as well as PORT when passed through kernel ftp proxy. + +don't allow window to become 0 in tcp state code + +make ipmon compile cleaner + +irix patches + +3.2.10beta 11/09/98 - Released + +stop fr_tcpsum() thinking it has run out of data when it hasn't. + +stop solaris panics due to fin_dp being something wild. + +revisit usage of ATOMIC_*() + +log closing state of TCP connection in "keep state" + +fix fake-arp table code for ipsend. + +ipmon now writes pid to a file. + +fix "ipmon -a" to actually activate all logging devices. + +add patches for BSDOS4. + +perl scripts for log analysis donated. + +3.2.9 22/06/98 - Released + +fix byte order for ICMP packets generated on Solaris + +fix some locking problems. + +fix malloc bug in NAT (introduced in 3.2.8). + +patch from guido for state connections that get fragmented + +3.2.8 08/06/98 - Released + +use readers/writers locks in Solaris2 in place of some mutexes. + +Solaris2 installation enhancements - Martin Forssen (maf@carlstedt.se) + +3.2.7 24/05/98 - Released + +u_long -> u_32_t conversions + +patches from Bernd Ernesti for NetBSD + +fixup ipmon to actually handle HUP's. + +Linux fixes from Michael H. Warfield (mhw@wittsend.com) + +update for keep state patch (not security related) - Guido + +dumphex() uses stdout rather than log + +3.2.6 18/05/98 - Released + +fix potential security loop hole in keep state code. + +update examples. + +3.2.5 09/05/98 - Released + +BSD/OS 3.1 .o files added for the kernel. + +fix sequence # skew vs window size check. + +fix minimum ICMP header size check. + +remove references to Cybersource. + +fix my email address. + +remove ntohl in ipnat - Thomas Tornblom + +3.2.4 09/04/98 - Released + +add script to make devices for /dev on BSD boxes + +fixup building into the kernel for FreeBSD 2.2.5 + +add -D command line option to ipmon to make it a daemon and SIGHUP causes +it to close and reopen the logfile + +fixup make clean and make package for SunOS5 - Marc Boucher + +postinstall keeps adding "minor=ipf ipl" - George Ross <gdmr@dcs.ed.ac.uk> + +protected by IP Filter gif - Sergey Solyanik <solik@atom.ru> + +3.2.3 10/11/97 - Released + +fix some iplang bugs + +fix tcp checksum data overrun, sgi #define changes, +avoid infinite loop when nat'ing to single IP# - Marc Boucher + +fixup DEVFS usage for FreeBSD + +fix sunos5 "make clean" cleaning up too much + +3.2.2 28/11/97 - Released + +change packet matching to return actual error, if bad packet, to facilitate +ECONNRESET for TCP. + +allow ip:netmask in grammar too now - Guido + +assume IRIX has u_int32_t in sys/types.h (needed for R10000) + +rewrite parts of command line options for ipmon + +fix TCP urgent packet & offset testing and add LAND attack test for iptest + +fix grammar error in yacc grammar for iplang + +redirect (rdr) destination port bytes-wapped when it shouldn't be. + +general: fr_check now returns error code, such as EHOSTUNREACH or +ECONNRESET (attempt to make ECONNRESET work for locally outbound +packets). + +linux: enable return-rst, need to filter tcp retransmits which are sent + separately from normal packets + +memory leak plugged in ip_proxy.c + +BSDI compatibility patches from Guido + +tcp checksum fix - Marc Boucher + +recursive mutex and ioctl param fix - Marc Boucher + +3.2.1 12/11/97 - Released + +port to BSD/OS 3.0 + +port to Linux 2.0.31 + +patches to make "map a/m -> 0/0" work with ftp proxying properly - Marc Boucher + +add "ipf -F s" and "ipf -F S" to flush state table entries. + +announce if logging is on or off when ip filter initializes. + +"ipf -F a" doesn't flush groups properly for Solaris. + +3.2 30/10/97 - Released + +ipnat doesn't successfully remove proxy mappings with "-rf" - +Alexander Romanyu + +use K&R C function style for solaris kernel code + +use m_adj() to decrease packet size in ftp proxy + +use mbufchainlen rather than msgdsize, +IRIX update - Marc Boucher + +fix NetBSD modunload bug (pfil_add_hook done twice) + +patches for OpenBSD 2.1 - Craig Bevins <craigb@bitcom.net.au> + +3.2beta10 24/10/97 - Released + +fix fragment table entries allocated for NAT. + +fix tcp checksum calculations over mbuf/mblk boundaries + +fix panic for blen < 0 in ftp kernel proxy - marc boucher + +fix flushing of rules which have been grouped. + +3.2beta9 20/10/97 - Released + +some nit picking on solaris2 with SUNWspro - Michael Lyle <mrl@rpnet.net> + +ftp kernel proxy patches from Marc Boucher + +3.2beta8 13/10/97 - Released + +add support for passing ICMP errors back through NAT. + +IRIX port update - Marc Boucher + +calculate correct MIN size of packet to log for UDP - Marc Boucher + +need htons(ETHERTYPE_x) on little endian BSD boxes - Dave Huang + +copyright header fixups + +3.2beta7 23/09/97 - Released + +fickup problems introduced by prior merges & changes. + +3.2beta6 23/09/97 - Released + +patch for spin-reading race condition - Marc Boucher. + +IRIX port by Marc Boucher. + +compatibility updates for Linux to ipsend + +3.2beta5 13/09/97 - Released + +patches from Bernd Ernesti for NetBSD integration (mostly prototyping and +compiler warning things) + +ipf -y will resync IP#'s allocated with 0/32 in NAT to match interface if it +changes. + +update manual pages and other documentation updates. + +3.2beta4 27/8/97 - Released + +enable setting IP and TCP options for iplang/ + +Solaris2 patches from Marc Boucher. + +add groups for filter rules. + +3.2beta3 21/8/97 - Released + +patches for Solaris2 (interface panic solution ?): fix FIONREAD and +replacing q_qinfo points - Marc Boucher <marc@CAM.ORG> + +change ipsend/* and ipsd/* copyright notices to be the same as ip filter's + +patch for SYN-ACK skew testing fix from Eric V. Smith <EricSmith@windsor.com> + +3.2beta2 6/8/97 - Released + +make it load on Solaris 2.3 + +rewrote logging to remove solaris errors, introduced checking to see if the +same packet is logged successively. + +fix filter cache to work when there are no rules loaded. + +add "raw" option to ipresend to send entire ethernet frames. + +nat list corruption bug - NetBSD - Klaus Klein + +3.2beta1 5/7/97 - Released + +patches from Jason Thorpe fixing: UNSIGNED_CHAR lossage, off_t being 64bits +lossage, and other NetBSD bits. + +NetBSD 1.2G update. + +fixup fwtk patches and add protocol field for SIOCGNATL. + +rdr bugs reported by Alexander Romanyu (alexr@aix.krid.crimea.ua), with +fixes: +* rdr matched all packets of a given protocol (ignored ports). +* severe bug in nat_delete which caused system crash/freeze. + +change Makefile so that CC isn't passed on for FreeBSD/NetBSD (will use +the default CC - cc, not gcc) + +3.2alpha9 16/6/97 - Released + +added "skip" keyword. + +implement preauthentication of packets, as outlined by Guido. + +Make it compile as cleanly as possible with -Wall & general code cleanup + +getopt returns int, not char. Bernd Ernesti + +3.2alpha8 13/6/97 - Released + +code added to support "auth" rules which require a user program to allow them +through. First revision and much of the code came from Guido. + +hex output from ipmon doesn't goto syslog when recovering from out of sync +error. Luke Mewburn (lukem@connect.com.au) + +fix solaris2.6 lookup of destination ire's. + +ipnat doesn't throw away unused bits (after masking), causing it to +behave incorrectly. Carson Gaspar + +NAT code doesn't include inteface name when matching - Alexey Mavrin +<lha@elco.spb.ru> + +replace old SunOS tcpip.h with new tcpip.h (from 4.4BSD) - Jason Thorpe. + +update install procedures to include ip_proxy.c + +mask out unused bits in NAT/RDR rules. + +use a generic type (u_32_t) for 32bit variables, rather than rely on +u_long being such - Jason Thorpe. + +create a local "netinet" directory and include from ~netinet/*" rather than +just "*" to make keeping the code working on ports easier. + +add an m_copydata and m_copyback for SunOS4 (based on 4.4BSD-Lite versions) + +documentation updates. + +NetBSD update from Jason Thorpe <thorpej@netbsd.org> + +allow RST's through with a matching SEQ # and 0 ACK. Guido Van Rooij + +ipmon uses excessive amounts of CPU on Solaris2 - Reinhard Bertram +<Reinhard.Bertram@KOM.th-darmstadt.de> + +3.2alpha7 25/5/97 - Released + +add strlen for pre-2.2 kernels - Doug Kite <dkite@websgi.icomnet.com> + +setup bits and pieces for compiling into a FreeBSD-2.2 kernel. + +split up "bsd" targets. Now a separate netbsd/freebsd/bsd target. +mln_ipl.c has been split up into itself and mlf_ipl.c (for freebsd). + +fix (negative) host matching in filtering. + +add sysctl interface for some variables when compiled into FreeBSD-2.2 kernels +or later. + +make all the candidates for kernel compiling include "netinet/..." and build +a subdirectory "netinet" when compiling and symlink all .h files into this. + +add install make target to Makefile.ipsend + +3.2alpha6 8/5/97 - Released + +Add "!" (not) to hostname/ip matching. + +Automatically add packet info to the fragment cache if it is a fragment +and we're translating addreses for. + +Automatically add packet info to the fragment cache if it is a fragment +and we're "keeping state" for the packet. + +Solaris2 patches - Anthony Baxter (arb@connect.com.au) + +change install procedure for FreeBSD 2.2 to allow building to a kernel +which is different to the running kernel. + +add FIONREAD for Solaris2! + +when expiring NAT table entries, if we would set a time to fr_tcpclosed +(which is 1), make it fr_tcplaskack(20) so that the state tables have a +chance to clear up. + +3.2alpha5 + +add proxying skeleton support and sample ftp transparent proxy code. + +add printfs at startup to tell user what is happening. + +add packets & bytes for EXPIRE NAT log records. + +fix the "install-bsd" target in the root Makefile. Chris Williams +<psion@mv.mv.com> + +Fixes for FreeBSD 2.2 (and later revs) to prevent panics. Julian Assange. + +3.2alpha4 2/4/97 - Released + +Some compiler warnings cleaned up. + +FreeBSD-2.2 patches for LKM completed. + +3.2alpha3 31/3/97 - Released + +ipmon changes: -N for reading NAT logfile, -S for reading state logfile. +-a for reading all. -n now toggles hostname resolution. + +Add logging of new state entries and expiration of old state entries. +count log successes and failures. + +Add logging of new NAT entries and expiration of old NAT entries. +count log successes and failures. + +Use u_quad_t for records of bytes & packets where kept +(IP Accounting: fr_hits, fr_bytes; IP state: is_pkts, is_bytes). + +Fixup use of CPU and DCPU in Makefiles. + +Fix broken 0/32 NAT mapping. Carl Makin <cmakin@nla.gov.au> + +3.2alpha2 + +Implement mapping to 0/32 as being an alias for automatically using the +interface's first IP address. + +Implement separate minor devices for both NAT and IP state code. + +Fully prototype all functions. + +Fix Makefile problem due to attempt to fix Sun compiling problems. + +3.1.10 23/3/97 - Released + +ipfstat -a requires a -i or -o command line option too. Print an error +when not present rather than attempt to do something. + +patch updates for SunOS4 for kernel compiling. +patch for ipmon -s (flush's syslog file which isn't good). Andrew J. Schorr +<schorr@ead.dsa.com> + +too many people hit their heads hard when compiling code into the kernel +that doesn't let any packets through. (fil.c - IPF_NOMATCH) + +icmp-type parsing doesn't return any errors when it isn't constructed +correctly. Neil Readwin + +Using "-conf" with modload on SunOS4 doesn't work. +Timothy Demarest <demarest@arraycomm.com> + +Need to define ARCH in makefile for SunOS4 building. "make sunos4" +in INSTALL.SunOS is incorrect. James R Grinter <jrg@blodwen.demon.co.uk> +[all SunOS targets now run buildsunos] + +NAT lookups are still incorrect, matching non-TCP/UDP with TCP/UDP +information. ArkanoiD <ark@paranoid.convey.ru> + +Need to check for __FreeBSD_version being 199511 rather than 199607 +in mln_ipl.c. Eric Feillant <Eric.Feillant@EUnet.fr> + +3.1.9 8/3/97 - Released + +fixed incorrect lookup of active NAT entries. + +patch for ip_deq() wrong for pre 2.1.6 FreeBSD. +fyeung@fyeung8.netific.com (Francis Yeung) + +check for out with return-rst/return-icmp at wrong place - Erkki Ritoniemi +(erkki@vlsi.fi) + +text_readip returns the interface pointer pointing to text on stack - +Neil Readwin + +fix from Pradeep Krishnan for printout rules "with not opt sec". + +3.1.8 18/2/97 - Released + +Diffs for ip_output.c and ip_input.c updated to fix bug with fastroute and +compiling warnings about reuse of m0. + +prevent use of return-rst and return-icmp with rules blocking packets going +out, preventing panics in certain situations. + +loop forms in frag cache table - Yury Pshenychny <yura@rd.zgik.zaporizhzhe.ua> + +should use SPLNET/SPLX around expire routines in NAT/frag/state code. + +redeclared malloc in 44arp.c - + +3.1.7 8/2/97 - Released + +Macros used for ntohs/htons supplied with gcc don't always work very well +when the assignment is the same variable being converted. + +Filter matching doesn't not match rule which checks tcp flags on packets +which are fragments - David Wilson + +3.1.7beta 30/1/97 - Released + +Fix up NAT bugs introduced in last major change (now tested), including +nat_delete(), nat_lookupredir(), checksum changes, etc. + +3.1.7alpha 30/1/97 - Released + +Many changes to NAT code, including contributions from Laurent Joncheray +<lpj@ans.net> + +Use "NO_SLEEP" when allocating memory under SunOS. + +Make kernel printf's nicer for BSD/SunOS4 + +Always do a checksum for packets being filtered going out and being +processed by fastroute. + +Leave kernel to play with cdevsw on *BSD systems with LKM's. + +ipnat.1 man page fixes. + +3.1.6 21/1/97 - Released + +Allow NAT to work on BSD systems in conjunction with "pass .. to ifname" + +Memory leak introduced in 3.1.3 in NAT lists, clearing of NAT table tried +to free memory twice. + +NAT recalculates IP header checksum based on difference between IP#'s and +port numbers - should be just IP#'s (Solaris2 only) + +3.1.5 13/1/97 - Released + +fixed setting of NAT timeouts and use different timeouts for concurrent +TCP sessions using the same IP# mapping (when port mapping isn't used) + +multiple loading/unloading of LKM's doesn't clean up cdevsw properly for +*BSD systems. + +3.1.4 10/1/97 - Released + +add command line options -C and -F to ipnat to flush NAT list and table + +ipnat -l loops on output - Neil Readwin (nreadwin@nysales.micrognosis.com) + +NetBSD/FreeBSD kernel malloc changes - Daniel Carosone + +3.1.3 10/1/97 - Released + +NAT chains not constructed correctly in hash tables - Antony Y.R Lu +(antony@hawk.ee.ncku.edu.tw) + +Updated INSTALL.NetBSD, INSTALL.FreeBSD and INSTALL.Sol2 + +man page update (ipf.5) from Daniel Carosone (dan@geek.com.au) + +ICMP header checksum update now included in NAT. + +Solaris2 needs to modify IP header checksums in ip_natin and ip_natout. + +3.1.2 4/12/96 - Released + +ipmon doesn't use syslog all the time when given -s option + +fixed mclput panic in ip_input.c and replace ntohs() with NTOHS() macro + +check the results of hostname resolution in ipnat + +"make *install" fixed for subdirectories. + +problems with "ARCH:=" and gnu make resolved + +parser reports an error for lines with whitespaces only rather than skipping +them. D.Carosone@abm.com.au (Daniel Carosone) + +patches for integration into NetBSD-current (post 1.2). + +add an option to allow non-IP packets going up/down the stream on Solaris2 +to be dropped. John Bass. + +3.1.2beta 21/11/96 - Released + +make ipsend compile on Linux 2.0.24 + +changes to TCP kept state algorithm, making it watch state on TCP +connections in both directions. Also use the same algorithm for NAT TCP. + +-Wall cleanup - Bernd Ernesti + +added "or-block" for "pass .. log or-block" after a suggestion from +David Oppenheim (davido@optimation.com.au) + +added subdirectories for building IP Filter in SunOS5/BSD for different +cpu architecures + +Solaris2 fixes to logging and pre-filtering packet processing - 3.1.1p2 + +mbuf logging not using mtod(), remove iplbusy - 3.1.1p1 1/11/96 + +3.1.1 28/10/96 - Released + +Installation script fixes and deinstall scripts for IP Filter on: +SunOS4/FreeBSD/NetBSD + +Man page fixes - Paul Dubois (dubois@primate.wisc.edu) + +Fix use of SOLARIS macro in ipmon, rewrote ipllog() (again!) + +parsing isn't completely case insensitive - David Wilson +(davidw@optimation.com.au) + +Release ipl_mutex across uiomove() calls + +print entire rule entries out for "ipf -z" when zero'ing per-rule stats. + +ipfstat returns same output for "hits" in "ipfstat -aio" - Terletsky Slavik +(ts@polynet.lviv.ua) + +New algorithm for setting timeouts for TCP connection (more closely follow +TCP FSM) - Pradeep Krishnan (pkrishna@netcom.com) + +Track both window sizes for TCP connections through "keep state". + +Solaris2 doesn't like _KERNEL defined in stdargs.h - Jos van Wezel +(wezel@bio.vu.nl) + +3.1.1-beta2 6/10/96 - Released + +Solaris2 fastroute/dup-to/to now works + +ipmon `record' reading rewritten + +Added post-NetBSD1.2 packet filter patches - Mathew Green (mrg@eterna.com.au) + +Attempt to use in_proto.c.diff, not "..diffs" for SunOS4 - David Wilson +(davidw@optimation.com.au) + +Michael Ryan (mike@NetworX.ie) reports the following: +* The Trumpet WinSock under Windows always sends its SYN packet with an ACK + value of 1, unlike any other implementation I've seen, which would set it + to zero. The "keep state" feature of IP Filter doesn't work when receiving + non-zero ACK values on new connection requests. +* */Makefile install rule doesn't install all the binaries/man pages +* Make ipnat use "tcp/udp" instead of "tcpudp" +* Print out "tcp/udp" properly +* ipnat "portmap tcp" matches "portmap udp" when adding/removing +* NAT dest. ip# increased by one on mask of 0xffffffff when it shouldn't + +3.1.1-beta 1/9/96 - Released + +add better detection of TCP connections closing to TCP state monitoring. + +fr_addstate() not called correctly for fragments. "keep state" and +"keep frag" code don't work together 100% - Songqing Cai +(songqing_cai@sterling.com) + +call to fr_addstate() incorrect for adding state in combination with keeping +fragment information - Songqing Cai (songqing_cai@sterling.com) + +KFREE() passed fp (incorrect) and not fr (correct) in ip_frag.c - John Hood +(cgull@smoke.marlboro.vt.us) + +make ipf parser recognise '\\' as a `continued line' marker - Dima Ruban +(dima@best.net) + +3.1.1-alpha 23/8/96 - Released + +kernel panic's when ICMP packets go through NAT code + +stats aren't zero'd properly with ipf -Z + +ipnat doesn't show port numbers correctly all the time and also add the +protocol (tcp/udp/tcpudp) to rdr output - Carson Gaspar (carson@lehman.com) + +fast checksum fixing not 100% - backout patch - Bill Dorsey (dorsey@lila.com) + +NetBSD-1.2 patches from - VaX#n8 <vax@linkdead.paranoia.com> + +Usage() call error in fils.c - Ajay Shekhawat (ajay@cedar.buffalo.edu) + +ip_optcopy() staticly defined in ip_output.c in SunOS4 - Nick Hall +(nrh@tardis.ed.ac.uk) + +3.1.0 7/7/96 - Released + +Reformatted ipnat output to be compatible with it's input, so that +"ipnat -l | ipnat -rf -" is possible. + +3.1.0beta 30/6/96 - Released + +NetBSD-1.2 patches from Greg Woods (woods@most.weird.com) + +kernel module must not be installed stripped (Solaris2), as created by +"make package" for Solaris2 - Peter Heimann +(peter@i3.informatik.rwth-aachen.de) + +3.1.0alpha 5/6/96 - Released + +include examples in package for solaris2 + +patches for removing an extra ip header checksum (FreeBSD/NetBSD/SunOS) + +removed trailing space from printouts of rules in ipf. + +ipresend supports the same range of inputs that ipftest does. + +sending a duplicate copy of a packet to another network devices is now +supported. ("dup-to") + +sending a packet to an arbitary interface is now supported, irrespective +of its actual route, with no ttl decrement. Can also be routed without +the ttl being decremented. ("to" and "fastroute"). + +"call" option added to support calling a generic function if a packet is +matched. + +show all (upto 4) recorded bytes from the interface name in logging from +ipmon. + +support for using unix file permissions for read/write access on the device +is now in place. + +recursive mutex in nat_new() for Solaris 2.x - Per L. Hagen <per@stibo.dk> + +ipftest doesn't call initparse() for THISHOST - Catherine Allen +(cla@connect.com.au) + +Man page corrections from Rex Bona (rex@pengo.comsmiths.com.au) + +3.0.4 10/4/96 - Released + +looop in `parsing' IP packets with optlen 0 for ip options. + +rule number not initialized and resulted in unexpected results for state +maching. + +option parsing and printing bugs - Pradeep Krishnan + +3.0.4beta 25/3/96 - Released + +wouldn't parse "keep flags keep state" correctly. + +SunOS4.1.x ip_input.c doesn't recognise all 1s broadcast address - Nigel Verdon + +patches for BSDI's BSD/OS 2.1 and libpcap reader on little endian systems +from Thorsten Lockert <tholo@tetherless.com> + +b* functions in fil.c on Solaris 2.4 + +3.0.3 17/3/96 - Released + +added patches to support IP Filter initialisation when compiled into the +kernel. + +added -x option to ipmon to display hex dumps of logged packets. + +added -H option to ipftest to allow ascii-hex formatted input to specify +arbitary IP packets. + +Sending TCP RSTs as a response now work for Solaris2 x86 + +add patches to make IP Filter compile into NetBSD kernels properly. + +patch to stop SunOS 4.1.x kernels panicing with "data traps". + +ipfboot script unloads and reloads ipf module on Solaris2 if it is already +loaded into the kernel. + +Installation of IP Filter as a Solaris2 package is now supported. + +Man pages for ipnat.4, ipnat.5 added. + +added some more regression tests and fixed up IP Filter to pass the new tests +(previous versions failed some of the tests in set 12). + +IP option filter processing has changed so that saying "with opt lsrr" will +check only for that one, but not mask out other options, so a packet with +strict source routing, along with loose source routing will match all of +"with opt lsrr", "with opt ssrr" and "with opt lsrr,ssrr". + +IPL_NAME needed in ipnat.c - Kelly (kelly@count04.mry.scruznet.com) + +patches for clean NetBSD compilation from Bernd Ernesti (bernd@arresum.inka.de) + +make install is incorrect - Julian Briggs (julian@lightwork.co.uk) + +strtol() returns 0x7fffffff for all negative numbers, +printfr() generates incorrect output for "opt sec-class *", +handling of "not opt xxx opt yyy" incorrect. +- Minh Tonthat (minht@sbei.com)/Pradeep Krishnan (pradeepk@sbei.com) + +m_pullup() called only for input and not output; caused problems +with filtering icmp - Nigel Verdon (verdenn@gb.swissbank.com) + +parsing problem for "port 1" and NetBSD patches incorrect - +Andreas Gustafsson (gson@guava.araneus.fi) + +3.0.2 4/2/96 - Released + +Corrected bug where NAT recalculates checksums for fragments. + +make NAT recalculate UDP checksums (rather than setting them to 0), +if they're non-zero. + +DNS patches - Real Page (Real.Page@Matrox.com) + +alteration of checksum recalculations in NAT code and addition of +redirection with NAT - Mike Neuman + +core dump, if tcp/udp is used with a port number and not service name, +in ipf - Mike Neuman (mcn@engarde.com) + +initparse() call, missing to prime "<thishost>" hook - Craig Bishop + +3.0.1 14/1/96 - Released + +miscellaneous patches for Solaris2 + +3.0 14/1/96 - Released + +Patch included for FDDI, from Richard Ohnemus +(Richard_Ohnemus@dallas.csd.sterling.com) + +Code cleanup for release. + +3.0beta4 10/1/96 + +recursive mutex in ipfr_slowtimer fixed, reported by Craig Bishop + +recursive mutex in sending TCP RSTs fixed, reported by Tony Becker + +3.0beta3 9/1/96 + +FIxup for Solaris2.5 install and interface name bug in ipftest from +Julian Briggs (julian@lightwork.co.uk) + +Byte order patches for ipmon from Tony Becker (tony@mcrsys.com) + +3.0beta2 7/1/96 + +Added the (somewhat warped) IP accounting as it exists in ipfw on FreeBSD. +Note, this isn't really what one would call IP account, when compared to +process accounting, sigh. + +Split up ipresend into iptest/ipresend/ipsend + +Added another m_pullup() inside fr_check() for BSD style kernels and +added some checks to ipllog() to not log more than is present (for short +packets). + +Fixed bug where failed hostname/netname resolution goes undetecte and +becomes 0.0.0.0 (any) (reported Guido van Rooij) + +3.0beta 11/11/95 - Released + +Rewrote the way rule testing is done, reducing the number of files needed and +generated. + +SIOCIPFFL was incorrectly affected by IPFILTER_LOG (Mathew Green) + +Patches from Guido van Rooij to fix sending back TCP RSTs on Net-2/Net-3 +BSD based Unixes (panic'd) + +Patches for FreeBSD/i86 ipmon from Riku Kalinen <riku@tequila.nixu.fi> +(I think someone else already told me about these but they got lost :-/) + +Changed Makefile structure to build object files for different operating +systems in separate directories by default. + +BSDI has ef0 for first ethernet interface + +Allow for a "not" operator before optional keywords. + +The "rule number" was being incorrectly incremented every time it went through +the loop rather than when it matched a rule. + +2.8.2 24/10/95 - Released + +Fixed up problems with "textip" for doing lots of testing. + +Fixed bug in detection of "short" tcp/ip packets (all reported as being short). + +Solaris 2.4 port now works 100%. + +Man page errors reported and fixed. + +Removed duplicate entry in etc/services for login on port 49 (Craig Bishop). + +Fixed ipmon output to put a space after the log-letter. + +Patch from Guido van Rooij to fix parsing problem. + +2.8.1 15/10/95 - Released + +Added ttl and tos filtering. + +Patches for fixing up compilation and port problems (little endian) +from Guido van Rooij <guido@IAEhv.nl>. + +Man page problems reported and fixed by Carson Gaspar <carson@lehman.com>. + +ipsend doesn't compile properly on Solaris2.4 + +Lots of work done for Solaris2.4 to make it MT/MP safe and work. + +2.8 15/9/95 - Released + +ipmon can now send messages to syslogd (-s) and use names instead of +numbers (-N). + +IP packets are now "compiled" into a structure only containing filterable +bits. + +Added regression testing in the test/ subdirectory, using a new option +(-b) with the ipftest program. + +Added "nomatch" return to filter results. These are counted and show +up in reports from ipfstat. + +Moved filter code out of ip_fil.c and into fil.c - there is now only one +instance of it in the package. + +Added Solaris 2.4 support. + +Added IPSO basic security option filtering. + +Added name support for filtering on all 19 named IP options. + +Patches from Ivan Brawley to log packet contents as well as packet headers. + +Update for sun/conf.c.diff from Ivan Brawley <ibrawley@awadi.com.AU> + +Added patches for FreeBSD 1, and added two new switches (-E, -D) to ipf, +along with a new ioctl, SIOCFRENB. +From: Dieter Dworkin Muller <dworkin@village.org> + +2.7.3 31/7.95 - Released + +Didn't compile cleanly without IPFILTER_LOG defined (Mathew Green). + +ipftest now deals with tcpdump3 binary output files (from libpcap) with -P. + +Brought ipftest program upto date with actual filter code. + +Filter would cause a match to occur when it wasn't meant to if the packet +had short headers and was missing portions that should have been there. +Err, it would rightly not match on them, but their absence caused a match +when it shouldn't have been. + +2.7.2 26/7/95 - Released + +Problem with filtering just SYN flagged packets reported by +Dieter Dworkin Muller <dworkin@village.org>. To solve this +problem, added support for masking TCP flags for comparison "flags X/Y". + +2.7.1 9/7/95 - Released + +Added ip_dirbroadcast support for Sun ip_input.c + +Fixed up the install scripts for FreeBSD/NetBSD to recognise where they are +better. + +2.7 7/7/95 - Released + +Added "return-rst" to return TCP RST's to TCP packets. + +Actually ported it to FreeBSD-i386 2.0.0, so it works there properly now. + +Added insertion of filter rules. Use "@<#>" at the beginning of a filter +to insert a rule at row #. + +Filter keeps track of how many times each rule is matched. + +Changed compile time things to match kernel option (IPFILTER_LKM & +IPFILTER_LOG). + +Updated ip_input.c and ip_output.c with paches for 3.5 Multicast IP. +(No change required for 3.6) + +Now includes TCP fragments which start inside the TCP header as being short. +Added counting the number of times each rule is matched. + + +2.6 11/5/95 - Released + +Added -n option to ipf: when supplied, no changes are made to the kernel. + +Added installation scripts for SunOS 4.1.x and NetBSD/FreeBSD/BSDI. + +Rewrote filtering to use a more generic mask & match procedure for +checking if a packet matches a rule. + +2.5.2 27/4/95 - Released + +"tcp/udp" and a non-initialised pointer caused the "proto" to become +a `random' value; added "ip#/dotted.mask" notation to the BNF. +From Adam W. Feigin <feigin@iis.ee.ethz.ch> + +2.5.1 22/3/95 - Released + +"tcp/udp" had a strange effect (undesired) on getserv*() functions, +causing protocol/service lookups to fail. Reported by Matthew Green. + +2.5 17/3/95 - Released + +Added a new keyword "all" to BNF and parsing of tcpdump/etherfind/snoop +output through the ipftest program. Suggestions from: +Michael Ciavarella (mikec@phyto.apana.org.au) + +Conflicts occur when "general" filter rules are used for ports and the +lack of a "proto" when used with "port" matches other packets when only +TCP/UDP are implied. +Reported Matthew Green (mrg@fulcom.com.au); +reported & fixed 6-8/3/95 + +Added filtering of short TCP packets using "with short" 28/2/95 +(These can possibly slip by checks for the various flags). Short UDP +or ICMP are dropped to the floor and logged. + +Added filtering of fragmented packets using "with frag" 24/2/95 + +Port to NetBSD-current completed 20/2/95, using LKM. + +Added logging of the rule # which caused the logging to happen and the +interface on which the packet is currently as suggested by +Andreas Greulich (greulich@math-stat.unibe.ch) 10/2/95 + +2.4 9/2/95 - Released +Fixed saving of IP headers in ICMP packets. + +2.3 29/1/95 +Added ipf -F [in|out|all] to flush filter rule sets (SIOCIPFFL). +Fixed iplread() and iplsave() with help from Marc Huber. + +2.2 7/1/95 - Released +Added code from Marc Huber <huber@fzi.de> to allow it to allocate +its own major char number dynamically when modload'ing. Fixed up +use of <, >, <=, >= and >< for ports. + +2.1 21/12/94 - Released +repackaged to include the correct ip_output.c and ip_input.c *goof* + +2.0 18/12/94 - Released +added code to check for port ranges - complete. +rewrote to work as a loadable kernel module - complete. + +1.1 +added code for ouput filtering as well as input filtering and added support for logging to a simple character device of packet headers. + +1.0 22/04/93 - Released +First release cut. diff --git a/contrib/ipfilter/LICENCE b/contrib/ipfilter/LICENCE new file mode 100644 index 0000000..f4cc8ee --- /dev/null +++ b/contrib/ipfilter/LICENCE @@ -0,0 +1,16 @@ +/* + * Copyright (C) 1993-2000 by Darren Reed. + * + * The author accepts no responsibility for the use of this software and + * provides it on an ``as is'' basis without express or implied warranty. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * I hate legaleese, don't you ? + */ diff --git a/contrib/ipfilter/Makefile b/contrib/ipfilter/Makefile new file mode 100644 index 0000000..1ac9c94 --- /dev/null +++ b/contrib/ipfilter/Makefile @@ -0,0 +1,410 @@ +# +# Copyright (C) 2012 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. +# +# $FreeBSD$ +# Id: Makefile,v 2.76.2.24 2007/09/26 10:04:03 darrenr Exp $ +# +SHELL=/bin/sh +BINDEST=/usr/local/bin +SBINDEST=/sbin +MANDIR=/usr/local/man +#To test prototyping +CC=gcc -Wstrict-prototypes -Wmissing-prototypes -Wunused -Wuninitialized +#CC=gcc +#CC=cc -Dconst= +DEBUG=-g +# -O +CFLAGS=-I$$(TOP) -D_BSD_SOURCE +CPU=`uname -m` +CPUDIR=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m` +OBJ=. +# +# To enable this to work as a Loadable Kernel Module... +# +IPFLKM=-DIPFILTER_LKM +# +# To enable logging of blocked/passed packets... +# +IPFLOG=-DIPFILTER_LOG +# +# To enable loading filter rules compiled to C code... +# +#COMPIPF=-DIPFILTER_COMPILED +# +# To enable IPFilter compatibility with older CLI utilities +# +#COMPATIPF=-DIPFILTER_COMPAT +# +# To enable synchronisation between IPFilter hosts +# +#SYNC=-DIPFILTER_SYNC +# +# The facility you wish to log messages from ipmon to syslogd with. +# +LOGFAC=-DLOGFAC=LOG_SECURITY +# +# To enable rules to be written with BPF syntax, uncomment these two lines. +# +# WARNING: If you're building a commercial product based on IPFilter, using +# this options *may* infringe at least one patent held by CheckPoint +# (5,606,668.) +# +#IPFBPF=-DIPFILTER_BPF -I/usr/local/include +#LIBBPF=-L/usr/local/lib -lpcap +# +# HP-UX and Solaris require this uncommented for BPF. +# +#BPFILTER=bpf_filter.o +# +# LINUXKERNEL is the path to the top of your Linux kernel source tree. +# By default IPFilter looks for /usr/src/linux, but you may have to change +# it to /usr/src/linux-2.4 or similar. +# +LINUXKERNEL=/usr/src/kernels/2.6.29.5-191.fc11.i586 +LINUX=`uname -r | awk -F. ' { printf"%d",$$1;for(i=1;i<NF&&i<3;i++){printf("%02d",$$(i+1));}}'` +# +# +# +#BUILDROOT=/usr/src/redhat/BUILD/ipfilter +BUILDROOT=${HOME}/rpmbuild/BUILDROOT/ipfilter-4.1.32-1.i386 + +# +# All of the compile-time options are here, used for compiling the userland +# tools for regression testing. Well, all except for IPFILTER_LKM, of course. +# +ALLOPTS=-DIPFILTER_LOG -DIPFILTER_LOOKUP \ + -DIPFILTER_SYNC -DIPFILTER_CKSUM + +# +# Uncomment the next 3 lines if you want to view the state table a la top(1) +# (requires that you have installed ncurses). +#STATETOP_CFLAGS=-DSTATETOP +# +# Where to find the ncurses include files (if not in default path), +# +#STATETOP_INC= +#STATETOP_INC=-I/usr/local/include +# +# How to link the ncurses library +# +#STATETOP_LIB=-lncurses +#STATETOP_LIB=-L/usr/local/lib -lncurses + +# +# Uncomment this when building IPv6 capability. +# +INET6=-DUSE_INET6 +# +# For packets which don't match any pass rules or any block rules, set either +# FR_PASS or FR_BLOCK (respectively). It defaults to FR_PASS if left +# undefined. This is ignored for ipftest, which can thus return three +# results: pass, block and nomatch. This is the sort of "block unless +# explicitly allowed" type #define switch. +# +POLICY=-DIPF_DEFAULT_PASS=FR_PASS +# +MFLAGS1='CFLAGS=$(CFLAGS) $(ARCHINC) $(SOLARIS2) $(SGIREV) $(INET6)' \ + "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \ + "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \ + "LIBBPF=$(LIBBPF)" "CPUDIR=$(CPUDIR)" "IPFBPF=$(IPFBPF)" \ + 'STATETOP_CFLAGS=$(STATETOP_CFLAGS)' "BPFILTER=$(BPFILTER)" \ + 'STATETOP_INC=$(STATETOP_INC)' 'STATETOP_LIB=$(STATETOP_LIB)' \ + "BITS=$(BITS)" "OBJ=$(OBJ)" "LOOKUP=$(LOOKUP)" "COMPIPF=$(COMPIPF)" \ + "COMPATIPF=$(COMPATIPF)" \ + 'SYNC=$(SYNC)' 'ALLOPTS=$(ALLOPTS)' 'LIBBPF=$(LIBBPF)' +MFLAGS=$(MFLAGS1) "IPFLKM=$(IPFLKM)" +MACHASSERT=`/bin/ls -1 /usr/sys/*/mach_assert.h | head -1` +# +SHELL=/bin/sh +# +########## ########## ########## ########## ########## ########## ########## +# +CP=/bin/cp +RM=/bin/rm +CHMOD=/bin/chmod +INSTALL=install +# + +all: + @echo "Chose one of the following targets for making IP filter:" + @echo "" + @echo "solaris - auto-selects SunOS4.1.x/Solaris 2.3-6/Solaris2.4-6x86" + @echo "netbsd - compile for NetBSD" + @echo "openbsd - compile for OpenBSD" + @echo "freebsd20 - compile for FreeBSD 2.0, 2.1 or earlier" + @echo "freebsd22 - compile for FreeBSD-2.2 or greater" + @echo "freebsd - compile for all other versions of FreeBSD" + @echo "bsd - compile for generic 4.4BSD systems" + @echo "bsdi - compile for BSD/OS" + @echo "irix - compile for SGI IRIX" + @echo "hpux - compile for HP-UX 11.00" + @echo "osf - compile for OSF/Tru64 5.1" + @echo "" + +tests: + @if [ -d test ]; then (cd test; make) \ + else echo test directory not present, sorry; fi + +retest: + @if [ -d test ]; then (cd test; make clean && make) \ + else echo test directory not present, sorry; fi + +include: + -mkdir -p net netinet + if [ ! -f netinet/done ] ; then \ + (cd netinet; ln -s ../*.h .; ln -s ../ip_*_pxy.c .;); \ + (cd netinet; ln -s ../ipsend/tcpip.h tcpip.h); \ + touch netinet/done; \ + fi + -(cd netinet; ln -s ../ip_rules.h ip_rules.h) + +sunos solaris: include + MAKE="$(MAKE)" MAKEFLAGS="$(MAKEFLAGS)" BPFILTER=$(BPFILTER) \ + CC="$(CC)" DEBUG="$(DEBUG)" ./buildsunos + +freebsd: + make freebsd`uname -r|cut -c1` + +freebsd22: include + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + -rm -f BSD/$(CPUDIR)/ioconf.h + -if [ x$(IPFILKERN) != x ] ; then \ + if [ -f /sys/compile/$(IPFILKERN)/ioconf.h ] ; then \ + ln -s /sys/compile/$(IPFILKERN)/ioconf.h BSD/$$y; \ + else \ + ln -s /sys/$(IPFILKERN)/ioconf.h BSD/$$y; \ + fi \ + else \ + x=`uname -v|sed -e 's@^.*:\(/[^: ]*\).*$$@\1/ioconf.h@'`; \ + y=`uname -s|sed -e 's@/@@g'`-`uname -r`-`uname -m`; \ + if [ ! -f $$x ] ; then \ + echo -n "Can't find ioconf.h at $$x "; \ + exit 1;\ + else \ + ln -s $$x BSD/$$y ; \ + fi \ + fi + make freebsd20 + +freebsd5 freebsd6 freebsd7 freebsd8: include + if [ x$(INET6) = x ] ; then \ + echo "#undef INET6" > opt_inet6.h; \ + else \ + echo "#define INET6" > opt_inet6.h; \ + fi + if [ "x$(IPFBPF)" = "x" ] ; then \ + echo "#undef NBPF" > opt_bpf.h; \ + echo "#undef NBPFILTER" > opt_bpf.h; \ + echo "#undef DEV_BPF" > opt_bpf.h; \ + else \ + echo "#define NBPF" > opt_bpf.h; \ + echo "#define NBPFILTER" > opt_bpf.h; \ + echo "#define DEV_BPF" > opt_bpf.h; \ + fi + if [ x$(ENABLE_PFIL) = x ] ; then \ + echo "#undef PFIL_HOOKS" > opt_pfil.h; \ + else \ + echo "#define PFIL_HOOKS" > opt_pfil.h; \ + fi + + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko.5" "LKMR=ipfrule.ko.5" "DLKM=-DKLD_MODULE" "MLR=mlfk_rule.o"; cd ..) +# (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..) + +freebsd4 : include + if [ x$(INET6) = x ] ; then \ + echo "#undef INET6" > opt_inet6.h; \ + else \ + echo "#define INET6" > opt_inet6.h; \ + fi + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlfk_ipl.c" "MLD=mlfk_ipl.c" "LKM=ipf.ko" "LKMR=ipfrule.ko" "DLKM=-DKLD_MODULE" "MLR=mlfk_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..) + +freebsd3 freebsd30: include + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS1) "ML=mlf_ipl.c" "MLR=mlf_rule.o" LKM= LKMR=; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS1); cd ..) + +netbsd: include + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + @if [ ! -d /sys -o ! -d /sys/arch ] ; then \ + echo "*****************************************************"; \ + echo "* *"; \ + echo "* Please extract source code to create /sys and *";\ + echo "* /sys/arch and run 'config GENERIC' *"; \ + echo "* *"; \ + echo "*****************************************************"; \ + exit 1; \ + fi + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c" LKMR= "MLR=mln_rule.o"; cd ..) +# (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) + +openbsd: include + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mlo_ipl.c" LKMR= "MLR=mlo_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) + +freebsd20 freebsd21: include + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) "ML=mlf_ipl.c" "MLR=mlf_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) + +osf tru64: null include + make setup "TARGOS=OSF" "CPUDIR=`OSF/cpurev`" + (cd OSF/`OSF/cpurev`; make build TRU64=`uname -v` TOP=../.. "DEBUG=-g" $(MFLAGS) "MACHASSERT=$(MACHASSERT)" "OSREV=`../cpurev`"; cd ..) + (cd OSF/`OSF/cpurev`; make -f Makefile.ipsend build TRU64=`uname -v` TOP=../.. $(MFLAGS) "OSREV=`../cpurev`"; cd ..) + +aix: null include + make setup "TARGOS=AIX" "CPUDIR=`AIX/cpurev`" + (cd AIX/`AIX/cpurev`; make build AIX=`uname -v` TOP=../.. "DEBUG=-g" $(MFLAGS) "OSREV=`../cpurev`" BITS=`../bootbits.sh`; cd ..) +# (cd AIX/`AIX/cpurev`; make -f Makefile.ipsend build AIX=`uname -v` TOP=../.. $(MFLAGS) "OSREV=`../cpurev`"; cd ..) + +bsd: include + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build TOP=../.. $(MFLAGS) 'DLKM=-D_LKM' "ML=mln_ipl.c" "MLR=mln_rule.o"; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build TOP=../.. $(MFLAGS); cd ..) + +bsdi bsdos: include + make setup "TARGOS=BSD" "CPUDIR=$(CPUDIR)" + (cd BSD/$(CPUDIR); make build "CC=$(CC)" TOP=../.. $(MFLAGS) LKM= LKMR= ; cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend build "CC=$(CC)" TOP=../.. $(MFLAGS); cd ..) + +irix IRIX: include + make setup TARGOS=IRIX CPUDIR=`IRIX/cpurev` + if [ "x${SGIREV}" = "x" ] ; then \ + make irix "SGIREV=-D_KMEMUSER -DIRIX=`IRIX/getrev`"; \ + else \ + (cd IRIX/`IRIX/cpurev`; smake -l -J 1 build TOP=../.. $(DEST) $(MFLAGS) IRIX=`../getrev` SGI=$$(IRIX) CPUDIR=`../cpurev`; cd ..); \ + (cd IRIX/`IRIX/cpurev`; make -f Makefile.ipsend build TOP=../.. $(DEST) $(MFLAGS) IRIX=`../getrev` SGI=$$(IRIX) CPUDIR=`../cpurev`; cd ..); \ + fi + +setup: + -if [ ! -d $(TARGOS)/$(CPUDIR) ] ; then mkdir $(TARGOS)/$(CPUDIR); fi + -rm -f $(TARGOS)/$(CPUDIR)/Makefile $(TARGOS)/$(CPUDIR)/Makefile.ipsend + -ln -s ../Makefile $(TARGOS)/$(CPUDIR)/Makefile + -ln -s ../Makefile.ipsend $(TARGOS)/$(CPUDIR)/Makefile.ipsend + -if [ -f $(TARGOS)/Makefile.common ] ; then \ + rm -f $(TARGOS)/$(CPUDIR)/Makefile.common; \ + ln -s ../Makefile.common $(TARGOS)/$(CPUDIR)/Makefile.common;\ + fi + +clean: clean-include + /bin/rm -rf h y.output + ${RM} -f core *.o ipt fils ipf ipfstat ipftest ipmon if_ipl ipflkm \ + vnode_if.h $(LKM) *~ + /bin/rm -rf sparcv7 sparcv9 mdbgen_build + (cd SunOS4; $(MAKE) TOP=.. clean) + -(cd SunOS5; $(MAKE) TOP=.. clean) + (cd BSD; $(MAKE) TOP=.. clean) + (cd HPUX; $(MAKE) BITS=32 TOP=.. clean) + (cd Linux; $(MAKE) TOP=.. clean) + (cd OSF; $(MAKE) TOP=.. clean) + (cd AIX; $(MAKE) TOP=.. clean) + if [ "`uname -s`" = "IRIX" ]; then (cd IRIX; $(MAKE) clean); fi + [ -d test ] && (cd test; $(MAKE) clean) + (cd ipsend; $(MAKE) clean) + +clean-include: + sh -c 'if [ -d netinet ] ; then cd netinet; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done fi' + sh -c 'if [ -d net ] ; then cd net; for i in *; do if [ -h $$i ] ; then /bin/rm -f $$i; fi; done fi' + ${RM} -f netinet/done net/done + +clean-bsd: clean-include + (cd BSD; make TOP=.. clean) + +clean-hpux: clean-include + (cd HPUX; $(MAKE) BITS=32 clean) + +clean-osf: clean-include + (cd OSF; make clean) + +clean-aix: clean-include + (cd AIX; make clean) + +clean-linux: clean-include + (cd Linux; make clean) + +clean-sunos4: clean-include + (cd SunOS4; make clean) + +clean-sunos5: clean-include + (cd SunOS5; $(MAKE) clean) + /bin/rm -rf sparcv? + +clean-irix: clean-include + (cd IRIX; $(MAKE) clean) + +h/xti.h: + mkdir -p h + ln -s /usr/include/sys/xti.h h + +hpux: include h/xti.h + make setup CPUDIR=`HPUX/cpurev` TARGOS=HPUX + (cd HPUX/`HPUX/cpurev`; $(MAKE) build TOP=../.. $(DEST) $(MFLAGS) "BITS=`getconf KERNEL_BITS`" `../makeargs`; cd ..) + (cd HPUX/`HPUX/cpurev`; $(MAKE) -f Makefile.ipsend build TOP=../.. $(DEST) $(MFLAGS) "BITS=`getconf KERNEL_BITS`" `../makeargs`; cd ..) + +sunos4 solaris1: + (cd SunOS4; make build TOP=.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) + (cd SunOS4; make -f Makefile.ipsend build "CC=$(CC)" TOP=.. $(DEST) $(MFLAGS); cd ..) + +sunos5 solaris2: null + (cd SunOS5/$(CPUDIR); $(MAKE) build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS) "SOLARIS2=$(SOLARIS2)" INSTANCE=$(INSTANCE); cd ..) + (cd SunOS5/$(CPUDIR); $(MAKE) -f Makefile.ipsend build TOP=../.. "CC=$(CC)" $(DEST) $(MFLAGS); cd ..) + +linux: include + (cd Linux; make build LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) LINUXKERNEL=$(LINUXKERNEL); cd ..) + (cd Linux; make ipflkm LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) LINUXKERNEL=$(LINUXKERNEL) WORKDIR=`pwd`; cd ..) +# (cd Linux; make -f Makefile.ipsend build LINUX=$(LINUX) TOP=.. "CC=$(CC)" $(MFLAGS); cd ..) + +install-linux: linux + (cd Linux/; make LINUX=$(LINUX) TOP=.. "DEBUG=-g" "CC=$(CC)" $(MFLAGS) OBJ=$(CPUDIR) ROOTDIR=$(BUILDROOT) install ; cd ..) + +install-bsd: + (cd BSD/$(CPUDIR); make install "TOP=../.." $(MFLAGS); cd ..) + (cd BSD/$(CPUDIR); make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(MFLAGS); cd ..) + +install-sunos4: solaris + (cd SunOS4; $(MAKE) CPU=$(CPU) TOP=.. install) + +install-sunos5: solaris null + (cd SunOS5; $(MAKE) TOP=.. install) + +install-aix: + (cd AIX/`AIX/cpurev`; make install "TOP=../.." $(MFLAGS); cd ..) +# (cd AIX/`AIX/cpurev`; make -f Makefile.ipsend INSTALL=$(INSTALL) install "TOP=../.." $(MFLAGS); cd ..) + +install-hpux: hpux + (cd HPUX/`HPUX/cpurev`; $(MAKE) CPU=$(CPU) TOP=../.. "BITS=`getconf KERNEL_BITS`" install) + +install-irix: irix + (cd IRIX; smake install CPU=$(CPU) TOP=.. $(DEST) $(MFLAGS) CPUDIR=`./cpurev`) + +install-osf install-tru64: + (cd OSF/`OSF/cpurev`; make install "TOP=../.." $(MFLAGS); cd ..) + +do-cvs: + find . -type d -name CVS -print | xargs /bin/rm -rf + find . -type f -name .cvsignore -print | xargs /bin/rm -f + /bin/rm -f ip_msnrpc_pxy.c ip_sunrpc_pxy.c + +ip_rules.c ip_rules.h: rules/ip_rules tools/ipfcomp.c + -./ipf -n -cc -f rules/ip_rules 2>/dev/null 1>&2 + +null: + @if [ "`$(MAKE) -v 2>&1 | sed -ne 's/GNU.*/GNU/p'`" = "GNU" ] ; then \ + echo 'Do not use GNU make (gmake) to compile IPFilter'; \ + exit 1; \ + fi + -@echo make ok + +mdb: + /bin/rm -rf mdbgen_build + mdbgen -D_KERNEL -DIPFILTER_LOG -DIPFILTER_LOOKUP -DSUNDDI \ + -DIPFILTER_SCAN -DIPFILTER_LKM -DSOLARIS2=10 -n ipf_mdb -k \ + -I/home/dr146992/pfil -I/home/dr146992/ipf -f \ + /usr/include/netinet/in_systm.h,/usr/include/sys/ethernet.h,/usr/include/netinet/in.h,/usr/include/netinet/ip.h,/usr/include/netinet/ip_var.h,/usr/include/netinet/tcp.h,/usr/include/netinet/tcpip.h,/usr/include/netinet/ip_icmp.h,/usr/include/netinet/udp.h,ip_compat.h,ip_fil.h,ip_nat.h,ip_state.h,ip_proxy.h,ip_scan.h diff --git a/contrib/ipfilter/NAT.FreeBSD b/contrib/ipfilter/NAT.FreeBSD new file mode 100644 index 0000000..4a1a7ed --- /dev/null +++ b/contrib/ipfilter/NAT.FreeBSD @@ -0,0 +1,104 @@ +These are Instructions for Configuring A FreeBSD Box For NAT +After you have installed IpFilter. + +You will need to change three files: + +/etc/rc.local +/etc/rc.conf +/etc/natrules + +You will have to: + +1) Load the kernel module +2) Make the ipnat rules +3) Load the ipnat rules +4) Enable routing between interfaces +5) Add static routes for the subnet ranges +6) Configure your network interfaces +7) reboot the computer for the changes to take effect. + +The FAQ was written by Chris Coleman <chris@@bbcc.ctc.edu> +This was tested using ipfilter 3.1.4 and FreeBSD 2.1.6-RELEASE +_________________________________________________________ +1) Loading the Kernel Module + +If you are using a Kernal Loadable Module you need to edit your +/etc/rc.local file and load the module at boot time. +use the line: + + modload /lkm/if_ipl.o + +If you are not loading a kernel module, skip this step. +_________________________________________________________ +2) Setting up the NAT Rules + +Make a file called /etc/natrules +put in the rules that you need for your system. + +If you want to use the whole 10 Network. Try: + +map fpx0 10.0.0.0/8 -> 208.8.0.1/32 portmap tcp/udp 10000:65000 + +_________________________________________________________ +Here is an explaination of each part of the command: + +map starts the command. + +fpx0 is the interface with the real internet address. + +10.0.0.0 is the subnet you want to use. + +/8 is the subnet mask. ie 255.0.0.0 + +208.8.0.1 is the real ip address that you use. + +/32 is the subnet mask 255.255.255.255, ie only use this ip address. + +portmap tcp/udp 10000:65000 + tells it to use the ports to redirect the tcp/udp calls through + + +The one line should work for the whole network. +_________________________________________________________ +3) Loading the NAT Rules: + +The NAT Rules will need to be loaded every time the computer +reboots. + +In your /etc/rc.local put the line: + +ipnat -f /etc/natrules + +To check and see if it is loaded, as root type + ipnat -ls +_________________________________________________________ +4) Enable Routing between interfaces. + +Tell the kernel to route these addresses. + +in the rc.local file put the line: + +sysctl -w net.inet.ip.forwarding=1 + +_________________________________________________________ +5) Static Routes to Subnet Ranges + +Now you have to add a static routes for the subnet ranges. +Edit your /etc/sysconfig to add them at bootup. + +static_routes="foo" +route_foo="10.0.0.0 -netmask 0xf0000000 -interface 10.0.0.1" + + +_________________________________________________________ +6) Make sure that you have your interfaces configured. + +I have two Intel Ether Express Pro B cards. +One is on 208.8.0.1 The other is on 10.0.0.1 + +You need to configure these in the /etc/sysconfig + +network_interfaces="fxp0 fxp1" +ifconfig_fxp0="inet 208.8.0.1 netmask 255.255.255.0" +ifconfig_fxp1="inet 10.0.0.1 netmask 255.0.0.0" +_________________________________________________________ diff --git a/contrib/ipfilter/README b/contrib/ipfilter/README new file mode 100644 index 0000000..8464af4 --- /dev/null +++ b/contrib/ipfilter/README @@ -0,0 +1,101 @@ +IP Filter - What's this about ? +============================ +Web site: http://coombs.anu.edu.au/~avalon/ip-filter.html +How-to: http://www.obfuscation.org/ipf/ipf-howto.txt + + The idea behind this package is allow those who use Unix workstations as +routers (a common occurance in Universities it appears) to apply packet +filtering to packets going in and out of them. This package has been +tested on all versions of SunOS 4.1 and Solaris 2.4/2.5, running on Sparcs. +It is also quite possible for this small kernel extension to be installed +and used effectively on Sun workstations which don't route IP, just for +added security. It can also be integrated with the multicast patches. +It has also been tested successfully on all of the modern free BSDs as +well as BSDI, and SGI's IRIX 6.2. + + The filter keeps a rule list for both inbound and outbound sides of +the IP packet queue and a check is made as early as possible, aiming to +stop the packet before it even gets as far as being checked for source +route options. In the file "BNF", a set of rules for constructing filter +rules understood by this package is given. The files in the directory +"rules", "example.1" ... "example.sr" show example rules you might apply. + + In practise, I've successfully isolated a workstation from all +machines except the NFS file servers on its local subnets (yeah, ok, so +this doesn't really increase security, because of NFS, but you get the +drift on how it can be applied and used). I've also successfully +setup and maintained my own firewalls using it with TIS's Firewall Toolkit, +including using it on an mbone router. + + When using it with multicast IP, the calls to fr_check() should be +before the packet is unwrapped and after it is encapsulated. So the +filter routines will see the packet as a UDP packet, protocol XYZ. +Whether this is better or worse than having it filter on class D addresses +is debateable, but the idea behind this package is to be able to +discriminate between packets as they are on the 'wire', before they +get routed anywhere, etc. + + It is worth noting, that it is possible, using a small MTU and +generating tiny fragmented IP packets to generate a TCP packet which +doesn't contain enough information to filter on the "flags". Filtering +on these types of packets is possible, but under the more general case +of the packets being "short". ICMP and UDP packets which are too small +(they don't contain a complete header) are dropped and logged, no questions +asked. When filtering on fragmented packets, the last fragment will get +through for TCP/UDP/ICMP packets. + +Bugs/Problems +------------- +If you have a problem with IP Filter on your operating system, please email +a copy of the file "BugReport" with the details of your setup as required +and email to darrenr@pobox.com. + +Some general notes. +------------------- + To add/delete a rule from memory, access to the device in /dev is needed, +allowing non-root maintenaince. The filter list in kernel memory is built +from the kernel's heap. Each packet coming *in* or *out* is checked against +the appropriate list, rejects dropped, others passed through. Thus this will +work on an individual host, not just gateways. Presently there is only one +list for all interfaces, the changes required to make it a per-interface list +require more .o replacements for the kernel. When checking a packet, the +packet is compared to the entire list from top to bottom, the last matching +line being effective. + + +What does what ? +---------------- +if_fil.o (Loadable kernel module) + - additional kernel routines to check an access list as to whether + or not to drop or pass a packet. It currently defaults to pass + on all packets. + +ipfstat + - digs through your kernel (need to check #define VMUNIX in fils.c) + and /dev/kmem for the access filter list and mini stats table. + Obviously needs to be run priviledged if required. + +ipf + - reads the files passed as parameters as input files containing new + filter rules to add/delete to the kernel list. The lines are + inserted in order; the first line is inserted first, and ends up + first on the list. Subsequent invocations append to the list + unless specified otherwise. + +ipftest + - test the ruleset given by filename. Reads in the ruleset and then + waits for stdin. + + See the man pages (ipf.1, ipftest.1, ipfstat.8) for more detailed + information on what the above do. + +mkfilters + - suggests a set of filter rules to employ and suggests how to add + routes to back these up. + +BNF + - BNF rule set for the filter rules + +Darren Reed +darrenr@pobox.com +http://coombs.anu.edu.au/~avalon/ip-filter.html diff --git a/contrib/ipfilter/STYLE.TXT b/contrib/ipfilter/STYLE.TXT new file mode 100644 index 0000000..384bcec --- /dev/null +++ b/contrib/ipfilter/STYLE.TXT @@ -0,0 +1,57 @@ + +Over time, I am moving all of the IPFilter code to what I consider a better +coding style than it had before. If you submit patches, I expect them to +conform as appropriate. + +Function Comments +================= +Preceeding each and every function, a comment block like this should +be present: + +/* ------------------------------------------------------------------------ */ +/* Function: function-name */ +/* Returns: return-type */ +/* Parameters: param1(I) - param1 is an input parameter */ +/* p2(O) - p2 is an output parameter passed as an arg */ +/* par3(IO) - par3 is a parameter which is both input and */ +/* output. Pointers to things which are used and */ +/* then get a result stored in them qualify here. */ +/* */ +/* Description about what the function does. This comment should explain */ +/* any gotchas or algorithms that are used which aren't obvious to the */ +/* casual reader. It should not be an excuse to not use comments inside */ +/* the function. */ +/* ------------------------------------------------------------------------ */ + + +Tab spacing +=========== +Tabs are to be at 8 characters. + + +Conditions +========== +All expressions which evaluate to a boolean for a test condition, such as +in an if()/while() statement must involve a boolean operation. Since C +has no native boolean type, this means that one of <,>,<=,>=,==,!= must +be present. Implied boolean evaluations are out. + +In code, the following is banned: + +if (x) +if (!x) +while ((a = b)) + +and should be replaced by: + +if (x != 0) +if (x == 0) +while ((a = b) != 0) + +If pointers are involved, always compare with NULL, ie.: + +if (x != NULL) +if (x == NULL) +while ((a = b) != NULL) + + diff --git a/contrib/ipfilter/WhatsNew50.txt b/contrib/ipfilter/WhatsNew50.txt new file mode 100644 index 0000000..adbf0a9 --- /dev/null +++ b/contrib/ipfilter/WhatsNew50.txt @@ -0,0 +1,83 @@ +What's new in 5.1 +================= + +General +------- +* all of the tuneables can now be set at any time, not just whilst disabled + or prior to loading rules; + +* group identifiers may now be a number or name (universal); + +* man pages rewritten + +* tunables can now be set via ipf.conf; + +Logging +------- +* ipmon.conf can now be used to generate SNMPv1 and SNMPv2 traps using + information from log entries from the kernel; + +NAT changes +----------- +* DNS proxy for the kernel that can block queries based on domain names; + +* FTP proxy can be configured to limit data connections to one or many + connections per client; + +* NAT on IPv6 is now supported; + +* rewrite command allows changing both the source and destination address + in a single NAT rule; + +* simple encapsulation can now be configured with ipnat.conf, + +* TFTP proxy now included; + +Packet Filtering +---------------- +* acceptance of ICMP packets for "keep state" rules can be refined through + the use of filtering rules; + +* alternative form for writing rules using simple filtering expressions; + +* CIPSO headers now recognised and analysed for filtering on DOI; + +* comments can now be a part of a rule and loaded into the kernel and + thus displayed with ipfstat; + +* decapsulation rules allow filtering on inner headers, providing they + are not encrypted; + +* interface names, aside from that the packet is on, can be present in + filter rules; + +* internally now a single list of filter rules, there is no longer an + IPv4 and IPv6 list; + +* rules can now be added with an expiration time, allowing for their + automatic removal after some period of time; + +* single file, ipf.conf, can now be used for both IPv4 and IPv6 rules; + +* stateful filtering now allows for limits to be placed on the number + of distinct hosts allowed per rule; + +Pools +----- +* addresses added to a pool via the command line (only!) can be given + an expiration timeout; + +* destination lists are a new type of address pool, primarily for use with + NAT rdr rules, supporting newer algorithms for target selection; + +* raw whois information saved to a file can be used to populate a pool; + +Solaris +------- +* support for use in zones with exclusive IP instances fully supported. + +Tools +----- +* use of matching expressions allows for refining what is displayed or + flushed; + diff --git a/contrib/ipfilter/Y2K b/contrib/ipfilter/Y2K new file mode 100644 index 0000000..a8350a5 --- /dev/null +++ b/contrib/ipfilter/Y2K @@ -0,0 +1,3 @@ +IP Filter is Year 2000 (Y2K) Compliant. + +Darren diff --git a/contrib/ipfilter/arc4random.c b/contrib/ipfilter/arc4random.c new file mode 100644 index 0000000..04b0797 --- /dev/null +++ b/contrib/ipfilter/arc4random.c @@ -0,0 +1,277 @@ +/*- + * THE BEER-WARE LICENSE + * + * <dan@FreeBSD.ORG> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you + * think this stuff is worth it, you can buy me a beer in return. + * + * Dan Moschuk + */ +#if !defined(SOLARIS2) && !defined(__osf__) +# include <sys/cdefs.h> +#endif + +#include <sys/types.h> +#include <sys/param.h> +#ifdef __FreeBSD__ +# include <sys/kernel.h> +#endif +#if !defined(__osf__) +# include <sys/random.h> +#endif +#ifdef __FreeBSD__ +# include <sys/libkern.h> +#endif +#include <sys/lock.h> +#ifndef __osf__ +# include <sys/mutex.h> +#endif +#include <sys/time.h> + +#if defined(SOLARIS2) && (SOLARIS2 < 9) +# include <netinet/in_systm.h> +#endif +#include <sys/socket.h> +#include <net/if.h> +#ifdef __osf__ +# include <net/route.h> +#endif +#include <netinet/in.h> +#include <netinet/ip.h> +#include "netinet/ip_compat.h" +#ifdef HAS_SYS_MD5_H +# include <sys/md5.h> +#else +# include "md5.h" +#endif + +#ifdef NEED_LOCAL_RAND +#if !defined(__GNUC__) +# define __inline +#endif + +#define ARC4_RESEED_BYTES 65536 +#define ARC4_RESEED_SECONDS 300 +#define ARC4_KEYBYTES (256 / 8) + +static u_int8_t arc4_i, arc4_j; +static int arc4_numruns = 0; +static u_int8_t arc4_sbox[256]; +static time_t arc4_t_reseed; +static ipfmutex_t arc4_mtx; +static MD5_CTX md5ctx; + +static u_int8_t arc4_randbyte(void); +static int ipf_read_random(void *dest, int length); + +static __inline void +arc4_swap(u_int8_t *a, u_int8_t *b) +{ + u_int8_t c; + + c = *a; + *a = *b; + *b = c; +} + +/* + * Stir our S-box. + */ +static void +arc4_randomstir (void) +{ + u_int8_t key[256]; + int r, n; + struct timeval tv_now; + + /* + * XXX read_random() returns unsafe numbers if the entropy + * device is not loaded -- MarkM. + */ + r = ipf_read_random(key, ARC4_KEYBYTES); + GETKTIME(&tv_now); + MUTEX_ENTER(&arc4_mtx); + /* If r == 0 || -1, just use what was on the stack. */ + if (r > 0) { + for (n = r; n < sizeof(key); n++) + key[n] = key[n % r]; + } + + for (n = 0; n < 256; n++) { + arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256; + arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]); + } + + /* Reset for next reseed cycle. */ + arc4_t_reseed = tv_now.tv_sec + ARC4_RESEED_SECONDS; + arc4_numruns = 0; + + /* + * Throw away the first N words of output, as suggested in the + * paper "Weaknesses in the Key Scheduling Algorithm of RC4" + * by Fluher, Mantin, and Shamir. (N = 256 in our case.) + */ + for (n = 0; n < 256*4; n++) + arc4_randbyte(); + MUTEX_EXIT(&arc4_mtx); +} + +/* + * Initialize our S-box to its beginning defaults. + */ +static void +arc4_init(void) +{ + int n; + + MD5Init(&md5ctx); + + MUTEX_INIT(&arc4_mtx, "arc4_mtx"); + arc4_i = arc4_j = 0; + for (n = 0; n < 256; n++) + arc4_sbox[n] = (u_int8_t) n; + + arc4_t_reseed = 0; +} + + +/* + * Generate a random byte. + */ +static u_int8_t +arc4_randbyte(void) +{ + u_int8_t arc4_t; + + arc4_i = (arc4_i + 1) % 256; + arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256; + + arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]); + + arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256; + return arc4_sbox[arc4_t]; +} + +/* + * MPSAFE + */ +void +arc4rand(void *ptr, u_int len, int reseed) +{ + u_int8_t *p; + struct timeval tv; + + GETKTIME(&tv); + if (reseed || + (arc4_numruns > ARC4_RESEED_BYTES) || + (tv.tv_sec > arc4_t_reseed)) + arc4_randomstir(); + + MUTEX_ENTER(&arc4_mtx); + arc4_numruns += len; + p = ptr; + while (len--) + *p++ = arc4_randbyte(); + MUTEX_EXIT(&arc4_mtx); +} + +uint32_t +ipf_random(void) +{ + uint32_t ret; + + arc4rand(&ret, sizeof ret, 0); + return ret; +} + + +static u_char pot[ARC4_RESEED_BYTES]; +static u_char *pothead = pot, *pottail = pot; +static int inpot = 0; + +/* + * This is not very strong, and this is understood, but the aim isn't to + * be cryptographically strong - it is just to make up something that is + * pseudo random. + */ +void +ipf_rand_push(void *src, int length) +{ + static int arc4_inited = 0; + u_char *nsrc; + int mylen; + + if (arc4_inited == 0) { + arc4_init(); + arc4_inited = 1; + } + + if (length < 64) { + MD5Update(&md5ctx, src, length); + return; + } + + nsrc = src; + mylen = length; + +#if defined(_SYS_MD5_H) && defined(SOLARIS2) +# define buf buf_un.buf8 +#endif + MUTEX_ENTER(&arc4_mtx); + while ((mylen > 64) && (sizeof(pot) - inpot > sizeof(md5ctx.buf))) { + MD5Update(&md5ctx, nsrc, 64); + mylen -= 64; + nsrc += 64; + if (pottail + sizeof(md5ctx.buf) > pot + sizeof(pot)) { + int left, numbytes; + + numbytes = pot + sizeof(pot) - pottail; + bcopy(md5ctx.buf, pottail, numbytes); + left = sizeof(md5ctx.buf) - numbytes; + pottail = pot; + bcopy(md5ctx.buf + sizeof(md5ctx.buf) - left, + pottail, left); + pottail += left; + } else { + bcopy(md5ctx.buf, pottail, sizeof(md5ctx.buf)); + pottail += sizeof(md5ctx.buf); + } + inpot += 64; + } + MUTEX_EXIT(&arc4_mtx); +#if defined(_SYS_MD5_H) && defined(SOLARIS2) +# undef buf +#endif +} + + +static int +ipf_read_random(void *dest, int length) +{ + if (length > inpot) + return 0; + + MUTEX_ENTER(&arc4_mtx); + if (pothead + length > pot + sizeof(pot)) { + int left, numbytes; + + left = length; + numbytes = pot + sizeof(pot) - pothead; + bcopy(pothead, dest, numbytes); + left -= numbytes; + pothead = pot; + bcopy(pothead, dest + length - left, left); + pothead += left; + } else { + bcopy(pothead, dest, length); + pothead += length; + } + inpot -= length; + if (inpot == 0) + pothead = pottail = pot; + MUTEX_EXIT(&arc4_mtx); + + return length; +} + +#endif /* NEED_LOCAL_RAND */ diff --git a/contrib/ipfilter/bpf-ipf.h b/contrib/ipfilter/bpf-ipf.h new file mode 100644 index 0000000..dc2b660 --- /dev/null +++ b/contrib/ipfilter/bpf-ipf.h @@ -0,0 +1,452 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /devel/CVS/IP-Filter/bpf-ipf.h,v 2.1 2002/10/26 12:14:26 darrenr Exp $ (LBL) + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +typedef int bpf_int32; +typedef u_int bpf_u_int32; + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXINSNS 512 +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for BIOCSETF. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct returned by BIOCGSTATS. + */ +struct bpf_stat { + u_int bs_recv; /* number of packets received */ + u_int bs_drop; /* number of packets dropped */ +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * BPF ioctls + * + * The first set is for compatibility with Sun's pcc style + * header files. If your using gcc, we assume that you + * have run fixincludes so the latter set should work. + */ +#if (defined(sun) || defined(ibm032)) && !defined(__GNUC__) +#define BIOCGBLEN _IOR(B,102, u_int) +#define BIOCSBLEN _IOWR(B,102, u_int) +#define BIOCSETF _IOW(B,103, struct bpf_program) +#define BIOCFLUSH _IO(B,104) +#define BIOCPROMISC _IO(B,105) +#define BIOCGDLT _IOR(B,106, u_int) +#define BIOCGETIF _IOR(B,107, struct ifreq) +#define BIOCSETIF _IOW(B,108, struct ifreq) +#define BIOCSRTIMEOUT _IOW(B,109, struct timeval) +#define BIOCGRTIMEOUT _IOR(B,110, struct timeval) +#define BIOCGSTATS _IOR(B,111, struct bpf_stat) +#define BIOCIMMEDIATE _IOW(B,112, u_int) +#define BIOCVERSION _IOR(B,113, struct bpf_version) +#define BIOCSTCPF _IOW(B,114, struct bpf_program) +#define BIOCSUDPF _IOW(B,115, struct bpf_program) +#else +#define BIOCGBLEN _IOR('B',102, u_int) +#define BIOCSBLEN _IOWR('B',102, u_int) +#define BIOCSETF _IOW('B',103, struct bpf_program) +#define BIOCFLUSH _IO('B',104) +#define BIOCPROMISC _IO('B',105) +#define BIOCGDLT _IOR('B',106, u_int) +#define BIOCGETIF _IOR('B',107, struct ifreq) +#define BIOCSETIF _IOW('B',108, struct ifreq) +#define BIOCSRTIMEOUT _IOW('B',109, struct timeval) +#define BIOCGRTIMEOUT _IOR('B',110, struct timeval) +#define BIOCGSTATS _IOR('B',111, struct bpf_stat) +#define BIOCIMMEDIATE _IOW('B',112, u_int) +#define BIOCVERSION _IOR('B',113, struct bpf_version) +#define BIOCSTCPF _IOW('B',114, struct bpf_program) +#define BIOCSUDPF _IOW('B',115, struct bpf_program) +#endif + +/* + * Structure prepended to each packet. + */ +struct bpf_hdr { + struct timeval bh_tstamp; /* time stamp */ + bpf_u_int32 bh_caplen; /* length of captured portion */ + bpf_u_int32 bh_datalen; /* original length of packet */ + u_short bh_hdrlen; /* length of bpf header (this struct + plus alignment padding) */ +}; +/* + * Because the structure above is not a multiple of 4 bytes, some compilers + * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work. + * Only the kernel needs to know about it; applications use bh_hdrlen. + */ +#if defined(KERNEL) || defined(_KERNEL) +#define SIZEOF_BPF_HDR 18 +#endif + +/* + * Data-link level type codes. + */ + +/* + * These are the types that are the same on all platforms; on other + * platforms, a <net/bpf.h> should be supplied that defines the additional + * DLT_* codes appropriately for that platform (the BSDs, for example, + * should not just pick up this version of "bpf.h"; they should also define + * the additional DLT_* codes used by their kernels, as well as the values + * defined here - and, if the values they use for particular DLT_ types + * differ from those here, they should use their values, not the ones + * here). + */ +#define DLT_NULL 0 /* no link-layer encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* IEEE 802 Networks */ +#define DLT_ARCNET 7 /* ARCNET */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are values from the traditional libpcap "bpf.h". + * Ports of this to particular platforms should replace these definitions + * with the ones appropriate to that platform, if the values are + * different on that platform. + */ +#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ +#define DLT_RAW 12 /* raw IP */ + +/* + * These are values from BSD/OS's "bpf.h". + * These are not the same as the values from the traditional libpcap + * "bpf.h"; however, these values shouldn't be generated by any + * OS other than BSD/OS, so the correct values to use here are the + * BSD/OS values. + * + * Platforms that have already assigned these values to other + * DLT_ codes, however, should give these codes the values + * from that platform, so that programs that use these codes will + * continue to compile - even though they won't correctly read + * files of these types. + */ +#ifdef __NetBSD__ +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * Values between 106 and 107 are used in capture file headers as + * link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * OpenBSD defines it as 12, but that collides with DLT_RAW, so we + * define it as 108 here. If OpenBSD picks up this file, it should + * define DLT_LOOP as 12 in its version, as per the comment above - + * and should not use 108 as a DLT_ value. + */ +#define DLT_LOOP 108 + +/* + * Values between 109 and 112 are used in capture file headers as + * link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * Reserved for use in capture-file headers as a link-layer type + * corresponding to OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, + * but that's DLT_LANE8023 in SuSE 6.3, so we can't use 17 for it + * in capture-file headers. + */ +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * Reserved for 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * Reserved for RFC 2625 IP-over-Fibre Channel, as per a request from + * Don Lee <donlee@cray.com>. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if defined(BSD) && (defined(KERNEL) || defined(_KERNEL)) +/* + * Systems based on non-BSD kernels don't have ifnet's (or they don't mean + * anything if it is in <net/if.h>) and won't work like this. + */ +# if __STDC__ +extern void bpf_tap(struct ifnet *, u_char *, u_int); +extern void bpf_mtap(struct ifnet *, struct mbuf *); +extern void bpfattach(struct ifnet *, u_int, u_int); +extern void bpfilterattach(int); +# else +extern void bpf_tap(); +extern void bpf_mtap(); +extern void bpfattach(); +extern void bpfilterattach(); +# endif /* __STDC__ */ +#endif /* BSD && (_KERNEL || KERNEL) */ +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(struct bpf_insn *, int); +extern u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/ipfilter/bpf_filter.c b/contrib/ipfilter/bpf_filter.c new file mode 100644 index 0000000..d75570e --- /dev/null +++ b/contrib/ipfilter/bpf_filter.c @@ -0,0 +1,595 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.c 7.5 (Berkeley) 7/15/91 + */ + +#if !(defined(lint) || defined(KERNEL) || defined(_KERNEL)) +static const char rcsid[] = + "@(#) $Header: /devel/CVS/IP-Filter/bpf_filter.c,v 2.2.2.3 2006/10/03 11:25:56 darrenr Exp $ (LBL)"; +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include "netinet/ip_compat.h" +#include "bpf-ipf.h" + + +#if (defined(__hpux) || SOLARIS) && (defined(_KERNEL) || defined(KERNEL)) +# include <sys/sysmacros.h> +# include <sys/stream.h> +#endif + +#include "pcap-ipf.h" + +#if !defined(KERNEL) && !defined(_KERNEL) +#include <stdlib.h> +#endif + +#define int32 bpf_int32 +#define u_int32 bpf_u_int32 + +static int m_xword __P((mb_t *, int, int *)); +static int m_xhalf __P((mb_t *, int, int *)); + +#ifndef LBL_ALIGN +/* + * XXX - IA-64? If not, this probably won't work on Win64 IA-64 + * systems, unless LBL_ALIGN is defined elsewhere for them. + * XXX - SuperH? If not, this probably won't work on WinCE SuperH + * systems, unless LBL_ALIGN is defined elsewhere for them. + */ +#if defined(sparc) || defined(__sparc__) || defined(mips) || \ + defined(ibm032) || defined(__alpha) || defined(__hpux) || \ + defined(__arm__) +#define LBL_ALIGN +#endif +#endif + +#ifndef LBL_ALIGN + +#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p)) +#define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p)) +#else +#define EXTRACT_SHORT(p)\ + ((u_short)\ + ((u_short)*((u_char *)p+0)<<8|\ + (u_short)*((u_char *)p+1)<<0)) +#define EXTRACT_LONG(p)\ + ((u_int32)*((u_char *)p+0)<<24|\ + (u_int32)*((u_char *)p+1)<<16|\ + (u_int32)*((u_char *)p+2)<<8|\ + (u_int32)*((u_char *)p+3)<<0) +#endif + +#define MINDEX(len, _m, _k) \ +{ \ + len = M_LEN(m); \ + while ((_k) >= len) { \ + (_k) -= len; \ + (_m) = (_m)->m_next; \ + if ((_m) == 0) \ + return 0; \ + len = M_LEN(m); \ + } \ +} + +static int +m_xword(m, k, err) + register mb_t *m; + register int k, *err; +{ + register int len; + register u_char *cp, *np; + register mb_t *m0; + + MINDEX(len, m, k); + cp = MTOD(m, u_char *) + k; + if (len - k >= 4) { + *err = 0; + return EXTRACT_LONG(cp); + } + m0 = m->m_next; + if (m0 == 0 || M_LEN(m0) + len - k < 4) + goto bad; + *err = 0; + np = MTOD(m0, u_char *); + switch (len - k) { + + case 1: + return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2]; + + case 2: + return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) | np[1]; + + default: + return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | np[0]; + } + bad: + *err = 1; + return 0; +} + +static int +m_xhalf(m, k, err) + register mb_t *m; + register int k, *err; +{ + register int len; + register u_char *cp; + register mb_t *m0; + + MINDEX(len, m, k); + cp = MTOD(m, u_char *) + k; + if (len - k >= 2) { + *err = 0; + return EXTRACT_SHORT(cp); + } + m0 = m->m_next; + if (m0 == 0) + goto bad; + *err = 0; + return (cp[0] << 8) | MTOD(m0, u_char *)[0]; + bad: + *err = 1; + return 0; +} + +/* + * Execute the filter program starting at pc on the packet p + * wirelen is the length of the original packet + * buflen is the amount of data present + * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0, + * in all other cases, p is a pointer to a buffer and buflen is its size. + */ +u_int +bpf_filter(pc, p, wirelen, buflen) + register struct bpf_insn *pc; + register u_char *p; + u_int wirelen; + register u_int buflen; +{ + register u_int32 A, X; + register int k; + int32 mem[BPF_MEMWORDS]; + mb_t *m, *n; + int merr = 0; /* XXX: GCC */ + int len; + + if (buflen == 0) { + m = (mb_t *)p; + p = MTOD(m, u_char *); + buflen = M_LEN(m); + } else + m = NULL; + + if (pc == 0) + /* + * No filter means accept all. + */ + return (u_int)-1; + A = 0; + X = 0; + --pc; + while (1) { + ++pc; + switch (pc->code) { + + default: + return 0; + case BPF_RET|BPF_K: + return (u_int)pc->k; + + case BPF_RET|BPF_A: + return (u_int)A; + + case BPF_LD|BPF_W|BPF_ABS: + k = pc->k; + if (k + sizeof(int32) > buflen) { + if (m == NULL) + return 0; + A = m_xword(m, k, &merr); + if (merr != 0) + return 0; + continue; + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_ABS: + k = pc->k; + if (k + sizeof(short) > buflen) { + if (m == NULL) + return 0; + A = m_xhalf(m, k, &merr); + if (merr != 0) + return 0; + continue; + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_ABS: + k = pc->k; + if (k >= buflen) { + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + A = MTOD(n, u_char *)[k]; + continue; + } + A = p[k]; + continue; + + case BPF_LD|BPF_W|BPF_LEN: + A = wirelen; + continue; + + case BPF_LDX|BPF_W|BPF_LEN: + X = wirelen; + continue; + + case BPF_LD|BPF_W|BPF_IND: + k = X + pc->k; + if (k + sizeof(int32) > buflen) { + if (m == NULL) + return 0; + A = m_xword(m, k, &merr); + if (merr != 0) + return 0; + continue; + } + A = EXTRACT_LONG(&p[k]); + continue; + + case BPF_LD|BPF_H|BPF_IND: + k = X + pc->k; + if (k + sizeof(short) > buflen) { + if (m == NULL) + return 0; + A = m_xhalf(m, k, &merr); + if (merr != 0) + return 0; + continue; + } + A = EXTRACT_SHORT(&p[k]); + continue; + + case BPF_LD|BPF_B|BPF_IND: + k = X + pc->k; + if (k >= buflen) { + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + A = MTOD(n, u_char *)[k]; + continue; + } + A = p[k]; + continue; + + case BPF_LDX|BPF_MSH|BPF_B: + k = pc->k; + if (k >= buflen) { + if (m == NULL) + return 0; + n = m; + MINDEX(len, n, k); + X = (MTOD(n, char *)[k] & 0xf) << 2; + continue; + } + X = (p[pc->k] & 0xf) << 2; + continue; + + case BPF_LD|BPF_IMM: + A = pc->k; + continue; + + case BPF_LDX|BPF_IMM: + X = pc->k; + continue; + + case BPF_LD|BPF_MEM: + A = mem[pc->k]; + continue; + + case BPF_LDX|BPF_MEM: + X = mem[pc->k]; + continue; + + case BPF_ST: + mem[pc->k] = A; + continue; + + case BPF_STX: + mem[pc->k] = X; + continue; + + case BPF_JMP|BPF_JA: + pc += pc->k; + continue; + + case BPF_JMP|BPF_JGT|BPF_K: + pc += (A > pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_K: + pc += (A >= pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_K: + pc += (A == pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; + + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + + case BPF_ALU|BPF_ADD|BPF_K: + A += pc->k; + continue; + + case BPF_ALU|BPF_SUB|BPF_K: + A -= pc->k; + continue; + + case BPF_ALU|BPF_MUL|BPF_K: + A *= pc->k; + continue; + + case BPF_ALU|BPF_DIV|BPF_K: + A /= pc->k; + continue; + + case BPF_ALU|BPF_AND|BPF_K: + A &= pc->k; + continue; + + case BPF_ALU|BPF_OR|BPF_K: + A |= pc->k; + continue; + + case BPF_ALU|BPF_LSH|BPF_K: + A <<= pc->k; + continue; + + case BPF_ALU|BPF_RSH|BPF_K: + A >>= pc->k; + continue; + + case BPF_ALU|BPF_NEG: + A = -A; + continue; + + case BPF_MISC|BPF_TAX: + X = A; + continue; + + case BPF_MISC|BPF_TXA: + A = X; + continue; + } + } +} + + +/* + * Return true if the 'fcode' is a valid filter program. + * The constraints are that each jump be forward and to a valid + * code, that memory accesses are within valid ranges (to the + * extent that this can be checked statically; loads of packet + * data have to be, and are, also checked at run time), and that + * the code terminates with either an accept or reject. + * + * The kernel needs to be able to verify an application's filter code. + * Otherwise, a bogus program could easily crash the system. + */ +int +bpf_validate(f, len) + struct bpf_insn *f; + int len; +{ + u_int i, from; + const struct bpf_insn *p; + + if (len == 0) + return 1; + + if (len < 1 || len > BPF_MAXINSNS) + return 0; + + for (i = 0; i < len; ++i) { + p = &f[i]; + switch (BPF_CLASS(p->code)) { + /* + * Check that memory operations use valid addresses. + */ + case BPF_LD: + case BPF_LDX: + switch (BPF_MODE(p->code)) { + case BPF_IMM: + break; + case BPF_ABS: + case BPF_IND: + case BPF_MSH: + /* + * More strict check with actual packet length + * is done runtime. + */ +#if 0 + if (p->k >= bpf_maxbufsize) + return 0; +#endif + break; + case BPF_MEM: + if (p->k >= BPF_MEMWORDS) + return 0; + break; + case BPF_LEN: + break; + default: + return 0; + } + break; + case BPF_ST: + case BPF_STX: + if (p->k >= BPF_MEMWORDS) + return 0; + break; + case BPF_ALU: + switch (BPF_OP(p->code)) { + case BPF_ADD: + case BPF_SUB: + case BPF_OR: + case BPF_AND: + case BPF_LSH: + case BPF_RSH: + case BPF_NEG: + break; + case BPF_DIV: + /* + * Check for constant division by 0. + */ + if (BPF_RVAL(p->code) == BPF_K && p->k == 0) + return 0; + default: + return 0; + } + break; + case BPF_JMP: + /* + * Check that jumps are within the code block, + * and that unconditional branches don't go + * backwards as a result of an overflow. + * Unconditional branches have a 32-bit offset, + * so they could overflow; we check to make + * sure they don't. Conditional branches have + * an 8-bit offset, and the from address is <= + * BPF_MAXINSNS, and we assume that BPF_MAXINSNS + * is sufficiently small that adding 255 to it + * won't overflow. + * + * We know that len is <= BPF_MAXINSNS, and we + * assume that BPF_MAXINSNS is < the maximum size + * of a u_int, so that i + 1 doesn't overflow. + */ + from = i + 1; + switch (BPF_OP(p->code)) { + case BPF_JA: + if (from + p->k < from || from + p->k >= len) + return 0; + break; + case BPF_JEQ: + case BPF_JGT: + case BPF_JGE: + case BPF_JSET: + if (from + p->jt >= len || from + p->jf >= len) + return 0; + break; + default: + return 0; + } + break; + case BPF_RET: + break; + case BPF_MISC: + break; + default: + return 0; + } + } + return BPF_CLASS(f[len - 1].code) == BPF_RET; +} diff --git a/contrib/ipfilter/genmask.c b/contrib/ipfilter/genmask.c new file mode 100644 index 0000000..75193e3 --- /dev/null +++ b/contrib/ipfilter/genmask.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +int genmask(family, msk, mskp) + int family; + char *msk; + i6addr_t *mskp; +{ + char *endptr = 0L; + u_32_t addr; + int bits; + + if (strchr(msk, '.') || strchr(msk, 'x') || strchr(msk, ':')) { + /* possibly of the form xxx.xxx.xxx.xxx + * or 0xYYYYYYYY */ + switch (family) + { +#ifdef USE_INET6 + case AF_INET6 : + if (inet_pton(AF_INET6, msk, &mskp->in4) != 1) + return -1; + break; +#endif + case AF_INET : + if (inet_aton(msk, &mskp->in4) == 0) + return -1; + break; + default : + return -1; + /*NOTREACHED*/ + } + } else { + /* + * set x most significant bits + */ + bits = (int)strtol(msk, &endptr, 0); + + switch (family) + { + case AF_INET6 : + if ((*endptr != '\0') || (bits < 0) || (bits > 128)) + return -1; + fill6bits(bits, mskp->i6); + break; + case AF_INET : + if (*endptr != '\0' || bits > 32 || bits < 0) + return -1; + if (bits == 0) + addr = 0; + else + addr = htonl(0xffffffff << (32 - bits)); + mskp->in4.s_addr = addr; + break; + default : + return -1; + /*NOTREACHED*/ + } + } + return 0; +} diff --git a/contrib/ipfilter/ip_dstlist.c b/contrib/ipfilter/ip_dstlist.c new file mode 100644 index 0000000..ce2e72e --- /dev/null +++ b/contrib/ipfilter/ip_dstlist.c @@ -0,0 +1,1351 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#if defined(__osf__) +# define _PROTO_NET_H_ +#endif +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#if !defined(_KERNEL) && !defined(__KERNEL__) +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL +#else +# include <sys/systm.h> +# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) +# include <sys/proc.h> +# endif +#endif +#include <sys/time.h> +#if !defined(linux) +# include <sys/protosw.h> +#endif +#include <sys/socket.h> +#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__)) +# include <sys/mbuf.h> +#endif +#if defined(__SVR4) || defined(__svr4__) +# include <sys/filio.h> +# include <sys/byteorder.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif +# include <sys/stream.h> +# include <sys/kmem.h> +#endif +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +#endif + +#include <net/if.h> +#include <netinet/in.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_dstlist.h" + +/* END OF INCLUDES */ + +#ifdef HAS_SYS_MD5_H +# include <sys/md5.h> +#else +# include "md5.h" +#endif + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: ip_dstlist.c,v 1.13.2.12 2012/07/20 08:40:19 darren_r Exp $"; +#endif + +typedef struct ipf_dstl_softc_s { + ippool_dst_t *dstlist[LOOKUP_POOL_SZ]; + ippool_dst_t **tails[LOOKUP_POOL_SZ]; + ipf_dstl_stat_t stats; +} ipf_dstl_softc_t; + + +static void *ipf_dstlist_soft_create __P((ipf_main_softc_t *)); +static void ipf_dstlist_soft_destroy __P((ipf_main_softc_t *, void *)); +static int ipf_dstlist_soft_init __P((ipf_main_softc_t *, void *)); +static void ipf_dstlist_soft_fini __P((ipf_main_softc_t *, void *)); +static int ipf_dstlist_addr_find __P((ipf_main_softc_t *, void *, int, + void *, u_int)); +static size_t ipf_dstlist_flush __P((ipf_main_softc_t *, void *, + iplookupflush_t *)); +static int ipf_dstlist_iter_deref __P((ipf_main_softc_t *, void *, int, int, + void *)); +static int ipf_dstlist_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *, + ipflookupiter_t *)); +static int ipf_dstlist_node_add __P((ipf_main_softc_t *, void *, + iplookupop_t *, int)); +static int ipf_dstlist_node_del __P((ipf_main_softc_t *, void *, + iplookupop_t *, int)); +static int ipf_dstlist_stats_get __P((ipf_main_softc_t *, void *, + iplookupop_t *)); +static int ipf_dstlist_table_add __P((ipf_main_softc_t *, void *, + iplookupop_t *)); +static int ipf_dstlist_table_del __P((ipf_main_softc_t *, void *, + iplookupop_t *)); +static int ipf_dstlist_table_deref __P((ipf_main_softc_t *, void *, void *)); +static void *ipf_dstlist_table_find __P((void *, int, char *)); +static void ipf_dstlist_table_free __P((ipf_dstl_softc_t *, ippool_dst_t *)); +static void ipf_dstlist_table_remove __P((ipf_main_softc_t *, + ipf_dstl_softc_t *, ippool_dst_t *)); +static void ipf_dstlist_table_clearnodes __P((ipf_dstl_softc_t *, + ippool_dst_t *)); +static ipf_dstnode_t *ipf_dstlist_select __P((fr_info_t *, ippool_dst_t *)); +static void *ipf_dstlist_select_ref __P((void *, int, char *)); +static void ipf_dstlist_node_free __P((ipf_dstl_softc_t *, ippool_dst_t *, ipf_dstnode_t *)); +static int ipf_dstlist_node_deref __P((void *, ipf_dstnode_t *)); +static void ipf_dstlist_expire __P((ipf_main_softc_t *, void *)); +static void ipf_dstlist_sync __P((ipf_main_softc_t *, void *)); + +ipf_lookup_t ipf_dstlist_backend = { + IPLT_DSTLIST, + ipf_dstlist_soft_create, + ipf_dstlist_soft_destroy, + ipf_dstlist_soft_init, + ipf_dstlist_soft_fini, + ipf_dstlist_addr_find, + ipf_dstlist_flush, + ipf_dstlist_iter_deref, + ipf_dstlist_iter_next, + ipf_dstlist_node_add, + ipf_dstlist_node_del, + ipf_dstlist_stats_get, + ipf_dstlist_table_add, + ipf_dstlist_table_del, + ipf_dstlist_table_deref, + ipf_dstlist_table_find, + ipf_dstlist_select_ref, + ipf_dstlist_select_node, + ipf_dstlist_expire, + ipf_dstlist_sync +}; + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_soft_create */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* */ +/* Allocating a chunk of memory filled with 0's is enough for the current */ +/* soft context used with destination lists. */ +/* ------------------------------------------------------------------------ */ +static void * +ipf_dstlist_soft_create(softc) + ipf_main_softc_t *softc; +{ + ipf_dstl_softc_t *softd; + int i; + + KMALLOC(softd, ipf_dstl_softc_t *); + if (softd == NULL) { + IPFERROR(120028); + return NULL; + } + + bzero((char *)softd, sizeof(*softd)); + for (i = 0; i <= IPL_LOGMAX; i++) + softd->tails[i] = &softd->dstlist[i]; + + return softd; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_soft_destroy */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* */ +/* For destination lists, the only thing we have to do when destroying the */ +/* soft context is free it! */ +/* ------------------------------------------------------------------------ */ +static void +ipf_dstlist_soft_destroy(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_dstl_softc_t *softd = arg; + + KFREE(softd); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_soft_init */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* */ +/* There is currently no soft context for destination list management. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_soft_init(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_soft_fini */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* */ +/* There is currently no soft context for destination list management. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_dstlist_soft_fini(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_dstl_softc_t *softd = arg; + int i; + + for (i = -1; i <= IPL_LOGMAX; i++) { + while (softd->dstlist[i + 1] != NULL) { + ipf_dstlist_table_remove(softc, softd, + softd->dstlist[i + 1]); + } + } + + ASSERT(softd->stats.ipls_numderefnodes == 0); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_addr_find */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg1(I) - pointer to local context to use */ +/* arg2(I) - pointer to local context to use */ +/* arg3(I) - pointer to local context to use */ +/* arg4(I) - pointer to local context to use */ +/* */ +/* There is currently no such thing as searching a destination list for an */ +/* address so this function becomes a no-op. Its presence is required as */ +/* ipf_lookup_res_name() stores the "addr_find" function pointer in the */ +/* pointer passed in to it as funcptr, although it could be a generic null- */ +/* op function rather than a specific one. */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +static int +ipf_dstlist_addr_find(softc, arg1, arg2, arg3, arg4) + ipf_main_softc_t *softc; + void *arg1, *arg3; + int arg2; + u_int arg4; +{ + return -1; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_flush */ +/* Returns: int - number of objects deleted */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* fop(I) - pointer to lookup flush operation data */ +/* */ +/* Flush all of the destination tables that match the data passed in with */ +/* the iplookupflush_t. There are two ways to match objects: the device for */ +/* which they are to be used with and their name. */ +/* ------------------------------------------------------------------------ */ +static size_t +ipf_dstlist_flush(softc, arg, fop) + ipf_main_softc_t *softc; + void *arg; + iplookupflush_t *fop; +{ + ipf_dstl_softc_t *softd = arg; + ippool_dst_t *node, *next; + int n, i; + + for (n = 0, i = -1; i <= IPL_LOGMAX; i++) { + if (fop->iplf_unit != IPLT_ALL && fop->iplf_unit != i) + continue; + for (node = softd->dstlist[i + 1]; node != NULL; node = next) { + next = node->ipld_next; + + if ((*fop->iplf_name != '\0') && + strncmp(fop->iplf_name, node->ipld_name, + FR_GROUPLEN)) + continue; + + ipf_dstlist_table_remove(softc, softd, node); + n++; + } + } + return n; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_iter_deref */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* otype(I) - type of data structure to iterate through */ +/* unit(I) - device we are working with */ +/* data(I) - address of object in kernel space */ +/* */ +/* This function is called when the iteration token is being free'd and is */ +/* responsible for dropping the reference count of the structure it points */ +/* to. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_iter_deref(softc, arg, otype, unit, data) + ipf_main_softc_t *softc; + void *arg; + int otype, unit; + void *data; +{ + if (data == NULL) { + IPFERROR(120001); + return EINVAL; + } + + if (unit < -1 || unit > IPL_LOGMAX) { + IPFERROR(120002); + return EINVAL; + } + + switch (otype) + { + case IPFLOOKUPITER_LIST : + ipf_dstlist_table_deref(softc, arg, (ippool_dst_t *)data); + break; + + case IPFLOOKUPITER_NODE : + ipf_dstlist_node_deref(arg, (ipf_dstnode_t *)data); + break; + } + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_iter_next */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operation data */ +/* uid(I) - uid of process doing the ioctl */ +/* */ +/* This function is responsible for either selecting the next destination */ +/* list or node on a destination list to be returned as a user process */ +/* iterates through the list of destination lists or nodes. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_iter_next(softc, arg, token, iter) + ipf_main_softc_t *softc; + void *arg; + ipftoken_t *token; + ipflookupiter_t *iter; +{ + ipf_dstnode_t zn, *nextnode = NULL, *node = NULL; + ippool_dst_t zero, *next = NULL, *dsttab = NULL; + ipf_dstl_softc_t *softd = arg; + int err = 0; + void *hint; + + switch (iter->ili_otype) + { + case IPFLOOKUPITER_LIST : + dsttab = token->ipt_data; + if (dsttab == NULL) { + next = softd->dstlist[(int)iter->ili_unit + 1]; + } else { + next = dsttab->ipld_next; + } + + if (next != NULL) { + ATOMIC_INC32(next->ipld_ref); + token->ipt_data = next; + hint = next->ipld_next; + } else { + bzero((char *)&zero, sizeof(zero)); + next = &zero; + token->ipt_data = NULL; + hint = NULL; + } + break; + + case IPFLOOKUPITER_NODE : + node = token->ipt_data; + if (node == NULL) { + dsttab = ipf_dstlist_table_find(arg, iter->ili_unit, + iter->ili_name); + if (dsttab == NULL) { + IPFERROR(120004); + err = ESRCH; + nextnode = NULL; + } else { + if (dsttab->ipld_dests == NULL) + nextnode = NULL; + else + nextnode = *dsttab->ipld_dests; + dsttab = NULL; + } + } else { + nextnode = node->ipfd_next; + } + + if (nextnode != NULL) { + MUTEX_ENTER(&nextnode->ipfd_lock); + nextnode->ipfd_ref++; + MUTEX_EXIT(&nextnode->ipfd_lock); + token->ipt_data = nextnode; + hint = nextnode->ipfd_next; + } else { + bzero((char *)&zn, sizeof(zn)); + nextnode = &zn; + token->ipt_data = NULL; + hint = NULL; + } + break; + default : + IPFERROR(120003); + err = EINVAL; + break; + } + + if (err != 0) + return err; + + switch (iter->ili_otype) + { + case IPFLOOKUPITER_LIST : + if (dsttab != NULL) + ipf_dstlist_table_deref(softc, arg, dsttab); + err = COPYOUT(next, iter->ili_data, sizeof(*next)); + if (err != 0) { + IPFERROR(120005); + err = EFAULT; + } + break; + + case IPFLOOKUPITER_NODE : + if (node != NULL) + ipf_dstlist_node_deref(arg, node); + err = COPYOUT(nextnode, iter->ili_data, sizeof(*nextnode)); + if (err != 0) { + IPFERROR(120006); + err = EFAULT; + } + break; + } + + if (hint == NULL) + ipf_token_mark_complete(token); + + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_node_add */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operation data */ +/* uid(I) - uid of process doing the ioctl */ +/* Locks: WRITE(ipf_poolrw) */ +/* */ +/* Add a new node to a destination list. To do this, we only copy in the */ +/* frdest_t structure because that contains the only data required from the */ +/* application to create a new node. The frdest_t doesn't contain the name */ +/* itself. When loading filter rules, fd_name is a 'pointer' to the name. */ +/* In this case, the 'pointer' does not work, instead it is the length of */ +/* the name and the name is immediately following the frdest_t structure. */ +/* fd_name must include the trailing \0, so it should be strlen(str) + 1. */ +/* For simple sanity checking, an upper bound on the size of fd_name is */ +/* imposed - 128. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_node_add(softc, arg, op, uid) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; + int uid; +{ + ipf_dstl_softc_t *softd = arg; + ipf_dstnode_t *node, **nodes; + ippool_dst_t *d; + frdest_t dest; + int err; + + if (op->iplo_size < sizeof(frdest_t)) { + IPFERROR(120007); + return EINVAL; + } + + err = COPYIN(op->iplo_struct, &dest, sizeof(dest)); + if (err != 0) { + IPFERROR(120009); + return EFAULT; + } + + d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name); + if (d == NULL) { + IPFERROR(120010); + return ESRCH; + } + + switch (dest.fd_addr.adf_family) + { + case AF_INET : + case AF_INET6 : + break; + default : + IPFERROR(120019); + return EINVAL; + } + + if (dest.fd_name < -1 || dest.fd_name > 128) { + IPFERROR(120018); + return EINVAL; + } + + KMALLOCS(node, ipf_dstnode_t *, sizeof(*node) + dest.fd_name); + if (node == NULL) { + softd->stats.ipls_nomem++; + IPFERROR(120008); + return ENOMEM; + } + bzero((char *)node, sizeof(*node) + dest.fd_name); + + bcopy(&dest, &node->ipfd_dest, sizeof(dest)); + node->ipfd_size = sizeof(*node) + dest.fd_name; + + if (dest.fd_name > 0) { + /* + * fd_name starts out as the length of the string to copy + * in (including \0) and ends up being the offset from + * fd_names (0). + */ + err = COPYIN((char *)op->iplo_struct + sizeof(dest), + node->ipfd_names, dest.fd_name); + if (err != 0) { + IPFERROR(120017); + KFREES(node, node->ipfd_size); + return EFAULT; + } + node->ipfd_dest.fd_name = 0; + } else { + node->ipfd_dest.fd_name = -1; + } + + if (d->ipld_nodes == d->ipld_maxnodes) { + KMALLOCS(nodes, ipf_dstnode_t **, + sizeof(*nodes) * (d->ipld_maxnodes + 1)); + if (nodes == NULL) { + softd->stats.ipls_nomem++; + IPFERROR(120022); + KFREES(node, node->ipfd_size); + return ENOMEM; + } + if (d->ipld_dests != NULL) { + bcopy(d->ipld_dests, nodes, + sizeof(*nodes) * d->ipld_maxnodes); + KFREES(d->ipld_dests, sizeof(*nodes) * d->ipld_nodes); + nodes[0]->ipfd_pnext = nodes; + } + d->ipld_dests = nodes; + d->ipld_maxnodes++; + } + d->ipld_dests[d->ipld_nodes] = node; + d->ipld_nodes++; + + if (d->ipld_nodes == 1) { + node->ipfd_pnext = d->ipld_dests; + } else if (d->ipld_nodes > 1) { + node->ipfd_pnext = &d->ipld_dests[d->ipld_nodes - 2]->ipfd_next; + } + *node->ipfd_pnext = node; + + MUTEX_INIT(&node->ipfd_lock, "ipf dst node lock"); + node->ipfd_uid = uid; + node->ipfd_ref = 1; + if (node->ipfd_dest.fd_name == 0) + (void) ipf_resolvedest(softc, node->ipfd_names, + &node->ipfd_dest, AF_INET); +#ifdef USE_INET6 + if (node->ipfd_dest.fd_name == 0 && + node->ipfd_dest.fd_ptr == (void *)-1) + (void) ipf_resolvedest(softc, node->ipfd_names, + &node->ipfd_dest, AF_INET6); +#endif + + softd->stats.ipls_numnodes++; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_node_deref */ +/* Returns: int - 0 = success, else error */ +/* Parameters: arg(I) - pointer to local context to use */ +/* node(I) - pointer to destionation node to free */ +/* */ +/* Dereference the use count by one. If it drops to zero then we can assume */ +/* that it has been removed from any lists/tables and is ripe for freeing. */ +/* The pointer to context is required for the purpose of maintaining */ +/* statistics. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_node_deref(arg, node) + void *arg; + ipf_dstnode_t *node; +{ + ipf_dstl_softc_t *softd = arg; + int ref; + + MUTEX_ENTER(&node->ipfd_lock); + ref = --node->ipfd_ref; + MUTEX_EXIT(&node->ipfd_lock); + + if (ref > 0) + return 0; + + if ((node->ipfd_flags & IPDST_DELETE) != 0) + softd->stats.ipls_numderefnodes--; + MUTEX_DESTROY(&node->ipfd_lock); + KFREES(node, node->ipfd_size); + softd->stats.ipls_numnodes--; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_node_del */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operation data */ +/* uid(I) - uid of process doing the ioctl */ +/* */ +/* Look for a matching destination node on the named table and free it if */ +/* found. Because the name embedded in the frdest_t is variable in length, */ +/* it is necessary to allocate some memory locally, to complete this op. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_node_del(softc, arg, op, uid) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; + int uid; +{ + ipf_dstl_softc_t *softd = arg; + ipf_dstnode_t *node; + frdest_t frd, *temp; + ippool_dst_t *d; + size_t size; + int err; + + d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name); + if (d == NULL) { + IPFERROR(120012); + return ESRCH; + } + + err = COPYIN(op->iplo_struct, &frd, sizeof(frd)); + if (err != 0) { + IPFERROR(120011); + return EFAULT; + } + + size = sizeof(*temp) + frd.fd_name; + KMALLOCS(temp, frdest_t *, size); + if (temp == NULL) { + softd->stats.ipls_nomem++; + IPFERROR(120026); + return ENOMEM; + } + + err = COPYIN(op->iplo_struct, temp, size); + if (err != 0) { + IPFERROR(120027); + return EFAULT; + } + + MUTEX_ENTER(&d->ipld_lock); + for (node = *d->ipld_dests; node != NULL; node = node->ipfd_next) { + if ((uid != 0) && (node->ipfd_uid != uid)) + continue; + if (node->ipfd_size != size) + continue; + if (!bcmp(&node->ipfd_dest.fd_ip6, &frd.fd_ip6, + size - offsetof(frdest_t, fd_ip6))) { + ipf_dstlist_node_free(softd, d, node); + MUTEX_EXIT(&d->ipld_lock); + KFREES(temp, size); + return 0; + } + } + MUTEX_EXIT(&d->ipld_lock); + KFREES(temp, size); + + return ESRCH; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_node_free */ +/* Returns: Nil */ +/* Parameters: softd(I) - pointer to the destination list context */ +/* d(I) - pointer to destination list */ +/* node(I) - pointer to node to free */ +/* Locks: MUTEX(ipld_lock) or WRITE(ipf_poolrw) */ +/* */ +/* Free the destination node by first removing it from any lists and then */ +/* checking if this was the last reference held to the object. While the */ +/* array of pointers to nodes is compacted, its size isn't reduced (by way */ +/* of allocating a new smaller one and copying) because the belief is that */ +/* it is likely the array will again reach that size. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_dstlist_node_free(softd, d, node) + ipf_dstl_softc_t *softd; + ippool_dst_t *d; + ipf_dstnode_t *node; +{ + int i; + + /* + * Compact the array of pointers to nodes. + */ + for (i = 0; i < d->ipld_nodes; i++) + if (d->ipld_dests[i] == node) + break; + if (d->ipld_nodes - i > 1) { + bcopy(&d->ipld_dests[i + 1], &d->ipld_dests[i], + sizeof(*d->ipld_dests) * (d->ipld_nodes - i - 1)); + } + d->ipld_nodes--; + + if (node->ipfd_pnext != NULL) + *node->ipfd_pnext = node->ipfd_next; + if (node->ipfd_next != NULL) + node->ipfd_next->ipfd_pnext = node->ipfd_pnext; + node->ipfd_pnext = NULL; + node->ipfd_next = NULL; + + if ((node->ipfd_flags & IPDST_DELETE) == 0) { + softd->stats.ipls_numderefnodes++; + node->ipfd_flags |= IPDST_DELETE; + } + + ipf_dstlist_node_deref(softd, node); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_stats_get */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operation data */ +/* */ +/* Return the current statistics for destination lists. This may be for all */ +/* of them or just information pertaining to a particular table. */ +/* ------------------------------------------------------------------------ */ +/*ARGSUSED*/ +static int +ipf_dstlist_stats_get(softc, arg, op) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; +{ + ipf_dstl_softc_t *softd = arg; + ipf_dstl_stat_t stats; + int unit, i, err = 0; + + if (op->iplo_size != sizeof(ipf_dstl_stat_t)) { + IPFERROR(120023); + return EINVAL; + } + + stats = softd->stats; + unit = op->iplo_unit; + if (unit == IPL_LOGALL) { + for (i = 0; i <= IPL_LOGMAX; i++) + stats.ipls_list[i] = softd->dstlist[i]; + } else if (unit >= 0 && unit <= IPL_LOGMAX) { + void *ptr; + + if (op->iplo_name[0] != '\0') + ptr = ipf_dstlist_table_find(softd, unit, + op->iplo_name); + else + ptr = softd->dstlist[unit + 1]; + stats.ipls_list[unit] = ptr; + } else { + IPFERROR(120024); + err = EINVAL; + } + + if (err == 0) { + err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); + if (err != 0) { + IPFERROR(120025); + return EFAULT; + } + } + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_table_add */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operation data */ +/* */ +/* Add a new destination table to the list of those available for the given */ +/* device. Because we seldom operate on these objects (find/add/delete), */ +/* they are just kept in a simple linked list. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_table_add(softc, arg, op) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; +{ + ipf_dstl_softc_t *softd = arg; + ippool_dst_t user, *d, *new; + int unit, err; + + d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name); + if (d != NULL) { + IPFERROR(120013); + return EEXIST; + } + + err = COPYIN(op->iplo_struct, &user, sizeof(user)); + if (err != 0) { + IPFERROR(120021); + return EFAULT; + } + + KMALLOC(new, ippool_dst_t *); + if (new == NULL) { + softd->stats.ipls_nomem++; + IPFERROR(120014); + return ENOMEM; + } + bzero((char *)new, sizeof(*new)); + + MUTEX_INIT(&new->ipld_lock, "ipf dst table lock"); + + strncpy(new->ipld_name, op->iplo_name, FR_GROUPLEN); + unit = op->iplo_unit; + new->ipld_unit = unit; + new->ipld_policy = user.ipld_policy; + new->ipld_seed = ipf_random(); + new->ipld_ref = 1; + + new->ipld_pnext = softd->tails[unit + 1]; + *softd->tails[unit + 1] = new; + softd->tails[unit + 1] = &new->ipld_next; + softd->stats.ipls_numlists++; + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_table_del */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operation data */ +/* */ +/* Find a named destinstion list table and delete it. If there are other */ +/* references to it, the caller isn't told. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_table_del(softc, arg, op) + ipf_main_softc_t *softc; + void *arg; + iplookupop_t *op; +{ + ippool_dst_t *d; + + d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name); + if (d == NULL) { + IPFERROR(120015); + return ESRCH; + } + + if (d->ipld_dests != NULL) { + IPFERROR(120016); + return EBUSY; + } + + ipf_dstlist_table_remove(softc, arg, d); + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_table_remove */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* softd(I) - pointer to the destination list context */ +/* d(I) - pointer to destination list */ +/* */ +/* Remove a given destination list from existance. While the IPDST_DELETE */ +/* flag is set every time we call this function and the reference count is */ +/* non-zero, the "numdereflists" counter is always incremented because the */ +/* decision about whether it will be freed or not is not made here. This */ +/* means that the only action the code can take here is to treat it as if */ +/* it will become a detached. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_dstlist_table_remove(softc, softd, d) + ipf_main_softc_t *softc; + ipf_dstl_softc_t *softd; + ippool_dst_t *d; +{ + + if (softd->tails[d->ipld_unit + 1] == &d->ipld_next) + softd->tails[d->ipld_unit + 1] = d->ipld_pnext; + + if (d->ipld_pnext != NULL) + *d->ipld_pnext = d->ipld_next; + if (d->ipld_next != NULL) + d->ipld_next->ipld_pnext = d->ipld_pnext; + d->ipld_pnext = NULL; + d->ipld_next = NULL; + + ipf_dstlist_table_clearnodes(softd, d); + + softd->stats.ipls_numdereflists++; + d->ipld_flags |= IPDST_DELETE; + + ipf_dstlist_table_deref(softc, softd, d); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_table_free */ +/* Returns: Nil */ +/* Parameters: softd(I) - pointer to the destination list context */ +/* d(I) - pointer to destination list */ +/* */ +/* Free up a destination list data structure and any other memory that was */ +/* directly allocated as part of creating it. Individual destination list */ +/* nodes are not freed. It is assumed the caller will have already emptied */ +/* the destination list. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_dstlist_table_free(softd, d) + ipf_dstl_softc_t *softd; + ippool_dst_t *d; +{ + MUTEX_DESTROY(&d->ipld_lock); + + if ((d->ipld_flags & IPDST_DELETE) != 0) + softd->stats.ipls_numdereflists--; + softd->stats.ipls_numlists--; + + if (d->ipld_dests != NULL) { + KFREES(d->ipld_dests, + d->ipld_maxnodes * sizeof(*d->ipld_dests)); + } + + KFREE(d); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_table_deref */ +/* Returns: int - 0 = success, else error */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* op(I) - pointer to lookup operation data */ +/* */ +/* Drops the reference count on a destination list table object and free's */ +/* it if 0 has been reached. */ +/* ------------------------------------------------------------------------ */ +static int +ipf_dstlist_table_deref(softc, arg, table) + ipf_main_softc_t *softc; + void *arg; + void *table; +{ + ippool_dst_t *d = table; + + d->ipld_ref--; + if (d->ipld_ref > 0) + return d->ipld_ref; + + ipf_dstlist_table_free(arg, d); + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_table_clearnodes */ +/* Returns: Nil */ +/* Parameters: softd(I) - pointer to the destination list context */ +/* dst(I) - pointer to destination list */ +/* */ +/* Free all of the destination nodes attached to the given table. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_dstlist_table_clearnodes(softd, dst) + ipf_dstl_softc_t *softd; + ippool_dst_t *dst; +{ + ipf_dstnode_t *node; + + if (dst->ipld_dests == NULL) + return; + + while ((node = *dst->ipld_dests) != NULL) { + ipf_dstlist_node_free(softd, dst, node); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_table_find */ +/* Returns: int - 0 = success, else error */ +/* Parameters: arg(I) - pointer to local context to use */ +/* unit(I) - device we are working with */ +/* name(I) - destination table name to find */ +/* */ +/* Return a pointer to a destination table that matches the unit+name that */ +/* is passed in. */ +/* ------------------------------------------------------------------------ */ +static void * +ipf_dstlist_table_find(arg, unit, name) + void *arg; + int unit; + char *name; +{ + ipf_dstl_softc_t *softd = arg; + ippool_dst_t *d; + + for (d = softd->dstlist[unit + 1]; d != NULL; d = d->ipld_next) { + if ((d->ipld_unit == unit) && + !strncmp(d->ipld_name, name, FR_GROUPLEN)) { + return d; + } + } + + return NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_select_ref */ +/* Returns: void * - NULL = failure, else pointer to table */ +/* Parameters: arg(I) - pointer to local context to use */ +/* unit(I) - device we are working with */ +/* name(I) - destination table name to find */ +/* */ +/* Attempt to find a destination table that matches the name passed in and */ +/* if successful, bump up the reference count on it because we intend to */ +/* store the pointer to it somewhere else. */ +/* ------------------------------------------------------------------------ */ +static void * +ipf_dstlist_select_ref(arg, unit, name) + void *arg; + int unit; + char *name; +{ + ippool_dst_t *d; + + d = ipf_dstlist_table_find(arg, unit, name); + if (d != NULL) { + MUTEX_ENTER(&d->ipld_lock); + d->ipld_ref++; + MUTEX_EXIT(&d->ipld_lock); + } + return d; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_select */ +/* Returns: void * - NULL = failure, else pointer to table */ +/* Parameters: fin(I) - pointer to packet information */ +/* d(I) - pointer to destination list */ +/* */ +/* Find the next node in the destination list to be used according to the */ +/* defined policy. Of these, "connection" is the most expensive policy to */ +/* implement as it always looks for the node with the least number of */ +/* connections associated with it. */ +/* */ +/* The hashes exclude the port numbers so that all protocols map to the */ +/* same destination. Otherwise, someone doing a ping would target a */ +/* different server than their TCP connection, etc. MD-5 is used to */ +/* transform the addressese into something random that the other end could */ +/* not easily guess and use in an attack. ipld_seed introduces an unknown */ +/* into the hash calculation to increase the difficult of an attacker */ +/* guessing the bucket. */ +/* */ +/* One final comment: mixing different address families in a single pool */ +/* will currently result in failures as the address family of the node is */ +/* only matched up with that in the packet as the last step. While this can */ +/* be coded around for the weighted connection and round-robin models, it */ +/* cannot be supported for the hash/random models as they do not search and */ +/* nor is the algorithm conducive to searching. */ +/* ------------------------------------------------------------------------ */ +static ipf_dstnode_t * +ipf_dstlist_select(fin, d) + fr_info_t *fin; + ippool_dst_t *d; +{ + ipf_dstnode_t *node, *sel; + int connects; + u_32_t hash[4]; + MD5_CTX ctx; + int family; + int x; + + if (d->ipld_dests == NULL || *d->ipld_dests == NULL) + return NULL; + + family = fin->fin_family; + + MUTEX_ENTER(&d->ipld_lock); + + switch (d->ipld_policy) + { + case IPLDP_ROUNDROBIN: + sel = d->ipld_selected; + if (sel == NULL) { + sel = *d->ipld_dests; + } else { + sel = sel->ipfd_next; + if (sel == NULL) + sel = *d->ipld_dests; + } + break; + + case IPLDP_CONNECTION: + if (d->ipld_selected == NULL) { + sel = *d->ipld_dests; + break; + } + + sel = d->ipld_selected; + connects = 0x7fffffff; + node = sel->ipfd_next; + if (node == NULL) + node = *d->ipld_dests; + while (node != d->ipld_selected) { + if (node->ipfd_states == 0) { + sel = node; + break; + } + if (node->ipfd_states < connects) { + sel = node; + connects = node->ipfd_states; + } + node = node->ipfd_next; + if (node == NULL) + node = *d->ipld_dests; + } + break; + + case IPLDP_RANDOM : + x = ipf_random() % d->ipld_nodes; + sel = d->ipld_dests[x]; + break; + + case IPLDP_HASHED : + MD5Init(&ctx); + MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed)); + MD5Update(&ctx, (u_char *)&fin->fin_src6, + sizeof(fin->fin_src6)); + MD5Update(&ctx, (u_char *)&fin->fin_dst6, + sizeof(fin->fin_dst6)); + MD5Final((u_char *)hash, &ctx); + x = hash[0] % d->ipld_nodes; + sel = d->ipld_dests[x]; + break; + + case IPLDP_SRCHASH : + MD5Init(&ctx); + MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed)); + MD5Update(&ctx, (u_char *)&fin->fin_src6, + sizeof(fin->fin_src6)); + MD5Final((u_char *)hash, &ctx); + x = hash[0] % d->ipld_nodes; + sel = d->ipld_dests[x]; + break; + + case IPLDP_DSTHASH : + MD5Init(&ctx); + MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed)); + MD5Update(&ctx, (u_char *)&fin->fin_dst6, + sizeof(fin->fin_dst6)); + MD5Final((u_char *)hash, &ctx); + x = hash[0] % d->ipld_nodes; + sel = d->ipld_dests[x]; + break; + + default : + sel = NULL; + break; + } + + if (sel->ipfd_dest.fd_addr.adf_family != family) + sel = NULL; + d->ipld_selected = sel; + + MUTEX_EXIT(&d->ipld_lock); + + return sel; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_select_node */ +/* Returns: int - -1 == failure, 0 == success */ +/* Parameters: fin(I) - pointer to packet information */ +/* group(I) - destination pool to search */ +/* addr(I) - pointer to store selected address */ +/* pfdp(O) - pointer to storage for selected destination node */ +/* */ +/* This function is only responsible for obtaining the next IP address for */ +/* use and storing it in the caller's address space (addr). "addr" is only */ +/* used for storage if pfdp is NULL. No permanent reference is currently */ +/* kept on the node. */ +/* ------------------------------------------------------------------------ */ +int +ipf_dstlist_select_node(fin, group, addr, pfdp) + fr_info_t *fin; + void *group; + u_32_t *addr; + frdest_t *pfdp; +{ +#ifdef USE_MUTEXES + ipf_main_softc_t *softc = fin->fin_main_soft; +#endif + ippool_dst_t *d = group; + ipf_dstnode_t *node; + frdest_t *fdp; + + READ_ENTER(&softc->ipf_poolrw); + + node = ipf_dstlist_select(fin, d); + if (node == NULL) { + RWLOCK_EXIT(&softc->ipf_poolrw); + return -1; + } + + if (pfdp != NULL) { + bcopy(&node->ipfd_dest, pfdp, sizeof(*pfdp)); + } else { + if (fin->fin_family == AF_INET) { + addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0]; + } else if (fin->fin_family == AF_INET6) { + addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0]; + addr[1] = node->ipfd_dest.fd_addr.adf_addr.i6[1]; + addr[2] = node->ipfd_dest.fd_addr.adf_addr.i6[2]; + addr[3] = node->ipfd_dest.fd_addr.adf_addr.i6[3]; + } + } + + fdp = &node->ipfd_dest; + if (fdp->fd_ptr == NULL) + fdp->fd_ptr = fin->fin_ifp; + + MUTEX_ENTER(&node->ipfd_lock); + node->ipfd_states++; + MUTEX_EXIT(&node->ipfd_lock); + + RWLOCK_EXIT(&softc->ipf_poolrw); + + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_expire */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* */ +/* There are currently no objects to expire in destination lists. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_dstlist_expire(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + return; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_dstlist_sync */ +/* Returns: Nil */ +/* Parameters: softc(I) - pointer to soft context main structure */ +/* arg(I) - pointer to local context to use */ +/* */ +/* When a network interface appears or disappears, we need to revalidate */ +/* all of the network interface names that have been configured as a target */ +/* in a destination list. */ +/* ------------------------------------------------------------------------ */ +void +ipf_dstlist_sync(softc, arg) + ipf_main_softc_t *softc; + void *arg; +{ + ipf_dstl_softc_t *softd = arg; + ipf_dstnode_t *node; + ippool_dst_t *list; + int i; + int j; + + for (i = 0; i < IPL_LOGMAX; i++) { + for (list = softd->dstlist[i]; list != NULL; + list = list->ipld_next) { + for (j = 0; j < list->ipld_maxnodes; j++) { + node = list->ipld_dests[j]; + if (node == NULL) + continue; + if (node->ipfd_dest.fd_name == -1) + continue; + (void) ipf_resolvedest(softc, + node->ipfd_names, + &node->ipfd_dest, + AF_INET); + } + } + } +} diff --git a/contrib/ipfilter/ip_dstlist.h b/contrib/ipfilter/ip_dstlist.h new file mode 100644 index 0000000..e2885e5 --- /dev/null +++ b/contrib/ipfilter/ip_dstlist.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: ip_dstlist.h,v 1.5.2.6 2012/07/22 08:04:23 darren_r Exp $ + */ + +#ifndef __IP_DSTLIST_H__ +#define __IP_DSTLIST_H__ + +typedef struct ipf_dstnode { + struct ipf_dstnode *ipfd_next; + struct ipf_dstnode **ipfd_pnext; + ipfmutex_t ipfd_lock; + frdest_t ipfd_dest; + u_long ipfd_syncat; + int ipfd_flags; + int ipfd_size; + int ipfd_states; + int ipfd_ref; + int ipfd_uid; + char ipfd_names[1]; +} ipf_dstnode_t; + +typedef enum ippool_policy_e { + IPLDP_NONE = 0, + IPLDP_ROUNDROBIN, + IPLDP_CONNECTION, + IPLDP_RANDOM, + IPLDP_HASHED, + IPLDP_SRCHASH, + IPLDP_DSTHASH +} ippool_policy_t; + +typedef struct ippool_dst { + struct ippool_dst *ipld_next; + struct ippool_dst **ipld_pnext; + ipfmutex_t ipld_lock; + int ipld_seed; + int ipld_unit; + int ipld_ref; + int ipld_flags; + int ipld_nodes; + int ipld_maxnodes; + ippool_policy_t ipld_policy; + ipf_dstnode_t **ipld_dests; + ipf_dstnode_t *ipld_selected; + char ipld_name[FR_GROUPLEN]; +} ippool_dst_t; + +#define IPDST_DELETE 0x01 + +typedef struct dstlist_stat_s { + void *ipls_list[LOOKUP_POOL_SZ]; + int ipls_numlists; + u_long ipls_nomem; + int ipls_numnodes; + int ipls_numdereflists; + int ipls_numderefnodes; +} ipf_dstl_stat_t; + +extern ipf_lookup_t ipf_dstlist_backend; + +extern int ipf_dstlist_select_node __P((fr_info_t *, void *, u_32_t *, + frdest_t *)); + +#endif /* __IP_DSTLIST_H__ */ diff --git a/contrib/ipfilter/ip_fil.c b/contrib/ipfilter/ip_fil.c new file mode 100644 index 0000000..03e4093 --- /dev/null +++ b/contrib/ipfilter/ip_fil.c @@ -0,0 +1,884 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#include "ipf.h" +#include "md5.h" +#include "ipt.h" + +ipf_main_softc_t ipfmain; + +static struct ifnet **ifneta = NULL; +static int nifs = 0; + +struct rtentry; + +static void ipf_setifpaddr __P((struct ifnet *, char *)); +void init_ifp __P((void)); +#if defined(__sgi) && (IRIX < 60500) +static int no_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *)); +static int write_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *)); +#else +# if TRU64 >= 1885 +static int no_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *, char *)); +static int write_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *, char *)); +# else +static int no_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); +static int write_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); +# endif +#endif + +struct ifaddr { + struct sockaddr_storage ifa_addr; +}; + +int +ipfattach(softc) + ipf_main_softc_t *softc; +{ + return 0; +} + + +int +ipfdetach(softc) + ipf_main_softc_t *softc; +{ + return 0; +} + + +/* + * Filter ioctl interface. + */ +int +ipfioctl(softc, dev, cmd, data, mode) + ipf_main_softc_t *softc; + int dev; + ioctlcmd_t cmd; + caddr_t data; + int mode; +{ + int error = 0, unit = 0, uid; + + uid = getuid(); + unit = dev; + + SPL_NET(s); + + error = ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, NULL); + if (error != -1) { + SPL_X(s); + return error; + } + SPL_X(s); + return error; +} + + +void +ipf_forgetifp(softc, ifp) + ipf_main_softc_t *softc; + void *ifp; +{ + register frentry_t *f; + + WRITE_ENTER(&softc->ipf_mutex); + for (f = softc->ipf_acct[0][softc->ipf_active]; (f != NULL); + f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = softc->ipf_acct[1][softc->ipf_active]; (f != NULL); + f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = softc->ipf_rules[0][softc->ipf_active]; (f != NULL); + f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = softc->ipf_rules[1][softc->ipf_active]; (f != NULL); + f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + RWLOCK_EXIT(&softc->ipf_mutex); + ipf_nat_sync(softc, ifp); + ipf_lookup_sync(softc, ifp); +} + + +static int +#if defined(__sgi) && (IRIX < 60500) +no_output(ifp, m, s) +#else +# if TRU64 >= 1885 +no_output (ifp, m, s, rt, cp) + char *cp; +# else +no_output(ifp, m, s, rt) +# endif + struct rtentry *rt; +#endif + struct ifnet *ifp; + struct mbuf *m; + struct sockaddr *s; +{ + return 0; +} + + +static int +#if defined(__sgi) && (IRIX < 60500) +write_output(ifp, m, s) +#else +# if TRU64 >= 1885 +write_output (ifp, m, s, rt, cp) + char *cp; +# else +write_output(ifp, m, s, rt) +# endif + struct rtentry *rt; +#endif + struct ifnet *ifp; + struct mbuf *m; + struct sockaddr *s; +{ + char fname[32]; + mb_t *mb; + ip_t *ip; + int fd; + + mb = (mb_t *)m; + ip = MTOD(mb, ip_t *); + +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + sprintf(fname, "/tmp/%s", ifp->if_xname); +#else + sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); +#endif + fd = open(fname, O_WRONLY|O_APPEND); + if (fd == -1) { + perror("open"); + return -1; + } + write(fd, (char *)ip, ntohs(ip->ip_len)); + close(fd); + return 0; +} + + +static void +ipf_setifpaddr(ifp, addr) + struct ifnet *ifp; + char *addr; +{ +#ifdef __sgi + struct in_ifaddr *ifa; +#else + struct ifaddr *ifa; +#endif + +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) + if (ifp->if_addrlist.tqh_first != NULL) +#else +# ifdef __sgi + if (ifp->in_ifaddr != NULL) +# else + if (ifp->if_addrlist != NULL) +# endif +#endif + return; + + ifa = (struct ifaddr *)malloc(sizeof(*ifa)); +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) + ifp->if_addrlist.tqh_first = ifa; +#else +# ifdef __sgi + ifp->in_ifaddr = ifa; +# else + ifp->if_addrlist = ifa; +# endif +#endif + + if (ifa != NULL) { + struct sockaddr_in *sin; + +#ifdef __sgi + sin = (struct sockaddr_in *)&ifa->ia_addr; +#else + sin = (struct sockaddr_in *)&ifa->ifa_addr; +#endif +#ifdef USE_INET6 + if (index(addr, ':') != NULL) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr; + sin6->sin6_family = AF_INET6; + /* Abort if bad address. */ + switch (inet_pton(AF_INET6, addr, &sin6->sin6_addr)) + { + case 1: + break; + case -1: + perror("inet_pton"); + abort(); + break; + default: + abort(); + break; + } + } else +#endif + { + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = inet_addr(addr); + if (sin->sin_addr.s_addr == 0) + abort(); + } + } +} + +struct ifnet * +get_unit(name, family) + char *name; + int family; +{ + struct ifnet *ifp, **ifpp, **old_ifneta; + char *addr; +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + + if (!*name) + return NULL; + + if (name == NULL) + name = "anon0"; + + addr = strchr(name, '='); + if (addr != NULL) + *addr++ = '\0'; + + for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { + if (!strcmp(name, ifp->if_xname)) { + if (addr != NULL) + ipf_setifpaddr(ifp, addr); + return ifp; + } + } +#else + char *s, ifname[LIFNAMSIZ+1]; + + if (name == NULL) + name = "anon0"; + + addr = strchr(name, '='); + if (addr != NULL) + *addr++ = '\0'; + + for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { + COPYIFNAME(family, ifp, ifname); + if (!strcmp(name, ifname)) { + if (addr != NULL) + ipf_setifpaddr(ifp, addr); + return ifp; + } + } +#endif + + if (!ifneta) { + ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); + if (!ifneta) + return NULL; + ifneta[1] = NULL; + ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp)); + if (!ifneta[0]) { + free(ifneta); + return NULL; + } + nifs = 1; + } else { + old_ifneta = ifneta; + nifs++; + ifneta = (struct ifnet **)realloc(ifneta, + (nifs + 1) * sizeof(ifp)); + if (!ifneta) { + free(old_ifneta); + nifs = 0; + return NULL; + } + ifneta[nifs] = NULL; + ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp)); + if (!ifneta[nifs - 1]) { + nifs--; + return NULL; + } + } + ifp = ifneta[nifs - 1]; + +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) + TAILQ_INIT(&ifp->if_addrlist); +#endif +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + (void) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname)); +#else + s = name + strlen(name) - 1; + for (; s > name; s--) { + if (!ISDIGIT(*s)) { + s++; + break; + } + } + + if ((s > name) && (*s != 0) && ISDIGIT(*s)) { + ifp->if_unit = atoi(s); + ifp->if_name = (char *)malloc(s - name + 1); + (void) strncpy(ifp->if_name, name, s - name); + ifp->if_name[s - name] = '\0'; + } else { + ifp->if_name = strdup(name); + ifp->if_unit = -1; + } +#endif + ifp->if_output = (void *)no_output; + + if (addr != NULL) { + ipf_setifpaddr(ifp, addr); + } + + return ifp; +} + + +char * +get_ifname(ifp) + struct ifnet *ifp; +{ + static char ifname[LIFNAMSIZ]; + +#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + sprintf(ifname, "%s", ifp->if_xname); +#else + if (ifp->if_unit != -1) + sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit); + else + strcpy(ifname, ifp->if_name); +#endif + return ifname; +} + + + +void +init_ifp() +{ + struct ifnet *ifp, **ifpp; + char fname[32]; + int fd; + +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { + ifp->if_output = (void *)write_output; + sprintf(fname, "/tmp/%s", ifp->if_xname); + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else + close(fd); + } +#else + + for (ifpp = ifneta; ifpp && (ifp = *ifpp); ifpp++) { + ifp->if_output = (void *)write_output; + sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else + close(fd); + } +#endif +} + + +int +ipf_fastroute(m, mpp, fin, fdp) + mb_t *m, **mpp; + fr_info_t *fin; + frdest_t *fdp; +{ + struct ifnet *ifp; + ip_t *ip = fin->fin_ip; + frdest_t node; + int error = 0; + frentry_t *fr; + void *sifp; + int sout; + + sifp = fin->fin_ifp; + sout = fin->fin_out; + fr = fin->fin_fr; + ip->ip_sum = 0; + + if (!(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) && + (fdp->fd_type == FRD_DSTLIST)) { + bzero(&node, sizeof(node)); + ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node); + fdp = &node; + } + ifp = fdp->fd_ptr; + + if (ifp == NULL) + return 0; /* no routing table out here */ + + if (fin->fin_out == 0) { + fin->fin_ifp = ifp; + fin->fin_out = 1; + (void) ipf_acctpkt(fin, NULL); + fin->fin_fr = NULL; + if (!fr || !(fr->fr_flags & FR_RETMASK)) { + u_32_t pass; + + (void) ipf_state_check(fin, &pass); + } + + switch (ipf_nat_checkout(fin, NULL)) + { + case 0 : + break; + case 1 : + ip->ip_sum = 0; + break; + case -1 : + error = -1; + goto done; + break; + } + + } + + m->mb_ifp = ifp; + printpacket(fin->fin_out, m); + +#if defined(__sgi) && (IRIX < 60500) + (*ifp->if_output)(ifp, (void *)ip, NULL); +# if TRU64 >= 1885 + (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0); +# else + (*ifp->if_output)(ifp, (void *)m, NULL, 0); +# endif +#endif +done: + fin->fin_ifp = sifp; + fin->fin_out = sout; + return error; +} + + +int +ipf_send_reset(fin) + fr_info_t *fin; +{ + ipfkverbose("- TCP RST sent\n"); + return 0; +} + + +int +ipf_send_icmp_err(type, fin, dst) + int type; + fr_info_t *fin; + int dst; +{ + ipfkverbose("- ICMP unreachable sent\n"); + return 0; +} + + +void +m_freem(m) + mb_t *m; +{ + return; +} + + +void +m_copydata(m, off, len, cp) + mb_t *m; + int off, len; + caddr_t cp; +{ + bcopy((char *)m + off, cp, len); +} + + +int +ipfuiomove(buf, len, rwflag, uio) + caddr_t buf; + int len, rwflag; + struct uio *uio; +{ + int left, ioc, num, offset; + struct iovec *io; + char *start; + + if (rwflag == UIO_READ) { + left = len; + ioc = 0; + + offset = uio->uio_offset; + + while ((left > 0) && (ioc < uio->uio_iovcnt)) { + io = uio->uio_iov + ioc; + num = io->iov_len; + if (num > left) + num = left; + start = (char *)io->iov_base + offset; + if (start > (char *)io->iov_base + io->iov_len) { + offset -= io->iov_len; + ioc++; + continue; + } + bcopy(buf, start, num); + uio->uio_resid -= num; + uio->uio_offset += num; + left -= num; + if (left > 0) + ioc++; + } + if (left > 0) + return EFAULT; + } + return 0; +} + + +u_32_t +ipf_newisn(fin) + fr_info_t *fin; +{ + static int iss_seq_off = 0; + u_char hash[16]; + u_32_t newiss; + MD5_CTX ctx; + + /* + * Compute the base value of the ISS. It is a hash + * of (saddr, sport, daddr, dport, secret). + */ + MD5Init(&ctx); + + MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, + sizeof(fin->fin_fi.fi_src)); + MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, + sizeof(fin->fin_fi.fi_dst)); + MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); + + /* MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); */ + + MD5Final(hash, &ctx); + + memcpy(&newiss, hash, sizeof(newiss)); + + /* + * Now increment our "timer", and add it in to + * the computed value. + * + * XXX Use `addin'? + * XXX TCP_ISSINCR too large to use? + */ + iss_seq_off += 0x00010000; + newiss += iss_seq_off; + return newiss; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_nextipid */ +/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Returns the next IPv4 ID to use for this packet. */ +/* ------------------------------------------------------------------------ */ +INLINE u_short +ipf_nextipid(fin) + fr_info_t *fin; +{ + static u_short ipid = 0; + ipf_main_softc_t *softc = fin->fin_main_soft; + u_short id; + + MUTEX_ENTER(&softc->ipf_rw); + if (fin->fin_pktnum != 0) { + /* + * The -1 is for aligned test results. + */ + id = (fin->fin_pktnum - 1) & 0xffff; + } else { + } + id = ipid++; + MUTEX_EXIT(&softc->ipf_rw); + + return id; +} + + +INLINE int +ipf_checkv4sum(fin) + fr_info_t *fin; +{ + + if (fin->fin_flx & FI_SHORT) + return 1; + + if (ipf_checkl4sum(fin) == -1) { + fin->fin_flx |= FI_BAD; + return -1; + } + return 0; +} + + +#ifdef USE_INET6 +INLINE int +ipf_checkv6sum(fin) + fr_info_t *fin; +{ + if (fin->fin_flx & FI_SHORT) + return 1; + + if (ipf_checkl4sum(fin) == -1) { + fin->fin_flx |= FI_BAD; + return -1; + } + return 0; +} +#endif + + +#if 0 +/* + * See above for description, except that all addressing is in user space. + */ +int +copyoutptr(softc, src, dst, size) + void *src, *dst; + size_t size; +{ + caddr_t ca; + + bcopy(dst, (char *)&ca, sizeof(ca)); + bcopy(src, ca, size); + return 0; +} + + +/* + * See above for description, except that all addressing is in user space. + */ +int +copyinptr(src, dst, size) + void *src, *dst; + size_t size; +{ + caddr_t ca; + + bcopy(src, (char *)&ca, sizeof(ca)); + bcopy(ca, dst, size); + return 0; +} +#endif + + +/* + * return the first IP Address associated with an interface + */ +int +ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask) + ipf_main_softc_t *softc; + int v, atype; + void *ifptr; + i6addr_t *inp, *inpmask; +{ + struct ifnet *ifp = ifptr; +#ifdef __sgi + struct in_ifaddr *ifa; +#else + struct ifaddr *ifa; +#endif + +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) + ifa = ifp->if_addrlist.tqh_first; +#else +# ifdef __sgi + ifa = (struct in_ifaddr *)ifp->in_ifaddr; +# else + ifa = ifp->if_addrlist; +# endif +#endif + if (ifa != NULL) { + if (v == 4) { + struct sockaddr_in *sin, mask; + + mask.sin_addr.s_addr = 0xffffffff; + +#ifdef __sgi + sin = (struct sockaddr_in *)&ifa->ia_addr; +#else + sin = (struct sockaddr_in *)&ifa->ifa_addr; +#endif + + return ipf_ifpfillv4addr(atype, sin, &mask, + &inp->in4, &inpmask->in4); + } +#ifdef USE_INET6 + if (v == 6) { + struct sockaddr_in6 *sin6, mask; + + sin6 = (struct sockaddr_in6 *)&ifa->ifa_addr; + ((i6addr_t *)&mask.sin6_addr)->i6[0] = 0xffffffff; + ((i6addr_t *)&mask.sin6_addr)->i6[1] = 0xffffffff; + ((i6addr_t *)&mask.sin6_addr)->i6[2] = 0xffffffff; + ((i6addr_t *)&mask.sin6_addr)->i6[3] = 0xffffffff; + return ipf_ifpfillv6addr(atype, sin6, &mask, + inp, inpmask); + } +#endif + } + return 0; +} + + +/* + * This function is not meant to be random, rather just produce a + * sequence of numbers that isn't linear to show "randomness". + */ +u_32_t +ipf_random() +{ + static unsigned int last = 0xa5a5a5a5; + static int calls = 0; + int number; + + calls++; + + /* + * These are deliberately chosen to ensure that there is some + * attempt to test whether the output covers the range in test n18. + */ + switch (calls) + { + case 1 : + number = 0; + break; + case 2 : + number = 4; + break; + case 3 : + number = 3999; + break; + case 4 : + number = 4000; + break; + case 5 : + number = 48999; + break; + case 6 : + number = 49000; + break; + default : + number = last; + last *= calls; + last++; + number ^= last; + break; + } + return number; +} + + +int +ipf_verifysrc(fin) + fr_info_t *fin; +{ + return 1; +} + + +int +ipf_inject(fin, m) + fr_info_t *fin; + mb_t *m; +{ + FREE_MB_T(m); + + return 0; +} + + +u_int +ipf_pcksum(fin, hlen, sum) + fr_info_t *fin; + int hlen; + u_int sum; +{ + u_short *sp; + u_int sum2; + int slen; + + slen = fin->fin_plen - hlen; + sp = (u_short *)((u_char *)fin->fin_ip + hlen); + + for (; slen > 1; slen -= 2) + sum += *sp++; + if (slen) + sum += ntohs(*(u_char *)sp << 8); + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum2 = (u_short)(~sum & 0xffff); + + return sum2; +} + + +void * +ipf_pullup(m, fin, plen) + mb_t *m; + fr_info_t *fin; + int plen; +{ + if (M_LEN(m) >= plen) + return fin->fin_ip; + + /* + * Fake ipf_pullup failing + */ + fin->fin_reason = FRB_PULLUP; + *fin->fin_mp = NULL; + fin->fin_m = NULL; + fin->fin_ip = NULL; + return NULL; +} diff --git a/contrib/ipfilter/ip_fil_compat.c b/contrib/ipfilter/ip_fil_compat.c new file mode 100644 index 0000000..d0b356f --- /dev/null +++ b/contrib/ipfilter/ip_fil_compat.c @@ -0,0 +1,4854 @@ +/* + * Copyright (C) 2002-2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if defined(KERNEL) || defined(_KERNEL) +# undef KERNEL +# undef _KERNEL +# define KERNEL 1 +# define _KERNEL 1 +#endif +#if defined(__osf__) +# define _PROTO_NET_H_ +#endif +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/file.h> +#if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include <sys/fcntl.h> +# include <sys/filio.h> +#else +# include <sys/ioctl.h> +#endif +#if !defined(_KERNEL) +# include <string.h> +# define _KERNEL +# ifdef __OpenBSD__ +struct file; +# endif +# include <sys/uio.h> +# undef _KERNEL +#endif +#include <sys/socket.h> +#if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL) +# include "radix_ipf_local.h" +# define _RADIX_H_ +#endif +#include <net/if.h> +#if defined(__FreeBSD__) +# include <sys/cdefs.h> +# include <sys/proc.h> +#endif +#if defined(_KERNEL) +# include <sys/systm.h> +# if !defined(__SVR4) && !defined(__svr4__) +# include <sys/mbuf.h> +# endif +#endif +#include <netinet/in.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_auth.h" +/* END OF INCLUDES */ + +/* + * NetBSD has moved to 64bit time_t for all architectures. + * For some, such as sparc64, there is no change because long is already + * 64bit, but for others (i386), there is... + */ +#ifdef IPFILTER_COMPAT + +# ifdef __NetBSD__ +typedef struct timeval_l { + long tv_sec; + long tv_usec; +} timeval_l_t; +# endif + +/* ------------------------------------------------------------------------ */ + +typedef struct tcpinfo4 { + u_short ts_sport; + u_short ts_dport; + tcpdata_t ts_data[2]; +} tcpinfo4_t; + +static void ipf_v5tcpinfoto4 __P((tcpinfo_t *, tcpinfo4_t *)); + +static void +ipf_v5tcpinfoto4(v5, v4) + tcpinfo_t *v5; + tcpinfo4_t *v4; +{ + v4->ts_sport = v5->ts_sport; + v4->ts_dport = v5->ts_dport; + v4->ts_data[0] = v5->ts_data[0]; + v4->ts_data[1] = v5->ts_data[1]; +} + +typedef struct fr_ip4 { + u_32_t fi_v:4; + u_32_t fi_xx:4; + u_32_t fi_tos:8; + u_32_t fi_ttl:8; + u_32_t fi_p:8; + u_32_t fi_optmsk; + i6addr_t fi_src; + i6addr_t fi_dst; + u_short ofi_secmsk; + u_short ofi_auth; + u_32_t fi_flx; + u_32_t fi_tcpmsk; + u_32_t fi_res1; +} frip4_t; + +typedef struct frpcmp4 { + int frp_cmp; + u_short frp_port; + u_short frp_top; +} frpcmp4_t; + +typedef struct frtuc4 { + u_char ftu_tcpfm; + u_char ftu_tcpf; + frpcmp4_t ftu_src; + frpcmp4_t ftu_dst; +} frtuc4_t; + +typedef struct fripf4 { + frip4_t fri_ip; + frip4_t fri_mip; + + u_short fri_icmpm; + u_short fri_icmp; + + frtuc4_t fri_tuc; + int fri_satype; + int fri_datype; + int fri_sifpidx; + int fri_difpidx; +} fripf4_t; + +typedef struct frdest_4 { + void *fd_ifp; + i6addr_t ofd_ip6; + char fd_ifname[LIFNAMSIZ]; +} frdest_4_t; + +/* ------------------------------------------------------------------------ */ + +/* 5.1.0 new release (current) + * 4.1.34 changed the size of the time structure used for pps + * 4.1.16 moved the location of fr_flineno + * 4.1.0 base version + */ +typedef struct frentry_4_1_34 { + ipfmutex_t fr_lock; + struct frentry *fr_next; + struct frentry **fr_grp; + struct ipscan *fr_isc; + void *fr_ifas[4]; + void *fr_ptr; /* for use with fr_arg */ + char *fr_comment; /* text comment for rule */ + int fr_ref; /* reference count - for grouping */ + int fr_statecnt; /* state count - for limit rules */ + int fr_flineno; /* line number from conf file */ + U_QUAD_T fr_hits; + U_QUAD_T fr_bytes; + union { + struct timeval frp_lastpkt; + char frp_bytes[12]; + } fr_lpu; + int fr_curpps; + union { + void *fru_data; + char *fru_caddr; + fripf4_t *fru_ipf; + frentfunc_t fru_func; + } fr_dun; + ipfunc_t fr_func; /* call this function */ + int fr_dsize; + int fr_pps; + int fr_statemax; /* max reference count */ + u_32_t fr_type; + u_32_t fr_flags; /* per-rule flags && options (see below) */ + u_32_t fr_logtag; /* user defined log tag # */ + u_32_t fr_collect; /* collection number */ + u_int fr_arg; /* misc. numeric arg for rule */ + u_int fr_loglevel; /* syslog log facility + priority */ + u_int fr_age[2]; /* non-TCP timeouts */ + u_char fr_v; + u_char fr_icode; /* return ICMP code */ + char fr_group[FR_GROUPLEN]; /* group to which this rule belongs */ + char fr_grhead[FR_GROUPLEN]; /* group # which this rule starts */ + ipftag_t fr_nattag; + char fr_ifnames[4][LIFNAMSIZ]; + char fr_isctag[16]; + frdest_4_t fr_tifs[2]; /* "to"/"reply-to" interface */ + frdest_4_t fr_dif; /* duplicate packet interface */ + u_int fr_cksum; /* checksum on filter rules for performance */ +} frentry_4_1_34_t; + +typedef struct frentry_4_1_16 { + ipfmutex_t fr_lock; + struct frentry *fr_next; + struct frentry **fr_grp; + struct ipscan *fr_isc; + void *fr_ifas[4]; + void *fr_ptr; + char *fr_comment; + int fr_ref; + int fr_statecnt; + int fr_flineno; + U_QUAD_T fr_hits; + U_QUAD_T fr_bytes; + union { +#ifdef __NetBSD__ + timeval_l_t frp_lastpkt; +#else + struct timeval frp_lastpkt; +#endif + } fr_lpu; + int fr_curpps; + union { + void *fru_data; + caddr_t fru_caddr; + fripf4_t *fru_ipf; + frentfunc_t fru_func; + } fr_dun; + ipfunc_t fr_func; + int fr_dsize; + int fr_pps; + int fr_statemax; + u_32_t fr_type; + u_32_t fr_flags; + u_32_t fr_logtag; + u_32_t fr_collect; + u_int fr_arg; + u_int fr_loglevel; + u_int fr_age[2]; + u_char fr_v; + u_char fr_icode; + char fr_group[FR_GROUPLEN]; + char fr_grhead[FR_GROUPLEN]; + ipftag_t fr_nattag; + char fr_ifnames[4][LIFNAMSIZ]; + char fr_isctag[16]; + frdest_4_t fr_tifs[2]; + frdest_4_t fr_dif; + u_int fr_cksum; +} frentry_4_1_16_t; + +typedef struct frentry_4_1_0 { + ipfmutex_t fr_lock; + struct frentry *fr_next; + struct frentry **fr_grp; + struct ipscan *fr_isc; + void *fr_ifas[4]; + void *fr_ptr; + char *fr_comment; + int fr_ref; + int fr_statecnt; + U_QUAD_T fr_hits; + U_QUAD_T fr_bytes; + union { +#ifdef __NetBSD__ + timeval_l_t frp_lastpkt; +#else + struct timeval frp_lastpkt; +#endif + } fr_lpu; + int fr_curpps; + + union { + void *fru_data; + caddr_t fru_caddr; + fripf4_t *fru_ipf; + frentfunc_t fru_func; + } fr_dun; + /* + * Fields after this may not change whilst in the kernel. + */ + ipfunc_t fr_func; + int fr_dsize; + int fr_pps; + int fr_statemax; + int fr_flineno; + u_32_t fr_type; + u_32_t fr_flags; + u_32_t fr_logtag; + u_32_t fr_collect; + u_int fr_arg; + u_int fr_loglevel; + u_int fr_age[2]; + u_char fr_v; + u_char fr_icode; + char fr_group[FR_GROUPLEN]; + char fr_grhead[FR_GROUPLEN]; + ipftag_t fr_nattag; + char fr_ifnames[4][LIFNAMSIZ]; + char fr_isctag[16]; + frdest_4_t fr_tifs[2]; + frdest_4_t fr_dif; + u_int fr_cksum; +} frentry_4_1_0_t; + +/* ------------------------------------------------------------------------ */ + +/* + * 5.1.0 new release (current) + * 4.1.32 removed both fin_state and fin_nat, added fin_pktnum + * 4.1.24 added fin_cksum + * 4.1.23 added fin_exthdr + * 4.1.11 added fin_ifname + * 4.1.4 added fin_hbuf + */ +typedef struct fr_info_4_1_32 { + void *fin_ifp; /* interface packet is `on' */ + frip4_t fin_fi; /* IP Packet summary */ + union { + u_short fid_16[2]; /* TCP/UDP ports, ICMP code/type */ + u_32_t fid_32; + } fin_dat; + int fin_out; /* in or out ? 1 == out, 0 == in */ + int fin_rev; /* state only: 1 = reverse */ + u_short fin_hlen; /* length of IP header in bytes */ + u_char ofin_tcpf; /* TCP header flags (SYN, ACK, etc) */ + u_char fin_icode; /* ICMP error to return */ + u_32_t fin_rule; /* rule # last matched */ + char fin_group[FR_GROUPLEN]; /* group number, -1 for none */ + struct frentry *fin_fr; /* last matching rule */ + void *fin_dp; /* start of data past IP header */ + int fin_dlen; /* length of data portion of packet */ + int fin_plen; + int fin_ipoff; /* # bytes from buffer start to hdr */ + u_short fin_id; /* IP packet id field */ + u_short fin_off; + int fin_depth; /* Group nesting depth */ + int fin_error; /* Error code to return */ + int fin_cksum; /* -1 bad, 1 good, 0 not done */ + u_int fin_pktnum; + void *fin_nattag; + void *fin_exthdr; + ip_t *ofin_ip; + mb_t **fin_mp; /* pointer to pointer to mbuf */ + mb_t *fin_m; /* pointer to mbuf */ +#ifdef MENTAT + mb_t *fin_qfm; /* pointer to mblk where pkt starts */ + void *fin_qpi; + char fin_ifname[LIFNAMSIZ]; +#endif +#ifdef __sgi + void *fin_hbuf; +#endif +} fr_info_4_1_32_t; + +typedef struct fr_info_4_1_24 { + void *fin_ifp; + frip4_t fin_fi; + union { + u_short fid_16[2]; + u_32_t fid_32; + } fin_dat; + int fin_out; + int fin_rev; + u_short fin_hlen; + u_char ofin_tcpf; + u_char fin_icode; + u_32_t fin_rule; + char fin_group[FR_GROUPLEN]; + struct frentry *fin_fr; + void *fin_dp; + int fin_dlen; + int fin_plen; + int fin_ipoff; + u_short fin_id; + u_short fin_off; + int fin_depth; + int fin_error; + int fin_cksum; + void *fin_state; + void *fin_nat; + void *fin_nattag; + void *fin_exthdr; + ip_t *ofin_ip; + mb_t **fin_mp; + mb_t *fin_m; +#ifdef MENTAT + mb_t *fin_qfm; + void *fin_qpi; + char fin_ifname[LIFNAMSIZ]; +#endif +#ifdef __sgi + void *fin_hbuf; +#endif +} fr_info_4_1_24_t; + +typedef struct fr_info_4_1_23 { + void *fin_ifp; + frip4_t fin_fi; + union { + u_short fid_16[2]; + u_32_t fid_32; + } fin_dat; + int fin_out; + int fin_rev; + u_short fin_hlen; + u_char ofin_tcpf; + u_char fin_icode; + u_32_t fin_rule; + char fin_group[FR_GROUPLEN]; + struct frentry *fin_fr; + void *fin_dp; + int fin_dlen; + int fin_plen; + int fin_ipoff; + u_short fin_id; + u_short fin_off; + int fin_depth; + int fin_error; + void *fin_state; + void *fin_nat; + void *fin_nattag; + void *fin_exthdr; + ip_t *ofin_ip; + mb_t **fin_mp; + mb_t *fin_m; +#ifdef MENTAT + mb_t *fin_qfm; + void *fin_qpi; + char fin_ifname[LIFNAMSIZ]; +#endif +#ifdef __sgi + void *fin_hbuf; +#endif +} fr_info_4_1_23_t; + +typedef struct fr_info_4_1_11 { + void *fin_ifp; + frip4_t fin_fi; + union { + u_short fid_16[2]; + u_32_t fid_32; + } fin_dat; + int fin_out; + int fin_rev; + u_short fin_hlen; + u_char ofin_tcpf; + u_char fin_icode; + u_32_t fin_rule; + char fin_group[FR_GROUPLEN]; + struct frentry *fin_fr; + void *fin_dp; + int fin_dlen; + int fin_plen; + int fin_ipoff; + u_short fin_id; + u_short fin_off; + int fin_depth; + int fin_error; + void *fin_state; + void *fin_nat; + void *fin_nattag; + ip_t *ofin_ip; + mb_t **fin_mp; + mb_t *fin_m; +#ifdef MENTAT + mb_t *fin_qfm; + void *fin_qpi; + char fin_ifname[LIFNAMSIZ]; +#endif +#ifdef __sgi + void *fin_hbuf; +#endif +} fr_info_4_1_11_t; + +/* ------------------------------------------------------------------------ */ + +typedef struct filterstats_4_1 { + u_long fr_pass; /* packets allowed */ + u_long fr_block; /* packets denied */ + u_long fr_nom; /* packets which don't match any rule */ + u_long fr_short; /* packets which are short */ + u_long fr_ppkl; /* packets allowed and logged */ + u_long fr_bpkl; /* packets denied and logged */ + u_long fr_npkl; /* packets unmatched and logged */ + u_long fr_pkl; /* packets logged */ + u_long fr_skip; /* packets to be logged but buffer full */ + u_long fr_ret; /* packets for which a return is sent */ + u_long fr_acct; /* packets for which counting was performed */ + u_long fr_bnfr; /* bad attempts to allocate fragment state */ + u_long fr_nfr; /* new fragment state kept */ + u_long fr_cfr; /* add new fragment state but complete pkt */ + 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_tcpbad; /* TCP checksum check failures */ + u_long fr_pull[2]; /* good and bad pullup attempts */ + u_long fr_badsrc; /* source received doesn't match route */ + u_long fr_badttl; /* TTL in packet doesn't reach minimum */ + u_long fr_bad; /* bad IP packets to the filter */ + u_long fr_ipv6; /* IPv6 packets in/out */ + u_long fr_ppshit; /* dropped because of pps ceiling */ + u_long fr_ipud; /* IP id update failures */ +} filterstats_4_1_t; + +/* + * 5.1.0 new release (current) + * 4.1.33 changed the size of f_locks from IPL_LOGMAX to IPL_LOGSIZE + */ +typedef struct friostat_4_1_33 { + struct filterstats_4_1 of_st[2]; + struct frentry *f_ipf[2][2]; + struct frentry *f_acct[2][2]; + struct frentry *f_ipf6[2][2]; + struct frentry *f_acct6[2][2]; + struct frentry *f_auth; + struct frgroup *f_groups[IPL_LOGSIZE][2]; + u_long f_froute[2]; + u_long f_ticks; + int f_locks[IPL_LOGSIZE]; + size_t f_kmutex_sz; + size_t f_krwlock_sz; + int f_defpass; /* default pass - from fr_pass */ + int f_active; /* 1 or 0 - active rule set */ + int f_running; /* 1 if running, else 0 */ + int f_logging; /* 1 if enabled, else 0 */ + int f_features; + char f_version[32]; /* version string */ +} friostat_4_1_33_t; + +typedef struct friostat_4_1_0 { + struct filterstats_4_1 of_st[2]; + struct frentry *f_ipf[2][2]; + struct frentry *f_acct[2][2]; + struct frentry *f_ipf6[2][2]; + struct frentry *f_acct6[2][2]; + struct frentry *f_auth; + struct frgroup *f_groups[IPL_LOGSIZE][2]; + u_long f_froute[2]; + u_long f_ticks; + int f_locks[IPL_LOGMAX]; + size_t f_kmutex_sz; + size_t f_krwlock_sz; + int f_defpass; + int f_active; + int f_running; + int f_logging; + int f_features; + char f_version[32]; +} friostat_4_1_0_t; + +/* ------------------------------------------------------------------------ */ + +/* + * 5.1.0 new release (current) + * 4.1.14 added in_lock + */ +typedef struct ipnat_4_1_14 { + ipfmutex_t in_lock; + struct ipnat *in_next; /* NAT rule list next */ + struct ipnat *in_rnext; /* rdr rule hash next */ + struct ipnat **in_prnext; /* prior rdr next ptr */ + struct ipnat *in_mnext; /* map rule hash next */ + struct ipnat **in_pmnext; /* prior map next ptr */ + struct ipftq *in_tqehead[2]; + void *in_ifps[2]; + void *in_apr; + char *in_comment; + i6addr_t in_next6; + u_long in_space; + u_long in_hits; + u_int in_use; + u_int in_hv; + int in_flineno; /* conf. file line number */ + u_short in_pnext; + u_char in_v; + u_char in_xxx; + /* From here to the end is covered by IPN_CMPSIZ */ + u_32_t in_flags; + u_32_t in_mssclamp; /* if != 0 clamp MSS to this */ + u_int in_age[2]; + int in_redir; /* see below for values */ + int in_p; /* protocol. */ + i6addr_t in_in[2]; + i6addr_t in_out[2]; + i6addr_t in_src[2]; + frtuc4_t in_tuc; + u_short in_port[2]; + u_short in_ppip; /* ports per IP. */ + u_short in_ippip; /* IP #'s per IP# */ + char in_ifnames[2][LIFNAMSIZ]; + char in_plabel[APR_LABELLEN]; /* proxy label. */ + ipftag_t in_tag; +} ipnat_4_1_14_t; + +typedef struct ipnat_4_1_0 { + struct ipnat *in_next; + struct ipnat *in_rnext; + struct ipnat **in_prnext; + struct ipnat *in_mnext; + struct ipnat **in_pmnext; + struct ipftq *in_tqehead[2]; + void *in_ifps[2]; + void *in_apr; + char *in_comment; + i6addr_t in_next6; + u_long in_space; + u_long in_hits; + u_int in_use; + u_int in_hv; + int in_flineno; + u_short in_pnext; + u_char in_v; + u_char in_xxx; + u_32_t in_flags; + u_32_t in_mssclamp; + u_int in_age[2]; + int in_redir; + int in_p; + i6addr_t in_in[2]; + i6addr_t in_out[2]; + i6addr_t in_src[2]; + frtuc4_t in_tuc; + u_short in_port[2]; + u_short in_ppip; + u_short in_ippip; + char in_ifnames[2][LIFNAMSIZ]; + char in_plabel[APR_LABELLEN]; + ipftag_t in_tag; +} ipnat_4_1_0_t; + +/* ------------------------------------------------------------------------ */ + +typedef struct natlookup_4_1_1 { + struct in_addr onl_inip; + struct in_addr onl_outip; + struct in_addr onl_realip; + int nl_flags; + u_short nl_inport; + u_short nl_outport; + u_short nl_realport; +} natlookup_4_1_1_t; + +/* ------------------------------------------------------------------------ */ + +/* + * 4.1.25 added nat_seqnext (current) + * 4.1.14 added nat_redir + * 4.1.3 moved nat_rev + * 4.1.2 added nat_rev + */ +typedef struct nat_4_1_25 { + ipfmutex_t nat_lock; + struct nat_4_1_25 *nat_next; + struct nat_4_1_25 **nat_pnext; + struct nat_4_1_25 *nat_hnext[2]; + struct nat_4_1_25 **nat_phnext[2]; + struct hostmap *nat_hm; + void *nat_data; + struct nat_4_1_25 **nat_me; + struct ipstate *nat_state; + struct ap_session *nat_aps; + frentry_t *nat_fr; + struct ipnat_4_1_14 *nat_ptr; + void *nat_ifps[2]; + void *nat_sync; + ipftqent_t nat_tqe; + u_32_t nat_flags; + u_32_t nat_sumd[2]; + u_32_t nat_ipsumd; + u_32_t nat_mssclamp; + i6addr_t nat_inip6; + i6addr_t nat_outip6; + i6addr_t nat_oip6; + U_QUAD_T nat_pkts[2]; + U_QUAD_T nat_bytes[2]; + union { + udpinfo_t nat_unu; + tcpinfo4_t nat_unt; + icmpinfo_t nat_uni; + greinfo_t nat_ugre; + } nat_un; + u_short nat_oport; + u_short nat_use; + u_char nat_p; + int nat_dir; + int nat_ref; + int nat_hv[2]; + char nat_ifnames[2][LIFNAMSIZ]; + int nat_rev; + int nat_redir; + u_32_t nat_seqnext[2]; +} nat_4_1_25_t; + +typedef struct nat_4_1_14 { + ipfmutex_t nat_lock; + struct nat *nat_next; + struct nat **nat_pnext; + struct nat *nat_hnext[2]; + struct nat **nat_phnext[2]; + struct hostmap *nat_hm; + void *nat_data; + struct nat **nat_me; + struct ipstate *nat_state; + struct ap_session *nat_aps; + frentry_t *nat_fr; + struct ipnat *nat_ptr; + void *nat_ifps[2]; + void *nat_sync; + ipftqent_t nat_tqe; + u_32_t nat_flags; + u_32_t nat_sumd[2]; + u_32_t nat_ipsumd; + u_32_t nat_mssclamp; + i6addr_t nat_inip6; + i6addr_t nat_outip6; + i6addr_t nat_oip6; + U_QUAD_T nat_pkts[2]; + U_QUAD_T nat_bytes[2]; + union { + udpinfo_t nat_unu; + tcpinfo4_t nat_unt; + icmpinfo_t nat_uni; + greinfo_t nat_ugre; + } nat_un; + u_short nat_oport; + u_short nat_use; + u_char nat_p; + int nat_dir; + int nat_ref; + int nat_hv[2]; + char nat_ifnames[2][LIFNAMSIZ]; + int nat_rev; + int nat_redir; +} nat_4_1_14_t; + +typedef struct nat_4_1_3 { + ipfmutex_t nat_lock; + struct nat *nat_next; + struct nat **nat_pnext; + struct nat *nat_hnext[2]; + struct nat **nat_phnext[2]; + struct hostmap *nat_hm; + void *nat_data; + struct nat **nat_me; + struct ipstate *nat_state; + struct ap_session *nat_aps; + frentry_t *nat_fr; + struct ipnat *nat_ptr; + void *nat_ifps[2]; + void *nat_sync; + ipftqent_t nat_tqe; + u_32_t nat_flags; + u_32_t nat_sumd[2]; + u_32_t nat_ipsumd; + u_32_t nat_mssclamp; + i6addr_t nat_inip6; + i6addr_t nat_outip6; + i6addr_t nat_oip6; + U_QUAD_T nat_pkts[2]; + U_QUAD_T nat_bytes[2]; + union { + udpinfo_t nat_unu; + tcpinfo4_t nat_unt; + icmpinfo_t nat_uni; + greinfo_t nat_ugre; + } nat_un; + u_short nat_oport; + u_short nat_use; + u_char nat_p; + int nat_dir; + int nat_ref; + int nat_hv[2]; + char nat_ifnames[2][LIFNAMSIZ]; + int nat_rev; +} nat_4_1_3_t; + + + +typedef struct nat_save_4_1_34 { + void *ipn_next; + struct nat_4_1_25 ipn_nat; + struct ipnat_4_1_14 ipn_ipnat; + struct frentry_4_1_34 ipn_fr; + int ipn_dsize; + char ipn_data[4]; +} nat_save_4_1_34_t; + +typedef struct nat_save_4_1_16 { + void *ipn_next; + nat_4_1_14_t ipn_nat; + ipnat_t ipn_ipnat; + frentry_4_1_16_t ipn_fr; + int ipn_dsize; + char ipn_data[4]; +} nat_save_4_1_16_t; + +typedef struct nat_save_4_1_14 { + void *ipn_next; + nat_4_1_14_t ipn_nat; + ipnat_t ipn_ipnat; + frentry_4_1_0_t ipn_fr; + int ipn_dsize; + char ipn_data[4]; +} nat_save_4_1_14_t; + +typedef struct nat_save_4_1_3 { + void *ipn_next; + nat_4_1_3_t ipn_nat; + ipnat_4_1_0_t ipn_ipnat; + frentry_4_1_0_t ipn_fr; + int ipn_dsize; + char ipn_data[4]; +} nat_save_4_1_3_t; + +/* ------------------------------------------------------------------------ */ + +/* + * 5.1.0 new release (current) + * 4.1.32 added ns_uncreate + * 4.1.27 added ns_orphans + * 4.1.16 added ns_ticks + */ +typedef struct natstat_4_1_32 { + u_long ns_mapped[2]; + u_long ns_rules; + u_long ns_added; + u_long ns_expire; + u_long ns_inuse; + u_long ns_logged; + u_long ns_logfail; + u_long ns_memfail; + u_long ns_badnat; + u_long ns_addtrpnt; + nat_t **ns_table[2]; + hostmap_t **ns_maptable; + ipnat_t *ns_list; + void *ns_apslist; + u_int ns_wilds; + u_int ns_nattab_sz; + u_int ns_nattab_max; + u_int ns_rultab_sz; + u_int ns_rdrtab_sz; + u_int ns_trpntab_sz; + u_int ns_hostmap_sz; + nat_t *ns_instances; + hostmap_t *ns_maplist; + u_long *ns_bucketlen[2]; + u_long ns_ticks; + u_int ns_orphans; + u_long ns_uncreate[2][2]; +} natstat_4_1_32_t; + +typedef struct natstat_4_1_27 { + u_long ns_mapped[2]; + u_long ns_rules; + u_long ns_added; + u_long ns_expire; + u_long ns_inuse; + u_long ns_logged; + u_long ns_logfail; + u_long ns_memfail; + u_long ns_badnat; + u_long ns_addtrpnt; + nat_t **ns_table[2]; + hostmap_t **ns_maptable; + ipnat_t *ns_list; + void *ns_apslist; + u_int ns_wilds; + u_int ns_nattab_sz; + u_int ns_nattab_max; + u_int ns_rultab_sz; + u_int ns_rdrtab_sz; + u_int ns_trpntab_sz; + u_int ns_hostmap_sz; + nat_t *ns_instances; + hostmap_t *ns_maplist; + u_long *ns_bucketlen[2]; + u_long ns_ticks; + u_int ns_orphans; +} natstat_4_1_27_t; + +typedef struct natstat_4_1_16 { + u_long ns_mapped[2]; + u_long ns_rules; + u_long ns_added; + u_long ns_expire; + u_long ns_inuse; + u_long ns_logged; + u_long ns_logfail; + u_long ns_memfail; + u_long ns_badnat; + u_long ns_addtrpnt; + nat_t **ns_table[2]; + hostmap_t **ns_maptable; + ipnat_t *ns_list; + void *ns_apslist; + u_int ns_wilds; + u_int ns_nattab_sz; + u_int ns_nattab_max; + u_int ns_rultab_sz; + u_int ns_rdrtab_sz; + u_int ns_trpntab_sz; + u_int ns_hostmap_sz; + nat_t *ns_instances; + hostmap_t *ns_maplist; + u_long *ns_bucketlen[2]; + u_long ns_ticks; +} natstat_4_1_16_t; + +typedef struct natstat_4_1_0 { + u_long ns_mapped[2]; + u_long ns_rules; + u_long ns_added; + u_long ns_expire; + u_long ns_inuse; + u_long ns_logged; + u_long ns_logfail; + u_long ns_memfail; + u_long ns_badnat; + u_long ns_addtrpnt; + nat_t **ns_table[2]; + hostmap_t **ns_maptable; + ipnat_t *ns_list; + void *ns_apslist; + u_int ns_wilds; + u_int ns_nattab_sz; + u_int ns_nattab_max; + u_int ns_rultab_sz; + u_int ns_rdrtab_sz; + u_int ns_trpntab_sz; + u_int ns_hostmap_sz; + nat_t *ns_instances; + hostmap_t *ns_maplist; + u_long *ns_bucketlen[2]; +} natstat_4_1_0_t; + +/* ------------------------------------------------------------------------ */ + +/* + * 5.1.0 new release (current) + * 4.1.32 fra_info:removed both fin_state & fin_nat, added fin_pktnum + * 4.1.29 added fra_flx + * 4.1.24 fra_info:added fin_cksum + * 4.1.23 fra_info:added fin_exthdr + * 4.1.11 fra_info:added fin_ifname + * 4.1.4 fra_info:added fin_hbuf + */ + +typedef struct frauth_4_1_32 { + int fra_age; + int fra_len; + int fra_index; + u_32_t fra_pass; + fr_info_4_1_32_t fra_info; + char *fra_buf; + u_32_t fra_flx; +#ifdef MENTAT + queue_t *fra_q; + mb_t *fra_m; +#endif +} frauth_4_1_32_t; + +typedef struct frauth_4_1_29 { + int fra_age; + int fra_len; + int fra_index; + u_32_t fra_pass; + fr_info_4_1_24_t fra_info; + char *fra_buf; + u_32_t fra_flx; +#ifdef MENTAT + queue_t *fra_q; + mb_t *fra_m; +#endif +} frauth_4_1_29_t; + +typedef struct frauth_4_1_24 { + int fra_age; + int fra_len; + int fra_index; + u_32_t fra_pass; + fr_info_4_1_24_t fra_info; + char *fra_buf; +#ifdef MENTAT + queue_t *fra_q; + mb_t *fra_m; +#endif +} frauth_4_1_24_t; + +typedef struct frauth_4_1_23 { + int fra_age; + int fra_len; + int fra_index; + u_32_t fra_pass; + fr_info_4_1_23_t fra_info; + char *fra_buf; +#ifdef MENTAT + queue_t *fra_q; + mb_t *fra_m; +#endif +} frauth_4_1_23_t; + +typedef struct frauth_4_1_11 { + int fra_age; + int fra_len; + int fra_index; + u_32_t fra_pass; + fr_info_4_1_11_t fra_info; + char *fra_buf; +#ifdef MENTAT + queue_t *fra_q; + mb_t *fra_m; +#endif +} frauth_4_1_11_t; + +/* ------------------------------------------------------------------------ */ + +/* + * 5.1.0 new release (current) + * 4.1.16 removed is_nat + */ +typedef struct ipstate_4_1_16 { + ipfmutex_t is_lock; + struct ipstate *is_next; + struct ipstate **is_pnext; + struct ipstate *is_hnext; + struct ipstate **is_phnext; + struct ipstate **is_me; + void *is_ifp[4]; + void *is_sync; + frentry_t *is_rule; + struct ipftq *is_tqehead[2]; + struct ipscan *is_isc; + U_QUAD_T is_pkts[4]; + U_QUAD_T is_bytes[4]; + U_QUAD_T is_icmppkts[4]; + struct ipftqent is_sti; + u_int is_frage[2]; + int is_ref; /* reference count */ + int is_isninc[2]; + u_short is_sumd[2]; + i6addr_t is_src; + i6addr_t is_dst; + u_int is_pass; + u_char is_p; /* Protocol */ + u_char is_v; + u_32_t is_hv; + u_32_t is_tag; + u_32_t is_opt[2]; /* packet options set */ + u_32_t is_optmsk[2]; /* " " mask */ + u_short is_sec; /* security options set */ + u_short is_secmsk; /* " " mask */ + u_short is_auth; /* authentication options set */ + u_short is_authmsk; /* " " mask */ + union { + icmpinfo_t is_ics; + tcpinfo4_t is_ts; + udpinfo_t is_us; + greinfo_t is_ug; + } is_ps; + u_32_t is_flags; + int is_flx[2][2]; + u_32_t is_rulen; /* rule number when created */ + u_32_t is_s0[2]; + u_short is_smsk[2]; + char is_group[FR_GROUPLEN]; + char is_sbuf[2][16]; + char is_ifname[4][LIFNAMSIZ]; +} ipstate_4_1_16_t; + +typedef struct ipstate_4_1_0 { + ipfmutex_t is_lock; + struct ipstate *is_next; + struct ipstate **is_pnext; + struct ipstate *is_hnext; + struct ipstate **is_phnext; + struct ipstate **is_me; + void *is_ifp[4]; + void *is_sync; + void *is_nat[2]; + frentry_t *is_rule; + struct ipftq *is_tqehead[2]; + struct ipscan *is_isc; + U_QUAD_T is_pkts[4]; + U_QUAD_T is_bytes[4]; + U_QUAD_T is_icmppkts[4]; + struct ipftqent is_sti; + u_int is_frage[2]; + int is_ref; + int is_isninc[2]; + u_short is_sumd[2]; + i6addr_t is_src; + i6addr_t is_dst; + u_int is_pass; + u_char is_p; + u_char is_v; + u_32_t is_hv; + u_32_t is_tag; + u_32_t is_opt[2]; + u_32_t is_optmsk[2]; + u_short is_sec; + u_short is_secmsk; + u_short is_auth; + u_short is_authmsk; + union { + icmpinfo_t is_ics; + tcpinfo4_t is_ts; + udpinfo_t is_us; + greinfo_t is_ug; + } is_ps; + u_32_t is_flags; + int is_flx[2][2]; + u_32_t is_rulen; + u_32_t is_s0[2]; + u_short is_smsk[2]; + char is_group[FR_GROUPLEN]; + char is_sbuf[2][16]; + char is_ifname[4][LIFNAMSIZ]; +} ipstate_4_1_0_t; + +typedef struct ipstate_save_4_1_34 { + void *ips_next; + struct ipstate_4_1_16 ips_is; + struct frentry_4_1_34 ips_fr; +} ipstate_save_4_1_34_t; + +typedef struct ipstate_save_4_1_16 { + void *ips_next; + ipstate_4_1_0_t ips_is; + frentry_4_1_16_t ips_fr; +} ipstate_save_4_1_16_t; + +typedef struct ipstate_save_4_1_0 { + void *ips_next; + ipstate_4_1_0_t ips_is; + frentry_4_1_0_t ips_fr; +} ipstate_save_4_1_0_t; + +/* ------------------------------------------------------------------------ */ + +/* + * 5.1.0 new release (current) + * 4.1.21 added iss_tcptab + */ +typedef struct ips_stat_4_1_21 { + u_long iss_hits; + u_long iss_miss; + u_long iss_max; + u_long iss_maxref; + u_long iss_tcp; + u_long iss_udp; + u_long iss_icmp; + u_long iss_nomem; + u_long iss_expire; + u_long iss_fin; + u_long iss_active; + u_long iss_logged; + u_long iss_logfail; + u_long iss_inuse; + u_long iss_wild; + u_long iss_killed; + u_long iss_ticks; + u_long iss_bucketfull; + int iss_statesize; + int iss_statemax; + ipstate_t **iss_table; + ipstate_t *iss_list; + u_long *iss_bucketlen; + ipftq_t *iss_tcptab; +} ips_stat_4_1_21_t; + +typedef struct ips_stat_4_1_0 { + u_long iss_hits; + u_long iss_miss; + u_long iss_max; + u_long iss_maxref; + u_long iss_tcp; + u_long iss_udp; + u_long iss_icmp; + u_long iss_nomem; + u_long iss_expire; + u_long iss_fin; + u_long iss_active; + u_long iss_logged; + u_long iss_logfail; + u_long iss_inuse; + u_long iss_wild; + u_long iss_killed; + u_long iss_ticks; + u_long iss_bucketfull; + int iss_statesize; + int iss_statemax; + ipstate_t **iss_table; + ipstate_t *iss_list; + u_long *iss_bucketlen; +} ips_stat_4_1_0_t; + +/* ------------------------------------------------------------------------ */ + +typedef struct ipfrstat_4_1_1 { + u_long ifs_exists; /* add & already exists */ + u_long ifs_nomem; + u_long ifs_new; + u_long ifs_hits; + u_long ifs_expire; + u_long ifs_inuse; + u_long ifs_retrans0; + u_long ifs_short; + struct ipfr **ifs_table; + struct ipfr **ifs_nattab; +} ipfrstat_4_1_1_t; + +/* ------------------------------------------------------------------------ */ +static int ipf_addfrstr __P((char *, int, char *, int)); +static void ipf_v4iptov5 __P((frip4_t *, fr_ip_t *)); +static void ipf_v5iptov4 __P((fr_ip_t *, frip4_t *)); +static void ipfv4tuctov5 __P((frtuc4_t *, frtuc_t *)); +static void ipfv5tuctov4 __P((frtuc_t *, frtuc4_t *)); +static int ipf_v4fripftov5 __P((fripf4_t *, char *)); +static void ipf_v5fripftov4 __P((fripf_t *, fripf4_t *)); +static int fr_frflags4to5 __P((u_32_t)); +static int fr_frflags5to4 __P((u_32_t)); + +static void friostat_current_to_4_1_0 __P((void *, friostat_4_1_0_t *, int)); +static void friostat_current_to_4_1_33 __P((void *, friostat_4_1_33_t *, int)); +static void ipstate_current_to_4_1_0 __P((void *, ipstate_4_1_0_t *)); +static void ipstate_current_to_4_1_16 __P((void *, ipstate_4_1_16_t *)); +static void ipnat_current_to_4_1_0 __P((void *, ipnat_4_1_0_t *)); +static void ipnat_current_to_4_1_14 __P((void *, ipnat_4_1_14_t *)); +static void frauth_current_to_4_1_11 __P((void *, frauth_4_1_11_t *)); +static void frauth_current_to_4_1_23 __P((void *, frauth_4_1_23_t *)); +static void frauth_current_to_4_1_24 __P((void *, frauth_4_1_24_t *)); +static void frauth_current_to_4_1_29 __P((void *, frauth_4_1_29_t *)); +static void frentry_current_to_4_1_0 __P((void *, frentry_4_1_0_t *)); +static void frentry_current_to_4_1_16 __P((void *, frentry_4_1_16_t *)); +static void frentry_current_to_4_1_34 __P((void *, frentry_4_1_34_t *)); +static void fr_info_current_to_4_1_11 __P((void *, fr_info_4_1_11_t *)); +static void fr_info_current_to_4_1_23 __P((void *, fr_info_4_1_23_t *)); +static void fr_info_current_to_4_1_24 __P((void *, fr_info_4_1_24_t *)); +static void nat_save_current_to_4_1_3 __P((void *, nat_save_4_1_3_t *)); +static void nat_save_current_to_4_1_14 __P((void *, nat_save_4_1_14_t *)); +static void nat_save_current_to_4_1_16 __P((void *, nat_save_4_1_16_t *)); +static void ipstate_save_current_to_4_1_0 __P((void *, ipstate_save_4_1_0_t *)); +static void ipstate_save_current_to_4_1_16 __P((void *, ipstate_save_4_1_16_t *)); +static void ips_stat_current_to_4_1_0 __P((void *, ips_stat_4_1_0_t *)); +static void ips_stat_current_to_4_1_21 __P((void *, ips_stat_4_1_21_t *)); +static void natstat_current_to_4_1_0 __P((void *, natstat_4_1_0_t *)); +static void natstat_current_to_4_1_16 __P((void *, natstat_4_1_16_t *)); +static void natstat_current_to_4_1_27 __P((void *, natstat_4_1_27_t *)); +static void natstat_current_to_4_1_32 __P((void *, natstat_4_1_32_t *)); +static void nat_current_to_4_1_3 __P((void *, nat_4_1_3_t *)); +static void nat_current_to_4_1_14 __P((void *, nat_4_1_14_t *)); +static void nat_current_to_4_1_25 __P((void *, nat_4_1_25_t *)); + +static void friostat_4_1_0_to_current __P((friostat_4_1_0_t *, void *)); +static void friostat_4_1_33_to_current __P((friostat_4_1_33_t *, void *)); +static void ipnat_4_1_0_to_current __P((ipnat_4_1_0_t *, void *, int)); +static void ipnat_4_1_14_to_current __P((ipnat_4_1_14_t *, void *, int)); +static void frauth_4_1_11_to_current __P((frauth_4_1_11_t *, void *)); +static void frauth_4_1_23_to_current __P((frauth_4_1_23_t *, void *)); +static void frauth_4_1_24_to_current __P((frauth_4_1_24_t *, void *)); +static void frauth_4_1_29_to_current __P((frauth_4_1_29_t *, void *)); +static void frauth_4_1_32_to_current __P((frauth_4_1_32_t *, void *)); +static void frentry_4_1_0_to_current __P((ipf_main_softc_t *, frentry_4_1_0_t *, void *, int)); +static void frentry_4_1_16_to_current __P((ipf_main_softc_t *, frentry_4_1_16_t *, void *, int)); +static void frentry_4_1_34_to_current __P((ipf_main_softc_t *, frentry_4_1_34_t *, void *, int)); +static void fr_info_4_1_11_to_current __P((fr_info_4_1_11_t *, void *)); +static void fr_info_4_1_23_to_current __P((fr_info_4_1_23_t *, void *)); +static void fr_info_4_1_24_to_current __P((fr_info_4_1_24_t *, void *)); +static void fr_info_4_1_32_to_current __P((fr_info_4_1_32_t *, void *)); +static void nat_save_4_1_3_to_current __P((ipf_main_softc_t *, nat_save_4_1_3_t *, void *)); +static void nat_save_4_1_14_to_current __P((ipf_main_softc_t *, nat_save_4_1_14_t *, void *)); +static void nat_save_4_1_16_to_current __P((ipf_main_softc_t *, nat_save_4_1_16_t *, void *)); + +/* ------------------------------------------------------------------------ */ +/* In this section is a series of short routines that deal with translating */ +/* the smaller data structures used above as their internal changes make */ +/* them inappropriate for simple assignment. */ +/* ------------------------------------------------------------------------ */ + + +static int +ipf_addfrstr(char *names, int namelen, char *str, int maxlen) +{ + char *t; + int i; + + for (i = maxlen, t = str; (*t != '\0') && (i > 0); i--) { + names[namelen++] = *t++; + } + names[namelen++] = '\0'; + return namelen; +} + + +static void +ipf_v4iptov5(v4, v5) + frip4_t *v4; + fr_ip_t *v5; +{ + v5->fi_v = v4->fi_v; + v5->fi_p = v4->fi_p; + v5->fi_xx = v4->fi_xx; + v5->fi_tos = v4->fi_tos; + v5->fi_ttl = v4->fi_ttl; + v5->fi_p = v4->fi_p; + v5->fi_optmsk = v4->fi_optmsk; + v5->fi_src = v4->fi_src; + v5->fi_dst = v4->fi_dst; + v5->fi_secmsk = v4->ofi_secmsk; + v5->fi_auth = v4->ofi_auth; + v5->fi_flx = v4->fi_flx; + v5->fi_tcpmsk = v4->fi_tcpmsk; +} + +static void +ipf_v5iptov4(v5, v4) + fr_ip_t *v5; + frip4_t *v4; +{ + v4->fi_v = v5->fi_v; + v4->fi_p = v5->fi_p; + v4->fi_xx = v5->fi_xx; + v4->fi_tos = v5->fi_tos; + v4->fi_ttl = v5->fi_ttl; + v4->fi_p = v5->fi_p; + v4->fi_optmsk = v5->fi_optmsk; + v4->fi_src = v5->fi_src; + v4->fi_dst = v5->fi_dst; + v4->ofi_secmsk = v5->fi_secmsk; + v4->ofi_auth = v5->fi_auth; + v4->fi_flx = v5->fi_flx; + v4->fi_tcpmsk = v5->fi_tcpmsk; +} + + +static void +ipfv4tuctov5(v4, v5) + frtuc4_t *v4; + frtuc_t *v5; +{ + v5->ftu_src.frp_cmp = v4->ftu_src.frp_cmp; + v5->ftu_src.frp_port = v4->ftu_src.frp_port; + v5->ftu_src.frp_top = v4->ftu_src.frp_top; + v5->ftu_dst.frp_cmp = v4->ftu_dst.frp_cmp; + v5->ftu_dst.frp_port = v4->ftu_dst.frp_port; + v5->ftu_dst.frp_top = v4->ftu_dst.frp_top; +} + + +static void +ipfv5tuctov4(v5, v4) + frtuc_t *v5; + frtuc4_t *v4; +{ + v4->ftu_src.frp_cmp = v5->ftu_src.frp_cmp; + v4->ftu_src.frp_port = v5->ftu_src.frp_port; + v4->ftu_src.frp_top = v5->ftu_src.frp_top; + v4->ftu_dst.frp_cmp = v5->ftu_dst.frp_cmp; + v4->ftu_dst.frp_port = v5->ftu_dst.frp_port; + v4->ftu_dst.frp_top = v5->ftu_dst.frp_top; +} + + +static int +ipf_v4fripftov5(frp4, dst) + fripf4_t *frp4; + char *dst; +{ + fripf_t *frp; + + frp = (fripf_t *)dst; + + ipf_v4iptov5(&frp4->fri_ip, &frp->fri_ip); + ipf_v4iptov5(&frp4->fri_mip, &frp->fri_mip); + frp->fri_icmpm = frp4->fri_icmpm; + frp->fri_icmp = frp4->fri_icmp; + frp->fri_tuc.ftu_tcpfm = frp4->fri_tuc.ftu_tcpfm; + frp->fri_tuc.ftu_tcpf = frp4->fri_tuc.ftu_tcpf; + ipfv4tuctov5(&frp4->fri_tuc, &frp->fri_tuc); + frp->fri_satype = frp4->fri_satype; + frp->fri_datype = frp4->fri_datype; + frp->fri_sifpidx = frp4->fri_sifpidx; + frp->fri_difpidx = frp4->fri_difpidx; + return 0; +} + + +static void +ipf_v5fripftov4(frp, frp4) + fripf_t *frp; + fripf4_t *frp4; +{ + + ipf_v5iptov4(&frp->fri_ip, &frp4->fri_ip); + ipf_v5iptov4(&frp->fri_mip, &frp4->fri_mip); + frp4->fri_icmpm = frp->fri_icmpm; + frp4->fri_icmp = frp->fri_icmp; + frp4->fri_tuc.ftu_tcpfm = frp->fri_tuc.ftu_tcpfm; + frp4->fri_tuc.ftu_tcpf = frp->fri_tuc.ftu_tcpf; + ipfv5tuctov4(&frp->fri_tuc, &frp4->fri_tuc); + frp4->fri_satype = frp->fri_satype; + frp4->fri_datype = frp->fri_datype; + frp4->fri_sifpidx = frp->fri_sifpidx; + frp4->fri_difpidx = frp->fri_difpidx; +} + + +/* ------------------------------------------------------------------------ */ +/* ipf_in_compat is the first of two service routines. It is responsible for*/ +/* converting data structures from user space into what's required by the */ +/* kernel module. */ +/* ------------------------------------------------------------------------ */ +int +ipf_in_compat(softc, obj, ptr, size) + ipf_main_softc_t *softc; + ipfobj_t *obj; + void *ptr; + int size; +{ + int error; + int sz; + + IPFERROR(140000); + error = EINVAL; + + switch (obj->ipfo_type) + { + default : + break; + + case IPFOBJ_FRENTRY : + if (obj->ipfo_rev >= 4013400) { + frentry_4_1_34_t *old; + + KMALLOC(old, frentry_4_1_34_t *); + if (old == NULL) { + IPFERROR(140001); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error == 0) { + if (old->fr_type != FR_T_NONE && + old->fr_type != FR_T_IPF) { + IPFERROR(140002); + error = EINVAL; + KFREE(old); + break; + } + frentry_4_1_34_to_current(softc, old, + ptr, size); + } else { + IPFERROR(140003); + } + KFREE(old); + } else if (obj->ipfo_rev >= 4011600) { + frentry_4_1_16_t *old; + + KMALLOC(old, frentry_4_1_16_t *); + if (old == NULL) { + IPFERROR(140004); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error == 0) { + if (old->fr_type != FR_T_NONE && + old->fr_type != FR_T_IPF) { + IPFERROR(140005); + error = EINVAL; + KFREE(old); + break; + } + frentry_4_1_16_to_current(softc, old, + ptr, size); + } else { + IPFERROR(140006); + } + KFREE(old); + } else { + frentry_4_1_0_t *old; + + KMALLOC(old, frentry_4_1_0_t *); + if (old == NULL) { + IPFERROR(140007); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error == 0) { + if (old->fr_type != FR_T_NONE && + old->fr_type != FR_T_IPF) { + IPFERROR(140008); + error = EINVAL; + KFREE(old); + break; + } + frentry_4_1_0_to_current(softc, old, ptr, size); + } else { + IPFERROR(140009); + } + KFREE(old); + } + break; + + case IPFOBJ_IPFSTAT : + if (obj->ipfo_rev >= 4013300) { + friostat_4_1_33_t *old; + + KMALLOC(old, friostat_4_1_33_t *); + if (old == NULL) { + IPFERROR(140010); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error == 0) { + friostat_4_1_33_to_current(old, ptr); + } else { + IPFERROR(140011); + } + } else { + friostat_4_1_0_t *old; + + KMALLOC(old, friostat_4_1_0_t *); + if (old == NULL) { + IPFERROR(140012); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error == 0) { + friostat_4_1_0_to_current(old, ptr); + } else { + IPFERROR(140013); + } + } + break; + + case IPFOBJ_IPFINFO : /* unused */ + break; + + case IPFOBJ_IPNAT : + if (obj->ipfo_rev >= 4011400) { + ipnat_4_1_14_t *old; + + KMALLOC(old, ipnat_4_1_14_t *); + if (old == NULL) { + IPFERROR(140014); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error == 0) { + ipnat_4_1_14_to_current(old, ptr, size); + } else { + IPFERROR(140015); + } + KFREE(old); + } else { + ipnat_4_1_0_t *old; + + KMALLOC(old, ipnat_4_1_0_t *); + if (old == NULL) { + IPFERROR(140016); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error == 0) { + ipnat_4_1_0_to_current(old, ptr, size); + } else { + IPFERROR(140017); + } + KFREE(old); + } + break; + + case IPFOBJ_NATSTAT : + /* + * Statistics are not copied in. + */ + break; + + case IPFOBJ_NATSAVE : + if (obj->ipfo_rev >= 4011600) { + nat_save_4_1_16_t *old16; + + KMALLOC(old16, nat_save_4_1_16_t *); + if (old16 == NULL) { + IPFERROR(140018); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old16, sizeof(*old16)); + if (error == 0) { + nat_save_4_1_16_to_current(softc, old16, ptr); + } else { + IPFERROR(140019); + } + KFREE(old16); + } else if (obj->ipfo_rev >= 4011400) { + nat_save_4_1_14_t *old14; + + KMALLOC(old14, nat_save_4_1_14_t *); + if (old14 == NULL) { + IPFERROR(140020); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old14, sizeof(*old14)); + if (error == 0) { + nat_save_4_1_14_to_current(softc, old14, ptr); + } else { + IPFERROR(140021); + } + KFREE(old14); + } else if (obj->ipfo_rev >= 4010300) { + nat_save_4_1_3_t *old3; + + KMALLOC(old3, nat_save_4_1_3_t *); + if (old3 == NULL) { + IPFERROR(140022); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old3, sizeof(*old3)); + if (error == 0) { + nat_save_4_1_3_to_current(softc, old3, ptr); + } else { + IPFERROR(140023); + } + KFREE(old3); + } + break; + + case IPFOBJ_STATESAVE : + if (obj->ipfo_rev >= 4013400) { + ipstate_save_4_1_34_t *old; + + KMALLOC(old, ipstate_save_4_1_34_t *); + if (old == NULL) { + IPFERROR(140024); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error != 0) { + IPFERROR(140025); + } + KFREE(old); + } else if (obj->ipfo_rev >= 4011600) { + ipstate_save_4_1_16_t *old; + + KMALLOC(old, ipstate_save_4_1_16_t *); + if (old == NULL) { + IPFERROR(140026); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error != 0) { + IPFERROR(140027); + } + KFREE(old); + } else { + ipstate_save_4_1_0_t *old; + + KMALLOC(old, ipstate_save_4_1_0_t *); + if (old == NULL) { + IPFERROR(140028); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error != 0) { + IPFERROR(140029); + } + KFREE(old); + } + break; + + case IPFOBJ_IPSTATE : + /* + * This structure is not copied in by itself. + */ + break; + + case IPFOBJ_STATESTAT : + /* + * Statistics are not copied in. + */ + break; + + case IPFOBJ_FRAUTH : + if (obj->ipfo_rev >= 4013200) { + frauth_4_1_32_t *old32; + + KMALLOC(old32, frauth_4_1_32_t *); + if (old32 == NULL) { + IPFERROR(140030); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old32, sizeof(*old32)); + if (error == 0) { + frauth_4_1_32_to_current(old32, ptr); + } else { + IPFERROR(140031); + } + KFREE(old32); + } else if (obj->ipfo_rev >= 4012900) { + frauth_4_1_29_t *old29; + + KMALLOC(old29, frauth_4_1_29_t *); + if (old29 == NULL) { + IPFERROR(140032); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old29, sizeof(*old29)); + if (error == 0) { + frauth_4_1_29_to_current(old29, ptr); + } else { + IPFERROR(140033); + } + KFREE(old29); + } else if (obj->ipfo_rev >= 4012400) { + frauth_4_1_24_t *old24; + + KMALLOC(old24, frauth_4_1_24_t *); + if (old24 == NULL) { + IPFERROR(140034); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old24, sizeof(*old24)); + if (error == 0) { + frauth_4_1_24_to_current(old24, ptr); + } else { + IPFERROR(140035); + } + KFREE(old24); + } else if (obj->ipfo_rev >= 4012300) { + frauth_4_1_23_t *old23; + + KMALLOC(old23, frauth_4_1_23_t *); + if (old23 == NULL) { + IPFERROR(140036); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old23, sizeof(*old23)); + if (error == 0) + frauth_4_1_23_to_current(old23, ptr); + KFREE(old23); + } else if (obj->ipfo_rev >= 4011100) { + frauth_4_1_11_t *old11; + + KMALLOC(old11, frauth_4_1_11_t *); + if (old11 == NULL) { + IPFERROR(140037); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old11, sizeof(*old11)); + if (error == 0) { + frauth_4_1_11_to_current(old11, ptr); + } else { + IPFERROR(140038); + } + KFREE(old11); + } + break; + + case IPFOBJ_NAT : + if (obj->ipfo_rev >= 4011400) { + sz = sizeof(nat_4_1_14_t); + } else if (obj->ipfo_rev >= 4010300) { + sz = sizeof(nat_4_1_3_t); + } else { + break; + } + bzero(ptr, sizeof(nat_t)); + error = COPYIN(obj->ipfo_ptr, ptr, sz); + if (error != 0) { + IPFERROR(140039); + } + break; + + case IPFOBJ_FRIPF : + if (obj->ipfo_rev < 5000000) { + fripf4_t *old; + + KMALLOC(old, fripf4_t *); + if (old == NULL) { + IPFERROR(140040); + error = ENOMEM; + break; + } + error = COPYIN(obj->ipfo_ptr, old, sizeof(*old)); + if (error == 0) { + ipf_v4fripftov5(old, ptr); + } else { + IPFERROR(140041); + } + KFREE(old); + } + break; + } + + return error; +} +/* ------------------------------------------------------------------------ */ + + +/* + * flags is v4 flags, returns v5 flags. + */ +static int +fr_frflags4to5(flags) + u_32_t flags; +{ + u_32_t nflags = 0; + + switch (flags & 0xf) { + case 0x0 : + nflags |= FR_CALL; + break; + case 0x1 : + nflags |= FR_BLOCK; + break; + case 0x2 : + nflags |= FR_PASS; + break; + case 0x3 : + nflags |= FR_AUTH; + break; + case 0x4 : + nflags |= FR_PREAUTH; + break; + case 0x5 : + nflags |= FR_ACCOUNT; + break; + case 0x6 : + nflags |= FR_SKIP; + break; + default : + break; + } + + if (flags & 0x00010) + nflags |= FR_LOG; + if (flags & 0x00020) + nflags |= FR_CALLNOW; + if (flags & 0x00080) + nflags |= FR_NOTSRCIP; + if (flags & 0x00040) + nflags |= FR_NOTDSTIP; + if (flags & 0x00100) + nflags |= FR_QUICK; + if (flags & 0x00200) + nflags |= FR_KEEPFRAG; + if (flags & 0x00400) + nflags |= FR_KEEPSTATE; + if (flags & 0x00800) + nflags |= FR_FASTROUTE; + if (flags & 0x01000) + nflags |= FR_RETRST; + if (flags & 0x02000) + nflags |= FR_RETICMP; + if (flags & 0x03000) + nflags |= FR_FAKEICMP; + if (flags & 0x04000) + nflags |= FR_OUTQUE; + if (flags & 0x08000) + nflags |= FR_INQUE; + if (flags & 0x10000) + nflags |= FR_LOGBODY; + if (flags & 0x20000) + nflags |= FR_LOGFIRST; + if (flags & 0x40000) + nflags |= FR_LOGORBLOCK; + if (flags & 0x100000) + nflags |= FR_FRSTRICT; + if (flags & 0x200000) + nflags |= FR_STSTRICT; + if (flags & 0x400000) + nflags |= FR_NEWISN; + if (flags & 0x800000) + nflags |= FR_NOICMPERR; + if (flags & 0x1000000) + nflags |= FR_STATESYNC; + if (flags & 0x8000000) + nflags |= FR_NOMATCH; + if (flags & 0x40000000) + nflags |= FR_COPIED; + if (flags & 0x80000000) + nflags |= FR_INACTIVE; + + return nflags; +} + +static void +frentry_4_1_34_to_current(softc, old, current, size) + ipf_main_softc_t *softc; + frentry_4_1_34_t *old; + void *current; + int size; +{ + frentry_t *fr = (frentry_t *)current; + + fr->fr_comment = -1; + fr->fr_ref = old->fr_ref; + fr->fr_statecnt = old->fr_statecnt; + fr->fr_hits = old->fr_hits; + fr->fr_bytes = old->fr_bytes; + fr->fr_lastpkt.tv_sec = old->fr_lastpkt.tv_sec; + fr->fr_lastpkt.tv_usec = old->fr_lastpkt.tv_usec; + bcopy(&old->fr_dun, &fr->fr_dun, sizeof(old->fr_dun)); + fr->fr_func = old->fr_func; + fr->fr_dsize = old->fr_dsize; + fr->fr_pps = old->fr_pps; + fr->fr_statemax = old->fr_statemax; + fr->fr_flineno = old->fr_flineno; + fr->fr_type = old->fr_type; + fr->fr_flags = fr_frflags4to5(old->fr_flags); + fr->fr_logtag = old->fr_logtag; + fr->fr_collect = old->fr_collect; + fr->fr_arg = old->fr_arg; + fr->fr_loglevel = old->fr_loglevel; + fr->fr_age[0] = old->fr_age[0]; + fr->fr_age[1] = old->fr_age[1]; + fr->fr_tifs[0].fd_ip6 = old->fr_tifs[0].ofd_ip6; + fr->fr_tifs[0].fd_type = FRD_NORMAL; + fr->fr_tifs[1].fd_ip6 = old->fr_tifs[1].ofd_ip6; + fr->fr_tifs[1].fd_type = FRD_NORMAL; + fr->fr_dif.fd_ip6 = old->fr_dif.ofd_ip6; + fr->fr_dif.fd_type = FRD_NORMAL; + if (old->fr_v == 4) + fr->fr_family = AF_INET; + if (old->fr_v == 6) + fr->fr_family = AF_INET6; + fr->fr_icode = old->fr_icode; + fr->fr_cksum = old->fr_cksum; + fr->fr_namelen = 0; + fr->fr_ifnames[0] = -1; + fr->fr_ifnames[1] = -1; + fr->fr_ifnames[2] = -1; + fr->fr_ifnames[3] = -1; + fr->fr_dif.fd_name = -1; + fr->fr_tifs[0].fd_name = -1; + fr->fr_tifs[1].fd_name = -1; + fr->fr_group = -1; + fr->fr_grhead = -1; + fr->fr_icmphead = -1; + if (size == 0) { + fr->fr_size = sizeof(*fr) + LIFNAMSIZ * 7 + FR_GROUPLEN * 2; + fr->fr_size += sizeof(fripf_t) + 16; + fr->fr_size += 9; /* room for \0's */ + } else { + char *names = fr->fr_names; + int nlen = fr->fr_namelen; + + fr->fr_size = size; + if (old->fr_ifnames[0][0] != '\0') { + fr->fr_ifnames[0] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[0], + LIFNAMSIZ); + } + if (old->fr_ifnames[1][0] != '\0') { + fr->fr_ifnames[1] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[1], + LIFNAMSIZ); + } + if (old->fr_ifnames[2][0] != '\0') { + fr->fr_ifnames[2] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[2], + LIFNAMSIZ); + } + if (old->fr_ifnames[3][0] != '\0') { + fr->fr_ifnames[3] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[3], + LIFNAMSIZ); + } + if (old->fr_tifs[0].fd_ifname[0] != '\0') { + fr->fr_tifs[0].fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_tifs[0].fd_ifname, + LIFNAMSIZ); + } + if (old->fr_tifs[1].fd_ifname[0] != '\0') { + fr->fr_tifs[1].fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_tifs[1].fd_ifname, + LIFNAMSIZ); + } + if (old->fr_dif.fd_ifname[0] != '\0') { + fr->fr_dif.fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_dif.fd_ifname, LIFNAMSIZ); + } + if (old->fr_group[0] != '\0') { + fr->fr_group = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_group, LIFNAMSIZ); + } + if (old->fr_grhead[0] != '\0') { + fr->fr_grhead = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_grhead, LIFNAMSIZ); + } + fr->fr_namelen = nlen; + + if (old->fr_type == FR_T_IPF) { + int offset = fr->fr_namelen; + ipfobj_t obj; + int error; + + obj.ipfo_type = IPFOBJ_FRIPF; + obj.ipfo_rev = 4010100; + obj.ipfo_ptr = old->fr_data; + + if ((offset & 7) != 0) + offset += 8 - (offset & 7); + error = ipf_in_compat(softc, &obj, + fr->fr_names + offset, 0); + if (error == 0) { + fr->fr_data = fr->fr_names + offset; + fr->fr_dsize = sizeof(fripf_t); + } + } + } +} + +static void +frentry_4_1_16_to_current(softc, old, current, size) + ipf_main_softc_t *softc; + frentry_4_1_16_t *old; + void *current; + int size; +{ + frentry_t *fr = (frentry_t *)current; + + fr->fr_comment = -1; + fr->fr_ref = old->fr_ref; + fr->fr_statecnt = old->fr_statecnt; + fr->fr_hits = old->fr_hits; + fr->fr_bytes = old->fr_bytes; + fr->fr_lastpkt.tv_sec = old->fr_lastpkt.tv_sec; + fr->fr_lastpkt.tv_usec = old->fr_lastpkt.tv_usec; + bcopy(&old->fr_dun, &fr->fr_dun, sizeof(old->fr_dun)); + fr->fr_func = old->fr_func; + fr->fr_dsize = old->fr_dsize; + fr->fr_pps = old->fr_pps; + fr->fr_statemax = old->fr_statemax; + fr->fr_flineno = old->fr_flineno; + fr->fr_type = old->fr_type; + fr->fr_flags = fr_frflags4to5(old->fr_flags); + fr->fr_logtag = old->fr_logtag; + fr->fr_collect = old->fr_collect; + fr->fr_arg = old->fr_arg; + fr->fr_loglevel = old->fr_loglevel; + fr->fr_age[0] = old->fr_age[0]; + fr->fr_age[1] = old->fr_age[1]; + fr->fr_tifs[0].fd_ip6 = old->fr_tifs[0].ofd_ip6; + fr->fr_tifs[0].fd_type = FRD_NORMAL; + fr->fr_tifs[1].fd_ip6 = old->fr_tifs[1].ofd_ip6; + fr->fr_tifs[1].fd_type = FRD_NORMAL; + fr->fr_dif.fd_ip6 = old->fr_dif.ofd_ip6; + fr->fr_dif.fd_type = FRD_NORMAL; + if (old->fr_v == 4) + fr->fr_family = AF_INET; + if (old->fr_v == 6) + fr->fr_family = AF_INET6; + fr->fr_icode = old->fr_icode; + fr->fr_cksum = old->fr_cksum; + fr->fr_namelen = 0; + fr->fr_ifnames[0] = -1; + fr->fr_ifnames[1] = -1; + fr->fr_ifnames[2] = -1; + fr->fr_ifnames[3] = -1; + fr->fr_dif.fd_name = -1; + fr->fr_tifs[0].fd_name = -1; + fr->fr_tifs[1].fd_name = -1; + fr->fr_group = -1; + fr->fr_grhead = -1; + fr->fr_icmphead = -1; + if (size == 0) { + fr->fr_size = sizeof(*fr) + LIFNAMSIZ * 7 + FR_GROUPLEN * 2; + fr->fr_size += 9; /* room for \0's */ + } else { + char *names = fr->fr_names; + int nlen = fr->fr_namelen; + + fr->fr_size = size; + if (old->fr_ifnames[0][0] != '\0') { + fr->fr_ifnames[0] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[0], + LIFNAMSIZ); + } + if (old->fr_ifnames[1][0] != '\0') { + fr->fr_ifnames[1] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[1], + LIFNAMSIZ); + } + if (old->fr_ifnames[2][0] != '\0') { + fr->fr_ifnames[2] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[2], + LIFNAMSIZ); + } + if (old->fr_ifnames[3][0] != '\0') { + fr->fr_ifnames[3] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[3], + LIFNAMSIZ); + } + if (old->fr_tifs[0].fd_ifname[0] != '\0') { + fr->fr_tifs[0].fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_tifs[0].fd_ifname, + LIFNAMSIZ); + } + if (old->fr_tifs[1].fd_ifname[0] != '\0') { + fr->fr_tifs[1].fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_tifs[1].fd_ifname, + LIFNAMSIZ); + } + if (old->fr_dif.fd_ifname[0] != '\0') { + fr->fr_dif.fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_dif.fd_ifname, LIFNAMSIZ); + } + if (old->fr_group[0] != '\0') { + fr->fr_group = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_group, LIFNAMSIZ); + } + if (old->fr_grhead[0] != '\0') { + fr->fr_grhead = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_grhead, LIFNAMSIZ); + } + fr->fr_namelen = nlen; + + if (old->fr_type == FR_T_IPF) { + int offset = fr->fr_namelen; + ipfobj_t obj; + int error; + + obj.ipfo_type = IPFOBJ_FRIPF; + obj.ipfo_rev = 4010100; + obj.ipfo_ptr = old->fr_data; + + if ((offset & 7) != 0) + offset += 8 - (offset & 7); + error = ipf_in_compat(softc, &obj, + fr->fr_names + offset, 0); + if (error == 0) { + fr->fr_data = fr->fr_names + offset; + fr->fr_dsize = sizeof(fripf_t); + } + } + } +} + + +static void +frentry_4_1_0_to_current(softc, old, current, size) + ipf_main_softc_t *softc; + frentry_4_1_0_t *old; + void *current; + int size; +{ + frentry_t *fr = (frentry_t *)current; + + fr->fr_size = sizeof(*fr); + fr->fr_comment = -1; + fr->fr_ref = old->fr_ref; + fr->fr_statecnt = old->fr_statecnt; + fr->fr_hits = old->fr_hits; + fr->fr_bytes = old->fr_bytes; + fr->fr_lastpkt.tv_sec = old->fr_lastpkt.tv_sec; + fr->fr_lastpkt.tv_usec = old->fr_lastpkt.tv_usec; + bcopy(&old->fr_dun, &fr->fr_dun, sizeof(old->fr_dun)); + fr->fr_func = old->fr_func; + fr->fr_dsize = old->fr_dsize; + fr->fr_pps = old->fr_pps; + fr->fr_statemax = old->fr_statemax; + fr->fr_flineno = old->fr_flineno; + fr->fr_type = old->fr_type; + fr->fr_flags = fr_frflags4to5(old->fr_flags); + fr->fr_logtag = old->fr_logtag; + fr->fr_collect = old->fr_collect; + fr->fr_arg = old->fr_arg; + fr->fr_loglevel = old->fr_loglevel; + fr->fr_age[0] = old->fr_age[0]; + fr->fr_age[1] = old->fr_age[1]; + fr->fr_tifs[0].fd_ip6 = old->fr_tifs[0].ofd_ip6; + fr->fr_tifs[0].fd_type = FRD_NORMAL; + fr->fr_tifs[1].fd_ip6 = old->fr_tifs[1].ofd_ip6; + fr->fr_tifs[1].fd_type = FRD_NORMAL; + fr->fr_dif.fd_ip6 = old->fr_dif.ofd_ip6; + fr->fr_dif.fd_type = FRD_NORMAL; + if (old->fr_v == 4) + fr->fr_family = AF_INET; + if (old->fr_v == 6) + fr->fr_family = AF_INET6; + fr->fr_icode = old->fr_icode; + fr->fr_cksum = old->fr_cksum; + fr->fr_namelen = 0; + fr->fr_ifnames[0] = -1; + fr->fr_ifnames[1] = -1; + fr->fr_ifnames[2] = -1; + fr->fr_ifnames[3] = -1; + fr->fr_dif.fd_name = -1; + fr->fr_tifs[0].fd_name = -1; + fr->fr_tifs[1].fd_name = -1; + fr->fr_group = -1; + fr->fr_grhead = -1; + fr->fr_icmphead = -1; + if (size == 0) { + fr->fr_size = sizeof(*fr) + LIFNAMSIZ * 7 + FR_GROUPLEN * 2; + fr->fr_size += 9; /* room for \0's */ + } else { + char *names = fr->fr_names; + int nlen = fr->fr_namelen; + + fr->fr_size = size; + if (old->fr_ifnames[0][0] != '\0') { + fr->fr_ifnames[0] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[0], + LIFNAMSIZ); + } + if (old->fr_ifnames[1][0] != '\0') { + fr->fr_ifnames[1] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[1], + LIFNAMSIZ); + } + if (old->fr_ifnames[2][0] != '\0') { + fr->fr_ifnames[2] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[2], + LIFNAMSIZ); + } + if (old->fr_ifnames[3][0] != '\0') { + fr->fr_ifnames[3] = nlen; + nlen = ipf_addfrstr(names, nlen, old->fr_ifnames[3], + LIFNAMSIZ); + } + if (old->fr_tifs[0].fd_ifname[0] != '\0') { + fr->fr_tifs[0].fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_tifs[0].fd_ifname, + LIFNAMSIZ); + } + if (old->fr_tifs[1].fd_ifname[0] != '\0') { + fr->fr_tifs[1].fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_tifs[1].fd_ifname, + LIFNAMSIZ); + } + if (old->fr_dif.fd_ifname[0] != '\0') { + fr->fr_dif.fd_name = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_dif.fd_ifname, LIFNAMSIZ); + } + if (old->fr_group[0] != '\0') { + fr->fr_group = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_group, LIFNAMSIZ); + } + if (old->fr_grhead[0] != '\0') { + fr->fr_grhead = nlen; + nlen = ipf_addfrstr(names, nlen, + old->fr_grhead, LIFNAMSIZ); + } + fr->fr_namelen = nlen; + + if (old->fr_type == FR_T_IPF) { + int offset = fr->fr_namelen; + ipfobj_t obj; + int error; + + obj.ipfo_type = IPFOBJ_FRIPF; + obj.ipfo_rev = 4010100; + obj.ipfo_ptr = old->fr_data; + + if ((offset & 7) != 0) + offset += 8 - (offset & 7); + offset += 8 - (offset & 7); + error = ipf_in_compat(softc, &obj, + fr->fr_names + offset, 0); + if (error == 0) { + fr->fr_data = fr->fr_names + offset; + fr->fr_dsize = sizeof(fripf_t); + } + } + } +} + + +static void +friostat_4_1_33_to_current(old, current) + friostat_4_1_33_t *old; + void *current; +{ + friostat_t *fiop = (friostat_t *)current; + + bcopy(&old->of_st[0], &fiop->f_st[0].fr_pass, sizeof(old->of_st[0])); + bcopy(&old->of_st[1], &fiop->f_st[1].fr_pass, sizeof(old->of_st[1])); + + fiop->f_ipf[0][0] = old->f_ipf[0][0]; + fiop->f_ipf[0][1] = old->f_ipf[0][1]; + fiop->f_ipf[1][0] = old->f_ipf[1][0]; + fiop->f_ipf[1][1] = old->f_ipf[1][1]; + fiop->f_acct[0][0] = old->f_acct[0][0]; + fiop->f_acct[0][1] = old->f_acct[0][1]; + fiop->f_acct[1][0] = old->f_acct[1][0]; + fiop->f_acct[1][1] = old->f_acct[1][1]; + fiop->f_auth = fiop->f_auth; + bcopy(&old->f_groups, &fiop->f_groups, sizeof(old->f_groups)); + bcopy(&old->f_froute, &fiop->f_froute, sizeof(old->f_froute)); + fiop->f_ticks = old->f_ticks; + bcopy(&old->f_locks, &fiop->f_locks, sizeof(old->f_locks)); + fiop->f_defpass = old->f_defpass; + fiop->f_active = old->f_active; + fiop->f_running = old->f_running; + fiop->f_logging = old->f_logging; + fiop->f_features = old->f_features; + bcopy(old->f_version, fiop->f_version, sizeof(old->f_version)); +} + + +static void +friostat_4_1_0_to_current(old, current) + friostat_4_1_0_t *old; + void *current; +{ + friostat_t *fiop = (friostat_t *)current; + + bcopy(&old->of_st[0], &fiop->f_st[0].fr_pass, sizeof(old->of_st[0])); + bcopy(&old->of_st[1], &fiop->f_st[1].fr_pass, sizeof(old->of_st[1])); + + fiop->f_ipf[0][0] = old->f_ipf[0][0]; + fiop->f_ipf[0][1] = old->f_ipf[0][1]; + fiop->f_ipf[1][0] = old->f_ipf[1][0]; + fiop->f_ipf[1][1] = old->f_ipf[1][1]; + fiop->f_acct[0][0] = old->f_acct[0][0]; + fiop->f_acct[0][1] = old->f_acct[0][1]; + fiop->f_acct[1][0] = old->f_acct[1][0]; + fiop->f_acct[1][1] = old->f_acct[1][1]; + fiop->f_auth = fiop->f_auth; + bcopy(&old->f_groups, &fiop->f_groups, sizeof(old->f_groups)); + bcopy(&old->f_froute, &fiop->f_froute, sizeof(old->f_froute)); + fiop->f_ticks = old->f_ticks; + bcopy(&old->f_locks, &fiop->f_locks, sizeof(old->f_locks)); + fiop->f_defpass = old->f_defpass; + fiop->f_active = old->f_active; + fiop->f_running = old->f_running; + fiop->f_logging = old->f_logging; + fiop->f_features = old->f_features; + bcopy(old->f_version, fiop->f_version, sizeof(old->f_version)); +} + + +static void +ipnat_4_1_14_to_current(old, current, size) + ipnat_4_1_14_t *old; + void *current; + int size; +{ + ipnat_t *np = (ipnat_t *)current; + + np->in_space = old->in_space; + np->in_hv[0] = old->in_hv; + np->in_hv[1] = old->in_hv; + np->in_flineno = old->in_flineno; + if (old->in_redir == NAT_REDIRECT) + np->in_dpnext = old->in_pnext; + else + np->in_spnext = old->in_pnext; + np->in_v[0] = old->in_v; + np->in_v[1] = old->in_v; + np->in_flags = old->in_flags; + np->in_mssclamp = old->in_mssclamp; + np->in_age[0] = old->in_age[0]; + np->in_age[1] = old->in_age[1]; + np->in_redir = old->in_redir; + np->in_pr[0] = old->in_p; + np->in_pr[1] = old->in_p; + if (np->in_redir == NAT_REDIRECT) { + np->in_ndst.na_nextaddr = old->in_next6; + np->in_ndst.na_addr[0] = old->in_in[0]; + np->in_ndst.na_addr[1] = old->in_in[1]; + np->in_ndst.na_atype = FRI_NORMAL; + np->in_odst.na_addr[0] = old->in_out[0]; + np->in_odst.na_addr[1] = old->in_out[1]; + np->in_odst.na_atype = FRI_NORMAL; + np->in_osrc.na_addr[0] = old->in_src[0]; + np->in_osrc.na_addr[1] = old->in_src[1]; + np->in_osrc.na_atype = FRI_NORMAL; + } else { + np->in_nsrc.na_nextaddr = old->in_next6; + np->in_nsrc.na_addr[0] = old->in_out[0]; + np->in_nsrc.na_addr[1] = old->in_out[1]; + np->in_nsrc.na_atype = FRI_NORMAL; + np->in_osrc.na_addr[0] = old->in_in[0]; + np->in_osrc.na_addr[1] = old->in_in[1]; + np->in_osrc.na_atype = FRI_NORMAL; + np->in_odst.na_addr[0] = old->in_src[0]; + np->in_odst.na_addr[1] = old->in_src[1]; + np->in_odst.na_atype = FRI_NORMAL; + } + ipfv4tuctov5(&old->in_tuc, &np->in_tuc); + if (np->in_redir == NAT_REDIRECT) { + np->in_dpmin = old->in_port[0]; + np->in_dpmax = old->in_port[1]; + } else { + np->in_spmin = old->in_port[0]; + np->in_spmax = old->in_port[1]; + } + np->in_ppip = old->in_ppip; + np->in_ippip = old->in_ippip; + np->in_tag = old->in_tag; + + np->in_namelen = 0; + np->in_plabel = -1; + np->in_ifnames[0] = -1; + np->in_ifnames[1] = -1; + + if (size == 0) { + np->in_size = sizeof(*np); + np->in_size += LIFNAMSIZ * 2 + APR_LABELLEN; + np->in_size += 3; + } else { + int nlen = np->in_namelen; + char *names = np->in_names; + + if (old->in_ifnames[0][0] != '\0') { + np->in_ifnames[0] = nlen; + nlen = ipf_addfrstr(names, nlen, old->in_ifnames[0], + LIFNAMSIZ); + } + if (old->in_ifnames[1][0] != '\0') { + np->in_ifnames[0] = nlen; + nlen = ipf_addfrstr(names, nlen, old->in_ifnames[1], + LIFNAMSIZ); + } + if (old->in_plabel[0] != '\0') { + np->in_plabel = nlen; + nlen = ipf_addfrstr(names, nlen, old->in_plabel, + LIFNAMSIZ); + } + np->in_namelen = nlen; + np->in_size = size; + } +} + + +static void +ipnat_4_1_0_to_current(old, current, size) + ipnat_4_1_0_t *old; + void *current; + int size; +{ + ipnat_t *np = (ipnat_t *)current; + + np->in_space = old->in_space; + np->in_hv[0] = old->in_hv; + np->in_hv[1] = old->in_hv; + np->in_flineno = old->in_flineno; + if (old->in_redir == NAT_REDIRECT) + np->in_dpnext = old->in_pnext; + else + np->in_spnext = old->in_pnext; + np->in_v[0] = old->in_v; + np->in_v[1] = old->in_v; + np->in_flags = old->in_flags; + np->in_mssclamp = old->in_mssclamp; + np->in_age[0] = old->in_age[0]; + np->in_age[1] = old->in_age[1]; + np->in_redir = old->in_redir; + np->in_pr[0] = old->in_p; + np->in_pr[1] = old->in_p; + if (np->in_redir == NAT_REDIRECT) { + np->in_ndst.na_nextaddr = old->in_next6; + bcopy(&old->in_in, &np->in_ndst.na_addr, sizeof(old->in_in)); + bcopy(&old->in_out, &np->in_odst.na_addr, sizeof(old->in_out)); + bcopy(&old->in_src, &np->in_osrc.na_addr, sizeof(old->in_src)); + } else { + np->in_nsrc.na_nextaddr = old->in_next6; + bcopy(&old->in_in, &np->in_osrc.na_addr, sizeof(old->in_in)); + bcopy(&old->in_out, &np->in_nsrc.na_addr, sizeof(old->in_out)); + bcopy(&old->in_src, &np->in_odst.na_addr, sizeof(old->in_src)); + } + ipfv4tuctov5(&old->in_tuc, &np->in_tuc); + if (np->in_redir == NAT_REDIRECT) { + np->in_dpmin = old->in_port[0]; + np->in_dpmax = old->in_port[1]; + } else { + np->in_spmin = old->in_port[0]; + np->in_spmax = old->in_port[1]; + } + np->in_ppip = old->in_ppip; + np->in_ippip = old->in_ippip; + bcopy(&old->in_tag, &np->in_tag, sizeof(np->in_tag)); + + np->in_namelen = 0; + np->in_plabel = -1; + np->in_ifnames[0] = -1; + np->in_ifnames[1] = -1; + + if (size == 0) { + np->in_size = sizeof(*np); + np->in_size += LIFNAMSIZ * 2 + APR_LABELLEN; + np->in_size += 3; + } else { + int nlen = np->in_namelen; + char *names = np->in_names; + + if (old->in_ifnames[0][0] != '\0') { + np->in_ifnames[0] = nlen; + nlen = ipf_addfrstr(names, nlen, old->in_ifnames[0], + LIFNAMSIZ); + } + if (old->in_ifnames[1][0] != '\0') { + np->in_ifnames[0] = nlen; + nlen = ipf_addfrstr(names, nlen, old->in_ifnames[1], + LIFNAMSIZ); + } + if (old->in_plabel[0] != '\0') { + np->in_plabel = nlen; + nlen = ipf_addfrstr(names, nlen, old->in_plabel, + LIFNAMSIZ); + } + np->in_namelen = nlen; + np->in_size = size; + } +} + + +static void +frauth_4_1_32_to_current(old, current) + frauth_4_1_32_t *old; + void *current; +{ + frauth_t *fra = (frauth_t *)current; + + fra->fra_age = old->fra_age; + fra->fra_len = old->fra_len; + fra->fra_index = old->fra_index; + fra->fra_pass = old->fra_pass; + fr_info_4_1_32_to_current(&old->fra_info, &fra->fra_info); + fra->fra_buf = old->fra_buf; + fra->fra_flx = old->fra_flx; +#ifdef MENTAT + fra->fra_q = old->fra_q; + fra->fra_m = old->fra_m; +#endif +} + + +static void +frauth_4_1_29_to_current(old, current) + frauth_4_1_29_t *old; + void *current; +{ + frauth_t *fra = (frauth_t *)current; + + fra->fra_age = old->fra_age; + fra->fra_len = old->fra_len; + fra->fra_index = old->fra_index; + fra->fra_pass = old->fra_pass; + fr_info_4_1_24_to_current(&old->fra_info, &fra->fra_info); + fra->fra_buf = old->fra_buf; + fra->fra_flx = old->fra_flx; +#ifdef MENTAT + fra->fra_q = old->fra_q; + fra->fra_m = old->fra_m; +#endif +} + + +static void +frauth_4_1_24_to_current(old, current) + frauth_4_1_24_t *old; + void *current; +{ + frauth_t *fra = (frauth_t *)current; + + fra->fra_age = old->fra_age; + fra->fra_len = old->fra_len; + fra->fra_index = old->fra_index; + fra->fra_pass = old->fra_pass; + fr_info_4_1_24_to_current(&old->fra_info, &fra->fra_info); + fra->fra_buf = old->fra_buf; +#ifdef MENTAT + fra->fra_q = old->fra_q; + fra->fra_m = old->fra_m; +#endif +} + + +static void +frauth_4_1_23_to_current(old, current) + frauth_4_1_23_t *old; + void *current; +{ + frauth_t *fra = (frauth_t *)current; + + fra->fra_age = old->fra_age; + fra->fra_len = old->fra_len; + fra->fra_index = old->fra_index; + fra->fra_pass = old->fra_pass; + fr_info_4_1_23_to_current(&old->fra_info, &fra->fra_info); + fra->fra_buf = old->fra_buf; +#ifdef MENTAT + fra->fra_q = old->fra_q; + fra->fra_m = old->fra_m; +#endif +} + + +static void +frauth_4_1_11_to_current(old, current) + frauth_4_1_11_t *old; + void *current; +{ + frauth_t *fra = (frauth_t *)current; + + fra->fra_age = old->fra_age; + fra->fra_len = old->fra_len; + fra->fra_index = old->fra_index; + fra->fra_pass = old->fra_pass; + fr_info_4_1_11_to_current(&old->fra_info, &fra->fra_info); + fra->fra_buf = old->fra_buf; +#ifdef MENTAT + fra->fra_q = old->fra_q; + fra->fra_m = old->fra_m; +#endif +} + + +static void +fr_info_4_1_32_to_current(old, current) + fr_info_4_1_32_t *old; + void *current; +{ + fr_info_t *fin = (fr_info_t *)current; + + fin->fin_ifp = old->fin_ifp; + ipf_v4iptov5(&old->fin_fi, &fin->fin_fi); + bcopy(&old->fin_dat, &fin->fin_dat, sizeof(old->fin_dat)); + fin->fin_out = old->fin_out; + fin->fin_rev = old->fin_rev; + fin->fin_hlen = old->fin_hlen; + fin->fin_tcpf = old->ofin_tcpf; + fin->fin_icode = old->fin_icode; + fin->fin_rule = old->fin_rule; + bcopy(old->fin_group, fin->fin_group, sizeof(old->fin_group)); + fin->fin_fr = old->fin_fr; + fin->fin_dp = old->fin_dp; + fin->fin_dlen = old->fin_dlen; + fin->fin_plen = old->fin_plen; + fin->fin_ipoff = old->fin_ipoff; + fin->fin_id = old->fin_id; + fin->fin_off = old->fin_off; + fin->fin_depth = old->fin_depth; + fin->fin_error = old->fin_error; + fin->fin_cksum = old->fin_cksum; + fin->fin_nattag = old->fin_nattag; + fin->fin_ip = old->ofin_ip; + fin->fin_mp = old->fin_mp; + fin->fin_m = old->fin_m; +#ifdef MENTAT + fin->fin_qfm = old->fin_qfm; + fin->fin_qpi = old->fin_qpi; +#endif +#ifdef __sgi + fin->fin_hbuf = old->fin_hbuf; +#endif +} + + +static void +fr_info_4_1_24_to_current(old, current) + fr_info_4_1_24_t *old; + void *current; +{ + fr_info_t *fin = (fr_info_t *)current; + + fin->fin_ifp = old->fin_ifp; + ipf_v4iptov5(&old->fin_fi, &fin->fin_fi); + bcopy(&old->fin_dat, &fin->fin_dat, sizeof(old->fin_dat)); + fin->fin_out = old->fin_out; + fin->fin_rev = old->fin_rev; + fin->fin_hlen = old->fin_hlen; + fin->fin_tcpf = old->ofin_tcpf; + fin->fin_icode = old->fin_icode; + fin->fin_rule = old->fin_rule; + bcopy(old->fin_group, fin->fin_group, sizeof(old->fin_group)); + fin->fin_fr = old->fin_fr; + fin->fin_dp = old->fin_dp; + fin->fin_dlen = old->fin_dlen; + fin->fin_plen = old->fin_plen; + fin->fin_ipoff = old->fin_ipoff; + fin->fin_id = old->fin_id; + fin->fin_off = old->fin_off; + fin->fin_depth = old->fin_depth; + fin->fin_error = old->fin_error; + fin->fin_cksum = old->fin_cksum; + fin->fin_nattag = old->fin_nattag; + fin->fin_ip = old->ofin_ip; + fin->fin_mp = old->fin_mp; + fin->fin_m = old->fin_m; +#ifdef MENTAT + fin->fin_qfm = old->fin_qfm; + fin->fin_qpi = old->fin_qpi; +#endif +#ifdef __sgi + fin->fin_hbuf = old->fin_hbuf; +#endif +} + + +static void +fr_info_4_1_23_to_current(old, current) + fr_info_4_1_23_t *old; + void *current; +{ + fr_info_t *fin = (fr_info_t *)current; + + fin->fin_ifp = old->fin_ifp; + ipf_v4iptov5(&old->fin_fi, &fin->fin_fi); + bcopy(&old->fin_dat, &fin->fin_dat, sizeof(old->fin_dat)); + fin->fin_out = old->fin_out; + fin->fin_rev = old->fin_rev; + fin->fin_hlen = old->fin_hlen; + fin->fin_tcpf = old->ofin_tcpf; + fin->fin_icode = old->fin_icode; + fin->fin_rule = old->fin_rule; + bcopy(old->fin_group, fin->fin_group, sizeof(old->fin_group)); + fin->fin_fr = old->fin_fr; + fin->fin_dp = old->fin_dp; + fin->fin_dlen = old->fin_dlen; + fin->fin_plen = old->fin_plen; + fin->fin_ipoff = old->fin_ipoff; + fin->fin_id = old->fin_id; + fin->fin_off = old->fin_off; + fin->fin_depth = old->fin_depth; + fin->fin_error = old->fin_error; + fin->fin_nattag = old->fin_nattag; + fin->fin_ip = old->ofin_ip; + fin->fin_mp = old->fin_mp; + fin->fin_m = old->fin_m; +#ifdef MENTAT + fin->fin_qfm = old->fin_qfm; + fin->fin_qpi = old->fin_qpi; +#endif +#ifdef __sgi + fin->fin_hbuf = fin->fin_hbuf; +#endif +} + + +static void +fr_info_4_1_11_to_current(old, current) + fr_info_4_1_11_t *old; + void *current; +{ + fr_info_t *fin = (fr_info_t *)current; + + fin->fin_ifp = old->fin_ifp; + ipf_v4iptov5(&old->fin_fi, &fin->fin_fi); + bcopy(&old->fin_dat, &fin->fin_dat, sizeof(old->fin_dat)); + fin->fin_out = old->fin_out; + fin->fin_rev = old->fin_rev; + fin->fin_hlen = old->fin_hlen; + fin->fin_tcpf = old->ofin_tcpf; + fin->fin_icode = old->fin_icode; + fin->fin_rule = old->fin_rule; + bcopy(old->fin_group, fin->fin_group, sizeof(old->fin_group)); + fin->fin_fr = old->fin_fr; + fin->fin_dp = old->fin_dp; + fin->fin_dlen = old->fin_dlen; + fin->fin_plen = old->fin_plen; + fin->fin_ipoff = old->fin_ipoff; + fin->fin_id = old->fin_id; + fin->fin_off = old->fin_off; + fin->fin_depth = old->fin_depth; + fin->fin_error = old->fin_error; + fin->fin_nattag = old->fin_nattag; + fin->fin_ip = old->ofin_ip; + fin->fin_mp = old->fin_mp; + fin->fin_m = old->fin_m; +#ifdef MENTAT + fin->fin_qfm = old->fin_qfm; + fin->fin_qpi = old->fin_qpi; +#endif +#ifdef __sgi + fin->fin_hbuf = fin->fin_hbuf; +#endif +} + + +static void +nat_4_1_3_to_current(nat_4_1_3_t *old, nat_t *current) +{ + bzero((void *)current, sizeof(*current)); + bcopy((void *)old, (void *)current, sizeof(*old)); +} + + +static void +nat_4_1_14_to_current(nat_4_1_14_t *old, nat_t *current) +{ + bzero((void *)current, sizeof(*current)); + bcopy((void *)old, (void *)current, sizeof(*old)); +} + + +static void +nat_save_4_1_16_to_current(softc, old, current) + ipf_main_softc_t *softc; + nat_save_4_1_16_t *old; + void *current; +{ + nat_save_t *nats = (nat_save_t *)current; + + nats->ipn_next = old->ipn_next; + nat_4_1_14_to_current(&old->ipn_nat, &nats->ipn_nat); + bcopy(&old->ipn_ipnat, &nats->ipn_ipnat, sizeof(old->ipn_ipnat)); + frentry_4_1_16_to_current(softc, &old->ipn_fr, &nats->ipn_fr, 0); + nats->ipn_dsize = old->ipn_dsize; + bcopy(old->ipn_data, nats->ipn_data, sizeof(nats->ipn_data)); +} + + +static void +nat_save_4_1_14_to_current(softc, old, current) + ipf_main_softc_t *softc; + nat_save_4_1_14_t *old; + void *current; +{ + nat_save_t *nats = (nat_save_t *)current; + + nats->ipn_next = old->ipn_next; + nat_4_1_14_to_current(&old->ipn_nat, &nats->ipn_nat); + bcopy(&old->ipn_ipnat, &nats->ipn_ipnat, sizeof(old->ipn_ipnat)); + frentry_4_1_0_to_current(softc, &old->ipn_fr, &nats->ipn_fr, 0); + nats->ipn_dsize = old->ipn_dsize; + bcopy(old->ipn_data, nats->ipn_data, sizeof(nats->ipn_data)); +} + + +static void +nat_save_4_1_3_to_current(softc, old, current) + ipf_main_softc_t *softc; + nat_save_4_1_3_t *old; + void *current; +{ + nat_save_t *nats = (nat_save_t *)current; + + nats->ipn_next = old->ipn_next; + nat_4_1_3_to_current(&old->ipn_nat, &nats->ipn_nat); + ipnat_4_1_0_to_current(&old->ipn_ipnat, &nats->ipn_ipnat, 0); + frentry_4_1_0_to_current(softc, &old->ipn_fr, &nats->ipn_fr, 0); + nats->ipn_dsize = old->ipn_dsize; + bcopy(old->ipn_data, nats->ipn_data, sizeof(nats->ipn_data)); +} + + +static void +natstat_current_to_4_1_32(current, old) + void *current; + natstat_4_1_32_t *old; +{ + natstat_t *ns = (natstat_t *)current; + + old->ns_mapped[0] = ns->ns_side[0].ns_translated; + old->ns_mapped[1] = ns->ns_side[1].ns_translated; + old->ns_rules = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse; + old->ns_added = ns->ns_side[0].ns_added + ns->ns_side[1].ns_added; + old->ns_expire = ns->ns_expire; + old->ns_inuse = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse; + old->ns_logged = ns->ns_log_ok; + old->ns_logfail = ns->ns_log_fail; + old->ns_memfail = ns->ns_side[0].ns_memfail + ns->ns_side[1].ns_memfail; + old->ns_badnat = ns->ns_side[0].ns_badnat + ns->ns_side[1].ns_badnat; + old->ns_addtrpnt = ns->ns_addtrpnt; + old->ns_table[0] = ns->ns_side[0].ns_table; + old->ns_table[1] = ns->ns_side[1].ns_table; + old->ns_maptable = NULL; + old->ns_list = ns->ns_list; + old->ns_apslist = NULL; + old->ns_wilds = ns->ns_wilds; + old->ns_nattab_sz = ns->ns_nattab_sz; + old->ns_nattab_max = ns->ns_nattab_max; + old->ns_rultab_sz = ns->ns_rultab_sz; + old->ns_rdrtab_sz = ns->ns_rdrtab_sz; + old->ns_trpntab_sz = ns->ns_trpntab_sz; + old->ns_hostmap_sz = 0; + old->ns_instances = ns->ns_instances; + old->ns_maplist = ns->ns_maplist; + old->ns_bucketlen[0] = (u_long *)ns->ns_side[0].ns_bucketlen; + old->ns_bucketlen[1] = (u_long *)ns->ns_side[1].ns_bucketlen; + old->ns_ticks = ns->ns_ticks; + old->ns_orphans = ns->ns_orphans; + old->ns_uncreate[0][0] = ns->ns_side[0].ns_uncreate[0]; + old->ns_uncreate[0][1] = ns->ns_side[0].ns_uncreate[1]; + old->ns_uncreate[1][0] = ns->ns_side[1].ns_uncreate[0]; + old->ns_uncreate[1][1] = ns->ns_side[1].ns_uncreate[1]; +} + + +static void +natstat_current_to_4_1_27(current, old) + void *current; + natstat_4_1_27_t *old; +{ + natstat_t *ns = (natstat_t *)current; + + old->ns_mapped[0] = ns->ns_side[0].ns_translated; + old->ns_mapped[1] = ns->ns_side[1].ns_translated; + old->ns_rules = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse; + old->ns_added = ns->ns_side[0].ns_added + ns->ns_side[1].ns_added; + old->ns_expire = ns->ns_expire; + old->ns_inuse = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse; + old->ns_logged = ns->ns_log_ok; + old->ns_logfail = ns->ns_log_fail; + old->ns_memfail = ns->ns_side[0].ns_memfail + ns->ns_side[1].ns_memfail; + old->ns_badnat = ns->ns_side[0].ns_badnat + ns->ns_side[1].ns_badnat; + old->ns_addtrpnt = ns->ns_addtrpnt; + old->ns_table[0] = ns->ns_side[0].ns_table; + old->ns_table[1] = ns->ns_side[1].ns_table; + old->ns_maptable = NULL; + old->ns_list = ns->ns_list; + old->ns_apslist = NULL; + old->ns_wilds = ns->ns_wilds; + old->ns_nattab_sz = ns->ns_nattab_sz; + old->ns_nattab_max = ns->ns_nattab_max; + old->ns_rultab_sz = ns->ns_rultab_sz; + old->ns_rdrtab_sz = ns->ns_rdrtab_sz; + old->ns_trpntab_sz = ns->ns_trpntab_sz; + old->ns_hostmap_sz = 0; + old->ns_instances = ns->ns_instances; + old->ns_maplist = ns->ns_maplist; + old->ns_bucketlen[0] = (u_long *)ns->ns_side[0].ns_bucketlen; + old->ns_bucketlen[1] = (u_long *)ns->ns_side[1].ns_bucketlen; + old->ns_ticks = ns->ns_ticks; + old->ns_orphans = ns->ns_orphans; +} + + +static void +natstat_current_to_4_1_16(current, old) + void *current; + natstat_4_1_16_t *old; +{ + natstat_t *ns = (natstat_t *)current; + + old->ns_mapped[0] = ns->ns_side[0].ns_translated; + old->ns_mapped[1] = ns->ns_side[1].ns_translated; + old->ns_rules = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse; + old->ns_added = ns->ns_side[0].ns_added + ns->ns_side[1].ns_added; + old->ns_expire = ns->ns_expire; + old->ns_inuse = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse; + old->ns_logged = ns->ns_log_ok; + old->ns_logfail = ns->ns_log_fail; + old->ns_memfail = ns->ns_side[0].ns_memfail + ns->ns_side[1].ns_memfail; + old->ns_badnat = ns->ns_side[0].ns_badnat + ns->ns_side[1].ns_badnat; + old->ns_addtrpnt = ns->ns_addtrpnt; + old->ns_table[0] = ns->ns_side[0].ns_table; + old->ns_table[1] = ns->ns_side[1].ns_table; + old->ns_maptable = NULL; + old->ns_list = ns->ns_list; + old->ns_apslist = NULL; + old->ns_wilds = ns->ns_wilds; + old->ns_nattab_sz = ns->ns_nattab_sz; + old->ns_nattab_max = ns->ns_nattab_max; + old->ns_rultab_sz = ns->ns_rultab_sz; + old->ns_rdrtab_sz = ns->ns_rdrtab_sz; + old->ns_trpntab_sz = ns->ns_trpntab_sz; + old->ns_hostmap_sz = 0; + old->ns_instances = ns->ns_instances; + old->ns_maplist = ns->ns_maplist; + old->ns_bucketlen[0] = (u_long *)ns->ns_side[0].ns_bucketlen; + old->ns_bucketlen[1] = (u_long *)ns->ns_side[1].ns_bucketlen; + old->ns_ticks = ns->ns_ticks; +} + + +static void +natstat_current_to_4_1_0(current, old) + void *current; + natstat_4_1_0_t *old; +{ + natstat_t *ns = (natstat_t *)current; + + old->ns_mapped[0] = ns->ns_side[0].ns_translated; + old->ns_mapped[1] = ns->ns_side[1].ns_translated; + old->ns_rules = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse; + old->ns_added = ns->ns_side[0].ns_added + ns->ns_side[1].ns_added; + old->ns_expire = ns->ns_expire; + old->ns_inuse = ns->ns_side[0].ns_inuse + ns->ns_side[1].ns_inuse; + old->ns_logged = ns->ns_log_ok; + old->ns_logfail = ns->ns_log_fail; + old->ns_memfail = ns->ns_side[0].ns_memfail + ns->ns_side[1].ns_memfail; + old->ns_badnat = ns->ns_side[0].ns_badnat + ns->ns_side[1].ns_badnat; + old->ns_addtrpnt = ns->ns_addtrpnt; + old->ns_table[0] = ns->ns_side[0].ns_table; + old->ns_table[1] = ns->ns_side[1].ns_table; + old->ns_maptable = NULL; + old->ns_list = ns->ns_list; + old->ns_apslist = NULL; + old->ns_wilds = ns->ns_wilds; + old->ns_nattab_sz = ns->ns_nattab_sz; + old->ns_nattab_max = ns->ns_nattab_max; + old->ns_rultab_sz = ns->ns_rultab_sz; + old->ns_rdrtab_sz = ns->ns_rdrtab_sz; + old->ns_trpntab_sz = ns->ns_trpntab_sz; + old->ns_hostmap_sz = 0; + old->ns_instances = ns->ns_instances; + old->ns_maplist = ns->ns_maplist; + old->ns_bucketlen[0] = (u_long *)ns->ns_side[0].ns_bucketlen; + old->ns_bucketlen[1] = (u_long *)ns->ns_side[1].ns_bucketlen; +} + + +static void +ipstate_save_current_to_4_1_16(current, old) + void *current; + ipstate_save_4_1_16_t *old; +{ + ipstate_save_t *ips = (ipstate_save_t *)current; + + old->ips_next = ips->ips_next; + ipstate_current_to_4_1_0(&ips->ips_is, &old->ips_is); + frentry_current_to_4_1_16(&ips->ips_fr, &old->ips_fr); +} + + +static void +ipstate_save_current_to_4_1_0(current, old) + void *current; + ipstate_save_4_1_0_t *old; +{ + ipstate_save_t *ips = (ipstate_save_t *)current; + + old->ips_next = ips->ips_next; + ipstate_current_to_4_1_0(&ips->ips_is, &old->ips_is); + frentry_current_to_4_1_0(&ips->ips_fr, &old->ips_fr); +} + + +int +ipf_out_compat(softc, obj, ptr) + ipf_main_softc_t *softc; + ipfobj_t *obj; + void *ptr; +{ + frentry_t *fr; + int error; + + IPFERROR(140042); + error = EINVAL; + + switch (obj->ipfo_type) + { + default : + break; + + case IPFOBJ_FRENTRY : + if (obj->ipfo_rev >= 4013400) { + frentry_4_1_34_t *old; + + KMALLOC(old, frentry_4_1_34_t *); + if (old == NULL) { + IPFERROR(140043); + error = ENOMEM; + break; + } + frentry_current_to_4_1_34(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error == 0 && old->fr_dsize > 0) { + char *dst = obj->ipfo_ptr; + + fr = ptr; + dst += sizeof(*old); + error = COPYOUT(fr->fr_data, dst, + old->fr_dsize); + if (error != 0) { + IPFERROR(140044); + } + } + KFREE(old); + obj->ipfo_size = sizeof(*old); + } else if (obj->ipfo_rev >= 4011600) { + frentry_4_1_16_t *old; + + KMALLOC(old, frentry_4_1_16_t *); + if (old == NULL) { + IPFERROR(140045); + error = ENOMEM; + break; + } + frentry_current_to_4_1_16(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140046); + } + KFREE(old); + obj->ipfo_size = sizeof(*old); + } else { + frentry_4_1_0_t *old; + + KMALLOC(old, frentry_4_1_0_t *); + if (old == NULL) { + IPFERROR(140047); + error = ENOMEM; + break; + } + frentry_current_to_4_1_0(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140048); + } + KFREE(old); + obj->ipfo_size = sizeof(*old); + } + break; + + case IPFOBJ_IPFSTAT : + if (obj->ipfo_rev >= 4013300) { + friostat_4_1_33_t *old; + + KMALLOC(old, friostat_4_1_33_t *); + if (old == NULL) { + IPFERROR(140049); + error = ENOMEM; + break; + } + friostat_current_to_4_1_33(ptr, old, obj->ipfo_rev); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140050); + } + KFREE(old); + } else { + friostat_4_1_0_t *old; + + KMALLOC(old, friostat_4_1_0_t *); + if (old == NULL) { + IPFERROR(140051); + error = ENOMEM; + break; + } + friostat_current_to_4_1_0(ptr, old, obj->ipfo_rev); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140052); + } + KFREE(old); + } + break; + + case IPFOBJ_IPFINFO : /* unused */ + break; + + case IPFOBJ_IPNAT : + if (obj->ipfo_rev >= 4011400) { + ipnat_4_1_14_t *old; + + KMALLOC(old, ipnat_4_1_14_t *); + if (old == NULL) { + IPFERROR(140053); + error = ENOMEM; + break; + } + ipnat_current_to_4_1_14(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140054); + } + KFREE(old); + } else { + ipnat_4_1_0_t *old; + + KMALLOC(old, ipnat_4_1_0_t *); + if (old == NULL) { + IPFERROR(140055); + error = ENOMEM; + break; + } + ipnat_current_to_4_1_0(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140056); + } + KFREE(old); + } + break; + + case IPFOBJ_NATSTAT : + if (obj->ipfo_rev >= 4013200) { + natstat_4_1_32_t *old; + + KMALLOC(old, natstat_4_1_32_t *); + if (old == NULL) { + IPFERROR(140057); + error = ENOMEM; + break; + } + natstat_current_to_4_1_32(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140058); + } + KFREE(old); + } else if (obj->ipfo_rev >= 4012700) { + natstat_4_1_27_t *old; + + KMALLOC(old, natstat_4_1_27_t *); + if (old == NULL) { + IPFERROR(140059); + error = ENOMEM; + break; + } + natstat_current_to_4_1_27(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140060); + } + KFREE(old); + } else if (obj->ipfo_rev >= 4011600) { + natstat_4_1_16_t *old; + + KMALLOC(old, natstat_4_1_16_t *); + if (old == NULL) { + IPFERROR(140061); + error = ENOMEM; + break; + } + natstat_current_to_4_1_16(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140062); + } + KFREE(old); + } else { + natstat_4_1_0_t *old; + + KMALLOC(old, natstat_4_1_0_t *); + if (old == NULL) { + IPFERROR(140063); + error = ENOMEM; + break; + } + natstat_current_to_4_1_0(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140064); + } + KFREE(old); + } + break; + + case IPFOBJ_STATESAVE : + if (obj->ipfo_rev >= 4011600) { + ipstate_save_4_1_16_t *old; + + KMALLOC(old, ipstate_save_4_1_16_t *); + if (old == NULL) { + IPFERROR(140065); + error = ENOMEM; + break; + } + ipstate_save_current_to_4_1_16(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140066); + } + KFREE(old); + } else { + ipstate_save_4_1_0_t *old; + + KMALLOC(old, ipstate_save_4_1_0_t *); + if (old == NULL) { + IPFERROR(140067); + error = ENOMEM; + break; + } + ipstate_save_current_to_4_1_0(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140068); + } + KFREE(old); + } + break; + + case IPFOBJ_NATSAVE : + if (obj->ipfo_rev >= 4011600) { + nat_save_4_1_16_t *old16; + + KMALLOC(old16, nat_save_4_1_16_t *); + if (old16 == NULL) { + IPFERROR(140069); + error = ENOMEM; + break; + } + nat_save_current_to_4_1_16(ptr, old16); + error = COPYOUT(&old16, obj->ipfo_ptr, sizeof(*old16)); + if (error != 0) { + IPFERROR(140070); + } + KFREE(old16); + } else if (obj->ipfo_rev >= 4011400) { + nat_save_4_1_14_t *old14; + + KMALLOC(old14, nat_save_4_1_14_t *); + if (old14 == NULL) { + IPFERROR(140071); + error = ENOMEM; + break; + } + nat_save_current_to_4_1_14(ptr, old14); + error = COPYOUT(&old14, obj->ipfo_ptr, sizeof(*old14)); + if (error != 0) { + IPFERROR(140072); + } + KFREE(old14); + } else if (obj->ipfo_rev >= 4010300) { + nat_save_4_1_3_t *old3; + + KMALLOC(old3, nat_save_4_1_3_t *); + if (old3 == NULL) { + IPFERROR(140073); + error = ENOMEM; + break; + } + nat_save_current_to_4_1_3(ptr, old3); + error = COPYOUT(&old3, obj->ipfo_ptr, sizeof(*old3)); + if (error != 0) { + IPFERROR(140074); + } + KFREE(old3); + } + break; + + case IPFOBJ_IPSTATE : + if (obj->ipfo_rev >= 4011600) { + ipstate_4_1_16_t *old; + + KMALLOC(old, ipstate_4_1_16_t *); + if (old == NULL) { + IPFERROR(140075); + error = ENOMEM; + break; + } + ipstate_current_to_4_1_16(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140076); + } + KFREE(old); + } else { + ipstate_4_1_0_t *old; + + KMALLOC(old, ipstate_4_1_0_t *); + if (old == NULL) { + IPFERROR(140077); + error = ENOMEM; + break; + } + ipstate_current_to_4_1_0(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140078); + } + KFREE(old); + } + break; + + case IPFOBJ_STATESTAT : + if (obj->ipfo_rev >= 4012100) { + ips_stat_4_1_21_t *old; + + KMALLOC(old, ips_stat_4_1_21_t *); + if (old == NULL) { + IPFERROR(140079); + error = ENOMEM; + break; + } + ips_stat_current_to_4_1_21(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140080); + } + KFREE(old); + } else { + ips_stat_4_1_0_t *old; + + KMALLOC(old, ips_stat_4_1_0_t *); + if (old == NULL) { + IPFERROR(140081); + error = ENOMEM; + break; + } + ips_stat_current_to_4_1_0(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140082); + } + KFREE(old); + } + break; + + case IPFOBJ_FRAUTH : + if (obj->ipfo_rev >= 4012900) { + frauth_4_1_29_t *old29; + + KMALLOC(old29, frauth_4_1_29_t *); + if (old29 == NULL) { + IPFERROR(140083); + error = ENOMEM; + break; + } + frauth_current_to_4_1_29(ptr, old29); + error = COPYOUT(old29, obj->ipfo_ptr, sizeof(*old29)); + if (error != 0) { + IPFERROR(140084); + } + KFREE(old29); + } else if (obj->ipfo_rev >= 4012400) { + frauth_4_1_24_t *old24; + + KMALLOC(old24, frauth_4_1_24_t *); + if (old24 == NULL) { + IPFERROR(140085); + error = ENOMEM; + break; + } + frauth_current_to_4_1_24(ptr, old24); + error = COPYOUT(old24, obj->ipfo_ptr, sizeof(*old24)); + if (error != 0) { + IPFERROR(140086); + } + KFREE(old24); + } else if (obj->ipfo_rev >= 4012300) { + frauth_4_1_23_t *old23; + + KMALLOC(old23, frauth_4_1_23_t *); + if (old23 == NULL) { + IPFERROR(140087); + error = ENOMEM; + break; + } + frauth_current_to_4_1_23(ptr, old23); + error = COPYOUT(old23, obj->ipfo_ptr, sizeof(*old23)); + if (error != 0) { + IPFERROR(140088); + } + KFREE(old23); + } else if (obj->ipfo_rev >= 4011100) { + frauth_4_1_11_t *old11; + + KMALLOC(old11, frauth_4_1_11_t *); + if (old11 == NULL) { + IPFERROR(140089); + error = ENOMEM; + break; + } + frauth_current_to_4_1_11(ptr, old11); + error = COPYOUT(old11, obj->ipfo_ptr, sizeof(*old11)); + if (error != 0) { + IPFERROR(140090); + } + KFREE(old11); + } + break; + + case IPFOBJ_NAT : + if (obj->ipfo_rev >= 4012500) { + nat_4_1_25_t *old; + + KMALLOC(old, nat_4_1_25_t *); + if (old == NULL) { + IPFERROR(140091); + error = ENOMEM; + break; + } + nat_current_to_4_1_25(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140092); + } + KFREE(old); + } else if (obj->ipfo_rev >= 4011400) { + nat_4_1_14_t *old; + + KMALLOC(old, nat_4_1_14_t *); + if (old == NULL) { + IPFERROR(140093); + error = ENOMEM; + break; + } + nat_current_to_4_1_14(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140094); + } + KFREE(old); + } else if (obj->ipfo_rev >= 4010300) { + nat_4_1_3_t *old; + + KMALLOC(old, nat_4_1_3_t *); + if (old == NULL) { + IPFERROR(140095); + error = ENOMEM; + break; + } + nat_current_to_4_1_3(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140096); + } + KFREE(old); + } + break; + + case IPFOBJ_FRIPF : + if (obj->ipfo_rev < 5000000) { + fripf4_t *old; + + KMALLOC(old, fripf4_t *); + if (old == NULL) { + IPFERROR(140097); + error = ENOMEM; + break; + } + ipf_v5fripftov4(ptr, old); + error = COPYOUT(old, obj->ipfo_ptr, sizeof(*old)); + if (error != 0) { + IPFERROR(140098); + } + KFREE(old); + } + break; + } + return error; +} + + +static void +friostat_current_to_4_1_33(current, old, rev) + void *current; + friostat_4_1_33_t *old; + int rev; +{ + friostat_t *fiop = (friostat_t *)current; + + bcopy(&fiop->f_st[0].fr_pass, &old->of_st[0], sizeof(old->of_st[0])); + bcopy(&fiop->f_st[1].fr_pass, &old->of_st[1], sizeof(old->of_st[1])); + + old->f_ipf[0][0] = fiop->f_ipf[0][0]; + old->f_ipf[0][1] = fiop->f_ipf[0][1]; + old->f_ipf[1][0] = fiop->f_ipf[1][0]; + old->f_ipf[1][1] = fiop->f_ipf[1][1]; + old->f_acct[0][0] = fiop->f_acct[0][0]; + old->f_acct[0][1] = fiop->f_acct[0][1]; + old->f_acct[1][0] = fiop->f_acct[1][0]; + old->f_acct[1][1] = fiop->f_acct[1][1]; + old->f_ipf6[0][0] = NULL; + old->f_ipf6[0][1] = NULL; + old->f_ipf6[1][0] = NULL; + old->f_ipf6[1][1] = NULL; + old->f_acct6[0][0] = NULL; + old->f_acct6[0][1] = NULL; + old->f_acct6[1][0] = NULL; + old->f_acct6[1][1] = NULL; + old->f_auth = fiop->f_auth; + bcopy(&fiop->f_groups, &old->f_groups, sizeof(old->f_groups)); + bcopy(&fiop->f_froute, &old->f_froute, sizeof(old->f_froute)); + old->f_ticks = fiop->f_ticks; + bcopy(&fiop->f_locks, &old->f_locks, sizeof(old->f_locks)); + old->f_kmutex_sz = 0; + old->f_krwlock_sz = 0; + old->f_defpass = fiop->f_defpass; + old->f_active = fiop->f_active; + old->f_running = fiop->f_running; + old->f_logging = fiop->f_logging; + old->f_features = fiop->f_features; + sprintf(old->f_version, "IP Filter: v%d.%d.%d", + (rev / 1000000) % 100, + (rev / 10000) % 100, + (rev / 100) % 100); +} + + +static void +friostat_current_to_4_1_0(current, old, rev) + void *current; + friostat_4_1_0_t *old; + int rev; +{ + friostat_t *fiop = (friostat_t *)current; + + bcopy(&fiop->f_st[0].fr_pass, &old->of_st[0], sizeof(old->of_st[0])); + bcopy(&fiop->f_st[1].fr_pass, &old->of_st[1], sizeof(old->of_st[1])); + + old->f_ipf[0][0] = fiop->f_ipf[0][0]; + old->f_ipf[0][1] = fiop->f_ipf[0][1]; + old->f_ipf[1][0] = fiop->f_ipf[1][0]; + old->f_ipf[1][1] = fiop->f_ipf[1][1]; + old->f_acct[0][0] = fiop->f_acct[0][0]; + old->f_acct[0][1] = fiop->f_acct[0][1]; + old->f_acct[1][0] = fiop->f_acct[1][0]; + old->f_acct[1][1] = fiop->f_acct[1][1]; + old->f_ipf6[0][0] = NULL; + old->f_ipf6[0][1] = NULL; + old->f_ipf6[1][0] = NULL; + old->f_ipf6[1][1] = NULL; + old->f_acct6[0][0] = NULL; + old->f_acct6[0][1] = NULL; + old->f_acct6[1][0] = NULL; + old->f_acct6[1][1] = NULL; + old->f_auth = fiop->f_auth; + bcopy(&fiop->f_groups, &old->f_groups, sizeof(old->f_groups)); + bcopy(&fiop->f_froute, &old->f_froute, sizeof(old->f_froute)); + old->f_ticks = fiop->f_ticks; + old->f_ipf[0][0] = fiop->f_ipf[0][0]; + old->f_ipf[0][1] = fiop->f_ipf[0][1]; + old->f_ipf[1][0] = fiop->f_ipf[1][0]; + old->f_ipf[1][1] = fiop->f_ipf[1][1]; + old->f_acct[0][0] = fiop->f_acct[0][0]; + old->f_acct[0][1] = fiop->f_acct[0][1]; + old->f_acct[1][0] = fiop->f_acct[1][0]; + old->f_acct[1][1] = fiop->f_acct[1][1]; + old->f_ipf6[0][0] = NULL; + old->f_ipf6[0][1] = NULL; + old->f_ipf6[1][0] = NULL; + old->f_ipf6[1][1] = NULL; + old->f_acct6[0][0] = NULL; + old->f_acct6[0][1] = NULL; + old->f_acct6[1][0] = NULL; + old->f_acct6[1][1] = NULL; + old->f_auth = fiop->f_auth; + bcopy(&fiop->f_groups, &old->f_groups, sizeof(old->f_groups)); + bcopy(&fiop->f_froute, &old->f_froute, sizeof(old->f_froute)); + old->f_ticks = fiop->f_ticks; + bcopy(&fiop->f_locks, &old->f_locks, sizeof(old->f_locks)); + old->f_kmutex_sz = 0; + old->f_krwlock_sz = 0; + old->f_defpass = fiop->f_defpass; + old->f_active = fiop->f_active; + old->f_running = fiop->f_running; + old->f_logging = fiop->f_logging; + old->f_features = fiop->f_features; + sprintf(old->f_version, "IP Filter: v%d.%d.%d", + (rev / 1000000) % 100, + (rev / 10000) % 100, + (rev / 100) % 100); +} + + +/* + * nflags is v5 flags, returns v4 flags. + */ +static int +fr_frflags5to4(nflags) + u_32_t nflags; +{ + u_32_t oflags = 0; + + switch (nflags & FR_CMDMASK) { + case FR_CALL : + oflags = 0x0; + break; + case FR_BLOCK : + oflags = 0x1; + break; + case FR_PASS : + oflags = 0x2; + break; + case FR_AUTH : + oflags = 0x3; + break; + case FR_PREAUTH : + oflags = 0x4; + break; + case FR_ACCOUNT : + oflags = 0x5; + break; + case FR_SKIP : + oflags = 0x6; + break; + default : + break; + } + + if (nflags & FR_LOG) + oflags |= 0x00010; + if (nflags & FR_CALLNOW) + oflags |= 0x00020; + if (nflags & FR_NOTSRCIP) + oflags |= 0x00080; + if (nflags & FR_NOTDSTIP) + oflags |= 0x00040; + if (nflags & FR_QUICK) + oflags |= 0x00100; + if (nflags & FR_KEEPFRAG) + oflags |= 0x00200; + if (nflags & FR_KEEPSTATE) + oflags |= 0x00400; + if (nflags & FR_FASTROUTE) + oflags |= 0x00800; + if (nflags & FR_RETRST) + oflags |= 0x01000; + if (nflags & FR_RETICMP) + oflags |= 0x02000; + if (nflags & FR_FAKEICMP) + oflags |= 0x03000; + if (nflags & FR_OUTQUE) + oflags |= 0x04000; + if (nflags & FR_INQUE) + oflags |= 0x08000; + if (nflags & FR_LOGBODY) + oflags |= 0x10000; + if (nflags & FR_LOGFIRST) + oflags |= 0x20000; + if (nflags & FR_LOGORBLOCK) + oflags |= 0x40000; + if (nflags & FR_FRSTRICT) + oflags |= 0x100000; + if (nflags & FR_STSTRICT) + oflags |= 0x200000; + if (nflags & FR_NEWISN) + oflags |= 0x400000; + if (nflags & FR_NOICMPERR) + oflags |= 0x800000; + if (nflags & FR_STATESYNC) + oflags |= 0x1000000; + if (nflags & FR_NOMATCH) + oflags |= 0x8000000; + if (nflags & FR_COPIED) + oflags |= 0x40000000; + if (nflags & FR_INACTIVE) + oflags |= 0x80000000; + + return oflags; +} + + +static void +frentry_current_to_4_1_34(current, old) + void *current; + frentry_4_1_34_t *old; +{ + frentry_t *fr = (frentry_t *)current; + + old->fr_lock = fr->fr_lock; + old->fr_next = fr->fr_next; + old->fr_grp = (void *)fr->fr_grp; + old->fr_isc = fr->fr_isc; + old->fr_ifas[0] = fr->fr_ifas[0]; + old->fr_ifas[1] = fr->fr_ifas[1]; + old->fr_ifas[2] = fr->fr_ifas[2]; + old->fr_ifas[3] = fr->fr_ifas[3]; + old->fr_ptr = fr->fr_ptr; + old->fr_comment = NULL; + old->fr_ref = fr->fr_ref; + old->fr_statecnt = fr->fr_statecnt; + old->fr_hits = fr->fr_hits; + old->fr_bytes = fr->fr_bytes; + old->fr_lastpkt.tv_sec = fr->fr_lastpkt.tv_sec; + old->fr_lastpkt.tv_usec = fr->fr_lastpkt.tv_usec; + old->fr_curpps = fr->fr_curpps; + old->fr_dun.fru_data = fr->fr_dun.fru_data; + old->fr_func = fr->fr_func; + old->fr_dsize = fr->fr_dsize; + old->fr_pps = fr->fr_pps; + old->fr_statemax = fr->fr_statemax; + old->fr_flineno = fr->fr_flineno; + old->fr_type = fr->fr_type; + old->fr_flags = fr_frflags5to4(fr->fr_flags); + old->fr_logtag = fr->fr_logtag; + old->fr_collect = fr->fr_collect; + old->fr_arg = fr->fr_arg; + old->fr_loglevel = fr->fr_loglevel; + old->fr_age[0] = fr->fr_age[0]; + old->fr_age[1] = fr->fr_age[1]; + if (fr->fr_family == AF_INET) + old->fr_v = 4; + if (fr->fr_family == AF_INET6) + old->fr_v = 6; + old->fr_icode = fr->fr_icode; + old->fr_cksum = fr->fr_cksum; + old->fr_tifs[0].ofd_ip6 = fr->fr_tifs[0].fd_ip6; + old->fr_tifs[1].ofd_ip6 = fr->fr_tifs[0].fd_ip6; + old->fr_dif.ofd_ip6 = fr->fr_dif.fd_ip6; + if (fr->fr_ifnames[0] >= 0) { + strncpy(old->fr_ifnames[0], fr->fr_names + fr->fr_ifnames[0], + LIFNAMSIZ); + old->fr_ifnames[0][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[1] >= 0) { + strncpy(old->fr_ifnames[1], fr->fr_names + fr->fr_ifnames[1], + LIFNAMSIZ); + old->fr_ifnames[1][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[2] >= 0) { + strncpy(old->fr_ifnames[2], fr->fr_names + fr->fr_ifnames[2], + LIFNAMSIZ); + old->fr_ifnames[2][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[3] >= 0) { + strncpy(old->fr_ifnames[3], fr->fr_names + fr->fr_ifnames[3], + LIFNAMSIZ); + old->fr_ifnames[3][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_tifs[0].fd_name >= 0) { + strncpy(old->fr_tifs[0].fd_ifname, + fr->fr_names + fr->fr_tifs[0].fd_name, LIFNAMSIZ); + old->fr_tifs[0].fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_tifs[1].fd_name >= 0) { + strncpy(old->fr_tifs[1].fd_ifname, + fr->fr_names + fr->fr_tifs[1].fd_name, LIFNAMSIZ); + old->fr_tifs[1].fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_dif.fd_name >= 0) { + strncpy(old->fr_dif.fd_ifname, + fr->fr_names + fr->fr_dif.fd_name, LIFNAMSIZ); + old->fr_dif.fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_group >= 0) { + strncpy(old->fr_group, fr->fr_names + fr->fr_group, + FR_GROUPLEN); + old->fr_group[FR_GROUPLEN - 1] = '\0'; + } + if (fr->fr_grhead >= 0) { + strncpy(old->fr_grhead, fr->fr_names + fr->fr_grhead, + FR_GROUPLEN); + old->fr_grhead[FR_GROUPLEN - 1] = '\0'; + } +} + + +static void +frentry_current_to_4_1_16(current, old) + void *current; + frentry_4_1_16_t *old; +{ + frentry_t *fr = (frentry_t *)current; + + old->fr_lock = fr->fr_lock; + old->fr_next = fr->fr_next; + old->fr_grp = (void *)fr->fr_grp; + old->fr_isc = fr->fr_isc; + old->fr_ifas[0] = fr->fr_ifas[0]; + old->fr_ifas[1] = fr->fr_ifas[1]; + old->fr_ifas[2] = fr->fr_ifas[2]; + old->fr_ifas[3] = fr->fr_ifas[3]; + old->fr_ptr = fr->fr_ptr; + old->fr_comment = NULL; + old->fr_ref = fr->fr_ref; + old->fr_statecnt = fr->fr_statecnt; + old->fr_hits = fr->fr_hits; + old->fr_bytes = fr->fr_bytes; + old->fr_lastpkt.tv_sec = fr->fr_lastpkt.tv_sec; + old->fr_lastpkt.tv_usec = fr->fr_lastpkt.tv_usec; + old->fr_curpps = fr->fr_curpps; + old->fr_dun.fru_data = fr->fr_dun.fru_data; + old->fr_func = fr->fr_func; + old->fr_dsize = fr->fr_dsize; + old->fr_pps = fr->fr_pps; + old->fr_statemax = fr->fr_statemax; + old->fr_flineno = fr->fr_flineno; + old->fr_type = fr->fr_type; + old->fr_flags = fr_frflags5to4(fr->fr_flags); + old->fr_logtag = fr->fr_logtag; + old->fr_collect = fr->fr_collect; + old->fr_arg = fr->fr_arg; + old->fr_loglevel = fr->fr_loglevel; + old->fr_age[0] = fr->fr_age[0]; + old->fr_age[1] = fr->fr_age[1]; + if (old->fr_v == 4) + fr->fr_family = AF_INET; + if (old->fr_v == 6) + fr->fr_family = AF_INET6; + old->fr_icode = fr->fr_icode; + old->fr_cksum = fr->fr_cksum; + old->fr_tifs[0].ofd_ip6 = fr->fr_tifs[0].fd_ip6; + old->fr_tifs[1].ofd_ip6 = fr->fr_tifs[0].fd_ip6; + old->fr_dif.ofd_ip6 = fr->fr_dif.fd_ip6; + if (fr->fr_ifnames[0] >= 0) { + strncpy(old->fr_ifnames[0], fr->fr_names + fr->fr_ifnames[0], + LIFNAMSIZ); + old->fr_ifnames[0][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[1] >= 0) { + strncpy(old->fr_ifnames[1], fr->fr_names + fr->fr_ifnames[1], + LIFNAMSIZ); + old->fr_ifnames[1][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[2] >= 0) { + strncpy(old->fr_ifnames[2], fr->fr_names + fr->fr_ifnames[2], + LIFNAMSIZ); + old->fr_ifnames[2][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[3] >= 0) { + strncpy(old->fr_ifnames[3], fr->fr_names + fr->fr_ifnames[3], + LIFNAMSIZ); + old->fr_ifnames[3][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_tifs[0].fd_name >= 0) { + strncpy(old->fr_tifs[0].fd_ifname, + fr->fr_names + fr->fr_tifs[0].fd_name, LIFNAMSIZ); + old->fr_tifs[0].fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_tifs[1].fd_name >= 0) { + strncpy(old->fr_tifs[1].fd_ifname, + fr->fr_names + fr->fr_tifs[1].fd_name, LIFNAMSIZ); + old->fr_tifs[1].fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_dif.fd_name >= 0) { + strncpy(old->fr_dif.fd_ifname, + fr->fr_names + fr->fr_dif.fd_name, LIFNAMSIZ); + old->fr_dif.fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_group >= 0) { + strncpy(old->fr_group, fr->fr_names + fr->fr_group, + FR_GROUPLEN); + old->fr_group[FR_GROUPLEN - 1] = '\0'; + } + if (fr->fr_grhead >= 0) { + strncpy(old->fr_grhead, fr->fr_names + fr->fr_grhead, + FR_GROUPLEN); + old->fr_grhead[FR_GROUPLEN - 1] = '\0'; + } +} + + +static void +frentry_current_to_4_1_0(current, old) + void *current; + frentry_4_1_0_t *old; +{ + frentry_t *fr = (frentry_t *)current; + + old->fr_lock = fr->fr_lock; + old->fr_next = fr->fr_next; + old->fr_grp = (void *)fr->fr_grp; + old->fr_isc = fr->fr_isc; + old->fr_ifas[0] = fr->fr_ifas[0]; + old->fr_ifas[1] = fr->fr_ifas[1]; + old->fr_ifas[2] = fr->fr_ifas[2]; + old->fr_ifas[3] = fr->fr_ifas[3]; + old->fr_ptr = fr->fr_ptr; + old->fr_comment = NULL; + old->fr_ref = fr->fr_ref; + old->fr_statecnt = fr->fr_statecnt; + old->fr_hits = fr->fr_hits; + old->fr_bytes = fr->fr_bytes; + old->fr_lastpkt.tv_sec = fr->fr_lastpkt.tv_sec; + old->fr_lastpkt.tv_usec = fr->fr_lastpkt.tv_usec; + old->fr_curpps = fr->fr_curpps; + old->fr_dun.fru_data = fr->fr_dun.fru_data; + old->fr_func = fr->fr_func; + old->fr_dsize = fr->fr_dsize; + old->fr_pps = fr->fr_pps; + old->fr_statemax = fr->fr_statemax; + old->fr_flineno = fr->fr_flineno; + old->fr_type = fr->fr_type; + old->fr_flags = fr_frflags5to4(fr->fr_flags); + old->fr_logtag = fr->fr_logtag; + old->fr_collect = fr->fr_collect; + old->fr_arg = fr->fr_arg; + old->fr_loglevel = fr->fr_loglevel; + old->fr_age[0] = fr->fr_age[0]; + old->fr_age[1] = fr->fr_age[1]; + if (old->fr_v == 4) + fr->fr_family = AF_INET; + if (old->fr_v == 6) + fr->fr_family = AF_INET6; + old->fr_icode = fr->fr_icode; + old->fr_cksum = fr->fr_cksum; + old->fr_tifs[0].ofd_ip6 = fr->fr_tifs[0].fd_ip6; + old->fr_tifs[1].ofd_ip6 = fr->fr_tifs[0].fd_ip6; + old->fr_dif.ofd_ip6 = fr->fr_dif.fd_ip6; + if (fr->fr_ifnames[0] >= 0) { + strncpy(old->fr_ifnames[0], fr->fr_names + fr->fr_ifnames[0], + LIFNAMSIZ); + old->fr_ifnames[0][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[1] >= 0) { + strncpy(old->fr_ifnames[1], fr->fr_names + fr->fr_ifnames[1], + LIFNAMSIZ); + old->fr_ifnames[1][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[2] >= 0) { + strncpy(old->fr_ifnames[2], fr->fr_names + fr->fr_ifnames[2], + LIFNAMSIZ); + old->fr_ifnames[2][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_ifnames[3] >= 0) { + strncpy(old->fr_ifnames[3], fr->fr_names + fr->fr_ifnames[3], + LIFNAMSIZ); + old->fr_ifnames[3][LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_tifs[0].fd_name >= 0) { + strncpy(old->fr_tifs[0].fd_ifname, + fr->fr_names + fr->fr_tifs[0].fd_name, LIFNAMSIZ); + old->fr_tifs[0].fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_tifs[1].fd_name >= 0) { + strncpy(old->fr_tifs[1].fd_ifname, + fr->fr_names + fr->fr_tifs[1].fd_name, LIFNAMSIZ); + old->fr_tifs[1].fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_dif.fd_name >= 0) { + strncpy(old->fr_dif.fd_ifname, + fr->fr_names + fr->fr_dif.fd_name, LIFNAMSIZ); + old->fr_dif.fd_ifname[LIFNAMSIZ - 1] = '\0'; + } + if (fr->fr_group >= 0) { + strncpy(old->fr_group, fr->fr_names + fr->fr_group, + FR_GROUPLEN); + old->fr_group[FR_GROUPLEN - 1] = '\0'; + } + if (fr->fr_grhead >= 0) { + strncpy(old->fr_grhead, fr->fr_names + fr->fr_grhead, + FR_GROUPLEN); + old->fr_grhead[FR_GROUPLEN - 1] = '\0'; + } +} + + +static void +fr_info_current_to_4_1_24(current, old) + void *current; + fr_info_4_1_24_t *old; +{ + fr_info_t *fin = (fr_info_t *)current; + + old->fin_ifp = fin->fin_ifp; + ipf_v5iptov4(&fin->fin_fi, &old->fin_fi); + bcopy(&fin->fin_dat, &old->fin_dat, sizeof(fin->fin_dat)); + old->fin_out = fin->fin_out; + old->fin_rev = fin->fin_rev; + old->fin_hlen = fin->fin_hlen; + old->ofin_tcpf = fin->fin_tcpf; + old->fin_icode = fin->fin_icode; + old->fin_rule = fin->fin_rule; + bcopy(fin->fin_group, old->fin_group, sizeof(fin->fin_group)); + old->fin_fr = fin->fin_fr; + old->fin_dp = fin->fin_dp; + old->fin_dlen = fin->fin_dlen; + old->fin_plen = fin->fin_plen; + old->fin_ipoff = fin->fin_ipoff; + old->fin_id = fin->fin_id; + old->fin_off = fin->fin_off; + old->fin_depth = fin->fin_depth; + old->fin_error = fin->fin_error; + old->fin_cksum = fin->fin_cksum; + old->fin_state = NULL; + old->fin_nat = NULL; + old->fin_nattag = fin->fin_nattag; + old->fin_exthdr = NULL; + old->ofin_ip = fin->fin_ip; + old->fin_mp = fin->fin_mp; + old->fin_m = fin->fin_m; +#ifdef MENTAT + old->fin_qfm = fin->fin_qfm; + old->fin_qpi = fin->fin_qpi; + old->fin_ifname[0] = '\0'; +#endif +#ifdef __sgi + old->fin_hbuf = fin->fin_hbuf; +#endif +} + + +static void +fr_info_current_to_4_1_23(current, old) + void *current; + fr_info_4_1_23_t *old; +{ + fr_info_t *fin = (fr_info_t *)current; + + old->fin_ifp = fin->fin_ifp; + ipf_v5iptov4(&fin->fin_fi, &old->fin_fi); + bcopy(&fin->fin_dat, &old->fin_dat, sizeof(fin->fin_dat)); + old->fin_out = fin->fin_out; + old->fin_rev = fin->fin_rev; + old->fin_hlen = fin->fin_hlen; + old->ofin_tcpf = fin->fin_tcpf; + old->fin_icode = fin->fin_icode; + old->fin_rule = fin->fin_rule; + bcopy(fin->fin_group, old->fin_group, sizeof(fin->fin_group)); + old->fin_fr = fin->fin_fr; + old->fin_dp = fin->fin_dp; + old->fin_dlen = fin->fin_dlen; + old->fin_plen = fin->fin_plen; + old->fin_ipoff = fin->fin_ipoff; + old->fin_id = fin->fin_id; + old->fin_off = fin->fin_off; + old->fin_depth = fin->fin_depth; + old->fin_error = fin->fin_error; + old->fin_state = NULL; + old->fin_nat = NULL; + old->fin_nattag = fin->fin_nattag; + old->ofin_ip = fin->fin_ip; + old->fin_mp = fin->fin_mp; + old->fin_m = fin->fin_m; +#ifdef MENTAT + old->fin_qfm = fin->fin_qfm; + old->fin_qpi = fin->fin_qpi; + old->fin_ifname[0] = '\0'; +#endif +#ifdef __sgi + old->fin_hbuf = fin->fin_hbuf; +#endif +} + + +static void +fr_info_current_to_4_1_11(current, old) + void *current; + fr_info_4_1_11_t *old; +{ + fr_info_t *fin = (fr_info_t *)current; + + old->fin_ifp = fin->fin_ifp; + ipf_v5iptov4(&fin->fin_fi, &old->fin_fi); + bcopy(&fin->fin_dat, &old->fin_dat, sizeof(fin->fin_dat)); + old->fin_out = fin->fin_out; + old->fin_rev = fin->fin_rev; + old->fin_hlen = fin->fin_hlen; + old->ofin_tcpf = fin->fin_tcpf; + old->fin_icode = fin->fin_icode; + old->fin_rule = fin->fin_rule; + bcopy(fin->fin_group, old->fin_group, sizeof(fin->fin_group)); + old->fin_fr = fin->fin_fr; + old->fin_dp = fin->fin_dp; + old->fin_dlen = fin->fin_dlen; + old->fin_plen = fin->fin_plen; + old->fin_ipoff = fin->fin_ipoff; + old->fin_id = fin->fin_id; + old->fin_off = fin->fin_off; + old->fin_depth = fin->fin_depth; + old->fin_error = fin->fin_error; + old->fin_state = NULL; + old->fin_nat = NULL; + old->fin_nattag = fin->fin_nattag; + old->ofin_ip = fin->fin_ip; + old->fin_mp = fin->fin_mp; + old->fin_m = fin->fin_m; +#ifdef MENTAT + old->fin_qfm = fin->fin_qfm; + old->fin_qpi = fin->fin_qpi; + old->fin_ifname[0] = '\0'; +#endif +#ifdef __sgi + old->fin_hbuf = fin->fin_hbuf; +#endif +} + + +static void +frauth_current_to_4_1_29(current, old) + void *current; + frauth_4_1_29_t *old; +{ + frauth_t *fra = (frauth_t *)current; + + old->fra_age = fra->fra_age; + old->fra_len = fra->fra_len; + old->fra_index = fra->fra_index; + old->fra_pass = fra->fra_pass; + fr_info_current_to_4_1_24(&fra->fra_info, &old->fra_info); + old->fra_buf = fra->fra_buf; + old->fra_flx = fra->fra_flx; +#ifdef MENTAT + old->fra_q = fra->fra_q; + old->fra_m = fra->fra_m; +#endif +} + + +static void +frauth_current_to_4_1_24(current, old) + void *current; + frauth_4_1_24_t *old; +{ + frauth_t *fra = (frauth_t *)current; + + old->fra_age = fra->fra_age; + old->fra_len = fra->fra_len; + old->fra_index = fra->fra_index; + old->fra_pass = fra->fra_pass; + fr_info_current_to_4_1_24(&fra->fra_info, &old->fra_info); + old->fra_buf = fra->fra_buf; +#ifdef MENTAT + old->fra_q = fra->fra_q; + old->fra_m = fra->fra_m; +#endif +} + + +static void +frauth_current_to_4_1_23(current, old) + void *current; + frauth_4_1_23_t *old; +{ + frauth_t *fra = (frauth_t *)current; + + old->fra_age = fra->fra_age; + old->fra_len = fra->fra_len; + old->fra_index = fra->fra_index; + old->fra_pass = fra->fra_pass; + fr_info_current_to_4_1_23(&fra->fra_info, &old->fra_info); + old->fra_buf = fra->fra_buf; +#ifdef MENTAT + old->fra_q = fra->fra_q; + old->fra_m = fra->fra_m; +#endif +} + + +static void +frauth_current_to_4_1_11(current, old) + void *current; + frauth_4_1_11_t *old; +{ + frauth_t *fra = (frauth_t *)current; + + old->fra_age = fra->fra_age; + old->fra_len = fra->fra_len; + old->fra_index = fra->fra_index; + old->fra_pass = fra->fra_pass; + fr_info_current_to_4_1_11(&fra->fra_info, &old->fra_info); + old->fra_buf = fra->fra_buf; +#ifdef MENTAT + old->fra_q = fra->fra_q; + old->fra_m = fra->fra_m; +#endif +} + + +static void +ipnat_current_to_4_1_14(current, old) + void *current; + ipnat_4_1_14_t *old; +{ + ipnat_t *np = (ipnat_t *)current; + + old->in_next = np->in_next; + old->in_rnext = np->in_rnext; + old->in_prnext = np->in_prnext; + old->in_mnext = np->in_mnext; + old->in_pmnext = np->in_pmnext; + old->in_tqehead[0] = np->in_tqehead[0]; + old->in_tqehead[1] = np->in_tqehead[1]; + old->in_ifps[0] = np->in_ifps[0]; + old->in_ifps[1] = np->in_ifps[1]; + old->in_apr = np->in_apr; + old->in_comment = np->in_comment; + old->in_space = np->in_space; + old->in_hits = np->in_hits; + old->in_use = np->in_use; + old->in_hv = np->in_hv[0]; + old->in_flineno = np->in_flineno; + if (old->in_redir == NAT_REDIRECT) + old->in_pnext = np->in_dpnext; + else + old->in_pnext = np->in_spnext; + old->in_v = np->in_v[0]; + old->in_flags = np->in_flags; + old->in_mssclamp = np->in_mssclamp; + old->in_age[0] = np->in_age[0]; + old->in_age[1] = np->in_age[1]; + old->in_redir = np->in_redir; + old->in_p = np->in_pr[0]; + if (np->in_redir == NAT_REDIRECT) { + old->in_next6 = np->in_ndst.na_nextaddr; + old->in_in[0] = np->in_ndst.na_addr[0]; + old->in_in[1] = np->in_ndst.na_addr[1]; + old->in_out[0] = np->in_odst.na_addr[0]; + old->in_out[1] = np->in_odst.na_addr[1]; + old->in_src[0] = np->in_osrc.na_addr[0]; + old->in_src[1] = np->in_osrc.na_addr[1]; + } else { + old->in_next6 = np->in_nsrc.na_nextaddr; + old->in_out[0] = np->in_nsrc.na_addr[0]; + old->in_out[1] = np->in_nsrc.na_addr[1]; + old->in_in[0] = np->in_osrc.na_addr[0]; + old->in_in[1] = np->in_osrc.na_addr[1]; + old->in_src[0] = np->in_odst.na_addr[0]; + old->in_src[1] = np->in_odst.na_addr[1]; + } + ipfv5tuctov4(&np->in_tuc, &old->in_tuc); + if (np->in_redir == NAT_REDIRECT) { + old->in_port[0] = np->in_dpmin; + old->in_port[1] = np->in_dpmax; + } else { + old->in_port[0] = np->in_spmin; + old->in_port[1] = np->in_spmax; + } + old->in_ppip = np->in_ppip; + old->in_ippip = np->in_ippip; + bcopy(&np->in_tag, &old->in_tag, sizeof(np->in_tag)); + + if (np->in_ifnames[0] >= 0) { + strncpy(old->in_ifnames[0], np->in_names + np->in_ifnames[0], + LIFNAMSIZ); + old->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; + } + if (np->in_ifnames[1] >= 0) { + strncpy(old->in_ifnames[1], np->in_names + np->in_ifnames[1], + LIFNAMSIZ); + old->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; + } + if (np->in_plabel >= 0) { + strncpy(old->in_plabel, np->in_names + np->in_plabel, + APR_LABELLEN); + old->in_plabel[APR_LABELLEN - 1] = '\0'; + } +} + + +static void +ipnat_current_to_4_1_0(current, old) + void *current; + ipnat_4_1_0_t *old; +{ + ipnat_t *np = (ipnat_t *)current; + + old->in_next = np->in_next; + old->in_rnext = np->in_rnext; + old->in_prnext = np->in_prnext; + old->in_mnext = np->in_mnext; + old->in_pmnext = np->in_pmnext; + old->in_tqehead[0] = np->in_tqehead[0]; + old->in_tqehead[1] = np->in_tqehead[1]; + old->in_ifps[0] = np->in_ifps[0]; + old->in_ifps[1] = np->in_ifps[1]; + old->in_apr = np->in_apr; + old->in_comment = np->in_comment; + old->in_space = np->in_space; + old->in_hits = np->in_hits; + old->in_use = np->in_use; + old->in_hv = np->in_hv[0]; + old->in_flineno = np->in_flineno; + if (old->in_redir == NAT_REDIRECT) + old->in_pnext = np->in_dpnext; + else + old->in_pnext = np->in_spnext; + old->in_v = np->in_v[0]; + old->in_flags = np->in_flags; + old->in_mssclamp = np->in_mssclamp; + old->in_age[0] = np->in_age[0]; + old->in_age[1] = np->in_age[1]; + old->in_redir = np->in_redir; + old->in_p = np->in_pr[0]; + if (np->in_redir == NAT_REDIRECT) { + old->in_next6 = np->in_ndst.na_nextaddr; + old->in_in[0] = np->in_ndst.na_addr[0]; + old->in_in[1] = np->in_ndst.na_addr[1]; + old->in_out[0] = np->in_odst.na_addr[0]; + old->in_out[1] = np->in_odst.na_addr[1]; + old->in_src[0] = np->in_osrc.na_addr[0]; + old->in_src[1] = np->in_osrc.na_addr[1]; + } else { + old->in_next6 = np->in_nsrc.na_nextaddr; + old->in_out[0] = np->in_nsrc.na_addr[0]; + old->in_out[1] = np->in_nsrc.na_addr[1]; + old->in_in[0] = np->in_osrc.na_addr[0]; + old->in_in[1] = np->in_osrc.na_addr[1]; + old->in_src[0] = np->in_odst.na_addr[0]; + old->in_src[1] = np->in_odst.na_addr[1]; + } + ipfv5tuctov4(&np->in_tuc, &old->in_tuc); + if (np->in_redir == NAT_REDIRECT) { + old->in_port[0] = np->in_dpmin; + old->in_port[1] = np->in_dpmax; + } else { + old->in_port[0] = np->in_spmin; + old->in_port[1] = np->in_spmax; + } + old->in_ppip = np->in_ppip; + old->in_ippip = np->in_ippip; + bcopy(&np->in_tag, &old->in_tag, sizeof(np->in_tag)); + + if (np->in_ifnames[0] >= 0) { + strncpy(old->in_ifnames[0], np->in_names + np->in_ifnames[0], + LIFNAMSIZ); + old->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; + } + if (np->in_ifnames[1] >= 0) { + strncpy(old->in_ifnames[1], np->in_names + np->in_ifnames[1], + LIFNAMSIZ); + old->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; + } + if (np->in_plabel >= 0) { + strncpy(old->in_plabel, np->in_names + np->in_plabel, + APR_LABELLEN); + old->in_plabel[APR_LABELLEN - 1] = '\0'; + } +} + + +static void +ipstate_current_to_4_1_16(current, old) + void *current; + ipstate_4_1_16_t *old; +{ + ipstate_t *is = (ipstate_t *)current; + + old->is_lock = is->is_lock; + old->is_next = is->is_next; + old->is_pnext = is->is_pnext; + old->is_hnext = is->is_hnext; + old->is_phnext = is->is_phnext; + old->is_me = is->is_me; + old->is_ifp[0] = is->is_ifp[0]; + old->is_ifp[1] = is->is_ifp[1]; + old->is_sync = is->is_sync; + old->is_rule = is->is_rule; + old->is_tqehead[0] = is->is_tqehead[0]; + old->is_tqehead[1] = is->is_tqehead[1]; + old->is_isc = is->is_isc; + old->is_pkts[0] = is->is_pkts[0]; + old->is_pkts[1] = is->is_pkts[1]; + old->is_pkts[2] = is->is_pkts[2]; + old->is_pkts[3] = is->is_pkts[3]; + old->is_bytes[0] = is->is_bytes[0]; + old->is_bytes[1] = is->is_bytes[1]; + old->is_bytes[2] = is->is_bytes[2]; + old->is_bytes[3] = is->is_bytes[3]; + old->is_icmppkts[0] = is->is_icmppkts[0]; + old->is_icmppkts[1] = is->is_icmppkts[1]; + old->is_icmppkts[2] = is->is_icmppkts[2]; + old->is_icmppkts[3] = is->is_icmppkts[3]; + old->is_sti = is->is_sti; + old->is_frage[0] = is->is_frage[0]; + old->is_frage[1] = is->is_frage[1]; + old->is_ref = is->is_ref; + old->is_isninc[0] = is->is_isninc[0]; + old->is_isninc[1] = is->is_isninc[1]; + old->is_sumd[0] = is->is_sumd[0]; + old->is_sumd[1] = is->is_sumd[1]; + old->is_src = is->is_src; + old->is_dst = is->is_dst; + old->is_pass = is->is_pass; + old->is_p = is->is_p; + old->is_v = is->is_v; + old->is_hv = is->is_hv; + old->is_tag = is->is_tag; + old->is_opt[0] = is->is_opt[0]; + old->is_opt[1] = is->is_opt[1]; + old->is_optmsk[0] = is->is_optmsk[0]; + old->is_optmsk[1] = is->is_optmsk[1]; + old->is_sec = is->is_sec; + old->is_secmsk = is->is_secmsk; + old->is_auth = is->is_auth; + old->is_authmsk = is->is_authmsk; + ipf_v5tcpinfoto4(&is->is_tcp, &old->is_tcp); + old->is_flags = is->is_flags; + old->is_flx[0][0] = is->is_flx[0][0]; + old->is_flx[0][1] = is->is_flx[0][1]; + old->is_flx[1][0] = is->is_flx[1][0]; + old->is_flx[1][1] = is->is_flx[1][1]; + old->is_rulen = is->is_rulen; + old->is_s0[0] = is->is_s0[0]; + old->is_s0[1] = is->is_s0[1]; + old->is_smsk[0] = is->is_smsk[0]; + old->is_smsk[1] = is->is_smsk[1]; + bcopy(is->is_group, old->is_group, sizeof(is->is_group)); + bcopy(is->is_sbuf, old->is_sbuf, sizeof(is->is_sbuf)); + bcopy(is->is_ifname, old->is_ifname, sizeof(is->is_ifname)); +} + + +static void +ipstate_current_to_4_1_0(current, old) + void *current; + ipstate_4_1_0_t *old; +{ + ipstate_t *is = (ipstate_t *)current; + + old->is_lock = is->is_lock; + old->is_next = is->is_next; + old->is_pnext = is->is_pnext; + old->is_hnext = is->is_hnext; + old->is_phnext = is->is_phnext; + old->is_me = is->is_me; + old->is_ifp[0] = is->is_ifp[0]; + old->is_ifp[1] = is->is_ifp[1]; + old->is_sync = is->is_sync; + bzero(&old->is_nat, sizeof(old->is_nat)); + old->is_rule = is->is_rule; + old->is_tqehead[0] = is->is_tqehead[0]; + old->is_tqehead[1] = is->is_tqehead[1]; + old->is_isc = is->is_isc; + old->is_pkts[0] = is->is_pkts[0]; + old->is_pkts[1] = is->is_pkts[1]; + old->is_pkts[2] = is->is_pkts[2]; + old->is_pkts[3] = is->is_pkts[3]; + old->is_bytes[0] = is->is_bytes[0]; + old->is_bytes[1] = is->is_bytes[1]; + old->is_bytes[2] = is->is_bytes[2]; + old->is_bytes[3] = is->is_bytes[3]; + old->is_icmppkts[0] = is->is_icmppkts[0]; + old->is_icmppkts[1] = is->is_icmppkts[1]; + old->is_icmppkts[2] = is->is_icmppkts[2]; + old->is_icmppkts[3] = is->is_icmppkts[3]; + old->is_sti = is->is_sti; + old->is_frage[0] = is->is_frage[0]; + old->is_frage[1] = is->is_frage[1]; + old->is_ref = is->is_ref; + old->is_isninc[0] = is->is_isninc[0]; + old->is_isninc[1] = is->is_isninc[1]; + old->is_sumd[0] = is->is_sumd[0]; + old->is_sumd[1] = is->is_sumd[1]; + old->is_src = is->is_src; + old->is_dst = is->is_dst; + old->is_pass = is->is_pass; + old->is_p = is->is_p; + old->is_v = is->is_v; + old->is_hv = is->is_hv; + old->is_tag = is->is_tag; + old->is_opt[0] = is->is_opt[0]; + old->is_opt[1] = is->is_opt[1]; + old->is_optmsk[0] = is->is_optmsk[0]; + old->is_optmsk[1] = is->is_optmsk[1]; + old->is_sec = is->is_sec; + old->is_secmsk = is->is_secmsk; + old->is_auth = is->is_auth; + old->is_authmsk = is->is_authmsk; + ipf_v5tcpinfoto4(&is->is_tcp, &old->is_tcp); + old->is_flags = is->is_flags; + old->is_flx[0][0] = is->is_flx[0][0]; + old->is_flx[0][1] = is->is_flx[0][1]; + old->is_flx[1][0] = is->is_flx[1][0]; + old->is_flx[1][1] = is->is_flx[1][1]; + old->is_rulen = is->is_rulen; + old->is_s0[0] = is->is_s0[0]; + old->is_s0[1] = is->is_s0[1]; + old->is_smsk[0] = is->is_smsk[0]; + old->is_smsk[1] = is->is_smsk[1]; + bcopy(is->is_group, old->is_group, sizeof(is->is_group)); + bcopy(is->is_sbuf, old->is_sbuf, sizeof(is->is_sbuf)); + bcopy(is->is_ifname, old->is_ifname, sizeof(is->is_ifname)); +} + + +static void +ips_stat_current_to_4_1_21(current, old) + void *current; + ips_stat_4_1_21_t *old; +{ + ips_stat_t *st = (ips_stat_t *)current; + + old->iss_hits = st->iss_hits; + old->iss_miss = st->iss_check_miss; + old->iss_max = st->iss_max; + old->iss_maxref = st->iss_max_ref; + old->iss_tcp = st->iss_proto[IPPROTO_TCP]; + old->iss_udp = st->iss_proto[IPPROTO_UDP]; + old->iss_icmp = st->iss_proto[IPPROTO_ICMP]; + old->iss_nomem = st->iss_nomem; + old->iss_expire = st->iss_expire; + old->iss_fin = st->iss_fin; + old->iss_active = st->iss_active; + old->iss_logged = st->iss_log_ok; + old->iss_logfail = st->iss_log_fail; + old->iss_inuse = st->iss_inuse; + old->iss_wild = st->iss_wild; + old->iss_ticks = st->iss_ticks; + old->iss_bucketfull = st->iss_bucket_full; + old->iss_statesize = st->iss_state_size; + old->iss_statemax = st->iss_state_max; + old->iss_table = st->iss_table; + old->iss_list = st->iss_list; + old->iss_bucketlen = (void *)st->iss_bucketlen; + old->iss_tcptab = st->iss_tcptab; +} + + +static void +ips_stat_current_to_4_1_0(current, old) + void *current; + ips_stat_4_1_0_t *old; +{ + ips_stat_t *st = (ips_stat_t *)current; + + old->iss_hits = st->iss_hits; + old->iss_miss = st->iss_check_miss; + old->iss_max = st->iss_max; + old->iss_maxref = st->iss_max_ref; + old->iss_tcp = st->iss_proto[IPPROTO_TCP]; + old->iss_udp = st->iss_proto[IPPROTO_UDP]; + old->iss_icmp = st->iss_proto[IPPROTO_ICMP]; + old->iss_nomem = st->iss_nomem; + old->iss_expire = st->iss_expire; + old->iss_fin = st->iss_fin; + old->iss_active = st->iss_active; + old->iss_logged = st->iss_log_ok; + old->iss_logfail = st->iss_log_fail; + old->iss_inuse = st->iss_inuse; + old->iss_wild = st->iss_wild; + old->iss_ticks = st->iss_ticks; + old->iss_bucketfull = st->iss_bucket_full; + old->iss_statesize = st->iss_state_size; + old->iss_statemax = st->iss_state_max; + old->iss_table = st->iss_table; + old->iss_list = st->iss_list; + old->iss_bucketlen = (void *)st->iss_bucketlen; +} + + +static void +nat_save_current_to_4_1_16(current, old) + void *current; + nat_save_4_1_16_t *old; +{ + nat_save_t *nats = (nat_save_t *)current; + + old->ipn_next = nats->ipn_next; + bcopy(&nats->ipn_nat, &old->ipn_nat, sizeof(old->ipn_nat)); + bcopy(&nats->ipn_ipnat, &old->ipn_ipnat, sizeof(old->ipn_ipnat)); + frentry_current_to_4_1_16(&nats->ipn_fr, &old->ipn_fr); + old->ipn_dsize = nats->ipn_dsize; + bcopy(nats->ipn_data, old->ipn_data, sizeof(nats->ipn_data)); +} + + +static void +nat_save_current_to_4_1_14(current, old) + void *current; + nat_save_4_1_14_t *old; +{ + nat_save_t *nats = (nat_save_t *)current; + + old->ipn_next = nats->ipn_next; + bcopy(&nats->ipn_nat, &old->ipn_nat, sizeof(old->ipn_nat)); + bcopy(&nats->ipn_ipnat, &old->ipn_ipnat, sizeof(old->ipn_ipnat)); + frentry_current_to_4_1_0(&nats->ipn_fr, &old->ipn_fr); + old->ipn_dsize = nats->ipn_dsize; + bcopy(nats->ipn_data, old->ipn_data, sizeof(nats->ipn_data)); +} + + +static void +nat_save_current_to_4_1_3(current, old) + void *current; + nat_save_4_1_3_t *old; +{ + nat_save_t *nats = (nat_save_t *)current; + + old->ipn_next = nats->ipn_next; + bcopy(&nats->ipn_nat, &old->ipn_nat, sizeof(old->ipn_nat)); + bcopy(&nats->ipn_ipnat, &old->ipn_ipnat, sizeof(old->ipn_ipnat)); + frentry_current_to_4_1_0(&nats->ipn_fr, &old->ipn_fr); + old->ipn_dsize = nats->ipn_dsize; + bcopy(nats->ipn_data, old->ipn_data, sizeof(nats->ipn_data)); +} + + +static void +nat_current_to_4_1_25(current, old) + void *current; + nat_4_1_25_t *old; +{ + nat_t *nat = (nat_t *)current; + + old->nat_lock = nat->nat_lock; + old->nat_next = (void *)nat->nat_next; + old->nat_pnext = (void *)nat->nat_pnext; + old->nat_hnext[0] = (void *)nat->nat_hnext[0]; + old->nat_hnext[1] = (void *)nat->nat_hnext[1]; + old->nat_phnext[0] = (void *)nat->nat_phnext[0]; + old->nat_phnext[1] = (void *)nat->nat_phnext[1]; + old->nat_hm = nat->nat_hm; + old->nat_data = nat->nat_data; + old->nat_me = (void *)nat->nat_me; + old->nat_state = nat->nat_state; + old->nat_aps = nat->nat_aps; + old->nat_fr = nat->nat_fr; + old->nat_ptr = (void *)nat->nat_ptr; + old->nat_ifps[0] = nat->nat_ifps[0]; + old->nat_ifps[1] = nat->nat_ifps[1]; + old->nat_sync = nat->nat_sync; + old->nat_tqe = nat->nat_tqe; + old->nat_flags = nat->nat_flags; + old->nat_sumd[0] = nat->nat_sumd[0]; + old->nat_sumd[1] = nat->nat_sumd[1]; + old->nat_ipsumd = nat->nat_ipsumd; + old->nat_mssclamp = nat->nat_mssclamp; + old->nat_pkts[0] = nat->nat_pkts[0]; + old->nat_pkts[1] = nat->nat_pkts[1]; + old->nat_bytes[0] = nat->nat_bytes[0]; + old->nat_bytes[1] = nat->nat_bytes[1]; + old->nat_ref = nat->nat_ref; + old->nat_dir = nat->nat_dir; + old->nat_p = nat->nat_pr[0]; + old->nat_use = nat->nat_use; + old->nat_hv[0] = nat->nat_hv[0]; + old->nat_hv[1] = nat->nat_hv[1]; + old->nat_rev = nat->nat_rev; + old->nat_redir = nat->nat_redir; + bcopy(nat->nat_ifnames[0], old->nat_ifnames[0], LIFNAMSIZ); + bcopy(nat->nat_ifnames[1], old->nat_ifnames[1], LIFNAMSIZ); + + if (nat->nat_redir == NAT_REDIRECT) { + old->nat_inip6 = nat->nat_ndst6; + old->nat_outip6 = nat->nat_odst6; + old->nat_oip6 = nat->nat_osrc6; + old->nat_un.nat_unt.ts_sport = nat->nat_ndport; + old->nat_un.nat_unt.ts_dport = nat->nat_odport; + } else { + old->nat_inip6 = nat->nat_osrc6; + old->nat_outip6 = nat->nat_nsrc6; + old->nat_oip6 = nat->nat_odst6; + old->nat_un.nat_unt.ts_sport = nat->nat_osport; + old->nat_un.nat_unt.ts_dport = nat->nat_nsport; + } +} + + +static void +nat_current_to_4_1_14(current, old) + void *current; + nat_4_1_14_t *old; +{ + nat_t *nat = (nat_t *)current; + + old->nat_lock = nat->nat_lock; + old->nat_next = nat->nat_next; + old->nat_pnext = NULL; + old->nat_hnext[0] = NULL; + old->nat_hnext[1] = NULL; + old->nat_phnext[0] = NULL; + old->nat_phnext[1] = NULL; + old->nat_hm = nat->nat_hm; + old->nat_data = nat->nat_data; + old->nat_me = (void *)nat->nat_me; + old->nat_state = nat->nat_state; + old->nat_aps = nat->nat_aps; + old->nat_fr = nat->nat_fr; + old->nat_ptr = nat->nat_ptr; + old->nat_ifps[0] = nat->nat_ifps[0]; + old->nat_ifps[1] = nat->nat_ifps[1]; + old->nat_sync = nat->nat_sync; + old->nat_tqe = nat->nat_tqe; + old->nat_flags = nat->nat_flags; + old->nat_sumd[0] = nat->nat_sumd[0]; + old->nat_sumd[1] = nat->nat_sumd[1]; + old->nat_ipsumd = nat->nat_ipsumd; + old->nat_mssclamp = nat->nat_mssclamp; + old->nat_pkts[0] = nat->nat_pkts[0]; + old->nat_pkts[1] = nat->nat_pkts[1]; + old->nat_bytes[0] = nat->nat_bytes[0]; + old->nat_bytes[1] = nat->nat_bytes[1]; + old->nat_ref = nat->nat_ref; + old->nat_dir = nat->nat_dir; + old->nat_p = nat->nat_pr[0]; + old->nat_use = nat->nat_use; + old->nat_hv[0] = nat->nat_hv[0]; + old->nat_hv[1] = nat->nat_hv[1]; + old->nat_rev = nat->nat_rev; + bcopy(nat->nat_ifnames[0], old->nat_ifnames[0], LIFNAMSIZ); + bcopy(nat->nat_ifnames[1], old->nat_ifnames[1], LIFNAMSIZ); + + if (nat->nat_redir == NAT_REDIRECT) { + old->nat_inip6 = nat->nat_ndst6; + old->nat_outip6 = nat->nat_odst6; + old->nat_oip6 = nat->nat_osrc6; + old->nat_un.nat_unt.ts_sport = nat->nat_ndport; + old->nat_un.nat_unt.ts_dport = nat->nat_odport; + } else { + old->nat_inip6 = nat->nat_osrc6; + old->nat_outip6 = nat->nat_nsrc6; + old->nat_oip6 = nat->nat_odst6; + old->nat_un.nat_unt.ts_sport = nat->nat_osport; + old->nat_un.nat_unt.ts_dport = nat->nat_nsport; + } +} + + +static void +nat_current_to_4_1_3(current, old) + void *current; + nat_4_1_3_t *old; +{ + nat_t *nat = (nat_t *)current; + + old->nat_lock = nat->nat_lock; + old->nat_next = nat->nat_next; + old->nat_pnext = NULL; + old->nat_hnext[0] = NULL; + old->nat_hnext[1] = NULL; + old->nat_phnext[0] = NULL; + old->nat_phnext[1] = NULL; + old->nat_hm = nat->nat_hm; + old->nat_data = nat->nat_data; + old->nat_me = (void *)nat->nat_me; + old->nat_state = nat->nat_state; + old->nat_aps = nat->nat_aps; + old->nat_fr = nat->nat_fr; + old->nat_ptr = nat->nat_ptr; + old->nat_ifps[0] = nat->nat_ifps[0]; + old->nat_ifps[1] = nat->nat_ifps[1]; + old->nat_sync = nat->nat_sync; + old->nat_tqe = nat->nat_tqe; + old->nat_flags = nat->nat_flags; + old->nat_sumd[0] = nat->nat_sumd[0]; + old->nat_sumd[1] = nat->nat_sumd[1]; + old->nat_ipsumd = nat->nat_ipsumd; + old->nat_mssclamp = nat->nat_mssclamp; + old->nat_pkts[0] = nat->nat_pkts[0]; + old->nat_pkts[1] = nat->nat_pkts[1]; + old->nat_bytes[0] = nat->nat_bytes[0]; + old->nat_bytes[1] = nat->nat_bytes[1]; + old->nat_ref = nat->nat_ref; + old->nat_dir = nat->nat_dir; + old->nat_p = nat->nat_pr[0]; + old->nat_use = nat->nat_use; + old->nat_hv[0] = nat->nat_hv[0]; + old->nat_hv[1] = nat->nat_hv[1]; + old->nat_rev = nat->nat_rev; + bcopy(nat->nat_ifnames[0], old->nat_ifnames[0], LIFNAMSIZ); + bcopy(nat->nat_ifnames[1], old->nat_ifnames[1], LIFNAMSIZ); + + if (nat->nat_redir == NAT_REDIRECT) { + old->nat_inip6 = nat->nat_ndst6; + old->nat_outip6 = nat->nat_odst6; + old->nat_oip6 = nat->nat_osrc6; + old->nat_un.nat_unt.ts_sport = nat->nat_ndport; + old->nat_un.nat_unt.ts_dport = nat->nat_odport; + } else { + old->nat_inip6 = nat->nat_osrc6; + old->nat_outip6 = nat->nat_nsrc6; + old->nat_oip6 = nat->nat_odst6; + old->nat_un.nat_unt.ts_sport = nat->nat_osport; + old->nat_un.nat_unt.ts_dport = nat->nat_nsport; + } +} + +#endif /* IPFILTER_COMPAT */ diff --git a/contrib/ipfilter/ip_msnrpc_pxy.c b/contrib/ipfilter/ip_msnrpc_pxy.c new file mode 100644 index 0000000..40bc084 --- /dev/null +++ b/contrib/ipfilter/ip_msnrpc_pxy.c @@ -0,0 +1,328 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2000-2003 by Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Simple DCE transparent proxy for MSN RPC. + * + * ******* NOTE: THIS PROXY DOES NOT DO ADDRESS TRANSLATION ******** + * + * Id: ip_msnrpc_pxy.c,v 2.17.2.1 2005/02/04 10:22:55 darrenr Exp + */ + +#define IPF_MSNRPC_PROXY + +#define IPF_MINMSNRPCLEN 24 +#define IPF_MSNRPCSKIP (2 + 19 + 2 + 2 + 2 + 19 + 2 + 2) + + +typedef struct msnrpchdr { + u_char mrh_major; /* major # == 5 */ + u_char mrh_minor; /* minor # == 0 */ + u_char mrh_type; + u_char mrh_flags; + u_32_t mrh_endian; + u_short mrh_dlen; /* data size */ + u_short mrh_alen; /* authentication length */ + u_32_t mrh_cid; /* call identifier */ + u_32_t mrh_hint; /* allocation hint */ + u_short mrh_ctxt; /* presentation context hint */ + u_char mrh_ccnt; /* cancel count */ + u_char mrh_ans; +} msnrpchdr_t; + +int ippr_msnrpc_init __P((void)); +void ippr_msnrpc_fini __P((void)); +int ippr_msnrpc_new __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_msnrpc_out __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_msnrpc_in __P((fr_info_t *, ap_session_t *, nat_t *)); +int ippr_msnrpc_check __P((ip_t *, msnrpchdr_t *)); + +static frentry_t msnfr; + +int msn_proxy_init = 0; + +/* + * Initialize local structures. + */ +int ippr_msnrpc_init() +{ + bzero((char *)&msnfr, sizeof(msnfr)); + msnfr.fr_ref = 1; + msnfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + MUTEX_INIT(&msnfr.fr_lock, "MSN RPC proxy rule lock"); + msn_proxy_init = 1; + + return 0; +} + + +void ippr_msnrpc_fini() +{ + if (msn_proxy_init == 1) { + MUTEX_DESTROY(&msnfr.fr_lock); + msn_proxy_init = 0; + } +} + + +int ippr_msnrpc_new(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + msnrpcinfo_t *mri; + + KMALLOC(mri, msnrpcinfo_t *); + if (mri == NULL) + return -1; + aps->aps_data = mri; + aps->aps_psiz = sizeof(msnrpcinfo_t); + + bzero((char *)mri, sizeof(*mri)); + mri->mri_cmd[0] = 0xff; + mri->mri_cmd[1] = 0xff; + return 0; +} + + +int ippr_msnrpc_check(ip, mrh) +ip_t *ip; +msnrpchdr_t *mrh; +{ + if (mrh->mrh_major != 5) + return -1; + if (mrh->mrh_minor != 0) + return -1; + if (mrh->mrh_alen != 0) + return -1; + if (mrh->mrh_endian == 0x10) { + /* Both gateway and packet match endian */ + if (mrh->mrh_dlen > ip->ip_len) + return -1; + if (mrh->mrh_type == 0 || mrh->mrh_type == 2) + if (mrh->mrh_hint > ip->ip_len) + return -1; + } else if (mrh->mrh_endian == 0x10000000) { + /* XXX - Endian mismatch - should be swapping! */ + return -1; + } else { + return -1; + } + return 0; +} + + +int ippr_msnrpc_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + msnrpcinfo_t *mri; + msnrpchdr_t *mrh; + tcphdr_t *tcp; + int dlen; + + mri = aps->aps_data; + if (mri == NULL) + return 0; + + tcp = (tcphdr_t *)fin->fin_dp; + dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); + if (dlen < IPF_MINMSNRPCLEN) + return 0; + + mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2)); + if (ippr_msnrpc_check(ip, mrh)) + return 0; + + mri->mri_valid++; + + switch (mrh->mrh_type) + { + case 0x0b : /* BIND */ + case 0x00 : /* REQUEST */ + break; + case 0x0c : /* BIND ACK */ + case 0x02 : /* RESPONSE */ + default: + return 0; + } + mri->mri_cmd[1] = mrh->mrh_type; + return 0; +} + + +int ippr_msnrpc_in(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + int dlen, sz, sz2, i; + msnrpcinfo_t *mri; + msnrpchdr_t *mrh; + fr_info_t fi; + u_short len; + char *s; + + mri = aps->aps_data; + if (mri == NULL) + return 0; + tcp = (tcphdr_t *)fin->fin_dp; + dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); + if (dlen < IPF_MINMSNRPCLEN) + return 0; + + mrh = (msnrpchdr_t *)((char *)tcp + (TCP_OFF(tcp) << 2)); + if (ippr_msnrpc_check(ip, mrh)) + return 0; + + mri->mri_valid++; + + switch (mrh->mrh_type) + { + case 0x0c : /* BIND ACK */ + if (mri->mri_cmd[1] != 0x0b) + return 0; + break; + case 0x02 : /* RESPONSE */ + if (mri->mri_cmd[1] != 0x00) + return 0; + break; + case 0x0b : /* BIND */ + case 0x00 : /* REQUEST */ + default: + return 0; + } + mri->mri_cmd[0] = mrh->mrh_type; + dlen -= sizeof(*mrh); + + /* + * Only processes RESPONSE's + */ + if (mrh->mrh_type != 0x02) + return 0; + + /* + * Skip over some bytes...what are these really ? + */ + if (dlen <= 44) + return 0; + s = (char *)(mrh + 1) + 20; + dlen -= 20; + bcopy(s, (char *)&len, sizeof(len)); + if (len == 1) { + s += 20; + dlen -= 20; + } else if (len == 2) { + s += 24; + dlen -= 24; + } else + return 0; + + if (dlen <= 10) + return 0; + dlen -= 10; + bcopy(s, (char *)&sz, sizeof(sz)); + s += sizeof(sz); + bcopy(s, (char *)&sz2, sizeof(sz2)); + s += sizeof(sz2); + if (sz2 != sz) + return 0; + if (sz > dlen) + return 0; + if (*s++ != 5) + return 0; + if (*s++ != 0) + return 0; + sz -= IPF_MSNRPCSKIP; + s += IPF_MSNRPCSKIP; + dlen -= IPF_MSNRPCSKIP; + + do { + if (sz < 7 || dlen < 7) + break; + bcopy(s, (char *)&len, sizeof(len)); + if (dlen < len) + break; + if (sz < len) + break; + + if (len != 1) + break; + sz -= 3; + i = *(s + 2); + s += 3; + dlen -= 3; + + bcopy(s, (char *)&len, sizeof(len)); + if (dlen < len) + break; + if (sz < len) + break; + s += sizeof(len); + + switch (i) + { + case 7 : + if (len == 2) { + bcopy(s, (char *)&mri->mri_rport, 2); + mri->mri_flags |= 1; + } + break; + case 9 : + if (len == 4) { + bcopy(s, (char *)&mri->mri_raddr, 4); + mri->mri_flags |= 2; + } + break; + default : + break; + } + sz -= len; + s += len; + dlen -= len; + } while (sz > 0); + + if (mri->mri_flags == 3) { + int slen; + + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp2); + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_win = htons(8192); + TCP_OFF_A(tcp2, 5); + fi.fin_data[0] = htons(mri->mri_rport); + tcp2->th_sport = mri->mri_rport; + fi.fin_data[1] = 0; + tcp2->th_dport = 0; + fi.fin_state = NULL; + fi.fin_nat = NULL; + fi.fin_dlen = sizeof(*tcp2); + fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); + fi.fin_dp = (char *)tcp2; + fi.fin_fi.fi_daddr = ip->ip_dst.s_addr; + fi.fin_fi.fi_saddr = mri->mri_raddr.s_addr; + if (!fi.fin_fr) + fi.fin_fr = &msnfr; + if (fr_stlookup(&fi, NULL, NULL)) { + RWLOCK_EXIT(&ipf_state); + } else { + (void) fr_addstate(&fi, NULL, SI_W_DPORT|SI_CLONE); + if (fi.fin_state != NULL) + fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + } + ip->ip_len = slen; + } + mri->mri_flags = 0; + return 0; +} diff --git a/contrib/ipfilter/ipf.h b/contrib/ipfilter/ipf.h new file mode 100644 index 0000000..dfae008 --- /dev/null +++ b/contrib/ipfilter/ipf.h @@ -0,0 +1,403 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * @(#)ipf.h 1.12 6/5/96 + * $Id$ + */ + +#ifndef __IPF_H__ +#define __IPF_H__ + +#if defined(__osf__) +# define radix_mask ipf_radix_mask +# define radix_node ipf_radix_node +# define radix_node_head ipf_radix_node_head +#endif + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/file.h> +/* + * This is a workaround for <sys/uio.h> troubles on FreeBSD, HPUX, OpenBSD. + * Needed here because on some systems <sys/uio.h> gets included by things + * like <sys/socket.h> + */ +#ifndef _KERNEL +# define ADD_KERNEL +# define _KERNEL +# define KERNEL +#endif +#ifdef __OpenBSD__ +struct file; +#endif +#include <sys/uio.h> +#ifdef ADD_KERNEL +# undef _KERNEL +# undef KERNEL +#endif +#include <sys/time.h> +#include <sys/socket.h> +#include <net/if.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#ifndef TCP_PAWS_IDLE /* IRIX */ +# include <netinet/tcp.h> +#endif +#include <netinet/udp.h> + +#include <arpa/inet.h> + +#include <errno.h> +#include <limits.h> +#include <netdb.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#if !defined(__SVR4) && !defined(__svr4__) && defined(sun) +# include <strings.h> +#endif +#include <string.h> +#include <unistd.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_auth.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_scan.h" +#include "netinet/ip_htable.h" +#include "netinet/ip_sync.h" +#include "netinet/ip_dstlist.h" + +#include "opts.h" + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +#ifndef __STDC__ +# undef const +# define const +#endif + +#ifndef U_32_T +# define U_32_T 1 +# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ + defined(__sgi) +typedef u_int32_t u_32_t; +# else +# if defined(__alpha__) || defined(__alpha) || defined(_LP64) +typedef unsigned int u_32_t; +# else +# if SOLARIS2 >= 6 +typedef uint32_t u_32_t; +# else +typedef unsigned int u_32_t; +# endif +# endif +# endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */ +#endif /* U_32_T */ + +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 256 +#endif + +#define MAX_ICMPCODE 16 +#define MAX_ICMPTYPE 19 + +#define PRINTF (void)printf +#define FPRINTF (void)fprintf + + +struct ipopt_names { + int on_value; + int on_bit; + int on_siz; + char *on_name; +}; + + +typedef struct alist_s { + struct alist_s *al_next; + int al_not; + int al_family; + i6addr_t al_i6addr; + i6addr_t al_i6mask; +} alist_t; + +#define al_addr al_i6addr.in4_addr +#define al_mask al_i6mask.in4_addr +#define al_1 al_addr +#define al_2 al_mask + + +typedef struct plist_s { + struct plist_s *pl_next; + int pl_compare; + u_short pl_port1; + u_short pl_port2; +} plist_t; + + +typedef struct { + u_short fb_c; + u_char fb_t; + u_char fb_f; + u_32_t fb_k; +} fakebpf_t; + + +typedef struct { + char *it_name; + int it_v4; + int it_v6; +} icmptype_t; + + +typedef struct wordtab { + char *w_word; + int w_value; +} wordtab_t; + + +typedef struct namelist { + struct namelist *na_next; + char *na_name; + int na_value; +} namelist_t; + + +typedef struct proxyrule { + struct proxyrule *pr_next; + char *pr_proxy; + char *pr_conf; + namelist_t *pr_names; + int pr_proto; +} proxyrule_t; + + +#if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ + SOLARIS || defined(__sgi) || defined(__osf__) || defined(linux) +# include <stdarg.h> +typedef int (* ioctlfunc_t) __P((int, ioctlcmd_t, ...)); +#else +typedef int (* ioctlfunc_t) __P((dev_t, ioctlcmd_t, void *)); +#endif +typedef int (* addfunc_t) __P((int, ioctlfunc_t, void *)); +typedef int (* copyfunc_t) __P((void *, void *, size_t)); + + +/* + * SunOS4 + */ +#if defined(sun) && !defined(__SVR4) && !defined(__svr4__) +extern int ioctl __P((int, int, void *)); +#endif + +extern char thishost[]; +extern char flagset[]; +extern u_char flags[]; +extern struct ipopt_names ionames[]; +extern struct ipopt_names secclass[]; +extern char *icmpcodes[MAX_ICMPCODE + 1]; +extern char *icmptypes[MAX_ICMPTYPE + 1]; +extern int use_inet6; +extern int lineNum; +extern int debuglevel; +extern struct ipopt_names v6ionames[]; +extern icmptype_t icmptypelist[]; +extern wordtab_t statefields[]; +extern wordtab_t natfields[]; +extern wordtab_t poolfields[]; + + +extern int addicmp __P((char ***, struct frentry *, int)); +extern int addipopt __P((char *, struct ipopt_names *, int, char *)); +extern int addkeep __P((char ***, struct frentry *, int)); +extern alist_t *alist_new __P((int, char *)); +extern void alist_free __P((alist_t *)); +extern void assigndefined __P((char *)); +extern void binprint __P((void *, size_t)); +extern u_32_t buildopts __P((char *, char *, int)); +extern int checkrev __P((char *)); +extern int connecttcp __P((char *, int)); +extern int count6bits __P((u_32_t *)); +extern int count4bits __P((u_32_t)); +extern char *fac_toname __P((int)); +extern int fac_findname __P((char *)); +extern const char *familyname __P((const int)); +extern void fill6bits __P((int, u_int *)); +extern wordtab_t *findword __P((wordtab_t *, char *)); +extern int ftov __P((int)); +extern char *ipf_geterror __P((int, ioctlfunc_t *)); +extern int genmask __P((int, char *, i6addr_t *)); +extern int gethost __P((int, char *, i6addr_t *)); +extern int geticmptype __P((int, char *)); +extern int getport __P((struct frentry *, char *, u_short *, char *)); +extern int getportproto __P((char *, int)); +extern int getproto __P((char *)); +extern char *getnattype __P((struct nat *)); +extern char *getsumd __P((u_32_t)); +extern u_32_t getoptbyname __P((char *)); +extern u_32_t getoptbyvalue __P((int)); +extern u_32_t getv6optbyname __P((char *)); +extern u_32_t getv6optbyvalue __P((int)); +extern char *icmptypename __P((int, int)); +extern void initparse __P((void)); +extern void ipf_dotuning __P((int, char *, ioctlfunc_t)); +extern int ipf_addrule __P((int, ioctlfunc_t, void *)); +extern void ipf_mutex_clean __P((void)); +extern int ipf_parsefile __P((int, addfunc_t, ioctlfunc_t *, char *)); +extern int ipf_parsesome __P((int, addfunc_t, ioctlfunc_t *, FILE *)); +extern void ipf_perror __P((int, char *)); +extern int ipf_perror_fd __P(( int, ioctlfunc_t, char *)); +extern void ipf_rwlock_clean __P((void)); +extern char *ipf_strerror __P((int)); +extern void ipferror __P((int, char *)); +extern int ipmon_parsefile __P((char *)); +extern int ipmon_parsesome __P((FILE *)); +extern int ipnat_addrule __P((int, ioctlfunc_t, void *)); +extern int ipnat_parsefile __P((int, addfunc_t, ioctlfunc_t, char *)); +extern int ipnat_parsesome __P((int, addfunc_t, ioctlfunc_t, FILE *)); +extern int ippool_parsefile __P((int, char *, ioctlfunc_t)); +extern int ippool_parsesome __P((int, FILE *, ioctlfunc_t)); +extern int kmemcpywrap __P((void *, void *, size_t)); +extern char *kvatoname __P((ipfunc_t, ioctlfunc_t)); +extern int load_dstlist __P((struct ippool_dst *, ioctlfunc_t, + ipf_dstnode_t *)); +extern int load_dstlistnode __P((int, char *, struct ipf_dstnode *, + ioctlfunc_t)); +extern alist_t *load_file __P((char *)); +extern int load_hash __P((struct iphtable_s *, struct iphtent_s *, + ioctlfunc_t)); +extern int load_hashnode __P((int, char *, struct iphtent_s *, int, + ioctlfunc_t)); +extern alist_t *load_http __P((char *)); +extern int load_pool __P((struct ip_pool_s *list, ioctlfunc_t)); +extern int load_poolnode __P((int, char *, ip_pool_node_t *, int, ioctlfunc_t)); +extern alist_t *load_url __P((char *)); +extern alist_t *make_range __P((int, struct in_addr, struct in_addr)); +extern void mb_hexdump __P((mb_t *, FILE *)); +extern ipfunc_t nametokva __P((char *, ioctlfunc_t)); +extern void nat_setgroupmap __P((struct ipnat *)); +extern int ntomask __P((int, int, u_32_t *)); +extern u_32_t optname __P((char ***, u_short *, int)); +extern wordtab_t *parsefields __P((wordtab_t *, char *)); +extern int *parseipfexpr __P((char *, char **)); +extern int parsewhoisline __P((char *, addrfamily_t *, addrfamily_t *)); +extern void pool_close __P((void)); +extern int pool_fd __P((void)); +extern int pool_ioctl __P((ioctlfunc_t, ioctlcmd_t, void *)); +extern int pool_open __P((void)); +extern char *portname __P((int, int)); +extern int pri_findname __P((char *)); +extern char *pri_toname __P((int)); +extern void print_toif __P((int, char *, char *, struct frdest *)); +extern void printaps __P((ap_session_t *, int, int)); +extern void printaddr __P((int, int, char *, int, u_32_t *, u_32_t *)); +extern void printbuf __P((char *, int, int)); +extern void printfieldhdr __P((wordtab_t *, wordtab_t *)); +extern void printfr __P((struct frentry *, ioctlfunc_t)); +extern struct iphtable_s *printhash __P((struct iphtable_s *, copyfunc_t, + char *, int, wordtab_t *)); +extern struct iphtable_s *printhash_live __P((iphtable_t *, int, char *, + int, wordtab_t *)); +extern ippool_dst_t *printdstl_live __P((ippool_dst_t *, int, char *, + int, wordtab_t *)); +extern void printhashdata __P((iphtable_t *, int)); +extern struct iphtent_s *printhashnode __P((struct iphtable_s *, + struct iphtent_s *, + copyfunc_t, int, wordtab_t *)); +extern void printhost __P((int, u_32_t *)); +extern void printhostmask __P((int, u_32_t *, u_32_t *)); +extern void printip __P((int, u_32_t *)); +extern void printlog __P((struct frentry *)); +extern void printlookup __P((char *, i6addr_t *addr, i6addr_t *mask)); +extern void printmask __P((int, u_32_t *)); +extern void printnataddr __P((int, char *, nat_addr_t *, int)); +extern void printnatfield __P((nat_t *, int)); +extern void printnatside __P((char *, nat_stat_side_t *)); +extern void printpacket __P((int, mb_t *)); +extern void printpacket6 __P((int, mb_t *)); +extern struct ippool_dst *printdstlist __P((struct ippool_dst *, copyfunc_t, + char *, int, ipf_dstnode_t *, + wordtab_t *)); +extern void printdstlistdata __P((ippool_dst_t *, int)); +extern ipf_dstnode_t *printdstlistnode __P((ipf_dstnode_t *, copyfunc_t, + int, wordtab_t *)); +extern void printdstlistpolicy __P((ippool_policy_t)); +extern struct ip_pool_s *printpool __P((struct ip_pool_s *, copyfunc_t, + char *, int, wordtab_t *)); +extern struct ip_pool_s *printpool_live __P((struct ip_pool_s *, int, + char *, int, wordtab_t *)); +extern void printpooldata __P((ip_pool_t *, int)); +extern void printpoolfield __P((void *, int, int)); +extern struct ip_pool_node *printpoolnode __P((struct ip_pool_node *, + int, wordtab_t *)); +extern void printproto __P((struct protoent *, int, struct ipnat *)); +extern void printportcmp __P((int, struct frpcmp *)); +extern void printstatefield __P((ipstate_t *, int)); +extern void printtqtable __P((ipftq_t *)); +extern void printtunable __P((ipftune_t *)); +extern void printunit __P((int)); +extern void optprint __P((u_short *, u_long, u_long)); +#ifdef USE_INET6 +extern void optprintv6 __P((u_short *, u_long, u_long)); +#endif +extern int remove_hash __P((struct iphtable_s *, ioctlfunc_t)); +extern int remove_hashnode __P((int, char *, struct iphtent_s *, ioctlfunc_t)); +extern int remove_pool __P((ip_pool_t *, ioctlfunc_t)); +extern int remove_poolnode __P((int, char *, ip_pool_node_t *, ioctlfunc_t)); +extern u_char tcpflags __P((char *)); +extern void printc __P((struct frentry *)); +extern void printC __P((int)); +extern void emit __P((int, int, void *, struct frentry *)); +extern u_char secbit __P((int)); +extern u_char seclevel __P((char *)); +extern void printfraginfo __P((char *, struct ipfr *)); +extern void printifname __P((char *, char *, void *)); +extern char *hostname __P((int, void *)); +extern struct ipstate *printstate __P((struct ipstate *, int, u_long)); +extern void printsbuf __P((char *)); +extern void printnat __P((struct ipnat *, int)); +extern void printactiveaddress __P((int, char *, i6addr_t *, char *)); +extern void printactivenat __P((struct nat *, int, u_long)); +extern void printhostmap __P((struct hostmap *, u_int)); +extern void printtcpflags __P((u_32_t, u_32_t)); +extern void printipfexpr __P((int *)); +extern void printstatefield __P((ipstate_t *, int)); +extern void printstatefieldhdr __P((int)); +extern int sendtrap_v1_0 __P((int, char *, char *, int, time_t)); +extern int sendtrap_v2_0 __P((int, char *, char *, int)); +extern int vtof __P((int)); + +extern void set_variable __P((char *, char *)); +extern char *get_variable __P((char *, char **, int)); +extern void resetlexer __P((void)); + +extern void debug __P((int, char *, ...)); +extern void verbose __P((int, char *, ...)); +extern void ipfkdebug __P((char *, ...)); +extern void ipfkverbose __P((char *, ...)); + +#if SOLARIS +extern int gethostname __P((char *, int )); +extern void sync __P((void)); +#endif + +#endif /* __IPF_H__ */ diff --git a/contrib/ipfilter/ipf_rb.h b/contrib/ipfilter/ipf_rb.h new file mode 100644 index 0000000..3d7a59d --- /dev/null +++ b/contrib/ipfilter/ipf_rb.h @@ -0,0 +1,364 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +typedef enum rbcolour_e { + C_BLACK = 0, + C_RED = 1 +} rbcolour_t; + +#define RBI_LINK(_n, _t) \ + struct _n##_rb_link { \ + struct _t *left; \ + struct _t *right; \ + struct _t *parent; \ + rbcolour_t colour; \ + } + +#define RBI_HEAD(_n, _t) \ +struct _n##_rb_head { \ + struct _t top; \ + int count; \ + int (* compare)(struct _t *, struct _t *); \ +} + +#define RBI_CODE(_n, _t, _f, _cmp) \ + \ +typedef void (*_n##_rb_walker_t)(_t *, void *); \ + \ +_t * _n##_rb_delete(struct _n##_rb_head *, _t *); \ +void _n##_rb_init(struct _n##_rb_head *); \ +void _n##_rb_insert(struct _n##_rb_head *, _t *); \ +_t * _n##_rb_search(struct _n##_rb_head *, void *); \ +void _n##_rb_walktree(struct _n##_rb_head *, _n##_rb_walker_t, void *);\ + \ +static void \ +rotate_left(struct _n##_rb_head *head, _t *node) \ +{ \ + _t *parent, *tmp1, *tmp2; \ + \ + parent = node->_f.parent; \ + tmp1 = node->_f.right; \ + tmp2 = tmp1->_f.left; \ + node->_f.right = tmp2; \ + if (tmp2 != & _n##_rb_zero) \ + tmp2->_f.parent = node; \ + if (parent == & _n##_rb_zero) \ + head->top._f.right = tmp1; \ + else if (parent->_f.right == node) \ + parent->_f.right = tmp1; \ + else \ + parent->_f.left = tmp1; \ + tmp1->_f.left = node; \ + tmp1->_f.parent = parent; \ + node->_f.parent = tmp1; \ +} \ + \ +static void \ +rotate_right(struct _n##_rb_head *head, _t *node) \ +{ \ + _t *parent, *tmp1, *tmp2; \ + \ + parent = node->_f.parent; \ + tmp1 = node->_f.left; \ + tmp2 = tmp1->_f.right; \ + node->_f.left = tmp2; \ + if (tmp2 != &_n##_rb_zero) \ + tmp2->_f.parent = node; \ + if (parent == &_n##_rb_zero) \ + head->top._f.right = tmp1; \ + else if (parent->_f.right == node) \ + parent->_f.right = tmp1; \ + else \ + parent->_f.left = tmp1; \ + tmp1->_f.right = node; \ + tmp1->_f.parent = parent; \ + node->_f.parent = tmp1; \ +} \ + \ +void \ +_n##_rb_insert(struct _n##_rb_head *head, _t *node) \ +{ \ + _t *n, *parent, **p, *tmp1, *gparent; \ + \ + parent = &head->top; \ + node->_f.left = &_n##_rb_zero; \ + node->_f.right = &_n##_rb_zero; \ + p = &head->top._f.right; \ + while ((n = *p) != &_n##_rb_zero) { \ + if (_cmp(node, n) < 0) \ + p = &n->_f.left; \ + else \ + p = &n->_f.right; \ + parent = n; \ + } \ + *p = node; \ + node->_f.colour = C_RED; \ + node->_f.parent = parent; \ + \ + while ((node != &_n##_rb_zero) && (parent->_f.colour == C_RED)){\ + gparent = parent->_f.parent; \ + if (parent == gparent->_f.left) { \ + tmp1 = gparent->_f.right; \ + if (tmp1->_f.colour == C_RED) { \ + parent->_f.colour = C_BLACK; \ + tmp1->_f.colour = C_BLACK; \ + gparent->_f.colour = C_RED; \ + node = gparent; \ + } else { \ + if (node == parent->_f.right) { \ + node = parent; \ + rotate_left(head, node); \ + parent = node->_f.parent; \ + } \ + parent->_f.colour = C_BLACK; \ + gparent->_f.colour = C_RED; \ + rotate_right(head, gparent); \ + } \ + } else { \ + tmp1 = gparent->_f.left; \ + if (tmp1->_f.colour == C_RED) { \ + parent->_f.colour = C_BLACK; \ + tmp1->_f.colour = C_BLACK; \ + gparent->_f.colour = C_RED; \ + node = gparent; \ + } else { \ + if (node == parent->_f.left) { \ + node = parent; \ + rotate_right(head, node); \ + parent = node->_f.parent; \ + } \ + parent->_f.colour = C_BLACK; \ + gparent->_f.colour = C_RED; \ + rotate_left(head, parent->_f.parent); \ + } \ + } \ + parent = node->_f.parent; \ + } \ + head->top._f.right->_f.colour = C_BLACK; \ + head->count++; \ +} \ + \ +static void \ +deleteblack(struct _n##_rb_head *head, _t *parent, _t *node) \ +{ \ + _t *tmp; \ + \ + while ((node == &_n##_rb_zero || node->_f.colour == C_BLACK) && \ + node != &head->top) { \ + if (parent->_f.left == node) { \ + tmp = parent->_f.right; \ + if (tmp->_f.colour == C_RED) { \ + tmp->_f.colour = C_BLACK; \ + parent->_f.colour = C_RED; \ + rotate_left(head, parent); \ + tmp = parent->_f.right; \ + } \ + if ((tmp->_f.left == &_n##_rb_zero || \ + tmp->_f.left->_f.colour == C_BLACK) && \ + (tmp->_f.right == &_n##_rb_zero || \ + tmp->_f.right->_f.colour == C_BLACK)) { \ + tmp->_f.colour = C_RED; \ + node = parent; \ + parent = node->_f.parent; \ + } else { \ + if (tmp->_f.right == &_n##_rb_zero || \ + tmp->_f.right->_f.colour == C_BLACK) {\ + _t *tmp2 = tmp->_f.left; \ + \ + if (tmp2 != &_n##_rb_zero) \ + tmp2->_f.colour = C_BLACK;\ + tmp->_f.colour = C_RED; \ + rotate_right(head, tmp); \ + tmp = parent->_f.right; \ + } \ + tmp->_f.colour = parent->_f.colour; \ + parent->_f.colour = C_BLACK; \ + if (tmp->_f.right != &_n##_rb_zero) \ + tmp->_f.right->_f.colour = C_BLACK;\ + rotate_left(head, parent); \ + node = head->top._f.right; \ + } \ + } else { \ + tmp = parent->_f.left; \ + if (tmp->_f.colour == C_RED) { \ + tmp->_f.colour = C_BLACK; \ + parent->_f.colour = C_RED; \ + rotate_right(head, parent); \ + tmp = parent->_f.left; \ + } \ + if ((tmp->_f.left == &_n##_rb_zero || \ + tmp->_f.left->_f.colour == C_BLACK) && \ + (tmp->_f.right == &_n##_rb_zero || \ + tmp->_f.right->_f.colour == C_BLACK)) { \ + tmp->_f.colour = C_RED; \ + node = parent; \ + parent = node->_f.parent; \ + } else { \ + if (tmp->_f.left == &_n##_rb_zero || \ + tmp->_f.left->_f.colour == C_BLACK) {\ + _t *tmp2 = tmp->_f.right; \ + \ + if (tmp2 != &_n##_rb_zero) \ + tmp2->_f.colour = C_BLACK;\ + tmp->_f.colour = C_RED; \ + rotate_left(head, tmp); \ + tmp = parent->_f.left; \ + } \ + tmp->_f.colour = parent->_f.colour; \ + parent->_f.colour = C_BLACK; \ + if (tmp->_f.left != &_n##_rb_zero) \ + tmp->_f.left->_f.colour = C_BLACK;\ + rotate_right(head, parent); \ + node = head->top._f.right; \ + break; \ + } \ + } \ + } \ + if (node != &_n##_rb_zero) \ + node->_f.colour = C_BLACK; \ +} \ + \ +_t * \ +_n##_rb_delete(struct _n##_rb_head *head, _t *node) \ +{ \ + _t *child, *parent, *old = node, *left; \ + rbcolour_t color; \ + \ + if (node->_f.left == &_n##_rb_zero) { \ + child = node->_f.right; \ + } else if (node->_f.right == &_n##_rb_zero) { \ + child = node->_f.left; \ + } else { \ + node = node->_f.right; \ + while ((left = node->_f.left) != &_n##_rb_zero) \ + node = left; \ + child = node->_f.right; \ + parent = node->_f.parent; \ + color = node->_f.colour; \ + if (child != &_n##_rb_zero) \ + child->_f.parent = parent; \ + if (parent != &_n##_rb_zero) { \ + if (parent->_f.left == node) \ + parent->_f.left = child; \ + else \ + parent->_f.right = child; \ + } else { \ + head->top._f.right = child; \ + } \ + if (node->_f.parent == old) \ + parent = node; \ + *node = *old; \ + if (old->_f.parent != &_n##_rb_zero) { \ + if (old->_f.parent->_f.left == old) \ + old->_f.parent->_f.left = node; \ + else \ + old->_f.parent->_f.right = node; \ + } else { \ + head->top._f.right = child; \ + } \ + old->_f.left->_f.parent = node; \ + if (old->_f.right != &_n##_rb_zero) \ + old->_f.right->_f.parent = node; \ + if (parent != &_n##_rb_zero) { \ + left = parent; \ + } \ + goto colour; \ + } \ + parent = node->_f.parent; \ + color= node->_f.colour; \ + if (child != &_n##_rb_zero) \ + child->_f.parent = parent; \ + if (parent != &_n##_rb_zero) { \ + if (parent->_f.left == node) \ + parent->_f.left = child; \ + else \ + parent->_f.right = child; \ + } else { \ + head->top._f.right = child; \ + } \ +colour: \ + if (color == C_BLACK) \ + deleteblack(head, parent, node); \ + head->count--; \ + return old; \ +} \ + \ +void \ +_n##_rb_init(struct _n##_rb_head *head) \ +{ \ + memset(head, 0, sizeof(*head)); \ + memset(&_n##_rb_zero, 0, sizeof(_n##_rb_zero)); \ + head->top._f.left = &_n##_rb_zero; \ + head->top._f.right = &_n##_rb_zero; \ + head->top._f.parent = &head->top; \ + _n##_rb_zero._f.left = &_n##_rb_zero; \ + _n##_rb_zero._f.right = &_n##_rb_zero; \ + _n##_rb_zero._f.parent = &_n##_rb_zero; \ +} \ + \ +void \ +_n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\ +{ \ + _t *prev; \ + _t *next; \ + _t *node = head->top._f.right; \ + _t *base; \ + \ + while (node != &_n##_rb_zero) \ + node = node->_f.left; \ + \ + for (;;) { \ + base = node; \ + prev = node; \ + while ((node->_f.parent->_f.right == node) && \ + (node != &_n##_rb_zero)) { \ + prev = node; \ + node = node->_f.parent; \ + } \ + \ + node = prev; \ + for (node = node->_f.parent->_f.right; node != &_n##_rb_zero;\ + node = node->_f.left) \ + prev = node; \ + next = prev; \ + \ + if (node != &_n##_rb_zero) \ + func(node, arg); \ + \ + node = next; \ + if (node == &_n##_rb_zero) \ + break; \ + } \ +} \ + \ +_t * \ +_n##_rb_search(struct _n##_rb_head *head, void *key) \ +{ \ + int match; \ + _t *node; \ + node = head->top._f.right; \ + while (node != &_n##_rb_zero) { \ + match = _cmp(key, node); \ + if (match == 0) \ + break; \ + if (match< 0) \ + node = node->_f.left; \ + else \ + node = node->_f.right; \ + } \ + if (node == &_n##_rb_zero || match != 0) \ + return (NULL); \ + return (node); \ +} + +#define RBI_DELETE(_n, _h, _v) _n##_rb_delete(_h, _v) +#define RBI_FIELD(_n) struct _n##_rb_link +#define RBI_INIT(_n, _h) _n##_rb_init(_h) +#define RBI_INSERT(_n, _h, _v) _n##_rb_insert(_h, _v) +#define RBI_ISEMPTY(_h) ((_h)->count == 0) +#define RBI_SEARCH(_n, _h, _k) _n##_rb_search(_h, _k) +#define RBI_WALK(_n, _h, _w, _a) _n##_rb_walktree(_h, _w, _a) +#define RBI_ZERO(_n) _n##_rb_zero diff --git a/contrib/ipfilter/iplang/BNF b/contrib/ipfilter/iplang/BNF new file mode 100644 index 0000000..b5fb8d0 --- /dev/null +++ b/contrib/ipfilter/iplang/BNF @@ -0,0 +1,69 @@ +line ::= iface | arp | send | defrouter | ipv4line . + +iface ::= ifhdr "{" ifaceopts "}" ";" . +ifhdr ::= "interface" | "iface" . +ifaceopts ::= "ifname" name | "mtu" mtu | "v4addr" ipaddr | + "eaddr" eaddr . + +send ::= "send" ";" | "send" "{" sendbodyopts "}" ";" . +sendbodyopts ::= sendbody [ sendbodyopts ] . +sendbody ::= "ifname" name | "via" ipaddr . + +defrouter ::= "router" ipaddr . + +arp ::= "arp" "{" arpbodyopts "}" ";" . +arpbodyopts ::= arpbody [ arpbodyopts ] . +arpbody ::= "v4addr" ipaddr | "eaddr" eaddr . + +bodyline ::= ipv4line | tcpline | udpline | icmpline | dataline . + +ipv4line ::= "ipv4" "{" ipv4bodyopts "}" ";" . +ipv4bodyopts ::= ipv4body [ ipv4bodyopts ] | bodyline . +ipv4body ::= "proto" protocol | "src" ipaddr | "dst" ipaddr | + "off" number | "v" number | "hl" number| "id" number | + "ttl" number | "tos" number | "sum" number | "len" number | + "opt" "{" ipv4optlist "}" ";" . +ipv4optlist ::= ipv4option [ ipv4optlist ] . +ipv4optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | + "tr" | "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | + "ssrr" | "addext" | "visa" | "imitd" | "eip" | "finn" | + "secclass" ipv4secclass. +ipv4secclass := "unclass" | "confid" | "reserv-1" | "reserv-2" | + "reserv-3" | "reserv-4" | "secret" | "topsecret" . + +tcpline ::= "tcp" "{" tcpbodyopts "}" ";" . +tcpbodyopts ::= tcpbody [ tcpbodyopts ] | bodyline . +tcpbody ::= "sport" port | "dport" port | "seq" number | "ack" number | + "off" number | "urp" number | "win" number | "sum" number | + "flags" tcpflags | data . + +udpline ::= "udp" "{" udpbodyopts "}" ";" . +udpbodyopts ::= udpbody [ udpbodyopts ] | bodyline . +udpbody ::= "sport" port | "dport" port | "len" number | "sum" number | + data . + +icmpline ::= "icmp" "{" icmpbodyopts "}" ";" . +icmpbodyopts ::= icmpbody [ icmpbodyopts ] | bodyline . +icmpbody ::= "type" icmptype [ "code" icmpcode ] . +icmptype ::= "echorep" | "echorep" "{" echoopts "}" ";" | "unreach" | + "unreach" "{" unreachtype "}" ";" | "squench" | "redir" | + "redir" "{" redirtype "}" ";" | "echo" "{" echoopts "}" ";" | + "echo" | "routerad" | "routersol" | "timex" | + "timex" "{" timextype "}" ";" | "paramprob" | + "paramprob" "{" parapptype "}" ";" | "timest" | "timestrep" | + "inforeq" | "inforep" | "maskreq" | "maskrep" . + +echoopts ::= echoopts [ icmpechoopts ] . +unreachtype ::= "net-unr" | "host-unr" | "proto-unr" | "port-unr" | + "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" | + "net-prohib" | "host-prohib" | "net-tos" | "host-tos" | + "filter-prohib" | "host-preced" | "cutoff-preced" . +redirtype ::= "net-redir" | "host-redir" | "tos-net-redir" | + "tos-host-redir" . +timextype ::= "intrans" | "reass" . +paramptype ::= "optabsent" . + +data ::= "data" "{" databodyopts "}" ";" . +databodyopts ::= "len" number | "value" string | "file" filename . + +icmpechoopts ::= "icmpseq" number | "icmpid" number . diff --git a/contrib/ipfilter/iplang/Makefile b/contrib/ipfilter/iplang/Makefile new file mode 100644 index 0000000..5b53e9a --- /dev/null +++ b/contrib/ipfilter/iplang/Makefile @@ -0,0 +1,31 @@ +# +# See the IPFILTER.LICENCE file for details on licencing. +# +#CC=gcc -Wuninitialized -Wstrict-prototypes -Werror -O +CFLAGS=-I.. + +all: $(DESTDIR)/iplang_y.o $(DESTDIR)/iplang_l.o + +$(DESTDIR)/iplang_y.o: $(DESTDIR)/iplang_y.c + $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/iplang_y.c -o $@ + +$(DESTDIR)/iplang_l.o: $(DESTDIR)/iplang_l.c + $(CC) $(DEBUG) -I. -I.. -I$(DESTDIR) -I../ipsend $(CFLAGS) $(LINUX) -c $(DESTDIR)/iplang_l.c -o $@ + +iplang_y.o: iplang_y.c + $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c $< -o $@ + +iplang_l.o: iplang_l.c + $(CC) $(DEBUG) -I. -I.. -I../ipsend $(CFLAGS) $(LINUX) -c $< -o $@ + +$(DESTDIR)/iplang_l.c: iplang_l.l $(DESTDIR)/iplang_y.h + lex iplang_l.l + mv lex.yy.c $(DESTDIR)/iplang_l.c + +$(DESTDIR)/iplang_y.c $(DESTDIR)/iplang_y.h: iplang_y.y + yacc -d iplang_y.y + mv y.tab.c $(DESTDIR)/iplang_y.c + mv y.tab.h $(DESTDIR)/iplang_y.h + +clean: + /bin/rm -f *.o lex.yy.c y.tab.c y.tab.h diff --git a/contrib/ipfilter/iplang/iplang.h b/contrib/ipfilter/iplang/iplang.h new file mode 100644 index 0000000..63cc078 --- /dev/null +++ b/contrib/ipfilter/iplang/iplang.h @@ -0,0 +1,54 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +typedef struct iface { + int if_MTU; + char *if_name; + struct in_addr if_addr; + struct ether_addr if_eaddr; + struct iface *if_next; + int if_fd; +} iface_t; + + +typedef struct send { + struct iface *snd_if; + struct in_addr snd_gw; +} send_t; + + +typedef struct arp { + struct in_addr arp_addr; + struct ether_addr arp_eaddr; + struct arp *arp_next; +} arp_t; + + +typedef struct aniphdr { + union { + ip_t *ahu_ip; + char *ahu_data; + tcphdr_t *ahu_tcp; + udphdr_t *ahu_udp; + icmphdr_t *ahu_icmp; + } ah_un; + int ah_optlen; + int ah_lastopt; + int ah_p; + size_t ah_len; + struct aniphdr *ah_next; + struct aniphdr *ah_prev; +} aniphdr_t; + +#define ah_ip ah_un.ahu_ip +#define ah_data ah_un.ahu_data +#define ah_tcp ah_un.ahu_tcp +#define ah_udp ah_un.ahu_udp +#define ah_icmp ah_un.ahu_icmp + +extern int get_arpipv4 __P((char *, char *)); + diff --git a/contrib/ipfilter/iplang/iplang.tst b/contrib/ipfilter/iplang/iplang.tst new file mode 100644 index 0000000..841c3ae --- /dev/null +++ b/contrib/ipfilter/iplang/iplang.tst @@ -0,0 +1,11 @@ +# +interface { ifname le0; mtu 1500; } ; + +ipv4 { + src 1.1.1.1; dst 2.2.2.2; + tcp { + seq 12345; ack 0; sport 9999; dport 23; flags S; + data { value "abcdef"; } ; + } ; +} ; +send { via 10.1.1.1; } ; diff --git a/contrib/ipfilter/iplang/iplang_l.l b/contrib/ipfilter/iplang/iplang_l.l new file mode 100644 index 0000000..029a417 --- /dev/null +++ b/contrib/ipfilter/iplang/iplang_l.l @@ -0,0 +1,322 @@ +/* $FreeBSD$ */ + +%{ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include <stdio.h> +#include <string.h> +#include <sys/param.h> +#if defined(__SVR4) || defined(__sysv__) +#include <sys/stream.h> +#endif +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include "iplang_y.h" +#include "ipf.h" + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +extern int opts; + +int lineNum = 0, ipproto = 0, oldipproto = 0, next = -1, laststate = 0; +int *prstack = NULL, numpr = 0, state = 0, token = 0; + +void yyerror __P((char *)); +void push_proto __P((void)); +void pop_proto __P((void)); +int next_state __P((int, int)); +int next_item __P((int)); +int save_token __P((void)); +void swallow __P((void)); +int yylex __P((void)); + +struct lwordtab { + char *word; + int state; + int next; +}; + +struct lwordtab words[] = { + { "interface", IL_INTERFACE, -1 }, + { "iface", IL_INTERFACE, -1 }, + { "name", IL_IFNAME, IL_TOKEN }, + { "ifname", IL_IFNAME, IL_TOKEN }, + { "router", IL_DEFROUTER, IL_TOKEN }, + { "mtu", IL_MTU, IL_NUMBER }, + { "eaddr", IL_EADDR, IL_TOKEN }, + { "v4addr", IL_V4ADDR, IL_TOKEN }, + { "ipv4", IL_IPV4, -1 }, + { "v", IL_V4V, IL_TOKEN }, + { "proto", IL_V4PROTO, IL_TOKEN }, + { "hl", IL_V4HL, IL_TOKEN }, + { "id", IL_V4ID, IL_TOKEN }, + { "ttl", IL_V4TTL, IL_TOKEN }, + { "tos", IL_V4TOS, IL_TOKEN }, + { "src", IL_V4SRC, IL_TOKEN }, + { "dst", IL_V4DST, IL_TOKEN }, + { "opt", IL_OPT, -1 }, + { "len", IL_LEN, IL_TOKEN }, + { "off", IL_OFF, IL_TOKEN }, + { "sum", IL_SUM, IL_TOKEN }, + { "tcp", IL_TCP, -1 }, + { "sport", IL_SPORT, IL_TOKEN }, + { "dport", IL_DPORT, IL_TOKEN }, + { "seq", IL_TCPSEQ, IL_TOKEN }, + { "ack", IL_TCPACK, IL_TOKEN }, + { "flags", IL_TCPFL, IL_TOKEN }, + { "urp", IL_TCPURP, IL_TOKEN }, + { "win", IL_TCPWIN, IL_TOKEN }, + { "udp", IL_UDP, -1 }, + { "send", IL_SEND, -1 }, + { "via", IL_VIA, IL_TOKEN }, + { "arp", IL_ARP, -1 }, + { "data", IL_DATA, -1 }, + { "value", IL_DVALUE, IL_TOKEN }, + { "file", IL_DFILE, IL_TOKEN }, + { "nop", IL_IPO_NOP, -1 }, + { "eol", IL_IPO_EOL, -1 }, + { "rr", IL_IPO_RR, -1 }, + { "zsu", IL_IPO_ZSU, -1 }, + { "mtup", IL_IPO_MTUP, -1 }, + { "mtur", IL_IPO_MTUR, -1 }, + { "encode", IL_IPO_ENCODE, -1 }, + { "ts", IL_IPO_TS, -1 }, + { "tr", IL_IPO_TR, -1 }, + { "sec", IL_IPO_SEC, -1 }, + { "secclass", IL_IPO_SECCLASS, IL_TOKEN }, + { "lsrr", IL_IPO_LSRR, -1 }, + { "esec", IL_IPO_ESEC, -1 }, + { "cipso", IL_IPO_CIPSO, -1 }, + { "satid", IL_IPO_SATID, -1 }, + { "ssrr", IL_IPO_SSRR, -1 }, + { "addext", IL_IPO_ADDEXT, -1 }, + { "visa", IL_IPO_VISA, -1 }, + { "imitd", IL_IPO_IMITD, -1 }, + { "eip", IL_IPO_EIP, -1 }, + { "finn", IL_IPO_FINN, -1 }, + { "mss", IL_TCPO_MSS, IL_TOKEN }, + { "wscale", IL_TCPO_WSCALE, IL_TOKEN }, + { "reserv-4", IL_IPS_RESERV4, -1 }, + { "topsecret", IL_IPS_TOPSECRET, -1 }, + { "secret", IL_IPS_SECRET, -1 }, + { "reserv-3", IL_IPS_RESERV3, -1 }, + { "confid", IL_IPS_CONFID, -1 }, + { "unclass", IL_IPS_UNCLASS, -1 }, + { "reserv-2", IL_IPS_RESERV2, -1 }, + { "reserv-1", IL_IPS_RESERV1, -1 }, + { "icmp", IL_ICMP, -1 }, + { "type", IL_ICMPTYPE, -1 }, + { "code", IL_ICMPCODE, -1 }, + { "echorep", IL_ICMP_ECHOREPLY, -1 }, + { "unreach", IL_ICMP_UNREACH, -1 }, + { "squench", IL_ICMP_SOURCEQUENCH, -1 }, + { "redir", IL_ICMP_REDIRECT, -1 }, + { "echo", IL_ICMP_ECHO, -1 }, + { "routerad", IL_ICMP_ROUTERADVERT, -1 }, + { "routersol", IL_ICMP_ROUTERSOLICIT, -1 }, + { "timex", IL_ICMP_TIMXCEED, -1 }, + { "paramprob", IL_ICMP_PARAMPROB, -1 }, + { "timest", IL_ICMP_TSTAMP, -1 }, + { "timestrep", IL_ICMP_TSTAMPREPLY, -1 }, + { "inforeq", IL_ICMP_IREQ, -1 }, + { "inforep", IL_ICMP_IREQREPLY, -1 }, + { "maskreq", IL_ICMP_MASKREQ, -1 }, + { "maskrep", IL_ICMP_MASKREPLY, -1 }, + { "net-unr", IL_ICMP_UNREACH_NET, -1 }, + { "host-unr", IL_ICMP_UNREACH_HOST, -1 }, + { "proto-unr", IL_ICMP_UNREACH_PROTOCOL, -1 }, + { "port-unr", IL_ICMP_UNREACH_PORT, -1 }, + { "needfrag", IL_ICMP_UNREACH_NEEDFRAG, -1 }, + { "srcfail", IL_ICMP_UNREACH_SRCFAIL, -1 }, + { "net-unk", IL_ICMP_UNREACH_NET_UNKNOWN, -1 }, + { "host-unk", IL_ICMP_UNREACH_HOST_UNKNOWN, -1 }, + { "isolate", IL_ICMP_UNREACH_ISOLATED, -1 }, + { "net-prohib", IL_ICMP_UNREACH_NET_PROHIB, -1 }, + { "host-prohib", IL_ICMP_UNREACH_HOST_PROHIB, -1 }, + { "net-tos", IL_ICMP_UNREACH_TOSNET, -1 }, + { "host-tos", IL_ICMP_UNREACH_TOSHOST, -1 }, + { "filter-prohib", IL_ICMP_UNREACH_FILTER_PROHIB, -1 }, + { "host-preced", IL_ICMP_UNREACH_HOST_PRECEDENCE, -1 }, + { "cutoff-preced", IL_ICMP_UNREACH_PRECEDENCE_CUTOFF, -1 }, + { "net-redir", IL_ICMP_REDIRECT_NET, -1 }, + { "host-redir", IL_ICMP_REDIRECT_HOST, -1 }, + { "tos-net-redir", IL_ICMP_REDIRECT_TOSNET, -1 }, + { "tos-host-redir", IL_ICMP_REDIRECT_TOSHOST, -1 }, + { "intrans", IL_ICMP_TIMXCEED_INTRANS, -1 }, + { "reass", IL_ICMP_TIMXCEED_REASS, -1 }, + { "optabsent", IL_ICMP_PARAMPROB_OPTABSENT, -1 }, + { "otime", IL_ICMP_OTIME, -1 }, + { "rtime", IL_ICMP_RTIME, -1 }, + { "ttime", IL_ICMP_TTIME, -1 }, + { "icmpseq", IL_ICMP_SEQ, -1 }, + { "icmpid", IL_ICMP_SEQ, -1 }, + { ".", IL_DOT, -1 }, + { NULL, 0, 0 } +}; +%} +white [ \t\r]+ +%% +{white} ; +\n { lineNum++; swallow(); } +\{ { push_proto(); return next_item('{'); } +\} { pop_proto(); return next_item('}'); } +; { return next_item(';'); } +[0-9]+ { return next_item(IL_NUMBER); } +[0-9a-fA-F] { return next_item(IL_HEXDIGIT); } +: { return next_item(IL_COLON); } +#[^\n]* { return next_item(IL_COMMENT); } +[^ \{\}\n\t;:{}]* { return next_item(IL_TOKEN); } +\"[^\"]*\" { return next_item(IL_TOKEN); } +%% +void yyerror(msg) +char *msg; +{ + fprintf(stderr, "%s error at \"%s\", line %d\n", msg, yytext, + lineNum + 1); + exit(1); +} + + +void push_proto() +{ + numpr++; + if (!prstack) + prstack = (int *)malloc(sizeof(int)); + else + prstack = (int *)realloc((char *)prstack, numpr * sizeof(int)); + prstack[numpr - 1] = oldipproto; +} + + +void pop_proto() +{ + numpr--; + ipproto = prstack[numpr]; + if (!numpr) { + free(prstack); + prstack = NULL; + return; + } + prstack = (int *)realloc((char *)prstack, numpr * sizeof(int)); +} + + +int save_token() +{ + + yylval.str = strdup((char *)yytext); + return IL_TOKEN; +} + + +int next_item(nstate) +int nstate; +{ + struct lwordtab *wt; + + if (opts & OPT_DEBUG) + printf("text=[%s] id=%d next=%d\n", yytext, nstate, next); + if (next == IL_TOKEN) { + next = -1; + return save_token(); + } + token++; + + for (wt = words; wt->word; wt++) + if (!strcasecmp(wt->word, (char *)yytext)) + return next_state(wt->state, wt->next); + if (opts & OPT_DEBUG) + printf("unknown keyword=[%s]\n", yytext); + next = -1; + if (nstate == IL_NUMBER) + yylval.num = atoi((char *)yytext); + token++; + return nstate; +} + + +int next_state(nstate, fornext) +int nstate, fornext; +{ + next = fornext; + + switch (nstate) + { + case IL_IPV4 : + case IL_TCP : + case IL_UDP : + case IL_ICMP : + case IL_DATA : + case IL_INTERFACE : + case IL_ARP : + oldipproto = ipproto; + ipproto = nstate; + break; + case IL_SUM : + if (ipproto == IL_IPV4) + nstate = IL_V4SUM; + else if (ipproto == IL_TCP) + nstate = IL_TCPSUM; + else if (ipproto == IL_UDP) + nstate = IL_UDPSUM; + break; + case IL_OPT : + if (ipproto == IL_IPV4) + nstate = IL_V4OPT; + else if (ipproto == IL_TCP) + nstate = IL_TCPOPT; + break; + case IL_IPO_NOP : + if (ipproto == IL_TCP) + nstate = IL_TCPO_NOP; + break; + case IL_IPO_EOL : + if (ipproto == IL_TCP) + nstate = IL_TCPO_EOL; + break; + case IL_IPO_TS : + if (ipproto == IL_TCP) + nstate = IL_TCPO_TS; + break; + case IL_OFF : + if (ipproto == IL_IPV4) + nstate = IL_V4OFF; + else if (ipproto == IL_TCP) + nstate = IL_TCPOFF; + break; + case IL_LEN : + if (ipproto == IL_IPV4) + nstate = IL_V4LEN; + else if (ipproto == IL_UDP) + nstate = IL_UDPLEN; + break; + } + return nstate; +} + + +void swallow() +{ + int c; + + c = input(); + + if (c == '#') { + while ((c != '\n') && (c != EOF)) + c = input(); + } + if (c != EOF) + unput(c); +} diff --git a/contrib/ipfilter/iplang/iplang_y.y b/contrib/ipfilter/iplang/iplang_y.y new file mode 100644 index 0000000..98c8f1a --- /dev/null +++ b/contrib/ipfilter/iplang/iplang_y.y @@ -0,0 +1,1858 @@ +/* $FreeBSD$ */ + +%{ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Id: iplang_y.y,v 2.9.2.4 2006/03/17 12:11:29 darrenr Exp $ + * $FreeBSD$ + */ + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#if !defined(__SVR4) && !defined(__svr4__) +# include <strings.h> +#else +# include <sys/byteorder.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/time.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#ifndef linux +# include <netinet/ip_var.h> +# include <net/route.h> +# include <netinet/if_ether.h> +#endif +#include <netdb.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <ctype.h> +#include "ipsend.h" +#include "ip_compat.h" +#include "ipf.h" +#include "iplang.h" + +#if !defined(__NetBSD__) && (!defined(__FreeBSD_version) && \ + __FreeBSD_version < 400020) && (!SOLARIS || SOLARIS2 < 10) +extern struct ether_addr *ether_aton __P((char *)); +#endif + +extern int opts; +extern struct ipopt_names ionames[]; +extern int state, state, lineNum, token; +extern int yylineno; +extern char yytext[]; +extern FILE *yyin; +int yylex __P((void)); +#define YYDEBUG 1 +#if !defined(ultrix) && !defined(hpux) +int yydebug = 1; +#else +extern int yydebug; +#endif + +iface_t *iflist = NULL, **iftail = &iflist; +iface_t *cifp = NULL; +arp_t *arplist = NULL, **arptail = &arplist, *carp = NULL; +struct in_addr defrouter; +send_t sending; +char *sclass = NULL; +u_short c_chksum __P((u_short *, u_int, u_long)); +u_long p_chksum __P((u_short *, u_int)); + +u_long ipbuffer[67584/sizeof(u_long)]; /* 66K */ +aniphdr_t *aniphead = NULL, *canip = NULL, **aniptail = &aniphead; +ip_t *ip = NULL; +udphdr_t *udp = NULL; +tcphdr_t *tcp = NULL; +icmphdr_t *icmp = NULL; + +struct statetoopt { + int sto_st; + int sto_op; +}; + +struct in_addr getipv4addr __P((char *arg)); +u_short getportnum __P((char *, char *)); +struct ether_addr *geteaddr __P((char *, struct ether_addr *)); +void *new_header __P((int)); +void free_aniplist __P((void)); +void inc_anipheaders __P((int)); +void new_data __P((void)); +void set_datalen __P((char **)); +void set_datafile __P((char **)); +void set_data __P((char **)); +void new_packet __P((void)); +void set_ipv4proto __P((char **)); +void set_ipv4src __P((char **)); +void set_ipv4dst __P((char **)); +void set_ipv4off __P((char **)); +void set_ipv4v __P((char **)); +void set_ipv4hl __P((char **)); +void set_ipv4ttl __P((char **)); +void set_ipv4tos __P((char **)); +void set_ipv4id __P((char **)); +void set_ipv4sum __P((char **)); +void set_ipv4len __P((char **)); +void new_tcpheader __P((void)); +void set_tcpsport __P((char **)); +void set_tcpdport __P((char **)); +void set_tcpseq __P((char **)); +void set_tcpack __P((char **)); +void set_tcpoff __P((char **)); +void set_tcpurp __P((char **)); +void set_tcpwin __P((char **)); +void set_tcpsum __P((char **)); +void set_tcpflags __P((char **)); +void set_tcpopt __P((int, char **)); +void end_tcpopt __P((void)); +void new_udpheader __P((void)); +void set_udplen __P((char **)); +void set_udpsum __P((char **)); +void prep_packet __P((void)); +void packet_done __P((void)); +void new_interface __P((void)); +void check_interface __P((void)); +void set_ifname __P((char **)); +void set_ifmtu __P((int)); +void set_ifv4addr __P((char **)); +void set_ifeaddr __P((char **)); +void new_arp __P((void)); +void set_arpeaddr __P((char **)); +void set_arpv4addr __P((char **)); +void reset_send __P((void)); +void set_sendif __P((char **)); +void set_sendvia __P((char **)); +void set_defaultrouter __P((char **)); +void new_icmpheader __P((void)); +void set_icmpcode __P((int)); +void set_icmptype __P((int)); +void set_icmpcodetok __P((char **)); +void set_icmptypetok __P((char **)); +void set_icmpid __P((int)); +void set_icmpseq __P((int)); +void set_icmpotime __P((int)); +void set_icmprtime __P((int)); +void set_icmpttime __P((int)); +void set_icmpmtu __P((int)); +void set_redir __P((int, char **)); +void new_ipv4opt __P((void)); +void set_icmppprob __P((int)); +void add_ipopt __P((int, void *)); +void end_ipopt __P((void)); +void set_secclass __P((char **)); +void free_anipheader __P((void)); +void end_ipv4 __P((void)); +void end_icmp __P((void)); +void end_udp __P((void)); +void end_tcp __P((void)); +void end_data __P((void)); +void yyerror __P((char *)); +void iplang __P((FILE *)); +int arp_getipv4 __P((char *, char *)); +int yyparse __P((void)); +%} +%union { + char *str; + int num; +} +%token <num> IL_NUMBER +%type <num> number digits optnumber +%token <str> IL_TOKEN +%type <str> token optoken +%token IL_HEXDIGIT IL_COLON IL_DOT IL_EOF IL_COMMENT +%token IL_INTERFACE IL_IFNAME IL_MTU IL_EADDR +%token IL_IPV4 IL_V4PROTO IL_V4SRC IL_V4DST IL_V4OFF IL_V4V IL_V4HL IL_V4TTL +%token IL_V4TOS IL_V4SUM IL_V4LEN IL_V4OPT IL_V4ID +%token IL_TCP IL_SPORT IL_DPORT IL_TCPFL IL_TCPSEQ IL_TCPACK IL_TCPOFF +%token IL_TCPWIN IL_TCPSUM IL_TCPURP IL_TCPOPT IL_TCPO_NOP IL_TCPO_EOL +%token IL_TCPO_MSS IL_TCPO_WSCALE IL_TCPO_TS +%token IL_UDP IL_UDPLEN IL_UDPSUM +%token IL_ICMP IL_ICMPTYPE IL_ICMPCODE +%token IL_SEND IL_VIA +%token IL_ARP +%token IL_DEFROUTER +%token IL_SUM IL_OFF IL_LEN IL_V4ADDR IL_OPT +%token IL_DATA IL_DLEN IL_DVALUE IL_DFILE +%token IL_IPO_NOP IL_IPO_RR IL_IPO_ZSU IL_IPO_MTUP IL_IPO_MTUR IL_IPO_EOL +%token IL_IPO_TS IL_IPO_TR IL_IPO_SEC IL_IPO_LSRR IL_IPO_ESEC +%token IL_IPO_SATID IL_IPO_SSRR IL_IPO_ADDEXT IL_IPO_VISA IL_IPO_IMITD +%token IL_IPO_EIP IL_IPO_FINN IL_IPO_SECCLASS IL_IPO_CIPSO IL_IPO_ENCODE +%token <str> IL_IPS_RESERV4 IL_IPS_TOPSECRET IL_IPS_SECRET IL_IPS_RESERV3 +%token <str> IL_IPS_CONFID IL_IPS_UNCLASS IL_IPS_RESERV2 IL_IPS_RESERV1 +%token IL_ICMP_ECHOREPLY IL_ICMP_UNREACH IL_ICMP_UNREACH_NET +%token IL_ICMP_UNREACH_HOST IL_ICMP_UNREACH_PROTOCOL IL_ICMP_UNREACH_PORT +%token IL_ICMP_UNREACH_NEEDFRAG IL_ICMP_UNREACH_SRCFAIL +%token IL_ICMP_UNREACH_NET_UNKNOWN IL_ICMP_UNREACH_HOST_UNKNOWN +%token IL_ICMP_UNREACH_ISOLATED IL_ICMP_UNREACH_NET_PROHIB +%token IL_ICMP_UNREACH_HOST_PROHIB IL_ICMP_UNREACH_TOSNET +%token IL_ICMP_UNREACH_TOSHOST IL_ICMP_UNREACH_FILTER_PROHIB +%token IL_ICMP_UNREACH_HOST_PRECEDENCE IL_ICMP_UNREACH_PRECEDENCE_CUTOFF +%token IL_ICMP_SOURCEQUENCH IL_ICMP_REDIRECT IL_ICMP_REDIRECT_NET +%token IL_ICMP_REDIRECT_HOST IL_ICMP_REDIRECT_TOSNET +%token IL_ICMP_REDIRECT_TOSHOST IL_ICMP_ECHO IL_ICMP_ROUTERADVERT +%token IL_ICMP_ROUTERSOLICIT IL_ICMP_TIMXCEED IL_ICMP_TIMXCEED_INTRANS +%token IL_ICMP_TIMXCEED_REASS IL_ICMP_PARAMPROB IL_ICMP_PARAMPROB_OPTABSENT +%token IL_ICMP_TSTAMP IL_ICMP_TSTAMPREPLY IL_ICMP_IREQ IL_ICMP_IREQREPLY +%token IL_ICMP_MASKREQ IL_ICMP_MASKREPLY IL_ICMP_SEQ IL_ICMP_ID +%token IL_ICMP_OTIME IL_ICMP_RTIME IL_ICMP_TTIME + +%% +file: line + | line file + | IL_COMMENT + | IL_COMMENT file + ; + +line: iface + | arp + | send + | defrouter + | ipline + ; + +iface: ifhdr '{' ifaceopts '}' ';' { check_interface(); } + ; + +ifhdr: IL_INTERFACE { new_interface(); } + ; + +ifaceopts: + ifaceopt + | ifaceopt ifaceopts + ; + +ifaceopt: + IL_IFNAME token { set_ifname(&$2); } + | IL_MTU number { set_ifmtu($2); } + | IL_V4ADDR token { set_ifv4addr(&$2); } + | IL_EADDR token { set_ifeaddr(&$2); } + ; + +send: sendhdr '{' sendbody '}' ';' { packet_done(); } + | sendhdr ';' { packet_done(); } + ; + +sendhdr: + IL_SEND { reset_send(); } + ; + +sendbody: + sendopt + | sendbody sendopt + ; + +sendopt: + IL_IFNAME token { set_sendif(&$2); } + | IL_VIA token { set_sendvia(&$2); } + ; + +arp: arphdr '{' arpbody '}' ';' + ; + +arphdr: IL_ARP { new_arp(); } + ; + +arpbody: + arpopt + | arpbody arpopt + ; + +arpopt: IL_V4ADDR token { set_arpv4addr(&$2); } + | IL_EADDR token { set_arpeaddr(&$2); } + ; + +defrouter: + IL_DEFROUTER token { set_defaultrouter(&$2); } + ; + +bodyline: + ipline + | tcp tcpline + | udp udpline + | icmp icmpline + | data dataline + ; + +ipline: ipv4 '{' ipv4body '}' ';' { end_ipv4(); } + ; + +ipv4: IL_IPV4 { new_packet(); } + +ipv4body: + ipv4type + | ipv4type ipv4body + | bodyline + ; + +ipv4type: + IL_V4PROTO token { set_ipv4proto(&$2); } + | IL_V4SRC token { set_ipv4src(&$2); } + | IL_V4DST token { set_ipv4dst(&$2); } + | IL_V4OFF token { set_ipv4off(&$2); } + | IL_V4V token { set_ipv4v(&$2); } + | IL_V4HL token { set_ipv4hl(&$2); } + | IL_V4ID token { set_ipv4id(&$2); } + | IL_V4TTL token { set_ipv4ttl(&$2); } + | IL_V4TOS token { set_ipv4tos(&$2); } + | IL_V4SUM token { set_ipv4sum(&$2); } + | IL_V4LEN token { set_ipv4len(&$2); } + | ipv4opt '{' ipv4optlist '}' ';' { end_ipopt(); } + ; + +tcp: IL_TCP { new_tcpheader(); } + ; + +tcpline: + '{' tcpheader '}' ';' { end_tcp(); } + ; + +tcpheader: + tcpbody + | tcpbody tcpheader + | bodyline + ; + +tcpbody: + IL_SPORT token { set_tcpsport(&$2); } + | IL_DPORT token { set_tcpdport(&$2); } + | IL_TCPSEQ token { set_tcpseq(&$2); } + | IL_TCPACK token { set_tcpack(&$2); } + | IL_TCPOFF token { set_tcpoff(&$2); } + | IL_TCPURP token { set_tcpurp(&$2); } + | IL_TCPWIN token { set_tcpwin(&$2); } + | IL_TCPSUM token { set_tcpsum(&$2); } + | IL_TCPFL token { set_tcpflags(&$2); } + | IL_TCPOPT '{' tcpopts '}' ';' { end_tcpopt(); } + ; + +tcpopts: + | tcpopt tcpopts + ; + +tcpopt: IL_TCPO_NOP ';' { set_tcpopt(IL_TCPO_NOP, NULL); } + | IL_TCPO_EOL ';' { set_tcpopt(IL_TCPO_EOL, NULL); } + | IL_TCPO_MSS optoken { set_tcpopt(IL_TCPO_MSS,&$2);} + | IL_TCPO_WSCALE optoken { set_tcpopt(IL_TCPO_WSCALE,&$2);} + | IL_TCPO_TS optoken { set_tcpopt(IL_TCPO_TS, &$2);} + ; + +udp: IL_UDP { new_udpheader(); } + ; + +udpline: + '{' udpheader '}' ';' { end_udp(); } + ; + + +udpheader: + udpbody + | udpbody udpheader + | bodyline + ; + +udpbody: + IL_SPORT token { set_tcpsport(&$2); } + | IL_DPORT token { set_tcpdport(&$2); } + | IL_UDPLEN token { set_udplen(&$2); } + | IL_UDPSUM token { set_udpsum(&$2); } + ; + +icmp: IL_ICMP { new_icmpheader(); } + ; + +icmpline: + '{' icmpbody '}' ';' { end_icmp(); } + ; + +icmpbody: + icmpheader + | icmpheader bodyline + ; + +icmpheader: + IL_ICMPTYPE icmptype + | IL_ICMPTYPE icmptype icmpcode + ; + +icmpcode: + IL_ICMPCODE token { set_icmpcodetok(&$2); } + ; + +icmptype: + IL_ICMP_ECHOREPLY ';' { set_icmptype(ICMP_ECHOREPLY); } + | IL_ICMP_ECHOREPLY '{' icmpechoopts '}' ';' + | unreach + | IL_ICMP_SOURCEQUENCH ';' { set_icmptype(ICMP_SOURCEQUENCH); } + | redirect + | IL_ICMP_ROUTERADVERT ';' { set_icmptype(ICMP_ROUTERADVERT); } + | IL_ICMP_ROUTERSOLICIT ';' { set_icmptype(ICMP_ROUTERSOLICIT); } + | IL_ICMP_ECHO ';' { set_icmptype(ICMP_ECHO); } + | IL_ICMP_ECHO '{' icmpechoopts '}' ';' + | IL_ICMP_TIMXCEED ';' { set_icmptype(ICMP_TIMXCEED); } + | IL_ICMP_TIMXCEED '{' exceed '}' ';' + | IL_ICMP_TSTAMP ';' { set_icmptype(ICMP_TSTAMP); } + | IL_ICMP_TSTAMPREPLY ';' { set_icmptype(ICMP_TSTAMPREPLY); } + | IL_ICMP_TSTAMPREPLY '{' icmptsopts '}' ';' + | IL_ICMP_IREQ ';' { set_icmptype(ICMP_IREQ); } + | IL_ICMP_IREQREPLY ';' { set_icmptype(ICMP_IREQREPLY); } + | IL_ICMP_IREQREPLY '{' data dataline '}' ';' + | IL_ICMP_MASKREQ ';' { set_icmptype(ICMP_MASKREQ); } + | IL_ICMP_MASKREPLY ';' { set_icmptype(ICMP_MASKREPLY); } + | IL_ICMP_MASKREPLY '{' token '}' ';' + | IL_ICMP_PARAMPROB ';' { set_icmptype(ICMP_PARAMPROB); } + | IL_ICMP_PARAMPROB '{' paramprob '}' ';' + | IL_TOKEN ';' { set_icmptypetok(&$1); } + ; + +icmpechoopts: + | icmpechoopts icmpecho + ; + +icmpecho: + IL_ICMP_SEQ number { set_icmpseq($2); } + | IL_ICMP_ID number { set_icmpid($2); } + ; + +icmptsopts: + | icmptsopts icmpts ';' + ; + +icmpts: IL_ICMP_OTIME number { set_icmpotime($2); } + | IL_ICMP_RTIME number { set_icmprtime($2); } + | IL_ICMP_TTIME number { set_icmpttime($2); } + ; + +unreach: + IL_ICMP_UNREACH + | IL_ICMP_UNREACH '{' unreachopts '}' ';' + ; + +unreachopts: + IL_ICMP_UNREACH_NET line + | IL_ICMP_UNREACH_HOST line + | IL_ICMP_UNREACH_PROTOCOL line + | IL_ICMP_UNREACH_PORT line + | IL_ICMP_UNREACH_NEEDFRAG number ';' { set_icmpmtu($2); } + | IL_ICMP_UNREACH_SRCFAIL line + | IL_ICMP_UNREACH_NET_UNKNOWN line + | IL_ICMP_UNREACH_HOST_UNKNOWN line + | IL_ICMP_UNREACH_ISOLATED line + | IL_ICMP_UNREACH_NET_PROHIB line + | IL_ICMP_UNREACH_HOST_PROHIB line + | IL_ICMP_UNREACH_TOSNET line + | IL_ICMP_UNREACH_TOSHOST line + | IL_ICMP_UNREACH_FILTER_PROHIB line + | IL_ICMP_UNREACH_HOST_PRECEDENCE line + | IL_ICMP_UNREACH_PRECEDENCE_CUTOFF line + ; + +redirect: + IL_ICMP_REDIRECT + | IL_ICMP_REDIRECT '{' redirectopts '}' ';' + ; + +redirectopts: + | IL_ICMP_REDIRECT_NET token { set_redir(0, &$2); } + | IL_ICMP_REDIRECT_HOST token { set_redir(1, &$2); } + | IL_ICMP_REDIRECT_TOSNET token { set_redir(2, &$2); } + | IL_ICMP_REDIRECT_TOSHOST token { set_redir(3, &$2); } + ; + +exceed: + IL_ICMP_TIMXCEED_INTRANS line + | IL_ICMP_TIMXCEED_REASS line + ; + +paramprob: + IL_ICMP_PARAMPROB_OPTABSENT + | IL_ICMP_PARAMPROB_OPTABSENT paraprobarg + +paraprobarg: + '{' number '}' ';' { set_icmppprob($2); } + ; + +ipv4opt: IL_V4OPT { new_ipv4opt(); } + ; + +ipv4optlist: + | ipv4opts ipv4optlist + ; + +ipv4opts: + IL_IPO_NOP ';' { add_ipopt(IL_IPO_NOP, NULL); } + | IL_IPO_RR optnumber { add_ipopt(IL_IPO_RR, &$2); } + | IL_IPO_ZSU ';' { add_ipopt(IL_IPO_ZSU, NULL); } + | IL_IPO_MTUP ';' { add_ipopt(IL_IPO_MTUP, NULL); } + | IL_IPO_MTUR ';' { add_ipopt(IL_IPO_MTUR, NULL); } + | IL_IPO_ENCODE ';' { add_ipopt(IL_IPO_ENCODE, NULL); } + | IL_IPO_TS ';' { add_ipopt(IL_IPO_TS, NULL); } + | IL_IPO_TR ';' { add_ipopt(IL_IPO_TR, NULL); } + | IL_IPO_SEC ';' { add_ipopt(IL_IPO_SEC, NULL); } + | IL_IPO_SECCLASS secclass { add_ipopt(IL_IPO_SECCLASS, sclass); } + | IL_IPO_LSRR token { add_ipopt(IL_IPO_LSRR,&$2); } + | IL_IPO_ESEC ';' { add_ipopt(IL_IPO_ESEC, NULL); } + | IL_IPO_CIPSO ';' { add_ipopt(IL_IPO_CIPSO, NULL); } + | IL_IPO_SATID optnumber { add_ipopt(IL_IPO_SATID,&$2);} + | IL_IPO_SSRR token { add_ipopt(IL_IPO_SSRR,&$2); } + | IL_IPO_ADDEXT ';' { add_ipopt(IL_IPO_ADDEXT, NULL); } + | IL_IPO_VISA ';' { add_ipopt(IL_IPO_VISA, NULL); } + | IL_IPO_IMITD ';' { add_ipopt(IL_IPO_IMITD, NULL); } + | IL_IPO_EIP ';' { add_ipopt(IL_IPO_EIP, NULL); } + | IL_IPO_FINN ';' { add_ipopt(IL_IPO_FINN, NULL); } + ; + +secclass: + IL_IPS_RESERV4 ';' { set_secclass(&$1); } + | IL_IPS_TOPSECRET ';' { set_secclass(&$1); } + | IL_IPS_SECRET ';' { set_secclass(&$1); } + | IL_IPS_RESERV3 ';' { set_secclass(&$1); } + | IL_IPS_CONFID ';' { set_secclass(&$1); } + | IL_IPS_UNCLASS ';' { set_secclass(&$1); } + | IL_IPS_RESERV2 ';' { set_secclass(&$1); } + | IL_IPS_RESERV1 ';' { set_secclass(&$1); } + ; + +data: IL_DATA { new_data(); } + ; + +dataline: + '{' databody '}' ';' { end_data(); } + ; + +databody: dataopts + | dataopts databody + ; + +dataopts: + IL_DLEN token { set_datalen(&$2); } + | IL_DVALUE token { set_data(&$2); } + | IL_DFILE token { set_datafile(&$2); } + ; + +token: IL_TOKEN ';' + ; + +optoken: ';' { $$ = ""; } + | token + ; + +number: digits ';' + ; + +optnumber: ';' { $$ = 0; } + | number + ; + +digits: IL_NUMBER + | digits IL_NUMBER + ; +%% + +struct statetoopt toipopts[] = { + { IL_IPO_NOP, IPOPT_NOP }, + { IL_IPO_RR, IPOPT_RR }, + { IL_IPO_ZSU, IPOPT_ZSU }, + { IL_IPO_MTUP, IPOPT_MTUP }, + { IL_IPO_MTUR, IPOPT_MTUR }, + { IL_IPO_ENCODE, IPOPT_ENCODE }, + { IL_IPO_TS, IPOPT_TS }, + { IL_IPO_TR, IPOPT_TR }, + { IL_IPO_SEC, IPOPT_SECURITY }, + { IL_IPO_SECCLASS, IPOPT_SECURITY }, + { IL_IPO_LSRR, IPOPT_LSRR }, + { IL_IPO_ESEC, IPOPT_E_SEC }, + { IL_IPO_CIPSO, IPOPT_CIPSO }, + { IL_IPO_SATID, IPOPT_SATID }, + { IL_IPO_SSRR, IPOPT_SSRR }, + { IL_IPO_ADDEXT, IPOPT_ADDEXT }, + { IL_IPO_VISA, IPOPT_VISA }, + { IL_IPO_IMITD, IPOPT_IMITD }, + { IL_IPO_EIP, IPOPT_EIP }, + { IL_IPO_FINN, IPOPT_FINN }, + { 0, 0 } +}; + +struct statetoopt tosecopts[] = { + { IL_IPS_RESERV4, IPSO_CLASS_RES4 }, + { IL_IPS_TOPSECRET, IPSO_CLASS_TOPS }, + { IL_IPS_SECRET, IPSO_CLASS_SECR }, + { IL_IPS_RESERV3, IPSO_CLASS_RES3 }, + { IL_IPS_CONFID, IPSO_CLASS_CONF }, + { IL_IPS_UNCLASS, IPSO_CLASS_UNCL }, + { IL_IPS_RESERV2, IPSO_CLASS_RES2 }, + { IL_IPS_RESERV1, IPSO_CLASS_RES1 }, + { 0, 0 } +}; + +#ifdef bsdi +struct ether_addr * +ether_aton(s) + char *s; +{ + static struct ether_addr n; + u_int i[6]; + + if (sscanf(s, " %x:%x:%x:%x:%x:%x ", &i[0], &i[1], + &i[2], &i[3], &i[4], &i[5]) == 6) { + n.ether_addr_octet[0] = (u_char)i[0]; + n.ether_addr_octet[1] = (u_char)i[1]; + n.ether_addr_octet[2] = (u_char)i[2]; + n.ether_addr_octet[3] = (u_char)i[3]; + n.ether_addr_octet[4] = (u_char)i[4]; + n.ether_addr_octet[5] = (u_char)i[5]; + return &n; + } + return NULL; +} +#endif + + +struct in_addr getipv4addr(arg) +char *arg; +{ + struct hostent *hp; + struct in_addr in; + + in.s_addr = 0xffffffff; + + if ((hp = gethostbyname(arg))) + bcopy(hp->h_addr, &in.s_addr, sizeof(struct in_addr)); + else + in.s_addr = inet_addr(arg); + return in; +} + + +u_short getportnum(pr, name) +char *pr, *name; +{ + struct servent *sp; + + if (!(sp = getservbyname(name, pr))) + return htons(atoi(name)); + return sp->s_port; +} + + +struct ether_addr *geteaddr(arg, buf) +char *arg; +struct ether_addr *buf; +{ + struct ether_addr *e; + +#if !defined(hpux) && !defined(linux) + e = ether_aton(arg); + if (!e) + fprintf(stderr, "Invalid ethernet address: %s\n", arg); + else +# ifdef __FreeBSD__ + bcopy(e->octet, buf->octet, sizeof(e->octet)); +# else + bcopy(e->ether_addr_octet, buf->ether_addr_octet, + sizeof(e->ether_addr_octet)); +# endif + return e; +#else + return NULL; +#endif +} + + +void *new_header(type) +int type; +{ + aniphdr_t *aip, *oip = canip; + int sz = 0; + + aip = (aniphdr_t *)calloc(1, sizeof(*aip)); + *aniptail = aip; + aniptail = &aip->ah_next; + aip->ah_p = type; + aip->ah_prev = oip; + canip = aip; + + if (type == IPPROTO_UDP) + sz = sizeof(udphdr_t); + else if (type == IPPROTO_TCP) + sz = sizeof(tcphdr_t); + else if (type == IPPROTO_ICMP) + sz = sizeof(icmphdr_t); + else if (type == IPPROTO_IP) + sz = sizeof(ip_t); + + if (oip) + canip->ah_data = oip->ah_data + oip->ah_len; + else + canip->ah_data = (char *)ipbuffer; + + /* + * Increase the size fields in all wrapping headers. + */ + for (aip = aniphead; aip; aip = aip->ah_next) { + aip->ah_len += sz; + if (aip->ah_p == IPPROTO_IP) + aip->ah_ip->ip_len += sz; + else if (aip->ah_p == IPPROTO_UDP) + aip->ah_udp->uh_ulen += sz; + } + return (void *)canip->ah_data; +} + + +void free_aniplist() +{ + aniphdr_t *aip, **aipp = &aniphead; + + while ((aip = *aipp)) { + *aipp = aip->ah_next; + free(aip); + } + aniptail = &aniphead; +} + + +void inc_anipheaders(inc) +int inc; +{ + aniphdr_t *aip; + + for (aip = aniphead; aip; aip = aip->ah_next) { + aip->ah_len += inc; + if (aip->ah_p == IPPROTO_IP) + aip->ah_ip->ip_len += inc; + else if (aip->ah_p == IPPROTO_UDP) + aip->ah_udp->uh_ulen += inc; + } +} + + +void new_data() +{ + (void) new_header(-1); + canip->ah_len = 0; +} + + +void set_datalen(arg) +char **arg; +{ + int len; + + len = strtol(*arg, NULL, 0); + inc_anipheaders(len); + free(*arg); + *arg = NULL; +} + + +void set_data(arg) +char **arg; +{ + u_char *s = (u_char *)*arg, *t = (u_char *)canip->ah_data, c; + int len = 0, todo = 0, quote = 0, val = 0; + + while ((c = *s++)) { + if (todo) { + if (ISDIGIT(c)) { + todo--; + if (c > '7') { + fprintf(stderr, "octal with %c!\n", c); + break; + } + val <<= 3; + val |= (c - '0'); + } + if (!ISDIGIT(c) || !todo) { + *t++ = (u_char)(val & 0xff); + todo = 0; + } + if (todo) + continue; + } + if (quote) { + if (ISDIGIT(c)) { + todo = 2; + if (c > '7') { + fprintf(stderr, "octal with %c!\n", c); + break; + } + val = (c - '0'); + } else { + switch (c) + { + case '\"' : + *t++ = '\"'; + break; + case '\\' : + *t++ = '\\'; + break; + case 'n' : + *t++ = '\n'; + break; + case 'r' : + *t++ = '\r'; + break; + case 't' : + *t++ = '\t'; + break; + } + } + quote = 0; + continue; + } + + if (c == '\\') + quote = 1; + else + *t++ = c; + } + if (todo) + *t++ = (u_char)(val & 0xff); + if (quote) + *t++ = '\\'; + len = t - (u_char *)canip->ah_data; + inc_anipheaders(len - canip->ah_len); + canip->ah_len = len; +} + + +void set_datafile(arg) +char **arg; +{ + struct stat sb; + char *file = *arg; + int fd, len; + + if ((fd = open(file, O_RDONLY)) == -1) { + perror("open"); + exit(-1); + } + + if (fstat(fd, &sb) == -1) { + perror("fstat"); + exit(-1); + } + + if ((sb.st_size + aniphead->ah_len ) > 65535) { + fprintf(stderr, "data file %s too big to include.\n", file); + close(fd); + return; + } + if ((len = read(fd, canip->ah_data, sb.st_size)) == -1) { + perror("read"); + close(fd); + return; + } + inc_anipheaders(len); + canip->ah_len += len; + close(fd); +} + + +void new_packet() +{ + static u_short id = 0; + + if (!aniphead) + bzero((char *)ipbuffer, sizeof(ipbuffer)); + + ip = (ip_t *)new_header(IPPROTO_IP); + ip->ip_v = IPVERSION; + ip->ip_hl = sizeof(ip_t) >> 2; + ip->ip_len = sizeof(ip_t); + ip->ip_ttl = 63; + ip->ip_id = htons(id++); +} + + +void set_ipv4proto(arg) +char **arg; +{ + struct protoent *pr; + + if ((pr = getprotobyname(*arg))) + ip->ip_p = pr->p_proto; + else + if (!(ip->ip_p = atoi(*arg))) + fprintf(stderr, "unknown protocol %s\n", *arg); + free(*arg); + *arg = NULL; +} + + +void set_ipv4src(arg) +char **arg; +{ + ip->ip_src = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_ipv4dst(arg) +char **arg; +{ + ip->ip_dst = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_ipv4off(arg) +char **arg; +{ + ip->ip_off = htons(strtol(*arg, NULL, 0)); + free(*arg); + *arg = NULL; +} + + +void set_ipv4v(arg) +char **arg; +{ + ip->ip_v = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4hl(arg) +char **arg; +{ + int newhl, inc; + + newhl = strtol(*arg, NULL, 0); + inc = (newhl - ip->ip_hl) << 2; + ip->ip_len += inc; + ip->ip_hl = newhl; + canip->ah_len += inc; + free(*arg); + *arg = NULL; +} + + +void set_ipv4ttl(arg) +char **arg; +{ + ip->ip_ttl = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4tos(arg) +char **arg; +{ + ip->ip_tos = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4id(arg) +char **arg; +{ + ip->ip_id = htons(strtol(*arg, NULL, 0)); + free(*arg); + *arg = NULL; +} + + +void set_ipv4sum(arg) +char **arg; +{ + ip->ip_sum = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_ipv4len(arg) +char **arg; +{ + int len; + + len = strtol(*arg, NULL, 0); + inc_anipheaders(len - ip->ip_len); + ip->ip_len = len; + free(*arg); + *arg = NULL; +} + + +void new_tcpheader() +{ + + if ((ip->ip_p) && (ip->ip_p != IPPROTO_TCP)) { + fprintf(stderr, "protocol %d specified with TCP!\n", ip->ip_p); + return; + } + ip->ip_p = IPPROTO_TCP; + + tcp = (tcphdr_t *)new_header(IPPROTO_TCP); + tcp->th_win = htons(4096); + tcp->th_off = sizeof(*tcp) >> 2; +} + + +void set_tcpsport(arg) +char **arg; +{ + u_short *port; + char *pr; + + if (ip->ip_p == IPPROTO_UDP) { + port = &udp->uh_sport; + pr = "udp"; + } else { + port = &tcp->th_sport; + pr = "udp"; + } + + *port = getportnum(pr, *arg); + free(*arg); + *arg = NULL; +} + + +void set_tcpdport(arg) +char **arg; +{ + u_short *port; + char *pr; + + if (ip->ip_p == IPPROTO_UDP) { + port = &udp->uh_dport; + pr = "udp"; + } else { + port = &tcp->th_dport; + pr = "udp"; + } + + *port = getportnum(pr, *arg); + free(*arg); + *arg = NULL; +} + + +void set_tcpseq(arg) +char **arg; +{ + tcp->th_seq = htonl(strtol(*arg, NULL, 0)); + free(*arg); + *arg = NULL; +} + + +void set_tcpack(arg) +char **arg; +{ + tcp->th_ack = htonl(strtol(*arg, NULL, 0)); + free(*arg); + *arg = NULL; +} + + +void set_tcpoff(arg) +char **arg; +{ + int off; + + off = strtol(*arg, NULL, 0); + inc_anipheaders((off - tcp->th_off) << 2); + tcp->th_off = off; + free(*arg); + *arg = NULL; +} + + +void set_tcpurp(arg) +char **arg; +{ + tcp->th_urp = htons(strtol(*arg, NULL, 0)); + free(*arg); + *arg = NULL; +} + + +void set_tcpwin(arg) +char **arg; +{ + tcp->th_win = htons(strtol(*arg, NULL, 0)); + free(*arg); + *arg = NULL; +} + + +void set_tcpsum(arg) +char **arg; +{ + tcp->th_sum = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void set_tcpflags(arg) +char **arg; +{ + static char flags[] = "ASURPF"; + static int flagv[] = { TH_ACK, TH_SYN, TH_URG, TH_RST, TH_PUSH, + TH_FIN } ; + char *s, *t; + + for (s = *arg; *s; s++) + if (!(t = strchr(flags, *s))) { + if (s - *arg) { + fprintf(stderr, "unknown TCP flag %c\n", *s); + break; + } + tcp->th_flags = strtol(*arg, NULL, 0); + break; + } else + tcp->th_flags |= flagv[t - flags]; + free(*arg); + *arg = NULL; +} + + +void set_tcpopt(state, arg) +int state; +char **arg; +{ + u_char *s; + int val, len, val2, pad, optval; + + if (arg && *arg) + val = atoi(*arg); + else + val = 0; + + s = (u_char *)tcp + sizeof(*tcp) + canip->ah_optlen; + switch (state) + { + case IL_TCPO_EOL : + optval = 0; + len = 1; + break; + case IL_TCPO_NOP : + optval = 1; + len = 1; + break; + case IL_TCPO_MSS : + optval = 2; + len = 4; + break; + case IL_TCPO_WSCALE : + optval = 3; + len = 3; + break; + case IL_TCPO_TS : + optval = 8; + len = 10; + break; + default : + optval = 0; + len = 0; + break; + } + + if (len > 1) { + /* + * prepend padding - if required. + */ + if (len & 3) + for (pad = 4 - (len & 3); pad; pad--) { + *s++ = 1; + canip->ah_optlen++; + } + /* + * build tcp option + */ + *s++ = (u_char)optval; + *s++ = (u_char)len; + if (len > 2) { + if (len == 3) { /* 1 byte - char */ + *s++ = (u_char)val; + } else if (len == 4) { /* 2 bytes - short */ + *s++ = (u_char)((val >> 8) & 0xff); + *s++ = (u_char)(val & 0xff); + } else if (len >= 6) { /* 4 bytes - long */ + val2 = htonl(val); + bcopy((char *)&val2, s, 4); + } + s += (len - 2); + } + } else + *s++ = (u_char)optval; + + canip->ah_lastopt = optval; + canip->ah_optlen += len; + + if (arg && *arg) { + free(*arg); + *arg = NULL; + } +} + + +void end_tcpopt() +{ + int pad; + char *s = (char *)tcp; + + s += sizeof(*tcp) + canip->ah_optlen; + /* + * pad out so that we have a multiple of 4 bytes in size fo the + * options. make sure last byte is EOL. + */ + if (canip->ah_optlen & 3) { + if (canip->ah_lastopt != 1) { + for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) { + *s++ = 1; + canip->ah_optlen++; + } + canip->ah_optlen++; + } else { + s -= 1; + + for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) { + *s++ = 1; + canip->ah_optlen++; + } + } + *s++ = 0; + } + tcp->th_off = (sizeof(*tcp) + canip->ah_optlen) >> 2; + inc_anipheaders(canip->ah_optlen); +} + + +void new_udpheader() +{ + if ((ip->ip_p) && (ip->ip_p != IPPROTO_UDP)) { + fprintf(stderr, "protocol %d specified with UDP!\n", ip->ip_p); + return; + } + ip->ip_p = IPPROTO_UDP; + + udp = (udphdr_t *)new_header(IPPROTO_UDP); + udp->uh_ulen = sizeof(*udp); +} + + +void set_udplen(arg) +char **arg; +{ + int len; + + len = strtol(*arg, NULL, 0); + inc_anipheaders(len - udp->uh_ulen); + udp->uh_ulen = len; + free(*arg); + *arg = NULL; +} + + +void set_udpsum(arg) +char **arg; +{ + udp->uh_sum = strtol(*arg, NULL, 0); + free(*arg); + *arg = NULL; +} + + +void prep_packet() +{ + iface_t *ifp; + struct in_addr gwip; + + ifp = sending.snd_if; + if (!ifp) { + fprintf(stderr, "no interface defined for sending!\n"); + return; + } + if (ifp->if_fd == -1) + ifp->if_fd = initdevice(ifp->if_name, 5); + gwip = sending.snd_gw; + if (!gwip.s_addr) { + if (aniphead == NULL) { + fprintf(stderr, + "no destination address defined for sending\n"); + return; + } + gwip = aniphead->ah_ip->ip_dst; + } + (void) send_ip(ifp->if_fd, ifp->if_MTU, (ip_t *)ipbuffer, gwip, 2); +} + + +void packet_done() +{ + char outline[80]; + int i, j, k; + u_char *s = (u_char *)ipbuffer, *t = (u_char *)outline; + + if (opts & OPT_VERBOSE) { + ip->ip_len = htons(ip->ip_len); + for (i = ntohs(ip->ip_len), j = 0; i; i--, j++, s++) { + if (j && !(j & 0xf)) { + *t++ = '\n'; + *t = '\0'; + fputs(outline, stdout); + fflush(stdout); + t = (u_char *)outline; + *t = '\0'; + } + sprintf((char *)t, "%02x", *s & 0xff); + t += 2; + if (!((j + 1) & 0xf)) { + s -= 15; + sprintf((char *)t, " "); + t += 8; + for (k = 16; k; k--, s++) + *t++ = (isprint(*s) ? *s : '.'); + s--; + } + + if ((j + 1) & 0xf) + *t++ = ' ';; + } + + if (j & 0xf) { + for (k = 16 - (j & 0xf); k; k--) { + *t++ = ' '; + *t++ = ' '; + *t++ = ' '; + } + sprintf((char *)t, " "); + t += 7; + s -= j & 0xf; + for (k = j & 0xf; k; k--, s++) + *t++ = (isprint(*s) ? *s : '.'); + *t++ = '\n'; + *t = '\0'; + } + fputs(outline, stdout); + fflush(stdout); + ip->ip_len = ntohs(ip->ip_len); + } + + prep_packet(); + free_aniplist(); +} + + +void new_interface() +{ + cifp = (iface_t *)calloc(1, sizeof(iface_t)); + *iftail = cifp; + iftail = &cifp->if_next; + cifp->if_fd = -1; +} + + +void check_interface() +{ + if (!cifp->if_name || !*cifp->if_name) + fprintf(stderr, "No interface name given!\n"); + if (!cifp->if_MTU || !*cifp->if_name) + fprintf(stderr, "Interface %s has an MTU of 0!\n", + cifp->if_name); +} + + +void set_ifname(arg) +char **arg; +{ + cifp->if_name = *arg; + *arg = NULL; +} + + +void set_ifmtu(arg) +int arg; +{ + cifp->if_MTU = arg; +} + + +void set_ifv4addr(arg) +char **arg; +{ + cifp->if_addr = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_ifeaddr(arg) +char **arg; +{ + (void) geteaddr(*arg, &cifp->if_eaddr); + free(*arg); + *arg = NULL; +} + + +void new_arp() +{ + carp = (arp_t *)calloc(1, sizeof(arp_t)); + *arptail = carp; + arptail = &carp->arp_next; +} + + +void set_arpeaddr(arg) +char **arg; +{ + (void) geteaddr(*arg, &carp->arp_eaddr); + free(*arg); + *arg = NULL; +} + + +void set_arpv4addr(arg) +char **arg; +{ + carp->arp_addr = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +int arp_getipv4(ip, addr) +char *ip; +char *addr; +{ + arp_t *a; + + for (a = arplist; a; a = a->arp_next) + if (!bcmp(ip, (char *)&a->arp_addr, 4)) { + bcopy((char *)&a->arp_eaddr, addr, 6); + return 0; + } + return -1; +} + + +void reset_send() +{ + sending.snd_if = iflist; + sending.snd_gw = defrouter; +} + + +void set_sendif(arg) +char **arg; +{ + iface_t *ifp; + + for (ifp = iflist; ifp; ifp = ifp->if_next) + if (ifp->if_name && !strcmp(ifp->if_name, *arg)) + break; + sending.snd_if = ifp; + if (!ifp) + fprintf(stderr, "couldn't find interface %s\n", *arg); + free(*arg); + *arg = NULL; +} + + +void set_sendvia(arg) +char **arg; +{ + sending.snd_gw = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_defaultrouter(arg) +char **arg; +{ + defrouter = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void new_icmpheader() +{ + if ((ip->ip_p) && (ip->ip_p != IPPROTO_ICMP)) { + fprintf(stderr, "protocol %d specified with ICMP!\n", + ip->ip_p); + return; + } + ip->ip_p = IPPROTO_ICMP; + icmp = (icmphdr_t *)new_header(IPPROTO_ICMP); +} + + +void set_icmpcode(code) +int code; +{ + icmp->icmp_code = code; +} + + +void set_icmptype(type) +int type; +{ + icmp->icmp_type = type; +} + + +void set_icmpcodetok(code) +char **code; +{ + char *s; + int i; + + for (i = 0; (s = icmpcodes[i]); i++) + if (!strcmp(s, *code)) { + icmp->icmp_code = i; + break; + } + if (!s) + fprintf(stderr, "unknown ICMP code %s\n", *code); + free(*code); + *code = NULL; +} + + +void set_icmptypetok(type) +char **type; +{ + char *s; + int i, done = 0; + + for (i = 0; !(s = icmptypes[i]) || strcmp(s, "END"); i++) + if (s && !strcmp(s, *type)) { + icmp->icmp_type = i; + done = 1; + break; + } + if (!done) + fprintf(stderr, "unknown ICMP type %s\n", *type); + free(*type); + *type = NULL; +} + + +void set_icmpid(arg) +int arg; +{ + icmp->icmp_id = htons(arg); +} + + +void set_icmpseq(arg) +int arg; +{ + icmp->icmp_seq = htons(arg); +} + + +void set_icmpotime(arg) +int arg; +{ + icmp->icmp_otime = htonl(arg); +} + + +void set_icmprtime(arg) +int arg; +{ + icmp->icmp_rtime = htonl(arg); +} + + +void set_icmpttime(arg) +int arg; +{ + icmp->icmp_ttime = htonl(arg); +} + + +void set_icmpmtu(arg) +int arg; +{ +#if BSD >= 199306 + icmp->icmp_nextmtu = htons(arg); +#endif +} + + +void set_redir(redir, arg) +int redir; +char **arg; +{ + icmp->icmp_code = redir; + icmp->icmp_gwaddr = getipv4addr(*arg); + free(*arg); + *arg = NULL; +} + + +void set_icmppprob(num) +int num; +{ + icmp->icmp_pptr = num; +} + + +void new_ipv4opt() +{ + new_header(-2); +} + + +void add_ipopt(state, ptr) +int state; +void *ptr; +{ + struct ipopt_names *io; + struct statetoopt *sto; + char numbuf[16], *arg, **param = ptr; + int inc, hlen; + + if (state == IL_IPO_RR || state == IL_IPO_SATID) { + if (param) + sprintf(numbuf, "%d", *(int *)param); + else + strcpy(numbuf, "0"); + arg = numbuf; + } else + arg = param ? *param : NULL; + + if (canip->ah_next) { + fprintf(stderr, "cannot specify options after data body\n"); + return; + } + for (sto = toipopts; sto->sto_st; sto++) + if (sto->sto_st == state) + break; + if (!sto->sto_st) { + fprintf(stderr, "No mapping for state %d to IP option\n", + state); + return; + } + + hlen = sizeof(ip_t) + canip->ah_optlen; + for (io = ionames; io->on_name; io++) + if (io->on_value == sto->sto_op) + break; + canip->ah_lastopt = io->on_value; + + if (io->on_name) { + inc = addipopt((char *)ip + hlen, io, hlen - sizeof(ip_t),arg); + if (inc > 0) { + while (inc & 3) { + ((char *)ip)[sizeof(*ip) + inc] = IPOPT_NOP; + canip->ah_lastopt = IPOPT_NOP; + inc++; + } + hlen += inc; + } + } + + canip->ah_optlen = hlen - sizeof(ip_t); + + if (state != IL_IPO_RR && state != IL_IPO_SATID) + if (param && *param) { + free(*param); + *param = NULL; + } + sclass = NULL; +} + + +void end_ipopt() +{ + int pad; + char *s, *buf = (char *)ip; + + /* + * pad out so that we have a multiple of 4 bytes in size fo the + * options. make sure last byte is EOL. + */ + if (canip->ah_lastopt == IPOPT_NOP) { + buf[sizeof(*ip) + canip->ah_optlen - 1] = IPOPT_EOL; + } else if (canip->ah_lastopt != IPOPT_EOL) { + s = buf + sizeof(*ip) + canip->ah_optlen; + + for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) { + *s++ = IPOPT_NOP; + *s = IPOPT_EOL; + canip->ah_optlen++; + } + canip->ah_optlen++; + } else { + s = buf + sizeof(*ip) + canip->ah_optlen - 1; + + for (pad = 3 - (canip->ah_optlen & 3); pad; pad--) { + *s++ = IPOPT_NOP; + *s = IPOPT_EOL; + canip->ah_optlen++; + } + } + ip->ip_hl = (sizeof(*ip) + canip->ah_optlen) >> 2; + inc_anipheaders(canip->ah_optlen); + free_anipheader(); +} + + +void set_secclass(arg) +char **arg; +{ + sclass = *arg; + *arg = NULL; +} + + +void free_anipheader() +{ + aniphdr_t *aip; + + aip = canip; + if ((canip = aip->ah_prev)) { + canip->ah_next = NULL; + aniptail = &canip->ah_next; + } + + if (canip) + free(aip); +} + + +void end_ipv4() +{ + aniphdr_t *aip; + + ip->ip_sum = 0; + ip->ip_len = htons(ip->ip_len); + ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); + ip->ip_len = ntohs(ip->ip_len); + free_anipheader(); + for (aip = aniphead, ip = NULL; aip; aip = aip->ah_next) + if (aip->ah_p == IPPROTO_IP) + ip = aip->ah_ip; +} + + +void end_icmp() +{ + aniphdr_t *aip; + + icmp->icmp_cksum = 0; + icmp->icmp_cksum = chksum((u_short *)icmp, canip->ah_len); + free_anipheader(); + for (aip = aniphead, icmp = NULL; aip; aip = aip->ah_next) + if (aip->ah_p == IPPROTO_ICMP) + icmp = aip->ah_icmp; +} + + +void end_udp() +{ + u_long sum; + aniphdr_t *aip; + ip_t iptmp; + + bzero((char *)&iptmp, sizeof(iptmp)); + iptmp.ip_p = ip->ip_p; + iptmp.ip_src = ip->ip_src; + iptmp.ip_dst = ip->ip_dst; + iptmp.ip_len = htons(ip->ip_len - (ip->ip_hl << 2)); + sum = p_chksum((u_short *)&iptmp, (u_int)sizeof(iptmp)); + udp->uh_ulen = htons(udp->uh_ulen); + udp->uh_sum = c_chksum((u_short *)udp, (u_int)ntohs(iptmp.ip_len), sum); + free_anipheader(); + for (aip = aniphead, udp = NULL; aip; aip = aip->ah_next) + if (aip->ah_p == IPPROTO_UDP) + udp = aip->ah_udp; +} + + +void end_tcp() +{ + u_long sum; + aniphdr_t *aip; + ip_t iptmp; + + bzero((char *)&iptmp, sizeof(iptmp)); + iptmp.ip_p = ip->ip_p; + iptmp.ip_src = ip->ip_src; + iptmp.ip_dst = ip->ip_dst; + iptmp.ip_len = htons(ip->ip_len - (ip->ip_hl << 2)); + sum = p_chksum((u_short *)&iptmp, (u_int)sizeof(iptmp)); + tcp->th_sum = 0; + tcp->th_sum = c_chksum((u_short *)tcp, (u_int)ntohs(iptmp.ip_len), sum); + free_anipheader(); + for (aip = aniphead, tcp = NULL; aip; aip = aip->ah_next) + if (aip->ah_p == IPPROTO_TCP) + tcp = aip->ah_tcp; +} + + +void end_data() +{ + free_anipheader(); +} + + +void iplang(fp) +FILE *fp; +{ + yyin = fp; + + yydebug = (opts & OPT_DEBUG) ? 1 : 0; + + while (!feof(fp)) + yyparse(); +} + + +u_short c_chksum(buf, len, init) +u_short *buf; +u_int len; +u_long init; +{ + u_long sum = init; + int nwords = len >> 1; + + for(; nwords > 0; nwords--) + sum += *buf++; + sum = (sum>>16) + (sum & 0xffff); + sum += (sum >>16); + return (~sum); +} + + +u_long p_chksum(buf,len) +u_short *buf; +u_int len; +{ + u_long sum = 0; + int nwords = len >> 1; + + for(; nwords > 0; nwords--) + sum += *buf++; + return sum; +} diff --git a/contrib/ipfilter/ipmon.h b/contrib/ipfilter/ipmon.h new file mode 100644 index 0000000..b469cc8 --- /dev/null +++ b/contrib/ipfilter/ipmon.h @@ -0,0 +1,142 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * @(#)ip_fil.h 1.35 6/5/96 + * $Id$ + */ + +typedef struct ipmon_msg_s { + int imm_msglen; + char *imm_msg; + int imm_dsize; + void *imm_data; + time_t imm_when; + int imm_loglevel; +} ipmon_msg_t; + +typedef void (*ims_destroy_func_t)(void *); +typedef void *(*ims_dup_func_t)(void *); +typedef int (*ims_match_func_t)(void *, void *); +typedef void *(*ims_parse_func_t)(char **); +typedef void (*ims_print_func_t)(void *); +typedef int (*ims_store_func_t)(void *, ipmon_msg_t *); + +typedef struct ipmon_saver_s { + char *ims_name; + ims_destroy_func_t ims_destroy; + ims_dup_func_t ims_dup; + ims_match_func_t ims_match; + ims_parse_func_t ims_parse; + ims_print_func_t ims_print; + ims_store_func_t ims_store; +} ipmon_saver_t; + +typedef struct ipmon_saver_int_s { + struct ipmon_saver_int_s *imsi_next; + ipmon_saver_t *imsi_stor; + void *imsi_handle; +} ipmon_saver_int_t; + +typedef struct ipmon_doing_s { + struct ipmon_doing_s *ipmd_next; + void *ipmd_token; + ipmon_saver_t *ipmd_saver; + /* + * ipmd_store is "cached" in this structure to avoid a double + * deref when doing saves.... + */ + int (*ipmd_store)(void *, ipmon_msg_t *); +} ipmon_doing_t; + + +typedef struct ipmon_action { + struct ipmon_action *ac_next; + int ac_mflag; /* collection of things to compare */ + int ac_dflag; /* flags to compliment the doing fields */ + int ac_logpri; + int ac_direction; + char ac_group[FR_GROUPLEN]; + char ac_nattag[16]; + u_32_t ac_logtag; + int ac_type; /* nat/state/ipf */ + int ac_proto; + int ac_rule; + int ac_packet; + int ac_second; + int ac_result; + u_32_t ac_sip; + u_32_t ac_smsk; + u_32_t ac_dip; + u_32_t ac_dmsk; + u_short ac_sport; + u_short ac_dport; + char *ac_iface; + /* + * used with ac_packet/ac_second + */ + struct timeval ac_last; + int ac_pktcnt; + /* + * What to do with matches + */ + ipmon_doing_t *ac_doing; +} ipmon_action_t; + +#define ac_lastsec ac_last.tv_sec +#define ac_lastusec ac_last.tv_usec + +/* + * Flags indicating what fields to do matching upon (ac_mflag). + */ +#define IPMAC_DIRECTION 0x0001 +#define IPMAC_DSTIP 0x0002 +#define IPMAC_DSTPORT 0x0004 +#define IPMAC_EVERY 0x0008 +#define IPMAC_GROUP 0x0010 +#define IPMAC_INTERFACE 0x0020 +#define IPMAC_LOGTAG 0x0040 +#define IPMAC_NATTAG 0x0080 +#define IPMAC_PROTOCOL 0x0100 +#define IPMAC_RESULT 0x0200 +#define IPMAC_RULE 0x0400 +#define IPMAC_SRCIP 0x0800 +#define IPMAC_SRCPORT 0x1000 +#define IPMAC_TYPE 0x2000 +#define IPMAC_WITH 0x4000 + +#define IPMR_BLOCK 1 +#define IPMR_PASS 2 +#define IPMR_NOMATCH 3 +#define IPMR_LOG 4 + +#define IPMON_SYSLOG 0x001 +#define IPMON_RESOLVE 0x002 +#define IPMON_HEXBODY 0x004 +#define IPMON_HEXHDR 0x010 +#define IPMON_TAIL 0x020 +#define IPMON_VERBOSE 0x040 +#define IPMON_NAT 0x080 +#define IPMON_STATE 0x100 +#define IPMON_FILTER 0x200 +#define IPMON_PORTNUM 0x400 +#define IPMON_LOGALL (IPMON_NAT|IPMON_STATE|IPMON_FILTER) +#define IPMON_LOGBODY 0x800 + +#define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) + +#ifndef LOGFAC +#define LOGFAC LOG_LOCAL0 +#endif + +extern void dump_config __P((void)); +extern int load_config __P((char *)); +extern void unload_config __P((void)); +extern void dumphex __P((FILE *, int, char *, int)); +extern int check_action __P((char *, char *, int, int)); +extern char *getword __P((int)); +extern void *add_doing __P((ipmon_saver_t *)); + diff --git a/contrib/ipfilter/ipsd/Celler/ip_compat.h b/contrib/ipfilter/ipsd/Celler/ip_compat.h new file mode 100644 index 0000000..5793776 --- /dev/null +++ b/contrib/ipfilter/ipsd/Celler/ip_compat.h @@ -0,0 +1,203 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1995 by Darren Reed. + * + * This code may be freely distributed as long as it retains this notice + * and is not changed in any way. The author accepts no responsibility + * for the use of this software. I hate legaleese, don't you ? + * + * @(#)ip_compat.h 1.1 9/14/95 + */ + +/* + * These #ifdef's are here mainly for linux, but who knows, they may + * not be in other places or maybe one day linux will grow up and some + * of these will turn up there too. + */ +#ifndef ICMP_UNREACH +# define ICMP_UNREACH ICMP_DEST_UNREACH +#endif +#ifndef ICMP_SOURCEQUENCH +# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH +#endif +#ifndef ICMP_TIMXCEED +# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED +#endif +#ifndef ICMP_PARAMPROB +# define ICMP_PARAMPROB ICMP_PARAMETERPROB +#endif +#ifndef IPVERSION +# define IPVERSION 4 +#endif +#ifndef IPOPT_MINOFF +# define IPOPT_MINOFF 4 +#endif +#ifndef IPOPT_COPIED +# define IPOPT_COPIED(x) ((x)&0x80) +#endif +#ifndef IPOPT_EOL +# define IPOPT_EOL 0 +#endif +#ifndef IPOPT_NOP +# define IPOPT_NOP 1 +#endif +#ifndef IP_MF +# define IP_MF ((u_short)0x2000) +#endif +#ifndef ETHERTYPE_IP +# define ETHERTYPE_IP ((u_short)0x0800) +#endif +#ifndef TH_FIN +# define TH_FIN 0x01 +#endif +#ifndef TH_SYN +# define TH_SYN 0x02 +#endif +#ifndef TH_RST +# define TH_RST 0x04 +#endif +#ifndef TH_PUSH +# define TH_PUSH 0x08 +#endif +#ifndef TH_ACK +# define TH_ACK 0x10 +#endif +#ifndef TH_URG +# define TH_URG 0x20 +#endif +#ifndef IPOPT_EOL +# define IPOPT_EOL 0 +#endif +#ifndef IPOPT_NOP +# define IPOPT_NOP 1 +#endif +#ifndef IPOPT_RR +# define IPOPT_RR 7 +#endif +#ifndef IPOPT_TS +# define IPOPT_TS 68 +#endif +#ifndef IPOPT_SECURITY +# define IPOPT_SECURITY 130 +#endif +#ifndef IPOPT_LSRR +# define IPOPT_LSRR 131 +#endif +#ifndef IPOPT_SATID +# define IPOPT_SATID 136 +#endif +#ifndef IPOPT_SSRR +# define IPOPT_SSRR 137 +#endif +#ifndef IPOPT_SECUR_UNCLASS +# define IPOPT_SECUR_UNCLASS ((u_short)0x0000) +#endif +#ifndef IPOPT_SECUR_CONFID +# define IPOPT_SECUR_CONFID ((u_short)0xf135) +#endif +#ifndef IPOPT_SECUR_EFTO +# define IPOPT_SECUR_EFTO ((u_short)0x789a) +#endif +#ifndef IPOPT_SECUR_MMMM +# define IPOPT_SECUR_MMMM ((u_short)0xbc4d) +#endif +#ifndef IPOPT_SECUR_RESTR +# define IPOPT_SECUR_RESTR ((u_short)0xaf13) +#endif +#ifndef IPOPT_SECUR_SECRET +# define IPOPT_SECUR_SECRET ((u_short)0xd788) +#endif +#ifndef IPOPT_SECUR_TOPSECRET +# define IPOPT_SECUR_TOPSECRET ((u_short)0x6bc5) +#endif + +#ifdef linux +# define icmp icmphdr +# define icmp_type type +# define icmp_code code + +/* + * From /usr/include/netinet/ip_var.h + * !%@#!$@# linux... + */ +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 */ +}; + +typedef struct { + __u16 th_sport; + __u16 th_dport; + __u32 th_seq; + __u32 th_ack; +# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ + defined(vax) + __u8 th_res:4; + __u8 th_off:4; +#else + __u8 th_off:4; + __u8 th_res:4; +#endif + __u8 th_flags; + __u16 th_win; + __u16 th_sum; + __u16 th_urp; +} tcphdr_t; + +typedef struct { + __u16 uh_sport; + __u16 uh_dport; + __s16 uh_ulen; + __u16 uh_sum; +} udphdr_t; + +typedef struct { +# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ + defined(vax) + __u8 ip_hl:4; + __u8 ip_v:4; +# else + __u8 ip_hl:4; + __u8 ip_v:4; +# endif + __u8 ip_tos; + __u16 ip_len; + __u16 ip_id; + __u16 ip_off; + __u8 ip_ttl; + __u8 ip_p; + __u16 ip_sum; + struct in_addr ip_src; + struct in_addr ip_dst; +} ip_t; + +typedef struct { + __u8 ether_dhost[6]; + __u8 ether_shost[6]; + __u16 ether_type; +} ether_header_t; + +# define bcopy(a,b,c) memmove(b,a,c) +# define bcmp(a,b,c) memcmp(a,b,c) + +# define ifnet device + +#else + +typedef struct udphdr udphdr_t; +typedef struct tcphdr tcphdr_t; +typedef struct ip ip_t; +typedef struct ether_header ether_header_t; + +#endif + +#ifdef solaris +# define bcopy(a,b,c) memmove(b,a,c) +# define bcmp(a,b,c) memcmp(a,b,c) +# define bzero(a,b) memset(a,0,b) +#endif diff --git a/contrib/ipfilter/ipsd/Makefile b/contrib/ipfilter/ipsd/Makefile new file mode 100644 index 0000000..d5dde8e --- /dev/null +++ b/contrib/ipfilter/ipsd/Makefile @@ -0,0 +1,61 @@ +# +# Copyright (C) 2012 by Darren Reed. +# +# See the IPFILTER.LICENCE file for details on licencing. +# +OBJS=ipsd.o +BINDEST=/usr/local/bin +SBINDEST=/sbin +MANDIR=/usr/share/man +BPF=sbpf.o +NIT=snit.o +SUNOS4= +BSD= +LINUX=slinux.o +SUNOS5=dlcommon.o sdlpi.o + +CC=gcc +CFLAGS=-g -I.. -I../ipsend + +all: + @echo "Use one of these targets:" + @echo " sunos4-nit (standard SunOS 4.1.x)" + @echo " sunos4-bpf (SunOS4.1.x with BPF in the kernel)" + @echo " bsd-bpf (4.4BSD variant with BPF in the kernel)" + @echo " linux (Linux kernels)" + @echo " sunos5 (Solaris 2.x)" + +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ + +ipsdr: ipsdr.o + $(CC) ipsdr.o -o $@ $(LIBS) + +bpf sunos4-bpf : + make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" + +nit sunos4 sunos4-nit : + make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(NIT) $(SUNOS4)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" + +sunos5 : + make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(SUNOS5)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -Dsolaris" "LIBS=-lsocket -lnsl" + +bsd-bpf : + make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(BSD)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS)" + +linux : + make ipsd "OBJS=$(OBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -I /usr/src/linux" + +ipsd: $(OBJS) $(UNIXOBJS) + $(CC) $(OBJS) $(UNIXOBJS) -o $@ $(LIBS) + +../ipft_sn.o ../ipft_pc.o: + (cd ..; make $(@:../%=%)) + +clean: + rm -rf *.o core a.out ipsd ipsdr diff --git a/contrib/ipfilter/ipsd/README b/contrib/ipfilter/ipsd/README new file mode 100644 index 0000000..eb6b798 --- /dev/null +++ b/contrib/ipfilter/ipsd/README @@ -0,0 +1,32 @@ + +IP Scan Detetor. +---------------- + +This program is designed to be a passive listener for TCP packets sent to +the host. It does not exercise the promiscous mode of interfaces. For +routing Unix boxes (and firewalls which route/proxy) this is sufficient to +detect all packets going to/through them. + +Upon compiling, a predefined set of "sensitive" ports are configured into +the program. Any TCP packets which are seen sent to these ports are counted +and the IP# of the sending host recorded, along with the time of the first +packet to that port for that IP#. + +After a given number of "hits", it will write the current table of packets +out to disk. This number defaults to 10,000. + +To analyze the information written to disk, a sample program called "ipsdr" +is used (should but doesn't implement a tree algorithm for storing data) +which reads all log files it recognises and totals up the number of ports +each host hit. By default, all ports have the same weighting (1). Another +group of passes is then made over this table using a netmask of 0xfffffffe, +grouping all results which fall under the same resulting IP#. This netmask +is then shrunk back to 0, with a output for each level given. This is aimed +at detecting port scans done from different hosts on the same subnet (although +I've not seen this done, if one was trying to do it obscurely...) + +Lastly, being passive means that no action is taken to stop port scans being +done or discourage them. + +Darren +darrenr@pobox.com diff --git a/contrib/ipfilter/ipsd/ipsd.c b/contrib/ipfilter/ipsd/ipsd.c new file mode 100644 index 0000000..ce51c1b --- /dev/null +++ b/contrib/ipfilter/ipsd/ipsd.c @@ -0,0 +1,296 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1995-1998 Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#include <stdio.h> +#include <fcntl.h> +#include <signal.h> +#include <stdlib.h> +#include <netdb.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/ip_icmp.h> +#ifndef linux +#include <netinet/ip_var.h> +#include <netinet/tcpip.h> +#endif +#include "ip_compat.h" +#ifdef linux +#include <linux/sockios.h> +#include "tcpip.h" +#endif +#include "ipsd.h" + +#ifndef lint +static const char sccsid[] = "@(#)ipsd.c 1.3 12/3/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +extern char *optarg; +extern int optind; + +#ifdef linux +char default_device[] = "eth0"; +#else +# ifdef sun +char default_device[] = "le0"; +# else +# ifdef ultrix +char default_device[] = "ln0"; +# else +char default_device[] = "lan0"; +# endif +# endif +#endif + +#define NPORTS 21 + +u_short defports[NPORTS] = { + 7, 9, 20, 21, 23, 25, 53, 69, 79, 111, + 123, 161, 162, 512, 513, 514, 515, 520, 540, 6000, 0 + }; + +ipsd_t *iphits[NPORTS]; +int writes = 0; + + +int ipcmp(sh1, sh2) + sdhit_t *sh1, *sh2; +{ + return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr; +} + + +/* + * Check to see if we've already received a packet from this host for this + * port. + */ +int findhit(ihp, src, dport) + ipsd_t *ihp; + struct in_addr src; + u_short dport; +{ + int i, j, k; + sdhit_t *sh; + + sh = NULL; + + if (ihp->sd_sz == 4) { + for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++) + if (src.s_addr == sh->sh_ip.s_addr) + return 1; + } else { + for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) { + k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr; + if (!k) + return 1; + else if (k < 0) + i -= j; + else + i += j; + } + } + return 0; +} + + +/* + * Search for port number amongst the sorted array of targets we're + * interested in. + */ +int detect(ip, tcp) + ip_t *ip; + tcphdr_t *tcp; +{ + ipsd_t *ihp; + sdhit_t *sh; + int i, j, k; + + for (i = 10, j = 4; j >= 0; j--) { + k = tcp->th_dport - defports[i]; + if (!k) { + ihp = iphits[i]; + if (findhit(ihp, ip->ip_src, tcp->th_dport)) + return 0; + sh = ihp->sd_hit + ihp->sd_cnt; + sh->sh_date = time(NULL); + sh->sh_ip.s_addr = ip->ip_src.s_addr; + if (++ihp->sd_cnt == ihp->sd_sz) + { + ihp->sd_sz += 8; + sh = realloc(sh, ihp->sd_sz * sizeof(*sh)); + ihp->sd_hit = sh; + } + qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp); + return 0; + } + if (k < 0) + i -= j; + else + i += j; + } + return -1; +} + + +/* + * Allocate initial storage for hosts + */ +setuphits() +{ + int i; + + for (i = 0; i < NPORTS; i++) { + if (iphits[i]) { + if (iphits[i]->sd_hit) + free(iphits[i]->sd_hit); + free(iphits[i]); + } + iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t)); + iphits[i]->sd_port = defports[i]; + iphits[i]->sd_cnt = 0; + iphits[i]->sd_sz = 4; + iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4); + } +} + + +/* + * cleanup exits + */ +waiter() +{ + wait(0); +} + + +/* + * Write statistics out to a file + */ +writestats(nwrites) + int nwrites; +{ + ipsd_t **ipsd, *ips; + char fname[32]; + int i, fd; + + (void) sprintf(fname, "/var/log/ipsd/ipsd-hits.%d", nwrites); + fd = open(fname, O_RDWR|O_CREAT|O_TRUNC|O_EXCL, 0644); + for (i = 0, ipsd = iphits; i < NPORTS; i++, ipsd++) { + ips = *ipsd; + if (ips->sd_cnt) { + write(fd, ips, sizeof(ipsd_t)); + write(fd, ips->sd_hit, sizeof(sdhit_t) * ips->sd_sz); + } + } + (void) close(fd); + exit(0); +} + + +void writenow() +{ + signal(SIGCHLD, waiter); + switch (fork()) + { + case 0 : + writestats(writes); + exit(0); + case -1 : + perror("vfork"); + break; + default : + writes++; + setuphits(); + break; + } +} + + +void usage(prog) + char *prog; +{ + fprintf(stderr, "Usage: %s [-d device]\n", prog); + exit(1); +} + + +void detecthits(fd, writecount) + int fd, writecount; +{ + struct in_addr ip; + int hits = 0; + + while (1) { + hits += readloop(fd, ip); + if (hits > writecount) { + writenow(); + hits = 0; + } + } +} + + +main(argc, argv) + int argc; + char *argv[]; +{ + char *name = argv[0], *dev = NULL; + int fd, writeafter = 10000, angelic = 0, c; + + while ((c = getopt(argc, argv, "ad:n:")) != -1) + switch (c) + { + case 'a' : + angelic = 1; + break; + case 'd' : + dev = optarg; + break; + case 'n' : + writeafter = atoi(optarg); + break; + default : + fprintf(stderr, "Unknown option \"%c\"\n", c); + usage(name); + } + + bzero(iphits, sizeof(iphits)); + setuphits(); + + if (!dev) + dev = default_device; + printf("Device: %s\n", dev); + fd = initdevice(dev, 60); + + if (!angelic) { + switch (fork()) + { + case 0 : + (void) close(0); + (void) close(1); + (void) close(2); + (void) setpgrp(0, getpgrp()); + (void) setsid(); + break; + case -1: + perror("fork"); + exit(-1); + default: + exit(0); + } + } + signal(SIGUSR1, writenow); + detecthits(fd, writeafter); +} diff --git a/contrib/ipfilter/ipsd/ipsd.h b/contrib/ipfilter/ipsd/ipsd.h new file mode 100644 index 0000000..f898c99 --- /dev/null +++ b/contrib/ipfilter/ipsd/ipsd.h @@ -0,0 +1,28 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1995-1998 Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * @(#)ipsd.h 1.3 12/3/95 + */ + +typedef struct { + time_t sh_date; + struct in_addr sh_ip; +} sdhit_t; + +typedef struct { + u_int sd_sz; + u_int sd_cnt; + u_short sd_port; + sdhit_t *sd_hit; +} ipsd_t; + +typedef struct { + struct in_addr ss_ip; + int ss_hits; + u_long ss_ports; +} ipss_t; + diff --git a/contrib/ipfilter/ipsd/ipsdr.c b/contrib/ipfilter/ipsd/ipsdr.c new file mode 100644 index 0000000..e1c0c0a --- /dev/null +++ b/contrib/ipfilter/ipsd/ipsdr.c @@ -0,0 +1,314 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1995-1998 Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#include <stdio.h> +#include <fcntl.h> +#include <signal.h> +#include <malloc.h> +#include <netdb.h> +#include <string.h> +#include <sys/dir.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/ip_icmp.h> +#ifndef linux +#include <netinet/ip_var.h> +#include <netinet/tcpip.h> +#endif +#include "ip_compat.h" +#ifdef linux +#include <linux/sockios.h> +#include "tcpip.h" +#endif +#include "ipsd.h" + +#ifndef lint +static const char sccsid[] = "@(#)ipsdr.c 1.3 12/3/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +extern char *optarg; +extern int optind; + +#define NPORTS 21 + +u_short defports[NPORTS] = { + 7, 9, 20, 21, 23, 25, 53, 69, 79, 111, + 123, 161, 162, 512, 513, 513, 515, 520, 540, 6000, 0 + }; +u_short pweights[NPORTS] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + +ipsd_t *iphits[NPORTS]; +int pkts; + + +int ipcmp(sh1, sh2) + sdhit_t *sh1, *sh2; +{ + return sh1->sh_ip.s_addr - sh2->sh_ip.s_addr; +} + + +int ssipcmp(sh1, sh2) + ipss_t *sh1, *sh2; +{ + return sh1->ss_ip.s_addr - sh2->ss_ip.s_addr; +} + + +int countpbits(num) + u_long num; +{ + int i, j; + + for (i = 1, j = 0; i; i <<= 1) + if (num & i) + j++; + return j; +} + + +/* + * Check to see if we've already received a packet from this host for this + * port. + */ +int findhit(ihp, src, dport) + ipsd_t *ihp; + struct in_addr src; + u_short dport; +{ + int i, j, k; + sdhit_t *sh; + + sh = NULL; + + if (ihp->sd_sz == 4) { + for (i = 0, sh = ihp->sd_hit; i < ihp->sd_cnt; i++, sh++) + if (src.s_addr == sh->sh_ip.s_addr) + return 1; + } else { + for (i = ihp->sd_cnt / 2, j = (i / 2) - 1; j >= 0; j--) { + k = ihp->sd_hit[i].sh_ip.s_addr - src.s_addr; + if (!k) + return 1; + else if (k < 0) + i -= j; + else + i += j; + } + } + return 0; +} + + +/* + * Search for port number amongst the sorted array of targets we're + * interested in. + */ +int detect(srcip, dport, date) + struct in_addr srcip; + u_short dport; + time_t date; +{ + ipsd_t *ihp; + sdhit_t *sh; + int i, j, k; + + for (i = 10, j = 4; j >= 0; j--) { + k = dport - defports[i]; + if (!k) { + ihp = iphits[i]; + if (findhit(ihp, srcip, dport)) + return 0; + sh = ihp->sd_hit + ihp->sd_cnt; + sh->sh_date = date; + sh->sh_ip = srcip; + if (++ihp->sd_cnt == ihp->sd_sz) + { + ihp->sd_sz += 8; + sh = realloc(sh, ihp->sd_sz * sizeof(*sh)); + ihp->sd_hit = sh; + } + qsort(sh, ihp->sd_cnt, sizeof(*sh), ipcmp); + return 0; + } + if (k < 0) + i -= j; + else + i += j; + } + return -1; +} + + +/* + * Allocate initial storage for hosts + */ +setuphits() +{ + int i; + + for (i = 0; i < NPORTS; i++) { + if (iphits[i]) { + if (iphits[i]->sd_hit) + free(iphits[i]->sd_hit); + free(iphits[i]); + } + iphits[i] = (ipsd_t *)malloc(sizeof(ipsd_t)); + iphits[i]->sd_port = defports[i]; + iphits[i]->sd_cnt = 0; + iphits[i]->sd_sz = 4; + iphits[i]->sd_hit = (sdhit_t *)malloc(sizeof(sdhit_t) * 4); + } +} + + +/* + * Write statistics out to a file + */ +addfile(file) + char *file; +{ + ipsd_t ipsd, *ips = &ipsd; + sdhit_t hit, *hp; + char fname[32]; + int i, fd, sz; + + if ((fd = open(file, O_RDONLY)) == -1) { + perror("open"); + return; + } + + printf("opened %s\n", file); + do { + if (read(fd, ips, sizeof(*ips)) != sizeof(*ips)) + break; + sz = ips->sd_sz * sizeof(*hp); + hp = (sdhit_t *)malloc(sz); + if (read(fd, hp, sz) != sz) + break; + for (i = 0; i < ips->sd_cnt; i++) + detect(hp[i].sh_ip, ips->sd_port, hp[i].sh_date); + } while (1); + (void) close(fd); +} + + +readfiles(dir) + char *dir; +{ + struct direct **d; + int i, j; + + d = NULL; + i = scandir(dir, &d, NULL, NULL); + + for (j = 0; j < i; j++) { + if (strncmp(d[j]->d_name, "ipsd-hits.", 10)) + continue; + addfile(d[j]->d_name); + } +} + + +void printreport(ss, num) + ipss_t *ss; + int num; +{ + struct in_addr ip; + ipss_t *sp; + int i, j, mask; + u_long ports; + + printf("Hosts detected: %d\n", num); + if (!num) + return; + for (i = 0; i < num; i++) + printf("%s %d %d\n", inet_ntoa(ss[i].ss_ip), ss[i].ss_hits, + countpbits(ss[i].ss_ports)); + + printf("--------------------------\n"); + for (mask = 0xfffffffe, j = 32; j; j--, mask <<= 1) { + ip.s_addr = ss[0].ss_ip.s_addr & mask; + ports = ss[0].ss_ports; + for (i = 1; i < num; i++) { + sp = ss + i; + if (ip.s_addr != (sp->ss_ip.s_addr & mask)) { + printf("Netmask: 0x%08x\n", mask); + printf("%s %d\n", inet_ntoa(ip), + countpbits(ports)); + ip.s_addr = sp->ss_ip.s_addr & mask; + ports = 0; + } + ports |= sp->ss_ports; + } + if (ports) { + printf("Netmask: 0x%08x\n", mask); + printf("%s %d\n", inet_ntoa(ip), countpbits(ports)); + } + } +} + + +collectips() +{ + ipsd_t *ips; + ipss_t *ss; + int i, num, nip, in, j, k; + + for (i = 0; i < NPORTS; i++) + nip += iphits[i]->sd_cnt; + + ss = (ipss_t *)malloc(sizeof(ipss_t) * nip); + + for (in = 0, i = 0, num = 0; i < NPORTS; i++) { + ips = iphits[i]; + for (j = 0; j < ips->sd_cnt; j++) { + for (k = 0; k < num; k++) + if (!bcmp(&ss[k].ss_ip, &ips->sd_hit[j].sh_ip, + sizeof(struct in_addr))) { + ss[k].ss_hits += pweights[i]; + ss[k].ss_ports |= (1 << i); + break; + } + if (k == num) { + ss[num].ss_ip = ips->sd_hit[j].sh_ip; + ss[num].ss_hits = pweights[i]; + ss[k].ss_ports |= (1 << i); + num++; + } + } + } + + qsort(ss, num, sizeof(*ss), ssipcmp); + + printreport(ss, num); +} + + +main(argc, argv) + int argc; + char *argv[]; +{ + char c, *name = argv[0], *dir = NULL; + int fd; + + setuphits(); + dir = dir ? dir : "."; + readfiles(dir); + collectips(); +} diff --git a/contrib/ipfilter/ipsd/linux.h b/contrib/ipfilter/ipsd/linux.h new file mode 100644 index 0000000..f00ea53 --- /dev/null +++ b/contrib/ipfilter/ipsd/linux.h @@ -0,0 +1,17 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * @(#)linux.h 1.1 8/19/95 + */ + +#include <linux/config.h> +#ifdef MODULE +#include <linux/module.h> +#include <linux/version.h> +#endif /* MODULE */ + +#include "ip_compat.h" diff --git a/contrib/ipfilter/ipsd/sbpf.c b/contrib/ipfilter/ipsd/sbpf.c new file mode 100644 index 0000000..74ba197 --- /dev/null +++ b/contrib/ipfilter/ipsd/sbpf.c @@ -0,0 +1,210 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1995-1998 Darren Reed. (from tcplog) + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#ifdef __NetBSD__ +# include <paths.h> +#endif +#include <sys/types.h> +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#if BSD < 199103 +#include <sys/fcntlcom.h> +#endif +#include <sys/dir.h> +#include <net/bpf.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include "ip_compat.h" + +#ifndef lint +static char sbpf[] = "@(#)sbpf.c 1.2 12/3/95 (C)1995 Darren Reed"; +#endif + +/* +(000) ldh [12] +(001) jeq #0x800 jt 2 jf 5 +(002) ldb [23] +(003) jeq #0x6 jt 4 jf 5 +(004) ret #68 +(005) ret #0 +*/ +struct bpf_insn filter[] = { +/* 0. */ { BPF_LD|BPF_H|BPF_ABS, 0, 0, 12 }, +/* 1. */ { BPF_JMP|BPF_JEQ, 0, 3, 0x0800 }, +/* 2. */ { BPF_LD|BPF_B|BPF_ABS, 0, 0, 23 }, +/* 3. */ { BPF_JMP|BPF_JEQ, 0, 1, 0x06 }, +/* 4. */ { BPF_RET, 0, 0, 68 }, +/* 5. */ { BPF_RET, 0, 0, 0 } +}; +/* + * the code herein is dervied from libpcap. + */ +static u_char *buf = NULL; +static u_int bufsize = 32768, timeout = 1; + + +int ack_recv(ep) + char *ep; +{ + struct tcpiphdr tip; + tcphdr_t *tcp; + ip_t *ip; + + ip = (ip_t *)&tip; + tcp = (tcphdr_t *)(ip + 1); + bcopy(ep + 14, (char *)ip, sizeof(*ip)); + bcopy(ep + 14 + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp)); + if (ip->ip_p != IPPROTO_TCP && ip->ip_p != IPPROTO_UDP) + return -1; + if (ip->ip_p & 0x1fff != 0) + return 0; + if (0 == detect(ip, tcp)) + return 1; + return 0; +} + + +int readloop(fd, port, dst) + int fd, port; + struct in_addr dst; +{ + register u_char *bp, *cp, *bufend; + register struct bpf_hdr *bh; + register int cc; + time_t in = time(NULL); + int done = 0; + + while ((cc = read(fd, buf, bufsize)) >= 0) { + if (!cc && (time(NULL) - in) > timeout) + return done; + bp = buf; + bufend = buf + cc; + /* + * loop through each snapshot in the chunk + */ + while (bp < bufend) { + bh = (struct bpf_hdr *)bp; + cp = bp + bh->bh_hdrlen; + done += ack_recv(cp); + bp += BPF_WORDALIGN(bh->bh_caplen + bh->bh_hdrlen); + } + return done; + } + perror("read"); + exit(-1); +} + +int initdevice(device, tout) + char *device; + int tout; +{ + struct bpf_program prog; + struct bpf_version bv; + struct timeval to; + struct ifreq ifr; +#ifdef _PATH_BPF + char *bpfname = _PATH_BPF; + int fd; + + if ((fd = open(bpfname, O_RDWR)) < 0) + { + fprintf(stderr, "no bpf devices available as /dev/bpfxx\n"); + return -1; + } +#else + char bpfname[16]; + int fd = -1, i; + + for (i = 0; i < 16; i++) + { + (void) sprintf(bpfname, "/dev/bpf%d", i); + if ((fd = open(bpfname, O_RDWR)) >= 0) + break; + } + if (i == 16) + { + fprintf(stderr, "no bpf devices available as /dev/bpfxx\n"); + return -1; + } +#endif + + if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) + { + perror("BIOCVERSION"); + return -1; + } + if (bv.bv_major != BPF_MAJOR_VERSION || + bv.bv_minor < BPF_MINOR_VERSION) + { + fprintf(stderr, "kernel bpf (v%d.%d) filter out of date:\n", + bv.bv_major, bv.bv_minor); + fprintf(stderr, "current version: %d.%d\n", + BPF_MAJOR_VERSION, BPF_MINOR_VERSION); + return -1; + } + + (void) strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(fd, BIOCSETIF, &ifr) == -1) + { + fprintf(stderr, "%s(%d):", ifr.ifr_name, fd); + perror("BIOCSETIF"); + exit(1); + } + /* + * set the timeout + */ + timeout = tout; + to.tv_sec = 1; + to.tv_usec = 0; + if (ioctl(fd, BIOCSRTIMEOUT, (caddr_t)&to) == -1) + { + perror("BIOCSRTIMEOUT"); + exit(-1); + } + /* + * get kernel buffer size + */ + if (ioctl(fd, BIOCSBLEN, &bufsize) == -1) + perror("BIOCSBLEN"); + if (ioctl(fd, BIOCGBLEN, &bufsize) == -1) + { + perror("BIOCGBLEN"); + exit(-1); + } + printf("BPF buffer size: %d\n", bufsize); + buf = (u_char*)malloc(bufsize); + + prog.bf_len = sizeof(filter) / sizeof(struct bpf_insn); + prog.bf_insns = filter; + if (ioctl(fd, BIOCSETF, (caddr_t)&prog) == -1) + { + perror("BIOCSETF"); + exit(-1); + } + (void) ioctl(fd, BIOCFLUSH, 0); + return fd; +} diff --git a/contrib/ipfilter/ipsd/sdlpi.c b/contrib/ipfilter/ipsd/sdlpi.c new file mode 100644 index 0000000..00c197b --- /dev/null +++ b/contrib/ipfilter/ipsd/sdlpi.c @@ -0,0 +1,261 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1992-1998 Darren Reed. (from tcplog) + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/stropts.h> + +#include <sys/pfmod.h> +#include <sys/bufmod.h> +#include <sys/dlpi.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#include "ip_compat.h" + +#ifndef lint +static char snitid[] = "%W% %G% (C)1995 Darren Reed"; +#endif + +#define BUFSPACE 32768 + +static int solfd; + +/* + * Be careful to only include those defined in the flags option for the + * interface are included in the header size. + */ +static int timeout; + + +void nullbell() +{ + return 0; +} + + +int ack_recv(ep) + char *ep; +{ + struct tcpiphdr tip; + tcphdr_t *tcp; + ip_t *ip; + + ip = (ip_t *)&tip; + tcp = (tcphdr_t *)(ip + 1); + bcopy(ep, (char *)ip, sizeof(*ip)); + bcopy(ep + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp)); + + if (ip->ip_off & 0x1fff != 0) + return 0; + if (0 == detect(ip, tcp)) + return 1; + return 0; +} + + +int readloop(fd, port, dst) + int fd, port; + struct in_addr dst; +{ + static u_char buf[BUFSPACE]; + register u_char *bp, *cp, *bufend; + register struct sb_hdr *hp; + register int cc; + struct strbuf dbuf; + ether_header_t eh; + time_t now = time(NULL); + int flags = 0, i, done = 0; + + fd = solfd; + dbuf.len = 0; + dbuf.buf = buf; + dbuf.maxlen = sizeof(buf); + /* + * no control data buffer... + */ + while (1) { + (void) signal(SIGALRM, nullbell); + alarm(1); + i = getmsg(fd, NULL, &dbuf, &flags); + alarm(0); + (void) signal(SIGALRM, nullbell); + + cc = dbuf.len; + if ((time(NULL) - now) > timeout) + return done; + if (i == -1) + if (errno == EINTR) + continue; + else + break; + bp = buf; + bufend = buf + cc; + /* + * loop through each snapshot in the chunk + */ + while (bp < bufend) { + /* + * get past bufmod header + */ + hp = (struct sb_hdr *)bp; + cp = (u_char *)((char *)bp + sizeof(*hp)); + bcopy(cp, (char *)&eh, sizeof(eh)); + /* + * next snapshot + */ + bp += hp->sbh_totlen; + cc -= hp->sbh_totlen; + + if (eh.ether_type != ETHERTYPE_IP) + continue; + + cp += sizeof(eh); + done += ack_recv(cp); + } + alarm(1); + } + perror("getmsg"); + exit(-1); +} + +int initdevice(device, tout) + char *device; + int tout; +{ + struct strioctl si; + struct timeval to; + struct ifreq ifr; + struct packetfilt pfil; + u_long if_flags; + u_short *fwp = pfil.Pf_Filter; + char devname[16], *s, buf[256]; + int i, offset, fd, snaplen= 58, chunksize = BUFSPACE; + + (void) sprintf(devname, "/dev/%s", device); + + s = devname + 5; + while (*s && !ISDIGIT(*s)) + s++; + if (!*s) + { + fprintf(stderr, "bad device name %s\n", devname); + exit(-1); + } + i = atoi(s); + *s = '\0'; + /* + * For reading + */ + if ((fd = open(devname, O_RDWR)) < 0) + { + fprintf(stderr, "O_RDWR(0) "); + perror(devname); + exit(-1); + } + if (dlattachreq(fd, i) == -1 || dlokack(fd, buf) == -1) + { + fprintf(stderr, "DLPI error\n"); + exit(-1); + } + dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0); + dlbindack(fd, buf); + /* + * read full headers + */ + if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1) + { + fprintf(stderr, "DLIOCRAW error\n"); + exit(-1); + } + /* + * Create some filter rules for our TCP watcher. We only want ethernet + * pacets which are IP protocol and only the TCP packets from IP. + */ + offset = 6; + *fwp++ = ENF_PUSHWORD + offset; + *fwp++ = ENF_PUSHLIT | ENF_CAND; + *fwp++ = htons(ETHERTYPE_IP); + *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; + *fwp++ = ENF_PUSHLIT | ENF_AND; + *fwp++ = htons(0x00ff); + *fwp++ = ENF_PUSHLIT | ENF_COR; + *fwp++ = htons(IPPROTO_TCP); + *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; + *fwp++ = ENF_PUSHLIT | ENF_AND; + *fwp++ = htons(0x00ff); + *fwp++ = ENF_PUSHLIT | ENF_CAND; + *fwp++ = htons(IPPROTO_UDP); + pfil.Pf_FilterLen = (fwp - &pfil.Pf_Filter[0]); + /* + * put filter in place. + */ + + if (ioctl(fd, I_PUSH, "pfmod") == -1) + { + perror("ioctl: I_PUSH pf"); + exit(1); + } + if (strioctl(fd, PFIOCSETF, -1, sizeof(pfil), (char *)&pfil) == -1) + { + perror("ioctl: PFIOCSETF"); + exit(1); + } + + /* + * arrange to get messages from the NIT STREAM and use NIT_BUF option + */ + if (ioctl(fd, I_PUSH, "bufmod") == -1) + { + perror("ioctl: I_PUSH bufmod"); + exit(1); + } + i = 128; + strioctl(fd, SBIOCSSNAP, -1, sizeof(i), (char *)&i); + /* + * set the timeout + */ + to.tv_sec = 1; + to.tv_usec = 0; + if (strioctl(fd, SBIOCSTIME, -1, sizeof(to), (char *)&to) == -1) + { + perror("strioctl(SBIOCSTIME)"); + exit(-1); + } + /* + * flush read queue + */ + if (ioctl(fd, I_FLUSH, FLUSHR) == -1) + { + perror("I_FLUSHR"); + exit(-1); + } + timeout = tout; + solfd = fd; + return fd; +} diff --git a/contrib/ipfilter/ipsd/slinux.c b/contrib/ipfilter/ipsd/slinux.c new file mode 100644 index 0000000..95ad8e5 --- /dev/null +++ b/contrib/ipfilter/ipsd/slinux.c @@ -0,0 +1,118 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1992-1998 Darren Reed. (from tcplog) + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/dir.h> +#include <linux/netdevice.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include "ip_compat.h" +#include "tcpip.h" + +#ifndef lint +static const char sccsid[] = "@(#)slinux.c 1.1 12/3/95 (C) 1995 Darren Reed"; +#endif + +#define BUFSPACE 32768 + +/* + * Be careful to only include those defined in the flags option for the + * interface are included in the header size. + */ + +static int timeout; +static char *eth_dev = NULL; + + +int ack_recv(bp) + char *bp; +{ + struct tcpip tip; + tcphdr_t *tcp; + ip_t *ip; + + ip = (struct ip *)&tip; + tcp = (tcphdr_t *)(ip + 1); + + bcopy(bp, (char *)&tip, sizeof(tip)); + bcopy(bp + (ip.ip_hl << 2), (char *)tcp, sizeof(*tcp)); + if (0 == detect(ip, tcp)) + return 1; + return 0; +} + + +void readloop(fd, port, dst) + int fd, port; + struct in_addr dst; +{ + static u_char buf[BUFSPACE]; + struct sockaddr dest; + register u_char *bp = buf; + register int cc; + int dlen, done = 0; + time_t now = time(NULL); + + do { + fflush(stdout); + dlen = sizeof(dest); + bzero((char *)&dest, dlen); + cc = recvfrom(fd, buf, BUFSPACE, 0, &dest, &dlen); + if (!cc) + if ((time(NULL) - now) > timeout) + return done; + else + continue; + + if (bp[12] != 0x8 || bp[13] != 0) + continue; /* not ip */ + + /* + * get rid of non-tcp or fragmented packets here. + */ + if (cc >= sizeof(struct tcpiphdr)) + { + if (((bp[14+9] != IPPROTO_TCP) && + (bp[14+9] != IPPROTO_UDP)) || + (bp[14+6] & 0x1f) || (bp[14+6] & 0xff)) + continue; + done += ack_recv(bp + 14); + } + } while (cc >= 0); + perror("read"); + exit(-1); +} + +int initdevice(dev, tout) + char *dev; + int tout; +{ + int fd; + + eth_dev = strdup(dev); + if ((fd = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_IP))) == -1) + { + perror("socket(SOCK_PACKET)"); + exit(-1); + } + + return fd; +} diff --git a/contrib/ipfilter/ipsd/snit.c b/contrib/ipfilter/ipsd/snit.c new file mode 100644 index 0000000..855afd5 --- /dev/null +++ b/contrib/ipfilter/ipsd/snit.c @@ -0,0 +1,228 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1992-1998 Darren Reed. (from tcplog) + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <net/nit.h> +#include <sys/fcntlcom.h> +#include <sys/dir.h> +#include <net/nit_if.h> +#include <net/nit_pf.h> +#include <net/nit_buf.h> +#include <net/packetfilt.h> +#include <sys/stropts.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> + +#ifndef lint +static char snitid[] = "@(#)snit.c 1.2 12/3/95 (C)1995 Darren Reed"; +#endif + +#define BUFSPACE 32768 + +/* + * Be careful to only include those defined in the flags option for the + * interface are included in the header size. + */ +#define BUFHDR_SIZE (sizeof(struct nit_bufhdr)) +#define NIT_HDRSIZE (BUFHDR_SIZE) + +static int timeout; + + +int ack_recv(ep) + char *ep; +{ + struct tcpiphdr tip; + struct tcphdr *tcp; + struct ip *ip; + + ip = (struct ip *)&tip; + tcp = (struct tcphdr *)(ip + 1); + bcopy(ep + 14, (char *)ip, sizeof(*ip)); + bcopy(ep + 14 + (ip->ip_hl << 2), (char *)tcp, sizeof(*tcp)); + if (ip->ip_off & 0x1fff != 0) + return 0; + if (0 == detect(ip, tcp)) + return 1; + return 0; +} + + +int readloop(fd, dst) + int fd; + struct in_addr dst; +{ + static u_char buf[BUFSPACE]; + register u_char *bp, *cp, *bufend; + register struct nit_bufhdr *hp; + register int cc; + time_t now = time(NULL); + int done = 0; + + while ((cc = read(fd, buf, BUFSPACE-1)) >= 0) { + if (!cc) + if ((time(NULL) - now) > timeout) + return done; + else + continue; + bp = buf; + bufend = buf + cc; + /* + * loop through each snapshot in the chunk + */ + while (bp < bufend) { + cp = (u_char *)((char *)bp + NIT_HDRSIZE); + /* + * get past NIT buffer + */ + hp = (struct nit_bufhdr *)bp; + /* + * next snapshot + */ + bp += hp->nhb_totlen; + done += ack_recv(cp); + } + return done; + } + perror("read"); + exit(-1); +} + +int initdevice(device, tout) + char *device; + int tout; +{ + struct strioctl si; + struct timeval to; + struct ifreq ifr; + struct packetfilt pfil; + u_long if_flags; + u_short *fwp = pfil.Pf_Filter; + int ret, offset, fd, snaplen= 76, chunksize = BUFSPACE; + + if ((fd = open("/dev/nit", O_RDWR)) < 0) + { + perror("/dev/nit"); + exit(-1); + } + + /* + * Create some filter rules for our TCP watcher. We only want ethernet + * pacets which are IP protocol and only the TCP packets from IP. + */ + offset = 6; + *fwp++ = ENF_PUSHWORD + offset; + *fwp++ = ENF_PUSHLIT | ENF_CAND; + *fwp++ = htons(ETHERTYPE_IP); + *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; + *fwp++ = ENF_PUSHLIT | ENF_AND; + *fwp++ = htons(0x00ff); + *fwp++ = ENF_PUSHLIT | ENF_COR; + *fwp++ = htons(IPPROTO_TCP); + *fwp++ = ENF_PUSHWORD + sizeof(struct ether_header)/sizeof(short)+4; + *fwp++ = ENF_PUSHLIT | ENF_AND; + *fwp++ = htons(0x00ff); + *fwp++ = ENF_PUSHLIT | ENF_CAND; + *fwp++ = htons(IPPROTO_UDP); + pfil.Pf_FilterLen = fwp - &pfil.Pf_Filter[0]; + /* + * put filter in place. + */ + if (ioctl(fd, I_PUSH, "pf") == -1) + { + perror("ioctl: I_PUSH pf"); + exit(1); + } + if (ioctl(fd, NIOCSETF, &pfil) == -1) + { + perror("ioctl: NIOCSETF"); + exit(1); + } + /* + * arrange to get messages from the NIT STREAM and use NIT_BUF option + */ + ioctl(fd, I_SRDOPT, (char*)RMSGD); + ioctl(fd, I_PUSH, "nbuf"); + /* + * set the timeout + */ + timeout = tout; + si.ic_timout = 1; + to.tv_sec = 1; + to.tv_usec = 0; + si.ic_cmd = NIOCSTIME; + si.ic_len = sizeof(to); + si.ic_dp = (char*)&to; + if (ioctl(fd, I_STR, (char*)&si) == -1) + { + perror("ioctl: NIT timeout"); + exit(-1); + } + /* + * set the chunksize + */ + si.ic_cmd = NIOCSCHUNK; + si.ic_len = sizeof(chunksize); + si.ic_dp = (char*)&chunksize; + if (ioctl(fd, I_STR, (char*)&si) == -1) + perror("ioctl: NIT chunksize"); + if (ioctl(fd, NIOCGCHUNK, (char*)&chunksize) == -1) + { + perror("ioctl: NIT chunksize"); + exit(-1); + } + printf("NIT buffer size: %d\n", chunksize); + + /* + * request the interface + */ + strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = ' '; + si.ic_cmd = NIOCBIND; + si.ic_len = sizeof(ifr); + si.ic_dp = (char*)𝔦 + if (ioctl(fd, I_STR, (char*)&si) == -1) + { + perror(ifr.ifr_name); + exit(1); + } + + /* + * set the snapshot length + */ + si.ic_cmd = NIOCSSNAP; + si.ic_len = sizeof(snaplen); + si.ic_dp = (char*)&snaplen; + if (ioctl(fd, I_STR, (char*)&si) == -1) + { + perror("ioctl: NIT snaplen"); + exit(1); + } + (void) ioctl(fd, I_FLUSH, (char*)FLUSHR); + return fd; +} diff --git a/contrib/ipfilter/ipsend/.OLD/ip_compat.h b/contrib/ipfilter/ipsend/.OLD/ip_compat.h new file mode 100644 index 0000000..b5b8f07 --- /dev/null +++ b/contrib/ipfilter/ipsend/.OLD/ip_compat.h @@ -0,0 +1,244 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1995 by Darren Reed. + * + * This code may be freely distributed as long as it retains this notice + * and is not changed in any way. The author accepts no responsibility + * for the use of this software. I hate legaleese, don't you ? + * + * @(#)ip_compat.h 1.2 12/7/95 + */ + +/* + * These #ifdef's are here mainly for linux, but who knows, they may + * not be in other places or maybe one day linux will grow up and some + * of these will turn up there too. + */ +#ifndef ICMP_UNREACH +# define ICMP_UNREACH ICMP_DEST_UNREACH +#endif +#ifndef ICMP_SOURCEQUENCH +# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH +#endif +#ifndef ICMP_TIMXCEED +# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED +#endif +#ifndef ICMP_PARAMPROB +# define ICMP_PARAMPROB ICMP_PARAMETERPROB +#endif +#ifndef IPVERSION +# define IPVERSION 4 +#endif +#ifndef IPOPT_MINOFF +# define IPOPT_MINOFF 4 +#endif +#ifndef IPOPT_COPIED +# define IPOPT_COPIED(x) ((x)&0x80) +#endif +#ifndef IPOPT_EOL +# define IPOPT_EOL 0 +#endif +#ifndef IPOPT_NOP +# define IPOPT_NOP 1 +#endif +#ifndef IP_MF +# define IP_MF ((u_short)0x2000) +#endif +#ifndef ETHERTYPE_IP +# define ETHERTYPE_IP ((u_short)0x0800) +#endif +#ifndef TH_FIN +# define TH_FIN 0x01 +#endif +#ifndef TH_SYN +# define TH_SYN 0x02 +#endif +#ifndef TH_RST +# define TH_RST 0x04 +#endif +#ifndef TH_PUSH +# define TH_PUSH 0x08 +#endif +#ifndef TH_ACK +# define TH_ACK 0x10 +#endif +#ifndef TH_URG +# define TH_URG 0x20 +#endif +#ifndef IPOPT_EOL +# define IPOPT_EOL 0 +#endif +#ifndef IPOPT_NOP +# define IPOPT_NOP 1 +#endif +#ifndef IPOPT_RR +# define IPOPT_RR 7 +#endif +#ifndef IPOPT_TS +# define IPOPT_TS 68 +#endif +#ifndef IPOPT_SECURITY +# define IPOPT_SECURITY 130 +#endif +#ifndef IPOPT_LSRR +# define IPOPT_LSRR 131 +#endif +#ifndef IPOPT_SATID +# define IPOPT_SATID 136 +#endif +#ifndef IPOPT_SSRR +# define IPOPT_SSRR 137 +#endif +#ifndef IPOPT_SECUR_UNCLASS +# define IPOPT_SECUR_UNCLASS ((u_short)0x0000) +#endif +#ifndef IPOPT_SECUR_CONFID +# define IPOPT_SECUR_CONFID ((u_short)0xf135) +#endif +#ifndef IPOPT_SECUR_EFTO +# define IPOPT_SECUR_EFTO ((u_short)0x789a) +#endif +#ifndef IPOPT_SECUR_MMMM +# define IPOPT_SECUR_MMMM ((u_short)0xbc4d) +#endif +#ifndef IPOPT_SECUR_RESTR +# define IPOPT_SECUR_RESTR ((u_short)0xaf13) +#endif +#ifndef IPOPT_SECUR_SECRET +# define IPOPT_SECUR_SECRET ((u_short)0xd788) +#endif +#ifndef IPOPT_SECUR_TOPSECRET +# define IPOPT_SECUR_TOPSECRET ((u_short)0x6bc5) +#endif + +#ifdef linux +# if LINUX < 0200 +# define icmp icmphdr +# define icmp_type type +# define icmp_code code +# endif + +/* + * From /usr/include/netinet/ip_var.h + * !%@#!$@# linux... + */ +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 */ +}; + +typedef struct { + __u16 th_sport; + __u16 th_dport; + __u32 th_seq; + __u32 th_ack; +# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ + defined(vax) + __u8 th_res:4; + __u8 th_off:4; +#else + __u8 th_off:4; + __u8 th_res:4; +#endif + __u8 th_flags; + __u16 th_win; + __u16 th_sum; + __u16 th_urp; +} tcphdr_t; + +typedef struct { + __u16 uh_sport; + __u16 uh_dport; + __s16 uh_ulen; + __u16 uh_sum; +} udphdr_t; + +typedef struct { +# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ + defined(vax) + __u8 ip_hl:4; + __u8 ip_v:4; +# else + __u8 ip_hl:4; + __u8 ip_v:4; +# endif + __u8 ip_tos; + __u16 ip_len; + __u16 ip_id; + __u16 ip_off; + __u8 ip_ttl; + __u8 ip_p; + __u16 ip_sum; + struct in_addr ip_src; + struct in_addr ip_dst; +} ip_t; + +typedef struct { + __u8 ether_dhost[6]; + __u8 ether_shost[6]; + __u16 ether_type; +} ether_header_t; + +typedef 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 +} icmphdr_t; + +# define bcopy(a,b,c) memmove(b,a,c) +# define bcmp(a,b,c) memcmp(a,b,c) + +# define ifnet device + +#else + +typedef struct udphdr udphdr_t; +typedef struct tcphdr tcphdr_t; +typedef struct ip ip_t; +typedef struct ether_header ether_header_t; + +#endif + +#if defined(__SVR4) || defined(__svr4__) +# define bcopy(a,b,c) memmove(b,a,c) +# define bcmp(a,b,c) memcmp(a,b,c) +# define bzero(a,b) memset(a,0,b) +#endif diff --git a/contrib/ipfilter/ipsend/44arp.c b/contrib/ipfilter/ipsend/44arp.c new file mode 100644 index 0000000..9215959 --- /dev/null +++ b/contrib/ipfilter/ipsend/44arp.c @@ -0,0 +1,120 @@ +/* $FreeBSD$ */ + +/* + * Based upon 4.4BSD's /usr/sbin/arp + */ +#include <sys/param.h> +#include <sys/file.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_types.h> +#ifndef __osf__ +# include <net/route.h> +#endif +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <netdb.h> +#include <errno.h> +#include <nlist.h> +#include <stdio.h> +#include "ipsend.h" +#include "iplang/iplang.h" + + +/* + * lookup host and return + * its IP address in address + * (4 bytes) + */ +int resolve(host, address) + char *host, *address; +{ + struct hostent *hp; + u_long add; + + add = inet_addr(host); + if (add == -1) + { + if (!(hp = gethostbyname(host))) + { + fprintf(stderr, "unknown host: %s\n", host); + return -1; + } + bcopy((char *)hp->h_addr, (char *)address, 4); + return 0; + } + bcopy((char*)&add, address, 4); + return 0; +} + + +int arp(addr, eaddr) + char *addr, *eaddr; +{ + int mib[6]; + size_t needed; + char *lim, *buf, *next; + struct rt_msghdr *rtm; + struct sockaddr_in *sin; + struct sockaddr_dl *sdl; + +#ifdef IPSEND + if (arp_getipv4(addr, ether) == 0) + return 0; +#endif + + if (!addr) + return -1; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_FLAGS; +#ifdef RTF_LLINFO + mib[5] = RTF_LLINFO; +#else + mib[5] = 0; +#endif + + if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) + { + perror("route-sysctl-estimate"); + exit(-1); + } + if ((buf = malloc(needed)) == NULL) + { + perror("malloc"); + exit(-1); + } + if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) + { + perror("actual retrieval of routing table"); + exit(-1); + } + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) + { + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_in *)(rtm + 1); + sdl = (struct sockaddr_dl *)(sin + 1); + if (!bcmp(addr, (char *)&sin->sin_addr, + sizeof(struct in_addr))) + { + bcopy(LLADDR(sdl), eaddr, sdl->sdl_alen); + return 0; + } + } + return -1; +} diff --git a/contrib/ipfilter/ipsend/Crashable b/contrib/ipfilter/ipsend/Crashable new file mode 100644 index 0000000..c7ffcde --- /dev/null +++ b/contrib/ipfilter/ipsend/Crashable @@ -0,0 +1,21 @@ +Test 1: + Solaris 2.4 - upto and including 101945-34, > 34 ? + Solaris 2.5 - 11/95 + Linux 1.2.13, < 1.3.45(?) + 3com/sonix bridge + Instant Internet + KA9Q NOS + Netblazer 40i, Version 3.2 OS + Irix 6.x + HP-UX 9.0 + HP-UX 10.1 + LivingstonsComOS + MacOS 7.x, 8.x + +Test 6: + SunOS 4.1.x + ULtrix 4.3 + +Test 7: + SunOS 4.1.x + Linux <= 1.3.84 diff --git a/contrib/ipfilter/ipsend/Makefile b/contrib/ipfilter/ipsend/Makefile new file mode 100644 index 0000000..34485ef --- /dev/null +++ b/contrib/ipfilter/ipsend/Makefile @@ -0,0 +1,183 @@ +# +# Copyright (C) 2012 by Darren Reed. +# +# See the IPFILTER.LICENCE file for details on licencing. +# +IPFT=ipft_ef.o ipft_hx.o ipft_pc.o ipft_sn.o ipft_td.o ipft_tx.o opt.o +OBJS=ipsend.o ip.o ipsopt.o y.tab.o lex.yy.o +ROBJS=ipresend.o ip.o resend.o $(IPFT) +TOBJS=iptest.o iptests.o ip.o +BPF=sbpf.o +NIT=snit.o +SUNOS4=sock.o arp.o inet_addr.o +BSD=sock.o 44arp.o +LINUX=lsock.o slinux.o larp.o +LINUXK= +TOP=.. +SUNOS5=dlcommon.o sdlpi.o arp.o inet_addr.o +ULTRIX=ultrix.o sock.o arp.o inet_addr.o +HPUX=hpux.o sock.o arp.o inet_addr.o + +#CC=gcc +DEBUG=-g +CFLAGS=$(DEBUG) -I. -Iipf +# +MFLAGS="BINDEST=$(BINDEST)" "SBINDEST=$(SBINDEST)" "MANDIR=$(MANDIR)" \ + "IPFLKM=$(IPFLKM)" \ + "IPFLOG=$(IPFLOG)" "LOGFAC=$(LOGFAC)" "POLICY=$(POLICY)" \ + "SOLARIS2=$(SOLARIS2)" "DEBUG=$(DEBUG)" "DCPU=$(CPU)" \ + "CPUDIR=$(CPUDIR)" +# +all: + @echo "Use one of these targets:" + @echo " sunos4-nit (standard SunOS 4.1.x)" + @echo " sunos4-bpf (SunOS4.1.x with BPF in the kernel)" + @echo " bsd-bpf (4.4BSD variant with BPF in the kernel)" + @echo " linux10 (Linux 1.0 kernels)" + @echo " linux12 (Linux 1.2 kernels)" + @echo " linux20 (Linux 2.0 kernels)" + @echo " sunos5 (Solaris 2.x)" + +ipf: + -if [ ! -d iplang ] ; then ln -s ../iplang iplang; fi + -if [ ! -d netinet ] ; then ln -s ../netinet netinet; fi + -if [ ! -d ipf ] ; then ln -s .. ipf; fi + +y.tab.o: iplang/iplang_y.y + -if [ -h iplang ] ; then \ + (cd iplang; ${MAKE} $(MFLAGS) 'DESTDIR=../ipsend' ) \ + else \ + (cd iplang; ${MAKE} $(MFLAGS) 'DESTDIR=..' ) \ + fi + +lex.yy.o: iplang/iplang_l.l + -if [ -h iplang ] ; then \ + (cd iplang; ${MAKE} $(MFLAGS) 'DESTDIR=../ipsend' ) \ + else \ + (cd iplang; ${MAKE} $(MFLAGS) 'DESTDIR=..' ) \ + fi + +.c.o: + $(CC) $(CFLAGS) $(LINUXK) -c $< -o $@ + +install: + -$(INSTALL) -cs -g wheel -m 755 -o root ipsend ipresend iptest $(BINDEST) + +bpf sunos4-bpf : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET -DIPSEND" "LLIB=-ll" + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET" + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(BPF) $(SUNOS4)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET" + +nit sunos4 sunos4-nit : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(NIT) $(SUNOS4)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET -DIPSEND" "LLIB=-ll" + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(NIT) $(SUNOS4)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET" + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(NIT) $(SUNOS4)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET" + +dlpi sunos5 : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(SUNOS5)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -Dsolaris -DIPSEND" "LIBS=-lsocket -lnsl" \ + "LLIB=-ll" + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(SUNOS5)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -Dsolaris" "LIBS=-lsocket -lnsl" + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(SUNOS5)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -Dsolaris" "LIBS=-lsocket -lnsl" + +bsd-bpf : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(BPF) $(BSD)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET -DIPSEND" "LLIB=-ll" + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(BPF) $(BSD)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET" + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(BPF) $(BSD)" "CC=$(CC)" \ + "CFLAGS=$(CFLAGS) -DDOSOCKET" + +linuxrev : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) $(INC) -DDOSOCKET -DIPSEND" $(LINUXK) + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) $(INC) -DDOSOCKET" $(LINUXK) + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(LINUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) $(INC) -DDOSOCKET" $(LINUXK) + +linux10: + make linuxrev 'LINUXK="LINUXK=-DLINUX=0100"' \ + "INC=-I/usr/src/linux/include" "LLIB=-lfl" + +linux12: + make linuxrev 'LINUXK="LINUXK=-DLINUX=0102"' "INC=-I/usr/src/linux" \ + "LLIB=-lfl" + +linux20: + make linuxrev 'LINUXK="LINUXK=-DLINUX=0200"' \ + "INC=-I/usr/src/linux/include" "LLIB=-lfl" "ELIB=-lelf" + +ultrix : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(ULTRIX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -DIPSEND" "LIBS=" "LLIB=-ll" + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(ULTRIX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS)" "LIBS=" + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(ULTRIX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS)" "LIBS=" + +hpux9 : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -DIPSEND" "LIBS=" + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS)" "LIBS=" + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS)" "LIBS=" + +hpux11 : + make ipsend "OBJS=$(OBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS) -DIPSEND" "LIBS=" + make ipresend "ROBJS=$(ROBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS)" "LIBS=" + make iptest "TOBJS=$(TOBJS)" "UNIXOBJS=$(HPUX)" "CC=$(CC)" \ + CFLAGS="$(CFLAGS)" "LIBS=" + +ipsend: ipf $(OBJS) $(UNIXOBJS) + $(CC) $(OBJS) $(UNIXOBJS) -o $@ $(LIBS) $(LLIB) $(ELIB) + +ipresend: $(ROBJS) $(UNIXOBJS) + $(CC) $(ROBJS) $(UNIXOBJS) -o $@ $(LIBS) $(ELIB) + +iptest: $(TOBJS) $(UNIXOBJS) + $(CC) $(TOBJS) $(UNIXOBJS) -o $@ $(LIBS) $(ELIB) + +ipft_ef.o: ipf/ipft_ef.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h + $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_ef.c -o $@ + +ipft_hx.o: ipf/ipft_hx.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h + $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_hx.c -o $@ + +ipft_pc.o: ipf/ipft_pc.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h + $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_pc.c -o $@ + +ipft_sn.o: ipf/ipft_sn.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h + $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_sn.c -o $@ + +ipft_td.o: ipf/ipft_td.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h + $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_td.c -o $@ + +ipft_tx.o: ipf/ipft_tx.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h + $(CC) $(CFLAGS) $(LINUXK) -c ipf/ipft_tx.c -o $@ + +opt.o: ipf/opt.c ipf/ipt.h ipf/ipf.h ipf/ip_compat.h + $(CC) $(CFLAGS) $(LINUXK) -c ipf/opt.c -o $@ + +inet_addr.o: ipf/inet_addr.c + $(CC) $(CFLAGS) $(LINUXK) -c ipf/inet_addr.c -o $@ + +clean: + rm -rf *.o *core a.out ipsend ipresend iptest + if [ -d iplang ]; then (cd iplang; $(MAKE) $(MFLAGS) clean); fi + if [ -d $(TOP)/iplang ]; then (cd $(TOP)/iplang; $(MAKE) $(MFLAGS) clean); fi + +do-cvs: + find . -type d -name CVS -print | xargs /bin/rm -rf + find . -type f -name .cvsignore -print | xargs /bin/rm -f diff --git a/contrib/ipfilter/ipsend/arp.c b/contrib/ipfilter/ipsend/arp.c new file mode 100644 index 0000000..58a1523 --- /dev/null +++ b/contrib/ipfilter/ipsend/arp.c @@ -0,0 +1,141 @@ +/* $FreeBSD$ */ + +/* + * arp.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)arp.c 1.4 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/types.h> +#include <sys/socket.h> +#if !defined(ultrix) && !defined(hpux) && !defined(__hpux) && !defined(__osf__) && !defined(_AIX51) +# include <sys/sockio.h> +#endif +#include <sys/ioctl.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <net/if.h> +#include <netinet/if_ether.h> +#ifndef ultrix +# include <net/if_arp.h> +#endif +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <stdio.h> +#include <errno.h> +#include <netdb.h> +#include "ipsend.h" +#include "iplang/iplang.h" + + +/* + * lookup host and return + * its IP address in address + * (4 bytes) + */ +int resolve(host, address) + char *host, *address; +{ + struct hostent *hp; + u_long add; + + add = inet_addr(host); + if (add == -1) + { + if (!(hp = gethostbyname(host))) + { + fprintf(stderr, "unknown host: %s\n", host); + return -1; + } + bcopy((char *)hp->h_addr, (char *)address, 4); + return 0; + } + bcopy((char*)&add, address, 4); + return 0; +} + +/* + * ARP for the MAC address corresponding + * to the IP address. This taken from + * some BSD program, I cant remember which. + */ +int arp(ip, ether) + char *ip; + char *ether; +{ + static int sfd = -1; + static char ethersave[6], ipsave[4]; + struct arpreq ar; + struct sockaddr_in *sin, san; + struct hostent *hp; + int fd; + +#ifdef IPSEND + if (arp_getipv4(ip, ether) == 0) + return 0; +#endif + if (!bcmp(ipsave, ip, 4)) { + bcopy(ethersave, ether, 6); + return 0; + } + fd = -1; + bzero((char *)&ar, sizeof(ar)); + sin = (struct sockaddr_in *)&ar.arp_pa; + sin->sin_family = AF_INET; + bcopy(ip, (char *)&sin->sin_addr.s_addr, 4); +#ifndef hpux + if ((hp = gethostbyaddr(ip, 4, AF_INET))) +# if SOLARIS && (SOLARIS2 >= 10) + if (!(ether_hostton(hp->h_name, (struct ether_addr *)ether))) +# else + if (!(ether_hostton(hp->h_name, ether))) +# endif + goto savearp; +#endif + + if (sfd == -1) + if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + perror("arp: socket"); + return -1; + } +tryagain: + if (ioctl(sfd, SIOCGARP, (caddr_t)&ar) == -1) + { + if (fd == -1) + { + bzero((char *)&san, sizeof(san)); + san.sin_family = AF_INET; + san.sin_port = htons(1); + bcopy(ip, &san.sin_addr.s_addr, 4); + fd = socket(AF_INET, SOCK_DGRAM, 0); + (void) sendto(fd, ip, 4, 0, + (struct sockaddr *)&san, sizeof(san)); + sleep(1); + (void) close(fd); + goto tryagain; + } + fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr)); + if (errno != ENXIO) + perror("SIOCGARP"); + return -1; + } + + if ((ar.arp_ha.sa_data[0] == 0) && (ar.arp_ha.sa_data[1] == 0) && + (ar.arp_ha.sa_data[2] == 0) && (ar.arp_ha.sa_data[3] == 0) && + (ar.arp_ha.sa_data[4] == 0) && (ar.arp_ha.sa_data[5] == 0)) { + fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr)); + return -1; + } + + bcopy(ar.arp_ha.sa_data, ether, 6); +savearp: + bcopy(ether, ethersave, 6); + bcopy(ip, ipsave, 4); + return 0; +} diff --git a/contrib/ipfilter/ipsend/dlcommon.c b/contrib/ipfilter/ipsend/dlcommon.c new file mode 100644 index 0000000..55bc942 --- /dev/null +++ b/contrib/ipfilter/ipsend/dlcommon.c @@ -0,0 +1,1383 @@ +/* $FreeBSD$ */ + +/* + * Common (shared) DLPI test routines. + * Mostly pretty boring boilerplate sorta stuff. + * These can be split into individual library routines later + * but it's just convenient to keep them in a single file + * while they're being developed. + * + * Not supported: + * Connection Oriented stuff + * QOS stuff + */ + +/* +typedef unsigned long ulong; +*/ + + +#include <sys/types.h> +#include <sys/stream.h> +#include <sys/stropts.h> +#ifdef __osf__ +# include <sys/dlpihdr.h> +#else +# include <sys/dlpi.h> +#endif +#include <sys/signal.h> +#include <stdio.h> +#include <string.h> +#include "dltest.h" + +#define CASERET(s) case s: return ("s") + + char *dlprim(); + char *dlstate(); + char *dlerrno(); + char *dlpromisclevel(); + char *dlservicemode(); + char *dlstyle(); + char *dlmactype(); + + +void +dlinforeq(fd) + int fd; +{ + dl_info_req_t info_req; + struct strbuf ctl; + int flags; + + info_req.dl_primitive = DL_INFO_REQ; + + ctl.maxlen = 0; + ctl.len = sizeof (info_req); + ctl.buf = (char *) &info_req; + + flags = RS_HIPRI; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlinforeq: putmsg"); +} + +void +dlinfoack(fd, bufp) + int fd; + char *bufp; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlinfoack"); + + dlp = (union DL_primitives *) ctl.buf; + + expecting(DL_INFO_ACK, dlp); + + if (ctl.len < sizeof (dl_info_ack_t)) + err("dlinfoack: response ctl.len too short: %d", ctl.len); + + if (flags != RS_HIPRI) + err("dlinfoack: DL_INFO_ACK was not M_PCPROTO"); + + if (ctl.len < sizeof (dl_info_ack_t)) + err("dlinfoack: short response ctl.len: %d", ctl.len); +} + +void +dlattachreq(fd, ppa) + int fd; + u_long ppa; +{ + dl_attach_req_t attach_req; + struct strbuf ctl; + int flags; + + attach_req.dl_primitive = DL_ATTACH_REQ; + attach_req.dl_ppa = ppa; + + ctl.maxlen = 0; + ctl.len = sizeof (attach_req); + ctl.buf = (char *) &attach_req; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlattachreq: putmsg"); +} + +void +dlenabmultireq(fd, addr, length) + int fd; + char *addr; + int length; +{ + long buf[MAXDLBUF]; + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + dlp = (union DL_primitives*) buf; + + dlp->enabmulti_req.dl_primitive = DL_ENABMULTI_REQ; + dlp->enabmulti_req.dl_addr_length = length; + dlp->enabmulti_req.dl_addr_offset = sizeof (dl_enabmulti_req_t); + + (void) memcpy((char*)OFFADDR(buf, sizeof (dl_enabmulti_req_t)), addr, length); + + ctl.maxlen = 0; + ctl.len = sizeof (dl_enabmulti_req_t) + length; + ctl.buf = (char*) buf; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlenabmultireq: putmsg"); +} + +void +dldisabmultireq(fd, addr, length) + int fd; + char *addr; + int length; +{ + long buf[MAXDLBUF]; + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + dlp = (union DL_primitives*) buf; + + dlp->disabmulti_req.dl_primitive = DL_ENABMULTI_REQ; + dlp->disabmulti_req.dl_addr_length = length; + dlp->disabmulti_req.dl_addr_offset = sizeof (dl_disabmulti_req_t); + + (void) memcpy((char*)OFFADDR(buf, sizeof (dl_disabmulti_req_t)), addr, length); + + ctl.maxlen = 0; + ctl.len = sizeof (dl_disabmulti_req_t) + length; + ctl.buf = (char*) buf; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dldisabmultireq: putmsg"); +} + +void +dlpromisconreq(fd, level) + int fd; + u_long level; +{ + dl_promiscon_req_t promiscon_req; + struct strbuf ctl; + int flags; + + promiscon_req.dl_primitive = DL_PROMISCON_REQ; + promiscon_req.dl_level = level; + + ctl.maxlen = 0; + ctl.len = sizeof (promiscon_req); + ctl.buf = (char *) &promiscon_req; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlpromiscon: putmsg"); + +} + +void +dlpromiscoff(fd, level) + int fd; + u_long level; +{ + dl_promiscoff_req_t promiscoff_req; + struct strbuf ctl; + int flags; + + promiscoff_req.dl_primitive = DL_PROMISCOFF_REQ; + promiscoff_req.dl_level = level; + + ctl.maxlen = 0; + ctl.len = sizeof (promiscoff_req); + ctl.buf = (char *) &promiscoff_req; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlpromiscoff: putmsg"); +} + +void +dlphysaddrreq(fd, addrtype) + int fd; + u_long addrtype; +{ + dl_phys_addr_req_t phys_addr_req; + struct strbuf ctl; + int flags; + + phys_addr_req.dl_primitive = DL_PHYS_ADDR_REQ; + phys_addr_req.dl_addr_type = addrtype; + + ctl.maxlen = 0; + ctl.len = sizeof (phys_addr_req); + ctl.buf = (char *) &phys_addr_req; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlphysaddrreq: putmsg"); +} + +void +dlsetphysaddrreq(fd, addr, length) + int fd; + char *addr; + int length; +{ + long buf[MAXDLBUF]; + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + dlp = (union DL_primitives*) buf; + + dlp->set_physaddr_req.dl_primitive = DL_ENABMULTI_REQ; + dlp->set_physaddr_req.dl_addr_length = length; + dlp->set_physaddr_req.dl_addr_offset = sizeof (dl_set_phys_addr_req_t); + + (void) memcpy((char*)OFFADDR(buf, sizeof (dl_set_phys_addr_req_t)), addr, length); + + ctl.maxlen = 0; + ctl.len = sizeof (dl_set_phys_addr_req_t) + length; + ctl.buf = (char*) buf; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlsetphysaddrreq: putmsg"); +} + +void +dldetachreq(fd) + int fd; +{ + dl_detach_req_t detach_req; + struct strbuf ctl; + int flags; + + detach_req.dl_primitive = DL_DETACH_REQ; + + ctl.maxlen = 0; + ctl.len = sizeof (detach_req); + ctl.buf = (char *) &detach_req; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dldetachreq: putmsg"); +} + +void +dlbindreq(fd, sap, max_conind, service_mode, conn_mgmt, xidtest) + int fd; + u_long sap; + u_long max_conind; + u_long service_mode; + u_long conn_mgmt; + u_long xidtest; +{ + dl_bind_req_t bind_req; + struct strbuf ctl; + int flags; + + bind_req.dl_primitive = DL_BIND_REQ; + bind_req.dl_sap = sap; + bind_req.dl_max_conind = max_conind; + bind_req.dl_service_mode = service_mode; + bind_req.dl_conn_mgmt = conn_mgmt; + bind_req.dl_xidtest_flg = xidtest; + + ctl.maxlen = 0; + ctl.len = sizeof (bind_req); + ctl.buf = (char *) &bind_req; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlbindreq: putmsg"); +} + +void +dlunitdatareq(fd, addrp, addrlen, minpri, maxpri, datap, datalen) + int fd; + u_char *addrp; + int addrlen; + u_long minpri, maxpri; + u_char *datap; + int datalen; +{ + long buf[MAXDLBUF]; + union DL_primitives *dlp; + struct strbuf data, ctl; + + dlp = (union DL_primitives*) buf; + + dlp->unitdata_req.dl_primitive = DL_UNITDATA_REQ; + dlp->unitdata_req.dl_dest_addr_length = addrlen; + dlp->unitdata_req.dl_dest_addr_offset = sizeof (dl_unitdata_req_t); + dlp->unitdata_req.dl_priority.dl_min = minpri; + dlp->unitdata_req.dl_priority.dl_max = maxpri; + + (void) memcpy(OFFADDR(dlp, sizeof (dl_unitdata_req_t)), addrp, addrlen); + + ctl.maxlen = 0; + ctl.len = sizeof (dl_unitdata_req_t) + addrlen; + ctl.buf = (char *) buf; + + data.maxlen = 0; + data.len = datalen; + data.buf = (char *) datap; + + if (putmsg(fd, &ctl, &data, 0) < 0) + syserr("dlunitdatareq: putmsg"); +} + +void +dlunbindreq(fd) + int fd; +{ + dl_unbind_req_t unbind_req; + struct strbuf ctl; + int flags; + + unbind_req.dl_primitive = DL_UNBIND_REQ; + + ctl.maxlen = 0; + ctl.len = sizeof (unbind_req); + ctl.buf = (char *) &unbind_req; + + flags = 0; + + if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0) + syserr("dlunbindreq: putmsg"); +} + +void +dlokack(fd, bufp) + int fd; + char *bufp; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlokack"); + + dlp = (union DL_primitives *) ctl.buf; + + expecting(DL_OK_ACK, dlp); + + if (ctl.len < sizeof (dl_ok_ack_t)) + err("dlokack: response ctl.len too short: %d", ctl.len); + + if (flags != RS_HIPRI) + err("dlokack: DL_OK_ACK was not M_PCPROTO"); + + if (ctl.len < sizeof (dl_ok_ack_t)) + err("dlokack: short response ctl.len: %d", ctl.len); +} + +void +dlerrorack(fd, bufp) + int fd; + char *bufp; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlerrorack"); + + dlp = (union DL_primitives *) ctl.buf; + + expecting(DL_ERROR_ACK, dlp); + + if (ctl.len < sizeof (dl_error_ack_t)) + err("dlerrorack: response ctl.len too short: %d", ctl.len); + + if (flags != RS_HIPRI) + err("dlerrorack: DL_OK_ACK was not M_PCPROTO"); + + if (ctl.len < sizeof (dl_error_ack_t)) + err("dlerrorack: short response ctl.len: %d", ctl.len); +} + +void +dlbindack(fd, bufp) + int fd; + char *bufp; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlbindack"); + + dlp = (union DL_primitives *) ctl.buf; + + expecting(DL_BIND_ACK, dlp); + + if (flags != RS_HIPRI) + err("dlbindack: DL_OK_ACK was not M_PCPROTO"); + + if (ctl.len < sizeof (dl_bind_ack_t)) + err("dlbindack: short response ctl.len: %d", ctl.len); +} + +void +dlphysaddrack(fd, bufp) + int fd; + char *bufp; +{ + union DL_primitives *dlp; + struct strbuf ctl; + int flags; + + ctl.maxlen = MAXDLBUF; + ctl.len = 0; + ctl.buf = bufp; + + strgetmsg(fd, &ctl, (struct strbuf*)NULL, &flags, "dlphysaddrack"); + + dlp = (union DL_primitives *) ctl.buf; + + expecting(DL_PHYS_ADDR_ACK, dlp); + + if (flags != RS_HIPRI) + err("dlbindack: DL_OK_ACK was not M_PCPROTO"); + + if (ctl.len < sizeof (dl_phys_addr_ack_t)) + err("dlphysaddrack: short response ctl.len: %d", ctl.len); +} + +void +sigalrm() +{ + (void) err("sigalrm: TIMEOUT"); +} + +strgetmsg(fd, ctlp, datap, flagsp, caller) + int fd; + struct strbuf *ctlp, *datap; + int *flagsp; + char *caller; +{ + int rc; + static char errmsg[80]; + + /* + * Start timer. + */ + (void) signal(SIGALRM, sigalrm); + if (alarm(MAXWAIT) < 0) { + (void) sprintf(errmsg, "%s: alarm", caller); + syserr(errmsg); + } + + /* + * Set flags argument and issue getmsg(). + */ + *flagsp = 0; + if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) { + (void) sprintf(errmsg, "%s: getmsg", caller); + syserr(errmsg); + } + + /* + * Stop timer. + */ + if (alarm(0) < 0) { + (void) sprintf(errmsg, "%s: alarm", caller); + syserr(errmsg); + } + + /* + * Check for MOREDATA and/or MORECTL. + */ + if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) + err("%s: MORECTL|MOREDATA", caller); + if (rc & MORECTL) + err("%s: MORECTL", caller); + if (rc & MOREDATA) + err("%s: MOREDATA", caller); + + /* + * Check for at least sizeof (long) control data portion. + */ + if (ctlp->len < sizeof (long)) + err("getmsg: control portion length < sizeof (long): %d", ctlp->len); +} + +expecting(prim, dlp) + int prim; + union DL_primitives *dlp; +{ + if (dlp->dl_primitive != (u_long)prim) { + printdlprim(dlp); + err("expected %s got %s", dlprim(prim), + dlprim(dlp->dl_primitive)); + exit(1); + } +} + +/* + * Print any DLPI msg in human readable format. + */ +printdlprim(dlp) + union DL_primitives *dlp; +{ + switch (dlp->dl_primitive) { + case DL_INFO_REQ: + printdlinforeq(dlp); + break; + + case DL_INFO_ACK: + printdlinfoack(dlp); + break; + + case DL_ATTACH_REQ: + printdlattachreq(dlp); + break; + + case DL_OK_ACK: + printdlokack(dlp); + break; + + case DL_ERROR_ACK: + printdlerrorack(dlp); + break; + + case DL_DETACH_REQ: + printdldetachreq(dlp); + break; + + case DL_BIND_REQ: + printdlbindreq(dlp); + break; + + case DL_BIND_ACK: + printdlbindack(dlp); + break; + + case DL_UNBIND_REQ: + printdlunbindreq(dlp); + break; + + case DL_SUBS_BIND_REQ: + printdlsubsbindreq(dlp); + break; + + case DL_SUBS_BIND_ACK: + printdlsubsbindack(dlp); + break; + + case DL_SUBS_UNBIND_REQ: + printdlsubsunbindreq(dlp); + break; + + case DL_ENABMULTI_REQ: + printdlenabmultireq(dlp); + break; + + case DL_DISABMULTI_REQ: + printdldisabmultireq(dlp); + break; + + case DL_PROMISCON_REQ: + printdlpromisconreq(dlp); + break; + + case DL_PROMISCOFF_REQ: + printdlpromiscoffreq(dlp); + break; + + case DL_UNITDATA_REQ: + printdlunitdatareq(dlp); + break; + + case DL_UNITDATA_IND: + printdlunitdataind(dlp); + break; + + case DL_UDERROR_IND: + printdluderrorind(dlp); + break; + + case DL_UDQOS_REQ: + printdludqosreq(dlp); + break; + + case DL_PHYS_ADDR_REQ: + printdlphysaddrreq(dlp); + break; + + case DL_PHYS_ADDR_ACK: + printdlphysaddrack(dlp); + break; + + case DL_SET_PHYS_ADDR_REQ: + printdlsetphysaddrreq(dlp); + break; + + default: + err("printdlprim: unknown primitive type 0x%x", + dlp->dl_primitive); + break; + } +} + +/* ARGSUSED */ +printdlinforeq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_INFO_REQ\n"); +} + +printdlinfoack(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + u_char brdcst[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->info_ack.dl_addr_offset), + dlp->info_ack.dl_addr_length, addr); + addrtostring(OFFADDR(dlp, dlp->info_ack.dl_brdcst_addr_offset), + dlp->info_ack.dl_brdcst_addr_length, brdcst); + + (void) printf("DL_INFO_ACK: max_sdu %d min_sdu %d\n", + dlp->info_ack.dl_max_sdu, + dlp->info_ack.dl_min_sdu); + (void) printf("addr_length %d mac_type %s current_state %s\n", + dlp->info_ack.dl_addr_length, + dlmactype(dlp->info_ack.dl_mac_type), + dlstate(dlp->info_ack.dl_current_state)); + (void) printf("sap_length %d service_mode %s qos_length %d\n", + dlp->info_ack.dl_sap_length, + dlservicemode(dlp->info_ack.dl_service_mode), + dlp->info_ack.dl_qos_length); + (void) printf("qos_offset %d qos_range_length %d qos_range_offset %d\n", + dlp->info_ack.dl_qos_offset, + dlp->info_ack.dl_qos_range_length, + dlp->info_ack.dl_qos_range_offset); + (void) printf("provider_style %s addr_offset %d version %d\n", + dlstyle(dlp->info_ack.dl_provider_style), + dlp->info_ack.dl_addr_offset, + dlp->info_ack.dl_version); + (void) printf("brdcst_addr_length %d brdcst_addr_offset %d\n", + dlp->info_ack.dl_brdcst_addr_length, + dlp->info_ack.dl_brdcst_addr_offset); + (void) printf("addr %s\n", addr); + (void) printf("brdcst_addr %s\n", brdcst); +} + +printdlattachreq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_ATTACH_REQ: ppa %d\n", + dlp->attach_req.dl_ppa); +} + +printdlokack(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_OK_ACK: correct_primitive %s\n", + dlprim(dlp->ok_ack.dl_correct_primitive)); +} + +printdlerrorack(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_ERROR_ACK: error_primitive %s errno %s unix_errno %d: %s\n", + dlprim(dlp->error_ack.dl_error_primitive), + dlerrno(dlp->error_ack.dl_errno), + dlp->error_ack.dl_unix_errno, + strerror(dlp->error_ack.dl_unix_errno)); +} + +printdlenabmultireq(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->enabmulti_req.dl_addr_offset), + dlp->enabmulti_req.dl_addr_length, addr); + + (void) printf("DL_ENABMULTI_REQ: addr_length %d addr_offset %d\n", + dlp->enabmulti_req.dl_addr_length, + dlp->enabmulti_req.dl_addr_offset); + (void) printf("addr %s\n", addr); +} + +printdldisabmultireq(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->disabmulti_req.dl_addr_offset), + dlp->disabmulti_req.dl_addr_length, addr); + + (void) printf("DL_DISABMULTI_REQ: addr_length %d addr_offset %d\n", + dlp->disabmulti_req.dl_addr_length, + dlp->disabmulti_req.dl_addr_offset); + (void) printf("addr %s\n", addr); +} + +printdlpromisconreq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_PROMISCON_REQ: level %s\n", + dlpromisclevel(dlp->promiscon_req.dl_level)); +} + +printdlpromiscoffreq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_PROMISCOFF_REQ: level %s\n", + dlpromisclevel(dlp->promiscoff_req.dl_level)); +} + +printdlphysaddrreq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_PHYS_ADDR_REQ: addr_type 0x%x\n", + dlp->physaddr_req.dl_addr_type); +} + +printdlphysaddrack(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->physaddr_ack.dl_addr_offset), + dlp->physaddr_ack.dl_addr_length, addr); + + (void) printf("DL_PHYS_ADDR_ACK: addr_length %d addr_offset %d\n", + dlp->physaddr_ack.dl_addr_length, + dlp->physaddr_ack.dl_addr_offset); + (void) printf("addr %s\n", addr); +} + +printdlsetphysaddrreq(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->set_physaddr_req.dl_addr_offset), + dlp->set_physaddr_req.dl_addr_length, addr); + + (void) printf("DL_SET_PHYS_ADDR_REQ: addr_length %d addr_offset %d\n", + dlp->set_physaddr_req.dl_addr_length, + dlp->set_physaddr_req.dl_addr_offset); + (void) printf("addr %s\n", addr); +} + +/* ARGSUSED */ +printdldetachreq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_DETACH_REQ\n"); +} + +printdlbindreq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_BIND_REQ: sap %d max_conind %d\n", + dlp->bind_req.dl_sap, + dlp->bind_req.dl_max_conind); + (void) printf("service_mode %s conn_mgmt %d xidtest_flg 0x%x\n", + dlservicemode(dlp->bind_req.dl_service_mode), + dlp->bind_req.dl_conn_mgmt, + dlp->bind_req.dl_xidtest_flg); +} + +printdlbindack(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->bind_ack.dl_addr_offset), + dlp->bind_ack.dl_addr_length, addr); + + (void) printf("DL_BIND_ACK: sap %d addr_length %d addr_offset %d\n", + dlp->bind_ack.dl_sap, + dlp->bind_ack.dl_addr_length, + dlp->bind_ack.dl_addr_offset); + (void) printf("max_conind %d xidtest_flg 0x%x\n", + dlp->bind_ack.dl_max_conind, + dlp->bind_ack.dl_xidtest_flg); + (void) printf("addr %s\n", addr); +} + +/* ARGSUSED */ +printdlunbindreq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_UNBIND_REQ\n"); +} + +printdlsubsbindreq(dlp) + union DL_primitives *dlp; +{ + u_char sap[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->subs_bind_req.dl_subs_sap_offset), + dlp->subs_bind_req.dl_subs_sap_length, sap); + + (void) printf("DL_SUBS_BIND_REQ: subs_sap_offset %d sub_sap_len %d\n", + dlp->subs_bind_req.dl_subs_sap_offset, + dlp->subs_bind_req.dl_subs_sap_length); + (void) printf("sap %s\n", sap); +} + +printdlsubsbindack(dlp) + union DL_primitives *dlp; +{ + u_char sap[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->subs_bind_ack.dl_subs_sap_offset), + dlp->subs_bind_ack.dl_subs_sap_length, sap); + + (void) printf("DL_SUBS_BIND_ACK: subs_sap_offset %d sub_sap_length %d\n", + dlp->subs_bind_ack.dl_subs_sap_offset, + dlp->subs_bind_ack.dl_subs_sap_length); + (void) printf("sap %s\n", sap); +} + +printdlsubsunbindreq(dlp) + union DL_primitives *dlp; +{ + u_char sap[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->subs_unbind_req.dl_subs_sap_offset), + dlp->subs_unbind_req.dl_subs_sap_length, sap); + + (void) printf("DL_SUBS_UNBIND_REQ: subs_sap_offset %d sub_sap_length %d\n", + dlp->subs_unbind_req.dl_subs_sap_offset, + dlp->subs_unbind_req.dl_subs_sap_length); + (void) printf("sap %s\n", sap); +} + +printdlunitdatareq(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->unitdata_req.dl_dest_addr_offset), + dlp->unitdata_req.dl_dest_addr_length, addr); + + (void) printf("DL_UNITDATA_REQ: dest_addr_length %d dest_addr_offset %d\n", + dlp->unitdata_req.dl_dest_addr_length, + dlp->unitdata_req.dl_dest_addr_offset); + (void) printf("dl_priority.min %d dl_priority.max %d\n", + dlp->unitdata_req.dl_priority.dl_min, + dlp->unitdata_req.dl_priority.dl_max); + (void) printf("addr %s\n", addr); +} + +printdlunitdataind(dlp) + union DL_primitives *dlp; +{ + u_char dest[MAXDLADDR]; + u_char src[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->unitdata_ind.dl_dest_addr_offset), + dlp->unitdata_ind.dl_dest_addr_length, dest); + addrtostring(OFFADDR(dlp, dlp->unitdata_ind.dl_src_addr_offset), + dlp->unitdata_ind.dl_src_addr_length, src); + + (void) printf("DL_UNITDATA_IND: dest_addr_length %d dest_addr_offset %d\n", + dlp->unitdata_ind.dl_dest_addr_length, + dlp->unitdata_ind.dl_dest_addr_offset); + (void) printf("src_addr_length %d src_addr_offset %d\n", + dlp->unitdata_ind.dl_src_addr_length, + dlp->unitdata_ind.dl_src_addr_offset); + (void) printf("group_address 0x%x\n", + dlp->unitdata_ind.dl_group_address); + (void) printf("dest %s\n", dest); + (void) printf("src %s\n", src); +} + +printdluderrorind(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->uderror_ind.dl_dest_addr_offset), + dlp->uderror_ind.dl_dest_addr_length, addr); + + (void) printf("DL_UDERROR_IND: dest_addr_length %d dest_addr_offset %d\n", + dlp->uderror_ind.dl_dest_addr_length, + dlp->uderror_ind.dl_dest_addr_offset); + (void) printf("unix_errno %d errno %s\n", + dlp->uderror_ind.dl_unix_errno, + dlerrno(dlp->uderror_ind.dl_errno)); + (void) printf("addr %s\n", addr); +} + +printdltestreq(dlp) + union DL_primitives *dlp; +{ + u_char addr[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->test_req.dl_dest_addr_offset), + dlp->test_req.dl_dest_addr_length, addr); + + (void) printf("DL_TEST_REQ: flag 0x%x dest_addr_length %d dest_addr_offset %d\n", + dlp->test_req.dl_flag, + dlp->test_req.dl_dest_addr_length, + dlp->test_req.dl_dest_addr_offset); + (void) printf("dest_addr %s\n", addr); +} + +printdltestind(dlp) + union DL_primitives *dlp; +{ + u_char dest[MAXDLADDR]; + u_char src[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->test_ind.dl_dest_addr_offset), + dlp->test_ind.dl_dest_addr_length, dest); + addrtostring(OFFADDR(dlp, dlp->test_ind.dl_src_addr_offset), + dlp->test_ind.dl_src_addr_length, src); + + (void) printf("DL_TEST_IND: flag 0x%x dest_addr_length %d dest_addr_offset %d\n", + dlp->test_ind.dl_flag, + dlp->test_ind.dl_dest_addr_length, + dlp->test_ind.dl_dest_addr_offset); + (void) printf("src_addr_length %d src_addr_offset %d\n", + dlp->test_ind.dl_src_addr_length, + dlp->test_ind.dl_src_addr_offset); + (void) printf("dest_addr %s\n", dest); + (void) printf("src_addr %s\n", src); +} + +printdltestres(dlp) + union DL_primitives *dlp; +{ + u_char dest[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->test_res.dl_dest_addr_offset), + dlp->test_res.dl_dest_addr_length, dest); + + (void) printf("DL_TEST_RES: flag 0x%x dest_addr_length %d dest_addr_offset %d\n", + dlp->test_res.dl_flag, + dlp->test_res.dl_dest_addr_length, + dlp->test_res.dl_dest_addr_offset); + (void) printf("dest_addr %s\n", dest); +} + +printdltestcon(dlp) + union DL_primitives *dlp; +{ + u_char dest[MAXDLADDR]; + u_char src[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->test_con.dl_dest_addr_offset), + dlp->test_con.dl_dest_addr_length, dest); + addrtostring(OFFADDR(dlp, dlp->test_con.dl_src_addr_offset), + dlp->test_con.dl_src_addr_length, src); + + (void) printf("DL_TEST_CON: flag 0x%x dest_addr_length %d dest_addr_offset %d\n", + dlp->test_con.dl_flag, + dlp->test_con.dl_dest_addr_length, + dlp->test_con.dl_dest_addr_offset); + (void) printf("src_addr_length %d src_addr_offset %d\n", + dlp->test_con.dl_src_addr_length, + dlp->test_con.dl_src_addr_offset); + (void) printf("dest_addr %s\n", dest); + (void) printf("src_addr %s\n", src); +} + +printdlxidreq(dlp) + union DL_primitives *dlp; +{ + u_char dest[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->xid_req.dl_dest_addr_offset), + dlp->xid_req.dl_dest_addr_length, dest); + + (void) printf("DL_XID_REQ: flag 0x%x dest_addr_length %d dest_addr_offset %d\n", + dlp->xid_req.dl_flag, + dlp->xid_req.dl_dest_addr_length, + dlp->xid_req.dl_dest_addr_offset); + (void) printf("dest_addr %s\n", dest); +} + +printdlxidind(dlp) + union DL_primitives *dlp; +{ + u_char dest[MAXDLADDR]; + u_char src[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->xid_ind.dl_dest_addr_offset), + dlp->xid_ind.dl_dest_addr_length, dest); + addrtostring(OFFADDR(dlp, dlp->xid_ind.dl_src_addr_offset), + dlp->xid_ind.dl_src_addr_length, src); + + (void) printf("DL_XID_IND: flag 0x%x dest_addr_length %d dest_addr_offset %d\n", + dlp->xid_ind.dl_flag, + dlp->xid_ind.dl_dest_addr_length, + dlp->xid_ind.dl_dest_addr_offset); + (void) printf("src_addr_length %d src_addr_offset %d\n", + dlp->xid_ind.dl_src_addr_length, + dlp->xid_ind.dl_src_addr_offset); + (void) printf("dest_addr %s\n", dest); + (void) printf("src_addr %s\n", src); +} + +printdlxidres(dlp) + union DL_primitives *dlp; +{ + u_char dest[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->xid_res.dl_dest_addr_offset), + dlp->xid_res.dl_dest_addr_length, dest); + + (void) printf("DL_XID_RES: flag 0x%x dest_addr_length %d dest_addr_offset %d\n", + dlp->xid_res.dl_flag, + dlp->xid_res.dl_dest_addr_length, + dlp->xid_res.dl_dest_addr_offset); + (void) printf("dest_addr %s\n", dest); +} + +printdlxidcon(dlp) + union DL_primitives *dlp; +{ + u_char dest[MAXDLADDR]; + u_char src[MAXDLADDR]; + + addrtostring(OFFADDR(dlp, dlp->xid_con.dl_dest_addr_offset), + dlp->xid_con.dl_dest_addr_length, dest); + addrtostring(OFFADDR(dlp, dlp->xid_con.dl_src_addr_offset), + dlp->xid_con.dl_src_addr_length, src); + + (void) printf("DL_XID_CON: flag 0x%x dest_addr_length %d dest_addr_offset %d\n", + dlp->xid_con.dl_flag, + dlp->xid_con.dl_dest_addr_length, + dlp->xid_con.dl_dest_addr_offset); + (void) printf("src_addr_length %d src_addr_offset %d\n", + dlp->xid_con.dl_src_addr_length, + dlp->xid_con.dl_src_addr_offset); + (void) printf("dest_addr %s\n", dest); + (void) printf("src_addr %s\n", src); +} + +printdludqosreq(dlp) + union DL_primitives *dlp; +{ + (void) printf("DL_UDQOS_REQ: qos_length %d qos_offset %d\n", + dlp->udqos_req.dl_qos_length, + dlp->udqos_req.dl_qos_offset); +} + +/* + * Return string. + */ +addrtostring(addr, length, s) + u_char *addr; + u_long length; + u_char *s; +{ + int i; + + for (i = 0; i < length; i++) { + (void) sprintf((char*) s, "%x:", addr[i] & 0xff); + s = s + strlen((char*)s); + } + if (length) + *(--s) = '\0'; +} + +/* + * Return length + */ +stringtoaddr(sp, addr) + char *sp; + char *addr; +{ + int n = 0; + char *p; + int val; + + p = sp; + while (p = strtok(p, ":")) { + if (sscanf(p, "%x", &val) != 1) + err("stringtoaddr: invalid input string: %s", sp); + if (val > 0xff) + err("stringtoaddr: invalid input string: %s", sp); + *addr++ = val; + n++; + p = NULL; + } + + return (n); +} + + +static char +hexnibble(c) + char c; +{ + static char hextab[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + }; + + return (hextab[c & 0x0f]); +} + +char* +dlprim(prim) + u_long prim; +{ + static char primbuf[80]; + + switch ((int)prim) { + CASERET(DL_INFO_REQ); + CASERET(DL_INFO_ACK); + CASERET(DL_ATTACH_REQ); + CASERET(DL_DETACH_REQ); + CASERET(DL_BIND_REQ); + CASERET(DL_BIND_ACK); + CASERET(DL_UNBIND_REQ); + CASERET(DL_OK_ACK); + CASERET(DL_ERROR_ACK); + CASERET(DL_SUBS_BIND_REQ); + CASERET(DL_SUBS_BIND_ACK); + CASERET(DL_UNITDATA_REQ); + CASERET(DL_UNITDATA_IND); + CASERET(DL_UDERROR_IND); + CASERET(DL_UDQOS_REQ); + CASERET(DL_CONNECT_REQ); + CASERET(DL_CONNECT_IND); + CASERET(DL_CONNECT_RES); + CASERET(DL_CONNECT_CON); + CASERET(DL_TOKEN_REQ); + CASERET(DL_TOKEN_ACK); + CASERET(DL_DISCONNECT_REQ); + CASERET(DL_DISCONNECT_IND); + CASERET(DL_RESET_REQ); + CASERET(DL_RESET_IND); + CASERET(DL_RESET_RES); + CASERET(DL_RESET_CON); + default: + (void) sprintf(primbuf, "unknown primitive 0x%x", prim); + return (primbuf); + } +} + + +char* +dlstate(state) + u_long state; +{ + static char statebuf[80]; + + switch (state) { + CASERET(DL_UNATTACHED); + CASERET(DL_ATTACH_PENDING); + CASERET(DL_DETACH_PENDING); + CASERET(DL_UNBOUND); + CASERET(DL_BIND_PENDING); + CASERET(DL_UNBIND_PENDING); + CASERET(DL_IDLE); + CASERET(DL_UDQOS_PENDING); + CASERET(DL_OUTCON_PENDING); + CASERET(DL_INCON_PENDING); + CASERET(DL_CONN_RES_PENDING); + CASERET(DL_DATAXFER); + CASERET(DL_USER_RESET_PENDING); + CASERET(DL_PROV_RESET_PENDING); + CASERET(DL_RESET_RES_PENDING); + CASERET(DL_DISCON8_PENDING); + CASERET(DL_DISCON9_PENDING); + CASERET(DL_DISCON11_PENDING); + CASERET(DL_DISCON12_PENDING); + CASERET(DL_DISCON13_PENDING); + CASERET(DL_SUBS_BIND_PND); + default: + (void) sprintf(statebuf, "unknown state 0x%x", state); + return (statebuf); + } +} + +char* +dlerrno(errno) + u_long errno; +{ + static char errnobuf[80]; + + switch (errno) { + CASERET(DL_ACCESS); + CASERET(DL_BADADDR); + CASERET(DL_BADCORR); + CASERET(DL_BADDATA); + CASERET(DL_BADPPA); + CASERET(DL_BADPRIM); + CASERET(DL_BADQOSPARAM); + CASERET(DL_BADQOSTYPE); + CASERET(DL_BADSAP); + CASERET(DL_BADTOKEN); + CASERET(DL_BOUND); + CASERET(DL_INITFAILED); + CASERET(DL_NOADDR); + CASERET(DL_NOTINIT); + CASERET(DL_OUTSTATE); + CASERET(DL_SYSERR); + CASERET(DL_UNSUPPORTED); + CASERET(DL_UNDELIVERABLE); + CASERET(DL_NOTSUPPORTED); + CASERET(DL_TOOMANY); + CASERET(DL_NOTENAB); + CASERET(DL_BUSY); + CASERET(DL_NOAUTO); + CASERET(DL_NOXIDAUTO); + CASERET(DL_NOTESTAUTO); + CASERET(DL_XIDAUTO); + CASERET(DL_TESTAUTO); + CASERET(DL_PENDING); + + default: + (void) sprintf(errnobuf, "unknown dlpi errno 0x%x", errno); + return (errnobuf); + } +} + +char* +dlpromisclevel(level) + u_long level; +{ + static char levelbuf[80]; + + switch (level) { + CASERET(DL_PROMISC_PHYS); + CASERET(DL_PROMISC_SAP); + CASERET(DL_PROMISC_MULTI); + default: + (void) sprintf(levelbuf, "unknown promisc level 0x%x", level); + return (levelbuf); + } +} + +char* +dlservicemode(servicemode) + u_long servicemode; +{ + static char servicemodebuf[80]; + + switch (servicemode) { + CASERET(DL_CODLS); + CASERET(DL_CLDLS); + CASERET(DL_CODLS|DL_CLDLS); + default: + (void) sprintf(servicemodebuf, + "unknown provider service mode 0x%x", servicemode); + return (servicemodebuf); + } +} + +char* +dlstyle(style) + long style; +{ + static char stylebuf[80]; + + switch (style) { + CASERET(DL_STYLE1); + CASERET(DL_STYLE2); + default: + (void) sprintf(stylebuf, "unknown provider style 0x%x", style); + return (stylebuf); + } +} + +char* +dlmactype(media) + u_long media; +{ + static char mediabuf[80]; + + switch (media) { + CASERET(DL_CSMACD); + CASERET(DL_TPB); + CASERET(DL_TPR); + CASERET(DL_METRO); + CASERET(DL_ETHER); + CASERET(DL_HDLC); + CASERET(DL_CHAR); + CASERET(DL_CTCA); + default: + (void) sprintf(mediabuf, "unknown media type 0x%x", media); + return (mediabuf); + } +} + +/*VARARGS1*/ +err(fmt, a1, a2, a3, a4) + char *fmt; + char *a1, *a2, *a3, *a4; +{ + (void) fprintf(stderr, fmt, a1, a2, a3, a4); + (void) fprintf(stderr, "\n"); + (void) exit(1); +} + +syserr(s) + char *s; +{ + (void) perror(s); + exit(1); +} + +strioctl(fd, cmd, timout, len, dp) + int fd; + int cmd; + int timout; + int len; + char *dp; +{ + struct strioctl sioc; + int rc; + + sioc.ic_cmd = cmd; + sioc.ic_timout = timout; + sioc.ic_len = len; + sioc.ic_dp = dp; + rc = ioctl(fd, I_STR, &sioc); + + if (rc < 0) + return (rc); + else + return (sioc.ic_len); +} diff --git a/contrib/ipfilter/ipsend/dltest.h b/contrib/ipfilter/ipsend/dltest.h new file mode 100644 index 0000000..086782c --- /dev/null +++ b/contrib/ipfilter/ipsend/dltest.h @@ -0,0 +1,34 @@ +/* $FreeBSD$ */ + +/* + * Common DLPI Test Suite header file + * + */ + +/* + * Maximum control/data buffer size (in long's !!) for getmsg(). + */ +#define MAXDLBUF 8192 + +/* + * Maximum number of seconds we'll wait for any + * particular DLPI acknowledgment from the provider + * after issuing a request. + */ +#define MAXWAIT 15 + +/* + * Maximum address buffer length. + */ +#define MAXDLADDR 1024 + + +/* + * Handy macro. + */ +#define OFFADDR(s, n) (u_char*)((char*)(s) + (int)(n)) + +/* + * externs go here + */ +extern void sigalrm(); diff --git a/contrib/ipfilter/ipsend/ip.c b/contrib/ipfilter/ipsend/ip.c new file mode 100644 index 0000000..fc76170 --- /dev/null +++ b/contrib/ipfilter/ipsend/ip.c @@ -0,0 +1,364 @@ +/* $FreeBSD$ */ + +/* + * ip.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <netinet/in_systm.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <sys/param.h> +#ifndef linux +# include <net/route.h> +# include <netinet/if_ether.h> +# include <netinet/ip_var.h> +#endif +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include "ipsend.h" + + +static char *ipbuf = NULL, *ethbuf = NULL; + + +u_short chksum(buf,len) + u_short *buf; + int len; +{ + u_long sum = 0; + int nwords = len >> 1; + + for(; nwords > 0; nwords--) + sum += *buf++; + sum = (sum>>16) + (sum & 0xffff); + sum += (sum >>16); + return (~sum); +} + + +int send_ether(nfd, buf, len, gwip) + int nfd, len; + char *buf; + struct in_addr gwip; +{ + static struct in_addr last_gw; + static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; + ether_header_t *eh; + char *s; + int err; + + if (!ethbuf) + ethbuf = (char *)calloc(1, 65536+1024); + s = ethbuf; + eh = (ether_header_t *)s; + + bcopy((char *)buf, s + sizeof(*eh), len); + if (gwip.s_addr == last_gw.s_addr) + { + bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); + } + else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) + { + perror("arp"); + return -2; + } + eh->ether_type = htons(ETHERTYPE_IP); + last_gw.s_addr = gwip.s_addr; + err = sendip(nfd, s, sizeof(*eh) + len); + return err; +} + + +/* + */ +int send_ip(nfd, mtu, ip, gwip, frag) + int nfd, mtu; + ip_t *ip; + struct in_addr gwip; + int frag; +{ + static struct in_addr last_gw, local_ip; + static char local_arp[6] = { 0, 0, 0, 0, 0, 0}; + static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; + static u_short id = 0; + ether_header_t *eh; + ip_t ipsv; + int err, iplen; + + if (!ipbuf) + { + ipbuf = (char *)malloc(65536); + if (!ipbuf) + { + perror("malloc failed"); + return -2; + } + } + + eh = (ether_header_t *)ipbuf; + + bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); + if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) + { + bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); + } + else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) + { + perror("arp"); + return -2; + } + bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp)); + eh->ether_type = htons(ETHERTYPE_IP); + + bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); + last_gw.s_addr = gwip.s_addr; + iplen = ip->ip_len; + ip->ip_len = htons(iplen); + if (!(frag & 2)) { + if (!IP_V(ip)) + IP_V_A(ip, IPVERSION); + if (!ip->ip_id) + ip->ip_id = htons(id++); + if (!ip->ip_ttl) + ip->ip_ttl = 60; + } + + if (ip->ip_src.s_addr != local_ip.s_addr) { + (void) arp((char *)&ip->ip_src, (char *)A_A local_arp); + bcopy(local_arp, (char *)A_A eh->ether_shost,sizeof(last_arp)); + local_ip = ip->ip_src; + } else + bcopy(local_arp, (char *)A_A eh->ether_shost, 6); + + if (!frag || (sizeof(*eh) + iplen < mtu)) + { + ip->ip_sum = 0; + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); + + bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); + err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); + } + else + { + /* + * Actually, this is bogus because we're putting all IP + * options in every packet, which isn't always what should be + * done. Will do for now. + */ + ether_header_t eth; + char optcpy[48], ol; + char *s; + int i, sent = 0, ts, hlen, olen; + + hlen = IP_HL(ip) << 2; + if (mtu < (hlen + 8)) { + fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", + mtu, hlen); + fprintf(stderr, "can't fragment data\n"); + return -2; + } + ol = (IP_HL(ip) << 2) - sizeof(*ip); + for (i = 0, s = (char*)(ip + 1); ol > 0; ) + if (*s == IPOPT_EOL) { + optcpy[i++] = *s; + break; + } else if (*s == IPOPT_NOP) { + s++; + ol--; + } else + { + olen = (int)(*(u_char *)(s + 1)); + ol -= olen; + if (IPOPT_COPIED(*s)) + { + bcopy(s, optcpy + i, olen); + i += olen; + s += olen; + } + } + if (i) + { + /* + * pad out + */ + while ((i & 3) && (i & 3) != 3) + optcpy[i++] = IPOPT_NOP; + if ((i & 3) == 3) + optcpy[i++] = IPOPT_EOL; + } + + bcopy((char *)eh, (char *)ð, sizeof(eth)); + s = (char *)ip + hlen; + iplen = ntohs(ip->ip_len) - hlen; + ip->ip_off |= htons(IP_MF); + + while (1) + { + if ((sent + (mtu - hlen)) >= iplen) + { + ip->ip_off ^= htons(IP_MF); + ts = iplen - sent; + } + else + ts = (mtu - hlen); + ip->ip_off &= htons(0xe000); + ip->ip_off |= htons(sent >> 3); + ts += hlen; + ip->ip_len = htons(ts); + ip->ip_sum = 0; + ip->ip_sum = chksum((u_short *)ip, hlen); + bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); + bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); + err = sendip(nfd, ipbuf, sizeof(*eh) + ts); + + bcopy((char *)ð, ipbuf, sizeof(eth)); + sent += (ts - hlen); + if (!(ntohs(ip->ip_off) & IP_MF)) + break; + else if (!(ip->ip_off & htons(0x1fff))) + { + hlen = i + sizeof(*ip); + IP_HL_A(ip, (sizeof(*ip) + i) >> 2); + bcopy(optcpy, (char *)(ip + 1), i); + } + } + } + + bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); + return err; +} + + +/* + * send a tcp packet. + */ +int send_tcp(nfd, mtu, ip, gwip) + int nfd, mtu; + ip_t *ip; + struct in_addr gwip; +{ + static tcp_seq iss = 2; + tcphdr_t *t, *t2; + int thlen, i, iplen, hlen; + u_32_t lbuf[20]; + ip_t *ip2; + + iplen = ip->ip_len; + hlen = IP_HL(ip) << 2; + t = (tcphdr_t *)((char *)ip + hlen); + ip2 = (struct ip *)lbuf; + t2 = (tcphdr_t *)((char *)ip2 + hlen); + thlen = TCP_OFF(t) << 2; + if (!thlen) + thlen = sizeof(tcphdr_t); + bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2)); + ip->ip_p = IPPROTO_TCP; + ip2->ip_p = ip->ip_p; + ip2->ip_src = ip->ip_src; + ip2->ip_dst = ip->ip_dst; + bcopy((char *)ip + hlen, (char *)t2, thlen); + + if (!t2->th_win) + t2->th_win = htons(4096); + iss += 63; + + i = sizeof(struct tcpiphdr) / sizeof(long); + + if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) && + (lbuf[i] != htonl(0x020405b4))) { + lbuf[i] = htonl(0x020405b4); + bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, + iplen - thlen - hlen); + thlen += 4; + } + TCP_OFF_A(t2, thlen >> 2); + ip2->ip_len = htons(thlen); + ip->ip_len = hlen + thlen; + t2->th_sum = 0; + t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t)); + + bcopy((char *)t2, (char *)ip + hlen, thlen); + return send_ip(nfd, mtu, ip, gwip, 1); +} + + +/* + * send a udp packet. + */ +int send_udp(nfd, mtu, ip, gwip) + int nfd, mtu; + ip_t *ip; + struct in_addr gwip; +{ + struct tcpiphdr *ti; + int thlen; + u_long lbuf[20]; + + ti = (struct tcpiphdr *)lbuf; + bzero((char *)ti, sizeof(*ti)); + thlen = sizeof(udphdr_t); + ti->ti_pr = ip->ip_p; + ti->ti_src = ip->ip_src; + ti->ti_dst = ip->ip_dst; + bcopy((char *)ip + (IP_HL(ip) << 2), + (char *)&ti->ti_sport, sizeof(udphdr_t)); + + ti->ti_len = htons(thlen); + ip->ip_len = (IP_HL(ip) << 2) + thlen; + ti->ti_sum = 0; + ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); + + bcopy((char *)&ti->ti_sport, + (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t)); + return send_ip(nfd, mtu, ip, gwip, 1); +} + + +/* + * send an icmp packet. + */ +int send_icmp(nfd, mtu, ip, gwip) + int nfd, mtu; + ip_t *ip; + struct in_addr gwip; +{ + struct icmp *ic; + + ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); + + ic->icmp_cksum = 0; + ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); + + return send_ip(nfd, mtu, ip, gwip, 1); +} + + +int send_packet(nfd, mtu, ip, gwip) + int nfd, mtu; + ip_t *ip; + struct in_addr gwip; +{ + switch (ip->ip_p) + { + case IPPROTO_TCP : + return send_tcp(nfd, mtu, ip, gwip); + case IPPROTO_UDP : + return send_udp(nfd, mtu, ip, gwip); + case IPPROTO_ICMP : + return send_icmp(nfd, mtu, ip, gwip); + default : + return send_ip(nfd, mtu, ip, gwip, 1); + } +} diff --git a/contrib/ipfilter/ipsend/ipresend.1 b/contrib/ipfilter/ipsend/ipresend.1 new file mode 100644 index 0000000..6761a18 --- /dev/null +++ b/contrib/ipfilter/ipsend/ipresend.1 @@ -0,0 +1,108 @@ +.\" $FreeBSD$ +.\" +.TH IPRESEND 1 +.SH NAME +ipresend \- resend IP packets out to network +.SH SYNOPSIS +.B ipresend +[ +.B \-EHPRSTX +] [ +.B \-d +<device> +] [ +.B \-g +<\fIgateway\fP> +] [ +.B \-m +<\fIMTU\fP> +] [ +.B \-r +<\fIfilename\fP> +] +.SH DESCRIPTION +.PP +\fBipresend\fP was designed to allow packets to be resent, once captured, +back out onto the network for use in testing. \fIipresend\fP supports a +number of different file formats as input, including saved snoop/tcpdump +binary data. +.SH OPTIONS +.TP +.BR \-d \0<interface> +Set the interface name to be the name supplied. 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. +.TP +.BR \-g \0<gateway> +Specify the hostname of the gateway through which to route packets. This +is required whenever the destination host isn't directly attached to the +same network as the host from which you're sending. +.TP +.BR \-m \0<MTU> +Specify the MTU to be used when sending out packets. This option allows you +to set a fake MTU, allowing the simulation of network interfaces with small +MTU's without setting them so. +.TP +.BR \-r \0<filename> +Specify the filename from which to take input. Default is stdin. +.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: +.PP +.nf + etherfind -n + etherfind -n -t +.fi +.LP +.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. +.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). +.TP +.B \-R +When sending packets out, send them out "raw" (the way they came in). The +only real significance here is that it will expect the link layer (i.e. +ethernet) headers to be prepended to the IP packet being output. +.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. +.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: +.PP +.nf + tcpdump -n + tcpdump -nq + tcpdump -nqt + tcpdump -nqtt + tcpdump -nqte +.fi +.LP +.TP +.B \-X +The input file is composed of text descriptions of IP packets. +.DT +.SH SEE ALSO +snoop(1m), tcpdump(8), etherfind(8c), ipftest(1), ipresend(1), iptest(1), bpf(4), dlpi(7p) +.SH DIAGNOSTICS +.PP +Needs to be run as root. +.SH BUGS +.PP +Not all of the input formats are sufficiently capable of introducing a +wide enough variety of packets for them to be all useful in testing. +If you find any, please send email to me at darrenr@pobox.com + diff --git a/contrib/ipfilter/ipsend/ipresend.c b/contrib/ipfilter/ipsend/ipresend.c new file mode 100644 index 0000000..7520a0e --- /dev/null +++ b/contrib/ipfilter/ipsend/ipresend.c @@ -0,0 +1,151 @@ +/* $FreeBSD$ */ + +/* + * ipresend.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#ifndef linux +#include <netinet/ip_var.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <string.h> +#include "ipsend.h" + + +extern char *optarg; +extern int optind; +#ifndef NO_IPF +extern struct ipread pcap, iphex, iptext; +#endif + +int opts = 0; +#ifndef DEFAULT_DEVICE +# ifdef linux +char default_device[] = "eth0"; +# else +# ifdef sun +char default_device[] = "le0"; +# else +# ifdef ultrix +char default_device[] = "ln0"; +# else +# ifdef __bsdi__ +char default_device[] = "ef0"; +# else +# ifdef __sgi +char default_device[] = "ec0"; +# else +char default_device[] = "lan0"; +# endif +# endif +# endif +# endif +# endif +#else +char default_device[] = DEFAULT_DEVICE; +#endif + + +static void usage __P((char *)); +int main __P((int, char **)); + + +static void usage(prog) + char *prog; +{ + fprintf(stderr, "Usage: %s [options] <-r filename|-R filename>\n\ +\t\t-r filename\tsnoop data file to resend\n\ +\t\t-R filename\tlibpcap data file to resend\n\ +\toptions:\n\ +\t\t-d device\tSend out on this device\n\ +\t\t-g gateway\tIP gateway to use if non-local dest.\n\ +\t\t-m mtu\t\tfake MTU to use when sending out\n\ +", prog); + exit(1); +} + + +int main(argc, argv) + int argc; + char **argv; +{ + struct in_addr gwip; + struct ipread *ipr = NULL; + char *name = argv[0], *gateway = NULL, *dev = NULL; + char *resend = NULL; + int mtu = 1500, c; + + while ((c = getopt(argc, argv, "EHPRSTXd:g:m:r:")) != -1) + switch (c) + { + case 'd' : + dev = optarg; + break; + case 'g' : + gateway = optarg; + break; + case 'm' : + mtu = atoi(optarg); + if (mtu < 28) + { + fprintf(stderr, "mtu must be > 28\n"); + exit(1); + } + case 'r' : + resend = optarg; + break; + case 'R' : + opts |= OPT_RAW; + break; +#ifndef NO_IPF + case 'H' : + ipr = &iphex; + break; + case 'P' : + ipr = &pcap; + break; + case 'X' : + ipr = &iptext; + break; +#endif + default : + fprintf(stderr, "Unknown option \"%c\"\n", c); + usage(name); + } + + if (!ipr || !resend) + usage(name); + + gwip.s_addr = 0; + if (gateway && resolve(gateway, (char *)&gwip) == -1) + { + fprintf(stderr,"Cant resolve %s\n", gateway); + exit(2); + } + + if (!dev) + dev = default_device; + + printf("Device: %s\n", dev); + printf("Gateway: %s\n", inet_ntoa(gwip)); + printf("mtu: %d\n", mtu); + + return ip_resend(dev, mtu, ipr, gwip, resend); +} diff --git a/contrib/ipfilter/ipsend/ipsend.1 b/contrib/ipfilter/ipsend/ipsend.1 new file mode 100644 index 0000000..7f0a8e3 --- /dev/null +++ b/contrib/ipfilter/ipsend/ipsend.1 @@ -0,0 +1,111 @@ +.\" $FreeBSD$ +.\" +.TH IPSEND 1 +.SH NAME +ipsend \- sends IP packets +.SH SYNOPSIS +.B ipsend +[ +.B \-dITUv +] [ +.B \-i +<interface> +] [ +.B \-f +<\fIoffset\fP> +] [ +.B \-g +<\fIgateway\fP> +] [ +.B \-m +<\fIMTU\fP> +] [ +.B \-o +<\fIoption\fP> +] [ +.B \-P +<protocol> +] [ +.B \-s +<\fIsource\fP> +] [ +.B \-t +<\fIdest. port\fP> +] [ +.B \-w +<\fIwindow\fP> +] <destination> [TCP-flags] +.SH DESCRIPTION +.PP +\fBipsend\fP can be compiled in two ways. The first is used to send one-off +packets to a destination host, using command line options to specify various +attributes present in the headers. The \fIdestination\fP must be given as +the last command line option, except for when TCP flags are specified as +a combination of A, S, F, U, P and R, last. +.PP +The other way it may be compiled, with DOSOCKET defined, is to allow an +attempt at making a TCP connection using a with ipsend resending the SYN +packet as per the command line options. +.SH OPTIONS +.TP +.BR \-d +enable debugging mode. +.TP +.BR \-f \0<offset> +The \fI-f\fP allows the IP offset field in the IP header to be set to an +arbitrary value, which can be specified in decimal or hexadecimal. +.TP +.BR \-g \0<gateway> +Specify the hostname of the gateway through which to route packets. This +is required whenever the destination host isn't directly attached to the +same network as the host from which you're sending. +.TP +.BR \-i \0<interface> +Set the interface name to be the name supplied. +.TP +.TP +.BR \-m \0<MTU> +Specify the MTU to be used when sending out packets. This option allows you +to set a fake MTU, allowing the simulation of network interfaces with small +MTU's without setting them so. +.TP +.BR \-o \0<option> +Specify options to be included at the end of the IP header. An EOL option +is automatically appended and need not be given. If an option would also +have data associated with it (source as an IP# for a lsrr option), then +this will not be initialised. +.TP +.BR \-s \0<source> +Set the source address in the packet to that provided - maybe either a +hostname or IP#. +.TP +.BR \-t \0<dest. port> +Set the destination port for TCP/UDP packets. +.TP +.BR \-w \0<window> +Set the window size for TCP packets. +.TP +.B \-I +Set the protocol to ICMP. +.TP +.B \-P <protocol> +Set the protocol to the value given. If the parameter is a name, the name +is looked up in the \fI/etc/protocols\fP file. +.TP +.B \-T +Set the protocol to TCP. +.TP +.B \-U +Set the protocol to UDP. +.TP +.BR \-v +enable verbose mode. +.DT +.SH SEE ALSO +ipsend(1), ipresend(1), iptest(1), protocols(4), bpf(4), dlpi(7p) +.SH DIAGNOSTICS +.PP +Needs to be run as root. +.SH BUGS +.PP +If you find any, please send email to me at darrenr@pobox.com diff --git a/contrib/ipfilter/ipsend/ipsend.5 b/contrib/ipfilter/ipsend/ipsend.5 new file mode 100644 index 0000000..fc86911 --- /dev/null +++ b/contrib/ipfilter/ipsend/ipsend.5 @@ -0,0 +1,402 @@ +.\" $FreeBSD$ +.TH IPSEND 5 +.SH NAME +ipsend \- IP packet description language +.SH DESCRIPTION +The \fBipsend\fP program expects, with the \fB-L\fP option, input to be a +text file which fits the grammar described below. The purpose of this +grammar is to allow IP packets to be described in an arbitary way which +also allows encapsulation to be so done to an arbitary level. +.SH GRAMMAR +.LP +.nf +line ::= iface | arp | send | defrouter | ipv4line . + +iface ::= ifhdr "{" ifaceopts "}" ";" . +ifhdr ::= "interface" | "iface" . +ifaceopts ::= "ifname" name | "mtu" mtu | "v4addr" ipaddr | + "eaddr" eaddr . + +send ::= "send" ";" | "send" "{" sendbodyopts "}" ";" . +sendbodyopts ::= sendbody [ sendbodyopts ] . +sendbody ::= "ifname" name | "via" ipaddr . + +defrouter ::= "router" ipaddr . + +arp ::= "arp" "{" arpbodyopts "}" ";" . +arpbodyopts ::= arpbody [ arpbodyopts ] . +arpbody ::= "v4addr" ipaddr | "eaddr" eaddr . + +bodyline ::= ipv4line | tcpline | udpline | icmpline | dataline . + +ipv4line ::= "ipv4" "{" ipv4bodyopts "}" ";" . +ipv4bodyopts ::= ipv4body [ ipv4bodyopts ] | bodyline . +ipv4body ::= "proto" protocol | "src" ipaddr | "dst" ipaddr | + "off" number | "v" number | "hl" number| "id" number | + "ttl" number | "tos" number | "sum" number | "len" number | + "opt" "{" ipv4optlist "}" ";" . +ipv4optlist ::= ipv4option [ ipv4optlist ] . +ipv4optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | + "tr" | "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | + "ssrr" | "addext" | "visa" | "imitd" | "eip" | "finn" | + "secclass" ipv4secclass. +ipv4secclass := "unclass" | "confid" | "reserv-1" | "reserv-2" | + "reserv-3" | "reserv-4" | "secret" | "topsecret" . + +tcpline ::= "tcp" "{" tcpbodyopts "}" ";" . +tcpbodyopts ::= tcpbody [ tcpbodyopts ] | bodyline . +tcpbody ::= "sport" port | "dport" port | "seq" number | "ack" number | + "off" number | "urp" number | "win" number | "sum" number | + "flags" tcpflags | data . + +udpline ::= "udp" "{" udpbodyopts "}" ";" . +udpbodyopts ::= udpbody [ udpbodyopts ] | bodyline . +udpbody ::= "sport" port | "dport" port | "len" number | "sum" number | + data . + +icmpline ::= "icmp" "{" icmpbodyopts "}" ";" . +icmpbodyopts ::= icmpbody [ icmpbodyopts ] | bodyline . +icmpbody ::= "type" icmptype [ "code" icmpcode ] . +icmptype ::= "echorep" | "echorep" "{" echoopts "}" ";" | "unreach" | + "unreach" "{" unreachtype "}" ";" | "squench" | "redir" | + "redir" "{" redirtype "}" ";" | "echo" "{" echoopts "}" ";" | + "echo" | "routerad" | "routersol" | "timex" | + "timex" "{" timextype "}" ";" | "paramprob" | + "paramprob" "{" parapptype "}" ";" | "timest" | "timestrep" | + "inforeq" | "inforep" | "maskreq" | "maskrep" . + +echoopts ::= echoopts [ icmpechoopts ] . +unreachtype ::= "net-unr" | "host-unr" | "proto-unr" | "port-unr" | + "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" | + "net-prohib" | "host-prohib" | "net-tos" | "host-tos" | + "filter-prohib" | "host-preced" | "cutoff-preced" . +redirtype ::= "net-redir" | "host-redir" | "tos-net-redir" | + "tos-host-redir" . +timextype ::= "intrans" | "reass" . +paramptype ::= "optabsent" . + +data ::= "data" "{" databodyopts "}" ";" . +databodyopts ::= "len" number | "value" string | "file" filename . + +icmpechoopts ::= "icmpseq" number | "icmpid" number . +.fi +.SH COMMANDS +.PP +Before sending any packets or defining any packets, it is necessary to +describe the interface(s) which will be used to send packets out. +.TP +.B interface +is used to describe a network interface. The description included need +not match the actual configuration currently employed by the operating +system. +.TP +.B send +is used to actually send out a packet across the network. If the +destination is not specified, it will attempt to send the packet +directly out on the network to the destination without routing it. +.TP +.B router +configures the default router for ipsend, as distinct from the default +route installed in the kernel. +.TP +.B ipv4 +is used to describe an IP (version 4) packet. IP header fields can be +specified, including options, followed by a data section which may contain +further protocol headers. +.SH IPv4 +.TP +.B hl <number> +manually specifies the IP header length (automatically adjusts with the +presence of IP options and defaults to 5); +.TP +.B v <number> +set the IP version. Default is 4. +.TP +.B tos <number> +set the type of service (TOS) field in the IP header. Default is 0. +.TP +.B len <number> +manually specifies the length of the IP packet. The length will automatically +be adjusted to accommodate data or further protocol headers. +.TP +.B off <number> +sets the fragment offset field of the IP packet. Default is 0. +.TP +.B ttl <number> +sets the time to live (TTL) field of the IP header. Default is 60. +.TP +.B proto <protocol> +sets the protocol field of the IP header. The protocol can either be a +number or a name found in \fB/etc/protocols\fP. +.TP +.B sum +manually specifies the checksum for the IP header. If left unset (0), it +will be calculated prior to being sent. +.TP +.B src +manually specifies the source address of the IP header. If left unset, it +will default to the host's IP address. +.TP +.B dst +sets the destination of the IP packet. The default is 0.0.0.0. +.TP +.B opt +is used to include IP options in the IP header. +.TP +.B tcp +is used to indicate the a TCP protocol header is to follow. See the \fBTCP\fP +section for TCP header options. +.TP +.B udp +is used to indicate the a UDP protocol header is to follow. See the \fBUDP\fP +section for UDP header options. +.TP +.B icmp +is used to indicate the a ICMP protocol header is to follow. See the +\fBICMP\fP section for ICMP header options. +.TP +.B data +is used to indicate that raw data is to be included in the IP packet. See the +\fBDATA\fP section for details on options available. +.SH "IPv4 Options" +these keywords indicate that the relevant IP option should be added to the +IP header (the header length field will be adjusted appropriately). +.TP +.B nop +No Operation [RFC 791] (space filler). +.TP +.B rr <number> +Record Router [RFC 791]. The number given specifies the number of +\fBbytes\fP to be used for storage. This should be a multiple of 4 for +proper operation. +.TP +.B zsu +Experimental Measurement. +.TP +.B mtup [RFC 1191]. +MTU Probe. +.TP +.B mtur [RFC 1191]. +MTU Ready. +.TP +.B encode +.TP +.B ts +Timestamp [RFC 791]. +.TP +.B tr +Traceroute [RFC 1393]. +.TP +.B "sec-class <security-level>, sec" +Security [RFC 1108]. This option specifies the security label for the packet. +Using \fBsec\fP sets up the framework of the security option but unless +\fBsec-class\fP is given, the level may not be set. +.TP +.B "lsrr <ip-address>" +Loose Source Route [RFC 791]. +.TP +.B e-sec +Extended Security [RFC 1108]. +.TP +.B cipso +Commercial Security. +.TP +.B satid +Stream ID [RFC 791]. +.TP +.B "ssrr <ip-address>" +Strict Source Route [RFC 791]. +.TP +.B addext +Address Extension +.TP +.B visa +Experimental Access Control. +.TP +.B imitd +IMI Traffic Descriptor. +.TP +.B eip +[RFC 1358]. +.TP +.B finn +Experimental Flow Control. +.SH TCP +.TP +.B sport <port> +sets the source port to the number/name given. Default is 0. +.TP +.B dport <port> +sets the destination port to the number/name given. Default is 0. +.TP +.B seq <number> +sets the sequence number to the number specified. Default is 0. +.TP +.B ack <number> +sets the acknowledge number to the number specified. Default is 0. +.TP +.B off <number> +sets the offset value for the start of data to the number specified. This +implies the size of the TCP header. It is automatically adjusted if TCP +options are included and defaults to 5. +.TP +.B urp <number> +sets the value of the urgent data pointer to the number specified. Default +is 0. +.TP +.B win <number> +sets the size of the TCP window to the number specified. Default is 4096. +.TP +.B sum <number> +manually specifies the checksum for the TCP pseudo-header and data. If left +unset, it defaults to 0 and is automatically calculated. +.TP +.B flags <tcp-flags> +sets the TCP flags field to match the flags specified. Valid flags are +"S" (SYN), "A" (ACK), "R" (RST), "F" (FIN), "U" (URG), "P" (PUSH). +.TP +.B opt +indicates that TCP header options follow. As TCP options are added to the +TCP header, the \fBoff\fP field is updated to match. +.TP +.B data +indicates that a data section is to follow and is to be included as raw +data, being appended to the header. +.SH "TCP options" +With a TCP header, it is possible to append a number of header options. +The TCP header offset will be updated automatically to reflect the change +in size. The valid options are: \fBnop\fP No Operation, +\fBeol\fP End Of (option) List, \fBmss [ size ]\fP Maximum Segment Size - this +sets the maximum receivable size of a packet containing data, +\fBwscale\fP Window Scale, \fBts\fP Timestamp. +.SH UDP +.TP +.B sport <port> +sets the source port to the number/name given. Default is 0. +.TP +.B dport <port> +sets the destination port to the number/name given. Default is 0. +.TP +.B len <number> +manually specifies the length of the UDP header and data. If left unset, +it is automatically adjusted to match the header presence and any data if +present. +.TP +.B sum <number> +manually specifies the checksum for the UDP pseudo-header and data. If left +unset, it defaults to 0 and is automatically calculated. +.TP +.B data +indicates that a data section is to follow and is to be included as raw +data, being appended to the header. +.SH ICMP +.TP +.B type <icmptype> +sets the ICMP type according the to the icmptype tag. This may either be +a number or one of the recognised tags (see the \fBICMP TYPES\fP section for a +list of names recognised). +.TP +.B code <icmpcode> +sets the ICMP code. +.TP +.B data +indicates that a data section is to follow and is to be included as raw +data, being appended to the header. +.SH DATA +Each of the following extend the packet in a different way. \fBLen\fP just +increases the length (without adding any content), \fBvalue\fP uses a string +and \fBfile\fP a file. +.TP +.B len <number> +extend the length of the packet by \fBnumber\fP bytes (without filling those +bytes with any particular data). +.TP +.B value <string> +indicates that the string provided should be added to the current packet as +data. A string may be a consecutive list of characters and numbers (with +no white spaces) or bounded by "'s (may not contain them, even if \\'d). +The \\ character is recognised with the appropriate C escaped values, including +octal numbers. +.TP +.B file <filename> +reads data in from the specified file and appends it to the current packet. +If the new total length would exceed 64k, an error will be reported. +.SH "ICMP TYPES" +.TP +.B echorep +Echo Reply. +.TP +.B "unreach [ unreachable-code ]" +Generic Unreachable error. This is used to indicate that an error has +occurred whilst trying to send the packet across the network and that the +destination cannot be reached. The unreachable code names are: +\fBnet-unr\fP network unreachable, \fBhost-unr\fP host unreachable, +\fBproto-unr\fP protocol unreachable, \fBport-unr\fP port unreachable, +\fBneedfrag\fP, \fBsrcfail\fP source route failed, +\fBnet-unk\fP network unknown, \fBhost-unk\fP host unknown, +\fBisolate\fP, \fBnet-prohib\fP administratively prohibited contact with +network, +\fBhost-prohib\fP administratively prohibited contact with host, +\fBnet-tos\fP network unreachable with given TOS, +\fBhost-tos\fP host unreachable with given TOS, +\fBfilter-prohib\fP packet prohibited by packet filter, +\fBhost-preced\fP, +\fBcutoff-preced\fP. +.TP +.B squench +Source Quence. +.TP +.B "redir [ redirect-code ]" +Redirect (routing). This is used to indicate that the route being chosen +for forwarding the packet is suboptimal and that the sender of the packet +should be routing packets via another route. The redirect code names are: +\fBnet-redir\fP redirect packets for a network, +\fBhost-redir\fP redirect packets for a host, +\fBtos-net-redir\fP redirect packets for a network with a given TOS, +\fBtos-host-redir\fP redirect packets for a host with a given TOS. +.TP +.B echo +Echo. +.TP +.B routerad +Router Advertisement. +.TP +.B routersol +Router solicitation. +.TP +.B "timex [ timexceed-code ]" +Time Exceeded. This is used to indicate that the packet failed to reach the +destination because it was in transit too long (i.e. ttl reached 0). The +valid code names are: \fBintrans\fP, +\fBreass\fP could not reassemble packet from fragments within a given time. +.TP +.B "paramprob [ paramprob-code ]" +Parameter problem. There is only one available parameter problem code name: +\fBoptabsent\fP. +.TP +.B timest +Time stamp request. +.TP +.B "timestrep [ { timestamp-code } ]" +Time stamp reply. In a timestamp reply, it is possible to supply the +following values: \fBrtime\fP, \fBotime\fP, \fBttime\fP. +.TP +.B inforeq +Information request. +.TP +.B inforep +Information reply. +.TP +.B maskreq +Address mask request. +.TP +.B maskrep +Address mask reply. +.SH FILES +/etc/hosts +.br +/etc/protocols +.br +/etc/services +.SH SEE ALSO +ipsend(1), iptest(1), hosts(5), protocols(5), services(5) diff --git a/contrib/ipfilter/ipsend/ipsend.c b/contrib/ipfilter/ipsend/ipsend.c new file mode 100644 index 0000000..3df5c07 --- /dev/null +++ b/contrib/ipfilter/ipsend/ipsend.c @@ -0,0 +1,440 @@ +/* $FreeBSD$ */ +/* + * ipsend.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/in_systm.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <netdb.h> +#include <string.h> +#include <netinet/ip.h> +#ifndef linux +# include <netinet/ip_var.h> +#endif +#include "ipsend.h" +#include "ipf.h" +#ifndef linux +# include <netinet/udp_var.h> +#endif + + +extern char *optarg; +extern int optind; +extern void iplang __P((FILE *)); + +char options[68]; +int opts; +#ifdef linux +char default_device[] = "eth0"; +#else +# ifdef ultrix +char default_device[] = "ln0"; +# else +# ifdef __bsdi__ +char default_device[] = "ef0"; +# else +# ifdef __sgi +char default_device[] = "ec0"; +# else +# ifdef __hpux +char default_device[] = "lan0"; +# else +char default_device[] = "le0"; +# endif /* __hpux */ +# endif /* __sgi */ +# endif /* __bsdi__ */ +# endif /* ultrix */ +#endif /* linux */ + + +static void usage __P((char *)); +static void do_icmp __P((ip_t *, char *)); +void udpcksum(ip_t *, struct udphdr *, int); +int main __P((int, char **)); + + +static void usage(prog) + char *prog; +{ + fprintf(stderr, "Usage: %s [options] dest [flags]\n\ +\toptions:\n\ +\t\t-d\tdebug mode\n\ +\t\t-i device\tSend out on this device\n\ +\t\t-f fragflags\tcan set IP_MF or IP_DF\n\ +\t\t-g gateway\tIP gateway to use if non-local dest.\n\ +\t\t-I code,type[,gw[,dst[,src]]]\tSet ICMP protocol\n\ +\t\t-m mtu\t\tfake MTU to use when sending out\n\ +\t\t-P protocol\tSet protocol by name\n\ +\t\t-s src\t\tsource address for IP packet\n\ +\t\t-T\t\tSet TCP protocol\n\ +\t\t-t port\t\tdestination port\n\ +\t\t-U\t\tSet UDP protocol\n\ +\t\t-v\tverbose mode\n\ +\t\t-w <window>\tSet the TCP window size\n\ +", prog); + fprintf(stderr, "Usage: %s [-dv] -L <filename>\n\ +\toptions:\n\ +\t\t-d\tdebug mode\n\ +\t\t-L filename\tUse IP language for sending packets\n\ +\t\t-v\tverbose mode\n\ +", prog); + exit(1); +} + + +static void do_icmp(ip, args) + ip_t *ip; + char *args; +{ + struct icmp *ic; + char *s; + + ip->ip_p = IPPROTO_ICMP; + ip->ip_len += sizeof(*ic); + ic = (struct icmp *)(ip + 1); + bzero((char *)ic, sizeof(*ic)); + if (!(s = strchr(args, ','))) + { + fprintf(stderr, "ICMP args missing: ,\n"); + return; + } + *s++ = '\0'; + ic->icmp_type = atoi(args); + ic->icmp_code = atoi(s); + if (ic->icmp_type == ICMP_REDIRECT && strchr(s, ',')) + { + char *t; + + t = strtok(s, ","); + t = strtok(NULL, ","); + if (resolve(t, (char *)&ic->icmp_gwaddr) == -1) + { + fprintf(stderr,"Cant resolve %s\n", t); + exit(2); + } + if ((t = strtok(NULL, ","))) + { + if (resolve(t, (char *)&ic->icmp_ip.ip_dst) == -1) + { + fprintf(stderr,"Cant resolve %s\n", t); + exit(2); + } + if ((t = strtok(NULL, ","))) + { + if (resolve(t, + (char *)&ic->icmp_ip.ip_src) == -1) + { + fprintf(stderr,"Cant resolve %s\n", t); + exit(2); + } + } + } + } +} + + +int send_packets(dev, mtu, ip, gwip) + char *dev; + int mtu; + ip_t *ip; + struct in_addr gwip; +{ + int wfd; + + wfd = initdevice(dev, 5); + if (wfd == -1) + return -1; + return send_packet(wfd, mtu, ip, gwip); +} + +void +udpcksum(ip_t *ip, struct udphdr *udp, int len) +{ + union pseudoh { + struct hdr { + u_short len; + u_char ttl; + u_char proto; + u_32_t src; + u_32_t dst; + } h; + u_short w[6]; + } ph; + u_32_t temp32; + u_short *opts; + + ph.h.len = htons(len); + ph.h.ttl = 0; + ph.h.proto = IPPROTO_UDP; + ph.h.src = ip->ip_src.s_addr; + ph.h.dst = ip->ip_dst.s_addr; + temp32 = 0; + opts = &ph.w[0]; + temp32 += opts[0] + opts[1] + opts[2] + opts[3] + opts[4] + opts[5]; + temp32 = (temp32 >> 16) + (temp32 & 65535); + temp32 += (temp32 >> 16); + udp->uh_sum = temp32 & 65535; + udp->uh_sum = chksum((u_short *)udp, len); + if (udp->uh_sum == 0) + udp->uh_sum = 0xffff; +} + +int main(argc, argv) + int argc; + char **argv; +{ + FILE *langfile = NULL; + struct in_addr gwip; + tcphdr_t *tcp; + udphdr_t *udp; + ip_t *ip; + char *name = argv[0], host[MAXHOSTNAMELEN + 1]; + char *gateway = NULL, *dev = NULL; + char *src = NULL, *dst, *s; + int mtu = 1500, olen = 0, c, nonl = 0; + + /* + * 65535 is maximum packet size...you never know... + */ + ip = (ip_t *)calloc(1, 65536); + tcp = (tcphdr_t *)(ip + 1); + udp = (udphdr_t *)tcp; + ip->ip_len = sizeof(*ip); + IP_HL_A(ip, sizeof(*ip) >> 2); + + while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) { + switch (c) + { + case 'I' : + nonl++; + if (ip->ip_p) + { + fprintf(stderr, "Protocol already set: %d\n", + ip->ip_p); + break; + } + do_icmp(ip, optarg); + break; + case 'L' : + if (nonl) { + fprintf(stderr, + "Incorrect usage of -L option.\n"); + usage(name); + } + if (!strcmp(optarg, "-")) + langfile = stdin; + else if (!(langfile = fopen(optarg, "r"))) { + fprintf(stderr, "can't open file %s\n", + optarg); + exit(1); + } + iplang(langfile); + return 0; + case 'P' : + { + struct protoent *p; + + nonl++; + if (ip->ip_p) + { + fprintf(stderr, "Protocol already set: %d\n", + ip->ip_p); + break; + } + if ((p = getprotobyname(optarg))) + ip->ip_p = p->p_proto; + else + fprintf(stderr, "Unknown protocol: %s\n", + optarg); + break; + } + case 'T' : + nonl++; + if (ip->ip_p) + { + fprintf(stderr, "Protocol already set: %d\n", + ip->ip_p); + break; + } + ip->ip_p = IPPROTO_TCP; + ip->ip_len += sizeof(tcphdr_t); + break; + case 'U' : + nonl++; + if (ip->ip_p) + { + fprintf(stderr, "Protocol already set: %d\n", + ip->ip_p); + break; + } + ip->ip_p = IPPROTO_UDP; + ip->ip_len += sizeof(udphdr_t); + break; + case 'd' : + opts |= OPT_DEBUG; + break; + case 'f' : + nonl++; + ip->ip_off = strtol(optarg, NULL, 0); + break; + case 'g' : + nonl++; + gateway = optarg; + break; + case 'i' : + nonl++; + dev = optarg; + break; + case 'm' : + nonl++; + mtu = atoi(optarg); + if (mtu < 28) + { + fprintf(stderr, "mtu must be > 28\n"); + exit(1); + } + break; + case 'o' : + nonl++; + olen = buildopts(optarg, options, (IP_HL(ip) - 5) << 2); + break; + case 's' : + nonl++; + src = optarg; + break; + case 't' : + nonl++; + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + tcp->th_dport = htons(atoi(optarg)); + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + case 'w' : + nonl++; + if (ip->ip_p == IPPROTO_TCP) + tcp->th_win = atoi(optarg); + else + fprintf(stderr, "set protocol to TCP first\n"); + break; + default : + fprintf(stderr, "Unknown option \"%c\"\n", c); + usage(name); + } + } + + if (argc - optind < 1) + usage(name); + dst = argv[optind++]; + + if (!src) + { + gethostname(host, sizeof(host)); + src = host; + } + + if (resolve(src, (char *)&ip->ip_src) == -1) + { + fprintf(stderr,"Cant resolve %s\n", src); + exit(2); + } + + if (resolve(dst, (char *)&ip->ip_dst) == -1) + { + fprintf(stderr,"Cant resolve %s\n", dst); + exit(2); + } + + if (!gateway) + gwip = ip->ip_dst; + else if (resolve(gateway, (char *)&gwip) == -1) + { + fprintf(stderr,"Cant resolve %s\n", gateway); + exit(2); + } + + if (olen) + { + int hlen; + char *p; + + printf("Options: %d\n", olen); + hlen = sizeof(*ip) + olen; + IP_HL_A(ip, hlen >> 2); + ip->ip_len += olen; + p = (char *)malloc(65536); + if (p == NULL) + { + fprintf(stderr, "malloc failed\n"); + exit(2); + } + + bcopy(ip, p, sizeof(*ip)); + bcopy(options, p + sizeof(*ip), olen); + bcopy(ip + 1, p + hlen, ip->ip_len - hlen); + ip = (ip_t *)p; + + if (ip->ip_p == IPPROTO_TCP) { + tcp = (tcphdr_t *)(p + hlen); + } else if (ip->ip_p == IPPROTO_UDP) { + udp = (udphdr_t *)(p + hlen); + } + } + + if (ip->ip_p == IPPROTO_TCP) + for (s = argv[optind]; s && (c = *s); s++) + switch(c) + { + case 'S' : case 's' : + tcp->th_flags |= TH_SYN; + break; + case 'A' : case 'a' : + tcp->th_flags |= TH_ACK; + break; + case 'F' : case 'f' : + tcp->th_flags |= TH_FIN; + break; + case 'R' : case 'r' : + tcp->th_flags |= TH_RST; + break; + case 'P' : case 'p' : + tcp->th_flags |= TH_PUSH; + break; + case 'U' : case 'u' : + tcp->th_flags |= TH_URG; + break; + } + + if (!dev) + dev = default_device; + printf("Device: %s\n", dev); + printf("Source: %s\n", inet_ntoa(ip->ip_src)); + printf("Dest: %s\n", inet_ntoa(ip->ip_dst)); + printf("Gateway: %s\n", inet_ntoa(gwip)); + if (ip->ip_p == IPPROTO_TCP && tcp->th_flags) + printf("Flags: %#x\n", tcp->th_flags); + printf("mtu: %d\n", mtu); + + if (ip->ip_p == IPPROTO_UDP) { + udp->uh_sum = 0; + udpcksum(ip, udp, ip->ip_len - (IP_HL(ip) << 2)); + } +#ifdef DOSOCKET + if (ip->ip_p == IPPROTO_TCP && tcp->th_dport) + return do_socket(dev, mtu, ip, gwip); +#endif + return send_packets(dev, mtu, ip, gwip); +} diff --git a/contrib/ipfilter/ipsend/ipsend.h b/contrib/ipfilter/ipsend/ipsend.h new file mode 100644 index 0000000..75a0496 --- /dev/null +++ b/contrib/ipfilter/ipsend/ipsend.h @@ -0,0 +1,73 @@ +/* $FreeBSD$ */ + +/* + * ipsend.h (C) 1997-1998 Darren Reed + * + * This was written to test what size TCP fragments would get through + * various TCP/IP packet filters, as used in IP firewalls. In certain + * conditions, enough of the TCP header is missing for unpredictable + * results unless the filter is aware that this can happen. + * + * The author provides this program as-is, with no gaurantee for its + * suitability for any specific purpose. The author takes no responsibility + * for the misuse/abuse of this program and provides it for the sole purpose + * of testing packet filter policies. This file maybe distributed freely + * providing it is not modified and that this notice remains in tact. + * + */ +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +#include <net/if.h> + +#include "ipf.h" +#ifdef linux +#include <linux/sockios.h> +#endif +/* XXX: The following is needed by tcpip.h */ +#include <netinet/ip_var.h> +#include "netinet/tcpip.h" +#include "ipt.h" + +extern int resolve __P((char *, char *)); +extern int arp __P((char *, char *)); +extern u_short chksum __P((u_short *, int)); +extern int send_ether __P((int, char *, int, struct in_addr)); +extern int send_ip __P((int, int, ip_t *, struct in_addr, int)); +extern int send_tcp __P((int, int, ip_t *, struct in_addr)); +extern int send_udp __P((int, int, ip_t *, struct in_addr)); +extern int send_icmp __P((int, int, ip_t *, struct in_addr)); +extern int send_packet __P((int, int, ip_t *, struct in_addr)); +extern int send_packets __P((char *, int, ip_t *, struct in_addr)); +extern u_short ipseclevel __P((char *)); +extern u_32_t buildopts __P((char *, char *, int)); +extern int addipopt __P((char *, struct ipopt_names *, int, char *)); +extern int initdevice __P((char *, int)); +extern int sendip __P((int, char *, int)); +#ifdef linux +extern struct sock *find_tcp __P((int, struct tcpiphdr *)); +#else +extern struct tcpcb *find_tcp __P((int, struct tcpiphdr *)); +#endif +extern int ip_resend __P((char *, int, struct ipread *, struct in_addr, char *)); + +extern void ip_test1 __P((char *, int, ip_t *, struct in_addr, int)); +extern void ip_test2 __P((char *, int, ip_t *, struct in_addr, int)); +extern void ip_test3 __P((char *, int, ip_t *, struct in_addr, int)); +extern void ip_test4 __P((char *, int, ip_t *, struct in_addr, int)); +extern void ip_test5 __P((char *, int, ip_t *, struct in_addr, int)); +extern void ip_test6 __P((char *, int, ip_t *, struct in_addr, int)); +extern void ip_test7 __P((char *, int, ip_t *, struct in_addr, int)); +extern int do_socket __P((char *, int, struct tcpiphdr *, struct in_addr)); +extern int kmemcpy __P((char *, void *, int)); + +#define KMCPY(a,b,c) kmemcpy((char *)(a), (void *)(b), (int)(c)) + +#ifndef OPT_RAW +#define OPT_RAW 0x80000 +#endif diff --git a/contrib/ipfilter/ipsend/ipsopt.c b/contrib/ipfilter/ipsend/ipsopt.c new file mode 100644 index 0000000..a2cc4d0 --- /dev/null +++ b/contrib/ipfilter/ipsend/ipsopt.c @@ -0,0 +1,200 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#ifndef linux +#include <netinet/ip_var.h> +#endif +#include <netinet/tcp.h> +#include <arpa/inet.h> +#include "ipsend.h" + + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + + +struct ipopt_names ionames[] = { + { IPOPT_EOL, 0x01, 1, "eol" }, + { IPOPT_NOP, 0x02, 1, "nop" }, + { IPOPT_RR, 0x04, 3, "rr" }, /* 1 route */ + { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */ + { IPOPT_SECURITY, 0x08, 11, "sec-level" }, + { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */ + { IPOPT_SATID, 0x20, 4, "satid" }, + { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */ + { 0, 0, 0, NULL } /* must be last */ +}; + +struct ipopt_names secnames[] = { + { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" }, + { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" }, + { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" }, + { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" }, + { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" }, + { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" }, + { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" }, + { 0, 0, 0, NULL } /* must be last */ +}; + + +u_short ipseclevel(slevel) + char *slevel; +{ + struct ipopt_names *so; + + for (so = secnames; so->on_name; so++) + if (!strcasecmp(slevel, so->on_name)) + break; + + if (!so->on_name) { + fprintf(stderr, "no such security level: %s\n", slevel); + return 0; + } + return so->on_value; +} + + +int addipopt(op, io, len, class) + char *op; + struct ipopt_names *io; + int len; + char *class; +{ + struct in_addr ipadr; + int olen = len, srr = 0; + u_short val; + u_char lvl; + char *s = op, *t; + + if ((len + io->on_siz) > 48) { + fprintf(stderr, "options too long\n"); + return 0; + } + len += io->on_siz; + *op++ = io->on_value; + if (io->on_siz > 1) { + /* + * Allow option to specify RR buffer length in bytes. + */ + if (io->on_value == IPOPT_RR) { + val = (class && *class) ? atoi(class) : 4; + *op++ = val + io->on_siz; + len += val; + } else + *op++ = io->on_siz; + if (io->on_value == IPOPT_TS) + *op++ = IPOPT_MINOFF + 1; + else + *op++ = IPOPT_MINOFF; + + while (class && *class) { + t = NULL; + switch (io->on_value) + { + case IPOPT_SECURITY : + lvl = ipseclevel(class); + *(op - 1) = lvl; + break; + case IPOPT_LSRR : + case IPOPT_SSRR : + if ((t = strchr(class, ','))) + *t = '\0'; + ipadr.s_addr = inet_addr(class); + srr++; + bcopy((char *)&ipadr, op, sizeof(ipadr)); + op += sizeof(ipadr); + break; + case IPOPT_SATID : + val = atoi(class); + bcopy((char *)&val, op, 2); + break; + } + + if (t) + *t++ = ','; + class = t; + } + if (srr) + s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr; + if (io->on_value == IPOPT_RR) + op += val; + else + op += io->on_siz - 3; + } + return len - olen; +} + + +u_32_t buildopts(cp, op, len) + char *cp, *op; + int len; +{ + struct ipopt_names *io; + u_32_t msk = 0; + char *s, *t; + int inc, lastop = -1; + + for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { + if ((t = strchr(s, '='))) + *t++ = '\0'; + for (io = ionames; io->on_name; io++) { + if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) + continue; + lastop = io->on_value; + if ((inc = addipopt(op, io, len, t))) { + op += inc; + len += inc; + } + msk |= io->on_bit; + break; + } + if (!io->on_name) { + fprintf(stderr, "unknown IP option name %s\n", s); + return 0; + } + } + + if (len & 3) { + while (len & 3) { + *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP; + len++; + } + } else { + if (lastop != IPOPT_EOL) { + if (lastop == IPOPT_NOP) + *(op - 1) = IPOPT_EOL; + else { + *op++ = IPOPT_NOP; + *op++ = IPOPT_NOP; + *op++ = IPOPT_NOP; + *op = IPOPT_EOL; + len += 4; + } + } + } + return len; +} diff --git a/contrib/ipfilter/ipsend/iptest.1 b/contrib/ipfilter/ipsend/iptest.1 new file mode 100644 index 0000000..8f25f4a --- /dev/null +++ b/contrib/ipfilter/ipsend/iptest.1 @@ -0,0 +1,103 @@ +.\" $FreeBSD$ +.\" +.TH IPTEST 1 +.SH NAME +iptest \- automatically generate a packets to test IP functionality +.SH SYNOPSIS +.B iptest +[ +.B \-1234567 +] [ +.B \-d +<device> +] [ +.B \-g +<gateway> +] [ +.B \-m +<\fIMTU\fP> +] [ +.B \-p +<\fIpointtest\fP> +] [ +.B \-s +<\fIsource\fP> +] <destination> +.SH DESCRIPTION +.PP +\fBiptest\fP ... +.SH OPTIONS +.TP +.B \-1 +Run IP test group #1. This group of tests generates packets with the IP +header fields set to invalid values given other packet characteristics. +The point tests are: 1 (ip_hl < ip_len), 2 (ip_hl > ip_len), +3 (ip_v < 4), 4 (ip_v > 4), 5 (ip_len < packetsize, long packets), +6 (ip_len > packet size, short packets), 7 (Zero length fragments), +8 (packet > 64k after reassembly), 9 (IP offset with MSB set), 10 (ttl +variations). +.TP +.B \-2 +Run IP test group #2. This group of tests generates packets with the IP +options constructed with invalid values given other packet characteristics. +The point tests are: 1 (option length > packet length), 2 (option length = 0). +.TP +.B \-3 +Run IP test group #3. This group of tests generates packets with the ICMP +header fields set to non-standard values. The point tests are: 1 (ICMP types +0-31 & 255), 2 (type 3 & code 0 - 31), 3 (type 4 & code 0, 127, 128, 255), +4 (type 5 & code 0, 127, 128, 255), 5 (types 8-10,13-18 with codes 0, 127, +128 and 255), 6 (type 12 & code 0, 127, 128, 129, 255) and 7 (type 3 & codes +9-10, 13-14 and 17-18 - shortened packets). +.TP +.B \-4 +Run IP test group #4. This group of tests generates packets with the UDP +header fields set to non-standard values. The point tests are: 1 (UDP length +> packet size), 2 (UDP length < packetsize), 3 (sport = 0, 1, 32767, 32768, +65535), 4 (dport = 0, 1, 32767, 32768, 65535) and 5 (sizeof(struct ip) <= MTU +<= sizeof(struct udphdr) + sizeof(struct ip)). +.TP +.B \-5 +Run IP test group #5. This group of tests generates packets with the TCP +header fields set to non-standard values. The point tests are: 1 (TCP flags +variations, all combinations), 2 (seq = 0, 0x7fffffff, 0x8000000, 0xa0000000, +0xffffffff), 3 (ack = 0, 0x7fffffff, 0x8000000, 0xa0000000, 0xffffffff), +4 (SYN packet with window of 0, 32768, 65535), 5 (set urgent pointer to 1, +0x7fff, 0x8000, 0xffff), 6 (data offset), 7 (sport = 0, 1, 32767, 32768, +65535) and 8 (dport = 0, 1, 32767, 32768, 65535). +.TP +.B \-6 +Run IP test group #6. This test generates a large number of fragments in +an attempt to exhaust the network buffers used for holding packets for later +reassembly. WARNING: this may crash or cause serious performance degradation +to the target host. +.TP +.B \-7 +Run IP test group #7. This test generates 1024 random IP packets with only +the IP version, checksum, length and IP offset field correct. +.TP +.BR \-d \0<interface> +Set the interface name to be the name supplied. +.TP +.BR \-g \0<gateway> +Specify the hostname of the gateway through which to route packets. This +is required whenever the destination host isn't directly attached to the +same network as the host from which you're sending. +.TP +.BR \-m \0<MTU> +Specify the MTU to be used when sending out packets. This option allows you +to set a fake MTU, allowing the simulation of network interfaces with small +MTU's without setting them so. +.TP +.B \-p <test> +Run a... +.DT +.SH SEE ALSO +ipsend(1), ipresend(1), bpf(4), ipsend(5), dlpi(7p) +.SH DIAGNOSTICS +Only one of the numeric test options may be given when \fIiptest\fP is run. +.PP +Needs to be run as root. +.SH BUGS +.PP +If you find any, please send email to me at darrenr@pobox.com diff --git a/contrib/ipfilter/ipsend/iptest.c b/contrib/ipfilter/ipsend/iptest.c new file mode 100644 index 0000000..c6cfb1c --- /dev/null +++ b/contrib/ipfilter/ipsend/iptest.c @@ -0,0 +1,218 @@ +/* $FreeBSD$ */ + +/* + * ipsend.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#ifndef linux +#include <netinet/ip_var.h> +#endif +#ifdef linux +#include <linux/sockios.h> +#endif +#include <stdio.h> +#include <netdb.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include "ipsend.h" + + +extern char *optarg; +extern int optind; + +char options[68]; +#ifdef linux +char default_device[] = "eth0"; +#else +# ifdef sun +char default_device[] = "le0"; +# else +# ifdef ultrix +char default_device[] = "ln0"; +# else +# ifdef __bsdi__ +char default_device[] = "ef0"; +# else +# ifdef __sgi +char default_device[] = "ec0"; +# else +char default_device[] = "lan0"; +# endif +# endif +# endif +# endif +#endif + +static void usage __P((char *)); +int main __P((int, char **)); + + +static void usage(prog) + char *prog; +{ + fprintf(stderr, "Usage: %s [options] dest\n\ +\toptions:\n\ +\t\t-d device\tSend out on this device\n\ +\t\t-g gateway\tIP gateway to use if non-local dest.\n\ +\t\t-m mtu\t\tfake MTU to use when sending out\n\ +\t\t-p pointtest\t\n\ +\t\t-s src\t\tsource address for IP packet\n\ +\t\t-1 \t\tPerform test 1 (IP header)\n\ +\t\t-2 \t\tPerform test 2 (IP options)\n\ +\t\t-3 \t\tPerform test 3 (ICMP)\n\ +\t\t-4 \t\tPerform test 4 (UDP)\n\ +\t\t-5 \t\tPerform test 5 (TCP)\n\ +\t\t-6 \t\tPerform test 6 (overlapping fragments)\n\ +\t\t-7 \t\tPerform test 7 (random packets)\n\ +", prog); + exit(1); +} + + +int main(argc, argv) + int argc; + char **argv; +{ + struct tcpiphdr *ti; + struct in_addr gwip; + ip_t *ip; + char *name = argv[0], host[MAXHOSTNAMELEN + 1]; + char *gateway = NULL, *dev = NULL; + char *src = NULL, *dst; + int mtu = 1500, tests = 0, pointtest = 0, c; + + /* + * 65535 is maximum packet size...you never know... + */ + ip = (ip_t *)calloc(1, 65536); + ti = (struct tcpiphdr *)ip; + ip->ip_len = sizeof(*ip); + IP_HL_A(ip, sizeof(*ip) >> 2); + + while ((c = getopt(argc, argv, "1234567d:g:m:p:s:")) != -1) + switch (c) + { + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + tests = c - '0'; + break; + case 'd' : + dev = optarg; + break; + case 'g' : + gateway = optarg; + break; + case 'm' : + mtu = atoi(optarg); + if (mtu < 28) + { + fprintf(stderr, "mtu must be > 28\n"); + exit(1); + } + break; + case 'p' : + pointtest = atoi(optarg); + break; + case 's' : + src = optarg; + break; + default : + fprintf(stderr, "Unknown option \"%c\"\n", c); + usage(name); + } + + if ((argc <= optind) || !argv[optind]) + usage(name); + dst = argv[optind++]; + + if (!src) + { + gethostname(host, sizeof(host)); + host[sizeof(host) - 1] = '\0'; + src = host; + } + + if (resolve(dst, (char *)&ip->ip_dst) == -1) + { + fprintf(stderr,"Cant resolve %s\n", dst); + exit(2); + } + + if (resolve(src, (char *)&ip->ip_src) == -1) + { + fprintf(stderr,"Cant resolve %s\n", src); + exit(2); + } + + if (!gateway) + gwip = ip->ip_dst; + else if (resolve(gateway, (char *)&gwip) == -1) + { + fprintf(stderr,"Cant resolve %s\n", gateway); + exit(2); + } + + + if (!dev) + dev = default_device; + printf("Device: %s\n", dev); + printf("Source: %s\n", inet_ntoa(ip->ip_src)); + printf("Dest: %s\n", inet_ntoa(ip->ip_dst)); + printf("Gateway: %s\n", inet_ntoa(gwip)); + printf("mtu: %d\n", mtu); + + switch (tests) + { + case 1 : + ip_test1(dev, mtu, (ip_t *)ti, gwip, pointtest); + break; + case 2 : + ip_test2(dev, mtu, (ip_t *)ti, gwip, pointtest); + break; + case 3 : + ip_test3(dev, mtu, (ip_t *)ti, gwip, pointtest); + break; + case 4 : + ip_test4(dev, mtu, (ip_t *)ti, gwip, pointtest); + break; + case 5 : + ip_test5(dev, mtu, (ip_t *)ti, gwip, pointtest); + break; + case 6 : + ip_test6(dev, mtu, (ip_t *)ti, gwip, pointtest); + break; + case 7 : + ip_test7(dev, mtu, (ip_t *)ti, gwip, pointtest); + break; + default : + ip_test1(dev, mtu, (ip_t *)ti, gwip, pointtest); + ip_test2(dev, mtu, (ip_t *)ti, gwip, pointtest); + ip_test3(dev, mtu, (ip_t *)ti, gwip, pointtest); + ip_test4(dev, mtu, (ip_t *)ti, gwip, pointtest); + ip_test5(dev, mtu, (ip_t *)ti, gwip, pointtest); + ip_test6(dev, mtu, (ip_t *)ti, gwip, pointtest); + ip_test7(dev, mtu, (ip_t *)ti, gwip, pointtest); + break; + } + return 0; +} diff --git a/contrib/ipfilter/ipsend/iptests.c b/contrib/ipfilter/ipsend/iptests.c new file mode 100644 index 0000000..0ca02db --- /dev/null +++ b/contrib/ipfilter/ipsend/iptests.c @@ -0,0 +1,1426 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#if !defined(lint) +static const char sccsid[] = "%W% %G% (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#if defined(__NetBSD__) && defined(__vax__) +/* + * XXX need to declare boolean_t for _KERNEL <sys/files.h> + * which ends up including <sys/device.h> for vax. See PR#32907 + * for further details. + */ +typedef int boolean_t; +#endif +#include <sys/time.h> +#if !defined(__osf__) +# ifdef __NetBSD__ +# include <machine/lock.h> +# include <machine/mutex.h> +# endif +# define _KERNEL +# define KERNEL +# if !defined(solaris) && !defined(linux) && !defined(__sgi) && !defined(hpux) +# include <sys/file.h> +# else +# ifdef solaris +# include <sys/dditypes.h> +# endif +# endif +# undef _KERNEL +# undef KERNEL +#endif +#if !defined(solaris) && !defined(linux) && !defined(__sgi) +# include <nlist.h> +# include <sys/user.h> +# include <sys/proc.h> +#endif +#if !defined(ultrix) && !defined(hpux) && !defined(linux) && \ + !defined(__sgi) && !defined(__osf__) && !defined(_AIX51) +# include <kvm.h> +#endif +#ifndef ultrix +# include <sys/socket.h> +#endif +#if defined(solaris) +# include <sys/stream.h> +#else +# include <sys/socketvar.h> +#endif +#ifdef sun +#include <sys/systm.h> +#include <sys/session.h> +#endif +#if BSD >= 199103 +# include <sys/sysctl.h> +# include <sys/filedesc.h> +# include <paths.h> +#endif +#include <netinet/in_systm.h> +#include <sys/socket.h> +#ifdef __hpux +# define _NET_ROUTE_INCLUDED +#endif +#include <net/if.h> +#if defined(linux) && (LINUX >= 0200) +# include <asm/atomic.h> +#endif +#if !defined(linux) +# if defined(__FreeBSD__) +# include "radix_ipf.h" +# endif +# if !defined(solaris) +# include <net/route.h> +# endif +#else +# define __KERNEL__ /* because there's a macro not wrapped by this */ +# include <net/route.h> /* in this file :-/ */ +#endif +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/ip.h> +#if defined(__SVR4) || defined(__svr4__) || defined(__sgi) +# include <sys/sysmacros.h> +#endif +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#ifdef __hpux +# undef _NET_ROUTE_INCLUDED +#endif +#if !defined(linux) +# include <netinet/ip_var.h> +# if !defined(__hpux) && !defined(solaris) +# include <netinet/in_pcb.h> +# endif +#endif +#include "ipsend.h" +#if !defined(linux) && !defined(__hpux) +# include <netinet/tcp_timer.h> +# include <netinet/tcp_var.h> +#endif +#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106000000) +# define USE_NANOSLEEP +#endif + + +#ifdef USE_NANOSLEEP +# define PAUSE() ts.tv_sec = 0; ts.tv_nsec = 10000000; \ + (void) nanosleep(&ts, NULL) +#else +# define PAUSE() tv.tv_sec = 0; tv.tv_usec = 10000; \ + (void) select(0, NULL, NULL, NULL, &tv) +#endif + + +void ip_test1(dev, mtu, ip, gwip, ptest) + char *dev; + int mtu; + ip_t *ip; + struct in_addr gwip; + int ptest; +{ +#ifdef USE_NANOSLEEP + struct timespec ts; +#else + struct timeval tv; +#endif + udphdr_t *u; + int nfd, i = 0, len, id = getpid(); + + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); + ip->ip_tos = 0; + ip->ip_off = 0; + ip->ip_ttl = 60; + ip->ip_p = IPPROTO_UDP; + ip->ip_sum = 0; + u = (udphdr_t *)(ip + 1); + u->uh_sport = htons(1); + u->uh_dport = htons(9); + u->uh_sum = 0; + u->uh_ulen = htons(sizeof(*u) + 4); + ip->ip_len = sizeof(*ip) + ntohs(u->uh_ulen); + len = ip->ip_len; + + nfd = initdevice(dev, 1); + if (nfd == -1) + return; + + if (!ptest || (ptest == 1)) { + /* + * Part1: hl < len + */ + ip->ip_id = 0; + printf("1.1. sending packets with ip_hl < ip_len\n"); + for (i = 0; i < ((sizeof(*ip) + ntohs(u->uh_ulen)) >> 2); i++) { + IP_HL_A(ip, i >> 2); + (void) send_ip(nfd, 1500, ip, gwip, 1); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 2)) { + /* + * Part2: hl > len + */ + ip->ip_id = 0; + printf("1.2. sending packets with ip_hl > ip_len\n"); + for (; i < ((sizeof(*ip) * 2 + ntohs(u->uh_ulen)) >> 2); i++) { + IP_HL_A(ip, i >> 2); + (void) send_ip(nfd, 1500, ip, gwip, 1); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 3)) { + /* + * Part3: v < 4 + */ + ip->ip_id = 0; + printf("1.3. ip_v < 4\n"); + IP_HL_A(ip, sizeof(*ip) >> 2); + for (i = 0; i < 4; i++) { + IP_V_A(ip, i); + (void) send_ip(nfd, 1500, ip, gwip, 1); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 4)) { + /* + * Part4: v > 4 + */ + ip->ip_id = 0; + printf("1.4. ip_v > 4\n"); + for (i = 5; i < 16; i++) { + IP_V_A(ip, i); + (void) send_ip(nfd, 1500, ip, gwip, 1); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 5)) { + /* + * Part5: len < packet + */ + ip->ip_id = 0; + IP_V_A(ip, IPVERSION); + i = ip->ip_len + 1; + printf("1.5.0 ip_len < packet size (size++, long packets)\n"); + for (; i < (ip->ip_len * 2); i++) { + ip->ip_id = htons(id++); + ip->ip_sum = 0; + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); + (void) send_ether(nfd, (char *)ip, i, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + printf("1.5.1 ip_len < packet size (ip_len-, short packets)\n"); + for (i = len; i > 0; i--) { + ip->ip_id = htons(id++); + ip->ip_len = i; + ip->ip_sum = 0; + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); + (void) send_ether(nfd, (char *)ip, len, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 6)) { + /* + * Part6: len > packet + */ + ip->ip_id = 0; + printf("1.6.0 ip_len > packet size (increase ip_len)\n"); + for (i = len + 1; i < (len * 2); i++) { + ip->ip_id = htons(id++); + ip->ip_len = i; + ip->ip_sum = 0; + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); + (void) send_ether(nfd, (char *)ip, len, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + ip->ip_len = len; + printf("1.6.1 ip_len > packet size (size--, short packets)\n"); + for (i = len; i > 0; i--) { + ip->ip_id = htons(id++); + ip->ip_sum = 0; + ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); + (void) send_ether(nfd, (char *)ip, i, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 7)) { + /* + * Part7: 0 length fragment + */ + printf("1.7.0 Zero length fragments (ip_off = 0x2000)\n"); + ip->ip_id = 0; + ip->ip_len = sizeof(*ip); + ip->ip_off = htons(IP_MF); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + printf("1.7.1 Zero length fragments (ip_off = 0x3000)\n"); + ip->ip_id = 0; + ip->ip_len = sizeof(*ip); + ip->ip_off = htons(IP_MF); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + printf("1.7.2 Zero length fragments (ip_off = 0xa000)\n"); + ip->ip_id = 0; + ip->ip_len = sizeof(*ip); + ip->ip_off = htons(0xa000); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + printf("1.7.3 Zero length fragments (ip_off = 0x0100)\n"); + ip->ip_id = 0; + ip->ip_len = sizeof(*ip); + ip->ip_off = htons(0x0100); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + } + + if (!ptest || (ptest == 8)) { + struct timeval tv; + + gettimeofday(&tv, NULL); + srand(tv.tv_sec ^ getpid() ^ tv.tv_usec); + /* + * Part8.1: 63k packet + 1k fragment at offset 0x1ffe + * Mark it as being ICMP (so it doesn't get junked), but + * don't bother about the ICMP header, we're not worrying + * about that here. + */ + ip->ip_p = IPPROTO_ICMP; + ip->ip_off = htons(IP_MF); + u->uh_dport = htons(9); + ip->ip_id = htons(id++); + printf("1.8.1 63k packet + 1k fragment at offset 0x1ffe\n"); + ip->ip_len = 768 + 20 + 8; + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + + ip->ip_len = MIN(768 + 20, mtu - 68); + i = 512; + for (; i < (63 * 1024 + 768); i += 768) { + ip->ip_off = htons(IP_MF | (i >> 3)); + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + ip->ip_len = 896 + 20; + ip->ip_off = htons(i >> 3); + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + putchar('\n'); + fflush(stdout); + + /* + * Part8.2: 63k packet + 1k fragment at offset 0x1ffe + * Mark it as being ICMP (so it doesn't get junked), but + * don't bother about the ICMP header, we're not worrying + * about that here. (Lossage here) + */ + ip->ip_p = IPPROTO_ICMP; + ip->ip_off = htons(IP_MF); + u->uh_dport = htons(9); + ip->ip_id = htons(id++); + printf("1.8.2 63k packet + 1k fragment at offset 0x1ffe\n"); + ip->ip_len = 768 + 20 + 8; + if ((rand() & 0x1f) != 0) { + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + } else + printf("skip 0\n"); + + ip->ip_len = MIN(768 + 20, mtu - 68); + i = 512; + for (; i < (63 * 1024 + 768); i += 768) { + ip->ip_off = htons(IP_MF | (i >> 3)); + if ((rand() & 0x1f) != 0) { + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + } else + printf("skip %d\n", i); + fflush(stdout); + PAUSE(); + } + ip->ip_len = 896 + 20; + ip->ip_off = htons(i >> 3); + if ((rand() & 0x1f) != 0) { + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + } else + printf("skip\n"); + putchar('\n'); + fflush(stdout); + + /* + * Part8.3: 33k packet - test for not dealing with -ve length + * Mark it as being ICMP (so it doesn't get junked), but + * don't bother about the ICMP header, we're not worrying + * about that here. + */ + ip->ip_p = IPPROTO_ICMP; + ip->ip_off = htons(IP_MF); + u->uh_dport = htons(9); + ip->ip_id = htons(id++); + printf("1.8.3 33k packet\n"); + ip->ip_len = 768 + 20 + 8; + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + + ip->ip_len = MIN(768 + 20, mtu - 68); + i = 512; + for (; i < (32 * 1024 + 768); i += 768) { + ip->ip_off = htons(IP_MF | (i >> 3)); + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + ip->ip_len = 896 + 20; + ip->ip_off = htons(i >> 3); + (void) send_ip(nfd, mtu, ip, gwip, 1); + printf("%d\r", i); + putchar('\n'); + fflush(stdout); + } + + ip->ip_len = len; + ip->ip_off = 0; + if (!ptest || (ptest == 9)) { + /* + * Part9: off & 0x8000 == 0x8000 + */ + ip->ip_id = 0; + ip->ip_off = htons(0x8000); + printf("1.9. ip_off & 0x8000 == 0x8000\n"); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + } + + ip->ip_off = 0; + + if (!ptest || (ptest == 10)) { + /* + * Part10: ttl = 255 + */ + ip->ip_id = 0; + ip->ip_ttl = 255; + printf("1.10.0 ip_ttl = 255\n"); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + ip->ip_ttl = 128; + printf("1.10.1 ip_ttl = 128\n"); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + ip->ip_ttl = 0; + printf("1.10.2 ip_ttl = 0\n"); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + } + + (void) close(nfd); +} + + +void ip_test2(dev, mtu, ip, gwip, ptest) + char *dev; + int mtu; + ip_t *ip; + struct in_addr gwip; + int ptest; +{ +#ifdef USE_NANOSLEEP + struct timespec ts; +#else + struct timeval tv; +#endif + int nfd; + u_char *s; + + + nfd = initdevice(dev, 1); + if (nfd == -1) + return; + + IP_HL_A(ip, 6); + ip->ip_len = IP_HL(ip) << 2; + s = (u_char *)(ip + 1); + s[IPOPT_OPTVAL] = IPOPT_NOP; + s++; + if (!ptest || (ptest == 1)) { + /* + * Test 1: option length > packet length, + * header length == packet length + */ + s[IPOPT_OPTVAL] = IPOPT_TS; + s[IPOPT_OLEN] = 4; + s[IPOPT_OFFSET] = IPOPT_MINOFF; + ip->ip_p = IPPROTO_IP; + printf("2.1 option length > packet length\n"); + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + } + + IP_HL_A(ip, 7); + ip->ip_len = IP_HL(ip) << 2; + if (!ptest || (ptest == 1)) { + /* + * Test 2: options have length = 0 + */ + printf("2.2.1 option length = 0, RR\n"); + s[IPOPT_OPTVAL] = IPOPT_RR; + s[IPOPT_OLEN] = 0; + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + printf("2.2.2 option length = 0, TS\n"); + s[IPOPT_OPTVAL] = IPOPT_TS; + s[IPOPT_OLEN] = 0; + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + printf("2.2.3 option length = 0, SECURITY\n"); + s[IPOPT_OPTVAL] = IPOPT_SECURITY; + s[IPOPT_OLEN] = 0; + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + printf("2.2.4 option length = 0, LSRR\n"); + s[IPOPT_OPTVAL] = IPOPT_LSRR; + s[IPOPT_OLEN] = 0; + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + printf("2.2.5 option length = 0, SATID\n"); + s[IPOPT_OPTVAL] = IPOPT_SATID; + s[IPOPT_OLEN] = 0; + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + + printf("2.2.6 option length = 0, SSRR\n"); + s[IPOPT_OPTVAL] = IPOPT_SSRR; + s[IPOPT_OLEN] = 0; + (void) send_ip(nfd, mtu, ip, gwip, 1); + fflush(stdout); + PAUSE(); + } + + (void) close(nfd); +} + + +/* + * test 3 (ICMP) + */ +void ip_test3(dev, mtu, ip, gwip, ptest) + char *dev; + int mtu; + ip_t *ip; + struct in_addr gwip; + int ptest; +{ + static int ict1[10] = { 8, 9, 10, 13, 14, 15, 16, 17, 18, 0 }; + static int ict2[8] = { 3, 9, 10, 13, 14, 17, 18, 0 }; +#ifdef USE_NANOSLEEP + struct timespec ts; +#else + struct timeval tv; +#endif + struct icmp *icp; + int nfd, i; + + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); + ip->ip_tos = 0; + ip->ip_off = 0; + ip->ip_ttl = 60; + ip->ip_p = IPPROTO_ICMP; + ip->ip_sum = 0; + ip->ip_len = sizeof(*ip) + sizeof(*icp); + icp = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); + + nfd = initdevice(dev, 1); + if (nfd == -1) + return; + + if (!ptest || (ptest == 1)) { + /* + * Type 0 - 31, 255, code = 0 + */ + bzero((char *)icp, sizeof(*icp)); + for (i = 0; i < 32; i++) { + icp->icmp_type = i; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.1.%d ICMP type %d code 0 (all 0's)\r", i, i); + } + icp->icmp_type = 255; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.1.%d ICMP type %d code 0 (all 0's)\r", i, 255); + putchar('\n'); + } + + if (!ptest || (ptest == 2)) { + /* + * Type 3, code = 0 - 31 + */ + icp->icmp_type = 3; + for (i = 0; i < 32; i++) { + icp->icmp_code = i; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.2.%d ICMP type 3 code %d (all 0's)\r", i, i); + } + } + + if (!ptest || (ptest == 3)) { + /* + * Type 4, code = 0,127,128,255 + */ + icp->icmp_type = 4; + icp->icmp_code = 0; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.3.1 ICMP type 4 code 0 (all 0's)\r"); + icp->icmp_code = 127; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.3.2 ICMP type 4 code 127 (all 0's)\r"); + icp->icmp_code = 128; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.3.3 ICMP type 4 code 128 (all 0's)\r"); + icp->icmp_code = 255; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.3.4 ICMP type 4 code 255 (all 0's)\r"); + } + + if (!ptest || (ptest == 4)) { + /* + * Type 5, code = 0,127,128,255 + */ + icp->icmp_type = 5; + icp->icmp_code = 0; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.4.1 ICMP type 5 code 0 (all 0's)\r"); + icp->icmp_code = 127; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.4.2 ICMP type 5 code 127 (all 0's)\r"); + icp->icmp_code = 128; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.4.3 ICMP type 5 code 128 (all 0's)\r"); + icp->icmp_code = 255; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.4.4 ICMP type 5 code 255 (all 0's)\r"); + } + + if (!ptest || (ptest == 5)) { + /* + * Type 8-10;13-18, code - 0,127,128,255 + */ + for (i = 0; ict1[i]; i++) { + icp->icmp_type = ict1[i]; + icp->icmp_code = 0; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.5.%d ICMP type 5 code 0 (all 0's)\r", + i * 4); + icp->icmp_code = 127; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.5.%d ICMP type 5 code 127 (all 0's)\r", + i * 4 + 1); + icp->icmp_code = 128; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.5.%d ICMP type 5 code 128 (all 0's)\r", + i * 4 + 2); + icp->icmp_code = 255; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.5.%d ICMP type 5 code 255 (all 0's)\r", + i * 4 + 3); + } + putchar('\n'); + } + + if (!ptest || (ptest == 6)) { + /* + * Type 12, code - 0,127,128,129,255 + */ + icp->icmp_type = 12; + icp->icmp_code = 0; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.6.1 ICMP type 12 code 0 (all 0's)\r"); + icp->icmp_code = 127; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.6.2 ICMP type 12 code 127 (all 0's)\r"); + icp->icmp_code = 128; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.6.3 ICMP type 12 code 128 (all 0's)\r"); + icp->icmp_code = 129; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.6.4 ICMP type 12 code 129 (all 0's)\r"); + icp->icmp_code = 255; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.6.5 ICMP type 12 code 255 (all 0's)\r"); + putchar('\n'); + } + + if (!ptest || (ptest == 7)) { + /* + * Type 3;9-10;13-14;17-18 - shorter packets + */ + ip->ip_len = sizeof(*ip) + sizeof(*icp) / 2; + for (i = 0; ict2[i]; i++) { + icp->icmp_type = ict1[i]; + icp->icmp_code = 0; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.5.%d ICMP type %d code 0 (all 0's)\r", + i * 4, icp->icmp_type); + icp->icmp_code = 127; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.5.%d ICMP type %d code 127 (all 0's)\r", + i * 4 + 1, icp->icmp_type); + icp->icmp_code = 128; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.5.%d ICMP type %d code 128 (all 0's)\r", + i * 4 + 2, icp->icmp_type); + icp->icmp_code = 255; + (void) send_icmp(nfd, mtu, ip, gwip); + PAUSE(); + printf("3.5.%d ICMP type %d code 127 (all 0's)\r", + i * 4 + 3, icp->icmp_type); + } + putchar('\n'); + } +} + + +/* Perform test 4 (UDP) */ + +void ip_test4(dev, mtu, ip, gwip, ptest) + char *dev; + int mtu; + ip_t *ip; + struct in_addr gwip; + int ptest; +{ +#ifdef USE_NANOSLEEP + struct timespec ts; +#else + struct timeval tv; +#endif + udphdr_t *u; + int nfd, i; + + + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); + ip->ip_tos = 0; + ip->ip_off = 0; + ip->ip_ttl = 60; + ip->ip_p = IPPROTO_UDP; + ip->ip_sum = 0; + u = (udphdr_t *)((char *)ip + (IP_HL(ip) << 2)); + u->uh_sport = htons(1); + u->uh_dport = htons(1); + u->uh_ulen = htons(sizeof(*u) + 4); + + nfd = initdevice(dev, 1); + if (nfd == -1) + return; + + if (!ptest || (ptest == 1)) { + /* + * Test 1. ulen > packet + */ + u->uh_ulen = htons(sizeof(*u) + 4); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); + printf("4.1 UDP uh_ulen > packet size - short packets\n"); + for (i = ntohs(u->uh_ulen) * 2; i > sizeof(*u) + 4; i--) { + u->uh_ulen = htons(i); + (void) send_udp(nfd, 1500, ip, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 2)) { + /* + * Test 2. ulen < packet + */ + u->uh_ulen = htons(sizeof(*u) + 4); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); + printf("4.2 UDP uh_ulen < packet size - short packets\n"); + for (i = ntohs(u->uh_ulen) * 2; i > sizeof(*u) + 4; i--) { + ip->ip_len = i; + (void) send_udp(nfd, 1500, ip, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 3)) { + /* + * Test 3: sport = 0, sport = 1, sport = 32767 + * sport = 32768, sport = 65535 + */ + u->uh_ulen = sizeof(*u) + 4; + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); + printf("4.3.1 UDP sport = 0\n"); + u->uh_sport = 0; + (void) send_udp(nfd, 1500, ip, gwip); + printf("0\n"); + fflush(stdout); + PAUSE(); + printf("4.3.2 UDP sport = 1\n"); + u->uh_sport = htons(1); + (void) send_udp(nfd, 1500, ip, gwip); + printf("1\n"); + fflush(stdout); + PAUSE(); + printf("4.3.3 UDP sport = 32767\n"); + u->uh_sport = htons(32767); + (void) send_udp(nfd, 1500, ip, gwip); + printf("32767\n"); + fflush(stdout); + PAUSE(); + printf("4.3.4 UDP sport = 32768\n"); + u->uh_sport = htons(32768); + (void) send_udp(nfd, 1500, ip, gwip); + printf("32768\n"); + putchar('\n'); + fflush(stdout); + PAUSE(); + printf("4.3.5 UDP sport = 65535\n"); + u->uh_sport = htons(65535); + (void) send_udp(nfd, 1500, ip, gwip); + printf("65535\n"); + fflush(stdout); + PAUSE(); + } + + if (!ptest || (ptest == 4)) { + /* + * Test 4: dport = 0, dport = 1, dport = 32767 + * dport = 32768, dport = 65535 + */ + u->uh_ulen = ntohs(sizeof(*u) + 4); + u->uh_sport = htons(1); + ip->ip_len = (IP_HL(ip) << 2) + ntohs(u->uh_ulen); + printf("4.4.1 UDP dport = 0\n"); + u->uh_dport = 0; + (void) send_udp(nfd, 1500, ip, gwip); + printf("0\n"); + fflush(stdout); + PAUSE(); + printf("4.4.2 UDP dport = 1\n"); + u->uh_dport = htons(1); + (void) send_udp(nfd, 1500, ip, gwip); + printf("1\n"); + fflush(stdout); + PAUSE(); + printf("4.4.3 UDP dport = 32767\n"); + u->uh_dport = htons(32767); + (void) send_udp(nfd, 1500, ip, gwip); + printf("32767\n"); + fflush(stdout); + PAUSE(); + printf("4.4.4 UDP dport = 32768\n"); + u->uh_dport = htons(32768); + (void) send_udp(nfd, 1500, ip, gwip); + printf("32768\n"); + fflush(stdout); + PAUSE(); + printf("4.4.5 UDP dport = 65535\n"); + u->uh_dport = htons(65535); + (void) send_udp(nfd, 1500, ip, gwip); + printf("65535\n"); + fflush(stdout); + PAUSE(); + } + + if (!ptest || (ptest == 5)) { + /* + * Test 5: sizeof(ip_t) <= MTU <= sizeof(udphdr_t) + + * sizeof(ip_t) + */ + printf("4.5 UDP 20 <= MTU <= 32\n"); + for (i = sizeof(*ip); i <= ntohs(u->uh_ulen); i++) { + (void) send_udp(nfd, i, ip, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } +} + + +/* Perform test 5 (TCP) */ + +void ip_test5(dev, mtu, ip, gwip, ptest) + char *dev; + int mtu; + ip_t *ip; + struct in_addr gwip; + int ptest; +{ +#ifdef USE_NANOSLEEP + struct timespec ts; +#else + struct timeval tv; +#endif + tcphdr_t *t; + int nfd, i; + + t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); +#if !defined(linux) && !defined(__osf__) + t->th_x2 = 0; +#endif + TCP_OFF_A(t, 0); + t->th_sport = htons(1); + t->th_dport = htons(1); + t->th_win = htons(4096); + t->th_urp = 0; + t->th_sum = 0; + t->th_seq = htonl(1); + t->th_ack = 0; + ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t); + + nfd = initdevice(dev, 1); + if (nfd == -1) + return; + + if (!ptest || (ptest == 1)) { + /* + * Test 1: flags variations, 0 - 3f + */ + TCP_OFF_A(t, sizeof(*t) >> 2); + printf("5.1 Test TCP flag combinations\n"); + for (i = 0; i <= (TH_URG|TH_ACK|TH_PUSH|TH_RST|TH_SYN|TH_FIN); + i++) { + t->th_flags = i; + (void) send_tcp(nfd, mtu, ip, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + } + + if (!ptest || (ptest == 2)) { + t->th_flags = TH_SYN; + /* + * Test 2: seq = 0, seq = 1, seq = 0x7fffffff, seq=0x80000000, + * seq = 0xa000000, seq = 0xffffffff + */ + printf("5.2.1 TCP seq = 0\n"); + t->th_seq = htonl(0); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.2.2 TCP seq = 1\n"); + t->th_seq = htonl(1); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.2.3 TCP seq = 0x7fffffff\n"); + t->th_seq = htonl(0x7fffffff); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.2.4 TCP seq = 0x80000000\n"); + t->th_seq = htonl(0x80000000); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.2.5 TCP seq = 0xc0000000\n"); + t->th_seq = htonl(0xc0000000); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.2.6 TCP seq = 0xffffffff\n"); + t->th_seq = htonl(0xffffffff); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + } + + if (!ptest || (ptest == 3)) { + t->th_flags = TH_ACK; + /* + * Test 3: ack = 0, ack = 1, ack = 0x7fffffff, ack = 0x8000000 + * ack = 0xa000000, ack = 0xffffffff + */ + printf("5.3.1 TCP ack = 0\n"); + t->th_ack = 0; + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.3.2 TCP ack = 1\n"); + t->th_ack = htonl(1); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.3.3 TCP ack = 0x7fffffff\n"); + t->th_ack = htonl(0x7fffffff); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.3.4 TCP ack = 0x80000000\n"); + t->th_ack = htonl(0x80000000); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.3.5 TCP ack = 0xc0000000\n"); + t->th_ack = htonl(0xc0000000); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.3.6 TCP ack = 0xffffffff\n"); + t->th_ack = htonl(0xffffffff); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + } + + if (!ptest || (ptest == 4)) { + t->th_flags = TH_SYN; + /* + * Test 4: win = 0, win = 32768, win = 65535 + */ + printf("5.4.1 TCP win = 0\n"); + t->th_seq = htonl(0); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.4.2 TCP win = 32768\n"); + t->th_seq = htonl(0x7fff); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.4.3 TCP win = 65535\n"); + t->th_win = htons(0xffff); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + } + +#if !defined(linux) && !defined(__SVR4) && !defined(__svr4__) && \ + !defined(__sgi) && !defined(__hpux) && !defined(__osf__) + { + struct tcpcb *tcbp, tcb; + struct tcpiphdr ti; + struct sockaddr_in sin; + int fd; + socklen_t slen; + + bzero((char *)&sin, sizeof(sin)); + + for (i = 1; i < 63; i++) { + fd = socket(AF_INET, SOCK_STREAM, 0); + bzero((char *)&sin, sizeof(sin)); + sin.sin_addr.s_addr = ip->ip_dst.s_addr; + sin.sin_port = htons(i); + sin.sin_family = AF_INET; + if (!connect(fd, (struct sockaddr *)&sin, sizeof(sin))) + break; + close(fd); + } + + if (i == 63) { + printf("Couldn't open a TCP socket between ports 1 and 63\n"); + printf("to host %s for test 5 and 6 - skipping.\n", + inet_ntoa(ip->ip_dst)); + goto skip_five_and_six; + } + + bcopy((char *)ip, (char *)&ti, sizeof(*ip)); + t->th_dport = htons(i); + slen = sizeof(sin); + if (!getsockname(fd, (struct sockaddr *)&sin, &slen)) + t->th_sport = sin.sin_port; + if (!(tcbp = find_tcp(fd, &ti))) { + printf("Can't find PCB\n"); + goto skip_five_and_six; + } + KMCPY(&tcb, tcbp, sizeof(tcb)); + ti.ti_win = tcb.rcv_adv; + ti.ti_seq = htonl(tcb.snd_nxt - 1); + ti.ti_ack = tcb.rcv_nxt; + + if (!ptest || (ptest == 5)) { + /* + * Test 5: urp + */ + t->th_flags = TH_ACK|TH_URG; + printf("5.5.1 TCP Urgent pointer, sport %hu dport %hu\n", + ntohs(t->th_sport), ntohs(t->th_dport)); + t->th_urp = htons(1); + (void) send_tcp(nfd, mtu, ip, gwip); + PAUSE(); + + t->th_seq = htonl(tcb.snd_nxt); + ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t) + 1; + t->th_urp = htons(0x7fff); + (void) send_tcp(nfd, mtu, ip, gwip); + PAUSE(); + t->th_urp = htons(0x8000); + (void) send_tcp(nfd, mtu, ip, gwip); + PAUSE(); + t->th_urp = htons(0xffff); + (void) send_tcp(nfd, mtu, ip, gwip); + PAUSE(); + t->th_urp = 0; + t->th_flags &= ~TH_URG; + ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t); + } + + if (!ptest || (ptest == 6)) { + /* + * Test 6: data offset, off = 0, off is inside, off is outside + */ + t->th_flags = TH_ACK; + printf("5.6.1 TCP off = 1-15, len = 40\n"); + for (i = 1; i < 16; i++) { + TCP_OFF_A(t, ntohs(i)); + (void) send_tcp(nfd, mtu, ip, gwip); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + ip->ip_len = sizeof(ip_t) + sizeof(tcphdr_t); + } + + (void) close(fd); + } +skip_five_and_six: +#endif + t->th_seq = htonl(1); + t->th_ack = htonl(1); + TCP_OFF_A(t, 0); + + if (!ptest || (ptest == 7)) { + t->th_flags = TH_SYN; + /* + * Test 7: sport = 0, sport = 1, sport = 32767 + * sport = 32768, sport = 65535 + */ + printf("5.7.1 TCP sport = 0\n"); + t->th_sport = 0; + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.7.2 TCP sport = 1\n"); + t->th_sport = htons(1); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.7.3 TCP sport = 32767\n"); + t->th_sport = htons(32767); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.7.4 TCP sport = 32768\n"); + t->th_sport = htons(32768); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.7.5 TCP sport = 65535\n"); + t->th_sport = htons(65535); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + } + + if (!ptest || (ptest == 8)) { + t->th_sport = htons(1); + t->th_flags = TH_SYN; + /* + * Test 8: dport = 0, dport = 1, dport = 32767 + * dport = 32768, dport = 65535 + */ + printf("5.8.1 TCP dport = 0\n"); + t->th_dport = 0; + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.8.2 TCP dport = 1\n"); + t->th_dport = htons(1); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.8.3 TCP dport = 32767\n"); + t->th_dport = htons(32767); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.8.4 TCP dport = 32768\n"); + t->th_dport = htons(32768); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + + printf("5.8.5 TCP dport = 65535\n"); + t->th_dport = htons(65535); + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + } + + /* LAND attack - self connect, so make src & dst ip/port the same */ + if (!ptest || (ptest == 9)) { + printf("5.9 TCP LAND attack. sport = 25, dport = 25\n"); + /* chose SMTP port 25 */ + t->th_sport = htons(25); + t->th_dport = htons(25); + t->th_flags = TH_SYN; + ip->ip_src = ip->ip_dst; + (void) send_tcp(nfd, mtu, ip, gwip); + fflush(stdout); + PAUSE(); + } + + /* TCP options header checking */ + /* 0 length options, etc */ +} + + +/* Perform test 6 (exhaust mbuf test) */ + +void ip_test6(dev, mtu, ip, gwip, ptest) + char *dev; + int mtu; + ip_t *ip; + struct in_addr gwip; + int ptest; +{ +#ifdef USE_NANOSLEEP + struct timespec ts; +#else + struct timeval tv; +#endif + udphdr_t *u; + int nfd, i, j, k; + + IP_V_A(ip, IPVERSION); + ip->ip_tos = 0; + ip->ip_off = 0; + ip->ip_ttl = 60; + ip->ip_p = IPPROTO_UDP; + ip->ip_sum = 0; + u = (udphdr_t *)(ip + 1); + u->uh_sport = htons(1); + u->uh_dport = htons(9); + u->uh_sum = 0; + + nfd = initdevice(dev, 1); + if (nfd == -1) + return; + + u->uh_ulen = htons(7168); + + printf("6. Exhaustive mbuf test.\n"); + printf(" Send 7k packet in 768 & 128 byte fragments, 128 times.\n"); + printf(" Total of around 8,900 packets\n"); + for (i = 0; i < 128; i++) { + /* + * First send the entire packet in 768 byte chunks. + */ + ip->ip_len = sizeof(*ip) + 768 + sizeof(*u); + IP_HL_A(ip, sizeof(*ip) >> 2); + ip->ip_off = htons(IP_MF); + (void) send_ip(nfd, 1500, ip, gwip, 1); + printf("%d %d\r", i, 0); + fflush(stdout); + PAUSE(); + /* + * And again using 128 byte chunks. + */ + ip->ip_len = sizeof(*ip) + 128 + sizeof(*u); + ip->ip_off = htons(IP_MF); + (void) send_ip(nfd, 1500, ip, gwip, 1); + printf("%d %d\r", i, 0); + fflush(stdout); + PAUSE(); + + for (j = 768; j < 3584; j += 768) { + ip->ip_len = sizeof(*ip) + 768; + ip->ip_off = htons(IP_MF|(j>>3)); + (void) send_ip(nfd, 1500, ip, gwip, 1); + printf("%d %d\r", i, j); + fflush(stdout); + PAUSE(); + + ip->ip_len = sizeof(*ip) + 128; + for (k = j - 768; k < j; k += 128) { + ip->ip_off = htons(IP_MF|(k>>3)); + (void) send_ip(nfd, 1500, ip, gwip, 1); + printf("%d %d\r", i, k); + fflush(stdout); + PAUSE(); + } + } + } + putchar('\n'); +} + + +/* Perform test 7 (random packets) */ + +static u_long tbuf[64]; + +void ip_test7(dev, mtu, ip, gwip, ptest) + char *dev; + int mtu; + ip_t *ip; + struct in_addr gwip; + int ptest; +{ + ip_t *pip; +#ifdef USE_NANOSLEEP + struct timespec ts; +#else + struct timeval tv; +#endif + int nfd, i, j; + u_char *s; + + nfd = initdevice(dev, 1); + if (nfd == -1) + return; + + pip = (ip_t *)tbuf; + + srand(time(NULL) ^ (getpid() * getppid())); + + printf("7. send 1024 random IP packets.\n"); + + for (i = 0; i < 512; i++) { + for (s = (u_char *)pip, j = 0; j < sizeof(tbuf); j++, s++) + *s = (rand() >> 13) & 0xff; + IP_V_A(pip, IPVERSION); + bcopy((char *)&ip->ip_dst, (char *)&pip->ip_dst, + sizeof(struct in_addr)); + pip->ip_sum = 0; + pip->ip_len &= 0xff; + (void) send_ip(nfd, mtu, pip, gwip, 0); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); + + for (i = 0; i < 512; i++) { + for (s = (u_char *)pip, j = 0; j < sizeof(tbuf); j++, s++) + *s = (rand() >> 13) & 0xff; + IP_V_A(pip, IPVERSION); + pip->ip_off &= htons(0xc000); + bcopy((char *)&ip->ip_dst, (char *)&pip->ip_dst, + sizeof(struct in_addr)); + pip->ip_sum = 0; + pip->ip_len &= 0xff; + (void) send_ip(nfd, mtu, pip, gwip, 0); + printf("%d\r", i); + fflush(stdout); + PAUSE(); + } + putchar('\n'); +} diff --git a/contrib/ipfilter/ipsend/larp.c b/contrib/ipfilter/ipsend/larp.c new file mode 100644 index 0000000..5b79f73 --- /dev/null +++ b/contrib/ipfilter/ipsend/larp.c @@ -0,0 +1,93 @@ +/* $FreeBSD$ */ + +/* + * larp.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#if !defined(lint) +static const char sccsid[] = "@(#)larp.c 1.1 8/19/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <stdio.h> +#include <netdb.h> +#include <errno.h> + +#include "ip_compat.h" +#include "iplang/iplang.h" + +/* + * lookup host and return + * its IP address in address + * (4 bytes) + */ +int resolve(host, address) + char *host, *address; +{ + struct hostent *hp; + u_long add; + + add = inet_addr(host); + if (add == -1) + { + if (!(hp = gethostbyname(host))) + { + fprintf(stderr, "unknown host: %s\n", host); + return -1; + } + bcopy((char *)hp->h_addr, (char *)address, 4); + return 0; + } + bcopy((char*)&add, address, 4); + return 0; +} + +/* + * ARP for the MAC address corresponding + * to the IP address. This taken from + * some BSD program, I cant remember which. + */ +int arp(ip, ether) + char *ip; + char *ether; +{ + static int s = -1; + struct arpreq ar; + struct sockaddr_in *sin; + char *inet_ntoa(); + +#ifdef IP_SEND + if (arp_getipv4(ip, ether) == 0) + return 0; +#endif + bzero((char *)&ar, sizeof(ar)); + sin = (struct sockaddr_in *)&ar.arp_pa; + sin->sin_family = AF_INET; + bcopy(ip, (char *)&sin->sin_addr.s_addr, 4); + + if (s == -1) + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + perror("arp: socket"); + return -1; + } + + if (ioctl(s, SIOCGARP, (caddr_t)&ar) == -1) + { + fprintf(stderr, "(%s):", inet_ntoa(sin->sin_addr)); + if (errno != ENXIO) + perror("SIOCGARP"); + return -1; + } + + bcopy(ar.arp_ha.sa_data, ether, 6); + return 0; +} diff --git a/contrib/ipfilter/ipsend/linux.h b/contrib/ipfilter/ipsend/linux.h new file mode 100644 index 0000000..e738f3b --- /dev/null +++ b/contrib/ipfilter/ipsend/linux.h @@ -0,0 +1,19 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * This code may be freely distributed as long as it retains this notice + * and is not changed in any way. The author accepts no responsibility + * for the use of this software. I hate legaleese, don't you ? + * + * @(#)linux.h 1.1 8/19/95 + */ + +#include <linux/config.h> +#ifdef MODULE +#include <linux/module.h> +#include <linux/version.h> +#endif /* MODULE */ + +#include "ip_compat.h" diff --git a/contrib/ipfilter/ipsend/lsock.c b/contrib/ipfilter/ipsend/lsock.c new file mode 100644 index 0000000..5cf2bf7 --- /dev/null +++ b/contrib/ipfilter/ipsend/lsock.c @@ -0,0 +1,259 @@ +/* $FreeBSD$ */ + +/* + * lsock.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#if !defined(lint) +static const char sccsid[] = "@(#)lsock.c 1.2 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <pwd.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/dir.h> +#define __KERNEL__ +#if LINUX >= 0200 +# undef UINT_MAX +# undef INT_MAX +# undef ULONG_MAX +# undef LONG_MAX +# include <linux/notifier.h> +#endif +#include <linux/fs.h> +#if LINUX >= 0200 +#include "linux/netdevice.h" +#include "net/sock.h" +#endif +#undef __KERNEL__ +#include <linux/sched.h> +#include <linux/netdevice.h> +#include <nlist.h> +#include <sys/user.h> +#include <sys/socket.h> +#include <math.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <net/if.h> +#if LINUX < 0200 +#include <net/inet/sock.h> +#endif +#include "ipsend.h" + +int nproc; +struct task_struct *proc; + +#ifndef KMEM +# ifdef _PATH_KMEM +# define KMEM _PATH_KMEM +# endif +#endif +#ifndef KMEM +# define KMEM "/dev/kmem" +#endif +#ifndef KERNEL +# define KERNEL "/System.map" +#endif + +int kmemcpy(buf, pos, n) + char *buf; + void *pos; + int n; +{ + static int kfd = -1; + + if (kfd == -1) + kfd = open(KMEM, O_RDONLY); + + if (lseek(kfd, (off_t)pos, SEEK_SET) == -1) + { + perror("lseek"); + return -1; + } + if (read(kfd, buf, n) == -1) + { + perror("read"); + return -1; + } + return n; +} + +struct nlist names[3] = { + { "_task" }, + { "_nr_tasks" }, + { NULL } + }; + +struct task_struct *getproc() +{ + struct task_struct *p, **pp; + void *v; + pid_t pid = getpid(); + int siz, n; + + n = nlist(KERNEL, names); + if (n != 0) + { + fprintf(stderr, "nlist(%#x) == %d\n", names, n); + return NULL; + } + if (KMCPY(&nproc, names[1].n_value, sizeof(nproc)) == -1) + { + fprintf(stderr, "read nproc (%#x)\n", names[1].n_value); + return NULL; + } + siz = nproc * sizeof(struct task_struct *); + if (KMCPY(&v, names[0].n_value, sizeof(v)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) proc\n", + names[0].n_value, &v, sizeof(v)); + return NULL; + } + pp = (struct task_struct **)malloc(siz); + if (KMCPY(pp, v, siz) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) proc\n", + v, pp, siz); + return NULL; + } + proc = (struct task_struct *)malloc(siz); + for (n = 0; n < NR_TASKS; n++) + { + if (KMCPY((proc + n), pp[n], sizeof(*proc)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) proc\n", + pp[n], proc + n, sizeof(*proc)); + return NULL; + } + } + + p = proc; + + for (n = NR_TASKS; n; n--, p++) + if (p->pid == pid) + break; + if (!n) + return NULL; + + return p; +} + + +struct sock *find_tcp(fd, ti) + int fd; + struct tcpiphdr *ti; +{ + struct sock *s; + struct inode *i; + struct files_struct *fs; + struct task_struct *p; + struct file *f, **o; + + if (!(p = getproc())) + return NULL; + + fs = p->files; + o = (struct file **)calloc(1, sizeof(*o) * (fs->count + 1)); + if (KMCPY(o, fs->fd, (fs->count + 1) * sizeof(*o)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) - fd - failed\n", + fs->fd, o, sizeof(*o)); + return NULL; + } + f = (struct file *)calloc(1, sizeof(*f)); + if (KMCPY(f, o[fd], sizeof(*f)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) - o[fd] - failed\n", + o[fd], f, sizeof(*f)); + return NULL; + } + + i = (struct inode *)calloc(1, sizeof(*i)); + if (KMCPY(i, f->f_inode, sizeof(*i)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) - f_inode - failed\n", + f->f_inode, i, sizeof(*i)); + return NULL; + } + return i->u.socket_i.data; +} + +int do_socket(dev, mtu, ti, gwip) + char *dev; + int mtu; + struct tcpiphdr *ti; + struct in_addr gwip; +{ + struct sockaddr_in rsin, lsin; + struct sock *s, sk; + int fd, nfd, len; + + printf("Dest. Port: %d\n", ti->ti_dport); + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + perror("socket"); + return -1; + } + + if (fcntl(fd, F_SETFL, FNDELAY) == -1) + { + perror("fcntl"); + return -1; + } + + bzero((char *)&lsin, sizeof(lsin)); + lsin.sin_family = AF_INET; + bcopy((char *)&ti->ti_src, (char *)&lsin.sin_addr, + sizeof(struct in_addr)); + if (bind(fd, (struct sockaddr *)&lsin, sizeof(lsin)) == -1) + { + perror("bind"); + return -1; + } + len = sizeof(lsin); + (void) getsockname(fd, (struct sockaddr *)&lsin, &len); + ti->ti_sport = lsin.sin_port; + printf("sport %d\n", ntohs(lsin.sin_port)); + nfd = initdevice(dev, 0); + if (nfd == -1) + return -1; + + if (!(s = find_tcp(fd, ti))) + return -1; + + bzero((char *)&rsin, sizeof(rsin)); + rsin.sin_family = AF_INET; + bcopy((char *)&ti->ti_dst, (char *)&rsin.sin_addr, + sizeof(struct in_addr)); + rsin.sin_port = ti->ti_dport; + if (connect(fd, (struct sockaddr *)&rsin, sizeof(rsin)) == -1 && + errno != EINPROGRESS) + { + perror("connect"); + return -1; + } + KMCPY(&sk, s, sizeof(sk)); + ti->ti_win = sk.window; + ti->ti_seq = sk.sent_seq - 1; + ti->ti_ack = sk.rcv_ack_seq; + ti->ti_flags = TH_SYN; + + if (send_tcp(nfd, mtu, (ip_t *)ti, gwip) == -1) + return -1; + (void)write(fd, "Hello World\n", 12); + sleep(2); + close(fd); + return 0; +} diff --git a/contrib/ipfilter/ipsend/resend.c b/contrib/ipfilter/ipsend/resend.c new file mode 100644 index 0000000..45159bf --- /dev/null +++ b/contrib/ipfilter/ipsend/resend.c @@ -0,0 +1,143 @@ +/* $FreeBSD$ */ + +/* + * resend.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#if !defined(lint) +static const char sccsid[] = "@(#)resend.c 1.3 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#ifndef linux +# include <netinet/ip_var.h> +# include <netinet/if_ether.h> +#endif +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "ipsend.h" + +extern int opts; + +void dumppacket __P((ip_t *)); + + +void dumppacket(ip) + ip_t *ip; +{ + tcphdr_t *t; + int i, j; + + t = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); + if (ip->ip_tos) + printf("tos %#x ", ip->ip_tos); + if (ip->ip_off & 0x3fff) + printf("frag @%#x ", (ip->ip_off & 0x1fff) << 3); + printf("len %d id %d ", ip->ip_len, ip->ip_id); + printf("ttl %d p %d src %s", ip->ip_ttl, ip->ip_p, + inet_ntoa(ip->ip_src)); + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + printf(",%d", t->th_sport); + printf(" dst %s", inet_ntoa(ip->ip_dst)); + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + printf(",%d", t->th_dport); + if (ip->ip_p == IPPROTO_TCP) { + printf(" seq %lu:%lu flags ", + (u_long)t->th_seq, (u_long)t->th_ack); + for (j = 0, i = 1; i < 256; i *= 2, j++) + if (t->th_flags & i) + printf("%c", "FSRPAU--"[j]); + } + putchar('\n'); +} + + +int ip_resend(dev, mtu, r, gwip, datain) + char *dev; + int mtu; + struct in_addr gwip; + struct ipread *r; + char *datain; +{ + ether_header_t *eh; + char dhost[6]; + ip_t *ip; + int fd, wfd = initdevice(dev, 5), len, i; + mb_t mb; + + if (wfd == -1) + return -1; + + if (datain) + fd = (*r->r_open)(datain); + else + fd = (*r->r_open)("-"); + + if (fd < 0) + exit(-1); + + ip = (struct ip *)mb.mb_buf; + eh = (ether_header_t *)malloc(sizeof(*eh)); + if(!eh) + { + perror("malloc failed"); + return -2; + } + + bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); + if (gwip.s_addr && (arp((char *)&gwip, dhost) == -1)) + { + perror("arp"); + free(eh); + return -2; + } + + while ((i = (*r->r_readip)(&mb, NULL, NULL)) > 0) + { + if (!(opts & OPT_RAW)) { + len = ntohs(ip->ip_len); + eh = (ether_header_t *)realloc((char *)eh, sizeof(*eh) + len); + eh->ether_type = htons((u_short)ETHERTYPE_IP); + if (!gwip.s_addr) { + if (arp((char *)&gwip, + (char *)A_A eh->ether_dhost) == -1) { + perror("arp"); + continue; + } + } else + bcopy(dhost, (char *)A_A eh->ether_dhost, + sizeof(dhost)); + if (!ip->ip_sum) + ip->ip_sum = chksum((u_short *)ip, + IP_HL(ip) << 2); + bcopy(ip, (char *)(eh + 1), len); + len += sizeof(*eh); + dumppacket(ip); + } else { + eh = (ether_header_t *)mb.mb_buf; + len = i; + } + + if (sendip(wfd, (char *)eh, len) == -1) + { + perror("send_packet"); + break; + } + } + (*r->r_close)(); + free(eh); + return 0; +} diff --git a/contrib/ipfilter/ipsend/sbpf.c b/contrib/ipfilter/ipsend/sbpf.c new file mode 100644 index 0000000..fcb66bc --- /dev/null +++ b/contrib/ipfilter/ipsend/sbpf.c @@ -0,0 +1,153 @@ +/* $FreeBSD$ */ +/* + * (C)opyright 1995-1998 Darren Reed. (from tcplog) + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/mbuf.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#if BSD < 199103 +#include <sys/fcntlcom.h> +#endif +#if (__FreeBSD_version >= 300000) +# include <sys/dirent.h> +#else +# include <sys/dir.h> +#endif +#include <net/bpf.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/udp.h> +#include <netinet/tcp.h> + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#ifdef __NetBSD__ +# include <paths.h> +#endif +#include <ctype.h> +#include <signal.h> +#include <errno.h> + +#include "ipsend.h" + +#if !defined(lint) +static const char sccsid[] = "@(#)sbpf.c 1.3 8/25/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +/* + * the code herein is dervied from libpcap. + */ +static u_char *buf = NULL; +static int bufsize = 0, timeout = 1; + + +int initdevice(device, tout) + char *device; + int tout; +{ + struct bpf_version bv; + struct timeval to; + struct ifreq ifr; +#ifdef _PATH_BPF + char *bpfname = _PATH_BPF; + int fd; + + if ((fd = open(bpfname, O_RDWR)) < 0) + { + fprintf(stderr, "no bpf devices available as /dev/bpfxx\n"); + return -1; + } +#else + char bpfname[16]; + int fd = 0, i; + + for (i = 0; i < 16; i++) + { + (void) sprintf(bpfname, "/dev/bpf%d", i); + if ((fd = open(bpfname, O_RDWR)) >= 0) + break; + } + if (i == 16) + { + fprintf(stderr, "no bpf devices available as /dev/bpfxx\n"); + return -1; + } +#endif + + if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) + { + perror("BIOCVERSION"); + return -1; + } + if (bv.bv_major != BPF_MAJOR_VERSION || + bv.bv_minor < BPF_MINOR_VERSION) + { + fprintf(stderr, "kernel bpf (v%d.%d) filter out of date:\n", + bv.bv_major, bv.bv_minor); + fprintf(stderr, "current version: %d.%d\n", + BPF_MAJOR_VERSION, BPF_MINOR_VERSION); + return -1; + } + + (void) strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(fd, BIOCSETIF, &ifr) == -1) + { + fprintf(stderr, "%s(%d):", ifr.ifr_name, fd); + perror("BIOCSETIF"); + exit(1); + } + /* + * get kernel buffer size + */ + if (ioctl(fd, BIOCGBLEN, &bufsize) == -1) + { + perror("BIOCSBLEN"); + exit(-1); + } + buf = (u_char*)malloc(bufsize); + /* + * set the timeout + */ + timeout = tout; + to.tv_sec = 1; + to.tv_usec = 0; + if (ioctl(fd, BIOCSRTIMEOUT, (caddr_t)&to) == -1) + { + perror("BIOCSRTIMEOUT"); + exit(-1); + } + + (void) ioctl(fd, BIOCFLUSH, 0); + return fd; +} + + +/* + * output an IP packet onto a fd opened for /dev/bpf + */ +int sendip(fd, pkt, len) + int fd, len; + char *pkt; +{ + if (write(fd, pkt, len) == -1) + { + perror("send"); + return -1; + } + + return len; +} diff --git a/contrib/ipfilter/ipsend/sdlpi.c b/contrib/ipfilter/ipsend/sdlpi.c new file mode 100644 index 0000000..1aee2e4 --- /dev/null +++ b/contrib/ipfilter/ipsend/sdlpi.c @@ -0,0 +1,173 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1992-1998 Darren Reed. (from tcplog) + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/stropts.h> + +#ifdef sun +# include <sys/pfmod.h> +# include <sys/bufmod.h> +#endif +#ifdef __osf__ +# include <sys/dlpihdr.h> +#else +# include <sys/dlpi.h> +#endif +#ifdef __hpux +# include <sys/dlpi_ext.h> +#endif + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> + +#include "ipsend.h" + +#if !defined(lint) +static const char sccsid[] = "@(#)sdlpi.c 1.3 10/30/95 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#define CHUNKSIZE 8192 +#define BUFSPACE (4*CHUNKSIZE) + + +/* + * Be careful to only include those defined in the flags option for the + * interface are included in the header size. + */ +int initdevice(device, tout) + char *device; + int tout; +{ + char devname[16], *s, buf[256]; + int i, fd; + + (void) strcpy(devname, "/dev/"); + (void) strncat(devname, device, sizeof(devname) - strlen(devname)); + + s = devname + 5; + while (*s && !ISDIGIT(*s)) + s++; + if (!*s) + { + fprintf(stderr, "bad device name %s\n", devname); + exit(-1); + } + i = atoi(s); + *s = '\0'; + /* + * For writing + */ + if ((fd = open(devname, O_RDWR)) < 0) + { + fprintf(stderr, "O_RDWR(1) "); + perror(devname); + exit(-1); + } + + if (dlattachreq(fd, i) == -1) + { + fprintf(stderr, "dlattachreq: DLPI error\n"); + exit(-1); + } + else if (dlokack(fd, buf) == -1) + { + fprintf(stderr, "dlokack(attach): DLPI error\n"); + exit(-1); + } +#ifdef DL_HP_RAWDLS + if (dlpromisconreq(fd, DL_PROMISC_SAP) < 0) + { + fprintf(stderr, "dlpromisconreq: DL_PROMISC_PHYS error\n"); + exit(-1); + } + else if (dlokack(fd, buf) < 0) + { + fprintf(stderr, "dlokack(promisc): DLPI error\n"); + exit(-1); + } + /* 22 is INSAP as per the HP-UX DLPI Programmer's Guide */ + + dlbindreq(fd, 22, 1, DL_HP_RAWDLS, 0, 0); +#else + dlbindreq(fd, ETHERTYPE_IP, 0, DL_CLDLS, 0, 0); +#endif + dlbindack(fd, buf); + /* + * write full headers + */ +#ifdef DLIOCRAW /* we require RAW DLPI mode, which is a Sun extension */ + if (strioctl(fd, DLIOCRAW, -1, 0, NULL) == -1) + { + fprintf(stderr, "DLIOCRAW error\n"); + exit(-1); + } +#endif + return fd; +} + + +/* + * output an IP packet onto a fd opened for /dev/nit + */ +int sendip(fd, pkt, len) + int fd, len; + char *pkt; +{ + struct strbuf dbuf, *dp = &dbuf, *cp = NULL; + int pri = 0; +#ifdef DL_HP_RAWDLS + struct strbuf cbuf; + dl_hp_rawdata_req_t raw; + + cp = &cbuf; + raw.dl_primitive = DL_HP_RAWDATA_REQ; + cp->len = sizeof(raw); + cp->buf = (char *)&raw; + cp->maxlen = cp->len; + pri = MSG_HIPRI; +#endif + /* + * construct NIT STREAMS messages, first control then data. + */ + dp->buf = pkt; + dp->len = len; + dp->maxlen = dp->len; + + if (putmsg(fd, cp, dp, pri) == -1) + { + perror("putmsg"); + return -1; + } + if (ioctl(fd, I_FLUSH, FLUSHW) == -1) + { + perror("I_FLUSHW"); + return -1; + } + return len; +} + diff --git a/contrib/ipfilter/ipsend/sirix.c b/contrib/ipfilter/ipsend/sirix.c new file mode 100644 index 0000000..3b565b1 --- /dev/null +++ b/contrib/ipfilter/ipsend/sirix.c @@ -0,0 +1,93 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1992-1998 Darren Reed. + * (C)opyright 1997 Marc Boucher. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#include <stdio.h> +#include <sys/types.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <net/raw.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include "ipsend.h" +#include <netinet/udp_var.h> + +#if !defined(lint) && defined(LIBC_SCCS) +static char sirix[] = "@(#)sirix.c 1.0 10/9/97 (C)1997 Marc Boucher"; +#endif + + +int initdevice(char *device, int tout) +{ + int fd; + struct sockaddr_raw sr; + + if ((fd = socket(PF_RAW, SOCK_RAW, RAWPROTO_DRAIN)) < 0) + { + perror("socket(PF_RAW, SOCK_RAW, RAWPROTO_DRAIN)"); + return -1; + } + + memset(&sr, 0, sizeof(sr)); + sr.sr_family = AF_RAW; + sr.sr_port = ETHERTYPE_IP; + strncpy(sr.sr_ifname, device, sizeof(sr.sr_ifname)); + if (bind(fd, &sr, sizeof(sr)) < 0) + { + perror("bind AF_RAW"); + close(fd); + return -1; + } + return fd; +} + + +/* + * output an IP packet + */ +int sendip(int fd, char *pkt, int len) +{ + struct sockaddr_raw sr; + int srlen = sizeof(sr); + struct ifreq ifr; + struct ether_header *eh = (struct ether_header *)pkt; + + if (getsockname(fd, &sr, &srlen) == -1) + { + perror("getsockname"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, sr.sr_ifname, sizeof ifr.ifr_name); + + if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) + { + perror("ioctl SIOCGIFADDR"); + return -1; + } + + memcpy(eh->ether_shost, ifr.ifr_addr.sa_data, sizeof(eh->ether_shost)); + + if (write(fd, pkt, len) == -1) + { + perror("send"); + return -1; + } + + return len; +} diff --git a/contrib/ipfilter/ipsend/slinux.c b/contrib/ipfilter/ipsend/slinux.c new file mode 100644 index 0000000..7405d5e --- /dev/null +++ b/contrib/ipfilter/ipsend/slinux.c @@ -0,0 +1,92 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1992-1998 Darren Reed. (from tcplog) + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <stdio.h> +#include <string.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/dir.h> +#include <linux/netdevice.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include "ipsend.h" + +#if !defined(lint) +static const char sccsid[] = "@(#)slinux.c 1.2 8/25/95"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#define CHUNKSIZE 8192 +#define BUFSPACE (4*CHUNKSIZE) + +/* + * Be careful to only include those defined in the flags option for the + * interface are included in the header size. + */ + +static int timeout; +static char *eth_dev = NULL; + + +int initdevice(dev, spare) + char *dev; + int spare; +{ + int fd; + + eth_dev = strdup(dev); + if ((fd = socket(AF_INET, SOCK_PACKET, htons(ETHERTYPE_IP))) == -1) + { + perror("socket(SOCK_PACKET)"); + exit(-1); + } + + return fd; +} + + +/* + * output an IP packet onto a fd opened for /dev/nit + */ +int sendip(fd, pkt, len) + int fd, len; + char *pkt; +{ + struct sockaddr s; + struct ifreq ifr; + + strncpy(ifr.ifr_name, eth_dev, sizeof(ifr.ifr_name)); + if (ioctl(fd, SIOCGIFHWADDR, &ifr) == -1) + { + perror("SIOCGIFHWADDR"); + return -1; + } + bcopy(ifr.ifr_hwaddr.sa_data, pkt + 6, 6); + s.sa_family = ETHERTYPE_IP; + strncpy(s.sa_data, eth_dev, sizeof(s.sa_data)); + + if (sendto(fd, pkt, len, 0, &s, sizeof(s)) == -1) + { + perror("send"); + return -1; + } + + return len; +} diff --git a/contrib/ipfilter/ipsend/snit.c b/contrib/ipfilter/ipsend/snit.c new file mode 100644 index 0000000..0d75b4e --- /dev/null +++ b/contrib/ipfilter/ipsend/snit.c @@ -0,0 +1,160 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 1992-1998 Darren Reed. (from tcplog) + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <stdio.h> +#include <netdb.h> +#include <ctype.h> +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/timeb.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <net/nit.h> +#include <sys/fcntlcom.h> +#include <sys/dir.h> +#include <net/nit_if.h> +#include <net/nit_pf.h> +#include <net/nit_buf.h> +#include <net/packetfilt.h> +#include <sys/stropts.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> + +#include "ipsend.h" + +#if !defined(lint) +static const char sccsid[] = "@(#)snit.c 1.5 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#define CHUNKSIZE 8192 +#define BUFSPACE (4*CHUNKSIZE) + +/* + * Be careful to only include those defined in the flags option for the + * interface are included in the header size. + */ +#define BUFHDR_SIZE (sizeof(struct nit_bufhdr)) +#define NIT_HDRSIZE (BUFHDR_SIZE) + +static int timeout; + + +int initdevice(device, tout) + char *device; + int tout; +{ + struct strioctl si; + struct timeval to; + struct ifreq ifr; + int fd; + + if ((fd = open("/dev/nit", O_RDWR)) < 0) + { + perror("/dev/nit"); + exit(-1); + } + + /* + * arrange to get messages from the NIT STREAM and use NIT_BUF option + */ + ioctl(fd, I_SRDOPT, (char*)RMSGD); + ioctl(fd, I_PUSH, "nbuf"); + + /* + * set the timeout + */ + timeout = tout; + si.ic_timout = 1; + to.tv_sec = 1; + to.tv_usec = 0; + si.ic_cmd = NIOCSTIME; + si.ic_len = sizeof(to); + si.ic_dp = (char*)&to; + if (ioctl(fd, I_STR, (char*)&si) == -1) + { + perror("ioctl: NIT timeout"); + exit(-1); + } + + /* + * request the interface + */ + strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = ' '; + si.ic_cmd = NIOCBIND; + si.ic_len = sizeof(ifr); + si.ic_dp = (char*)𝔦 + if (ioctl(fd, I_STR, (char*)&si) == -1) + { + perror(ifr.ifr_name); + exit(1); + } + return fd; +} + + +/* + * output an IP packet onto a fd opened for /dev/nit + */ +int sendip(fd, pkt, len) + int fd, len; + char *pkt; +{ + struct sockaddr sk, *sa = &sk; + struct strbuf cbuf, *cp = &cbuf, dbuf, *dp = &dbuf; + + /* + * For ethernet, need at least 802.3 header and IP header. + */ + if (len < (sizeof(sa->sa_data) + sizeof(struct ip))) + return -1; + /* + * to avoid any output processing for IP, say we're not. + */ + sa->sa_family = AF_UNSPEC; + bcopy(pkt, sa->sa_data, sizeof(sa->sa_data)); + pkt += sizeof(sa->sa_data); + len -= sizeof(sa->sa_data); + + /* + * construct NIT STREAMS messages, first control then data. + */ + cp->len = sizeof(*sa); + cp->maxlen = sizeof(*sa); + cp->buf = (char *)sa; + + dp->buf = pkt; + dp->len = len; + dp->maxlen = dp->len; + + if (putmsg(fd, cp, dp, 0) == -1) + { + perror("putmsg"); + return -1; + } + + if (ioctl(fd, I_FLUSH, FLUSHW) == -1) + { + perror("I_FLUSH"); + return -1; + } + return len; +} diff --git a/contrib/ipfilter/ipsend/sock.c b/contrib/ipfilter/ipsend/sock.c new file mode 100644 index 0000000..6d0f3db --- /dev/null +++ b/contrib/ipfilter/ipsend/sock.c @@ -0,0 +1,457 @@ +/* $FreeBSD$ */ +/* + * sock.c (C) 1995-1998 Darren Reed + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +#if !defined(lint) +static const char sccsid[] = "@(#)sock.c 1.2 1/11/96 (C)1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#if defined(__NetBSD__) && defined(__vax__) +/* + * XXX need to declare boolean_t for _KERNEL <sys/files.h> + * which ends up including <sys/device.h> for vax. See PR#32907 + * for further details. + */ +typedef int boolean_t; +#endif +#ifndef ultrix +#include <fcntl.h> +#endif +#if (__FreeBSD_version >= 300000) +# include <sys/dirent.h> +#else +# include <sys/dir.h> +#endif +#if !defined(__osf__) +# ifdef __NetBSD__ +# include <machine/lock.h> +# endif +# ifdef __FreeBSD__ +# define _WANT_FILE +# else +# define _KERNEL +# define KERNEL +# endif +# ifdef ultrix +# undef LOCORE +# include <sys/smp_lock.h> +# endif +# include <sys/file.h> +# ifdef __FreeBSD__ +# undef _WANT_FILE +# else +# undef _KERNEL +# undef KERNEL +# endif +#endif +#include <nlist.h> +#include <sys/user.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/proc.h> +#if !defined(ultrix) && !defined(hpux) && !defined(__osf__) +# include <kvm.h> +#endif +#ifdef sun +#include <sys/systm.h> +#include <sys/session.h> +#endif +#if BSD >= 199103 +#include <sys/sysctl.h> +#include <sys/filedesc.h> +#include <paths.h> +#endif +#include <math.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <net/if.h> +#ifndef __osf__ +# include <net/route.h> +#endif +#include <netinet/ip_var.h> +#include <netinet/in_pcb.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <pwd.h> +#include "ipsend.h" + + +int nproc; +struct proc *proc; + +#ifndef KMEM +# ifdef _PATH_KMEM +# define KMEM _PATH_KMEM +# endif +#endif +#ifndef KERNEL +# ifdef _PATH_UNIX +# define KERNEL _PATH_UNIX +# endif +#endif +#ifndef KMEM +# define KMEM "/dev/kmem" +#endif +#ifndef KERNEL +# define KERNEL "/vmunix" +#endif + + +#if BSD < 199103 +static struct proc *getproc __P((void)); +#else +static struct kinfo_proc *getproc __P((void)); +#endif + + +int kmemcpy(buf, pos, n) + char *buf; + void *pos; + int n; +{ + static int kfd = -1; + off_t offset = (u_long)pos; + + if (kfd == -1) + kfd = open(KMEM, O_RDONLY); + + if (lseek(kfd, offset, SEEK_SET) == -1) + { + perror("lseek"); + return -1; + } + if (read(kfd, buf, n) == -1) + { + perror("read"); + return -1; + } + return n; +} + +struct nlist names[4] = { + { "_proc" }, + { "_nproc" }, +#ifdef ultrix + { "_u" }, +#else + { NULL }, +#endif + { NULL } + }; + +#if BSD < 199103 +static struct proc *getproc() +{ + struct proc *p; + pid_t pid = getpid(); + int siz, n; + + n = nlist(KERNEL, names); + if (n != 0) + { + fprintf(stderr, "nlist(%#x) == %d\n", names, n); + return NULL; + } + if (KMCPY(&nproc, names[1].n_value, sizeof(nproc)) == -1) + { + fprintf(stderr, "read nproc (%#x)\n", names[1].n_value); + return NULL; + } + siz = nproc * sizeof(struct proc); + if (KMCPY(&p, names[0].n_value, sizeof(p)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) proc\n", + names[0].n_value, &p, sizeof(p)); + return NULL; + } + proc = (struct proc *)malloc(siz); + if (KMCPY(proc, p, siz) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) proc\n", + p, proc, siz); + return NULL; + } + + p = proc; + + for (n = nproc; n; n--, p++) + if (p->p_pid == pid) + break; + if (!n) + return NULL; + + return p; +} + + +struct tcpcb *find_tcp(fd, ti) + int fd; + struct tcpiphdr *ti; +{ + struct tcpcb *t; + struct inpcb *i; + struct socket *s; + struct user *up; + struct proc *p; + struct file *f, **o; + + if (!(p = getproc())) + return NULL; + up = (struct user *)malloc(sizeof(*up)); +#ifndef ultrix + if (KMCPY(up, p->p_uarea, sizeof(*up)) == -1) + { + fprintf(stderr, "read(%#x,%#x) failed\n", p, p->p_uarea); + return NULL; + } +#else + if (KMCPY(up, names[2].n_value, sizeof(*up)) == -1) + { + fprintf(stderr, "read(%#x,%#x) failed\n", p, names[2].n_value); + return NULL; + } +#endif + + o = (struct file **)calloc(1, sizeof(*o) * (up->u_lastfile + 1)); + if (KMCPY(o, up->u_ofile, (up->u_lastfile + 1) * sizeof(*o)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) - u_ofile - failed\n", + up->u_ofile, o, sizeof(*o)); + return NULL; + } + f = (struct file *)calloc(1, sizeof(*f)); + if (KMCPY(f, o[fd], sizeof(*f)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) - o[fd] - failed\n", + up->u_ofile[fd], f, sizeof(*f)); + return NULL; + } + + s = (struct socket *)calloc(1, sizeof(*s)); + if (KMCPY(s, f->f_data, sizeof(*s)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) - f_data - failed\n", + o[fd], s, sizeof(*s)); + return NULL; + } + + i = (struct inpcb *)calloc(1, sizeof(*i)); + if (KMCPY(i, s->so_pcb, sizeof(*i)) == -1) + { + fprintf(stderr, "kvm_read(%#x,%#x,%d) - so_pcb - failed\n", + s->so_pcb, i, sizeof(*i)); + return NULL; + } + + t = (struct tcpcb *)calloc(1, sizeof(*t)); + if (KMCPY(t, i->inp_ppcb, sizeof(*t)) == -1) + { + fprintf(stderr, "read(%#x,%#x,%d) - inp_ppcb - failed\n", + i->inp_ppcb, t, sizeof(*t)); + return NULL; + } + return (struct tcpcb *)i->inp_ppcb; +} +#else +static struct kinfo_proc *getproc() +{ + static struct kinfo_proc kp; + pid_t pid = getpid(); + int mib[4]; + size_t n; + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = pid; + + n = sizeof(kp); + if (sysctl(mib, 4, &kp, &n, NULL, 0) == -1) + { + perror("sysctl"); + return NULL; + } + return &kp; +} + + +struct tcpcb *find_tcp(tfd, ti) + int tfd; + struct tcpiphdr *ti; +{ + struct tcpcb *t; + struct inpcb *i; + struct socket *s; + struct filedesc *fd; + struct kinfo_proc *p; + struct file *f, **o; + + if (!(p = getproc())) + return NULL; + + fd = (struct filedesc *)malloc(sizeof(*fd)); + if (fd == NULL) + return NULL; +#if defined( __FreeBSD_version) && __FreeBSD_version >= 500013 + if (KMCPY(fd, p->ki_fd, sizeof(*fd)) == -1) + { + fprintf(stderr, "read(%#lx,%#lx) failed\n", + (u_long)p, (u_long)p->ki_fd); + free(fd); + return NULL; + } +#else + if (KMCPY(fd, p->kp_proc.p_fd, sizeof(*fd)) == -1) + { + fprintf(stderr, "read(%#lx,%#lx) failed\n", + (u_long)p, (u_long)p->kp_proc.p_fd); + free(fd); + return NULL; + } +#endif + + o = NULL; + f = NULL; + s = NULL; + i = NULL; + t = NULL; + + o = (struct file **)calloc(1, sizeof(*o) * (fd->fd_lastfile + 1)); + if (KMCPY(o, fd->fd_ofiles, (fd->fd_lastfile + 1) * sizeof(*o)) == -1) + { + fprintf(stderr, "read(%#lx,%#lx,%lu) - u_ofile - failed\n", + (u_long)fd->fd_ofiles, (u_long)o, (u_long)sizeof(*o)); + goto finderror; + } + f = (struct file *)calloc(1, sizeof(*f)); + if (KMCPY(f, o[tfd], sizeof(*f)) == -1) + { + fprintf(stderr, "read(%#lx,%#lx,%lu) - o[tfd] - failed\n", + (u_long)o[tfd], (u_long)f, (u_long)sizeof(*f)); + goto finderror; + } + + s = (struct socket *)calloc(1, sizeof(*s)); + if (KMCPY(s, f->f_data, sizeof(*s)) == -1) + { + fprintf(stderr, "read(%#lx,%#lx,%lu) - f_data - failed\n", + (u_long)f->f_data, (u_long)s, (u_long)sizeof(*s)); + goto finderror; + } + + i = (struct inpcb *)calloc(1, sizeof(*i)); + if (KMCPY(i, s->so_pcb, sizeof(*i)) == -1) + { + fprintf(stderr, "kvm_read(%#lx,%#lx,%lu) - so_pcb - failed\n", + (u_long)s->so_pcb, (u_long)i, (u_long)sizeof(*i)); + goto finderror; + } + + t = (struct tcpcb *)calloc(1, sizeof(*t)); + if (KMCPY(t, i->inp_ppcb, sizeof(*t)) == -1) + { + fprintf(stderr, "read(%#lx,%#lx,%lu) - inp_ppcb - failed\n", + (u_long)i->inp_ppcb, (u_long)t, (u_long)sizeof(*t)); + goto finderror; + } + return (struct tcpcb *)i->inp_ppcb; + +finderror: + if (o != NULL) + free(o); + if (f != NULL) + free(f); + if (s != NULL) + free(s); + if (i != NULL) + free(i); + if (t != NULL) + free(t); + return NULL; +} +#endif /* BSD < 199301 */ + +int do_socket(dev, mtu, ti, gwip) + char *dev; + int mtu; + struct tcpiphdr *ti; + struct in_addr gwip; +{ + struct sockaddr_in rsin, lsin; + struct tcpcb *t, tcb; + int fd, nfd; + socklen_t len; + + printf("Dest. Port: %d\n", ti->ti_dport); + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + { + perror("socket"); + return -1; + } + + if (fcntl(fd, F_SETFL, FNDELAY) == -1) + { + perror("fcntl"); + return -1; + } + + bzero((char *)&lsin, sizeof(lsin)); + lsin.sin_family = AF_INET; + bcopy((char *)&ti->ti_src, (char *)&lsin.sin_addr, + sizeof(struct in_addr)); + if (bind(fd, (struct sockaddr *)&lsin, sizeof(lsin)) == -1) + { + perror("bind"); + return -1; + } + len = sizeof(lsin); + (void) getsockname(fd, (struct sockaddr *)&lsin, &len); + ti->ti_sport = lsin.sin_port; + printf("sport %d\n", ntohs(lsin.sin_port)); + + nfd = initdevice(dev, 1); + if (nfd == -1) + return -1; + + if (!(t = find_tcp(fd, ti))) + return -1; + + bzero((char *)&rsin, sizeof(rsin)); + rsin.sin_family = AF_INET; + bcopy((char *)&ti->ti_dst, (char *)&rsin.sin_addr, + sizeof(struct in_addr)); + rsin.sin_port = ti->ti_dport; + if (connect(fd, (struct sockaddr *)&rsin, sizeof(rsin)) == -1 && + errno != EINPROGRESS) + { + perror("connect"); + return -1; + } + KMCPY(&tcb, t, sizeof(tcb)); + ti->ti_win = tcb.rcv_adv; + ti->ti_seq = tcb.snd_nxt - 1; + ti->ti_ack = tcb.rcv_nxt; + + if (send_tcp(nfd, mtu, (ip_t *)ti, gwip) == -1) + return -1; + (void)write(fd, "Hello World\n", 12); + sleep(2); + close(fd); + return 0; +} diff --git a/contrib/ipfilter/ipsend/sockraw.c b/contrib/ipfilter/ipsend/sockraw.c new file mode 100644 index 0000000..c923227 --- /dev/null +++ b/contrib/ipfilter/ipsend/sockraw.c @@ -0,0 +1,89 @@ +/* $FreeBSD$ */ + +/* + * (C)opyright 2000 Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * WARNING: Attempting to use this .c file on HP-UX 11.00 will cause the + * system to crash. + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netinet/ip_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <netinet/tcp.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include "ipsend.h" + +#if !defined(lint) && defined(LIBC_SCCS) +static char sirix[] = "@(#)sirix.c 1.0 10/9/97 (C)1997 Marc Boucher"; +#endif + + +int initdevice(char *device, int tout) +{ + struct sockaddr s; + struct ifreq ifr; + int fd; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name); + + if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + { + perror("socket(AF_INET, SOCK_RAW, IPPROTO_RAW)"); + return -1; + } + + if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) + { + perror("ioctl SIOCGIFADDR"); + return -1; + } + + bzero((char *)&s, sizeof(s)); + s.sa_family = AF_INET; + bcopy(&ifr.ifr_addr, s.sa_data, 4); + if (bind(fd, &s, sizeof(s)) == -1) + perror("bind"); + return fd; +} + + +/* + * output an IP packet + */ +int sendip(int fd, char *pkt, int len) +{ + struct ether_header *eh; + struct sockaddr_in sin; + + eh = (struct ether_header *)pkt; + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + pkt += 14; + len -= 14; + bcopy(pkt + 12, (char *)&sin.sin_addr, 4); + + if (sendto(fd, pkt, len, 0, &sin, sizeof(sin)) == -1) + { + perror("send"); + return -1; + } + + return len; +} diff --git a/contrib/ipfilter/ipt.h b/contrib/ipfilter/ipt.h new file mode 100644 index 0000000..16d88df --- /dev/null +++ b/contrib/ipfilter/ipt.h @@ -0,0 +1,40 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#ifndef __IPT_H__ +#define __IPT_H__ + +#ifndef __P +# define P_DEF +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +#include <fcntl.h> + + +struct ipread { + int (*r_open) __P((char *)); + int (*r_close) __P((void)); + int (*r_readip) __P((mb_t *, char **, int *)); + int r_flags; +}; + +#define R_DO_CKSUM 0x01 + +#ifdef P_DEF +# undef __P +# undef P_DEF +#endif + +#endif /* __IPT_H__ */ diff --git a/contrib/ipfilter/kmem.h b/contrib/ipfilter/kmem.h new file mode 100644 index 0000000..ce6ad56 --- /dev/null +++ b/contrib/ipfilter/kmem.h @@ -0,0 +1,34 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * $Id$ + */ + +#ifndef __KMEM_H__ +#define __KMEM_H__ + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +extern int openkmem __P((char *, char *)); +extern int kmemcpy __P((char *, long, int)); +extern int kstrncpy __P((char *, long, int)); + +#if defined(__NetBSD__) || defined(__OpenBSD) +# include <paths.h> +#endif + +#ifdef _PATH_KMEM +# define KMEM _PATH_KMEM +#else +# define KMEM "/dev/kmem" +#endif + +#endif /* __KMEM_H__ */ diff --git a/contrib/ipfilter/l4check/Makefile b/contrib/ipfilter/l4check/Makefile new file mode 100644 index 0000000..e7366b6 --- /dev/null +++ b/contrib/ipfilter/l4check/Makefile @@ -0,0 +1,10 @@ +# For Solaris +#LIBS=-lsocket -lnsl + +all: l4check + +l4check: l4check.c + $(CC) -g -I.. $(CFLAGS) $(LIBS) l4check.c -o $@ + +clean: + /bin/rm -f l4check diff --git a/contrib/ipfilter/l4check/http.check b/contrib/ipfilter/l4check/http.check new file mode 100644 index 0000000..56d93d9 --- /dev/null +++ b/contrib/ipfilter/l4check/http.check @@ -0,0 +1,2 @@ +GET / + diff --git a/contrib/ipfilter/l4check/http.ok b/contrib/ipfilter/l4check/http.ok new file mode 100644 index 0000000..2b5d2c1 --- /dev/null +++ b/contrib/ipfilter/l4check/http.ok @@ -0,0 +1 @@ +<HTML>
\ No newline at end of file diff --git a/contrib/ipfilter/l4check/l4check.c b/contrib/ipfilter/l4check/l4check.c new file mode 100644 index 0000000..014446d --- /dev/null +++ b/contrib/ipfilter/l4check/l4check.c @@ -0,0 +1,807 @@ +/* $FreeBSD$ */ + +/* + * (C)Copyright (C) 2012 by Darren Reed. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/ioctl.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> + +#include <net/if.h> + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> + +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_nat.h" + +#include "ipf.h" + +extern char *optarg; + + +typedef struct l4cfg { + struct l4cfg *l4_next; + struct ipnat l4_nat; /* NAT rule */ + struct sockaddr_in l4_sin; /* remote socket to connect */ + time_t l4_last; /* when we last connected */ + int l4_alive; /* 1 = remote alive */ + int l4_fd; + int l4_rw; /* 0 = reading, 1 = writing */ + char *l4_rbuf; /* read buffer */ + int l4_rsize; /* size of buffer */ + int l4_rlen; /* how much used */ + char *l4_wptr; /* next byte to write */ + int l4_wlen; /* length yet to be written */ +} l4cfg_t; + + +l4cfg_t *l4list = NULL; +char *response = NULL; +char *probe = NULL; +l4cfg_t template; +int frequency = 20; +int ctimeout = 1; +int rtimeout = 1; +size_t plen = 0; +size_t rlen = 0; +int natfd = -1; +int opts = 0; + +#if defined(sun) && !defined(__svr4__) && !defined(__SVR4) +# define strerror(x) sys_errlist[x] +#endif + + +char *copystr(dst, src) + char *dst, *src; +{ + register char *s, *t, c; + register int esc = 0; + + for (s = src, t = dst; s && t && (c = *s++); ) + if (esc) { + esc = 0; + switch (c) + { + case 'n' : + *t++ = '\n'; + break; + case 'r' : + *t++ = '\r'; + break; + case 't' : + *t++ = '\t'; + break; + } + } else if (c != '\\') + *t++ = c; + else + esc = 1; + *t = '\0'; + return dst; +} + +void addnat(l4) + l4cfg_t *l4; +{ + ipnat_t *ipn = &l4->l4_nat; + + printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]), + ipn->in_outmsk, ntohs(ipn->in_pmin)); + printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext)); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(natfd, SIOCADNAT, &ipn) == -1) + perror("ioctl(SIOCADNAT)"); + } +} + + +void delnat(l4) + l4cfg_t *l4; +{ + ipnat_t *ipn = &l4->l4_nat; + + printf("Remove NAT rule for %s/%#x,%u -> ", + inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin); + printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(natfd, SIOCRMNAT, &ipn) == -1) + perror("ioctl(SIOCRMNAT)"); + } +} + + +void connectl4(l4) + l4cfg_t *l4; +{ + l4->l4_rw = 1; + l4->l4_rlen = 0; + l4->l4_wlen = plen; + if (!l4->l4_wlen) { + l4->l4_alive = 1; + addnat(l4); + } else + l4->l4_wptr = probe; +} + + +void closel4(l4, dead) + l4cfg_t *l4; + int dead; +{ + close(l4->l4_fd); + l4->l4_fd = -1; + l4->l4_rw = -1; + if (dead && l4->l4_alive) { + l4->l4_alive = 0; + delnat(l4); + } +} + + +void connectfd(l4) + l4cfg_t *l4; +{ + if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin, + sizeof(l4->l4_sin)) == -1) { + if (errno == EISCONN) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Connected fd %d\n", + l4->l4_fd); + connectl4(l4); + return; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Connect failed fd %d: %s\n", + l4->l4_fd, strerror(errno)); + closel4(l4, 1); + return; + } + l4->l4_rw = 1; +} + + +void writefd(l4) + l4cfg_t *l4; +{ + char buf[80], *ptr; + int n, i, fd; + + fd = l4->l4_fd; + + if (l4->l4_rw == -2) { + connectfd(l4); + return; + } + + n = l4->l4_wlen; + + i = send(fd, l4->l4_wptr, n, 0); + if (i == 0 || i == -1) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Send on fd %d failed: %s\n", + fd, strerror(errno)); + closel4(l4, 1); + } else { + l4->l4_wptr += i; + l4->l4_wlen -= i; + if (l4->l4_wlen == 0) + l4->l4_rw = 0; + if (opts & OPT_VERBOSE) + fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd); + } +} + + +void readfd(l4) + l4cfg_t *l4; +{ + char buf[80], *ptr; + int n, i, fd; + + fd = l4->l4_fd; + + if (l4->l4_rw == -2) { + connectfd(l4); + return; + } + + if (l4->l4_rsize) { + n = l4->l4_rsize - l4->l4_rlen; + ptr = l4->l4_rbuf + l4->l4_rlen; + } else { + n = sizeof(buf) - 1; + ptr = buf; + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Read %d bytes on fd %d to %p\n", + n, fd, ptr); + i = recv(fd, ptr, n, 0); + if (i == 0 || i == -1) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Read error on fd %d: %s\n", + fd, (i == 0) ? "EOF" : strerror(errno)); + closel4(l4, 1); + } else { + if (ptr == buf) + ptr[i] = '\0'; + if (opts & OPT_VERBOSE) + fprintf(stderr, "%d: Read %d bytes [%*.*s]\n", + fd, i, i, i, ptr); + if (ptr != buf) { + l4->l4_rlen += i; + if (l4->l4_rlen >= l4->l4_rsize) { + if (!strncmp(response, l4->l4_rbuf, + l4->l4_rsize)) { + printf("%d: Good response\n", + fd); + if (!l4->l4_alive) { + l4->l4_alive = 1; + addnat(l4); + } + closel4(l4, 0); + } else { + if (opts & OPT_VERBOSE) + printf("%d: Bad response\n", + fd); + closel4(l4, 1); + } + } + } else if (!l4->l4_alive) { + l4->l4_alive = 1; + addnat(l4); + closel4(l4, 0); + } + } +} + + +int runconfig() +{ + int fd, opt, res, mfd, i; + struct timeval tv; + time_t now, now1; + fd_set rfd, wfd; + l4cfg_t *l4; + + mfd = 0; + opt = 1; + now = time(NULL); + + /* + * First, initiate connections that are closed, as required. + */ + for (l4 = l4list; l4; l4 = l4->l4_next) { + if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) { + l4->l4_last = now; + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + continue; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, + sizeof(opt)); +#ifdef O_NONBLOCK + if ((res = fcntl(fd, F_GETFL, 0)) != -1) + fcntl(fd, F_SETFL, res | O_NONBLOCK); +#endif + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Connecting to %s,%d (fd %d)...", + inet_ntoa(l4->l4_sin.sin_addr), + ntohs(l4->l4_sin.sin_port), fd); + if (connect(fd, (struct sockaddr *)&l4->l4_sin, + sizeof(l4->l4_sin)) == -1) { + if (errno != EINPROGRESS) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "failed\n"); + perror("connect"); + close(fd); + fd = -1; + } else { + if (opts & OPT_VERBOSE) + fprintf(stderr, "waiting\n"); + l4->l4_rw = -2; + } + } else { + if (opts & OPT_VERBOSE) + fprintf(stderr, "connected\n"); + connectl4(l4); + } + l4->l4_fd = fd; + } + } + + /* + * Now look for fd's which we're expecting to read/write from. + */ + FD_ZERO(&rfd); + FD_ZERO(&wfd); + tv.tv_sec = MIN(rtimeout, ctimeout); + tv.tv_usec = 0; + + for (l4 = l4list; l4; l4 = l4->l4_next) + if (l4->l4_rw == 0) { + if (now - l4->l4_last > rtimeout) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "%d: Read timeout\n", + l4->l4_fd); + closel4(l4, 1); + continue; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Wait for read on fd %d\n", + l4->l4_fd); + FD_SET(l4->l4_fd, &rfd); + if (l4->l4_fd > mfd) + mfd = l4->l4_fd; + } else if ((l4->l4_rw == 1 && l4->l4_wlen) || + l4->l4_rw == -2) { + if ((l4->l4_rw == -2) && + (now - l4->l4_last > ctimeout)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, + "%d: connect timeout\n", + l4->l4_fd); + closel4(l4); + continue; + } + if (opts & OPT_VERBOSE) + fprintf(stderr, "Wait for write on fd %d\n", + l4->l4_fd); + FD_SET(l4->l4_fd, &wfd); + if (l4->l4_fd > mfd) + mfd = l4->l4_fd; + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1, + tv.tv_sec); + i = select(mfd + 1, &rfd, &wfd, NULL, &tv); + if (i == -1) { + perror("select"); + return -1; + } + + now1 = time(NULL); + + for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) { + if (l4->l4_fd < 0) + continue; + if (FD_ISSET(l4->l4_fd, &rfd)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Ready to read on fd %d\n", + l4->l4_fd); + readfd(l4); + i--; + } + + if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) { + if (opts & OPT_VERBOSE) + fprintf(stderr, "Ready to write on fd %d\n", + l4->l4_fd); + writefd(l4); + i--; + } + } + return 0; +} + + +int gethostport(str, lnum, ipp, portp) + char *str; + int lnum; + u_32_t *ipp; + u_short *portp; +{ + struct servent *sp; + struct hostent *hp; + char *host, *port; + struct in_addr ip; + + host = str; + port = strchr(host, ','); + if (port) + *port++ = '\0'; + +#ifdef HAVE_INET_ATON + if (ISDIGIT(*host) && inet_aton(host, &ip)) + *ipp = ip.s_addr; +#else + if (ISDIGIT(*host)) + *ipp = inet_addr(host); +#endif + else { + if (!(hp = gethostbyname(host))) { + fprintf(stderr, "%d: can't resolve hostname: %s\n", + lnum, host); + return 0; + } + *ipp = *(u_32_t *)hp->h_addr; + } + + if (port) { + if (ISDIGIT(*port)) + *portp = htons(atoi(port)); + else { + sp = getservbyname(port, "tcp"); + if (sp) + *portp = sp->s_port; + else { + fprintf(stderr, "%d: unknown service %s\n", + lnum, port); + return 0; + } + } + } else + *portp = 0; + return 1; +} + + +char *mapfile(file, sizep) + char *file; + size_t *sizep; +{ + struct stat sb; + caddr_t addr; + int fd; + + fd = open(file, O_RDONLY); + if (fd == -1) { + perror("open(mapfile)"); + return NULL; + } + + if (fstat(fd, &sb) == -1) { + perror("fstat(mapfile)"); + close(fd); + return NULL; + } + + addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (addr == (caddr_t)-1) { + perror("mmap(mapfile)"); + close(fd); + return NULL; + } + close(fd); + *sizep = sb.st_size; + return (char *)addr; +} + + +int readconfig(filename) + char *filename; +{ + char c, buf[512], *s, *t, *errtxt = NULL, *line; + int num, err = 0; + ipnat_t *ipn; + l4cfg_t *l4; + FILE *fp; + + fp = fopen(filename, "r"); + if (!fp) { + perror("open(configfile)"); + return -1; + } + + bzero((char *)&template, sizeof(template)); + template.l4_fd = -1; + template.l4_rw = -1; + template.l4_sin.sin_family = AF_INET; + ipn = &template.l4_nat; + ipn->in_flags = IPN_TCP|IPN_ROUNDR; + ipn->in_redir = NAT_REDIRECT; + + for (num = 1; fgets(buf, sizeof(buf), fp); num++) { + s = strchr(buf, '\n'); + if (!s) { + fprintf(stderr, "%d: line too long\n", num); + fclose(fp); + return -1; + } + + *s = '\0'; + + /* + * lines which are comments + */ + s = strchr(buf, '#'); + if (s) + *s = '\0'; + + /* + * Skip leading whitespace + */ + for (line = buf; (c = *line) && ISSPACE(c); line++) + ; + if (!*line) + continue; + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Parsing: [%s]\n", line); + t = strtok(line, " \t"); + if (!t) + continue; + if (!strcasecmp(t, "interface")) { + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, "\t"); + if (!s || !t) { + errtxt = line; + err = -1; + break; + } + + if (!strchr(t, ',')) { + fprintf(stderr, + "%d: local address,port missing\n", + num); + err = -1; + break; + } + + strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname)); + if (!gethostport(t, num, &ipn->in_outip, + &ipn->in_pmin)) { + errtxt = line; + err = -1; + break; + } + ipn->in_outmsk = 0xffffffff; + ipn->in_pmax = ipn->in_pmin; + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Interface %s %s/%#x port %u\n", + ipn->in_ifname, + inet_ntoa(ipn->in_out[0]), + ipn->in_outmsk, ipn->in_pmin); + } else if (!strcasecmp(t, "remote")) { + if (!*ipn->in_ifname) { + fprintf(stderr, + "%d: ifname not set prior to remote\n", + num); + err = -1; + break; + } + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, ""); + if (!s || !t || strcasecmp(s, "server")) { + errtxt = line; + err = -1; + break; + } + + ipn->in_pnext = 0; + if (!gethostport(t, num, &ipn->in_inip, + &ipn->in_pnext)) { + errtxt = line; + err = -1; + break; + } + ipn->in_inmsk = 0xffffffff; + if (ipn->in_pnext == 0) + ipn->in_pnext = ipn->in_pmin; + + l4 = (l4cfg_t *)malloc(sizeof(*l4)); + if (!l4) { + fprintf(stderr, "%d: out of memory (%d)\n", + num, sizeof(*l4)); + err = -1; + break; + } + bcopy((char *)&template, (char *)l4, sizeof(*l4)); + l4->l4_sin.sin_addr = ipn->in_in[0]; + l4->l4_sin.sin_port = ipn->in_pnext; + l4->l4_next = l4list; + l4list = l4; + } else if (!strcasecmp(t, "connect")) { + s = strtok(NULL, " \t"); + if (s) + t = strtok(NULL, "\t"); + if (!s || !t) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "timeout")) { + ctimeout = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, "connect timeout %d\n", + ctimeout); + } else if (!strcasecmp(s, "frequency")) { + frequency = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "connect frequency %d\n", + frequency); + } else { + errtxt = line; + err = -1; + break; + } + } else if (!strcasecmp(t, "probe")) { + s = strtok(NULL, " \t"); + if (!s) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "string")) { + if (probe) { + fprintf(stderr, + "%d: probe already set\n", + num); + err = -1; + break; + } + t = strtok(NULL, ""); + if (!t) { + fprintf(stderr, + "%d: No probe string\n", num); + err = -1; + break; + } + + probe = malloc(strlen(t)); + copystr(probe, t); + plen = strlen(probe); + if (opts & OPT_VERBOSE) + fprintf(stderr, "Probe string [%s]\n", + probe); + } else if (!strcasecmp(s, "file")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + if (probe) { + fprintf(stderr, + "%d: probe already set\n", + num); + err = -1; + break; + } + probe = mapfile(t, &plen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Probe file %s len %u@%p\n", + t, plen, probe); + } + } else if (!strcasecmp(t, "response")) { + s = strtok(NULL, " \t"); + if (!s) { + errtxt = line; + err = -1; + break; + } else if (!strcasecmp(s, "timeout")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + rtimeout = atoi(t); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "response timeout %d\n", + rtimeout); + } else if (!strcasecmp(s, "string")) { + if (response) { + fprintf(stderr, + "%d: response already set\n", + num); + err = -1; + break; + } + response = strdup(strtok(NULL, "")); + rlen = strlen(response); + template.l4_rsize = rlen; + template.l4_rbuf = malloc(rlen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Response string [%s]\n", + response); + } else if (!strcasecmp(s, "file")) { + t = strtok(NULL, " \t"); + if (!t) { + errtxt = line; + err = -1; + break; + } + if (response) { + fprintf(stderr, + "%d: response already set\n", + num); + err = -1; + break; + } + response = mapfile(t, &rlen); + template.l4_rsize = rlen; + template.l4_rbuf = malloc(rlen); + if (opts & OPT_VERBOSE) + fprintf(stderr, + "Response file %s len %u@%p\n", + t, rlen, response); + } + } else { + errtxt = line; + err = -1; + break; + } + } + + if (errtxt) + fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt); + fclose(fp); + return err; +} + + +void usage(prog) + char *prog; +{ + fprintf(stderr, "Usage: %s -f <configfile>\n", prog); + exit(1); +} + + +int main(argc, argv) + int argc; + char *argv[]; +{ + char *config = NULL; + int c; + + while ((c = getopt(argc, argv, "f:nv")) != -1) + switch (c) + { + case 'f' : + config = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (config == NULL) + usage(argv[0]); + + if (readconfig(config)) + exit(1); + + if (!l4list) { + fprintf(stderr, "No remote servers, exiting."); + exit(1); + } + + if (!(opts & OPT_DONOTHING)) { + natfd = open(IPL_NAT, O_RDWR); + if (natfd == -1) { + perror("open(IPL_NAT)"); + exit(1); + } + } + + if (opts & OPT_VERBOSE) + fprintf(stderr, "Starting...\n"); + while (runconfig() == 0) + ; +} diff --git a/contrib/ipfilter/l4check/l4check.conf b/contrib/ipfilter/l4check/l4check.conf new file mode 100644 index 0000000..d000e9f --- /dev/null +++ b/contrib/ipfilter/l4check/l4check.conf @@ -0,0 +1,31 @@ +# +# NOTE: ORDER IS IMPORTANT IN THIS FILE +# +# Interface to do the redirections on and the IP address which will be +# targeted. +# +interface nf0 192.168.1.1,2100 +# +connect timeout 1 +connect frequency 20 +# +# If no probe string is specified, a successful connection implies the +# server is still alive. +# +probe string GET /\n\n +#probe file http.check +# +response timeout 4 +response string <HTML> +#response file http.ok +# +# Here we have multiple servers, listed because that's what happens to be +# used for testing of connect timeoutes, read timeouts, success and things +# which don't connect. +# +remote server 192.168.1.2,23 +remote server 192.168.1.2,2101 +remote server 192.168.1.3,25 +remote server 192.168.1.254,8000 +remote server 192.168.1.1,9 +# diff --git a/contrib/ipfilter/lib/Makefile b/contrib/ipfilter/lib/Makefile new file mode 100644 index 0000000..fdda78e --- /dev/null +++ b/contrib/ipfilter/lib/Makefile @@ -0,0 +1,443 @@ +# +# Copyright (C) 2012 by Darren Reed. +# +# See the IPFILTER.LICENCE file for details on licencing. +# +# $Id$ +# +INCDEP=$(TOP)/ip_compat.h $(TOP)/ip_fil.h $(TOP)/ipf.h + +LIBOBJS=$(DEST)/addicmp.o \ + $(DEST)/addipopt.o \ + $(DEST)/alist_free.o \ + $(DEST)/alist_new.o \ + $(DEST)/allocmbt.o \ + $(DEST)/assigndefined.o \ + $(DEST)/bcopywrap.o \ + $(DEST)/binprint.o \ + $(DEST)/buildopts.o \ + $(DEST)/checkrev.o \ + $(DEST)/connecttcp.o \ + $(DEST)/count6bits.o \ + $(DEST)/count4bits.o \ + $(DEST)/debug.o \ + $(DEST)/dupmbt.o \ + $(DEST)/familyname.o \ + $(DEST)/facpri.o \ + $(DEST)/fill6bits.o \ + $(DEST)/findword.o \ + $(DEST)/flags.o \ + $(DEST)/freembt.o \ + $(DEST)/ftov.o \ + $(DEST)/genmask.o \ + $(DEST)/gethost.o \ + $(DEST)/geticmptype.o \ + $(DEST)/getifname.o \ + $(DEST)/getnattype.o \ + $(DEST)/getport.o \ + $(DEST)/getportproto.o \ + $(DEST)/getproto.o \ + $(DEST)/getsumd.o \ + $(DEST)/hostname.o \ + $(DEST)/icmpcode.o \ + $(DEST)/icmptypename.o \ + $(DEST)/icmptypes.o \ + $(DEST)/initparse.o \ + $(DEST)/interror.o \ + $(DEST)/ionames.o \ + $(DEST)/ipf_dotuning.o \ + $(DEST)/ipf_perror.o \ + $(DEST)/ipft_hx.o \ + $(DEST)/ipft_pc.o \ + $(DEST)/ipft_tx.o \ + $(DEST)/ipoptsec.o \ + $(DEST)/kmem.o \ + $(DEST)/kmemcpywrap.o \ + $(DEST)/kvatoname.o \ + $(DEST)/load_file.o \ + $(DEST)/load_dstlist.o \ + $(DEST)/load_dstlistnode.o \ + $(DEST)/load_hash.o \ + $(DEST)/load_hashnode.o \ + $(DEST)/load_http.o \ + $(DEST)/load_pool.o \ + $(DEST)/load_poolnode.o \ + $(DEST)/load_url.o \ + $(DEST)/msgdsize.o \ + $(DEST)/mutex_emul.o \ + $(DEST)/nametokva.o \ + $(DEST)/nat_setgroupmap.o \ + $(DEST)/ntomask.o \ + $(DEST)/optname.o \ + $(DEST)/optprint.o \ + $(DEST)/optprintv6.o \ + $(DEST)/optvalue.o \ + $(DEST)/parsefields.o \ + $(DEST)/parseipfexpr.o \ + $(DEST)/parsewhoisline.o \ + $(DEST)/poolio.o \ + $(DEST)/portname.o \ + $(DEST)/print_toif.o \ + $(DEST)/printactiveaddr.o \ + $(DEST)/printactivenat.o \ + $(DEST)/printaddr.o \ + $(DEST)/printaps.o \ + $(DEST)/printbuf.o \ + $(DEST)/printdstlist.o \ + $(DEST)/printdstlistdata.o \ + $(DEST)/printdstlistnode.o \ + $(DEST)/printdstlistpolicy.o \ + $(DEST)/printdstl_live.o \ + $(DEST)/printfieldhdr.o \ + $(DEST)/printfr.o \ + $(DEST)/printfraginfo.o \ + $(DEST)/printhash.o \ + $(DEST)/printhashdata.o \ + $(DEST)/printhashnode.o \ + $(DEST)/printhash_live.o \ + $(DEST)/printhost.o \ + $(DEST)/printhostmap.o \ + $(DEST)/printhostmask.o \ + $(DEST)/printifname.o \ + $(DEST)/printip.o \ + $(DEST)/printipfexpr.o \ + $(DEST)/printlog.o \ + $(DEST)/printlookup.o \ + $(DEST)/printmask.o \ + $(DEST)/printnat.o \ + $(DEST)/printnataddr.o \ + $(DEST)/printnatfield.o \ + $(DEST)/printnatside.o \ + $(DEST)/printpool.o \ + $(DEST)/printpooldata.o \ + $(DEST)/printpoolfield.o \ + $(DEST)/printpoolnode.o \ + $(DEST)/printpool_live.o \ + $(DEST)/printproto.o \ + $(DEST)/printportcmp.o \ + $(DEST)/printpacket.o \ + $(DEST)/printpacket6.o \ + $(DEST)/printsbuf.o \ + $(DEST)/printstate.o \ + $(DEST)/printstatefields.o \ + $(DEST)/printtcpflags.o \ + $(DEST)/printtqtable.o \ + $(DEST)/printtunable.o \ + $(DEST)/printunit.o \ + $(DEST)/remove_hash.o \ + $(DEST)/remove_hashnode.o \ + $(DEST)/remove_pool.o \ + $(DEST)/remove_poolnode.o \ + $(DEST)/resetlexer.o \ + $(DEST)/rwlock_emul.o \ + $(DEST)/save_execute.o \ + $(DEST)/save_file.o \ + $(DEST)/save_nothing.o \ + $(DEST)/save_syslog.o \ + $(DEST)/save_v1trap.o \ + $(DEST)/save_v2trap.o \ + $(DEST)/tcpflags.o \ + $(DEST)/var.o \ + $(DEST)/verbose.o \ + $(DEST)/vtof.o \ + $(DEST)/v6ionames.o \ + $(DEST)/v6optvalue.o + +$(DEST)/libipf.a: $(LIBOBJS) + /bin/rm -f $@ + ar $(AROPTS) $@ $(LIBOBJS) + $(RANLIB) $@ + +$(DEST)/addicmp.o: $(LIBSRC)/addicmp.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/addicmp.c -o $@ +$(DEST)/addipopt.o: $(LIBSRC)/addipopt.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/addipopt.c -o $@ +$(DEST)/alist_free.o: $(LIBSRC)/alist_free.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/alist_free.c -o $@ +$(DEST)/alist_new.o: $(LIBSRC)/alist_new.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/alist_new.c -o $@ +$(DEST)/allocmbt.o: $(LIBSRC)/allocmbt.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/allocmbt.c -o $@ +$(DEST)/assigndefined.o: $(LIBSRC)/assigndefined.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/assigndefined.c -o $@ +$(DEST)/bcopywrap.o: $(LIBSRC)/bcopywrap.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/bcopywrap.c -o $@ +$(DEST)/binprint.o: $(LIBSRC)/binprint.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/binprint.c -o $@ +$(DEST)/buildopts.o: $(LIBSRC)/buildopts.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/buildopts.c -o $@ +$(DEST)/connecttcp.o: $(LIBSRC)/connecttcp.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/connecttcp.c -o $@ +$(DEST)/count6bits.o: $(LIBSRC)/count6bits.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/count6bits.c -o $@ +$(DEST)/checkrev.o: $(LIBSRC)/checkrev.c $(INCDEP) $(TOP)/ipl.h + $(CC) $(CCARGS) -c $(LIBSRC)/checkrev.c -o $@ +$(DEST)/count4bits.o: $(LIBSRC)/count4bits.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/count4bits.c -o $@ +$(DEST)/debug.o: $(LIBSRC)/debug.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/debug.c -o $@ +$(DEST)/dupmbt.o: $(LIBSRC)/dupmbt.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/dupmbt.c -o $@ +$(DEST)/facpri.o: $(LIBSRC)/facpri.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/facpri.c -o $@ +$(DEST)/familyname.o: $(LIBSRC)/familyname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/familyname.c -o $@ +$(DEST)/fill6bits.o: $(LIBSRC)/fill6bits.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/fill6bits.c -o $@ +$(DEST)/findword.o: $(LIBSRC)/findword.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/findword.c -o $@ +$(DEST)/flags.o: $(LIBSRC)/flags.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/flags.c -o $@ +$(DEST)/freembt.o: $(LIBSRC)/freembt.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/freembt.c -o $@ +$(DEST)/ftov.o: $(LIBSRC)/ftov.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ftov.c -o $@ +$(DEST)/genmask.o: $(LIBSRC)/genmask.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/genmask.c -o $@ +$(DEST)/gethost.o: $(LIBSRC)/gethost.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/gethost.c -o $@ +$(DEST)/geticmptype.o: $(LIBSRC)/geticmptype.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/geticmptype.c -o $@ +$(DEST)/getifname.o: $(LIBSRC)/getifname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getifname.c -o $@ +$(DEST)/getnattype.o: $(LIBSRC)/getnattype.c $(INCDEP) $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/getnattype.c -o $@ +$(DEST)/getport.o: $(LIBSRC)/getport.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getport.c -o $@ +$(DEST)/getportproto.o: $(LIBSRC)/getportproto.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getportproto.c -o $@ +$(DEST)/getproto.o: $(LIBSRC)/getproto.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getproto.c -o $@ +$(DEST)/getsumd.o: $(LIBSRC)/getsumd.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/getsumd.c -o $@ +$(DEST)/hostname.o: $(LIBSRC)/hostname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/hostname.c -o $@ +$(DEST)/icmpcode.o: $(LIBSRC)/icmpcode.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/icmpcode.c -o $@ +$(DEST)/icmptypename.o: $(LIBSRC)/icmptypename.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/icmptypename.c -o $@ +$(DEST)/icmptypes.o: $(LIBSRC)/icmptypes.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/icmptypes.c -o $@ +$(DEST)/interror.o: $(LIBSRC)/interror.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/interror.c -o $@ +$(DEST)/ipoptsec.o: $(LIBSRC)/ipoptsec.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipoptsec.c -o $@ +$(DEST)/initparse.o: $(LIBSRC)/initparse.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/initparse.c -o $@ +$(DEST)/ionames.o: $(LIBSRC)/ionames.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ionames.c -o $@ +$(DEST)/ipf_dotuning.o: $(LIBSRC)/ipf_dotuning.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipf_dotuning.c -o $@ +$(DEST)/ipf_perror.o: $(LIBSRC)/ipf_perror.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipf_perror.c -o $@ +$(DEST)/ipft_hx.o: $(LIBSRC)/ipft_hx.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_hx.c -o $@ +$(DEST)/ipft_pc.o: $(LIBSRC)/ipft_pc.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_pc.c -o $@ +$(DEST)/ipft_tx.o: $(LIBSRC)/ipft_tx.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/ipft_tx.c -o $@ +$(DEST)/kmem.o: $(LIBSRC)/kmem.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/kmem.c -o $@ +$(DEST)/kmemcpywrap.o: $(LIBSRC)/kmemcpywrap.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/kmemcpywrap.c -o $@ +$(DEST)/kvatoname.o: $(LIBSRC)/kvatoname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/kvatoname.c -o $@ +$(DEST)/load_file.o: $(LIBSRC)/load_file.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/load_file.c -o $@ +$(DEST)/load_dstlist.o: $(LIBSRC)/load_dstlist.c $(INCDEP) $(TOP)/ip_dstlist.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_dstlist.c -o $@ +$(DEST)/load_dstlistnode.o: $(LIBSRC)/load_dstlistnode.c $(INCDEP) \ + $(TOP)/ip_dstlist.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_dstlistnode.c -o $@ +$(DEST)/load_hash.o: $(LIBSRC)/load_hash.c $(INCDEP) $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_hash.c -o $@ +$(DEST)/load_hashnode.o: $(LIBSRC)/load_hashnode.c $(INCDEP) $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_hashnode.c -o $@ +$(DEST)/load_http.o: $(LIBSRC)/load_http.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/load_http.c -o $@ +$(DEST)/load_pool.o: $(LIBSRC)/load_pool.c $(INCDEP) $(TOP)/ip_pool.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_pool.c -o $@ +$(DEST)/load_poolnode.o: $(LIBSRC)/load_poolnode.c $(INCDEP) $(TOP)/ip_pool.h + $(CC) $(CCARGS) -c $(LIBSRC)/load_poolnode.c -o $@ +$(DEST)/load_url.o: $(LIBSRC)/load_url.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/load_url.c -o $@ +$(DEST)/msgdsize.o: $(LIBSRC)/msgdsize.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/msgdsize.c -o $@ +$(DEST)/mutex_emul.o: $(LIBSRC)/mutex_emul.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/mutex_emul.c -o $@ +$(DEST)/nametokva.o: $(LIBSRC)/nametokva.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/nametokva.c -o $@ +$(DEST)/nat_setgroupmap.o: $(LIBSRC)/nat_setgroupmap.c $(TOP)/ip_compat.h \ + $(TOP)/ipf.h $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/nat_setgroupmap.c -o $@ +$(DEST)/ntomask.o: $(LIBSRC)/ntomask.c $(TOP)/ip_compat.h + $(CC) $(CCARGS) -c $(LIBSRC)/ntomask.c -o $@ +$(DEST)/optname.o: $(LIBSRC)/optname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/optname.c -o $@ +$(DEST)/optprint.o: $(LIBSRC)/optprint.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/optprint.c -o $@ +$(DEST)/optprintv6.o: $(LIBSRC)/optprintv6.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/optprintv6.c -o $@ +$(DEST)/optvalue.o: $(LIBSRC)/optvalue.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/optvalue.c -o $@ +$(DEST)/parsefields.o: $(LIBSRC)/parsefields.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/parsefields.c -o $@ +$(DEST)/parseipfexpr.o: $(LIBSRC)/parseipfexpr.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/parseipfexpr.c -o $@ +$(DEST)/parsewhoisline.o: $(LIBSRC)/parsewhoisline.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/parsewhoisline.c -o $@ +$(DEST)/poolio.o: $(LIBSRC)/poolio.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/poolio.c -o $@ +$(DEST)/portname.o: $(LIBSRC)/portname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/portname.c -o $@ +$(DEST)/print_toif.o: $(LIBSRC)/print_toif.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/print_toif.c -o $@ +$(DEST)/printactiveaddr.o: $(LIBSRC)/printactiveaddr.c $(INCDEP) $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/printactiveaddr.c -o $@ +$(DEST)/printactivenat.o: $(LIBSRC)/printactivenat.c $(INCDEP) $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/printactivenat.c -o $@ +$(DEST)/printaddr.o: $(LIBSRC)/printaddr.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printaddr.c -o $@ +$(DEST)/printaps.o: $(LIBSRC)/printaps.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printaps.c -o $@ +$(DEST)/printbuf.o: $(LIBSRC)/printbuf.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printbuf.c -o $@ +$(DEST)/printdstlist.o: $(LIBSRC)/printdstlist.c $(INCDEP) $(TOP)/ip_dstlist.h + $(CC) $(CCARGS) -c $(LIBSRC)/printdstlist.c -o $@ +$(DEST)/printdstlistdata.o: $(LIBSRC)/printdstlistdata.c $(INCDEP) \ + $(TOP)/ip_dstlist.h + $(CC) $(CCARGS) -c $(LIBSRC)/printdstlistdata.c -o $@ +$(DEST)/printdstlistnode.o: $(LIBSRC)/printdstlistnode.c $(INCDEP) \ + $(TOP)/ip_dstlist.h + $(CC) $(CCARGS) -c $(LIBSRC)/printdstlistnode.c -o $@ +$(DEST)/printdstlistpolicy.o: $(LIBSRC)/printdstlistpolicy.c $(INCDEP) \ + $(TOP)/ip_dstlist.h + $(CC) $(CCARGS) -c $(LIBSRC)/printdstlistpolicy.c -o $@ +$(DEST)/printfieldhdr.o: $(LIBSRC)/printfieldhdr.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printfieldhdr.c -o $@ +$(DEST)/printfr.o: $(LIBSRC)/printfr.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printfr.c -o $@ +$(DEST)/printfraginfo.o: $(LIBSRC)/printfraginfo.c $(TOP)/ip_fil.h \ + $(TOP)/ip_frag.h + $(CC) $(CCARGS) -c $(LIBSRC)/printfraginfo.c -o $@ +$(DEST)/printhash.o: $(LIBSRC)/printhash.c $(TOP)/ip_fil.h $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhash.c -o $@ +$(DEST)/printhashdata.o: $(LIBSRC)/printhashdata.c $(TOP)/ip_fil.h \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhashdata.c -o $@ +$(DEST)/printhashnode.o: $(LIBSRC)/printhashnode.c $(TOP)/ip_fil.h \ + $(TOP)/ip_htable.h $(TOP)/ip_lookup.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhashnode.c -o $@ +$(DEST)/printhash_live.o: $(LIBSRC)/printhash_live.c $(TOP)/ip_fil.h \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhash_live.c -o $@ +$(DEST)/printdstl_live.o: $(LIBSRC)/printdstl_live.c $(TOP)/ip_fil.h \ + $(TOP)/ip_dstlist.h + $(CC) $(CCARGS) -c $(LIBSRC)/printdstl_live.c -o $@ +$(DEST)/printip.o: $(LIBSRC)/printip.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printip.c -o $@ +$(DEST)/printipfexpr.o: $(LIBSRC)/printipfexpr.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printipfexpr.c -o $@ +$(DEST)/printlookup.o: $(LIBSRC)/printlookup.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printlookup.c -o $@ +$(DEST)/printnataddr.o: $(LIBSRC)/printnataddr.c $(INCDEP) $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/printnataddr.c -o $@ +$(DEST)/printnatside.o: $(LIBSRC)/printnatside.c $(INCDEP) $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/printnatside.c -o $@ +$(DEST)/printpool.o: $(LIBSRC)/printpool.c $(TOP)/ip_fil.h $(TOP)/ip_pool.h + $(CC) $(CCARGS) -c $(LIBSRC)/printpool.c -o $@ +$(DEST)/printpooldata.o: $(LIBSRC)/printpooldata.c $(TOP)/ip_fil.h \ + $(TOP)/ip_pool.h $(TOP)/ip_lookup.h + $(CC) $(CCARGS) -c $(LIBSRC)/printpooldata.c -o $@ +$(DEST)/printpoolfield.o: $(LIBSRC)/printpoolfield.c $(TOP)/ip_fil.h \ + $(TOP)/ip_pool.h $(TOP)/ip_lookup.h + $(CC) $(CCARGS) -c $(LIBSRC)/printpoolfield.c -o $@ +$(DEST)/printpoolnode.o: $(LIBSRC)/printpoolnode.c $(TOP)/ip_fil.h \ + $(TOP)/ip_pool.h $(TOP)/ip_lookup.h + $(CC) $(CCARGS) -c $(LIBSRC)/printpoolnode.c -o $@ +$(DEST)/printpool_live.o: $(LIBSRC)/printpool_live.c $(TOP)/ip_fil.h \ + $(TOP)/ip_pool.h $(TOP)/ip_lookup.h + $(CC) $(CCARGS) -c $(LIBSRC)/printpool_live.c -o $@ +$(DEST)/printproto.o: $(LIBSRC)/printproto.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printproto.c -o $@ +$(DEST)/printhost.o: $(LIBSRC)/printhost.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhost.c -o $@ +$(DEST)/printhostmap.o: $(LIBSRC)/printhostmap.c $(TOP)/ip_fil.h + $(CC) $(CCARGS) -c $(LIBSRC)/printhostmap.c -o $@ +$(DEST)/printifname.o: $(LIBSRC)/printifname.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printifname.c -o $@ +$(DEST)/printmask.o: $(LIBSRC)/printmask.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printmask.c -o $@ +$(DEST)/printnat.o: $(LIBSRC)/printnat.c $(INCDEP) $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/printnat.c -o $@ +$(DEST)/printnatfield.o: $(LIBSRC)/printnatfield.c $(INCDEP) $(TOP)/ip_nat.h + $(CC) $(CCARGS) -c $(LIBSRC)/printnatfield.c -o $@ +$(DEST)/printhostmask.o: $(LIBSRC)/printhostmask.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printhostmask.c -o $@ +$(DEST)/printlog.o: $(LIBSRC)/printlog.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printlog.c -o $@ +$(DEST)/printpacket.o: $(LIBSRC)/printpacket.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printpacket.c -o $@ +$(DEST)/printpacket6.o: $(LIBSRC)/printpacket6.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printpacket6.c -o $@ +$(DEST)/printportcmp.o: $(LIBSRC)/printportcmp.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printportcmp.c -o $@ +$(DEST)/printsbuf.o: $(LIBSRC)/printsbuf.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printsbuf.c -o $@ +$(DEST)/printstate.o: $(LIBSRC)/printstate.c $(INCDEP) $(TOP)/ip_state.h + $(CC) $(CCARGS) -c $(LIBSRC)/printstate.c -o $@ +$(DEST)/printstatefields.o: $(LIBSRC)/printstatefields.c $(INCDEP) $(TOP)/ip_state.h + $(CC) $(CCARGS) -c $(LIBSRC)/printstatefields.c -o $@ +$(DEST)/printtcpflags.o: $(LIBSRC)/printtcpflags.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printtcpflags.c -o $@ +$(DEST)/printtqtable.o: $(LIBSRC)/printtqtable.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printtqtable.c -o $@ +$(DEST)/printtunable.o: $(LIBSRC)/printtunable.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printtunable.c -o $@ +$(DEST)/printunit.o: $(LIBSRC)/printunit.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/printunit.c -o $@ +$(DEST)/remove_hash.o: $(LIBSRC)/remove_hash.c $(INCDEP) \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/remove_hash.c -o $@ +$(DEST)/remove_hashnode.o: $(LIBSRC)/remove_hashnode.c $(INCDEP) \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/remove_hashnode.c -o $@ +$(DEST)/remove_pool.o: $(LIBSRC)/remove_pool.c $(INCDEP) \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/remove_pool.c -o $@ +$(DEST)/remove_poolnode.o: $(LIBSRC)/remove_poolnode.c $(INCDEP) \ + $(TOP)/ip_htable.h + $(CC) $(CCARGS) -c $(LIBSRC)/remove_poolnode.c -o $@ +$(DEST)/resetlexer.o: $(LIBSRC)/resetlexer.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/resetlexer.c -o $@ +$(DEST)/rwlock_emul.o: $(LIBSRC)/rwlock_emul.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/rwlock_emul.c -o $@ +$(DEST)/tcpflags.o: $(LIBSRC)/tcpflags.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/tcpflags.c -o $@ +$(DEST)/tcp_flags.o: $(LIBSRC)/tcp_flags.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/tcp_flags.c -o $@ +$(DEST)/var.o: $(LIBSRC)/var.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/var.c -o $@ +$(DEST)/verbose.o: $(LIBSRC)/verbose.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/verbose.c -o $@ +$(DEST)/save_execute.o: $(LIBSRC)/save_execute.c $(TOP)/ipl.h + $(CC) $(CCARGS) -c $(LIBSRC)/save_execute.c -o $@ +$(DEST)/save_file.o: $(LIBSRC)/save_file.c $(TOP)/ipl.h + $(CC) $(CCARGS) -c $(LIBSRC)/save_file.c -o $@ +$(DEST)/save_nothing.o: $(LIBSRC)/save_nothing.c $(TOP)/ipl.h + $(CC) $(CCARGS) -c $(LIBSRC)/save_nothing.c -o $@ +$(DEST)/save_syslog.o: $(LIBSRC)/save_syslog.c $(TOP)/ipl.h + $(CC) $(CCARGS) -c $(LIBSRC)/save_syslog.c -o $@ +$(DEST)/vtof.o: $(LIBSRC)/vtof.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/vtof.c -o $@ +$(DEST)/save_v1trap.o: $(LIBSRC)/save_v1trap.c $(TOP)/ipl.h + $(CC) $(CCARGS) -c $(LIBSRC)/save_v1trap.c -o $@ +$(DEST)/save_v2trap.o: $(LIBSRC)/save_v2trap.c $(TOP)/ipl.h + $(CC) $(CCARGS) -c $(LIBSRC)/save_v2trap.c -o $@ +$(DEST)/v6ionames.o: $(LIBSRC)/v6ionames.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/v6ionames.c -o $@ +$(DEST)/v6optvalue.o: $(LIBSRC)/v6optvalue.c $(INCDEP) + $(CC) $(CCARGS) -c $(LIBSRC)/v6optvalue.c -o $@ + +clean-lib: + /bin/rm -f ${LIBOBJS} ${LIB} diff --git a/contrib/ipfilter/lib/addicmp.c b/contrib/ipfilter/lib/addicmp.c new file mode 100644 index 0000000..da52f1c --- /dev/null +++ b/contrib/ipfilter/lib/addicmp.c @@ -0,0 +1,21 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <ctype.h> + +#include "ipf.h" + + +char *icmptypes[MAX_ICMPTYPE + 1] = { + "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", + "redir", (char *)NULL, (char *)NULL, "echo", "routerad", + "routersol", "timex", "paramprob", "timest", "timestrep", + "inforeq", "inforep", "maskreq", "maskrep", "END" +}; diff --git a/contrib/ipfilter/lib/addipopt.c b/contrib/ipfilter/lib/addipopt.c new file mode 100644 index 0000000..26aff83 --- /dev/null +++ b/contrib/ipfilter/lib/addipopt.c @@ -0,0 +1,65 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +int addipopt(op, io, len, class) + char *op; + struct ipopt_names *io; + int len; + char *class; +{ + int olen = len; + struct in_addr ipadr; + u_short val; + u_char lvl; + char *s; + + if ((len + io->on_siz) > 48) { + fprintf(stderr, "options too long\n"); + return 0; + } + len += io->on_siz; + *op++ = io->on_value; + if (io->on_siz > 1) { + s = op; + *op++ = io->on_siz; + *op++ = IPOPT_MINOFF; + + if (class) { + switch (io->on_value) + { + case IPOPT_SECURITY : + lvl = seclevel(class); + *(op - 1) = lvl; + break; + case IPOPT_RR : + case IPOPT_TS : + s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4; + break; + case IPOPT_LSRR : + case IPOPT_SSRR : + ipadr.s_addr = inet_addr(class); + s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4; + bcopy((char *)&ipadr, op, sizeof(ipadr)); + break; + case IPOPT_SATID : + val = atoi(class); + bcopy((char *)&val, op, 2); + break; + } + } + } + if (opts & OPT_DEBUG) + fprintf(stderr, "bo: %s %d %#x: %d\n", + io->on_name, io->on_value, io->on_bit, len); + return len - olen; +} diff --git a/contrib/ipfilter/lib/alist_free.c b/contrib/ipfilter/lib/alist_free.c new file mode 100644 index 0000000..44dea13 --- /dev/null +++ b/contrib/ipfilter/lib/alist_free.c @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: alist_free.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ +#include "ipf.h" + +void +alist_free(hosts) + alist_t *hosts; +{ + alist_t *a, *next; + + for (a = hosts; a != NULL; a = next) { + next = a->al_next; + free(a); + } +} diff --git a/contrib/ipfilter/lib/alist_new.c b/contrib/ipfilter/lib/alist_new.c new file mode 100644 index 0000000..73bc030 --- /dev/null +++ b/contrib/ipfilter/lib/alist_new.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: alist_new.c,v 1.5.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" +#include <ctype.h> + +alist_t * +alist_new(int family, char *host) +{ + int a, b, c, d, bits; + char *slash; + alist_t *al; + u_int mask; + + if (family == AF_UNSPEC) { + if (strchr(host, ':') != NULL) + family = AF_INET6; + else + family = AF_INET; + } + if (family != AF_INET && family != AF_INET6) + return NULL; + + al = calloc(1, sizeof(*al)); + if (al == NULL) { + fprintf(stderr, "alist_new out of memory\n"); + return NULL; + } + + while (ISSPACE(*host)) + host++; + + if (*host == '!') { + al->al_not = 1; + host++; + while (ISSPACE(*host)) + host++; + } + + bits = -1; + slash = strchr(host, '/'); + if (slash != NULL) { + *slash = '\0'; + bits = atoi(slash + 1); + } + + if (family == AF_INET) { + if (bits > 32) + goto bad; + + a = b = c = d = -1; + sscanf(host, "%d.%d.%d.%d", &a, &b, &c, &d); + + if (bits > 0 && bits < 33) { + mask = 0xffffffff << (32 - bits); + } else if (b == -1) { + mask = 0xff000000; + b = c = d = 0; + } else if (c == -1) { + mask = 0xffff0000; + c = d = 0; + } else if (d == -1) { + mask = 0xffffff00; + d = 0; + } else { + mask = 0xffffffff; + } + al->al_mask = htonl(mask); + } else { + if (bits > 128) + goto bad; + fill6bits(bits, al->al_i6mask.i6); + } + + if (gethost(family, host, &al->al_i6addr) == -1) { + if (slash != NULL) + *slash = '/'; + fprintf(stderr, "Cannot parse hostname\n"); + goto bad; + } + al->al_family = family; + if (slash != NULL) + *slash = '/'; + return al; +bad: + free(al); + return NULL; +} diff --git a/contrib/ipfilter/lib/allocmbt.c b/contrib/ipfilter/lib/allocmbt.c new file mode 100644 index 0000000..df77684 --- /dev/null +++ b/contrib/ipfilter/lib/allocmbt.c @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: allocmbt.c,v 1.1.4.1 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + +mb_t *allocmbt(size_t len) +{ + mb_t *m; + + m = (mb_t *)malloc(sizeof(mb_t)); + if (m == NULL) + return NULL; + m->mb_len = len; + m->mb_next = NULL; + m->mb_data = (char *)m->mb_buf; + return m; +} diff --git a/contrib/ipfilter/lib/assigndefined.c b/contrib/ipfilter/lib/assigndefined.c new file mode 100644 index 0000000..34f8d9a --- /dev/null +++ b/contrib/ipfilter/lib/assigndefined.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: assigndefined.c,v 1.4.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + +void assigndefined(env) + char *env; +{ + char *s, *t; + + if (env == NULL) + return; + + for (s = strtok(env, ";"); s != NULL; s = strtok(NULL, ";")) { + t = strchr(s, '='); + if (t == NULL) + continue; + *t++ = '\0'; + set_variable(s, t); + *--t = '='; + } +} diff --git a/contrib/ipfilter/lib/bcopywrap.c b/contrib/ipfilter/lib/bcopywrap.c new file mode 100644 index 0000000..453c046 --- /dev/null +++ b/contrib/ipfilter/lib/bcopywrap.c @@ -0,0 +1,20 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +int bcopywrap(from, to, size) + void *from, *to; + size_t size; +{ + bcopy((caddr_t)from, (caddr_t)to, size); + return 0; +} + diff --git a/contrib/ipfilter/lib/binprint.c b/contrib/ipfilter/lib/binprint.c new file mode 100644 index 0000000..f826721 --- /dev/null +++ b/contrib/ipfilter/lib/binprint.c @@ -0,0 +1,31 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void binprint(ptr, size) + void *ptr; + size_t size; +{ + u_char *s; + int i, j; + + for (i = size, j = 0, s = (u_char *)ptr; i; i--, s++) { + j++; + printf("%02x ", *s); + if (j == 16) { + printf("\n"); + j = 0; + } + } + putchar('\n'); + (void)fflush(stdout); +} diff --git a/contrib/ipfilter/lib/buildopts.c b/contrib/ipfilter/lib/buildopts.c new file mode 100644 index 0000000..1d1de8c --- /dev/null +++ b/contrib/ipfilter/lib/buildopts.c @@ -0,0 +1,50 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +u_32_t buildopts(cp, op, len) + char *cp, *op; + int len; +{ + struct ipopt_names *io; + u_32_t msk = 0; + char *s, *t; + int inc; + + for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { + if ((t = strchr(s, '='))) + *t++ = '\0'; + else + t = ""; + for (io = ionames; io->on_name; io++) { + if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) + continue; + if ((inc = addipopt(op, io, len, t))) { + op += inc; + len += inc; + } + msk |= io->on_bit; + break; + } + if (!io->on_name) { + fprintf(stderr, "unknown IP option name %s\n", s); + return 0; + } + } + while ((len & 3) != 3) { + *op++ = IPOPT_NOP; + len++; + } + *op++ = IPOPT_EOL; + len++; + return len; +} diff --git a/contrib/ipfilter/lib/checkrev.c b/contrib/ipfilter/lib/checkrev.c new file mode 100644 index 0000000..b6f8eee --- /dev/null +++ b/contrib/ipfilter/lib/checkrev.c @@ -0,0 +1,46 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <sys/ioctl.h> +#include <fcntl.h> + +#include "ipf.h" +#include "netinet/ipl.h" + +int checkrev(ipfname) + char *ipfname; +{ + static int vfd = -1; + struct friostat fio; + ipfobj_t obj; + + bzero((caddr_t)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(fio); + obj.ipfo_ptr = (void *)&fio; + obj.ipfo_type = IPFOBJ_IPFSTAT; + + if ((vfd == -1) && ((vfd = open(ipfname, O_RDONLY)) == -1)) { + perror("open device"); + return -1; + } + + if (ioctl(vfd, SIOCGETFS, &obj)) { + ipferror(vfd, "ioctl(SIOCGETFS)"); + close(vfd); + vfd = -1; + return -1; + } + + if (strncmp(IPL_VERSION, fio.f_version, sizeof(fio.f_version))) { + return -1; + } + return 0; +} diff --git a/contrib/ipfilter/lib/connecttcp.c b/contrib/ipfilter/lib/connecttcp.c new file mode 100644 index 0000000..2bab2af --- /dev/null +++ b/contrib/ipfilter/lib/connecttcp.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: connecttcp.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" +#include <ctype.h> + +/* + * Format expected is one addres per line, at the start of each line. + */ +int +connecttcp(char *server, int port) +{ + struct sockaddr_in sin; + struct hostent *host; + int fd; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(port & 65535); + + if (ISDIGIT(*server)) { + if (inet_aton(server, &sin.sin_addr) == -1) { + return -1; + } + } else { + host = gethostbyname(server); + if (host == NULL) + return -1; + memcpy(&sin.sin_addr, host->h_addr_list[0], + sizeof(sin.sin_addr)); + } + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd == -1) + return -1; + + if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + close(fd); + return -1; + } + + return fd; +} diff --git a/contrib/ipfilter/lib/count4bits.c b/contrib/ipfilter/lib/count4bits.c new file mode 100644 index 0000000..a847388 --- /dev/null +++ b/contrib/ipfilter/lib/count4bits.c @@ -0,0 +1,40 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +/* + * count consecutive 1's in bit mask. If the mask generated by counting + * consecutive 1's is different to that passed, return -1, else return # + * of bits. + */ +int count4bits(ip) + u_int ip; +{ + int cnt = 0, i, j; + u_int ipn; + + ip = ipn = ntohl(ip); + for (i = 32; i; i--, ipn *= 2) + if (ipn & 0x80000000) + cnt++; + else + break; + ipn = 0; + for (i = 32, j = cnt; i; i--, j--) { + ipn *= 2; + if (j > 0) + ipn++; + } + if (ipn == ip) + return cnt; + return -1; +} diff --git a/contrib/ipfilter/lib/count6bits.c b/contrib/ipfilter/lib/count6bits.c new file mode 100644 index 0000000..b8f4320 --- /dev/null +++ b/contrib/ipfilter/lib/count6bits.c @@ -0,0 +1,29 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +int count6bits(msk) + u_32_t *msk; +{ + int i = 0, k; + u_32_t j; + + for (k = 3; k >= 0; k--) + if (msk[k] == 0xffffffff) + i += 32; + else { + for (j = msk[k]; j; j <<= 1) + if (j & 0x80000000) + i++; + } + return i; +} diff --git a/contrib/ipfilter/lib/debug.c b/contrib/ipfilter/lib/debug.c new file mode 100644 index 0000000..02e5f5b --- /dev/null +++ b/contrib/ipfilter/lib/debug.c @@ -0,0 +1,58 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#if defined(__STDC__) +# include <stdarg.h> +#else +# include <varargs.h> +#endif +#include <stdio.h> + +#include "ipf.h" +#include "opts.h" + +int debuglevel = 0; + + +#ifdef __STDC__ +void debug(int level, char *fmt, ...) +#else +void debug(level, fmt, va_alist) + int level; + char *fmt; + va_dcl +#endif +{ + va_list pvar; + + va_start(pvar, fmt); + + if ((debuglevel > 0) && (level <= debuglevel)) + vfprintf(stderr, fmt, pvar); + va_end(pvar); +} + + +#ifdef __STDC__ +void ipfkdebug(char *fmt, ...) +#else +void ipfkdebug(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list pvar; + + va_start(pvar, fmt); + + if (opts & OPT_DEBUG) + debug(0x1fffffff, fmt, pvar); + va_end(pvar); +} diff --git a/contrib/ipfilter/lib/dupmbt.c b/contrib/ipfilter/lib/dupmbt.c new file mode 100644 index 0000000..0929eeb --- /dev/null +++ b/contrib/ipfilter/lib/dupmbt.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: dupmbt.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + +mb_t *dupmbt(orig) + mb_t *orig; +{ + mb_t *m; + + m = (mb_t *)malloc(sizeof(mb_t)); + if (m == NULL) + return NULL; + m->mb_len = orig->mb_len; + m->mb_next = NULL; + m->mb_data = (char *)m->mb_buf + (orig->mb_data - (char *)orig->mb_buf); + bcopy(orig->mb_data, m->mb_data, m->mb_len); + return m; +} diff --git a/contrib/ipfilter/lib/facpri.c b/contrib/ipfilter/lib/facpri.c new file mode 100644 index 0000000..c9b4774 --- /dev/null +++ b/contrib/ipfilter/lib/facpri.c @@ -0,0 +1,153 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#if !defined(__SVR4) && !defined(__svr4__) +#include <strings.h> +#endif +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <syslog.h> +#include "facpri.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + + +typedef struct table { + char *name; + int value; +} table_t; + +table_t facs[] = { + { "kern", LOG_KERN }, { "user", LOG_USER }, + { "mail", LOG_MAIL }, { "daemon", LOG_DAEMON }, + { "auth", LOG_AUTH }, { "syslog", LOG_SYSLOG }, + { "lpr", LOG_LPR }, { "news", LOG_NEWS }, + { "uucp", LOG_UUCP }, +#if LOG_CRON == LOG_CRON2 + { "cron2", LOG_CRON1 }, +#else + { "cron", LOG_CRON1 }, +#endif +#ifdef LOG_FTP + { "ftp", LOG_FTP }, +#endif +#ifdef LOG_AUTHPRIV + { "authpriv", LOG_AUTHPRIV }, +#endif +#ifdef LOG_AUDIT + { "audit", LOG_AUDIT }, +#endif +#ifdef LOG_LFMT + { "logalert", LOG_LFMT }, +#endif +#if LOG_CRON == LOG_CRON1 + { "cron", LOG_CRON2 }, +#else + { "cron2", LOG_CRON2 }, +#endif +#ifdef LOG_SECURITY + { "security", LOG_SECURITY }, +#endif + { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, + { NULL, 0 } +}; + + +/* + * map a facility number to its name + */ +char * +fac_toname(facpri) + int facpri; +{ + int i, j, fac; + + fac = facpri & LOG_FACMASK; + j = fac >> 3; + if (j < (sizeof(facs)/sizeof(facs[0]))) { + if (facs[j].value == fac) + return facs[j].name; + } + for (i = 0; facs[i].name; i++) + if (fac == facs[i].value) + return facs[i].name; + + return NULL; +} + + +/* + * map a facility name to its number + */ +int +fac_findname(name) + char *name; +{ + int i; + + for (i = 0; facs[i].name; i++) + if (!strcmp(facs[i].name, name)) + return facs[i].value; + return -1; +} + + +table_t pris[] = { + { "emerg", LOG_EMERG }, { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, { "err", LOG_ERR }, + { "warn", LOG_WARNING }, { "notice", LOG_NOTICE }, + { "info", LOG_INFO }, { "debug", LOG_DEBUG }, + { NULL, 0 } +}; + + +/* + * map a facility name to its number + */ +int +pri_findname(name) + char *name; +{ + int i; + + for (i = 0; pris[i].name; i++) + if (!strcmp(pris[i].name, name)) + return pris[i].value; + return -1; +} + + +/* + * map a priority number to its name + */ +char * +pri_toname(facpri) + int facpri; +{ + int i, pri; + + pri = facpri & LOG_PRIMASK; + if (pris[pri].value == pri) + return pris[pri].name; + for (i = 0; pris[i].name; i++) + if (pri == pris[i].value) + return pris[i].name; + return NULL; +} diff --git a/contrib/ipfilter/lib/facpri.h b/contrib/ipfilter/lib/facpri.h new file mode 100644 index 0000000..54ecabd --- /dev/null +++ b/contrib/ipfilter/lib/facpri.h @@ -0,0 +1,43 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#ifndef __FACPRI_H__ +#define __FACPRI_H__ + +#ifndef __P +# define P_DEF +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +extern char *fac_toname __P((int)); +extern int fac_findname __P((char *)); + +extern char *pri_toname __P((int)); +extern int pri_findname __P((char *)); + +#ifdef P_DEF +# undef __P +# undef P_DEF +#endif + +#if LOG_CRON == (9<<3) +# define LOG_CRON1 LOG_CRON +# define LOG_CRON2 (15<<3) +#endif +#if LOG_CRON == (15<<3) +# define LOG_CRON1 (9<<3) +# define LOG_CRON2 LOG_CRON +#endif + +#endif /* __FACPRI_H__ */ diff --git a/contrib/ipfilter/lib/familyname.c b/contrib/ipfilter/lib/familyname.c new file mode 100644 index 0000000..35bb975 --- /dev/null +++ b/contrib/ipfilter/lib/familyname.c @@ -0,0 +1,12 @@ +#include "ipf.h" + +const char *familyname(int family) +{ + if (family == AF_INET) + return "inet"; +#ifdef AF_INET6 + if (family == AF_INET6) + return "inet6"; +#endif + return "unknown"; +} diff --git a/contrib/ipfilter/lib/fill6bits.c b/contrib/ipfilter/lib/fill6bits.c new file mode 100644 index 0000000..39ec735 --- /dev/null +++ b/contrib/ipfilter/lib/fill6bits.c @@ -0,0 +1,48 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void fill6bits(bits, msk) + int bits; + u_int *msk; +{ + if (bits == 0) { + msk[0] = 0; + msk[1] = 0; + msk[2] = 0; + msk[3] = 0; + return; + } + + msk[0] = 0xffffffff; + msk[1] = 0xffffffff; + msk[2] = 0xffffffff; + msk[3] = 0xffffffff; + + if (bits == 128) + return; + if (bits > 96) { + msk[3] = htonl(msk[3] << (128 - bits)); + } else if (bits > 64) { + msk[3] = 0; + msk[2] = htonl(msk[2] << (96 - bits)); + } else if (bits > 32) { + msk[3] = 0; + msk[2] = 0; + msk[1] = htonl(msk[1] << (64 - bits)); + } else { + msk[3] = 0; + msk[2] = 0; + msk[1] = 0; + msk[0] = htonl(msk[0] << (32 - bits)); + } +} diff --git a/contrib/ipfilter/lib/findword.c b/contrib/ipfilter/lib/findword.c new file mode 100644 index 0000000..e06f213 --- /dev/null +++ b/contrib/ipfilter/lib/findword.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: findword.c,v 1.3.4.1 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + + +wordtab_t *findword(words, name) + wordtab_t *words; + char *name; +{ + wordtab_t *w; + + for (w = words; w->w_word != NULL; w++) + if (!strcmp(name, w->w_word)) + break; + if (w->w_word == NULL) + return NULL; + + return w; +} diff --git a/contrib/ipfilter/lib/flags.c b/contrib/ipfilter/lib/flags.c new file mode 100644 index 0000000..05fcc98 --- /dev/null +++ b/contrib/ipfilter/lib/flags.c @@ -0,0 +1,25 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +/* + * ECN is a new addition to TCP - RFC 2481 + */ +#ifndef TH_ECN +# define TH_ECN 0x40 +#endif +#ifndef TH_CWR +# define TH_CWR 0x80 +#endif + +char flagset[] = "FSRPAUEC"; +u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG, + TH_ECN, TH_CWR }; diff --git a/contrib/ipfilter/lib/freembt.c b/contrib/ipfilter/lib/freembt.c new file mode 100644 index 0000000..0fc748d --- /dev/null +++ b/contrib/ipfilter/lib/freembt.c @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: freembt.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + +void freembt(m) + mb_t *m; +{ + + free(m); +} diff --git a/contrib/ipfilter/lib/ftov.c b/contrib/ipfilter/lib/ftov.c new file mode 100644 index 0000000..cb9715d --- /dev/null +++ b/contrib/ipfilter/lib/ftov.c @@ -0,0 +1,16 @@ +#include "ipf.h" + +int +ftov(version) + int version; +{ +#ifdef USE_INET6 + if (version == AF_INET6) + return 6; +#endif + if (version == AF_INET) + return 4; + if (version == AF_UNSPEC) + return 0; + return -1; +} diff --git a/contrib/ipfilter/lib/gethost.c b/contrib/ipfilter/lib/gethost.c new file mode 100644 index 0000000..14099e2 --- /dev/null +++ b/contrib/ipfilter/lib/gethost.c @@ -0,0 +1,76 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +int gethost(family, name, hostp) + int family; + char *name; + i6addr_t *hostp; +{ + struct hostent *h; + struct netent *n; + u_32_t addr; + + bzero(hostp, sizeof(*hostp)); + if (!strcmp(name, "test.host.dots")) { + if (family == AF_INET) { + hostp->in4.s_addr = htonl(0xfedcba98); + } +#ifdef USE_INET6 + if (family == AF_INET6) { + hostp->i6[0] = htonl(0xfe80aa55); + hostp->i6[1] = htonl(0x12345678); + hostp->i6[2] = htonl(0x5a5aa5a5); + hostp->i6[3] = htonl(0xfedcba98); + } +#endif + return 0; + } + + if (!strcmp(name, "<thishost>")) + name = thishost; + + if (family == AF_INET) { + h = gethostbyname(name); + if (h != NULL) { + if ((h->h_addr != NULL) && + (h->h_length == sizeof(addr))) { + bcopy(h->h_addr, (char *)&addr, sizeof(addr)); + hostp->in4.s_addr = addr; + return 0; + } + } + + n = getnetbyname(name); + if (n != NULL) { + hostp->in4.s_addr = htonl(n->n_net & 0xffffffff); + return 0; + } + } +#ifdef USE_INET6 + if (family == AF_INET6) { + struct addrinfo hints, *res; + struct sockaddr_in6 *sin6; + + bzero((char *)&hints, sizeof(hints)); + hints.ai_family = PF_INET6; + + getaddrinfo(name, NULL, &hints, &res); + if (res != NULL) { + sin6 = (struct sockaddr_in6 *)res->ai_addr; + hostp->in6 = sin6->sin6_addr; + freeaddrinfo(res); + return 0; + } + } +#endif + return -1; +} diff --git a/contrib/ipfilter/lib/geticmptype.c b/contrib/ipfilter/lib/geticmptype.c new file mode 100644 index 0000000..5c962e9 --- /dev/null +++ b/contrib/ipfilter/lib/geticmptype.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + +int geticmptype(family, name) + int family; + char *name; +{ + icmptype_t *i; + + for (i = icmptypelist; i->it_name != NULL; i++) { + if (!strcmp(name, i->it_name)) { + if (family == AF_INET) + return i->it_v4; +#ifdef USE_INET6 + if (family == AF_INET6) + return i->it_v6; +#endif + return -1; + } + } + + return -1; +} diff --git a/contrib/ipfilter/lib/getifname.c b/contrib/ipfilter/lib/getifname.c new file mode 100644 index 0000000..88cad32 --- /dev/null +++ b/contrib/ipfilter/lib/getifname.c @@ -0,0 +1,95 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +#include "kmem.h" + +/* + * Given a pointer to an interface in the kernel, return a pointer to a + * string which is the interface name. + */ +#if 0 +char *getifname(ptr) + struct ifnet *ptr; +{ +#if SOLARIS || defined(__hpux) +# if SOLARIS +# include <sys/mutex.h> +# include <sys/condvar.h> +# endif +# ifdef __hpux +# include "compat.h" +# endif +# include "../pfil/qif.h" + char *ifname; + qif_t qif; + + if ((void *)ptr == (void *)-1) + return "!"; + if (ptr == NULL) + return "-"; + + if (kmemcpy((char *)&qif, (u_long)ptr, sizeof(qif)) == -1) + return "X"; + ifname = strdup(qif.qf_name); + if ((ifname != NULL) && (*ifname == '\0')) { + free(ifname); + return "!"; + } + return ifname; +#else +# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ + defined(__OpenBSD__) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) +#else + char buf[LIFNAMSIZ]; + int len; +# endif + struct ifnet netif; + + if ((void *)ptr == (void *)-1) + return "!"; + if (ptr == NULL) + return "-"; + + if (kmemcpy((char *)&netif, (u_long)ptr, sizeof(netif)) == -1) + return "X"; +# if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ + defined(__OpenBSD__) || defined(linux) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) + return strdup(netif.if_xname); +# else + if (kstrncpy(buf, (u_long)netif.if_name, sizeof(buf)) == -1) + return "X"; + if (netif.if_unit < 10) + len = 2; + else if (netif.if_unit < 1000) + len = 3; + else if (netif.if_unit < 10000) + len = 4; + else + len = 5; + buf[sizeof(buf) - len] = '\0'; + sprintf(buf + strlen(buf), "%d", netif.if_unit % 10000); + return strdup(buf); +# endif +#endif +} +#else +char *getifname(ptr) + struct ifnet *ptr; +{ +#if 0 + ptr = ptr; +#endif + return "X"; +} +#endif diff --git a/contrib/ipfilter/lib/getnattype.c b/contrib/ipfilter/lib/getnattype.c new file mode 100644 index 0000000..ef7ffd4 --- /dev/null +++ b/contrib/ipfilter/lib/getnattype.c @@ -0,0 +1,70 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ +#include "ipf.h" +#include "kmem.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + + +/* + * Get a nat filter type given its kernel address. + */ +char * +getnattype(nat) + nat_t *nat; +{ + static char unknownbuf[20]; + char *which; + + if (!nat) + return "???"; + + switch (nat->nat_redir) + { + case NAT_MAP : + which = "MAP"; + break; + case NAT_MAPBLK : + which = "MAP-BLOCK"; + break; + case NAT_REDIRECT : + which = "RDR"; + break; + case NAT_MAP|NAT_REWRITE : + which = "RWR-MAP"; + break; + case NAT_REDIRECT|NAT_REWRITE : + which = "RWR-RDR"; + break; + case NAT_BIMAP : + which = "BIMAP"; + break; + case NAT_REDIRECT|NAT_DIVERTUDP : + which = "DIV-RDR"; + break; + case NAT_MAP|NAT_DIVERTUDP : + which = "DIV-MAP"; + break; + case NAT_REDIRECT|NAT_ENCAP : + which = "ENC-RDR"; + break; + case NAT_MAP|NAT_ENCAP : + which = "ENC-MAP"; + break; + default : + sprintf(unknownbuf, "unknown(%04x)", + nat->nat_redir & 0xffffffff); + which = unknownbuf; + break; + } + return which; +} diff --git a/contrib/ipfilter/lib/getport.c b/contrib/ipfilter/lib/getport.c new file mode 100644 index 0000000..0981ff1 --- /dev/null +++ b/contrib/ipfilter/lib/getport.c @@ -0,0 +1,90 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" +#include <ctype.h> + +int getport(fr, name, port, proto) + frentry_t *fr; + char *name, *proto; + u_short *port; +{ + struct protoent *p; + struct servent *s; + u_short p1; + + if (fr == NULL || fr->fr_type != FR_T_IPF) { + s = getservbyname(name, proto); + if (s != NULL) { + *port = s->s_port; + return 0; + } + + if (ISDIGIT(*name)) { + int portval = atoi(name); + if (portval < 0 || portval > 65535) + return -1; + *port = htons((u_short)portval); + return 0; + } + return -1; + } + + /* + * Some people will use port names in rules without specifying + * either TCP or UDP because it is implied by the group head. + * If we don't know the protocol, then the best we can do here is + * to take either only the TCP or UDP mapping (if one or the other + * is missing) or make sure both of them agree. + */ + if (fr->fr_proto == 0) { + s = getservbyname(name, "tcp"); + if (s != NULL) + p1 = s->s_port; + else + p1 = 0; + s = getservbyname(name, "udp"); + if (s != NULL) { + if (p1 != s->s_port) + return -1; + } + if ((p1 == 0) && (s == NULL)) + return -1; + if (p1) + *port = p1; + else + *port = s->s_port; + return 0; + } + + if ((fr->fr_flx & FI_TCPUDP) != 0) { + /* + * If a rule is "tcp/udp" then check that both TCP and UDP + * mappings for this protocol name match ports. + */ + s = getservbyname(name, "tcp"); + if (s == NULL) + return -1; + p1 = s->s_port; + s = getservbyname(name, "udp"); + if (s == NULL || s->s_port != p1) + return -1; + *port = p1; + return 0; + } + + p = getprotobynumber(fr->fr_proto); + s = getservbyname(name, p ? p->p_name : NULL); + if (s != NULL) { + *port = s->s_port; + return 0; + } + return -1; +} diff --git a/contrib/ipfilter/lib/getportproto.c b/contrib/ipfilter/lib/getportproto.c new file mode 100644 index 0000000..69fecff --- /dev/null +++ b/contrib/ipfilter/lib/getportproto.c @@ -0,0 +1,40 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <ctype.h> +#include "ipf.h" + +int getportproto(name, proto) + char *name; + int proto; +{ + struct servent *s; + struct protoent *p; + + if (ISDIGIT(*name)) { + int number; + char *s; + + for (s = name; *s != '\0'; s++) + if (!ISDIGIT(*s)) + return -1; + + number = atoi(name); + if (number < 0 || number > 65535) + return -1; + return htons(number); + } + + p = getprotobynumber(proto); + s = getservbyname(name, p ? p->p_name : NULL); + if (s != NULL) + return s->s_port; + return -1; +} diff --git a/contrib/ipfilter/lib/getproto.c b/contrib/ipfilter/lib/getproto.c new file mode 100644 index 0000000..6c52cd3 --- /dev/null +++ b/contrib/ipfilter/lib/getproto.c @@ -0,0 +1,41 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" +#include <ctype.h> + +int getproto(name) + char *name; +{ + struct protoent *p; + char *s; + + for (s = name; *s != '\0'; s++) + if (!ISDIGIT(*s)) + break; + if (*s == '\0') + return atoi(name); + +#ifdef _AIX51 + /* + * For some bogus reason, "ip" is 252 in /etc/protocols on AIX 5 + * The IANA has doubled up on the definition of 0 - it is now also + * used for IPv6 hop-opts, so we can no longer rely on /etc/protocols + * providing the correct name->number mapping + */ +#endif + if (!strcasecmp(name, "ip")) + return 0; + + p = getprotobyname(name); + if (p != NULL) + return p->p_proto; + return -1; +} diff --git a/contrib/ipfilter/lib/getsumd.c b/contrib/ipfilter/lib/getsumd.c new file mode 100644 index 0000000..84acc7a --- /dev/null +++ b/contrib/ipfilter/lib/getsumd.c @@ -0,0 +1,23 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +char *getsumd(sum) + u_32_t sum; +{ + static char sumdbuf[17]; + + if (sum & NAT_HW_CKSUM) + sprintf(sumdbuf, "hw(%#0x)", sum & 0xffff); + else + sprintf(sumdbuf, "%#0x", sum); + return sumdbuf; +} diff --git a/contrib/ipfilter/lib/hostname.c b/contrib/ipfilter/lib/hostname.c new file mode 100644 index 0000000..28ead89 --- /dev/null +++ b/contrib/ipfilter/lib/hostname.c @@ -0,0 +1,60 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +char *hostname(family, ip) + int family; + void *ip; +{ + static char hostbuf[MAXHOSTNAMELEN+1]; + struct hostent *hp; + struct in_addr ipa; + struct netent *np; + + memset(&ipa, 0, sizeof(ipa)); /* XXX gcc */ + + if (family == AF_INET) { + ipa.s_addr = *(u_32_t *)ip; + if (ipa.s_addr == htonl(0xfedcba98)) + return "test.host.dots"; + } + + if ((opts & OPT_NORESOLVE) == 0) { + if (family == AF_INET) { + hp = gethostbyaddr(ip, 4, AF_INET); + if (hp != NULL && hp->h_name != NULL && + *hp->h_name != '\0') { + strncpy(hostbuf, hp->h_name, sizeof(hostbuf)); + hostbuf[sizeof(hostbuf) - 1] = '\0'; + return hostbuf; + } + + np = getnetbyaddr(ipa.s_addr, AF_INET); + if (np != NULL && np->n_name != NULL && + *np->n_name != '\0') { + strncpy(hostbuf, np->n_name, sizeof(hostbuf)); + hostbuf[sizeof(hostbuf) - 1] = '\0'; + return hostbuf; + } + } + } + + if (family == AF_INET) { + return inet_ntoa(ipa); + } +#ifdef USE_INET6 + (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); + hostbuf[MAXHOSTNAMELEN] = '\0'; + return hostbuf; +#else + return "IPv6"; +#endif +} diff --git a/contrib/ipfilter/lib/icmpcode.c b/contrib/ipfilter/lib/icmpcode.c new file mode 100644 index 0000000..e898ebf --- /dev/null +++ b/contrib/ipfilter/lib/icmpcode.c @@ -0,0 +1,24 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <ctype.h> + +#include "ipf.h" + +#ifndef MIN +# define MIN(a,b) ((a) > (b) ? (b) : (a)) +#endif + + +char *icmpcodes[MAX_ICMPCODE + 1] = { + "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail", + "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib", + "net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff", + NULL }; diff --git a/contrib/ipfilter/lib/icmptypename.c b/contrib/ipfilter/lib/icmptypename.c new file mode 100644 index 0000000..d7eb3bd --- /dev/null +++ b/contrib/ipfilter/lib/icmptypename.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + +char *icmptypename(family, type) + int family, type; +{ + icmptype_t *i; + + if ((type < 0) || (type > 255)) + return NULL; + + for (i = icmptypelist; i->it_name != NULL; i++) { + if ((family == AF_INET) && (i->it_v4 == type)) + return i->it_name; +#ifdef USE_INET6 + if ((family == AF_INET6) && (i->it_v6 == type)) + return i->it_name; +#endif + } + + return NULL; +} diff --git a/contrib/ipfilter/lib/icmptypes.c b/contrib/ipfilter/lib/icmptypes.c new file mode 100644 index 0000000..c1123ff --- /dev/null +++ b/contrib/ipfilter/lib/icmptypes.c @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + +#ifndef USE_INET6 +# undef ICMP6_ECHO_REQUEST +# define ICMP6_ECHO_REQUEST 0 +# undef ICMP6_ECHO_REPLY +# define ICMP6_ECHO_REPLY 0 +# undef ICMP6_NI_QUERY +# define ICMP6_NI_QUERY 0 +# undef ICMP6_NI_REPLY +# define ICMP6_NI_REPLY 0 +# undef ICMP6_PARAM_PROB +# define ICMP6_PARAM_PROB 0 +# undef ND_ROUTER_ADVERT +# define ND_ROUTER_ADVERT 0 +# undef ND_ROUTER_SOLICIT +# define ND_ROUTER_SOLICIT 0 +# undef ICMP6_TIME_EXCEEDED +# define ICMP6_TIME_EXCEEDED 0 +# undef ICMP6_DST_UNREACH +# define ICMP6_DST_UNREACH 0 +# undef ICMP6_PACKET_TOO_BIG +# define ICMP6_PACKET_TOO_BIG 0 +# undef MLD_LISTENER_QUERY +# define MLD_LISTENER_QUERY 0 +# undef MLD_LISTENER_REPORT +# define MLD_LISTENER_REPORT 0 +# undef MLD_LISTENER_DONE +# define MLD_LISTENER_DONE 0 +# undef ICMP6_MEMBERSHIP_QUERY +# define ICMP6_MEMBERSHIP_QUERY 0 +# undef ICMP6_MEMBERSHIP_REPORT +# define ICMP6_MEMBERSHIP_REPORT 0 +# undef ICMP6_MEMBERSHIP_REDUCTION +# define ICMP6_MEMBERSHIP_REDUCTION 0 +# undef ND_NEIGHBOR_ADVERT +# define ND_NEIGHBOR_ADVERT 0 +# undef ND_NEIGHBOR_SOLICIT +# define ND_NEIGHBOR_SOLICIT 0 +# undef ICMP6_ROUTER_RENUMBERING +# define ICMP6_ROUTER_RENUMBERING 0 +# undef ICMP6_WRUREQUEST +# define ICMP6_WRUREQUEST 0 +# undef ICMP6_WRUREPLY +# define ICMP6_WRUREPLY 0 +# undef ICMP6_FQDN_QUERY +# define ICMP6_FQDN_QUERY 0 +# undef ICMP6_FQDN_REPLY +# define ICMP6_FQDN_REPLY 0 +#else +# if !defined(MLD_LISTENER_QUERY) +# define MLD_LISTENER_QUERY 130 +# endif +# if !defined(MLD_LISTENER_REPORT) +# define MLD_LISTENER_REPORT 131 +# endif +# if !defined(MLD_LISTENER_DONE) +# define MLD_LISTENER_DONE 132 +# endif +# if defined(MLD_LISTENER_REDUCTION) && !defined(MLD_LISTENER_DONE) +# define MLD_LISTENER_DONE MLD_LISTENER_REDUCTION +# endif +#endif + +icmptype_t icmptypelist[] = { + { "echo", ICMP_ECHO, ICMP6_ECHO_REQUEST }, + { "echorep", ICMP_ECHOREPLY, ICMP6_ECHO_REPLY }, + { "fqdnquery", -1, ICMP6_FQDN_QUERY }, + { "fqdnreply", -1, ICMP6_FQDN_REPLY }, + { "infoqry", -1, ICMP6_NI_QUERY }, + { "inforeq", ICMP_IREQ, ICMP6_NI_QUERY }, + { "inforep", ICMP_IREQREPLY, ICMP6_NI_REPLY }, + { "listendone", -1, MLD_LISTENER_DONE }, + { "listenqry", -1, MLD_LISTENER_QUERY }, + { "listenrep", -1, MLD_LISTENER_REPORT }, + { "maskrep", ICMP_MASKREPLY, -1 }, + { "maskreq", ICMP_MASKREQ, -1 }, + { "memberqry", -1, ICMP6_MEMBERSHIP_QUERY }, + { "memberred", -1, ICMP6_MEMBERSHIP_REDUCTION }, + { "memberreply",-1, ICMP6_MEMBERSHIP_REPORT }, + { "neighadvert", -1, ND_NEIGHBOR_ADVERT }, + { "neighborsol", -1, ND_NEIGHBOR_SOLICIT }, + { "neighborsolicit", -1, ND_NEIGHBOR_SOLICIT }, + { "paramprob", ICMP_PARAMPROB, ICMP6_PARAM_PROB }, + { "redir", ICMP_REDIRECT, ND_REDIRECT }, + { "renumber", -1, ICMP6_ROUTER_RENUMBERING }, + { "routerad", ICMP_ROUTERADVERT, ND_ROUTER_ADVERT }, + { "routeradvert",ICMP_ROUTERADVERT, ND_ROUTER_ADVERT }, + { "routersol", ICMP_ROUTERSOLICIT, ND_ROUTER_SOLICIT }, + { "routersolcit",ICMP_ROUTERSOLICIT, ND_ROUTER_SOLICIT }, + { "squench", ICMP_SOURCEQUENCH, -1 }, + { "timest", ICMP_TSTAMP, -1 }, + { "timestrep", ICMP_TSTAMPREPLY, -1 }, + { "timex", ICMP_TIMXCEED, ICMP6_TIME_EXCEEDED }, + { "toobig", -1, ICMP6_PACKET_TOO_BIG }, + { "unreach", ICMP_UNREACH, ICMP6_DST_UNREACH }, + { "whorep", -1, ICMP6_WRUREPLY }, + { "whoreq", -1, ICMP6_WRUREQUEST }, + { NULL, -1, -1 } +}; diff --git a/contrib/ipfilter/lib/inet_addr.c b/contrib/ipfilter/lib/inet_addr.c new file mode 100644 index 0000000..c7ae443 --- /dev/null +++ b/contrib/ipfilter/lib/inet_addr.c @@ -0,0 +1,210 @@ +/* $FreeBSD$ */ + +/* + * ++Copyright++ 1983, 1990, 1993 + * - + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if !defined(lint) +static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +static const char rcsid[] = "@(#)$Id: inet_addr.c,v 1.8.2.3 2004/12/09 19:41:20 darrenr Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +#ifndef linux +int inet_aton __P((const char *, struct in_addr *)); + +/* + * Because the ctype(3) posix definition, if used "safely" in code everywhere, + * would mean all normal code that walks through strings needed casts. Yuck. + */ +#define ISALNUM(x) isalnum((u_char)(x)) +#define ISALPHA(x) isalpha((u_char)(x)) +#define ISASCII(x) isascii((u_char)(x)) +#define ISDIGIT(x) isdigit((u_char)(x)) +#define ISPRINT(x) isprint((u_char)(x)) +#define ISSPACE(x) isspace((u_char)(x)) +#define ISUPPER(x) isupper((u_char)(x)) +#define ISXDIGIT(x) isxdigit((u_char)(x)) +#define ISLOWER(x) islower((u_char)(x)) + +/* + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(cp, addr) + register const char *cp; + struct in_addr *addr; +{ + register u_long val; + register int base, n; + register char c; + u_int parts[4]; + register u_int *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!ISDIGIT(c)) + return (0); + val = 0; base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else + base = 8; + } + for (;;) { + if (ISASCII(c) && ISDIGIT(c)) { + val = (val * base) + (c - '0'); + c = *++cp; + } else if (base == 16 && ISASCII(c) && ISXDIGIT(c)) { + val = (val << 4) | + (c + 10 - (ISLOWER(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!ISASCII(c) || !ISSPACE(c))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); +} +#endif + +/* these are compatibility routines, not needed on recent BSD releases */ + +/* + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +#if 0 +inet_addr(cp) + const char *cp; +{ + struct in_addr val; + + if (inet_aton(cp, &val)) + return (val.s_addr); + return (0xffffffff); +} +#endif diff --git a/contrib/ipfilter/lib/initparse.c b/contrib/ipfilter/lib/initparse.c new file mode 100644 index 0000000..a16ac0f --- /dev/null +++ b/contrib/ipfilter/lib/initparse.c @@ -0,0 +1,20 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + + +char thishost[MAXHOSTNAMELEN]; + + +void initparse __P((void)) +{ + gethostname(thishost, sizeof(thishost)); + thishost[sizeof(thishost) - 1] = '\0'; +} diff --git a/contrib/ipfilter/lib/interror.c b/contrib/ipfilter/lib/interror.c new file mode 100644 index 0000000..c13f5f8 --- /dev/null +++ b/contrib/ipfilter/lib/interror.c @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: interror.c,v 1.9.2.12 2012/07/22 08:03:39 darren_r Exp $ + */ + +#include "ipf.h" +#include <fcntl.h> +#include <sys/ioctl.h> + +typedef struct { + int iee_number; + char *iee_text; +} ipf_error_entry_t; + +static ipf_error_entry_t *find_error __P((int)); + +#define IPF_NUM_ERRORS 475 + +/* + * NO REUSE OF NUMBERS! + * + * IF YOU WANT TO ADD AN ERROR TO THIS TABLE, _ADD_ A NEW NUMBER. + * DO _NOT_ USE AN EMPTY NUMBER OR FILL IN A GAP. + */ +static ipf_error_entry_t ipf_errors[IPF_NUM_ERRORS] = { + { 1, "auth table locked/full" }, + { 2, "" }, + { 3, "copyinptr received bad address" }, + { 4, "copyoutptr received bad address" }, + { 5, "" }, + { 6, "cannot load a rule with FR_T_BUILTIN flag set" }, + { 7, "internal rule without FR_T_BUILDINT flag set" }, + { 8, "no data provided with filter rule" }, + { 9, "invalid ioctl for rule" }, + { 10, "rule protocol is not 4 or 6" }, + { 11, "cannot find rule function" }, + { 12, "cannot find rule group" }, + { 13, "group in/out does not match rule in/out" }, + { 14, "rule without in/out does not belong to a group" }, + { 15, "cannot determine where to append rule" }, + { 16, "malloc for rule data failed" }, + { 17, "copyin for rule data failed" }, + { 18, "" }, + { 19, "zero data size for BPF rule" }, + { 20, "BPF validation failed" }, + { 21, "incorrect data size for IPF rule" }, + { 22, "'keep state' rule included 'with oow'" }, + { 23, "bad interface index with dynamic source address" }, + { 24, "bad interface index with dynamic dest. address" }, + { 25, "match array verif failed for filter rule" }, + { 26, "bad filter rule type" }, + { 27, "rule not found for zero'stats" }, + { 28, "copyout failed for zero'ing stats" }, + { 29, "rule not found for removing" }, + { 30, "cannot remove internal rule" }, + { 31, "rule in use" }, + { 32, "rule already exists" }, + { 33, "no memory for another rule" }, + { 34, "could not find function" }, + { 35, "copyout failed for resolving function name -> addr" }, + { 36, "copyout failed for resolving function addr -> name" }, + { 37, "function name/addr resolving search failed" }, + { 38, "group map cannot find it's hash table" }, + { 39, "group map hash-table in/out do not match rule" }, + { 40, "bcopyout failed for SIOCIPFINTERROR" }, + { 41, "" }, + { 42, "ipfilter not enabled for NAT ioctl" }, + { 43, "ipfilter not enabled for state ioctl" }, + { 44, "ipfilter not enabled for auth ioctl" }, + { 45, "ipfilter not enbaled for sync ioctl" }, + { 46, "ipfilter not enabled for scan ioctl" }, + { 47, "ipfilter not enabled for lookup ioctl" }, + { 48, "unrecognised device minor number for ioctl" }, + { 49, "unrecognised object type for copying in ipfobj" }, + { 50, "mismatching object type for copying in ipfobj" }, + { 51, "object size too small for copying in ipfobj" }, + { 52, "object size mismatch for copying in ipfobj" }, + { 53, "compat object size too small for copying in ipfobj" }, + { 54, "compat object size mismatch for copying in ipfobj" }, + { 55, "error doing copyin of data for in ipfobj" }, + { 56, "unrecognised object type for size copy in ipfobj" }, + { 57, "object size too small for size copy in ipfobj" }, + { 58, "mismatching object type for size copy in ipfobj" }, + { 59, "object size mismatch for size copy in ipfobj" }, + { 60, "compat object size mismatch for size copy in ipfobj" }, + { 61, "error doing size copyin of data for in ipfobj" }, + { 62, "bad object type for size copy out ipfobj" }, + { 63, "mismatching object type for size copy out ipfobj" }, + { 64, "object size mismatch for size copy out ipfobj" }, + { 65, "compat object size wrong for size copy out ipfobj" }, + { 66, "error doing size copyout of data for out ipfobj" }, + { 67, "unrecognised object type for copying out ipfobj" }, + { 68, "mismatching object type for copying out ipfobj" }, + { 69, "object size too small for copying out ipfobj" }, + { 70, "object size mismatch for copying out ipfobj" }, + { 71, "compat object size too small for copying out ipfobj" }, + { 72, "compat object size mismatch for copying out ipfobj" }, + { 73, "error doing copyout of data for out ipfobj" }, + { 74, "attempt to add existing tunable name" }, + { 75, "cannot find tunable name to delete" }, + { 76, "internal data too big for next tunable" }, + { 77, "could not find tunable" }, + { 78, "tunable can only be changed when ipfilter disabled" }, + { 79, "new tunable value outside accepted range" }, + { 80, "ipftune called for unrecognised ioctl" }, + { 81, "" }, + { 82, "could not find token to delete" }, + { 83, "" }, + { 84, "attempt to get next rule when no more exist" }, + { 85, "value for iri_inout outside accepted range" }, + { 86, "value for iri_active outside accepted range" }, + { 87, "value for iri_nrules is 0" }, + { 88, "NULL pointer specified for where to copy rule to" }, + { 89, "copyout of rule failed" }, + { 90, "" }, + { 91, "could not get token for rule iteration" }, + { 92, "unrecognised generic iterator" }, + { 93, "could not find token for generic iterator" }, + { 94, "need write permissions to disable/enable ipfilter" }, + { 95, "error copying in enable/disable value" }, + { 96, "need write permissions to set ipf tunable" }, + { 97, "need write permissions to set ipf flags" }, + { 98, "error doing copyin of ipf flags" }, + { 99, "error doing copyout of ipf flags" }, + { 100, "need write permissions to add another rule" }, + { 101, "need write permissions to insert another rule" }, + { 102, "need write permissions to swap active rule set" }, + { 103, "error copying out current active rule set" }, + { 104, "need write permissions to zero ipf stats" }, + { 105, "need write permissions to flush ipf v4 rules" }, + { 106, "error copying out v4 flush results" }, + { 107, "error copying in v4 flush command" }, + { 108, "need write permissions to flush ipf v6 rules" }, + { 109, "error copying out v6 flush results" }, + { 110, "error copying in v6 flush command" }, + { 111, "error copying in new lock state for ipfilter" }, + { 112, "need write permissions to flush ipf logs" }, + { 113, "error copying out results of log flush" }, + { 114, "need write permissions to resync ipf" }, + { 115, "unrecognised ipf ioctl" }, + { 116, "error copying in match array" }, + { 117, "match array type is not IPFOBJ_IPFEXPR" }, + { 118, "bad size for match array" }, + { 119, "cannot allocate memory for match aray" }, + { 120, "error copying in match array" }, + { 121, "error verifying contents of match array" }, + { 122, "need write permissions to set ipf lock status" }, + { 123, "error copying in data for function resolution" }, + { 124, "error copying in ipfobj structure" }, + { 125, "error copying in ipfobj structure" }, + { 126, "error copying in ipfobj structure" }, + { 127, "error copying in ipfobj structure" }, + { 128, "no memory for filter rule comment" }, + { 129, "error copying in filter rule comment" }, + { 130, "error copying out filter rule comment" }, + { 131, "no memory for new rule alloc buffer" }, + { 132, "cannot find source lookup pool" }, + { 133, "unknown source address type" }, + { 134, "cannot find destination lookup pool" }, + { 135, "unknown destination address type" }, + { 136, "icmp head group name index incorrect" }, + { 137, "group head name index incorrect" }, + { 138, "group name index incorrect" }, + { 139, "to interface name index incorrect" }, + { 140, "dup-to interface name index incorrect" }, + { 141, "reply-to interface name index incorrect" }, + { 142, "could not initialise call now function" }, + { 143, "could not initialise call function" }, + { 144, "could not find destination list" }, + { 145, "auth rules cannot have dup/to/fastroute" }, + { 146, "incorrect size for object to copy out" }, + { 147, "object type out of bounds for kernel copyout" }, + { 148, "object size too small for kernel copyout" }, + { 149, "object size validation failed for kernel copyout" }, + { 150, "error copying data out for kernel copyout" }, + { 151, "version mismatch for kernel copyout" }, +/* -------------------------------------------------------------------------- */ + { 10001, "could not find token for auth iterator" }, + { 10002, "write permissions require to add/remove auth rule" }, + { 10003, "need write permissions to set auth lock" }, + { 10004, "error copying out results of auth flush" }, + { 10005, "unknown auth ioctl" }, + { 10006, "can only append or remove preauth rules" }, + { 10007, "NULL pointers passed in for preauth remove" }, + { 10008, "preauth rule not found to remove" }, + { 10009, "could not malloc memory for preauth entry" }, + { 10010, "unrecognised preauth rule ioctl command" }, + { 10011, "iterator data supplied with NULL pointer" }, + { 10012, "unknown auth iterator type" }, + { 10013, "iterator error copying out auth data" }, + { 10014, "sleep waiting for auth packet interrupted" }, + { 10015, "bad index supplied in auth reply" }, + { 10016, "error injecting outbound packet back into kernel" }, + { 10017, "error injecting inbound packet back into kernel" }, + { 10018, "could not attempt to inject packet back into kernel" }, + { 10019, "packet id does not match" }, +/* -------------------------------------------------------------------------- */ + { 20001, "invalid frag token data pointer supplied" }, + { 20002, "error copying out frag token data" }, + { 20003, "can only copy one fragment state entry at a time" }, +/* -------------------------------------------------------------------------- */ + { 30001, "incorrect object size to get hash table stats" }, + { 30002, "could not malloc memory for new hash table" }, + { 30003, "error coping in hash table structure" }, + { 30004, "hash table already exists" }, + { 30005, "mismach between new hash table and operation unit" }, + { 30006, "could not malloc memory for hash table base" }, + { 30007, "could not find hash table" }, + { 30008, "mismatch between hash table and operation unit" }, + { 30009, "could not find hash table for iterators next node" }, + { 30010, "unknown iterator tpe" }, + { 30011, "iterator error copying out hash table" }, + { 30012, "iterator error copying out hash table entry" }, + { 30013, "error copying out hash table statistics" }, + { 30014, "table node delete structure wrong size" }, + { 30015, "error copying in node to delete" }, + { 30016, "table to delete node from does not exist" }, + { 30017, "could not find table to remove node from" }, + { 30018, "table node add structure wrong size" }, + { 30019, "error copying in node to add" }, + { 30020, "could not find table to add node to" }, + { 30021, "node already exists in the table" }, + { 30022, "could not find node to delete in table" }, + { 30023, "uid mismatch on node to delete" }, + { 30024, "object size incorrect for hash table" }, + { 30025, "hash table size must be at least 1"}, + { 30026, "cannot allocate memory for hash table context" }, +/* -------------------------------------------------------------------------- */ + { 40001, "invalid minor device numebr for log read" }, + { 40002, "read size too small" }, + { 40003, "interrupted waiting for log data to read" }, + { 40004, "interrupted waiting for log data to read" }, + { 40005, "read size too large" }, + { 40006, "uiomove for read operation failed" }, +/* -------------------------------------------------------------------------- */ + { 50001, "unknown lookup ioctl" }, + { 50002, "error copying in object data for add node" }, + { 50003, "invalid unit for lookup add node" }, + { 50004, "incorrect size for adding a pool node" }, + { 50005, "error copying in pool node structure" }, + { 50006, "mismatch in pool node address/mask families" }, + { 50007, "could not find pool name" }, + { 50008, "node already exists in pool" }, + { 50009, "incorrect size for adding a hash node" }, + { 50010, "error copying in hash node structure" }, + { 50011, "could not find hash table name" }, + { 50012, "unrecognised object type for lookup add node" }, + { 50013, "invalid unit for lookup delete node" }, + { 50014, "incorrect size for deleting a pool node" }, + { 50015, "error copying in pool node structure" }, + { 50016, "could not find pool name" }, + { 50017, "could not find pool node" }, + { 50018, "incorrect size for removing a hash node" }, + { 50019, "error copying in hash node structure" }, + { 50020, "could not find hash table name" }, + { 50021, "unrecognised object type for lookup delete node" }, + { 50022, "error copying in add table data" }, + { 50023, "invalid unit for lookup add table" }, + { 50024, "pool name already exists" }, + { 50025, "hash table name already exists" }, + { 50026, "unrecognised object type for lookup add table" }, + { 50027, "error copying table data back out" }, + { 50028, "error copying in remove table data" }, + { 50029, "invalid unit for lookup remove table" }, + { 50030, "unrecognised object type for lookup remove table" }, + { 50031, "error copying in lookup stats structure" }, + { 50032, "invalid unit for lookup stats" }, + { 50033, "unrecognised object type for lookup stats" }, + { 50034, "error copying in flush lookup data" }, + { 50035, "invalid unit for lookup flush" }, + { 50036, "incorrect table type for lookup flush" }, + { 50037, "error copying out lookup flush results" }, + { 50038, "invalid unit for lookup iterator" }, + { 50039, "invalid unit for lookup iterator" }, + { 50040, "could not find token for lookup iterator" }, + { 50041, "unrecognised object type for lookup interator" }, + { 50042, "error copying in lookup delete node operation" }, +/* -------------------------------------------------------------------------- */ + { 60001, "insufficient privilege for NAT write operation" }, + { 60002, "need write permissions to flush NAT logs" }, + { 60003, "need write permissions to turn NAT logging on/off" }, + { 60004, "error copying out current NAT log setting" }, + { 60005, "error copying out bytes waiting to be read in NAT \ +log" }, + { 60006, "need write permissions to add NAT rule" }, + { 60007, "NAT rule already exists" }, + { 60008, "could not allocate memory for NAT rule" }, + { 60009, "need write permissions to remove NAT rule" }, + { 60010, "NAT rule could not be found" }, + { 60011, "could not find NAT entry for redirect lookup" }, + { 60012, "need write permissions to flush NAT table" }, + { 60013, "error copying in NAT flush command" }, + { 60014, "need write permissions to do matching NAT flush" }, + { 60015, "need write permissions to set NAT lock" }, + { 60016, "need write permissions to add entry to NAT table" }, + { 60017, "NAT not locked for size retrieval" }, + { 60018, "NAT not locked for fetching NAT table entry" }, + { 60019, "error copying in NAT token data for deletion" }, + { 60020, "unknown NAT ioctl" }, + { 60021, "" }, + { 60022, "resolving proxy name in NAT rule failed" }, + { 60023, "only reply age specified in NAT rule" }, + { 60024, "error doing copyin to determine NAT entry size" }, + { 60025, "error copying out NAT size of 0" }, + { 60026, "NAT entry not found" }, + { 60027, "error doing copyout of NAT entry size" }, + { 60028, "invalid data size for getting NAT entry" }, + { 60029, "could not malloc temporary space for NAT entry" }, + { 60030, "no NAT table entries present" }, + { 60031, "NAT entry to get next from not found" }, + { 60032, "not enough space for proxy structure" }, + { 60033, "not enough space for private proxy data" }, + { 60034, "NAT entry size is too large" }, + { 60035, "could not malloc memory for NAT entry sratch space" }, + { 60036, "" }, + { 60037, "could not malloc memory for NAT entry" }, + { 60038, "could not malloc memory for NAT entry rule" }, + { 60039, "could not resolve NAT entry rule's proxy" }, + { 60040, "cannot add outbound duplicate NAT entry" }, + { 60041, "cannot add inbound duplicate NAT entry" }, + { 60042, "cannot add NAT entry that is neither IN nor OUT" }, + { 60043, "could not malloc memory for NAT proxy data" }, + { 60044, "proxy data size too big" }, + { 60045, "could not malloc proxy private data for NAT entry" }, + { 60046, "could not malloc memory for new NAT filter rule" }, + { 60047, "could not find existing filter rule for NAT entry" }, + { 60048, "insertion into NAT table failed" }, + { 60049, "iterator error copying out hostmap data" }, + { 60050, "iterator error copying out NAT rule data" }, + { 60051, "iterator error copying out NAT entry data" }, + { 60052, "iterator data supplied with NULL pointer" }, + { 60053, "unknown NAT iterator type" }, + { 60054, "unknwon next address type" }, + { 60055, "iterator suppled with unknown type for get-next" }, + { 60056, "unknown lookup group for next address" }, + { 60057, "error copying out NAT log flush results" }, + { 60058, "bucket table type is incorrect" }, + { 60059, "error copying out NAT bucket table" }, + { 60060, "function not found for lookup" }, + { 60061, "address family not supported with SIOCSTPUT" }, + { 60062, "unknown timeout name" }, + { 60063, "cannot allocate new inbound NAT entry table" }, + { 60064, "cannot allocate new outbound NAT entry table" }, + { 60065, "cannot allocate new inbound NAT bucketlen table" }, + { 60066, "cannot allocate new outbound NAT bucketlen table" }, + { 60067, "cannot allocate new NAT rules table" }, + { 60068, "cannot allocate new NAT hostmap table" }, + { 60069, "new source lookup type is not dstlist" }, + { 60070, "cannot allocate NAT rule scratch space" }, + { 60071, "new destination lookup type is not dstlist" }, + { 60072, "function not found for lookup (ipv6)" }, + { 60073, "unknown lookup group for next address (ipv6)" }, + { 60074, "unknown next address type (ipv6)" }, + { 60075, "one object at a time must be copied" }, +/* -------------------------------------------------------------------------- */ + { 70001, "incorrect object size to get pool stats" }, + { 70002, "could not malloc memory for new pool node" }, + { 70003, "invalid addresss length for new pool node" }, + { 70004, "invalid mask length for new pool node" }, + { 70005, "error adding node to pool" }, + { 70006, "pool already exists" }, + { 70007, "could not malloc memory for new pool" }, + { 70008, "could not allocate radix tree for new pool" }, + { 70009, "could not find pool" }, + { 70010, "unknown pool name for iteration" }, + { 70011, "unknown pool iterator" }, + { 70012, "error copying out pool head" }, + { 70013, "error copying out pool node" }, + { 70014, "add node size incorrect" }, + { 70015, "error copying in pool node" }, + { 70016, "" }, + { 70017, "cannot find pool for node" }, + { 70018, "node entry already present in pool" }, + { 70019, "delete node size incorrect" }, + { 70020, "error copying in node to delete" }, + { 70021, "cannot find pool to delete node from" }, + { 70022, "cannot find node to delete in pool" }, + { 70023, "pool name already exists" }, + { 70024, "uid mismatch for node removal" }, + { 70025, "stats device unit is invalid" }, + { 70026, "error copying out statistics" }, + { 70027, "could not remove node from radix tree" }, + { 70028, "incorrect address length in pool node add" }, + { 70029, "incorrect mask length in pool node add" }, + { 70030, "incorrect address length in pool node remove" }, + { 70031, "incorrect mask length in pool node remove" }, + { 70032, "cannot allocate memory for pool context" }, + { 70033, "cannot allocate memory for radix tree context" }, + { 70034, "adding IPv6 node with incorrect address length" }, + { 70035, "IPv4 address not masked" }, + { 70036, "IPv6 address not masked" }, + { 70037, "removing IPv6 node with incorrect address length" }, +/* -------------------------------------------------------------------------- */ + { 80001, "could not find proxy" }, + { 80002, "proxy does not support control operations" }, + { 80003, "could not allocate data to hold proxy operation" }, + { 80004, "unknown proxy ioctl" }, + { 80005, "could not copyin proxy control structure" }, + { 80006, "DNS proxy could not find rule to delete" }, + { 80007, "DNS proxy found existing matching rule" }, + { 80008, "DNS proxy could not allocate memory for new rule" }, + { 80009, "DNS proxy unknown command request" }, +/* -------------------------------------------------------------------------- */ + { 90001, "could not malloc space for new scan structure" }, + { 90002, "scan tag already exists" }, + { 90003, "scan structure in use" }, + { 90004, "could not find matching scan tag for filter rule" }, + { 90005, "could not copyout scan statistics" }, +/* -------------------------------------------------------------------------- */ + { 100001, "cannot find matching state entry to remove" }, + { 100002, "error copying in v4 state flush command" }, + { 100003, "error copying out v4 state flush results" }, + { 100004, "error copying in v6 state flush command" }, + { 100005, "error copying out v6 state flush results" }, + { 100006, "" }, + { 100007, "" }, + { 100008, "need write permissions to flush state log" }, + { 100009, "erorr copyout results of flushing state log" }, + { 100010, "need write permissions to turn state logging on/off" }, + { 100011, "error copying in new state logging state" }, + { 100012, "error copying out current state logging state" }, + { 100013, "error copying out bytes waiting to be read in state \ +log" }, + { 100014, "need write permissions to set state lock" }, + { 100015, "need write permissions to add entry to state table" }, + { 100016, "state not locked for size retrieval" }, + { 100017, "error copying out hash table bucket lengths" }, + { 100018, "could not find token for state iterator" }, + { 100019, "error copying in state token data for deletion" }, + { 100020, "unknown state ioctl" }, + { 100021, "no state table entries present" }, + { 100022, "state entry to get next from not found" }, + { 100023, "could not malloc memory for state entry" }, + { 100024, "could not malloc memory for state entry rule" }, + { 100025, "could not copy back state entry to user space" }, + { 100026, "iterator data supplied with NULL pointer" }, + { 100027, "iterator supplied with 0 item count" }, + { 100028, "iterator type is incorrect" }, + { 100029, "invalid state token data pointer supplied" }, + { 100030, "error copying out next state entry" }, + { 100031, "unrecognised table request" }, + { 100032, "error copying out bucket length data" }, + { 100033, "could not find existing filter rule for state entry" }, + { 100034, "could not find timeout name" }, + { 100035, "could not allocate new state table" }, + { 100036, "could not allocate new state bucket length table" }, +/* -------------------------------------------------------------------------- */ + { 110001, "sync write header magic number is incorrect" }, + { 110002, "sync write header protocol is incorrect" }, + { 110003, "sync write header command is incorrect" }, + { 110004, "sync write header table number is incorrect" }, + { 110005, "data structure too small for sync write operation" }, + { 110006, "zero length data with sync write header" }, + { 110007, "insufficient data for sync write" }, + { 110008, "bad sync read size" }, + { 110009, "interrupted sync read (solaris)" }, + { 110010, "interrupted sync read (hpux)" }, + { 110011, "interrupted sync read (osf)" }, + { 110012, "interrupted sync read" }, + { 110013, "could not malloc memory for sync'd state" }, + { 110014, "could not malloc memory for sync-state list item" }, + { 110015, "sync update could not find state" }, + { 110016, "unrecognised sync state command" }, + { 110017, "could not malloc memory for new sync'd NAT entry" }, + { 110018, "could not malloc memory for sync-NAT list item" }, + { 110019, "sync update could not find NAT entry" }, + { 110020, "unrecognised sync NAT command" }, + { 110021, "ioctls are not handled with sync" }, +/* -------------------------------------------------------------------------- */ + { 120001, "null data pointer for iterator" }, + { 120002, "unit outside of acceptable range" }, + { 120003, "unknown iterator subtype" }, + { 120004, "cannot find dest. list for iteration" }, + { 120005, "error copying out destination iteration list" }, + { 120006, "error copying out destination iteration node" }, + { 120007, "wrong size for frdest_t structure" }, + { 120008, "cannot allocate memory for new destination node" }, + { 120009, "error copying in destination node to add" }, + { 120010, "could not find destination list to add node to" }, + { 120011, "error copying in destination node to remove" }, + { 120012, "could not find dest. list to remove node from" }, + { 120013, "destination list already exists" }, + { 120014, "could not allocate new destination table" }, + { 120015, "could not find destination list to remove" }, + { 120016, "destination list cannot be removed - it is busy" }, + { 120017, "error copying in names for destination" }, + { 120018, "destination name is too long/short" }, + { 120019, "unrecognised address family in destination" }, + { 120020, "" }, + { 120021, "error copying in new destination table" }, + { 120022, "cannot allocate memory for node table" }, + { 120023, "stats object size is incorrect for dest. lists" }, + { 120024, "stats device unit is invalid for dest. lists" }, + { 120025, "error copying out dest. list statistics" }, + { 120026, "cannot allocate memory for destination node" }, + { 120027, "error copying in destination node" }, + { 120028, "cannot allocate memory for destination context " }, +/* -------------------------------------------------------------------------- */ + { 130001, "ioctl denied by system security level" }, + { 130002, "ioctl operation on invalid minor device" }, + { 130003, "ioctl on device denied, ipfitler is disabled" }, + { 130004, "ioctl command not allowed when disabled" }, + { 130005, "ioctl denied due to insufficient authorisation" }, + { 130006, "cannot read while ipfilter is disabled" }, + { 130007, "read on minor device not supported" }, + { 130008, "cannot write while ipfilter is disabled" }, + { 130009, "write on minor device not supported" }, + { 130010, "poll on minor device is not supported" }, + { 130011, "error removing IPv4 filter hooks" }, + { 130012, "error removing IPv6 filter hooks" }, + { 130013, "attaching IPv4 hook failed" }, + { 130014, "attaching IPv6 hook failed" }, + { 130015, "ipf_init_all failed" }, + { 130016, "finding pfil head failed" }, + { 130017, "ipfilter is already initialised and running" }, +}; + + +static ipf_error_entry_t * +find_error(errnum) + int errnum; +{ + ipf_error_entry_t *ie; + + int l = -1, r = IPF_NUM_ERRORS + 1, step; + step = (r - l) / 2;; + + while (step != 0) { + ie = ipf_errors + l + step; + if (ie->iee_number == errnum) + return ie; + step = l + step; + if (ie->iee_number > errnum) + r = step; + else + l = step; + step = (r - l) / 2;; + } + + return NULL; +} + +char * +ipf_geterror(fd, func) + int fd; + ioctlfunc_t *func; +{ + static char text[80]; + ipf_error_entry_t *ie; + int errnum; + + if ((*func)(fd, SIOCIPFINTERROR, &errnum) == 0) { + + ie = find_error(errnum); + if (ie != NULL) + return ie->iee_text; + sprintf(text, "unknown error %d", errnum); + } else { + sprintf(text, "retrieving error number failed (%d)", errno); + } + return text; +} + + +char * +ipf_strerror(errnum) + int errnum; +{ + static char text[80]; + ipf_error_entry_t *ie; + + + ie = find_error(errnum); + if (ie != NULL) + return ie->iee_text; + + sprintf(text, "unknown error %d", errnum); + return text; +} diff --git a/contrib/ipfilter/lib/ionames.c b/contrib/ipfilter/lib/ionames.c new file mode 100644 index 0000000..9b58642 --- /dev/null +++ b/contrib/ipfilter/lib/ionames.c @@ -0,0 +1,41 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + + +struct ipopt_names ionames[] ={ + { IPOPT_NOP, 0x000001, 1, "nop" }, /* RFC791 */ + { IPOPT_RR, 0x000002, 8, "rr" }, /* 1 route */ + { IPOPT_ZSU, 0x000004, 4, "zsu" }, /* size ?? */ + { IPOPT_MTUP, 0x000008, 4, "mtup" }, /* RFC1191 */ + { IPOPT_MTUR, 0x000010, 4, "mtur" }, /* RFC1191 */ + { IPOPT_ENCODE, 0x000020, 4, "encode" }, /* size ?? */ + { IPOPT_TS, 0x000040, 8, "ts" }, /* 1 TS */ + { IPOPT_TR, 0x000080, 4, "tr" }, /* RFC1393 */ + { IPOPT_SECURITY,0x000100, 12, "sec" }, /* RFC1108 */ + { IPOPT_SECURITY,0x000100, 12, "sec-class" }, /* RFC1108 */ + { IPOPT_LSRR, 0x000200, 8, "lsrr" }, /* 1 route */ + { IPOPT_E_SEC, 0x000400, 8, "e-sec" }, /* RFC1108 */ + { IPOPT_CIPSO, 0x000800, 8, "cipso" }, /* size ?? */ + { IPOPT_SATID, 0x001000, 4, "satid" }, /* RFC791 */ + { IPOPT_SSRR, 0x002000, 8, "ssrr" }, /* 1 route */ + { IPOPT_ADDEXT, 0x004000, 4, "addext" }, /* IPv7 ?? */ + { IPOPT_VISA, 0x008000, 4, "visa" }, /* size ?? */ + { IPOPT_IMITD, 0x010000, 4, "imitd" }, /* size ?? */ + { IPOPT_EIP, 0x020000, 4, "eip" }, /* RFC1385 */ + { IPOPT_FINN, 0x040000, 4, "finn" }, /* size ?? */ + { IPOPT_DPS, 0x080000, 4, "dps" }, /* size ?? */ + { IPOPT_SDB, 0x100000, 4, "sdb" }, /* size ?? */ + { IPOPT_NSAPA, 0x200000, 4, "nsapa" }, /* size ?? */ + { IPOPT_RTRALRT,0x400000, 4, "rtralrt" }, /* RFC2113 */ + { IPOPT_UMP, 0x800000, 4, "ump" }, /* size ?? */ + { IPOPT_AH, 0x1000000, 0, "ah" }, /* IPPROTO_AH */ + { 0, 0, 0, (char *)NULL } /* must be last */ +}; diff --git a/contrib/ipfilter/lib/ipf_dotuning.c b/contrib/ipfilter/lib/ipf_dotuning.c new file mode 100644 index 0000000..b0ac8b4 --- /dev/null +++ b/contrib/ipfilter/lib/ipf_dotuning.c @@ -0,0 +1,74 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" +#include "netinet/ipl.h" +#include <sys/ioctl.h> + +void ipf_dotuning(fd, tuneargs, iocfn) + int fd; + char *tuneargs; + ioctlfunc_t iocfn; +{ + ipfobj_t obj; + ipftune_t tu; + char *s, *t; + + bzero((char *)&tu, sizeof(tu)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(tu);; + obj.ipfo_ptr = (void *)&tu; + obj.ipfo_type = IPFOBJ_TUNEABLE; + + for (s = strtok(tuneargs, ","); s != NULL; s = strtok(NULL, ",")) { + if (!strcmp(s, "list")) { + while (1) { + if ((*iocfn)(fd, SIOCIPFGETNEXT, &obj) == -1) { + ipf_perror_fd(fd, iocfn, + "ioctl(SIOCIPFGETNEXT)"); + break; + } + if (tu.ipft_cookie == NULL) + break; + + tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; + printtunable(&tu); + } + } else if ((t = strchr(s, '=')) != NULL) { + tu.ipft_cookie = NULL; + *t++ = '\0'; + strncpy(tu.ipft_name, s, sizeof(tu.ipft_name)); + if (sscanf(t, "%lu", &tu.ipft_vlong) == 1) { + if ((*iocfn)(fd, SIOCIPFSET, &obj) == -1) { + ipf_perror_fd(fd, iocfn, + "ioctl(SIOCIPFSET)"); + return; + } + } else { + fprintf(stderr, "invalid value '%s'\n", s); + return; + } + } else { + tu.ipft_cookie = NULL; + strncpy(tu.ipft_name, s, sizeof(tu.ipft_name)); + if ((*iocfn)(fd, SIOCIPFGET, &obj) == -1) { + ipf_perror_fd(fd, iocfn, "ioctl(SIOCIPFGET)"); + return; + } + if (tu.ipft_cookie == NULL) { + fprintf(stderr, "Null cookie for %s\n", s); + return; + } + + tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; + printtunable(&tu); + } + } +} diff --git a/contrib/ipfilter/lib/ipf_perror.c b/contrib/ipfilter/lib/ipf_perror.c new file mode 100644 index 0000000..85a1b1d --- /dev/null +++ b/contrib/ipfilter/lib/ipf_perror.c @@ -0,0 +1,47 @@ +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" + +void +ipf_perror(err, string) + int err; + char *string; +{ + if (err == 0) + fprintf(stderr, "%s\n", string); + else + fprintf(stderr, "%s %s\n", string, ipf_strerror(err)); +} + +int +ipf_perror_fd(fd, iocfunc, string) + int fd; + ioctlfunc_t iocfunc; + char *string; +{ + int save; + int realerr; + + save = errno; + if ((*iocfunc)(fd, SIOCIPFINTERROR, &realerr) == -1) + realerr = 0; + + errno = save; + fprintf(stderr, "%d:", realerr); + ipf_perror(realerr, string); + return realerr ? realerr : save; + +} + +void +ipferror(fd, msg) + int fd; + char *msg; +{ + if (fd >= 0) { + ipf_perror_fd(fd, ioctl, msg); + } else { + fprintf(stderr, "0:"); + perror(msg); + } +} diff --git a/contrib/ipfilter/lib/ipft_hx.c b/contrib/ipfilter/lib/ipft_hx.c new file mode 100644 index 0000000..15002ea --- /dev/null +++ b/contrib/ipfilter/lib/ipft_hx.c @@ -0,0 +1,185 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ipft_hx.c 1.1 3/9/96 (C) 1996 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#include <ctype.h> + +#include "ipf.h" +#include "ipt.h" + + +extern int opts; + +static int hex_open __P((char *)); +static int hex_close __P((void)); +static int hex_readip __P((mb_t *, char **, int *)); +static char *readhex __P((char *, char *)); + +struct ipread iphex = { hex_open, hex_close, hex_readip, 0 }; +static FILE *tfp = NULL; +static int tfd = -1; + +static int hex_open(fname) + char *fname; +{ + if (tfp && tfd != -1) { + rewind(tfp); + return tfd; + } + + if (!strcmp(fname, "-")) { + tfd = 0; + tfp = stdin; + } else { + tfd = open(fname, O_RDONLY); + if (tfd != -1) + tfp = fdopen(tfd, "r"); + } + return tfd; +} + + +static int hex_close() +{ + int cfd = tfd; + + tfd = -1; + return close(cfd); +} + + +static int hex_readip(mb, ifn, dir) + mb_t *mb; + char **ifn; + int *dir; +{ + register char *s, *t, *u; + char line[513]; + ip_t *ip; + char *buf; + int cnt; + + buf = (char *)mb->mb_buf; + cnt = sizeof(mb->mb_buf); + /* + * interpret start of line as possibly "[ifname]" or + * "[in/out,ifname]". + */ + if (ifn) + *ifn = NULL; + if (dir) + *dir = 0; + ip = (ip_t *)buf; + while (fgets(line, sizeof(line)-1, tfp)) { + if ((s = strchr(line, '\n'))) { + if (s == line) { + mb->mb_len = (char *)ip - buf; + return mb->mb_len; + } + *s = '\0'; + } + if ((s = strchr(line, '#'))) + *s = '\0'; + if (!*line) + continue; + if ((opts & OPT_DEBUG) != 0) { + printf("input: %s", line); + } + + if ((*line == '[') && (s = strchr(line, ']'))) { + t = line + 1; + if (s - t > 0) { + *s++ = '\0'; + if ((u = strchr(t, ',')) && (u < s)) { + u++; + if (ifn) + *ifn = strdup(u); + if (dir) { + if (*t == 'i') + *dir = 0; + else if (*t == 'o') + *dir = 1; + } + } else if (ifn) + *ifn = t; + } + + while (*s++ == '+') { + if (!strncasecmp(s, "mcast", 5)) { + mb->mb_flags |= M_MCAST; + s += 5; + } + if (!strncasecmp(s, "bcast", 5)) { + mb->mb_flags |= M_BCAST; + s += 5; + } + if (!strncasecmp(s, "mbcast", 6)) { + mb->mb_flags |= M_MBCAST; + s += 6; + } + } + while (ISSPACE(*s)) + s++; + } else + s = line; + t = (char *)ip; + ip = (ip_t *)readhex(s, (char *)ip); + if ((opts & OPT_DEBUG) != 0) { + if (opts & OPT_ASCII) { + int c = *t; + if (t < (char *)ip) + putchar('\t'); + while (t < (char *)ip) { + if (isprint(c) && isascii(c)) + putchar(c); + else + putchar('.'); + t++; + } + } + putchar('\n'); + fflush(stdout); + } + } + if (feof(tfp)) + return 0; + return -1; +} + + +static char *readhex(src, dst) +register char *src, *dst; +{ + int state = 0; + char c; + + while ((c = *src++)) { + if (ISSPACE(c)) { + if (state) { + dst++; + state = 0; + } + continue; + } else if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F')) { + c = ISDIGIT(c) ? (c - '0') : (TOUPPER(c) - 55); + if (state == 0) { + *dst = (c << 4); + state++; + } else { + *dst++ |= c; + state = 0; + } + } else + break; + } + return dst; +} diff --git a/contrib/ipfilter/lib/ipft_pc.c b/contrib/ipfilter/lib/ipft_pc.c new file mode 100644 index 0000000..3a264bd --- /dev/null +++ b/contrib/ipfilter/lib/ipft_pc.c @@ -0,0 +1,254 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" +#include "ipt.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + +struct llc { + int lc_type; + int lc_sz; /* LLC header length */ + int lc_to; /* LLC Type offset */ + int lc_tl; /* LLC Type length */ +}; + +/* + * While many of these maybe the same, some do have different header formats + * which make this useful. + */ + +static struct llc llcs[] = { + { 0, 0, 0, 0 }, /* DLT_NULL */ + { 1, 14, 12, 2 }, /* DLT_Ethernet */ + { 10, 0, 0, 0 }, /* DLT_FDDI */ + { 12, 0, 0, 0 }, /* DLT_RAW */ + { -1, -1, -1, -1 } +}; + +typedef struct { + u_int id; + u_short major; + u_short minor; + u_int timezone; + u_int sigfigs; + u_int snaplen; + u_int type; +} fileheader_t; + +typedef struct { + u_32_t seconds; + u_32_t microseconds; + u_32_t caplen; + u_32_t wirelen; +} packetheader_t; + +static int ipcap_open __P((char *)); +static int ipcap_close __P((void)); +static int ipcap_readip __P((mb_t *, char **, int *)); +static int ipcap_read_rec __P((packetheader_t *)); +static void iswap_hdr __P((fileheader_t *)); + +static int pfd = -1, swapped = 0; +static struct llc *llcp = NULL; + +struct ipread pcap = { ipcap_open, ipcap_close, ipcap_readip, 0 }; + +#define SWAPLONG(y) \ + ((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff)) +#define SWAPSHORT(y) \ + ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) ) + +static void iswap_hdr(p) + fileheader_t *p; +{ + p->major = SWAPSHORT(p->major); + p->minor = SWAPSHORT(p->minor); + p->timezone = SWAPLONG(p->timezone); + p->sigfigs = SWAPLONG(p->sigfigs); + p->snaplen = SWAPLONG(p->snaplen); + p->type = SWAPLONG(p->type); +} + +static int ipcap_open(fname) + char *fname; +{ + fileheader_t ph; + int fd, i; + + if (pfd != -1) + return pfd; + + if (!strcmp(fname, "-")) + fd = 0; + else if ((fd = open(fname, O_RDONLY)) == -1) + return -1; + + if (read(fd, (char *)&ph, sizeof(ph)) != sizeof(ph)) + return -2; + + if (ph.id != 0xa1b2c3d4) { + if (SWAPLONG(ph.id) != 0xa1b2c3d4) { + (void) close(fd); + return -2; + } + swapped = 1; + iswap_hdr(&ph); + } + + for (i = 0; llcs[i].lc_type != -1; i++) + if (llcs[i].lc_type == ph.type) { + llcp = llcs + i; + break; + } + + if (llcp == NULL) { + (void) close(fd); + return -2; + } + + pfd = fd; + printf("opened pcap file %s:\n", fname); + printf("\tid: %08x version: %d.%d type: %d snap %d\n", + ph.id, ph.major, ph.minor, ph.type, ph.snaplen); + + return fd; +} + + +static int ipcap_close() +{ + return close(pfd); +} + + +/* + * read in the header (and validate) which should be the first record + * in a pcap file. + */ +static int ipcap_read_rec(rec) + packetheader_t *rec; +{ + int n, p, i; + char *s; + + s = (char *)rec; + n = sizeof(*rec); + + while (n > 0) { + i = read(pfd, (char *)rec, sizeof(*rec)); + if (i <= 0) + return -2; + s += i; + n -= i; + } + + if (swapped) { + rec->caplen = SWAPLONG(rec->caplen); + rec->wirelen = SWAPLONG(rec->wirelen); + rec->seconds = SWAPLONG(rec->seconds); + rec->microseconds = SWAPLONG(rec->microseconds); + } + p = rec->caplen; + n = MIN(p, rec->wirelen); + if (!n || n < 0) + return -3; + + if (p < 0 || p > 65536) + return -4; + return p; +} + + +#ifdef notyet +/* + * read an entire pcap packet record. only the data part is copied into + * the available buffer, with the number of bytes copied returned. + */ +static int ipcap_read(buf, cnt) + char *buf; + int cnt; +{ + packetheader_t rec; + static char *bufp = NULL; + int i, n; + + if ((i = ipcap_read_rec(&rec)) <= 0) + return i; + + if (!bufp) + bufp = malloc(i); + else + bufp = realloc(bufp, i); + + if (read(pfd, bufp, i) != i) + return -2; + + n = MIN(i, cnt); + bcopy(bufp, buf, n); + return n; +} +#endif + + +/* + * return only an IP packet read into buf + */ +static int ipcap_readip(mb, ifn, dir) + mb_t *mb; + char **ifn; + int *dir; +{ + static char *bufp = NULL; + packetheader_t rec; + struct llc *l; + char *s, ty[4]; + int i, j, n; + char *buf; + int cnt; + +#if 0 + ifn = ifn; /* gcc -Wextra */ + dir = dir; /* gcc -Wextra */ +#endif + buf = (char *)mb->mb_buf; + cnt = sizeof(mb->mb_buf); + l = llcp; + + /* do { */ + if ((i = ipcap_read_rec(&rec)) <= 0) + return i; + + if (!bufp) + bufp = malloc(i); + else + bufp = realloc(bufp, i); + s = bufp; + + for (j = i, n = 0; j > 0; ) { + n = read(pfd, s, j); + if (n <= 0) + return -2; + j -= n; + s += n; + } + s = bufp; + + i -= l->lc_sz; + s += l->lc_to; + bcopy(s, ty, l->lc_tl); + s += l->lc_tl; + /* } while (ty[0] != 0x8 && ty[1] != 0); */ + n = MIN(i, cnt); + bcopy(s, buf, n); + mb->mb_len = n; + return n; +} diff --git a/contrib/ipfilter/lib/ipft_tx.c b/contrib/ipfilter/lib/ipft_tx.c new file mode 100644 index 0000000..a996c5b --- /dev/null +++ b/contrib/ipfilter/lib/ipft_tx.c @@ -0,0 +1,510 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#include <ctype.h> + +#include "ipf.h" +#include "ipt.h" + +extern int opts; + +static char *tx_proto = ""; + +static int text_open __P((char *)), text_close __P((void)); +static int text_readip __P((mb_t *, char **, int *)); +static int parseline __P((char *, ip_t *, char **, int *)); + +static char myflagset[] = "FSRPAUEC"; +static u_char myflags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, + TH_ACK, TH_URG, TH_ECN, TH_CWR }; + +struct ipread iptext = { text_open, text_close, text_readip, R_DO_CKSUM }; +static FILE *tfp = NULL; +static int tfd = -1; + +static u_32_t tx_hostnum __P((char *, int *)); +static u_short tx_portnum __P((char *)); + +#ifdef USE_INET6 +int parseipv6 __P((char **, ip6_t *, char **, int *)); +#endif + +/* + * returns an ip address as a long var as a result of either a DNS lookup or + * straight inet_addr() call + */ +static u_32_t tx_hostnum(host, resolved) + char *host; + int *resolved; +{ + i6addr_t ipa; + + *resolved = 0; + if (!strcasecmp("any", host)) + return 0L; + if (ISDIGIT(*host)) + return inet_addr(host); + + if (gethost(AF_INET, host, &ipa) == -1) { + *resolved = -1; + fprintf(stderr, "can't resolve hostname: %s\n", host); + return 0; + } + return ipa.in4.s_addr; +} + + +/* + * find the port number given by the name, either from getservbyname() or + * straight atoi() + */ +static u_short tx_portnum(name) + char *name; +{ + struct servent *sp; + + if (ISDIGIT(*name)) + return (u_short)atoi(name); + sp = getservbyname(name, tx_proto); + if (sp) + return ntohs(sp->s_port); + (void) fprintf(stderr, "unknown service \"%s\".\n", name); + return 0; +} + + +static int text_open(fname) + char *fname; +{ + if (tfp && tfd != -1) { + rewind(tfp); + return tfd; + } + + if (!strcmp(fname, "-")) { + tfd = 0; + tfp = stdin; + } else { + tfd = open(fname, O_RDONLY); + if (tfd != -1) + tfp = fdopen(tfd, "r"); + } + return tfd; +} + + +static int text_close() +{ + int cfd = tfd; + + tfd = -1; + return close(cfd); +} + + +static int text_readip(mb, ifn, dir) + mb_t *mb; + char **ifn; + int *dir; +{ + register char *s; + char line[513]; + ip_t *ip; + char *buf; + int cnt; + + buf = (char *)mb->mb_buf; + cnt = sizeof(mb->mb_buf); + + *ifn = NULL; + while (fgets(line, sizeof(line)-1, tfp)) { + if ((s = strchr(line, '\n'))) + *s = '\0'; + if ((s = strchr(line, '\r'))) + *s = '\0'; + if ((s = strchr(line, '#'))) + *s = '\0'; + if (!*line) + continue; + if ((opts & OPT_DEBUG) != 0) + printf("input: %s\n", line); + *ifn = NULL; + *dir = 0; + if (!parseline(line, (ip_t *)buf, ifn, dir)) { + ip = (ip_t *)buf; + if (IP_V(ip) == 6) { +#ifdef USE_INET6 + mb->mb_len = ntohs(((ip6_t *)ip)->ip6_plen) + + sizeof(ip6_t); +#else + mb->mb_len = 0; +#endif + } else { + mb->mb_len = ntohs(ip->ip_len); + } + return mb->mb_len; + } + } + if (feof(tfp)) + return 0; + return -1; +} + +static int parseline(line, ip, ifn, out) + char *line; + ip_t *ip; + char **ifn; + int *out; +{ + tcphdr_t th, *tcp = &th; + struct icmp icmp, *ic = &icmp; + char *cps[20], **cpp, c, ipopts[68]; + int i, r; + + if (*ifn) + free(*ifn); + bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip)); + bzero((char *)tcp, sizeof(*tcp)); + bzero((char *)ic, sizeof(*ic)); + bzero(ipopts, sizeof(ipopts)); + IP_HL_A(ip, sizeof(*ip) >> 2); + IP_V_A(ip, IPVERSION); + ip->ip_ttl = 63; + for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && i < 19; ) + cps[++i] = strtok(NULL, " \b\t\r\n"); + + cpp = cps; + if (!*cpp) + return 1; + + c = **cpp; + if (!ISALPHA(c) || (TOLOWER(c) != 'o' && TOLOWER(c) != 'i')) { + fprintf(stderr, "bad direction \"%s\"\n", *cpp); + return 1; + } + +#ifdef USE_INET6 + if (!strcasecmp(*cpp, "out6") || !strcasecmp(*cpp, "in6")) { + return parseipv6(cpp, (ip6_t *)ip, ifn, out); + } +#endif + + *out = (TOLOWER(c) == 'o') ? 1 : 0; + cpp++; + if (!*cpp) + return 1; + + if (!strcasecmp(*cpp, "on")) { + cpp++; + if (!*cpp) + return 1; + *ifn = strdup(*cpp++); + if (!*cpp) + return 1; + } + + c = **cpp; + ip->ip_len = sizeof(ip_t); + if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") || + !strcasecmp(*cpp, "icmp")) { + if (c == 't') { + ip->ip_p = IPPROTO_TCP; + ip->ip_len += sizeof(struct tcphdr); + tx_proto = "tcp"; + } else if (c == 'u') { + ip->ip_p = IPPROTO_UDP; + ip->ip_len += sizeof(struct udphdr); + tx_proto = "udp"; + } else { + ip->ip_p = IPPROTO_ICMP; + ip->ip_len += ICMPERR_IPICMPHLEN; + tx_proto = "icmp"; + } + cpp++; + } else if (ISDIGIT(**cpp) && !index(*cpp, '.')) { + ip->ip_p = atoi(*cpp); + cpp++; + } else + ip->ip_p = IPPROTO_IP; + + if (!*cpp) + return 1; + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { + char *last; + + last = strchr(*cpp, ','); + if (!last) { + fprintf(stderr, "tcp/udp with no source port\n"); + return 1; + } + *last++ = '\0'; + tcp->th_sport = htons(tx_portnum(last)); + if (ip->ip_p == IPPROTO_TCP) { + tcp->th_win = htons(4096); + TCP_OFF_A(tcp, sizeof(*tcp) >> 2); + } + } + ip->ip_src.s_addr = tx_hostnum(*cpp, &r); + cpp++; + if (!*cpp) + return 1; + + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) { + char *last; + + last = strchr(*cpp, ','); + if (!last) { + fprintf(stderr, "tcp/udp with no destination port\n"); + return 1; + } + *last++ = '\0'; + tcp->th_dport = htons(tx_portnum(last)); + } + ip->ip_dst.s_addr = tx_hostnum(*cpp, &r); + cpp++; + if (ip->ip_p == IPPROTO_TCP) { + if (*cpp != NULL) { + char *s, *t; + + tcp->th_flags = 0; + for (s = *cpp; *s; s++) + if ((t = strchr(myflagset, *s))) + tcp->th_flags |= myflags[t-myflagset]; + if (tcp->th_flags) + cpp++; + } + + if (tcp->th_flags & TH_URG) + tcp->th_urp = htons(1); + + if (*cpp && !strncasecmp(*cpp, "seq=", 4)) { + tcp->th_seq = htonl(atoi(*cpp + 4)); + cpp++; + } + + if (*cpp && !strncasecmp(*cpp, "ack=", 4)) { + tcp->th_ack = htonl(atoi(*cpp + 4)); + cpp++; + } + } else if (*cpp && ip->ip_p == IPPROTO_ICMP) { + char *t; + + t = strchr(*cpp, ','); + if (t != NULL) + *t = '\0'; + + ic->icmp_type = geticmptype(AF_INET, *cpp); + if (t != NULL) + ic->icmp_code = atoi(t + 1); + cpp++; + + if (ic->icmp_type == ICMP_ECHO || + ic->icmp_type == ICMP_ECHOREPLY) + ic->icmp_id = htons(getpid()); + if (t != NULL) + *t = ','; + } + + if (*cpp && !strcasecmp(*cpp, "opt")) { + u_long olen; + + cpp++; + olen = buildopts(*cpp, ipopts, (IP_HL(ip) - 5) << 2); + if (olen) { + bcopy(ipopts, (char *)(ip + 1), olen); + IP_HL_A(ip, IP_HL(ip) + (olen >> 2)); + ip->ip_len += olen; + } + } + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + bcopy((char *)tcp, ((char *)ip) + (IP_HL(ip) << 2), + sizeof(*tcp)); + else if (ip->ip_p == IPPROTO_ICMP) + bcopy((char *)ic, ((char *)ip) + (IP_HL(ip) << 2), + sizeof(*ic)); + ip->ip_len = htons(ip->ip_len); + return 0; +} + + +#ifdef USE_INET6 +int parseipv6(cpp, ip6, ifn, out) + char **cpp; + ip6_t *ip6; + char **ifn; + int *out; +{ + tcphdr_t th, *tcp = &th; + struct icmp6_hdr icmp, *ic6 = &icmp; + + bzero((char *)ip6, MAX(sizeof(*tcp), sizeof(*ic6)) + sizeof(*ip6)); + bzero((char *)tcp, sizeof(*tcp)); + bzero((char *)ic6, sizeof(*ic6)); + ip6->ip6_vfc = 0x60; + + *out = (**cpp == 'o') ? 1 : 0; + cpp++; + if (!*cpp) + return 1; + + if (!strcasecmp(*cpp, "on")) { + cpp++; + if (!*cpp) + return 1; + *ifn = strdup(*cpp++); + if (!*cpp) + return 1; + } + + if (!strcasecmp(*cpp, "tcp")) { + ip6->ip6_nxt = IPPROTO_TCP; + tx_proto = "tcp"; + cpp++; + } else if (!strcasecmp(*cpp, "udp")) { + ip6->ip6_nxt = IPPROTO_UDP; + tx_proto = "udp"; + cpp++; + } else if (!strcasecmp(*cpp, "icmpv6")) { + ip6->ip6_nxt = IPPROTO_ICMPV6; + tx_proto = "icmpv6"; + cpp++; + } else if (ISDIGIT(**cpp) && !index(*cpp, ':')) { + ip6->ip6_nxt = atoi(*cpp); + cpp++; + } else + ip6->ip6_nxt = IPPROTO_IPV6; + + if (!*cpp) + return 1; + + switch (ip6->ip6_nxt) + { + case IPPROTO_TCP : + ip6->ip6_plen = sizeof(struct tcphdr); + break; + case IPPROTO_UDP : + ip6->ip6_plen = sizeof(struct udphdr); + break; + case IPPROTO_ICMPV6 : + ip6->ip6_plen = ICMP6ERR_IPICMPHLEN; + break; + default : + break; + } + + if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) { + char *last; + + last = strchr(*cpp, ','); + if (!last) { + fprintf(stderr, "tcp/udp with no source port\n"); + return 1; + } + *last++ = '\0'; + tcp->th_sport = htons(tx_portnum(last)); + if (ip6->ip6_nxt == IPPROTO_TCP) { + tcp->th_win = htons(4096); + TCP_OFF_A(tcp, sizeof(*tcp) >> 2); + } + } + + if (inet_pton(AF_INET6, *cpp, &ip6->ip6_src) != 1) { + fprintf(stderr, "cannot parse source address '%s'\n", *cpp); + return 1; + } + + cpp++; + if (!*cpp) + return 1; + + if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) { + char *last; + + last = strchr(*cpp, ','); + if (!last) { + fprintf(stderr, "tcp/udp with no destination port\n"); + return 1; + } + *last++ = '\0'; + tcp->th_dport = htons(tx_portnum(last)); + } + + if (inet_pton(AF_INET6, *cpp, &ip6->ip6_dst) != 1) { + fprintf(stderr, "cannot parse destination address '%s'\n", + *cpp); + return 1; + } + + cpp++; + if (ip6->ip6_nxt == IPPROTO_TCP) { + if (*cpp != NULL) { + char *s, *t; + + tcp->th_flags = 0; + for (s = *cpp; *s; s++) + if ((t = strchr(myflagset, *s))) + tcp->th_flags |= myflags[t-myflagset]; + if (tcp->th_flags) + cpp++; + } + + if (tcp->th_flags & TH_URG) + tcp->th_urp = htons(1); + + if (*cpp && !strncasecmp(*cpp, "seq=", 4)) { + tcp->th_seq = htonl(atoi(*cpp + 4)); + cpp++; + } + + if (*cpp && !strncasecmp(*cpp, "ack=", 4)) { + tcp->th_ack = htonl(atoi(*cpp + 4)); + cpp++; + } + } else if (*cpp && ip6->ip6_nxt == IPPROTO_ICMPV6) { + char *t; + + t = strchr(*cpp, ','); + if (t != NULL) + *t = '\0'; + + ic6->icmp6_type = geticmptype(AF_INET6, *cpp); + if (t != NULL) + ic6->icmp6_code = atoi(t + 1); + + if (ic6->icmp6_type == ICMP6_ECHO_REQUEST || + ic6->icmp6_type == ICMP6_ECHO_REPLY) + ic6->icmp6_id = htons(getpid()); + + if (t != NULL) + *t = ','; + } + + if (ip6->ip6_nxt == IPPROTO_TCP || ip6->ip6_nxt == IPPROTO_UDP) { + bcopy((char *)tcp, (char *)ip6 + sizeof(*ip6), + sizeof(*tcp)); + } else if (ip6->ip6_nxt == IPPROTO_ICMPV6) { + bcopy((char *)ic6, (char *)ip6 + sizeof(*ip6), + sizeof(*ic6)); + } + + /* + * Because a length of 0 == jumbo gram... + */ + if (ip6->ip6_plen == 0) { + ip6->ip6_plen++; + } + ip6->ip6_plen = htons(ip6->ip6_plen); + return 0; +} +#endif diff --git a/contrib/ipfilter/lib/ipoptsec.c b/contrib/ipfilter/lib/ipoptsec.c new file mode 100644 index 0000000..5e585ba --- /dev/null +++ b/contrib/ipfilter/lib/ipoptsec.c @@ -0,0 +1,61 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +struct ipopt_names secclass[] = { + { IPSO_CLASS_RES4, 0x01, 0, "reserv-4" }, + { IPSO_CLASS_TOPS, 0x02, 0, "topsecret" }, + { IPSO_CLASS_SECR, 0x04, 0, "secret" }, + { IPSO_CLASS_RES3, 0x08, 0, "reserv-3" }, + { IPSO_CLASS_CONF, 0x10, 0, "confid" }, + { IPSO_CLASS_UNCL, 0x20, 0, "unclass" }, + { IPSO_CLASS_RES2, 0x40, 0, "reserv-2" }, + { IPSO_CLASS_RES1, 0x80, 0, "reserv-1" }, + { 0, 0, 0, NULL } /* must be last */ +}; + + +u_char seclevel(slevel) + char *slevel; +{ + struct ipopt_names *so; + + if (slevel == NULL || *slevel == '\0') + return 0; + + for (so = secclass; so->on_name; so++) + if (!strcasecmp(slevel, so->on_name)) + break; + + if (!so->on_name) { + fprintf(stderr, "no such security level: '%s'\n", slevel); + return 0; + } + return (u_char)so->on_value; +} + + +u_char secbit(class) + int class; +{ + struct ipopt_names *so; + + for (so = secclass; so->on_name; so++) + if (so->on_value == class) + break; + + if (!so->on_name) { + fprintf(stderr, "no such security class: %d.\n", class); + return 0; + } + return (u_char)so->on_bit; +} diff --git a/contrib/ipfilter/lib/kmem.c b/contrib/ipfilter/lib/kmem.c new file mode 100644 index 0000000..d895baf --- /dev/null +++ b/contrib/ipfilter/lib/kmem.c @@ -0,0 +1,201 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * kmemcpy() - copies n bytes from kernel memory into user buffer. + * returns 0 on success, -1 on error. + */ + +#include <stdio.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/file.h> +#if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(_AIX51) +#include <kvm.h> +#endif +#include <fcntl.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <net/if.h> +#if defined(linux) || defined(__osf__) || defined(__sgi) || defined(__hpux) +# include <stdlib.h> +#endif + +#include "kmem.h" + +#ifndef __STDC__ +# define const +#endif + +#if !defined(lint) +static const char sccsid[] = "@(#)kmem.c 1.4 1/12/96 (C) 1992 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + + + +#if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && \ + !defined(linux) && !defined(_AIX51) +/* + * For all platforms where there is a libkvm and a kvm_t, we use that... + */ +static kvm_t *kvm_f = NULL; + +#else +/* + *...and for the others (HP-UX, IRIX, Tru64), we have to provide our own. + */ + +typedef int * kvm_t; + +static kvm_t kvm_f = NULL; +static char *kvm_errstr = NULL; + +kvm_t kvm_open __P((char *, char *, char *, int, char *)); +int kvm_read __P((kvm_t, u_long, char *, size_t)); + +kvm_t kvm_open(kernel, core, swap, mode, errstr) + char *kernel, *core, *swap; + int mode; + char *errstr; +{ + kvm_t k; + int fd; + + kvm_errstr = errstr; + + if (core == NULL) + core = "/dev/kmem"; + + fd = open(core, mode); + if (fd == -1) + return NULL; + k = malloc(sizeof(*k)); + if (k == NULL) + return NULL; + *k = fd; + return k; +} + +int kvm_read(kvm, pos, buffer, size) + kvm_t kvm; + u_long pos; + char *buffer; + size_t size; +{ + int r = 0, left; + char *bufp; + + if (lseek(*kvm, pos, 0) == -1) { + if (kvm_errstr != NULL) { + fprintf(stderr, "%s", kvm_errstr); + perror("lseek"); + } + return -1; + } + + for (bufp = buffer, left = size; left > 0; bufp += r, left -= r) { + r = read(*kvm, bufp, left); +#ifdef __osf__ + /* + * Tru64 returns "0" for successful operation, not the number + * of bytes read. + */ + if (r == 0) + r = left; +#endif + if (r <= 0) + return -1; + } + return r; +} +#endif /* !defined(__sgi) && !defined(__hpux) && !defined(__osf__) */ + +int openkmem(kern, core) + char *kern, *core; +{ + kvm_f = kvm_open(kern, core, NULL, O_RDONLY, NULL); + if (kvm_f == NULL) + { + perror("openkmem:open"); + return -1; + } + return kvm_f != NULL; +} + +int kmemcpy(buf, pos, n) + register char *buf; + long pos; + register int n; +{ + register int r; + + if (!n) + return 0; + + if (kvm_f == NULL) + if (openkmem(NULL, NULL) == -1) + return -1; + + while ((r = kvm_read(kvm_f, pos, buf, n)) < n) + if (r <= 0) + { + fprintf(stderr, "pos=0x%lx ", (u_long)pos); + perror("kmemcpy:read"); + return -1; + } + else + { + buf += r; + pos += r; + n -= r; + } + return 0; +} + +int kstrncpy(buf, pos, n) + register char *buf; + long pos; + register int n; +{ + register int r; + + if (!n) + return 0; + + if (kvm_f == NULL) + if (openkmem(NULL, NULL) == -1) + return -1; + + while (n > 0) + { + r = kvm_read(kvm_f, pos, buf, 1); + if (r <= 0) + { + fprintf(stderr, "pos=0x%lx ", (u_long)pos); + perror("kmemcpy:read"); + return -1; + } + else + { + if (*buf == '\0') + break; + buf++; + pos++; + n--; + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/kmem.h b/contrib/ipfilter/lib/kmem.h new file mode 100644 index 0000000..ce6ad56 --- /dev/null +++ b/contrib/ipfilter/lib/kmem.h @@ -0,0 +1,34 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * $Id$ + */ + +#ifndef __KMEM_H__ +#define __KMEM_H__ + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +extern int openkmem __P((char *, char *)); +extern int kmemcpy __P((char *, long, int)); +extern int kstrncpy __P((char *, long, int)); + +#if defined(__NetBSD__) || defined(__OpenBSD) +# include <paths.h> +#endif + +#ifdef _PATH_KMEM +# define KMEM _PATH_KMEM +#else +# define KMEM "/dev/kmem" +#endif + +#endif /* __KMEM_H__ */ diff --git a/contrib/ipfilter/lib/kmemcpywrap.c b/contrib/ipfilter/lib/kmemcpywrap.c new file mode 100644 index 0000000..6c398d6 --- /dev/null +++ b/contrib/ipfilter/lib/kmemcpywrap.c @@ -0,0 +1,23 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" +#include "kmem.h" + +int kmemcpywrap(from, to, size) + void *from, *to; + size_t size; +{ + int ret; + + ret = kmemcpy((caddr_t)to, (u_long)from, size); + return ret; +} + diff --git a/contrib/ipfilter/lib/kvatoname.c b/contrib/ipfilter/lib/kvatoname.c new file mode 100644 index 0000000..65b5240 --- /dev/null +++ b/contrib/ipfilter/lib/kvatoname.c @@ -0,0 +1,39 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +#include <fcntl.h> +#include <sys/ioctl.h> + +char *kvatoname(func, iocfunc) + ipfunc_t func; + ioctlfunc_t iocfunc; +{ + static char funcname[40]; + ipfunc_resolve_t res; + int fd; + + res.ipfu_addr = func; + res.ipfu_name[0] = '\0'; + fd = -1; + + if ((opts & OPT_DONTOPEN) == 0) { + fd = open(IPL_NAME, O_RDONLY); + if (fd == -1) + return NULL; + } + (void) (*iocfunc)(fd, SIOCFUNCL, &res); + if (fd >= 0) + close(fd); + strncpy(funcname, res.ipfu_name, sizeof(funcname)); + funcname[sizeof(funcname) - 1] = '\0'; + return funcname; +} diff --git a/contrib/ipfilter/lib/load_dstlist.c b/contrib/ipfilter/lib/load_dstlist.c new file mode 100644 index 0000000..760699d --- /dev/null +++ b/contrib/ipfilter/lib/load_dstlist.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: load_dstlist.c,v 1.1.2.5 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_dstlist.h" + + +int +load_dstlist(dst, iocfunc, nodes) + ippool_dst_t *dst; + ioctlfunc_t iocfunc; + ipf_dstnode_t *nodes; +{ + iplookupop_t op; + ipf_dstnode_t *a; + ippool_dst_t dest; + + if (dst->ipld_name[0] == '\0') + return -1; + + if (pool_open() == -1) + return -1; + + op.iplo_unit = dst->ipld_unit; + op.iplo_type = IPLT_DSTLIST; + op.iplo_arg = 0; + strncpy(op.iplo_name, dst->ipld_name, sizeof(op.iplo_name)); + op.iplo_size = sizeof(dest); + op.iplo_struct = &dest; + bzero((char *)&dest, sizeof(dest)); + dest.ipld_unit = dst->ipld_unit; + dest.ipld_policy = dst->ipld_policy; + dest.ipld_flags = dst->ipld_flags; + strncpy(dest.ipld_name, dst->ipld_name, sizeof(dest.ipld_name)); + + if ((opts & OPT_REMOVE) == 0) { + if (pool_ioctl(iocfunc, SIOCLOOKUPADDTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "add destination list table"); + } + } + + if ((opts & OPT_VERBOSE) != 0) { + dest.ipld_dests = dst->ipld_dests; + printdstlist(&dest, bcopywrap, dest.ipld_name, opts, nodes, NULL); + dest.ipld_dests = NULL; + } + + for (a = nodes; a != NULL; a = a->ipfd_next) + load_dstlistnode(dst->ipld_unit, dest.ipld_name, a, iocfunc); + + if ((opts & OPT_REMOVE) != 0) { + if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "delete destination list table"); + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/load_dstlistnode.c b/contrib/ipfilter/lib/load_dstlistnode.c new file mode 100644 index 0000000..e1ec001 --- /dev/null +++ b/contrib/ipfilter/lib/load_dstlistnode.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: load_dstlistnode.c,v 1.1.2.5 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" + + +int +load_dstlistnode(role, name, node, iocfunc) + int role; + char *name; + ipf_dstnode_t *node; + ioctlfunc_t iocfunc; +{ + iplookupop_t op; + frdest_t *dst; + char *what; + int err; + + if (pool_open() == -1) + return -1; + + dst = calloc(1, sizeof(*dst) + node->ipfd_dest.fd_name); + if (dst == NULL) + return -1; + + op.iplo_unit = role; + op.iplo_type = IPLT_DSTLIST; + op.iplo_arg = 0; + op.iplo_struct = dst; + op.iplo_size = sizeof(*dst); + if (node->ipfd_dest.fd_name >= 0) + op.iplo_size += node->ipfd_dest.fd_name; + (void) strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + + dst->fd_addr = node->ipfd_dest.fd_addr; + dst->fd_type = node->ipfd_dest.fd_type; + dst->fd_name = node->ipfd_dest.fd_name; + if (node->ipfd_dest.fd_name >= 0) + bcopy(node->ipfd_names, (char *)dst + sizeof(*dst), + node->ipfd_dest.fd_name); + + if ((opts & OPT_REMOVE) == 0) { + what = "add"; + err = pool_ioctl(iocfunc, SIOCLOOKUPADDNODE, &op); + } else { + what = "delete"; + err = pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op); + } + free(dst); + + if (err != 0) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + (void) sprintf(msg, "%s lookup node", what); + return ipf_perror_fd(pool_fd(), iocfunc, msg); + } + } + + return 0; +} diff --git a/contrib/ipfilter/lib/load_file.c b/contrib/ipfilter/lib/load_file.c new file mode 100644 index 0000000..a1d1f70 --- /dev/null +++ b/contrib/ipfilter/lib/load_file.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: load_file.c,v 1.6.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" +#include <ctype.h> + +alist_t * +load_file(char *filename) +{ + alist_t *a, *rtop, *rbot; + char *s, line[1024], *t; + int linenum, not; + FILE *fp; + + fp = fopen(filename + 7, "r"); + if (fp == NULL) { + fprintf(stderr, "load_file cannot open '%s'\n", filename); + return NULL; + } + + a = NULL; + rtop = NULL; + rbot = NULL; + linenum = 0; + + while (fgets(line, sizeof(line) - 1, fp)) { + line[sizeof(line) - 1] = '\0'; + linenum++; + /* + * Hunt for CR/LF. If no LF, stop processing. + */ + s = strchr(line, '\n'); + if (s == NULL) { + fprintf(stderr, "%d:%s: line too long\n", + linenum, filename); + fclose(fp); + alist_free(rtop); + return NULL; + } + + /* + * Remove trailing spaces + */ + for (; ISSPACE(*s); s--) + *s = '\0'; + + s = strchr(line, '\r'); + if (s != NULL) + *s = '\0'; + for (t = line; ISSPACE(*t); t++) + ; + if (*t == '!') { + not = 1; + t++; + } else + not = 0; + + /* + * Remove comment markers + */ + s = strchr(t, '#'); + if (s != NULL) { + *s = '\0'; + if (s == t) + continue; + } + + /* + * Trim off tailing white spaces + */ + s = strlen(t) + t - 1; + while (ISSPACE(*s)) + *s-- = '\0'; + + a = alist_new(AF_UNSPEC, t); + if (a != NULL) { + a->al_not = not; + if (rbot != NULL) + rbot->al_next = a; + else + rtop = a; + rbot = a; + } else { + fprintf(stderr, "%s:%d unrecognised content :%s\n", + filename, linenum, t); + } + } + fclose(fp); + + return rtop; +} diff --git a/contrib/ipfilter/lib/load_hash.c b/contrib/ipfilter/lib/load_hash.c new file mode 100644 index 0000000..7ec79a9 --- /dev/null +++ b/contrib/ipfilter/lib/load_hash.c @@ -0,0 +1,103 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + + +int +load_hash(iphp, list, iocfunc) + iphtable_t *iphp; + iphtent_t *list; + ioctlfunc_t iocfunc; +{ + iplookupop_t op; + iphtable_t iph; + iphtent_t *a; + size_t size; + int n; + + if (pool_open() == -1) + return -1; + + for (n = 0, a = list; a != NULL; a = a->ipe_next) + n++; + + bzero((char *)&iph, sizeof(iph)); + op.iplo_arg = 0; + op.iplo_type = IPLT_HASH; + op.iplo_unit = iphp->iph_unit; + strncpy(op.iplo_name, iphp->iph_name, sizeof(op.iplo_name)); + if (*op.iplo_name == '\0') + op.iplo_arg = IPHASH_ANON; + op.iplo_size = sizeof(iph); + op.iplo_struct = &iph; + iph = *iphp; + if (n <= 0) + n = 1; + if (iphp->iph_size == 0) + size = n * 2 - 1; + else + size = iphp->iph_size; + if ((list == NULL) && (size == 1)) { + fprintf(stderr, + "WARNING: empty hash table %s, recommend setting %s\n", + iphp->iph_name, "size to match expected use"); + } + iph.iph_size = size; + iph.iph_table = NULL; + iph.iph_list = NULL; + iph.iph_ref = 0; + + if ((opts & OPT_REMOVE) == 0) { + if (pool_ioctl(iocfunc, SIOCLOOKUPADDTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "add lookup hash table"); + } + } + + strncpy(iph.iph_name, op.iplo_name, sizeof(op.iplo_name)); + strncpy(iphp->iph_name, op.iplo_name, sizeof(op.iplo_name)); + + if (opts & OPT_VERBOSE) { + iph.iph_table = calloc(size, sizeof(*iph.iph_table)); + if (iph.iph_table == NULL) { + perror("calloc(size, sizeof(*iph.iph_table))"); + return -1; + } + iph.iph_list = list; + printhash(&iph, bcopywrap, iph.iph_name, opts, NULL); + free(iph.iph_table); + + for (a = list; a != NULL; a = a->ipe_next) { + a->ipe_addr.in4_addr = htonl(a->ipe_addr.in4_addr); + a->ipe_mask.in4_addr = htonl(a->ipe_mask.in4_addr); + } + } + + if (opts & OPT_DEBUG) + printf("Hash %s:\n", iph.iph_name); + + for (a = list; a != NULL; a = a->ipe_next) + load_hashnode(iphp->iph_unit, iph.iph_name, a, 0, iocfunc); + + if ((opts & OPT_REMOVE) != 0) { + if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "delete lookup hash table"); + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/load_hashnode.c b/contrib/ipfilter/lib/load_hashnode.c new file mode 100644 index 0000000..2aac433 --- /dev/null +++ b/contrib/ipfilter/lib/load_hashnode.c @@ -0,0 +1,67 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + + +int +load_hashnode(unit, name, node, ttl, iocfunc) + int unit; + char *name; + iphtent_t *node; + int ttl; + ioctlfunc_t iocfunc; +{ + iplookupop_t op; + iphtent_t ipe; + char *what; + int err; + + if (pool_open() == -1) + return -1; + + op.iplo_type = IPLT_HASH; + op.iplo_unit = unit; + op.iplo_arg = 0; + op.iplo_size = sizeof(ipe); + op.iplo_struct = &ipe; + strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + + bzero((char *)&ipe, sizeof(ipe)); + ipe.ipe_family = node->ipe_family; + ipe.ipe_die = ttl; + bcopy((char *)&node->ipe_addr, (char *)&ipe.ipe_addr, + sizeof(ipe.ipe_addr)); + bcopy((char *)&node->ipe_mask, (char *)&ipe.ipe_mask, + sizeof(ipe.ipe_mask)); + bcopy((char *)&node->ipe_group, (char *)&ipe.ipe_group, + sizeof(ipe.ipe_group)); + + if ((opts & OPT_REMOVE) == 0) { + what = "add"; + err = pool_ioctl(iocfunc, SIOCLOOKUPADDNODE, &op); + } else { + what = "delete"; + err = pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op); + } + + if (err != 0) + if (!(opts & OPT_DONOTHING)) { + char msg[80]; + + sprintf(msg, "%s node from lookup hash table", what); + return ipf_perror_fd(pool_fd(), iocfunc, msg); + } + return 0; +} diff --git a/contrib/ipfilter/lib/load_http.c b/contrib/ipfilter/lib/load_http.c new file mode 100644 index 0000000..88fc1e3 --- /dev/null +++ b/contrib/ipfilter/lib/load_http.c @@ -0,0 +1,208 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: load_http.c,v 1.5.2.5 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" +#include <ctype.h> + +/* + * Because the URL can be included twice into the buffer, once as the + * full path for the "GET" and once as the "Host:", the buffer it is + * put in needs to be larger than 512*2 to make room for the supporting + * text. Why not just use snprintf and truncate? The warning about the + * URL being too long tells you something is wrong and does not fetch + * any data - just truncating the URL (with snprintf, etc) and sending + * that to the server is allowing an unknown and unintentioned action + * to happen. + */ +#define MAX_URL_LEN 512 +#define LOAD_BUFSIZE (MAX_URL_LEN * 2 + 128) + +/* + * Format expected is one addres per line, at the start of each line. + */ +alist_t * +load_http(char *url) +{ + int fd, len, left, port, endhdr, removed, linenum = 0; + char *s, *t, *u, buffer[LOAD_BUFSIZE], *myurl; + alist_t *a, *rtop, *rbot; + size_t avail; + int error; + + /* + * More than this would just be absurd. + */ + if (strlen(url) > MAX_URL_LEN) { + fprintf(stderr, "load_http has a URL > %d bytes?!\n", + MAX_URL_LEN); + return NULL; + } + + fd = -1; + rtop = NULL; + rbot = NULL; + + avail = sizeof(buffer); + error = snprintf(buffer, avail, "GET %s HTTP/1.0\r\n", url); + + /* + * error is always less then avail due to the constraint on + * the url length above. + */ + avail -= error; + + myurl = strdup(url); + if (myurl == NULL) + goto done; + + s = myurl + 7; /* http:// */ + t = strchr(s, '/'); + if (t == NULL) { + fprintf(stderr, "load_http has a malformed URL '%s'\n", url); + free(myurl); + return NULL; + } + *t++ = '\0'; + + /* + * 10 is the length of 'Host: \r\n\r\n' below. + */ + if (strlen(s) + strlen(buffer) + 10 > sizeof(buffer)) { + fprintf(stderr, "load_http has a malformed URL '%s'\n", url); + free(myurl); + return NULL; + } + + u = strchr(s, '@'); + if (u != NULL) + s = u + 1; /* AUTH */ + + error = snprintf(buffer + strlen(buffer), avail, "Host: %s\r\n\r\n", s); + if (error >= avail) { + fprintf(stderr, "URL is too large: %s\n", url); + goto done; + } + + u = strchr(s, ':'); + if (u != NULL) { + *u++ = '\0'; + port = atoi(u); + if (port < 0 || port > 65535) + goto done; + } else { + port = 80; + } + + + fd = connecttcp(s, port); + if (fd == -1) + goto done; + + + len = strlen(buffer); + if (write(fd, buffer, len) != len) + goto done; + + s = buffer; + endhdr = 0; + left = sizeof(buffer) - 1; + + while ((len = read(fd, s, left)) > 0) { + s[len] = '\0'; + left -= len; + s += len; + + if (endhdr >= 0) { + if (endhdr == 0) { + t = strchr(buffer, ' '); + if (t == NULL) + continue; + t++; + if (*t != '2') + break; + } + + u = buffer; + while ((t = strchr(u, '\r')) != NULL) { + if (t == u) { + if (*(t + 1) == '\n') { + u = t + 2; + endhdr = -1; + break; + } else + t++; + } else if (*(t + 1) == '\n') { + endhdr++; + u = t + 2; + } else + u = t + 1; + } + if (endhdr >= 0) + continue; + removed = (u - buffer) + 1; + memmove(buffer, u, (sizeof(buffer) - left) - removed); + s -= removed; + left += removed; + } + + do { + t = strchr(buffer, '\n'); + if (t == NULL) + break; + + linenum++; + *t = '\0'; + + /* + * Remove comment and continue to the next line if + * the comment is at the start of the line. + */ + u = strchr(buffer, '#'); + if (u != NULL) { + *u = '\0'; + if (u == buffer) + continue; + } + + /* + * Trim off tailing white spaces, will include \r + */ + for (u = t - 1; (u >= buffer) && ISSPACE(*u); u--) + *u = '\0'; + + a = alist_new(AF_UNSPEC, buffer); + if (a != NULL) { + if (rbot != NULL) + rbot->al_next = a; + else + rtop = a; + rbot = a; + } else { + fprintf(stderr, + "%s:%d unrecognised content:%s\n", + url, linenum, buffer); + } + + t++; + removed = t - buffer; + memmove(buffer, t, sizeof(buffer) - left - removed); + s -= removed; + left += removed; + + } while (1); + } + +done: + if (myurl != NULL) + free(myurl); + if (fd != -1) + close(fd); + return rtop; +} diff --git a/contrib/ipfilter/lib/load_pool.c b/contrib/ipfilter/lib/load_pool.c new file mode 100644 index 0000000..190a2df --- /dev/null +++ b/contrib/ipfilter/lib/load_pool.c @@ -0,0 +1,72 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" + + +int +load_pool(plp, iocfunc) + ip_pool_t *plp; + ioctlfunc_t iocfunc; +{ + iplookupop_t op; + ip_pool_node_t *a; + ip_pool_t pool; + + if (pool_open() == -1) + return -1; + + op.iplo_unit = plp->ipo_unit; + op.iplo_type = IPLT_POOL; + op.iplo_arg = 0; + strncpy(op.iplo_name, plp->ipo_name, sizeof(op.iplo_name)); + op.iplo_size = sizeof(pool); + op.iplo_struct = &pool; + bzero((char *)&pool, sizeof(pool)); + pool.ipo_unit = plp->ipo_unit; + strncpy(pool.ipo_name, plp->ipo_name, sizeof(pool.ipo_name)); + if (plp->ipo_name[0] == '\0') + op.iplo_arg |= IPOOL_ANON; + + if ((opts & OPT_REMOVE) == 0) { + if (pool_ioctl(iocfunc, SIOCLOOKUPADDTABLE, &op)) { + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "add lookup table"); + } + } + } + + if (op.iplo_arg & IPOOL_ANON) + strncpy(pool.ipo_name, op.iplo_name, sizeof(pool.ipo_name)); + + if ((opts & OPT_VERBOSE) != 0) { + pool.ipo_list = plp->ipo_list; + (void) printpool(&pool, bcopywrap, pool.ipo_name, opts, NULL); + pool.ipo_list = NULL; + } + + for (a = plp->ipo_list; a != NULL; a = a->ipn_next) + load_poolnode(plp->ipo_unit, pool.ipo_name, + a, 0, iocfunc); + + if ((opts & OPT_REMOVE) != 0) { + if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op)) + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "delete lookup table"); + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/load_poolnode.c b/contrib/ipfilter/lib/load_poolnode.c new file mode 100644 index 0000000..5afca84 --- /dev/null +++ b/contrib/ipfilter/lib/load_poolnode.c @@ -0,0 +1,70 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" + + +int +load_poolnode(role, name, node, ttl, iocfunc) + int role; + char *name; + ip_pool_node_t *node; + int ttl; + ioctlfunc_t iocfunc; +{ + ip_pool_node_t pn; + iplookupop_t op; + char *what; + int err; + + if (pool_open() == -1) + return -1; + + op.iplo_unit = role; + op.iplo_type = IPLT_POOL; + op.iplo_arg = 0; + op.iplo_struct = &pn; + op.iplo_size = sizeof(pn); + strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + + bzero((char *)&pn, sizeof(pn)); + bcopy((char *)&node->ipn_addr, (char *)&pn.ipn_addr, + sizeof(pn.ipn_addr)); + bcopy((char *)&node->ipn_mask, (char *)&pn.ipn_mask, + sizeof(pn.ipn_mask)); + pn.ipn_info = node->ipn_info; + pn.ipn_die = ttl; + strncpy(pn.ipn_name, node->ipn_name, sizeof(pn.ipn_name)); + + if ((opts & OPT_REMOVE) == 0) { + what = "add"; + err = pool_ioctl(iocfunc, SIOCLOOKUPADDNODE, &op); + } else { + what = "delete"; + err = pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op); + } + + if (err != 0) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + sprintf(msg, "%s pool node(%s/", what, + inet_ntoa(pn.ipn_addr.adf_addr.in4)); + strcat(msg, inet_ntoa(pn.ipn_mask.adf_addr.in4)); + return ipf_perror_fd(pool_fd(), iocfunc, msg); + } + } + + return 0; +} diff --git a/contrib/ipfilter/lib/load_url.c b/contrib/ipfilter/lib/load_url.c new file mode 100644 index 0000000..dcda4c0 --- /dev/null +++ b/contrib/ipfilter/lib/load_url.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: load_url.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + +alist_t * +load_url(char *url) +{ + alist_t *hosts = NULL; + + if (strncmp(url, "file://", 7) == 0) { + /* + * file:///etc/passwd + * ^------------s + */ + hosts = load_file(url); + + } else if (*url == '/' || *url == '.') { + hosts = load_file(url); + + } else if (strncmp(url, "http://", 7) == 0) { + hosts = load_http(url); + } + + return hosts; +} diff --git a/contrib/ipfilter/lib/mb_hexdump.c b/contrib/ipfilter/lib/mb_hexdump.c new file mode 100644 index 0000000..6da6563 --- /dev/null +++ b/contrib/ipfilter/lib/mb_hexdump.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: mb_hexdump.c,v 1.1.2.3 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + +void +mb_hexdump(m, fp) + mb_t *m; + FILE *fp; +{ + u_char *s; + int len; + int i; + + for (; m != NULL; m = m->mb_next) { + len = m->mb_len; + for (s = (u_char *)m->mb_data, i = 0; i < len; i++) { + fprintf(fp, "%02x", *s++ & 0xff); + if (len - i > 1) { + i++; + fprintf(fp, "%02x", *s++ & 0xff); + } + fputc(' ', fp); + } + } + fputc('\n', fp); +} diff --git a/contrib/ipfilter/lib/msgdsize.c b/contrib/ipfilter/lib/msgdsize.c new file mode 100644 index 0000000..9bdc584 --- /dev/null +++ b/contrib/ipfilter/lib/msgdsize.c @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: msgdsize.c,v 1.2.4.3 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + +size_t msgdsize(orig) + mb_t *orig; +{ + size_t sz = 0; + mb_t *m; + + for (m = orig; m != NULL; m = m->mb_next) + sz += m->mb_len; + return sz; +} diff --git a/contrib/ipfilter/lib/mutex_emul.c b/contrib/ipfilter/lib/mutex_emul.c new file mode 100644 index 0000000..1846701 --- /dev/null +++ b/contrib/ipfilter/lib/mutex_emul.c @@ -0,0 +1,133 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +#define EMM_MAGIC 0x9d7adba3 + +static int mutex_debug = 0; +static FILE *mutex_file = NULL; +static int initcount = 0; + +void +eMmutex_enter(mtx, file, line) + eMmutex_t *mtx; + char *file; + int line; +{ + if (mutex_debug & 2) + fprintf(mutex_file, "%s:%d:eMmutex_enter(%s)\n", file, line, + mtx->eMm_owner); + if (mtx->eMm_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMmutex_enter(%p): bad magic: %#x\n", + mtx->eMm_owner, mtx, mtx->eMm_magic); + abort(); + } + if (mtx->eMm_held != 0) { + fprintf(stderr, "%s:eMmutex_enter(%p): already locked: %d\n", + mtx->eMm_owner, mtx, mtx->eMm_held); + abort(); + } + mtx->eMm_held++; + mtx->eMm_heldin = file; + mtx->eMm_heldat = line; +} + + +void +eMmutex_exit(mtx, file, line) + eMmutex_t *mtx; + char *file; + int line; +{ + if (mutex_debug & 2) + fprintf(mutex_file, "%s:%d:eMmutex_exit(%s)\n", file, line, + mtx->eMm_owner); + if (mtx->eMm_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMmutex_exit(%p): bad magic: %#x\n", + mtx->eMm_owner, mtx, mtx->eMm_magic); + abort(); + } + if (mtx->eMm_held != 1) { + fprintf(stderr, "%s:eMmutex_exit(%p): not locked: %d\n", + mtx->eMm_owner, mtx, mtx->eMm_held); + abort(); + } + mtx->eMm_held--; + mtx->eMm_heldin = NULL; + mtx->eMm_heldat = 0; +} + + +void +eMmutex_init(mtx, who, file, line) + eMmutex_t *mtx; + char *who; + char *file; + int line; +{ + if (mutex_file == NULL && mutex_debug) + mutex_file = fopen("ipf_mutex_log", "w"); + if (mutex_debug & 1) + fprintf(mutex_file, "%s:%d:eMmutex_init(%p,%s)\n", + file, line, mtx, who); + if (mtx->eMm_magic == EMM_MAGIC) { /* safe bet ? */ + fprintf(stderr, + "%s:eMmutex_init(%p): already initialised?: %#x\n", + mtx->eMm_owner, mtx, mtx->eMm_magic); + abort(); + } + mtx->eMm_magic = EMM_MAGIC; + mtx->eMm_held = 0; + if (who != NULL) + mtx->eMm_owner = strdup(who); + else + mtx->eMm_owner = NULL; + initcount++; +} + + +void +eMmutex_destroy(mtx, file, line) + eMmutex_t *mtx; + char *file; + int line; +{ + if (mutex_debug & 1) + fprintf(mutex_file, + "%s:%d:eMmutex_destroy(%p,%s)\n", file, line, + mtx, mtx->eMm_owner); + if (mtx->eMm_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMmutex_destroy(%p): bad magic: %#x\n", + mtx->eMm_owner, mtx, mtx->eMm_magic); + abort(); + } + if (mtx->eMm_held != 0) { + fprintf(stderr, + "%s:eMmutex_enter(%p): still locked: %d\n", + mtx->eMm_owner, mtx, mtx->eMm_held); + abort(); + } + if (mtx->eMm_owner != NULL) + free(mtx->eMm_owner); + memset(mtx, 0xa5, sizeof(*mtx)); + initcount--; +} + + +void +ipf_mutex_clean() +{ + if (initcount != 0) { + if (mutex_file) + fprintf(mutex_file, "initcount %d\n", initcount); + abort(); + } +} diff --git a/contrib/ipfilter/lib/nametokva.c b/contrib/ipfilter/lib/nametokva.c new file mode 100644 index 0000000..8e7af94 --- /dev/null +++ b/contrib/ipfilter/lib/nametokva.c @@ -0,0 +1,38 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +#include <sys/ioctl.h> +#include <fcntl.h> + +ipfunc_t nametokva(name, iocfunc) + char *name; + ioctlfunc_t iocfunc; +{ + ipfunc_resolve_t res; + int fd; + + strncpy(res.ipfu_name, name, sizeof(res.ipfu_name)); + res.ipfu_addr = NULL; + fd = -1; + + if ((opts & OPT_DONTOPEN) == 0) { + fd = open(IPL_NAME, O_RDONLY); + if (fd == -1) + return NULL; + } + (void) (*iocfunc)(fd, SIOCFUNCL, &res); + if (fd >= 0) + close(fd); + if (res.ipfu_addr == NULL) + res.ipfu_addr = (ipfunc_t)-1; + return res.ipfu_addr; +} diff --git a/contrib/ipfilter/lib/nat_setgroupmap.c b/contrib/ipfilter/lib/nat_setgroupmap.c new file mode 100644 index 0000000..15c21f6 --- /dev/null +++ b/contrib/ipfilter/lib/nat_setgroupmap.c @@ -0,0 +1,34 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + +#include "ipf.h" + +void nat_setgroupmap(n) + ipnat_t *n; +{ + if (n->in_nsrcmsk == n->in_osrcmsk) + n->in_ippip = 1; + else if (n->in_flags & IPN_AUTOPORTMAP) { + n->in_ippip = ~ntohl(n->in_osrcmsk); + if (n->in_nsrcmsk != 0xffffffff) + n->in_ippip /= (~ntohl(n->in_nsrcmsk) + 1); + n->in_ippip++; + if (n->in_ippip == 0) + n->in_ippip = 1; + n->in_ppip = USABLE_PORTS / n->in_ippip; + } else { + n->in_space = USABLE_PORTS * ~ntohl(n->in_nsrcmsk); + n->in_snip = 0; + if (!(n->in_ppip = n->in_spmin)) + n->in_ppip = 1; + n->in_ippip = USABLE_PORTS / n->in_ppip; + } +} diff --git a/contrib/ipfilter/lib/ntomask.c b/contrib/ipfilter/lib/ntomask.c new file mode 100644 index 0000000..98e3b26 --- /dev/null +++ b/contrib/ipfilter/lib/ntomask.c @@ -0,0 +1,47 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +int ntomask(family, nbits, ap) + int family, nbits; + u_32_t *ap; +{ + u_32_t mask; + + if (nbits < 0) + return -1; + + switch (family) + { + case AF_INET : + if (nbits > 32 || use_inet6 == 1) + return -1; + if (nbits == 0) { + mask = 0; + } else { + mask = 0xffffffff; + mask <<= (32 - nbits); + } + *ap = htonl(mask); + break; + + case 0 : + case AF_INET6 : + if ((nbits > 128) || (use_inet6 == -1)) + return -1; + fill6bits(nbits, ap); + break; + + default : + return -1; + } + return 0; +} diff --git a/contrib/ipfilter/lib/optname.c b/contrib/ipfilter/lib/optname.c new file mode 100644 index 0000000..2bc811b --- /dev/null +++ b/contrib/ipfilter/lib/optname.c @@ -0,0 +1,65 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +u_32_t optname(cp, sp, linenum) + char ***cp; + u_short *sp; + int linenum; +{ + struct ipopt_names *io, *so; + u_long msk = 0; + u_short smsk = 0; + char *s; + int sec = 0; + + for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) { + for (io = ionames; io->on_name; io++) + if (!strcasecmp(s, io->on_name)) { + msk |= io->on_bit; + break; + } + if (!io->on_name) { + fprintf(stderr, "%d: unknown IP option name %s\n", + linenum, s); + return 0; + } + if (!strcasecmp(s, "sec-class")) + sec = 1; + } + + if (sec && !*(*cp + 1)) { + fprintf(stderr, "%d: missing security level after sec-class\n", + linenum); + return 0; + } + + if (sec) { + (*cp)++; + for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) { + for (so = secclass; so->on_name; so++) + if (!strcasecmp(s, so->on_name)) { + smsk |= so->on_bit; + break; + } + if (!so->on_name) { + fprintf(stderr, + "%d: no such security level: %s\n", + linenum, s); + return 0; + } + } + if (smsk) + *sp = smsk; + } + return msk; +} diff --git a/contrib/ipfilter/lib/optprint.c b/contrib/ipfilter/lib/optprint.c new file mode 100644 index 0000000..8b1f5cd --- /dev/null +++ b/contrib/ipfilter/lib/optprint.c @@ -0,0 +1,83 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + + +void optprint(sec, optmsk, optbits) + u_short *sec; + u_long optmsk, optbits; +{ + u_short secmsk = sec[0], secbits = sec[1]; + struct ipopt_names *io, *so; + char *s; + + s = " opt "; + for (io = ionames; io->on_name; io++) + if ((io->on_bit & optmsk) && + ((io->on_bit & optmsk) == (io->on_bit & optbits))) { + if ((io->on_value != IPOPT_SECURITY) || + (!secmsk && !secbits)) { + printf("%s%s", s, io->on_name); + /* + * Because the ionames table has this entry + * twice. + */ + if (io->on_value == IPOPT_SECURITY) + io++; + s = ","; + } + } + + + if (secmsk & secbits) { + printf("%ssec-class", s); + s = " "; + for (so = secclass; so->on_name; so++) + if ((secmsk & so->on_bit) && + ((so->on_bit & secmsk) == (so->on_bit & secbits))) { + printf("%s%s", s, so->on_name); + s = ","; + } + } + + if ((optmsk && (optmsk != optbits)) || + (secmsk && (secmsk != secbits))) { + s = " "; + printf(" not opt"); + if (optmsk != optbits) { + for (io = ionames; io->on_name; io++) + if ((io->on_bit & optmsk) && + ((io->on_bit & optmsk) != + (io->on_bit & optbits))) { + if ((io->on_value != IPOPT_SECURITY) || + (!secmsk && !secbits)) { + printf("%s%s", s, io->on_name); + s = ","; + if (io->on_value == + IPOPT_SECURITY) + io++; + } else + io++; + } + } + + if (secmsk != secbits) { + printf("%ssec-class", s); + s = " "; + for (so = secclass; so->on_name; so++) + if ((so->on_bit & secmsk) && + ((so->on_bit & secmsk) != + (so->on_bit & secbits))) { + printf("%s%s", s, so->on_name); + s = ","; + } + } + } +} diff --git a/contrib/ipfilter/lib/optprintv6.c b/contrib/ipfilter/lib/optprintv6.c new file mode 100644 index 0000000..752d1b3 --- /dev/null +++ b/contrib/ipfilter/lib/optprintv6.c @@ -0,0 +1,47 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + + +#ifdef USE_INET6 + +void optprintv6(sec, optmsk, optbits) + u_short *sec; + u_long optmsk, optbits; +{ + u_short secmsk = sec[0], secbits = sec[1]; + struct ipopt_names *io; + char *s; + + s = " v6hdr "; + for (io = v6ionames; io->on_name; io++) + if ((io->on_bit & optmsk) && + ((io->on_bit & optmsk) == (io->on_bit & optbits))) { + printf("%s%s", s, io->on_name); + s = ","; + } + + if ((optmsk && (optmsk != optbits)) || + (secmsk && (secmsk != secbits))) { + s = " "; + printf(" not v6hdrs"); + if (optmsk != optbits) { + for (io = v6ionames; io->on_name; io++) + if ((io->on_bit & optmsk) && + ((io->on_bit & optmsk) != + (io->on_bit & optbits))) { + printf("%s%s", s, io->on_name); + s = ","; + } + } + + } +} +#endif diff --git a/contrib/ipfilter/lib/optvalue.c b/contrib/ipfilter/lib/optvalue.c new file mode 100644 index 0000000..5bc1f42 --- /dev/null +++ b/contrib/ipfilter/lib/optvalue.c @@ -0,0 +1,34 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + + +u_32_t getoptbyname(optname) + char *optname; +{ + struct ipopt_names *io; + + for (io = ionames; io->on_name; io++) + if (!strcasecmp(optname, io->on_name)) + return io->on_bit; + return -1; +} + + +u_32_t getoptbyvalue(optval) + int optval; +{ + struct ipopt_names *io; + + for (io = ionames; io->on_name; io++) + if (io->on_value == optval) + return io->on_bit; + return -1; +} diff --git a/contrib/ipfilter/lib/parsefields.c b/contrib/ipfilter/lib/parsefields.c new file mode 100644 index 0000000..241496c --- /dev/null +++ b/contrib/ipfilter/lib/parsefields.c @@ -0,0 +1,48 @@ +#include "ipf.h" + +extern int nohdrfields; + +wordtab_t *parsefields(table, arg) + wordtab_t *table; + char *arg; +{ + wordtab_t *f, *fields; + char *s, *t; + int num; + + fields = NULL; + num = 0; + + for (s = strtok(arg, ","); s != NULL; s = strtok(NULL, ",")) { + t = strchr(s, '='); + if (t != NULL) { + *t++ = '\0'; + if (*t == '\0') + nohdrfields = 1; + } + + f = findword(table, s); + if (f == NULL) { + fprintf(stderr, "Unknown field '%s'\n", s); + exit(1); + } + + num++; + if (fields == NULL) { + fields = malloc(2 * sizeof(*fields)); + } else { + fields = realloc(fields, (num + 1) * sizeof(*fields)); + } + + if (t == NULL) { + fields[num - 1].w_word = f->w_word; + } else { + fields[num - 1].w_word = t; + } + fields[num - 1].w_value = f->w_value; + fields[num].w_word = NULL; + fields[num].w_value = 0; + } + + return fields; +} diff --git a/contrib/ipfilter/lib/parseipfexpr.c b/contrib/ipfilter/lib/parseipfexpr.c new file mode 100644 index 0000000..9a2a207 --- /dev/null +++ b/contrib/ipfilter/lib/parseipfexpr.c @@ -0,0 +1,283 @@ +#include "ipf.h" +#include <ctype.h> + + +typedef struct ipfopentry { + int ipoe_cmd; + int ipoe_nbasearg; + int ipoe_maxarg; + int ipoe_argsize; + char *ipoe_word; +} ipfopentry_t; + +static ipfopentry_t opwords[17] = { + { IPF_EXP_IP_ADDR, 2, 0, 1, "ip.addr" }, + { IPF_EXP_IP6_ADDR, 2, 0, 4, "ip6.addr" }, + { IPF_EXP_IP_PR, 1, 0, 1, "ip.p" }, + { IPF_EXP_IP_SRCADDR, 2, 0, 1, "ip.src" }, + { IPF_EXP_IP_DSTADDR, 2, 0, 1, "ip.dst" }, + { IPF_EXP_IP6_SRCADDR, 2, 0, 4, "ip6.src" }, + { IPF_EXP_IP6_DSTADDR, 2, 0, 4, "ip6.dst" }, + { IPF_EXP_TCP_PORT, 1, 0, 1, "tcp.port" }, + { IPF_EXP_TCP_DPORT, 1, 0, 1, "tcp.dport" }, + { IPF_EXP_TCP_SPORT, 1, 0, 1, "tcp.sport" }, + { IPF_EXP_TCP_FLAGS, 2, 0, 1, "tcp.flags" }, + { IPF_EXP_UDP_PORT, 1, 0, 1, "udp.port" }, + { IPF_EXP_UDP_DPORT, 1, 0, 1, "udp.dport" }, + { IPF_EXP_UDP_SPORT, 1, 0, 1, "udp.sport" }, + { IPF_EXP_TCP_STATE, 1, 0, 1, "tcp.state" }, + { IPF_EXP_IDLE_GT, 1, 1, 1, "idle-gt" }, + { -1, 0, 0, 0, NULL } +}; + + +int * +parseipfexpr(line, errorptr) + char *line; + char **errorptr; +{ + int not, items, asize, *oplist, osize, i; + char *temp, *arg, *s, *t, *ops, *error; + ipfopentry_t *e; + ipfexp_t *ipfe; + + asize = 0; + error = NULL; + oplist = NULL; + + temp = strdup(line); + if (temp == NULL) { + error = "strdup failed"; + goto parseerror; + } + + /* + * Eliminate any white spaces to make parsing easier. + */ + for (s = temp; *s != '\0'; ) { + if (ISSPACE(*s)) + strcpy(s, s + 1); + else + s++; + } + + /* + * Parse the string. + * It should be sets of "ip.dst=1.2.3.4/32;" things. + * There must be a "=" or "!=" and it must end in ";". + */ + if (temp[strlen(temp) - 1] != ';') { + error = "last character not ';'"; + goto parseerror; + } + + /* + * Work through the list of complete operands present. + */ + for (ops = strtok(temp, ";"); ops != NULL; ops = strtok(NULL, ";")) { + arg = strchr(ops, '='); + if ((arg < ops + 2) || (arg == NULL)) { + error = "bad 'arg' vlaue"; + goto parseerror; + } + + if (*(arg - 1) == '!') { + *(arg - 1) = '\0'; + not = 1; + } else { + not = 0; + } + *arg++ = '\0'; + + + for (e = opwords; e->ipoe_word; e++) { + if (strcmp(ops, e->ipoe_word) == 0) + break; + } + if (e->ipoe_word == NULL) { + error = malloc(32); + if (error != NULL) { + sprintf(error, "keyword (%.10s) not found", + ops); + } + goto parseerror; + } + + /* + * Count the number of commas so we know how big to + * build the array + */ + for (s = arg, items = 1; *s != '\0'; s++) + if (*s == ',') + items++; + + if ((e->ipoe_maxarg != 0) && (items > e->ipoe_maxarg)) { + error = "too many items"; + goto parseerror; + } + + /* + * osize will mark the end of where we have filled up to + * and is thus where we start putting new data. + */ + osize = asize; + asize += 4 + (items * e->ipoe_nbasearg * e->ipoe_argsize); + if (oplist == NULL) + oplist = calloc(1, sizeof(int) * (asize + 2)); + else + oplist = realloc(oplist, sizeof(int) * (asize + 2)); + if (oplist == NULL) { + error = "oplist alloc failed"; + goto parseerror; + } + ipfe = (ipfexp_t *)(oplist + osize); + osize += 4; + ipfe->ipfe_cmd = e->ipoe_cmd; + ipfe->ipfe_not = not; + ipfe->ipfe_narg = items * e->ipoe_nbasearg; + ipfe->ipfe_size = items * e->ipoe_nbasearg * e->ipoe_argsize; + ipfe->ipfe_size += 4; + + for (s = arg; (*s != '\0') && (osize < asize); s = t) { + /* + * Look for the end of this arg or the ',' to say + * there is another following. + */ + for (t = s; (*t != '\0') && (*t != ','); t++) + ; + if (*t == ',') + *t++ = '\0'; + + if (!strcasecmp(ops, "ip.addr") || + !strcasecmp(ops, "ip.src") || + !strcasecmp(ops, "ip.dst")) { + i6addr_t mask, addr; + char *delim; + + delim = strchr(s, '/'); + if (delim != NULL) { + *delim++ = '\0'; + if (genmask(AF_INET, delim, + &mask) == -1) { + error = "genmask failed"; + goto parseerror; + } + } else { + mask.in4.s_addr = 0xffffffff; + } + if (gethost(AF_INET, s, &addr) == -1) { + error = "gethost failed"; + goto parseerror; + } + + oplist[osize++] = addr.in4.s_addr; + oplist[osize++] = mask.in4.s_addr; + +#ifdef USE_INET6 + } else if (!strcasecmp(ops, "ip6.addr") || + !strcasecmp(ops, "ip6.src") || + !strcasecmp(ops, "ip6.dst")) { + i6addr_t mask, addr; + char *delim; + + delim = strchr(s, '/'); + if (delim != NULL) { + *delim++ = '\0'; + if (genmask(AF_INET6, delim, + &mask) == -1) { + error = "genmask failed"; + goto parseerror; + } + } else { + mask.i6[0] = 0xffffffff; + mask.i6[1] = 0xffffffff; + mask.i6[2] = 0xffffffff; + mask.i6[3] = 0xffffffff; + } + if (gethost(AF_INET6, s, &addr) == -1) { + error = "gethost failed"; + goto parseerror; + } + + oplist[osize++] = addr.i6[0]; + oplist[osize++] = addr.i6[1]; + oplist[osize++] = addr.i6[2]; + oplist[osize++] = addr.i6[3]; + oplist[osize++] = mask.i6[0]; + oplist[osize++] = mask.i6[1]; + oplist[osize++] = mask.i6[2]; + oplist[osize++] = mask.i6[3]; +#endif + + } else if (!strcasecmp(ops, "ip.p")) { + int p; + + p = getproto(s); + if (p == -1) + goto parseerror; + oplist[osize++] = p; + + } else if (!strcasecmp(ops, "tcp.flags")) { + u_32_t mask, flags; + char *delim; + + delim = strchr(s, '/'); + if (delim != NULL) { + *delim++ = '\0'; + mask = tcpflags(delim); + } else { + mask = 0xff; + } + flags = tcpflags(s); + + oplist[osize++] = flags; + oplist[osize++] = mask; + + + } else if (!strcasecmp(ops, "tcp.port") || + !strcasecmp(ops, "tcp.sport") || + !strcasecmp(ops, "tcp.dport") || + !strcasecmp(ops, "udp.port") || + !strcasecmp(ops, "udp.sport") || + !strcasecmp(ops, "udp.dport")) { + char proto[4]; + u_short port; + + strncpy(proto, ops, 3); + proto[3] = '\0'; + if (getport(NULL, s, &port, proto) == -1) + goto parseerror; + oplist[osize++] = port; + + } else if (!strcasecmp(ops, "tcp.state")) { + oplist[osize++] = atoi(s); + + } else { + error = "unknown word"; + goto parseerror; + } + } + } + + free(temp); + + if (errorptr != NULL) + *errorptr = NULL; + + for (i = asize; i > 0; i--) + oplist[i] = oplist[i - 1]; + + oplist[0] = asize + 2; + oplist[asize + 1] = IPF_EXP_END; + + return oplist; + +parseerror: + if (errorptr != NULL) + *errorptr = error; + if (oplist != NULL) + free(oplist); + if (temp != NULL) + free(temp); + return NULL; +} diff --git a/contrib/ipfilter/lib/parsewhoisline.c b/contrib/ipfilter/lib/parsewhoisline.c new file mode 100644 index 0000000..526935c --- /dev/null +++ b/contrib/ipfilter/lib/parsewhoisline.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: parsewhoisline.c,v 1.2.2.5 2012/07/22 08:04:24 darren_r Exp $ + */ +#include "ipf.h" + +/* +Microsoft Corp MICROSOFT19 (NET-198-136-97-0-1) 198.137.97.0 - 198.137.97.255 +Microsoft Corp SAVV-S233053-6 (NET-206-79-74-32-1) 206.79.74.32 - 206.79.74.47 + */ +int +parsewhoisline(line, addrp, maskp) + char *line; + addrfamily_t *addrp; + addrfamily_t *maskp; +{ + struct in_addr a1, a2; + char *src = line; + char *s = NULL; + + if (line == NULL) + return -1; + + while (*src != '\0') { + s = strchr(src, '('); + if (s == NULL) + break; + + if (strncmp(s, "(NET", 4)) { + src = s + 1; + } + break; + } + + if (s == NULL) + return -1; + + memset(addrp, 0x00, sizeof(*maskp)); + memset(maskp, 0x00, sizeof(*maskp)); + + if (*(s + 4) == '6') { +#ifdef USE_INET6 + i6addr_t a61, a62; + + s = strchr(s, ')'); + if (s == NULL || *++s != ' ') + return -1; + /* + * Parse the IPv6 + */ + if (inet_pton(AF_INET6, s, &a61.in6) != 1) + return -1; + + s = strchr(s, ' '); + if (s == NULL || strncmp(s, " - ", 3)) + return -1; + + s += 3; + if (inet_pton(AF_INET6, s, &a62) != 1) + return -1; + + addrp->adf_addr = a61; + addrp->adf_family = AF_INET6; + addrp->adf_len = offsetof(addrfamily_t, adf_addr) + + sizeof(struct in6_addr); + + maskp->adf_addr.i6[0] = ~(a62.i6[0] ^ a61.i6[0]); + maskp->adf_addr.i6[1] = ~(a62.i6[1] ^ a61.i6[1]); + maskp->adf_addr.i6[2] = ~(a62.i6[2] ^ a61.i6[2]); + maskp->adf_addr.i6[3] = ~(a62.i6[3] ^ a61.i6[3]); + + /* + * If the mask that's been generated isn't a consecutive mask + * then we can't add it into a pool. + */ + if (count6bits(maskp->adf_addr.i6) == -1) + return -1; + + maskp->adf_family = AF_INET6; + maskp->adf_len = addrp->adf_len; + + if (IP6_MASKNEQ(&addrp->adf_addr.in6, &maskp->adf_addr.in6, + &addrp->adf_addr.in6)) { + return -1; + } + return 0; +#else + return -1; +#endif + } + + s = strchr(s, ')'); + if (s == NULL || *++s != ' ') + return -1; + + s++; + + if (inet_aton(s, &a1) != 1) + return -1; + + s = strchr(s, ' '); + if (s == NULL || strncmp(s, " - ", 3)) + return -1; + + s += 3; + if (inet_aton(s, &a2) != 1) + return -1; + + addrp->adf_addr.in4 = a1; + addrp->adf_family = AF_INET; + addrp->adf_len = offsetof(addrfamily_t, adf_addr) + + sizeof(struct in_addr); + maskp->adf_addr.in4.s_addr = ~(a2.s_addr ^ a1.s_addr); + + /* + * If the mask that's been generated isn't a consecutive mask then + * we can't add it into a pool. + */ + if (count4bits(maskp->adf_addr.in4.s_addr) == -1) + return -1; + + maskp->adf_family = AF_INET; + maskp->adf_len = addrp->adf_len; + bzero((char *)maskp + maskp->adf_len, sizeof(*maskp) - maskp->adf_len); + if ((addrp->adf_addr.in4.s_addr & maskp->adf_addr.in4.s_addr) != + addrp->adf_addr.in4.s_addr) + return -1; + return 0; +} diff --git a/contrib/ipfilter/lib/poolio.c b/contrib/ipfilter/lib/poolio.c new file mode 100644 index 0000000..18cf698 --- /dev/null +++ b/contrib/ipfilter/lib/poolio.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: poolio.c,v 1.1.2.3 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" + +static int poolfd = -1; + + +int +pool_open() +{ + + if ((opts & OPT_DONTOPEN) != 0) + return 0; + + if (poolfd == -1) + poolfd = open(IPLOOKUP_NAME, O_RDWR); + return poolfd; +} + +int +pool_ioctl(iocfunc, cmd, ptr) + ioctlfunc_t iocfunc; + ioctlcmd_t cmd; + void *ptr; +{ + return (*iocfunc)(poolfd, cmd, ptr); +} + + +void +pool_close() +{ + if (poolfd != -1) { + close(poolfd); + poolfd = -1; + } +} + +int +pool_fd() +{ + return poolfd; +} diff --git a/contrib/ipfilter/lib/portname.c b/contrib/ipfilter/lib/portname.c new file mode 100644 index 0000000..59345f4 --- /dev/null +++ b/contrib/ipfilter/lib/portname.c @@ -0,0 +1,43 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + + +char *portname(pr, port) + int pr, port; +{ + static char buf[32]; + struct protoent *p = NULL; + struct servent *sv = NULL; + struct servent *sv1 = NULL; + + if ((opts & OPT_NORESOLVE) == 0) { + if (pr == -1) { + if ((sv = getservbyport(htons(port), "tcp"))) { + strncpy(buf, sv->s_name, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + sv1 = getservbyport(htons(port), "udp"); + sv = strncasecmp(buf, sv->s_name, strlen(buf)) ? + NULL : sv1; + } + if (sv) + return buf; + } else if ((pr != -2) && (p = getprotobynumber(pr))) { + if ((sv = getservbyport(htons(port), p->p_name))) { + strncpy(buf, sv->s_name, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + return buf; + } + } + } + + (void) sprintf(buf, "%d", port); + return buf; +} diff --git a/contrib/ipfilter/lib/prependmbt.c b/contrib/ipfilter/lib/prependmbt.c new file mode 100644 index 0000000..4f7220b --- /dev/null +++ b/contrib/ipfilter/lib/prependmbt.c @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: prependmbt.c,v 1.3.2.3 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + +int prependmbt(fin, m) + fr_info_t *fin; + mb_t *m; +{ + m->mb_next = *fin->fin_mp; + *fin->fin_mp = m; + return 0; +} diff --git a/contrib/ipfilter/lib/print_toif.c b/contrib/ipfilter/lib/print_toif.c new file mode 100644 index 0000000..fb4a266 --- /dev/null +++ b/contrib/ipfilter/lib/print_toif.c @@ -0,0 +1,50 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void +print_toif(family, tag, base, fdp) + int family; + char *tag; + char *base; + frdest_t *fdp; +{ + switch (fdp->fd_type) + { + case FRD_NORMAL : + PRINTF("%s %s%s", tag, base + fdp->fd_name, + (fdp->fd_ptr || (long)fdp->fd_ptr == -1) ? "" : "(!)"); +#ifdef USE_INET6 + if (family == AF_INET6) { + if (IP6_NOTZERO(&fdp->fd_ip6)) { + char ipv6addr[80]; + + inet_ntop(AF_INET6, &fdp->fd_ip6, ipv6addr, + sizeof(fdp->fd_ip6)); + PRINTF(":%s", ipv6addr); + } + } else +#endif + if (fdp->fd_ip.s_addr) + PRINTF(":%s", inet_ntoa(fdp->fd_ip)); + putchar(' '); + break; + + case FRD_DSTLIST : + PRINTF("%s dstlist/%s ", tag, base + fdp->fd_name); + break; + + default : + PRINTF("%s <%d>", tag, fdp->fd_type); + break; + } +} diff --git a/contrib/ipfilter/lib/printactiveaddr.c b/contrib/ipfilter/lib/printactiveaddr.c new file mode 100644 index 0000000..531cdc1 --- /dev/null +++ b/contrib/ipfilter/lib/printactiveaddr.c @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ + +#include "ipf.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: printactiveaddr.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $"; +#endif + + +void +printactiveaddress(v, fmt, addr, ifname) + int v; + char *fmt, *ifname; + i6addr_t *addr; +{ + switch (v) + { + case 4 : + PRINTF(fmt, inet_ntoa(addr->in4)); + break; +#ifdef USE_INET6 + case 6 : + printaddr(AF_INET6, FRI_NORMAL, ifname, 0, + (u_32_t *)&addr->in6, NULL); + break; +#endif + default : + break; + } +} diff --git a/contrib/ipfilter/lib/printactivenat.c b/contrib/ipfilter/lib/printactivenat.c new file mode 100644 index 0000000..c696c0b --- /dev/null +++ b/contrib/ipfilter/lib/printactivenat.c @@ -0,0 +1,149 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ + +#include "ipf.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + + +void +printactivenat(nat, opts, ticks) + nat_t *nat; + int opts; + u_long ticks; +{ + + PRINTF("%s", getnattype(nat)); + + if (nat->nat_flags & SI_CLONE) + PRINTF(" CLONE"); + if (nat->nat_phnext[0] == NULL && nat->nat_phnext[1] == NULL) + PRINTF(" ORPHAN"); + + putchar(' '); + if (nat->nat_redir & NAT_REWRITE) { + printactiveaddress(nat->nat_v[0], "%-15s", &nat->nat_osrc6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %-5hu", ntohs(nat->nat_osport)); + + putchar(' '); + printactiveaddress(nat->nat_v[0], "%-15s", &nat->nat_odst6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %-5hu", ntohs(nat->nat_odport)); + + PRINTF("<- -> "); + printactiveaddress(nat->nat_v[1], "%-15s", &nat->nat_nsrc6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %-5hu", ntohs(nat->nat_nsport)); + + putchar(' '); + printactiveaddress(nat->nat_v[1], "%-15s", &nat->nat_ndst6, + nat->nat_ifnames[0]); + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %-5hu", ntohs(nat->nat_ndport)); + + } else if (nat->nat_dir == NAT_OUTBOUND) { + printactiveaddress(nat->nat_v[0], "%-15s", &nat->nat_osrc6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %-5hu", ntohs(nat->nat_osport)); + + PRINTF(" <- -> "); + printactiveaddress(nat->nat_v[1], "%-15s", &nat->nat_nsrc6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %-5hu", ntohs(nat->nat_nsport)); + + PRINTF(" ["); + printactiveaddress(nat->nat_v[0], "%s", &nat->nat_odst6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %hu", ntohs(nat->nat_odport)); + PRINTF("]"); + } else { + printactiveaddress(nat->nat_v[1], "%-15s", &nat->nat_ndst6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %-5hu", ntohs(nat->nat_ndport)); + + PRINTF(" <- -> "); + printactiveaddress(nat->nat_v[0], "%-15s", &nat->nat_odst6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %-5hu", ntohs(nat->nat_odport)); + + PRINTF(" ["); + printactiveaddress(nat->nat_v[0], "%s", &nat->nat_osrc6, + nat->nat_ifnames[0]); + + if ((nat->nat_flags & IPN_TCPUDP) != 0) + PRINTF(" %hu", ntohs(nat->nat_osport)); + PRINTF("]"); + } + + if (opts & OPT_VERBOSE) { + PRINTF("\n\tttl %lu use %hu sumd %s/", + nat->nat_age - ticks, nat->nat_use, + getsumd(nat->nat_sumd[0])); + PRINTF("%s pr %u/%u hash %u/%u flags %x\n", + getsumd(nat->nat_sumd[1]), + nat->nat_pr[0], nat->nat_pr[1], + nat->nat_hv[0], nat->nat_hv[1], nat->nat_flags); + PRINTF("\tifp %s", getifname(nat->nat_ifps[0])); + PRINTF(",%s ", getifname(nat->nat_ifps[1])); +#ifdef USE_QUAD_T + PRINTF("bytes %"PRIu64"/%"PRIu64" pkts %"PRIu64"/%"PRIu64"", + (unsigned long long)nat->nat_bytes[0], + (unsigned long long)nat->nat_bytes[1], + (unsigned long long)nat->nat_pkts[0], + (unsigned long long)nat->nat_pkts[1]); +#else + PRINTF("bytes %lu/%lu pkts %lu/%lu", nat->nat_bytes[0], + nat->nat_bytes[1], nat->nat_pkts[0], nat->nat_pkts[1]); +#endif + PRINTF(" ipsumd %x", nat->nat_ipsumd); + } + + if (opts & OPT_DEBUG) { + PRINTF("\n\tnat_next %p _pnext %p _hm %p\n", + nat->nat_next, nat->nat_pnext, nat->nat_hm); + PRINTF("\t_hnext %p/%p _phnext %p/%p\n", + nat->nat_hnext[0], nat->nat_hnext[1], + nat->nat_phnext[0], nat->nat_phnext[1]); + PRINTF("\t_data %p _me %p _state %p _aps %p\n", + nat->nat_data, nat->nat_me, nat->nat_state, + nat->nat_aps); + PRINTF("\tfr %p ptr %p ifps %p/%p sync %p\n", + nat->nat_fr, nat->nat_ptr, nat->nat_ifps[0], + nat->nat_ifps[1], nat->nat_sync); + PRINTF("\ttqe:pnext %p next %p ifq %p parent %p/%p\n", + nat->nat_tqe.tqe_pnext, nat->nat_tqe.tqe_next, + nat->nat_tqe.tqe_ifq, nat->nat_tqe.tqe_parent, nat); + PRINTF("\ttqe:die %d touched %d flags %x state %d/%d\n", + nat->nat_tqe.tqe_die, nat->nat_tqe.tqe_touched, + nat->nat_tqe.tqe_flags, nat->nat_tqe.tqe_state[0], + nat->nat_tqe.tqe_state[1]); + } + putchar('\n'); +} diff --git a/contrib/ipfilter/lib/printaddr.c b/contrib/ipfilter/lib/printaddr.c new file mode 100644 index 0000000..03fbacb --- /dev/null +++ b/contrib/ipfilter/lib/printaddr.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +void +printaddr(family, type, base, ifidx, addr, mask) + int family, type, ifidx; + char *base; + u_32_t *addr, *mask; +{ + char *suffix; + + switch (type) + { + case FRI_BROADCAST : + suffix = "bcast"; + break; + + case FRI_DYNAMIC : + PRINTF("%s", base + ifidx); + printmask(family, mask); + suffix = NULL; + break; + + case FRI_NETWORK : + suffix = "net"; + break; + + case FRI_NETMASKED : + suffix = "netmasked"; + break; + + case FRI_PEERADDR : + suffix = "peer"; + break; + + case FRI_LOOKUP : + suffix = NULL; + printlookup(base, (i6addr_t *)addr, (i6addr_t *)mask); + break; + + case FRI_NONE : + case FRI_NORMAL : + printhostmask(family, addr, mask); + suffix = NULL; + break; + case FRI_RANGE : + printhost(family, addr); + putchar('-'); + printhost(family, mask); + suffix = NULL; + break; + case FRI_SPLIT : + printhost(family, addr); + putchar(','); + printhost(family, mask); + suffix = NULL; + break; + default : + PRINTF("<%d>", type); + printmask(family, mask); + suffix = NULL; + break; + } + + if (suffix != NULL) { + PRINTF("%s/%s", base + ifidx, suffix); + } +} diff --git a/contrib/ipfilter/lib/printaps.c b/contrib/ipfilter/lib/printaps.c new file mode 100644 index 0000000..0304f34 --- /dev/null +++ b/contrib/ipfilter/lib/printaps.c @@ -0,0 +1,113 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ + +#include "ipf.h" +#include "kmem.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + + +void +printaps(aps, opts, proto) + ap_session_t *aps; + int opts, proto; +{ + ipsec_pxy_t ipsec; + ap_session_t ap; + ftpinfo_t ftp; + aproxy_t apr; + raudio_t ra; + + if (kmemcpy((char *)&ap, (long)aps, sizeof(ap))) + return; + if (kmemcpy((char *)&apr, (long)ap.aps_apr, sizeof(apr))) + return; + PRINTF("\tproxy %s/%d use %d flags %x\n", apr.apr_label, + apr.apr_p, apr.apr_ref, apr.apr_flags); +#ifdef USE_QUAD_T + PRINTF("\tbytes %"PRIu64" pkts %"PRIu64"", + (unsigned long long)ap.aps_bytes, + (unsigned long long)ap.aps_pkts); +#else + PRINTF("\tbytes %lu pkts %lu", ap.aps_bytes, ap.aps_pkts); +#endif + PRINTF(" data %s\n", ap.aps_data ? "YES" : "NO"); + if ((proto == IPPROTO_TCP) && (opts & OPT_VERBOSE)) { + PRINTF("\t\tstate[%u,%u], sel[%d,%d]\n", + ap.aps_state[0], ap.aps_state[1], + ap.aps_sel[0], ap.aps_sel[1]); +#if (defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011)) || \ + (__FreeBSD_version >= 300000) || defined(OpenBSD) + PRINTF("\t\tseq: off %hd/%hd min %x/%x\n", + ap.aps_seqoff[0], ap.aps_seqoff[1], + ap.aps_seqmin[0], ap.aps_seqmin[1]); + PRINTF("\t\tack: off %hd/%hd min %x/%x\n", + ap.aps_ackoff[0], ap.aps_ackoff[1], + ap.aps_ackmin[0], ap.aps_ackmin[1]); +#else + PRINTF("\t\tseq: off %hd/%hd min %lx/%lx\n", + ap.aps_seqoff[0], ap.aps_seqoff[1], + ap.aps_seqmin[0], ap.aps_seqmin[1]); + PRINTF("\t\tack: off %hd/%hd min %lx/%lx\n", + ap.aps_ackoff[0], ap.aps_ackoff[1], + ap.aps_ackmin[0], ap.aps_ackmin[1]); +#endif + } + + if (!strcmp(apr.apr_label, "raudio") && ap.aps_psiz == sizeof(ra)) { + if (kmemcpy((char *)&ra, (long)ap.aps_data, sizeof(ra))) + return; + PRINTF("\tReal Audio Proxy:\n"); + PRINTF("\t\tSeen PNA: %d\tVersion: %d\tEOS: %d\n", + ra.rap_seenpna, ra.rap_version, ra.rap_eos); + PRINTF("\t\tMode: %#x\tSBF: %#x\n", ra.rap_mode, ra.rap_sbf); + PRINTF("\t\tPorts:pl %hu, pr %hu, sr %hu\n", + ra.rap_plport, ra.rap_prport, ra.rap_srport); + } else if (!strcmp(apr.apr_label, "ftp") && + (ap.aps_psiz == sizeof(ftp))) { + if (kmemcpy((char *)&ftp, (long)ap.aps_data, sizeof(ftp))) + return; + PRINTF("\tFTP Proxy:\n"); + PRINTF("\t\tpassok: %d\n", ftp.ftp_passok); + ftp.ftp_side[0].ftps_buf[FTP_BUFSZ - 1] = '\0'; + ftp.ftp_side[1].ftps_buf[FTP_BUFSZ - 1] = '\0'; + PRINTF("\tClient:\n"); + PRINTF("\t\tseq %x (ack %x) len %d junk %d cmds %d\n", + ftp.ftp_side[0].ftps_seq[0], + ftp.ftp_side[0].ftps_seq[1], + ftp.ftp_side[0].ftps_len, ftp.ftp_side[0].ftps_junk, + ftp.ftp_side[0].ftps_cmds); + PRINTF("\t\tbuf ["); + printbuf(ftp.ftp_side[0].ftps_buf, FTP_BUFSZ, 1); + PRINTF("]\n\tServer:\n"); + PRINTF("\t\tseq %x (ack %x) len %d junk %d cmds %d\n", + ftp.ftp_side[1].ftps_seq[0], + ftp.ftp_side[1].ftps_seq[1], + ftp.ftp_side[1].ftps_len, ftp.ftp_side[1].ftps_junk, + ftp.ftp_side[1].ftps_cmds); + PRINTF("\t\tbuf ["); + printbuf(ftp.ftp_side[1].ftps_buf, FTP_BUFSZ, 1); + PRINTF("]\n"); + } else if (!strcmp(apr.apr_label, "ipsec") && + (ap.aps_psiz == sizeof(ipsec))) { + if (kmemcpy((char *)&ipsec, (long)ap.aps_data, sizeof(ipsec))) + return; + PRINTF("\tIPSec Proxy:\n"); + PRINTF("\t\tICookie %08x%08x RCookie %08x%08x %s\n", + (u_int)ntohl(ipsec.ipsc_icookie[0]), + (u_int)ntohl(ipsec.ipsc_icookie[1]), + (u_int)ntohl(ipsec.ipsc_rcookie[0]), + (u_int)ntohl(ipsec.ipsc_rcookie[1]), + ipsec.ipsc_rckset ? "(Set)" : "(Not set)"); + } +} diff --git a/contrib/ipfilter/lib/printbuf.c b/contrib/ipfilter/lib/printbuf.c new file mode 100644 index 0000000..4e9236f0 --- /dev/null +++ b/contrib/ipfilter/lib/printbuf.c @@ -0,0 +1,34 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <ctype.h> + +#include "ipf.h" + + +void +printbuf(buf, len, zend) + char *buf; + int len, zend; +{ + char *s; + int c; + int i; + + for (s = buf, i = len; i; i--) { + c = *s++; + if (isprint(c)) + putchar(c); + else + PRINTF("\\%03o", c); + if ((c == '\0') && zend) + break; + } +} diff --git a/contrib/ipfilter/lib/printdstl_live.c b/contrib/ipfilter/lib/printdstl_live.c new file mode 100644 index 0000000..c8741ed --- /dev/null +++ b/contrib/ipfilter/lib/printdstl_live.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ipl.h" + + +/* + * Because the ipf_dstnode_t can vary in size because of the interface name, + * the size may be larger than just sizeof(). + */ +ippool_dst_t * +printdstl_live(d, fd, name, opts, fields) + ippool_dst_t *d; + int fd; + char *name; + int opts; + wordtab_t *fields; +{ + ipf_dstnode_t *entry, *zero; + ipflookupiter_t iter; + int printed, last; + ipfobj_t obj; + + if ((name != NULL) && strncmp(name, d->ipld_name, FR_GROUPLEN)) + return d->ipld_next; + + entry = calloc(1, sizeof(*entry) + 64); + if (entry == NULL) + return d->ipld_next; + zero = calloc(1, sizeof(*zero) + 64); + if (zero == NULL) { + free(entry); + return d->ipld_next; + } + + if (fields == NULL) + printdstlistdata(d, opts); + + if ((d->ipld_flags & IPHASH_DELETE) != 0) + PRINTF("# "); + + if ((opts & OPT_DEBUG) == 0) + PRINTF("\t{"); + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_LOOKUPITER; + obj.ipfo_ptr = &iter; + obj.ipfo_size = sizeof(iter); + + iter.ili_data = entry; + iter.ili_type = IPLT_DSTLIST; + iter.ili_otype = IPFLOOKUPITER_NODE; + iter.ili_ival = IPFGENITER_LOOKUP; + iter.ili_unit = d->ipld_unit; + strncpy(iter.ili_name, d->ipld_name, FR_GROUPLEN); + + last = 0; + printed = 0; + + while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) { + if (entry->ipfd_next == NULL) + last = 1; + if (bcmp((char *)zero, (char *)entry, sizeof(*zero)) == 0) + break; + (void) printdstlistnode(entry, bcopywrap, opts, fields); + printed++; + } + + (void) ioctl(fd, SIOCIPFDELTOK, &iter.ili_key); + free(entry); + free(zero); + + if (printed == 0) + putchar(';'); + + if ((opts & OPT_DEBUG) == 0) + PRINTF(" };\n"); + return d->ipld_next; +} diff --git a/contrib/ipfilter/lib/printdstlist.c b/contrib/ipfilter/lib/printdstlist.c new file mode 100644 index 0000000..829a1d2 --- /dev/null +++ b/contrib/ipfilter/lib/printdstlist.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +ippool_dst_t * +printdstlist(pp, copyfunc, name, opts, nodes, fields) + ippool_dst_t *pp; + copyfunc_t copyfunc; + char *name; + int opts; + ipf_dstnode_t *nodes; + wordtab_t *fields; +{ + ipf_dstnode_t *node; + ippool_dst_t dst; + + if ((*copyfunc)(pp, &dst, sizeof(dst))) + return NULL; + + if ((name != NULL) && strncmp(name, dst.ipld_name, FR_GROUPLEN)) + return dst.ipld_next; + + if (fields == NULL) + printdstlistdata(&dst, opts); + + if ((dst.ipld_flags & IPDST_DELETE) != 0) + PRINTF("# "); + if ((opts & OPT_DEBUG) == 0) + PRINTF("\t{"); + + if (nodes == NULL) { + putchar(';'); + } else { + for (node = nodes; node != NULL; ) { + ipf_dstnode_t *n; + + n = calloc(1, node->ipfd_size); + if (n == NULL) + break; + if ((*copyfunc)(node, n, node->ipfd_size)) { + free(n); + return NULL; + } + + node = printdstlistnode(n, bcopywrap, opts, fields); + + free(n); + } + } + + if ((opts & OPT_DEBUG) == 0) + PRINTF(" };\n"); + + return dst.ipld_next; +} diff --git a/contrib/ipfilter/lib/printdstlistdata.c b/contrib/ipfilter/lib/printdstlistdata.c new file mode 100644 index 0000000..8b55afd --- /dev/null +++ b/contrib/ipfilter/lib/printdstlistdata.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" +#include <ctype.h> + + +void +printdstlistdata(pool, opts) + ippool_dst_t *pool; + int opts; +{ + + if ((opts & OPT_DEBUG) == 0) { + if ((pool->ipld_flags & IPDST_DELETE) != 0) + PRINTF("# "); + PRINTF("pool "); + } else { + if ((pool->ipld_flags & IPDST_DELETE) != 0) + PRINTF("# "); + PRINTF("Name: %s\tRole: ", pool->ipld_name); + } + + printunit(pool->ipld_unit); + + if ((opts & OPT_DEBUG) == 0) { + PRINTF("/dstlist (name %s;", pool->ipld_name); + if (pool->ipld_policy != IPLDP_NONE) { + PRINTF(" policy "); + printdstlistpolicy(pool->ipld_policy); + putchar(';'); + } + PRINTF(")\n"); + } else { + putchar(' '); + + PRINTF("\tReferences: %d\n", pool->ipld_ref); + if ((pool->ipld_flags & IPDST_DELETE) != 0) + PRINTF("# "); + PRINTF("Policy: \n"); + printdstlistpolicy(pool->ipld_policy); + PRINTF("\n\tNodes Starting at %p\n", pool->ipld_dests); + } +} diff --git a/contrib/ipfilter/lib/printdstlistnode.c b/contrib/ipfilter/lib/printdstlistnode.c new file mode 100644 index 0000000..898986d --- /dev/null +++ b/contrib/ipfilter/lib/printdstlistnode.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +ipf_dstnode_t * +printdstlistnode(inp, copyfunc, opts, fields) + ipf_dstnode_t *inp; + copyfunc_t copyfunc; + int opts; + wordtab_t *fields; +{ + ipf_dstnode_t node, *np; + int i; +#ifdef USE_INET6 + char buf[INET6_ADDRSTRLEN+1]; + const char *str; +#endif + + if ((*copyfunc)(inp, &node, sizeof(node))) + return NULL; + + np = calloc(1, node.ipfd_size); + if (np == NULL) + return node.ipfd_next; + if ((*copyfunc)(inp, np, node.ipfd_size)) + return NULL; + + if (fields != NULL) { + for (i = 0; fields[i].w_value != 0; i++) { + printpoolfield(np, IPLT_DSTLIST, i); + if (fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } else if ((opts & OPT_DEBUG) == 0) { + putchar(' '); + if (np->ipfd_dest.fd_name >= 0) + PRINTF("%s:", np->ipfd_names); + if (np->ipfd_dest.fd_addr.adf_family == AF_INET) { + printip(AF_INET, (u_32_t *)&np->ipfd_dest.fd_ip); + } else { +#ifdef USE_INET6 + str = inet_ntop(AF_INET6, &np->ipfd_dest.fd_ip6, + buf, sizeof(buf) - 1); + if (str != NULL) + PRINTF("%s", str); +#endif + } + putchar(';'); + } else { + PRINTF("Interface: [%s]/%d\n", np->ipfd_names, + np->ipfd_dest.fd_name); +#ifdef USE_INET6 + str = inet_ntop(np->ipfd_dest.fd_addr.adf_family, + &np->ipfd_dest.fd_ip6, buf, sizeof(buf) - 1); + if (str != NULL) { + PRINTF("\tAddress: %s\n", str); + } +#else + PRINTF("\tAddress: %s\n", inet_ntoa(np->ipfd_dest.fd_ip)); +#endif + PRINTF( +#ifdef USE_QUAD_T + "\t\tStates %d\tRef %d\tName [%s]\tUid %d\n", +#else + "\t\tStates %d\tRef %d\tName [%s]\tUid %d\n", +#endif + np->ipfd_states, np->ipfd_ref, + np->ipfd_names, np->ipfd_uid); + } + free(np); + return node.ipfd_next; +} diff --git a/contrib/ipfilter/lib/printdstlistpolicy.c b/contrib/ipfilter/lib/printdstlistpolicy.c new file mode 100644 index 0000000..4873b95 --- /dev/null +++ b/contrib/ipfilter/lib/printdstlistpolicy.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +void +printdstlistpolicy(policy) + ippool_policy_t policy; +{ + switch (policy) + { + case IPLDP_NONE : + PRINTF("none"); + break; + case IPLDP_ROUNDROBIN : + PRINTF("round-robin"); + break; + case IPLDP_CONNECTION : + PRINTF("weighting connection"); + break; + case IPLDP_RANDOM : + PRINTF("random"); + break; + default : + break; + } +} diff --git a/contrib/ipfilter/lib/printfieldhdr.c b/contrib/ipfilter/lib/printfieldhdr.c new file mode 100644 index 0000000..3cc22a6 --- /dev/null +++ b/contrib/ipfilter/lib/printfieldhdr.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: printfieldhdr.c,v 1.5.2.3 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" +#include <ctype.h> + + +void +printfieldhdr(words, field) + wordtab_t *words, *field; +{ + wordtab_t *w; + char *s, *t; + int i; + + if (field->w_value == -2) { + for (i = 0, w = words; w->w_word != NULL; ) { + if (w->w_value > 0) { + printfieldhdr(words, w); + w++; + if (w->w_value > 0) + putchar('\t'); + } else { + w++; + } + } + return; + } + + for (w = words; w->w_word != NULL; w++) { + if (w->w_value == field->w_value) { + if (w->w_word == field->w_word) { + s = strdup(w->w_word); + } else { + s = NULL; + } + + if ((w->w_word != field->w_word) || (s == NULL)) { + PRINTF("%s", field->w_word); + } else { + for (t = s; *t != '\0'; t++) { + if (ISALPHA(*t) && ISLOWER(*t)) + *t = TOUPPER(*t); + } + PRINTF("%s", s); + free(s); + } + } + } +} diff --git a/contrib/ipfilter/lib/printfr.c b/contrib/ipfilter/lib/printfr.c new file mode 100644 index 0000000..9883df4 --- /dev/null +++ b/contrib/ipfilter/lib/printfr.c @@ -0,0 +1,473 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +/* + * print the filter structure in a useful way + */ +void +printfr(fp, iocfunc) + struct frentry *fp; + ioctlfunc_t iocfunc; +{ + struct protoent *p; + u_short sec[2]; + u_32_t type; + int pr, af; + char *s; + int hash; + + pr = -2; + type = fp->fr_type & ~FR_T_BUILTIN; + + if ((fp->fr_type & FR_T_BUILTIN) != 0) + PRINTF("# Builtin: "); + + if (fp->fr_collect != 0) + PRINTF("%u ", fp->fr_collect); + + if (fp->fr_type == FR_T_CALLFUNC) { + ; + } else if (fp->fr_func != NULL) { + PRINTF("call"); + if ((fp->fr_flags & FR_CALLNOW) != 0) + PRINTF(" now"); + s = kvatoname(fp->fr_func, iocfunc); + PRINTF(" %s/%u", s ? s : "?", fp->fr_arg); + } else if (FR_ISPASS(fp->fr_flags)) + PRINTF("pass"); + else if (FR_ISBLOCK(fp->fr_flags)) { + PRINTF("block"); + } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) { + printlog(fp); + } else if (FR_ISACCOUNT(fp->fr_flags)) + PRINTF("count"); + else if (FR_ISAUTH(fp->fr_flags)) + PRINTF("auth"); + else if (FR_ISPREAUTH(fp->fr_flags)) + PRINTF("preauth"); + else if (FR_ISNOMATCH(fp->fr_flags)) + PRINTF("nomatch"); + else if (FR_ISDECAPS(fp->fr_flags)) + PRINTF("decapsulate"); + else if (FR_ISSKIP(fp->fr_flags)) + PRINTF("skip %u", fp->fr_arg); + else { + PRINTF("%x", fp->fr_flags); + } + if (fp->fr_flags & FR_RETICMP) { + if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP) + PRINTF(" return-icmp-as-dest"); + else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP) + PRINTF(" return-icmp"); + if (fp->fr_icode) { + if (fp->fr_icode <= MAX_ICMPCODE) + PRINTF("(%s)", + icmpcodes[(int)fp->fr_icode]); + else + PRINTF("(%d)", fp->fr_icode); + } + } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST) + PRINTF(" return-rst"); + + if (fp->fr_flags & FR_OUTQUE) + PRINTF(" out "); + else if (fp->fr_flags & FR_INQUE) + PRINTF(" in "); + + if (((fp->fr_flags & FR_LOGB) == FR_LOGB) || + ((fp->fr_flags & FR_LOGP) == FR_LOGP)) { + printlog(fp); + putchar(' '); + } + + if (fp->fr_flags & FR_QUICK) + PRINTF("quick "); + + if (fp->fr_ifnames[0] != -1) { + printifname("on ", fp->fr_names + fp->fr_ifnames[0], + fp->fr_ifa); + if (fp->fr_ifnames[1] != -1 && + strcmp(fp->fr_names + fp->fr_ifnames[1], "*")) + printifname(",", fp->fr_names + fp->fr_ifnames[1], + fp->fr_ifas[1]); + putchar(' '); + } + + if (fp->fr_tif.fd_name != -1) + print_toif(fp->fr_family, "to", fp->fr_names, &fp->fr_tif); + if (fp->fr_dif.fd_name != -1) + print_toif(fp->fr_family, "dup-to", fp->fr_names, + &fp->fr_dif); + if (fp->fr_rif.fd_name != -1) + print_toif(fp->fr_family, "reply-to", fp->fr_names, + &fp->fr_rif); + if (fp->fr_flags & FR_FASTROUTE) + PRINTF("fastroute "); + + if ((fp->fr_ifnames[2] != -1 && + strcmp(fp->fr_names + fp->fr_ifnames[2], "*")) || + (fp->fr_ifnames[3] != -1 && + strcmp(fp->fr_names + fp->fr_ifnames[3], "*"))) { + if (fp->fr_flags & FR_OUTQUE) + PRINTF("in-via "); + else + PRINTF("out-via "); + + if (fp->fr_ifnames[2] != -1) { + printifname("", fp->fr_names + fp->fr_ifnames[2], + fp->fr_ifas[2]); + if (fp->fr_ifnames[3] != -1) { + printifname(",", + fp->fr_names + fp->fr_ifnames[3], + fp->fr_ifas[3]); + } + putchar(' '); + } + } + + if (fp->fr_family == AF_INET) { + PRINTF("inet "); + af = AF_INET; +#ifdef USE_INET6 + } else if (fp->fr_family == AF_INET6) { + PRINTF("inet6 "); + af = AF_INET6; +#endif + } else { + af = -1; + } + + if (type == FR_T_IPF) { + if (fp->fr_mip.fi_tos) + PRINTF("tos %#x ", fp->fr_tos); + if (fp->fr_mip.fi_ttl) + PRINTF("ttl %d ", fp->fr_ttl); + if (fp->fr_flx & FI_TCPUDP) { + PRINTF("proto tcp/udp "); + pr = -1; + } else if (fp->fr_mip.fi_p) { + pr = fp->fr_ip.fi_p; + p = getprotobynumber(pr); + PRINTF("proto "); + printproto(p, pr, NULL); + putchar(' '); + } + } + + switch (type) + { + case FR_T_NONE : + PRINTF("all"); + break; + + case FR_T_IPF : + PRINTF("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : ""); + printaddr(af, fp->fr_satype, fp->fr_names, fp->fr_ifnames[0], + &fp->fr_src.s_addr, &fp->fr_smsk.s_addr); + if (fp->fr_scmp) + printportcmp(pr, &fp->fr_tuc.ftu_src); + + PRINTF(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : ""); + printaddr(af, fp->fr_datype, fp->fr_names, fp->fr_ifnames[0], + &fp->fr_dst.s_addr, &fp->fr_dmsk.s_addr); + if (fp->fr_dcmp) + printportcmp(pr, &fp->fr_tuc.ftu_dst); + + if (((fp->fr_proto == IPPROTO_ICMP) || + (fp->fr_proto == IPPROTO_ICMPV6)) && fp->fr_icmpm) { + int type = fp->fr_icmp, code; + char *name; + + type = ntohs(fp->fr_icmp); + code = type & 0xff; + type /= 256; + name = icmptypename(fp->fr_family, type); + if (name == NULL) + PRINTF(" icmp-type %d", type); + else + PRINTF(" icmp-type %s", name); + if (ntohs(fp->fr_icmpm) & 0xff) + PRINTF(" code %d", code); + } + if ((fp->fr_proto == IPPROTO_TCP) && + (fp->fr_tcpf || fp->fr_tcpfm)) { + PRINTF(" flags "); + printtcpflags(fp->fr_tcpf, fp->fr_tcpfm); + } + break; + + case FR_T_BPFOPC : + { + fakebpf_t *fb; + int i; + + PRINTF("bpf-v%d { \"", fp->fr_family); + i = fp->fr_dsize / sizeof(*fb); + + for (fb = fp->fr_data, s = ""; i; i--, fb++, s = " ") + PRINTF("%s%#x %#x %#x %#x", s, fb->fb_c, fb->fb_t, + fb->fb_f, fb->fb_k); + + PRINTF("\" }"); + break; + } + + case FR_T_COMPIPF : + break; + + case FR_T_CALLFUNC : + PRINTF("call function at %p", fp->fr_data); + break; + + case FR_T_IPFEXPR : + PRINTF("exp { \""); + printipfexpr(fp->fr_data); + PRINTF("\" } "); + break; + + default : + PRINTF("[unknown filter type %#x]", fp->fr_type); + break; + } + + if ((type == FR_T_IPF) && + ((fp->fr_flx & FI_WITH) || (fp->fr_mflx & FI_WITH) || + fp->fr_optbits || fp->fr_optmask || + fp->fr_secbits || fp->fr_secmask)) { + char *comma = " "; + + PRINTF(" with"); + if (fp->fr_optbits || fp->fr_optmask || + fp->fr_secbits || fp->fr_secmask) { + sec[0] = fp->fr_secmask; + sec[1] = fp->fr_secbits; + if (fp->fr_family == AF_INET) + optprint(sec, fp->fr_optmask, fp->fr_optbits); +#ifdef USE_INET6 + else + optprintv6(sec, fp->fr_optmask, + fp->fr_optbits); +#endif + } else if (fp->fr_mflx & FI_OPTIONS) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_OPTIONS)) + PRINTF("not "); + PRINTF("ipopts"); + comma = ","; + } + if (fp->fr_mflx & FI_SHORT) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_SHORT)) + PRINTF("not "); + PRINTF("short"); + comma = ","; + } + if (fp->fr_mflx & FI_FRAG) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_FRAG)) + PRINTF("not "); + PRINTF("frag"); + comma = ","; + } + if (fp->fr_mflx & FI_FRAGBODY) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_FRAGBODY)) + PRINTF("not "); + PRINTF("frag-body"); + comma = ","; + } + if (fp->fr_mflx & FI_NATED) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_NATED)) + PRINTF("not "); + PRINTF("nat"); + comma = ","; + } + if (fp->fr_mflx & FI_LOWTTL) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_LOWTTL)) + PRINTF("not "); + PRINTF("lowttl"); + comma = ","; + } + if (fp->fr_mflx & FI_BAD) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_BAD)) + PRINTF("not "); + PRINTF("bad"); + comma = ","; + } + if (fp->fr_mflx & FI_BADSRC) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_BADSRC)) + PRINTF("not "); + PRINTF("bad-src"); + comma = ","; + } + if (fp->fr_mflx & FI_BADNAT) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_BADNAT)) + PRINTF("not "); + PRINTF("bad-nat"); + comma = ","; + } + if (fp->fr_mflx & FI_OOW) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_OOW)) + PRINTF("not "); + PRINTF("oow"); + comma = ","; + } + if (fp->fr_mflx & FI_MBCAST) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_MBCAST)) + PRINTF("not "); + PRINTF("mbcast"); + comma = ","; + } + if (fp->fr_mflx & FI_BROADCAST) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_BROADCAST)) + PRINTF("not "); + PRINTF("bcast"); + comma = ","; + } + if (fp->fr_mflx & FI_MULTICAST) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_MULTICAST)) + PRINTF("not "); + PRINTF("mcast"); + comma = ","; + } + if (fp->fr_mflx & FI_STATE) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_STATE)) + PRINTF("not "); + PRINTF("state"); + comma = ","; + } + if (fp->fr_mflx & FI_V6EXTHDR) { + fputs(comma, stdout); + if (!(fp->fr_flx & FI_V6EXTHDR)) + PRINTF("not "); + PRINTF("v6hdrs"); + comma = ","; + } + } + + if (fp->fr_flags & FR_KEEPSTATE) { + host_track_t *src = &fp->fr_srctrack; + PRINTF(" keep state"); + if ((fp->fr_flags & (FR_STSTRICT|FR_NEWISN| + FR_NOICMPERR|FR_STATESYNC)) || + (fp->fr_statemax != 0) || (fp->fr_age[0] != 0) || + (src->ht_max_nodes != 0)) { + char *comma = ""; + PRINTF(" ("); + if (fp->fr_statemax != 0) { + PRINTF("limit %u", fp->fr_statemax); + comma = ","; + } + if (src->ht_max_nodes != 0) { + PRINTF("%smax-nodes %d", comma, + src->ht_max_nodes); + if (src->ht_max_per_node) + PRINTF(", max-per-src %d/%d", + src->ht_max_per_node, + src->ht_netmask); + comma = ","; + } + if (fp->fr_flags & FR_STSTRICT) { + PRINTF("%sstrict", comma); + comma = ","; + } + if (fp->fr_flags & FR_STLOOSE) { + PRINTF("%sloose", comma); + comma = ","; + } + if (fp->fr_flags & FR_NEWISN) { + PRINTF("%snewisn", comma); + comma = ","; + } + if (fp->fr_flags & FR_NOICMPERR) { + PRINTF("%sno-icmp-err", comma); + comma = ","; + } + if (fp->fr_flags & FR_STATESYNC) { + PRINTF("%ssync", comma); + comma = ","; + } + if (fp->fr_age[0] || fp->fr_age[1]) + PRINTF("%sage %d/%d", comma, fp->fr_age[0], + fp->fr_age[1]); + PRINTF(")"); + } + } + if (fp->fr_flags & FR_KEEPFRAG) { + PRINTF(" keep frags"); + if (fp->fr_flags & (FR_FRSTRICT)) { + PRINTF(" ("); + if (fp->fr_flags & FR_FRSTRICT) + PRINTF("strict"); + PRINTF(")"); + + } + } + if (fp->fr_isc != (struct ipscan *)-1) { + if (fp->fr_isctag != -1) + PRINTF(" scan %s", fp->fr_isctag + fp->fr_names); + else + PRINTF(" scan *"); + } + if (fp->fr_grhead != -1) + PRINTF(" head %s", fp->fr_names + fp->fr_grhead); + if (fp->fr_group != -1) + PRINTF(" group %s", fp->fr_names + fp->fr_group); + if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag) { + char *s = ""; + + PRINTF(" set-tag("); + if (fp->fr_logtag != FR_NOLOGTAG) { + PRINTF("log=%u", fp->fr_logtag); + s = ", "; + } + if (*fp->fr_nattag.ipt_tag) { + PRINTF("%snat=%-.*s", s, IPFTAG_LEN, + fp->fr_nattag.ipt_tag); + } + PRINTF(")"); + } + + if (fp->fr_pps) + PRINTF(" pps %d", fp->fr_pps); + + if (fp->fr_comment != -1) + PRINTF(" comment \"%s\"", fp->fr_names + fp->fr_comment); + + hash = 0; + if ((fp->fr_flags & FR_KEEPSTATE) && (opts & OPT_VERBOSE)) { + PRINTF(" # count %d", fp->fr_statecnt); + if (fp->fr_die != 0) + PRINTF(" rule-ttl %u", fp->fr_die); + hash = 1; + } else if (fp->fr_die != 0) { + PRINTF(" # rule-ttl %u", fp->fr_die); + hash = 1; + } + if (opts & OPT_DEBUG) { + if (hash == 0) + putchar('#'); + PRINTF(" ref %d", fp->fr_ref); + } + (void)putchar('\n'); +} diff --git a/contrib/ipfilter/lib/printfraginfo.c b/contrib/ipfilter/lib/printfraginfo.c new file mode 100644 index 0000000..dd2966f --- /dev/null +++ b/contrib/ipfilter/lib/printfraginfo.c @@ -0,0 +1,42 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" +#include "kmem.h" + + +void +printfraginfo(prefix, ifr) + char *prefix; + struct ipfr *ifr; +{ + frentry_t fr; + int family; + + PRINTF("%s", prefix); + if (ifr->ipfr_v == 6) { + PRINTF("inet6"); + family = AF_INET6; + } else { + PRINTF("inet"); + family = AF_INET; + } + fr.fr_flags = 0xffffffff; + + PRINTF(" %s -> ", hostname(family, &ifr->ipfr_src)); +/* + if (kmemcpy((char *)&fr, (u_long)ifr->ipfr_rule, + sizeof(fr)) == -1) + return; + */ + PRINTF("%s id %x ttl %lu pr %d pkts %u bytes %u seen0 %d ref %d\n", + hostname(family, &ifr->ipfr_dst), ifr->ipfr_id, + ifr->ipfr_ttl, ifr->ipfr_p, ifr->ipfr_pkts, ifr->ipfr_bytes, + ifr->ipfr_seen0, ifr->ipfr_ref); +} diff --git a/contrib/ipfilter/lib/printhash.c b/contrib/ipfilter/lib/printhash.c new file mode 100644 index 0000000..3779662 --- /dev/null +++ b/contrib/ipfilter/lib/printhash.c @@ -0,0 +1,58 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +iphtable_t * +printhash(hp, copyfunc, name, opts, fields) + iphtable_t *hp; + copyfunc_t copyfunc; + char *name; + int opts; + wordtab_t *fields; +{ + iphtent_t *ipep, **table; + iphtable_t iph; + int printed; + size_t sz; + + if ((*copyfunc)((char *)hp, (char *)&iph, sizeof(iph))) + return NULL; + + if ((name != NULL) && strncmp(name, iph.iph_name, FR_GROUPLEN)) + return iph.iph_next; + + if (fields == NULL) + printhashdata(hp, opts); + + if ((hp->iph_flags & IPHASH_DELETE) != 0) + PRINTF("# "); + + if ((opts & OPT_DEBUG) == 0) + PRINTF("\t{"); + + sz = iph.iph_size * sizeof(*table); + table = malloc(sz); + if ((*copyfunc)((char *)iph.iph_table, (char *)table, sz)) + return NULL; + + for (printed = 0, ipep = iph.iph_list; ipep != NULL; ) { + ipep = printhashnode(&iph, ipep, copyfunc, opts, fields); + printed++; + } + if (printed == 0) + putchar(';'); + + free(table); + + if ((opts & OPT_DEBUG) == 0) + PRINTF(" };\n"); + + return iph.iph_next; +} diff --git a/contrib/ipfilter/lib/printhash_live.c b/contrib/ipfilter/lib/printhash_live.c new file mode 100644 index 0000000..53159b1 --- /dev/null +++ b/contrib/ipfilter/lib/printhash_live.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ipl.h" + + +iphtable_t * +printhash_live(hp, fd, name, opts, fields) + iphtable_t *hp; + int fd; + char *name; + int opts; + wordtab_t *fields; +{ + iphtent_t entry, zero; + ipflookupiter_t iter; + int last, printed; + ipfobj_t obj; + + if ((name != NULL) && strncmp(name, hp->iph_name, FR_GROUPLEN)) + return hp->iph_next; + + if (fields == NULL) + printhashdata(hp, opts); + + if ((hp->iph_flags & IPHASH_DELETE) != 0) + PRINTF("# "); + + if ((opts & OPT_DEBUG) == 0) + PRINTF("\t{"); + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_LOOKUPITER; + obj.ipfo_ptr = &iter; + obj.ipfo_size = sizeof(iter); + + iter.ili_data = &entry; + iter.ili_type = IPLT_HASH; + iter.ili_otype = IPFLOOKUPITER_NODE; + iter.ili_ival = IPFGENITER_LOOKUP; + iter.ili_unit = hp->iph_unit; + strncpy(iter.ili_name, hp->iph_name, FR_GROUPLEN); + + last = 0; + printed = 0; + bzero((char *)&zero, sizeof(zero)); + + while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) { + if (entry.ipe_next == NULL) + last = 1; + if (bcmp(&zero, &entry, sizeof(zero)) == 0) + break; + (void) printhashnode(hp, &entry, bcopywrap, opts, fields); + printed++; + } + if (last == 0) + ipferror(fd, "walking hash nodes:"); + + if (printed == 0) + putchar(';'); + + if ((opts & OPT_DEBUG) == 0) + PRINTF(" };\n"); + return hp->iph_next; +} diff --git a/contrib/ipfilter/lib/printhashdata.c b/contrib/ipfilter/lib/printhashdata.c new file mode 100644 index 0000000..ea2d416 --- /dev/null +++ b/contrib/ipfilter/lib/printhashdata.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" +#include <ctype.h> + + +void +printhashdata(hp, opts) + iphtable_t *hp; + int opts; +{ + + if ((opts & OPT_DEBUG) == 0) { + if ((hp->iph_type & IPHASH_ANON) == IPHASH_ANON) + PRINTF("# 'anonymous' table refs %d\n", hp->iph_ref); + if ((hp->iph_flags & IPHASH_DELETE) == IPHASH_DELETE) + PRINTF("# "); + switch (hp->iph_type & ~IPHASH_ANON) + { + case IPHASH_LOOKUP : + PRINTF("table"); + break; + case IPHASH_GROUPMAP : + PRINTF("group-map"); + if (hp->iph_flags & FR_INQUE) + PRINTF(" in"); + else if (hp->iph_flags & FR_OUTQUE) + PRINTF(" out"); + else + PRINTF(" ???"); + break; + default : + PRINTF("%#x", hp->iph_type); + break; + } + PRINTF(" role="); + } else { + PRINTF("Hash Table %s: %s", + ISDIGIT(*hp->iph_name) ? "Number" : "Name", + hp->iph_name); + if ((hp->iph_type & IPHASH_ANON) == IPHASH_ANON) + PRINTF("(anon)"); + putchar(' '); + PRINTF("Role: "); + } + + printunit(hp->iph_unit); + + if ((opts & OPT_DEBUG) == 0) { + if ((hp->iph_type & ~IPHASH_ANON) == IPHASH_LOOKUP) + PRINTF(" type=hash"); + PRINTF(" %s=%s size=%lu", + ISDIGIT(*hp->iph_name) ? "number" : "name", + hp->iph_name, (u_long)hp->iph_size); + if (hp->iph_seed != 0) + PRINTF(" seed=%lu", hp->iph_seed); + putchar('\n'); + } else { + PRINTF(" Type: "); + switch (hp->iph_type & ~IPHASH_ANON) + { + case IPHASH_LOOKUP : + PRINTF("lookup"); + break; + case IPHASH_GROUPMAP : + PRINTF("groupmap Group. %s", hp->iph_name); + break; + default : + break; + } + + putchar('\n'); + PRINTF("\t\tSize: %lu\tSeed: %lu", + (u_long)hp->iph_size, hp->iph_seed); + PRINTF("\tRef. Count: %d\tMasks: %#x\n", hp->iph_ref, + hp->iph_maskset[0]); + } + + if ((opts & OPT_DEBUG) != 0) { + struct in_addr m; + int i; + + for (i = 0; i < 32; i++) { + if ((1 << i) & hp->iph_maskset[0]) { + ntomask(AF_INET, i, &m.s_addr); + PRINTF("\t\tMask: %s\n", inet_ntoa(m)); + } + } + } +} diff --git a/contrib/ipfilter/lib/printhashnode.c b/contrib/ipfilter/lib/printhashnode.c new file mode 100644 index 0000000..e245535 --- /dev/null +++ b/contrib/ipfilter/lib/printhashnode.c @@ -0,0 +1,69 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +iphtent_t * +printhashnode(iph, ipep, copyfunc, opts, fields) + iphtable_t *iph; + iphtent_t *ipep; + copyfunc_t copyfunc; + int opts; + wordtab_t *fields; +{ + iphtent_t ipe; + u_int hv; + int i; + + if ((*copyfunc)(ipep, &ipe, sizeof(ipe))) + return NULL; + + hv = IPE_V4_HASH_FN(ipe.ipe_addr.i6[0], ipe.ipe_mask.i6[0], + iph->iph_size); + + if (fields != NULL) { + for (i = 0; fields[i].w_value != 0; i++) { + printpoolfield(&ipe, IPLT_HASH, i); + if (fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } else if ((opts & OPT_DEBUG) != 0) { + PRINTF("\t%d\tAddress: %s", hv, + inet_ntoa(ipe.ipe_addr.in4)); + printmask(ipe.ipe_family, (u_32_t *)&ipe.ipe_mask.in4_addr); + PRINTF("\tRef. Count: %d\tGroup: %s\n", ipe.ipe_ref, + ipe.ipe_group); +#ifdef USE_QUAD_T + PRINTF("\tHits: %"PRIu64"\tBytes: %"PRIu64"\n", + ipe.ipe_hits, ipe.ipe_bytes); +#else + PRINTF("\tHits: %lu\tBytes: %lu\n", + ipe.ipe_hits, ipe.ipe_bytes); +#endif + } else { + putchar(' '); + printip(ipe.ipe_family, (u_32_t *)&ipe.ipe_addr.in4_addr); + printmask(ipe.ipe_family, (u_32_t *)&ipe.ipe_mask.in4_addr); + if (ipe.ipe_value != 0) { + switch (iph->iph_type & ~IPHASH_ANON) + { + case IPHASH_GROUPMAP : + if (strncmp(ipe.ipe_group, iph->iph_name, + FR_GROUPLEN)) + PRINTF(", group=%s", ipe.ipe_group); + break; + } + } + putchar(';'); + } + + ipep = ipe.ipe_next; + return ipep; +} diff --git a/contrib/ipfilter/lib/printhost.c b/contrib/ipfilter/lib/printhost.c new file mode 100644 index 0000000..009a9bb --- /dev/null +++ b/contrib/ipfilter/lib/printhost.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: printhost.c,v 1.3.2.2 2012/07/22 08:04:24 darren_r Exp $ + */ + +#include "ipf.h" + + +void +printhost(family, addr) + int family; + u_32_t *addr; +{ +#ifdef USE_INET6 + char ipbuf[64]; +#else + struct in_addr ipa; +#endif + + if ((family == -1) || !*addr) + PRINTF("any"); + else { +#ifdef USE_INET6 + void *ptr = addr; + + PRINTF("%s", inet_ntop(family, ptr, ipbuf, sizeof(ipbuf))); +#else + ipa.s_addr = *addr; + PRINTF("%s", inet_ntoa(ipa)); +#endif + } +} diff --git a/contrib/ipfilter/lib/printhostmap.c b/contrib/ipfilter/lib/printhostmap.c new file mode 100644 index 0000000..714bc41 --- /dev/null +++ b/contrib/ipfilter/lib/printhostmap.c @@ -0,0 +1,31 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +void +printhostmap(hmp, hv) + hostmap_t *hmp; + u_int hv; +{ + + printactiveaddress(hmp->hm_v, "%s", &hmp->hm_osrcip6, NULL); + putchar(','); + printactiveaddress(hmp->hm_v, "%s", &hmp->hm_odstip6, NULL); + PRINTF(" -> "); + printactiveaddress(hmp->hm_v, "%s", &hmp->hm_nsrcip6, NULL); + putchar(','); + printactiveaddress(hmp->hm_v, "%s", &hmp->hm_ndstip6, NULL); + putchar(' '); + PRINTF("(use = %d", hmp->hm_ref); + if (opts & OPT_VERBOSE) + PRINTF(" hv = %u", hv); + printf(")\n"); +} diff --git a/contrib/ipfilter/lib/printhostmask.c b/contrib/ipfilter/lib/printhostmask.c new file mode 100644 index 0000000..b1e41f9 --- /dev/null +++ b/contrib/ipfilter/lib/printhostmask.c @@ -0,0 +1,39 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void +printhostmask(family, addr, mask) + int family; + u_32_t *addr, *mask; +{ +#ifdef USE_INET6 + char ipbuf[64]; +#else + struct in_addr ipa; +#endif + + if ((family == -1) || ((!addr || !*addr) && (!mask || !*mask))) + PRINTF("any"); + else { +#ifdef USE_INET6 + void *ptr = addr; + + PRINTF("%s", inet_ntop(family, ptr, ipbuf, sizeof(ipbuf))); +#else + ipa.s_addr = *addr; + PRINTF("%s", inet_ntoa(ipa)); +#endif + if (mask != NULL) + printmask(family, mask); + } +} diff --git a/contrib/ipfilter/lib/printifname.c b/contrib/ipfilter/lib/printifname.c new file mode 100644 index 0000000..2e554d9 --- /dev/null +++ b/contrib/ipfilter/lib/printifname.c @@ -0,0 +1,22 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void +printifname(format, name, ifp) + char *format, *name; + void *ifp; +{ + PRINTF("%s%s", format, name); + if ((ifp == NULL) && strcmp(name, "-") && strcmp(name, "*")) + PRINTF("(!)"); +} diff --git a/contrib/ipfilter/lib/printip.c b/contrib/ipfilter/lib/printip.c new file mode 100644 index 0000000..6d414fe --- /dev/null +++ b/contrib/ipfilter/lib/printip.c @@ -0,0 +1,43 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void +printip(family, addr) + int family; + u_32_t *addr; +{ + struct in_addr ipa; + + if (family == AF_INET) { + ipa.s_addr = *addr; + if (ntohl(ipa.s_addr) < 256) + PRINTF("%lu", (u_long)ntohl(ipa.s_addr)); + else + PRINTF("%s", inet_ntoa(ipa)); + } +#ifdef AF_INET6 + else if (family == AF_INET6) { + char buf[INET6_ADDRSTRLEN + 1]; + const char *str; + + buf[0] = '\0'; + str = inet_ntop(AF_INET6, addr, buf, sizeof(buf) - 1); + if (str != NULL) + PRINTF("%s", str); + else + PRINTF("???"); + } +#endif + else + PRINTF("?(%d)?", family); +} diff --git a/contrib/ipfilter/lib/printipfexpr.c b/contrib/ipfilter/lib/printipfexpr.c new file mode 100644 index 0000000..06b987e --- /dev/null +++ b/contrib/ipfilter/lib/printipfexpr.c @@ -0,0 +1,199 @@ +#include "ipf.h" + +static void printport __P((int *)); +static void printhosts __P((int *)); +static void printsingle __P((int *)); +#ifdef USE_INET6 +static void printhostsv6 __P((int *)); +#endif + +void +printipfexpr(array) + int *array; +{ + int i, nelems, j, not; + ipfexp_t *ipfe; + + nelems = array[0]; + + for (i = 1; i < nelems; ) { + ipfe = (ipfexp_t *)(array + i); + if (ipfe->ipfe_cmd == IPF_EXP_END) + break; + + not = ipfe->ipfe_not; + + switch (ipfe->ipfe_cmd) + { + case IPF_EXP_IP_ADDR : + PRINTF("ip.addr %s= ", not ? "!" : ""); + printhosts(array + i); + break; + + case IPF_EXP_IP_PR : + PRINTF("ip.p %s= ", not ? "!" : ""); + printsingle(array + i); + break; + + case IPF_EXP_IP_SRCADDR : + PRINTF("ip.src %s= ", not ? "!" : ""); + printhosts(array + i); + break; + + case IPF_EXP_IP_DSTADDR : + PRINTF("ip.dst %s= ", not ? "!" : ""); + printhosts(array + i); + break; + + case IPF_EXP_TCP_PORT : + PRINTF("tcp.port %s= ", not ? "!" : ""); + printport(array + i); + break; + + case IPF_EXP_TCP_DPORT : + PRINTF("tcp.dport %s= ", not ? "!" : ""); + printport(array + i); + break; + + case IPF_EXP_TCP_SPORT : + PRINTF("tcp.sport %s= ", not ? "!" : ""); + printport(array + i); + break; + + case IPF_EXP_TCP_FLAGS : + PRINTF("tcp.flags %s= ", not ? "!" : ""); + + for (j = 0; j < ipfe->ipfe_narg; ) { + printtcpflags(array[i + 4], array[i + 5]); + j += 2; + if (j < array[4]) + putchar(','); + } + break; + + case IPF_EXP_UDP_PORT : + PRINTF("udp.port %s= ", not ? "!" : ""); + printport(array + i); + break; + + case IPF_EXP_UDP_DPORT : + PRINTF("udp.dport %s= ", not ? "!" : ""); + printport(array + i); + break; + + case IPF_EXP_UDP_SPORT : + PRINTF("udp.sport %s= ", not ? "!" : ""); + printport(array + i); + break; + + case IPF_EXP_IDLE_GT : + PRINTF("idle-gt %s= ", not ? "!" : ""); + printsingle(array + i); + break; + + case IPF_EXP_TCP_STATE : + PRINTF("tcp-state %s= ", not ? "!" : ""); + printsingle(array + i); + break; + +#ifdef USE_INET6 + case IPF_EXP_IP6_ADDR : + PRINTF("ip6.addr %s= ", not ? "!" : ""); + printhostsv6(array + i); + break; + + case IPF_EXP_IP6_SRCADDR : + PRINTF("ip6.src %s= ", not ? "!" : ""); + printhostsv6(array + i); + break; + + case IPF_EXP_IP6_DSTADDR : + PRINTF("ip6.dst %s= ", not ? "!" : ""); + printhostsv6(array + i); + break; +#endif + + case IPF_EXP_END : + break; + + default : + PRINTF("#%#x,len=%d;", + ipfe->ipfe_cmd, ipfe->ipfe_narg); + } + + if (array[i] != IPF_EXP_END) + putchar(';'); + + i += ipfe->ipfe_size; + if (array[i] != IPF_EXP_END) + putchar(' '); + } +} + + +static void +printsingle(array) + int *array; +{ + ipfexp_t *ipfe = (ipfexp_t *)array; + int i; + + for (i = 0; i < ipfe->ipfe_narg; ) { + PRINTF("%d", array[i + 4]); + i++; + if (i < ipfe->ipfe_narg) + putchar(','); + } +} + + +static void +printport(array) + int *array; +{ + ipfexp_t *ipfe = (ipfexp_t *)array; + int i; + + for (i = 0; i < ipfe->ipfe_narg; ) { + PRINTF("%d", ntohs(array[i + 4])); + i++; + if (i < ipfe->ipfe_narg) + putchar(','); + } +} + + +static void +printhosts(array) + int *array; +{ + ipfexp_t *ipfe = (ipfexp_t *)array; + int i, j; + + for (i = 0, j = 0; i < ipfe->ipfe_narg; j++) { + printhostmask(AF_INET, (u_32_t *)ipfe->ipfe_arg0 + j * 2, + (u_32_t *)ipfe->ipfe_arg0 + j * 2 + 1); + i += 2; + if (i < ipfe->ipfe_narg) + putchar(','); + } +} + + +#ifdef USE_INET6 +static void +printhostsv6(array) + int *array; +{ + ipfexp_t *ipfe = (ipfexp_t *)array; + int i, j; + + for (i = 4, j= 0; i < ipfe->ipfe_size; j++) { + printhostmask(AF_INET6, (u_32_t *)ipfe->ipfe_arg0 + j * 8, + (u_32_t *)ipfe->ipfe_arg0 + j * 8 + 4); + i += 8; + if (i < ipfe->ipfe_size) + putchar(','); + } +} +#endif diff --git a/contrib/ipfilter/lib/printiphdr.c b/contrib/ipfilter/lib/printiphdr.c new file mode 100644 index 0000000..fdf0f75 --- /dev/null +++ b/contrib/ipfilter/lib/printiphdr.c @@ -0,0 +1,20 @@ +/* + * Copyright (C) by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: printiphdr.c,v 1.1 2009/03/01 12:48:32 darren_r Exp $ + */ + +#include "ipf.h" + + +void +printiphdr(ip) + ip_t *ip; +{ + PRINTF("ip(v=%d,hl=%d,len=%d,tos=%#x,off=%#x,sum=%#x,src=%#x,dst=%#x", + ip->ip_v, ip->ip_hl, ntohs(ip->ip_len), ip->ip_tos, + ntohs(ip->ip_off), ntohs(ip->ip_sum), ntohl(ip->ip_src.s_addr), + ntohl(ip->ip_dst.s_addr)); +} diff --git a/contrib/ipfilter/lib/printlog.c b/contrib/ipfilter/lib/printlog.c new file mode 100644 index 0000000..c5278cd --- /dev/null +++ b/contrib/ipfilter/lib/printlog.c @@ -0,0 +1,39 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +#include <syslog.h> + + +void +printlog(fp) + frentry_t *fp; +{ + char *s, *u; + + PRINTF("log"); + if (fp->fr_flags & FR_LOGBODY) + PRINTF(" body"); + if (fp->fr_flags & FR_LOGFIRST) + PRINTF(" first"); + if (fp->fr_flags & FR_LOGORBLOCK) + PRINTF(" or-block"); + if (fp->fr_loglevel != 0xffff) { + PRINTF(" level "); + s = fac_toname(fp->fr_loglevel); + if (s == NULL || *s == '\0') + s = "!!!"; + u = pri_toname(fp->fr_loglevel); + if (u == NULL || *u == '\0') + u = "!!!"; + PRINTF("%s.%s", s, u); + } +} diff --git a/contrib/ipfilter/lib/printlookup.c b/contrib/ipfilter/lib/printlookup.c new file mode 100644 index 0000000..51f8d6e --- /dev/null +++ b/contrib/ipfilter/lib/printlookup.c @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void +printlookup(base, addr, mask) + char *base; + i6addr_t *addr, *mask; +{ + char name[32]; + + switch (addr->iplookuptype) + { + case IPLT_POOL : + PRINTF("pool/"); + break; + case IPLT_HASH : + PRINTF("hash/"); + break; + case IPLT_DSTLIST : + PRINTF("dstlist/"); + break; + default : + PRINTF("lookup(%x)=", addr->iplookuptype); + break; + } + + if (addr->iplookupsubtype == 0) + PRINTF("%u", addr->iplookupnum); + else if (addr->iplookupsubtype == 1) { + strncpy(name, base + addr->iplookupname, sizeof(name)); + name[sizeof(name) - 1] = '\0'; + PRINTF("%s", name); + } +} diff --git a/contrib/ipfilter/lib/printmask.c b/contrib/ipfilter/lib/printmask.c new file mode 100644 index 0000000..365d7ff --- /dev/null +++ b/contrib/ipfilter/lib/printmask.c @@ -0,0 +1,30 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void +printmask(family, mask) + int family; + u_32_t *mask; +{ + struct in_addr ipa; + int ones; + + if (family == AF_INET6) { + PRINTF("/%d", count6bits(mask)); + } else if ((ones = count4bits(*mask)) == -1) { + ipa.s_addr = *mask; + PRINTF("/%s", inet_ntoa(ipa)); + } else { + PRINTF("/%d", ones); + } +} diff --git a/contrib/ipfilter/lib/printnat.c b/contrib/ipfilter/lib/printnat.c new file mode 100644 index 0000000..a94d4ee --- /dev/null +++ b/contrib/ipfilter/lib/printnat.c @@ -0,0 +1,353 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ + +#include "ipf.h" +#include "kmem.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + + +/* + * Print out a NAT rule + */ +void +printnat(np, opts) + ipnat_t *np; + int opts; +{ + struct protoent *pr; + char *base; + int family; + int proto; + + if (np->in_v[0] == 4) + family = AF_INET; +#ifdef USE_INET6 + else if (np->in_v[0] == 6) + family = AF_INET6; +#endif + else + family = AF_UNSPEC; + + if (np->in_flags & IPN_NO) + PRINTF("no "); + + switch (np->in_redir) + { + case NAT_REDIRECT|NAT_ENCAP : + PRINTF("encap in on"); + proto = np->in_pr[0]; + break; + case NAT_MAP|NAT_ENCAP : + PRINTF("encap out on"); + proto = np->in_pr[1]; + break; + case NAT_REDIRECT|NAT_DIVERTUDP : + PRINTF("divert in on"); + proto = np->in_pr[0]; + break; + case NAT_MAP|NAT_DIVERTUDP : + PRINTF("divert out on"); + proto = np->in_pr[1]; + break; + case NAT_REDIRECT|NAT_REWRITE : + PRINTF("rewrite in on"); + proto = np->in_pr[0]; + break; + case NAT_MAP|NAT_REWRITE : + PRINTF("rewrite out on"); + proto = np->in_pr[1]; + break; + case NAT_REDIRECT : + PRINTF("rdr"); + proto = np->in_pr[0]; + break; + case NAT_MAP : + PRINTF("map"); + proto = np->in_pr[1]; + break; + case NAT_MAPBLK : + PRINTF("map-block"); + proto = np->in_pr[1]; + break; + case NAT_BIMAP : + PRINTF("bimap"); + proto = np->in_pr[0]; + break; + default : + FPRINTF(stderr, "unknown value for in_redir: %#x\n", + np->in_redir); + proto = np->in_pr[0]; + break; + } + + pr = getprotobynumber(proto); + + base = np->in_names; + if (!strcmp(base + np->in_ifnames[0], "-")) + PRINTF(" \"%s\"", base + np->in_ifnames[0]); + else + PRINTF(" %s", base + np->in_ifnames[0]); + if ((np->in_ifnames[1] != -1) && + (strcmp(base + np->in_ifnames[0], base + np->in_ifnames[1]) != 0)) { + if (!strcmp(base + np->in_ifnames[1], "-")) + PRINTF(",\"%s\"", base + np->in_ifnames[1]); + else + PRINTF(",%s", base + np->in_ifnames[1]); + } + putchar(' '); + + if (family == AF_INET6) + PRINTF("inet6 "); + + if (np->in_redir & (NAT_REWRITE|NAT_ENCAP|NAT_DIVERTUDP)) { + if ((proto != 0) || (np->in_flags & IPN_TCPUDP)) { + PRINTF("proto "); + printproto(pr, proto, np); + putchar(' '); + } + } + + if (np->in_flags & IPN_FILTER) { + if (np->in_flags & IPN_NOTSRC) + PRINTF("! "); + PRINTF("from "); + printnataddr(np->in_v[0], np->in_names, &np->in_osrc, + np->in_ifnames[0]); + if (np->in_scmp) + printportcmp(proto, &np->in_tuc.ftu_src); + + if (np->in_flags & IPN_NOTDST) + PRINTF(" !"); + PRINTF(" to "); + printnataddr(np->in_v[0], np->in_names, &np->in_odst, + np->in_ifnames[0]); + if (np->in_dcmp) + printportcmp(proto, &np->in_tuc.ftu_dst); + } + + if (np->in_redir & (NAT_ENCAP|NAT_DIVERTUDP)) { + PRINTF(" -> src "); + printnataddr(np->in_v[1], np->in_names, &np->in_nsrc, + np->in_ifnames[0]); + if ((np->in_redir & NAT_DIVERTUDP) != 0) + PRINTF(",%u", np->in_spmin); + PRINTF(" dst "); + printnataddr(np->in_v[1], np->in_names, &np->in_ndst, + np->in_ifnames[0]); + if ((np->in_redir & NAT_DIVERTUDP) != 0) + PRINTF(",%u udp", np->in_dpmin); + if ((np->in_flags & IPN_PURGE) != 0) + PRINTF(" purge"); + PRINTF(";\n"); + + } else if (np->in_redir & NAT_REWRITE) { + PRINTF(" -> src "); + if (np->in_nsrc.na_atype == FRI_LOOKUP && + np->in_nsrc.na_type == IPLT_DSTLIST) { + PRINTF("dstlist/"); + if (np->in_nsrc.na_subtype == 0) + PRINTF("%d", np->in_nsrc.na_num); + else + PRINTF("%s", base + np->in_nsrc.na_num); + } else { + printnataddr(np->in_v[1], np->in_names, &np->in_nsrc, + np->in_ifnames[0]); + } + if ((((np->in_flags & IPN_TCPUDP) != 0)) && + (np->in_spmin != 0)) { + if ((np->in_flags & IPN_FIXEDSPORT) != 0) { + PRINTF(",port = %u", np->in_spmin); + } else { + PRINTF(",%u", np->in_spmin); + if (np->in_spmax != np->in_spmin) + PRINTF("-%u", np->in_spmax); + } + } + PRINTF(" dst "); + if (np->in_ndst.na_atype == FRI_LOOKUP && + np->in_ndst.na_type == IPLT_DSTLIST) { + PRINTF("dstlist/"); + if (np->in_ndst.na_subtype == 0) + PRINTF("%d", np->in_nsrc.na_num); + else + PRINTF("%s", base + np->in_ndst.na_num); + } else { + printnataddr(np->in_v[1], np->in_names, &np->in_ndst, + np->in_ifnames[0]); + } + if ((((np->in_flags & IPN_TCPUDP) != 0)) && + (np->in_dpmin != 0)) { + if ((np->in_flags & IPN_FIXEDDPORT) != 0) { + PRINTF(",port = %u", np->in_dpmin); + } else { + PRINTF(",%u", np->in_dpmin); + if (np->in_dpmax != np->in_dpmin) + PRINTF("-%u", np->in_dpmax); + } + } + if ((np->in_flags & IPN_PURGE) != 0) + PRINTF(" purge"); + PRINTF(";\n"); + + } else if (np->in_redir == NAT_REDIRECT) { + if (!(np->in_flags & IPN_FILTER)) { + printnataddr(np->in_v[0], np->in_names, &np->in_odst, + np->in_ifnames[0]); + if (np->in_flags & IPN_TCPUDP) { + PRINTF(" port %d", np->in_odport); + if (np->in_odport != np->in_dtop) + PRINTF("-%d", np->in_dtop); + } + } + if (np->in_flags & IPN_NO) { + putchar(' '); + printproto(pr, proto, np); + PRINTF(";\n"); + return; + } + PRINTF(" -> "); + printnataddr(np->in_v[1], np->in_names, &np->in_ndst, + np->in_ifnames[0]); + if (np->in_flags & IPN_TCPUDP) { + if ((np->in_flags & IPN_FIXEDDPORT) != 0) + PRINTF(" port = %d", np->in_dpmin); + else { + PRINTF(" port %d", np->in_dpmin); + if (np->in_dpmin != np->in_dpmax) + PRINTF("-%d", np->in_dpmax); + } + } + putchar(' '); + printproto(pr, proto, np); + if (np->in_flags & IPN_ROUNDR) + PRINTF(" round-robin"); + if (np->in_flags & IPN_FRAG) + PRINTF(" frag"); + if (np->in_age[0] != 0 || np->in_age[1] != 0) { + PRINTF(" age %d/%d", np->in_age[0], np->in_age[1]); + } + if (np->in_flags & IPN_STICKY) + PRINTF(" sticky"); + if (np->in_mssclamp != 0) + PRINTF(" mssclamp %d", np->in_mssclamp); + if (np->in_plabel != -1) + PRINTF(" proxy %s", np->in_names + np->in_plabel); + if (np->in_tag.ipt_tag[0] != '\0') + PRINTF(" tag %-.*s", IPFTAG_LEN, np->in_tag.ipt_tag); + if ((np->in_flags & IPN_PURGE) != 0) + PRINTF(" purge"); + PRINTF("\n"); + if (opts & OPT_DEBUG) + PRINTF("\tpmax %u\n", np->in_dpmax); + + } else { + int protoprinted = 0; + + if (!(np->in_flags & IPN_FILTER)) { + printnataddr(np->in_v[0], np->in_names, &np->in_osrc, + np->in_ifnames[0]); + } + if (np->in_flags & IPN_NO) { + putchar(' '); + printproto(pr, proto, np); + PRINTF(";\n"); + return; + } + PRINTF(" -> "); + if (np->in_flags & IPN_SIPRANGE) { + PRINTF("range "); + printnataddr(np->in_v[1], np->in_names, &np->in_nsrc, + np->in_ifnames[0]); + } else { + printnataddr(np->in_v[1], np->in_names, &np->in_nsrc, + np->in_ifnames[0]); + } + if (np->in_plabel != -1) { + PRINTF(" proxy port "); + if (np->in_odport != 0) { + char *s; + + s = portname(proto, np->in_odport); + if (s != NULL) + fputs(s, stdout); + else + fputs("???", stdout); + } + PRINTF(" %s/", np->in_names + np->in_plabel); + printproto(pr, proto, NULL); + protoprinted = 1; + } else if (np->in_redir == NAT_MAPBLK) { + if ((np->in_spmin == 0) && + (np->in_flags & IPN_AUTOPORTMAP)) + PRINTF(" ports auto"); + else + PRINTF(" ports %d", np->in_spmin); + if (opts & OPT_DEBUG) + PRINTF("\n\tip modulous %d", np->in_spmax); + + } else if (np->in_spmin || np->in_spmax) { + if (np->in_flags & IPN_ICMPQUERY) { + PRINTF(" icmpidmap "); + } else { + PRINTF(" portmap "); + } + printproto(pr, proto, np); + protoprinted = 1; + if (np->in_flags & IPN_AUTOPORTMAP) { + PRINTF(" auto"); + if (opts & OPT_DEBUG) + PRINTF(" [%d:%d %d %d]", + np->in_spmin, np->in_spmax, + np->in_ippip, np->in_ppip); + } else { + PRINTF(" %d:%d", np->in_spmin, np->in_spmax); + } + if (np->in_flags & IPN_SEQUENTIAL) + PRINTF(" sequential"); + } + + if (np->in_flags & IPN_FRAG) + PRINTF(" frag"); + if (np->in_age[0] != 0 || np->in_age[1] != 0) { + PRINTF(" age %d/%d", np->in_age[0], np->in_age[1]); + } + if (np->in_mssclamp != 0) + PRINTF(" mssclamp %d", np->in_mssclamp); + if (np->in_tag.ipt_tag[0] != '\0') + PRINTF(" tag %s", np->in_tag.ipt_tag); + if (!protoprinted && (np->in_flags & IPN_TCPUDP || proto)) { + putchar(' '); + printproto(pr, proto, np); + } + if ((np->in_flags & IPN_PURGE) != 0) + PRINTF(" purge"); + PRINTF("\n"); + if (opts & OPT_DEBUG) { + PRINTF("\tnextip "); + printip(family, &np->in_snip); + PRINTF(" pnext %d\n", np->in_spnext); + } + } + + if (opts & OPT_DEBUG) { + PRINTF("\tspace %lu use %u hits %lu flags %#x proto %d/%d", + np->in_space, np->in_use, np->in_hits, + np->in_flags, np->in_pr[0], np->in_pr[1]); + PRINTF(" hv %u/%u\n", np->in_hv[0], np->in_hv[1]); + PRINTF("\tifp[0] %p ifp[1] %p apr %p\n", + np->in_ifps[0], np->in_ifps[1], np->in_apr); + PRINTF("\ttqehead %p/%p comment %p\n", + np->in_tqehead[0], np->in_tqehead[1], np->in_comment); + } +} diff --git a/contrib/ipfilter/lib/printnataddr.c b/contrib/ipfilter/lib/printnataddr.c new file mode 100644 index 0000000..89faa62 --- /dev/null +++ b/contrib/ipfilter/lib/printnataddr.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ + +#include "ipf.h" +#include "kmem.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: printnataddr.c,v 1.4.2.2 2012/07/22 08:04:24 darren_r Exp $"; +#endif + + +void +printnataddr(v, base, addr, ifidx) + int v; + char *base; + nat_addr_t *addr; + int ifidx; +{ + switch (v) + { + case 4 : + if (addr->na_atype == FRI_NORMAL && + addr->na_addr[0].in4.s_addr == 0) { + PRINTF("0/%d", count4bits(addr->na_addr[1].in4.s_addr)); + } else { + printaddr(AF_INET, addr->na_atype, base, ifidx, + (u_32_t *)&addr->na_addr[0].in4.s_addr, + (u_32_t *)&addr->na_addr[1].in4.s_addr); + } + break; +#ifdef USE_INET6 + case 6 : + printaddr(AF_INET6, addr->na_atype, base, ifidx, + (u_32_t *)&addr->na_addr[0].in6, + (u_32_t *)&addr->na_addr[1].in6); + break; +#endif + default : + printf("{v=%d}", v); + break; + } +} diff --git a/contrib/ipfilter/lib/printnatfield.c b/contrib/ipfilter/lib/printnatfield.c new file mode 100644 index 0000000..49596f6 --- /dev/null +++ b/contrib/ipfilter/lib/printnatfield.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: printnatfield.c,v 1.6.2.2 2012/01/26 05:44:26 darren_r Exp $ + */ + +#include "ipf.h" + +wordtab_t natfields[] = { + { "all", -2 }, + { "ifp0", 1 }, + { "ifp1", 2 }, + { "mtu0", 3 }, + { "mtu1", 4 }, + { "ifname0", 5 }, + { "ifname1", 6 }, + { "sumd0", 7 }, + { "sumd1", 8 }, + { "pkts0", 9 }, + { "pkts1", 10 }, + { "bytes0", 11 }, + { "bytes1", 12 }, + { "proto0", 13 }, + { "proto1", 14 }, + { "hash0", 15 }, + { "hash1", 16 }, + { "ref", 17 }, + { "rev", 18 }, + { "v0", 19 }, + { "redir", 20 }, + { "use", 21 }, + { "ipsumd", 22 }, + { "dir", 23 }, + { "olddstip", 24 }, + { "oldsrcip", 25 }, + { "newdstip", 26 }, + { "newsrcip", 27 }, + { "olddport", 28 }, + { "oldsport", 29 }, + { "newdport", 30 }, + { "newsport", 31 }, + { "age", 32 }, + { "v1", 33 }, + { NULL, 0 } +}; + + +void +printnatfield(n, fieldnum) + nat_t *n; + int fieldnum; +{ + int i; + + switch (fieldnum) + { + case -2 : + for (i = 1; natfields[i].w_word != NULL; i++) { + if (natfields[i].w_value > 0) { + printnatfield(n, i); + if (natfields[i + 1].w_value > 0) + putchar('\t'); + } + } + break; + + case 1: + PRINTF("%#lx", (u_long)n->nat_ifps[0]); + break; + + case 2: + PRINTF("%#lx", (u_long)n->nat_ifps[1]); + break; + + case 3: + PRINTF("%d", n->nat_mtu[0]); + break; + + case 4: + PRINTF("%d", n->nat_mtu[1]); + break; + + case 5: + PRINTF("%s", n->nat_ifnames[0]); + break; + + case 6: + PRINTF("%s", n->nat_ifnames[1]); + break; + + case 7: + PRINTF("%d", n->nat_sumd[0]); + break; + + case 8: + PRINTF("%d", n->nat_sumd[1]); + break; + + case 9: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", n->nat_pkts[0]); +#else + PRINTF("%lu", n->nat_pkts[0]); +#endif + break; + + case 10: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", n->nat_pkts[1]); +#else + PRINTF("%lu", n->nat_pkts[1]); +#endif + break; + + case 11: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", n->nat_bytes[0]); +#else + PRINTF("%lu", n->nat_bytes[0]); +#endif + break; + + case 12: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", n->nat_bytes[1]); +#else + PRINTF("%lu", n->nat_bytes[1]); +#endif + break; + + case 13: + PRINTF("%d", n->nat_pr[0]); + break; + + case 14: + PRINTF("%d", n->nat_pr[1]); + break; + + case 15: + PRINTF("%u", n->nat_hv[0]); + break; + + case 16: + PRINTF("%u", n->nat_hv[1]); + break; + + case 17: + PRINTF("%d", n->nat_ref); + break; + + case 18: + PRINTF("%d", n->nat_rev); + break; + + case 19: + PRINTF("%d", n->nat_v[0]); + break; + + case 33: + PRINTF("%d", n->nat_v[0]); + break; + + case 20: + PRINTF("%d", n->nat_redir); + break; + + case 21: + PRINTF("%d", n->nat_use); + break; + + case 22: + PRINTF("%u", n->nat_ipsumd); + break; + + case 23: + PRINTF("%d", n->nat_dir); + break; + + case 24: + PRINTF("%s", hostname(n->nat_v[0], &n->nat_odstip)); + break; + + case 25: + PRINTF("%s", hostname(n->nat_v[0], &n->nat_osrcip)); + break; + + case 26: + PRINTF("%s", hostname(n->nat_v[1], &n->nat_ndstip)); + break; + + case 27: + PRINTF("%s", hostname(n->nat_v[1], &n->nat_nsrcip)); + break; + + case 28: + PRINTF("%hu", ntohs(n->nat_odport)); + break; + + case 29: + PRINTF("%hu", ntohs(n->nat_osport)); + break; + + case 30: + PRINTF("%hu", ntohs(n->nat_ndport)); + break; + + case 31: + PRINTF("%hu", ntohs(n->nat_nsport)); + break; + + case 32: + PRINTF("%u", n->nat_age); + break; + + default: + break; + } +} diff --git a/contrib/ipfilter/lib/printnatside.c b/contrib/ipfilter/lib/printnatside.c new file mode 100644 index 0000000..37e1cb8 --- /dev/null +++ b/contrib/ipfilter/lib/printnatside.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: printnatside.c,v 1.2.2.6 2012/07/22 08:04:24 darren_r Exp $ + */ +#include "ipf.h" + +void +printnatside(side, ns) + char *side; + nat_stat_side_t *ns; +{ + PRINTF("%lu\tproxy create fail %s\n", ns->ns_appr_fail, side); + PRINTF("%lu\tproxy fail %s\n", ns->ns_ipf_proxy_fail, side); + PRINTF("%lu\tbad nat %s\n", ns->ns_badnat, side); + PRINTF("%lu\tbad nat new %s\n", ns->ns_badnatnew, side); + PRINTF("%lu\tbad next addr %s\n", ns->ns_badnextaddr, side); + PRINTF("%lu\tbucket max %s\n", ns->ns_bucket_max, side); + PRINTF("%lu\tclone nomem %s\n", ns->ns_clone_nomem, side); + PRINTF("%lu\tdecap bad %s\n", ns->ns_decap_bad, side); + PRINTF("%lu\tdecap fail %s\n", ns->ns_decap_fail, side); + PRINTF("%lu\tdecap pullup %s\n", ns->ns_decap_pullup, side); + PRINTF("%lu\tdivert dup %s\n", ns->ns_divert_dup, side); + PRINTF("%lu\tdivert exist %s\n", ns->ns_divert_exist, side); + PRINTF("%lu\tdrop %s\n", ns->ns_drop, side); + PRINTF("%lu\texhausted %s\n", ns->ns_exhausted, side); + PRINTF("%lu\ticmp address %s\n", ns->ns_icmp_address, side); + PRINTF("%lu\ticmp basic %s\n", ns->ns_icmp_basic, side); + PRINTF("%lu\tinuse %s\n", ns->ns_inuse, side); + PRINTF("%lu\ticmp mbuf wrong size %s\n", ns->ns_icmp_mbuf, side); + PRINTF("%lu\ticmp header unmatched %s\n", ns->ns_icmp_notfound, side); + PRINTF("%lu\ticmp rebuild failures %s\n", ns->ns_icmp_rebuild, side); + PRINTF("%lu\ticmp short %s\n", ns->ns_icmp_short, side); + PRINTF("%lu\ticmp packet size wrong %s\n", ns->ns_icmp_size, side); + PRINTF("%lu\tIFP address fetch failures %s\n", + ns->ns_ifpaddrfail, side); + PRINTF("%lu\tpackets untranslated %s\n", ns->ns_ignored, side); + PRINTF("%lu\tNAT insert failures %s\n", ns->ns_insert_fail, side); + PRINTF("%lu\tNAT lookup misses %s\n", ns->ns_lookup_miss, side); + PRINTF("%lu\tNAT lookup nowild %s\n", ns->ns_lookup_nowild, side); + PRINTF("%lu\tnew ifpaddr failed %s\n", ns->ns_new_ifpaddr, side); + PRINTF("%lu\tmemory requests failed %s\n", ns->ns_memfail, side); + PRINTF("%lu\ttable max reached %s\n", ns->ns_table_max, side); + PRINTF("%lu\tpackets translated %s\n", ns->ns_translated, side); + PRINTF("%lu\tfinalised failed %s\n", ns->ns_unfinalised, side); + PRINTF("%lu\tsearch wraps %s\n", ns->ns_wrap, side); + PRINTF("%lu\tnull translations %s\n", ns->ns_xlate_null, side); + PRINTF("%lu\ttranslation exists %s\n", ns->ns_xlate_exists, side); + PRINTF("%lu\tno memory %s\n", ns->ns_memfail, side); + + if (opts & OPT_VERBOSE) + PRINTF("%p table %s\n", ns->ns_table, side); +} diff --git a/contrib/ipfilter/lib/printpacket.c b/contrib/ipfilter/lib/printpacket.c new file mode 100644 index 0000000..5c4a749 --- /dev/null +++ b/contrib/ipfilter/lib/printpacket.c @@ -0,0 +1,110 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +#ifndef IP_OFFMASK +# define IP_OFFMASK 0x3fff +#endif + + +void +printpacket(dir, m) + int dir; + mb_t *m; +{ + u_short len, off; + tcphdr_t *tcp; + ip_t *ip; + + ip = MTOD(m, ip_t *); + + if (IP_V(ip) == 6) { +#ifdef USE_INET6 + len = ntohs(((ip6_t *)ip)->ip6_plen); +#else + len = ntohs(((u_short *)ip)[2]); +#endif + len += 40; + } else { + len = ntohs(ip->ip_len); + } + ASSERT(len == msgdsize(m)); + + if ((opts & OPT_HEX) == OPT_HEX) { + u_char *s; + int i; + + for (; m != NULL; m = m->mb_next) { + len = m->mb_len; + for (s = (u_char *)m->mb_data, i = 0; i < len; i++) { + PRINTF("%02x", *s++ & 0xff); + if (len - i > 1) { + i++; + PRINTF("%02x", *s++ & 0xff); + } + putchar(' '); + } + } + putchar('\n'); + putchar('\n'); + return; + } + + if (IP_V(ip) == 6) { + printpacket6(dir, m); + return; + } + + if (dir) + PRINTF("> "); + else + PRINTF("< "); + + PRINTF("%s ", IFNAME(m->mb_ifp)); + + off = ntohs(ip->ip_off); + tcp = (struct tcphdr *)((char *)ip + (IP_HL(ip) << 2)); + PRINTF("ip #%d %d(%d) %d", ntohs(ip->ip_id), ntohs(ip->ip_len), + IP_HL(ip) << 2, ip->ip_p); + if (off & IP_OFFMASK) + PRINTF(" @%d", off << 3); + PRINTF(" %s", inet_ntoa(ip->ip_src)); + if (!(off & IP_OFFMASK)) + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + PRINTF(",%d", ntohs(tcp->th_sport)); + PRINTF(" > "); + PRINTF("%s", inet_ntoa(ip->ip_dst)); + if (!(off & IP_OFFMASK)) { + if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) + PRINTF(",%d", ntohs(tcp->th_dport)); + if ((ip->ip_p == IPPROTO_TCP) && (tcp->th_flags != 0)) { + putchar(' '); + if (tcp->th_flags & TH_FIN) + putchar('F'); + if (tcp->th_flags & TH_SYN) + putchar('S'); + if (tcp->th_flags & TH_RST) + putchar('R'); + if (tcp->th_flags & TH_PUSH) + putchar('P'); + if (tcp->th_flags & TH_ACK) + putchar('A'); + if (tcp->th_flags & TH_URG) + putchar('U'); + if (tcp->th_flags & TH_ECN) + putchar('E'); + if (tcp->th_flags & TH_CWR) + putchar('C'); + } + } + + putchar('\n'); +} diff --git a/contrib/ipfilter/lib/printpacket6.c b/contrib/ipfilter/lib/printpacket6.c new file mode 100644 index 0000000..6363e55 --- /dev/null +++ b/contrib/ipfilter/lib/printpacket6.c @@ -0,0 +1,60 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +/* + * This is meant to work without the IPv6 header files being present or + * the inet_ntop() library. + */ +void +printpacket6(dir, m) + int dir; + mb_t *m; +{ + u_char *buf, p; + u_short plen, *addrs; + tcphdr_t *tcp; + u_32_t flow; + + buf = (u_char *)m->mb_data; + tcp = (tcphdr_t *)(buf + 40); + p = buf[6]; + flow = ntohl(*(u_32_t *)buf); + flow &= 0xfffff; + plen = ntohs(*((u_short *)buf +2)); + addrs = (u_short *)buf + 4; + + if (dir) + PRINTF("> "); + else + PRINTF("< "); + + PRINTF("%s ", IFNAME(m->mb_ifp)); + + PRINTF("ip6/%d %d %#x %d", buf[0] & 0xf, plen, flow, p); + PRINTF(" %x:%x:%x:%x:%x:%x:%x:%x", + ntohs(addrs[0]), ntohs(addrs[1]), ntohs(addrs[2]), + ntohs(addrs[3]), ntohs(addrs[4]), ntohs(addrs[5]), + ntohs(addrs[6]), ntohs(addrs[7])); + if (plen >= 4) + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + (void)PRINTF(",%d", ntohs(tcp->th_sport)); + PRINTF(" >"); + addrs += 8; + PRINTF(" %x:%x:%x:%x:%x:%x:%x:%x", + ntohs(addrs[0]), ntohs(addrs[1]), ntohs(addrs[2]), + ntohs(addrs[3]), ntohs(addrs[4]), ntohs(addrs[5]), + ntohs(addrs[6]), ntohs(addrs[7])); + if (plen >= 4) + if (p == IPPROTO_TCP || p == IPPROTO_UDP) + PRINTF(",%d", ntohs(tcp->th_dport)); + putchar('\n'); +} diff --git a/contrib/ipfilter/lib/printpool.c b/contrib/ipfilter/lib/printpool.c new file mode 100644 index 0000000..8d8cdcc --- /dev/null +++ b/contrib/ipfilter/lib/printpool.c @@ -0,0 +1,65 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +ip_pool_t * +printpool(pp, copyfunc, name, opts, fields) + ip_pool_t *pp; + copyfunc_t copyfunc; + char *name; + int opts; + wordtab_t *fields; +{ + ip_pool_node_t *ipnp, *ipnpn, ipn, **pnext; + ip_pool_t ipp; + + if ((*copyfunc)(pp, &ipp, sizeof(ipp))) + return NULL; + + if ((name != NULL) && strncmp(name, ipp.ipo_name, FR_GROUPLEN)) + return ipp.ipo_next; + + printpooldata(&ipp, opts); + + if ((ipp.ipo_flags & IPOOL_DELETE) != 0) + PRINTF("# "); + if ((opts & OPT_DEBUG) == 0) + PRINTF("\t{"); + + ipnpn = ipp.ipo_list; + ipp.ipo_list = NULL; + pnext = &ipp.ipo_list; + while (ipnpn != NULL) { + ipnp = (ip_pool_node_t *)malloc(sizeof(*ipnp)); + (*copyfunc)(ipnpn, ipnp, sizeof(ipn)); + ipnpn = ipnp->ipn_next; + *pnext = ipnp; + pnext = &ipnp->ipn_next; + ipnp->ipn_next = NULL; + } + + if (ipp.ipo_list == NULL) { + putchar(';'); + } else { + for (ipnp = ipp.ipo_list; ipnp != NULL; ipnp = ipnpn) { + ipnpn = printpoolnode(ipnp, opts, fields); + free(ipnp); + + if ((opts & OPT_DEBUG) == 0) { + putchar(';'); + } + } + } + + if ((opts & OPT_DEBUG) == 0) + PRINTF(" };\n"); + + return ipp.ipo_next; +} diff --git a/contrib/ipfilter/lib/printpool_live.c b/contrib/ipfilter/lib/printpool_live.c new file mode 100644 index 0000000..2aabf32 --- /dev/null +++ b/contrib/ipfilter/lib/printpool_live.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ipl.h" + + +ip_pool_t * +printpool_live(pool, fd, name, opts, fields) + ip_pool_t *pool; + int fd; + char *name; + int opts; + wordtab_t *fields; +{ + ip_pool_node_t entry; + ipflookupiter_t iter; + int printed, last; + ipfobj_t obj; + + if ((name != NULL) && strncmp(name, pool->ipo_name, FR_GROUPLEN)) + return pool->ipo_next; + + if (fields == NULL) + printpooldata(pool, opts); + + if ((pool->ipo_flags & IPOOL_DELETE) != 0) + PRINTF("# "); + if ((opts & OPT_DEBUG) == 0) + PRINTF("\t{"); + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_LOOKUPITER; + obj.ipfo_ptr = &iter; + obj.ipfo_size = sizeof(iter); + + iter.ili_data = &entry; + iter.ili_type = IPLT_POOL; + iter.ili_otype = IPFLOOKUPITER_NODE; + iter.ili_ival = IPFGENITER_LOOKUP; + iter.ili_unit = pool->ipo_unit; + strncpy(iter.ili_name, pool->ipo_name, FR_GROUPLEN); + + last = 0; + printed = 0; + + if (pool->ipo_list != NULL) { + while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) { + if (entry.ipn_next == NULL) + last = 1; + (void) printpoolnode(&entry, opts, fields); + if ((opts & OPT_DEBUG) == 0) + putchar(';'); + printed++; + } + } + + if (printed == 0) + putchar(';'); + + if ((opts & OPT_DEBUG) == 0) + PRINTF(" };\n"); + + (void) ioctl(fd,SIOCIPFDELTOK, &iter.ili_key); + + return pool->ipo_next; +} diff --git a/contrib/ipfilter/lib/printpooldata.c b/contrib/ipfilter/lib/printpooldata.c new file mode 100644 index 0000000..a159177 --- /dev/null +++ b/contrib/ipfilter/lib/printpooldata.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" +#include <ctype.h> + + +void +printpooldata(pool, opts) + ip_pool_t *pool; + int opts; +{ + + if ((opts & OPT_DEBUG) == 0) { + if ((pool->ipo_flags & IPOOL_ANON) != 0) + PRINTF("# 'anonymous' tree %s\n", pool->ipo_name); + if ((pool->ipo_flags & IPOOL_DELETE) != 0) + PRINTF("# "); + PRINTF("table role="); + } else { + if ((pool->ipo_flags & IPOOL_DELETE) != 0) + PRINTF("# "); + PRINTF("%s: %s", + ISDIGIT(*pool->ipo_name) ? "Number" : "Name", + pool->ipo_name); + if ((pool->ipo_flags & IPOOL_ANON) == IPOOL_ANON) + PRINTF("(anon)"); + putchar(' '); + PRINTF("Role: "); + } + + printunit(pool->ipo_unit); + + if ((opts & OPT_DEBUG) == 0) { + PRINTF(" type=tree %s=%s\n", + (!*pool->ipo_name || ISDIGIT(*pool->ipo_name)) ? \ + "number" : "name", pool->ipo_name); + } else { + putchar(' '); + + PRINTF("\tReferences: %d\tHits: %lu\n", pool->ipo_ref, + pool->ipo_hits); + if ((pool->ipo_flags & IPOOL_DELETE) != 0) + PRINTF("# "); + PRINTF("\tNodes Starting at %p\n", pool->ipo_list); + } +} diff --git a/contrib/ipfilter/lib/printpoolfield.c b/contrib/ipfilter/lib/printpoolfield.c new file mode 100644 index 0000000..9254ab8 --- /dev/null +++ b/contrib/ipfilter/lib/printpoolfield.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: printpoolfield.c,v 1.1.2.4 2012/01/26 05:44:26 darren_r Exp $ + */ + +#include "ipf.h" + +wordtab_t poolfields[] = { + { "all", -2 }, + { "address", 1 }, + { "mask", 2 }, + { "ifname", 3 }, + { "pkts", 4 }, + { "bytes", 5 }, + { "family", 6 }, + { NULL, 0 } +}; + + +void +printpoolfield(p, ptype, fieldnum) + void *p; + int ptype; + int fieldnum; +{ + addrfamily_t *a; + char abuf[80]; + int i; + + switch (fieldnum) + { + case -2 : + for (i = 1; poolfields[i].w_word != NULL; i++) { + if (poolfields[i].w_value > 0) { + printpoolfield(p, ptype, i); + if (poolfields[i + 1].w_value > 0) + putchar('\t'); + } + } + break; + + case 1: + if (ptype == IPLT_POOL) { + ip_pool_node_t *node = (ip_pool_node_t *)p; + + if (node->ipn_info) + PRINTF("!"); + a = &node->ipn_addr; + PRINTF("%s", inet_ntop(a->adf_family, &a->adf_addr, + abuf, sizeof(abuf))); + } else if (ptype == IPLT_HASH) { + iphtent_t *node = (iphtent_t *)p; + + PRINTF("%s", inet_ntop(node->ipe_family, + &node->ipe_addr, + abuf, sizeof(abuf))); + } else if (ptype == IPLT_DSTLIST) { + ipf_dstnode_t *node = (ipf_dstnode_t *)p; + + a = &node->ipfd_dest.fd_addr; + PRINTF("%s", inet_ntop(a->adf_family, &a->adf_addr, + abuf, sizeof(abuf))); + } + break; + + case 2: + if (ptype == IPLT_POOL) { + ip_pool_node_t *node = (ip_pool_node_t *)p; + + a = &node->ipn_mask; + PRINTF("%s", inet_ntop(a->adf_family, &a->adf_addr, + abuf, sizeof(abuf))); + } else if (ptype == IPLT_HASH) { + iphtent_t *node = (iphtent_t *)p; + + PRINTF("%s", inet_ntop(node->ipe_family, + &node->ipe_mask, + abuf, sizeof(abuf))); + } else if (ptype == IPLT_DSTLIST) { + PRINTF("%s", ""); + } + break; + + case 3: + if (ptype == IPLT_POOL) { + PRINTF("%s", ""); + } else if (ptype == IPLT_HASH) { + PRINTF("%s", ""); + } else if (ptype == IPLT_DSTLIST) { + ipf_dstnode_t *node = (ipf_dstnode_t *)p; + + if (node->ipfd_dest.fd_name == -1) { + PRINTF("%s", ""); + } else { + PRINTF("%s", node->ipfd_names + + node->ipfd_dest.fd_name); + } + } + break; + + case 4: + if (ptype == IPLT_POOL) { + ip_pool_node_t *node = (ip_pool_node_t *)p; + +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", node->ipn_hits); +#else + PRINTF("%lu", node->ipn_hits); +#endif + } else if (ptype == IPLT_HASH) { + iphtent_t *node = (iphtent_t *)p; + +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", node->ipe_hits); +#else + PRINTF("%lu", node->ipe_hits); +#endif + } else if (ptype == IPLT_DSTLIST) { + printf("0"); + } + break; + + case 5: + if (ptype == IPLT_POOL) { + ip_pool_node_t *node = (ip_pool_node_t *)p; + +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", node->ipn_bytes); +#else + PRINTF("%lu", node->ipn_bytes); +#endif + } else if (ptype == IPLT_HASH) { + iphtent_t *node = (iphtent_t *)p; + +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", node->ipe_bytes); +#else + PRINTF("%lu", node->ipe_bytes); +#endif + } else if (ptype == IPLT_DSTLIST) { + printf("0"); + } + break; + + case 6: + if (ptype == IPLT_POOL) { + ip_pool_node_t *node = (ip_pool_node_t *)p; + + PRINTF("%s", familyname(node->ipn_addr.adf_family)); + } else if (ptype == IPLT_HASH) { + iphtent_t *node = (iphtent_t *)p; + + PRINTF("%s", familyname(node->ipe_family)); + } else if (ptype == IPLT_DSTLIST) { + ipf_dstnode_t *node = (ipf_dstnode_t *)p; + + a = &node->ipfd_dest.fd_addr; + PRINTF("%s", familyname(a->adf_family)); + } + break; + + default : + break; + } +} diff --git a/contrib/ipfilter/lib/printpoolnode.c b/contrib/ipfilter/lib/printpoolnode.c new file mode 100644 index 0000000..aa2aed9 --- /dev/null +++ b/contrib/ipfilter/lib/printpoolnode.c @@ -0,0 +1,51 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +ip_pool_node_t * +printpoolnode(np, opts, fields) + ip_pool_node_t *np; + int opts; + wordtab_t *fields; +{ + int i; + + if (fields != NULL) { + for (i = 0; fields[i].w_value != 0; i++) { + printpoolfield(np, IPLT_POOL, i); + if (fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } else if ((opts & OPT_DEBUG) == 0) { + putchar(' '); + if (np->ipn_info == 1) + PRINTF("! "); + printip(np->ipn_addr.adf_family, + (u_32_t *)&np->ipn_addr.adf_addr.in4); + printmask(np->ipn_addr.adf_family, + (u_32_t *)&np->ipn_mask.adf_addr); + } else { + PRINTF("\tAddress: %s%s", np->ipn_info ? "! " : "", + inet_ntoa(np->ipn_addr.adf_addr.in4)); + printmask(np->ipn_addr.adf_family, + (u_32_t *)&np->ipn_mask.adf_addr); +#ifdef USE_QUAD_T + PRINTF("\n\t\tHits %"PRIu64"\tBytes %"PRIu64"\tName %s\tRef %d\n", + np->ipn_hits, np->ipn_bytes, + np->ipn_name, np->ipn_ref); +#else + PRINTF("\n\t\tHits %lu\tBytes %lu\tName %s\tRef %d\n", + np->ipn_hits, np->ipn_bytes, + np->ipn_name, np->ipn_ref); +#endif + } + return np->ipn_next; +} diff --git a/contrib/ipfilter/lib/printportcmp.c b/contrib/ipfilter/lib/printportcmp.c new file mode 100644 index 0000000..2a5bd02 --- /dev/null +++ b/contrib/ipfilter/lib/printportcmp.c @@ -0,0 +1,30 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +void +printportcmp(pr, frp) + int pr; + frpcmp_t *frp; +{ + static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=", + "<>", "><", ":" }; + + if (frp->frp_cmp == FR_INRANGE || frp->frp_cmp == FR_OUTRANGE) + PRINTF(" port %d %s %d", frp->frp_port, + pcmp1[frp->frp_cmp], frp->frp_top); + else if (frp->frp_cmp == FR_INCRANGE) + PRINTF(" port %d:%d", frp->frp_port, frp->frp_top); + else + PRINTF(" port %s %s", pcmp1[frp->frp_cmp], + portname(pr, frp->frp_port)); +} diff --git a/contrib/ipfilter/lib/printproto.c b/contrib/ipfilter/lib/printproto.c new file mode 100644 index 0000000..d411bfa --- /dev/null +++ b/contrib/ipfilter/lib/printproto.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + + +void +printproto(pr, p, np) + struct protoent *pr; + int p; + ipnat_t *np; +{ + if (np != NULL) { + 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"); + else if (np->in_flags & IPN_ICMPQUERY) + PRINTF("icmp"); +#ifdef _AIX51 + /* + * To make up for "ip = 252" and "hopopt = 0" in /etc/protocols + * The IANA has doubled up on the definition of 0 - it is now + * also used for IPv6 hop-opts, so we can no longer rely on + * /etc/protocols providing the correct name->number mapping. + */ +#endif + else if (np->in_pr[0] == 0) + PRINTF("ip"); + else if (pr != NULL) + PRINTF("%s", pr->p_name); + else + PRINTF("%d", np->in_pr[0]); + } else { +#ifdef _AIX51 + if (p == 0) + PRINTF("ip"); + else +#endif + if (pr != NULL) + PRINTF("%s", pr->p_name); + else + PRINTF("%d", p); + } +} diff --git a/contrib/ipfilter/lib/printsbuf.c b/contrib/ipfilter/lib/printsbuf.c new file mode 100644 index 0000000..efda99e --- /dev/null +++ b/contrib/ipfilter/lib/printsbuf.c @@ -0,0 +1,42 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#ifdef IPFILTER_SCAN + +#include <ctype.h> +#include <stdio.h> +#include "ipf.h" +#include "netinet/ip_scan.h" + +void +printsbuf(buf) + char *buf; +{ + u_char *s; + int i; + + for (s = (u_char *)buf, i = ISC_TLEN; i; i--, s++) { + if (ISPRINT(*s)) + putchar(*s); + else + PRINTF("\\%o", *s); + } +} +#else +void printsbuf(char *buf); + +void printsbuf(buf) + char *buf; +{ +#if 0 + buf = buf; /* gcc -Wextra */ +#endif +} +#endif diff --git a/contrib/ipfilter/lib/printstate.c b/contrib/ipfilter/lib/printstate.c new file mode 100644 index 0000000..fc85a70 --- /dev/null +++ b/contrib/ipfilter/lib/printstate.c @@ -0,0 +1,224 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" +#include "kmem.h" + + +ipstate_t * +printstate(sp, opts, now) + ipstate_t *sp; + int opts; + u_long now; +{ + struct protoent *pr; + synclist_t ipsync; + + if ((opts & OPT_NORESOLVE) == 0) + pr = getprotobynumber(sp->is_p); + else + pr = NULL; + + PRINTF("%d:", sp->is_v); + if (pr != NULL) + PRINTF("%s", pr->p_name); + else + PRINTF("%d", sp->is_p); + + PRINTF(" src:%s", hostname(sp->is_family, &sp->is_src.in4)); + if (sp->is_p == IPPROTO_UDP || sp->is_p == IPPROTO_TCP) { + if (sp->is_flags & IS_WSPORT) + PRINTF(",*"); + else + PRINTF(",%d", ntohs(sp->is_sport)); + } + + PRINTF(" dst:%s", hostname(sp->is_family, &sp->is_dst.in4)); + if (sp->is_p == IPPROTO_UDP || sp->is_p == IPPROTO_TCP) { + if (sp->is_flags & IS_WDPORT) + PRINTF(",*"); + else + PRINTF(",%d", ntohs(sp->is_dport)); + } + + if (sp->is_p == IPPROTO_TCP) { + PRINTF(" state:%d/%d", sp->is_state[0], sp->is_state[1]); + } + + PRINTF(" %ld", sp->is_die - now); + if (sp->is_phnext == NULL) + PRINTF(" ORPHAN"); + if (sp->is_flags & IS_CLONE) + PRINTF(" CLONE"); + putchar('\n'); + + if (sp->is_p == IPPROTO_TCP) { + PRINTF("\t%x:%x %hu<<%d:%hu<<%d\n", + sp->is_send, sp->is_dend, + sp->is_maxswin, sp->is_swinscale, + sp->is_maxdwin, sp->is_dwinscale); + if ((opts & OPT_VERBOSE) != 0) { + PRINTF("\tcmsk %04x smsk %04x isc %p s0 %08x/%08x\n", + sp->is_smsk[0], sp->is_smsk[1], sp->is_isc, + sp->is_s0[0], sp->is_s0[1]); + PRINTF("\tFWD: ISN inc %x sumd %x\n", + sp->is_isninc[0], sp->is_sumd[0]); + PRINTF("\tREV: ISN inc %x sumd %x\n", + sp->is_isninc[1], sp->is_sumd[1]); +#ifdef IPFILTER_SCAN + PRINTF("\tsbuf[0] ["); + printsbuf(sp->is_sbuf[0]); + PRINTF("] sbuf[1] ["); + printsbuf(sp->is_sbuf[1]); + PRINTF("]\n"); +#endif + } + } else if (sp->is_p == IPPROTO_GRE) { + PRINTF("\tcall %hx/%hx\n", ntohs(sp->is_gre.gs_call[0]), + ntohs(sp->is_gre.gs_call[1])); + } else if (sp->is_p == IPPROTO_ICMP +#ifdef USE_INET6 + || sp->is_p == IPPROTO_ICMPV6 +#endif + ) { + PRINTF("\tid %hu seq %hu type %d\n", sp->is_icmp.ici_id, + sp->is_icmp.ici_seq, sp->is_icmp.ici_type); + } + +#ifdef USE_QUAD_T + PRINTF("\tFWD: IN pkts %"PRIu64" bytes %"PRIu64" OUT pkts %"PRIu64" bytes %"PRIu64"\n\tREV: IN pkts %"PRIu64" bytes %"PRIu64" OUT pkts %"PRIu64" bytes %"PRIu64"\n", + sp->is_pkts[0], sp->is_bytes[0], + sp->is_pkts[1], sp->is_bytes[1], + sp->is_pkts[2], sp->is_bytes[2], + sp->is_pkts[3], sp->is_bytes[3]); +#else + PRINTF("\tFWD: IN pkts %lu bytes %lu OUT pkts %lu bytes %lu\n\tREV: IN pkts %lu bytes %lu OUT pkts %lu bytes %lu\n", + sp->is_pkts[0], sp->is_bytes[0], + sp->is_pkts[1], sp->is_bytes[1], + sp->is_pkts[2], sp->is_bytes[2], + sp->is_pkts[3], sp->is_bytes[3]); +#endif + + PRINTF("\ttag %u pass %#x = ", sp->is_tag, sp->is_pass); + + /* + * Print out bits set in the result code for the state being + * kept as they would for a rule. + */ + if (FR_ISPASS(sp->is_pass)) { + PRINTF("pass"); + } else if (FR_ISBLOCK(sp->is_pass)) { + PRINTF("block"); + switch (sp->is_pass & FR_RETMASK) + { + case FR_RETICMP : + PRINTF(" return-icmp"); + break; + case FR_FAKEICMP : + PRINTF(" return-icmp-as-dest"); + break; + case FR_RETRST : + PRINTF(" return-rst"); + break; + default : + break; + } + } else if ((sp->is_pass & FR_LOGMASK) == FR_LOG) { + PRINTF("log"); + if (sp->is_pass & FR_LOGBODY) + PRINTF(" body"); + if (sp->is_pass & FR_LOGFIRST) + PRINTF(" first"); + } else if (FR_ISACCOUNT(sp->is_pass)) { + PRINTF("count"); + } else if (FR_ISPREAUTH(sp->is_pass)) { + PRINTF("preauth"); + } else if (FR_ISAUTH(sp->is_pass)) + PRINTF("auth"); + + if (sp->is_pass & FR_OUTQUE) + PRINTF(" out"); + else + PRINTF(" in"); + + if ((sp->is_pass & FR_LOG) != 0) { + PRINTF(" log"); + if (sp->is_pass & FR_LOGBODY) + PRINTF(" body"); + if (sp->is_pass & FR_LOGFIRST) + PRINTF(" first"); + if (sp->is_pass & FR_LOGORBLOCK) + PRINTF(" or-block"); + } + if (sp->is_pass & FR_QUICK) + PRINTF(" quick"); + if (sp->is_pass & FR_KEEPFRAG) + PRINTF(" keep frags"); + /* a given; no? */ + if (sp->is_pass & FR_KEEPSTATE) { + PRINTF(" keep state"); + if (sp->is_pass & (FR_STATESYNC|FR_STSTRICT|FR_STLOOSE)) { + PRINTF(" ("); + if (sp->is_pass & FR_STATESYNC) + PRINTF(" sync"); + if (sp->is_pass & FR_STSTRICT) + PRINTF(" strict"); + if (sp->is_pass & FR_STLOOSE) + PRINTF(" loose"); + PRINTF(" )"); + } + } + PRINTF("\n"); + + if ((opts & OPT_VERBOSE) != 0) { + PRINTF("\tref %d", sp->is_ref); + PRINTF(" pkt_flags & %x(%x) = %x\n", + sp->is_flags & 0xf, sp->is_flags, sp->is_flags >> 4); + PRINTF("\tpkt_options & %x = %x, %x = %x \n", sp->is_optmsk[0], + sp->is_opt[0], sp->is_optmsk[1], sp->is_opt[1]); + PRINTF("\tpkt_security & %x = %x, pkt_auth & %x = %x\n", + sp->is_secmsk, sp->is_sec, sp->is_authmsk, + sp->is_auth); + PRINTF("\tis_flx %#x %#x %#x %#x\n", sp->is_flx[0][0], + sp->is_flx[0][1], sp->is_flx[1][0], sp->is_flx[1][1]); + } + PRINTF("\tinterfaces: in %s[%s", getifname(sp->is_ifp[0]), + sp->is_ifname[0]); + if (opts & OPT_DEBUG) + PRINTF("/%p", sp->is_ifp[0]); + putchar(']'); + PRINTF(",%s[%s", getifname(sp->is_ifp[1]), sp->is_ifname[1]); + if (opts & OPT_DEBUG) + PRINTF("/%p", sp->is_ifp[1]); + putchar(']'); + PRINTF(" out %s[%s", getifname(sp->is_ifp[2]), sp->is_ifname[2]); + if (opts & OPT_DEBUG) + PRINTF("/%p", sp->is_ifp[2]); + putchar(']'); + PRINTF(",%s[%s", getifname(sp->is_ifp[3]), sp->is_ifname[3]); + if (opts & OPT_DEBUG) + PRINTF("/%p", sp->is_ifp[3]); + PRINTF("]\n"); + + PRINTF("\tSync status: "); + if (sp->is_sync != NULL) { + if (kmemcpy((char *)&ipsync, (u_long)sp->is_sync, + sizeof(ipsync))) { + PRINTF("status could not be retrieved\n"); + return NULL; + } + + PRINTF("idx %d num %d v %d pr %d rev %d\n", + ipsync.sl_idx, ipsync.sl_num, ipsync.sl_v, + ipsync.sl_p, ipsync.sl_rev); + } else { + PRINTF("not synchronized\n"); + } + + return sp->is_next; +} diff --git a/contrib/ipfilter/lib/printstatefields.c b/contrib/ipfilter/lib/printstatefields.c new file mode 100644 index 0000000..5632d84 --- /dev/null +++ b/contrib/ipfilter/lib/printstatefields.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: printstatefields.c,v 1.4.2.2 2012/01/26 05:44:26 darren_r Exp $ + */ + +#include "ipf.h" + +wordtab_t statefields[] = { + { "all", -2 }, + { "ifp0", 1 }, + { "ifp1", 2 }, + { "ifp2", 3 }, + { "ifp3", 4 }, + { "ifname0", 5 }, + { "ifname1", 6 }, + { "ifname2", 7 }, + { "ifname3", 8 }, + { "pkts0", 9 }, + { "pkts1", 10 }, + { "pkts2", 11 }, + { "pkts3", 12 }, + { "bytes0", 13 }, + { "bytes1", 14 }, + { "bytes2", 15 }, + { "bytes3", 16 }, + { "state0", 17 }, + { "state1", 18 }, + { "age0", 19 }, + { "age1", 20 }, + { "ref", 21 }, + { "isn0", 22 }, + { "isn1", 23 }, + { "sumd0", 24 }, + { "sumd1", 25 }, + { "src", 26 }, + { "dst", 27 }, + { "sport", 28 }, + { "dport", 29 }, + { "icmptype", 30 }, + { "-", 31 }, + { "pass", 32 }, + { "proto", 33 }, + { "version", 34 }, + { "hash", 35 }, + { "tag", 36 }, + { "flags", 37 }, + { "rulen", 38 }, + { "group", 39 }, + { "flx0", 40 }, + { "flx1", 41 }, + { "flx2", 42 }, + { "flx3", 43 }, + { "opt0", 44 }, + { "opt1", 45 }, + { "optmsk0", 46 }, + { "optmsk1", 47 }, + { "sec", 48 }, + { "secmsk", 49 }, + { "auth", 50 }, + { "authmsk", 51 }, + { "icmppkts0", 52 }, + { "icmppkts1", 53 }, + { "icmppkts2", 54 }, + { "icmppkts3", 55 }, + { NULL, 0 } +}; + + +void +printstatefield(sp, fieldnum) + ipstate_t *sp; + int fieldnum; +{ + int i; + + switch (fieldnum) + { + case -2 : + for (i = 1; statefields[i].w_word != NULL; i++) { + if (statefields[i].w_value > 0) { + printstatefield(sp, i); + if (statefields[i + 1].w_value > 0) + putchar('\t'); + } + } + break; + + case 1: + PRINTF("%#lx", (u_long)sp->is_ifp[0]); + break; + + case 2: + PRINTF("%#lx", (u_long)sp->is_ifp[1]); + break; + + case 3: + PRINTF("%#lx", (u_long)sp->is_ifp[2]); + break; + + case 4: + PRINTF("%#lx", (u_long)sp->is_ifp[3]); + break; + + case 5: + PRINTF("%s", sp->is_ifname[0]); + break; + + case 6: + PRINTF("%s", sp->is_ifname[1]); + break; + + case 7: + PRINTF("%s", sp->is_ifname[2]); + break; + + case 8: + PRINTF("%s", sp->is_ifname[3]); + break; + + case 9: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_pkts[0]); +#else + PRINTF("%lu", sp->is_pkts[0]); +#endif + break; + + case 10: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_pkts[1]); +#else + PRINTF("%lu", sp->is_pkts[1]); +#endif + break; + + case 11: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_pkts[2]); +#else + PRINTF("%lu", sp->is_pkts[2]); +#endif + break; + + case 12: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_pkts[3]); +#else + PRINTF("%lu", sp->is_pkts[3]); +#endif + break; + + case 13: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_bytes[0]); +#else + PRINTF("%lu", sp->is_bytes[0]); +#endif + break; + + case 14: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_bytes[1]); +#else + PRINTF("%lu", sp->is_bytes[1]); +#endif + break; + + case 15: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_bytes[2]); +#else + PRINTF("%lu", sp->is_bytes[2]); +#endif + break; + + case 16: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_bytes[3]); +#else + PRINTF("%lu", sp->is_bytes[3]); +#endif + break; + + case 17: + PRINTF("%d", sp->is_state[0]); + break; + + case 18: + PRINTF("%d", sp->is_state[1]); + break; + + case 19: + PRINTF("%d", sp->is_frage[0]); + break; + + case 20: + PRINTF("%d", sp->is_frage[1]); + break; + + case 21: + PRINTF("%d", sp->is_ref); + break; + + case 22: + PRINTF("%d", sp->is_isninc[0]); + break; + + case 23: + PRINTF("%d", sp->is_isninc[1]); + break; + + case 24: + PRINTF("%hd", sp->is_sumd[0]); + break; + + case 25: + PRINTF("%hd", sp->is_sumd[1]); + break; + + case 26: + PRINTF("%s", hostname(sp->is_v, &sp->is_src.in4)); + break; + + case 27: + PRINTF("%s", hostname(sp->is_v, &sp->is_dst.in4)); + break; + + case 28: + PRINTF("%hu", ntohs(sp->is_sport)); + break; + + case 29: + PRINTF("%hu", ntohs(sp->is_dport)); + break; + + case 30: + PRINTF("%d", sp->is_type); + break; + + case 32: + PRINTF("%#x", sp->is_pass); + break; + + case 33: + PRINTF("%d", sp->is_p); + break; + + case 34: + PRINTF("%d", sp->is_v); + break; + + case 35: + PRINTF("%d", sp->is_hv); + break; + + case 36: + PRINTF("%d", sp->is_tag); + break; + + case 37: + PRINTF("%#x", sp->is_flags); + break; + + case 38: + PRINTF("%d", sp->is_rulen); + break; + + case 39: + PRINTF("%s", sp->is_group); + break; + + case 40: + PRINTF("%#x", sp->is_flx[0][0]); + break; + + case 41: + PRINTF("%#x", sp->is_flx[0][1]); + break; + + case 42: + PRINTF("%#x", sp->is_flx[1][0]); + break; + + case 43: + PRINTF("%#x", sp->is_flx[1][1]); + break; + + case 44: + PRINTF("%#x", sp->is_opt[0]); + break; + + case 45: + PRINTF("%#x", sp->is_opt[1]); + break; + + case 46: + PRINTF("%#x", sp->is_optmsk[0]); + break; + + case 47: + PRINTF("%#x", sp->is_optmsk[1]); + break; + + case 48: + PRINTF("%#x", sp->is_sec); + break; + + case 49: + PRINTF("%#x", sp->is_secmsk); + break; + + case 50: + PRINTF("%#x", sp->is_auth); + break; + + case 51: + PRINTF("%#x", sp->is_authmsk); + break; + + case 52: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_icmppkts[0]); +#else + PRINTF("%lu", sp->is_icmppkts[0]); +#endif + break; + + case 53: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_icmppkts[1]); +#else + PRINTF("%lu", sp->is_icmppkts[1]); +#endif + break; + + case 54: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_icmppkts[2]); +#else + PRINTF("%lu", sp->is_icmppkts[2]); +#endif + break; + + case 55: +#ifdef USE_QUAD_T + PRINTF("%"PRIu64"", sp->is_icmppkts[3]); +#else + PRINTF("%lu", sp->is_icmppkts[3]); +#endif + break; + + default: + break; + } +} diff --git a/contrib/ipfilter/lib/printtcpflags.c b/contrib/ipfilter/lib/printtcpflags.c new file mode 100644 index 0000000..9860780 --- /dev/null +++ b/contrib/ipfilter/lib/printtcpflags.c @@ -0,0 +1,30 @@ +#include "ipf.h" + + +void +printtcpflags(tcpf, tcpfm) + u_32_t tcpf, tcpfm; +{ + u_char *t; + char *s; + + if (tcpf & ~TCPF_ALL) { + PRINTF("0x%x", tcpf); + } else { + for (s = flagset, t = flags; *s; s++, t++) { + if (tcpf & *t) + (void)putchar(*s); + } + } + + if (tcpfm) { + (void)putchar('/'); + if (tcpfm & ~TCPF_ALL) { + PRINTF("0x%x", tcpfm); + } else { + for (s = flagset, t = flags; *s; s++, t++) + if (tcpfm & *t) + (void)putchar(*s); + } + } +} diff --git a/contrib/ipfilter/lib/printtqtable.c b/contrib/ipfilter/lib/printtqtable.c new file mode 100644 index 0000000..ffb512d --- /dev/null +++ b/contrib/ipfilter/lib/printtqtable.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" + + +void +printtqtable(table) + ipftq_t *table; +{ + int i; + + PRINTF("TCP Entries per state\n"); + for (i = 0; i < IPF_TCP_NSTATES; i++) + PRINTF(" %5d", i); + PRINTF("\n"); + + for (i = 0; i < IPF_TCP_NSTATES; i++) + PRINTF(" %5d", table[i].ifq_ref - 1); + PRINTF("\n"); +} diff --git a/contrib/ipfilter/lib/printtunable.c b/contrib/ipfilter/lib/printtunable.c new file mode 100644 index 0000000..aa82841 --- /dev/null +++ b/contrib/ipfilter/lib/printtunable.c @@ -0,0 +1,30 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +void +printtunable(tup) + ipftune_t *tup; +{ + PRINTF("%s\tmin %lu\tmax %lu\tcurrent ", + tup->ipft_name, tup->ipft_min, tup->ipft_max); + if (tup->ipft_sz == sizeof(u_long)) + PRINTF("%lu\n", tup->ipft_vlong); + else if (tup->ipft_sz == sizeof(u_int)) + PRINTF("%u\n", tup->ipft_vint); + else if (tup->ipft_sz == sizeof(u_short)) + PRINTF("%hu\n", tup->ipft_vshort); + else if (tup->ipft_sz == sizeof(u_char)) + PRINTF("%u\n", (u_int)tup->ipft_vchar); + else { + PRINTF("sz = %d\n", tup->ipft_sz); + } +} diff --git a/contrib/ipfilter/lib/printunit.c b/contrib/ipfilter/lib/printunit.c new file mode 100644 index 0000000..bac3d45 --- /dev/null +++ b/contrib/ipfilter/lib/printunit.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#include "ipf.h" + + +void +printunit(unit) + int unit; +{ + + switch (unit) + { + case IPL_LOGIPF : + PRINTF("ipf"); + break; + case IPL_LOGNAT : + PRINTF("nat"); + break; + case IPL_LOGSTATE : + PRINTF("state"); + break; + case IPL_LOGAUTH : + PRINTF("auth"); + break; + case IPL_LOGSYNC : + PRINTF("sync"); + break; + case IPL_LOGSCAN : + PRINTF("scan"); + break; + case IPL_LOGLOOKUP : + PRINTF("lookup"); + break; + case IPL_LOGCOUNT : + PRINTF("count"); + break; + case IPL_LOGALL : + PRINTF("all"); + break; + default : + PRINTF("unknown(%d)", unit); + } +} diff --git a/contrib/ipfilter/lib/remove_hash.c b/contrib/ipfilter/lib/remove_hash.c new file mode 100644 index 0000000..a60c1fd --- /dev/null +++ b/contrib/ipfilter/lib/remove_hash.c @@ -0,0 +1,50 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + + +int +remove_hash(iphp, iocfunc) + iphtable_t *iphp; + ioctlfunc_t iocfunc; +{ + iplookupop_t op; + iphtable_t iph; + + if (pool_open() == -1) + return -1; + + op.iplo_type = IPLT_HASH; + op.iplo_unit = iphp->iph_unit; + strncpy(op.iplo_name, iphp->iph_name, sizeof(op.iplo_name)); + if (*op.iplo_name == '\0') + op.iplo_arg = IPHASH_ANON; + op.iplo_size = sizeof(iph); + op.iplo_struct = &iph; + + bzero((char *)&iph, sizeof(iph)); + iph.iph_unit = iphp->iph_unit; + iph.iph_type = iphp->iph_type; + strncpy(iph.iph_name, iphp->iph_name, sizeof(iph.iph_name)); + iph.iph_flags = iphp->iph_flags; + + if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op)) { + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "remove lookup hash table"); + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/remove_hashnode.c b/contrib/ipfilter/lib/remove_hashnode.c new file mode 100644 index 0000000..58e9125 --- /dev/null +++ b/contrib/ipfilter/lib/remove_hashnode.c @@ -0,0 +1,56 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + + +int +remove_hashnode(unit, name, node, iocfunc) + int unit; + char *name; + iphtent_t *node; + ioctlfunc_t iocfunc; +{ + iplookupop_t op; + iphtent_t ipe; + + if (pool_open() == -1) + return -1; + + op.iplo_type = IPLT_HASH; + op.iplo_unit = unit; + op.iplo_size = sizeof(ipe); + op.iplo_struct = &ipe; + op.iplo_arg = 0; + strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + + bzero((char *)&ipe, sizeof(ipe)); + bcopy((char *)&node->ipe_addr, (char *)&ipe.ipe_addr, + sizeof(ipe.ipe_addr)); + bcopy((char *)&node->ipe_mask, (char *)&ipe.ipe_mask, + sizeof(ipe.ipe_mask)); + + if (opts & OPT_DEBUG) { + printf("\t%s - ", inet_ntoa(ipe.ipe_addr.in4)); + printf("%s\n", inet_ntoa(ipe.ipe_mask.in4)); + } + + if (pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op)) { + if (!(opts & OPT_DONOTHING)) { + return ipf_perror_fd(pool_fd(), iocfunc, + "remove lookup hash node"); + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/remove_pool.c b/contrib/ipfilter/lib/remove_pool.c new file mode 100644 index 0000000..8e75549 --- /dev/null +++ b/contrib/ipfilter/lib/remove_pool.c @@ -0,0 +1,47 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_htable.h" + + +int +remove_pool(poolp, iocfunc) + ip_pool_t *poolp; + ioctlfunc_t iocfunc; +{ + iplookupop_t op; + ip_pool_t pool; + + if (pool_open() == -1) + return -1; + + op.iplo_type = IPLT_POOL; + op.iplo_unit = poolp->ipo_unit; + strncpy(op.iplo_name, poolp->ipo_name, sizeof(op.iplo_name)); + op.iplo_size = sizeof(pool); + op.iplo_struct = &pool; + + bzero((char *)&pool, sizeof(pool)); + pool.ipo_unit = poolp->ipo_unit; + strncpy(pool.ipo_name, poolp->ipo_name, sizeof(pool.ipo_name)); + pool.ipo_flags = poolp->ipo_flags; + + if (pool_ioctl(iocfunc, SIOCLOOKUPDELTABLE, &op)) { + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "delete lookup pool"); + } + } + return 0; +} diff --git a/contrib/ipfilter/lib/remove_poolnode.c b/contrib/ipfilter/lib/remove_poolnode.c new file mode 100644 index 0000000..0b78118 --- /dev/null +++ b/contrib/ipfilter/lib/remove_poolnode.c @@ -0,0 +1,54 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" + + +int +remove_poolnode(unit, name, node, iocfunc) + int unit; + char *name; + ip_pool_node_t *node; + ioctlfunc_t iocfunc; +{ + ip_pool_node_t pn; + iplookupop_t op; + + if (pool_open() == -1) + return -1; + + op.iplo_unit = unit; + op.iplo_type = IPLT_POOL; + op.iplo_arg = 0; + strncpy(op.iplo_name, name, sizeof(op.iplo_name)); + op.iplo_struct = &pn; + op.iplo_size = sizeof(pn); + + bzero((char *)&pn, sizeof(pn)); + bcopy((char *)&node->ipn_addr, (char *)&pn.ipn_addr, + sizeof(pn.ipn_addr)); + bcopy((char *)&node->ipn_mask, (char *)&pn.ipn_mask, + sizeof(pn.ipn_mask)); + pn.ipn_info = node->ipn_info; + strncpy(pn.ipn_name, node->ipn_name, sizeof(pn.ipn_name)); + + if (pool_ioctl(iocfunc, SIOCLOOKUPDELNODE, &op)) { + if ((opts & OPT_DONOTHING) == 0) { + return ipf_perror_fd(pool_fd(), iocfunc, + "remove lookup pool node"); + } + } + + return 0; +} diff --git a/contrib/ipfilter/lib/resetlexer.c b/contrib/ipfilter/lib/resetlexer.c new file mode 100644 index 0000000..558db98 --- /dev/null +++ b/contrib/ipfilter/lib/resetlexer.c @@ -0,0 +1,25 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +long string_start = -1; +long string_end = -1; +char *string_val = NULL; +long pos = 0; + + +void resetlexer() +{ + string_start = -1; + string_end = -1; + string_val = NULL; + pos = 0; +} diff --git a/contrib/ipfilter/lib/rwlock_emul.c b/contrib/ipfilter/lib/rwlock_emul.c new file mode 100644 index 0000000..24d00a5 --- /dev/null +++ b/contrib/ipfilter/lib/rwlock_emul.c @@ -0,0 +1,145 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + +#define EMM_MAGIC 0x97dd8b3a + +void eMrwlock_read_enter(rw, file, line) + eMrwlock_t *rw; + char *file; + int line; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_read_enter(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_read != 0 || rw->eMrw_write != 0) { + fprintf(stderr, + "%s:eMrwlock_read_enter(%p): already locked: %d/%d\n", + rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write); + abort(); + } + rw->eMrw_read++; + rw->eMrw_heldin = file; + rw->eMrw_heldat = line; +} + + +void eMrwlock_write_enter(rw, file, line) + eMrwlock_t *rw; + char *file; + int line; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_write_enter(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_read != 0 || rw->eMrw_write != 0) { + fprintf(stderr, + "%s:eMrwlock_write_enter(%p): already locked: %d/%d\n", + rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write); + abort(); + } + rw->eMrw_write++; + rw->eMrw_heldin = file; + rw->eMrw_heldat = line; +} + + +void eMrwlock_downgrade(rw, file, line) + eMrwlock_t *rw; + char *file; + int line; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_write_enter(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_read != 0 || rw->eMrw_write != 1) { + fprintf(stderr, + "%s:eMrwlock_write_enter(%p): already locked: %d/%d\n", + rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write); + abort(); + } + rw->eMrw_write--; + rw->eMrw_read++; + rw->eMrw_heldin = file; + rw->eMrw_heldat = line; +} + + +void eMrwlock_exit(rw) + eMrwlock_t *rw; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_exit(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_read != 1 && rw->eMrw_write != 1) { + fprintf(stderr, "%s:eMrwlock_exit(%p): not locked: %d/%d\n", + rw->eMrw_owner, rw, rw->eMrw_read, rw->eMrw_write); + abort(); + } + if (rw->eMrw_read == 1) + rw->eMrw_read--; + else if (rw->eMrw_write == 1) + rw->eMrw_write--; + rw->eMrw_heldin = NULL; + rw->eMrw_heldat = 0; +} + + +static int initcount = 0; + +void eMrwlock_init(rw, who) + eMrwlock_t *rw; + char *who; +{ + if (rw->eMrw_magic == EMM_MAGIC) { /* safe bet ? */ + fprintf(stderr, + "%s:eMrwlock_init(%p): already initialised?: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + rw->eMrw_magic = EMM_MAGIC; + rw->eMrw_read = 0; + rw->eMrw_write = 0; + if (who != NULL) + rw->eMrw_owner = strdup(who); + else + rw->eMrw_owner = NULL; + initcount++; +} + + +void eMrwlock_destroy(rw) + eMrwlock_t *rw; +{ + if (rw->eMrw_magic != EMM_MAGIC) { + fprintf(stderr, "%s:eMrwlock_destroy(%p): bad magic: %#x\n", + rw->eMrw_owner, rw, rw->eMrw_magic); + abort(); + } + if (rw->eMrw_owner != NULL) + free(rw->eMrw_owner); + memset(rw, 0xa5, sizeof(*rw)); + initcount--; +} + +void ipf_rwlock_clean() +{ + if (initcount != 0) + abort(); +} diff --git a/contrib/ipfilter/lib/save_execute.c b/contrib/ipfilter/lib/save_execute.c new file mode 100644 index 0000000..65caca4 --- /dev/null +++ b/contrib/ipfilter/lib/save_execute.c @@ -0,0 +1,80 @@ +#include "ipf.h" +#include "ipmon.h" + +static void *execute_parse __P((char **)); +static void execute_destroy __P((void *)); +static int execute_send __P((void *, ipmon_msg_t *)); +static void execute_print __P((void *)); + +typedef struct execute_opts_s { + char *path; +} execute_opts_t; + +ipmon_saver_t executesaver = { + "execute", + execute_destroy, + NULL, /* dup */ + NULL, /* match */ + execute_parse, + execute_print, + execute_send +}; + + +static void * +execute_parse(char **strings) +{ + execute_opts_t *ctx; + + ctx = calloc(1, sizeof(*ctx)); + + if (ctx != NULL && strings[0] != NULL && strings[0][0] != '\0') { + ctx->path = strdup(strings[0]); + + } else { + free(ctx); + return NULL; + } + + return ctx; +} + + +static void +execute_print(ctx) + void *ctx; +{ + execute_opts_t *exe = ctx; + + printf("%s", exe->path); +} + + +static void +execute_destroy(ctx) + void *ctx; +{ + execute_opts_t *exe = ctx; + + if (exe != NULL) + free(exe->path); + free(exe); +} + + +static int +execute_send(ctx, msg) + void *ctx; + ipmon_msg_t *msg; +{ + execute_opts_t *exe = ctx; + FILE *fp; + + fp = popen(exe->path, "w"); + if (fp != NULL) { + fwrite(msg->imm_msg, msg->imm_msglen, 1, fp); + pclose(fp); + } + return 0; +} + diff --git a/contrib/ipfilter/lib/save_file.c b/contrib/ipfilter/lib/save_file.c new file mode 100644 index 0000000..b852bd6 --- /dev/null +++ b/contrib/ipfilter/lib/save_file.c @@ -0,0 +1,130 @@ +#include "ipf.h" +#include "ipmon.h" + +static void *file_parse __P((char **)); +static void file_destroy __P((void *)); +static int file_send __P((void *, ipmon_msg_t *)); +static void file_print __P((void *)); +static int file_match __P((void *, void *)); +static void *file_dup __P((void *)); + +typedef struct file_opts_s { + FILE *fp; + int raw; + char *path; + int ref; +} file_opts_t; + +ipmon_saver_t filesaver = { + "file", + file_destroy, + file_dup, + file_match, + file_parse, + file_print, + file_send +}; + + +static void * +file_parse(strings) + char **strings; +{ + file_opts_t *ctx; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + if (strings[0] != NULL && strings[0][0] != '\0') { + ctx->ref = 1; + if (!strncmp(strings[0], "raw://", 6)) { + ctx->raw = 1; + ctx->path = strdup(strings[0] + 6); + ctx->fp = fopen(ctx->path, "ab"); + } else if (!strncmp(strings[0], "file://", 7)) { + ctx->path = strdup(strings[0] + 7); + ctx->fp = fopen(ctx->path, "a"); + } else { + free(ctx); + ctx = NULL; + } + } else { + free(ctx); + ctx = NULL; + } + + return ctx; +} + + +static int +file_match(ctx1, ctx2) + void *ctx1, *ctx2; +{ + file_opts_t *f1 = ctx1, *f2 = ctx2; + + if (f1->raw != f2->raw) + return 1; + if (strcmp(f1->path, f2->path)) + return 1; + return 0; +} + + +static void * +file_dup(ctx) + void *ctx; +{ + file_opts_t *f = ctx; + + f->ref++; + return f; +} + + +static void +file_print(ctx) + void *ctx; +{ + file_opts_t *file = ctx; + + if (file->raw) + printf("raw://"); + else + printf("file://"); + printf("%s", file->path); +} + + +static void +file_destroy(ctx) + void *ctx; +{ + file_opts_t *file = ctx; + + file->ref--; + if (file->ref > 0) + return; + + if (file->path != NULL) + free(file->path); + free(file); +} + + +static int +file_send(ctx, msg) + void *ctx; + ipmon_msg_t *msg; +{ + file_opts_t *file = ctx; + + if (file->raw) { + fwrite(msg->imm_data, msg->imm_dsize, 1, file->fp); + } else { + fprintf(file->fp, "%s", msg->imm_msg); + } + return 0; +} + diff --git a/contrib/ipfilter/lib/save_nothing.c b/contrib/ipfilter/lib/save_nothing.c new file mode 100644 index 0000000..d25ab51 --- /dev/null +++ b/contrib/ipfilter/lib/save_nothing.c @@ -0,0 +1,62 @@ +#include "ipf.h" +#include "ipmon.h" + +static void *nothing_parse __P((char **)); +static void nothing_destroy __P((void *)); +static int nothing_send __P((void *, ipmon_msg_t *)); + +typedef struct nothing_opts_s { + FILE *fp; + int raw; + char *path; +} nothing_opts_t; + +ipmon_saver_t nothingsaver = { + "nothing", + nothing_destroy, + NULL, /* dup */ + NULL, /* match */ + nothing_parse, + NULL, /* print */ + nothing_send +}; + + +static void * +nothing_parse(char **strings) +{ + void *ctx; + +#if 0 + strings = strings; /* gcc -Wextra */ +#endif + + ctx = calloc(1, sizeof(void *)); + + return ctx; +} + + +static void +nothing_destroy(ctx) + void *ctx; +{ + free(ctx); +} + + +static int +nothing_send(ctx, msg) + void *ctx; + ipmon_msg_t *msg; +{ +#if 0 + ctx = ctx; /* gcc -Wextra */ + msg = msg; /* gcc -Wextra */ +#endif + /* + * Do nothing + */ + return 0; +} + diff --git a/contrib/ipfilter/lib/save_syslog.c b/contrib/ipfilter/lib/save_syslog.c new file mode 100644 index 0000000..c1efdf4 --- /dev/null +++ b/contrib/ipfilter/lib/save_syslog.c @@ -0,0 +1,137 @@ +#include "ipf.h" +#include "ipmon.h" +#include <syslog.h> + +static void *syslog_parse __P((char **)); +static void syslog_destroy __P((void *)); +static int syslog_send __P((void *, ipmon_msg_t *)); +static void syslog_print __P((void *)); + +typedef struct syslog_opts_s { + int facpri; + int fac; + int pri; +} syslog_opts_t; + +ipmon_saver_t syslogsaver = { + "syslog", + syslog_destroy, + NULL, /* dup */ + NULL, /* match */ + syslog_parse, + syslog_print, + syslog_send +}; + + +static void * +syslog_parse(char **strings) +{ + syslog_opts_t *ctx; + char *str; + char *s; + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->facpri = -1; + + if (strings[0] != NULL && strings[0][0] != '\0') { + str = strdup(*strings); + if (str != NULL && *str != '\0') { + int fac = -1, pri = -1; + + s = strchr(str, '.'); + if (s != NULL) + *s++ = '\0'; + + if (*str != '\0') { + fac = fac_findname(str); + if (fac == -1) { + free(str); + free(ctx); + return NULL; + } + } + + if (s != NULL && *s != '\0') { + pri = pri_findname(s); + if (pri == -1) { + free(str); + free(ctx); + return NULL; + } + } + free(str); + + ctx->fac = fac; + ctx->pri = pri; + if (pri == -1) + ctx->facpri = fac; + else if (fac == -1) + ctx->facpri = pri; + else + ctx->facpri = fac | pri; + } else { + if (str != NULL) + free(str); + free(ctx); + ctx = NULL; + } + } + + return ctx; +} + + +static void +syslog_print(ctx) + void *ctx; +{ + syslog_opts_t *sys = ctx; + + if (sys->facpri == -1) + return; + + if (sys->fac == -1) { + printf(".%s", pri_toname(sys->pri)); + } else if (sys->pri == -1) { + printf("%s.", fac_toname(sys->fac)); + } else { + printf("%s.%s", fac_toname(sys->facpri & LOG_FACMASK), + pri_toname(sys->facpri & LOG_PRIMASK)); + } +} + + +static void +syslog_destroy(ctx) + void *ctx; +{ + free(ctx); +} + + +static int +syslog_send(ctx, msg) + void *ctx; + ipmon_msg_t *msg; +{ + syslog_opts_t *sys = ctx; + int facpri; + + if (sys->facpri == -1) { + facpri = msg->imm_loglevel; + } else { + if (sys->pri == -1) { + facpri = sys->fac | (msg->imm_loglevel & LOG_PRIMASK); + } else if (sys->fac == -1) { + facpri = sys->pri | (msg->imm_loglevel & LOG_FACMASK); + } else { + facpri = sys->facpri; + } + } + syslog(facpri, "%s", msg->imm_msg); + return 0; +} diff --git a/contrib/ipfilter/lib/save_v1trap.c b/contrib/ipfilter/lib/save_v1trap.c new file mode 100644 index 0000000..78671c7 --- /dev/null +++ b/contrib/ipfilter/lib/save_v1trap.c @@ -0,0 +1,463 @@ +#include "ipf.h" +#include "netinet/ipl.h" +#include "ipmon.h" +#include <ctype.h> + +#define IPF_ENTERPRISE 9932 +/* + * Enterprise number OID: + * 1.3.6.1.4.1.9932 + */ +static u_char ipf_enterprise[] = { 6, 7, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c }; +static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 }; +static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 }; + +static int writeint __P((u_char *, int)); +static int writelength __P((u_char *, u_int)); +static int maketrap_v1 __P((char *, u_char *, int, u_char *, int, u_32_t, + time_t)); +static void snmpv1_destroy __P((void *)); +static void *snmpv1_dup __P((void *)); +static int snmpv1_match __P((void *, void *)); +static void *snmpv1_parse __P((char **)); +static void snmpv1_print __P((void *)); +static int snmpv1_send __P((void *, ipmon_msg_t *)); + +typedef struct snmpv1_opts_s { + char *community; + int fd; + int v6; + int ref; +#ifdef USE_INET6 + struct sockaddr_in6 sin6; +#endif + struct sockaddr_in sin; +} snmpv1_opts_t; + +ipmon_saver_t snmpv1saver = { + "snmpv1", + snmpv1_destroy, + snmpv1_dup, /* dup */ + snmpv1_match, /* match */ + snmpv1_parse, + snmpv1_print, + snmpv1_send +}; + + +static int +snmpv1_match(ctx1, ctx2) + void *ctx1, *ctx2; +{ + snmpv1_opts_t *s1 = ctx1, *s2 = ctx2; + + if (s1->v6 != s2->v6) + return 1; + + if (strcmp(s1->community, s2->community)) + return 1; + +#ifdef USE_INET6 + if (s1->v6 == 1) { + if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6))) + return 1; + } else +#endif + { + if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin))) + return 1; + } + + return 0; +} + + +static void * +snmpv1_dup(ctx) + void *ctx; +{ + snmpv1_opts_t *s = ctx; + + s->ref++; + return s; +} + + +static void +snmpv1_print(ctx) + void *ctx; +{ + snmpv1_opts_t *snmpv1 = ctx; + + printf("%s ", snmpv1->community); +#ifdef USE_INET6 + if (snmpv1->v6 == 1) { + char buf[80]; + + printf("%s", inet_ntop(AF_INET6, &snmpv1->sin6.sin6_addr, buf, + sizeof(snmpv1->sin6.sin6_addr))); + } else +#endif + { + printf("%s", inet_ntoa(snmpv1->sin.sin_addr)); + } +} + + +static void * +snmpv1_parse(char **strings) +{ + snmpv1_opts_t *ctx; + int result; + char *str; + char *s; + + if (strings[0] == NULL || strings[0][0] == '\0') + return NULL; + + if (strchr(*strings, ' ') == NULL) + return NULL; + + str = strdup(*strings); + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->fd = -1; + + s = strchr(str, ' '); + *s++ = '\0'; + ctx->community = str; + + while (ISSPACE(*s)) + s++; + if (!*s) { + free(str); + free(ctx); + return NULL; + } + +#ifdef USE_INET6 + if (strchr(s, ':') == NULL) { + result = inet_pton(AF_INET, s, &ctx->sin.sin_addr); + if (result == 1) { + ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (ctx->fd >= 0) { + ctx->sin.sin_family = AF_INET; + ctx->sin.sin_port = htons(162); + if (connect(ctx->fd, + (struct sockaddr *)&ctx->sin, + sizeof(ctx->sin)) != 0) { + snmpv1_destroy(ctx); + return NULL; + } + } + } + } else { + result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr); + if (result == 1) { + ctx->v6 = 1; + ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (ctx->fd >= 0) { + ctx->sin6.sin6_family = AF_INET6; + ctx->sin6.sin6_port = htons(162); + if (connect(ctx->fd, + (struct sockaddr *)&ctx->sin6, + sizeof(ctx->sin6)) != 0) { + snmpv1_destroy(ctx); + return NULL; + } + } + } + } +#else + result = inet_aton(s, &ctx->sin.sin_addr); + if (result == 1) { + ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (ctx->fd >= 0) { + ctx->sin.sin_family = AF_INET; + ctx->sin.sin_port = htons(162); + if (connect(ctx->fd, (struct sockaddr *)&ctx->sin, + sizeof(ctx->sin)) != 0) { + snmpv1_destroy(ctx); + return NULL; + } + } + } +#endif + + if (result != 1) { + free(str); + free(ctx); + return NULL; + } + + ctx->ref = 1; + + return ctx; +} + + +static void +snmpv1_destroy(ctx) + void *ctx; +{ + snmpv1_opts_t *v1 = ctx; + + v1->ref--; + if (v1->ref > 0) + return; + + if (v1->community) + free(v1->community); + if (v1->fd >= 0) + close(v1->fd); + free(v1); +} + + +static int +snmpv1_send(ctx, msg) + void *ctx; + ipmon_msg_t *msg; +{ + snmpv1_opts_t *v1 = ctx; + + return sendtrap_v1_0(v1->fd, v1->community, + msg->imm_msg, msg->imm_msglen, msg->imm_when); +} + +static char def_community[] = "public"; /* ublic */ + +static int +writelength(buffer, value) + u_char *buffer; + u_int value; +{ + u_int n = htonl(value); + int len; + + if (value < 128) { + *buffer = value; + return 1; + } + if (value > 0xffffff) + len = 4; + else if (value > 0xffff) + len = 3; + else if (value > 0xff) + len = 2; + else + len = 1; + + *buffer = 0x80 | len; + + bcopy((u_char *)&n + 4 - len, buffer + 1, len); + + return len + 1; +} + + +static int +writeint(buffer, value) + u_char *buffer; + int value; +{ + u_char *s = buffer; + u_int n = value; + + if (value == 0) { + *buffer = 0; + return 1; + } + + if (n > 4194304) { + *s++ = 0x80 | (n / 4194304); + n -= 4194304 * (n / 4194304); + } + if (n > 32768) { + *s++ = 0x80 | (n / 32768); + n -= 32768 * (n / 327678); + } + if (n > 128) { + *s++ = 0x80 | (n / 128); + n -= (n / 128) * 128; + } + *s++ = (u_char)n; + + return s - buffer; +} + + + +/* + * First style of traps is: + * 1.3.6.1.4.1.9932.1.1 + */ +static int +maketrap_v1(community, buffer, bufsize, msg, msglen, ipaddr, when) + char *community; + u_char *buffer; + int bufsize; + u_char *msg; + int msglen; + u_32_t ipaddr; + time_t when; +{ + u_char *s = buffer, *t, *pdulen, *varlen; + int basesize = 73; + u_short len; + int trapmsglen; + int pdulensz; + int varlensz; + int baselensz; + int n; + + if (community == NULL || *community == '\0') + community = def_community; + basesize += strlen(community) + msglen; + + if (basesize + 8 > bufsize) + return 0; + + memset(buffer, 0xff, bufsize); + *s++ = 0x30; /* Sequence */ + if (basesize - 1 >= 128) { + baselensz = 2; + basesize++; + } else { + baselensz = 1; + } + s += baselensz; + *s++ = 0x02; /* Integer32 */ + *s++ = 0x01; /* length 1 */ + *s++ = 0x00; /* version 1 */ + *s++ = 0x04; /* octet string */ + *s++ = strlen(community); /* length of "public" */ + bcopy(community, s, s[-1]); + s += s[-1]; + *s++ = 0xA4; /* PDU(4) */ + pdulen = s++; + if (basesize - (s - buffer) >= 128) { + pdulensz = 2; + basesize++; + s++; + } else { + pdulensz = 1; + } + + /* enterprise */ + bcopy(ipf_enterprise, s, sizeof(ipf_enterprise)); + s += sizeof(ipf_enterprise); + + /* Agent address */ + *s++ = 0x40; + *s++ = 0x4; + bcopy(&ipaddr, s, 4); + s += 4; + + /* Generic Trap code */ + *s++ = 0x2; + n = writeint(s + 1, 6); + if (n == 0) + return 0; + *s = n; + s += n + 1; + + /* Specific Trap code */ + *s++ = 0x2; + n = writeint(s + 1, 0); + if (n == 0) + return 0; + *s = n; + s += n + 1; + + /* Time stamp */ + *s++ = 0x43; /* TimeTicks */ + *s++ = 0x04; /* TimeTicks */ + s[0] = when >> 24; + s[1] = when >> 16; + s[2] = when >> 8; + s[3] = when & 0xff; + s += 4; + + /* + * The trap0 message is "ipfilter_version" followed by the message + */ + *s++ = 0x30; + varlen = s; + if (basesize - (s - buffer) >= 128) { + varlensz = 2; + basesize++; + } else { + varlensz = 1; + } + s += varlensz; + + *s++ = 0x30; + t = s + 1; + bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1)); + t += sizeof(ipf_trap0_1); + + *t++ = 0x2; /* Integer */ + n = writeint(t + 1, IPFILTER_VERSION); + *t = n; + t += n + 1; + + len = t - s - 1; + writelength(s, len); + + s = t; + *s++ = 0x30; + if (basesize - (s - buffer) >= 128) { + trapmsglen = 2; + basesize++; + } else { + trapmsglen = 1; + } + t = s + trapmsglen; + bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2)); + t += sizeof(ipf_trap0_2); + + *t++ = 0x4; /* Octet string */ + n = writelength(t, msglen); + t += n; + bcopy(msg, t, msglen); + t += msglen; + + len = t - s - trapmsglen; + writelength(s, len); + + len = t - varlen - varlensz; + writelength(varlen, len); /* pdu length */ + + len = t - pdulen - pdulensz; + writelength(pdulen, len); /* pdu length */ + + len = t - buffer - baselensz - 1; + writelength(buffer + 1, len); /* length of trap */ + + return t - buffer; +} + + +int +sendtrap_v1_0(fd, community, msg, msglen, when) + int fd; + char *community, *msg; + int msglen; + time_t when; +{ + + u_char buffer[1500]; + int n; + + n = maketrap_v1(community, buffer, sizeof(buffer), + (u_char *)msg, msglen, 0, when); + if (n > 0) { + return send(fd, buffer, n, 0); + } + + return 0; +} diff --git a/contrib/ipfilter/lib/save_v2trap.c b/contrib/ipfilter/lib/save_v2trap.c new file mode 100644 index 0000000..78e76f6 --- /dev/null +++ b/contrib/ipfilter/lib/save_v2trap.c @@ -0,0 +1,459 @@ +#include "ipf.h" +#include "netinet/ipl.h" +#include "ipmon.h" +#include <ctype.h> + +static u_char sysuptime[] = { 6, 8, 0x2b, 6, 1, 2, 1, 1, 3, 0 }; +/* + * Enterprise number OID: + * 1.3.6.1.4.1.9932 + */ +static u_char ipf_trap0_1[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 1 }; +static u_char ipf_trap0_2[] = { 6, 10, 0x2b, 6, 1, 4, 1, 0xcd, 0x4c, 1, 1, 2 }; + +static int writeint __P((u_char *, int)); +static int writelength __P((u_char *, u_int)); +static int maketrap_v2 __P((char *, u_char *, int, u_char *, int)); +static void snmpv2_destroy __P((void *)); +static void *snmpv2_dup __P((void *)); +static int snmpv2_match __P((void *, void *)); +static void *snmpv2_parse __P((char **)); +static void snmpv2_print __P((void *)); +static int snmpv2_send __P((void *, ipmon_msg_t *)); + + +int sendtrap_v2_0 __P((int, char *, char *, int)); + +static char def_community[] = "public"; /* ublic */ + +typedef struct snmpv2_opts_s { + char *community; + char *server; + int fd; + int v6; + int ref; +#ifdef USE_INET6 + struct sockaddr_in6 sin6; +#endif + struct sockaddr_in sin; +} snmpv2_opts_t; + +ipmon_saver_t snmpv2saver = { + "snmpv2", + snmpv2_destroy, + snmpv2_dup, /* dup */ + snmpv2_match, /* match */ + snmpv2_parse, + snmpv2_print, + snmpv2_send +}; + + +static int +snmpv2_match(ctx1, ctx2) + void *ctx1, *ctx2; +{ + snmpv2_opts_t *s1 = ctx1, *s2 = ctx2; + + if (s1->v6 != s2->v6) + return 1; + + if (strcmp(s1->community, s2->community)) + return 1; + +#ifdef USE_INET6 + if (s1->v6 == 1) { + if (memcmp(&s1->sin6, &s2->sin6, sizeof(s1->sin6))) + return 1; + } else +#endif + { + if (memcmp(&s1->sin, &s2->sin, sizeof(s1->sin))) + return 1; + } + + return 0; +} + + +static void * +snmpv2_dup(ctx) + void *ctx; +{ + snmpv2_opts_t *s = ctx; + + s->ref++; + return s; +} + + +static void +snmpv2_print(ctx) + void *ctx; +{ + snmpv2_opts_t *snmpv2 = ctx; + + printf("%s ", snmpv2->community); +#ifdef USE_INET6 + if (snmpv2->v6 == 1) { + char buf[80]; + + printf("%s", inet_ntop(AF_INET6, &snmpv2->sin6.sin6_addr, buf, + sizeof(snmpv2->sin6.sin6_addr))); + } else +#endif + { + printf("%s", inet_ntoa(snmpv2->sin.sin_addr)); + } +} + + +static void * +snmpv2_parse(char **strings) +{ + snmpv2_opts_t *ctx; + int result; + char *str; + char *s; + + if (strings[0] == NULL || strings[0][0] == '\0') + return NULL; + if (strchr(*strings, ' ') == NULL) + return NULL; + + str = strdup(*strings); + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return NULL; + + ctx->fd = -1; + + s = strchr(str, ' '); + *s++ = '\0'; + ctx->community = str; + + while (ISSPACE(*s)) + s++; + if (!*s) { + free(str); + free(ctx); + return NULL; + } + +#ifdef USE_INET6 + if (strchr(s, ':') == NULL) { + result = inet_pton(AF_INET, s, &ctx->sin.sin_addr); + if (result == 1) { + ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (ctx->fd >= 0) { + ctx->sin.sin_family = AF_INET; + ctx->sin.sin_port = htons(162); + if (connect(ctx->fd, + (struct sockaddr *)&ctx->sin, + sizeof(ctx->sin)) != 0) { + snmpv2_destroy(ctx); + return NULL; + } + } + } + } else { + result = inet_pton(AF_INET6, s, &ctx->sin6.sin6_addr); + if (result == 1) { + ctx->v6 = 1; + ctx->fd = socket(AF_INET6, SOCK_DGRAM, 0); + if (ctx->fd >= 0) { + ctx->sin6.sin6_family = AF_INET6; + ctx->sin6.sin6_port = htons(162); + if (connect(ctx->fd, + (struct sockaddr *)&ctx->sin6, + sizeof(ctx->sin6)) != 0) { + snmpv2_destroy(ctx); + return NULL; + } + } + } + } +#else + result = inet_aton(s, &ctx->sin.sin_addr); + if (result == 1) { + ctx->fd = socket(AF_INET, SOCK_DGRAM, 0); + if (ctx->fd >= 0) { + ctx->sin.sin_family = AF_INET; + ctx->sin.sin_port = htons(162); + if (connect(ctx->fd, (struct sockaddr *)&ctx->sin, + sizeof(ctx->sin)) != 0) { + snmpv2_destroy(ctx); + return NULL; + } + } + } +#endif + + if (result != 1) { + free(str); + free(ctx); + return NULL; + } + + ctx->ref = 1; + + return ctx; +} + + +static void +snmpv2_destroy(ctx) + void *ctx; +{ + snmpv2_opts_t *v2 = ctx; + + v2->ref--; + if (v2->ref > 0) + return; + + if (v2->community) + free(v2->community); + if (v2->fd >= 0) + close(v2->fd); + free(v2); +} + + +static int +snmpv2_send(ctx, msg) + void *ctx; + ipmon_msg_t *msg; +{ + snmpv2_opts_t *v2 = ctx; + + return sendtrap_v2_0(v2->fd, v2->community, + msg->imm_msg, msg->imm_msglen); +} +static int +writelength(buffer, value) + u_char *buffer; + u_int value; +{ + u_int n = htonl(value); + int len; + + if (value < 128) { + *buffer = value; + return 1; + } + if (value > 0xffffff) + len = 4; + else if (value > 0xffff) + len = 3; + else if (value > 0xff) + len = 2; + else + len = 1; + + *buffer = 0x80 | len; + + bcopy((u_char *)&n + 4 - len, buffer + 1, len); + + return len + 1; +} + + +static int +writeint(buffer, value) + u_char *buffer; + int value; +{ + u_char *s = buffer; + u_int n = value; + + if (value == 0) { + *buffer = 0; + return 1; + } + + if (n > 4194304) { + *s++ = 0x80 | (n / 4194304); + n -= 4194304 * (n / 4194304); + } + if (n > 32768) { + *s++ = 0x80 | (n / 32768); + n -= 32768 * (n / 327678); + } + if (n > 128) { + *s++ = 0x80 | (n / 128); + n -= (n / 128) * 128; + } + *s++ = (u_char)n; + + return s - buffer; +} + + + +/* + * First style of traps is: + * 1.3.6.1.4.1.9932.1.1 + */ +static int +maketrap_v2(community, buffer, bufsize, msg, msglen) + char *community; + u_char *buffer; + int bufsize; + u_char *msg; + int msglen; +{ + u_char *s = buffer, *t, *pdulen; + u_char *varlen; + int basesize = 77; + u_short len; + int trapmsglen; + int pdulensz; + int varlensz; + int baselensz; + int n; + + if (community == NULL || *community == '\0') + community = def_community; + basesize += strlen(community) + msglen; + + if (basesize + 8 > bufsize) + return 0; + + memset(buffer, 0xff, bufsize); + *s++ = 0x30; /* Sequence */ + + if (basesize - 1 >= 128) { + baselensz = 2; + basesize++; + } else { + baselensz = 1; + } + s += baselensz; + *s++ = 0x02; /* Integer32 */ + *s++ = 0x01; /* length 1 */ + *s++ = 0x01; /* version 2 */ + *s++ = 0x04; /* octet string */ + *s++ = strlen(community); /* length of "public" */ + bcopy(community, s, s[-1]); + s += s[-1]; + *s++ = 0xA7; /* PDU(7) */ + pdulen = s++; + if (basesize - (s - buffer) >= 128) { + pdulensz = 2; + basesize++; + s++; + } else { + pdulensz = 1; + } + /* request id */ + *s++ = 0x2; /* integer */ + *s++ = 0x4; /* len 4 */ + *s++ = 0x0; /* noError */ + *s++ = 0x0; /* noError */ + *s++ = 0x0; /* noError */ + *s++ = 0x0; /* noError */ + + /* error status */ + *s++ = 0x2; /* integer */ + *s++ = 0x1; /* len 1 */ + *s++ = 0x0; /* noError */ + + /* error-index */ + *s++ = 0x2; /* integer */ + *s++ = 0x1; /* len 1 */ + *s++ = 0x0; /* noError */ + + *s++ = 0x30; /* sequence */ + varlen = s++; + if (basesize - (s - buffer) >= 128) { + varlensz = 2; + basesize++; + s++; + } else { + varlensz = 1; + } + + *s++ = 0x30; /* sequence */ + *s++ = sizeof(sysuptime) + 6; + + bcopy(sysuptime, s, sizeof(sysuptime)); + s += sizeof(sysuptime); + + *s++ = 0x43; /* Timestamp */ + *s++ = 0x04; /* TimeTicks */ + *s++ = 0x0; + *s++ = 0x0; + *s++ = 0x0; + *s++ = 0x0; + + *s++ = 0x30; + t = s + 1; + bcopy(ipf_trap0_1, t, sizeof(ipf_trap0_1)); + t += sizeof(ipf_trap0_1); + + *t++ = 0x2; /* Integer */ + n = writeint(t + 1, IPFILTER_VERSION); + *t = n; + t += n + 1; + + len = t - s - 1; + writelength(s, len); + + s = t; + *s++ = 0x30; + if (msglen < 128) { + if (msglen + 1 + 1 + sizeof(ipf_trap0_2) >= 128) + trapmsglen = 2; + else + trapmsglen = 1; + } else { + if (msglen + 2 + 1 + sizeof(ipf_trap0_2) >= 128) + trapmsglen = 2; + else + trapmsglen = 1; + } + t = s + trapmsglen; + bcopy(ipf_trap0_2, t, sizeof(ipf_trap0_2)); + t += sizeof(ipf_trap0_2); + + *t++ = 0x4; /* Octet string */ + n = writelength(t, msglen); + t += n; + bcopy(msg, t, msglen); + t += msglen; + + len = t - s - trapmsglen; + writelength(s, len); + + len = t - varlen - varlensz; + writelength(varlen, len); /* pdu length */ + + len = t - pdulen - pdulensz; + writelength(pdulen, len); /* pdu length */ + + len = t - buffer - baselensz - 1; + writelength(buffer + 1, len); /* length of trap */ + + return t - buffer; +} + + +int +sendtrap_v2_0(fd, community, msg, msglen) + int fd; + char *community, *msg; + int msglen; +{ + + u_char buffer[1500]; + int n; + + n = maketrap_v2(community, buffer, sizeof(buffer), + (u_char *)msg, msglen); + if (n > 0) { + return send(fd, buffer, n, 0); + } + + return 0; +} diff --git a/contrib/ipfilter/lib/tcp_flags.c b/contrib/ipfilter/lib/tcp_flags.c new file mode 100644 index 0000000..0b602e6 --- /dev/null +++ b/contrib/ipfilter/lib/tcp_flags.c @@ -0,0 +1,50 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2000-2004 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id: tcp_flags.c,v 1.8.2.1 2006/06/16 17:21:17 darrenr Exp $ + */ + +#include "ipf.h" + +extern char flagset[]; +extern u_char flags[]; + + +u_char tcp_flags(flgs, mask, linenum) +char *flgs; +u_char *mask; +int linenum; +{ + u_char tcpf = 0, tcpfm = 0; + char *s; + + s = strchr(flgs, '/'); + if (s) + *s++ = '\0'; + + if (*flgs == '0') { + tcpf = strtol(flgs, NULL, 0); + } else { + tcpf = tcpflags(flgs); + } + + if (s != NULL) { + if (*s == '0') + tcpfm = strtol(s, NULL, 0); + else + tcpfm = tcpflags(s); + } + + if (!tcpfm) { + if (tcpf == TH_SYN) + tcpfm = 0xff & ~(TH_ECN|TH_CWR); + else + tcpfm = 0xff & ~(TH_ECN); + } + *mask = tcpfm; + return tcpf; +} diff --git a/contrib/ipfilter/lib/tcpflags.c b/contrib/ipfilter/lib/tcpflags.c new file mode 100644 index 0000000..feb3e8a --- /dev/null +++ b/contrib/ipfilter/lib/tcpflags.c @@ -0,0 +1,45 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +/* + * ECN is a new addition to TCP - RFC 2481 + */ +#ifndef TH_ECN +# define TH_ECN 0x40 +#endif +#ifndef TH_CWR +# define TH_CWR 0x80 +#endif + +extern char flagset[]; +extern u_char flags[]; + + +u_char tcpflags(flgs) + char *flgs; +{ + u_char tcpf = 0; + char *s, *t; + + for (s = flgs; *s; s++) { + if (*s == 'W') + tcpf |= TH_CWR; + else { + if (!(t = strchr(flagset, *s))) { + return 0; + } + tcpf |= flags[t - flagset]; + } + } + return tcpf; +} diff --git a/contrib/ipfilter/lib/tcpoptnames.c b/contrib/ipfilter/lib/tcpoptnames.c new file mode 100644 index 0000000..24e41bb --- /dev/null +++ b/contrib/ipfilter/lib/tcpoptnames.c @@ -0,0 +1,22 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include "ipf.h" + + +struct ipopt_names tcpoptnames[] ={ + { TCPOPT_NOP, 0x000001, 1, "nop" }, + { TCPOPT_MAXSEG, 0x000002, 4, "maxseg" }, + { TCPOPT_WINDOW, 0x000004, 3, "wscale" }, + { TCPOPT_SACK_PERMITTED, 0x000008, 2, "sackok" }, + { TCPOPT_SACK, 0x000010, 3, "sack" }, + { TCPOPT_TIMESTAMP, 0x000020, 10, "tstamp" }, + { 0, 0, 0, (char *)NULL } /* must be last */ +}; diff --git a/contrib/ipfilter/lib/v6ionames.c b/contrib/ipfilter/lib/v6ionames.c new file mode 100644 index 0000000..9f1207f --- /dev/null +++ b/contrib/ipfilter/lib/v6ionames.c @@ -0,0 +1,28 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + + +#ifdef USE_INET6 + +struct ipopt_names v6ionames[] ={ + { IPPROTO_HOPOPTS, 0x000001, 0, "hopopts" }, + { IPPROTO_IPV6, 0x000002, 0, "ipv6" }, + { IPPROTO_ROUTING, 0x000004, 0, "routing" }, + { IPPROTO_FRAGMENT, 0x000008, 0, "frag" }, + { IPPROTO_ESP, 0x000010, 0, "esp" }, + { IPPROTO_AH, 0x000020, 0, "ah" }, + { IPPROTO_NONE, 0x000040, 0, "none" }, + { IPPROTO_DSTOPTS, 0x000080, 0, "dstopts" }, + { IPPROTO_MOBILITY, 0x000100, 0, "mobility" }, + { 0, 0, 0, (char *)NULL } +}; + +#endif diff --git a/contrib/ipfilter/lib/v6optvalue.c b/contrib/ipfilter/lib/v6optvalue.c new file mode 100644 index 0000000..a6eff92 --- /dev/null +++ b/contrib/ipfilter/lib/v6optvalue.c @@ -0,0 +1,39 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ +#include "ipf.h" + + + +u_32_t getv6optbyname(optname) + char *optname; +{ +#ifdef USE_INET6 + struct ipopt_names *io; + + for (io = v6ionames; io->on_name; io++) + if (!strcasecmp(optname, io->on_name)) + return io->on_bit; +#endif + return -1; +} + + +u_32_t getv6optbyvalue(optval) + int optval; +{ +#ifdef USE_INET6 + struct ipopt_names *io; + + for (io = v6ionames; io->on_name; io++) + if (io->on_value == optval) + return io->on_bit; +#endif + return -1; +} diff --git a/contrib/ipfilter/lib/var.c b/contrib/ipfilter/lib/var.c new file mode 100644 index 0000000..e61c8d1 --- /dev/null +++ b/contrib/ipfilter/lib/var.c @@ -0,0 +1,179 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#include <ctype.h> + +#include "ipf.h" + +typedef struct variable { + struct variable *v_next; + char *v_name; + char *v_value; +} variable_t; + +static variable_t *vtop = NULL; + +static variable_t *find_var __P((char *)); +static char *expand_string __P((char *, int)); + + +static variable_t *find_var(name) + char *name; +{ + variable_t *v; + + for (v = vtop; v != NULL; v = v->v_next) + if (!strcmp(name, v->v_name)) + return v; + return NULL; +} + + +char *get_variable(string, after, line) + char *string, **after; + int line; +{ + char c, *s, *t, *value; + variable_t *v; + + s = string; + + if (*s == '{') { + s++; + for (t = s; *t != '\0'; t++) + if (*t == '}') + break; + if (*t == '\0') { + fprintf(stderr, "%d: { without }\n", line); + return NULL; + } + } else if (ISALPHA(*s)) { + for (t = s + 1; *t != '\0'; t++) + if (!ISALPHA(*t) && !ISDIGIT(*t) && (*t != '_')) + break; + } else { + fprintf(stderr, "%d: variables cannot start with '%c'\n", + line, *s); + return NULL; + } + + if (after != NULL) + *after = t; + c = *t; + *t = '\0'; + v = find_var(s); + *t = c; + if (v == NULL) { + fprintf(stderr, "%d: unknown variable '%s'\n", line, s); + return NULL; + } + + s = strdup(v->v_value); + value = expand_string(s, line); + if (value != s) + free(s); + return value; +} + + +static char *expand_string(oldstring, line) + char *oldstring; + int line; +{ + char c, *s, *p1, *p2, *p3, *newstring, *value; + int len; + + p3 = NULL; + newstring = oldstring; + + for (s = oldstring; *s != '\0'; s++) + if (*s == '$') { + *s = '\0'; + s++; + + switch (*s) + { + case '$' : + bcopy(s, s - 1, strlen(s)); + break; + default : + c = *s; + if (c == '\0') + return newstring; + + value = get_variable(s, &p3, line); + if (value == NULL) + return NULL; + + p2 = expand_string(value, line); + if (p2 == NULL) + return NULL; + + len = strlen(newstring) + strlen(p2); + if (p3 != NULL) { + if (c == '{' && *p3 == '}') + p3++; + len += strlen(p3); + } + p1 = malloc(len + 1); + if (p1 == NULL) + return NULL; + + *(s - 1) = '\0'; + strcpy(p1, newstring); + strcat(p1, p2); + if (p3 != NULL) + strcat(p1, p3); + + s = p1 + len - strlen(p3) - 1; + if (newstring != oldstring) + free(newstring); + newstring = p1; + break; + } + } + return newstring; +} + + +void set_variable(name, value) + char *name; + char *value; +{ + variable_t *v; + int len; + + if (name == NULL || value == NULL || *name == '\0') + return; + + v = find_var(name); + if (v != NULL) { + free(v->v_value); + v->v_value = strdup(value); + return; + } + + len = strlen(value); + + if ((*value == '"' && value[len - 1] == '"') || + (*value == '\'' && value[len - 1] == '\'')) { + value[len - 1] = '\0'; + value++; + len -=2; + } + + v = (variable_t *)malloc(sizeof(*v)); + if (v == NULL) + return; + v->v_name = strdup(name); + v->v_value = strdup(value); + v->v_next = vtop; + vtop = v; +} diff --git a/contrib/ipfilter/lib/verbose.c b/contrib/ipfilter/lib/verbose.c new file mode 100644 index 0000000..710daab --- /dev/null +++ b/contrib/ipfilter/lib/verbose.c @@ -0,0 +1,55 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#if defined(__STDC__) +# include <stdarg.h> +#else +# include <varargs.h> +#endif +#include <stdio.h> + +#include "ipf.h" +#include "opts.h" + + +#if defined(__STDC__) +void verbose(int level, char *fmt, ...) +#else +void verbose(level, fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list pvar; + + va_start(pvar, fmt); + + if (opts & OPT_VERBOSE) + vprintf(fmt, pvar); + va_end(pvar); +} + + +#if defined(__STDC__) +void ipfkverbose(char *fmt, ...) +#else +void ipfkverbose(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list pvar; + + va_start(pvar, fmt); + + if (opts & OPT_VERBOSE) + verbose(0x1fffffff, fmt, pvar); + va_end(pvar); +} diff --git a/contrib/ipfilter/lib/vtof.c b/contrib/ipfilter/lib/vtof.c new file mode 100644 index 0000000..fd1a984 --- /dev/null +++ b/contrib/ipfilter/lib/vtof.c @@ -0,0 +1,16 @@ +#include "ipf.h" + +int +vtof(version) + int version; +{ +#ifdef USE_INET6 + if (version == 6) + return AF_INET6; +#endif + if (version == 4) + return AF_INET; + if (version == 0) + return AF_UNSPEC; + return -1; +} diff --git a/contrib/ipfilter/man/Makefile b/contrib/ipfilter/man/Makefile new file mode 100644 index 0000000..04e97fb --- /dev/null +++ b/contrib/ipfilter/man/Makefile @@ -0,0 +1,31 @@ +# +# Copyright (C) 2012 by Darren Reed. +# +# See the IPFILTER.LICENCE file for details on licencing. +# +# $FreeBSD$ +# + +all: + +install: + $(INSTALL) -m 0644 -c -o root -g bin mkfilters.1 $(MANDIR)/man1 + $(INSTALL) -m 0644 -c -o root -g bin ipftest.1 $(MANDIR)/man1 + $(INSTALL) -m 0644 -c -o root -g bin ipnat.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipf.4 $(MANDIR)/man4 + $(INSTALL) -m 0644 -c -o root -g bin ipfilter.4 $(MANDIR)/man4 + $(INSTALL) -m 0644 -c -o root -g bin ipl.4 $(MANDIR)/man4 + $(INSTALL) -m 0644 -c -o root -g bin ipnat.4 $(MANDIR)/man4 + $(INSTALL) -m 0644 -c -o root -g bin ipf.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipfilter.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipnat.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipf.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipfs.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipmon.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipmon.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ippool.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ippool.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipscan.8 $(MANDIR)/man8 + $(INSTALL) -m 0644 -c -o root -g bin ipscan.5 $(MANDIR)/man5 + $(INSTALL) -m 0644 -c -o root -g bin ipfstat.8 $(MANDIR)/man8 + @echo "Remember to rebuild the whatis database." diff --git a/contrib/ipfilter/man/ipf.4 b/contrib/ipfilter/man/ipf.4 new file mode 100644 index 0000000..aaa050d --- /dev/null +++ b/contrib/ipfilter/man/ipf.4 @@ -0,0 +1,254 @@ +.\" $FreeBSD$ +.TH IPF 4 +.SH NAME +ipf \- packet filtering kernel interface +.SH SYNOPSIS +#include <netinet/ip_compat.h> +.br +#include <netinet/ip_fil.h> +.SH IOCTLS +.PP +To add and delete rules to the filter list, three 'basic' ioctls are provided +for use. The ioctl's are called as: +.LP +.nf + ioctl(fd, SIOCADDFR, struct frentry **) + ioctl(fd, SIOCDELFR, struct frentry **) + ioctl(fd, SIOCIPFFL, int *) +.fi +.PP +However, the full complement is as follows: +.LP +.nf + ioctl(fd, SIOCADAFR, struct frentry **) (same as SIOCADDFR) + ioctl(fd, SIOCRMAFR, struct frentry **) (same as SIOCDELFR) + ioctl(fd, SIOCADIFR, struct frentry **) + ioctl(fd, SIOCRMIFR, struct frentry **) + ioctl(fd, SIOCINAFR, struct frentry **) + ioctl(fd, SIOCINIFR, struct frentry **) + ioctl(fd, SIOCSETFF, u_int *) + ioctl(fd, SIOGGETFF, u_int *) + ioctl(fd, SIOCGETFS, struct friostat **) + ioctl(fd, SIOCIPFFL, int *) + ioctl(fd, SIOCIPFFB, int *) + ioctl(fd, SIOCSWAPA, u_int *) + ioctl(fd, SIOCFRENB, u_int *) + ioctl(fd, SIOCFRSYN, u_int *) + ioctl(fd, SIOCFRZST, struct friostat **) + ioctl(fd, SIOCZRLST, struct frentry **) + ioctl(fd, SIOCAUTHW, struct fr_info **) + ioctl(fd, SIOCAUTHR, struct fr_info **) + ioctl(fd, SIOCATHST, struct fr_authstat **) +.fi +.PP +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 (i.e., /dev/ipl). +.PP +The three groups of ioctls above perform adding rules to the end of the +list (SIOCAD*), deletion of rules from any place in the list (SIOCRM*) +and insertion of a rule into the list (SIOCIN*). The rule place into +which it is inserted is stored in the "fr_hits" field, below. +.LP +.nf +typedef struct frentry { + struct frentry *fr_next; + u_short fr_group; /* group to which this rule belongs */ + u_short fr_grhead; /* group # which this rule starts */ + struct frentry *fr_grp; + int fr_ref; /* reference count - for grouping */ + void *fr_ifa; +#if BSD >= 199306 + void *fr_oifa; +#endif + /* + * These are only incremented when a packet matches this rule and + * it is the last match + */ + U_QUAD_T fr_hits; + U_QUAD_T fr_bytes; + /* + * Fields after this may not change whilst in the kernel. + */ + struct fr_ip fr_ip; + struct fr_ip fr_mip; /* mask structure */ + + u_char fr_tcpfm; /* tcp flags mask */ + u_char fr_tcpf; /* tcp flags */ + + u_short fr_icmpm; /* data for ICMP packets (mask) */ + u_short fr_icmp; + + u_char fr_scmp; /* data for port comparisons */ + u_char fr_dcmp; + u_short fr_dport; + u_short fr_sport; + u_short fr_stop; /* top port for <> and >< */ + u_short fr_dtop; /* top port for <> and >< */ + u_32_t fr_flags; /* per-rule flags && options (see below) */ + u_short fr_skip; /* # of rules to skip */ + u_short fr_loglevel; /* syslog log facility + priority */ + int (*fr_func) __P((int, ip_t *, fr_info_t *)); + char fr_icode; /* return ICMP code */ + char fr_ifname[IFNAMSIZ]; +#if BSD > 199306 + char fr_oifname[IFNAMSIZ]; +#endif + struct frdest fr_tif; /* "to" interface */ + struct frdest fr_dif; /* duplicate packet interfaces */ +} frentry_t; +.fi +.PP +When adding a new rule, all unused fields (in the filter rule) should be +initialised to be zero. To insert a rule, at a particular position in the +filter list, the number of the rule which it is to be inserted before must +be put in the "fr_hits" field (the first rule is number 0). +.PP +Flags which are recognised in fr_flags: +.nf + + FR_BLOCK 0x000001 /* do not allow packet to pass */ + FR_PASS 0x000002 /* allow packet to pass */ + FR_OUTQUE 0x000004 /* outgoing packets */ + FR_INQUE 0x000008 /* ingoing packets */ + FR_LOG 0x000010 /* Log */ + FR_LOGB 0x000011 /* Log-fail */ + FR_LOGP 0x000012 /* Log-pass */ + FR_LOGBODY 0x000020 /* log the body of packets too */ + FR_LOGFIRST 0x000040 /* log only the first packet to match */ + FR_RETRST 0x000080 /* return a TCP RST packet if blocked */ + FR_RETICMP 0x000100 /* return an ICMP packet if blocked */ + FR_FAKEICMP 0x00180 /* Return ICMP unreachable with fake source */ + FR_NOMATCH 0x000200 /* no match occured */ + FR_ACCOUNT 0x000400 /* count packet bytes */ + FR_KEEPFRAG 0x000800 /* keep fragment information */ + FR_KEEPSTATE 0x001000 /* keep `connection' state information */ + FR_INACTIVE 0x002000 + FR_QUICK 0x004000 /* match & stop processing list */ + FR_FASTROUTE 0x008000 /* bypass normal routing */ + FR_CALLNOW 0x010000 /* call another function (fr_func) if matches */ + FR_DUP 0x020000 /* duplicate the packet */ + FR_LOGORBLOCK 0x040000 /* block the packet if it can't be logged */ + FR_NOTSRCIP 0x080000 /* not the src IP# */ + FR_NOTDSTIP 0x100000 /* not the dst IP# */ + FR_AUTH 0x200000 /* use authentication */ + FR_PREAUTH 0x400000 /* require preauthentication */ + +.fi +.PP +Values for fr_scomp and fr_dcomp (source and destination port value +comparisons) : +.LP +.nf + FR_NONE 0 + FR_EQUAL 1 + FR_NEQUAL 2 + FR_LESST 3 + FR_GREATERT 4 + FR_LESSTE 5 + FR_GREATERTE 6 + FR_OUTRANGE 7 + FR_INRANGE 8 +.fi +.PP +The third ioctl, SIOCIPFFL, flushes either the input filter list, the +output filter list or both and it returns the number of filters removed +from the list(s). The values which it will take and recognise are FR_INQUE +and FR_OUTQUE (see above). This ioctl is also implemented for +\fB/dev/ipstate\fP and will flush all state tables entries if passed 0 +or just all those which are not established if passed 1. + +.IP "\fBGeneral Logging Flags\fP" 0 +There are two flags which can be set to log packets independently of the +rules used. These allow for packets which are either passed or blocked +to be logged. To set (and clear)/get these flags, two ioctls are +provided: +.IP SIOCSETFF 16 +Takes an unsigned integer as the parameter. The flags are then set to +those provided (clearing/setting all in one). +.nf + + FF_LOGPASS 0x10000000 + FF_LOGBLOCK 0x20000000 + FF_LOGNOMATCH 0x40000000 + FF_BLOCKNONIP 0x80000000 /* Solaris 2.x only */ +.fi +.IP SIOCGETFF 16 +Takes a pointer to an unsigned integer as the parameter. A copy of the +flags currently in used is copied to user space. +.IP "\fBFilter statistics\fP" 0 +Statistics on the various operations performed by this package on packets +is kept inside the kernel. These statistics apply to packets traversing +through the kernel. To retrieve this structure, use this ioctl: +.nf + + ioctl(fd, SIOCGETFS, struct friostat *) + +struct friostat { + struct filterstats f_st[2]; + struct frentry *f_fin[2]; + struct frentry *f_fout[2]; + struct frentry *f_acctin[2]; + struct frentry *f_acctout[2]; + struct frentry *f_auth; + u_long f_froute[2]; + int f_active; /* 1 or 0 - active rule set */ + int f_defpass; /* default pass - from fr_pass */ + int f_running; /* 1 if running, else 0 */ + int f_logging; /* 1 if enabled, else 0 */ + char f_version[32]; /* version string */ +}; + +struct filterstats { + u_long fr_pass; /* packets allowed */ + u_long fr_block; /* packets denied */ + u_long fr_nom; /* packets which don't match any rule */ + u_long fr_ppkl; /* packets allowed and logged */ + u_long fr_bpkl; /* packets denied and logged */ + u_long fr_npkl; /* packets unmatched and logged */ + u_long fr_pkl; /* packets logged */ + u_long fr_skip; /* packets to be logged but buffer full */ + u_long fr_ret; /* packets for which a return is sent */ + u_long fr_acct; /* packets for which counting was performed */ + u_long fr_bnfr; /* bad attempts to allocate fragment state */ + u_long fr_nfr; /* new fragment state kept */ + u_long fr_cfr; /* add new fragment state but complete pkt */ + 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_notdata; /* PROTO/PCPROTO that have no data */ + u_long fr_nodata; /* mblks that have no data */ + u_long fr_bad; /* bad IP packets to the filter */ + u_long fr_notip; /* packets passed through no on ip queue */ + u_long fr_drop; /* packets dropped - no info for them! */ +#endif +}; +.fi +If we wanted to retrieve all the statistics and reset the counters back to +0, then the ioctl() call would be made to SIOCFRZST rather than SIOCGETFS. +In addition to the statistics above, each rule keeps a hit count, counting +both number of packets and bytes. To reset these counters for a rule, +load the various rule information into a frentry structure and call +SIOCZRLST. +.IP "Swapping Active lists" 0 +IP Filter supports two lists of rules for filtering and accounting: an +active list and an inactive list. This allows for large scale rule base +changes to be put in place atomically with otherwise minimal interruption. +Which of the two is active can be changed using the SIOCSWAPA ioctl. It +is important to note that no passed argument is recognised and that the +value returned is that of the list which is now inactive. +.br +.SH FILES +/dev/ipauth +.br +/dev/ipl +.br +/dev/ipnat +.br +/dev/ipstate +.SH SEE ALSO +ipl(4), ipnat(4), ipf(5), ipf(8), ipfstat(8) diff --git a/contrib/ipfilter/man/ipf.5 b/contrib/ipfilter/man/ipf.5 new file mode 100644 index 0000000..3e5e9b2 --- /dev/null +++ b/contrib/ipfilter/man/ipf.5 @@ -0,0 +1,1698 @@ +.\" $FreeBSD$ +.TH IPF 5 +.SH NAME +ipf, ipf.conf \- IPFilter firewall rules file format +.SH DESCRIPTION +.PP +The ipf.conf file is used to specify rules for the firewall, packet +authentication and packet accounting components of IPFilter. To load rules +specified in the ipf.conf file, the ipf(8) program is used. +.PP +For use as a firewall, there are two important rule types: those that block +and drop packets (block rules) and those that allow packets through (pass +rules.) Accompanying the decision to apply is a collection of statements +that specify under what conditions the result is to be applied and how. +.PP +The simplest rules that can be used in ipf.conf are expressed like this: +.PP +.nf +block in all +pass out all +.fi +.PP +Each rule must contain at least the following three components +.RS +.IP * +a decision keyword (pass, block, etc.) +.IP * +the direction of the packet (in or out) +.IP * +address patterns or "all" to match any address information +.RE +.SS Long lines +.PP +For rules lines that are particularly long, it is possible to split +them over multiple lines implicity like this: +.PP +.nf +pass in on bgeo proto tcp from 1.1.1.1 port > 1000 + to 2.2.2.2 port < 5000 flags S keep state +.fi +.PP +or explicitly using the backslash ('\\') character: +.PP +.nf +pass in on bgeo proto tcp from 1.1.1.1 port > 1000 \\ + to 2.2.2.2 port < 5000 flags S keep state +.fi +.SS Comments +.PP +Comments in the ipf.conf file are indicated by the use of the '#' character. +This can either be at the start of the line, like this: +.PP +.nf +# Allow all ICMP packets in +pass in proto icmp from any to any +.fi +.PP +Or at the end of a like, like this: +.PP +.nf +pass in proto icmp from any to any # Allow all ICMP packets in +.fi +.SH Firewall rules +.PP +This section goes into detail on how to construct firewall rules that +are placed in the ipf.conf file. +.PP +It is beyond the scope of this document to describe what makes a good +firewall rule set or which packets should be blocked or allowed in. +Some suggestions will be provided but further reading is expected to +fully understand what is safe and unsafe to allow in/out. +.SS Filter rule keywords +.PP +The first word found in any filter rule describes what the eventual outcome +of a packet that matches it will be. Descriptions of the many and various +sections that can be used to match on the contents of packet headers will +follow on below. +.PP +The complete list of keywords, along with what they do is as follows: +.RS +.HP +pass +rules that match a packet indicate to ipfilter that it should be +allowed to continue on in the direction it is flowing. +.HP +block +rules are used when it is desirable to prevent a packet from going +any further. Packets that are blocked on the "in" side are never seen by +TCP/IP and those that are blocked going "out" are never seen on the wire. +.HP +log +when IPFilter successfully matches a packet against a log rule a log +record is generated and made available for ipmon(8) to read. These rules +have no impact on whether or not a packet is allowed through or not. +So if a packet first matched a block rule and then matched a log rule, +the status of the packet after the log rule is that it will still be +blocked. +.HP +count +rules provide the administrator with the ability to count packets and +bytes that match the criteria laid out in the configuration file. +The count rules are applied after NAT and filter rules on the inbound +path. For outbound packets, count rules are applied before NAT and +before the packet is dropped. Thus the count rule cannot be used as +a true indicator of link layer +.HP +auth +rules cause the matching packet to be queued up for processing by a +user space program. The user space program is responsible for making +an ioctl system call to collect the information about the queued +packet and another ioctl system call to return the verdict (block, +pass, etc) on what to do with the packet. In the event that the queue +becomes full, the packets will end up being dropped. +.HP +call +provides access to functions built into IPFilter that allow for more +complex actions to be taken as part of the decision making that goes +with the rule. +.HP +decapsulate +rules instruct ipfilter to remove any +other headers (IP, UDP, AH) and then process what is inside as a new packet. +For non-UDP packets, there are builtin checks that are applied in addition +to whatever is specified in the rule, to only allow decapsulation of +recognised protocols. After decapsulating the inner packet, any filtering +result that is applied to the inner packet is also applied to the other +packet. +.PP +The default way in which filter rules are applied is for the last +matching rule to be used as the decision maker. So even if the first +rule to match a packet is a pass, if there is a later matching rule +that is a block and no further rules match the packet, then it will +be blocked. +.SS Matching Network Interfaces +.PP +On systems with more than one network interface, it is necessary +to be able to specify different filter rules for each of them. +In the first instance, this is because different networks will send us +packets via each network interface but it is also because of the hosts, +the role and the resulting security policy that we need to be able to +distinguish which network interface a packet is on. +.PP +To accomodate systems where the presence of a network interface is +dynamic, it is not necessary for the network interface named in a +filter rule to be present in the system when the rule is loaded. +This can lead to silent errors being introduced and unexpected +behaviour with the simplest of keyboard mistakes - for example, +typing in hem0 instead of hme0 or hme2 instead of hme3. +.PP +On Solaris systems prior to Solaris 10 Update 4, it is not possible +to filter packets on the loopback interface (lo0) so filter rules +that specify it will have no impact on the corresponding flow of +packets. See below for Solaris specific tips on how to enable this. +.PP +Some examples of including the network interface in filter rules are: +.PP +.nf +block in on bge0 all +pass out on bge0 all +.fi +.SS Address matching (basic) +.PP +The first and most basic part of matching for filtering rules is to +specify IP addresses and TCP/UDP port numbers. The source address +information is matched by the "from" information in a filter rule +and the destination address information is matched with the "to" +information in a filter rule. +.PP +The typical format used for IP addresses is CIDR notation, where an +IP address (or network) is followed by a '/' and a number representing +the size of the netmask in bits. This notation is used for specifying +address matching in both IPv4 and IPv6. If the '/' and bitmask size +are excluded from the matching string, it is assumed that the address +specified is a host address and that the netmask applied should be +all 1's. +.PP +Some examples of this are: +.PP +.nf +pass in from 10.1.0.0/24 to any +block out from any to 10.1.1.1 +.fi +.PP +It is not possible to specify a range of addresses that does not +have a boundary that can be defined by a standard subnet mask. +.IP +.B Names instead of addresses +.RS +.PP +Hostnames, resolved either via DNS or /etc/hosts, or network names, +resolved via /etc/networks, may be used in place of actual addresses +in the filter rules. WARNING: if a hostname expands to more than one +address, only the *first* is used in building the filter rule. +.PP +Caution should be exercised when relying on DNS for filter rules in +case the sending and receiving of DNS packets is blocked when ipf(8) +is processing that part of the configuration file, leading to long +delays, if not errors, in loading the filter rules. +.RE +.SS Protocol Matching +.PP +To match packets based on TCP/UDP port information, it is first necessary +to indicate which protocol the packet must be. This is done using the +"proto" keyword, followed by either the protocol number or a name which +is mapped to the protocol number, usually through the /etc/protocols file. +.PP +.nf +pass in proto tcp from 10.1.0.0/24 to any +block out proto udp from any to 10.1.1.1 +pass in proto icmp from any to 192.168.0.0/16 +.fi +.SS Sending back error packets +.PP +When a packet is just discarded using a block rule, there is no feedback given +to the host that sent the packet. This is both good and bad. If this is the +desired behaviour and it is not desirable to send any feedback about packets +that are to be denied. The catch is that often a host trying to connect to a +TCP port or with a UDP based application will send more than one packet +because it assumes that just one packet may be discarded so a retry is +required. The end result being logs can become cluttered with duplicate +entries due to the retries. +.PP +To address this problem, a block rule can be qualified in two ways. +The first of these is specific to TCP and instructs IPFilter to send back +a reset (RST) packet. This packet indicates to the remote system that the +packet it sent has been rejected and that it shouldn't make any further +attempts to send packets to that port. Telling IPFilter to return a TCP +RST packet in response to something that has been received is achieved +with the return-rst keyword like this: +.PP +.nf +block return-rst in proto tcp from 10.0.0.0/8 to any +.fi +.PP +When sending back a TCP RST packet, IPFilter must construct a new packet +that has the source address of the intended target, not the source address +of the system it is running on (if they are different.) +.PP +For all of the other protocols handled by the IP protocol suite, to send +back an error indicating that the received packet was dropped requires +sending back an ICMP error packet. Whilst these can also be used for TCP, +the sending host may not treat the received ICMP error as a hard error +in the same way as it does the TCP RST packet. To return an ICMP error +it is necessary to place return-icmp after the block keyword like this: +.PP +.nf +block return-icmp in proto udp from any to 192.168.0.1/24 +.fi +.PP +When electing to return an ICMP error packet, it is also possible to +select what type of ICMP error is returned. Whilst the full compliment +of ICMP unreachable codes can be used by specifying a number instead of +the string below, only the following should be used in conjunction with +return-icmp. Which return code to use is a choice to be made when +weighing up the pro's and con's. Using some of the codes may make it +more obvious that a firewall is being used rather than just the host +not responding. +.RS +.HP +filter-prohib +(prohibited by filter) +sending packets to the destination given in the received packet is +prohibited due to the application of a packet filter +.HP +net-prohib +(prohibited network) +sending packets to the destination given in the received packet is +administratively prohibited. +.HP +host-unk +(host unknown) +the destination host address is not known by the system receiving +the packet and therefore cannot be reached. +.HP +host-unr +(host unreachable) +it is not possible to reach the host as given by the destination address +in the packet header. +.HP +net-unk +(network unknown) +the destination network address is not known by the system receiving +the packet and therefore cannot be reached. +.HP +net-unr +(network unreachable) +it is not possible to forward the packet on to its final destination +as given by the destination address +.HP +port-unr +(port unreachable) +there is no application using the given destination port and therefore +it is not possible to reach that port. +.HP +proto-unr +(protocol unreachable) +the IP protocol specified in the packet is not available to receive +packets. +.DE +.PP +An example that shows how to send back a port unreachable packet for +UDP packets to 192.168.1.0/24 is as follows: +.PP +.nf +block return-icmp(port-unr) in proto udp from any to 192.168.1.0/24 +.fi +.PP +In the above examples, when sending the ICMP packet, IPFilter will construct +a new ICMP packet with a source address of the network interface used to +send the packet back to the original source. This can give away that there +is an intermediate system blocking packets. To have IPFilter send back +ICMP packets where the source address is the original destination, regardless +of whether or not it is on the local host, return-icmp-as-dest is used like +this: +.PP +.nf +block return-icmp-as-dest(port-unr) in proto udp \\ + from any to 192.168.1.0/24 +.fi +.SS TCP/UDP Port Matching +.PP +Having specified which protocol is being matched, it is then possible to +indicate which port numbers a packet must have in order to match the rule. +Due to port numbers being used differently to addresses, it is therefore +possible to match on them in different ways. IPFilter allows you to use +the following logical operations: +.IP "< x" +is true if the port number is greater than or equal to x and less than or +equal to y +is true if the port number in the packet is less than x +.IP "<= x" +is true if the port number in the packet is less than or equal to x +.IP "> x" +is true if the port number in the packet is greater than x +.IP ">= x" +is true if the port number in the packet is greater or equal to x +.IP "= x" +is true if the port number in the packet is equal to x +.IP "!= x" +is true if the port number in the packet is not equal to x +.PP +Additionally, there are a number of ways to specify a range of ports: +.IP "x <> y" +is true if the port number is less than a and greater than y +.IP "x >< y" +is true if the port number is greater than x and less than y +.IP "x:y" +is true if the port number is greater than or equal to x and less than or +equal to y +.PP +Some examples of this are: +.PP +.nf +block in proto tcp from any port >= 1024 to any port < 1024 +pass in proto tcp from 10.1.0.0/24 to any port = 22 +block out proto udp from any to 10.1.1.1 port = 135 +pass in proto udp from 1.1.1.1 port = 123 to 10.1.1.1 port = 123 +pass in proto tcp from 127.0.0.0/8 to any port = 6000:6009 +.fi +.PP +If there is no desire to mention any specific source or destintion +information in a filter rule then the word "all" can be used to +indicate that all addresses are considered to match the rule. +.SS IPv4 or IPv6 +.PP +If a filter rule is constructed without any addresses then IPFilter +will attempt to match both IPv4 and IPv6 packets with it. In the +next list of rules, each one can be applied to either network protocol +because there is no address specified from which IPFilter can derive +with network protocol to expect. +.PP +.nf +pass in proto udp from any to any port = 53 +block in proto tcp from any port < 1024 to any +.fi +.PP +To explicitly match a particular network address family with a specific +rule, the family must be added to the rule. For IPv4 it is necessary to +add family inet and for IPv6, family inet6. Thus the next rule will +block all packets (both IPv4 and IPv6: +.PP +.nf +block in all +.fi +.PP +but in the following example, we block all IPv4 packets and only allow +in IPv6 packets: +.PP +.nf +block in family inet all +pass in family inet6 all +.fi +.PP +To continue on from the example where we allowed either IPv4 or IPv6 +packets to port 53 in, to change that such that only IPv6 packets to +port 53 need to allowed blocked then it is possible to add in a +protocol family qualifier: +.PP +.nf +pass in family inet6 proto udp from any to any port = 53 +.fi +.SS First match vs last match +.PP +To change the default behaviour from being the last matched rule decides +the outcome to being the first matched rule, the word "quick" is inserted +to the rule. +.SH Extended Packet Matching +.SS Beyond using plain addresses +.PP +On firewalls that are working with large numbers of hosts and networks +or simply trying to filter discretely against various hosts, it can +be an easier administration task to define a pool of addresses and have +a filter rule reference that address pool rather than have a rule for +each address. +.PP +In addition to being able to use address pools, it is possible to use +the interface name(s) in the from/to address fields of a rule. If the +name being used in the address section can be matched to any of the +interface names mentioned in the rule's "on" or "via" fields then it +can be used with one of the following keywords for extended effect: +.HP +broadcast +use the primary broadcast address of the network interface for matching +packets with this filter rule; +.IP +.nf +pass in on fxp0 proto udp from any to fxp0/broadcast port = 123 +.fi +.HP +peer +use the peer address on point to point network interfaces for matching +packets with this filter rule. This option typically only has meaningful +use with link protocols such as SLIP and PPP. +For example, this rule allows ICMP packets from the remote peer of ppp0 +to be received if they're destined for the address assigned to the link +at the firewall end. +.IP +.nf +pass in on ppp0 proto icmp from ppp0/peer to ppp0/32 +.fi +.HP +netmasked +use the primary network address, with its netmask, of the network interface +for matching packets with this filter rule. If a network interface had an +IP address of 192.168.1.1 and its netmask was 255.255.255.0 (/24), then +using the word "netmasked" after the interface name would match any +addresses that would match 192.168.1.0/24. If we assume that bge0 has +this IP address and netmask then the following two rules both serve +to produce the same effect: +.IP +.nf +pass in on bge0 proto icmp from any to 192.168.1.0/24 +pass in on bge0 proto icmp from any to bge0/netmasked +.fi +.HP +network +using the primary network address, and its netmask, of the network interface, +construct an address for exact matching. If a network interface has an +address of 192.168.1.1 and its netmask is 255.255.255.0, using this +option would only match packets to 192.168.1.0. +.IP +.nf +pass in on bge0 proto icmp from any to bge0/network +.fi +.PP +Another way to use the name of a network interface to get the address +is to wrap the name in ()'s. In the above method, IPFilter +looks at the interface names in use and to decide whether or not +the name given is a hostname or network interface name. With the +use of ()'s, it is possible to tell IPFilter that the name should +be treated as a network interface name even though it doesn't +appear in the list of network interface that the rule ias associated +with. +.IP +.nf +pass in proto icmp from any to (bge0)/32 +.fi +.SS Using address pools +.PP +Rather than list out multiple rules that either allow or deny specific +addresses, it is possible to create a single object, call an address +pool, that contains all of those addresses and reference that in the +filter rule. For documentation on how to write the configuration file +for those pools and load them, see ippool.conf(5) and ippool(8). +There are two types of address pools that can be defined in ippool.conf(5): +trees and hash tables. To refer to a tree defined in ippool.conf(5), +use this syntax: +.PP +.nf +pass in from pool/trusted to any +.fi +.PP +Either a name or number can be used after the '/', just so long as it +matches up with something that has already been defined in ipool.conf(5) +and loaded in with ippool(8). Loading a filter rule that references a +pool that does not exist will result in an error. +.PP +If hash tables have been used in ippool.conf(5) to store the addresses +in instead of a tree, then replace the word pool with hash: +.IP +.nf +pass in from any to hash/webservers +.fi +.PP +There are different operational characteristics with each, so there +may be some situations where a pool works better than hash and vice +versa. +.SS Matching TCP flags +.PP +The TCP header contains a field of flags that is used to decide if the +packet is a connection request, connection termination, data, etc. +By matching on the flags in conjunction with port numbers, it is +possible to restrict the way in which IPFilter allows connections to +be created. A quick overview of the TCP +flags is below. Each is listed with the letter used in IPFilter +rules, followed by its three or four letter pneumonic. +.HP +S +SYN - this bit is set when a host is setting up a connection. +The initiator typically sends a packet with the SYN bit and the +responder sends back SYN plus ACK. +.HP +A +ACK - this bit is set when the sender wishes to acknowledge the receipt +of a packet from another host +.HP +P +PUSH - this bit is set when a sending host has send some data that +is yet to be acknowledged and a reply is sought +.HP +F +FIN - this bit is set when one end of a connection starts to close +the connection down +.HP +U +URG - this bit is set to indicate that the packet contains urgent data +.HP +R +RST - this bit is set only in packets that are a reply to another +that has been received but is not targetted at any open port +.HP +C +CWN +.HP +E +ECN +.PP +When matching TCP flags, it is normal to just list the flag that you +wish to be set. By default the set of flags it is compared against +is "FSRPAU". Rules that say "flags S" will be displayed by ipfstat(8) +as having "flags S/FSRPAU". This is normal. +The last two flags, "C" and "E", are optional - they +may or may not be used by an end host and have no bearing on either +the acceptance of data nor control of the connection. Masking them +out with "flags S/FSRPAUCE" may cause problems for remote hosts +making a successful connection. +.PP +.nf +pass in quick proto tcp from any to any port = 22 flags S/SAFR +pass out quick proto tcp from any port = 22 to any flags SA +.fi +.PP +By itself, filtering based on the TCP flags becomes more work but when +combined with stateful filtering (see below), the situation changes. +.SS Matching on ICMP header information +.PP +The TCP and UDP are not the only protocols for which filtering beyond +just the IP header is possible, extended matching on ICMP packets is +also available. The list of valid ICMP types is different for IPv4 +vs IPv6. +.PP +As a practical example, to allow the ping command to work +against a specific target requires allowing two different types of +ICMP packets, like this: +.PP +.nf +pass in proto icmp from any to webserver icmp-type echo +pass out proto icmp from webserver to any icmp-type echorep +.fi +.PP +The ICMP header has two fields that are of interest for filtering: +the ICMP type and code. Filter rules can accept either a name or +number for both the type and code. The list of names supported for +ICMP types is listed below, however only ICMP unreachable errors +have named codes (see above.) +.PP +The list of ICMP types that are available for matching an IPv4 packet +are as follows: +.PP +echo (echo request), +echorep (echo reply), +inforeq (information request), +inforep (information reply), +maskreq (mask request), +maskrep (mask reply), +paramprob (parameter problem), +redir (redirect), +routerad (router advertisement), +routersol (router solicit), +squence (source quence), +timest (timestamp), +timestreq (timestamp reply), +timex (time exceeded), +unreach (unreachable). +.PP +The list of ICMP types that are available for matching an IPv6 packet +are as follows: +.PP +echo (echo request), +echorep (echo reply), +fqdnquery (FQDN query), +fqdnreply (FQDN reply), +inforeq (information request), +inforep (information reply), +listendone (MLD listener done), +listendqry (MLD listener query), +listendrep (MLD listener reply), +neighadvert (neighbour advert), +neighborsol (neighbour solicit), +paramprob (parameter problem), +redir (redirect), +renumber (router renumbering), +routerad (router advertisement), +routersol (router solicit), +timex (time exceeded), +toobig (packet too big), +unreach (unreachable, +whoreq (WRU request), +whorep (WRU reply). +.SH Stateful Packet Filtering +.PP +Stateful packet filtering is where IPFilter remembers some information from +one or more packets that it has seen and is able to apply it to future +packets that it receives from the network. +.PP +What this means for each transport layer protocol is different. +For TCP it means that if IPFilter +sees the very first packet of an attempt to make a connection, it has enough +information to allow all other subsequent packets without there needing to +be any explicit rules to match them. IPFilter uses the TCP port numbers, +TCP flags, window size and sequence numbers to determine which packets +should be matched. For UDP, only the UDP port numbers are available. +For ICMP, the ICMP types can be combined with the ICMP id field to +determine which reply packets match a request/query that has already +been seen. For all other protocols, only matching on IP address and +protocol number is available for determining if a packet received is a mate +to one that has already been let through. +.PP +The difference this makes is a reduction in the number of rules from +2 or 4 to 1. For example, these 4 rules: +.PP +.nf +pass in on bge0 proto tcp from any to any port = 22 +pass out on bge1 proto tcp from any to any port = 22 +pass in on bge1 proto tcp from any port = 22 to any +pass out on bge0 proto tcp from any port = 22 to any +.fi +.PP +can be replaced with this single rule: +.PP +.nf +pass in on bge0 proto tcp from any to any port = 22 flags S keep state +.fi +.PP +Similar rules for UDP and ICMP might be: +.PP +.nf +pass in on bge0 proto udp from any to any port = 53 keep state +pass in on bge0 proto icmp all icmp-type echo keep state +.fi +.PP +When using stateful filtering with TCP it is best to add "flags S" to the +rule to ensure that state is only created when a packet is seen that is +an indication of a new connection. Although IPFilter can gather some +information from packets in the middle of a TCP connection to do stateful +filtering, there are some options that are only sent at the start of the +connection which alter the valid window of what TCP accepts. The end result +of trying to pickup TCP state in mid connection is that some later packets +that are part of the connection may not match the known state information +and be dropped or blocked, causing problems. If a TCP packet matches IP +addresses and port numbers but does not fit into the recognised window, +it will not be automatically allowed and will be flagged inside of +IPFitler as "out of window" (oow). See below, "Extra packet attributes", +for how to match on this attribute. +.PP +Once a TCP connection has reached the established state, the default +timeout allows for it to be idle for 5 days before it is removed from +the state table. The timeouts for the other TCP connection states +vary from 240 seconds to 30 seconds. +Both UDP and ICMP state entries have asymetric timeouts where the timeout +set upon seeing packets in the forward direction is much larger than +for the reverse direction. For UDP the default timeouts are 120 and +12 seconds, for ICMP 60 and 6 seconds. This is a reflection of the +use of these protocols being more for query-response than for ongoing +connections. For all other protocols the +timeout is 60 seconds in both directions. +.SS Stateful filtering options +.PP +The following options can be used with stateful filtering: +.HP +limit +limit the number of state table entries that this rule can create to +the number given after limit. A rule that has a limit specified is +always permitted that many state table entries, even if creating an +additional entry would cause the table to have more entries than the +otherwise global limit. +.IP +.nf +pass ... keep state(limit 100) +.fi +.HP +age +sets the timeout for the state entry when it sees packets going through +it. Additionally it is possible to set the tieout for the reply packets +that come back through the firewall to a different value than for the +forward path. allowing a short timeout to be set after the reply has +been seen and the state no longer required. +.RS +.PP +.nf +pass in quick proto icmp all icmp-type echo \\ + keep state (age 3) +pass in quick proto udp from any \\ + to any port = 53 keep state (age 30/1) +.fi +.RE +.HP +strict +only has an impact when used with TCP. It forces all packets that are +allowed through the firewall to be sequential: no out of order delivery +of packets is allowed. This can cause significant slowdown for some +connections and may stall others. Use with caution. +.IP +.nf +pass in proto tcp ... keep state(strict) +.fi +.HP +noicmperr +prevents ICMP error packets from being able to match state table entries +created with this flag using the contents of the original packet included. +.IP +.nf +pass ... keep state(noicmperr) +.fi +.HP +sync +indicates to IPFilter that it needs to provide information to the user +land daemons responsible for syncing other machines state tables up +with this one. +.IP +.nf +pass ... keep state(sync) +.fi +.HP +nolog +do not generate any log records for the creation or deletion of state +table entries. +.IP +.nf +pass ... keep state(nolog) +.fi +.HP +icmp-head +rather than just precent ICMP error packets from being able to match +state table entries, allow an ACL to be processed that can filter in or +out ICMP error packets based as you would with normal firewall rules. +The icmp-head option requires a filter rule group number or name to +be present, just as you would use with head. +.RS +.PP +.nf +pass in quick proto tcp ... keep state(icmp-head 101) +block in proto icmp from 10.0.0.0/8 to any group 101 +.fi +.RE +.HP +max-srcs +allows the number of distinct hosts that can create a state entry to +be defined. +.IP +.nf +pass ... keep state(max-srcs 100) +pass ... keep state(limit 1000, max-srcs 100) +.fi +.HP +max-per-src +whilst max-srcs limits the number of individual hosts that may cause +the creation of a state table entry, each one of those hosts is still +table to fill up the state table with new entries until the global +maximum is reached. This option allows the number of state table entries +per address to be limited. +.IP +.nf +pass ... keep state(max-srcs 100, max-per-src 1) +pass ... keep state(limit 100, max-srcs 100, max-per-src 1) +.fi +.IP +Whilst these two rules might seem identical, in that they both +ultimately limit the number of hosts and state table entries created +from the rule to 100, there is a subtle difference: the second will +always allow up to 100 state table entries to be created whereas the +first may not if the state table fills up from other rules. +.IP +Further, it is possible to specify a netmask size after the per-host +limit that enables the per-host limit to become a per-subnet or +per-network limit. +.IP +.nf +pass ... keep state(max-srcs 100, max-per-src 1/24) +.fi +.IP +If there is no IP protocol implied by addresses or other features of +the rule, IPFilter will assume that no netmask is an all ones netmask +for both IPv4 and IPv6. +.SS Tieing down a connection +.PP +For any connection that transits a firewall, each packet will be seen +twice: once going in and once going out. Thus a connection has 4 flows +of packets: +.HP +forward +inbound packets +.HP +forward +outbound packets +.HP +reverse +inbound packets +.HP +reverse +outbound packets +.PP +IPFilter allows you to define the network interface to be used at all +four points in the flow of packets. For rules that match inbound packets, +out-via is used to specify which interfaces the packets go out, For rules +that match outbound packets, in-via is used to match the inbound packets. +In each case, the syntax generalises to this: +.PP +.nf +pass ... in on forward-in,reverse-in \\ + out-via forward-out,reverse-out ... + +pass ... out on forward-out,reverse-out \\ + in-via forward-in,reverse-in ... +.fi +.PP +An example that pins down all 4 network interfaces used by an ssh +connection might look something like this: +.PP +.nf +pass in on bge0,bge1 out-via bge1,bge0 proto tcp \\ + from any to any port = 22 flags S keep state +.fi +.SS Working with packet fragments +.PP +Fragmented packets result in 1 packet containing all of the layer 3 and 4 +header information whilst the data is split across a number of other packets. +.PP +To enforce access control on fragmented packets, one of two approaches +can be taken. The first is to allow through all of the data fragments +(those that made up the body of the original packet) and rely on matching +the header information in the "first" fragment, when it is seen. The +reception of body fragments without the first will result in the receiving +host being unable to completely reassemble the packet and discarding all +of the fragments. The following three rules deny all fragmented packets +from being received except those that are UDP and even then only allows +those destined for port 2049 to be completed. +.PP +.nf +block in all with frags +pass in proto udp from any to any with frag-body +pass in proto udp from any to any port = 2049 with frags +.fi +.PP +Another mechanism that is available is to track "fragment state". +This relies on the first fragment of a packet that arrives to be +the fragment that contains all of the layer 3 and layer 4 header +information. With the receipt of that fragment before any other, +it is possible to determine which other fragments are to be allowed +through without needing to explicitly allow all fragment body packets. +An example of how this is done is as follows: +.PP +.nf +pass in proto udp from any prot = 2049 to any with frags keep fags +.fi +.SH Building a tree of rules +.PP +Writing your filter rules as one long list of rules can be both inefficient +in terms of processing the rules and difficult to understand. To make the +construction of filter rules easier, it is possible to place them in groups. +A rule can be both a member of a group and the head of a new group. +.PP +Using filter groups requires at least two rules: one to be in the group +one one to send matchign packets to the group. If a packet matches a +filtre rule that is a group head but does not match any of the rules +in that group, then the packet is considered to have matched the head +rule. +.PP +Rules that are a member of a group contain the word group followed by +either a name or number that defines which group they're in. Rules that +form the branch point or starting point for the group must use the +word head, followed by either a group name or number. If rules are +loaded in that define a group but there is no matching head then they +will effectively be orphaned rules. It is possible to have more than +one head rule point to the same group, allowing groups to be used +like subroutines to implement specific common policies. +.PP +A common use of filter groups is to define head rules that exist in the +filter "main line" for each direction with the interfaces in use. For +example: +.PP +.nf +block in quick on bge0 all head 100 +block out quick on bge0 all head 101 +block in quick on fxp0 all head internal-in +block out quick on fxp0 all head internal-out +pass in quick proto icmp all icmp-type echo group 100 +.fi +.PP +In the above set of rules, there are four groups defined but only one +of them has a member rule. The only packets that would be allowed +through the above ruleset would be ICMP echo packets that are +received on bge0. +.PP +Rules can be both a member of a group and the head of a new group, +allowing groups to specialise. +.PP +.nf +block in quick on bge0 all head 100 +block in quick proto tcp all head 1006 group 100 +.fi +.PP +Another use of filter rule groups is to provide a place for rules to +be dynamically added without needing to worry about their specific +ordering amongst the entire ruleset. For example, if I was using this +simple ruleset: +.PP +.nf +block in quick all with bad +block in proto tcp from any to any port = smtp head spammers +pass in quick proto tcp from any to any port = smtp flags S keep state +.fi +.PP +and I was getting lots of connections to my email server from 10.1.1.1 +to deliver spam, I could load the following rule to complement the above: +.IP +.nf +block in quick from 10.1.1.1 to any group spammers +.fi +.SS Decapsulation +.PP +Rule groups also form a different but vital role for decapsulation rules. +With the following simple rule, if IPFilter receives an IP packet that has +an AH header as its layer 4 payload, IPFilter would adjust its view of the +packet internally and then jump to group 1001 using the data beyond the +AH header as the new transport header. +.PP +.nf +decapsulate in proto ah all head 1001 +.fi +.PP +For protocols that +are recognised as being used with tunnelling or otherwise encapsulating +IP protocols, IPFilter is able to decide what it has on the inside +without any assistance. Some tunnelling protocols use UDP as the +transport mechanism. In this case, it is necessary to instruct IPFilter +as to what protocol is inside UDP. +.PP +.nf +decapsulate l5-as(ip) in proto udp from any \\ + to any port = 1520 head 1001 +.fi +.PP +Currently IPFilter only supports finding IPv4 and IPv6 headers +directly after the UDP header. +.PP +If a packet matches a decapsulate rule but fails to match any of the rules +that are within the specified group, processing of the packet continues +to the next rule after the decapsulate and IPFilter's internal view of the +packet is returned to what it was prior to the decapsulate rule. +.PP +It is possible to construct a decapsulate rule without the group +head at the end that ipf(8) will accept but such rules will not +result in anything happening. +.SS Policy Based Routing +.PP +With firewalls being in the position they often are, at the boundary +of different networks connecting together and multiple connections that +have different properties, it is often desirable to have packets flow +in a direction different to what the routing table instructs the kernel. +These decisions can often be extended to changing the route based on +both source and destination address or even port numbers. +.PP +To support this kind of configuration, IPFilter allows the next hop +destination to be specified with a filter rule. The next hop is given +with the interface name to use for output. The syntax for this is +interface:ip.address. It is expected that the address given as the next +hop is directly connected to the network to which the interface is. +.PP +.nf +pass in on bge0 to bge1:1.1.1.1 proto tcp \\ + from 1.1.2.3 to any port = 80 flags S keep state +.fi +.PP +When this feature is combined with stateful filtering, it becomes +possible to influence the network interface used to transmit packets +in both directions because we now have a sense for what its reverse +flow of packets is. +.PP +.nf +pass in on bge0 to bge1:1.1.1.1 reply-to hme1:2.1.1.2 \\ + proto tcp from 1.1.2.3 to any port = 80 flags S keep state +.fi +.PP +If the actions of the routing table are perfectly acceptable, but +you would like to mask the presence of the firewall by not changing +the TTL in IP packets as they transit it, IPFilter can be instructed +to do a "fastroute" action like this: +.PP +.nf +pass in on bge0 fastroute proto icmp all +.fi +.PP +This should be used with caution as it can lead to endless packet +loops. Additionally, policy based routing does not change the IP +header's TTL value. +.PP +A variation on this type of rule supports a duplicate of the original +packet being created and sent out a different network. This can be +useful for monitoring traffic and other purposes. +.PP +.nf +pass in on bge0 to bge1:1.1.1.1 reply-to hme1:2.1.1.2 \\ + dup-to fxp0:10.0.0.1 proto tcp from 1.1.2.3 \\ + to any port = 80 flags S keep state +.fi +.SS Matching IPv4 options +.PP +The design for IPv4 allows for the header to be upto 64 bytes long, +however most traffic only uses the basic header which is 20 bytes long. +The other 44 bytes can be uesd to store IP options. These options are +generally not necessary for proper interaction and function on the +Internet today. For most people it is sufficient to block and drop +all packets that have any options set. This can be achieved with this +rule: +.PP +.nf +block in quick all with ipopts +.fi +.PP +This rule is usually placed towards the top of the configuration +so that all incoming packets are blocked. +.PP +If you wanted to allow in a specific IP option type, the syntax +changes slightly: +.PP +.nf +pass in quick proto igmp all with opt rtralrt +.fi +.PP +The following is a list of IP options that most people encounter and +what their use/threat is. +.HP +lsrr +(loose source route) the sender of the packet includes a list of addresses +that they wish the packet to be routed through to on the way to the +destination. Because replies to such packets are expected to use the +list of addresses in reverse, hackers are able to very effectively use +this header option in address spoofing attacks. +.HP +rr +(record route) the sender allocates some buffer space for recording the +IP address of each router that the packet goes through. This is most often +used with ping, where the ping response contains a copy of all addresses +from the original packet, telling the sender what route the packet took +to get there. Due to performance and security issues with IP header +options, this is almost no longer used. +.HP +rtralrt +(router alert) this option is often used in IGMP messages as a flag to +routers that the packet needs to be handled differently. It is unlikely +to ever be received from an unknown sender. It may be found on LANs or +otherwise controlled networks where the RSVP protocol and multicast +traffic is in heavy use. +.HP +ssrr +(strict source route) the sender of the packet includes a list of addresses +that they wish the packet to be routed through to on the way to the +destination. Where the lsrr option allows the sender to specify only +some of the nodes the packet must go through, with the ssrr option, +every next hop router must be specified. +.PP +The complete list of IPv4 options that can be matched on is: +addext (Address Extention), +cipso (Classical IP Security Option), +dps (Dynamic Packet State), +e-sec (Extended Security), +eip (Extended Internet Protocol), +encode (ENCODE), +finn (Experimental Flow Control), +imitd (IMI Traffic Descriptor), +lsrr (Loose Source Route), +mtup (MTU Probe - obsolete), +mtur (MTU response - obsolete), +nop (No Operation), +nsapa (NSAP Address), +rr (Record Route), +rtralrt (Router Alert), +satid (Stream Identifier), +sdb (Selective Directed Broadcast), +sec (Security), +ssrr (Strict Source Route), +tr (Tracerote), +ts (Timestamp), +ump (Upstream Multicast Packet), +visa (Experimental Access Control) +and zsu (Experimental Measurement). +.SS Security with CIPSO and IPSO +.PP +IPFilter supports filtering on IPv4 packets using security attributes embedded +in the IP options part of the packet. These options are usually only used on +networks and systems that are using lablled security. Unless you know that +you are using labelled security and your networking is also labelled, it +is highly unlikely that this section will be relevant to you. +.PP +With the traditional IP Security Options (IPSO), packets can be tagged with +a security level. The following keywords are recognised and match with the +relevant RFC with respect to the bit patterns matched: +confid (confidential), +rserve-1 (1st reserved value), +rserve-2 (2nd reserved value), +rserve-3 (3rd reserved value), +rserve-4 (4th reserved value), +secret (secret), +topsecret (top secret), +unclass (unclassified). +.PP +.nf +block in quick all with opt sec-class unclass +pass in all with opt sec-class secret +.fi +.SS Matching IPv6 extension headers +.PP +Just as it is possible to filter on the various IPv4 header options, +so too it is possible to filter on the IPv6 extension headers that are +placed between the IPv6 header and the transport protocol header. +.PP +dstopts (destination options), +esp (encrypted, secure, payload), +frag (fragment), +hopopts (hop-by-hop options), +ipv6 (IPv6 header), +mobility (IP mobility), +none, +routing. +.SS Logging +.PP +There are two ways in which packets can be logged with IPFilter. The +first is with a rule that specifically says log these types of packets +and the second is a qualifier to one of the other keywords. Thus it is +possible to both log and allow or deny a packet with a single rule. +.PP +.nf +pass in log quick proto tcp from any to any port = 22 +.fi +.PP +When using stateful filtering, the log action becomes part of the result +that is remembered about a packet. Thus if the above rule was qualified +with keep state, every packet in the connection would be logged. To only +log the first packet from every packet flow tracked with keep state, it +is necessary to indicate to IPFilter that you only wish to log the first +packet. +.PP +.nf +pass in log first quick proto tcp from any to any port = 22 \\ + flags S keep state +.fi +.PP +If it is a requirement that the logging provide an accurate representation +of which connections are allowed, the log action can be qualified with the +option or-block. This allows the administrator to instruct IPFilter to +block the packet if the attempt to record the packet in IPFilter's kernel +log records (which have an upper bound on size) failed. Unless the system +shuts down or reboots, once a log record is written into the kernel buffer, +it is there until ipmon(8) reads it. +.PP +.nf +block in log proto tcp from any to any port = smtp +pass in log or-block first quick proto tcp from any \\ + to any port = 22 flags S keep state +.fi +.PP +By default, IPFilter will only log the header portion of a packet received +on the network. A portion of the body of a packet, upto 128 bytes, can also +be logged with the body keyword. ipmon(8) will display the contents of the +portion of the body logged in hex. +.PP +.nf +block in log body proto icmp all +.fi +.PP +When logging packets from ipmon(8) to syslog, by default ipmon(8) will +control what syslog facility and priority a packet will be logged with. +This can be tuned on a per rule basis like this: +.PP +.nf +block in quick log level err all with bad +pass in log level local1.info proto tcp \\ + from any to any port = 22 flags S keep state +.fi +.PP +ipfstat(8) reports how many packets have been successfully logged and how +many failed attempts to log a packet there were. +.SS Filter rule comments +.PP +If there is a desire to associate a text string, be it an administrative +comment or otherwise, with an IPFilter rule, this can be achieved by giving +the filter rule a comment. The comment is loaded with the rule into the +kernel and can be seen when the rules are listed with ipfstat. +.PP +.nf +pass in quick proto tcp from any \\ + to port = 80 comment "all web server traffic is ok" +pass out quick proto tcp from any port = 80 \\ + to any comment "all web server traffic is ok" +.fi +.SS Tags +.PP +To enable filtering and NAT to correctly match up packets with rules, +tags can be added at with NAT (for inbound packets) and filtering (for +outbound packets.) This allows a filter to be correctly mated with its +NAT rule in the event that the NAT rule changed the packet in a way +that would mean it is not obvious what it was. +.PP +For inbound packets, IPFilter can match the tag used in the filter +rules with that set by NAT. For outbound rules, it is the reverse, +the filter sets the tag and the NAT rule matches up with it. +.PP +.nf +pass in ... match-tag(nat=proxy) +pass out ... set-tag(nat=proxy) +.fi +.PP +Another use of tags is to supply a number that is only used with logging. +When packets match these rules, the log tag is carried over into the +log file records generated by ipmon(8). With the correct use of tools +such as grep, extracting log records of interest is simplified. +.PP +.nf +block in quick log ... set-tag(log=33) +.fi +.SH Filter Rule Expiration +.PP +IPFilter allows rules to be added into the kernel that it will remove after +a specific period of time by specifying rule-ttl at the end of a rule. +When listing rules in the kernel using ipfstat(8), rules that are going +to expire will NOT display "rule-ttl" with the timeout, rather what will +be seen is a comment with how many ipfilter ticks left the rule has to +live. +.PP +The time to live is specified in seconds. +.PP +.nf +pass in on fxp0 proto tcp from any \\ + to port = 22 flags S keep state rule-ttl 30 +.fi +.SH Internal packet attributes +.PP +In addition to being able to filter on very specific network and transport +header fields, it is possible to filter on other attributes that IPFilter +attaches to a packet. These attributes are placed in a rule after the +keyword "with", as can be seen with frags and frag-body above. The +following is a list of the other attributes available: +.HP +oow +the packet's IP addresses and TCP ports match an existing entry in the +state table but the sequence numbers indicate that it is outside of the +accepted window. +.IP +.nf +block return-rst in quick proto tcp from any to any with not oow +.fi +.HP +bcast +this is set by IPFilter when it receives notification that the link +layer packet was a broadcast packet. No checking of the IP addresses +is performned to determine if it is a broadcast destination or not. +.IP +.nf +block in quick proto udp all with bcast +.fi +.HP +mcast +this is set by IPFilter when it receives notification that the link +layer packet was a multicast packet. No checking of the IP addresses +is performned to determine if it is a multicast destination or not. +.IP +.nf +pass in quick proto udp from any to any port = dns with mcast +.fi +.HP +mbcast +can be used to match a packet that is either a multicast or broadcast +packet at the link layer, as indicated by the operating system. +.IP +.nf +pass in quick proto udp from any to any port = ntp with mbcast +.fi +.HP +nat +the packet positively matched a NAT table entry. +.HP +bad +sanity checking of the packet failed. This could indicate that the +layer 3/4 headers are not properly formed. +.HP +bad-src +when reverse path verification is enabled, this flag will be set when +the interface the packet is received on does not match that which would +be used to send a packet out of to the source address in the received +packet. +.HP +bad-nat +an attempt to perform NAT on the packet failed. +.HP +not +each one of the attributes matched using the "with" keyword can also be +looked for to not be present. For example, to only allow in good packets, +I can do this: +.PP +.nf +block in all +pass in all with not bad +.fi +.SH Tuning IPFilter +.PP +The ipf.conf file can also be used to tune the behaviour of IPFilter, +allowing, for example, timeouts for the NAT/state table(s) to be set +along with their sizes. The presence and names of tunables may change +from one release of IPFilter to the next. The tunables that can be +changed via ipf.conf is the same as those that can be seen and modified +using the -T command line option to ipf(8). +.PP +NOTE: When parsing ipf.conf, ipf(8) will apply the settings before +loading any rules. Thus if your settings are at the top, these may +be applied whilst the rules not applied if there is an error further +down in the configuration file. +.PP +To set one of the values below, the syntax is simple: "set", followed +by the name of the tuneable to set and then the value to set it to. +.PP +.nf +set state_max 9999; +set state_size 10101; +.fi +.PP +A list of the currently available variables inside IPFilter that may +be tuned from ipf.conf are as follows: +.HP +active +set through -s command line switch of ipf(8). See ipf(8) for detals. +.HP +chksrc +when set, enables reverse path verification on source addresses and +for filters to match packets with bad-src attribute. +.HP +control_forwarding +when set turns off kernel forwarding when IPFilter is disabled or unloaded. +.HP +default_pass +the default policy - whether packets are blocked or passed, etc - is +represented by the value of this variable. It is a bit field and the +bits that can be set are found in <netinet/ip_fil.h>. It is not +recommended to tune this value directly. +.HP +ftp_debug +set the debugging level of the in-kernel FTP proxy. +Debug messages will be printed to the system console. +.HP +ftp_forcepasv +when set the FTP proxy must see a PASV/EPSV command before creating +the state/NAT entries for the 227 response. +.HP +ftp_insecure +when set the FTP proxy will not wait for a user to login before allowing +data connections to be created. +.HP +ftp_pasvonly +when set the proxy will not create state/NAT entries for when it +sees either the PORT or EPRT command. +.HP +ftp_pasvrdr +when enabled causes the FTP proxy to create very insecure NAT/state +entries that will allow any connection between the client and server +hosts when a 227 reply is seen. Use with extreme caution. +.HP +ftp_single_xfer +when set the FTP proxy will only allow one data connection at a time. +.HP +hostmap_size +sets the size of the hostmap table used by NAT to store address mappings +for use with sticky rules. +.HP +icmp_ack_timeout +default timeout used for ICMP NAT/state when a reply packet is seen for +an ICMP state that already exists +.HP +icmp_minfragmtu +sets the minimum MTU that is considered acceptable in an ICMP error +before deciding it is a bad packet. +.HP +icmp_timeout +default timeout used for ICMP NAT/state when the packet matches the rule +.HP +ip_timeout +default timeout used for NAT/state entries that are not TCP/UDP/ICMP. +.HP +ipf_flags +.HP +ips_proxy_debug +this sets the debugging level for the proxy support code. +When enabled, debugging messages will be printed to the system console. +.HP +log_all +when set it changes the behaviour of "log body" to log the entire packet +rather than just the first 128 bytes. +.HP +log_size +sets the size of the in-kernel log buffer in bytes. +.HP +log_suppress +when set, IPFilter will check to see if the packet it is logging is +similar to the one it previously logged and if so, increases +the occurance count for that packet. The previously logged packet +must not have yet been read by ipmon(8). +.HP +min_ttl +is used to set the TTL value that packets below will be marked with +the low-ttl attribute. +.HP +nat_doflush +if set it will cause the NAT code to do a more aggressive flush of the +NAT table at the next opportunity. Once the flush has been done, the +value is reset to 0. +.HP +nat_lock +this should only be changed using ipfs(8) +.HP +nat_logging +when set, NAT will create log records that can be read from /dev/ipnat. +.HP +nat_maxbucket +maximum number of entries allowed to exist in each NAT hash bucket. +This prevents an attacker trying to load up the hash table with +entries in a single bucket, reducing performance. +.HP +nat_rules_size +size of the hash table to store map rules. +.HP +nat_table_max +maximum number of entries allowed into the NAT table +.HP +nat_table_size +size of the hash table used for NAT +.HP +nat_table_wm_high +when the fill percentage of the NAT table exceeds this mark, more +aggressive flushing is enabled. +.HP +nat_table_wm_low +this sets the percentage at which the NAT table's agressive flushing +will turn itself off at. +.HP +rdr_rules_size +size of the hash table to store rdr rules. +.HP +state_lock +this should only be changed using ipfs(8) +.HP +state_logging +when set, the stateful filtering will create log records +that can be read from /dev/ipstate. +.HP +state_max +maximum number of entries allowed into the state table +.HP +state_maxbucket +maximum number of entries allowed to exist in each state hash bucket. +This prevents an attacker trying to load up the hash table with +entries in a single bucket, reducing performance. +.HP +state_size +size of the hash table used for stateful filtering +.HP +state_wm_freq +this controls how often the agressive flushing should be run once the +state table exceeds state_wm_high in percentage full. +.HP +state_wm_high +when the fill percentage of the state table exceeds this mark, more +aggressive flushing is enabled. +.HP +state_wm_low +this sets the percentage at which the state table's agressive flushing +will turn itself off at. +.HP +tcp_close_wait +timeout used when a TCP state entry reaches the FIN_WAIT_2 state. +.HP +tcp_closed +timeout used when a TCP state entry is ready to be removed after either +a RST packet is seen. +.HP +tcp_half_closed +timeout used when a TCP state entry reaches the CLOSE_WAIT state. +.HP +tcp_idle_timeout +timeout used when a TCP state entry reaches the ESTABLISHED state. +.HP +tcp_last_ack +timeout used when a TCP NAT/state entry reaches the LAST_ACK state. +.HP +tcp_syn_received +timeout applied to a TCP NAT/state entry after SYN-ACK packet has been seen. +.HP +tcp_syn_sent +timeout applied to a TCP NAT/state entry after SYN packet has been seen. +.HP +tcp_time_wait +timeout used when a TCP NAT/state entry reaches the TIME_WAIT state. +.HP +tcp_timeout +timeout used when a TCP NAT/state entry reaches either the half established +state (one ack is seen after a SYN-ACK) or one side is in FIN_WAIT_1. +.HP +udp_ack_timeout +default timeout used for UDP NAT/state when a reply packet is seen for +a UDP state that already exists +.HP +udp_timeout +default timeout used for UDP NAT/state when the packet matches the rule +.HP +update_ipid +when set, turns on changing the IP id field in NAT'd packets to a random +number. +.SS Table of visible variables +.PP +A list of all of the tunables, their minimum, maximum and current +values is as follows. +.PP +.nf +Name Min Max Current +active 0 0 0 +chksrc 0 1 0 +control_forwarding 0 1 0 +default_pass 0 MAXUINT 134217730 +ftp_debug 0 10 0 +ftp_forcepasv 0 1 1 +ftp_insecure 0 1 0 +ftp_pasvonly 0 1 0 +ftp_pasvrdr 0 1 0 +ftp_single_xfer 0 1 0 +hostmap_size 1 MAXINT 2047 +icmp_ack_timeout 1 MAXINT 12 +icmp_minfragmtu 0 1 68 +icmp_timeout 1 MAXINT 120 +ip_timeout 1 MAXINT 120 +ipf_flags 0 MAXUINT 0 +ips_proxy_debug 0 10 0 +log_all 0 1 0 +log_size 0 524288 32768 +log_suppress 0 1 1 +min_ttl 0 1 4 +nat_doflush 0 1 0 +nat_lock 0 1 0 +nat_logging 0 1 1 +nat_maxbucket 1 MAXINT 22 +nat_rules_size 1 MAXINT 127 +nat_table_max 1 MAXINT 30000 +nat_table_size 1 MAXINT 2047 +nat_table_wm_high 2 100 99 +nat_table_wm_low 1 99 90 +rdr_rules_size 1 MAXINT 127 +state_lock 0 1 0 +state_logging 0 1 1 +state_max 1 MAXINT 4013 +state_maxbucket 1 MAXINT 26 +state_size 1 MAXINT 5737 +state_wm_freq 2 999999 20 +state_wm_high 2 100 99 +state_wm_low 1 99 90 +tcp_close_wait 1 MAXINT 480 +tcp_closed 1 MAXINT 60 +tcp_half_closed 1 MAXINT 14400 +tcp_idle_timeout 1 MAXINT 864000 +tcp_last_ack 1 MAXINT 60 +tcp_syn_received 1 MAXINT 480 +tcp_syn_sent 1 MAXINT 480 +tcp_time_wait 1 MAXINT 480 +tcp_timeout 1 MAXINT 480 +udp_ack_timeout 1 MAXINT 24 +udp_timeout 1 MAXINT 240 +update_ipid 0 1 0 +.fi +.SH Calling out to internal functions +.PP +IPFilter provides a pair of functions that can be called from a rule +that allow for a single rule to jump out to a group rather than walk +through a list of rules to find the group. If you've got multiple +networks, each with its own group of rules, this feature may help +provide better filtering performance. +.PP +The lookup to find which rule group to jump to is done on either the +source address or the destination address but not both. +.PP +In this example below, we are blocking all packets by default but then +doing a lookup on the source address from group 1010. The two rules in +the ipf.conf section are lone members of their group. For an incoming +packet that is from 1.1.1.1, it will go through three rules: (1) the +block rule, (2) the call rule and (3) the pass rule for group 1020. +For a packet that is from 3.3.2.2, it will also go through three rules: +(1) the block rule, (2) the call rule and (3) the pass rule for group +1030. Should a packet from 3.1.1.1 arrive, it will be blocked as it +does not match any of the entries in group 1010, leaving it to only +match the first rule. +.PP +.nf +from ipf.conf +------------- +block in all +call now srcgrpmap/1010 in all +pass in proto tcp from any to any port = 80 group 1020 +pass in proto icmp all icmp-type echo group 1030 + +from ippool.conf +---------------- +group-map in role=ipf number=1010 + { 1.1.1.1 group = 1020, 3.3.0.0/16 group = 1030; }; +.fi +.SS IPFilter matching expressions +.PP +An experimental feature that has been added to filter rules is to use +the same expression matching that is available with various commands +to flush and list state/NAT table entries. The use of such an expression +precludes the filter rule from using the normal IP header matching. +.PP +.nf +pass in exp { "tcp.sport 23 or tcp.sport 50" } keep state +.fi +.SS Filter rules with BPF +.PP +On platforms that have the BPF built into the kernel, IPFilter can be +built to allow BPF expressions in filter rules. This allows for packet +matching to be on arbitrary data in the packt. The use of a BPF expression +replaces all of the other protocol header matching done by IPFilter. +.PP +.nf +pass in bpf-v4 { "tcp and (src port 23 or src port 50)" } \\ + keep state +.fi +.PP +These rules tend to be +write-only because the act of compiling the filter expression into the +BPF instructions loaded into the kernel can make it difficut to +accurately reconstruct the original text filter. The end result is that +while ipf.conf() can be easy to read, understanding the output from +ipfstat might not be. +.SH VARIABLES +.PP +This configuration file, like all others used with IPFilter, supports the +use of variable substitution throughout the text. +.PP +.nf +nif="ppp0"; +pass in on $nif from any to any +.fi +.PP +would become +.PP +.nf +pass in on ppp0 from any to any +.fi +.PP +Variables can be used recursively, such as 'foo="$bar baz";', so long as +$bar exists when the parser reaches the assignment for foo. +.PP +See +.B ipf(8) +for instructions on how to define variables to be used from a shell +environment. +.DT +.SH FILES +/dev/ipf +/etc/ipf.conf +.br +/usr/share/examples/ipf Directory with examples. +.SH SEE ALSO +ipf(8), ipfstat(8), ippool.conf(5), ippool(8) diff --git a/contrib/ipfilter/man/ipf.8 b/contrib/ipfilter/man/ipf.8 new file mode 100644 index 0000000..6e88a9d --- /dev/null +++ b/contrib/ipfilter/man/ipf.8 @@ -0,0 +1,172 @@ +.\" $FreeBSD$ +.TH IPF 8 +.SH NAME +ipf \- alters packet filtering lists for IP packet input and output +.SH SYNOPSIS +.B ipf +[ +.B \-6AcdDEInoPrsvVyzZ +] [ +.B \-l +<block|pass|nomatch> +] [ +.B \-T +<optionlist> +] [ +.B \-F +<i|o|a|s|S> +] +.B \-f +<\fIfilename\fP> +[ +.B \-f +<\fIfilename\fP> +[...]] +.SH DESCRIPTION +.PP +\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 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 +.TP +.B \-6 +This option is required to parse IPv6 rules and to have them loaded. +.TP +.B \-A +Set the list to make changes to the active list (default). +.TP +.B \-c <language> +This option causes \fBipf\fP to generate output files for a compiler that +supports \fBlanguage\fI. At present, the only target language supported is +\fBC\fB (-cc) for which two files - \fBip_rules.c\fP +and \fBip_rules.h\fP are generated in the \fBCURRENT DIRECTORY\fP when +\fBipf\fP is being run. These files can be used with the +\fBIPFILTER_COMPILED\fP kernel option to build filter rules staticlly into +the kernel. +.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. +.TP +.B \-E +Enable the filter (if disabled). Not effective for loadable kernel versions. +.TP +.BR \-F \0<i|o|a> +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. +.TP +.BR \-F \0<s|S> +To flush entries from the state table, the \fB-F\fP option is used in +conjunction with either "s" (removes state information about any non-fully +established connections) or "S" (deletes the entire state table). Only +one of the two options may be given. A fully established connection +will show up in \fBipfstat -s\fP output as 5/5, with deviations either +way indicating it is not fully established any more. +.TP +.BR \-F <5|6|7|8|9|10|11> +For the TCP states that represent the closing of a connection has begun, +be it only one side or the complete connection, it is possible to flush +those states directly using the number corresponding to that state. +The numbers relate to the states as follows: 5 = close-wait, 6 = fin-wait-1, +7 = closing, 8 = last-ack, 9 = fin-wait-2, 10 = time-wait, 11 = closed. +.TP +.BR \-F <number> +If the argument supplied to \fB-F\fP is greater than 30, then state table +entries that have been idle for more than this many seconds will be flushed. +.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. +.TP +.B \-I +Set the list to make changes to the inactive list. +.TP +.B \-l \0<pass|block|nomatch> +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. +.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. +.TP +.B \-o +Force rules by default to be added/deleted to/from the output list, rather +than the (default) input list. +.TP +.B \-P +Add rules as temporary entries in the authentication rule table. +.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 \-T <optionlist> +This option allows run-time changing of IPFilter kernel variables. Some +variables require IPFilter to be in a disabled state (\fB-D\fP) for changing, +others do not. The optionlist parameter is a comma separated list of tuning +commands. A tuning command is either "list" (retrieve a list of all variables +in the kernel, their maximum, minimum and current value), a single variable +name (retrieve its current value) and a variable name with a following +assignment to set a new value. Some examples follow. +.nf +# Print out all IPFilter kernel tunable parameters +ipf -T list +# Display the current TCP idle timeout and then set it to 3600 +ipf -D -T fr_tcpidletimeout,fr_tcpidletimeout=3600 -E +# Display current values for fr_pass and fr_chksrc, then set fr_chksrc to 1. +ipf -T fr_pass,fr_chksrc,fr_chksrc=1 +.fi +.TP +.B \-v +Turn verbose mode on. Displays information relating to rule processing. +.TP +.B \-V +Show version information. This will display the version information compiled +into the ipf binary and retrieve it from the kernel code (if running/present). +If it is present in the kernel, information about its current state will be +displayed (whether logging is active, default filtering, etc). +.TP +.B \-y +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 zeroed. +.TP +.B \-Z +Zero global statistics held in the kernel for filtering only (this doesn't +affect fragment or state statistics). +.DT +.SH FILES +/dev/ipauth +.br +/dev/ipl +.br +/dev/ipstate +.SH SEE ALSO +ipftest(1), mkfilters(1), ipf(4), ipl(4), ipf(5), ipfstat(8), ipmon(8), ipnat(8) +.SH DIAGNOSTICS +.PP +Needs to be run as root for the packet filtering lists to actually +be affected inside the kernel. +.SH BUGS +.PP +If you find any, please send email to me at darrenr@pobox.com diff --git a/contrib/ipfilter/man/ipfilter.4 b/contrib/ipfilter/man/ipfilter.4 new file mode 100644 index 0000000..10fd18e --- /dev/null +++ b/contrib/ipfilter/man/ipfilter.4 @@ -0,0 +1,241 @@ +.\" $FreeBSD$ +.\" +.TH IP\ FILTER 4 +.SH NAME +ipfilter \- Introduction to IP packet filtering +.SH DESCRIPTION +IP Filter is a TCP/IP packet filter, suitable for use in a firewall +environment. To use, it can either be used as a loadable kernel module or +incorporated into your UNIX kernel; use as a loadable kernel module where +possible is highly recommended. Scripts are provided to install and patch +system files, as required. +.SH FEATURES +The IP packet filter can: +.IP +explicitly deny/permit any packet from passing through +.IP +distinguish between various interfaces +.IP +filter by IP networks or hosts +.IP +selectively filter any IP protocol +.IP +selectively filter fragmented IP packets +.IP +selectively filter packets with IP options +.IP +send back an ICMP error/TCP reset for blocked packets +.IP +keep packet state information for TCP, UDP and ICMP packet flows +.IP +keep fragment state information for any IP packet, applying the same rule +to all fragments. +.IP +act as a Network Address Translator (NAT) +.IP +use redirection to setup true transparent proxy connections +.IP +provide packet header details to a user program for authentication +.IP +in addition, supports temporary storage of pre-authenticated rules for passing packets through +.PP +Special provision is made for the three most common Internet protocols, TCP, +UDP and ICMP. The IP Packet filter allows filtering of: +.IP +Inverted host/net matchingTCP/UDP packets by port number or a port number +range +.IP +ICMP packets by type/code +.IP +"established" TCP packets +.IP +On any arbitrary combination of TCP flags +.IP +"short" (fragmented) IP packets with incomplete headers can be filtered +.IP +any of the 19 IP options or 8 registered IP security classes TOS (Type of +Service) field in packets +.PP +To keep track of the performance of the IP packet filter, a logging device +is used which supports logging of: +.IP +the TCP/UDP/ICMP and IP packet headers +.IP +the first 128 bytes of the packet (including headers) +.PP +A packet can be logged when: +.IP +it is successfully passed through +.IP +it is blocked from passing through +.IP +it matches a rule setup to look for suspicious packets +.PP +IP Filter keeps its own set of statistics on: +.IP +packets blocked +.IP +packets (and bytes!) used for accounting +.IP +packets passed +.IP +packets logged +.IP +attempts to log which failed (buffer full) +.IP +and much more, for packets going both in and out. + +.SH Tools +The current implementation provides a small set of tools, which can easily +be used and integrated with regular unix shells and tools. A brief description +of the tools provided: +.PP +ipf(8) +reads in a set of rules, from either stdin or a file, and adds them to +the kernels current list (appending them). It can also be used to flush the +current filter set or delete individual filter rules. The file format is +described in ipf(5). +.PP +ipfs(8) +is a utility to temporarily lock the IP Filter kernel tables (state tables +and NAT mappings) and write them to disk. After that the system can be +rebooted, and ipfs can be used to read these tables from disk and restore +them into the kernel. This way the system can be rebooted without the +connections being terminated. +.PP +ipfstat(8) +interrogates the kernel for statistics on packet filtering, so +far, and retrieves the list of filters in operation for inbound and outbound +packets. +.PP +ipftest(1) +reads in a filter rule file and then applies sample IP packets to +the rule file. This allows for testing of filter list and examination of how +a packet is passed along through it. +.PP +ipmon(8) +reads buffered data from the logging device (default is /dev/ipl) +for output to either: +.IP +screen (standard output) +.IP +file +.IP +syslog +.PP +ipsend(1) +generates arbitary IP packets for ethernet connected machines. +.PP +ipresend(1) +reads in a data file of saved IP packets (ie +snoop/tcpdump/etherfind output) and sends it back across the network. +.PP +iptest(1) +contains a set of test "programs" which send out a series of IP +packets, aimed at testing the strength of the TCP/IP stack at which it is +aimed at. WARNING: this may crash machine(s) targeted! +.PP +ipnat(8) +reads in a set of rules, from either stdin or a file and adds them +to the kernels current list of active NAT rules. NAT rules can also be +deleted using ipnat. The format of the configuration file to be used +with ipnat is described in ipnat(5). +.PP +For use in your own programs (e.g. for writing of transparent application +proxies), the programming interface and the associated ioctl's are +documented in ipf(4). + +Documentation on ioctl's and the format of data saved +to the logging character device is provided in ipl(4) +so that you may develop your own applications to work with or in place of any +of the above. + +Similar, the interface to the NAT code is documented in ipnat(4). + +.SH PACKET PROCESSING FLOW +The following diagram illustrates the flow of TCP/IP packets through the +various stages introduced by IP Filter. +.PP +.nf + IN + | + V + +-------------------------+--------------------------+ + | | | + | V | + | Network Address Translation | + | | | + | authenticated | | + | +-------<---------+ | + | | | | + | | V | + | V IP Accounting | + | | | | + | | V | + | | Fragment Cache Check--+ | + | | | | | + | V V V | + | | Packet State Check-->+ | + | | | | | + | | +->--+ | | | + | | | | V | | + | V groups IP Filtering V | + | | | | | | | + | | +--<-+ | | | + | | | | | + | +---------------->|<-----------+ | + | | | + | V | + | +---<----+ | + | | | | + | function | | + | | V | + | +--->----+ | + | | | + | V | + +--|---<--- fast-route ---<--+ | + | | | | + | | V | + | +-------------------------+--------------------------+ + | | + | pass only + | | + | V + V [KERNEL TCP/IP Processing] + | | + | +-------------------------+--------------------------+ + | | | | + | | V | + | | Fragment Cache Check--+ | + | | | | | + | | V V | + | | Packet State Check-->+ | + | | | | | + | | V | | + V | IP Filtering | | + | | | V | + | | |<-----------+ | + | | V | + | | IP Accounting | + | | | | + | | V | + | | Network Address Translation | + | | | | + | | V | + | +-------------------------+--------------------------+ + | | + | pass only + V | + +--------------------------->| + V + OUT +.fi + +.SH MORE INFORMATION +More information (including pointers to the FAQ and the mailing list) can be +obtained from the sofware's official homepage: www.ipfilter.org + +.SH SEE ALSO +ipf(4), ipf(5), ipf(8), ipfilter(5), ipfs(8), ipfstat(8), ipftest(1), +ipl(4), ipmon(8), ipnat(8), ipnat(4), + diff --git a/contrib/ipfilter/man/ipfilter.4.mandoc b/contrib/ipfilter/man/ipfilter.4.mandoc new file mode 100644 index 0000000..22e1f36 --- /dev/null +++ b/contrib/ipfilter/man/ipfilter.4.mandoc @@ -0,0 +1,267 @@ +.Dd December 8, 2000 +.Dt IP\ FILTER 4 +.Os +.Sh NAME +.Nm IP Filter +.Nd Introduction to IP packet filtering +.Sh DESCRIPTION +IP Filter is a TCP/IP packet filter, suitable for use in a firewall +environment. To use, it can either be used as a loadable kernel module or +incorporated into your UNIX kernel; use as a loadable kernel module where +possible is highly recommended. Scripts are provided to install and patch +system files, as required. +.Sh FEATURES +The IP packet filter can: +.Bl -bullet -offset indent -compact +.It +explicitly deny/permit any packet from passing through +.It +distinguish between various interfaces +.It +filter by IP networks or hosts +.It +selectively filter any IP protocol +.It +selectively filter fragmented IP packets +.It +selectively filter packets with IP options +.It +send back an ICMP error/TCP reset for blocked packets +.It +keep packet state information for TCP, UDP and ICMP packet flows +.It +keep fragment state information for any IP packet, applying the same rule +to all fragments. +.It +act as a Network Address Translator (NAT) +.It +use redirection to setup true transparent proxy connections +.It +provide packet header details to a user program for authentication +.It +in addition, supports temporary storage of pre-authenticated rules for passing packets through +.El +.Pp +Special provision is made for the three most common Internet protocols, TCP, +UDP and ICMP. The IP Packet filter allows filtering of: +.Bl -bullet -offset indent -compact +.It +Inverted host/net matchingTCP/UDP packets by port number or a port number +range +.It +ICMP packets by type/code +.It +"established" TCP packets +.It +On any arbitrary combination of TCP flags +.It +"short" (fragmented) IP packets with incomplete headers can be filtered +.It +any of the 19 IP options or 8 registered IP security classes TOS (Type of +Service) field in packets +.El +.Pp +To keep track of the performance of the IP packet filter, a logging device +is used which supports logging of: +.Bl -bullet -offset indent -compact +.It +the TCP/UDP/ICMP and IP packet headers +.It +the first 128 bytes of the packet (including headers) +.El +.Pp +A packet can be logged when: +.Bl -bullet -offset indent -compact +.It +it is successfully passed through +.It +it is blocked from passing through +.It +it matches a rule setup to look for suspicious packets +.El +.Pp +IP Filter keeps its own set of statistics on: +.Bl -bullet -offset indent -compact +.It +packets blocked +.It +packets (and bytes!) used for accounting +.It +packets passed +.li +packets logged +.It +attempts to log which failed (buffer full) +.El +and much more, for packets going both in and out. + +.Sh Tools +The current implementation provides a small set of tools, which can easily +be used and integrated with regular unix shells and tools. A brief description +of the tools provided: +.Pp +.Xr ipf 8 +reads in a set of rules, from either stdin or a file, and adds them to +the kernels current list (appending them). It can also be used to flush the +current filter set or delete individual filter rules. The file format is +described in +.Xr ipf 5 . +.Pp +.Xr ipfs 8 +is a utility to temporarily lock the IP Filter kernel tables (state tables +and NAT mappings) and write them to disk. After that the system can be +rebooted, and ipfs can be used to read these tables from disk and restore +them into the kernel. This way the system can be rebooted without the +connections being terminated. +.Pp +.Xr ipfstat 8 +interrogates the kernel for statistics on packet filtering, so +far, and retrieves the list of filters in operation for inbound and outbound +packets. +.Pp +.Xr ipftest 1 +reads in a filter rule file and then applies sample IP packets to +the rule file. This allows for testing of filter list and examination of how +a packet is passed along through it. +.Pp +.Xr ipmon 8 +reads buffered data from the logging device (default is /dev/ipl) +for output to either: +.Bl -bullet -offset indent -compact +.It +screen (standard output) +.It +file +.It +syslog +.El +.Pp +.Xr ipsend 1 +generates arbitary IP packets for ethernet connected machines. +.Pp +.Xr ipresend 1 +reads in a data file of saved IP packets (ie +snoop/tcpdump/etherfind output) and sends it back across the network. +.Pp +.Xr iptest 1 +contains a set of test "programs" which send out a series of IP +packets, aimed at testing the strength of the TCP/IP stack at which it is +aimed at. WARNING: this may crash machine(s) targeted! +.Pp +.Xr ipnat 8 +reads in a set of rules, from either stdin or a file and adds them +to the kernels current list of active NAT rules. NAT rules can also be +deleted using ipnat. The format of the configuration file to be used +with ipnat is described in +.Xr ipnat 5 . +.Pp +For use in your own programs (e.g. for writing of transparent application +proxies), the programming interface and the associated ioctl's are +documented in +.Xr ipf 4 . + +Documentation on ioctl's and the format of data saved +to the logging character device is provided in +.Xr ipl 4 +so that you may develop your own applications to work with or in place of any +of the above. + +Similar, the interface to the NAT code is documented in +.Xr ipnat 4 . + +.Sh PACKET PROCESSING FLOW +The following diagram illustrates the flow of TCP/IP packets through the +various stages introduced by IP Filter. +.Pp +.nf + IN + | + V + +-------------------------+--------------------------+ + | | | + | V | + | Network Address Translation | + | | | + | authenticated | | + | +-------<---------+ | + | | | | + | | V | + | V IP Accounting | + | | | | + | | V | + | | Fragment Cache Check--+ | + | | | | | + | V V V | + | | Packet State Check-->+ | + | | | | | + | | +->--+ | | | + | | | | V | | + | V groups IP Filtering V | + | | | | | | | + | | +--<-+ | | | + | | | | | + | +---------------->|<-----------+ | + | | | + | V | + | +---<----+ | + | | | | + | function | | + | | V | + | +--->----+ | + | | | + | V | + +--|---<--- fast-route ---<--+ | + | | | | + | | V | + | +-------------------------+--------------------------+ + | | + | pass only + | | + | V + V [KERNEL TCP/IP Processing] + | | + | +-------------------------+--------------------------+ + | | | | + | | V | + | | Fragment Cache Check--+ | + | | | | | + | | V V | + | | Packet State Check-->+ | + | | | | | + | | V | | + V | IP Filtering | | + | | | V | + | | |<-----------+ | + | | V | + | | IP Accounting | + | | | | + | | V | + | | Network Address Translation | + | | | | + | | V | + | +-------------------------+--------------------------+ + | | + | pass only + V | + +--------------------------->| + V + OUT +.fi + +.Sh MORE INFORMATION +More information (including pointers to the FAQ and the mailing list) can be +obtained from the sofware's official homepage: www.ipfilter.org + +.Sh SEE ALSO +.Xr ipf 4 , +.Xr ipf 5 , +.Xr ipf 8 , +.Xr ipfilter 5 , +.Xr ipfs 8 , +.Xr ipfstat 8 , +.Xr ipftest 1 , +.Xr ipl 4 , +.Xr ipmon 8 , +.Xr ipnat 4 , +.Xr ipnat 8 , + diff --git a/contrib/ipfilter/man/ipfilter.5 b/contrib/ipfilter/man/ipfilter.5 new file mode 100644 index 0000000..97e504d --- /dev/null +++ b/contrib/ipfilter/man/ipfilter.5 @@ -0,0 +1,11 @@ +.\" $FreeBSD$ +.TH IPFILTER 1 +.SH NAME +IP Filter +.SH DESCRIPTION +.PP +IP Filter is a package providing packet filtering capabilities for a variety +of operating systems. On a properly setup system, it can be used to build a +firewall. +.SH SEE ALSO +ipf(8), ipf(1), ipf(5), ipnat(8), ipnat(5), mkfilters(1) diff --git a/contrib/ipfilter/man/ipfs.8 b/contrib/ipfilter/man/ipfs.8 new file mode 100644 index 0000000..01d0c70 --- /dev/null +++ b/contrib/ipfilter/man/ipfs.8 @@ -0,0 +1,127 @@ +.\" $FreeBSD$ +.\" +.TH IPFS 8 +.SH NAME +ipfs \- saves and restores information for NAT and state tables. +.SH SYNOPSIS +.B ipfs +[-nv] -l +.PP +.B ipfs +[-nv] -u +.PP +.B ipfs +[-nv] [ +.B \-d +<\fIdirname\fP> +] -R +.PP +.B ipfs +[-nv] [ +.B \-d +<\fIdirname\fP> +] -W +.PP +.B ipfs +[-nNSv] [ +.B \-f +<\fIfilename\fP> +] -r +.PP +.B ipfs +[-nNSv] [ +.B \-f +<\fIfilename\fP> +] -w +.PP +.B ipfs +[-nNSv] +.B \-f +<\fIfilename\fP> +.B \-i +<if1>,<if2> +.SH DESCRIPTION +.PP +\fBipfs\fP allows state information created for NAT entries and rules using +\fIkeep state\fP to be locked (modification prevented) and then saved to disk, +allowing for the system to experience a reboot, followed by the restoration +of that information, resulting in connections not being interrupted. +.SH OPTIONS +.TP +.B \-d +Change the default directory used with +.B \-R +and +.B \-W +options for saving state information. +.TP +.B \-n +Don't actually take any action that would affect information stored in +the kernel or on disk. +.TP +.B \-v +Provides a verbose description of what's being done. +.TP +.B \-i <ifname1>,<ifname2> +Change all instances of interface name ifname1 in the state save file to +ifname2. Useful if you're restoring state information after a hardware +reconfiguration or change. +.TP +.B \-N +Operate on NAT information. +.TP +.B \-S +Operate on filtering state information. +.TP +.B \-u +Unlock state tables in the kernel. +.TP +.B \-l +Lock state tables in the kernel. +.TP +.B \-r +Read information in from the specified file and load it into the +kernel. This requires the state tables to have already been locked +and does not change the lock once complete. +.TP +.B \-w +Write information out to the specified file and from the kernel. +This requires the state tables to have already been locked +and does not change the lock once complete. +.TP +.B \-R +Restores all saved state information, if any, from two files, +\fIipstate.ipf\fP and \fIipnat.ipf\fP, stored in the \fI/var/db/ipf\fP +directory unless otherwise specified by the +.B \-d +option. The state tables are locked at the beginning of this +operation and unlocked once complete. +.TP +.B \-W +Saves in-kernel state information, if any, out to two files, +\fIipstate.ipf\fP and \fIipnat.ipf\fP, stored in the \fI/var/db/ipf\fP +directory unless otherwise specified by the +.B \-d +option. The state tables are locked at the beginning of this +operation and unlocked once complete. +.DT +.SH FILES +/var/db/ipf/ipstate.ipf +.br +/var/db/ipf/ipnat.ipf +.br +/dev/ipl +.br +/dev/ipstate +.br +/dev/ipnat +.SH SEE ALSO +ipf(8), ipl(4), ipmon(8), ipnat(8) +.SH DIAGNOSTICS +.PP +Perhaps the -W and -R operations should set the locking but rather than +undo it, restore it to what it was previously. Fragment table information +is currently not saved. +.SH BUGS +.PP +If you find any, please send email to me at darrenr@pobox.com diff --git a/contrib/ipfilter/man/ipfstat.8 b/contrib/ipfilter/man/ipfstat.8 new file mode 100644 index 0000000..cea8d5f --- /dev/null +++ b/contrib/ipfilter/man/ipfstat.8 @@ -0,0 +1,194 @@ +.\" $FreeBSD$ +.TH ipfstat 8 +.SH NAME +ipfstat \- reports on packet filter statistics and filter list +.SH SYNOPSIS +.B ipfstat +[ +.B \-6aAdfghIilnoRsv +] +.br +.B ipfstat -t +[ +.B \-6C +] [ +.B \-D +<addrport> +] [ +.B \-P +<protocol> +] [ +.B \-S +<addrport> +] [ +.B \-T +<refresh time> +] +.SH DESCRIPTION +\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/boot/kernel/kernel\fP. +.PP +The default behaviour of \fBipfstat\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 +.TP +.B \-6 +Display filter lists and states for IPv6, if available. +.TP +.B \-a +Display the accounting filter list and show bytes counted against each rule. +.TP +.B \-A +Display packet authentication statistics. +.TP +.B \-C +This option is only valid in combination with \fB\-t\fP. +Display "closed" states as well in the top. Normally, a TCP connection is +not displayed when it reaches the CLOSE_WAIT protocol state. With this +option enabled, all state entries are displayed. +.TP +.BR \-d +Produce debugging output when displaying data. +.TP +.BR \-D \0<addrport> +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries whose destination IP address and port +match the addrport argument. The addrport specification is of the form +ipaddress[,port]. The ipaddress and port should be either numerical or the +string "any" (specifying any IP address resp. any port). If the \fB\-D\fP +option is not specified, it defaults to "\fB\-D\fP any,any". +.TP +.B \-f +Show fragment state information (statistics) and held state information (in +the kernel) if any is present. +.TP +.B \-g +Show groups currently configured (both active and inactive). +.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 +.BR \-P \0<protocol> +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries that match a specific protocol. The +argument can be a protocol name (as defined in \fB/etc/protocols\fP) or a +protocol number. If this option is not specified, state entries for any +protocol are specified. +.TP +.BR \-R +Don't try to resolve addresses to hostnames and ports to services while +printing statistics. +.TP +.B \-s +Show packet/flow state information (statistics only). +.TP +.B \-sl +Show held state information (in the kernel) if any is present (no statistics). +.TP +.BR \-S \0<addrport> +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries whose source IP address and port match +the addrport argument. The addrport specification is of the form +ipaddress[,port]. The ipaddress and port should be either numerical or the +string "any" (specifying any IP address resp. any port). If the \fB\-S\fP +option is not specified, it defaults to "\fB\-S\fP any,any". +.TP +.B \-t +Show the state table in a way similar to the way \fBtop(1)\fP shows the process +table. States can be sorted using a number of different ways. This option +requires \fBcurses(3)\fP and needs to be compiled in. It may not be available on +all operating systems. See below, for more information on the keys that can +be used while ipfstat is in top mode. +.TP +.BR \-T \0<refreshtime> +This option is only valid in combination with \fB\-t\fP. Specifies how often +the state top display should be updated. The refresh time is the number of +seconds between an update. Any positive integer can be used. The default (and +minimal update time) is 1. +.TP +.B \-v +Turn verbose mode on. Displays more debugging information. When used with +either \fB-i\fP or \fB-o\fP, counters associated with the rule, such as the +number of times it has been matched and the number of bytes from such packets +is displayed. For "keep state" rules, a count of the number of state sessions +active against the rule is also displayed. +.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 +the appropriate list of filter rules currently installed and in use by the +kernel. +.PP +One of the statistics that \fBipfstat\fP shows is \fBticks\fP. +This number indicates how long the filter has been enabled. +The number is incremented every half\-second. +.SH STATE TOP +Using the \fB\-t\fP option \fBipfstat\fP will enter the state top mode. In +this mode the state table is displayed similar to the way \fBtop\fP displays +the process table. The \fB\-C\fP, \fB\-D\fP, \fB\-P\fP, \fB\-S\fP and \fB\-T\fP +command line options can be used to restrict the state entries that will be +shown and to specify the frequency of display updates. +.PP +In state top mode, the following keys can be used to influence the displayed +information: +.TP +\fBb\fP show packets/bytes from backward direction. +.TP +\fBf\fP show packets/bytes from forward direction. (default) +.TP +\fBl\fP redraw the screen. +.TP +\fBq\fP quit the program. +.TP +\fBs\fP switch between different sorting criterion. +.TP +\fBr\fP reverse the sorting criterion. +.PP +States can be sorted by protocol number, by number of IP packets, by number +of bytes and by time-to-live of the state entry. The default is to sort by +the number of bytes. States are sorted in descending order, but you can use +the \fBr\fP key to sort them in ascending order. +.SH STATE TOP LIMITATIONS +It is currently not possible to interactively change the source, destination +and protocol filters or the refresh frequency. This must be done from the +command line. +.PP +The screen must have at least 80 columns. This is however not checked. +When running state top in IPv6 mode, the screen must be much wider to display +the very long IPv6 addresses. +.PP +Only the first X-5 entries that match the sort and filter criteria are +displayed (where X is the number of rows on the display. The only way to see +more entries is to resize the screen. +.SH FILES +/dev/kmem +.br +/dev/ipl +.br +/dev/ipstate +.br +/kernel +.SH SEE ALSO +ipf(8) +.SH BUGS +none known. diff --git a/contrib/ipfilter/man/ipftest.1 b/contrib/ipfilter/man/ipftest.1 new file mode 100644 index 0000000..10232d3 --- /dev/null +++ b/contrib/ipfilter/man/ipftest.1 @@ -0,0 +1,205 @@ +.\" $FreeBSD$ +.TH ipftest 1 +.SH NAME +ipftest \- test packet filter rules with arbitrary input. +.SH SYNOPSIS +.B ipftest +[ +.B \-6bCdDoRvx +] [ +.B \-F +input-format +] [ +.B \-i +<filename> +] [ +.B \-I +interface +] [ +.B \-l +<filename> +] [ +.B \-N +<filename> +] [ +.B \-P +<filename> +] [ +.B \-r +<filename> +] [ +.B \-S +<ip_address> +] [ +.B \-T +<optionlist> +] +.SH DESCRIPTION +.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 proceed +to test their effectiveness. The hope is that this minimises disruptions +in providing a secure IP environment. +.PP +\fBipftest\fP will parse any standard ruleset for use with \fBipf\fP, +\fBipnat\fP and/or \fBippool\fP +and apply input, returning output as to the result. However, \fBipftest\fP +will return one of three values for packets passed through the filter: +pass, block or nomatch. This is intended to give the operator a better +idea of what is happening with packets passing through their filter +ruleset. +.PP +At least one of \fB\-N\fP, \fB-P\fP or \fB\-r\fP must be specified. +.SH OPTIONS +.TP +.B \-6 +Use IPv6. +.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. +.TP +.B \-C +Force the checksums to be (re)calculated for all packets being input into +\fBipftest\fP. This may be necessary if pcap files from tcpdump are being +fed in where there are partial checksums present due to hardware offloading. +.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). +.TP +.B \-D +Dump internal tables before exiting. +This excludes log messages. +.TP +.B \-F +This option is used to select which input format the input file is in. +The following formats are available: etherfind, hex, pcap, snoop, tcpdump,text. +.RS +.TP +.B etherfind +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: +.PP +.nf + etherfind -n + etherfind -n -t +.fi +.TP +.B hex +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. A packet may be broken up over several lines of hex digits, +a blank line indicating the end of the packet. It is possible to specify +both the interface name and direction of the packet (for filtering purposes) +at the start of the line using this format: [direction,interface] To define +a packet going in on le0, we would use \fB[in,le0]\fP - the []'s are required +and part of the input syntax. +.HP +.B pcap +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 snoop +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. +.TP +.B tcpdump +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: +.PP +.nf + tcpdump -n + tcpdump -nq + tcpdump -nqt + tcpdump -nqtt + tcpdump -nqte +.fi +.TP +.B text +The input file is in \fBipftest\fP text input format. +This is the default if no \fB\-F\fP argument is specified. +The format used is as follows: +.nf + "in"|"out" "on" if ["tcp"|"udp"|"icmp"] + srchost[,srcport] dsthost[,destport] [FSRPAU] +.fi +.PP +This allows for a packet going "in" or "out" of an interface (if) to be +generated, being one of the three main protocols (optionally), and if +either TCP or UDP, a port parameter is also expected. If TCP is selected, +it is possible to (optionally) supply TCP flags at the end. Some examples +are: +.nf + # a UDP packet coming in on le0 + in on le0 udp 10.1.1.1,2210 10.2.1.5,23 + # an IP packet coming in on le0 from localhost - hmm :) + in on le0 localhost 10.4.12.1 + # a TCP packet going out of le0 with the SYN flag set. + out on le0 tcp 10.4.12.1,2245 10.1.1.1,23 S +.fi +.RE +.DT +.TP +.BR \-i \0<filename> +Specify the filename from which to take input. Default is stdin. +.TP +.BR \-I \0<interface> +Set the interface name (used in rule matching) to be the name supplied. +This is useful where it is +not otherwise possible to associate a packet with an interface. Normal +"text packets" can override this setting. +.TP +.BR \-l \0<filename> +Dump log messages generated during testing to the specified file. +.TP +.BR \-N \0<filename> +Specify the filename from which to read NAT rules in \fBipnat\fP(5) format. +.TP +.B \-o +Save output packets that would have been written to each interface in +a file /tmp/\fIinterface_name\fP in raw format. +.TP +.BR \-P \0<filename> +Read IP pool configuration information in \fBippool\fP(5) format from the +specified file. +.TP +.BR \-r \0<filename> +Specify the filename from which to read filter rules in \fBipf\fP(5) format. +.TP +.B \-R +Don't attempt to convert IP addresses to hostnames. +.TP +.BR \-S \0<ip_address> +The IP address specifived with this option is used by ipftest to determine +whether a packet should be treated as "input" or "output". If the source +address in an IP packet matches then it is considered to be inbound. If it +does not match then it is considered to be outbound. This is primarily +for use with tcpdump (pcap) files where there is no in/out information +saved with each packet. +.TP +.BR \-T \0<optionlist> +This option simulates the run-time changing of IPFilter kernel variables +available with the \fB\-T\fP option of \fBipf\fP. +The optionlist parameter is a comma separated list of tuning +commands. A tuning command is either "list" (retrieve a list of all variables +in the kernel, their maximum, minimum and current value), a single variable +name (retrieve its current value) and a variable name with a following +assignment to set a new value. See \fBipf\fP(8) for examples. +.TP +.B \-v +Verbose mode. This provides more information about which parts of rule +matching the input packet passes and fails. +.TP +.B \-x +Print a hex dump of each packet before printing the decoded contents. +.SH SEE ALSO +ipf(5), ipf(8), snoop(1m), tcpdump(8), etherfind(8c) +.SH BUGS +Not all of the input formats are sufficiently capable of introducing a +wide enough variety of packets for them to be all useful in testing. diff --git a/contrib/ipfilter/man/ipl.4 b/contrib/ipfilter/man/ipl.4 new file mode 100644 index 0000000..da1d9e6 --- /dev/null +++ b/contrib/ipfilter/man/ipl.4 @@ -0,0 +1,81 @@ +.\" $FreeBSD$ +.\" +.TH IPL 4 +.SH NAME +ipl \- IP packet log device +.SH DESCRIPTION +The \fBipl\fP pseudo device's purpose is to provide an easy way to gather +packet headers of packets you wish to log. If a packet header is to be +logged, the entire header is logged (including any IP options \- TCP/UDP +options are not included when it calculates header size) or not at all. +The packet contents are also logged after the header. If the log reader +is busy or otherwise unable to read log records, up to IPLLOGSIZE (8192 is the +default) bytes of data are stored. +.PP +Prepending every packet header logged is a structure containing information +relevant to the packet following and why it was logged. The structure's +format is as follows: +.LP +.nf +/* + * Log structure. Each packet header logged is prepended by one of these. + * Following this in the log records read from the device will be an ipflog + * structure which is then followed by any packet data. + */ +typedef struct iplog { + u_long ipl_sec; + u_long ipl_usec; + u_int ipl_len; + u_int ipl_count; + size_t ipl_dsize; + struct iplog *ipl_next; +} iplog_t; + + +typedef struct ipflog { +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) + u_char fl_ifname[IFNAMSIZ]; +#else + u_int fl_unit; + u_char fl_ifname[4]; +#endif + u_char fl_plen; /* extra data after hlen */ + u_char fl_hlen; /* length of IP headers saved */ + u_short fl_rule; /* assume never more than 64k rules, total */ + u_32_t fl_flags; +} ipflog_t; + +.fi +.PP +When reading from the \fBipl\fP device, it is necessary to call read(2) with +a buffer big enough to hold at least 1 complete log record - reading of partial +log records is not supported. +.PP +If the packet contents are more than 128 bytes when \fBlog body\fP is used, +then only 128 bytes of the packet contents are logged. +.PP +Although it is only possible to read from the \fBipl\fP device, opening it +for writing is required when using an ioctl which changes any kernel data. +.PP +The ioctls which are loaded with this device can be found under \fBipf(4)\fP. +The ioctls which are for use with logging and don't affect the filter are: +.LP +.nf + ioctl(fd, SIOCIPFFB, int *) + ioctl(fd, FIONREAD, int *) +.fi +.PP +The SIOCIPFFB ioctl flushes the log buffer and returns the number of bytes +flushed. FIONREAD returns the number of bytes currently used for storing +log data. If IPFILTER_LOG is not defined when compiling, SIOCIPFFB is not +available and FIONREAD will return but not do anything. +.PP +There is currently no support for non-blocking IO with this device, meaning +all read operations should be considered blocking in nature (if there is no +data to read, it will sleep until some is made available). +.SH SEE ALSO +ipf(4) +.SH BUGS +Packet headers are dropped when the internal buffer (static size) fills. +.SH FILES +/dev/ipl0 diff --git a/contrib/ipfilter/man/ipmon.5 b/contrib/ipfilter/man/ipmon.5 new file mode 100644 index 0000000..95126f0 --- /dev/null +++ b/contrib/ipfilter/man/ipmon.5 @@ -0,0 +1,226 @@ +.\" $FreeBSD$ +.\" +.TH IPMON 5 +.SH NAME +ipmon, ipmon.conf \- ipmon configuration file format +.SH DESCRIPTION +The +.B ipmon.conf +file is optionally loaded by +.B ipmon +when it starts. Its primary purpose is to direct +.B ipmon +to do extra actions when it sees a specific log entry from the kernel. +.PP +A line in the +.B ipmon.conf +file is either a comment or a +.B match +line. Each line must have a matching segment and an action segment. +These are to the left and right of the word "do", respectively. +A comment line is any line that starts with a #. +.PP +.B NOTE: +This file differs from all other IPFilter configuration files because it +attempts to match every line with every log record received. It does +.B not +stop at the +.B first +match or only use the +.B last +match. +.PP +For the action segment, a +.B match +line can delivery output to one of three destinations: +\fBfile\fR, \fBemail\fR or \fBcommand\fR. For example: +.nf + +match { type = ipf; } do { save("file:///var/log/ipf-log"); }; +match { type = nat; } do { syslog; }; +match { type = state; } do { execute("/bin/mail root"); }; +.fi +.PP +and is roughly described like this: +.PP +match { \fImatch-it ,match-it, ...\fP } do { \fIaction, action, ...\fP}; +.PP +where there can be a list of matching expressions and a list of actions +to perform if all of the matching expressions are matched up with by +the current log entry. +.PP +The lines above would save all ipf log entries to /var/log/ipf-log, send +all of the entries for NAT (ipnat related) to syslog and generate an email +to root for each log entry from the state tables. +.SH SYNTAX - MATCHING +.PP +In the above example, the matching segment was confined to matching on +the type of log entry generated. The full list of fields that can be +used here is: +.TP +direction <in|out> +This option is used to match on log records generated for packets going +in or out. +.TP +dstip <address/mask> +This option is used to match against the destination address associated +with the packet being logged. A "/mask" must be given and given in CIDR +notation (/0-/32) so to specify host 192.2.2.1, 192.2.2.1/32 must be given. +.TP +dstport <portnumber> +This option is used to match against the destination port in log entries. +A number must be given, symbolic names (such as those from /etc/services) +are not recognised by the parser. +.TP +every <second|# seconds|packet|# packets> +This option is used to regulate how often an \fBipmon.conf\fR entry is +actioned in response to an otherwise matching log record from the kernel. +.TP +group <name|number> +.TP +interface <interface-name> +This option is used to match against the network interface name associated +with the action causing the logging to happen. In general this will be the +network interface where the packet is seen by IPFilter. +.TP +logtag <number> +This option is used to match against tags set by ipf rules in \fBipf.conf\fR. +These tags are set with "set-tag(log=100)" appended to filter rules. +.TP +nattag <string> +This option is used to match against tags set by NAT rules in \fBipnat.conf\fR. +.TP +protocol <name|number> +This option is used to match against the IP protocol field in the packet +being logged. +.TP +result <pass|block|nomatch|log> +This option is used to match against the result of packet matching in the +kernel. If a packet is logged, using a \fBlog\fR rule in \fBipf.conf\fR +then it will match "log" here. The "nomatch" option is for use with +matching log records generated for all packets as the default. +.TP +rule <number> +This option is used to match against the \fInumber\fR of the rule +causing the record to be generated. The \fInumber\fR of a rule can be +observed using "ipfstat -ion". +.TP +srcip <address/mask> +This option is used to match against the source address associated +with the packet being logged. A "/mask" must be given and given in CIDR +notation (/0-/32) so to specify host 192.2.2.1, 192.2.2.1/32 must be given. +.TP +srcport <portnumber> +This option is used to match against the source port in log entries. +A number must be given, symbolic names (such as those from /etc/services) +are not recognised by the parser. +.TP +type <ipf|nat|state> +The format for files accepted by ipmon is described by the following grammar: +.B NOTE: +At present, only IPv4 matching is available for source/destination address +matching. +.SH SYNTAX - ACTIONS +The list of actions supported is as follows: +.TP +save("file://<filename>") +save("raw://<filename>") +Write out the log record to the filename given. This file will be closed +and reopened on receipt of a SIGHUP. If the \fIraw\fP target is used, +binary log data, as read from the kernel, is written out rather than a +text log record. The filename should be an absolute target, including +the root directory. Thus, saving to /var/log/ipmon.log would be, as an +example, save("file:///var/log/ipmon.log"). +.TP +syslog("<facility>.<priority>") +syslog("<facility>.") +syslog(".<priority>") +To log a text record via syslog, the \fBsyslog\fP action word is used. +The facility used by default is determined at first by the default +compiled into \fBipmon\fP (usually LOG_LOCAL0), which can be changed +via the command line (-L <facility>) or in an \fBipf.conf\fP rule +using the \fIlevel\fP option with logging. If the facility is +specified here, it takes precedence over all other settings. +The same applies to the syslog priority. By default, ipmon will +determine a priority for the packet, depending on whether or not it +has been blocked, passed, etc. It is possible to force the complete +facility/priority value for each log entry or to choose to replace +only one of them. +.TP +execute("<command string>") +The +.B execute +action runs the specified command each time the log entry matches +and feeds the log entry, as text, to the command being executed. +The command string given is executed using /bin/sh. +.TP +nothing +Literally, do nothing. Use this if you want to be verbose in your config +file about doing nothing for a particular log record. +.SH PLUGIN ACTIONS +It is possible to configure +.B ipmon +to use externally supplied modules to save log entries with. +These are added to +.B ipmon +using the +.I load_action +configuration line. The syntax of this line is: +.nf + +load_action <name> <path>; +.fi +.TP +name +is a short name for the action. It does not need to correspond to the +name of the library file, but inside the library file, the functions +.B <name>destroy +, +.B <name>parse +and +.B <name>store +must be present. +.TP +path +specifies the path in the filesystem to the shared object +that contains the implementation of the new action. After the new +action has been declared using +.I load_action +it can then be used in any +.I do +statement. +.SH EXAMPLES +.PP +Some further examples are: +.nf + +# +# log everything to syslog local4, regardless +# +match { ; } do { syslog("local4."); }; +# +# keep a local copy of things packets to/from port 80 +# +match { srcport = 80; } do { save("file:///var/log/web"); }; +match { dstport = 80; } do { save("file:///var/log/web"); }; +# +load_action local "/usr/lib/libmyaction.so"; +match { dstip 127.0.0.1; } do { local("local options"); }; +# +.fi +.SH MATCHING +.PP +All entries of the rules present in the file are +compared for matches - there is no first or last rule match. +.SH FILES +/dev/ipl +.br +/dev/ipf +.br +/dev/ipnat +.br +/dev/ipstate +.br +/etc/ipmon.conf +.SH SEE ALSO +ipmon(8), ipl(4) diff --git a/contrib/ipfilter/man/ipmon.8 b/contrib/ipfilter/man/ipmon.8 new file mode 100644 index 0000000..126f4a7 --- /dev/null +++ b/contrib/ipfilter/man/ipmon.8 @@ -0,0 +1,186 @@ +.\" $FreeBSD$ +.TH ipmon 8 +.SH NAME +ipmon \- monitors /dev/ipl for logged packets +.SH SYNOPSIS +.B ipmon +[ +.B \-abBDFhnpstvxX +] [ +.B "\-N <device>" +] [ +.B "\-L <facility>" +] [ +.B "\-o [NSI]" +] [ +.B "\-O [NSI]" +] [ +.B "\-P <pidfile>" +] [ +.B "\-S <device>" +] [ +.B "\-f <device>" +] [ +.B <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 +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. +.LP +Messages generated by ipmon consist of whitespace separated fields. +Fields common to all messages are: +.LP +1. The date of packet receipt. This is suppressed when the message is +sent to syslog. +.LP +2. The time of packet receipt. This is in the form HH:MM:SS.F, for hours, +minutes seconds, and fractions of a second (which can be several digits +long). +.LP +3. The name of the interface the packet was processed on, e.g., \fBwe1\fP. +.LP +4. The group and rule number of the rule, e.g., \fB@0:17\fP. These can be +viewed with \fBipfstat -n\fP. +.LP +5. The action: \fBp\fP for passed, \fBb\fP for blocked, \fB\fP for a short +packet, \fBn\fP did not match any rules or \fBL\fP for a log rule. +.LP +6. The addresses. +This is actually three fields: the source address and port +(separated by a comma), the \fB->\fP symbol, and the destination address +and port. E.g.: \fB209.53.17.22,80 -> 198.73.220.17,1722\fP. +.LP +7. \fBPR\fP followed by the protocol name or number, e.g., \fBPR tcp\fP. +.LP +8. \fBlen\fP followed by the header length and total length of the packet, +e.g., \fBlen 20 40\fP. +.LP +If the packet is a TCP packet, there will be an additional field starting +with a hyphen followed by letters corresponding to any flags that were set. +See the ipf.conf manual page for a list of letters and their flags. +.LP +If the packet is an ICMP packet, there will be two fields at the end, +the first always being `icmp', and the next being the ICMP message and +submessage type, separated by a slash, e.g., \fBicmp 3/3\fP for a port +unreachable message. +.LP +In order for \fBipmon\fP to properly work, the kernel option +\fBIPFILTER_LOG\fP must be turned on in your kernel. Please see +\fBoptions(4)\fP for more details. +.LP +\fBipmon\fP reopens its log file(s) and rereads its configuration file +when it receives a SIGHUP signal. +.SH OPTIONS +.TP +.B \-a +Open all of the device logfiles for reading log entries from. All entries +are displayed to the same output 'device' (stderr or syslog). +.TP +.B \-b +For rules which log the body of a packet, generate hex output representing +the packet contents after the headers. +.TP +.B \-B <binarylogfilename> +Enable logging of the raw, unformatted binary data to the specified +\fI<binarylogfilename>\fP file. This can be read, later, using \fBipmon\fP +with the \fB-f\fP option. +.TP +.B \-D +Cause ipmon to turn itself into a daemon. Using subshells or backgrounding +of ipmon is not required to turn it into an orphan so it can run indefinitely. +.TP +.B "\-f <device>" +specify an alternative device/file from which to read the log information +for normal IP Filter log records. +.TP +.B \-F +Flush the current packet log buffer. The number of bytes flushed is displayed, +even should the result be zero. +.TP +.B \-L <facility> +Using this option allows you to change the default syslog facility that +ipmon uses for syslog messages. The default is local0. +.TP +.B \-n +IP addresses and port numbers will be mapped, where possible, back into +hostnames and service names. +.TP +.B "\-N <device>" +Set the logfile to be opened for reading NAT log records from to <device>. +.TP +.B \-o +Specify which log files to actually read data from. N - NAT logfile, +S - State logfile, I - normal IP Filter logfile. The \fB-a\fP option is +equivalent to using \fB-o NSI\fP. +.TP +.B \-O +Specify which log files you do not wish to read from. This is most sensibly +used with the \fB-a\fP. Letters available as parameters to this are the same +as for \fB-o\fP. +.TP +.B \-p +Cause the port number in log messages to always be printed as a number and +never attempt to look it up as from \fI/etc/services\fP, etc. +.TP +.B \-P <pidfile> +Write the pid of the ipmon process to a file. By default this is +\fI//etc/opt/ipf/ipmon.pid\fP (Solaris), \fI/var/run/ipmon.pid\fP (44BSD +or later) or \fI/etc/ipmon.pid\fP for all others. +.TP +.B \-s +Packet information read in will be sent through syslogd rather than +saved to a file. The default facility when compiled and installed is +\fBsecurity\fP. The following levels are used: +.IP +.B LOG_INFO +\- packets logged using the "log" keyword as the action rather +than pass or block. +.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". +.TP +.B "\-S <device>" +Set the logfile to be opened for reading state log records from to <device>. +.TP +.B \-t +read the input file/device in a manner akin to tail(1). +.TP +.B \-v +show tcp window, ack and sequence fields. +.TP +.B \-x +show the packet data in hex. +.TP +.B \-X +show the log header record data in hex. +.SH DIAGNOSTICS +\fBipmon\fP expects data that it reads to be consistent with how it should be +saved and will abort if it fails an assertion which detects an anomaly in the +recorded data. +.SH FILES +/dev/ipl +.br +/dev/ipnat +.br +/dev/ipstate +.br +/etc/services +.SH SEE ALSO +ipl(4), ipf(8), ipfstat(8), ipnat(8) +.SH BUGS +.PP +If you find any, please send email to me at darrenr@pobox.com diff --git a/contrib/ipfilter/man/ipnat.1 b/contrib/ipfilter/man/ipnat.1 new file mode 100644 index 0000000..f241415 --- /dev/null +++ b/contrib/ipfilter/man/ipnat.1 @@ -0,0 +1,48 @@ +.TH IPNAT 1 +.SH NAME +ipnat \- user interface to the NAT +.SH SYNOPSIS +.B ipnat +[ +.B \-lnrsvCF +] +.B \-f <\fIfilename\fP> +.SH DESCRIPTION +.PP +\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 +is added to the kernels 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 \fBipnat\fP. +.SH OPTIONS +.TP +.B \-C +delete all entries in the current NAT rule listing (NAT rules) +.TP +.B \-F +delete all active entries in the current NAT translation table (currently +active NAT mappings) +.TP +.B \-l +Show the list of current NAT table entry mappings. +.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. +.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 +and active rules/table entries. +.DT +.SH FILES +/dev/ipnat +.SH SEE ALSO +ipnat(5), ipf(8), ipfstat(8) diff --git a/contrib/ipfilter/man/ipnat.4 b/contrib/ipfilter/man/ipnat.4 new file mode 100644 index 0000000..80c5ba4 --- /dev/null +++ b/contrib/ipfilter/man/ipnat.4 @@ -0,0 +1,97 @@ +.\" $FreeBSD$ +.TH IPNAT 4 +.SH NAME +ipnat \- Network Address Translation kernel interface +.SH SYNOPSIS +#include <netinet/ip_compat.h> +.br +#include <netinet/ip_fil.h> +.br +#include <netinet/ip_proxy.h> +.br +#include <netinet/ip_nat.h> +.SH IOCTLS +.PP +To add and delete rules to the NAT list, two 'basic' ioctls are provided +for use. The ioctl's are called as: +.LP +.nf + ioctl(fd, SIOCADNAT, struct ipnat **) + ioctl(fd, SIOCRMNAT, struct ipnat **) + ioctl(fd, SIOCGNATS, struct natstat **) + ioctl(fd, SIOCGNATL, struct natlookup **) +.fi +.PP +Unlike \fBipf(4)\fP, there is only a single list supported by the kernel NAT +interface. An inactive list which can be swapped to is not currently +supported. + +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 +(i.e., /dev/ipl). +.PP +The structure used with the NAT interface is described below: +.LP +.nf +typedef struct ipnat { + struct ipnat *in_next; + void *in_ifp; + u_short in_flags; + u_short in_pnext; + 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 in_pmin in_port[0] /* Also holds static redir port */ +#define in_pmax in_port[1] +#define in_nip in_nextip.s_addr +#define in_inip in_in[0].s_addr +#define in_inmsk in_in[1].s_addr +#define in_outip in_out[0].s_addr +#define in_outmsk in_out[1].s_addr + +.fi +.PP +Recognised values for in_redir: +.LP +.nf +#define NAT_MAP 0 +#define NAT_REDIRECT 1 +.fi +.LP +\fBNAT statistics\fP +Statistics on the number of packets mapped, going in and out are kept, +the number of times a new entry is added and deleted (through expiration) to +the NAT table and the current usage level of the NAT table. +.PP +Pointers to the NAT table inside the kernel, as well as to the top of the +internal NAT lists constructed with the \fBSIOCADNAT\fP ioctls. The table +itself is a hash table of size NAT_SIZE (default size is 367). +.PP +To retrieve the statistics, the \fBSIOCGNATS\fP ioctl must be used, with +the appropriate structure passed by reference, as follows: +.nf + ioctl(fd, SIOCGNATS, struct natstat *) + +typedef struct natstat { + u_long ns_mapped[2]; + u_long ns_added; + u_long ns_expire; + u_long ns_inuse; + nat_t ***ns_table; + ipnat_t *ns_list; +} natstat_t; +.fi +.SH BUGS +It would be nice if there were more flexibility when adding and deleting +filter rules. +.SH FILES +/dev/ipnat +.SH SEE ALSO +ipf(4), ipnat(5), ipf(8), ipnat(8), ipfstat(8) diff --git a/contrib/ipfilter/man/ipnat.5 b/contrib/ipfilter/man/ipnat.5 new file mode 100644 index 0000000..69163fc --- /dev/null +++ b/contrib/ipfilter/man/ipnat.5 @@ -0,0 +1,728 @@ +.\" $FreeBSD$ +.\" +.TH IPNAT 5 +.SH NAME +ipnat, ipnat.conf \- IPFilter NAT file format +.SH DESCRIPTION +.PP +The +.B ipnat.conf +file is used to specify rules for the Network Address Translation (NAT) +component of IPFilter. To load rules specified in the +.B ipnat.conf +file, the +.B ipnat(8) +program is used. +.PP +For standard NAT functionality, a rule should start with \fBmap\fP and then +proceeds to specify the interface for which outgoing packets will have their +source address rewritten. Following this it is expected that the old source +address, and optionally port number, will be specified. +.PP +In general, all NAT rules conform to the following layout: +the first word indicates what type of NAT rule is present, this is followed +by some stanzas to match a packet, followed by a "->" and this is then +followed by several more stanzas describing the new data to be put in the +packet. +.PP +In this text and in others, +use of the term "left hand side" (LHS) when talking about a NAT rule refers +to text that appears before the "->" and the "right hand side" (RHS) for text +that appears after it. In essence, the LHS is the packet matching and the +RHS is the new data to be used. +.SH VARIABLES +.PP +This configuration file, like all others used with IPFilter, supports the +use of variable substitution throughout the text. +.nf + +nif="ppp0"; +map $nif 0/0 -> 0/32 +.fi +.PP +would become +.nf + +map ppp0 0/0 -> 0/32 +.fi +.PP +Variables can be used recursively, such as 'foo="$bar baz";', so long as +$bar exists when the parser reaches the assignment for foo. +.PP +See +.B ipnat(8) +for instructions on how to define variables to be used from a shell +environment. +.SH OUTBOUND SOURCE TRANSLATION (map'ing) +Changing the source address of a packet is traditionally performed using +.B map +rules. Both the source address and optionally port number can be changed +according to various controls. +.PP +To start out with, a common rule used is of the form: +.nf + +map le0 0/0 -> 0/32 +.fi +.PP +Here we're saying change the source address of all packets going out of +le0 (the address/mask pair of 0/0 matching all packets) to that of the +interface le0 (0/32 is a synonym for the interface's own address at +the current point in time.) If we wanted to pass the packet through +with no change in address, we would write it as: +.nf + +map le0 0/0 -> 0/0 +.fi +.PP +If we only want to change a portion of our internal network and to a +different address that is routed back through this host, we might do: +.nf + +map le0 10.1.1.0/24 -> 192.168.55.3/32 +.fi +.PP +In some instances, we may have an entire subnet to map internal addresses +out onto, in which case we can express the translation as this: +.nf + +map le0 10.0.0.0/8 -> 192.168.55.0/24 +.fi +.PP +IPFilter will cycle through each of the 256 addresses in the 192.168.55.0/24 +address space to ensure that they all get used. +.PP +Of course this poses a problem for TCP and UDP, with many connections made, +each with its own port number pair. If we're unlucky, translations can be +dropped because the new address/port pair mapping already exists. To +mitigate this problem, we add in port translation or port mapping: +.nf + +map le0 10.0.0.0/8 -> 192.168.55.0/24 portmap tcp/udp auto +.fi +.PP +In this instance, the word "auto" tells IPFilter to calculate a private +range of port numbers for each address on the LHS to use without fear +of them being trampled by others. This can lead to problems if there are +connections being generated mire quickly than IPFilter can expire them. +In this instance, and if we want to get away from a private range of +port numbers, we can say: +.nf + +map le0 10.0.0.0/8 -> 192.168.55.0/24 portmap tcp/udp 5000:65000 +.fi +.PP +And now each connection through le0 will add to the enumeration of +the port number space 5000-65000 as well as the IP address subnet +of 192.168.55.0/24. +.PP +If the new addresses to be used are in a consecutive range, rather +than a complete subnet, we can express this as: +.nf + +map le0 10.0.0.0/8 -> range 192.168.55.10-192.168.55.249 + portmap tcp/udp 5000:65000 +.fi +.PP +This tells IPFilter that it has a range of 240 IP address to use, from +192.168.55.10 to 192.168.55.249, inclusive. +.PP +If there were several ranges of addresses for use, we can use each one +in a round-robin fashion as followed: +.nf + +map le0 10.0.0.0/8 -> range 192.168.55.10-192.168.55.29 + portmap tcp/udp 5000:65000 round-robin +map le0 10.0.0.0/8 -> range 192.168.55.40-192.168.55.49 + portmap tcp/udp 5000:65000 round-robin +.fi +.PP +To specify translation rules that impact a specific IP protocol, +the protocol name or number is appended to the rule like this: +.nf + +map le0 10.0.0.0/8 -> 192.168.55.0/24 tcp/udp +map le0 10.0.0.0/8 -> 192.168.55.1/32 icmp +map le0 10.0.0.0/8 -> 192.168.55.2/32 gre +.fi +.PP +For TCP connections exiting a connection such as PPPoE where the MTU is +slightly smaller than normal ethernet, it can be useful to reduce the +Maximum Segment Size (MSS) offered by the internal machines to match, +reducing the liklihood that the either end will attempt to send packets +that are too big and result in fragmentation. This is acheived using the +.B mssclamp +option with TCP +.B map +rules like this: +.nf + +map pppoe0 0/0 -> 0/32 mssclamp 1400 tcp +.fi +.PP +For ICMP packets, we can map the ICMP id space in query packets: +.nf + +map le0 10.0.0.0/8 -> 192.168.55.1/32 icmpidmap icmp 1000:20000 +.fi +.PP +If we wish to be more specific about our initial matching criteria on the +LHS, we can expand to using a syntax more similar to that in +.B ipf.conf(5) +: +.nf + +map le0 from 10.0.0.0/8 to 26.0.0.0/8 -> + 192.168.55.1 +map le0 from 10.0.0.0/8 port > 1024 to 26.0.0.0/8 -> + 192.168.55.2 portmap 5000:9999 tcp/udp +map le0 from 10.0.0.0/8 ! to 26.0.0.0/8 -> + 192.168.55.3 portmap 5000:9999 tcp/udp +.fi +.TP +.B NOTE: +negation matching with source addresses is +.B NOT +possible with +.B map +/ +.B map-block +rules. +.PP +The NAT code has builtin default timeouts for TCP, UDP, ICMP and another +for all other protocols. In general, the timeout for an entry to be +deleted shrinks once a reply packet has been seen (excluding TCP.) +If you wish to specify your own timeouts, this can be achieved either +by setting one timeout for both directions: +.nf + +map le0 0/0 -> 0/32 gre age 30 +.fi +.PP +or setting a different timeout for the reply: +.nf + +map le0 from any to any port = 53 -> 0/32 age 60/10 udp +.fi +.PP +A pressing problem that many people encounter when using NAT is that the +address protocol can be embedded inside an application's communication. +To address this problem, IPFilter provides a number of built-in proxies +for the more common trouble makers, such as FTP. These proxies can be +used as follows: +.nf + +map le0 0/0 -> 0/32 proxy port 21 ftp/tcp +.fi +.PP +In this rule, the word "proxy" tells us that we want to connect up this +translation with an internal proxy. The "port 21" is an extra restriction +that requires the destination port number to be 21 if this rule is to be +activated. The word "ftp" is the proxy identifier that the kernel will +try and resolve internally, "tcp" the protocol that packets must match. +.PP +See below for a list of proxies and their relative staus. +.PP +To associate NAT rules with filtering rules, it is possible to set and +match tags during either inbound or outbound processing. At present the +tags for forwarded packets are not preserved by forwarding, so once the +packet leaves IPFilter, the tag is forgotten. For +.B map +rules, we can match tags set by filter rules like this: +.nf + +map le0 0/0 -> 0/32 proxy portmap 5000:5999 tag lan1 tcp +.fi +.PP +This would be used with "pass out" rules that includes a stanza such +as "set-tag (nat = lan1)". +.PP +If the interface in which packets are received is different from the +interface on which packets are sent out, then the translation rule needs +to be written to take this into account: +.nf + +map hme0,le0 0/0 -> 0/32 +.fi +.PP +Although this might seem counterintuitive, the interfaces when listed +in rules for +.B ipnat.conf +are always in the +.I inbound +, +.I outbound +order. In this case, hme0 would be the return interface and le0 would be +the outgoing interface. If you wish to allow return packets on any +interface, the correct syntax to use would be: +.nf + +map *,le0 0/0 -> 0/32 +.fi +.LP +A special variant of +.B map +rules exists, called +.B map-block. +This command is intended for use when there is a large network to be mapped +onto a smaller network, where the difference in netmasks is upto 14 bits +difference in size. This is achieved by dividing the address space and +port space up to ensure that each source address has its own private range +of ports to use. For example, this rule: +.nf + +map-block ppp0 172.192.0.0/16 -> 209.1.2.0/24 ports auto +.fi +.PP +would result in 172.192.0.0/24 being mapped to 209.1.2.0/32 +with each address, from 172.192.0.0 to 172.192.0.255 having 252 ports of its +own. As opposed to the above use of \fBmap\fP, if for some reason the user +of (say) 172.192.0.2 wanted 260 simultaneous connections going out, they would +be limited to 252 with \fBmap-block\fP but would just \fImove on\fP to the next +IP address with the \fBmap\fP command. +.SS Extended matching +.PP +If it is desirable to match on both the source and destination of a packet +before applying an address translation to it, this can be achieved by using +the same from-to syntax as is used in \fBipf.conf\fP(5). What follows +applies equally to the +.B map +rules discussed above and +.B rdr +rules discussed below. A simple example is as follows: +.nf + +map bge0 from 10.1.0.0/16 to 192.168.1.0/24 -> 172.12.1.4 +.fi +.PP +This would only match packets that are coming from hosts that have a source +address matching 10.1.0.0/16 and a destination matching 192.168.1.0/24. +This can be expanded upon with ports for TCP like this: +.nf + +rdr bge0 from 10.1.0.0/16 to any port = 25 -> 127.0.0.1 port 2501 tcp +.fi +.PP +Where only TCP packets from 10.1.0.0/16 to port 25 will be redirected to +port 2501. +.PP +As with \fBipf.conf\fR(5), if we have a large set of networks or addresses +that we would like to match up with then we can define a pool using +\fBippool\fR(8) in \fBippool.conf\fR(5) and then refer to it in an +\fBipnat\fR rule like this: +.nf + +map bge0 from pool/100 to any port = 25 -> 127.0.0.1 port 2501 tcp +.fi +.TP +.B NOTE: +In this situation, the rule is considered to have a netmask of "0" and +thus is looked at last, after any rules with /16's or /24's in them, +.I even if +the defined pool only has /24's or /32's. Pools may also be used +.I wherever +the from-to syntax in \fBipnat.conf\fR(5) is allowed. +.SH INBOUND DESTINATION TRANSLATION (redirection) +.PP +Redirection of packets is used to change the destination fields in a packet +and is supported for packets that are moving \fIin\fP on a network interface. +While the same general syntax for +.B map +rules is supported, there are differences and limitations. +.PP +Firstly, by default all redirection rules target a single IP address, not +a network or range of network addresses, so a rule written like this: +.nf + +rdr le0 0/0 -> 192.168.1.0 +.fi +.PP +Will not spread packets across all 256 IP addresses in that class C network. +If you were to try a rule like this: +.nf + +rdr le0 0/0 -> 192.168.1.0/24 +.fi +.PP +then you will receive a parsing error. +.PP +The from-to source-destination matching used with +.B map +rules can be used with rdr rules, along with negation, however the +restriction moves - only a source address match can be negated: +.nf + +rdr le0 from 1.1.0.0/16 to any -> 192.168.1.3 +rdr le0 ! from 1.1.0.0/16 to any -> 192.168.1.4 +.fi +.PP +If there is a consective set of addresses you wish to spread the packets +over, then this can be done in one of two ways, the word "range" optional +to preserve: +.nf + +rdr le0 0/0 -> 192.168.1.1 - 192.168.1.5 +rdr le0 0/0 -> range 192.168.1.1 - 192.168.1.5 +.fi +.PP +If there are only two addresses to split the packets across, the +recommended method is to use a comma (",") like this: +.nf + +rdr le0 0/0 -> 192.168.1.1,192.168.1.2 +.fi +.PP +If there is a large group of destination addresses that are somewhat +disjoint in nature, we can cycle through them using a +.B round-robin +technique like this: +.nf + +rdr le0 0/0 -> 192.168.1.1,192.168.1.2 round-robin +rdr le0 0/0 -> 192.168.1.5,192.168.1.7 round-robin +rdr le0 0/0 -> 192.168.1.9 round-robin +.fi +.PP +If there are a large number of redirect rules and hosts being targetted +then it may be desirable to have all those from a single source address +be targetted at the same destination address. To achieve this, the +word +.B sticky +is appended to the rule like this: +.nf + +rdr le0 0/0 -> 192.168.1.1,192.168.1.2 sticky +rdr le0 0/0 -> 192.168.1.5,192.168.1.7 round-robin sticky +rdr le0 0/0 -> 192.168.1.9 round-robin sticky +.fi +.PP +The +.B sticky +feature can only be combined with +.B round-robin +and the use of comma. +.PP +For TCP and UDP packets, it is possible to both match on the destiantion +port number and to modify it. For example, to change the destination port +from 80 to 3128, we would use a rule like this: +.nf + +rdr de0 0/0 port 80 -> 127.0.0.1 port 3128 tcp +.fi +.PP +If a range of ports is given on the LHS and a single port is given on the +RHS, the entire range of ports is moved. For example, if we had this: +.nf + +rdr le0 0/0 port 80-88 -> 127.0.0.1 port 3128 tcp +.fi +.PP +then port 80 would become 3128, port 81 would become 3129, etc. If we +want to redirect a number of different pots to just a single port, an +equals sign ("=") is placed before the port number on the RHS like this: +.nf + +rdr le0 0/0 port 80-88 -> 127.0.0.1 port = 3128 tcp +.fi +.PP +In this case, port 80 goes to 3128, port 81 to 3128, etc. +.PP +As with +.B map +rules, it is possible to manually set a timeout using the +.B age +option, like this: +.nf + +rdr le0 0/0 port 53 -> 127.0.0.1 port 10053 udp age 5/5 +.fi +.PP +The use of proxies is not restricted to +.B map +rules and outbound sessions. Proxies can also be used with redirect +rules, although the syntax is slightly different: +.nf + +rdr ge0 0/0 port 21 -> 127.0.0.1 port 21 tcp proxy ftp +.fi +.PP +For +.B rdr +rules, the interfaces supplied are in the same order as +.B map +rules - input first, then output. In situations where the outgoing interface +is not certain, it is also possible to use a wildcard ("*") to effect a match +on any interface. +.nf + +rdr le0,* 0/0 -> 192.168.1.0 +.fi +.PP +A single rule, with as many options set as possible would look something like +this: +.nf + +rdr le0,ppp0 9.8.7.6/32 port 80 -> 1.1.1.1,1.1.1.2 port 80 tcp + round-robin frag age 40/40 sticky mssclamp 1000 tag tagged +.fi +.SH REWRITING SOURCE AND DESTINATION +.PP +Whilst the above two commands provide a lot of flexibility in changing +addressing fields in packets, often it can be of benefit to translate +\fIboth\fP source \fBand\fR destination at the same time or to change +the source address on input or the destination address on output. +Doing all of these things can be accomplished using +.B rewrite +NAT rules. +.PP +A +.B rewrite +rule requires the same level of packet matching as before, protocol and +source/destination information but in addition allows either +.B in +or +.B out +to be specified like this: +.nf + +rewrite in on ppp0 proto tcp from any to any port = 80 -> + src 0/0 dst 127.0.0.1,3128; +rewrite out on ppp0 from any to any -> + src 0/32 dst 10.1.1.0/24; +.fi +.PP +On the RHS we can specify both new source and destination information to place +into the packet being sent out. As with other rules used in +\fBipnat.conf\fR, there are shortcuts syntaxes available to use the original +address information (\fB0/0\fR) and the address associated with the network +interface (\fB0/32\fR.) For TCP and UDP, both address and port information +can be changed. At present it is only possible to specify either a range of +port numbers to be used (\fBX-Y\fR) or a single port number (\fB= X\fR) as +follows: +.nf + +rewrite in on le0 proto tcp from any to any port = 80 -> + src 0/0,2000-20000 dst 127.0.0.1,port = 3128; +.fi +.PP +There are four fields that are stepped through in enumerating the number +space available for creating a new destination: +.LP +source address +.LP +source port +.LP +destination address +.LP +destination port +.PP +If one of these happens to be a static then it will be skipped and the next +one incremented. As an example: +.nf + +rewrite out on le0 proto tcp from any to any port = 80 -> + src 1.0.0.0/8,5000-5999 dst 2.0.0.0/24,6000-6999; +.fi +.PP +The translated packets would be: +.LP +1st src=1.0.0.1,5000 dst=2.0.0.1,6000 +.LP +2nd src=1.0.0.2,5000 dst=2.0.0.1,6000 +.LP +3rd src=1.0.0.2,5001 dst=2.0.0.1,6000 +.LP +4th src=1.0.0.2,5001 dst=2.0.0.2,6000 +.LP +5th src=1.0.0.2,5001 dst=2.0.0.2,6001 +.LP +6th src=1.0.0.3,5001 dst=2.0.0.2,6001 +.PP +and so on. +.PP +As with +.B map +rules, it is possible to specify a range of addresses by including the word +\fIrange\fR before the addresses: +.nf + +rewrite from any to any port = 80 -> + src 1.1.2.3 - 1.1.2.6 dst 2.2.3.4 - 2.2.3.6; +.fi +.SH DIVERTING PACKETS +.PP +If you'd like to send packets to a UDP socket rather than just another +computer to be decapsulated, this can be achieved using a +.B divert +rule. +.PP +Divert rules can be be used with both inbound and outbound packet +matching however the rule +.B must +specify host addresses for the outer packet, not ranges of addresses +or netmasks, just single addresses. +Additionally the syntax must supply required information for UDP. +An example of what a divert rule looks ike is as follows: +.nf + +divert in on le0 proto udp from any to any port = 53 -> + src 192.1.1.1,54 dst 192.168.1.22.1,5300; +.fi +.PP +On the LHS is a normal set of matching capabilities but on the RHS it is +a requirement to specify both the source and destination addresses and +ports. +.PP +As this feature is intended to be used with targetting packets at sockets +and not IPFilter running on other systems, there is no rule provided to +\fIundivert\fR packets. +.TP +.B NOTE: +Diverted packets \fImay\fP be fragmented if the addition of the +encapsulating IP header plus UDP header causes the packet to exceed +the size allowed by the outbound network interface. At present it is +not possible to cause Path MTU discovery to happen as this feature +is intended to be transparent to both endpoints. +.B Path MTU Discovery +If Path MTU discovery is being used and the "do not fragment" flag +is set in packets to be encapsulated, an ICMP error message will +be sent back to the sender if the new packet would need to be +fragmented. +.SH COMMON OPTIONS +This section deals with options that are available with all rules. +.TP +.B purge +When the purge keyword is added to the end of a NAT rule, it will +cause all of the active NAT sessions to be removed when the rule +is removed as an individual operation. If all of the NAT rules +are flushed out, it is expected that the operator will similarly +flush the NAT table and thus NAT sessions are not removed when the +NAT rules are flushed out. +.SH RULE ORDERING +.PP +.B NOTE: +Rules in +.B ipnat.conf +are read in sequentially as listed and loaded into the kernel in this +fashion +.B BUT +packet matching is done on \fBnetmask\fR, going from 32 down to 0. +If a rule uses +.B pool +or +.B hash +to reference a set of addresses or networks, the netmask value for +these fields is considered to be "0". +So if your +.B ipnat.conf +has the following rules: +.nf + +rdr le0 192.0.0.0/8 port 80 -> 127.0.0.1 3132 tcp +rdr le0 192.2.0.0/16 port 80 -> 127.0.0.1 3131 tcp +rdr le0 from any to pool/100 port 80 -> 127.0.0.1 port 3130 tcp +rdr le0 192.2.2.0/24 port 80 -> 127.0.0.1 3129 tcp +rdr le0 192.2.2.1 port 80 -> 127.0.0.1 3128 tcp +.fi +.PP +then the rule with 192.2.2.1 will match \fBfirst\fR, regardless of where +it appears in the ordering of the above rules. In fact, the order in +which they would be used to match a packet is: +.nf + +rdr le0 192.2.2.1 port 80 -> 127.0.0.1 3128 tcp +rdr le0 192.2.2.0/24 port 80 -> 127.0.0.1 3129 tcp +rdr le0 192.2.0.0/16 port 80 -> 127.0.0.1 3131 tcp +rdr le0 192.0.0.0/8 port 80 -> 127.0.0.1 3132 tcp +rdr le0 from any to pool/100 port 80 -> 127.0.0.1 port 3130 tcp +.fi +.PP +where the first line is actually a /32. +.PP +If your +.B ipnat.conf +file has entries with matching target fields (source address for +.B map +rules and destination address for +.B rdr +rules), then the ordering in the +.B ipnat.conf +file does matter. So if you had the following: +.nf + +rdr le0 from 1.1.0.0/16 to 192.2.2.1 port 80 -> 127.0.0.1 3129 tcp +rdr le0 from 1.1.1.0/24 to 192.2.2.1 port 80 -> 127.0.0.1 3128 tcp +.fi +.PP +Then no packets will match the 2nd rule, they'll all match the first. +.SH IPv6 +.PP +In all of the examples above, where an IPv4 address is present, an IPv6 +address can also be used. All rules must use either IPv4 addresses with +both halves of the NAT rule or IPv6 addresses for both halves. Mixing +IPv6 addresses with IPv4 addresses, in a single rule, will result in an +error. +.PP +For shorthand notations such as "0/32", the equivalent for IPv6 is +"0/128". IPFilter will treat any netmask greater than 32 as an +implicit direction that the address should be IPv6, not IPv4. +To be unambiguous with 0/0, for IPv6 use ::0/0. +.SH KERNEL PROXIES +.PP +IP Filter comes with a few, simple, proxies built into the code that is loaded +into the kernel to allow secondary channels to be opened without forcing the +packets through a user program. The current state of the proxies is listed +below, as one of three states: +.HP +Aging - protocol is roughly understood from +the time at which the proxy was written but it is not well tested or +maintained; +.HP +Developmental - basic functionality exists, works most of the time but +may be problematic in extended real use; +.HP +Experimental - rough support for the protocol at best, may or may not +work as testing has been at best sporadic, possible large scale changes +to the code in order to properly support the protocol. +.HP +Mature - well tested, protocol is properly +understood by the proxy; +.PP +The currently compiled in proxy list is as follows: +.TP +FTP - Mature +(map ... proxy port ftp ftp/tcp) +.TP +IRC - Experimental +(proxy port 6667 irc/tcp) +.TP +rpcbind - Experimental +.TP +PPTP - Experimental +.TP +H.323 - Experimental +(map ... proxy port 1720 h323/tcp) +.TP +Real Audio (PNA) - Aging +.TP +DNS - Developmental +(map ... proxy port 53 dns/udp { block .cnn.com; }) +.TP +IPsec - Developmental +(map ... proxy port 500 ipsec/tcp) +.TP +netbios - Experimental +.TP +R-command - Mature +(map ... proxy port shell rcmd/tcp) +.SH KERNEL PROXIES +.SH FILES +/dev/ipnat +.br +/etc/protocols +.br +/etc/services +.br +/etc/hosts +.SH SEE ALSO +ipnat(4), hosts(5), ipf(5), services(5), ipf(8), ipnat(8) diff --git a/contrib/ipfilter/man/ipnat.8 b/contrib/ipfilter/man/ipnat.8 new file mode 100644 index 0000000..a49f337 --- /dev/null +++ b/contrib/ipfilter/man/ipnat.8 @@ -0,0 +1,76 @@ +.\" $FreeBSD$ +.\" +.TH IPNAT 8 +.SH NAME +ipnat \- user interface to the NAT subsystem +.SH SYNOPSIS +.B ipnat +[ +.B \-dhlnrsvCF +] +[ +.B \-M core +] +[ +.B \-N system +] +.B \-f <\fIfilename\fP> +.SH DESCRIPTION +.PP +\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 +is added to the kernels 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 \fBipnat\fP. +.PP +Note that if +\fBipf(8)\fP +is not enabled when NAT is configured, it will be enabled +automatically, as the same kernel facilities are used for +NAT functionality. In addition, packet forwarding must be +enabled. +.SH OPTIONS +.TP +.B \-C +delete all entries in the current NAT rule listing (NAT rules) +.TP +.B \-d +Enable printing of some extra debugging information. +.TP +.B \-F +delete all active entries in the current NAT translation table (currently +active NAT mappings) +.TP +.B \-h +Print number of hits for each MAP/Redirect filter. +.TP +.B \-l +Show the list of current NAT table entry mappings. +.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. +.TP +.B \-p +This flag is used with the \fB-r\fP flag to cause any active NAT +sessions that were created by the rules being removed and that are +currently active to also be removed. +.TP +.B \-r +Remove matching NAT rules rather than add them to the internal lists. +.TP +.B \-s +Retrieve and display NAT statistics. +.TP +.B \-v +Turn verbose mode on. Displays information relating to rule processing +and active rules/table entries. +.DT +.SH FILES +/dev/ipnat +.br +/usr/share/examples/ipfilter Directory with examples. +.SH SEE ALSO +ipnat(5), ipf(8), ipfstat(8) diff --git a/contrib/ipfilter/man/ippool.5 b/contrib/ipfilter/man/ippool.5 new file mode 100644 index 0000000..4de19a4 --- /dev/null +++ b/contrib/ipfilter/man/ippool.5 @@ -0,0 +1,320 @@ +.\" $FreeBSD$ +.\" +.TH IPPOOL 5 +.SH NAME +ippool, ippool.conf \- IP Pool file format +.SH DESCRIPTION +The file ippool.conf is used with ippool(8) to configure address pools for +use with ipnat(8) and ipf(8). +.PP +There are four different types of address pools that can be configured +through ippool.conf. The various types are presented below with a brief +description of how they are used: +.HP +dstlist +.IP +destination list - is a collection of IP addresses with an optional +network interface name that can be used with either redirect (rdr) rules +in ipnat.conf(5) or as the destination in ipf.conf(5) for policy based +routing. +.HP +group-map +.IP +group maps - support the srcgrpmap and dstgrpmap call functions in +ipf.conf(5) by providing a list of addresses or networks rule group +numbers to start processing them with. +.HP +hash +.IP +hash tables - provide the means for performing a very efficient +lookup address or network when there is expected to be only one +exact match. These are best used with more static sets of addresses +so they can be sized optimally. +.HP +pool +.IP +address pools - are an alternative to hash tables that can perform just +as well in most circumstances. In addition, the address pools allow for +heirarchical matching, so it is possible to define a subnet as matching +but then exclude specific addresses from it. +.SS +Evolving Configuration +.PP +Over time the configuration syntax used by ippool.conf(5) has evolved. +Originally the syntax used was more verbose about what a particular +value was being used for, for example: +.PP +.nf +table role = ipf type = tree number = 100 + { 1.1.1.1/32; !2.2.0.0/16; 2.2.2.0/24; ef00::5/128; }; +.fi +.PP +This is rather long winded. The evolution of the configuration syntax +has also replaced the use of numbers with names, although numbers can +still be used as can be seen here: +.PP +.nf +pool ipf/tree (name "100";) + { 1.1.1.1/32; !2.2.0.0/16; 2.2.2.0/24; ef00::5/128; }; +.fi +.PP +Both of the above examples produce the same configuration in the kernel +for use with ipf.conf(5). +.PP +Newer options for use in ippool.conf(5) will only be offered in the new +configuration syntax and all output using "ippool -l" will also be in the +new configuration syntax. +.SS +IPFilter devices and pools +.PP +To cater to different administration styles, ipool.conf(5) allows you to +tie a pool to a specific role in IPFilter. The recognised role names are: +.HP +ipf +.IP +pools defined for role "ipf" are available for use with all rules that are +found in ipf.conf(5) except for auth rules. +.HP +nat +.IP +pools defined for role "nat" are available for use with all rules that are +found in ipnat.conf(5). +.HP +auth +.IP +pools defined for role "auth" are available only for use with "auth" rules +that are found in ipf.conf(5) +.HP +all +.IP +pools that are defined for the "all" role are available to all types of +rules, be they NAT rules in ipnat.conf(5) or firewall rules in ipf.conf(5). +.SH Address Pools +.PP +An address pool can be used in ipf.conf(5) and ipnat.conf(5) for matching +the source or destination address of packets. They can be referred to either +by name or number and can hold an arbitrary number of address patterns to +match. +.PP +An address pool is considered to be a "tree type". In the older configuration +style, it was necessary to have "type=tree" in ippool.conf(5). In the new +style configuration, it follows the IPFilter device with which the pool +is being configured. +Now it is the default if left out. +.PP +For convenience, both IPv4 and IPv6 addresses can be stored in the same +address pool. It should go without saying that either type of packet can +only ever match an entry in a pool that is of the same address family. +.PP +The address pool searches the list of addresses configured for the best +match. The "best match" is considered to be the match that has the highest +number of bits set in the mask. Thus if both 2.2.0.0/16 and 2.2.2.0/24 are +present in an address pool, the addres 2.2.2.1 will match 2.2.2.0/24 and +2.2.1.1 will match 2.2.0.0/16. The reason for this is to allow exceptions +to be added through the use of negative matching. In the following example, +the pool contains "2.2.0.0/16" and "!2.2.2.0/24", meaning that all packets +that match 2.2.0.0/16, except those that match 2.2.2.0/24, will be considered +as a match for this pool. +.PP +table role = ipf type = tree number = 100 + { 1.1.1.1/32; 2.2.0.0/16; !2.2.2.0/24; ef00::5/128; }; +.PP +For the sake of clarity and to aid in managing large numbers of addresses +inside address pools, it is possible to specify a location to load the +addresses from. To do this simply use a "file://" URL where you would +specify an actual IP address. +.PP +.nf +pool ipf/tree (name rfc1918;) { file:///etc/ipf/rfc1918; }; +.fi +.PP +The contents of the file might look something like this: +.PP +.nf +# RFC 1918 networks +10.0.0.0/8 +!127.0.0.0/8 +172.16.0.0/12 +192.168.0.0/24 +.fi +.PP +In this example, the inclusion of the line "!127.0.0.0/8" is, strictly +speaking not correct and serves only as an example to show that negative +matching is also supported in this file. +.PP +Another format that ippool(8) recognises for input from a file is that +from whois servers. In the following example, output from a query to a +WHOIS server for information about which networks are associated with +the name "microsoft" has been saved in a file named "ms-networks". +There is no need to modify the output from the whois server, so using +either the whois command or dumping data directly from it over a TCP +connection works perfectly file as input. +.PP +.nf +pool ipf/tree (name microsoft;) { whois file "/etc/ipf/ms-networks"; }; +.fi +.PP +And to then block all packets to/from networks defined in that file, +a rule like this might be used: +.PP +.nf +block in from pool/microsoft to any +.fi +.PP +Note that there are limitations on the output returned by whois servers +so be aware that their output may not be 100% perfect for your goal. +.SH Destination Lists +.PP +Destination lists are provided for use primarily with NAT redirect rules +(rdr). Their purpose is to allow more sophisticated methods of selecting +which host to send traffic to next than the simple round-robin technique +that is present with with "round-robin" rules in ipnat.conf(5). +.PP +When building a list of hosts to use as a redirection list, it is +necessary to list each host to be used explicitly. Expressing a +collection of hosts as a range or a subnet is not supported. With each +address it is also possible to specify a network interface name. The +network interface name is ignored by NAT when using destination lists. +The network itnerface name is currently only used with policy based +routing (use of "to"/"dup-to" in ipf.conf(5)). +.PP +Unlike the other directives that can be expressed in this file, destination +lists must be written using the new configuration syntax. Each destination +list must have a name associated with it and a next hop selection policy. +Some policies have further options. The currently available selection +policies are: +.HP +round-robin +.IP +steps through the list of hosts configured with the destination list +one by one +.HP +random +.IP +the next hop is chosen by random selection from the list available +.HP +src-hash +.IP +a hash is made of the source address components of the packet +(address and port number) and this is used to select which +next hop address is used +.HP +dst-hash +.IP +a hash is made of the destination address components of the packet +(address and port number) and this is used to select which +next hop address is used +.HP +hash +.IP +a hash is made of all the address components in the packet +(addresses and port numbers) and this is used to select which +next hop address is used +.HP +weighted +.IP +selecting a weighted policy for destination selection needs further +clarification as to what type of weighted selection will be used. +The sub-options to a weighted policy are: +.RS +.HP +connection +.IP +the host that has received the least number of connections is selected +to be the next hop. When all hosts have the same connection count, +the last one used will be the next address selected. +.RE +.PP +The first example here shows 4 destinations that are used with a +round-robin selection policy. +.PP +.nf +pool nat/dstlist (name servers; policy round-robin;) + { 1.1.1.2; 1.1.1.4; 1.1.1.5; 1.1.1.9; }; +.fi +.PP +In the following example, the destination is chosen by whichever has +had the least number of connections. By placing the interface name +with each address and saying "all/dstlist", the destination list can +be used with both ipnat.conf(5) and ipf.conf(5). +.PP +.nf +pool all/dstlist (name servers; policy weighted connection;) + { bge0:1.1.1.2; bge0:1.1.1.4; bge1:1.1.1.5; bge1:1.1.1.9; }; +.fi +.SH Group maps +.PP +Group maps are provided to allow more efficient processing of packets +where there are a larger number of subnets and groups of rules for those +subnets. Group maps are used with "call" rules in ipf.conf(5) that +use the "srcgrpmap" and "dstgrpmap" functions. +.PP +A group map declaration must mention which group is the default group +for all matching addresses to be applied to. Then inside the list of +addresses and networks for the group, each one may optionally have +a group number associated with it. A simple example like this, where +the first two entries would map to group 2020 but 5.0.0.0/8 sends +rule processing to group 2040. +.PP +.nf +group-map out role = ipf number = 2010 group = 2020 + { 2.2.2.2/32; 4.4.0.0/16; 5.0.0.0/8, group = 2040; }; +.fi +.PP +An example that outlines the real purpose of group maps is below, +where each one of the 12 subnets is mapped to a different group +number. This might be because each subnet has its own policy and +rather than write a list of twelve rules in ipf.conf(5) that match +the subnet and branch off with a head statement, a single rule can +be used with this group map to achieve the same result. +.PP +.nf +group-map ( name "2010"; in; ) + { 192.168.1.0/24, group = 10010; 192.168.2.0/24, group = 10020; + 192.168.3.0/24, group = 10030; 192.168.4.0/24, group = 10040; + 192.168.5.0/24, group = 10050; 192.168.6.0/24, group = 10060; + 192.168.7.0/24, group = 10070; 192.168.8.0/24, group = 10080; + 192.168.9.0/24, group = 10090; 192.168.10.0/24, group = 10100; + 192.168.11.0/24, group = 10110; 192.168.12.0/24, group = 10120; + }; +.fi +.PP +The limitation with group maps is that only the source address or the +destination address can be used to map the packet to the starting group, +not both, in your ipf.conf(5) file. +.SH Hash Tables +.PP +The hash table is operationally similar to the address pool. It is +used as a store for a collection of address to match on, saving the +need to write a lengthy list of rules. As with address pools, searching +will attempt to find the best match - an address specification with the +largest contiguous netmask. +.PP +Hash tables are best used where the list of addresses, subnets and +networks is relatively static, which is something of a contrast to +the address pool that can work with either static or changing +address list sizes. +.PP +Further work is still needed to have IPFilter correctly size and tune +the hash table to optimise searching. The goal is to allow for small to +medium sized tables to achieve close to O(1) for either a positive or +negative match, in contrast to the address pool, which is O(logn). +.PP +The following two examples build the same table in the kernel, using +the old configuration format (first) and the new one (second). +.PP +.nf +table role=all type=hash name=servers size=5 + { 1.1.1.2/32; 1.1.1.3/32; 11.23.44.66/32; }; + +pool all/hash (name servers; size 5;) + { 1.1.1.2; 1.1.1.3; 11.23.44.66; }; +.fi +.SH FILES +/dev/iplookup +.br +/etc/ippool.conf +.br +/etc/hosts +.SH SEE ALSO +ippool(8), hosts(5), ipf(5), ipf(8), ipnat(8) diff --git a/contrib/ipfilter/man/ippool.8 b/contrib/ipfilter/man/ippool.8 new file mode 100644 index 0000000..26cec20 --- /dev/null +++ b/contrib/ipfilter/man/ippool.8 @@ -0,0 +1,133 @@ +.\" $FreeBSD$ +.\" +.TH IPPOOL 8 +.SH NAME +ippool \- user interface to the IPFilter pools +.SH SYNOPSIS +.br +.B ippool +-a [-dnv] [-m <name>] [-o <role>] [-t <type>] [-T ttl] -i <ipaddr>[/<netmask>] +.br +.B ippool +-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>] +.br +.B ippool +-f <file> [-dnuv] +.br +.B ippool +-F [-dv] [-o <role>] [-t <type>] +.br +.B ippool +-l [-dv] [-m <name>] [-t <type>] +.br +.B ippool +-r [-dnv] [-m <name>] [-o <role>] [-t <type>] -i <ipaddr>[/<netmask>] +.br +.B ippool +-R [-dnv] [-m <name>] [-o <role>] [-t <type>] +.br +.B ippool +-s [-dtv] [-M <core>] [-N <namelist>] +.SH DESCRIPTION +.PP +.B Ippool +is used to manage information stored in the IP pools subsystem of IPFilter. +Configuration file information may be parsed and loaded into the kernel, +currently configured pools removed or changed as well as inspected. +.PP +The command line options used are broken into two sections: the global +options and the instance specific options. +.SH GLOBAL OPTIONS +.TP +.B \-d +Toggle debugging of processing the configuration file. +.TP +.B \-n +This flag (no-change) prevents +.B ippool +from actually making any ioctl +calls or doing anything which would alter the currently running kernel. +.TP +.B \-v +Turn verbose mode on. +.SH COMMAND OPTIONS +.TP +.B -a +Add a new data node to an existing pool in the kernel. +.TP +.B -A +Add a new (empty) pool to the kernel. +.TP +.B -f <file> +Read in IP pool configuration information from the file and load it into +the kernel. +.TP +.B -F +Flush loaded pools from the kernel. +.TP +.B -l +Display a list of pools currently loaded into the kernel. +.TP +.B -r +Remove an existing data node from a pool in the kernel. +.TP +.B -R +Remove an existing pool from within the kernel. +.TP +.B -s +Display IP pool statistical information. +.SH OPTIONS +.TP +.B -i <ipaddr>[/<netmask>] +Sets the IP address for the operation being undertaken with an +all-one's mask or, optionally, a specific netmask given in either +the dotted-quad notation or a single integer. +.TP +.B -m <name> +Sets the pool name for the current operation. +.TP +.B -M <core> +Specify an alternative path to /dev/kmem to retrieve statistical information +from. +.TP +.B -N <namelist> +Specify an alternative path to lookup symbol name information from when +retrieving statistical information. +.TP +.B -o <role> +Sets the role with which this pool is to be used. Currently only +.B ipf, +.B auth +and +.B count +are accepted as arguments to this option. +.TP +.B -S <seed> +Sets the hashing seed to the number specified. Only for use with +.B hash +type pools. +.TP +.B -t <type> +Sets the type of pool being defined. Myst be one of +.B tree, +.B hash, +.B group-map. +.TP +.B -T <ttl> +Sets the expiration of the node being added. The timeout is expressed +as a number of seconds. +.B tree, +.B hash, +.B group-map. +.TP +.B -u +When parsing a configuration file, rather than load new pool data into the +kernel, unload it. +.DT +.SH FILES +.br +/dev/iplookup +.br +/etc/ippool.conf +.SH SEE ALSO +ippool(5), ipf(8), ipfstat(8) diff --git a/contrib/ipfilter/man/ipscan.5 b/contrib/ipfilter/man/ipscan.5 new file mode 100644 index 0000000..91bf9b0 --- /dev/null +++ b/contrib/ipfilter/man/ipscan.5 @@ -0,0 +1,52 @@ +.\" $FreeBSD$ +.\" +.TH IPSCAN 5 +.SH NAME +ipscan, ipscan.conf \- ipscan file format +.SH DESCRIPTION +.PP +WARNING: This feature is to be considered experimental and may change +significantly until a final implementation is drawn up. +.PP +The format for files accept by ipscan currently follow this rough grammar: +.LP +.nf +line ::= name ":" matchup [ "," matchup ] "=" action . +matchup ::= "(" ")" | "(" literal ")" | "(" literal "," match ")" . +action ::= result | result "else" result . +result ::= "close" | "track" | redirect . +redirect ::= "redirect" ip-address [ "(" "," port-number ")" ] . +match ::= { match-char } +match-char ::= "*" | "?" | "." +.fi +.PP +In this example an ip-address is a dotted-quad IPv4 address and a port-number +is a number betwee 1 and 65535, inclusive. The match string is must be of +same length as the literal string that it is matching (literal). The length +of either string is limited to 16 bytes. +.PP +Currently, the redirect option is not yet been implemented. +.LP +.nf +# +# * = match any character, . = exact match, ? = case insensitive +# +# Scan for anything that looks like HTTP and redirect it to the local +# proxy. One catch - this feature (redirect) is not yet implemented. +# +http : ("GET ", "???." ) = redirect(127.0.0.1) +# +# Track ssh connections (i.e do nothing) +# +ssh : (), ("SSH-") = track +# +# Things which look like smtp to be tracked else closed. +# Client can start with EHLO (ESMTP) or HELO (SMTP). +# +smtp : ("HELO ", "**??."), ("220 ", "....") = track else close +# +.fi +.SH FILES +/etc/ipscan.conf +.SH SEE ALSO +ipscan(8) diff --git a/contrib/ipfilter/man/ipscan.8 b/contrib/ipfilter/man/ipscan.8 new file mode 100644 index 0000000..513dc94 --- /dev/null +++ b/contrib/ipfilter/man/ipscan.8 @@ -0,0 +1,44 @@ +.\" $FreeBSD$ +.\" +.TH IPSCAN 8 +.SH NAME +ipscan \- user interface to the IPFilter content scanning +.SH SYNOPSIS +.B ipscan +[ +.B \-dlnrsv +] [ +] +.B \-f <\fIfilename\fP> +.SH DESCRIPTION +.PP +\fBipscan\fP opens the filename given (treating "\-" as stdin) and parses the +file to build up a content scanning configuration to load into the kernel. +Currently only the first 16 bytes of a connection can be compared. +.SH OPTIONS +.TP +.B \-d +Toggle debugging of processing the configuration file. +.TP +.B \-l +Show the list of currently configured content scanning entries. +.TP +.B \-n +This flag (no-change) prevents \fBipscan\fP from actually making any ioctl +calls or doing anything which would alter the currently running kernel. +.TP +.B \-r +Remove commands from kernel configuration as they are read from the +configuration file rather than adding new ones. +.TP +.B \-s +Retrieve and display content scanning statistics +.TP +.B \-v +Turn verbose mode on. +.DT +.SH FILES +/dev/ipscan +/etc/ipscan.conf +.SH SEE ALSO +ipscan(5), ipf(8) diff --git a/contrib/ipfilter/man/mkfilters.1 b/contrib/ipfilter/man/mkfilters.1 new file mode 100644 index 0000000..262e365 --- /dev/null +++ b/contrib/ipfilter/man/mkfilters.1 @@ -0,0 +1,16 @@ +.\" $FreeBSD$ +.\" +.TH MKFILTERS 1 +.SH NAME +mkfilters \- generate a minimal firewall ruleset for ipfilter +.SH SYNOPSIS +.B mkfilters +.SH FILES +/usr/share/examples/ipfilter/mkfilters +.SH DESCRIPTION +.PP +\fBmkfilters\fP is a perl script that generates a minimal filter rule set for +use with \fBipfilter\fP by parsing the output of \fBifconfig\fP. +.DT +.SH SEE ALSO +ipf(8), ipf(5), ipfilter(5), ifconfig(8) diff --git a/contrib/ipfilter/md5.c b/contrib/ipfilter/md5.c new file mode 100644 index 0000000..35756cd --- /dev/null +++ b/contrib/ipfilter/md5.c @@ -0,0 +1,319 @@ +/* $FreeBSD$ */ + + + +/* + *********************************************************************** + ** md5.c -- the source code for MD5 routines ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#if defined(linux) && defined(_KERNEL) +extern void *memcpy(void *, const void *, unsigned long); +# define bcopy(a,b,c) memcpy(b,a,c) +#else +# if defined(_KERNEL) && !defined(__sgi) +# include <sys/systm.h> +# else +# include <string.h> +# endif +#endif + +#include "md5.h" + +/* + *********************************************************************** + ** Message-digest routines: ** + ** To form the message digest for a message M ** + ** (1) Initialize a context buffer mdContext using MD5Init ** + ** (2) Call MD5Update on mdContext and M ** + ** (3) Call MD5Final on mdContext ** + ** The message digest is now in mdContext->digest[0...15] ** + *********************************************************************** + */ + +/* forward declaration */ +static void Transform __P((UINT4 *, UINT4 *)); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#ifdef __STDC__ +#define UL(x) x##U +#else +#define UL(x) x +#endif + +/* The routine MD5Init initializes the message-digest context + mdContext. All fields are set to zero. + */ +void MD5Init (mdContext) +MD5_CTX *mdContext; +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301; + mdContext->buf[1] = (UINT4)0xefcdab89; + mdContext->buf[2] = (UINT4)0x98badcfe; + mdContext->buf[3] = (UINT4)0x10325476; +} + +/* The routine MD5Update updates the message-digest context to + account for the presence of each of the characters inBuf[0..inLen-1] + in the message whose digest is being computed. + */ +void MD5Update (mdContext, inBuf, inLen) +MD5_CTX *mdContext; +unsigned char *inBuf; +unsigned int inLen; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +/* The routine MD5Final terminates the message-digest computation and + ends with the desired message digest in mdContext->digest[0...15]. + */ +void MD5Final (hash, mdContext) +unsigned char hash[]; +MD5_CTX *mdContext; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } + bcopy((char *)mdContext->digest, (char *)hash, 16); +} + +/* Basic MD5 step. Transforms buf based on in. + */ +static void Transform (buf, in) +UINT4 *buf; +UINT4 *in; +{ + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ + FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ + FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ + FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ + FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ + FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ + FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ + GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ + GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ + GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ + GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ + GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ + GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ + HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ + HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ + HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ + HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ + HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ + HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ + II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ + II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ + II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ + II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ + II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ + II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ + II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ + II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ + II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ + II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ + II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ + II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ + II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ + II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ + II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + *********************************************************************** + ** End of md5.c ** + ******************************** (cut) ******************************** + */ diff --git a/contrib/ipfilter/md5.h b/contrib/ipfilter/md5.h new file mode 100644 index 0000000..914df74 --- /dev/null +++ b/contrib/ipfilter/md5.h @@ -0,0 +1,72 @@ +/* $FreeBSD$ */ + +/* + *********************************************************************** + ** md5.h -- header file for implementation of MD5 ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** + ** Revised (for MD5): RLR 4/27/91 ** + ** -- G modified to have y&~z instead of y&z ** + ** -- FF, GG, HH modified to add in last register done ** + ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** + ** -- distinct additive constant for each step ** + ** -- round 4 added, working mod 7 ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#if !defined(__MD5_INCLUDE__) && !defined(_SYS_MD5_H) + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif +#ifndef __STDC__ +# undef const +# define const +#endif + +/* typedef a 32-bit type */ +typedef unsigned int UINT4; + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { + UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ + UINT4 buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +extern void MD5Init __P((MD5_CTX *)); +extern void MD5Update __P((MD5_CTX *, unsigned char *, unsigned int)); +extern void MD5Final __P((unsigned char *, MD5_CTX *)); + +#define __MD5_INCLUDE__ +#endif /* __MD5_INCLUDE__ */ diff --git a/contrib/ipfilter/mkfilters b/contrib/ipfilter/mkfilters new file mode 100644 index 0000000..fe15c55 --- /dev/null +++ b/contrib/ipfilter/mkfilters @@ -0,0 +1,116 @@ +#!/usr/local/bin/perl +# for best results, bring up all your interfaces before running this + +if ($^O =~ m/^irix/i) +{ + &irix_mkfilters || regular_mkfilters || die $!; +} +else +{ + ®ular_mkfilters || irix_mkfilters || die $!; +} + +foreach $i (keys %ifaces) { + $net{$i} = $inet{$i}."/".$netmask{$i} if (defined($inet{$i})); +} +# +# print out route suggestions +# +print "#\n"; +print "# The following routes should be configured, if not already:\n"; +print "#\n"; +foreach $i (keys %ifaces) { + next if (($i =~ /lo/) || !defined($net{$i}) || defined($ppp{$i})); + print "# route add $inet{$i} localhost 0\n"; +} +print "#\n"; + +# +# print out some generic filters which people should use somewhere near the top +# +print "block in log quick from any to any with ipopts\n"; +print "block in log quick proto tcp from any to any with short\n"; + +$grpi = 0; + +foreach $i (keys %ifaces) { + if (!defined($inet{$i})) { + next; + } + + $grpi += 100; + $grpo = $grpi + 50; + + if ($i !~ /lo/) { + print "pass out on $i all head $grpo\n"; + print "block out from 127.0.0.0/8 to any group $grpo\n"; + print "block out from any to 127.0.0.0/8 group $grpo\n"; + print "block out from any to $inet{$i}/32 group $grpo\n"; + print "pass in on $i all head $grpi\n"; + print "block in from 127.0.0.0/8 to any group $grpi\n"; + print "block in from $inet{$i}/32 to any group $grpi\n"; + foreach $j (keys %ifaces) { + if ($i ne $j && $j !~ /^lo/ && defined($net{$j})) { + print "block in from $net{$j} to any group $grpi\n"; + } + } + } +} + +sub irix_mkfilters +{ + open(NETSTAT, "/usr/etc/netstat -i|") || return 0; + + while (defined($line = <NETSTAT>)) + { + if ($line =~ m/^Name/) + { + next; + } + elsif ($line =~ m/^(\S+)/) + { + open(I, "/usr/etc/ifconfig $1|") || return 0; + &scan_ifconfig; + close I; # being neat... - Allen + } + } + close NETSTAT; # again, being neat... - Allen + return 1; +} + +sub regular_mkfilters +{ + open(I, "ifconfig -a|") || return 0; + &scan_ifconfig; + close I; # being neat... - Allen + return 1; +} + +sub scan_ifconfig +{ + while (<I>) { + chop; + if (/^[a-zA-Z]+\d+:/) { + ($iface = $_) =~ s/^([a-zA-Z]+\d+).*/$1/; + $ifaces{$iface} = $iface; + next; + } + if (/inet/) { + if (/\-\-\>/) { # PPP, (SLIP?) + ($inet{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$1/; + ($ppp{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$2/; + } else { + ($inet{$iface} = $_) =~ s/.*inet ([^ ]+).*/$1/; + } + } + if (/netmask/) { + ($mask = $_) =~ s/.*netmask ([^ ]+).*/$1/; + $mask =~ s/^/0x/ if ($mask =~ /^[0-9a-f]*$/); + $netmask{$iface} = $mask; + } + if (/broadcast/) { + ($bcast{$iface} = $_) =~ s/.*broadcast ([^ ]+).*/$1/; + } + } +} + diff --git a/contrib/ipfilter/ml_ipl.c b/contrib/ipfilter/ml_ipl.c new file mode 100644 index 0000000..aaf61a4 --- /dev/null +++ b/contrib/ipfilter/ml_ipl.c @@ -0,0 +1,164 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate + * its own major char number! Way cool patch! + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/file.h> +#include <sys/conf.h> +#include <sys/syslog.h> +#include <sys/buf.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/uio.h> +#include <sys/vnode.h> +#include <sundev/mbvar.h> +#include <sun/autoconf.h> +#include <sun/vddrv.h> +#if defined(sun4c) || defined(sun4m) +#include <sun/openprom.h> +#endif + +#ifndef IPL_NAME +#define IPL_NAME "/dev/ipf" +#endif + +extern int ipfattach(), ipfopen(), ipfclose(), ipfioctl(), ipfread(); +extern int nulldev(), ipfidentify(), errno; + +struct cdevsw ipfdevsw = +{ + ipfopen, ipfclose, ipfread, nulldev, + ipfioctl, nulldev, nulldev, nulldev, + 0, nulldev, +}; + + +struct dev_ops ipf_ops = +{ + 1, + ipfidentify, + ipfattach, + ipfopen, + ipfclose, + ipfread, + NULL, /* write */ + NULL, /* strategy */ + NULL, /* dump */ + 0, /* psize */ + ipfioctl, + NULL, /* reset */ + NULL /* mmap */ +}; + +int ipf_major = 0; + +#ifdef sun4m +struct vdldrv vd = +{ + VDMAGIC_PSEUDO, + "ipf", + &ipf_ops, + NULL, + &ipfdevsw, + 0, + 0, + NULL, + NULL, + NULL, + 0, + 1, +}; +#else /* sun4m */ +struct vdldrv vd = +{ + VDMAGIC_PSEUDO, /* magic */ + "ipf", /* name */ +#ifdef sun4c + &ipf_ops, /* dev_ops */ +#else + NULL, /* struct mb_ctlr *mb_ctlr */ + NULL, /* struct mb_driver *mb_driver */ + NULL, /* struct mb_device *mb_device */ + 0, /* num ctlrs */ + 1, /* numdevs */ +#endif /* sun4c */ + NULL, /* bdevsw */ + &ipfdevsw, /* cdevsw */ + 0, /* block major */ + 0, /* char major */ +}; +#endif /* sun4m */ + +extern int vd_unuseddev(); +extern struct cdevsw cdevsw[]; +extern int nchrdev; + +xxxinit(fc, vdp, vdi, vds) + u_int fc; + struct vddrv *vdp; + caddr_t vdi; + struct vdstat *vds; +{ + struct vdlinkage *v; + int i; + + switch (fc) + { + case VDLOAD: + while (ipf_major < nchrdev && + cdevsw[ipf_major].d_open != vd_unuseddev) + ipf_major++; + if (ipf_major == nchrdev) + return ENODEV; + vd.Drv_charmajor = ipf_major; + vdp->vdd_vdtab = (struct vdlinkage *)&vd; + return ipf_attach(vdi); + case VDUNLOAD: + return unload(vdp, vdi); + + case VDSTAT: + return 0; + + default: + return EIO; + } +} + +static unload(vdp, vdi) + struct vddrv *vdp; + struct vdioctl_unload *vdi; +{ + int i; + + (void) vn_remove(IPL_NAME, UIO_SYSSPACE, FILE); + return ipfdetach(); +} + + +static int ipf_attach(vdi) +struct vdioctl_load *vdi; +{ + struct vnode *vp; + struct vattr vattr; + int error = 0, fmode = S_IFCHR|0600; + + (void) vn_remove(IPL_NAME, UIO_SYSSPACE, FILE); + vattr_null(&vattr); + vattr.va_type = MFTOVT(fmode); + vattr.va_mode = (fmode & 07777); + vattr.va_rdev = ipf_major<<8; + + error = vn_create(IPL_NAME, UIO_SYSSPACE, &vattr, EXCL, 0, &vp); + if (error == 0) + VN_RELE(vp); + return ipfattach(0); +} diff --git a/contrib/ipfilter/mlf_ipl.c b/contrib/ipfilter/mlf_ipl.c new file mode 100644 index 0000000..93995af --- /dev/null +++ b/contrib/ipfilter/mlf_ipl.c @@ -0,0 +1,596 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate + * its own major char number! Way cool patch! + */ + + +#include <sys/param.h> + +#ifdef IPFILTER_LKM +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +# define ACTUALLY_LKM_NOT_KERNEL +#else +# ifndef __FreeBSD_cc_version +# include <sys/osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <sys/osreldate.h> +# endif +# endif +#endif +#include <sys/systm.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +# ifndef ACTUALLY_LKM_NOT_KERNEL +# include "opt_devfs.h" +# endif +# include <sys/conf.h> +# include <sys/kernel.h> +# ifdef DEVFS +# include <sys/devfsext.h> +# endif /*DEVFS*/ +#endif +#include <sys/conf.h> +#include <sys/file.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/lock.h> +#endif +#include <sys/stat.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/vnode.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/mount.h> +#include <sys/exec.h> +#include <sys/mbuf.h> +#if BSD >= 199506 +# include <sys/sysctl.h> +#endif +#if (__FreeBSD_version >= 300000) +# include <sys/socket.h> +#endif +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <sys/sysent.h> +#include <sys/lkm.h> +#include "netinet/ipl.h" +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_state.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_auth.h" +#include "netinet/ip_frag.h" + + +#if !defined(VOP_LEASE) && defined(LEASE_CHECK) +#define VOP_LEASE LEASE_CHECK +#endif + +int xxxinit __P((struct lkm_table *, int, int)); + +#ifdef SYSCTL_OID +int sysctl_ipf_int SYSCTL_HANDLER_ARGS; +# define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \ + ptr, val, sysctl_ipf_int, "I", descr); +# define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */ +# define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF) +SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &ipf_flags, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &ipf_pass, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &ipf_active, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &ipf_chksrc, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &ipf_minttl, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO, + &ipf_tcpidletimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO, + &ipf_tcphalfclosed, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO, + &ipf_tcpclosewait, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO, + &ipf_tcplastack, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO, + &ipf_tcptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO, + &ipf_tcpclosed, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO, + &ipf_udptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO, + &ipf_icmptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO, + &ipf_defnatage, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, + &ipf_ipfrttl, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_running, CTLFLAG_RD, + &ipf_running, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO, + &ipf_statesize, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO, + &ipf_statemax, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO, + &ipf_authsize, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, + &ipf_authused, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, + &ipf_defaultauthage, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, + &ippr_ftp_pasvonly, 0, ""); +#endif + +#ifdef DEVFS +static void *ipf_devfs[IPL_LOGSIZE]; +#endif + +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) +int ipf_major = 0; + +static struct cdevsw ipfdevsw = +{ + ipfopen, /* open */ + ipfclose, /* close */ + ipfread, /* read */ + (void *)nullop, /* write */ + ipfioctl, /* ioctl */ + (void *)nullop, /* stop */ + (void *)nullop, /* reset */ + (void *)NULL, /* tty */ + (void *)nullop, /* select */ + (void *)nullop, /* mmap */ + NULL /* strategy */ +}; + +MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipfdevsw); + +extern struct cdevsw cdevsw[]; +extern int vd_unuseddev __P((void)); +extern int nchrdev; +#else + +static struct cdevsw ipf_cdevsw = { + ipfopen, ipfclose, ipfread, nowrite, /* 79 */ + ipfioctl, nostop, noreset, nodevtotty, +#if (__FreeBSD_version >= 300000) + seltrue, nommap, nostrategy, "ipf", +#else + noselect, nommap, nostrategy, "ipf", +#endif + NULL, -1 +}; +#endif + +static void ipf_drvinit __P((void *)); + +#ifdef ACTUALLY_LKM_NOT_KERNEL +static int if_ipf_unload __P((struct lkm_table *, int)); +static int if_ipf_load __P((struct lkm_table *, int)); +static int if_ipf_remove __P((void)); +static int ipf_major = CDEV_MAJOR; + +static int ipfaction __P((struct lkm_table *, int)); +static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, + IPL_SCAN, IPL_SYNC, IPL_POOL, NULL }; + +extern int lkmenodev __P((void)); + +static int ipfaction(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) + int i = ipf_major; + struct lkm_dev *args = lkmtp->private.lkm_dev; +#endif + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) + for (i = 0; i < nchrdev; i++) + if (cdevsw[i].d_open == lkmenodev || + cdevsw[i].d_open == ipfopen) + break; + if (i == nchrdev) { + printf("IP Filter: No free cdevsw slots\n"); + return ENODEV; + } + + ipf_major = i; + args->lkm_offset = i; /* slot in cdevsw[] */ +#endif + printf("IP Filter: loaded into slot %d\n", ipf_major); + err = if_ipf_load(lkmtp, cmd); + if (!err) + ipf_drvinit((void *)NULL); + return err; + break; + case LKM_E_UNLOAD : + err = if_ipf_unload(lkmtp, cmd); + if (!err) { + printf("IP Filter: unloaded from slot %d\n", + ipf_major); +#ifdef DEVFS + if (ipf_devfs[IPL_LOGIPF]) + devfs_remove_dev(ipf_devfs[IPL_LOGIPF]); + if (ipf_devfs[IPL_LOGNAT]) + devfs_remove_dev(ipf_devfs[IPL_LOGNAT]); + if (ipf_devfs[IPL_LOGSTATE]) + devfs_remove_dev(ipf_devfs[IPL_LOGSTATE]); + if (ipf_devfs[IPL_LOGAUTH]) + devfs_remove_dev(ipf_devfs[IPL_LOGAUTH]); + if (ipf_devfs[IPL_LOGSCAN]) + devfs_remove_dev(ipf_devfs[IPL_LOGSCAN]); + if (ipf_devfs[IPL_LOGSYNC]) + devfs_remove_dev(ipf_devfs[IPL_LOGSYNC]); + if (ipf_devfs[IPL_LOGLOOKUP]) + devfs_remove_dev(ipf_devfs[IPL_LOGLOOKUP]); +#endif + } + return err; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return 0; +} + + +static int if_ipf_remove __P((void)) +{ + char *name; + struct nameidata nd; + int error, i; + + for (i = 0; (name = ipf_devfiles[i]); i++) { + NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); + if ((error = namei(&nd))) + return (error); + VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); +#if (__FreeBSD_version >= 300000) + VOP_LOCK(nd.ni_vp, LK_RETRY | LK_EXCLUSIVE, curproc); + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); + + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + if (nd.ni_vp != NULLVP) + vput(nd.ni_vp); +#else + VOP_LOCK(nd.ni_vp); + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); +#endif + } + + return 0; +} + + +static int if_ipf_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + int error = 0; + + error = ipfdetach(); + if (!error) + error = if_ipf_remove(); + return error; +} + + +static int if_ipf_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + struct nameidata nd; + struct vattr vattr; + int error = 0, fmode = S_IFCHR|0600, i; + char *name; + + error = ipfattach(); + if (error) + return error; + (void) if_ipf_remove(); + + for (i = 0; (name = ipf_devfiles[i]); i++) { + NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); + if ((error = namei(&nd))) + return error; + if (nd.ni_vp != NULL) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + vrele(nd.ni_vp); + return (EEXIST); + } + VATTR_NULL(&vattr); + vattr.va_type = VCHR; + vattr.va_mode = (fmode & 07777); + vattr.va_rdev = (ipf_major << 8) | i; + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); +#if (__FreeBSD_version >= 300000) + vput(nd.ni_dvp); +#endif + if (error) + return error; + } + return 0; +} + +#endif /* actually LKM */ + +#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000) +/* + * strlen isn't present in 2.1.* kernels. + */ +size_t strlen(string) + char *string; +{ + register char *s; + + for (s = string; *s; s++) + ; + return (size_t)(s - string); +} + + +int xxxinit(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction); +} +#else /* __FREEBSD_version >= 220000 */ +# ifdef IPFILTER_LKM +# include <sys/exec.h> + +# if (__FreeBSD_version >= 300000) +MOD_DEV(if_ipf, LM_DT_CHAR, CDEV_MAJOR, &ipf_cdevsw); +# else +MOD_DECL(if_ipf); + + +static struct lkm_dev _module = { + LM_DEV, + LKM_VERSION, + IPL_VERSION, + CDEV_MAJOR, + LM_DT_CHAR, + { (void *)&ipf_cdevsw } +}; +# endif + + +int if_ipf __P((struct lkm_table *, int, int)); + + +int if_ipf(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd, ver; +{ +# if (__FreeBSD_version >= 300000) + MOD_DISPATCH(if_ipf, lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction); +# else + DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction); +# endif +} +# endif /* IPFILTER_LKM */ +static ipf_devsw_installed = 0; + +static void ipf_drvinit __P((void *unused)) +{ + dev_t dev; +# ifdef DEVFS + void **tp = ipf_devfs; +# endif + + if (!ipf_devsw_installed ) { + dev = makedev(CDEV_MAJOR, 0); + cdevsw_add(&dev, &ipf_cdevsw, NULL); + ipf_devsw_installed = 1; + +# ifdef DEVFS + tp[IPL_LOGIPF] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGIPF, + DV_CHR, 0, 0, 0600, "ipf"); + tp[IPL_LOGNAT] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGNAT, + DV_CHR, 0, 0, 0600, "ipnat"); + tp[IPL_LOGSTATE] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGSTATE, + DV_CHR, 0, 0, 0600, + "ipstate"); + tp[IPL_LOGAUTH] = devfs_add_devswf(&ipf_cdevsw, IPL_LOGAUTH, + DV_CHR, 0, 0, 0600, + "ipauth"); +# endif + } +} + + +#ifdef SYSCTL_IPF +int +sysctl_ipf_int SYSCTL_HANDLER_ARGS +{ + int error = 0; + + if (arg1) + error = SYSCTL_OUT(req, arg1, sizeof(int)); + else + error = SYSCTL_OUT(req, &arg2, sizeof(int)); + + if (error || !req->newptr) + return (error); + + if (!arg1) + error = EPERM; + else { + if ((oidp->oid_kind & CTLFLAG_OFF) && (ipf_running > 0)) + error = EBUSY; + else + error = SYSCTL_IN(req, arg1, sizeof(int)); + } + return (error); +} +#endif + + +# if defined(IPFILTER_LKM) || \ + defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +SYSINIT(ipfdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipf_drvinit,NULL) +# endif /* IPFILTER_LKM */ +#endif /* _FreeBSD_version */ + + +/* + * routines below for saving IP headers to buffer + */ +int ipfopen(dev, flags +#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) +, devtype, p) + int devtype; +# if (__FreeBSD_version >= 500024) + struct thread *p; +# else + struct proc *p; +# endif /* __FreeBSD_version >= 500024 */ +#else +) +#endif +#if (__FreeBSD_version >= 502116) + struct cdev *dev; +#else + dev_t dev; +#endif + int flags; +{ + u_int unit = GET_MINOR(dev); + + if (IPL_LOGMAX < unit) + unit = ENXIO; + else + unit = 0; + return unit; +} + + +int ipfclose(dev, flags +#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) +, devtype, p) + int devtype; +# if (__FreeBSD_version >= 500024) + struct thread *p; +# else + struct proc *p; +# endif /* __FreeBSD_version >= 500024 */ +#else +) +#endif +#if (__FreeBSD_version >= 502116) + struct cdev *dev; +#else + dev_t dev; +#endif + int flags; +{ + u_int unit = GET_MINOR(dev); + + if (IPL_LOGMAX < unit) + unit = ENXIO; + else + unit = 0; + return unit; +} + +/* + * ipfread/ipflog + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +#if (BSD >= 199306) +int ipfread(dev, uio, ioflag) + int ioflag; +#else +int ipfread(dev, uio) +#endif +#if (__FreeBSD_version >= 502116) + struct cdev *dev; +#else + dev_t dev; +#endif + register struct uio *uio; +{ + u_int unit = GET_MINOR(dev); + + if (unit < 0) + return ENXIO; + + if (ipf_running < 1) + return EIO; + + if (unit == IPL_LOGSYNC) + return ipfsync_read(uio); + +#ifdef IPFILTER_LOG + return ipflog_read(unit, uio); +#else + return ENXIO; +#endif +} + + +/* + * ipfwrite + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +#if (BSD >= 199306) +int ipfwrite(dev, uio, ioflag) + int ioflag; +#else +int ipfwrite(dev, uio) +#endif +#if (__FreeBSD_version >= 502116) + struct cdev *dev; +#else + dev_t dev; +#endif + register struct uio *uio; +{ + + if (ipf_running < 1) + return EIO; + + if (GET_MINOR(dev) == IPL_LOGSYNC) + return ipfsync_write(uio); + return ENXIO; +} diff --git a/contrib/ipfilter/mlf_rule.c b/contrib/ipfilter/mlf_rule.c new file mode 100644 index 0000000..babd2c6 --- /dev/null +++ b/contrib/ipfilter/mlf_rule.c @@ -0,0 +1,168 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate + * its own major char number! Way cool patch! + */ + + +#include <sys/param.h> + +#if defined(__FreeBSD__) && (__FreeBSD__ > 1) +# ifdef IPFILTER_LKM +# include <osreldate.h> +# define ACTUALLY_LKM_NOT_KERNEL +# else +# include <sys/osreldate.h> +# endif +#endif +#include <sys/systm.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +# include <sys/conf.h> +# include <sys/kernel.h> +# ifdef DEVFS +# include <sys/devfsext.h> +# endif /*DEVFS*/ +#endif +#include <sys/conf.h> +#include <sys/file.h> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/lock.h> +#endif +#include <sys/stat.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/vnode.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/mount.h> +#include <sys/exec.h> +#include <sys/mbuf.h> +#if BSD >= 199506 +# include <sys/sysctl.h> +#endif +#if (__FreeBSD_version >= 300000) +# include <sys/socket.h> +#endif +#if (__FreeBSD_version >= 199511) +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#endif +#if (__FreeBSD__ > 1) +# include <sys/sysent.h> +#endif +#include <sys/lkm.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_rules.h" + + +int xxxinit __P((struct lkm_table *, int, int)); + +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) +MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); +#endif + +static int ipfrule_ioctl __P((struct lkm_table *, int)); + +#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000) + +int xxxinit(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl, ipfrule_ioctl); +} +#else /* __FREEBSD_version >= 220000 */ +# ifdef IPFILTER_LKM +# include <sys/exec.h> + +# if (__FreeBSD_version >= 300000) +MOD_MISC(ipfrule); +# else +MOD_DECL(ipfrule); + + +static struct lkm_misc _module = { + LM_MISC, + LKM_VERSION, + "IP Filter rules", + 0, +}; +# endif + + +int ipfrule __P((struct lkm_table *, int, int)); + + +int ipfrule(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd, ver; +{ +# if (__FreeBSD_version >= 300000) + MOD_DISPATCH(ipfrule, lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl, + ipfrule_ioctl); +# else + DISPATCH(lkmtp, cmd, ver, ipfrule_ioctl, ipfrule_ioctl, ipfrule_ioctl); +# endif +} +# endif /* IPFILTER_LKM */ + + +int ipfrule_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return ipfrule_add(); +} + + +int ipfrule_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return ipfrule_remove(); +} + + +static int ipfrule_ioctl(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + + err = ipfrule_load(lkmtp, cmd); + if (!err) + ipf_refcnt++; + break; + case LKM_E_UNLOAD : + err = ipfrule_unload(lkmtp, cmd); + if (!err) + ipf_refcnt--; + break; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return err; +} +#endif /* _FreeBSD_version */ diff --git a/contrib/ipfilter/mlfk_ipl.c b/contrib/ipfilter/mlfk_ipl.c new file mode 100644 index 0000000..ba1f44f --- /dev/null +++ b/contrib/ipfilter/mlfk_ipl.c @@ -0,0 +1,529 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/select.h> +#if __FreeBSD_version >= 500000 +# include <sys/selinfo.h> +#endif +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> + + +#include "netinet/ipl.h" +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_state.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_auth.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_sync.h" + +extern ipf_main_softc_t ipfmain; + +#if __FreeBSD_version >= 502116 +static struct cdev *ipf_devs[IPL_LOGSIZE]; +#else +static dev_t ipf_devs[IPL_LOGSIZE]; +#endif + +#if 0 +static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ); +#endif +static int ipf_modload(void); +static int ipf_modunload(void); + +#if (__FreeBSD_version >= 500024) +# if (__FreeBSD_version >= 502116) +static int ipfopen __P((struct cdev*, int, int, struct thread *)); +static int ipfclose __P((struct cdev*, int, int, struct thread *)); +# else +static int ipfopen __P((dev_t, int, int, struct thread *)); +static int ipfclose __P((dev_t, int, int, struct thread *)); +# endif /* __FreeBSD_version >= 502116 */ +#else +static int ipfopen __P((dev_t, int, int, struct proc *)); +static int ipfclose __P((dev_t, int, int, struct proc *)); +#endif +#if (__FreeBSD_version >= 502116) +static int ipfread __P((struct cdev*, struct uio *, int)); +static int ipfwrite __P((struct cdev*, struct uio *, int)); +#else +static int ipfread __P((dev_t, struct uio *, int)); +static int ipfwrite __P((dev_t, struct uio *, int)); +#endif /* __FreeBSD_version >= 502116 */ + + + +SYSCTL_DECL(_net_inet); +#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \ + SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \ + ptr, val, sysctl_ipf_int, "I", descr); +#define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */ +#define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF) +SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); +#if 0 +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &ipf_flags, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &ipf_pass, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &ipf_active, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO, + &ipf_tcpidletimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO, + &ipf_tcphalfclosed, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO, + &ipf_tcpclosewait, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO, + &ipf_tcplastack, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO, + &ipf_tcptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO, + &ipf_tcpclosed, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO, + &ipf_udptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO, + &ipf_udpacktimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO, + &ipf_icmptimeout, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO, + &ipf_nat_defage, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, + &ipf_ipfrttl, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_running, CTLFLAG_RD, + &ipf_running, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO, + &ipf_state_size, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO, + &ipf_state_max, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO, + &ipf_nat_table_sz, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO, + &ipf_nat_maprules_sz, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO, + &ipf_nat_rdrrules_sz, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO, + &ipf_nat_hostmap_sz, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO, + &ipf_auth_size, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, + &ipf_auth_used, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, + &ipf_auth_defaultage, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &ipf_chksrc, 0, ""); +SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &ipf_minttl, 0, ""); +#endif + +#define CDEV_MAJOR 79 +#include <sys/poll.h> +#if __FreeBSD_version >= 500043 +# include <sys/select.h> +static int ipfpoll(struct cdev *dev, int events, struct thread *td); + +static struct cdevsw ipf_cdevsw = { +#if __FreeBSD_version >= 502103 + .d_version = D_VERSION, + .d_flags = 0, /* D_NEEDGIANT - Should be SMP safe */ +#endif + .d_open = ipfopen, + .d_close = ipfclose, + .d_read = ipfread, + .d_write = ipfwrite, + .d_ioctl = ipfioctl, + .d_poll = ipfpoll, + .d_name = "ipf", +#if __FreeBSD_version < 600000 + .d_maj = CDEV_MAJOR, +#endif +}; +#else +static int ipfpoll(dev_t dev, int events, struct proc *td); + +static struct cdevsw ipf_cdevsw = { + /* open */ ipfopen, + /* close */ ipfclose, + /* read */ ipfread, + /* write */ ipfwrite, + /* ioctl */ ipfioctl, + /* poll */ ipfpoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "ipf", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ 0, +# if (__FreeBSD_version < 500043) + /* bmaj */ -1, +# endif +# if (__FreeBSD_version >= 430000) + /* kqfilter */ NULL +# endif +}; +#endif + +static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME, + IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL }; + + +static int +ipfilter_modevent(module_t mod, int type, void *unused) +{ + int error = 0; + + switch (type) + { + case MOD_LOAD : + error = ipf_modload(); + break; + + case MOD_UNLOAD : + error = ipf_modunload(); + break; + default: + error = EINVAL; + break; + } + return error; +} + + +static int +ipf_modload() +{ + char *defpass, *c, *str; + int i, j, error; + + if (ipf_load_all() != 0) + return EIO; + + if (ipf_create_all(&ipfmain) == NULL) + return EIO; + + error = ipfattach(&ipfmain); + if (error) + return error; + + for (i = 0; i < IPL_LOGSIZE; i++) + ipf_devs[i] = NULL; + + for (i = 0; (str = ipf_devfiles[i]); i++) { + c = NULL; + for(j = strlen(str); j > 0; j--) + if (str[j] == '/') { + c = str + j + 1; + break; + } + if (!c) + c = str; + ipf_devs[i] = make_dev(&ipf_cdevsw, i, 0, 0, 0600, c); + } + + error = ipf_pfil_hook(); + if (error != 0) + return error; + ipf_event_reg(); + + if (FR_ISPASS(ipfmain.ipf_pass)) + defpass = "pass"; + else if (FR_ISBLOCK(ipfmain.ipf_pass)) + defpass = "block"; + else + defpass = "no-match -> block"; + + printf("%s initialized. Default = %s all, Logging = %s%s\n", + ipfilter_version, defpass, +#ifdef IPFILTER_LOG + "enabled", +#else + "disabled", +#endif +#ifdef IPFILTER_COMPILED + " (COMPILED)" +#else + "" +#endif + ); + return 0; +} + + +static int +ipf_modunload() +{ + int error, i; + + if (ipfmain.ipf_refcnt) + return EBUSY; + + error = ipf_pfil_unhook(); + if (error != 0) + return error; + + if (ipfmain.ipf_running >= 0) { + error = ipfdetach(&ipfmain); + if (error != 0) + return error; + + ipf_destroy_all(&ipfmain); + ipf_unload_all(); + } else + error = 0; + + ipfmain.ipf_running = -2; + + for (i = 0; ipf_devfiles[i]; i++) { + if (ipf_devs[i] != NULL) + destroy_dev(ipf_devs[i]); + } + + printf("%s unloaded\n", ipfilter_version); + + return error; +} + + +static moduledata_t ipfiltermod = { + "ipfilter", + ipfilter_modevent, + 0 +}; + + +DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); +#ifdef MODULE_VERSION +MODULE_VERSION(ipfilter, 1); +#endif + + +#if 0 +#ifdef SYSCTL_IPF +int +sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ) +{ + int error = 0; + + if (arg1) + error = SYSCTL_OUT(req, arg1, sizeof(int)); + else + error = SYSCTL_OUT(req, &arg2, sizeof(int)); + + if (error || !req->newptr) + return (error); + + if (!arg1) + error = EPERM; + else { + if ((oidp->oid_kind & CTLFLAG_OFF) && (ipfmain.ipf_running > 0)) + error = EBUSY; + else + error = SYSCTL_IN(req, arg1, sizeof(int)); + } + return (error); +} +#endif +#endif + + +static int +#if __FreeBSD_version >= 500043 +ipfpoll(struct cdev *dev, int events, struct thread *td) +#else +ipfpoll(dev_t dev, int events, struct proc *td) +#endif +{ + u_int unit = GET_MINOR(dev); + int revents; + + if (unit < 0 || unit > IPL_LOGMAX) + return 0; + + revents = 0; + + switch (unit) + { + case IPL_LOGIPF : + case IPL_LOGNAT : + case IPL_LOGSTATE : +#ifdef IPFILTER_LOG + if ((events & (POLLIN | POLLRDNORM)) && ipf_log_canread(&ipfmain, unit)) + revents |= events & (POLLIN | POLLRDNORM); +#endif + break; + case IPL_LOGAUTH : + if ((events & (POLLIN | POLLRDNORM)) && ipf_auth_waiting(&ipfmain)) + revents |= events & (POLLIN | POLLRDNORM); + break; + case IPL_LOGSYNC : + if ((events & (POLLIN | POLLRDNORM)) && ipf_sync_canread(&ipfmain)) + revents |= events & (POLLIN | POLLRDNORM); + if ((events & (POLLOUT | POLLWRNORM)) && ipf_sync_canwrite(&ipfmain)) + revents |= events & (POLLOUT | POLLWRNORM); + break; + case IPL_LOGSCAN : + case IPL_LOGLOOKUP : + default : + break; + } + + if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0)) + selrecord(td, &ipfmain.ipf_selwait[unit]); + + return revents; +} + + +/* + * routines below for saving IP headers to buffer + */ +static int ipfopen(dev, flags +#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) +, devtype, p) + int devtype; +# if (__FreeBSD_version >= 500024) + struct thread *p; +# else + struct proc *p; +# endif /* __FreeBSD_version >= 500024 */ +#else +) +#endif +#if (__FreeBSD_version >= 502116) + struct cdev *dev; +#else + dev_t dev; +#endif + int flags; +{ + u_int unit = GET_MINOR(dev); + int error; + + if (IPL_LOGMAX < unit) + error = ENXIO; + else { + switch (unit) + { + case IPL_LOGIPF : + case IPL_LOGNAT : + case IPL_LOGSTATE : + case IPL_LOGAUTH : + case IPL_LOGLOOKUP : + case IPL_LOGSYNC : +#ifdef IPFILTER_SCAN + case IPL_LOGSCAN : +#endif + error = 0; + break; + default : + error = ENXIO; + break; + } + } + return error; +} + + +static int ipfclose(dev, flags +#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) +, devtype, p) + int devtype; +# if (__FreeBSD_version >= 500024) + struct thread *p; +# else + struct proc *p; +# endif /* __FreeBSD_version >= 500024 */ +#else +) +#endif +#if (__FreeBSD_version >= 502116) + struct cdev *dev; +#else + dev_t dev; +#endif + int flags; +{ + u_int unit = GET_MINOR(dev); + + if (IPL_LOGMAX < unit) + unit = ENXIO; + else + unit = 0; + return unit; +} + +/* + * ipfread/ipflog + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +#if (BSD >= 199306) +static int ipfread(dev, uio, ioflag) + int ioflag; +#else +static int ipfread(dev, uio) +#endif +#if (__FreeBSD_version >= 502116) + struct cdev *dev; +#else + dev_t dev; +#endif + struct uio *uio; +{ + u_int unit = GET_MINOR(dev); + + if (unit < 0) + return ENXIO; + + if (ipfmain.ipf_running < 1) + return EIO; + + if (unit == IPL_LOGSYNC) + return ipf_sync_read(&ipfmain, uio); + +#ifdef IPFILTER_LOG + return ipf_log_read(&ipfmain, unit, uio); +#else + return ENXIO; +#endif +} + + +/* + * ipfwrite + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +#if (BSD >= 199306) +static int ipfwrite(dev, uio, ioflag) + int ioflag; +#else +static int ipfwrite(dev, uio) +#endif +#if (__FreeBSD_version >= 502116) + struct cdev *dev; +#else + dev_t dev; +#endif + struct uio *uio; +{ + + if (ipfmain.ipf_running < 1) + return EIO; + + if (GET_MINOR(dev) == IPL_LOGSYNC) + return ipf_sync_write(&ipfmain, uio); + return ENXIO; +} diff --git a/contrib/ipfilter/mlfk_rule.c b/contrib/ipfilter/mlfk_rule.c new file mode 100644 index 0000000..9f951cf --- /dev/null +++ b/contrib/ipfilter/mlfk_rule.c @@ -0,0 +1,70 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> + +#include <netinet/ipl.h> +#include <netinet/ip_compat.h> +#include <netinet/ip_fil.h> +#include <netinet/ip_state.h> +#include <netinet/ip_nat.h> +#include <netinet/ip_auth.h> +#include <netinet/ip_frag.h> + +#include "ip_rules.h" + +extern ipf_main_softc_t ipfmain; + +static int +ipfrule_modevent(module_t mod, int type, void *unused) +{ + int error = 0; + + switch (type) + { + case MOD_LOAD : + error = ipfrule_add(); + if (!error) + ipfmain.ipf_refcnt++; + break; + case MOD_UNLOAD : + error = ipfrule_remove(); + if (!error) + ipfmain.ipf_refcnt--; + break; + default: + error = EINVAL; + break; + } + return error; +} + +static moduledata_t ipfrulemod = { + "ipfrule", + ipfrule_modevent, + 0 +}; +DECLARE_MODULE(ipfrule, ipfrulemod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); +#ifdef MODULE_DEPEND +MODULE_DEPEND(ipfrule, ipfilter, 1, 1, 1); +#endif +#ifdef MODULE_VERSION +MODULE_VERSION(ipfrule, 1); +#endif diff --git a/contrib/ipfilter/mlh_rule.c b/contrib/ipfilter/mlh_rule.c new file mode 100644 index 0000000..cc2a74c --- /dev/null +++ b/contrib/ipfilter/mlh_rule.c @@ -0,0 +1,114 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +/* #pragma ident "@(#)solaris.c 1.12 6/5/96 (C) 1995 Darren Reed"*/ + +/*typedef unsigned int spustate_t;*/ +struct uio; + +#include <sys/types.h> +#include <sys/cmn_err.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/conf.h> +#include <sys/callout.h> +#include <sys/moddefs.h> +#include <sys/io.h> +#include <sys/wsio.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/byteorder.h> +#include <sys/socket.h> +#include <sys/stropts.h> +#include <net/if.h> +#include <net/af.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/tcpip.h> +#include <netinet/ip_icmp.h> + +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_rules.h" + + +/* + * Driver Header + */ +static drv_info_t ipf_drv_info = { + "IP Filter Rules", /* type */ + "pseudo", /* class */ + DRV_PSEUDO|DRV_SAVE_CONF|DRV_MP_SAFE, /* flags */ + -1, /* b_major */ + -1, /* c_major */ + NULL, /* cdio */ + NULL, /* gio_private */ + NULL, /* cdio_private */ +}; + + +extern struct mod_operations gio_mod_ops; +static drv_info_t ipf_drv_info; +extern struct mod_conf_data ipf_conf_data; + +static struct mod_type_data ipf_drv_link = { + IPL_VERSION, (void *)NULL +}; + +static struct modlink ipf_mod_link[] = { + { &gio_mod_ops, (void *)&ipf_drv_link }, + { NULL, (void *)NULL } +}; + +struct modwrapper ipf_wrapper = { + MODREV, + ipf_load, + ipf_unload, + (void (*)())NULL, + (void *)&ipf_conf_data, + ipf_mod_link +}; + + +static int ipf_load(void *arg) +{ + int i; + + i = ipfrule_add(); + if (!i) + ipf_refcnt--; +#ifdef IPFDEBUG + printf("IP Filter Rules: ipfrule_add() = %d\n", i); +#endif + if (!i) + cmn_err(CE_CONT, "IP Filter Rules: Loaded\n"); + return i; +} + + +static int ipf_unload(void *arg) +{ + int i; + + i = ipfrule_remove(); + if (!i) + ipf_refcnt--; +#ifdef IPFDEBUG + printf("IP Filter Rules: ipfrule_remove() = %d\n", i); +#endif + if (!i) + cmn_err(CE_CONT, "IP Filter Rules: Unloaded\n"); + return i; +} diff --git a/contrib/ipfilter/mli_ipl.c b/contrib/ipfilter/mli_ipl.c new file mode 100644 index 0000000..2a0024c --- /dev/null +++ b/contrib/ipfilter/mli_ipl.c @@ -0,0 +1,683 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * (C)opyright 1997 by Marc Boucher. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +/* TODO: (MARCXXX) + - ipl_init failure -> open ENODEV or whatever + - prevent multiple LKM loads + - surround access to ifnet structures by IFNET_LOCK()/IFNET_UNLOCK() ? + - m != m1 problem +*/ + +#include <sys/types.h> +#include <sys/conf.h> +#ifdef IPFILTER_LKM +#include <sys/mload.h> +#endif +#include <sys/systm.h> +#include <sys/errno.h> +#include <net/if.h> +#include <net/route.h> +#include <netinet/in.h> +#ifdef IFF_DRVRLOCK /* IRIX6 */ +#include <sys/hashing.h> +#include <netinet/in_var.h> +#endif +#include <sys/mbuf.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/tcpip.h> +#include <netinet/ip_icmp.h> +#include <netinet/ipfilter.h> +#include "ipl.h" +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_nat.h" + +#ifndef MBUF_IS_CLUSTER +# define MBUF_IS_CLUSTER(m) ((m)->m_flags & MCL_CLUSTER) +#endif +#undef IPFDEBUG /* #define IPFDEBUG 9 */ + +#ifdef IPFILTER_LKM +u_int ipldevflag = D_MP; +char *iplmversion = M_VERSION; +#else +u_int ipfilterdevflag = D_MP; +char *ipfiltermversion = M_VERSION; +#endif + +ipfmutex_t ipl_mutex, ipfi_mutex, ipf_rw, ipf_stinsert, ipf_auth_mx; +ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; +ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; +ipfrwlock_t ipf_global, ipf_mutex, ipf_ipidfrag, ipf_frcache, ipf_tokens; + +int (*ipf_checkp) __P((struct ip *, int, void *, int, mb_t **)); + +#ifdef IPFILTER_LKM +static int *ipff_addr = 0; +static int ipff_value; +static __psunsigned_t *ipfk_addr = 0; +static __psunsigned_t ipfk_code[4]; +#endif +static void nifattach(); +static void nifdetach(); + +typedef struct nif { + struct nif *nf_next; + struct ifnet *nf_ifp; +#if (IRIX < 60500) + int (*nf_output)(struct ifnet *, struct mbuf *, struct sockaddr *); +#else + int (*nf_output)(struct ifnet *, struct mbuf *, struct sockaddr *, + struct rtentry *); +#endif + char nf_name[LIFNAMSIZ]; + int nf_unit; +} nif_t; + +static nif_t *nif_head = 0; +static int nif_interfaces = 0; +extern int in_interfaces; +#if IRIX >= 60500 +toid_t ipf_timer_id; +#endif + +extern ipnat_t *nat_list; + +#ifdef IPFDEBUG +static void ipf_dumppacket(m) + struct mbuf *m; +{ + u_char *s; + char *t, line[80]; + int len, off, i; + + off = 0; + + while (m != NULL) { + len = M_LEN(m); + s = mtod(m, u_char *); + printf("mbuf 0x%lx len %d flags %x type %d\n", + m, len, m->m_flags, m->m_type); + printf("dat 0x%lx off 0x%lx/%d s 0x%lx next 0x%lx\n", + m->m_dat, m->m_off, m->m_off, s, m->m_next); + while (len > 0) { + t = line; + for (i = 0; (i < 16) && (len > 0); len--, i++) + sprintf(t, " %02x", *s++), t += strlen(t); + *s = '\0'; + printf("mbuf:%x:%s\n", off, line); + off += 16; + } + m = m->m_next; + } +} +#endif + + +static int +#if IRIX < 60500 +ipl_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst) +#else +ipl_if_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, + struct rtentry *rt) +#endif +{ +#if (IPFDEBUG >= 0) + static unsigned int cnt = 0; +#endif + nif_t *nif; + + MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */ + for (nif = nif_head; nif; nif = nif->nf_next) + if (nif->nf_ifp == ifp) + break; + MUTEX_EXIT(&ipfi_mutex); + + if (nif == NULL) { + printf("IP Filter: ipl_if_output intf %x NOT FOUND\n", ifp); + return ENETDOWN; + } + +#if (IPFDEBUG >= 7) + if ((++cnt % 200) == 0) + printf("IP Filter: ipl_if_output(ifp=0x%lx, m=0x%lx, dst=0x%lx), m_type=%d m_flags=0x%lx m_off=0x%lx\n", ifp, m, dst, m->m_type, (u_long)m->m_flags, m->m_off); +#endif + + if (ipf_checkp) { + struct mbuf *m1 = m; + struct ip *ip; + int hlen; + + switch(m->m_type) + { + case MT_HEADER: + if (m->m_len == 0) { + if (m->m_next == NULL) + break; + m = m->m_next; + } + /* FALLTHROUGH */ + case MT_DATA: + if (!MBUF_IS_CLUSTER(m) && + ((m->m_off < MMINOFF) || (m->m_off > MMAXOFF))) { +#if (IPFDEBUG >= 4) + printf("IP Filter: ipl_if_output: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off); +#endif + break; + } + if (m->m_len < sizeof(char)) { +#if (IPFDEBUG >= 3) + printf("IP Filter: ipl_if_output: mbuf block too small (m_len=%d) for IP vers+hlen, m_type=%d m_flags=0x%lx\n", m->m_len, m->m_type, (u_long)m->m_flags); +#endif + break; + } + ip = mtod(m, struct ip *); + if (ip->ip_v != IPVERSION) { +#if (IPFDEBUG >= 2) + ipf_dumppacket(m); + printf("IP Filter: ipl_if_output: bad ip_v m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off); +#endif + break; + } + + hlen = ip->ip_hl << 2; + if ((*ipf_checkp)(ip, hlen, ifp, 1, &m1) || (m1 == NULL)) + return EHOSTUNREACH; + + m = m1; + break; + + default: +#if (IPFDEBUG >= 2) + printf("IP Filter: ipl_if_output: bad m_type=%d m_flags=0x%lxm_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off); +#endif + break; + } + } +#if (IRIX < 60500) + return (*nif->nf_output)(ifp, m, dst); +#else + return (*nif->nf_output)(ifp, m, dst, rt); +#endif +} + +int + + +#if !defined(IPFILTER_LKM) && (IRIX >= 60500) +ipfilter_kernel(struct ifnet *rcvif, struct mbuf *m) +#else +ipl_kernel(struct ifnet *rcvif, struct mbuf *m) +#endif +{ +#if (IPFDEBUG >= 7) + static unsigned int cnt = 0; + + if ((++cnt % 200) == 0) + printf("IP Filter: ipl_kernel(rcvif=0x%lx, m=0x%lx\n", + rcvif, m); +#endif + + if (ipf_running <= 0) + return IPF_ACCEPTIT; + + /* + * Check if we want to allow this packet to be processed. + * Consider it to be bad if not. + */ + if (ipf_checkp) { + struct mbuf *m1 = m; + struct ip *ip; + int hlen; + + if ((m->m_type != MT_DATA) && (m->m_type != MT_HEADER)) { +#if (IPFDEBUG >= 4) + printf("IP Filter: ipl_kernel: bad m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off); +#endif + return IPF_ACCEPTIT; + } + + if (!MBUF_IS_CLUSTER(m) && + ((m->m_off < MMINOFF) || (m->m_off > MMAXOFF))) { +#if (IPFDEBUG >= 4) + printf("IP Filter: ipl_kernel: bad m_off m_type=%d m_flags=0x%lx m_off=0x%lx\n", m->m_type, (u_long)m->m_flags, m->m_off); +#endif + return IPF_ACCEPTIT; + } + + if (m->m_len < sizeof(char)) { +#if (IPFDEBUG >= 1) + printf("IP Filter: ipl_kernel: mbuf block too small (m_len=%d) for IP vers+hlen, m_type=%d m_flags=0x%lx\n", m->m_len, m->m_type, (u_long)m->m_flags); +#endif + return IPF_ACCEPTIT; + } + + ip = mtod(m, struct ip *); + if (ip->ip_v != IPVERSION) { +#if (IPFDEBUG >= 4) + printf("IP Filter: ipl_kernel: bad ip_v\n"); +#endif + m_freem(m); + return IPF_DROPIT; + } + + ip->ip_len = htons(ip->ip_len); + ip->ip_off = htons(ip->ip_off); + hlen = ip->ip_hl << 2; + if ((*ipf_checkp)(ip, hlen, rcvif, 0, &m1) || !m1) + return IPF_DROPIT; + ip = mtod(m1, struct ip *); + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + +#if (IPFDEBUG >= 2) + if (m != m1) + printf("IP Filter: ipl_kernel: m != m1\n"); +#endif + } + + return IPF_ACCEPTIT; +} + +int +ipl_ipfilter_attach(void) +{ +#if defined(IPFILTER_LKM) + __psunsigned_t *addr_ff, *addr_fk; + + st_findaddr("ipfilterflag", &addr_ff); +# if (IPFDEBUG >= 1) + printf("IP Filter: st_findaddr ipfilterflag=0x%lx\n", addr_ff); +# endif + if (!addr_ff) + return ESRCH; + + st_findaddr("ipfilter_kernel", &addr_fk); +# if (IPFDEBUG >= 1) + printf("IP Filter: st_findaddr ipfilter_kernel=0x%lx\n", addr_fk); +# endif + if (!addr_fk) + return ESRCH; + + MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */ + + ipff_addr = (int *)addr_ff; + + ipff_value = *ipff_addr; + *ipff_addr = 0; + + + ipfk_addr = addr_fk; + + bcopy(ipfk_addr, ipfk_code, sizeof(ipfk_code)); + + /* write a "li t4, ipl_kernel" instruction */ + ipfk_addr[0] = 0x3c0c0000 | + (((__psunsigned_t)ipl_kernel >> 16) & 0xffff); + ipfk_addr[1] = 0x358c0000 | + ((__psunsigned_t)ipl_kernel & 0xffff); + /* write a "jr t4" instruction" */ + ipfk_addr[2] = 0x01800008; + + /* write a "nop" instruction */ + ipfk_addr[3] = 0; + + icache_inval(ipfk_addr, sizeof(ipfk_code)); + + *ipff_addr = 1; /* enable ipfilter_kernel */ + + MUTEX_EXIT(&ipfi_mutex); +#else + extern int ipfilterflag; + + ipfilterflag = 1; +#endif + nif_interfaces = 0; + nifattach(); + + return 0; +} + + +/* + * attach the packet filter to each non-loopback interface that is running + */ +static void +nifattach() +{ + nif_t *nif, *qf2; + struct ifnet *ifp; + struct frentry *f; + ipnat_t *np; + + MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */ + + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + if ((!(ifp->if_flags & IFF_RUNNING)) || + (ifp->if_flags & IFF_LOOPBACK)) + continue; + + /* + * Look for entry already setup for this device + */ + for (nif = nif_head; nif; nif = nif->nf_next) + if (nif->nf_ifp == ifp) + break; + if (nif) + continue; + + if (ifp->if_output == ipl_if_output) { + printf("IP Filter: ERROR INTF 0x%lx STILL ATTACHED\n", + ifp); + continue; + } +#if (IPFDEBUG >= 2) + printf("IP Filter: nifattach nif %x opt %x\n", + ifp, ifp->if_output); +#endif + KMALLOC(nif, nif_t *); + if (!nif) { + printf("IP Filter: malloc(%d) for nif_t failed\n", + sizeof(nif_t)); + continue; + } + + nif->nf_ifp = ifp; + (void) strncpy(nif->nf_name, ifp->if_name, + sizeof(nif->nf_name)); + nif->nf_name[sizeof(nif->nf_name) - 1] = '\0'; + nif->nf_unit = ifp->if_unit; + + nif->nf_next = nif_head; + nif_head = nif; + + /* + * Activate any rules directly associated with this interface + */ + WRITE_ENTER(&ipf_mutex); + for (f = ipf_rules[0][0]; f; f = f->fr_next) { + if ((f->fr_ifa == (struct ifnet *)-1)) { + if (f->fr_ifname[0] && + (GETIFP(f->fr_ifname, 4) == ifp)) + f->fr_ifa = ifp; + } + } + for (f = ipf_rules[1][0]; f; f = f->fr_next) { + if ((f->fr_ifa == (struct ifnet *)-1)) { + if (f->fr_ifname[0] && + (GETIFP(f->fr_ifname, 4) == ifp)) + f->fr_ifa = ifp; + } + } + RWLOCK_EXIT(&ipf_mutex); + WRITE_ENTER(&ipf_nat); + for (np = nat_list; np; np = np->in_next) { + if ((np->in_ifps[0] == (void *)-1)) { + if (np->in_ifnames[0][0] && + (GETIFP(np->in_ifnames[0], 4) == ifp)) + np->in_ifps[0] = (void *)ifp; + } + if ((np->in_ifps[1] == (void *)-1)) { + if (np->in_ifnames[1][0] && + (GETIFP(np->in_ifnames[1], 4) == ifp)) + np->in_ifps[1] = (void *)ifp; + } + } + RWLOCK_EXIT(&ipf_nat); + + nif->nf_output = ifp->if_output; + ifp->if_output = ipl_if_output; + +#if (IPFDEBUG >= 2) + printf("IP Filter: nifattach: ifp(%lx)->if_output FROM %lx TO %lx\n", + ifp, nif->nf_output, ifp->if_output); +#endif + + printf("IP Filter: attach to [%s,%d]\n", + nif->nf_name, ifp->if_unit); + } + if (!nif_head) + printf("IP Filter: not attached to any interfaces\n"); + + nif_interfaces = in_interfaces; + + MUTEX_EXIT(&ipfi_mutex); + + return; +} + + +/* + * unhook the IP filter from all defined interfaces with IP addresses + */ +static void +nifdetach() +{ + nif_t *nif, *qf2, **qp; + struct ifnet *ifp; + + MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */ + /* + * Make two passes, first get rid of all the unknown devices, next + * unlink known devices. + */ + for (qp = &nif_head; (nif = *qp); ) { + for (ifp = ifnet; ifp; ifp = ifp->if_next) + if (nif->nf_ifp == ifp) + break; + if (ifp) { + qp = &nif->nf_next; + continue; + } + printf("IP Filter: removing [%s]\n", nif->nf_name); + *qp = nif->nf_next; + KFREE(nif); + } + + while ((nif = nif_head)) { + nif_head = nif->nf_next; + for (ifp = ifnet; ifp; ifp = ifp->if_next) + if (nif->nf_ifp == ifp) + break; + if (ifp) { + printf("IP Filter: detaching [%s,%d]\n", + nif->nf_name, ifp->if_unit); + +#if (IPFDEBUG >= 4) + printf("IP Filter: nifdetach: ifp(%lx)->if_output FROM %lx TO %lx\n", + ifp, ifp->if_output, nif->nf_output); +#endif + ifp->if_output = nif->nf_output; + } + KFREE(nif); + } + MUTEX_EXIT(&ipfi_mutex); + + return; +} + + +void +ipl_ipfilter_detach(void) +{ +#ifdef IPFILTER_LKM + nifdetach(); + MUTEX_ENTER(&ipfi_mutex); /* sets interrupt priority level to splhi */ + + if (ipff_addr) { + *ipff_addr = 0; + + if (ipfk_addr) { + bcopy(ipfk_code, ipfk_addr, sizeof(ipfk_code)); + icache_inval(ipfk_addr - 16, sizeof(ipfk_code)+32); + } + + *ipff_addr = ipff_value; + } + + MUTEX_EXIT(&ipfi_mutex); +#else + extern int ipfilterflag; + + nifdetach(); + + ipfilterflag = 0; +#endif +} + + +/* this function is called from ipf_slowtimer at 500ms intervals to + keep our interface list in sync */ +void +ipl_ipfilter_intfsync(void) +{ + MUTEX_ENTER(&ipfi_mutex); + if (nif_interfaces != in_interfaces) { + /* if the number of interfaces has changed, resync */ + MUTEX_EXIT(&ipfi_mutex); + ipf_sync(&ipfmain, NULL); + } else + MUTEX_EXIT(&ipfi_mutex); +} + +#ifdef IPFILTER_LKM +/* this routine should be treated as an interrupt routine and should + not call any routines that would cause it to sleep, such as: biowait(), + sleep(), psema() or delay(). +*/ +int +iplunload(void) +{ + int error = 0; + + if (ipf_refcnt) + return EBUSY; + + WRITE_ENTER(&ipf_global); + error = ipl_detach(); + if (error != 0) { + RWLOCK_EXIT(&ipf_global); + return error; + } + ipf_running = -2; + +#if (IRIX < 60500) + LOCK_DEALLOC(ipl_mutex.l); + LOCK_DEALLOC(ipf_rw.l); + LOCK_DEALLOC(ipf_auth.l); + LOCK_DEALLOC(ipf_natfrag.l); + LOCK_DEALLOC(ipf_ipidfrag.l); + LOCK_DEALLOC(ipf_tokens.l); + LOCK_DEALLOC(ipf_stinsert.l); + LOCK_DEALLOC(ipf_nat_new.l); + LOCK_DEALLOC(ipf_natio.l); + LOCK_DEALLOC(ipf_nat.l); + LOCK_DEALLOC(ipf_state.l); + LOCK_DEALLOC(ipf_frag.l); + LOCK_DEALLOC(ipf_auth_mx.l); + LOCK_DEALLOC(ipf_mutex.l); + LOCK_DEALLOC(ipf_frcache.l); + LOCK_DEALLOC(ipfi_mutex.l); + RWLOCK_EXIT(&ipf_global); + LOCK_DEALLOC(ipf_global.l); +#else + MUTEX_DESTROY(&ipf_rw); + MUTEX_DESTROY(&ipfi_mutex); + MUTEX_DESTROY(&ipf_timeoutlock); + RW_DESTROY(&ipf_mutex); + RW_DESTROY(&ipf_frcache); + RW_DESTROY(&ipf_tokens); + RWLOCK_EXIT(&ipf_global); + delay(hz); + RW_DESTROY(&ipf_global); +#endif + + printf("%s unloaded\n", ipfilter_version); + + delay(hz); + + return 0; +} +#endif + +void +ipfilterinit(void) +{ +#ifdef IPFILTER_LKM + int error; +#endif + +#if (IRIX < 60500) + ipfi_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); +ipf_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); +ipf_frcache.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); +ipf_timeoutlock.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_global.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_frag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_state.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_nat.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_stinsert.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_natfrag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_ipidfrag.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_tokens.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_auth.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipf_rw.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + ipl_mutex.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP); + + if (!ipfi_mutex.l || !ipf_mutex.l || !ipf_timeoutlock.l || + !ipf_frag.l || !ipf_state.l || !ipf_nat.l || !ipf_natfrag.l || + !ipf_auth.l || !ipf_rw.l || !ipf_ipidfrag.l || !ipl_mutex.l || + !ipf_stinsert.l || !ipf_auth_mx.l || !ipf_frcache.l || + !ipf_tokens.l) + panic("IP Filter: LOCK_ALLOC failed"); +#else + MUTEX_INIT(&ipf_rw, "ipf rw mutex"); + MUTEX_INIT(&ipf_timeoutlock, "ipf timeout mutex"); + RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); + RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); + RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock"); +#endif + +#ifdef IPFILTER_LKM + error = ipl_attach(); + if (error) { + iplunload(); + } else { + char *defpass; + + if (FR_ISPASS(ipf_pass)) + defpass = "pass"; + else if (FR_ISBLOCK(ipf_pass)) + defpass = "block"; + else + defpass = "no-match -> block"; + + printf("%s initialized. Default = %s all, Logging = %s%s\n", + ipfilter_version, defpass, +# ifdef IPFILTER_LOG + "enabled", +# else + "disabled", +# endif +# ifdef IPFILTER_COMPILED + " (COMPILED)" +# else + "" +# endif + ); + } +#endif + + return; +} diff --git a/contrib/ipfilter/mln_ipl.c b/contrib/ipfilter/mln_ipl.c new file mode 100644 index 0000000..28b5407 --- /dev/null +++ b/contrib/ipfilter/mln_ipl.c @@ -0,0 +1,355 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +/* + * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate + * its own major char number! Way cool patch! + */ + + +#include <sys/param.h> + +/* + * Post NetBSD 1.2 has the PFIL interface for packet filters. This turns + * on those hooks. We don't need any special mods with this! + */ +#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \ + (defined(NetBSD1_2) && NetBSD1_2 > 1) +# define NETBSD_PF +#endif + +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/proc.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/vnode.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/mount.h> +#include <sys/exec.h> +#include <sys/mbuf.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <sys/lkm.h> +#include <sys/poll.h> +#include <sys/select.h> +#include "ipl.h" +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_auth.h" +#include "ip_state.h" +#include "ip_nat.h" +#include "ip_sync.h" + +#if !defined(__NetBSD_Version__) || __NetBSD_Version__ < 103050000 +#define vn_lock(v,f) VOP_LOCK(v) +#endif + +#if !defined(VOP_LEASE) && defined(LEASE_CHECK) +#define VOP_LEASE LEASE_CHECK +#endif + + +extern int lkmenodev __P((void)); + +#if NetBSD >= 199706 +int ipflkm_lkmentry __P((struct lkm_table *, int, int)); +#else +int xxxinit __P((struct lkm_table *, int, int)); +#endif +static int ipf_unload __P((void)); +static int ipf_load __P((void)); +static int ipf_remove __P((void)); +static int ipfaction __P((struct lkm_table *, int)); +static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, + IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, + IPLOOKUP_NAME, NULL }; + +int ipf_major = 0; +extern ipf_main_softc_t ipfmain; +extern const struct cdevsw ipl_cdevsw; + +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) +MOD_DEV(IPL_VERSION, "ipf", NULL, -1, &ipl_cdevsw, -1); +#else +MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); +#endif + +extern int vd_unuseddev __P((void)); +extern struct cdevsw cdevsw[]; +extern int nchrdev; + + +int +#if NetBSD >= 199706 +ipflkm_lkmentry(lkmtp, cmd, ver) +#else +xxxinit(lkmtp, cmd, ver) +#endif + struct lkm_table *lkmtp; + int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction); +} + + +static int +ipfaction(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ +#if !defined(__NetBSD__) || (__NetBSD_Version__ < 106080000) + int i; +#endif + struct lkm_dev *args = lkmtp->private.lkm_dev; + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) +# if (__NetBSD_Version__ < 200000000) + err = devsw_attach(args->lkm_devname, + args->lkm_bdev, &args->lkm_bdevmaj, + args->lkm_cdev, &args->lkm_cdevmaj); + if (err != 0) + return (err); +# endif + ipf_major = args->lkm_cdevmaj; +#else + for (i = 0; i < nchrdev; i++) + if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev || + cdevsw[i].d_open == ipfopen) + break; + if (i == nchrdev) { + printf("IP Filter: No free cdevsw slots\n"); + return ENODEV; + } + + ipf_major = i; + args->lkm_offset = i; /* slot in cdevsw[] */ +#endif + printf("IP Filter: loaded into slot %d\n", ipf_major); + return ipf_load(); + case LKM_E_UNLOAD : +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) + devsw_detach(args->lkm_bdev, args->lkm_cdev); + args->lkm_bdevmaj = -1; + args->lkm_cdevmaj = -1; +#endif + err = ipf_unload(); + if (!err) + printf("IP Filter: unloaded from slot %d\n", + ipf_major); + break; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return err; +} + + +static int +ipf_remove() +{ + char *name; + struct nameidata nd; + int error, i; + + for (i = 0; (name = ipf_devfiles[i]); i++) { +#if (__NetBSD_Version__ > 106009999) +# if (__NetBSD_Version__ > 399001400) +# if (__NetBSD_Version__ > 499001400) + NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, + name); +# else + NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, + name, curlwp); +# endif +# else + NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, UIO_SYSSPACE, + name, curproc); +# endif +#else + NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); +#endif + if ((error = namei(&nd))) + return (error); +#if (__NetBSD_Version__ > 399001400) +# if (__NetBSD_Version__ > 399002000) +# if (__NetBSD_Version__ < 499001400) + VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE); +# endif +# else + VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); +# endif +#else + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); +#endif +#if !defined(__NetBSD_Version__) || (__NetBSD_Version__ < 106000000) + vn_lock(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY); +#endif +#if (__NetBSD_Version__ >= 399002000) +# if (__NetBSD_Version__ < 499001400) + VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_cred, LEASE_WRITE); +# endif +#else +# if (__NetBSD_Version__ > 399001400) + VOP_LEASE(nd.ni_vp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); +# else + VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); +# endif +#endif + (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); + } + return 0; +} + + +static int +ipf_unload() +{ + int error = 0; + + /* + * Unloading - remove the filter rule check from the IP + * input/output stream. + */ + if (ipfmain.ipf_refcnt) + error = EBUSY; + else if (ipfmain.ipf_running >= 0) { + error = ipfdetach(&ipfmain); + if (error == 0) { + ipf_destroy_all(&ipfmain); + ipf_unload_all(); + } + } + + if (error == 0) { + ipfmain.ipf_running = -2; + error = ipf_remove(); + printf("%s unloaded\n", ipfilter_version); + } + return error; +} + + +static int +ipf_load() +{ + struct nameidata nd; + struct vattr vattr; + int error = 0, fmode = S_IFCHR|0600, i; + char *name; + + /* + * XXX Remove existing device nodes prior to creating new ones + * XXX using the assigned LKM device slot's major number. In a + * XXX perfect world we could use the ones specified by cdevsw[]. + */ + (void)ipf_remove(); + + bzero((char *)&ipfmain, sizeof(ipfmain)); + error = ipf_load_all(); + if (error != 0) + return error; + if (ipf_create_all(&ipfmain) == NULL) { + ipf_unload_all(); + return EIO; + } + + error = ipfattach(&ipfmain); + if (error != 0) { + (void) ipf_unload(); + return error; + } + + for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) { +#if (__NetBSD_Version__ > 399001400) +# if (__NetBSD_Version__ > 499001400) + NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name); +# else + NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curlwp); +# endif +#else + NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); +#endif + if ((error = namei(&nd))) + break; + if (nd.ni_vp != NULL) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + vrele(nd.ni_vp); + error = EEXIST; + break; + } + VATTR_NULL(&vattr); + vattr.va_type = VCHR; + vattr.va_mode = (fmode & 07777); + vattr.va_rdev = (ipf_major << 8) | i; +#if (__NetBSD_Version__ > 399001400) +# if (__NetBSD_Version__ >= 399002000) +# if (__NetBSD_Version__ < 499001400) + VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_cred, LEASE_WRITE); +# endif +# else + VOP_LEASE(nd.ni_dvp, curlwp, curlwp->l_proc->p_ucred, LEASE_WRITE); +# endif +#else + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); +#endif + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); + if (error == 0) + vput(nd.ni_vp); + } + + if (error == 0) { + char *defpass; + + if (FR_ISPASS(ipfmain.ipf_pass)) + defpass = "pass"; + else if (FR_ISBLOCK(ipfmain.ipf_pass)) + defpass = "block"; + else + defpass = "no-match -> block"; + + printf("%s initialized. Default = %s all, Logging = %s%s\n", + ipfilter_version, defpass, +#ifdef IPFILTER_LOG + "enabled", +#else + "disabled", +#endif +#ifdef IPFILTER_COMPILED + " (COMPILED)" +#else + "" +#endif + ); + ipfmain.ipf_running = 1; + } + return error; +} diff --git a/contrib/ipfilter/mln_rule.c b/contrib/ipfilter/mln_rule.c new file mode 100644 index 0000000..2df3376 --- /dev/null +++ b/contrib/ipfilter/mln_rule.c @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/exec.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <sys/lkm.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_rules.h" + + +static int ipfruleaction __P((struct lkm_table *, int)); + +#ifdef IPFILTER_LKM +# if NetBSD >= 199706 +int ipfrule_lkmentry __P((struct lkm_table *, int, int)); +# else +int xxxinit __P((struct lkm_table *, int, int)); +# endif + + +MOD_MISC("IPFilter Rules"); + +# if NetBSD >= 199706 +int ipfrule_lkmentry(lkmtp, cmd, ver) +# else +int xxxinit(lkmtp, cmd, ver) +# endif + struct lkm_table *lkmtp; + int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, ipfruleaction, ipfruleaction, ipfruleaction); +} + +static int ipfruleaction(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + + err = ipfrule_add(); + if (!err) + ipf_refcnt++; + break; + case LKM_E_UNLOAD : + err = ipfrule_remove(); + if (!err) + ipf_refcnt--; + break; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return err; +} +#endif /* IPFILTER_LKM */ diff --git a/contrib/ipfilter/mlo_ipl.c b/contrib/ipfilter/mlo_ipl.c new file mode 100644 index 0000000..35556fa --- /dev/null +++ b/contrib/ipfilter/mlo_ipl.c @@ -0,0 +1,364 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/proc.h> +#include <sys/uio.h> +#include <sys/kernel.h> +#include <sys/vnode.h> +#include <sys/namei.h> +#include <sys/malloc.h> +#include <sys/mount.h> +#include <sys/exec.h> +#include <sys/mbuf.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <sys/lkm.h> +#include "ipl.h" +#include "ip_compat.h" +#include "ip_fil.h" + +#define vn_lock(v,f) VOP_LOCK(v) + +#if !defined(VOP_LEASE) && defined(LEASE_CHECK) +#define VOP_LEASE LEASE_CHECK +#endif + + +extern int lkmenodev __P((void)); + +#if OpenBSD >= 200311 +int if_ipf_lkmentry __P((struct lkm_table *, int, int)); +#else +int if_ipf __P((struct lkm_table *, int, int)); +#endif +static int ipf_unload __P((void)); +static int ipf_load __P((void)); +static int ipf_remove __P((void)); +static int ipfaction __P((struct lkm_table *, int)); +static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, + IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, + IPLOOKUP_NAME, NULL }; + + +struct cdevsw ipfdevsw = +{ + ipfopen, /* open */ + ipfclose, /* close */ + ipfread, /* read */ + (void *)nullop, /* write */ + ipfioctl, /* ioctl */ + (void *)nullop, /* stop */ + (void *)NULL, /* tty */ + (void *)nullop, /* select */ + (void *)nullop, /* mmap */ + NULL /* strategy */ +}; + +int ipf_major = 0; + +MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipfdevsw); + +extern int vd_unuseddev __P((void)); +extern struct cdevsw cdevsw[]; +extern int nchrdev; + + +#if OpenBSD >= 200311 +int if_ipf_lkmentry (lkmtp, cmd, ver) +#else +int if_ipf(lkmtp, cmd, ver) +#endif + struct lkm_table *lkmtp; + int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, ipfaction, ipfaction, ipfaction); +} + +int lkmexists __P((struct lkm_table *)); /* defined in /sys/kern/kern_lkm.c */ + +static int ipfaction(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + int i; + struct lkm_dev *args = lkmtp->private.lkm_dev; + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + + for (i = 0; i < nchrdev; i++) + if (cdevsw[i].d_open == (dev_type_open((*)))lkmenodev || + cdevsw[i].d_open == ipfopen) + break; + if (i == nchrdev) { + printf("IP Filter: No free cdevsw slots\n"); + return ENODEV; + } + + ipf_major = i; + args->lkm_offset = i; /* slot in cdevsw[] */ + printf("IP Filter: loaded into slot %d\n", ipf_major); + return ipf_load(); + case LKM_E_UNLOAD : + err = ipf_unload(); + if (!err) + printf("IP Filter: unloaded from slot %d\n", + ipf_major); + break; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return err; +} + + +static int ipf_remove() +{ + struct nameidata nd; + int error, i; + char *name; + + for (i = 0; (name = ipf_devfiles[i]); i++) { +#if OpenBSD >= 200311 + NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, + name, curproc); +#else + NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); +#endif + if ((error = namei(&nd))) + return (error); + VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); +#if OpenBSD < 200311 + VOP_LOCK(nd.ni_vp, LK_EXCLUSIVE | LK_RETRY, curproc); + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); +#else + (void)uvm_vnp_uncache(nd.ni_vp); + + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); +#endif + (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); + } + return 0; +} + + +static int ipf_unload() +{ + int error = 0; + + /* + * Unloading - remove the filter rule check from the IP + * input/output stream. + */ + if (ipf_refcnt) + error = EBUSY; + else if (ipf_running >= 0) + error = ipfdetach(); + + if (error == 0) { + ipf_running = -2; + error = ipf_remove(); + printf("%s unloaded\n", ipfilter_version); + } + return error; +} + + +static int ipf_load() +{ + struct nameidata nd; + struct vattr vattr; + int error = 0, fmode = S_IFCHR|0600, i; + char *name; + + /* + * XXX Remove existing device nodes prior to creating new ones + * XXX using the assigned LKM device slot's major number. In a + * XXX perfect world we could use the ones specified by cdevsw[]. + */ + (void)ipf_remove(); + + error = ipfattach(); + + for (i = 0; (error == 0) && (name = ipf_devfiles[i]); i++) { + NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); + if ((error = namei(&nd))) + break; + if (nd.ni_vp != NULL) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + vrele(nd.ni_vp); + error = EEXIST; + break; + } + VATTR_NULL(&vattr); + vattr.va_type = VCHR; + vattr.va_mode = (fmode & 07777); + vattr.va_rdev = (ipf_major << 8) | i; + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); + } + + if (error == 0) { + char *defpass; + + if (FR_ISPASS(ipf_pass)) + defpass = "pass"; + else if (FR_ISBLOCK(ipf_pass)) + defpass = "block"; + else + defpass = "no-match -> block"; + + printf("%s initialized. Default = %s all, Logging = %s%s\n", + ipfilter_version, defpass, +#ifdef IPFILTER_LOG + "enabled", +#else + "disabled", +#endif +#ifdef IPFILTER_COMPILED + " (COMPILED)" +#else + "" +#endif + ); + ipf_running = 1; + } + return error; +} + + +/* + * routines below for saving IP headers to buffer + */ +int +ipfopen(dev, flags, devtype, p) + dev_t dev; + int flags; + int devtype; + struct proc *p; +{ + u_int min = GET_MINOR(dev); + int error; + + if (IPL_LOGMAX < min) { + error = ENXIO; + } else { + switch (unit) + { + case IPL_LOGIPF : + case IPL_LOGNAT : + case IPL_LOGSTATE : + case IPL_LOGAUTH : + case IPL_LOGLOOKUP : + case IPL_LOGSYNC : +#ifdef IPFILTER_SCAN + case IPL_LOGSCAN : +#endif + error = 0; + break; + default : + error = ENXIO; + break; + } + } + return error; +} + + +int +ipfclose(dev, flags, devtype, p) + dev_t dev; + int flags; + int devtype; + struct proc *p; +{ + u_int min = GET_MINOR(dev); + + if (IPL_LOGMAX < min) + min = ENXIO; + else + min = 0; + return min; +} + + +/* + * ipfread/ipflog + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +int +ipfread(dev, uio, ioflag) + dev_t dev; + register struct uio *uio; + int ioflag; +{ + + if (ipf_running < 1) + return EIO; + + if (GET_MINOR(dev) == IPL_LOGSYNC) + return ipfsync_read(uio); + +#ifdef IPFILTER_LOG + return ipflog_read(GET_MINOR(dev), uio); +#else + return ENXIO; +#endif +} + + +/* + * ipfwrite + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +int +#if (BSD >= 199306) +ipfwrite(dev, uio, ioflag) + int ioflag; +#else +ipfwrite(dev, uio) +#endif + dev_t dev; + register struct uio *uio; +{ + + if (ipf_running < 1) + return EIO; + + if (GET_MINOR(dev) == IPL_LOGSYNC) + return ipfsync_write(uio); + return ENXIO; +} diff --git a/contrib/ipfilter/mlo_rule.c b/contrib/ipfilter/mlo_rule.c new file mode 100644 index 0000000..dbd4305 --- /dev/null +++ b/contrib/ipfilter/mlo_rule.c @@ -0,0 +1,80 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <sys/ioctl.h> +#include <sys/kernel.h> +#include <sys/mbuf.h> +#include <sys/exec.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <sys/lkm.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_rules.h" + + +#ifdef IPFILTER_LKM + +static int ipfruleaction __P((struct lkm_table *, int)); + +int ipfrule __P((struct lkm_table *, int, int)); + + +MOD_MISC("IPFilter Rules"); + +int ipfrule(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, ipfruleaction, ipfruleaction, ipfruleaction); +} + +int lkmexists __P((struct lkm_table *)); /* defined in /sys/kern/kern_lkm.c */ + +static int ipfruleaction(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + + err = ipfrule_add(); + if (!err) + ipf_refcnt++; + break; + case LKM_E_UNLOAD : + err = ipfrule_remove(); + if (!err) + ipf_refcnt--; + break; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return err; +} +#endif /* IPFILTER_LKM */ diff --git a/contrib/ipfilter/mls_ipl.c b/contrib/ipfilter/mls_ipl.c new file mode 100644 index 0000000..4388b61 --- /dev/null +++ b/contrib/ipfilter/mls_ipl.c @@ -0,0 +1,351 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate + * its own major char number! Way cool patch! + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/file.h> +#include <sys/socket.h> +#include <sys/conf.h> +#include <sys/syslog.h> +#include <sys/buf.h> +#include <sys/mbuf.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/uio.h> +#include <sys/vnode.h> +#include <sundev/mbvar.h> +#include <sun/autoconf.h> +#include <sun/vddrv.h> +#if defined(sun4c) || defined(sun4m) +# include <sun/openprom.h> +#endif +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <net/if.h> +#include "ipl.h" +#include "ip_compat.h" +#include "ip_fil.h" + + +#if !defined(lint) +static const char sccsid[] = "@(#)mls_ipl.c 2.6 10/15/95 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +extern int ipfdetach __P((void)); +#ifndef IPFILTER_LOG +#define ipfread nulldev +#endif +extern int nulldev __P((void)); +extern int errno; + +extern int nodev __P((void)); + +static int unload __P((void)); +static int ipf_attach __P((void)); +int xxxinit __P((u_int, struct vddrv *, caddr_t, struct vdstat *)); +static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, + IPAUTH_NAME, IPSYNC_NAME, IPSCAN_NAME, + IPLOOKUP_NAME, NULL }; +static int ipfopen __P((dev_t, int)); +static int ipfclose __P((dev_t, int)); +static int ipfread __P((dev_t, struct uio *)); +static int ipfwrite __P((dev_t, struct uio *)); + + +struct cdevsw ipfdevsw = +{ + ipfopen, ipfclose, ipfread, nulldev, + ipfioctl, nulldev, nulldev, nulldev, + 0, nulldev, +}; + + +struct dev_ops ipf_ops = +{ + 1, + ipfidentify, + ipfattach, + ipfopen, + ipfclose, + ipfread, + ipfwrite, + NULL, /* strategy */ + NULL, /* dump */ + 0, /* psize */ + ipfioctl, + NULL, /* reset */ + NULL /* mmap */ +}; + +int ipf_major = 0; + +#ifdef sun4m +struct vdldrv vd = +{ + VDMAGIC_PSEUDO, + IPL_VERSION, + &ipf_ops, + NULL, + &ipfdevsw, + 0, + 0, + NULL, + NULL, + NULL, + 0, + 1, +}; +#else /* sun4m */ +struct vdldrv vd = +{ + VDMAGIC_PSEUDO, /* magic */ + IPL_VERSION, +#ifdef sun4c + &ipf_ops, /* dev_ops */ +#else + NULL, /* struct mb_ctlr *mb_ctlr */ + NULL, /* struct mb_driver *mb_driver */ + NULL, /* struct mb_device *mb_device */ + 0, /* num ctlrs */ + 1, /* numdevs */ +#endif /* sun4c */ + NULL, /* bdevsw */ + &ipfdevsw, /* cdevsw */ + 0, /* block major */ + 0, /* char major */ +}; +#endif /* sun4m */ + +extern int vd_unuseddev __P((void)); +extern struct cdevsw cdevsw[]; +extern int nchrdev; + +xxxinit(fc, vdp, data, vds) + u_int fc; + struct vddrv *vdp; + caddr_t data; + struct vdstat *vds; +{ + struct vdioctl_load *vdi = (struct vdioctl_load *)data; + + switch (fc) + { + case VDLOAD: + { + struct vdconf *vdc; + if (vdi && vdi->vdi_userconf) + for (vdc = vdi->vdi_userconf; vdc->vdc_type; vdc++) + if (vdc->vdc_type == VDCCHARMAJOR) { + ipf_major = vdc->vdc_data; + break; + } + + if (!ipf_major) { + while (ipf_major < nchrdev && + cdevsw[ipf_major].d_open != vd_unuseddev) + ipf_major++; + if (ipf_major == nchrdev) + return ENODEV; + } + vdp->vdd_vdtab = (struct vdlinkage *)&vd; + vd.Drv_charmajor = ipf_major; + return ipf_attach(); + } + case VDUNLOAD: + return unload(); + case VDSTAT: + return 0; + default: + return EIO; + } +} + + +static int +unload() +{ + int err = 0, i; + char *name; + + if (ipf_refcnt != 0) + err = EBUSY; + else if (ipf_running >= 0) + err = ipfdetach(); + if (err) + return err; + + ipf_running = -2; + for (i = 0; (name = ipf_devfiles[i]); i++) + (void) vn_remove(name, UIO_SYSSPACE, FILE); + printf("%s unloaded\n", ipfilter_version); + return 0; +} + + +static int +ipf_attach() +{ + struct vnode *vp; + struct vattr vattr; + int error = 0, fmode = S_IFCHR|0600, i; + char *name; + + error = ipfattach(); + if (error) + return error; + + for (i = 0; (name = ipf_devfiles[i]); i++) { + (void) vn_remove(name, UIO_SYSSPACE, FILE); + vattr_null(&vattr); + vattr.va_type = MFTOVT(fmode); + vattr.va_mode = (fmode & 07777); + vattr.va_rdev = (ipf_major << 8) | i; + + error = vn_create(name, UIO_SYSSPACE, &vattr, EXCL, 0, &vp); + if (error) { + printf("IP Filter: vn_create(%s) = %d\n", name, error); + break; + } else { + VN_RELE(vp); + } + } + + if (error == 0) { + char *defpass; + + if (FR_ISPASS(ipf_pass)) + defpass = "pass"; + else if (FR_ISBLOCK(ipf_pass)) + defpass = "block"; + else + defpass = "no-match -> block"; + + printf("%s initialized. Default = %s all, Logging = %s%s\n", + ipfilter_version, defpass, +#ifdef IPFILTER_LOG + "enabled", +#else + "disabled", +#endif +#ifdef IPFILTER_COMPILED + " (COMPILED)" +#else + "" +#endif + ); + ipf_running = 1; + } + return error; +} + + +/* + * routines below for saving IP headers to buffer + */ +static int +ipfopen(dev, flags) + dev_t dev; + int flags; +{ + u_int unit = GET_MINOR(dev); + int error; + + if (IPL_LOGMAX < unit) { + error = ENXIO; + } else { + switch (unit) + { + case IPL_LOGIPF : + case IPL_LOGNAT : + case IPL_LOGSTATE : + case IPL_LOGAUTH : + case IPL_LOGLOOKUP : + case IPL_LOGSYNC : +#ifdef IPFILTER_SCAN + case IPL_LOGSCAN : +#endif + error = 0; + break; + default : + error = ENXIO; + break; + } + } + return error; +} + + +static int +ipfclose(dev, flags) + dev_t dev; + int flags; +{ + u_int unit = GET_MINOR(dev); + + if (IPL_LOGMAX < unit) + unit = ENXIO; + else + unit = 0; + return unit; +} + + +/* + * ipfread/ipflog + * both of these must operate with at least splnet() lest they be + * called during packet processing and cause an inconsistancy to appear in + * the filter lists. + */ +static int +ipfread(dev, uio) + dev_t dev; + register struct uio *uio; +{ + + if (ipf_running < 1) { + ipfmain.ipf_interror = 130006; + return EIO; + } + +#ifdef IPFILTER_LOG + return ipflog_read(GET_MINOR(dev), uio); +#else + ipfmain.ipf_interror = 130007; + return ENXIO; +#endif +} + + +/* + * ipfwrite + */ +static int +ipfwrite(dev, uio) + dev_t dev; + register struct uio *uio; +{ + + if (ipf_running < 1) { + ipfmain.ipf_interror = 130008; + return EIO; + } + + if (getminor(dev) == IPL_LOGSYNC) + return ipfsync_write(uio); + ipfmain.ipf_interror = 130009; + return ENXIO; +} diff --git a/contrib/ipfilter/mls_rule.c b/contrib/ipfilter/mls_rule.c new file mode 100644 index 0000000..e37df0c --- /dev/null +++ b/contrib/ipfilter/mls_rule.c @@ -0,0 +1,116 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +/* + * 29/12/94 Added code from Marc Huber <huber@fzi.de> to allow it to allocate + * its own major char number! Way cool patch! + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/file.h> +#include <sys/socket.h> +#include <sys/conf.h> +#include <sys/syslog.h> +#include <sys/buf.h> +#include <sys/mbuf.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/uio.h> +#include <sys/vnode.h> +#include <sundev/mbvar.h> +#include <sun/autoconf.h> +#include <sun/vddrv.h> +#if defined(sun4c) || defined(sun4m) +# include <sun/openprom.h> +#endif +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcpip.h> +#include <net/if.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_rules.h" + + +extern int errno; + + +int xxxinit __P((u_int, struct vddrv *, caddr_t, struct vdstat *)); + +int ipl_major = 0; + +#ifdef sun4m +struct vdldrv vd = +{ + VDMAGIC_USER, + "IP Filter rules", + NULL, + NULL, + NULL, + 0, + 0, + NULL, + NULL, + NULL, + 0, + 1, +}; +#else /* sun4m */ +struct vdldrv vd = +{ + VDMAGIC_USER, /* magic */ + "IP Filter rules", +#ifdef sun4c + NULL, /* dev_ops */ +#else + NULL, /* struct mb_ctlr *mb_ctlr */ + NULL, /* struct mb_driver *mb_driver */ + NULL, /* struct mb_device *mb_device */ + 0, /* num ctlrs */ + 1, /* numdevs */ +#endif /* sun4c */ + NULL, /* bdevsw */ + NULL, /* cdevsw */ + 0, /* block major */ + 0, /* char major */ +}; +#endif /* sun4m */ + + +xxxinit(fc, vdp, data, vds) + u_int fc; + struct vddrv *vdp; + caddr_t data; + struct vdstat *vds; +{ + struct vdioctl_load *vdi = (struct vdioctl_load *)data; + int err; + + switch (fc) + { + case VDLOAD: + err = ipfrule_add(); + if (!err) + ipf_refcnt++; + break; + case VDUNLOAD: + err = ipfrule_remove(); + if (!err) + ipf_refcnt--; + break; + case VDSTAT: + err = 0; + break; + default: + err = EIO; + break; + } +} diff --git a/contrib/ipfilter/mlso_rule.c b/contrib/ipfilter/mlso_rule.c new file mode 100644 index 0000000..a9395f2 --- /dev/null +++ b/contrib/ipfilter/mlso_rule.c @@ -0,0 +1,130 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#pragma ident "@(#)$Id$" + +#include <sys/systm.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/errno.h> +#include <sys/uio.h> +#include <sys/buf.h> +#include <sys/modctl.h> +#include <sys/open.h> +#include <sys/kmem.h> +#include <sys/conf.h> +#include <sys/cmn_err.h> +#include <sys/stat.h> +#include <sys/cred.h> +#include <sys/dditypes.h> +#include <sys/stream.h> +#include <sys/poll.h> +#include <sys/autoconf.h> +#include <sys/byteorder.h> +#include <sys/socket.h> +#include <sys/dlpi.h> +#include <sys/stropts.h> +#include <sys/sockio.h> +#include <net/if.h> +#if SOLARIS2 >= 6 +# include <net/if_types.h> +#endif +#include <net/af.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/if_ether.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/udp.h> +#include <netinet/tcpip.h> +#include <netinet/ip_icmp.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_rules.h" + +char _depends_on[] = "drv/ipf"; + + +extern ipf_main_softc_t ipfmain; +extern struct mod_ops mod_miscops; +static struct modlmisc ipfrulemod = { + &mod_miscops, + "IP Filter rules" +}; + +static struct modlinkage modlink1 = { + MODREV_1, + &ipfrulemod, + NULL +}; + + +int _init() +{ + int ipfruleinst; + + ipfruleinst = mod_install(&modlink1); +#ifdef IPFRULEDEBUG + cmn_err(CE_NOTE, "IP Filter Rules: _init() = %d", ipfruleinst); +#endif + + if (ipfruleinst == 0) { + if (ipfmain.ipf_running >= 0) { + ipfruleinst = ipfrule_add(); + if (!ipfruleinst) + ipfmain.ipf_refcnt++; + else { + cmn_err(CE_NOTE, + "IP Filter Rules: ipfrule_add failed"); + ipfruleinst = -1; + } + } else + ipfruleinst = -1; + } + if (ipfruleinst == 0) + cmn_err(CE_CONT, "IP Filter Rules: loaded\n"); + return ipfruleinst; +} + + +int _fini(void) +{ + int ipfruleinst; + + ipfruleinst = mod_remove(&modlink1); +#ifdef IPFRULEDEBUG + cmn_err(CE_NOTE, "IP Filter Rules: _fini() = %d", ipfruleinst); +#endif + if (ipfruleinst == 0) { + ipfruleinst = ipfrule_remove(); + if (!ipfruleinst) + ipfmain.ipf_refcnt--; + else + ipfruleinst = -1; + } + if (ipfruleinst == 0) + cmn_err(CE_CONT, "IP Filter Rules: unloaded\n"); + return ipfruleinst; +} + + +int _info(modinfop) + struct modinfo *modinfop; +{ + int ipfruleinst; + + ipfruleinst = mod_info(&modlink1, modinfop); +#ifdef IPFRULEDEBUG + cmn_err(CE_NOTE, "IP Filter Rules: _info(%x) = %x", + modinfop, ipfruleinst); +#endif + return ipfruleinst; +} diff --git a/contrib/ipfilter/opt_inet6.h b/contrib/ipfilter/opt_inet6.h new file mode 100644 index 0000000..43e7657 --- /dev/null +++ b/contrib/ipfilter/opt_inet6.h @@ -0,0 +1 @@ +#define INET6 diff --git a/contrib/ipfilter/opts.h b/contrib/ipfilter/opts.h new file mode 100644 index 0000000..3c8b88b --- /dev/null +++ b/contrib/ipfilter/opts.h @@ -0,0 +1,69 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * $Id$ + */ + +#ifndef __OPTS_H__ +#define __OPTS_H__ + +#ifndef SOLARIS +#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +#endif +#define OPT_REMOVE 0x000001 +#define OPT_DEBUG 0x000002 +#define OPT_AUTHSTATS 0x000004 +#define OPT_RAW 0x000008 +#define OPT_LOG 0x000010 +#define OPT_SHOWLIST 0x000020 +#define OPT_VERBOSE 0x000040 +#define OPT_DONOTHING 0x000080 +#define OPT_HITS 0x000100 +#define OPT_BRIEF 0x000200 +#define OPT_ACCNT 0x000400 +#define OPT_FRSTATES 0x000800 +#define OPT_SHOWLINENO 0x001000 +#define OPT_PRINTFR 0x002000 +#define OPT_OUTQUE FR_OUTQUE /* 0x4000 */ +#define OPT_INQUE FR_INQUE /* 0x8000 */ +#define OPT_ZERORULEST 0x010000 +#define OPT_SAVEOUT 0x020000 +#define OPT_IPSTATES 0x040000 +#define OPT_INACTIVE 0x080000 +#define OPT_NAT 0x100000 +#define OPT_GROUPS 0x200000 +#define OPT_STATETOP 0x400000 +#define OPT_FLUSH 0x800000 +#define OPT_CLEAR 0x1000000 +#define OPT_HEX 0x2000000 +#define OPT_ASCII 0x4000000 +#define OPT_NORESOLVE 0x8000000 +#define OPT_DONTOPEN 0x10000000 +#define OPT_PURGE 0x20000000 + +#define OPT_STAT OPT_FRSTATES +#define OPT_LIST OPT_SHOWLIST + + +#ifndef __P +# ifdef __STDC__ +# define __P(x) x +# else +# define __P(x) () +# endif +#endif + +#if defined(sun) && !SOLARIS +# define STRERROR(x) sys_errlist[x] +extern char *sys_errlist[]; +#else +# define STRERROR(x) strerror(x) +#endif + +extern int opts; + +#endif /* __OPTS_H__ */ diff --git a/contrib/ipfilter/pcap-bpf.h b/contrib/ipfilter/pcap-bpf.h new file mode 100644 index 0000000..51002a3 --- /dev/null +++ b/contrib/ipfilter/pcap-bpf.h @@ -0,0 +1,687 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from the Stanford/CMU enet packet filter, + * (net/enet.c) distributed as part of 4.3BSD, and code contributed + * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence + * Berkeley Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)bpf.h 7.1 (Berkeley) 5/7/91 + * + * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.37 2005/05/01 19:46:27 guy Exp $ (LBL) + */ + +/* + * This is libpcap's cut-down version of bpf.h; it includes only + * the stuff needed for the code generator and the userland BPF + * interpreter, and the libpcap APIs for setting filters, etc.. + * + * "pcap-bpf.c" will include the native OS version, as it deals with + * the OS's BPF implementation. + * + * XXX - should this all just be moved to "pcap.h"? + */ + +#ifndef BPF_MAJOR_VERSION + +#ifdef __cplusplus +extern "C" { +#endif + +/* BSD style release date */ +#define BPF_RELEASE 199606 + +#ifdef MSDOS /* must be 32-bit */ +typedef long bpf_int32; +typedef unsigned long bpf_u_int32; +#else +typedef int bpf_int32; +typedef u_int bpf_u_int32; +#endif + +/* + * Alignment macros. BPF_WORDALIGN rounds up to the next + * even multiple of BPF_ALIGNMENT. + */ +#ifndef __NetBSD__ +#define BPF_ALIGNMENT sizeof(bpf_int32) +#else +#define BPF_ALIGNMENT sizeof(long) +#endif +#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1)) + +#define BPF_MAXINSNS 512 +#define BPF_MAXBUFSIZE 0x8000 +#define BPF_MINBUFSIZE 32 + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + u_int bf_len; + struct bpf_insn *bf_insns; +}; + +/* + * Struct return by BIOCVERSION. This represents the version number of + * the filter language described by the instruction encodings below. + * bpf understands a program iff kernel_major == filter_major && + * kernel_minor >= filter_minor, that is, if the value returned by the + * running kernel has the same major number and a minor number equal + * equal to or less than the filter being downloaded. Otherwise, the + * results are undefined, meaning an error may be returned or packets + * may be accepted haphazardly. + * It has nothing to do with the source code version. + */ +struct bpf_version { + u_short bv_major; + u_short bv_minor; +}; +/* Current version number of filter architecture. */ +#define BPF_MAJOR_VERSION 1 +#define BPF_MINOR_VERSION 1 + +/* + * Data-link level type codes. + * + * Do *NOT* add new values to this list without asking + * "tcpdump-workers@tcpdump.org" for a value. Otherwise, you run the + * risk of using a value that's already being used for some other purpose, + * and of having tools that read libpcap-format captures not being able + * to handle captures with your new DLT_ value, with no hope that they + * will ever be changed to do so (as that would destroy their ability + * to read captures using that value for that other purpose). + */ + +/* + * These are the types that are the same on all platforms, and that + * have been defined by <net/bpf.h> for ages. + */ +#define DLT_NULL 0 /* BSD loopback encapsulation */ +#define DLT_EN10MB 1 /* Ethernet (10Mb) */ +#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ +#define DLT_AX25 3 /* Amateur Radio AX.25 */ +#define DLT_PRONET 4 /* Proteon ProNET Token Ring */ +#define DLT_CHAOS 5 /* Chaos */ +#define DLT_IEEE802 6 /* IEEE 802 Networks */ +#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ +#define DLT_SLIP 8 /* Serial Line IP */ +#define DLT_PPP 9 /* Point-to-point Protocol */ +#define DLT_FDDI 10 /* FDDI */ + +/* + * These are types that are different on some platforms, and that + * have been defined by <net/bpf.h> for ages. We use #ifdefs to + * detect the BSDs that define them differently from the traditional + * libpcap <net/bpf.h> + * + * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS, + * but I don't know what the right #define is for BSD/OS. + */ +#define DLT_ATM_RFC1483 11 /* LLC/SNAP encapsulated atm */ + +#ifdef __OpenBSD__ +#define DLT_RAW 14 /* raw IP */ +#else +#define DLT_RAW 12 /* raw IP */ +#endif + +/* + * Given that the only OS that currently generates BSD/OS SLIP or PPP + * is, well, BSD/OS, arguably everybody should have chosen its values + * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they + * didn't. So it goes. + */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */ +#endif +#else +#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */ +#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */ +#endif + +/* + * 17 is used for DLT_OLD_PFLOG in OpenBSD; + * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below. + * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else. + */ + +#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */ + +/* + * Apparently Redback uses this for its SmartEdge 400/800. I hope + * nobody else decided to use it, too. + */ +#define DLT_REDBACK_SMARTEDGE 32 + +/* + * These values are defined by NetBSD; other platforms should refrain from + * using them for other purposes, so that NetBSD savefiles with link + * types of 50 or 51 can be read as this type on all platforms. + */ +#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */ +#define DLT_PPP_ETHER 51 /* PPP over Ethernet */ + +/* + * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses + * a link-layer type of 99 for the tcpdump it supplies. The link-layer + * header has 6 bytes of unknown data, something that appears to be an + * Ethernet type, and 36 bytes that appear to be 0 in at least one capture + * I've seen. + */ +#define DLT_SYMANTEC_FIREWALL 99 + +/* + * Values between 100 and 103 are used in capture file headers as + * link-layer types corresponding to DLT_ types that differ + * between platforms; don't use those values for new DLT_ new types. + */ + +/* + * This value was defined by libpcap 0.5; platforms that have defined + * it with a different value should define it here with that value - + * a link type of 104 in a save file will be mapped to DLT_C_HDLC, + * whatever value that happens to be, so programs will correctly + * handle files with that link type regardless of the value of + * DLT_C_HDLC. + * + * The name DLT_C_HDLC was used by BSD/OS; we use that name for source + * compatibility with programs written for BSD/OS. + * + * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well, + * for source compatibility with programs written for libpcap 0.5. + */ +#define DLT_C_HDLC 104 /* Cisco HDLC */ +#define DLT_CHDLC DLT_C_HDLC + +#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */ + +/* + * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW, + * except when it isn't. (I.e., sometimes it's just raw IP, and + * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL, + * so that we don't have to worry about the link-layer header.) + */ + +/* + * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides + * with other values. + * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header + * (DLCI, etc.). + */ +#define DLT_FRELAY 107 + +/* + * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except + * that the AF_ type in the link-layer header is in network byte order. + * + * OpenBSD defines it as 12, but that collides with DLT_RAW, so we + * define it as 108 here. If OpenBSD picks up this file, it should + * define DLT_LOOP as 12 in its version, as per the comment above - + * and should not use 108 as a DLT_ value. + */ +#define DLT_LOOP 108 + +/* + * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's + * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other + * than OpenBSD. + */ +#ifdef __OpenBSD__ +#define DLT_ENC 13 +#else +#define DLT_ENC 109 +#endif + +/* + * Values between 110 and 112 are reserved for use in capture file headers + * as link-layer types corresponding to DLT_ types that might differ + * between platforms; don't use those values for new DLT_ types + * other than the corresponding DLT_ types. + */ + +/* + * This is for Linux cooked sockets. + */ +#define DLT_LINUX_SLL 113 + +/* + * Apple LocalTalk hardware. + */ +#define DLT_LTALK 114 + +/* + * Acorn Econet. + */ +#define DLT_ECONET 115 + +/* + * Reserved for use with OpenBSD ipfilter. + */ +#define DLT_IPFILTER 116 + +/* + * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023 + * in SuSE 6.3, so we can't use 17 for it in capture-file headers. + * + * XXX: is there a conflict with DLT_PFSYNC 18 as well? + */ +#ifdef __OpenBSD__ +#define DLT_OLD_PFLOG 17 +#define DLT_PFSYNC 18 +#endif +#define DLT_PFLOG 117 + +/* + * Registered for Cisco-internal use. + */ +#define DLT_CISCO_IOS 118 + +/* + * For 802.11 cards using the Prism II chips, with a link-layer + * header including Prism monitor mode information plus an 802.11 + * header. + */ +#define DLT_PRISM_HEADER 119 + +/* + * Reserved for Aironet 802.11 cards, with an Aironet link-layer header + * (see Doug Ambrisko's FreeBSD patches). + */ +#define DLT_AIRONET_HEADER 120 + +/* + * Reserved for Siemens HiPath HDLC. + */ +#define DLT_HHDLC 121 + +/* + * This is for RFC 2625 IP-over-Fibre Channel. + * + * This is not for use with raw Fibre Channel, where the link-layer + * header starts with a Fibre Channel frame header; it's for IP-over-FC, + * where the link-layer header starts with an RFC 2625 Network_Header + * field. + */ +#define DLT_IP_OVER_FC 122 + +/* + * This is for Full Frontal ATM on Solaris with SunATM, with a + * pseudo-header followed by an AALn PDU. + * + * There may be other forms of Full Frontal ATM on other OSes, + * with different pseudo-headers. + * + * If ATM software returns a pseudo-header with VPI/VCI information + * (and, ideally, packet type information, e.g. signalling, ILMI, + * LANE, LLC-multiplexed traffic, etc.), it should not use + * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump + * and the like don't have to infer the presence or absence of a + * pseudo-header and the form of the pseudo-header. + */ +#define DLT_SUNATM 123 /* Solaris+SunATM */ + +/* + * Reserved as per request from Kent Dahlgren <kent@praesum.com> + * for private use. + */ +#define DLT_RIO 124 /* RapidIO */ +#define DLT_PCI_EXP 125 /* PCI Express */ +#define DLT_AURORA 126 /* Xilinx Aurora link layer */ + +/* + * Header for 802.11 plus a number of bits of link-layer information + * including radio information, used by some recent BSD drivers as + * well as the madwifi Atheros driver for Linux. + */ +#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ + +/* + * Reserved for the TZSP encapsulation, as per request from + * Chris Waters <chris.waters@networkchemistry.com> + * TZSP is a generic encapsulation for any other link type, + * which includes a means to include meta-information + * with the packet, e.g. signal strength and channel + * for 802.11 packets. + */ +#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */ + +/* + * BSD's ARCNET headers have the source host, destination host, + * and type at the beginning of the packet; that's what's handed + * up to userland via BPF. + * + * Linux's ARCNET headers, however, have a 2-byte offset field + * between the host IDs and the type; that's what's handed up + * to userland via PF_PACKET sockets. + * + * We therefore have to have separate DLT_ values for them. + */ +#define DLT_ARCNET_LINUX 129 /* ARCNET */ + +/* + * Juniper-private data link types, as per request from + * Hannes Gredler <hannes@juniper.net>. The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MLPPP 130 +#define DLT_JUNIPER_MLFR 131 +#define DLT_JUNIPER_ES 132 +#define DLT_JUNIPER_GGSN 133 +#define DLT_JUNIPER_MFR 134 +#define DLT_JUNIPER_ATM2 135 +#define DLT_JUNIPER_SERVICES 136 +#define DLT_JUNIPER_ATM1 137 + +/* + * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund + * <dieter@apple.com>. The header that's presented is an Ethernet-like + * header: + * + * #define FIREWIRE_EUI64_LEN 8 + * struct firewire_header { + * u_char firewire_dhost[FIREWIRE_EUI64_LEN]; + * u_char firewire_shost[FIREWIRE_EUI64_LEN]; + * u_short firewire_type; + * }; + * + * with "firewire_type" being an Ethernet type value, rather than, + * for example, raw GASP frames being handed up. + */ +#define DLT_APPLE_IP_OVER_IEEE1394 138 + +/* + * Various SS7 encapsulations, as per a request from Jeff Morriss + * <jeff.morriss[AT]ulticom.com> and subsequent discussions. + */ +#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */ +#define DLT_MTP2 140 /* MTP2, without pseudo-header */ +#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */ +#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */ + +/* + * DOCSIS MAC frames. + */ +#define DLT_DOCSIS 143 + +/* + * Linux-IrDA packets. Protocol defined at http://www.irda.org. + * Those packets include IrLAP headers and above (IrLMP...), but + * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy + * framing can be handled by the hardware and depend on the bitrate. + * This is exactly the format you would get capturing on a Linux-IrDA + * interface (irdaX), but not on a raw serial port. + * Note the capture is done in "Linux-cooked" mode, so each packet include + * a fake packet header (struct sll_header). This is because IrDA packet + * decoding is dependant on the direction of the packet (incomming or + * outgoing). + * When/if other platform implement IrDA capture, we may revisit the + * issue and define a real DLT_IRDA... + * Jean II + */ +#define DLT_LINUX_IRDA 144 + +/* + * Reserved for IBM SP switch and IBM Next Federation switch. + */ +#define DLT_IBM_SP 145 +#define DLT_IBM_SN 146 + +/* + * Reserved for private use. If you have some link-layer header type + * that you want to use within your organization, with the capture files + * using that link-layer header type not ever be sent outside your + * organization, you can use these values. + * + * No libpcap release will use these for any purpose, nor will any + * tcpdump release use them, either. + * + * Do *NOT* use these in capture files that you expect anybody not using + * your private versions of capture-file-reading tools to read; in + * particular, do *NOT* use them in products, otherwise you may find that + * people won't be able to use tcpdump, or snort, or Ethereal, or... to + * read capture files from your firewall/intrusion detection/traffic + * monitoring/etc. appliance, or whatever product uses that DLT_ value, + * and you may also find that the developers of those applications will + * not accept patches to let them read those files. + * + * Also, do not use them if somebody might send you a capture using them + * for *their* private type and tools using them for *your* private type + * would have to read them. + * + * Instead, ask "tcpdump-workers@tcpdump.org" for a new DLT_ value, + * as per the comment above, and use the type you're given. + */ +#define DLT_USER0 147 +#define DLT_USER1 148 +#define DLT_USER2 149 +#define DLT_USER3 150 +#define DLT_USER4 151 +#define DLT_USER5 152 +#define DLT_USER6 153 +#define DLT_USER7 154 +#define DLT_USER8 155 +#define DLT_USER9 156 +#define DLT_USER10 157 +#define DLT_USER11 158 +#define DLT_USER12 159 +#define DLT_USER13 160 +#define DLT_USER14 161 +#define DLT_USER15 162 + +/* + * For future use with 802.11 captures - defined by AbsoluteValue + * Systems to store a number of bits of link-layer information + * including radio information: + * + * http://www.shaftnet.org/~pizza/software/capturefrm.txt + * + * but it might be used by some non-AVS drivers now or in the + * future. + */ +#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */ + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler <hannes@juniper.net>. The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, etc.. + */ +#define DLT_JUNIPER_MONITOR 164 + +/* + * Reserved for BACnet MS/TP. + */ +#define DLT_BACNET_MS_TP 165 + +/* + * Another PPP variant as per request from Karsten Keil <kkeil@suse.de>. + * + * This is used in some OSes to allow a kernel socket filter to distinguish + * between incoming and outgoing packets, on a socket intended to + * supply pppd with outgoing packets so it can do dial-on-demand and + * hangup-on-lack-of-demand; incoming packets are filtered out so they + * don't cause pppd to hold the connection up (you don't want random + * input packets such as port scans, packets from old lost connections, + * etc. to force the connection to stay up). + * + * The first byte of the PPP header (0xff03) is modified to accomodate + * the direction - 0x00 = IN, 0x01 = OUT. + */ +#define DLT_PPP_PPPD 166 + +/* + * Names for backwards compatibility with older versions of some PPP + * software; new software should use DLT_PPP_PPPD. + */ +#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD +#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler <hannes@juniper.net>. The DLT_s are used + * for passing on chassis-internal metainformation such as + * QOS profiles, cookies, etc.. + */ +#define DLT_JUNIPER_PPPOE 167 +#define DLT_JUNIPER_PPPOE_ATM 168 + +#define DLT_GPRS_LLC 169 /* GPRS LLC */ +#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */ +#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */ + +/* + * Requested by Oolan Zimmer <oz@gcom.com> for use in Gcom's T1/E1 line + * monitoring equipment. + */ +#define DLT_GCOM_T1E1 172 +#define DLT_GCOM_SERIAL 173 + +/* + * Juniper-private data link type, as per request from + * Hannes Gredler <hannes@juniper.net>. The DLT_ is used + * for internal communication to Physical Interface Cards (PIC) + */ +#define DLT_JUNIPER_PIC_PEER 174 + +/* + * Link types requested by Gregor Maier <gregor@endace.com> of Endace + * Measurement Systems. They add an ERF header (see + * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of + * the link-layer header. + */ +#define DLT_ERF_ETH 175 /* Ethernet */ +#define DLT_ERF_POS 176 /* Packet-over-SONET */ + +/* + * Requested by Daniele Orlandi <daniele@orlandi.com> for raw LAPD + * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header + * includes additional information before the LAPD header, so it's + * not necessarily a generic LAPD header. + */ +#define DLT_LINUX_LAPD 177 + +/* + * The instruction encodings. + */ +/* instruction classes */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_LDX 0x01 +#define BPF_ST 0x02 +#define BPF_STX 0x03 +#define BPF_ALU 0x04 +#define BPF_JMP 0x05 +#define BPF_RET 0x06 +#define BPF_MISC 0x07 + +/* ld/ldx fields */ +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_W 0x00 +#define BPF_H 0x08 +#define BPF_B 0x10 +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_ABS 0x20 +#define BPF_IND 0x40 +#define BPF_MEM 0x60 +#define BPF_LEN 0x80 +#define BPF_MSH 0xa0 + +/* alu/jmp fields */ +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 +#define BPF_SUB 0x10 +#define BPF_MUL 0x20 +#define BPF_DIV 0x30 +#define BPF_OR 0x40 +#define BPF_AND 0x50 +#define BPF_LSH 0x60 +#define BPF_RSH 0x70 +#define BPF_NEG 0x80 +#define BPF_JA 0x00 +#define BPF_JEQ 0x10 +#define BPF_JGT 0x20 +#define BPF_JGE 0x30 +#define BPF_JSET 0x40 +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +/* ret - BPF_K and BPF_X also apply */ +#define BPF_RVAL(code) ((code) & 0x18) +#define BPF_A 0x10 + +/* misc */ +#define BPF_MISCOP(code) ((code) & 0xf8) +#define BPF_TAX 0x00 +#define BPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct bpf_insn { + u_short code; + u_char jt; + u_char jf; + bpf_int32 k; +}; + +/* + * Macros for insn array initializers. + */ +#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k } +#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k } + +#if __STDC__ || defined(__cplusplus) +extern int bpf_validate(struct bpf_insn *, int); +extern u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int); +#else +extern int bpf_validate(); +extern u_int bpf_filter(); +#endif + +/* + * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST). + */ +#define BPF_MEMWORDS 16 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/ipfilter/pcap-ipf.h b/contrib/ipfilter/pcap-ipf.h new file mode 100644 index 0000000..b856760 --- /dev/null +++ b/contrib/ipfilter/pcap-ipf.h @@ -0,0 +1,35 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + */ +/* + * This header file is constructed to match the version described by + * PCAP_VERSION_MAJ. + * + * The structure largely derives from libpcap which wouldn't include + * nicely without bpf. + */ +typedef struct pcap_filehdr { + u_int pc_id; + u_short pc_v_maj; + u_short pc_v_min; + u_int pc_zone; + u_int pc_sigfigs; + u_int pc_slen; + u_int pc_type; +} pcaphdr_t; + +#define TCPDUMP_MAGIC 0xa1b2c3d4 + +#define PCAP_VERSION_MAJ 2 + +typedef struct pcap_pkthdr { + struct timeval ph_ts; + u_int ph_clen; + u_int ph_len; +} pcappkt_t; + diff --git a/contrib/ipfilter/radix_ipf.c b/contrib/ipfilter/radix_ipf.c new file mode 100644 index 0000000..f145c38 --- /dev/null +++ b/contrib/ipfilter/radix_ipf.c @@ -0,0 +1,1528 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <net/if.h> +#if !defined(_KERNEL) +# include <stddef.h> +# include <stdlib.h> +# include <strings.h> +# include <string.h> +#endif +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#ifdef RDX_DEBUG +# include <arpa/inet.h> +# include <stdlib.h> +# include <stdio.h> +#endif +#include "netinet/radix_ipf.h" + +#define ADF_OFF offsetof(addrfamily_t, adf_addr) +#define ADF_OFF_BITS (ADF_OFF << 3) + +static ipf_rdx_node_t *ipf_rx_insert __P((ipf_rdx_head_t *, + ipf_rdx_node_t nodes[2], int *)); +static void ipf_rx_attach_mask __P((ipf_rdx_node_t *, ipf_rdx_mask_t *)); +static int count_mask_bits __P((addrfamily_t *, u_32_t **)); +static void buildnodes __P((addrfamily_t *, addrfamily_t *, + ipf_rdx_node_t n[2])); +static ipf_rdx_node_t *ipf_rx_find_addr __P((ipf_rdx_node_t *, u_32_t *)); +static ipf_rdx_node_t *ipf_rx_lookup __P((ipf_rdx_head_t *, addrfamily_t *, + addrfamily_t *)); +static ipf_rdx_node_t *ipf_rx_match __P((ipf_rdx_head_t *, addrfamily_t *)); + +/* + * Foreword. + * --------- + * The code in this file has been written to target using the addrfamily_t + * data structure to house the address information and no other. Thus there + * are certain aspects of thise code (such as offsets to the address itself) + * that are hard coded here whilst they might be more variable elsewhere. + * Similarly, this code enforces no maximum key length as that's implied by + * all keys needing to be stored in addrfamily_t. + */ + +/* ------------------------------------------------------------------------ */ +/* Function: count_mask_bits */ +/* Returns: number of consecutive bits starting at "mask". */ +/* */ +/* Count the number of bits set in the address section of addrfamily_t and */ +/* return both that number and a pointer to the last word with a bit set if */ +/* lastp is not NULL. The bit count is performed using network byte order */ +/* as the guide for which bit is the most significant bit. */ +/* ------------------------------------------------------------------------ */ +static int +count_mask_bits(mask, lastp) + addrfamily_t *mask; + u_32_t **lastp; +{ + u_32_t *mp = (u_32_t *)&mask->adf_addr; + u_32_t m; + int count = 0; + int mlen; + + mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr); + for (; mlen > 0; mlen -= 4, mp++) { + if ((m = ntohl(*mp)) == 0) + break; + if (lastp != NULL) + *lastp = mp; + for (; m & 0x80000000; m <<= 1) + count++; + } + + return count; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: buildnodes */ +/* Returns: Nil */ +/* Parameters: addr(I) - network address for this radix node */ +/* mask(I) - netmask associated with the above address */ +/* nodes(O) - pair of ipf_rdx_node_t's to initialise with data */ +/* associated with addr and mask. */ +/* */ +/* Initialise the fields in a pair of radix tree nodes according to the */ +/* data supplied in the paramters "addr" and "mask". It is expected that */ +/* "mask" will contain a consecutive string of bits set. Masks with gaps in */ +/* the middle are not handled by this implementation. */ +/* ------------------------------------------------------------------------ */ +static void +buildnodes(addr, mask, nodes) + addrfamily_t *addr, *mask; + ipf_rdx_node_t nodes[2]; +{ + u_32_t maskbits; + u_32_t lastbits; + u_32_t lastmask; + u_32_t *last; + int masklen; + + last = NULL; + maskbits = count_mask_bits(mask, &last); + if (last == NULL) { + masklen = 0; + lastmask = 0; + } else { + masklen = last - (u_32_t *)mask; + lastmask = *last; + } + lastbits = maskbits & 0x1f; + + bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2); + nodes[0].maskbitcount = maskbits; + nodes[0].index = -1 - (ADF_OFF_BITS + maskbits); + nodes[0].addrkey = (u_32_t *)addr; + nodes[0].maskkey = (u_32_t *)mask; + nodes[0].addroff = nodes[0].addrkey + masklen; + nodes[0].maskoff = nodes[0].maskkey + masklen; + nodes[0].parent = &nodes[1]; + nodes[0].offset = masklen; + nodes[0].lastmask = lastmask; + nodes[1].offset = masklen; + nodes[1].left = &nodes[0]; + nodes[1].maskbitcount = maskbits; +#ifdef RDX_DEBUG + (void) strcpy(nodes[0].name, "_BUILD.0"); + (void) strcpy(nodes[1].name, "_BUILD.1"); +#endif +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_find_addr */ +/* Returns: ipf_rdx_node_t * - pointer to a node in the radix tree. */ +/* Parameters: tree(I) - pointer to first right node in tree to search */ +/* addr(I) - pointer to address to match */ +/* */ +/* Walk the radix tree given by "tree", looking for a leaf node that is a */ +/* match for the address given by "addr". */ +/* ------------------------------------------------------------------------ */ +static ipf_rdx_node_t * +ipf_rx_find_addr(tree, addr) + ipf_rdx_node_t *tree; + u_32_t *addr; +{ + ipf_rdx_node_t *cur; + + for (cur = tree; cur->index >= 0;) { + if (cur->bitmask & addr[cur->offset]) { + cur = cur->right; + } else { + cur = cur->left; + } + } + + return (cur); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_match */ +/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ +/* added to the tree. */ +/* Paramters: head(I) - pointer to tree head to search */ +/* addr(I) - pointer to address to find */ +/* */ +/* Search the radix tree for the best match to the address pointed to by */ +/* "addr" and return a pointer to that node. This search will not match the */ +/* address information stored in either of the root leaves as neither of */ +/* them are considered to be part of the tree of data being stored. */ +/* ------------------------------------------------------------------------ */ +static ipf_rdx_node_t * +ipf_rx_match(head, addr) + ipf_rdx_head_t *head; + addrfamily_t *addr; +{ + ipf_rdx_mask_t *masknode; + ipf_rdx_node_t *prev; + ipf_rdx_node_t *node; + ipf_rdx_node_t *cur; + u_32_t *data; + u_32_t *mask; + u_32_t *key; + u_32_t *end; + int len; + int i; + + len = addr->adf_len; + end = (u_32_t *)((u_char *)addr + len); + node = ipf_rx_find_addr(head->root, (u_32_t *)addr); + + /* + * Search the dupkey list for a potential match. + */ + for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) { + i = cur[0].addroff - cur[0].addrkey; + data = cur[0].addrkey + i; + mask = cur[0].maskkey + i; + key = (u_32_t *)addr + i; + for (; key < end; data++, key++, mask++) + if ((*key & *mask) != *data) + break; + if ((end == key) && (cur->root == 0)) + return (cur); /* Equal keys */ + } + prev = node->parent; + key = (u_32_t *)addr; + + for (node = prev; node->root == 0; node = node->parent) { + /* + * We know that the node hasn't matched so therefore only + * the entries in the mask list are searched, not the top + * node nor the dupkey list. + */ + masknode = node->masks; + for (; masknode != NULL; masknode = masknode->next) { + if (masknode->maskbitcount > node->maskbitcount) + continue; + cur = masknode->node; + for (i = ADF_OFF >> 2; i <= node->offset; i++) { + if ((key[i] & masknode->mask[i]) == + cur->addrkey[i]) + return (cur); + } + } + } + + return NULL; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_lookup */ +/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ +/* added to the tree. */ +/* Paramters: head(I) - pointer to tree head to search */ +/* addr(I) - address part of the key to match */ +/* mask(I) - netmask part of the key to match */ +/* */ +/* ipf_rx_lookup searches for an exact match on (addr,mask). The intention */ +/* is to see if a given key is in the tree, not to see if a route exists. */ +/* ------------------------------------------------------------------------ */ +ipf_rdx_node_t * +ipf_rx_lookup(head, addr, mask) + ipf_rdx_head_t *head; + addrfamily_t *addr, *mask; +{ + ipf_rdx_node_t *found; + ipf_rdx_node_t *node; + u_32_t *akey; + int count; + + found = ipf_rx_find_addr(head->root, (u_32_t *)addr); + if (found->root == 1) + return NULL; + + /* + * It is possible to find a matching address in the tree but for the + * netmask to not match. If the netmask does not match and there is + * no list of alternatives present at dupkey, return a failure. + */ + count = count_mask_bits(mask, NULL); + if (count != found->maskbitcount && found->dupkey == NULL) + return (NULL); + + akey = (u_32_t *)addr; + if ((found->addrkey[found->offset] & found->maskkey[found->offset]) != + akey[found->offset]) + return NULL; + + if (found->dupkey != NULL) { + node = found; + while (node != NULL && node->maskbitcount != count) + node = node->dupkey; + if (node == NULL) + return (NULL); + found = node; + } + return found; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_attach_mask */ +/* Returns: Nil */ +/* Parameters: node(I) - pointer to a radix tree node */ +/* mask(I) - pointer to mask structure to add */ +/* */ +/* Add the netmask to the given node in an ordering where the most specific */ +/* netmask is at the top of the list. */ +/* ------------------------------------------------------------------------ */ +static void +ipf_rx_attach_mask(node, mask) + ipf_rdx_node_t *node; + ipf_rdx_mask_t *mask; +{ + ipf_rdx_mask_t **pm; + ipf_rdx_mask_t *m; + + for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next) + if (m->maskbitcount < mask->maskbitcount) + break; + mask->next = *pm; + *pm = mask; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_insert */ +/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ +/* added to the tree. */ +/* Paramters: head(I) - pointer to tree head to add nodes to */ +/* nodes(I) - pointer to radix nodes to be added */ +/* dup(O) - set to 1 if node is a duplicate, else 0. */ +/* */ +/* Add the new radix tree entry that owns nodes[] to the tree given by head.*/ +/* If there is already a matching key in the table, "dup" will be set to 1 */ +/* and the existing node pointer returned if there is a complete key match. */ +/* A complete key match is a matching of all key data that is presented by */ +/* by the netmask. */ +/* ------------------------------------------------------------------------ */ +static ipf_rdx_node_t * +ipf_rx_insert(head, nodes, dup) + ipf_rdx_head_t *head; + ipf_rdx_node_t nodes[2]; + int *dup; +{ + ipf_rdx_mask_t **pmask; + ipf_rdx_node_t *node; + ipf_rdx_node_t *prev; + ipf_rdx_mask_t *mask; + ipf_rdx_node_t *cur; + u_32_t nodemask; + u_32_t *addr; + u_32_t *data; + int nodebits; + u_32_t *key; + u_32_t *end; + u_32_t bits; + int nodekey; + int nodeoff; + int nlen; + int len; + + addr = nodes[0].addrkey; + + node = ipf_rx_find_addr(head->root, addr); + len = ((addrfamily_t *)addr)->adf_len; + key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr; + data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr; + end = (u_32_t *)((u_char *)addr + len); + for (nlen = 0; key < end; data++, key++, nlen += 32) + if (*key != *data) + break; + if (end == data) { + *dup = 1; + return (node); /* Equal keys */ + } + *dup = 0; + + bits = (ntohl(*data) ^ ntohl(*key)); + for (; bits != 0; nlen++) { + if ((bits & 0x80000000) != 0) + break; + bits <<= 1; + } + nlen += ADF_OFF_BITS; + nodes[1].index = nlen; + nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f)); + nodes[0].offset = nlen / 32; + nodes[1].offset = nlen / 32; + + /* + * Walk through the tree and look for the correct place to attach + * this node. ipf_rx_fin_addr is not used here because the place + * to attach this node may be an internal node (same key, different + * netmask.) Additionally, the depth of the search is forcibly limited + * here to not exceed the netmask, so that a short netmask will be + * added higher up the tree even if there are lower branches. + */ + cur = head->root; + key = nodes[0].addrkey; + do { + prev = cur; + if (key[cur->offset] & cur->bitmask) { + cur = cur->right; + } else { + cur = cur->left; + } + } while (nlen > (unsigned)cur->index); + + if ((key[prev->offset] & prev->bitmask) == 0) { + prev->left = &nodes[1]; + } else { + prev->right = &nodes[1]; + } + cur->parent = &nodes[1]; + nodes[1].parent = prev; + if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) { + nodes[1].right = cur; + } else { + nodes[1].right = &nodes[0]; + nodes[1].left = cur; + } + + nodeoff = nodes[0].offset; + nodekey = nodes[0].addrkey[nodeoff]; + nodemask = nodes[0].lastmask; + nodebits = nodes[0].maskbitcount; + prev = NULL; + /* + * Find the node up the tree with the largest pattern that still + * matches the node being inserted to see if this mask can be + * moved there. + */ + for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) { + if (cur->maskbitcount <= nodebits) + break; + if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey) + break; + prev = cur; + } + + KMALLOC(mask, ipf_rdx_mask_t *); + if (mask == NULL) + return NULL; + bzero(mask, sizeof(*mask)); + mask->next = NULL; + mask->node = &nodes[0]; + mask->maskbitcount = nodebits; + mask->mask = nodes[0].maskkey; + nodes[0].mymask = mask; + + if (prev != NULL) { + ipf_rdx_mask_t *m; + + for (pmask = &prev->masks; (m = *pmask) != NULL; + pmask = &m->next) { + if (m->maskbitcount < nodebits) + break; + } + } else { + /* + * No higher up nodes qualify, so attach mask locally. + */ + pmask = &nodes[0].masks; + } + mask->next = *pmask; + *pmask = mask; + + /* + * Search the mask list on each child to see if there are any masks + * there that can be moved up to this newly inserted node. + */ + cur = nodes[1].right; + if (cur->root == 0) { + for (pmask = &cur->masks; (mask = *pmask) != NULL; ) { + if (mask->maskbitcount < nodebits) { + *pmask = mask->next; + ipf_rx_attach_mask(&nodes[0], mask); + } else { + pmask = &mask->next; + } + } + } + cur = nodes[1].left; + if (cur->root == 0 && cur != &nodes[0]) { + for (pmask = &cur->masks; (mask = *pmask) != NULL; ) { + if (mask->maskbitcount < nodebits) { + *pmask = mask->next; + ipf_rx_attach_mask(&nodes[0], mask); + } else { + pmask = &mask->next; + } + } + } + return (&nodes[0]); +} + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_addroute */ +/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */ +/* added to the tree. */ +/* Paramters: head(I) - pointer to tree head to search */ +/* addr(I) - address portion of "route" to add */ +/* mask(I) - netmask portion of "route" to add */ +/* nodes(I) - radix tree data nodes inside allocate structure */ +/* */ +/* Attempt to add a node to the radix tree. The key for the node is the */ +/* (addr,mask). No memory allocation for the radix nodes themselves is */ +/* performed here, the data structure that this radix node is being used to */ +/* find is expected to house the node data itself however the call to */ +/* ipf_rx_insert() will attempt to allocate memory in order for netmask to */ +/* be promoted further up the tree. */ +/* In this case, the ip_pool_node_t structure from ip_pool.h contains both */ +/* the key material (addr,mask) and the radix tree nodes[]. */ +/* */ +/* The mechanics of inserting the node into the tree is handled by the */ +/* function ipf_rx_insert() above. Here, the code deals with the case */ +/* where the data to be inserted is a duplicate. */ +/* ------------------------------------------------------------------------ */ +ipf_rdx_node_t * +ipf_rx_addroute(head, addr, mask, nodes) + ipf_rdx_head_t *head; + addrfamily_t *addr, *mask; + ipf_rdx_node_t *nodes; +{ + ipf_rdx_node_t *node; + ipf_rdx_node_t *prev; + ipf_rdx_node_t *x; + int dup; + + buildnodes(addr, mask, nodes); + x = ipf_rx_insert(head, nodes, &dup); + if (x == NULL) + return NULL; + + if (dup == 1) { + node = &nodes[0]; + prev = NULL; + /* + * The duplicate list is kept sorted with the longest + * mask at the top, meaning that the most specific entry + * in the listis found first. This list thus allows for + * duplicates such as 128.128.0.0/32 and 128.128.0.0/16. + */ + while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) { + prev = x; + x = x->dupkey; + } + + /* + * Is it a complete duplicate? If so, return NULL and + * fail the insert. Otherwise, insert it into the list + * of netmasks active for this key. + */ + if ((x != NULL) && (x->maskbitcount == node->maskbitcount)) + return (NULL); + + if (prev != NULL) { + nodes[0].dupkey = x; + prev->dupkey = &nodes[0]; + nodes[0].parent = prev; + if (x != NULL) + x->parent = &nodes[0]; + } else { + nodes[0].dupkey = x->dupkey; + prev = x->parent; + nodes[0].parent = prev; + x->parent = &nodes[0]; + if (prev->left == x) + prev->left = &nodes[0]; + else + prev->right = &nodes[0]; + } + } + + return &nodes[0]; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_delete */ +/* Returns: ipf_rdx_node_t * - NULL on error, else node removed from */ +/* the tree. */ +/* Paramters: head(I) - pointer to tree head to search */ +/* addr(I) - pointer to the address part of the key */ +/* mask(I) - pointer to the netmask part of the key */ +/* */ +/* Search for an entry in the radix tree that is an exact match for (addr, */ +/* mask) and remove it if it exists. In the case where (addr,mask) is a not */ +/* a unique key, the tree structure itself is not changed - only the list */ +/* of duplicate keys. */ +/* ------------------------------------------------------------------------ */ +ipf_rdx_node_t * +ipf_rx_delete(head, addr, mask) + ipf_rdx_head_t *head; + addrfamily_t *addr, *mask; +{ + ipf_rdx_mask_t **pmask; + ipf_rdx_node_t *parent; + ipf_rdx_node_t *found; + ipf_rdx_node_t *prev; + ipf_rdx_node_t *node; + ipf_rdx_node_t *cur; + ipf_rdx_mask_t *m; + int count; + + found = ipf_rx_find_addr(head->root, (u_32_t *)addr); + if (found == NULL) + return NULL; + if (found->root == 1) + return NULL; + count = count_mask_bits(mask, NULL); + parent = found->parent; + if (found->dupkey != NULL) { + node = found; + while (node != NULL && node->maskbitcount != count) + node = node->dupkey; + if (node == NULL) + return (NULL); + if (node != found) { + /* + * Remove from the dupkey list. Here, "parent" is + * the previous node on the list (rather than tree) + * and "dupkey" is the next node on the list. + */ + parent = node->parent; + parent->dupkey = node->dupkey; + node->dupkey->parent = parent; + } else { + /* + * + * When removing the top node of the dupkey list, + * the pointers at the top of the list that point + * to other tree nodes need to be preserved and + * any children must have their parent updated. + */ + node = node->dupkey; + node->parent = found->parent; + node->right = found->right; + node->left = found->left; + found->right->parent = node; + found->left->parent = node; + if (parent->left == found) + parent->left = node; + else + parent->right= node; + } + } else { + if (count != found->maskbitcount) + return (NULL); + /* + * Remove the node from the tree and reconnect the subtree + * below. + */ + /* + * If there is a tree to the left, look for something to + * attach in place of "found". + */ + prev = found + 1; + cur = parent->parent; + if (parent != found + 1) { + if ((found + 1)->parent->right == found + 1) + (found + 1)->parent->right = parent; + else + (found + 1)->parent->left = parent; + if (cur->right == parent) { + if (parent->left == found) { + cur->right = parent->right; + } else if (parent->left != parent - 1) { + cur->right = parent->left; + } else { + cur->right = parent - 1; + } + cur->right->parent = cur; + } else { + if (parent->right == found) { + cur->left = parent->left; + } else if (parent->right != parent - 1) { + cur->left = parent->right; + } else { + cur->left = parent - 1; + } + cur->left->parent = cur; + } + parent->left = (found + 1)->left; + if ((found + 1)->right != parent) + parent->right = (found + 1)->right; + parent->left->parent = parent; + parent->right->parent = parent; + parent->parent = (found + 1)->parent; + + parent->bitmask = prev->bitmask; + parent->offset = prev->offset; + parent->index = prev->index; + } else { + /* + * We found an edge node. + */ + cur = parent->parent; + if (cur->left == parent) { + if (parent->left == found) { + cur->left = parent->right; + parent->right->parent = cur; + } else { + cur->left = parent->left; + parent->left->parent = cur; + } + } else { + if (parent->right != found) { + cur->right = parent->right; + parent->right->parent = cur; + } else { + cur->right = parent->left; + prev->left->parent = cur; + } + } + } + } + + /* + * Remove mask associated with this node. + */ + for (cur = parent; cur->root == 0; cur = cur->parent) { + ipf_rdx_mask_t **pm; + + if (cur->maskbitcount <= found->maskbitcount) + break; + if (((cur - 1)->addrkey[found->offset] & found->bitmask) != + found->addrkey[found->offset]) + break; + for (pm = &cur->masks; (m = *pm) != NULL; ) + if (m->node == cur) { + *pm = m->next; + break; + } else { + pm = &m->next; + } + } + KFREE(found->mymask); + + /* + * Masks that have been brought up to this node from below need to + * be sent back down. + */ + for (pmask = &parent->masks; (m = *pmask) != NULL; ) { + *pmask = m->next; + cur = m->node; + if (cur == found) + continue; + if (found->addrkey[cur->offset] & cur->lastmask) { + ipf_rx_attach_mask(parent->right, m); + } else if (parent->left != found) { + ipf_rx_attach_mask(parent->left, m); + } + } + + return (found); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_walktree */ +/* Returns: Nil */ +/* Paramters: head(I) - pointer to tree head to search */ +/* walker(I) - function to call for each node in the tree */ +/* arg(I) - parameter to pass to walker, in addition to the */ +/* node pointer */ +/* */ +/* A standard tree walking function except that it is iterative, rather */ +/* than recursive and tracks the next node in case the "walker" function */ +/* should happen to delete and free the current node. It thus goes without */ +/* saying that the "walker" function is not permitted to cause any change */ +/* in the validity of the data found at either the left or right child. */ +/* ------------------------------------------------------------------------ */ +void +ipf_rx_walktree(head, walker, arg) + ipf_rdx_head_t *head; + radix_walk_func_t walker; + void *arg; +{ + ipf_rdx_node_t *next; + ipf_rdx_node_t *node = head->root; + ipf_rdx_node_t *base; + + while (node->index >= 0) + node = node->left; + + for (;;) { + base = node; + while ((node->parent->right == node) && (node->root == 0)) + node = node->parent; + + for (node = node->parent->right; node->index >= 0; ) + node = node->left; + next = node; + + for (node = base; node != NULL; node = base) { + base = node->dupkey; + if (node->root == 0) + walker(node, arg); + } + node = next; + if (node->root) + return; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_inithead */ +/* Returns: int - 0 = success, else failure */ +/* Paramters: softr(I) - pointer to radix context */ +/* headp(O) - location for where to store allocated tree head */ +/* */ +/* This function allocates and initialises a radix tree head structure. */ +/* As a traditional radix tree, node 0 is used as the "0" sentinel and node */ +/* "2" is used as the all ones sentinel, leaving node "1" as the root from */ +/* which the tree is hung with node "0" on its left and node "2" to the */ +/* right. The context, "softr", is used here to provide a common source of */ +/* the zeroes and ones data rather than have one per head. */ +/* ------------------------------------------------------------------------ */ +int +ipf_rx_inithead(softr, headp) + radix_softc_t *softr; + ipf_rdx_head_t **headp; +{ + ipf_rdx_head_t *ptr; + ipf_rdx_node_t *node; + + KMALLOC(ptr, ipf_rdx_head_t *); + *headp = ptr; + if (ptr == NULL) + return -1; + bzero(ptr, sizeof(*ptr)); + node = ptr->nodes; + ptr->root = node + 1; + node[0].index = ADF_OFF_BITS; + node[0].index = -1 - node[0].index; + node[1].index = ADF_OFF_BITS; + node[2].index = node[0].index; + node[0].parent = node + 1; + node[1].parent = node + 1; + node[2].parent = node + 1; + node[1].bitmask = htonl(0x80000000); + node[0].root = 1; + node[1].root = 1; + node[2].root = 1; + node[0].offset = ADF_OFF_BITS >> 5; + node[1].offset = ADF_OFF_BITS >> 5; + node[2].offset = ADF_OFF_BITS >> 5; + node[1].left = &node[0]; + node[1].right = &node[2]; + node[0].addrkey = (u_32_t *)softr->zeros; + node[2].addrkey = (u_32_t *)softr->ones; +#ifdef RDX_DEBUG + (void) strcpy(node[0].name, "0_ROOT"); + (void) strcpy(node[1].name, "1_ROOT"); + (void) strcpy(node[2].name, "2_ROOT"); +#endif + + ptr->addaddr = ipf_rx_addroute; + ptr->deladdr = ipf_rx_delete; + ptr->lookup = ipf_rx_lookup; + ptr->matchaddr = ipf_rx_match; + ptr->walktree = ipf_rx_walktree; + return 0; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_freehead */ +/* Returns: Nil */ +/* Paramters: head(I) - pointer to tree head to free */ +/* */ +/* This function simply free's up the radix tree head. Prior to calling */ +/* this function, it is expected that the tree will have been emptied. */ +/* ------------------------------------------------------------------------ */ +void +ipf_rx_freehead(head) + ipf_rdx_head_t *head; +{ + KFREE(head); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_create */ +/* Parameters: Nil */ +/* */ +/* ------------------------------------------------------------------------ */ +void * +ipf_rx_create() +{ + radix_softc_t *softr; + + KMALLOC(softr, radix_softc_t *); + if (softr == NULL) + return NULL; + bzero((char *)softr, sizeof(*softr)); + + KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t)); + if (softr->zeros == NULL) { + KFREE(softr); + return (NULL); + } + softr->ones = softr->zeros + sizeof(addrfamily_t); + + return softr; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_init */ +/* Returns: int - 0 = success (always) */ +/* */ +/* ------------------------------------------------------------------------ */ +int +ipf_rx_init(ctx) + void *ctx; +{ + radix_softc_t *softr = ctx; + + memset(softr->zeros, 0, 3 * sizeof(addrfamily_t)); + memset(softr->ones, 0xff, sizeof(addrfamily_t)); + + return (0); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_rx_destroy */ +/* Returns: Nil */ +/* */ +/* ------------------------------------------------------------------------ */ +void +ipf_rx_destroy(ctx) + void *ctx; +{ + radix_softc_t *softr = ctx; + + if (softr->zeros != NULL) + KFREES(softr->zeros, 3 * sizeof(addrfamily_t)); + KFREE(softr); +} + +/* ====================================================================== */ + +#ifdef RDX_DEBUG +/* + * To compile this file as a standalone test unit, use -DRDX_DEBUG=1 + */ +#define NAME(x) ((x)->index < 0 ? (x)->name : (x)->name) +#define GNAME(y) ((y) == NULL ? "NULL" : NAME(y)) + +typedef struct myst { + struct ipf_rdx_node nodes[2]; + addrfamily_t dst; + addrfamily_t mask; + struct myst *next; + int printed; +} myst_t; + +typedef struct tabe_s { + char *host; + char *mask; + char *what; +} tabe_t; + +tabe_t builtin[] = { +#if 1 + { "192:168:100::0", "48", "d" }, + { "192:168:100::2", "128", "d" }, +#else + { "127.192.0.0", "255.255.255.0", "d" }, + { "127.128.0.0", "255.255.255.0", "d" }, + { "127.96.0.0", "255.255.255.0", "d" }, + { "127.80.0.0", "255.255.255.0", "d" }, + { "127.72.0.0", "255.255.255.0", "d" }, + { "127.64.0.0", "255.255.255.0", "d" }, + { "127.56.0.0", "255.255.255.0", "d" }, + { "127.48.0.0", "255.255.255.0", "d" }, + { "127.40.0.0", "255.255.255.0", "d" }, + { "127.32.0.0", "255.255.255.0", "d" }, + { "127.24.0.0", "255.255.255.0", "d" }, + { "127.16.0.0", "255.255.255.0", "d" }, + { "127.8.0.0", "255.255.255.0", "d" }, + { "124.0.0.0", "255.0.0.0", "d" }, + { "125.0.0.0", "255.0.0.0", "d" }, + { "126.0.0.0", "255.0.0.0", "d" }, + { "127.0.0.0", "255.0.0.0", "d" }, + { "10.0.0.0", "255.0.0.0", "d" }, + { "128.250.0.0", "255.255.0.0", "d" }, + { "192.168.0.0", "255.255.0.0", "d" }, + { "192.168.1.0", "255.255.255.0", "d" }, +#endif + { NULL, NULL, NULL } +}; + +char *mtable[][1] = { +#if 1 + { "192:168:100::2" }, + { "192:168:101::2" }, +#else + { "9.0.0.0" }, + { "9.0.0.1" }, + { "11.0.0.0" }, + { "11.0.0.1" }, + { "127.0.0.1" }, + { "127.0.1.0" }, + { "255.255.255.0" }, + { "126.0.0.1" }, + { "128.251.0.0" }, + { "128.251.0.1" }, + { "128.251.255.255" }, + { "129.250.0.0" }, + { "129.250.0.1" }, + { "192.168.255.255" }, +#endif + { NULL } +}; + + +int forder[22] = { + 14, 13, 12, 5, 10, 3, 19, 7, 4, 20, 8, + 2, 17, 9, 16, 11, 15, 1, 6, 18, 0, 21 +}; + +static int nodecount = 0; +myst_t *myst_top = NULL; +tabe_t *ttable = NULL; + +void add_addr(ipf_rdx_head_t *, int , int); +void checktree(ipf_rdx_head_t *); +void delete_addr(ipf_rdx_head_t *rnh, int item); +void dumptree(ipf_rdx_head_t *rnh); +void nodeprinter(ipf_rdx_node_t *, void *); +void printroots(ipf_rdx_head_t *); +void random_add(ipf_rdx_head_t *); +void random_delete(ipf_rdx_head_t *); +void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int); + + +static void +ipf_rx_freenode(node, arg) + ipf_rdx_node_t *node; + void *arg; +{ + ipf_rdx_head_t *head = arg; + ipf_rdx_node_t *rv; + myst_t *stp; + + stp = (myst_t *)node; + rv = ipf_rx_delete(head, &stp->dst, &stp->mask); + if (rv != NULL) { + free(rv); + } +} + + +const char * +addrname(ap) + addrfamily_t *ap; +{ + static char name[80]; + const char *txt; + + bzero((char *)name, sizeof(name)); + txt = inet_ntop(ap->adf_family, &ap->adf_addr, name, + sizeof(name)); + return txt; +} + + +void +fill6bits(bits, msk) + int bits; + u_int *msk; +{ + if (bits == 0) { + msk[0] = 0; + msk[1] = 0; + msk[2] = 0; + msk[3] = 0; + return; + } + + msk[0] = 0xffffffff; + msk[1] = 0xffffffff; + msk[2] = 0xffffffff; + msk[3] = 0xffffffff; + + if (bits == 128) + return; + if (bits > 96) { + msk[3] = htonl(msk[3] << (128 - bits)); + } else if (bits > 64) { + msk[3] = 0; + msk[2] = htonl(msk[2] << (96 - bits)); + } else if (bits > 32) { + msk[3] = 0; + msk[2] = 0; + msk[1] = htonl(msk[1] << (64 - bits)); + } else { + msk[3] = 0; + msk[2] = 0; + msk[1] = 0; + msk[0] = htonl(msk[0] << (32 - bits)); + } +} + + +void +setaddr(afp, str) + addrfamily_t *afp; + char *str; +{ + + bzero((char *)afp, sizeof(*afp)); + + if (strchr(str, ':') == NULL) { + afp->adf_family = AF_INET; + afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; + } else { + afp->adf_family = AF_INET6; + afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16; + } + inet_pton(afp->adf_family, str, &afp->adf_addr); +} + + +void +setmask(afp, str) + addrfamily_t *afp; + char *str; +{ + if (strchr(str, '.') != NULL) { + afp->adf_addr.in4.s_addr = inet_addr(str); + afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; + } else if (afp->adf_family == AF_INET) { + afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str))); + afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4; + } else if (afp->adf_family == AF_INET6) { + fill6bits(atoi(str), afp->adf_addr.i6); + afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16; + } +} + + +void +nodeprinter(node, arg) + ipf_rdx_node_t *node; + void *arg; +{ + myst_t *stp = (myst_t *)node; + + printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n", + node[0].name, + GNAME(node[1].left), GNAME(node[1].right), + GNAME(node[0].parent), GNAME(node[1].parent), + addrname(&stp->dst), node[0].maskbitcount); + if (stp->printed == -1) + printf("!!! %d\n", stp->printed); + else + stp->printed = 1; +} + + +void +printnode(stp) + myst_t *stp; +{ + ipf_rdx_node_t *node = &stp->nodes[0]; + + if (stp->nodes[0].index > 0) + stp = (myst_t *)&stp->nodes[-1]; + + printf("Node %-9.9s ", node[0].name); + printf("L %-9.9s ", GNAME(node[1].left)); + printf("R %-9.9s ", GNAME(node[1].right)); + printf("P %9.9s", GNAME(node[0].parent)); + printf("/%-9.9s ", GNAME(node[1].parent)); + printf("%s P%d\n", addrname(&stp->dst), stp->printed); +} + + +void +buildtab(void) +{ + char line[80], *s; + tabe_t *tab; + int lines; + FILE *fp; + + lines = 0; + fp = fopen("hosts", "r"); + + while (fgets(line, sizeof(line), fp) != NULL) { + s = strchr(line, '\n'); + if (s != NULL) + *s = '\0'; + lines++; + if (lines == 1) + tab = malloc(sizeof(*tab) * 2); + else + tab = realloc(tab, (lines + 1) * sizeof(*tab)); + tab[lines - 1].host = strdup(line); + s = strchr(tab[lines - 1].host, '/'); + *s++ = '\0'; + tab[lines - 1].mask = s; + tab[lines - 1].what = "d"; + } + fclose(fp); + + tab[lines].host = NULL; + tab[lines].mask = NULL; + tab[lines].what = NULL; + ttable = tab; +} + + +void +printroots(rnh) + ipf_rdx_head_t *rnh; +{ + printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n", + GNAME(&rnh->nodes[0]), + rnh->nodes[0].index, GNAME(rnh->nodes[0].parent), + GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right)); + printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n", + GNAME(&rnh->nodes[1]), + rnh->nodes[1].index, GNAME(rnh->nodes[1].parent), + GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right)); + printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n", + GNAME(&rnh->nodes[2]), + rnh->nodes[2].index, GNAME(rnh->nodes[2].parent), + GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right)); +} + + +int +main(int argc, char *argv[]) +{ + addrfamily_t af; + ipf_rdx_head_t *rnh; + radix_softc_t *ctx; + int j; + int i; + + rnh = NULL; + + buildtab(); + ctx = ipf_rx_create(); + ipf_rx_init(ctx); + ipf_rx_inithead(ctx, &rnh); + + printf("=== ADD-0 ===\n"); + for (i = 0; ttable[i].host != NULL; i++) { + add_addr(rnh, i, i); + checktree(rnh); + } + printroots(rnh); + ipf_rx_walktree(rnh, nodeprinter, NULL); + printf("=== DELETE-0 ===\n"); + for (i = 0; ttable[i].host != NULL; i++) { + delete_addr(rnh, i); + printroots(rnh); + ipf_rx_walktree(rnh, nodeprinter, NULL); + } + printf("=== ADD-1 ===\n"); + for (i = 0; ttable[i].host != NULL; i++) { + setaddr(&af, ttable[i].host); + add_addr(rnh, i, i); /*forder[i]); */ + checktree(rnh); + } + dumptree(rnh); + ipf_rx_walktree(rnh, nodeprinter, NULL); + printf("=== TEST-1 ===\n"); + for (i = 0; ttable[i].host != NULL; i++) { + setaddr(&af, ttable[i].host); + test_addr(rnh, i, &af, -1); + } + + printf("=== TEST-2 ===\n"); + for (i = 0; mtable[i][0] != NULL; i++) { + setaddr(&af, mtable[i][0]); + test_addr(rnh, i, &af, -1); + } + printf("=== DELETE-1 ===\n"); + for (i = 0; ttable[i].host != NULL; i++) { + if (ttable[i].what[0] != 'd') + continue; + delete_addr(rnh, i); + for (j = 0; ttable[j].host != NULL; j++) { + setaddr(&af, ttable[j].host); + test_addr(rnh, i, &af, 3); + } + printroots(rnh); + ipf_rx_walktree(rnh, nodeprinter, NULL); + } + + dumptree(rnh); + + printf("=== ADD-2 ===\n"); + random_add(rnh); + checktree(rnh); + dumptree(rnh); + ipf_rx_walktree(rnh, nodeprinter, NULL); + printf("=== DELETE-2 ===\n"); + random_delete(rnh); + checktree(rnh); + dumptree(rnh); + + ipf_rx_walktree(rnh, ipf_rx_freenode, rnh); + + return 0; +} + + +void +dumptree(rnh) + ipf_rdx_head_t *rnh; +{ + myst_t *stp; + + printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n"); + printroots(rnh); + for (stp = myst_top; stp; stp = stp->next) + printnode(stp); + printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); +} + + +void +test_addr(rnh, pref, addr, limit) + ipf_rdx_head_t *rnh; + int pref; + addrfamily_t *addr; +{ + static int extras[14] = { 0, -1, 1, 3, 5, 8, 9, + 15, 16, 19, 255, 256, 65535, 65536 + }; + ipf_rdx_node_t *rn; + addrfamily_t af; + char name[80]; + myst_t *stp; + int i; + + memset(&af, 0, sizeof(af)); +#if 0 + if (limit < 0 || limit > 14) + limit = 14; + + for (i = 0; i < limit; i++) { + if (ttable[i].host == NULL) + break; + setaddr(&af, ttable[i].host); + printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af)); + rn = ipf_rx_match(rnh, &af); + stp = (myst_t *)rn; + printf(" = %s (%s/%d)\n", GNAME(rn), + rn ? addrname(&stp->dst) : "NULL", + rn ? rn->maskbitcount : 0); + } +#else + printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr)); + rn = ipf_rx_match(rnh, addr); + stp = (myst_t *)rn; + printf(" = %s (%s/%d)\n", GNAME(rn), + rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0); +#endif +} + + +void +delete_addr(rnh, item) + ipf_rdx_head_t *rnh; + int item; +{ + ipf_rdx_node_t *rn; + addrfamily_t mask; + addrfamily_t af; + myst_t **pstp; + myst_t *stp; + + memset(&af, 0, sizeof(af)); + memset(&mask, 0, sizeof(mask)); + setaddr(&af, ttable[item].host); + mask.adf_family = af.adf_family; + setmask(&mask, ttable[item].mask); + + printf("DELETE(%s)\n", addrname(&af)); + rn = ipf_rx_delete(rnh, &af, &mask); + if (rn == NULL) { + printf("FAIL LOOKUP DELETE\n"); + checktree(rnh); + for (stp = myst_top; stp != NULL; stp = stp->next) + if (stp->printed != -1) + stp->printed = -2; + ipf_rx_walktree(rnh, nodeprinter, NULL); + dumptree(rnh); + abort(); + } + printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn)); + + for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next) + if (stp == (myst_t *)rn) + break; + stp->printed = -1; + stp->nodes[0].parent = &stp->nodes[0]; + stp->nodes[1].parent = &stp->nodes[1]; + *pstp = stp->next; + free(stp); + nodecount--; + checktree(rnh); +} + + +void +add_addr(rnh, n, item) + ipf_rdx_head_t *rnh; + int n, item; +{ + ipf_rdx_node_t *rn; + myst_t *stp; + + stp = calloc(1, sizeof(*stp)); + rn = (ipf_rdx_node_t *)stp; + setaddr(&stp->dst, ttable[item].host); + stp->mask.adf_family = stp->dst.adf_family; + setmask(&stp->mask, ttable[item].mask); + stp->next = myst_top; + myst_top = stp; + (void) sprintf(rn[0].name, "_BORN.0"); + (void) sprintf(rn[1].name, "_BORN.1"); + rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes); + (void) sprintf(rn[0].name, "%d_NODE.0", item); + (void) sprintf(rn[1].name, "%d_NODE.1", item); + printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name); + nodecount++; + checktree(rnh); +} + + +void +checktree(ipf_rdx_head_t *head) +{ + myst_t *s1; + ipf_rdx_node_t *rn; + + if (nodecount <= 1) + return; + + for (s1 = myst_top; s1 != NULL; s1 = s1->next) { + int fault = 0; + if (s1->printed == -1) + continue; + rn = &s1->nodes[1]; + if (rn->right->parent != rn) + fault |= 1; + if (rn->left->parent != rn) + fault |= 2; + if (rn->parent->left != rn && rn->parent->right != rn) + fault |= 4; + if (fault != 0) { + printf("FAULT %#x %s\n", fault, rn->name); + dumptree(head); + ipf_rx_walktree(head, nodeprinter, NULL); + fflush(stdout); + fflush(stderr); + printf("--\n"); + abort(); + } + } +} + + +int * +randomize(int *pnitems) +{ + int *order; + int nitems; + int choice; + int j; + int i; + + nitems = sizeof(ttable) / sizeof(ttable[0]); + *pnitems = nitems; + order = calloc(nitems, sizeof(*order)); + srandom(getpid() * time(NULL)); + memset(order, 0xff, nitems * sizeof(*order)); + order[21] = 21; + for (i = 0; i < nitems - 1; i++) { + do { + choice = rand() % (nitems - 1); + for (j = 0; j < nitems; j++) + if (order[j] == choice) + break; + } while (j != nitems); + order[i] = choice; + } + + return order; +} + + +void +random_add(rnh) + ipf_rdx_head_t *rnh; +{ + int *order; + int nitems; + int i; + + order = randomize(&nitems); + + for (i = 0; i < nitems - 1; i++) { + add_addr(rnh, i, order[i]); + checktree(rnh); + } +} + + +void +random_delete(rnh) + ipf_rdx_head_t *rnh; +{ + int *order; + int nitems; + int i; + + order = randomize(&nitems); + + for (i = 0; i < nitems - 1; i++) { + delete_addr(rnh, i); + checktree(rnh); + } +} +#endif /* RDX_DEBUG */ diff --git a/contrib/ipfilter/radix_ipf.h b/contrib/ipfilter/radix_ipf.h new file mode 100644 index 0000000..bbbf559 --- /dev/null +++ b/contrib/ipfilter/radix_ipf.h @@ -0,0 +1,97 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#ifndef __RADIX_IPF_H__ +#define __RADIX_IPF_H__ + +#ifndef U_32_T +typedef unsigned int u_32_t; +# define U_32_T 1 +#endif + +typedef struct ipf_rdx_mask { + struct ipf_rdx_mask *next; + struct ipf_rdx_node *node; + u_32_t *mask; + int maskbitcount; +} ipf_rdx_mask_t; + +typedef struct ipf_rdx_node { + struct ipf_rdx_node *left; + struct ipf_rdx_node *right; + struct ipf_rdx_node *parent; + struct ipf_rdx_node *dupkey; + struct ipf_rdx_mask *masks; + struct ipf_rdx_mask *mymask; + u_32_t *addrkey; + u_32_t *maskkey; + u_32_t *addroff; + u_32_t *maskoff; + u_32_t lastmask; + u_32_t bitmask; + int offset; + int index; + int maskbitcount; + int root; +#ifdef RDX_DEBUG + char name[40]; +#endif +} ipf_rdx_node_t; + +struct ipf_rdx_head; + +typedef void (* radix_walk_func_t)(ipf_rdx_node_t *, void *); +typedef ipf_rdx_node_t *(* idx_hamn_func_t)(struct ipf_rdx_head *, + addrfamily_t *, addrfamily_t *, + ipf_rdx_node_t *); +typedef ipf_rdx_node_t *(* idx_ham_func_t)(struct ipf_rdx_head *, + addrfamily_t *, addrfamily_t *); +typedef ipf_rdx_node_t *(* idx_ha_func_t)(struct ipf_rdx_head *, + addrfamily_t *); +typedef void (* idx_walk_func_t)(struct ipf_rdx_head *, + radix_walk_func_t, void *); + +typedef struct ipf_rdx_head { + ipf_rdx_node_t *root; + ipf_rdx_node_t nodes[3]; + ipfmutex_t lock; + idx_hamn_func_t addaddr; /* add addr/mask to tree */ + idx_ham_func_t deladdr; /* delete addr/mask from tree */ + idx_ham_func_t lookup; /* look for specific addr/mask */ + idx_ha_func_t matchaddr; /* search tree for address match */ + idx_walk_func_t walktree; /* walk entire tree */ +} ipf_rdx_head_t; + +typedef struct radix_softc { + u_char *zeros; + u_char *ones; +} radix_softc_t; + +#undef RADIX_NODE_HEAD_LOCK +#undef RADIX_NODE_HEAD_UNLOCK +#ifdef _KERNEL +# define RADIX_NODE_HEAD_LOCK(x) MUTEX_ENTER(&(x)->lock) +# define RADIX_NODE_HEAD_UNLOCK(x) MUTEX_UNLOCK(&(x)->lock) +#else +# define RADIX_NODE_HEAD_LOCK(x) +# define RADIX_NODE_HEAD_UNLOCK(x) +#endif + +extern void *ipf_rx_create __P((void)); +extern int ipf_rx_init __P((void *)); +extern void ipf_rx_destroy __P((void *)); +extern int ipf_rx_inithead __P((radix_softc_t *, ipf_rdx_head_t **)); +extern void ipf_rx_freehead __P((ipf_rdx_head_t *)); +extern ipf_rdx_node_t *ipf_rx_addroute __P((ipf_rdx_head_t *, + addrfamily_t *, addrfamily_t *, + ipf_rdx_node_t *)); +extern ipf_rdx_node_t *ipf_rx_delete __P((ipf_rdx_head_t *, addrfamily_t *, + addrfamily_t *)); +extern void ipf_rx_walktree __P((ipf_rdx_head_t *, radix_walk_func_t, + void *)); + +#endif /* __RADIX_IPF_H__ */ diff --git a/contrib/ipfilter/rules/BASIC.NAT b/contrib/ipfilter/rules/BASIC.NAT new file mode 100644 index 0000000..213e338 --- /dev/null +++ b/contrib/ipfilter/rules/BASIC.NAT @@ -0,0 +1,46 @@ +#!/sbin/ipnat -f - +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# If we have only 1 valid IP address from our ISP, then we do this: +# +# To make ftp work, using the internal ftp proxy, use: +# +map ppp0 w.x.y.z/24 -> a.b.c.d/32 proxy port ftp ftp/tcp +# +# For normal TCP/UDP and other IP protocols +# +map ppp0 w.x.y.z/24 -> a.b.c.d/32 portmap tcp/udp 40000:60000 +map ppp0 w.x.y.z/24 -> a.b.c.d/32 +# +# if we get a different dialup IP address each time, then we would use: +# +#map ppp0 w.x.y.z/24 -> 0/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.z/24 -> 0/32 +# +# If we have a class C address space of valid IP#'s from our ISP, then we can +# do this: +# +#map ppp0 w.x.y.z/24 -> a.b.c.d/24 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.z/24 -> a.b.c.d/24 +# +# or, if we only have a small number of PC's, this: +# +#map ppp0 w.x.y.v/32 -> a.b.c.E/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.v/32 -> a.b.c.E/32 +#map ppp0 w.x.y.u/32 -> a.b.c.F/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.u/32 -> a.b.c.F/32 +#map ppp0 w.x.y.t/32 -> a.b.c.G/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.t/32 -> a.b.c.G/32 +#map ppp0 w.x.y.s/32 -> a.b.c.H/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.s/32 -> a.b.c.H/32 +#map ppp0 w.x.y.r/32 -> a.b.c.I/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.r/32 -> a.b.c.I/32 +#map ppp0 w.x.y.q/32 -> a.b.c.J/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.q/32 -> a.b.c.J/32 +#map ppp0 w.x.y.p/32 -> a.b.c.K/32 portmap tcp/udp 40000:60000 +#map ppp0 w.x.y.p/32 -> a.b.c.K/32 diff --git a/contrib/ipfilter/rules/BASIC_1.FW b/contrib/ipfilter/rules/BASIC_1.FW new file mode 100644 index 0000000..642dde0 --- /dev/null +++ b/contrib/ipfilter/rules/BASIC_1.FW @@ -0,0 +1,99 @@ +#!/sbin/ipf -f - +# +# SAMPLE: RESTRICTIVE FILTER RULES +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# This file contains the basic rules needed to construct a firewall for the +# above situation. +# +#------------------------------------------------------- +# *Nasty* packets we don't want to allow near us at all! +# short packets which are packets fragmented too short to be real. +block in log quick all with short +#------------------------------------------------------- +# Group setup. +# ============ +# By default, block and log everything. This maybe too much logging +# (especially for ed0) and needs to be further refined. +# +block in log on ppp0 all head 100 +block in log proto tcp all flags S/SA head 101 group 100 +block out log on ppp0 all head 150 +block in log on ed0 from w.x.y.z/24 to any head 200 +block in log proto tcp all flags S/SA head 201 group 200 +block in log proto udp all head 202 group 200 +block out log on ed0 all head 250 +#------------------------------------------------------- +# Localhost packets. +# ================== +# packets going in/out of network interfaces that aren't on the loopback +# interface should *NOT* exist. +block in log quick from 127.0.0.0/8 to any group 100 +block in log quick from any to 127.0.0.0/8 group 100 +block in log quick from 127.0.0.0/8 to any group 200 +block in log quick from any to 127.0.0.0/8 group 200 +# And of course, make sure the loopback allows packets to traverse it. +pass in quick on lo0 all +pass out quick on lo0 all +#------------------------------------------------------- +# Invalid Internet packets. +# ========================= +# +# Deny reserved addresses. +# +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log quick from 172.16.0.0/12 to any group 100 +# +# Prevent IP spoofing. +# +block in log quick from a.b.c.d/24 to any group 100 +# +#------------------------------------------------------- +# Allow outgoing DNS requests (no named on firewall) +# +pass in quick proto udp from any to any port = 53 keep state group 202 +# +# If we were running named on the firewall and all internal hosts talked to +# it, we'd use the following: +# +#pass in quick proto udp from any to w.x.y.z/32 port = 53 keep state group 202 +#pass out quick on ppp0 proto udp from a.b.c.d/32 to any port = 53 keep state +# +# Allow outgoing FTP from any internal host to any external FTP server. +# +pass in quick proto tcp from any to any port = ftp keep state group 201 +pass in quick proto tcp from any to any port = ftp-data keep state group 201 +pass in quick proto tcp from any port = ftp-data to any port > 1023 keep state group 101 +# +# Allow NTP from any internal host to any external NTP server. +# +pass in quick proto udp from any to any port = ntp keep state group 202 +# +# Allow outgoing connections: SSH, TELNET, WWW +# +pass in quick proto tcp from any to any port = 22 keep state group 201 +pass in quick proto tcp from any to any port = telnet keep state group 201 +pass in quick proto tcp from any to any port = www keep state group 201 +# +#------------------------------------------------------- +block in log proto tcp from any to a.b.c.d/32 flags S/SA head 110 group 100 +# +# Allow incoming to the external firewall interface: mail, WWW, DNS +# +pass in log quick proto tcp from any to any port = smtp keep state group 110 +pass in log quick proto tcp from any to any port = www keep state group 110 +pass in log quick proto tcp from any to any port = 53 keep state group 110 +pass in log quick proto udp from any to any port = 53 keep state group 100 +#------------------------------------------------------- +# Log these: +# ========== +# * return RST packets for invalid SYN packets to help the other end close +block return-rst in log proto tcp from any to any flags S/SA group 100 +# * return ICMP error packets for invalid UDP packets +block return-icmp(net-unr) in proto udp all group 100 diff --git a/contrib/ipfilter/rules/BASIC_2.FW b/contrib/ipfilter/rules/BASIC_2.FW new file mode 100644 index 0000000..1d4fd73 --- /dev/null +++ b/contrib/ipfilter/rules/BASIC_2.FW @@ -0,0 +1,72 @@ +#!/sbin/ipf -f - +# +# SAMPLE: PERMISSIVE FILTER RULES +# +# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3 +# +# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32 +# +# ed0 - (internal) network interface, address w.x.y.z/32 +# +# This file contains the basic rules needed to construct a firewall for the +# above situation. +# +#------------------------------------------------------- +# *Nasty* packets we don't want to allow near us at all! +# short packets which are packets fragmented too short to be real. +block in log quick all with short +#------------------------------------------------------- +# Group setup. +# ============ +# By default, block and log everything. This maybe too much logging +# (especially for ed0) and needs to be further refined. +# +block in log on ppp0 all head 100 +block out log on ppp0 all head 150 +block in log on ed0 from w.x.y.z/24 to any head 200 +block out log on ed0 all head 250 +#------------------------------------------------------- +# Invalid Internet packets. +# ========================= +# +# Deny reserved addresses. +# +block in log quick from 10.0.0.0/8 to any group 100 +block in log quick from 192.168.0.0/16 to any group 100 +block in log quick from 172.16.0.0/12 to any group 100 +# +# Prevent IP spoofing. +# +block in log quick from a.b.c.d/24 to any group 100 +# +#------------------------------------------------------- +# Localhost packets. +# ================== +# packets going in/out of network interfaces that aren't on the loopback +# interface should *NOT* exist. +block in log quick from 127.0.0.0/8 to any group 100 +block in log quick from any to 127.0.0.0/8 group 100 +block in log quick from 127.0.0.0/8 to any group 200 +block in log quick from any to 127.0.0.0/8 group 200 +# And of course, make sure the loopback allows packets to traverse it. +pass in quick on lo0 all +pass out quick on lo0 all +#------------------------------------------------------- +# Allow any communication between the inside network and the outside only. +# +# Allow all outgoing connections (SSH, TELNET, FTP, WWW, gopher, etc) +# +pass in log quick proto tcp all flags S/SA keep state group 200 +# +# Support all UDP `connections' initiated from inside. +# +# Allow ping out +# +pass in log quick proto icmp all keep state group 200 +#------------------------------------------------------- +# Log these: +# ========== +# * return RST packets for invalid SYN packets to help the other end close +block return-rst in log proto tcp from any to any flags S/SA group 100 +# * return ICMP error packets for invalid UDP packets +block return-icmp(net-unr) in proto udp all group 100 diff --git a/contrib/ipfilter/rules/example.1 b/contrib/ipfilter/rules/example.1 new file mode 100644 index 0000000..ff93f49 --- /dev/null +++ b/contrib/ipfilter/rules/example.1 @@ -0,0 +1,4 @@ +# +# block all incoming TCP packets on le0 from host 10.1.1.1 to any destination. +# +block in on le0 proto tcp from 10.1.1.1/32 to any diff --git a/contrib/ipfilter/rules/example.10 b/contrib/ipfilter/rules/example.10 new file mode 100644 index 0000000..560d1e6 --- /dev/null +++ b/contrib/ipfilter/rules/example.10 @@ -0,0 +1,12 @@ +# +# pass ack packets (ie established connection) +# +pass in proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A +pass out proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A +# +# block incoming connection requests to my internal network from the big bad +# internet. +# +block in on le0 proto tcp from any to 10.1.0.0/16 flags S/SA +# to block the replies: +block out on le0 proto tcp from 10.1.0.0 to any flags SA/SA diff --git a/contrib/ipfilter/rules/example.11 b/contrib/ipfilter/rules/example.11 new file mode 100644 index 0000000..c6b4e7f --- /dev/null +++ b/contrib/ipfilter/rules/example.11 @@ -0,0 +1,26 @@ +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass in proto tcp from 10.2.2.2/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass in proto udp from 10.2.2.2 port != 53 to localhost +# +# block anything trying to get to X terminal ports, X:0 to X:9 +# +block in proto tcp from any to any port 5999 >< 6010 +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +block in proto tcp/udp all +pass in proto tcp/udp from any to any port 512 <> 515 +# +# allow any connections to be made, except to BSD print/r-services +# this will also protect syslog. +# +pass in proto tcp/udp all +block in proto tcp/udp from any to any port 511 >< 516 diff --git a/contrib/ipfilter/rules/example.12 b/contrib/ipfilter/rules/example.12 new file mode 100644 index 0000000..c0ba1d3 --- /dev/null +++ b/contrib/ipfilter/rules/example.12 @@ -0,0 +1,17 @@ +# +# get rid of all short IP fragments (too small for valid comparison) +# +block in proto tcp all with short +# +# drop and log any IP packets with options set in them. +# +block in log all with ipopts +# +# log packets with BOTH ssrr and lsrr set +# +log in all with opt lsrr,ssrr +# +# drop any source routing options +# +block in quick all with opt lsrr +block in quick all with opt ssrr diff --git a/contrib/ipfilter/rules/example.13 b/contrib/ipfilter/rules/example.13 new file mode 100644 index 0000000..854f07f --- /dev/null +++ b/contrib/ipfilter/rules/example.13 @@ -0,0 +1,17 @@ +# +# Log all short TCP packets to qe3, with 10.3.3.3 as the intended +# destination for the packet. +# +block in on qe0 to qe3:10.3.3.3 proto tcp all with short +# +# Log all connection attempts for TCP +# +pass in on le0 dup-to le1:10.3.3.3 proto tcp all flags S/SA +# +# Route all UDP packets through transparently. +# +pass in on ppp0 fastroute proto udp all +# +# Route all ICMP packets to network 10 out through le1, to 10.3.3.1 +# +pass in on le0 to le1:10.3.3.1 proto icmp all diff --git a/contrib/ipfilter/rules/example.2 b/contrib/ipfilter/rules/example.2 new file mode 100644 index 0000000..4f81725 --- /dev/null +++ b/contrib/ipfilter/rules/example.2 @@ -0,0 +1,5 @@ +# +# block all outgoing TCP packets on le0 from any host to port 23 of +# host 10.1.1.2 +# +block out on le0 proto tcp from any to 10.1.1.3/32 port = 23 diff --git a/contrib/ipfilter/rules/example.3 b/contrib/ipfilter/rules/example.3 new file mode 100644 index 0000000..cd31f73 --- /dev/null +++ b/contrib/ipfilter/rules/example.3 @@ -0,0 +1,40 @@ +# +# block all inbound packets. +# +block in from any to any +# +# pass through packets to and from localhost. +# +pass in from 127.0.0.1/32 to 127.0.0.1/32 +# +# allow a variety of individual hosts to send any type of IP packet to any +# other host. +# +pass in from 10.1.3.1/32 to any +pass in from 10.1.3.2/32 to any +pass in from 10.1.3.3/32 to any +pass in from 10.1.3.4/32 to any +pass in from 10.1.3.5/32 to any +pass in from 10.1.0.13/32 to any +pass in from 10.1.1.1/32 to any +pass in from 10.1.2.1/32 to any +# +# +# block all outbound packets. +# +block out from any to any +# +# allow any packets destined for localhost out. +# +pass out from any to 127.0.0.1/32 +# +# allow any host to send any IP packet out to a limited number of hosts. +# +pass out from any to 10.1.3.1/32 +pass out from any to 10.1.3.2/32 +pass out from any to 10.1.3.3/32 +pass out from any to 10.1.3.4/32 +pass out from any to 10.1.3.5/32 +pass out from any to 10.1.0.13/32 +pass out from any to 10.1.1.1/32 +pass out from any to 10.1.2.1/32 diff --git a/contrib/ipfilter/rules/example.4 b/contrib/ipfilter/rules/example.4 new file mode 100644 index 0000000..7918ec2 --- /dev/null +++ b/contrib/ipfilter/rules/example.4 @@ -0,0 +1,4 @@ +# +# block all ICMP packets. +# +block in proto icmp from any to any diff --git a/contrib/ipfilter/rules/example.5 b/contrib/ipfilter/rules/example.5 new file mode 100644 index 0000000..6d688b5 --- /dev/null +++ b/contrib/ipfilter/rules/example.5 @@ -0,0 +1,25 @@ +# +# test ruleset +# +# allow packets coming from foo to bar through. +# +pass in from 10.1.1.2 to 10.2.1.1 +# +# allow any TCP packets from the same subnet as foo is on through to host +# 10.1.1.2 if they are destined for port 6667. +# +pass in proto tcp from 10.2.2.2/24 to 10.1.1.2/32 port = 6667 +# +# allow in UDP packets which are NOT from port 53 and are destined for +# localhost +# +pass in proto udp from 10.2.2.2 port != 53 to localhost +# +# block all ICMP unreachables. +# +block in proto icmp from any to any icmp-type unreach +# +# allow packets through which have a non-standard IP header length (ie there +# are IP options such as source-routing present). +# +pass in from any to any with ipopts diff --git a/contrib/ipfilter/rules/example.6 b/contrib/ipfilter/rules/example.6 new file mode 100644 index 0000000..d40f0f3 --- /dev/null +++ b/contrib/ipfilter/rules/example.6 @@ -0,0 +1,5 @@ +# +# block all TCP packets with only the SYN flag set (this is the first +# packet sent to establish a connection) out of the SYN-ACK pair. +# +block in proto tcp from any to any flags S/SA diff --git a/contrib/ipfilter/rules/example.7 b/contrib/ipfilter/rules/example.7 new file mode 100644 index 0000000..062de98 --- /dev/null +++ b/contrib/ipfilter/rules/example.7 @@ -0,0 +1,12 @@ +# block all ICMP packets. +# +block in proto icmp all +# +# allow in ICMP echos and echo-replies. +# +pass in on le1 proto icmp from any to any icmp-type echo +pass in on le1 proto icmp from any to any icmp-type echorep +# +# block all ICMP destination unreachable packets which are port-unreachables +# +block in on le1 proto icmp from any to any icmp-type unreach code 3 diff --git a/contrib/ipfilter/rules/example.8 b/contrib/ipfilter/rules/example.8 new file mode 100644 index 0000000..baa0258 --- /dev/null +++ b/contrib/ipfilter/rules/example.8 @@ -0,0 +1,10 @@ +# +# block all incoming TCP connections but send back a TCP-RST for ones to +# the ident port +# +block in proto tcp from any to any flags S/SA +block return-rst in quick proto tcp from any to any port = 113 flags S/SA +# +# block all inbound UDP packets and send back an ICMP error. +# +block return-icmp in proto udp from any to any diff --git a/contrib/ipfilter/rules/example.9 b/contrib/ipfilter/rules/example.9 new file mode 100644 index 0000000..daff203 --- /dev/null +++ b/contrib/ipfilter/rules/example.9 @@ -0,0 +1,12 @@ +# +# drop all packets without IP security options +# +block in all +pass in all with opt sec +# +# only allow packets in and out on le1 which are top secret +# +block out on le1 all +pass out on le1 all with opt sec-class topsecret +block in on le1 all +pass in on le1 all with opt sec-class topsecret diff --git a/contrib/ipfilter/rules/example.sr b/contrib/ipfilter/rules/example.sr new file mode 100644 index 0000000..c4c1994 --- /dev/null +++ b/contrib/ipfilter/rules/example.sr @@ -0,0 +1,61 @@ +# +# log all inbound packet on le0 which has IP options present +# +log in on le0 from any to any with ipopts +# +# block any inbound packets on le0 which are fragmented and "too short" to +# do any meaningful comparison on. This actually only applies to TCP +# packets which can be missing the flags/ports (depending on which part +# of the fragment you see). +# +block in log quick on le0 from any to any with short frag +# +# log all inbound TCP packets with the SYN flag (only) set +# (NOTE: if it were an inbound TCP packet with the SYN flag set and it +# had IP options present, this rule and the above would cause it +# to be logged twice). +# +log in on le0 proto tcp from any to any flags S/SA +# +# block and log any inbound ICMP unreachables +# +block in log on le0 proto icmp from any to any icmp-type unreach +# +# block and log any inbound UDP packets on le0 which are going to port 2049 +# (the NFS port). +# +block in log on le0 proto udp from any to any port = 2049 +# +# quickly allow any packets to/from a particular pair of hosts +# +pass in quick from any to 10.1.3.2/32 +pass in quick from any to 10.1.0.13/32 +pass in quick from 10.1.3.2/32 to any +pass in quick from 10.1.0.13/32 to any +# +# block (and stop matching) any packet with IP options present. +# +block in quick on le0 from any to any with ipopts +# +# allow any packet through +# +pass in from any to any +# +# block any inbound UDP packets destined for these subnets. +# +block in on le0 proto udp from any to 10.1.3.0/24 +block in on le0 proto udp from any to 10.1.1.0/24 +block in on le0 proto udp from any to 10.1.2.0/24 +# +# block any inbound TCP packets with only the SYN flag set that are +# destined for these subnets. +# +block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA +block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA +# +# block any inbound ICMP packets destined for these subnets. +# +block in on le0 proto icmp from any to 10.1.3.0/24 +block in on le0 proto icmp from any to 10.1.1.0/24 +block in on le0 proto icmp from any to 10.1.2.0/24 diff --git a/contrib/ipfilter/rules/firewall b/contrib/ipfilter/rules/firewall new file mode 100644 index 0000000..f26b715 --- /dev/null +++ b/contrib/ipfilter/rules/firewall @@ -0,0 +1,39 @@ +Configuring IP Filter for firewall usage. +========================================= + +Step 1 - Block out "bad" IP packets. +------------------------------------ + +Run the perl script "mkfilters". This will generate a list of blocking +rules which: + a) blocks all packets which might belong to an IP Spoofing attack; + b) blocks all packets with IP options; + c) blocks all packets which have a length which is too short for + any legal packet; + +Step 2 - Convert Network Security Policy to filter rules. +--------------------------------------------------------- + +Draw up a list of which services you want to allow users to use on the +Internet (e.g. WWW, ftp, etc). Draw up a separate list for what you +want each host that is part of your firewall to be allowed to do, including +communication with internal hosts. + +Step 3 - Create TCP "keep state" rules. +--------------------------------------- + +For each service that uses TCP, create a rule as follows: + +pass in on <int-a> proto tcp from <int-net> to any port <ext-service> flags S/SA keep state + +where +* "int-a" is the internal interface of the firewall. That is, it is the + closest to your internal network in terms of network hops. + +* "int-net" is the internal network IP# subnet address range. This might + be something like 10.1.0.0/16, or 128.33.1.0/24 + +* "ext-service" is the service to which you wish to connect or if it doesn't + have a proper name, a number can be used. The translation of "ext-service" + as a name to a number is controlled with the /etc/services file. + diff --git a/contrib/ipfilter/rules/ftp-proxy b/contrib/ipfilter/rules/ftp-proxy new file mode 100644 index 0000000..ad2f717 --- /dev/null +++ b/contrib/ipfilter/rules/ftp-proxy @@ -0,0 +1,45 @@ +How to setup FTP proxying using the built in proxy code. +======================================================== + +NOTE: Currently, the built-in FTP proxy is only available for use with NAT + (i.e. only if you're already using "map" rules with ipnat). It does + support null-NAT mappings, that is, using the proxy without changing + the addresses. + +Lets assume your network diagram looks something like this: + + +[host A] + |a +---+-------------+---------- + |b + [host B] + |c +---+-------------+---------- + |d +[host C] + +and IP Filter is running on host B. If you want to proxy FTP from A to C +then you would do: + +map int-c ipaddr-a/32 -> ip-addr-c-net/32 proxy port ftp ftp/tcp + +int-c = name of "interface c" +ipaddr-a = ip# of interface a +ipaddr-c-net = another ip# on the C-network (usually not the same as the +interface). + +e.g., if host A was 10.1.1.1, host B had two network interfaces ed0 and vx0 +which had IP#'s 10.1.1.2 and 203.45.67.89 respectively, and host C was +203.45.67.90, you would do: + +map vx0 10.1.1.1/32 -> 203.45.67.91/32 proxy port ftp ftp/tcp + +where: +ipaddr-a = 10.1.1.1 +int-c = vx0 +ipaddr-c-net = 203.45.67.91 + +The "map" rule for this proxy should precede any other NAT rules you are +using. + diff --git a/contrib/ipfilter/rules/ftppxy b/contrib/ipfilter/rules/ftppxy new file mode 100755 index 0000000..2c42c52 --- /dev/null +++ b/contrib/ipfilter/rules/ftppxy @@ -0,0 +1,6 @@ +#!/bin/sh +# The proxy bit is as follows: +# proxy [port <portname>] <tag>/<protocol> +# the <tag> should match a tagname in the proxy table, as does the protocol. +# this format isn't finalised yet +echo "map ed0 0/0 -> 192.1.1.1/32 proxy port ftp ftp/tcp" | /sbin/ipnat -f - diff --git a/contrib/ipfilter/rules/ip_rules b/contrib/ipfilter/rules/ip_rules new file mode 100644 index 0000000..9850f16 --- /dev/null +++ b/contrib/ipfilter/rules/ip_rules @@ -0,0 +1,3 @@ +# Used to generate ../ip_rules.c and ../ip_rules.h +pass in all +pass out all diff --git a/contrib/ipfilter/rules/ipmon.conf b/contrib/ipfilter/rules/ipmon.conf new file mode 100644 index 0000000..652afce --- /dev/null +++ b/contrib/ipfilter/rules/ipmon.conf @@ -0,0 +1,25 @@ +# +# +# +# +match { logtag = 10000; } +do { execute("/usr/bin/mail -s 'logtag 10000' root"); }; +# +match { logtag = 2000, every 10 seconds; } +do { execute("echo 'XXXXXXXX tag 2000 packet XXXXXXXX'"); }; +# +match { protocol = udp, result = block; } +do { file("file:///var/log/udp-block"); }; +# +match { protocol = tcp, result = block, dstport = 25; } +do { syslog("local0.info"), syslog("local1."), syslog(".warn"); }; +# +match { srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; } +do { execute("/usr/bin/mail -s 'from 10.1 to 192.168.1' root"); }; + +# +match { + rule = 12, logtag = 101, direction = in, result = block, + protocol = udp, srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; } +do { nothing; }; +# diff --git a/contrib/ipfilter/rules/nat-setup b/contrib/ipfilter/rules/nat-setup new file mode 100644 index 0000000..b10e8f1 --- /dev/null +++ b/contrib/ipfilter/rules/nat-setup @@ -0,0 +1,77 @@ +Configuring NAT on your network. +================================ + +To start setting up NAT, we need to define which is your "internal" interface +and which is your "external" interface. The "internal" interface is the +network adapter connected to the network with private IP addresses which +you need to change for communicating on the Internet. The "external" +interface is configured with a valid internet address. + +For example, your internal interface might have an IP# of 10.1.1.1 and be +connected to your ethernet, whilst your external interface might be a PPP +connection with an IP number of 204.51.62.176. + +Thus your network might look like this: + +<Internal Network> + [pc] [pc] + | | ++-+---------+------+ + | + [firewall] + | + | + Internet +<External Network> + + +Writing the map-rule. +--------------------- +When you're connected to the Internet, you will either have a block of IP +addresses assigned to you, maybe several different blocks, or you use a +single IP address, i.e. with dialup PPP. If you have a block of addresses +assigned, these can be used to create either a 1:1 mapping (if you have +only a few internal IP addresses) or N:1 mappings, where groups of internal +addresses map to a single IP address and unless you have enough Internet +addresses for a 1:1 mapping, you will want to do "portmapping" for TCP and +UDP port numbers. + +For an N:1 situation, you might have: + +map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap + +where if you had 16 addresses available, you could do: + +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap + +Or if you wanted to allocate subnets to each IP#, you might do: + +map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap tcp/udp 10000:40000 +map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap +map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap +map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap + +*** NOTE: NAT rules are used on a first-match basis only! + + +Filtering with NAT. +------------------- +IP Filter will always translate addresses in a packet _BEFORE_ it checks its +access list for inbound packets and translates addresses _AFTER_ it has +checked the access control lists for outbound packets. + +For example (using the above NAT rules), if you wanted to prevent all hosts +in the 10.1.2.0/24 subnet from using NAT, you might use the following rule +with ipf: + +block out on ppp0 from 10.1.2.0/24 to any +block in on ppp0 from any to 10.1.2.0/24 + +and use these with ipnat: + +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000 +map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap diff --git a/contrib/ipfilter/rules/nat.eg b/contrib/ipfilter/rules/nat.eg new file mode 100644 index 0000000..9c26754 --- /dev/null +++ b/contrib/ipfilter/rules/nat.eg @@ -0,0 +1,14 @@ +# map all tcp connections from 10.1.0.0/16 to 240.1.0.1, changing the source +# port number to something between 10,000 and 20,000 inclusive. For all other +# IP packets, allocate an IP # between 240.1.0.0 and 240.1.0.255, temporarily +# for each new user. +# +map ed1 10.1.0.0/16 -> 240.1.0.1/32 portmap tcp 10000:20000 +map ed1 10.1.0.0/16 -> 240.1.0.0/24 +# +# Redirection is triggered for input packets. +# For example, to redirect FTP connections through this box, to the local ftp +# port, forcing them to connect through a proxy, you would use: +# +rdr ed0 0.0.0.0/0 port ftp -> 127.0.0.1 port ftp +# diff --git a/contrib/ipfilter/rules/pool.conf b/contrib/ipfilter/rules/pool.conf new file mode 100644 index 0000000..285398d --- /dev/null +++ b/contrib/ipfilter/rules/pool.conf @@ -0,0 +1,4 @@ +# +pool 0 = { !10.0.0.0 - 10.255.255.255, 10.1.0.0 - 10.1.255.255, + 10.1.1.0 - 10.1.1.255, !10.1.2.0 - 10.2.2.255, + 10.1.2.3 - 10.1.2.3, 10.1.2.15 - 10.1.2.15 }; diff --git a/contrib/ipfilter/rules/server b/contrib/ipfilter/rules/server new file mode 100644 index 0000000..de0e9bb --- /dev/null +++ b/contrib/ipfilter/rules/server @@ -0,0 +1,11 @@ +# +# For a network server, which has two interfaces, 128.1.40.1 (le0) and +# 128.1.2.1 (le1), we want to block all IP spoofing attacks. le1 is +# connected to the majority of the network, whilst le0 is connected to a +# leaf subnet. We're not concerned about filtering individual services +# or +# +pass in quick on le0 from 128.1.40.0/24 to any +block in log quick on le0 from any to any +block in log quick on le1 from 128.1.1.0/24 to any +pass in quick on le1 from any to any diff --git a/contrib/ipfilter/rules/tcpstate b/contrib/ipfilter/rules/tcpstate new file mode 100644 index 0000000..339a25f --- /dev/null +++ b/contrib/ipfilter/rules/tcpstate @@ -0,0 +1,13 @@ +# +# Only allow TCP packets in/out of le0 if there is an outgoing connection setup +# somewhere, waiting for it. +# +pass out quick on le0 proto tcp from any to any flags S/SAFR keep state +block out on le0 proto tcp all +block in on le0 proto tcp all +# +# allow nameserver queries and replies to pass through, but no other UDP +# +pass out quick on le0 proto udp from any to any port = 53 keep state +block out on le0 proto udp all +block in on le0 proto udp all diff --git a/contrib/ipfilter/samples/Makefile b/contrib/ipfilter/samples/Makefile new file mode 100644 index 0000000..47ab4a2 --- /dev/null +++ b/contrib/ipfilter/samples/Makefile @@ -0,0 +1,24 @@ +CC=gcc +all: + @echo "Please do one of the following:" + @echo "make bsd" + @echo "make bsdi" + @echo "make freebsd" + @echo "make freebsd22" + @echo "make netbsd" + @echo "make openbsd" + @echo "make sunos4" + @echo "make sunos5" + +sunos5: + $(CC) -I.. userauth.c -o userauth -lsocket -lnsl + $(CC) -I.. proxy.c -o proxy -lsocket -lnsl + $(CC) -I.. relay.c -o relay -lsocket -lnsl + +freebsd freebsd22 netbsd bsd bsdi sunos4 openbsd: + $(CC) -I.. userauth.c -o userauth + $(CC) -I.. proxy.c -o proxy + $(CC) -I.. relay.c -o relay + +clean: + /bin/rm -f userauth proxy relay diff --git a/contrib/ipfilter/samples/ipfilter-pb.gif b/contrib/ipfilter/samples/ipfilter-pb.gif Binary files differnew file mode 100644 index 0000000..afaefa8 --- /dev/null +++ b/contrib/ipfilter/samples/ipfilter-pb.gif diff --git a/contrib/ipfilter/samples/proxy.c b/contrib/ipfilter/samples/proxy.c new file mode 100644 index 0000000..483c4b5 --- /dev/null +++ b/contrib/ipfilter/samples/proxy.c @@ -0,0 +1,317 @@ +/* $FreeBSD$ */ + +/* + * Sample transparent proxy program. + * + * Sample implementation of a program which intercepts a TCP connectiona and + * just echos all data back to the origin. Written to work via inetd as a + * "nonwait" program running as root; ie. + * tcpmux stream tcp nowait root /usr/local/bin/proxy proxy + * with a NAT rue like this: + * rdr smc0 0/0 port 80 -> 127.0.0.1/32 port 1 + */ +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <syslog.h> +#if !defined(__SVR4) && !defined(__svr4__) +#include <strings.h> +#else +#include <sys/byteorder.h> +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# include <sys/ioccom.h> +# include <sys/sysmacros.h> +#endif +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <net/if.h> +#include <netdb.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <ctype.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" +#include "netinet/ip_proxy.h" +#include "netinet/ip_nat.h" +#include "netinet/ipl.h" + + +main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin, sloc, sout; + ipfobj_t obj; + natlookup_t natlook; + char buffer[512]; + int namelen, fd, n; + + /* + * get IP# and port # of the remote end of the connection (at the + * origin). + */ + namelen = sizeof(sin); + if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) { + perror("getpeername"); + exit(-1); + } + + /* + * get IP# and port # of the local end of the connection (at the + * man-in-the-middle). + */ + namelen = sizeof(sin); + if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) { + perror("getsockname"); + exit(-1); + } + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(natlook); + obj.ipfo_ptr = &natlook; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + + /* + * Build up the NAT natlookup structure. + */ + bzero((char *)&natlook, sizeof(natlook)); + natlook.nl_outip = sin.sin_addr; + natlook.nl_inip = sloc.sin_addr; + natlook.nl_flags = IPN_TCP; + natlook.nl_outport = sin.sin_port; + natlook.nl_inport = sloc.sin_port; + + /* + * Open the NAT device and lookup the mapping pair. + */ + fd = open(IPNAT_NAME, O_RDONLY); + if (ioctl(fd, SIOCGNATL, &obj) == -1) { + perror("ioctl(SIOCGNATL)"); + exit(-1); + } + +#define DO_NAT_OUT +#ifdef DO_NAT_OUT + if (argc > 1) + do_nat_out(0, 1, fd, &natlook, argv[1]); +#else + + /* + * Log it + */ + syslog(LOG_DAEMON|LOG_INFO, "connect to %s,%d", + inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); + printf("connect to %s,%d\n", + inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); + + /* + * Just echo data read in from stdin to stdout + */ + while ((n = read(0, buffer, sizeof(buffer))) > 0) + if (write(1, buffer, n) != n) + break; + close(0); +#endif +} + + +#ifdef DO_NAT_OUT +do_nat_out(in, out, fd, nlp, extif) + int fd; + natlookup_t *nlp; + char *extif; +{ + nat_save_t ns, *nsp = &ns; + struct sockaddr_in usin; + u_32_t sum1, sum2, sumd; + int onoff, ofd, slen; + ipfobj_t obj; + ipnat_t *ipn; + nat_t *nat; + + bzero((char *)&ns, sizeof(ns)); + + nat = &ns.ipn_nat; + nat->nat_p = IPPROTO_TCP; + nat->nat_dir = NAT_OUTBOUND; + if ((extif != NULL) && (*extif != '\0')) { + strncpy(nat->nat_ifnames[0], extif, + sizeof(nat->nat_ifnames[0])); + strncpy(nat->nat_ifnames[1], extif, + sizeof(nat->nat_ifnames[1])); + nat->nat_ifnames[0][sizeof(nat->nat_ifnames[0]) - 1] = '\0'; + nat->nat_ifnames[1][sizeof(nat->nat_ifnames[1]) - 1] = '\0'; + } + + ofd = socket(AF_INET, SOCK_DGRAM, 0); + bzero((char *)&usin, sizeof(usin)); + usin.sin_family = AF_INET; + usin.sin_addr = nlp->nl_realip; + usin.sin_port = nlp->nl_realport; + (void) connect(ofd, (struct sockaddr *)&usin, sizeof(usin)); + slen = sizeof(usin); + (void) getsockname(ofd, (struct sockaddr *)&usin, &slen); + close(ofd); +printf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr)); + + if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1) + perror("socket"); + usin.sin_port = 0; + if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin))) + perror("bind"); + slen = sizeof(usin); + if (getsockname(ofd, (struct sockaddr *)&usin, &slen)) + perror("getsockname"); +printf("local port# to use: %d\n", ntohs(usin.sin_port)); + + nat->nat_inip = usin.sin_addr; + nat->nat_outip = nlp->nl_outip; + nat->nat_oip = nlp->nl_realip; + + sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) + ntohs(usin.sin_port); + sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) + ntohs(nlp->nl_outport); + CALC_SUMD(sum1, sum2, sumd); + nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); + nat->nat_sumd[1] = nat->nat_sumd[0]; + + sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)); + sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); + CALC_SUMD(sum1, sum2, sumd); + nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); + + nat->nat_inport = usin.sin_port; + nat->nat_outport = nlp->nl_outport; + nat->nat_oport = nlp->nl_realport; + + nat->nat_flags = IPN_TCPUDP; + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*nsp); + obj.ipfo_ptr = nsp; + obj.ipfo_type = IPFOBJ_NATSAVE; + + onoff = 1; + if (ioctl(fd, SIOCSTLCK, &onoff) == 0) { + if (ioctl(fd, SIOCSTPUT, &obj) != 0) + perror("SIOCSTPUT"); + onoff = 0; + if (ioctl(fd, SIOCSTLCK, &onoff) != 0) + perror("SIOCSTLCK"); + } + + usin.sin_addr = nlp->nl_realip; + usin.sin_port = nlp->nl_realport; +printf("remote end for connection: %s,%d\n", inet_ntoa(usin.sin_addr), +ntohs(usin.sin_port)); +fflush(stdout); + if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin))) + perror("connect"); + + relay(in, out, ofd); +} + + +relay(in, out, net) + int in, out, net; +{ + char netbuf[1024], outbuf[1024]; + char *nwptr, *nrptr, *owptr, *orptr; + size_t nsz, osz; + fd_set rd, wr; + int i, n, maxfd; + + n = 0; + maxfd = in; + if (out > maxfd) + maxfd = out; + if (net > maxfd) + maxfd = net; + + nrptr = netbuf; + nwptr = netbuf; + nsz = sizeof(netbuf); + orptr = outbuf; + owptr = outbuf; + osz = sizeof(outbuf); + + while (n >= 0) { + FD_ZERO(&rd); + FD_ZERO(&wr); + + if (nrptr - netbuf < sizeof(netbuf)) + FD_SET(in, &rd); + if (orptr - outbuf < sizeof(outbuf)) + FD_SET(net, &rd); + + if (nsz < sizeof(netbuf)) + FD_SET(net, &wr); + if (osz < sizeof(outbuf)) + FD_SET(out, &wr); + + n = select(maxfd + 1, &rd, &wr, NULL, NULL); + + if ((n > 0) && FD_ISSET(in, &rd)) { + i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf)); + if (i <= 0) + break; + nsz -= i; + nrptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(net, &rd)) { + i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf)); + if (i <= 0) + break; + osz -= i; + orptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(out, &wr)) { + i = write(out, owptr, orptr - owptr); + if (i <= 0) + break; + osz += i; + if (osz == sizeof(outbuf) || owptr == orptr) { + orptr = outbuf; + owptr = outbuf; + } else + owptr += i; + n--; + } + + if ((n > 0) && FD_ISSET(net, &wr)) { + i = write(net, nwptr, nrptr - nwptr); + if (i <= 0) + break; + nsz += i; + if (nsz == sizeof(netbuf) || nwptr == nrptr) { + nrptr = netbuf; + nwptr = netbuf; + } else + nwptr += i; + } + } + + close(net); + close(out); + close(in); +} +#endif diff --git a/contrib/ipfilter/samples/relay.c b/contrib/ipfilter/samples/relay.c new file mode 100644 index 0000000..11b76b0 --- /dev/null +++ b/contrib/ipfilter/samples/relay.c @@ -0,0 +1,196 @@ +/* $FreeBSD$ */ + +/* + * Sample program to be used as a transparent proxy. + * + * Must be executed with permission enough to do an ioctl on /dev/ipl + * or equivalent. This is just a sample and is only alpha quality. + * - Darren Reed (8 April 1996) + */ +#include <unistd.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/syslog.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <net/if.h> +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ipl.h" + +#define RELAY_BUFSZ 8192 + +char ibuff[RELAY_BUFSZ]; +char obuff[RELAY_BUFSZ]; + +int relay(ifd, ofd, rfd) + int ifd, ofd, rfd; +{ + fd_set rfds, wfds; + char *irh, *irt, *rrh, *rrt; + char *iwh, *iwt, *rwh, *rwt; + int nfd, n, rw; + + irh = irt = ibuff; + iwh = iwt = obuff; + nfd = ifd; + if (nfd < ofd) + nfd = ofd; + if (nfd < rfd) + nfd = rfd; + + while (1) { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + if (irh > irt) + FD_SET(rfd, &wfds); + if (irh < (ibuff + RELAY_BUFSZ)) + FD_SET(ifd, &rfds); + if (iwh > iwt) + FD_SET(ofd, &wfds); + if (iwh < (obuff + RELAY_BUFSZ)) + FD_SET(rfd, &rfds); + + switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL))) + { + case -1 : + case 0 : + return -1; + default : + if (FD_ISSET(ifd, &rfds)) { + rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh); + if (rw == -1) + return -1; + if (rw == 0) + return 0; + irh += rw; + n--; + } + if (n && FD_ISSET(ofd, &wfds)) { + rw = write(ofd, iwt, iwh - iwt); + if (rw == -1) + return -1; + iwt += rw; + n--; + } + if (n && FD_ISSET(rfd, &rfds)) { + rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh); + if (rw == -1) + return -1; + if (rw == 0) + return 0; + iwh += rw; + n--; + } + if (n && FD_ISSET(rfd, &wfds)) { + rw = write(rfd, irt, irh - irt); + if (rw == -1) + return -1; + irt += rw; + n--; + } + if (irh == irt) + irh = irt = ibuff; + if (iwh == iwt) + iwh = iwt = obuff; + } + } +} + +main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin; + ipfobj_t obj; + natlookup_t nl; + natlookup_t *nlp = &nl; + int fd, sl = sizeof(sl), se; + + openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON); + if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) { + se = errno; + perror("open"); + errno = se; + syslog(LOG_ERR, "open: %m\n"); + exit(-1); + } + + bzero(&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(nl); + obj.ipfo_ptr = &nl; + obj.ipfo_type = IPFOBJ_NATLOOKUP; + + bzero(&nl, sizeof(nl)); + nl.nl_flags = IPN_TCP; + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sl = sizeof(sin); + if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) { + se = errno; + perror("getsockname"); + errno = se; + syslog(LOG_ERR, "getsockname: %m\n"); + exit(-1); + } else { + nl.nl_inip.s_addr = sin.sin_addr.s_addr; + nl.nl_inport = sin.sin_port; + } + + bzero(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sl = sizeof(sin); + if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) { + se = errno; + perror("getpeername"); + errno = se; + syslog(LOG_ERR, "getpeername: %m\n"); + exit(-1); + } else { + nl.nl_outip.s_addr = sin.sin_addr.s_addr; + nl.nl_outport = sin.sin_port; + } + + if (ioctl(fd, SIOCGNATL, &obj) == -1) { + se = errno; + perror("ioctl"); + errno = se; + syslog(LOG_ERR, "ioctl: %m\n"); + exit(-1); + } + + sin.sin_port = nl.nl_realport; + sin.sin_addr = nl.nl_realip; + sl = sizeof(sin); + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (connect(fd, (struct sockaddr *)&sin, sl) == -1) { + se = errno; + perror("connect"); + errno = se; + syslog(LOG_ERR, "connect: %m\n"); + exit(-1); + } + + (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); + + syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr), + ntohs(sin.sin_port)); + if (relay(0, 1, fd) == -1) { + se = errno; + perror("relay"); + errno = se; + syslog(LOG_ERR, "relay: %m\n"); + exit(-1); + } + exit(0); +} diff --git a/contrib/ipfilter/samples/userauth.c b/contrib/ipfilter/samples/userauth.c new file mode 100644 index 0000000..620bd72 --- /dev/null +++ b/contrib/ipfilter/samples/userauth.c @@ -0,0 +1,62 @@ +/* $FreeBSD$ */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <netinet/in.h> +#include <net/if.h> +#include "ip_compat.h" +#include "ip_fil.h" +#include "ip_auth.h" + +extern int errno; + +main() +{ + struct frauth fra; + struct frauth *frap = &fra; + fr_info_t *fin = &fra.fra_info; + fr_ip_t *fi = &fin->fin_fi; + char yn[16]; + int fd; + + fd = open(IPL_NAME, O_RDWR); + fra.fra_len = 0; + fra.fra_buf = NULL; + while (ioctl(fd, SIOCAUTHW, &frap) == 0) { + if (fra.fra_info.fin_out) + fra.fra_pass = FR_OUTQUE; + else + fra.fra_pass = FR_INQUE; + + printf("%s ", inet_ntoa(fi->fi_src)); + if (fi->fi_flx & FI_TCPUDP) + printf("port %d ", fin->fin_data[0]); + printf("-> %s ", inet_ntoa(fi->fi_dst)); + if (fi->fi_flx & FI_TCPUDP) + printf("port %d ", fin->fin_data[1]); + printf("\n"); + printf("Allow packet through ? [y/n]"); + fflush(stdout); + if (!fgets(yn, sizeof(yn), stdin)) + break; + fflush(stdin); + if (yn[0] == 'n' || yn[0] == 'N') + fra.fra_pass |= FR_BLOCK; + else if (yn[0] == 'y' || yn[0] == 'Y') { + fra.fra_pass |= FR_PASS; + if (fra.fra_info.fin_fi.fi_flx & FI_TCPUDP) + fra.fra_pass |= FR_KEEPSTATE; + } else + fra.fra_pass |= FR_NOMATCH; + printf("answer = %c (%x), id %d idx %d\n", yn[0], + fra.fra_pass, fra.fra_info.fin_id, fra.fra_index); + if (ioctl(fd, SIOCAUTHR, &frap) != 0) + perror("SIOCAUTHR"); + } + fprintf(stderr, "errno=%d \n", errno); + perror("frauth-SIOCAUTHW"); +} diff --git a/contrib/ipfilter/snoop.h b/contrib/ipfilter/snoop.h new file mode 100644 index 0000000..74bc247 --- /dev/null +++ b/contrib/ipfilter/snoop.h @@ -0,0 +1,47 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#ifndef __SNOOP_H__ +#define __SNOOP_H__ + +/* + * written to comply with the RFC (1761) from Sun. + * $Id$ + */ +struct snoophdr { + char s_id[8]; + int s_v; + int s_type; +}; + +#define SNOOP_VERSION 2 + +#define SDL_8023 0 +#define SDL_8024 1 +#define SDL_8025 2 +#define SDL_8026 3 +#define SDL_ETHER 4 +#define SDL_HDLC 5 +#define SDL_CHSYNC 6 +#define SDL_IBMCC 7 +#define SDL_FDDI 8 +#define SDL_OTHER 9 + +#define SDL_MAX 9 + + +struct snooppkt { + int sp_olen; + int sp_ilen; + int sp_plen; + int sp_drop; + int sp_sec; + int sp_usec; +}; + +#endif /* __SNOOP_H__ */ diff --git a/contrib/ipfilter/sys/tree.h b/contrib/ipfilter/sys/tree.h new file mode 100644 index 0000000..5855885 --- /dev/null +++ b/contrib/ipfilter/sys/tree.h @@ -0,0 +1,750 @@ +/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */ +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* $FreeBSD: src/sys/sys/tree.h,v 1.7 2007/12/28 07:03:26 jasone Exp $ */ + +/*- + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +/* + * Undef for Linux + */ +#undef RB_BLACK +#undef RB_RED +#undef RB_ROOT + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#endif /* _SYS_TREE_H_ */ diff --git a/contrib/ipfilter/tools/BNF.ipf b/contrib/ipfilter/tools/BNF.ipf new file mode 100644 index 0000000..0740c58 --- /dev/null +++ b/contrib/ipfilter/tools/BNF.ipf @@ -0,0 +1,80 @@ +filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ] + [ proto ] [ ip ] [ group ] [ tag ] [ pps ] . + +insert = "@" decnumber . +action = block | "pass" | log | "count" | auth | call . +in-out = "in" | "out" . +options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] . +tos = "tos" decnumber | "tos" hexnumber . +ttl = "ttl" decnumber . +proto = "proto" protocol . +ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] . +group = [ "head" decnumber ] [ "group" decnumber ] . +pps = "pps" decnumber . + +onif = "on" interface-name [ "out-via" interface-name ] . +block = "block" [ return-icmp[return-code] | "return-rst" ] . +auth = "auth" | "preauth" . +log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] . +tag = "tag" tagid . +call = "call" [ "now" ] function-name . +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 . + +return-icmp = "return-icmp" | "return-icmp-as-dest" . +loglevel = facility"."priority | priority . +object = addr [ port-comp | port-range ] . +addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] . +port-comp = "port" compare port-num . +port-range = "port" port-num range port-num . +flags = "flags" flag { flag } [ "/" flag { flag } ] . +with = "with" | "and" . +icmp = "icmp-type" icmp-type [ "code" decnumber ] . +return-code = "("icmp-code")" . +keep = "keep" "state" [ "limit" number ] | "keep" "frags" . + +nummask = host-name [ "/" decnumber ] . +host-name = ipaddr | hostname | "any" . +ipaddr = host-num "." host-num "." host-num "." host-num . +host-num = digit [ digit [ digit ] ] . +port-num = service-name | decnumber . + +withopt = [ "not" | "no" ] opttype [ withopt ] . +opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" | + "mbcast" | "opt" ipopts . +optname = ipopts [ "," optname ] . +ipopts = optlist | "sec-class" [ secname ] . +secname = seclvl [ "," secname ] . +seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" | + "reserv-4" | "secret" | "topsecret" . +icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" | + "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" | + "inforep" | "maskreq" | "maskrep" | "routerad" | + "routersol" | decnumber . +icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" | + "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" | + "net-prohib" | "host-prohib" | "net-tos" | "host-tos" | + "filter-prohib" | "host-preced" | "cutoff-preced" . +optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" | + "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" | + "visa" | "imitd" | "eip" | "finn" . +facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" | + "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" | + "audit" | "logalert" | "local0" | "local1" | "local2" | + "local3" | "local4" | "local5" | "local6" | "local7" . +priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" | + "info" | "debug" . + +hexnumber = "0" "x" hexstring . +hexstring = hexdigit [ hexstring ] . +decnumber = digit [ decnumber ] . + +compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" | + "le" | "ge" . +range = "<>" | "><" . +hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" . +digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" . +flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" . diff --git a/contrib/ipfilter/tools/BNF.ipnat b/contrib/ipfilter/tools/BNF.ipnat new file mode 100644 index 0000000..69ed8a2 --- /dev/null +++ b/contrib/ipfilter/tools/BNF.ipnat @@ -0,0 +1,28 @@ +ipmap :: = mapblock | redir | map . + +map ::= mapit ifname ipmask "->" ipmask [ mapport | mapicmpid ] . +map ::= mapit ifname fromto "->" ipmask [ mapport | mapicmpid ] . +mapblock ::= "map-block" ifname ipmask "->" ipmask [ ports ] . +redir ::= "rdr" ifname ipmask dport "->" ip [ "," ip ] [ ports ] options . + +dport ::= "port" portnum [ "-" portnum ] . +ports ::= "ports" numports | "auto" . +mapit ::= "map" | "bimap" . +fromto ::= "from" object "to" object . +ipmask ::= ip "/" bits | ip "/" mask | ip "netmask" mask . +mapport ::= "portmap" tcpudp portnumber ":" portnumber . +mapicmpid ::= "icmpidmap" icmp idnumber ":" idnumber . +options ::= [ tcpudp ] [ rr ] . + +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 . + +rr ::= "round-robin" . +tcpudp ::= "tcp" | "udp" | "tcp/udp" . +portnumber ::= number { numbers } | "auto" . +idnumber ::= number { numbers } . +ifname ::= 'A' - 'Z' { 'A' - 'Z' } numbers . + +numbers ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' . diff --git a/contrib/ipfilter/tools/Makefile b/contrib/ipfilter/tools/Makefile new file mode 100644 index 0000000..ce1ab0e --- /dev/null +++ b/contrib/ipfilter/tools/Makefile @@ -0,0 +1,104 @@ +YACC=yacc -v + +DEST=. + +all: $(DEST)/ipf_y.c $(DEST)/ipf_y.h $(DEST)/ipf_l.c \ + $(DEST)/ipmon_y.c $(DEST)/ipmon_y.h $(DEST)/ipmon_l.c \ + $(DEST)/ipnat_y.c $(DEST)/ipnat_y.h $(DEST)/ipnat_l.c \ + $(DEST)/ipscan_y.c $(DEST)/ipscan_y.h $(DEST)/ipscan_l.c \ + $(DEST)/ippool_y.c $(DEST)/ippool_y.h $(DEST)/ippool_l.c \ + $(DEST)/ipf_l.h $(DEST)/ipnat_l.h $(DEST)/ipscan_l.h \ + $(DEST)/ippool_l.h $(DEST)/ipmon_l.h + +$(DEST)/ipf_y.h: $(DEST)/ipf_y.c + +$(DEST)/ipf_y.c: ipf_y.y + $(YACC) -d ipf_y.y + sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.c/' \ + -e 's/"ipf_y.y"/"..\/tools\/ipf_y.y"/' \ + y.tab.c > $(DEST)/ipf_y.c + sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' y.tab.h > $(DEST)/ipf_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ipf_l.c: lexer.c + sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' \ + -e 's/lexer.h/ipf_l.h/' lexer.c > $@ + +$(DEST)/ipmon_y.n: $(DEST)/ipmon_y.c + +$(DEST)/ipmon_y.c $(DEST)/ipmon_y.h: ipmon_y.y + $(YACC) -d ipmon_y.y + sed -e 's/yy/ipmon_yy/g' -e 's/"ipmon_y.y"/"..\/tools\/ipmon_y.y"/' \ + y.tab.c > $(DEST)/ipmon_y.c + sed -e 's/yy/ipmon_yy/g' y.tab.h > $(DEST)/ipmon_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ipmon_l.c: lexer.c + sed -e 's/yy/ipmon_yy/g' -e 's/y.tab.h/ipmon_y.h/' \ + -e 's/lexer.h/ipmon_l.h/' lexer.c > $@ + +$(DEST)/ipscan_y.h: $(DEST)/ipscan_y.c + +$(DEST)/ipscan_y.c $(DEST)/ipscan_y.h: ipscan_y.y + $(YACC) -d ipscan_y.y + sed -e 's/yy/ipscan_yy/g' \ + -e 's/"ipscan_y.y"/"..\/tools\/ipscan_y.y"/' \ + y.tab.c > $(DEST)/ipscan_y.c + sed -e 's/yy/ipscan_yy/g' y.tab.h > $(DEST)/ipscan_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ipscan_l.c: lexer.c + sed -e 's/yy/ipscan_yy/g' -e 's/y.tab.h/ipscan_y.h/' \ + -e 's/lexer.h/ipscan_l.h/' lexer.c > $@ + +$(DEST)/ippool_y.h: $(DEST)/ippool_y.c + +$(DEST)/ippool_y.c $(DEST)/ippool_y.h: ippool_y.y + $(YACC) -d ippool_y.y + sed -e 's/yy/ippool_yy/g' -e 's/"ippool_y.y"/"..\/tools\/ippool_y.y"/' \ + y.tab.c > $(DEST)/ippool_y.c + sed -e 's/yy/ippool_yy/g' y.tab.h > $(DEST)/ippool_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ippool_l.c: lexer.c + sed -e 's/yy/ippool_yy/g' -e 's/y.tab.h/ippool_y.h/' \ + -e 's/lexer.h/ippool_l.h/' lexer.c > $@ + +$(DEST)/ipnat_y.h: $(DEST)/ipnat_y.c + +$(DEST)/ipnat_y.c $(DEST)/ipnat_y.h: ipnat_y.y + $(YACC) -d ipnat_y.y + sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.c/ipnat_y.c/' \ + -e s/\"ipnat_y.y\"/\"..\\/tools\\/ipnat_y.y\"/ \ + y.tab.c > $(DEST)/ipnat_y.c + sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \ + y.tab.h > $(DEST)/ipnat_y.h + /bin/rm -f y.tab.c y.tab.h + +$(DEST)/ipnat_l.c: lexer.c + sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \ + -e 's/lexer.h/ipnat_l.h/' lexer.c > $@ + +$(DEST)/ipf_l.h: lexer.h + sed -e 's/yy/ipf_yy/g' lexer.h > $@ + +$(DEST)/ipmon_l.h: lexer.h + sed -e 's/yy/ipmon_yy/g' lexer.h > $@ + +$(DEST)/ipscan_l.h: lexer.h + sed -e 's/yy/ipscan_yy/g' lexer.h > $@ + +$(DEST)/ippool_l.h: lexer.h + sed -e 's/yy/ippool_yy/g' lexer.h > $@ + +$(DEST)/ipnat_l.h: lexer.h + sed -e 's/yy/ipnat_yy/g' lexer.h > $@ + +clean: + /bin/rm -f $(DEST)/ipf_y.c $(DEST)/ipf_y.h $(DEST)/ipf_l.c + /bin/rm -f $(DEST)/ipmon_y.c $(DEST)/ipmon_y.h $(DEST)/ipmon_l.c + /bin/rm -f $(DEST)/ipscan_y.c $(DEST)/ipscan_y.h $(DEST)/ipscan_l.c + /bin/rm -f $(DEST)/ippool_y.c $(DEST)/ippool_y.h $(DEST)/ippool_l.c + /bin/rm -f $(DEST)/ipnat_y.c $(DEST)/ipnat_y.h $(DEST)/ipnat_l.c + /bin/rm -f $(DEST)/ipf_l.h $(DEST)/ipmon_l.h $(DEST)/ippool_l.h + /bin/rm -f $(DEST)/ipscan_l.h $(DEST)/ipnat_l.h diff --git a/contrib/ipfilter/tools/ipf.c b/contrib/ipfilter/tools/ipf.c new file mode 100644 index 0000000..08cfb0a --- /dev/null +++ b/contrib/ipfilter/tools/ipf.c @@ -0,0 +1,601 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#ifdef __FreeBSD__ +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +#endif +#include "ipf.h" +#include <fcntl.h> +#include <ctype.h> +#include <sys/ioctl.h> +#include "netinet/ipl.h" + +#if !defined(lint) +static const char sccsid[] = "@(#)ipf.c 1.23 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#if !defined(__SVR4) && defined(__GNUC__) +extern char *index __P((const char *, int)); +#endif + +extern char *optarg; +extern int optind; +extern frentry_t *frtop; + + +void ipf_frsync __P((void)); +void zerostats __P((void)); +int main __P((int, char *[])); + +int opts = 0; +int outputc = 0; +int use_inet6 = 0; +int exitstatus = 0; + +static void procfile __P((char *)); +static void flushfilter __P((char *, int *)); +static void set_state __P((u_int)); +static void showstats __P((friostat_t *)); +static void packetlogon __P((char *)); +static void swapactive __P((void)); +static int opendevice __P((char *, int)); +static void closedevice __P((void)); +static char *ipfname = IPL_NAME; +static void usage __P((void)); +static int showversion __P((void)); +static int get_flags __P((void)); +static int ipf_interceptadd __P((int, ioctlfunc_t, void *)); + +static int fd = -1; +static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ioctl, ioctl, ioctl, + ioctl, ioctl, ioctl, + ioctl, ioctl }; + +/* XXX The following was added to satisfy a rescue/rescue/ build + XXX requirement. */ +int nohdrfields; + +static void usage() +{ + fprintf(stderr, "usage: ipf [-6AdDEInoPrRsvVyzZ] %s %s %s\n", + "[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]", + "[-f filename] [-T <tuneopts>]"); + exit(1); +} + + +int main(argc,argv) + int argc; + char *argv[]; +{ + int c, *filter = NULL; + + if (argc < 2) + usage(); + + assigndefined(getenv("IPF_PREDEFINED")); + + while ((c = getopt(argc, argv, "46Ac:dDEf:F:Il:m:noPrRsT:vVyzZ")) != -1) { + switch (c) + { + case '?' : + usage(); + break; + case '4' : + use_inet6 = -1; + break; + case '6' : + use_inet6 = 1; + break; + case 'A' : + opts &= ~OPT_INACTIVE; + break; + case 'c' : + if (strcmp(optarg, "c") == 0) + outputc = 1; + break; + case 'E' : + set_state((u_int)1); + break; + case 'D' : + set_state((u_int)0); + break; + case 'd' : + opts ^= OPT_DEBUG; + break; + case 'f' : + procfile(optarg); + break; + case 'F' : + flushfilter(optarg, filter); + break; + case 'I' : + opts ^= OPT_INACTIVE; + break; + case 'l' : + packetlogon(optarg); + break; + case 'm' : + filter = parseipfexpr(optarg, NULL); + break; + case 'n' : + opts ^= OPT_DONOTHING|OPT_DONTOPEN; + break; + case 'o' : + break; + case 'P' : + ipfname = IPAUTH_NAME; + break; + case 'R' : + opts ^= OPT_NORESOLVE; + break; + case 'r' : + opts ^= OPT_REMOVE; + break; + case 's' : + swapactive(); + break; + case 'T' : + if (opendevice(ipfname, 1) >= 0) + ipf_dotuning(fd, optarg, ioctl); + break; + case 'v' : + opts += OPT_VERBOSE; + break; + case 'V' : + if (showversion()) + exit(1); + break; + case 'y' : + ipf_frsync(); + break; + case 'z' : + opts ^= OPT_ZERORULEST; + break; + case 'Z' : + zerostats(); + break; + } + } + + if (optind < 2) + usage(); + + if (fd != -1) + (void) close(fd); + + return(exitstatus); + /* NOTREACHED */ +} + + +static int opendevice(ipfdev, check) + char *ipfdev; + int check; +{ + if (opts & OPT_DONOTHING) + return -2; + + if (check && checkrev(ipfname) == -1) { + fprintf(stderr, "User/kernel version check failed\n"); + return -2; + } + + if (!ipfdev) + ipfdev = ipfname; + + if (fd == -1) + if ((fd = open(ipfdev, O_RDWR)) == -1) + if ((fd = open(ipfdev, O_RDONLY)) == -1) + ipferror(fd, "open device"); + return fd; +} + + +static void closedevice() +{ + close(fd); + fd = -1; +} + + +static int get_flags() +{ + int i = 0; + + if ((opendevice(ipfname, 1) != -2) && + (ioctl(fd, SIOCGETFF, &i) == -1)) { + ipferror(fd, "SIOCGETFF"); + return 0; + } + return i; +} + + +static void set_state(enable) + u_int enable; +{ + if (opendevice(ipfname, 0) != -2) { + if (ioctl(fd, SIOCFRENB, &enable) == -1) { + if (errno == EBUSY) { + fprintf(stderr, + "IP FIlter: already initialized\n"); + } else { + ipferror(fd, "SIOCFRENB"); + } + } + } + return; +} + + +static void procfile(file) + char *file; +{ + (void) opendevice(ipfname, 1); + + initparse(); + + ipf_parsefile(fd, ipf_interceptadd, iocfunctions, file); + + if (outputc) { + printC(0); + printC(1); + emit(-1, -1, NULL, NULL); + } +} + + +static int ipf_interceptadd(fd, ioctlfunc, ptr) + int fd; + ioctlfunc_t ioctlfunc; + void *ptr; +{ + if (outputc) + printc(ptr); + + if (ipf_addrule(fd, ioctlfunc, ptr) != 0) + exitstatus = 1; + return 0; +} + + +static void packetlogon(opt) + char *opt; +{ + int flag, xfd, logopt, change = 0; + + flag = get_flags(); + if (flag != 0) { + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) + printf("log flag is currently %#x\n", flag); + } + + flag &= ~(FF_LOGPASS|FF_LOGNOMATCH|FF_LOGBLOCK); + + if (strstr(opt, "pass")) { + flag |= FF_LOGPASS; + if (opts & OPT_VERBOSE) + printf("set log flag: pass\n"); + change = 1; + } + if (strstr(opt, "nomatch")) { + flag |= FF_LOGNOMATCH; + if (opts & OPT_VERBOSE) + printf("set log flag: nomatch\n"); + change = 1; + } + if (strstr(opt, "block") || strchr(opt, 'd')) { + flag |= FF_LOGBLOCK; + if (opts & OPT_VERBOSE) + printf("set log flag: block\n"); + change = 1; + } + if (strstr(opt, "none")) { + if (opts & OPT_VERBOSE) + printf("disable all log flags\n"); + change = 1; + } + + if (change == 1) { + if (opendevice(ipfname, 1) != -2 && + (ioctl(fd, SIOCSETFF, &flag) != 0)) + ipferror(fd, "ioctl(SIOCSETFF)"); + } + + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { + flag = get_flags(); + printf("log flags are now %#x\n", flag); + } + + if (strstr(opt, "state")) { + if (opts & OPT_VERBOSE) + printf("set state log flag\n"); + xfd = open(IPSTATE_NAME, O_RDWR); + if (xfd >= 0) { + logopt = 0; + if (ioctl(xfd, SIOCGETLG, &logopt)) + ipferror(fd, "ioctl(SIOCGETLG)"); + else { + logopt = 1 - logopt; + if (ioctl(xfd, SIOCSETLG, &logopt)) + ipferror(xfd, "ioctl(SIOCSETLG)"); + } + close(xfd); + } + } + + if (strstr(opt, "nat")) { + if (opts & OPT_VERBOSE) + printf("set nat log flag\n"); + xfd = open(IPNAT_NAME, O_RDWR); + if (xfd >= 0) { + logopt = 0; + if (ioctl(xfd, SIOCGETLG, &logopt)) + ipferror(xfd, "ioctl(SIOCGETLG)"); + else { + logopt = 1 - logopt; + if (ioctl(xfd, SIOCSETLG, &logopt)) + ipferror(xfd, "ioctl(SIOCSETLG)"); + } + close(xfd); + } + } +} + + +static void flushfilter(arg, filter) + char *arg; + int *filter; +{ + int fl = 0, rem; + + if (!arg || !*arg) + return; + if (!strcmp(arg, "s") || !strcmp(arg, "S") || ISDIGIT(*arg)) { + if (*arg == 'S') + fl = 0; + else if (*arg == 's') + fl = 1; + else + fl = atoi(arg); + rem = fl; + + closedevice(); + if (opendevice(IPSTATE_NAME, 1) == -2) + exit(1); + + if (!(opts & OPT_DONOTHING)) { + if (use_inet6) { + fprintf(stderr, + "IPv6 rules are no longer seperate\n"); + } else if (filter != NULL) { + ipfobj_t obj; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = filter[0] * sizeof(int); + obj.ipfo_type = IPFOBJ_IPFEXPR; + obj.ipfo_ptr = filter; + if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) { + ipferror(fd, "ioctl(SIOCMATCHFLUSH)"); + fl = -1; + } else { + fl = obj.ipfo_retval; + } + } else { + if (ioctl(fd, SIOCIPFFL, &fl) == -1) { + ipferror(fd, "ioctl(SIOCIPFFL)"); + exit(1); + } + } + } + if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) { + printf("remove flags %s (%d)\n", arg, rem); + } + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { + printf("%d state entries removed\n", fl); + } + closedevice(); + return; + } + +#ifdef SIOCIPFFA + if (!strcmp(arg, "u")) { + closedevice(); + /* + * Flush auth rules and packets + */ + if (opendevice(IPL_AUTH, 1) == -1) + perror("open(IPL_AUTH)"); + else { + if (ioctl(fd, SIOCIPFFA, &fl) == -1) + ipferror(fd, "ioctl(SIOCIPFFA)"); + } + closedevice(); + return; + } +#endif + + if (strchr(arg, 'i') || strchr(arg, 'I')) + fl = FR_INQUE; + if (strchr(arg, 'o') || strchr(arg, 'O')) + fl = FR_OUTQUE; + if (strchr(arg, 'a') || strchr(arg, 'A')) + fl = FR_OUTQUE|FR_INQUE; + if (opts & OPT_INACTIVE) + fl |= FR_INACTIVE; + rem = fl; + + if (opendevice(ipfname, 1) == -2) + exit(1); + + if (!(opts & OPT_DONOTHING)) { + if (use_inet6) { + if (ioctl(fd, SIOCIPFL6, &fl) == -1) { + ipferror(fd, "ioctl(SIOCIPFL6)"); + exit(1); + } + } else { + if (ioctl(fd, SIOCIPFFL, &fl) == -1) { + ipferror(fd, "ioctl(SIOCIPFFL)"); + exit(1); + } + } + } + + if ((opts & (OPT_DONOTHING|OPT_DEBUG)) == OPT_DEBUG) { + printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "", + (rem & FR_OUTQUE) ? "O" : "", rem); + } + if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { + printf("%d filter rules removed\n", fl); + } + return; +} + + +static void swapactive() +{ + int in = 2; + + if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1) + ipferror(fd, "ioctl(SIOCSWAPA)"); + else + printf("Set %d now inactive\n", in); +} + + +void ipf_frsync() +{ + int frsyn = 0; + + if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCFRSYN, &frsyn) == -1) + ipferror(fd, "SIOCFRSYN"); + else + printf("filter sync'd\n"); +} + + +void zerostats() +{ + ipfobj_t obj; + friostat_t fio; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_IPFSTAT; + obj.ipfo_size = sizeof(fio); + obj.ipfo_ptr = &fio; + obj.ipfo_offset = 0; + + if (opendevice(ipfname, 1) != -2) { + if (ioctl(fd, SIOCFRZST, &obj) == -1) { + ipferror(fd, "ioctl(SIOCFRZST)"); + exit(-1); + } + showstats(&fio); + } + +} + + +/* + * read the kernel stats for packets blocked and passed + */ +static void showstats(fp) + friostat_t *fp; +{ + printf("bad packets:\t\tin %lu\tout %lu\n", + fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); + printf(" input packets:\t\tblocked %lu passed %lu nomatch %lu", + fp->f_st[0].fr_block, fp->f_st[0].fr_pass, + fp->f_st[0].fr_nom); + printf(" counted %lu\n", fp->f_st[0].fr_acct); + printf("output packets:\t\tblocked %lu passed %lu nomatch %lu", + fp->f_st[1].fr_block, fp->f_st[1].fr_pass, + fp->f_st[1].fr_nom); + printf(" counted %lu\n", fp->f_st[0].fr_acct); + printf(" input packets logged:\tblocked %lu passed %lu\n", + 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); +} + + +static int showversion() +{ + struct friostat fio; + ipfobj_t ipfo; + u_32_t flags; + char *s; + int vfd; + + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_size = sizeof(fio); + ipfo.ipfo_ptr = (void *)&fio; + ipfo.ipfo_type = IPFOBJ_IPFSTAT; + + printf("ipf: %s (%d)\n", IPL_VERSION, (int)sizeof(frentry_t)); + + if ((vfd = open(ipfname, O_RDONLY)) == -1) { + perror("open device"); + return 1; + } + + if (ioctl(vfd, SIOCGETFS, &ipfo)) { + ipferror(vfd, "ioctl(SIOCGETFS)"); + close(vfd); + return 1; + } + close(vfd); + flags = get_flags(); + + printf("Kernel: %-*.*s\n", (int)sizeof(fio.f_version), + (int)sizeof(fio.f_version), fio.f_version); + printf("Running: %s\n", (fio.f_running > 0) ? "yes" : "no"); + printf("Log Flags: %#x = ", flags); + s = ""; + if (flags & FF_LOGPASS) { + printf("pass"); + s = ", "; + } + if (flags & FF_LOGBLOCK) { + printf("%sblock", s); + s = ", "; + } + if (flags & FF_LOGNOMATCH) { + printf("%snomatch", s); + s = ", "; + } + if (flags & FF_BLOCKNONIP) { + printf("%snonip", s); + s = ", "; + } + if (!*s) + printf("none set"); + putchar('\n'); + + printf("Default: "); + if (FR_ISPASS(fio.f_defpass)) + s = "pass"; + else if (FR_ISBLOCK(fio.f_defpass)) + s = "block"; + else + s = "nomatch -> block"; + printf("%s all, Logging: %savailable\n", s, fio.f_logging ? "" : "un"); + printf("Active list: %d\n", fio.f_active); + printf("Feature mask: %#x\n", fio.f_features); + + return 0; +} diff --git a/contrib/ipfilter/tools/ipf_y.y b/contrib/ipfilter/tools/ipf_y.y new file mode 100644 index 0000000..e0dc847 --- /dev/null +++ b/contrib/ipfilter/tools/ipf_y.y @@ -0,0 +1,2749 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +%{ +#include "ipf.h" +#include <sys/ioctl.h> +#include <syslog.h> +#ifdef IPFILTER_BPF +# include <pcap.h> +#endif +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#include "netinet/ipl.h" +#include "ipf_l.h" + +#define YYDEBUG 1 +#define DOALL(x) for (fr = frc; fr != NULL; fr = fr->fr_next) { x } +#define DOREM(x) for (; fr != NULL; fr = fr->fr_next) { x } + +extern void yyerror __P((char *)); +extern int yyparse __P((void)); +extern int yylex __P((void)); +extern int yydebug; +extern FILE *yyin; +extern int yylineNum; + +static int addname __P((frentry_t **, char *)); +static frentry_t *addrule __P((void)); +static frentry_t *allocfr __P((void)); +static void build_dstaddr_af __P((frentry_t *, void *)); +static void build_srcaddr_af __P((frentry_t *, void *)); +static void dobpf __P((int, char *)); +static void doipfexpr __P((char *)); +static void do_tuneint __P((char *, int)); +static void do_tunestr __P((char *, char *)); +static void fillgroup __P((frentry_t *)); +static int lookuphost __P((char *, i6addr_t *)); +static u_int makehash __P((struct alist_s *)); +static int makepool __P((struct alist_s *)); +static struct alist_s *newalist __P((struct alist_s *)); +static void newrule __P((void)); +static void resetaddr __P((void)); +static void setgroup __P((frentry_t **, char *)); +static void setgrhead __P((frentry_t **, char *)); +static void seticmphead __P((frentry_t **, char *)); +static void setifname __P((frentry_t **, int, char *)); +static void setipftype __P((void)); +static void setsyslog __P((void)); +static void unsetsyslog __P((void)); + +frentry_t *fr = NULL, *frc = NULL, *frtop = NULL, *frold = NULL; + +static int ifpflag = 0; +static int nowith = 0; +static int dynamic = -1; +static int pooled = 0; +static int hashed = 0; +static int nrules = 0; +static int newlist = 0; +static int added = 0; +static int ipffd = -1; +static int *yycont = NULL; +static ioctlfunc_t ipfioctls[IPL_LOGSIZE]; +static addfunc_t ipfaddfunc = NULL; + +%} +%union { + char *str; + u_32_t num; + frentry_t fr; + frtuc_t *frt; + struct alist_s *alist; + u_short port; + struct in_addr ip4; + struct { + u_short p1; + u_short p2; + int pc; + } pc; + struct ipp_s { + int type; + int ifpos; + int f; + int v; + int lif; + union i6addr a; + union i6addr m; + char *name; + } ipp; + struct { + i6addr_t adr; + int f; + } adr; + i6addr_t ip6; + struct { + char *if1; + char *if2; + } ifs; + char gname[FR_GROUPLEN]; +}; + +%type <port> portnum +%type <num> facility priority icmpcode seclevel secname icmptype +%type <num> opt compare range opttype flagset optlist ipv6hdrlist ipv6hdr +%type <num> portc porteq ipmask maskopts +%type <ip4> ipv4 ipv4_16 ipv4_24 +%type <adr> hostname +%type <ipp> addr ipaddr +%type <str> servicename name interfacename groupname +%type <pc> portrange portcomp +%type <alist> addrlist poollist +%type <ifs> onname + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN +%token <ip6> YY_IPV6 + +%token IPFY_SET +%token IPFY_PASS IPFY_BLOCK IPFY_COUNT IPFY_CALL IPFY_NOMATCH +%token IPFY_RETICMP IPFY_RETRST IPFY_RETICMPASDST +%token IPFY_IN IPFY_OUT +%token IPFY_QUICK IPFY_ON IPFY_OUTVIA IPFY_INVIA +%token IPFY_DUPTO IPFY_TO IPFY_FROUTE IPFY_REPLY_TO IPFY_ROUTETO +%token IPFY_TOS IPFY_TTL IPFY_PROTO IPFY_INET IPFY_INET6 +%token IPFY_HEAD IPFY_GROUP +%token IPFY_AUTH IPFY_PREAUTH +%token IPFY_LOG IPFY_BODY IPFY_FIRST IPFY_LEVEL IPFY_ORBLOCK IPFY_L5AS +%token IPFY_LOGTAG IPFY_MATCHTAG IPFY_SETTAG IPFY_SKIP IPFY_DECAPS +%token IPFY_FROM IPFY_ALL IPFY_ANY IPFY_BPFV4 IPFY_BPFV6 IPFY_POOL IPFY_HASH +%token IPFY_IPFEXPR IPFY_PPS IPFY_FAMILY IPFY_DSTLIST +%token IPFY_ESP IPFY_AH +%token IPFY_WITH IPFY_AND IPFY_NOT IPFY_NO IPFY_OPT +%token IPFY_TCPUDP IPFY_TCP IPFY_UDP +%token IPFY_FLAGS IPFY_MULTICAST +%token IPFY_MASK IPFY_BROADCAST IPFY_NETWORK IPFY_NETMASKED IPFY_PEER +%token IPFY_RPC IPFY_PORT +%token IPFY_NOW IPFY_COMMENT IPFY_RULETTL +%token IPFY_ICMP IPFY_ICMPTYPE IPFY_ICMPCODE +%token IPFY_IPOPTS IPFY_SHORT IPFY_NAT IPFY_BADSRC IPFY_LOWTTL IPFY_FRAG +%token IPFY_MBCAST IPFY_BAD IPFY_BADNAT IPFY_OOW IPFY_NEWISN IPFY_NOICMPERR +%token IPFY_KEEP IPFY_STATE IPFY_FRAGS IPFY_LIMIT IPFY_STRICT IPFY_AGE +%token IPFY_SYNC IPFY_FRAGBODY IPFY_ICMPHEAD IPFY_NOLOG IPFY_LOOSE +%token IPFY_MAX_SRCS IPFY_MAX_PER_SRC +%token IPFY_IPOPT_NOP IPFY_IPOPT_RR IPFY_IPOPT_ZSU IPFY_IPOPT_MTUP +%token IPFY_IPOPT_MTUR IPFY_IPOPT_ENCODE IPFY_IPOPT_TS IPFY_IPOPT_TR +%token IPFY_IPOPT_SEC IPFY_IPOPT_LSRR IPFY_IPOPT_ESEC IPFY_IPOPT_CIPSO +%token IPFY_IPOPT_SATID IPFY_IPOPT_SSRR IPFY_IPOPT_ADDEXT IPFY_IPOPT_VISA +%token IPFY_IPOPT_IMITD IPFY_IPOPT_EIP IPFY_IPOPT_FINN IPFY_IPOPT_DPS +%token IPFY_IPOPT_SDB IPFY_IPOPT_NSAPA IPFY_IPOPT_RTRALRT IPFY_IPOPT_UMP +%token IPFY_SECCLASS IPFY_SEC_UNC IPFY_SEC_CONF IPFY_SEC_RSV1 IPFY_SEC_RSV2 +%token IPFY_SEC_RSV4 IPFY_SEC_SEC IPFY_SEC_TS IPFY_SEC_RSV3 IPFY_DOI + +%token IPFY_V6HDRS IPFY_IPV6OPT IPFY_IPV6OPT_DSTOPTS IPFY_IPV6OPT_HOPOPTS +%token IPFY_IPV6OPT_IPV6 IPFY_IPV6OPT_NONE IPFY_IPV6OPT_ROUTING IPFY_V6HDR +%token IPFY_IPV6OPT_MOBILITY IPFY_IPV6OPT_ESP IPFY_IPV6OPT_FRAG + +%token IPFY_ICMPT_UNR IPFY_ICMPT_ECHO IPFY_ICMPT_ECHOR IPFY_ICMPT_SQUENCH +%token IPFY_ICMPT_REDIR IPFY_ICMPT_TIMEX IPFY_ICMPT_PARAMP IPFY_ICMPT_TIMEST +%token IPFY_ICMPT_TIMESTREP IPFY_ICMPT_INFOREQ IPFY_ICMPT_INFOREP +%token IPFY_ICMPT_MASKREQ IPFY_ICMPT_MASKREP IPFY_ICMPT_ROUTERAD +%token IPFY_ICMPT_ROUTERSOL + +%token IPFY_ICMPC_NETUNR IPFY_ICMPC_HSTUNR IPFY_ICMPC_PROUNR IPFY_ICMPC_PORUNR +%token IPFY_ICMPC_NEEDF IPFY_ICMPC_SRCFAIL IPFY_ICMPC_NETUNK IPFY_ICMPC_HSTUNK +%token IPFY_ICMPC_ISOLATE IPFY_ICMPC_NETPRO IPFY_ICMPC_HSTPRO +%token IPFY_ICMPC_NETTOS IPFY_ICMPC_HSTTOS IPFY_ICMPC_FLTPRO IPFY_ICMPC_HSTPRE +%token IPFY_ICMPC_CUTPRE + +%token IPFY_FAC_KERN IPFY_FAC_USER IPFY_FAC_MAIL IPFY_FAC_DAEMON IPFY_FAC_AUTH +%token IPFY_FAC_SYSLOG IPFY_FAC_LPR IPFY_FAC_NEWS IPFY_FAC_UUCP IPFY_FAC_CRON +%token IPFY_FAC_LOCAL0 IPFY_FAC_LOCAL1 IPFY_FAC_LOCAL2 IPFY_FAC_LOCAL3 +%token IPFY_FAC_LOCAL4 IPFY_FAC_LOCAL5 IPFY_FAC_LOCAL6 IPFY_FAC_LOCAL7 +%token IPFY_FAC_SECURITY IPFY_FAC_FTP IPFY_FAC_AUTHPRIV IPFY_FAC_AUDIT +%token IPFY_FAC_LFMT IPFY_FAC_CONSOLE + +%token IPFY_PRI_EMERG IPFY_PRI_ALERT IPFY_PRI_CRIT IPFY_PRI_ERR IPFY_PRI_WARN +%token IPFY_PRI_NOTICE IPFY_PRI_INFO IPFY_PRI_DEBUG +%% +file: settings rules + | rules + ; + +settings: + YY_COMMENT + | setting + | settings setting + ; + +rules: line + | assign + | rules line + | rules assign + ; + +setting: + IPFY_SET YY_STR YY_NUMBER ';' { do_tuneint($2, $3); } + | IPFY_SET YY_STR YY_HEX ';' { do_tuneint($2, $3); } + | IPFY_SET YY_STR YY_STR ';' { do_tunestr($2, $3); } + ; + +line: rule { while ((fr = frtop) != NULL) { + frtop = fr->fr_next; + fr->fr_next = NULL; + if ((fr->fr_type == FR_T_IPF) && + (fr->fr_ip.fi_v == 0)) + fr->fr_mip.fi_v = 0; + /* XXX validate ? */ + (*ipfaddfunc)(ipffd, ipfioctls[IPL_LOGIPF], fr); + fr->fr_next = frold; + frold = fr; + } + resetlexer(); + } + | YY_COMMENT + ; + +xx: { newrule(); } + ; + +assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + yyvarnext = 0; + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +rule: inrule eol + | outrule eol + ; + +eol: | ';' + ; + +inrule: + rulehead markin inopts rulemain ruletail intag ruletail2 + ; + +outrule: + rulehead markout outopts rulemain ruletail outtag ruletail2 + ; + +rulehead: + xx collection action + | xx insert collection action + ; + +markin: IPFY_IN { fr->fr_flags |= FR_INQUE; } + ; + +markout: + IPFY_OUT { fr->fr_flags |= FR_OUTQUE; } + ; + +rulemain: + ipfrule + | bpfrule + | exprrule + ; + +ipfrule: + family tos ttl proto ip + ; + +family: | IPFY_FAMILY IPFY_INET { if (use_inet6 == 1) { + YYERROR; + } else { + frc->fr_family = AF_INET; + } + } + | IPFY_INET { if (use_inet6 == 1) { + YYERROR; + } else { + frc->fr_family = AF_INET; + } + } + | IPFY_FAMILY IPFY_INET6 { if (use_inet6 == -1) { + YYERROR; + } else { + frc->fr_family = AF_INET6; + } + } + | IPFY_INET6 { if (use_inet6 == -1) { + YYERROR; + } else { + frc->fr_family = AF_INET6; + } + } + ; + +bpfrule: + IPFY_BPFV4 '{' YY_STR '}' { dobpf(4, $3); free($3); } + | IPFY_BPFV6 '{' YY_STR '}' { dobpf(6, $3); free($3); } + ; + +exprrule: + IPFY_IPFEXPR '{' YY_STR '}' { doipfexpr($3); } + ; + +ruletail: + with keep head group + ; + +ruletail2: + pps age new rulettl comment + ; + +intag: settagin matchtagin + ; + +outtag: settagout matchtagout + ; + +insert: + '@' YY_NUMBER { fr->fr_hits = (U_QUAD_T)$2 + 1; } + ; + +collection: + | YY_NUMBER { fr->fr_collect = $1; } + ; + +action: block + | IPFY_PASS { fr->fr_flags |= FR_PASS; } + | IPFY_NOMATCH { fr->fr_flags |= FR_NOMATCH; } + | log + | IPFY_COUNT { fr->fr_flags |= FR_ACCOUNT; } + | decaps { fr->fr_flags |= FR_DECAPSULATE; } + | auth + | IPFY_SKIP YY_NUMBER { fr->fr_flags |= FR_SKIP; + fr->fr_arg = $2; } + | IPFY_CALL func + | IPFY_CALL IPFY_NOW func { fr->fr_flags |= FR_CALLNOW; } + ; + +block: blocked + | blocked blockreturn + ; + +blocked: + IPFY_BLOCK { fr->fr_flags = FR_BLOCK; } + ; +blockreturn: + IPFY_RETICMP { fr->fr_flags |= FR_RETICMP; } + | IPFY_RETICMP returncode { fr->fr_flags |= FR_RETICMP; } + | IPFY_RETICMPASDST { fr->fr_flags |= FR_FAKEICMP; } + | IPFY_RETICMPASDST returncode { fr->fr_flags |= FR_FAKEICMP; } + | IPFY_RETRST { fr->fr_flags |= FR_RETRST; } + ; + +decaps: IPFY_DECAPS + | IPFY_DECAPS IPFY_L5AS '(' YY_STR ')' + { fr->fr_icode = atoi($4); } + ; + +log: IPFY_LOG { fr->fr_flags |= FR_LOG; } + | IPFY_LOG logoptions { fr->fr_flags |= FR_LOG; } + ; + +auth: IPFY_AUTH { fr->fr_flags |= FR_AUTH; } + | IPFY_AUTH blockreturn { fr->fr_flags |= FR_AUTH;} + | IPFY_PREAUTH { fr->fr_flags |= FR_PREAUTH; } + ; + +func: YY_STR '/' YY_NUMBER + { fr->fr_func = nametokva($1, ipfioctls[IPL_LOGIPF]); + fr->fr_arg = $3; + free($1); + } + ; + +inopts: + | inopts inopt + ; + +inopt: + logopt + | quick + | on + | dup + | froute + | proute + | replyto + ; + +outopts: + | outopts outopt + ; + +outopt: + logopt + | quick + | on + | dup + | proute + | froute + | replyto + ; + +tos: | settos YY_NUMBER { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) } + | settos YY_HEX { DOALL(fr->fr_tos = $2; fr->fr_mtos = 0xff;) } + | settos lstart toslist lend + ; + +settos: IPFY_TOS { setipftype(); } + ; + +toslist: + YY_NUMBER { DOALL(fr->fr_tos = $1; fr->fr_mtos = 0xff;) } + | YY_HEX { DOREM(fr->fr_tos = $1; fr->fr_mtos = 0xff;) } + | toslist lmore YY_NUMBER + { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) } + | toslist lmore YY_HEX + { DOREM(fr->fr_tos = $3; fr->fr_mtos = 0xff;) } + ; + +ttl: | setttl YY_NUMBER + { DOALL(fr->fr_ttl = $2; fr->fr_mttl = 0xff;) } + | setttl lstart ttllist lend + ; + +lstart: '{' { newlist = 1; fr = frc; added = 0; } + ; + +lend: '}' { nrules += added; } + ; + +lmore: lanother { if (newlist == 1) { + newlist = 0; + } + fr = addrule(); + if (yycont != NULL) + *yycont = 1; + } + ; + +lanother: + | ',' + ; + +setttl: IPFY_TTL { setipftype(); } + ; + +ttllist: + YY_NUMBER { DOREM(fr->fr_ttl = $1; fr->fr_mttl = 0xff;) } + | ttllist lmore YY_NUMBER + { DOREM(fr->fr_ttl = $3; fr->fr_mttl = 0xff;) } + ; + +proto: | protox protocol { yyresetdict(); } + ; + +protox: IPFY_PROTO { setipftype(); + fr = frc; + yysetdict(NULL); } + ; + +ip: srcdst flags icmp + ; + +group: | IPFY_GROUP groupname { DOALL(setgroup(&fr, $2); \ + fillgroup(fr);); + free($2); + } + ; + +head: | IPFY_HEAD groupname { DOALL(setgrhead(&fr, $2);); + free($2); + } + ; + +groupname: + YY_STR { $$ = $1; + if (strlen($$) >= FR_GROUPLEN) + $$[FR_GROUPLEN - 1] = '\0'; + } + | YY_NUMBER { $$ = malloc(16); + sprintf($$, "%d", $1); + } + ; + +settagin: + | IPFY_SETTAG '(' taginlist ')' + ; + +taginlist: + taginspec + | taginlist ',' taginspec + ; + +taginspec: + logtag + ; + +nattag: IPFY_NAT '=' YY_STR { DOALL(strncpy(fr->fr_nattag.ipt_tag,\ + $3, IPFTAG_LEN);); + free($3); } + | IPFY_NAT '=' YY_NUMBER { DOALL(sprintf(fr->fr_nattag.ipt_tag,\ + "%d", $3 & 0xffffffff);) } + ; + +logtag: IPFY_LOG '=' YY_NUMBER { DOALL(fr->fr_logtag = $3;) } + ; + +settagout: + | IPFY_SETTAG '(' tagoutlist ')' + ; + +tagoutlist: + tagoutspec + | tagoutlist ',' tagoutspec + ; + +tagoutspec: + logtag + | nattag + ; + +matchtagin: + | IPFY_MATCHTAG '(' tagoutlist ')' + ; + +matchtagout: + | IPFY_MATCHTAG '(' taginlist ')' + ; + +pps: | IPFY_PPS YY_NUMBER { DOALL(fr->fr_pps = $2;) } + ; + +new: | savegroup file restoregroup + ; + +rulettl: + | IPFY_RULETTL YY_NUMBER { DOALL(fr->fr_die = $2;) } + ; + +comment: + | IPFY_COMMENT YY_STR { DOALL(fr->fr_comment = addname(&fr, \ + $2);) } + ; + +savegroup: + '{' + ; + +restoregroup: + '}' + ; + +logopt: log + ; + +quick: IPFY_QUICK { fr->fr_flags |= FR_QUICK; } + ; + +on: IPFY_ON onname { setifname(&fr, 0, $2.if1); + free($2.if1); + if ($2.if2 != NULL) { + setifname(&fr, 1, + $2.if2); + free($2.if2); + } + } + | IPFY_ON lstart onlist lend + | IPFY_ON onname IPFY_INVIA vianame { setifname(&fr, 0, $2.if1); + free($2.if1); + if ($2.if2 != NULL) { + setifname(&fr, 1, + $2.if2); + free($2.if2); + } + } + | IPFY_ON onname IPFY_OUTVIA vianame { setifname(&fr, 0, $2.if1); + free($2.if1); + if ($2.if2 != NULL) { + setifname(&fr, 1, + $2.if2); + free($2.if2); + } + } + ; + +onlist: onname { DOREM(setifname(&fr, 0, $1.if1); \ + if ($1.if2 != NULL) \ + setifname(&fr, 1, $1.if2); \ + ) + free($1.if1); + if ($1.if2 != NULL) + free($1.if2); + } + | onlist lmore onname { DOREM(setifname(&fr, 0, $3.if1); \ + if ($3.if2 != NULL) \ + setifname(&fr, 1, $3.if2); \ + ) + free($3.if1); + if ($3.if2 != NULL) + free($3.if2); + } + ; + +onname: interfacename { $$.if1 = $1; + $$.if2 = NULL; + } + | interfacename ',' interfacename + { $$.if1 = $1; + $$.if2 = $3; + } + ; + +vianame: + name { setifname(&fr, 2, $1); + free($1); + } + | name ',' name { setifname(&fr, 2, $1); + free($1); + setifname(&fr, 3, $3); + free($3); + } + ; + +dup: IPFY_DUPTO name + { int idx = addname(&fr, $2); + fr->fr_dif.fd_name = idx; + free($2); + } + | IPFY_DUPTO IPFY_DSTLIST '/' name + { int idx = addname(&fr, $4); + fr->fr_dif.fd_name = idx; + fr->fr_dif.fd_type = FRD_DSTLIST; + free($4); + } + | IPFY_DUPTO name duptoseparator hostname + { int idx = addname(&fr, $2); + fr->fr_dif.fd_name = idx; + fr->fr_dif.fd_ptr = (void *)-1; + fr->fr_dif.fd_ip6 = $4.adr; + if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC) + fr->fr_family = $4.f; + yyexpectaddr = 0; + free($2); + } + ; + +duptoseparator: + ':' { yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); } + ; + +froute: IPFY_FROUTE { fr->fr_flags |= FR_FASTROUTE; } + ; + +proute: routeto name + { int idx = addname(&fr, $2); + fr->fr_tif.fd_name = idx; + free($2); + } + | routeto IPFY_DSTLIST '/' name + { int idx = addname(&fr, $4); + fr->fr_tif.fd_name = idx; + fr->fr_tif.fd_type = FRD_DSTLIST; + free($4); + } + | routeto name duptoseparator hostname + { int idx = addname(&fr, $2); + fr->fr_tif.fd_name = idx; + fr->fr_tif.fd_ptr = (void *)-1; + fr->fr_tif.fd_ip6 = $4.adr; + if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC) + fr->fr_family = $4.f; + yyexpectaddr = 0; + free($2); + } + ; + +routeto: + IPFY_TO + | IPFY_ROUTETO + ; + +replyto: + IPFY_REPLY_TO name + { int idx = addname(&fr, $2); + fr->fr_rif.fd_name = idx; + free($2); + } + | IPFY_REPLY_TO IPFY_DSTLIST '/' name + { fr->fr_rif.fd_name = addname(&fr, $4); + fr->fr_rif.fd_type = FRD_DSTLIST; + free($4); + } + | IPFY_REPLY_TO name duptoseparator hostname + { int idx = addname(&fr, $2); + fr->fr_rif.fd_name = idx; + fr->fr_rif.fd_ptr = (void *)-1; + fr->fr_rif.fd_ip6 = $4.adr; + if (fr->fr_family == AF_UNSPEC && $4.f != AF_UNSPEC) + fr->fr_family = $4.f; + free($2); + } + ; + +logoptions: + logoption + | logoptions logoption + ; + +logoption: + IPFY_BODY { fr->fr_flags |= FR_LOGBODY; } + | IPFY_FIRST { fr->fr_flags |= FR_LOGFIRST; } + | IPFY_ORBLOCK { fr->fr_flags |= FR_LOGORBLOCK; } + | level loglevel { unsetsyslog(); } + ; + +returncode: + starticmpcode icmpcode ')' { fr->fr_icode = $2; yyresetdict(); } + ; + +starticmpcode: + '(' { yysetdict(icmpcodewords); } + ; + +srcdst: | IPFY_ALL + | fromto + ; + +protocol: + YY_NUMBER { DOALL(fr->fr_proto = $1; \ + fr->fr_mproto = 0xff;) + } + | YY_STR { if (!strcmp($1, "tcp-udp")) { + DOALL(fr->fr_flx |= FI_TCPUDP; \ + fr->fr_mflx |= FI_TCPUDP;) + } else { + int p = getproto($1); + if (p == -1) + yyerror("protocol unknown"); + DOALL(fr->fr_proto = p; \ + fr->fr_mproto = 0xff;) + } + free($1); + } + | YY_STR nextstring YY_STR + { if (!strcmp($1, "tcp") && + !strcmp($3, "udp")) { + DOREM(fr->fr_flx |= FI_TCPUDP; \ + fr->fr_mflx |= FI_TCPUDP;) + } else { + YYERROR; + } + free($1); + free($3); + } + ; + +nextstring: + '/' { yysetdict(NULL); } + ; + +fromto: from srcobject to dstobject { yyexpectaddr = 0; yycont = NULL; } + | to dstobject { yyexpectaddr = 0; yycont = NULL; } + | from srcobject { yyexpectaddr = 0; yycont = NULL; } + ; + +from: IPFY_FROM { setipftype(); + if (fr == NULL) + fr = frc; + yyexpectaddr = 1; + if (yydebug) + printf("set yyexpectaddr\n"); + yycont = &yyexpectaddr; + yysetdict(addrwords); + resetaddr(); } + ; + +to: IPFY_TO { if (fr == NULL) + fr = frc; + yyexpectaddr = 1; + if (yydebug) + printf("set yyexpectaddr\n"); + yycont = &yyexpectaddr; + yysetdict(addrwords); + resetaddr(); + } + ; + +with: | andwith withlist + ; + +andwith: + IPFY_WITH { nowith = 0; setipftype(); } + | IPFY_AND { nowith = 0; setipftype(); } + ; + +flags: | startflags flagset + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) } + | startflags flagset '/' flagset + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } + | startflags '/' flagset + { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) } + | startflags YY_NUMBER + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = FR_TCPFMAX;) } + | startflags '/' YY_NUMBER + { DOALL(fr->fr_tcpf = 0; fr->fr_tcpfm = $3;) } + | startflags YY_NUMBER '/' YY_NUMBER + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } + | startflags flagset '/' YY_NUMBER + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } + | startflags YY_NUMBER '/' flagset + { DOALL(fr->fr_tcpf = $2; fr->fr_tcpfm = $4;) } + ; + +startflags: + IPFY_FLAGS { if (frc->fr_type != FR_T_IPF) + yyerror("flags with non-ipf type rule"); + if (frc->fr_proto != IPPROTO_TCP) + yyerror("flags with non-TCP rule"); + } + ; + +flagset: + YY_STR { $$ = tcpflags($1); free($1); } + | YY_HEX { $$ = $1; } + ; + +srcobject: + { yyresetdict(); } fromport + | srcaddr srcport + | '!' srcaddr srcport + { DOALL(fr->fr_flags |= FR_NOTSRCIP;) } + ; + +srcaddr: + addr { build_srcaddr_af(fr, &$1); } + | lstart srcaddrlist lend + ; + +srcaddrlist: + addr { build_srcaddr_af(fr, &$1); } + | srcaddrlist lmore addr + { build_srcaddr_af(fr, &$3); } + ; + +srcport: + | portcomp + { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) } + | portrange + { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \ + fr->fr_stop = $1.p2;) } + | porteq lstart srcportlist lend + { yyresetdict(); } + ; + +fromport: + portcomp + { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1;) } + | portrange + { DOALL(fr->fr_scmp = $1.pc; fr->fr_sport = $1.p1; \ + fr->fr_stop = $1.p2;) } + | porteq lstart srcportlist lend + { yyresetdict(); } + ; + +srcportlist: + portnum { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $1;) } + | portnum ':' portnum + { DOREM(fr->fr_scmp = FR_INCRANGE; fr->fr_sport = $1; \ + fr->fr_stop = $3;) } + | portnum YY_RANGE_IN portnum + { DOREM(fr->fr_scmp = FR_INRANGE; fr->fr_sport = $1; \ + fr->fr_stop = $3;) } + | srcportlist lmore portnum + { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $3;) } + | srcportlist lmore portnum ':' portnum + { DOREM(fr->fr_scmp = FR_INCRANGE; fr->fr_sport = $3; \ + fr->fr_stop = $5;) } + | srcportlist lmore portnum YY_RANGE_IN portnum + { DOREM(fr->fr_scmp = FR_INRANGE; fr->fr_sport = $3; \ + fr->fr_stop = $5;) } + ; + +dstobject: + { yyresetdict(); } toport + | dstaddr dstport + | '!' dstaddr dstport + { DOALL(fr->fr_flags |= FR_NOTDSTIP;) } + ; + +dstaddr: + addr { if (($1.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) && + ($1.f != frc->fr_family)) + yyerror("1.src/dst address family mismatch"); + build_dstaddr_af(fr, &$1); + } + | lstart dstaddrlist lend + ; + +dstaddrlist: + addr { if (($1.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) && + ($1.f != frc->fr_family)) + yyerror("2.src/dst address family mismatch"); + build_dstaddr_af(fr, &$1); + } + | dstaddrlist lmore addr + { if (($3.f != AF_UNSPEC) && (frc->fr_family != AF_UNSPEC) && + ($3.f != frc->fr_family)) + yyerror("3.src/dst address family mismatch"); + build_dstaddr_af(fr, &$3); + } + ; + + +dstport: + | portcomp + { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) } + | portrange + { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \ + fr->fr_dtop = $1.p2;) } + | porteq lstart dstportlist lend + { yyresetdict(); } + ; + +toport: + portcomp + { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1;) } + | portrange + { DOALL(fr->fr_dcmp = $1.pc; fr->fr_dport = $1.p1; \ + fr->fr_dtop = $1.p2;) } + | porteq lstart dstportlist lend + { yyresetdict(); } + ; + +dstportlist: + portnum { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $1;) } + | portnum ':' portnum + { DOREM(fr->fr_dcmp = FR_INCRANGE; fr->fr_dport = $1; \ + fr->fr_dtop = $3;) } + | portnum YY_RANGE_IN portnum + { DOREM(fr->fr_dcmp = FR_INRANGE; fr->fr_dport = $1; \ + fr->fr_dtop = $3;) } + | dstportlist lmore portnum + { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $3;) } + | dstportlist lmore portnum ':' portnum + { DOREM(fr->fr_dcmp = FR_INCRANGE; fr->fr_dport = $3; \ + fr->fr_dtop = $5;) } + | dstportlist lmore portnum YY_RANGE_IN portnum + { DOREM(fr->fr_dcmp = FR_INRANGE; fr->fr_dport = $3; \ + fr->fr_dtop = $5;) } + ; + +addr: pool '/' YY_NUMBER { pooled = 1; + yyexpectaddr = 0; + $$.type = FRI_LOOKUP; + $$.v = 0; + $$.ifpos = -1; + $$.f = AF_UNSPEC; + $$.a.iplookuptype = IPLT_POOL; + $$.a.iplookupsubtype = 0; + $$.a.iplookupnum = $3; } + | pool '/' YY_STR { pooled = 1; + $$.ifpos = -1; + $$.f = AF_UNSPEC; + $$.type = FRI_LOOKUP; + $$.a.iplookuptype = IPLT_POOL; + $$.a.iplookupsubtype = 1; + $$.a.iplookupname = addname(&fr, $3); + } + | pool '=' '(' { yyexpectaddr = 1; + pooled = 1; + } + poollist ')' { yyexpectaddr = 0; + $$.v = 0; + $$.ifpos = -1; + $$.f = AF_UNSPEC; + $$.type = FRI_LOOKUP; + $$.a.iplookuptype = IPLT_POOL; + $$.a.iplookupsubtype = 0; + $$.a.iplookupnum = makepool($5); + } + | hash '/' YY_NUMBER { hashed = 1; + yyexpectaddr = 0; + $$.v = 0; + $$.ifpos = -1; + $$.f = AF_UNSPEC; + $$.type = FRI_LOOKUP; + $$.a.iplookuptype = IPLT_HASH; + $$.a.iplookupsubtype = 0; + $$.a.iplookupnum = $3; + } + | hash '/' YY_STR { hashed = 1; + $$.type = FRI_LOOKUP; + $$.v = 0; + $$.ifpos = -1; + $$.f = AF_UNSPEC; + $$.a.iplookuptype = IPLT_HASH; + $$.a.iplookupsubtype = 1; + $$.a.iplookupname = addname(&fr, $3); + } + | hash '=' '(' { hashed = 1; + yyexpectaddr = 1; + } + addrlist ')' { yyexpectaddr = 0; + $$.v = 0; + $$.ifpos = -1; + $$.f = AF_UNSPEC; + $$.type = FRI_LOOKUP; + $$.a.iplookuptype = IPLT_HASH; + $$.a.iplookupsubtype = 0; + $$.a.iplookupnum = makehash($5); + } + | ipaddr { $$ = $1; + yyexpectaddr = 0; } + ; + +ipaddr: IPFY_ANY { memset(&($$), 0, sizeof($$)); + $$.type = FRI_NORMAL; + $$.ifpos = -1; + yyexpectaddr = 0; + } + | hostname { memset(&($$), 0, sizeof($$)); + $$.a = $1.adr; + $$.f = $1.f; + if ($1.f == AF_INET6) + fill6bits(128, $$.m.i6); + else if ($1.f == AF_INET) + fill6bits(32, $$.m.i6); + $$.v = ftov($1.f); + $$.ifpos = dynamic; + $$.type = FRI_NORMAL; + } + | hostname { yyresetdict(); } + maskspace { yysetdict(maskwords); + yyexpectaddr = 2; } + ipmask { memset(&($$), 0, sizeof($$)); + ntomask($1.f, $5, $$.m.i6); + $$.a = $1.adr; + $$.a.i6[0] &= $$.m.i6[0]; + $$.a.i6[1] &= $$.m.i6[1]; + $$.a.i6[2] &= $$.m.i6[2]; + $$.a.i6[3] &= $$.m.i6[3]; + $$.f = $1.f; + $$.v = ftov($1.f); + $$.type = ifpflag; + $$.ifpos = dynamic; + if (ifpflag != 0 && $$.v == 0) { + if (frc->fr_family == AF_INET6){ + $$.v = 6; + $$.f = AF_INET6; + } else { + $$.v = 4; + $$.f = AF_INET; + } + } + yyresetdict(); + yyexpectaddr = 0; + } + | '(' YY_STR ')' { memset(&($$), 0, sizeof($$)); + $$.type = FRI_DYNAMIC; + ifpflag = FRI_DYNAMIC; + $$.ifpos = addname(&fr, $2); + $$.lif = 0; + } + | '(' YY_STR ')' '/' + { ifpflag = FRI_DYNAMIC; yysetdict(maskwords); } + maskopts + { memset(&($$), 0, sizeof($$)); + $$.type = ifpflag; + $$.ifpos = addname(&fr, $2); + $$.lif = 0; + if (frc->fr_family == AF_UNSPEC) + frc->fr_family = AF_INET; + if (ifpflag == FRI_DYNAMIC) { + ntomask(frc->fr_family, + $6, $$.m.i6); + } + yyresetdict(); + yyexpectaddr = 0; + } + | '(' YY_STR ':' YY_NUMBER ')' '/' + { ifpflag = FRI_DYNAMIC; yysetdict(maskwords); } + maskopts + { memset(&($$), 0, sizeof($$)); + $$.type = ifpflag; + $$.ifpos = addname(&fr, $2); + $$.lif = $4; + if (frc->fr_family == AF_UNSPEC) + frc->fr_family = AF_INET; + if (ifpflag == FRI_DYNAMIC) { + ntomask(frc->fr_family, + $8, $$.m.i6); + } + yyresetdict(); + yyexpectaddr = 0; + } + ; + +maskspace: + '/' + | IPFY_MASK + ; + +ipmask: ipv4 { $$ = count4bits($1.s_addr); } + | YY_HEX { $$ = count4bits(htonl($1)); } + | YY_NUMBER { $$ = $1; } + | YY_IPV6 { $$ = count6bits($1.i6); } + | maskopts { $$ = $1; } + ; + +maskopts: + IPFY_BROADCAST { if (ifpflag == FRI_DYNAMIC) { + ifpflag = FRI_BROADCAST; + } else { + YYERROR; + } + $$ = 0; + } + | IPFY_NETWORK { if (ifpflag == FRI_DYNAMIC) { + ifpflag = FRI_NETWORK; + } else { + YYERROR; + } + $$ = 0; + } + | IPFY_NETMASKED { if (ifpflag == FRI_DYNAMIC) { + ifpflag = FRI_NETMASKED; + } else { + YYERROR; + } + $$ = 0; + } + | IPFY_PEER { if (ifpflag == FRI_DYNAMIC) { + ifpflag = FRI_PEERADDR; + } else { + YYERROR; + } + $$ = 0; + } + | YY_NUMBER { $$ = $1; } + ; + +hostname: + ipv4 { memset(&($$), 0, sizeof($$)); + $$.adr.in4 = $1; + if (frc->fr_family == AF_INET6) + YYERROR; + $$.f = AF_INET; + yyexpectaddr = 2; + } + | YY_NUMBER { memset(&($$), 0, sizeof($$)); + if (frc->fr_family == AF_INET6) + YYERROR; + $$.adr.in4_addr = $1; + $$.f = AF_INET; + yyexpectaddr = 2; + } + | YY_HEX { memset(&($$), 0, sizeof($$)); + if (frc->fr_family == AF_INET6) + YYERROR; + $$.adr.in4_addr = $1; + $$.f = AF_INET; + yyexpectaddr = 2; + } + | YY_STR { memset(&($$), 0, sizeof($$)); + if (lookuphost($1, &$$.adr) == 0) + $$.f = AF_INET; + free($1); + yyexpectaddr = 2; + } + | YY_IPV6 { memset(&($$), 0, sizeof($$)); + if (frc->fr_family == AF_INET) + YYERROR; + $$.adr = $1; + $$.f = AF_INET6; + yyexpectaddr = 2; + } + ; + +addrlist: + ipaddr { $$ = newalist(NULL); + $$->al_family = $1.f; + $$->al_i6addr = $1.a; + $$->al_i6mask = $1.m; + } + | ipaddr ',' { yyexpectaddr = 1; } addrlist + { $$ = newalist($4); + $$->al_family = $1.f; + $$->al_i6addr = $1.a; + $$->al_i6mask = $1.m; + } + ; + +pool: IPFY_POOL { yyexpectaddr = 0; yycont = NULL; yyresetdict(); } + ; + +hash: IPFY_HASH { yyexpectaddr = 0; yycont = NULL; yyresetdict(); } + ; + +poollist: + ipaddr { $$ = newalist(NULL); + $$->al_family = $1.f; + $$->al_i6addr = $1.a; + $$->al_i6mask = $1.m; + } + | '!' ipaddr { $$ = newalist(NULL); + $$->al_not = 1; + $$->al_family = $2.f; + $$->al_i6addr = $2.a; + $$->al_i6mask = $2.m; + } + | poollist ',' ipaddr + { $$ = newalist($1); + $$->al_family = $3.f; + $$->al_i6addr = $3.a; + $$->al_i6mask = $3.m; + } + | poollist ',' '!' ipaddr + { $$ = newalist($1); + $$->al_not = 1; + $$->al_family = $4.f; + $$->al_i6addr = $4.a; + $$->al_i6mask = $4.m; + } + ; + +port: IPFY_PORT { yyexpectaddr = 0; + yycont = NULL; + if (frc->fr_proto != 0 && + frc->fr_proto != IPPROTO_UDP && + frc->fr_proto != IPPROTO_TCP) + yyerror("port use incorrect"); + } + ; + +portc: port compare { $$ = $2; + yysetdict(NULL); + } + | porteq { $$ = $1; } + ; + +porteq: port '=' { $$ = FR_EQUAL; + yysetdict(NULL); + } + ; + +portr: IPFY_PORT { yyexpectaddr = 0; + yycont = NULL; + yysetdict(NULL); + } + ; + +portcomp: + portc portnum { $$.pc = $1; + $$.p1 = $2; + yyresetdict(); + } + ; + +portrange: + portr portnum range portnum { $$.p1 = $2; + $$.pc = $3; + $$.p2 = $4; + yyresetdict(); + } + ; + +icmp: | itype icode + ; + +itype: seticmptype icmptype + { DOALL(fr->fr_icmp = htons($2 << 8); fr->fr_icmpm = htons(0xff00);); + yyresetdict(); + } + | seticmptype lstart typelist lend { yyresetdict(); } + ; + +seticmptype: + IPFY_ICMPTYPE { if (frc->fr_family == AF_UNSPEC) + frc->fr_family = AF_INET; + if (frc->fr_family == AF_INET && + frc->fr_type == FR_T_IPF && + frc->fr_proto != IPPROTO_ICMP) { + yyerror("proto not icmp"); + } + if (frc->fr_family == AF_INET6 && + frc->fr_type == FR_T_IPF && + frc->fr_proto != IPPROTO_ICMPV6) { + yyerror("proto not ipv6-icmp"); + } + setipftype(); + DOALL(if (fr->fr_family == AF_INET) { \ + fr->fr_ip.fi_v = 4; \ + fr->fr_mip.fi_v = 0xf; \ + } + if (fr->fr_family == AF_INET6) { \ + fr->fr_ip.fi_v = 6; \ + fr->fr_mip.fi_v = 0xf; \ + } + ) + yysetdict(NULL); + } + ; + +icode: | seticmpcode icmpcode + { DOALL(fr->fr_icmp |= htons($2); fr->fr_icmpm |= htons(0xff);); + yyresetdict(); + } + | seticmpcode lstart codelist lend { yyresetdict(); } + ; + +seticmpcode: + IPFY_ICMPCODE { yysetdict(icmpcodewords); } + ; + +typelist: + icmptype + { DOREM(fr->fr_icmp = htons($1 << 8); fr->fr_icmpm = htons(0xff00);) } + | typelist lmore icmptype + { DOREM(fr->fr_icmp = htons($3 << 8); fr->fr_icmpm = htons(0xff00);) } + ; + +codelist: + icmpcode + { DOREM(fr->fr_icmp |= htons($1); fr->fr_icmpm |= htons(0xff);) } + | codelist lmore icmpcode + { DOREM(fr->fr_icmp &= htons(0xff00); fr->fr_icmp |= htons($3); \ + fr->fr_icmpm |= htons(0xff);) } + ; + +age: | IPFY_AGE YY_NUMBER { DOALL(fr->fr_age[0] = $2; \ + fr->fr_age[1] = $2;) } + | IPFY_AGE YY_NUMBER '/' YY_NUMBER + { DOALL(fr->fr_age[0] = $2; \ + fr->fr_age[1] = $4;) } + ; + +keep: | IPFY_KEEP keepstate keep + | IPFY_KEEP keepfrag keep + ; + +keepstate: + IPFY_STATE stateoptlist { DOALL(fr->fr_flags |= FR_KEEPSTATE;)} + ; + +keepfrag: + IPFY_FRAGS fragoptlist { DOALL(fr->fr_flags |= FR_KEEPFRAG;) } + | IPFY_FRAG fragoptlist { DOALL(fr->fr_flags |= FR_KEEPFRAG;) } + ; + +fragoptlist: + | '(' fragopts ')' + ; + +fragopts: + fragopt lanother fragopts + | fragopt + ; + +fragopt: + IPFY_STRICT { DOALL(fr->fr_flags |= FR_FRSTRICT;) } + ; + +stateoptlist: + | '(' stateopts ')' + ; + +stateopts: + stateopt lanother stateopts + | stateopt + ; + +stateopt: + IPFY_LIMIT YY_NUMBER { DOALL(fr->fr_statemax = $2;) } + | IPFY_STRICT { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \ + YYERROR; \ + } else if (fr->fr_flags & FR_STLOOSE) {\ + YYERROR; \ + } else \ + fr->fr_flags |= FR_STSTRICT;) + } + | IPFY_LOOSE { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \ + YYERROR; \ + } else if (fr->fr_flags & FR_STSTRICT){\ + YYERROR; \ + } else \ + fr->fr_flags |= FR_STLOOSE;) + } + | IPFY_NEWISN { DOALL(if (fr->fr_proto != IPPROTO_TCP) { \ + YYERROR; \ + } else \ + fr->fr_flags |= FR_NEWISN;) + } + | IPFY_NOICMPERR { DOALL(fr->fr_flags |= FR_NOICMPERR;) } + + | IPFY_SYNC { DOALL(fr->fr_flags |= FR_STATESYNC;) } + | IPFY_AGE YY_NUMBER { DOALL(fr->fr_age[0] = $2; \ + fr->fr_age[1] = $2;) } + | IPFY_AGE YY_NUMBER '/' YY_NUMBER + { DOALL(fr->fr_age[0] = $2; \ + fr->fr_age[1] = $4;) } + | IPFY_ICMPHEAD groupname + { DOALL(seticmphead(&fr, $2);) + free($2); + } + | IPFY_NOLOG + { DOALL(fr->fr_nostatelog = 1;) } + | IPFY_RPC + { DOALL(fr->fr_rpc = 1;) } + | IPFY_RPC IPFY_IN YY_STR + { DOALL(fr->fr_rpc = 1;) } + | IPFY_MAX_SRCS YY_NUMBER + { DOALL(fr->fr_srctrack.ht_max_nodes = $2;) } + | IPFY_MAX_PER_SRC YY_NUMBER + { DOALL(fr->fr_srctrack.ht_max_per_node = $2; \ + fr->fr_srctrack.ht_netmask = \ + fr->fr_family == AF_INET ? 32: 128;) + } + | IPFY_MAX_PER_SRC YY_NUMBER '/' YY_NUMBER + { DOALL(fr->fr_srctrack.ht_max_per_node = $2; \ + fr->fr_srctrack.ht_netmask = $4;) + } + ; + +portnum: + servicename { if (getport(frc, $1, + &($$), NULL) == -1) + yyerror("service unknown"); + $$ = ntohs($$); + free($1); + } + | YY_NUMBER { if ($1 > 65535) /* Unsigned */ + yyerror("invalid port number"); + else + $$ = $1; + } + ; + +withlist: + withopt { nowith = 0; } + | withlist withopt { nowith = 0; } + | withlist ',' withopt { nowith = 0; } + ; + +withopt: + opttype { DOALL(fr->fr_flx |= $1; fr->fr_mflx |= $1;) } + | notwith opttype { DOALL(fr->fr_mflx |= $2;) } + | ipopt ipopts { yyresetdict(); } + | notwith ipopt ipopts { yyresetdict(); } + | startv6hdr ipv6hdrs { yyresetdict(); } + ; + +ipopt: IPFY_OPT { yysetdict(ipv4optwords); } + ; + +startv6hdr: + IPFY_V6HDR { if (frc->fr_family != AF_INET6) + yyerror("only available with IPv6"); + yysetdict(ipv6optwords); + } + ; + +notwith: + IPFY_NOT { nowith = 1; } + | IPFY_NO { nowith = 1; } + ; + +opttype: + IPFY_IPOPTS { $$ = FI_OPTIONS; } + | IPFY_SHORT { $$ = FI_SHORT; } + | IPFY_NAT { $$ = FI_NATED; } + | IPFY_BAD { $$ = FI_BAD; } + | IPFY_BADNAT { $$ = FI_BADNAT; } + | IPFY_BADSRC { $$ = FI_BADSRC; } + | IPFY_LOWTTL { $$ = FI_LOWTTL; } + | IPFY_FRAG { $$ = FI_FRAG; } + | IPFY_FRAGBODY { $$ = FI_FRAGBODY; } + | IPFY_FRAGS { $$ = FI_FRAG; } + | IPFY_MBCAST { $$ = FI_MBCAST; } + | IPFY_MULTICAST { $$ = FI_MULTICAST; } + | IPFY_BROADCAST { $$ = FI_BROADCAST; } + | IPFY_STATE { $$ = FI_STATE; } + | IPFY_OOW { $$ = FI_OOW; } + | IPFY_AH { $$ = FI_AH; } + | IPFY_V6HDRS { $$ = FI_V6EXTHDR; } + ; + +ipopts: optlist { DOALL(fr->fr_mip.fi_optmsk |= $1; + if (fr->fr_family == AF_UNSPEC) { + fr->fr_family = AF_INET; + fr->fr_ip.fi_v = 4; + fr->fr_mip.fi_v = 0xf; + } else if (fr->fr_family != AF_INET) { + YYERROR; + } + if (!nowith) + fr->fr_ip.fi_optmsk |= $1;) + } + ; + +optlist: + opt { $$ |= $1; } + | optlist ',' opt { $$ |= $1 | $3; } + ; + +ipv6hdrs: + ipv6hdrlist { DOALL(fr->fr_mip.fi_optmsk |= $1; + if (!nowith) + fr->fr_ip.fi_optmsk |= $1;) + } + ; + +ipv6hdrlist: + ipv6hdr { $$ |= $1; } + | ipv6hdrlist ',' ipv6hdr { $$ |= $1 | $3; } + ; + +secname: + seclevel { $$ |= $1; } + | secname ',' seclevel { $$ |= $1 | $3; } + ; + +seclevel: + IPFY_SEC_UNC { $$ = secbit(IPSO_CLASS_UNCL); } + | IPFY_SEC_CONF { $$ = secbit(IPSO_CLASS_CONF); } + | IPFY_SEC_RSV1 { $$ = secbit(IPSO_CLASS_RES1); } + | IPFY_SEC_RSV2 { $$ = secbit(IPSO_CLASS_RES2); } + | IPFY_SEC_RSV3 { $$ = secbit(IPSO_CLASS_RES3); } + | IPFY_SEC_RSV4 { $$ = secbit(IPSO_CLASS_RES4); } + | IPFY_SEC_SEC { $$ = secbit(IPSO_CLASS_SECR); } + | IPFY_SEC_TS { $$ = secbit(IPSO_CLASS_TOPS); } + ; + +icmptype: + YY_NUMBER { $$ = $1; } + | YY_STR { $$ = geticmptype(frc->fr_family, $1); + if ($$ == -1) + yyerror("unrecognised icmp type"); + } + ; + +icmpcode: + YY_NUMBER { $$ = $1; } + | IPFY_ICMPC_NETUNR { $$ = ICMP_UNREACH_NET; } + | IPFY_ICMPC_HSTUNR { $$ = ICMP_UNREACH_HOST; } + | IPFY_ICMPC_PROUNR { $$ = ICMP_UNREACH_PROTOCOL; } + | IPFY_ICMPC_PORUNR { $$ = ICMP_UNREACH_PORT; } + | IPFY_ICMPC_NEEDF { $$ = ICMP_UNREACH_NEEDFRAG; } + | IPFY_ICMPC_SRCFAIL { $$ = ICMP_UNREACH_SRCFAIL; } + | IPFY_ICMPC_NETUNK { $$ = ICMP_UNREACH_NET_UNKNOWN; } + | IPFY_ICMPC_HSTUNK { $$ = ICMP_UNREACH_HOST_UNKNOWN; } + | IPFY_ICMPC_ISOLATE { $$ = ICMP_UNREACH_ISOLATED; } + | IPFY_ICMPC_NETPRO { $$ = ICMP_UNREACH_NET_PROHIB; } + | IPFY_ICMPC_HSTPRO { $$ = ICMP_UNREACH_HOST_PROHIB; } + | IPFY_ICMPC_NETTOS { $$ = ICMP_UNREACH_TOSNET; } + | IPFY_ICMPC_HSTTOS { $$ = ICMP_UNREACH_TOSHOST; } + | IPFY_ICMPC_FLTPRO { $$ = ICMP_UNREACH_ADMIN_PROHIBIT; } + | IPFY_ICMPC_HSTPRE { $$ = 14; } + | IPFY_ICMPC_CUTPRE { $$ = 15; } + ; + +opt: + IPFY_IPOPT_NOP { $$ = getoptbyvalue(IPOPT_NOP); } + | IPFY_IPOPT_RR { $$ = getoptbyvalue(IPOPT_RR); } + | IPFY_IPOPT_ZSU { $$ = getoptbyvalue(IPOPT_ZSU); } + | IPFY_IPOPT_MTUP { $$ = getoptbyvalue(IPOPT_MTUP); } + | IPFY_IPOPT_MTUR { $$ = getoptbyvalue(IPOPT_MTUR); } + | IPFY_IPOPT_ENCODE { $$ = getoptbyvalue(IPOPT_ENCODE); } + | IPFY_IPOPT_TS { $$ = getoptbyvalue(IPOPT_TS); } + | IPFY_IPOPT_TR { $$ = getoptbyvalue(IPOPT_TR); } + | IPFY_IPOPT_SEC { $$ = getoptbyvalue(IPOPT_SECURITY); } + | IPFY_IPOPT_LSRR { $$ = getoptbyvalue(IPOPT_LSRR); } + | IPFY_IPOPT_ESEC { $$ = getoptbyvalue(IPOPT_E_SEC); } + | IPFY_IPOPT_CIPSO { $$ = getoptbyvalue(IPOPT_CIPSO); } + | IPFY_IPOPT_CIPSO doi { $$ = getoptbyvalue(IPOPT_CIPSO); } + | IPFY_IPOPT_SATID { $$ = getoptbyvalue(IPOPT_SATID); } + | IPFY_IPOPT_SSRR { $$ = getoptbyvalue(IPOPT_SSRR); } + | IPFY_IPOPT_ADDEXT { $$ = getoptbyvalue(IPOPT_ADDEXT); } + | IPFY_IPOPT_VISA { $$ = getoptbyvalue(IPOPT_VISA); } + | IPFY_IPOPT_IMITD { $$ = getoptbyvalue(IPOPT_IMITD); } + | IPFY_IPOPT_EIP { $$ = getoptbyvalue(IPOPT_EIP); } + | IPFY_IPOPT_FINN { $$ = getoptbyvalue(IPOPT_FINN); } + | IPFY_IPOPT_DPS { $$ = getoptbyvalue(IPOPT_DPS); } + | IPFY_IPOPT_SDB { $$ = getoptbyvalue(IPOPT_SDB); } + | IPFY_IPOPT_NSAPA { $$ = getoptbyvalue(IPOPT_NSAPA); } + | IPFY_IPOPT_RTRALRT { $$ = getoptbyvalue(IPOPT_RTRALRT); } + | IPFY_IPOPT_UMP { $$ = getoptbyvalue(IPOPT_UMP); } + | setsecclass secname + { DOALL(fr->fr_mip.fi_secmsk |= $2; + if (fr->fr_family == AF_UNSPEC) { + fr->fr_family = AF_INET; + fr->fr_ip.fi_v = 4; + fr->fr_mip.fi_v = 0xf; + } else if (fr->fr_family != AF_INET) { + YYERROR; + } + if (!nowith) + fr->fr_ip.fi_secmsk |= $2;) + $$ = 0; + yyresetdict(); + } + ; + +setsecclass: + IPFY_SECCLASS { yysetdict(ipv4secwords); } + ; + +doi: IPFY_DOI YY_NUMBER { DOALL(fr->fr_doimask = 0xffffffff; \ + if (!nowith) \ + fr->fr_doi = $2;) } + | IPFY_DOI YY_HEX { DOALL(fr->fr_doimask = 0xffffffff; \ + if (!nowith) \ + fr->fr_doi = $2;) } + ; + +ipv6hdr: + IPFY_AH { $$ = getv6optbyvalue(IPPROTO_AH); } + | IPFY_IPV6OPT_DSTOPTS { $$ = getv6optbyvalue(IPPROTO_DSTOPTS); } + | IPFY_IPV6OPT_ESP { $$ = getv6optbyvalue(IPPROTO_ESP); } + | IPFY_IPV6OPT_HOPOPTS { $$ = getv6optbyvalue(IPPROTO_HOPOPTS); } + | IPFY_IPV6OPT_IPV6 { $$ = getv6optbyvalue(IPPROTO_IPV6); } + | IPFY_IPV6OPT_NONE { $$ = getv6optbyvalue(IPPROTO_NONE); } + | IPFY_IPV6OPT_ROUTING { $$ = getv6optbyvalue(IPPROTO_ROUTING); } + | IPFY_IPV6OPT_FRAG { $$ = getv6optbyvalue(IPPROTO_FRAGMENT); } + | IPFY_IPV6OPT_MOBILITY { $$ = getv6optbyvalue(IPPROTO_MOBILITY); } + ; + +level: IPFY_LEVEL { setsyslog(); } + ; + +loglevel: + priority { fr->fr_loglevel = LOG_LOCAL0|$1; } + | facility '.' priority { fr->fr_loglevel = $1 | $3; } + ; + +facility: + IPFY_FAC_KERN { $$ = LOG_KERN; } + | IPFY_FAC_USER { $$ = LOG_USER; } + | IPFY_FAC_MAIL { $$ = LOG_MAIL; } + | IPFY_FAC_DAEMON { $$ = LOG_DAEMON; } + | IPFY_FAC_AUTH { $$ = LOG_AUTH; } + | IPFY_FAC_SYSLOG { $$ = LOG_SYSLOG; } + | IPFY_FAC_LPR { $$ = LOG_LPR; } + | IPFY_FAC_NEWS { $$ = LOG_NEWS; } + | IPFY_FAC_UUCP { $$ = LOG_UUCP; } + | IPFY_FAC_CRON { $$ = LOG_CRON; } + | IPFY_FAC_FTP { $$ = LOG_FTP; } + | IPFY_FAC_AUTHPRIV { $$ = LOG_AUTHPRIV; } + | IPFY_FAC_AUDIT { $$ = LOG_AUDIT; } + | IPFY_FAC_LFMT { $$ = LOG_LFMT; } + | IPFY_FAC_LOCAL0 { $$ = LOG_LOCAL0; } + | IPFY_FAC_LOCAL1 { $$ = LOG_LOCAL1; } + | IPFY_FAC_LOCAL2 { $$ = LOG_LOCAL2; } + | IPFY_FAC_LOCAL3 { $$ = LOG_LOCAL3; } + | IPFY_FAC_LOCAL4 { $$ = LOG_LOCAL4; } + | IPFY_FAC_LOCAL5 { $$ = LOG_LOCAL5; } + | IPFY_FAC_LOCAL6 { $$ = LOG_LOCAL6; } + | IPFY_FAC_LOCAL7 { $$ = LOG_LOCAL7; } + | IPFY_FAC_SECURITY { $$ = LOG_SECURITY; } + ; + +priority: + IPFY_PRI_EMERG { $$ = LOG_EMERG; } + | IPFY_PRI_ALERT { $$ = LOG_ALERT; } + | IPFY_PRI_CRIT { $$ = LOG_CRIT; } + | IPFY_PRI_ERR { $$ = LOG_ERR; } + | IPFY_PRI_WARN { $$ = LOG_WARNING; } + | IPFY_PRI_NOTICE { $$ = LOG_NOTICE; } + | IPFY_PRI_INFO { $$ = LOG_INFO; } + | IPFY_PRI_DEBUG { $$ = LOG_DEBUG; } + ; + +compare: + YY_CMP_EQ { $$ = FR_EQUAL; } + | YY_CMP_NE { $$ = FR_NEQUAL; } + | YY_CMP_LT { $$ = FR_LESST; } + | YY_CMP_LE { $$ = FR_LESSTE; } + | YY_CMP_GT { $$ = FR_GREATERT; } + | YY_CMP_GE { $$ = FR_GREATERTE; } + ; + +range: YY_RANGE_IN { $$ = FR_INRANGE; } + | YY_RANGE_OUT { $$ = FR_OUTRANGE; } + | ':' { $$ = FR_INCRANGE; } + ; + +servicename: + YY_STR { $$ = $1; } + ; + +interfacename: name { $$ = $1; } + | name ':' YY_NUMBER + { $$ = $1; + fprintf(stderr, "%d: Logical interface %s:%d unsupported, " + "use the physical interface %s instead.\n", + yylineNum, $1, $3, $1); + } + ; + +name: YY_STR { $$ = $1; } + | '-' { $$ = strdup("-"); } + ; + +ipv4_16: + YY_NUMBER '.' YY_NUMBER + { if ($1 > 255 || $3 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr = ($1 << 24) | ($3 << 16); + $$.s_addr = htonl($$.s_addr); + } + ; + +ipv4_24: + ipv4_16 '.' YY_NUMBER + { if ($3 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr |= htonl($3 << 8); + } + ; + +ipv4: ipv4_24 '.' YY_NUMBER + { if ($3 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr |= htonl($3); + } + | ipv4_24 + | ipv4_16 + ; + +%% + + +static struct wordtab ipfwords[] = { + { "age", IPFY_AGE }, + { "ah", IPFY_AH }, + { "all", IPFY_ALL }, + { "and", IPFY_AND }, + { "auth", IPFY_AUTH }, + { "bad", IPFY_BAD }, + { "bad-nat", IPFY_BADNAT }, + { "bad-src", IPFY_BADSRC }, + { "bcast", IPFY_BROADCAST }, + { "block", IPFY_BLOCK }, + { "body", IPFY_BODY }, + { "bpf-v4", IPFY_BPFV4 }, +#ifdef USE_INET6 + { "bpf-v6", IPFY_BPFV6 }, +#endif + { "call", IPFY_CALL }, + { "code", IPFY_ICMPCODE }, + { "comment", IPFY_COMMENT }, + { "count", IPFY_COUNT }, + { "decapsulate", IPFY_DECAPS }, + { "dstlist", IPFY_DSTLIST }, + { "doi", IPFY_DOI }, + { "dup-to", IPFY_DUPTO }, + { "eq", YY_CMP_EQ }, + { "esp", IPFY_ESP }, + { "exp", IPFY_IPFEXPR }, + { "family", IPFY_FAMILY }, + { "fastroute", IPFY_FROUTE }, + { "first", IPFY_FIRST }, + { "flags", IPFY_FLAGS }, + { "frag", IPFY_FRAG }, + { "frag-body", IPFY_FRAGBODY }, + { "frags", IPFY_FRAGS }, + { "from", IPFY_FROM }, + { "ge", YY_CMP_GE }, + { "group", IPFY_GROUP }, + { "gt", YY_CMP_GT }, + { "head", IPFY_HEAD }, + { "icmp", IPFY_ICMP }, + { "icmp-head", IPFY_ICMPHEAD }, + { "icmp-type", IPFY_ICMPTYPE }, + { "in", IPFY_IN }, + { "in-via", IPFY_INVIA }, + { "inet", IPFY_INET }, + { "inet6", IPFY_INET6 }, + { "ipopt", IPFY_IPOPTS }, + { "ipopts", IPFY_IPOPTS }, + { "keep", IPFY_KEEP }, + { "l5-as", IPFY_L5AS }, + { "le", YY_CMP_LE }, + { "level", IPFY_LEVEL }, + { "limit", IPFY_LIMIT }, + { "log", IPFY_LOG }, + { "loose", IPFY_LOOSE }, + { "lowttl", IPFY_LOWTTL }, + { "lt", YY_CMP_LT }, + { "mask", IPFY_MASK }, + { "match-tag", IPFY_MATCHTAG }, + { "max-per-src", IPFY_MAX_PER_SRC }, + { "max-srcs", IPFY_MAX_SRCS }, + { "mbcast", IPFY_MBCAST }, + { "mcast", IPFY_MULTICAST }, + { "multicast", IPFY_MULTICAST }, + { "nat", IPFY_NAT }, + { "ne", YY_CMP_NE }, + { "net", IPFY_NETWORK }, + { "newisn", IPFY_NEWISN }, + { "no", IPFY_NO }, + { "no-icmp-err", IPFY_NOICMPERR }, + { "nolog", IPFY_NOLOG }, + { "nomatch", IPFY_NOMATCH }, + { "now", IPFY_NOW }, + { "not", IPFY_NOT }, + { "oow", IPFY_OOW }, + { "on", IPFY_ON }, + { "opt", IPFY_OPT }, + { "or-block", IPFY_ORBLOCK }, + { "out", IPFY_OUT }, + { "out-via", IPFY_OUTVIA }, + { "pass", IPFY_PASS }, + { "port", IPFY_PORT }, + { "pps", IPFY_PPS }, + { "preauth", IPFY_PREAUTH }, + { "proto", IPFY_PROTO }, + { "quick", IPFY_QUICK }, + { "reply-to", IPFY_REPLY_TO }, + { "return-icmp", IPFY_RETICMP }, + { "return-icmp-as-dest", IPFY_RETICMPASDST }, + { "return-rst", IPFY_RETRST }, + { "route-to", IPFY_ROUTETO }, + { "rule-ttl", IPFY_RULETTL }, + { "rpc", IPFY_RPC }, + { "sec-class", IPFY_SECCLASS }, + { "set", IPFY_SET }, + { "set-tag", IPFY_SETTAG }, + { "skip", IPFY_SKIP }, + { "short", IPFY_SHORT }, + { "state", IPFY_STATE }, + { "state-age", IPFY_AGE }, + { "strict", IPFY_STRICT }, + { "sync", IPFY_SYNC }, + { "tcp", IPFY_TCP }, + { "tcp-udp", IPFY_TCPUDP }, + { "tos", IPFY_TOS }, + { "to", IPFY_TO }, + { "ttl", IPFY_TTL }, + { "udp", IPFY_UDP }, + { "v6hdr", IPFY_V6HDR }, + { "v6hdrs", IPFY_V6HDRS }, + { "with", IPFY_WITH }, + { NULL, 0 } +}; + +static struct wordtab addrwords[] = { + { "any", IPFY_ANY }, + { "hash", IPFY_HASH }, + { "pool", IPFY_POOL }, + { NULL, 0 } +}; + +static struct wordtab maskwords[] = { + { "broadcast", IPFY_BROADCAST }, + { "netmasked", IPFY_NETMASKED }, + { "network", IPFY_NETWORK }, + { "peer", IPFY_PEER }, + { NULL, 0 } +}; + +static struct wordtab icmpcodewords[] = { + { "cutoff-preced", IPFY_ICMPC_CUTPRE }, + { "filter-prohib", IPFY_ICMPC_FLTPRO }, + { "isolate", IPFY_ICMPC_ISOLATE }, + { "needfrag", IPFY_ICMPC_NEEDF }, + { "net-prohib", IPFY_ICMPC_NETPRO }, + { "net-tos", IPFY_ICMPC_NETTOS }, + { "host-preced", IPFY_ICMPC_HSTPRE }, + { "host-prohib", IPFY_ICMPC_HSTPRO }, + { "host-tos", IPFY_ICMPC_HSTTOS }, + { "host-unk", IPFY_ICMPC_HSTUNK }, + { "host-unr", IPFY_ICMPC_HSTUNR }, + { "net-unk", IPFY_ICMPC_NETUNK }, + { "net-unr", IPFY_ICMPC_NETUNR }, + { "port-unr", IPFY_ICMPC_PORUNR }, + { "proto-unr", IPFY_ICMPC_PROUNR }, + { "srcfail", IPFY_ICMPC_SRCFAIL }, + { NULL, 0 }, +}; + +static struct wordtab ipv4optwords[] = { + { "addext", IPFY_IPOPT_ADDEXT }, + { "cipso", IPFY_IPOPT_CIPSO }, + { "dps", IPFY_IPOPT_DPS }, + { "e-sec", IPFY_IPOPT_ESEC }, + { "eip", IPFY_IPOPT_EIP }, + { "encode", IPFY_IPOPT_ENCODE }, + { "finn", IPFY_IPOPT_FINN }, + { "imitd", IPFY_IPOPT_IMITD }, + { "lsrr", IPFY_IPOPT_LSRR }, + { "mtup", IPFY_IPOPT_MTUP }, + { "mtur", IPFY_IPOPT_MTUR }, + { "nop", IPFY_IPOPT_NOP }, + { "nsapa", IPFY_IPOPT_NSAPA }, + { "rr", IPFY_IPOPT_RR }, + { "rtralrt", IPFY_IPOPT_RTRALRT }, + { "satid", IPFY_IPOPT_SATID }, + { "sdb", IPFY_IPOPT_SDB }, + { "sec", IPFY_IPOPT_SEC }, + { "ssrr", IPFY_IPOPT_SSRR }, + { "tr", IPFY_IPOPT_TR }, + { "ts", IPFY_IPOPT_TS }, + { "ump", IPFY_IPOPT_UMP }, + { "visa", IPFY_IPOPT_VISA }, + { "zsu", IPFY_IPOPT_ZSU }, + { NULL, 0 }, +}; + +static struct wordtab ipv4secwords[] = { + { "confid", IPFY_SEC_CONF }, + { "reserv-1", IPFY_SEC_RSV1 }, + { "reserv-2", IPFY_SEC_RSV2 }, + { "reserv-3", IPFY_SEC_RSV3 }, + { "reserv-4", IPFY_SEC_RSV4 }, + { "secret", IPFY_SEC_SEC }, + { "topsecret", IPFY_SEC_TS }, + { "unclass", IPFY_SEC_UNC }, + { NULL, 0 }, +}; + +static struct wordtab ipv6optwords[] = { + { "dstopts", IPFY_IPV6OPT_DSTOPTS }, + { "esp", IPFY_IPV6OPT_ESP }, + { "frag", IPFY_IPV6OPT_FRAG }, + { "hopopts", IPFY_IPV6OPT_HOPOPTS }, + { "ipv6", IPFY_IPV6OPT_IPV6 }, + { "mobility", IPFY_IPV6OPT_MOBILITY }, + { "none", IPFY_IPV6OPT_NONE }, + { "routing", IPFY_IPV6OPT_ROUTING }, + { NULL, 0 }, +}; + +static struct wordtab logwords[] = { + { "kern", IPFY_FAC_KERN }, + { "user", IPFY_FAC_USER }, + { "mail", IPFY_FAC_MAIL }, + { "daemon", IPFY_FAC_DAEMON }, + { "auth", IPFY_FAC_AUTH }, + { "syslog", IPFY_FAC_SYSLOG }, + { "lpr", IPFY_FAC_LPR }, + { "news", IPFY_FAC_NEWS }, + { "uucp", IPFY_FAC_UUCP }, + { "cron", IPFY_FAC_CRON }, + { "ftp", IPFY_FAC_FTP }, + { "authpriv", IPFY_FAC_AUTHPRIV }, + { "audit", IPFY_FAC_AUDIT }, + { "logalert", IPFY_FAC_LFMT }, + { "console", IPFY_FAC_CONSOLE }, + { "security", IPFY_FAC_SECURITY }, + { "local0", IPFY_FAC_LOCAL0 }, + { "local1", IPFY_FAC_LOCAL1 }, + { "local2", IPFY_FAC_LOCAL2 }, + { "local3", IPFY_FAC_LOCAL3 }, + { "local4", IPFY_FAC_LOCAL4 }, + { "local5", IPFY_FAC_LOCAL5 }, + { "local6", IPFY_FAC_LOCAL6 }, + { "local7", IPFY_FAC_LOCAL7 }, + { "emerg", IPFY_PRI_EMERG }, + { "alert", IPFY_PRI_ALERT }, + { "crit", IPFY_PRI_CRIT }, + { "err", IPFY_PRI_ERR }, + { "warn", IPFY_PRI_WARN }, + { "notice", IPFY_PRI_NOTICE }, + { "info", IPFY_PRI_INFO }, + { "debug", IPFY_PRI_DEBUG }, + { NULL, 0 }, +}; + + + + +int ipf_parsefile(fd, addfunc, iocfuncs, filename) +int fd; +addfunc_t addfunc; +ioctlfunc_t *iocfuncs; +char *filename; +{ + FILE *fp = NULL; + char *s; + + yylineNum = 1; + yysettab(ipfwords); + + s = getenv("YYDEBUG"); + if (s != NULL) + yydebug = atoi(s); + else + yydebug = 0; + + if (strcmp(filename, "-")) { + fp = fopen(filename, "r"); + if (fp == NULL) { + fprintf(stderr, "fopen(%s) failed: %s\n", filename, + STRERROR(errno)); + return -1; + } + } else + fp = stdin; + + while (ipf_parsesome(fd, addfunc, iocfuncs, fp) == 1) + ; + if (fp != NULL) + fclose(fp); + return 0; +} + + +int ipf_parsesome(fd, addfunc, iocfuncs, fp) +int fd; +addfunc_t addfunc; +ioctlfunc_t *iocfuncs; +FILE *fp; +{ + char *s; + int i; + + ipffd = fd; + for (i = 0; i <= IPL_LOGMAX; i++) + ipfioctls[i] = iocfuncs[i]; + ipfaddfunc = addfunc; + + if (feof(fp)) + return 0; + i = fgetc(fp); + if (i == EOF) + return 0; + if (ungetc(i, fp) == 0) + return 0; + if (feof(fp)) + return 0; + s = getenv("YYDEBUG"); + if (s != NULL) + yydebug = atoi(s); + else + yydebug = 0; + + yyin = fp; + yyparse(); + return 1; +} + + +static void newrule() +{ + frentry_t *frn; + + frn = allocfr(); + for (fr = frtop; fr != NULL && fr->fr_next != NULL; fr = fr->fr_next) + ; + if (fr != NULL) { + fr->fr_next = frn; + frn->fr_pnext = &fr->fr_next; + } + if (frtop == NULL) { + frtop = frn; + frn->fr_pnext = &frtop; + } + fr = frn; + frc = frn; + fr->fr_loglevel = 0xffff; + fr->fr_isc = (void *)-1; + fr->fr_logtag = FR_NOLOGTAG; + fr->fr_type = FR_T_NONE; + fr->fr_flineno = yylineNum; + + if (use_inet6 == 1) + fr->fr_family = AF_INET6; + else if (use_inet6 == -1) + fr->fr_family = AF_INET; + + nrules = 1; +} + + +static void setipftype() +{ + for (fr = frc; fr != NULL; fr = fr->fr_next) { + if (fr->fr_type == FR_T_NONE) { + fr->fr_type = FR_T_IPF; + fr->fr_data = (void *)calloc(sizeof(fripf_t), 1); + fr->fr_dsize = sizeof(fripf_t); + fr->fr_family = frc->fr_family; + if (fr->fr_family == AF_INET) { + fr->fr_ip.fi_v = 4; + } + else if (fr->fr_family == AF_INET6) { + fr->fr_ip.fi_v = 6; + } + fr->fr_mip.fi_v = 0xf; + fr->fr_ipf->fri_sifpidx = -1; + fr->fr_ipf->fri_difpidx = -1; + } + if (fr->fr_type != FR_T_IPF) { + fprintf(stderr, "IPF Type not set\n"); + } + } +} + + +static frentry_t *addrule() +{ + frentry_t *f, *f1, *f2; + int count; + + for (f2 = frc; f2->fr_next != NULL; f2 = f2->fr_next) + ; + + count = nrules; + f = f2; + for (f1 = frc; count > 0; count--, f1 = f1->fr_next) { + f->fr_next = allocfr(); + if (f->fr_next == NULL) + return NULL; + f->fr_next->fr_pnext = &f->fr_next; + added++; + f = f->fr_next; + *f = *f1; + f->fr_next = NULL; + if (f->fr_caddr != NULL) { + f->fr_caddr = malloc(f->fr_dsize); + bcopy(f1->fr_caddr, f->fr_caddr, f->fr_dsize); + } + } + + return f2->fr_next; +} + + +static int +lookuphost(name, addrp) + char *name; + i6addr_t *addrp; +{ + int i; + + hashed = 0; + pooled = 0; + dynamic = -1; + + for (i = 0; i < 4; i++) { + if (fr->fr_ifnames[i] == -1) + continue; + if (strcmp(name, fr->fr_names + fr->fr_ifnames[i]) == 0) { + ifpflag = FRI_DYNAMIC; + dynamic = addname(&fr, name); + return 1; + } + } + + if (gethost(AF_INET, name, addrp) == -1) { + fprintf(stderr, "unknown name \"%s\"\n", name); + return -1; + } + return 0; +} + + +static void dobpf(v, phrase) +int v; +char *phrase; +{ +#ifdef IPFILTER_BPF + struct bpf_program bpf; + struct pcap *p; +#endif + fakebpf_t *fb; + u_32_t l; + char *s; + int i; + + for (fr = frc; fr != NULL; fr = fr->fr_next) { + if (fr->fr_type != FR_T_NONE) { + fprintf(stderr, "cannot mix IPF and BPF matching\n"); + return; + } + fr->fr_family = vtof(v); + fr->fr_type = FR_T_BPFOPC; + + if (!strncmp(phrase, "0x", 2)) { + fb = malloc(sizeof(fakebpf_t)); + + for (i = 0, s = strtok(phrase, " \r\n\t"); s != NULL; + s = strtok(NULL, " \r\n\t"), i++) { + fb = realloc(fb, (i / 4 + 1) * sizeof(*fb)); + l = (u_32_t)strtol(s, NULL, 0); + switch (i & 3) + { + case 0 : + fb[i / 4].fb_c = l & 0xffff; + break; + case 1 : + fb[i / 4].fb_t = l & 0xff; + break; + case 2 : + fb[i / 4].fb_f = l & 0xff; + break; + case 3 : + fb[i / 4].fb_k = l; + break; + } + } + if ((i & 3) != 0) { + fprintf(stderr, + "Odd number of bytes in BPF code\n"); + exit(1); + } + i--; + fr->fr_dsize = (i / 4 + 1) * sizeof(*fb); + fr->fr_data = fb; + return; + } + +#ifdef IPFILTER_BPF + bzero((char *)&bpf, sizeof(bpf)); + p = pcap_open_dead(DLT_RAW, 1); + if (!p) { + fprintf(stderr, "pcap_open_dead failed\n"); + return; + } + + if (pcap_compile(p, &bpf, phrase, 1, 0xffffffff)) { + pcap_perror(p, "ipf"); + pcap_close(p); + fprintf(stderr, "pcap parsing failed (%s)\n", phrase); + return; + } + pcap_close(p); + + fr->fr_dsize = bpf.bf_len * sizeof(struct bpf_insn); + fr->fr_data = malloc(fr->fr_dsize); + bcopy((char *)bpf.bf_insns, fr->fr_data, fr->fr_dsize); + if (!bpf_validate(fr->fr_data, bpf.bf_len)) { + fprintf(stderr, "BPF validation failed\n"); + return; + } +#endif + } + +#ifdef IPFILTER_BPF + if (opts & OPT_DEBUG) + bpf_dump(&bpf, 0); +#else + fprintf(stderr, "BPF filter expressions not supported\n"); + exit(1); +#endif +} + + +static void resetaddr() +{ + hashed = 0; + pooled = 0; + dynamic = -1; +} + + +static alist_t *newalist(ptr) +alist_t *ptr; +{ + alist_t *al; + + al = malloc(sizeof(*al)); + if (al == NULL) + return NULL; + al->al_not = 0; + al->al_next = ptr; + return al; +} + + +static int +makepool(list) + alist_t *list; +{ + ip_pool_node_t *n, *top; + ip_pool_t pool; + alist_t *a; + int num; + + if (list == NULL) + return 0; + top = calloc(1, sizeof(*top)); + if (top == NULL) + return 0; + + for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) { + if (use_inet6 == 1) { +#ifdef AF_INET6 + n->ipn_addr.adf_family = AF_INET6; + n->ipn_addr.adf_addr = a->al_i6addr; + n->ipn_addr.adf_len = offsetof(addrfamily_t, + adf_addr) + 16; + n->ipn_mask.adf_family = AF_INET6; + n->ipn_mask.adf_addr = a->al_i6mask; + n->ipn_mask.adf_len = offsetof(addrfamily_t, + adf_addr) + 16; + +#endif + } else { + n->ipn_addr.adf_family = AF_INET; + n->ipn_addr.adf_addr.in4.s_addr = a->al_1; + n->ipn_addr.adf_len = offsetof(addrfamily_t, + adf_addr) + 4; + n->ipn_mask.adf_family = AF_INET; + n->ipn_mask.adf_addr.in4.s_addr = a->al_2; + n->ipn_mask.adf_len = offsetof(addrfamily_t, + adf_addr) + 4; + } + n->ipn_info = a->al_not; + if (a->al_next != NULL) { + n->ipn_next = calloc(1, sizeof(*n)); + n = n->ipn_next; + } + } + + bzero((char *)&pool, sizeof(pool)); + pool.ipo_unit = IPL_LOGIPF; + pool.ipo_list = top; + num = load_pool(&pool, ipfioctls[IPL_LOGLOOKUP]); + + while ((n = top) != NULL) { + top = n->ipn_next; + free(n); + } + return num; +} + + +static u_int makehash(list) +alist_t *list; +{ + iphtent_t *n, *top; + iphtable_t iph; + alist_t *a; + int num; + + if (list == NULL) + return 0; + top = calloc(1, sizeof(*top)); + if (top == NULL) + return 0; + + for (n = top, a = list; (n != NULL) && (a != NULL); a = a->al_next) { + if (a->al_family == AF_INET6) { + n->ipe_family = AF_INET6; + n->ipe_addr = a->al_i6addr; + n->ipe_mask = a->al_i6mask; + } else { + n->ipe_family = AF_INET; + n->ipe_addr.in4_addr = a->al_1; + n->ipe_mask.in4_addr = a->al_2; + } + n->ipe_value = 0; + if (a->al_next != NULL) { + n->ipe_next = calloc(1, sizeof(*n)); + n = n->ipe_next; + } + } + + bzero((char *)&iph, sizeof(iph)); + iph.iph_unit = IPL_LOGIPF; + iph.iph_type = IPHASH_LOOKUP; + *iph.iph_name = '\0'; + + if (load_hash(&iph, top, ipfioctls[IPL_LOGLOOKUP]) == 0) + sscanf(iph.iph_name, "%u", &num); + else + num = 0; + + while ((n = top) != NULL) { + top = n->ipe_next; + free(n); + } + return num; +} + + +int ipf_addrule(fd, ioctlfunc, ptr) +int fd; +ioctlfunc_t ioctlfunc; +void *ptr; +{ + ioctlcmd_t add, del; + frentry_t *fr; + ipfobj_t obj; + + if (ptr == NULL) + return 0; + + fr = ptr; + add = 0; + del = 0; + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = fr->fr_size; + obj.ipfo_type = IPFOBJ_FRENTRY; + obj.ipfo_ptr = ptr; + + if ((opts & OPT_DONOTHING) != 0) + fd = -1; + + if (opts & OPT_ZERORULEST) { + add = SIOCZRLST; + } else if (opts & OPT_INACTIVE) { + add = (u_int)fr->fr_hits ? SIOCINIFR : + SIOCADIFR; + del = SIOCRMIFR; + } else { + add = (u_int)fr->fr_hits ? SIOCINAFR : + SIOCADAFR; + del = SIOCRMAFR; + } + + if ((opts & OPT_OUTQUE) != 0) + fr->fr_flags |= FR_OUTQUE; + if (fr->fr_hits) + fr->fr_hits--; + if ((opts & OPT_VERBOSE) != 0) + printfr(fr, ioctlfunc); + + if ((opts & OPT_DEBUG) != 0) { + binprint(fr, sizeof(*fr)); + if (fr->fr_data != NULL) + binprint(fr->fr_data, fr->fr_dsize); + } + + if ((opts & OPT_ZERORULEST) != 0) { + if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + sprintf(msg, "%d:ioctl(zero rule)", + fr->fr_flineno); + return ipf_perror_fd(fd, ioctlfunc, msg); + } + } else { +#ifdef USE_QUAD_T + printf("hits %qd bytes %qd ", + (long long)fr->fr_hits, + (long long)fr->fr_bytes); +#else + printf("hits %ld bytes %ld ", + fr->fr_hits, fr->fr_bytes); +#endif + printfr(fr, ioctlfunc); + } + } else if ((opts & OPT_REMOVE) != 0) { + if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + sprintf(msg, "%d:ioctl(delete rule)", + fr->fr_flineno); + return ipf_perror_fd(fd, ioctlfunc, msg); + } + } + } else { + if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + sprintf(msg, "%d:ioctl(add/insert rule)", + fr->fr_flineno); + return ipf_perror_fd(fd, ioctlfunc, msg); + } + } + } + return 0; +} + +static void setsyslog() +{ + yysetdict(logwords); + yybreakondot = 1; +} + + +static void unsetsyslog() +{ + yyresetdict(); + yybreakondot = 0; +} + + +static void fillgroup(fr) +frentry_t *fr; +{ + frentry_t *f; + + for (f = frold; f != NULL; f = f->fr_next) { + if (f->fr_grhead == -1 && fr->fr_group == -1) + break; + if (f->fr_grhead == -1 || fr->fr_group == -1) + continue; + if (strcmp(f->fr_names + f->fr_grhead, + fr->fr_names + fr->fr_group) == 0) + break; + } + + if (f == NULL) + return; + + /* + * Only copy down matching fields if the rules are of the same type + * and are of ipf type. The only fields that are copied are those + * that impact the rule parsing itself, eg. need for knowing what the + * protocol should be for rules with port comparisons in them. + */ + if (f->fr_type != fr->fr_type || f->fr_type != FR_T_IPF) + return; + + if (fr->fr_family == 0 && f->fr_family != 0) + fr->fr_family = f->fr_family; + + if (fr->fr_mproto == 0 && f->fr_mproto != 0) + fr->fr_mproto = f->fr_mproto; + if (fr->fr_proto == 0 && f->fr_proto != 0) + fr->fr_proto = f->fr_proto; + + if ((fr->fr_mproto == 0) && ((fr->fr_flx & FI_TCPUDP) == 0) && + ((f->fr_flx & FI_TCPUDP) != 0)) { + fr->fr_flx |= FI_TCPUDP; + fr->fr_mflx |= FI_TCPUDP; + } +} + + +static void doipfexpr(line) +char *line; +{ + int *array; + char *error; + + array = parseipfexpr(line, &error); + if (array == NULL) { + fprintf(stderr, "%s:", error); + yyerror("error parsing ipf matching expression"); + return; + } + + fr->fr_type = FR_T_IPFEXPR; + fr->fr_data = array; + fr->fr_dsize = array[0] * sizeof(*array); +} + + +static void do_tuneint(varname, value) +char *varname; +int value; +{ + char buffer[80]; + + strncpy(buffer, varname, 60); + buffer[59] = '\0'; + strcat(buffer, "="); + sprintf(buffer, "%u", value); + ipf_dotuning(ipffd, buffer, ioctl); +} + + +static void do_tunestr(varname, value) +char *varname, *value; +{ + + if (!strcasecmp(value, "true")) { + do_tuneint(varname, 1); + } else if (!strcasecmp(value, "false")) { + do_tuneint(varname, 0); + } else { + yyerror("did not find true/false where expected"); + } +} + + +static void setifname(frp, idx, name) +frentry_t **frp; +int idx; +char *name; +{ + int pos; + + pos = addname(frp, name); + if (pos == -1) + return; + (*frp)->fr_ifnames[idx] = pos; +} + + +static int addname(frp, name) +frentry_t **frp; +char *name; +{ + frentry_t *f; + int nlen; + int pos; + + nlen = strlen(name) + 1; + f = realloc(*frp, (*frp)->fr_size + nlen); + if (*frp == frc) + frc = f; + *frp = f; + if (f == NULL) + return -1; + if (f->fr_pnext != NULL) + *f->fr_pnext = f; + f->fr_size += nlen; + pos = f->fr_namelen; + f->fr_namelen += nlen; + strcpy(f->fr_names + pos, name); + f->fr_names[f->fr_namelen] = '\0'; + return pos; +} + + +static frentry_t *allocfr() +{ + frentry_t *fr; + + fr = calloc(1, sizeof(*fr)); + if (fr != NULL) { + fr->fr_size = sizeof(*fr); + fr->fr_comment = -1; + fr->fr_group = -1; + fr->fr_grhead = -1; + fr->fr_icmphead = -1; + fr->fr_ifnames[0] = -1; + fr->fr_ifnames[1] = -1; + fr->fr_ifnames[2] = -1; + fr->fr_ifnames[3] = -1; + fr->fr_tif.fd_name = -1; + fr->fr_rif.fd_name = -1; + fr->fr_dif.fd_name = -1; + } + return fr; +} + + +static void setgroup(frp, name) +frentry_t **frp; +char *name; +{ + int pos; + + pos = addname(frp, name); + if (pos == -1) + return; + (*frp)->fr_group = pos; +} + + +static void setgrhead(frp, name) +frentry_t **frp; +char *name; +{ + int pos; + + pos = addname(frp, name); + if (pos == -1) + return; + (*frp)->fr_grhead = pos; +} + + +static void seticmphead(frp, name) +frentry_t **frp; +char *name; +{ + int pos; + + pos = addname(frp, name); + if (pos == -1) + return; + (*frp)->fr_icmphead = pos; +} + + +static void +build_dstaddr_af(fp, ptr) + frentry_t *fp; + void *ptr; +{ + struct ipp_s *ipp = ptr; + frentry_t *f = fp; + + if (f->fr_family != AF_UNSPEC && ipp->f == AF_UNSPEC) { + ipp->f = f->fr_family; + ipp->v = f->fr_ip.fi_v; + } + if (ipp->f == AF_INET) + ipp->v = 4; + else if (ipp->f == AF_INET6) + ipp->v = 6; + + for (; f != NULL; f = f->fr_next) { + f->fr_ip.fi_dst = ipp->a; + f->fr_mip.fi_dst = ipp->m; + f->fr_family = ipp->f; + f->fr_ip.fi_v = ipp->v; + f->fr_mip.fi_v = 0xf; + f->fr_datype = ipp->type; + if (ipp->ifpos != -1) + f->fr_ipf->fri_difpidx = ipp->ifpos; + } + fr = NULL; +} + + +static void +build_srcaddr_af(fp, ptr) + frentry_t *fp; + void *ptr; +{ + struct ipp_s *ipp = ptr; + frentry_t *f = fp; + + if (f->fr_family != AF_UNSPEC && ipp->f == AF_UNSPEC) { + ipp->f = f->fr_family; + ipp->v = f->fr_ip.fi_v; + } + if (ipp->f == AF_INET) + ipp->v = 4; + else if (ipp->f == AF_INET6) + ipp->v = 6; + + for (; f != NULL; f = f->fr_next) { + f->fr_ip.fi_src = ipp->a; + f->fr_mip.fi_src = ipp->m; + f->fr_family = ipp->f; + f->fr_ip.fi_v = ipp->v; + f->fr_mip.fi_v = 0xf; + f->fr_satype = ipp->type; + f->fr_ipf->fri_sifpidx = ipp->ifpos; + } + fr = NULL; +} diff --git a/contrib/ipfilter/tools/ipfcomp.c b/contrib/ipfilter/tools/ipfcomp.c new file mode 100644 index 0000000..eba28ce --- /dev/null +++ b/contrib/ipfilter/tools/ipfcomp.c @@ -0,0 +1,1374 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#include "ipf.h" + + +typedef struct { + int c; + int e; + int n; + int p; + int s; +} mc_t; + + +static char *portcmp[] = { "*", "==", "!=", "<", ">", "<=", ">=", "**", "***" }; +static int count = 0; + +int intcmp __P((const void *, const void *)); +static void indent __P((FILE *, int)); +static void printeq __P((FILE *, char *, int, int, int)); +static void printipeq __P((FILE *, char *, int, int, int)); +static void addrule __P((FILE *, frentry_t *)); +static void printhooks __P((FILE *, int, int, frgroup_t *)); +static void emitheader __P((frgroup_t *, u_int, u_int)); +static void emitGroup __P((int, int, void *, frentry_t *, char *, + u_int, u_int)); +static void emittail __P((void)); +static void printCgroup __P((int, frentry_t *, mc_t *, char *)); + +#define FRC_IFN 0 +#define FRC_V 1 +#define FRC_P 2 +#define FRC_FL 3 +#define FRC_TOS 4 +#define FRC_TTL 5 +#define FRC_SRC 6 +#define FRC_DST 7 +#define FRC_TCP 8 +#define FRC_SP 9 +#define FRC_DP 10 +#define FRC_OPT 11 +#define FRC_SEC 12 +#define FRC_ATH 13 +#define FRC_ICT 14 +#define FRC_ICC 15 +#define FRC_MAX 16 + + +static FILE *cfile = NULL; + +/* + * This is called once per filter rule being loaded to emit data structures + * required. + */ +void printc(fr) + frentry_t *fr; +{ + fripf_t *ipf; + u_long *ulp; + char *and; + FILE *fp; + int i; + + if (fr->fr_family == 6) + return; + if ((fr->fr_type != FR_T_IPF) && (fr->fr_type != FR_T_NONE)) + return; + if ((fr->fr_type == FR_T_IPF) && + ((fr->fr_datype != FRI_NORMAL) || (fr->fr_satype != FRI_NORMAL))) + return; + ipf = fr->fr_ipf; + + if (cfile == NULL) + cfile = fopen("ip_rules.c", "w"); + if (cfile == NULL) + return; + fp = cfile; + if (count == 0) { + fprintf(fp, "/*\n"); + fprintf(fp, "* Copyright (C) 2012 by Darren Reed.\n"); + fprintf(fp, "*\n"); + fprintf(fp, "* Redistribution and use in source and binary forms are permitted\n"); + fprintf(fp, "* provided that this notice is preserved and due credit is given\n"); + fprintf(fp, "* to the original author and the contributors.\n"); + fprintf(fp, "*/\n\n"); + + fprintf(fp, "#include <sys/param.h>\n"); + fprintf(fp, "#include <sys/types.h>\n"); + fprintf(fp, "#include <sys/time.h>\n"); + fprintf(fp, "#include <sys/socket.h>\n"); + fprintf(fp, "#if (__FreeBSD_version >= 40000)\n"); + fprintf(fp, "# if defined(_KERNEL)\n"); + fprintf(fp, "# include <sys/libkern.h>\n"); + fprintf(fp, "# else\n"); + fprintf(fp, "# include <sys/unistd.h>\n"); + fprintf(fp, "# endif\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "#if (__NetBSD_Version__ >= 399000000)\n"); + fprintf(fp, "#else\n"); + fprintf(fp, "# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n"); + fprintf(fp, "# include <sys/systm.h>\n"); + fprintf(fp, "# endif\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "#include <sys/errno.h>\n"); + fprintf(fp, "#include <sys/param.h>\n"); + fprintf(fp, +"#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n"); + fprintf(fp, "# include <sys/mbuf.h>\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, +"#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n"); + fprintf(fp, "# include <sys/sockio.h>\n"); + fprintf(fp, "#else\n"); + fprintf(fp, "# include <sys/ioctl.h>\n"); + fprintf(fp, "#endif /* FreeBSD */\n"); + fprintf(fp, "#include <net/if.h>\n"); + fprintf(fp, "#include <netinet/in.h>\n"); + fprintf(fp, "#include <netinet/in_systm.h>\n"); + fprintf(fp, "#include <netinet/ip.h>\n"); + fprintf(fp, "#include <netinet/tcp.h>\n"); + fprintf(fp, "#include \"netinet/ip_compat.h\"\n"); + fprintf(fp, "#include \"netinet/ip_fil.h\"\n\n"); + fprintf(fp, "#include \"netinet/ip_rules.h\"\n\n"); + fprintf(fp, "#ifndef _KERNEL\n"); + fprintf(fp, "# include <string.h>\n"); + fprintf(fp, "#endif /* _KERNEL */\n"); + fprintf(fp, "\n"); + fprintf(fp, "#ifdef IPFILTER_COMPILED\n"); + fprintf(fp, "\n"); + fprintf(fp, "extern ipf_main_softc_t ipfmain;\n"); + fprintf(fp, "\n"); + } + + addrule(fp, fr); + fr->fr_type |= FR_T_BUILTIN; + and = ""; + fr->fr_ref = 1; + i = sizeof(*fr); + if (i & -(1 - sizeof(*ulp))) + i += sizeof(u_long); + for (i /= sizeof(u_long), ulp = (u_long *)fr; i > 0; i--) { + fprintf(fp, "%s%#lx", and, *ulp++); + and = ", "; + } + fprintf(fp, "\n};\n"); + fr->fr_type &= ~FR_T_BUILTIN; + + count++; + + fflush(fp); +} + + +static frgroup_t *groups = NULL; + + +static void addrule(fp, fr) + FILE *fp; + frentry_t *fr; +{ + frentry_t *f, **fpp; + frgroup_t *g; + u_long *ulp; + char *ghead; + char *gname; + char *and; + int i; + + f = (frentry_t *)malloc(sizeof(*f)); + bcopy((char *)fr, (char *)f, sizeof(*fr)); + if (fr->fr_ipf) { + f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf)); + bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf, + sizeof(*fr->fr_ipf)); + } + + f->fr_next = NULL; + gname = FR_NAME(fr, fr_group); + + for (g = groups; g != NULL; g = g->fg_next) + if ((strncmp(g->fg_name, gname, FR_GROUPLEN) == 0) && + (g->fg_flags == (f->fr_flags & FR_INOUT))) + break; + + if (g == NULL) { + g = (frgroup_t *)calloc(1, sizeof(*g)); + g->fg_next = groups; + groups = g; + g->fg_head = f; + strncpy(g->fg_name, gname, FR_GROUPLEN); + g->fg_ref = 0; + g->fg_flags = f->fr_flags & FR_INOUT; + } + + for (fpp = &g->fg_start; *fpp != NULL; ) + fpp = &((*fpp)->fr_next); + *fpp = f; + + if (fr->fr_dsize > 0) { + fprintf(fp, "\ +static u_long ipf%s_rule_data_%s_%u[] = {\n", + f->fr_flags & FR_INQUE ? "in" : "out", + g->fg_name, g->fg_ref); + and = ""; + i = fr->fr_dsize; + ulp = fr->fr_data; + for (i /= sizeof(u_long); i > 0; i--) { + fprintf(fp, "%s%#lx", and, *ulp++); + and = ", "; + } + fprintf(fp, "\n};\n"); + } + + fprintf(fp, "\nstatic u_long %s_rule_%s_%d[] = {\n", + f->fr_flags & FR_INQUE ? "in" : "out", g->fg_name, g->fg_ref); + + g->fg_ref++; + + if (f->fr_grhead != -1) { + ghead = FR_NAME(f, fr_grhead); + for (g = groups; g != NULL; g = g->fg_next) + if ((strncmp(g->fg_name, ghead, FR_GROUPLEN) == 0) && + g->fg_flags == (f->fr_flags & FR_INOUT)) + break; + if (g == NULL) { + g = (frgroup_t *)calloc(1, sizeof(*g)); + g->fg_next = groups; + groups = g; + g->fg_head = f; + strncpy(g->fg_name, ghead, FR_GROUPLEN); + g->fg_ref = 0; + g->fg_flags = f->fr_flags & FR_INOUT; + } + } +} + + +int intcmp(c1, c2) + const void *c1, *c2; +{ + const mc_t *i1 = (const mc_t *)c1, *i2 = (const mc_t *)c2; + + if (i1->n == i2->n) { + return i1->c - i2->c; + } + return i2->n - i1->n; +} + + +static void indent(fp, in) + FILE *fp; + int in; +{ + for (; in; in--) + fputc('\t', fp); +} + +static void printeq(fp, var, m, max, v) + FILE *fp; + char *var; + int m, max, v; +{ + if (m == max) + fprintf(fp, "%s == %#x) {\n", var, v); + else + fprintf(fp, "(%s & %#x) == %#x) {\n", var, m, v); +} + +/* + * Parameters: var - IP# being compared + * fl - 0 for positive match, 1 for negative match + * m - netmask + * v - required address + */ +static void printipeq(fp, var, fl, m, v) + FILE *fp; + char *var; + int fl, m, v; +{ + if (m == 0xffffffff) + fprintf(fp, "%s ", var); + else + fprintf(fp, "(%s & %#x) ", var, m); + fprintf(fp, "%c", fl ? '!' : '='); + fprintf(fp, "= %#x) {\n", v); +} + + +void emit(num, dir, v, fr) + int num, dir; + void *v; + frentry_t *fr; +{ + u_int incnt, outcnt; + frgroup_t *g; + frentry_t *f; + + for (g = groups; g != NULL; g = g->fg_next) { + if (dir == 0 || dir == -1) { + if ((g->fg_flags & FR_INQUE) == 0) + continue; + for (incnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + incnt++; + emitGroup(num, dir, v, fr, g->fg_name, incnt, 0); + } + if (dir == 1 || dir == -1) { + if ((g->fg_flags & FR_OUTQUE) == 0) + continue; + for (outcnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + outcnt++; + emitGroup(num, dir, v, fr, g->fg_name, 0, outcnt); + } + } + + if (num == -1 && dir == -1) { + for (g = groups; g != NULL; g = g->fg_next) { + if ((g->fg_flags & FR_INQUE) != 0) { + for (incnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + incnt++; + if (incnt > 0) + emitheader(g, incnt, 0); + } + if ((g->fg_flags & FR_OUTQUE) != 0) { + for (outcnt = 0, f = g->fg_start; f != NULL; + f = f->fr_next) + outcnt++; + if (outcnt > 0) + emitheader(g, 0, outcnt); + } + } + emittail(); + fprintf(cfile, "#endif /* IPFILTER_COMPILED */\n"); + } + +} + + +static void emitheader(grp, incount, outcount) + frgroup_t *grp; + u_int incount, outcount; +{ + static FILE *fph = NULL; + frgroup_t *g; + + if (fph == NULL) { + fph = fopen("ip_rules.h", "w"); + if (fph == NULL) + return; + + fprintf(fph, "extern int ipfrule_add __P((void));\n"); + fprintf(fph, "extern int ipfrule_remove __P((void));\n"); + } + + printhooks(cfile, incount, outcount, grp); + + if (incount) { + fprintf(fph, "\n\ +extern frentry_t *ipfrule_match_in_%s __P((fr_info_t *, u_32_t *));\n\ +extern frentry_t *ipf_rules_in_%s[%d];\n", + grp->fg_name, grp->fg_name, incount); + + for (g = groups; g != grp; g = g->fg_next) + if ((strncmp(g->fg_name, grp->fg_name, + FR_GROUPLEN) == 0) && + g->fg_flags == grp->fg_flags) + break; + if (g == grp) { + fprintf(fph, "\n\ +extern int ipfrule_add_in_%s __P((void));\n\ +extern int ipfrule_remove_in_%s __P((void));\n", grp->fg_name, grp->fg_name); + } + } + if (outcount) { + fprintf(fph, "\n\ +extern frentry_t *ipfrule_match_out_%s __P((fr_info_t *, u_32_t *));\n\ +extern frentry_t *ipf_rules_out_%s[%d];\n", + grp->fg_name, grp->fg_name, outcount); + + for (g = groups; g != grp; g = g->fg_next) + if ((strncmp(g->fg_name, grp->fg_name, + FR_GROUPLEN) == 0) && + g->fg_flags == grp->fg_flags) + break; + if (g == grp) { + fprintf(fph, "\n\ +extern int ipfrule_add_out_%s __P((void));\n\ +extern int ipfrule_remove_out_%s __P((void));\n", + grp->fg_name, grp->fg_name); + } + } +} + +static void emittail() +{ + frgroup_t *g; + + fprintf(cfile, "\n\ +int ipfrule_add()\n\ +{\n\ + int err;\n\ +\n"); + for (g = groups; g != NULL; g = g->fg_next) + fprintf(cfile, "\ + err = ipfrule_add_%s_%s();\n\ + if (err != 0)\n\ + return err;\n", + (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); + fprintf(cfile, "\ + return 0;\n"); + fprintf(cfile, "}\n\ +\n"); + + fprintf(cfile, "\n\ +int ipfrule_remove()\n\ +{\n\ + int err;\n\ +\n"); + for (g = groups; g != NULL; g = g->fg_next) + fprintf(cfile, "\ + err = ipfrule_remove_%s_%s();\n\ + if (err != 0)\n\ + return err;\n", + (g->fg_flags & FR_INQUE) ? "in" : "out", g->fg_name); + fprintf(cfile, "\ + return 0;\n"); + fprintf(cfile, "}\n"); +} + + +static void emitGroup(num, dir, v, fr, group, incount, outcount) + int num, dir; + void *v; + frentry_t *fr; + char *group; + u_int incount, outcount; +{ + static FILE *fp = NULL; + static int header[2] = { 0, 0 }; + static char egroup[FR_GROUPLEN] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static int openfunc = 0; + static mc_t *n = NULL; + static int sin = 0; + frentry_t *f; + frgroup_t *g; + fripf_t *ipf; + int i, in, j; + mc_t *m = v; + + if (fp == NULL) + fp = cfile; + if (fp == NULL) + return; + if (strncmp(egroup, group, FR_GROUPLEN)) { + for (sin--; sin > 0; sin--) { + indent(fp, sin); + fprintf(fp, "}\n"); + } + if (openfunc == 1) { + fprintf(fp, "\treturn fr;\n}\n"); + openfunc = 0; + if (n != NULL) { + free(n); + n = NULL; + } + } + sin = 0; + header[0] = 0; + header[1] = 0; + strncpy(egroup, group, FR_GROUPLEN); + } else if (openfunc == 1 && num < 0) { + if (n != NULL) { + free(n); + n = NULL; + } + for (sin--; sin > 0; sin--) { + indent(fp, sin); + fprintf(fp, "}\n"); + } + if (openfunc == 1) { + fprintf(fp, "\treturn fr;\n}\n"); + openfunc = 0; + } + } + + if (dir == -1) + return; + + for (g = groups; g != NULL; g = g->fg_next) { + if (dir == 0 && (g->fg_flags & FR_INQUE) == 0) + continue; + else if (dir == 1 && (g->fg_flags & FR_OUTQUE) == 0) + continue; + if (strncmp(g->fg_name, group, FR_GROUPLEN) != 0) + continue; + break; + } + + /* + * Output the array of pointers to rules for this group. + */ + if (g != NULL && num == -2 && dir == 0 && header[0] == 0 && + incount != 0) { + fprintf(fp, "\nfrentry_t *ipf_rules_in_%s[%d] = {", + group, incount); + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if ((f->fr_flags & FR_INQUE) == 0) + continue; + if ((i & 1) == 0) { + fprintf(fp, "\n\t"); + } + fprintf(fp, "(frentry_t *)&in_rule_%s_%d", + FR_NAME(f, fr_group), i); + if (i + 1 < incount) + fprintf(fp, ", "); + i++; + } + fprintf(fp, "\n};\n"); + } + + if (g != NULL && num == -2 && dir == 1 && header[0] == 0 && + outcount != 0) { + fprintf(fp, "\nfrentry_t *ipf_rules_out_%s[%d] = {", + group, outcount); + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if ((f->fr_flags & FR_OUTQUE) == 0) + continue; + if ((i & 1) == 0) { + fprintf(fp, "\n\t"); + } + fprintf(fp, "(frentry_t *)&out_rule_%s_%d", + FR_NAME(f, fr_group), i); + if (i + 1 < outcount) + fprintf(fp, ", "); + i++; + } + fprintf(fp, "\n};\n"); + fp = NULL; + } + + if (num < 0) + return; + + in = 0; + ipf = fr->fr_ipf; + + /* + * If the function header has not been printed then print it now. + */ + if (g != NULL && header[dir] == 0) { + int pdst = 0, psrc = 0; + + openfunc = 1; + fprintf(fp, "\nfrentry_t *ipfrule_match_%s_%s(fin, passp)\n", + (dir == 0) ? "in" : "out", group); + fprintf(fp, "fr_info_t *fin;\n"); + fprintf(fp, "u_32_t *passp;\n"); + fprintf(fp, "{\n"); + fprintf(fp, "\tfrentry_t *fr = NULL;\n"); + + /* + * Print out any variables that need to be declared. + */ + for (f = g->fg_start, i = 0; f != NULL; f = f->fr_next) { + if (incount + outcount > m[FRC_SRC].e + 1) + psrc = 1; + if (incount + outcount > m[FRC_DST].e + 1) + pdst = 1; + } + if (psrc == 1) + fprintf(fp, "\tu_32_t src = ntohl(%s);\n", + "fin->fin_fi.fi_saddr"); + if (pdst == 1) + fprintf(fp, "\tu_32_t dst = ntohl(%s);\n", + "fin->fin_fi.fi_daddr"); + } + + for (i = 0; i < FRC_MAX; i++) { + switch(m[i].c) + { + case FRC_IFN : + if (fr->fr_ifnames[0] != -1) + m[i].s = 1; + break; + case FRC_V : + if (ipf != NULL && ipf->fri_mip.fi_v != 0) + m[i].s = 1; + break; + case FRC_FL : + if (ipf != NULL && ipf->fri_mip.fi_flx != 0) + m[i].s = 1; + break; + case FRC_P : + if (ipf != NULL && ipf->fri_mip.fi_p != 0) + m[i].s = 1; + break; + case FRC_TTL : + if (ipf != NULL && ipf->fri_mip.fi_ttl != 0) + m[i].s = 1; + break; + case FRC_TOS : + if (ipf != NULL && ipf->fri_mip.fi_tos != 0) + m[i].s = 1; + break; + case FRC_TCP : + if (ipf == NULL) + break; + if ((ipf->fri_ip.fi_p == IPPROTO_TCP) && + fr->fr_tcpfm != 0) + m[i].s = 1; + break; + case FRC_SP : + if (ipf == NULL) + break; + if (fr->fr_scmp == FR_INRANGE) + m[i].s = 1; + else if (fr->fr_scmp == FR_OUTRANGE) + m[i].s = 1; + else if (fr->fr_scmp != 0) + m[i].s = 1; + break; + case FRC_DP : + if (ipf == NULL) + break; + if (fr->fr_dcmp == FR_INRANGE) + m[i].s = 1; + else if (fr->fr_dcmp == FR_OUTRANGE) + m[i].s = 1; + else if (fr->fr_dcmp != 0) + m[i].s = 1; + break; + case FRC_SRC : + if (ipf == NULL) + break; + if (fr->fr_satype == FRI_LOOKUP) { + ; + } else if ((fr->fr_smask != 0) || + (fr->fr_flags & FR_NOTSRCIP) != 0) + m[i].s = 1; + break; + case FRC_DST : + if (ipf == NULL) + break; + if (fr->fr_datype == FRI_LOOKUP) { + ; + } else if ((fr->fr_dmask != 0) || + (fr->fr_flags & FR_NOTDSTIP) != 0) + m[i].s = 1; + break; + case FRC_OPT : + if (ipf == NULL) + break; + if (fr->fr_optmask != 0) + m[i].s = 1; + break; + case FRC_SEC : + if (ipf == NULL) + break; + if (fr->fr_secmask != 0) + m[i].s = 1; + break; + case FRC_ATH : + if (ipf == NULL) + break; + if (fr->fr_authmask != 0) + m[i].s = 1; + break; + case FRC_ICT : + if (ipf == NULL) + break; + if ((fr->fr_icmpm & 0xff00) != 0) + m[i].s = 1; + break; + case FRC_ICC : + if (ipf == NULL) + break; + if ((fr->fr_icmpm & 0xff) != 0) + m[i].s = 1; + break; + } + } + + if (!header[dir]) { + fprintf(fp, "\n"); + header[dir] = 1; + sin = 0; + } + + qsort(m, FRC_MAX, sizeof(mc_t), intcmp); + + if (n) { + /* + * Calculate the indentation interval upto the last common + * common comparison being made. + */ + for (i = 0, in = 1; i < FRC_MAX; i++) { + if (n[i].c != m[i].c) + break; + if (n[i].s != m[i].s) + break; + if (n[i].s) { + if (n[i].n && (n[i].n > n[i].e)) { + m[i].p++; + in += m[i].p; + break; + } + if (n[i].e > 0) { + in++; + } else + break; + } + } + if (sin != in) { + for (j = sin - 1; j >= in; j--) { + indent(fp, j); + fprintf(fp, "}\n"); + } + } + } else { + in = 1; + i = 0; + } + + /* + * print out C code that implements a filter rule. + */ + for (; i < FRC_MAX; i++) { + switch(m[i].c) + { + case FRC_IFN : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_ifp == "); + fprintf(fp, "ipf_rules_%s_%s[%d]->fr_ifa) {\n", + dir ? "out" : "in", group, num); + in++; + } + break; + case FRC_V : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_v == %d) {\n", + ipf->fri_ip.fi_v); + in++; + } + break; + case FRC_FL : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_flx", + ipf->fri_mip.fi_flx, 0xf, + ipf->fri_ip.fi_flx); + in++; + } + break; + case FRC_P : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_p == %d) {\n", + ipf->fri_ip.fi_p); + in++; + } + break; + case FRC_TTL : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_ttl", + ipf->fri_mip.fi_ttl, 0xff, + ipf->fri_ip.fi_ttl); + in++; + } + break; + case FRC_TOS : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if (fin->fin_tos"); + printeq(fp, "fin->fin_tos", + ipf->fri_mip.fi_tos, 0xff, + ipf->fri_ip.fi_tos); + in++; + } + break; + case FRC_TCP : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_tcpf", fr->fr_tcpfm, + 0xff, fr->fr_tcpf); + in++; + } + break; + case FRC_SP : + if (!m[i].s) + break; + if (fr->fr_scmp == FR_INRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[0] > %d) && ", + fr->fr_sport); + fprintf(fp, "(fin->fin_data[0] < %d)", + fr->fr_stop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_scmp == FR_OUTRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[0] < %d) || ", + fr->fr_sport); + fprintf(fp, "(fin->fin_data[0] > %d)", + fr->fr_stop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_scmp) { + indent(fp, in); + fprintf(fp, "if (fin->fin_data[0] %s %d)", + portcmp[fr->fr_scmp], fr->fr_sport); + fprintf(fp, " {\n"); + in++; + } + break; + case FRC_DP : + if (!m[i].s) + break; + if (fr->fr_dcmp == FR_INRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[1] > %d) && ", + fr->fr_dport); + fprintf(fp, "(fin->fin_data[1] < %d)", + fr->fr_dtop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_dcmp == FR_OUTRANGE) { + indent(fp, in); + fprintf(fp, "if ((fin->fin_data[1] < %d) || ", + fr->fr_dport); + fprintf(fp, "(fin->fin_data[1] > %d)", + fr->fr_dtop); + fprintf(fp, ") {\n"); + in++; + } else if (fr->fr_dcmp) { + indent(fp, in); + fprintf(fp, "if (fin->fin_data[1] %s %d)", + portcmp[fr->fr_dcmp], fr->fr_dport); + fprintf(fp, " {\n"); + in++; + } + break; + case FRC_SRC : + if (!m[i].s) + break; + if (fr->fr_satype == FRI_LOOKUP) { + ; + } else if ((fr->fr_smask != 0) || + (fr->fr_flags & FR_NOTSRCIP) != 0) { + indent(fp, in); + fprintf(fp, "if ("); + printipeq(fp, "src", + fr->fr_flags & FR_NOTSRCIP, + fr->fr_smask, fr->fr_saddr); + in++; + } + break; + case FRC_DST : + if (!m[i].s) + break; + if (fr->fr_datype == FRI_LOOKUP) { + ; + } else if ((fr->fr_dmask != 0) || + (fr->fr_flags & FR_NOTDSTIP) != 0) { + indent(fp, in); + fprintf(fp, "if ("); + printipeq(fp, "dst", + fr->fr_flags & FR_NOTDSTIP, + fr->fr_dmask, fr->fr_daddr); + in++; + } + break; + case FRC_OPT : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_optmsk", + fr->fr_optmask, 0xffffffff, + fr->fr_optbits); + in++; + } + break; + case FRC_SEC : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_secmsk", + fr->fr_secmask, 0xffff, + fr->fr_secbits); + in++; + } + break; + case FRC_ATH : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_fi.fi_authmsk", + fr->fr_authmask, 0xffff, + fr->fr_authbits); + in++; + } + break; + case FRC_ICT : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_data[0]", + fr->fr_icmpm & 0xff00, 0xffff, + fr->fr_icmp & 0xff00); + in++; + } + break; + case FRC_ICC : + if (m[i].s) { + indent(fp, in); + fprintf(fp, "if ("); + printeq(fp, "fin->fin_data[0]", + fr->fr_icmpm & 0xff, 0xffff, + fr->fr_icmp & 0xff); + in++; + } + break; + } + + } + + indent(fp, in); + if (fr->fr_flags & FR_QUICK) { + fprintf(fp, "return (frentry_t *)&%s_rule_%s_%d;\n", + fr->fr_flags & FR_INQUE ? "in" : "out", + FR_NAME(fr, fr_group), num); + } else { + fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n", + fr->fr_flags & FR_INQUE ? "in" : "out", + FR_NAME(fr, fr_group), num); + } + if (n == NULL) + n = (mc_t *)malloc(sizeof(*n) * FRC_MAX); + bcopy((char *)m, (char *)n, sizeof(*n) * FRC_MAX); + sin = in; +} + + +void printC(dir) + int dir; +{ + static mc_t *m = NULL; + frgroup_t *g; + + if (m == NULL) + m = (mc_t *)calloc(1, sizeof(*m) * FRC_MAX); + + for (g = groups; g != NULL; g = g->fg_next) { + if ((dir == 0) && ((g->fg_flags & FR_INQUE) != 0)) + printCgroup(dir, g->fg_start, m, g->fg_name); + if ((dir == 1) && ((g->fg_flags & FR_OUTQUE) != 0)) + printCgroup(dir, g->fg_start, m, g->fg_name); + } + + emit(-1, dir, m, NULL); +} + + +/* + * Now print out code to implement all of the rules. + */ +static void printCgroup(dir, top, m, group) + int dir; + frentry_t *top; + mc_t *m; + char *group; +{ + frentry_t *fr, *fr1; + int i, n, rn; + u_int count; + + for (count = 0, fr1 = top; fr1 != NULL; fr1 = fr1->fr_next) { + if ((dir == 0) && ((fr1->fr_flags & FR_INQUE) != 0)) + count++; + else if ((dir == 1) && ((fr1->fr_flags & FR_OUTQUE) != 0)) + count++; + } + + if (dir == 0) + emitGroup(-2, dir, m, fr1, group, count, 0); + else if (dir == 1) + emitGroup(-2, dir, m, fr1, group, 0, count); + + /* + * Before printing each rule, check to see how many of its fields are + * matched by subsequent rules. + */ + for (fr1 = top, rn = 0; fr1 != NULL; fr1 = fr1->fr_next, rn++) { + if (!dir && !(fr1->fr_flags & FR_INQUE)) + continue; + if (dir && !(fr1->fr_flags & FR_OUTQUE)) + continue; + n = 0xfffffff; + + for (i = 0; i < FRC_MAX; i++) + m[i].e = 0; + qsort(m, FRC_MAX, sizeof(mc_t), intcmp); + + for (i = 0; i < FRC_MAX; i++) { + m[i].c = i; + m[i].e = 0; + m[i].n = 0; + m[i].s = 0; + } + + for (fr = fr1->fr_next; fr; fr = fr->fr_next) { + if (!dir && !(fr->fr_flags & FR_INQUE)) + continue; + if (dir && !(fr->fr_flags & FR_OUTQUE)) + continue; + + if ((n & 0x0001) && + !strcmp(fr1->fr_names + fr1->fr_ifnames[0], + fr->fr_names + fr->fr_ifnames[0])) { + m[FRC_IFN].e++; + m[FRC_IFN].n++; + } else + n &= ~0x0001; + + if ((n & 0x0002) && (fr1->fr_family == fr->fr_family)) { + m[FRC_V].e++; + m[FRC_V].n++; + } else + n &= ~0x0002; + + if ((n & 0x0004) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_mip.fi_flx == fr->fr_mip.fi_flx) && + (fr1->fr_ip.fi_flx == fr->fr_ip.fi_flx)) { + m[FRC_FL].e++; + m[FRC_FL].n++; + } else + n &= ~0x0004; + + if ((n & 0x0008) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_proto == fr->fr_proto)) { + m[FRC_P].e++; + m[FRC_P].n++; + } else + n &= ~0x0008; + + if ((n & 0x0010) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_ttl == fr->fr_ttl)) { + m[FRC_TTL].e++; + m[FRC_TTL].n++; + } else + n &= ~0x0010; + + if ((n & 0x0020) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_tos == fr->fr_tos)) { + m[FRC_TOS].e++; + m[FRC_TOS].n++; + } else + n &= ~0x0020; + + if ((n & 0x0040) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_tcpfm == fr->fr_tcpfm) && + (fr1->fr_tcpf == fr->fr_tcpf))) { + m[FRC_TCP].e++; + m[FRC_TCP].n++; + } else + n &= ~0x0040; + + if ((n & 0x0080) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_scmp == fr->fr_scmp) && + (fr1->fr_stop == fr->fr_stop) && + (fr1->fr_sport == fr->fr_sport))) { + m[FRC_SP].e++; + m[FRC_SP].n++; + } else + n &= ~0x0080; + + if ((n & 0x0100) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_dcmp == fr->fr_dcmp) && + (fr1->fr_dtop == fr->fr_dtop) && + (fr1->fr_dport == fr->fr_dport))) { + m[FRC_DP].e++; + m[FRC_DP].n++; + } else + n &= ~0x0100; + + if ((n & 0x0200) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_satype == FRI_LOOKUP) && + (fr->fr_satype == FRI_LOOKUP) && + (fr1->fr_srcnum == fr->fr_srcnum))) { + m[FRC_SRC].e++; + m[FRC_SRC].n++; + } else if ((n & 0x0200) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (((fr1->fr_flags & FR_NOTSRCIP) == + (fr->fr_flags & FR_NOTSRCIP)))) { + if ((fr1->fr_smask == fr->fr_smask) && + (fr1->fr_saddr == fr->fr_saddr)) + m[FRC_SRC].e++; + else + n &= ~0x0200; + if (fr1->fr_smask && + (fr1->fr_saddr & fr1->fr_smask) == + (fr->fr_saddr & fr1->fr_smask)) { + m[FRC_SRC].n++; + n |= 0x0200; + } + } else { + n &= ~0x0200; + } + + if ((n & 0x0400) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_datype == FRI_LOOKUP) && + (fr->fr_datype == FRI_LOOKUP) && + (fr1->fr_dstnum == fr->fr_dstnum))) { + m[FRC_DST].e++; + m[FRC_DST].n++; + } else if ((n & 0x0400) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (((fr1->fr_flags & FR_NOTDSTIP) == + (fr->fr_flags & FR_NOTDSTIP)))) { + if ((fr1->fr_dmask == fr->fr_dmask) && + (fr1->fr_daddr == fr->fr_daddr)) + m[FRC_DST].e++; + else + n &= ~0x0400; + if (fr1->fr_dmask && + (fr1->fr_daddr & fr1->fr_dmask) == + (fr->fr_daddr & fr1->fr_dmask)) { + m[FRC_DST].n++; + n |= 0x0400; + } + } else { + n &= ~0x0400; + } + + if ((n & 0x0800) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_optmask == fr->fr_optmask) && + (fr1->fr_optbits == fr->fr_optbits)) { + m[FRC_OPT].e++; + m[FRC_OPT].n++; + } else + n &= ~0x0800; + + if ((n & 0x1000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_secmask == fr->fr_secmask) && + (fr1->fr_secbits == fr->fr_secbits)) { + m[FRC_SEC].e++; + m[FRC_SEC].n++; + } else + n &= ~0x1000; + + if ((n & 0x10000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + (fr1->fr_authmask == fr->fr_authmask) && + (fr1->fr_authbits == fr->fr_authbits)) { + m[FRC_ATH].e++; + m[FRC_ATH].n++; + } else + n &= ~0x10000; + + if ((n & 0x20000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_icmpm & 0xff00) == + (fr->fr_icmpm & 0xff00)) && + ((fr1->fr_icmp & 0xff00) == + (fr->fr_icmp & 0xff00))) { + m[FRC_ICT].e++; + m[FRC_ICT].n++; + } else + n &= ~0x20000; + + if ((n & 0x40000) && + (fr->fr_type == fr1->fr_type) && + (fr->fr_type == FR_T_IPF) && + ((fr1->fr_icmpm & 0xff) == (fr->fr_icmpm & 0xff)) && + ((fr1->fr_icmp & 0xff) == (fr->fr_icmp & 0xff))) { + m[FRC_ICC].e++; + m[FRC_ICC].n++; + } else + n &= ~0x40000; + } + /*msort(m);*/ + + if (dir == 0) + emitGroup(rn, dir, m, fr1, group, count, 0); + else if (dir == 1) + emitGroup(rn, dir, m, fr1, group, 0, count); + } +} + +static void printhooks(fp, in, out, grp) + FILE *fp; + int in; + int out; + frgroup_t *grp; +{ + frentry_t *fr; + char *group; + int dogrp, i; + char *instr; + + group = grp->fg_name; + dogrp = 0; + + if (in && out) { + fprintf(stderr, + "printhooks called with both in and out set\n"); + exit(1); + } + + if (in) { + instr = "in"; + } else if (out) { + instr = "out"; + } else { + instr = "???"; + } + fprintf(fp, "static frentry_t ipfrule_%s_%s;\n", instr, group); + + fprintf(fp, "\ +\n\ +int ipfrule_add_%s_%s()\n", instr, group); + fprintf(fp, "\ +{\n\ + int i, j, err = 0, max;\n\ + frentry_t *fp;\n"); + + if (dogrp) + fprintf(fp, "\ + frgroup_t *fg;\n"); + + fprintf(fp, "\n"); + + for (i = 0, fr = grp->fg_start; fr != NULL; i++, fr = fr->fr_next) + if (fr->fr_dsize > 0) { + fprintf(fp, "\ + ipf_rules_%s_%s[%d]->fr_data = &ipf%s_rule_data_%s_%u;\n", + instr, grp->fg_name, i, + instr, grp->fg_name, i); + } + fprintf(fp, "\ + max = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *);\n\ + for (i = 0; i < max; i++) {\n\ + fp = ipf_rules_%s_%s[i];\n\ + fp->fr_next = NULL;\n", instr, group, instr, group); + + fprintf(fp, "\ + for (j = i + 1; j < max; j++)\n\ + if (strncmp(fp->fr_names + fp->fr_group,\n\ + ipf_rules_%s_%s[j]->fr_names +\n\ + ipf_rules_%s_%s[j]->fr_group,\n\ + FR_GROUPLEN) == 0) {\n\ + if (ipf_rules_%s_%s[j] != NULL)\n\ + ipf_rules_%s_%s[j]->fr_pnext =\n\ + &fp->fr_next;\n\ + fp->fr_pnext = &ipf_rules_%s_%s[j];\n\ + fp->fr_next = ipf_rules_%s_%s[j];\n\ + break;\n\ + }\n", instr, group, instr, group, instr, group, + instr, group, instr, group, instr, group); + if (dogrp) + fprintf(fp, "\ +\n\ + if (fp->fr_grhead != -1) {\n\ + fg = fr_addgroup(fp->fr_names + fp->fr_grhead,\n\ + fp, FR_INQUE, IPL_LOGIPF, 0);\n\ + if (fg != NULL)\n\ + fp->fr_grp = &fg->fg_start;\n\ + }\n"); + fprintf(fp, "\ + }\n\ +\n\ + fp = &ipfrule_%s_%s;\n", instr, group); + fprintf(fp, "\ + bzero((char *)fp, sizeof(*fp));\n\ + fp->fr_type = FR_T_CALLFUNC_BUILTIN;\n\ + fp->fr_flags = FR_%sQUE|FR_NOMATCH;\n\ + fp->fr_data = (void *)ipf_rules_%s_%s[0];\n", + (in != 0) ? "IN" : "OUT", instr, group); + fprintf(fp, "\ + fp->fr_dsize = sizeof(ipf_rules_%s_%s[0]);\n", + instr, group); + + fprintf(fp, "\ + fp->fr_family = AF_INET;\n\ + fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\ + err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,\n\ + ipfmain.ipf_active, 0);\n", + instr, group); + fprintf(fp, "\treturn err;\n}\n"); + + fprintf(fp, "\n\n\ +int ipfrule_remove_%s_%s()\n", instr, group); + fprintf(fp, "\ +{\n\ + int err = 0, i;\n\ + frentry_t *fp;\n\ +\n\ + /*\n\ + * Try to remove the %sbound rule.\n", instr); + + fprintf(fp, "\ + */\n\ + if (ipfrule_%s_%s.fr_ref > 0) {\n", instr, group); + + fprintf(fp, "\ + err = EBUSY;\n\ + } else {\n"); + + fprintf(fp, "\ + i = sizeof(ipf_rules_%s_%s)/sizeof(frentry_t *) - 1;\n\ + for (; i >= 0; i--) {\n\ + fp = ipf_rules_%s_%s[i];\n\ + if (fp->fr_ref > 1) {\n\ + err = EBUSY;\n\ + break;\n\ + }\n\ + }\n\ + }\n\ + if (err == 0)\n\ + err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,\n\ + (caddr_t)&ipfrule_%s_%s,\n\ + ipfmain.ipf_active, 0);\n", + instr, group, instr, group, instr, group); + fprintf(fp, "\ + if (err)\n\ + return err;\n\ +\n\n"); + + fprintf(fp, "\treturn err;\n}\n"); +} diff --git a/contrib/ipfilter/tools/ipfs.c b/contrib/ipfilter/tools/ipfs.c new file mode 100644 index 0000000..43abd74 --- /dev/null +++ b/contrib/ipfilter/tools/ipfs.c @@ -0,0 +1,881 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#ifdef __FreeBSD__ +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +#endif +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#if !defined(__SVR4) && !defined(__GNUC__) +#include <strings.h> +#endif +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#include <stdlib.h> +#include <stddef.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <sys/time.h> +#include <net/if.h> +#include <netinet/ip.h> +#include <netdb.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include "ipf.h" +#include "netinet/ipl.h" + +#if !defined(lint) +static const char rcsid[] = "@(#)$Id$"; +#endif + +#ifndef IPF_SAVEDIR +# define IPF_SAVEDIR "/var/db/ipf" +#endif +#ifndef IPF_NATFILE +# define IPF_NATFILE "ipnat.ipf" +#endif +#ifndef IPF_STATEFILE +# define IPF_STATEFILE "ipstate.ipf" +#endif + +#if !defined(__SVR4) && defined(__GNUC__) +extern char *index __P((const char *, int)); +#endif + +extern char *optarg; +extern int optind; + +int main __P((int, char *[])); +void usage __P((void)); +int changestateif __P((char *, char *)); +int changenatif __P((char *, char *)); +int readstate __P((int, char *)); +int readnat __P((int, char *)); +int writestate __P((int, char *)); +int opendevice __P((char *)); +void closedevice __P((int)); +int setlock __P((int, int)); +int writeall __P((char *)); +int readall __P((char *)); +int writenat __P((int, char *)); + +int opts = 0; +char *progname; + + +void usage() +{ + fprintf(stderr, "usage: %s [-nv] -l\n", progname); + fprintf(stderr, "usage: %s [-nv] -u\n", progname); + fprintf(stderr, "usage: %s [-nv] [-d <dir>] -R\n", progname); + fprintf(stderr, "usage: %s [-nv] [-d <dir>] -W\n", progname); + fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -r\n", progname); + fprintf(stderr, "usage: %s [-nNSv] [-f <file>] -w\n", progname); + fprintf(stderr, "usage: %s [-nNSv] -f <filename> -i <if1>,<if2>\n", + progname); + exit(1); +} + + +/* + * Change interface names in state information saved out to disk. + */ +int changestateif(ifs, fname) + char *ifs, *fname; +{ + int fd, olen, nlen, rw; + ipstate_save_t ips; + off_t pos; + char *s; + + s = strchr(ifs, ','); + if (!s) + usage(); + *s++ = '\0'; + nlen = strlen(s); + olen = strlen(ifs); + if (nlen >= sizeof(ips.ips_is.is_ifname) || + olen >= sizeof(ips.ips_is.is_ifname)) + usage(); + + fd = open(fname, O_RDWR); + if (fd == -1) { + perror("open"); + exit(1); + } + + for (pos = 0; read(fd, &ips, sizeof(ips)) == sizeof(ips); ) { + rw = 0; + if (!strncmp(ips.ips_is.is_ifname[0], ifs, olen + 1)) { + strcpy(ips.ips_is.is_ifname[0], s); + rw = 1; + } + if (!strncmp(ips.ips_is.is_ifname[1], ifs, olen + 1)) { + strcpy(ips.ips_is.is_ifname[1], s); + rw = 1; + } + if (!strncmp(ips.ips_is.is_ifname[2], ifs, olen + 1)) { + strcpy(ips.ips_is.is_ifname[2], s); + rw = 1; + } + if (!strncmp(ips.ips_is.is_ifname[3], ifs, olen + 1)) { + strcpy(ips.ips_is.is_ifname[3], s); + rw = 1; + } + if (rw == 1) { + if (lseek(fd, pos, SEEK_SET) != pos) { + perror("lseek"); + exit(1); + } + if (write(fd, &ips, sizeof(ips)) != sizeof(ips)) { + perror("write"); + exit(1); + } + } + pos = lseek(fd, 0, SEEK_CUR); + } + close(fd); + + return 0; +} + + +/* + * Change interface names in NAT information saved out to disk. + */ +int changenatif(ifs, fname) + char *ifs, *fname; +{ + int fd, olen, nlen, rw; + nat_save_t ipn; + nat_t *nat; + off_t pos; + char *s; + + s = strchr(ifs, ','); + if (!s) + usage(); + *s++ = '\0'; + nlen = strlen(s); + olen = strlen(ifs); + nat = &ipn.ipn_nat; + if (nlen >= sizeof(nat->nat_ifnames[0]) || + olen >= sizeof(nat->nat_ifnames[0])) + usage(); + + fd = open(fname, O_RDWR); + if (fd == -1) { + perror("open"); + exit(1); + } + + for (pos = 0; read(fd, &ipn, sizeof(ipn)) == sizeof(ipn); ) { + rw = 0; + if (!strncmp(nat->nat_ifnames[0], ifs, olen + 1)) { + strcpy(nat->nat_ifnames[0], s); + rw = 1; + } + if (!strncmp(nat->nat_ifnames[1], ifs, olen + 1)) { + strcpy(nat->nat_ifnames[1], s); + rw = 1; + } + if (rw == 1) { + if (lseek(fd, pos, SEEK_SET) != pos) { + perror("lseek"); + exit(1); + } + if (write(fd, &ipn, sizeof(ipn)) != sizeof(ipn)) { + perror("write"); + exit(1); + } + } + pos = lseek(fd, 0, SEEK_CUR); + } + close(fd); + + return 0; +} + + +int main(argc,argv) + int argc; + char *argv[]; +{ + int c, lock = -1, devfd = -1, err = 0, rw = -1, ns = -1, set = 0; + char *dirname = NULL, *filename = NULL, *ifs = NULL; + + progname = argv[0]; + while ((c = getopt(argc, argv, "d:f:i:lNnSRruvWw")) != -1) + switch (c) + { + case 'd' : + if ((set == 0) && !dirname && !filename) + dirname = optarg; + else + usage(); + break; + case 'f' : + if ((set != 0) && !dirname && !filename) + filename = optarg; + else + usage(); + break; + case 'i' : + ifs = optarg; + set = 1; + break; + case 'l' : + if (filename || dirname || set) + usage(); + lock = 1; + set = 1; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'N' : + if ((ns >= 0) || dirname || (rw != -1) || set) + usage(); + ns = 0; + set = 1; + break; + case 'r' : + if (dirname || (rw != -1) || (ns == -1)) + usage(); + rw = 0; + set = 1; + break; + case 'R' : + rw = 2; + set = 1; + break; + case 'S' : + if ((ns >= 0) || dirname || (rw != -1) || set) + usage(); + ns = 1; + set = 1; + break; + case 'u' : + if (filename || dirname || set) + usage(); + lock = 0; + set = 1; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + case 'w' : + if (dirname || (rw != -1) || (ns == -1)) + usage(); + rw = 1; + set = 1; + break; + case 'W' : + rw = 3; + set = 1; + break; + case '?' : + default : + usage(); + } + + if (ifs) { + if (!filename || ns < 0) + usage(); + if (ns == 0) + return changenatif(ifs, filename); + else + return changestateif(ifs, filename); + } + + if ((ns >= 0) || (lock >= 0)) { + if (lock >= 0) + devfd = opendevice(NULL); + else if (ns >= 0) { + if (ns == 1) + devfd = opendevice(IPSTATE_NAME); + else if (ns == 0) + devfd = opendevice(IPNAT_NAME); + } + if (devfd == -1) + exit(1); + } + + if (lock >= 0) + err = setlock(devfd, lock); + else if (rw >= 0) { + if (rw & 1) { /* WRITE */ + if (rw & 2) + err = writeall(dirname); + else { + if (ns == 0) + err = writenat(devfd, filename); + else if (ns == 1) + err = writestate(devfd, filename); + } + } else { + if (rw & 2) + err = readall(dirname); + else { + if (ns == 0) + err = readnat(devfd, filename); + else if (ns == 1) + err = readstate(devfd, filename); + } + } + } + return err; +} + + +int opendevice(ipfdev) + char *ipfdev; +{ + int fd = -1; + + if (opts & OPT_DONOTHING) + return -2; + + if (!ipfdev) + ipfdev = IPL_NAME; + + if ((fd = open(ipfdev, O_RDWR)) == -1) + if ((fd = open(ipfdev, O_RDONLY)) == -1) + perror("open device"); + return fd; +} + + +void closedevice(fd) + int fd; +{ + close(fd); +} + + +int setlock(fd, lock) + int fd, lock; +{ + if (opts & OPT_VERBOSE) + printf("Turn lock %s\n", lock ? "on" : "off"); + if (!(opts & OPT_DONOTHING)) { + if (ioctl(fd, SIOCSTLCK, &lock) == -1) { + perror("SIOCSTLCK"); + return 1; + } + if (opts & OPT_VERBOSE) + printf("Lock now %s\n", lock ? "on" : "off"); + } + return 0; +} + + +int writestate(fd, file) + int fd; + char *file; +{ + ipstate_save_t ips, *ipsp; + ipfobj_t obj; + int wfd = -1; + + if (!file) + file = IPF_STATEFILE; + + wfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); + if (wfd == -1) { + fprintf(stderr, "%s ", file); + perror("state:open"); + return 1; + } + + ipsp = &ips; + bzero((char *)&obj, sizeof(obj)); + bzero((char *)ipsp, sizeof(ips)); + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*ipsp); + obj.ipfo_type = IPFOBJ_STATESAVE; + obj.ipfo_ptr = ipsp; + + do { + + if (opts & OPT_VERBOSE) + printf("Getting state from addr %p\n", ips.ips_next); + if (ioctl(fd, SIOCSTGET, &obj)) { + if (errno == ENOENT) + break; + perror("state:SIOCSTGET"); + close(wfd); + return 1; + } + if (opts & OPT_VERBOSE) + printf("Got state next %p\n", ips.ips_next); + if (write(wfd, ipsp, sizeof(ips)) != sizeof(ips)) { + perror("state:write"); + close(wfd); + return 1; + } + } while (ips.ips_next != NULL); + close(wfd); + + return 0; +} + + +int readstate(fd, file) + int fd; + char *file; +{ + ipstate_save_t ips, *is, *ipshead = NULL, *is1, *ipstail = NULL; + int sfd = -1, i; + ipfobj_t obj; + + if (!file) + file = IPF_STATEFILE; + + sfd = open(file, O_RDONLY, 0600); + if (sfd == -1) { + fprintf(stderr, "%s ", file); + perror("open"); + return 1; + } + + bzero((char *)&ips, sizeof(ips)); + + /* + * 1. Read all state information in. + */ + do { + i = read(sfd, &ips, sizeof(ips)); + if (i == -1) { + perror("read"); + goto freeipshead; + } + if (i == 0) + break; + if (i != sizeof(ips)) { + fprintf(stderr, "state:incomplete read: %d != %d\n", + i, (int)sizeof(ips)); + goto freeipshead; + } + is = (ipstate_save_t *)malloc(sizeof(*is)); + if (is == NULL) { + fprintf(stderr, "malloc failed\n"); + goto freeipshead; + } + + bcopy((char *)&ips, (char *)is, sizeof(ips)); + + /* + * Check to see if this is the first state entry that will + * reference a particular rule and if so, flag it as such + * else just adjust the rule pointer to become a pointer to + * the other. We do this so we have a means later for tracking + * who is referencing us when we get back the real pointer + * in is_rule after doing the ioctl. + */ + for (is1 = ipshead; is1 != NULL; is1 = is1->ips_next) + if (is1->ips_rule == is->ips_rule) + break; + if (is1 == NULL) + is->ips_is.is_flags |= SI_NEWFR; + else + is->ips_rule = (void *)&is1->ips_rule; + + /* + * Use a tail-queue type list (add things to the end).. + */ + is->ips_next = NULL; + if (!ipshead) + ipshead = is; + if (ipstail) + ipstail->ips_next = is; + ipstail = is; + } while (1); + + close(sfd); + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(*is); + obj.ipfo_type = IPFOBJ_STATESAVE; + + while ((is = ipshead) != NULL) { + if (opts & OPT_VERBOSE) + printf("Loading new state table entry\n"); + if (is->ips_is.is_flags & SI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Loading new filter rule\n"); + } + + obj.ipfo_ptr = is; + if (!(opts & OPT_DONOTHING)) + if (ioctl(fd, SIOCSTPUT, &obj)) { + perror("SIOCSTPUT"); + goto freeipshead; + } + + if (is->ips_is.is_flags & SI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Real rule addr %p\n", is->ips_rule); + for (is1 = is->ips_next; is1; is1 = is1->ips_next) + if (is1->ips_rule == (frentry_t *)&is->ips_rule) + is1->ips_rule = is->ips_rule; + } + + ipshead = is->ips_next; + free(is); + } + + return 0; + +freeipshead: + while ((is = ipshead) != NULL) { + ipshead = is->ips_next; + free(is); + } + if (sfd != -1) + close(sfd); + return 1; +} + + +int readnat(fd, file) + int fd; + char *file; +{ + nat_save_t ipn, *in, *ipnhead = NULL, *in1, *ipntail = NULL; + ipfobj_t obj; + int nfd, i; + nat_t *nat; + char *s; + int n; + + nfd = -1; + in = NULL; + ipnhead = NULL; + ipntail = NULL; + + if (!file) + file = IPF_NATFILE; + + nfd = open(file, O_RDONLY); + if (nfd == -1) { + fprintf(stderr, "%s ", file); + perror("nat:open"); + return 1; + } + + bzero((char *)&ipn, sizeof(ipn)); + + /* + * 1. Read all state information in. + */ + do { + i = read(nfd, &ipn, sizeof(ipn)); + if (i == -1) { + perror("read"); + goto freenathead; + } + if (i == 0) + break; + if (i != sizeof(ipn)) { + fprintf(stderr, "nat:incomplete read: %d != %d\n", + i, (int)sizeof(ipn)); + goto freenathead; + } + + in = (nat_save_t *)malloc(ipn.ipn_dsize); + if (in == NULL) { + fprintf(stderr, "nat:cannot malloc nat save atruct\n"); + goto freenathead; + } + + if (ipn.ipn_dsize > sizeof(ipn)) { + n = ipn.ipn_dsize - sizeof(ipn); + if (n > 0) { + s = in->ipn_data + sizeof(in->ipn_data); + i = read(nfd, s, n); + if (i == 0) + break; + if (i != n) { + fprintf(stderr, + "nat:incomplete read: %d != %d\n", + i, n); + goto freenathead; + } + } + } + bcopy((char *)&ipn, (char *)in, sizeof(ipn)); + + /* + * Check to see if this is the first NAT entry that will + * reference a particular rule and if so, flag it as such + * else just adjust the rule pointer to become a pointer to + * the other. We do this so we have a means later for tracking + * who is referencing us when we get back the real pointer + * in is_rule after doing the ioctl. + */ + nat = &in->ipn_nat; + if (nat->nat_fr != NULL) { + for (in1 = ipnhead; in1 != NULL; in1 = in1->ipn_next) + if (in1->ipn_rule == nat->nat_fr) + break; + if (in1 == NULL) + nat->nat_flags |= SI_NEWFR; + else + nat->nat_fr = &in1->ipn_fr; + } + + /* + * Use a tail-queue type list (add things to the end).. + */ + in->ipn_next = NULL; + if (!ipnhead) + ipnhead = in; + if (ipntail) + ipntail->ipn_next = in; + ipntail = in; + } while (1); + + close(nfd); + nfd = -1; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_NATSAVE; + + while ((in = ipnhead) != NULL) { + if (opts & OPT_VERBOSE) + printf("Loading new NAT table entry\n"); + nat = &in->ipn_nat; + if (nat->nat_flags & SI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Loading new filter rule\n"); + } + + obj.ipfo_ptr = in; + obj.ipfo_size = in->ipn_dsize; + if (!(opts & OPT_DONOTHING)) + if (ioctl(fd, SIOCSTPUT, &obj)) { + fprintf(stderr, "in=%p:", in); + perror("SIOCSTPUT"); + return 1; + } + + if (nat->nat_flags & SI_NEWFR) { + if (opts & OPT_VERBOSE) + printf("Real rule addr %p\n", nat->nat_fr); + for (in1 = in->ipn_next; in1; in1 = in1->ipn_next) + if (in1->ipn_rule == &in->ipn_fr) + in1->ipn_rule = nat->nat_fr; + } + + ipnhead = in->ipn_next; + free(in); + } + + return 0; + +freenathead: + while ((in = ipnhead) != NULL) { + ipnhead = in->ipn_next; + free(in); + } + if (nfd != -1) + close(nfd); + return 1; +} + + +int writenat(fd, file) + int fd; + char *file; +{ + nat_save_t *ipnp = NULL, *next = NULL; + ipfobj_t obj; + int nfd = -1; + natget_t ng; + + if (!file) + file = IPF_NATFILE; + + nfd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0600); + if (nfd == -1) { + fprintf(stderr, "%s ", file); + perror("nat:open"); + return 1; + } + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_NATSAVE; + + do { + if (opts & OPT_VERBOSE) + printf("Getting nat from addr %p\n", ipnp); + ng.ng_ptr = next; + ng.ng_sz = 0; + if (ioctl(fd, SIOCSTGSZ, &ng)) { + perror("nat:SIOCSTGSZ"); + close(nfd); + if (ipnp != NULL) + free(ipnp); + return 1; + } + + if (opts & OPT_VERBOSE) + printf("NAT size %d from %p\n", ng.ng_sz, ng.ng_ptr); + + if (ng.ng_sz == 0) + break; + + if (!ipnp) + ipnp = malloc(ng.ng_sz); + else + ipnp = realloc((char *)ipnp, ng.ng_sz); + if (!ipnp) { + fprintf(stderr, + "malloc for %d bytes failed\n", ng.ng_sz); + break; + } + + bzero((char *)ipnp, ng.ng_sz); + obj.ipfo_size = ng.ng_sz; + obj.ipfo_ptr = ipnp; + ipnp->ipn_dsize = ng.ng_sz; + ipnp->ipn_next = next; + if (ioctl(fd, SIOCSTGET, &obj)) { + if (errno == ENOENT) + break; + perror("nat:SIOCSTGET"); + close(nfd); + free(ipnp); + return 1; + } + + if (opts & OPT_VERBOSE) + printf("Got nat next %p ipn_dsize %d ng_sz %d\n", + ipnp->ipn_next, ipnp->ipn_dsize, ng.ng_sz); + if (write(nfd, ipnp, ipnp->ipn_dsize) != ipnp->ipn_dsize) { + perror("nat:write"); + close(nfd); + free(ipnp); + return 1; + } + next = ipnp->ipn_next; + } while (ipnp && next); + if (ipnp != NULL) + free(ipnp); + close(nfd); + + return 0; +} + + +int writeall(dirname) + char *dirname; +{ + int fd, devfd; + + if (!dirname) + dirname = IPF_SAVEDIR; + + if (chdir(dirname)) { + fprintf(stderr, "IPF_SAVEDIR=%s: ", dirname); + perror("chdir(IPF_SAVEDIR)"); + return 1; + } + + fd = opendevice(NULL); + if (fd == -1) + return 1; + if (setlock(fd, 1)) { + close(fd); + return 1; + } + + devfd = opendevice(IPSTATE_NAME); + if (devfd == -1) + goto bad; + if (writestate(devfd, NULL)) + goto bad; + close(devfd); + + devfd = opendevice(IPNAT_NAME); + if (devfd == -1) + goto bad; + if (writenat(devfd, NULL)) + goto bad; + close(devfd); + + if (setlock(fd, 0)) { + close(fd); + return 1; + } + + close(fd); + return 0; + +bad: + setlock(fd, 0); + close(fd); + return 1; +} + + +int readall(dirname) + char *dirname; +{ + int fd, devfd; + + if (!dirname) + dirname = IPF_SAVEDIR; + + if (chdir(dirname)) { + perror("chdir(IPF_SAVEDIR)"); + return 1; + } + + fd = opendevice(NULL); + if (fd == -1) + return 1; + if (setlock(fd, 1)) { + close(fd); + return 1; + } + + devfd = opendevice(IPSTATE_NAME); + if (devfd == -1) + return 1; + if (readstate(devfd, NULL)) + return 1; + close(devfd); + + devfd = opendevice(IPNAT_NAME); + if (devfd == -1) + return 1; + if (readnat(devfd, NULL)) + return 1; + close(devfd); + + if (setlock(fd, 0)) { + close(fd); + return 1; + } + + return 0; +} diff --git a/contrib/ipfilter/tools/ipfstat.c b/contrib/ipfilter/tools/ipfstat.c new file mode 100644 index 0000000..3261cef --- /dev/null +++ b/contrib/ipfilter/tools/ipfstat.c @@ -0,0 +1,2375 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#ifdef __FreeBSD__ +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +#endif +#include <sys/ioctl.h> +#include <ctype.h> +#include <fcntl.h> +#ifdef linux +# include <linux/a.out.h> +#else +# include <nlist.h> +#endif +#include <ctype.h> +#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# include <stddef.h> +#endif +#include "ipf.h" +#include "netinet/ipl.h" +#if defined(STATETOP) +# if defined(_BSDI_VERSION) +# undef STATETOP +# endif +# if defined(__FreeBSD__) && \ + (!defined(__FreeBSD_version) || (__FreeBSD_version < 430000)) +# undef STATETOP +# endif +# if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105000000) +# undef STATETOP +# endif +# if defined(sun) +# if defined(__svr4__) || defined(__SVR4) +# include <sys/select.h> +# else +# undef STATETOP /* NOT supported on SunOS4 */ +# endif +# endif +#endif +#if defined(STATETOP) && !defined(linux) +# include <netinet/ip_var.h> +# include <netinet/tcp_fsm.h> +#endif +#ifdef STATETOP +# include <ctype.h> +# include <signal.h> +# include <time.h> +# if SOLARIS || defined(__NetBSD__) || defined(_BSDI_VERSION) || \ + defined(__sgi) +# ifdef ERR +# undef ERR +# endif +# include <curses.h> +# else /* SOLARIS */ +# include <ncurses.h> +# endif /* SOLARIS */ +#endif /* STATETOP */ +#include "kmem.h" +#if defined(__NetBSD__) || (__OpenBSD__) +# include <paths.h> +#endif + +#if !defined(lint) +static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +#ifdef __hpux +# define nlist nlist64 +#endif + +extern char *optarg; +extern int optind; +extern int opterr; + +#define PRINTF (void)printf +#define FPRINTF (void)fprintf +static char *filters[4] = { "ipfilter(in)", "ipfilter(out)", + "ipacct(in)", "ipacct(out)" }; +static int state_logging = -1; +static wordtab_t *state_fields = NULL; + +int nohdrfields = 0; +int opts = 0; +int use_inet6 = 0; +int live_kernel = 1; +int state_fd = -1; +int ipf_fd = -1; +int auth_fd = -1; +int nat_fd = -1; +frgroup_t *grtop = NULL; +frgroup_t *grtail = NULL; + +char *blockreasons[FRB_MAX_VALUE + 1] = { + "packet blocked", + "log rule failure", + "pps rate exceeded", + "jumbogram", + "makefrip failed", + "cannot add state", + "IP ID update failed", + "log-or-block failed", + "decapsulate failure", + "cannot create new auth entry", + "packet queued for auth", + "buffer coalesce failure", + "buffer pullup failure", + "auth feedback", + "bad fragment", + "IPv4 NAT failure", + "IPv6 NAT failure" +}; + +#ifdef STATETOP +#define STSTRSIZE 80 +#define STGROWSIZE 16 +#define HOSTNMLEN 40 + +#define STSORT_PR 0 +#define STSORT_PKTS 1 +#define STSORT_BYTES 2 +#define STSORT_TTL 3 +#define STSORT_SRCIP 4 +#define STSORT_SRCPT 5 +#define STSORT_DSTIP 6 +#define STSORT_DSTPT 7 +#define STSORT_MAX STSORT_DSTPT +#define STSORT_DEFAULT STSORT_BYTES + + +typedef struct statetop { + i6addr_t st_src; + i6addr_t st_dst; + u_short st_sport; + u_short st_dport; + u_char st_p; + u_char st_v; + u_char st_state[2]; + U_QUAD_T st_pkts; + U_QUAD_T st_bytes; + u_long st_age; +} statetop_t; +#endif + +int main __P((int, char *[])); + +static int fetchfrag __P((int, int, ipfr_t *)); +static void showstats __P((friostat_t *, u_32_t)); +static void showfrstates __P((ipfrstat_t *, u_long)); +static void showlist __P((friostat_t *)); +static void showstatestats __P((ips_stat_t *)); +static void showipstates __P((ips_stat_t *, int *)); +static void showauthstates __P((ipf_authstat_t *)); +static void showtqtable_live __P((int)); +static void showgroups __P((friostat_t *)); +static void usage __P((char *)); +static int state_matcharray __P((ipstate_t *, int *)); +static int printlivelist __P((friostat_t *, int, int, frentry_t *, + char *, char *)); +static void printdeadlist __P((friostat_t *, int, int, frentry_t *, + char *, char *)); +static void printside __P((char *, ipf_statistics_t *)); +static void parse_ipportstr __P((const char *, i6addr_t *, int *)); +static void ipfstate_live __P((char *, friostat_t **, ips_stat_t **, + ipfrstat_t **, ipf_authstat_t **, u_32_t *)); +static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **, + ipfrstat_t **, ipf_authstat_t **, u_32_t *)); +static ipstate_t *fetchstate __P((ipstate_t *, ipstate_t *)); +#ifdef STATETOP +static void topipstates __P((i6addr_t, i6addr_t, int, int, int, + int, int, int, int *)); +static void sig_break __P((int)); +static void sig_resize __P((int)); +static char *getip __P((int, i6addr_t *)); +static char *ttl_to_string __P((long)); +static int sort_p __P((const void *, const void *)); +static int sort_pkts __P((const void *, const void *)); +static int sort_bytes __P((const void *, const void *)); +static int sort_ttl __P((const void *, const void *)); +static int sort_srcip __P((const void *, const void *)); +static int sort_srcpt __P((const void *, const void *)); +static int sort_dstip __P((const void *, const void *)); +static int sort_dstpt __P((const void *, const void *)); +#endif + + +static void usage(name) + char *name; +{ +#ifdef USE_INET6 + fprintf(stderr, "Usage: %s [-6aAdfghIilnoRsv]\n", name); +#else + fprintf(stderr, "Usage: %s [-aAdfghIilnoRsv]\n", name); +#endif + fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name); +#ifdef USE_INET6 + fprintf(stderr, " %s -t [-6C] ", name); +#else + fprintf(stderr, " %s -t [-C] ", name); +#endif + fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); + exit(1); +} + + +int main(argc,argv) + int argc; + char *argv[]; +{ + ipf_authstat_t frauthst; + ipf_authstat_t *frauthstp = &frauthst; + friostat_t fio; + friostat_t *fiop = &fio; + ips_stat_t ipsst; + ips_stat_t *ipsstp = &ipsst; + ipfrstat_t ifrst; + ipfrstat_t *ifrstp = &ifrst; + char *options; + char *kern = NULL; + char *memf = NULL; + int c; + int myoptind; + int *filter = NULL; + + int protocol = -1; /* -1 = wild card for any protocol */ + int refreshtime = 1; /* default update time */ + int sport = -1; /* -1 = wild card for any source port */ + int dport = -1; /* -1 = wild card for any dest port */ + int topclosed = 0; /* do not show closed tcp sessions */ + i6addr_t saddr, daddr; + u_32_t frf; + +#ifdef USE_INET6 + options = "6aACdfghIilnostvD:m:M:N:O:P:RS:T:"; +#else + options = "aACdfghIilnostvD:m:M:N:O:P:RS:T:"; +#endif + + saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */ + daddr.in4.s_addr = INADDR_ANY; /* default any v4 dest addr */ +#ifdef USE_INET6 + saddr.in6 = in6addr_any; /* default any v6 source addr */ + daddr.in6 = in6addr_any; /* default any v6 dest addr */ +#endif + + /* Don't warn about invalid flags when we run getopt for the 1st time */ + opterr = 0; + + /* + * Parse these two arguments now lest there be any buffer overflows + * in the parsing of the rest. + */ + myoptind = optind; + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) + { + case 'M' : + memf = optarg; + live_kernel = 0; + break; + case 'N' : + kern = optarg; + live_kernel = 0; + break; + } + } + optind = myoptind; + + if (live_kernel == 1) { + if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) { + perror("open(IPSTATE_NAME)"); + exit(-1); + } + if ((auth_fd = open(IPAUTH_NAME, O_RDONLY)) == -1) { + perror("open(IPAUTH_NAME)"); + exit(-1); + } + if ((nat_fd = open(IPNAT_NAME, O_RDONLY)) == -1) { + perror("open(IPAUTH_NAME)"); + exit(-1); + } + if ((ipf_fd = open(IPL_NAME, O_RDONLY)) == -1) { + fprintf(stderr, "open(%s)", IPL_NAME); + perror(""); + exit(-1); + } + } + + if (kern != NULL || memf != NULL) { + (void)setgid(getgid()); + (void)setuid(getuid()); + } + + if (live_kernel == 1) { + (void) checkrev(IPL_NAME); + } else { + if (openkmem(kern, memf) == -1) + exit(-1); + } + + (void)setgid(getgid()); + (void)setuid(getuid()); + + opterr = 1; + + while ((c = getopt(argc, argv, options)) != -1) + { + switch (c) + { +#ifdef USE_INET6 + case '6' : + use_inet6 = 1; + break; +#endif + case 'a' : + opts |= OPT_ACCNT|OPT_SHOWLIST; + break; + case 'A' : + opts |= OPT_AUTHSTATS; + break; + case 'C' : + topclosed = 1; + break; + case 'd' : + opts |= OPT_DEBUG; + break; + case 'D' : + parse_ipportstr(optarg, &daddr, &dport); + break; + case 'f' : + opts |= OPT_FRSTATES; + break; + case 'g' : + opts |= OPT_GROUPS; + break; + case 'h' : + opts |= OPT_HITS; + break; + case 'i' : + opts |= OPT_INQUE|OPT_SHOWLIST; + break; + case 'I' : + opts |= OPT_INACTIVE; + break; + case 'l' : + opts |= OPT_SHOWLIST; + break; + case 'm' : + filter = parseipfexpr(optarg, NULL); + if (filter == NULL) { + fprintf(stderr, "Error parseing '%s'\n", + optarg); + exit(1); + } + break; + case 'M' : + break; + case 'N' : + break; + case 'n' : + opts |= OPT_SHOWLINENO; + break; + case 'o' : + opts |= OPT_OUTQUE|OPT_SHOWLIST; + break; + case 'O' : + state_fields = parsefields(statefields, optarg); + break; + case 'P' : + protocol = getproto(optarg); + if (protocol == -1) { + fprintf(stderr, "%s: Invalid protocol: %s\n", + argv[0], optarg); + exit(-2); + } + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 's' : + opts |= OPT_IPSTATES; + break; + case 'S' : + parse_ipportstr(optarg, &saddr, &sport); + break; + case 't' : +#ifdef STATETOP + opts |= OPT_STATETOP; + break; +#else + fprintf(stderr, + "%s: state top facility not compiled in\n", + argv[0]); + exit(-2); +#endif + case 'T' : + if (!sscanf(optarg, "%d", &refreshtime) || + (refreshtime <= 0)) { + fprintf(stderr, + "%s: Invalid refreshtime < 1 : %s\n", + argv[0], optarg); + exit(-2); + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + default : + usage(argv[0]); + break; + } + } + + if (live_kernel == 1) { + bzero((char *)&fio, sizeof(fio)); + bzero((char *)&ipsst, sizeof(ipsst)); + bzero((char *)&ifrst, sizeof(ifrst)); + + ipfstate_live(IPL_NAME, &fiop, &ipsstp, &ifrstp, + &frauthstp, &frf); + } else { + ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); + } + + if (opts & OPT_IPSTATES) { + showipstates(ipsstp, filter); + } else if (opts & OPT_SHOWLIST) { + showlist(fiop); + if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){ + opts &= ~OPT_OUTQUE; + showlist(fiop); + } + } else if (opts & OPT_FRSTATES) + showfrstates(ifrstp, fiop->f_ticks); +#ifdef STATETOP + else if (opts & OPT_STATETOP) + topipstates(saddr, daddr, sport, dport, protocol, + use_inet6 ? 6 : 4, refreshtime, topclosed, filter); +#endif + else if (opts & OPT_AUTHSTATS) + showauthstates(frauthstp); + else if (opts & OPT_GROUPS) + showgroups(fiop); + else + showstats(fiop, frf); + + return 0; +} + + +/* + * Fill in the stats structures from the live kernel, using a combination + * of ioctl's and copying directly from kernel memory. + */ +static void ipfstate_live(device, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) + char *device; + friostat_t **fiopp; + ips_stat_t **ipsstpp; + ipfrstat_t **ifrstpp; + ipf_authstat_t **frauthstpp; + u_32_t *frfp; +{ + ipfobj_t ipfo; + + if (checkrev(device) == -1) { + fprintf(stderr, "User/kernel version check failed\n"); + exit(1); + } + + if ((opts & OPT_AUTHSTATS) == 0) { + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_type = IPFOBJ_IPFSTAT; + ipfo.ipfo_size = sizeof(friostat_t); + ipfo.ipfo_ptr = (void *)*fiopp; + + if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) { + ipferror(ipf_fd, "ioctl(ipf:SIOCGETFS)"); + exit(-1); + } + + if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1) + ipferror(ipf_fd, "ioctl(SIOCGETFF)"); + } + + if ((opts & OPT_IPSTATES) != 0) { + + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_type = IPFOBJ_STATESTAT; + ipfo.ipfo_size = sizeof(ips_stat_t); + ipfo.ipfo_ptr = (void *)*ipsstpp; + + if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { + ipferror(state_fd, "ioctl(state:SIOCGETFS)"); + exit(-1); + } + if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) { + ipferror(state_fd, "ioctl(state:SIOCGETLG)"); + exit(-1); + } + } + + if ((opts & OPT_FRSTATES) != 0) { + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_type = IPFOBJ_FRAGSTAT; + ipfo.ipfo_size = sizeof(ipfrstat_t); + ipfo.ipfo_ptr = (void *)*ifrstpp; + + if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) { + ipferror(ipf_fd, "ioctl(SIOCGFRST)"); + exit(-1); + } + } + + if (opts & OPT_DEBUG) + PRINTF("opts %#x name %s\n", opts, device); + + if ((opts & OPT_AUTHSTATS) != 0) { + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_type = IPFOBJ_AUTHSTAT; + ipfo.ipfo_size = sizeof(ipf_authstat_t); + ipfo.ipfo_ptr = (void *)*frauthstpp; + + if (ioctl(auth_fd, SIOCATHST, &ipfo) == -1) { + ipferror(auth_fd, "ioctl(SIOCATHST)"); + exit(-1); + } + } +} + + +/* + * Build up the stats structures from data held in the "core" memory. + * This is mainly useful when looking at data in crash dumps and ioctl's + * just won't work any more. + */ +static void ipfstate_dead(kernel, fiopp, ipsstpp, ifrstpp, frauthstpp, frfp) + char *kernel; + friostat_t **fiopp; + ips_stat_t **ipsstpp; + ipfrstat_t **ifrstpp; + ipf_authstat_t **frauthstpp; + u_32_t *frfp; +{ + static ipf_authstat_t frauthst, *frauthstp; + static ipftq_t ipstcptab[IPF_TCP_NSTATES]; + static ips_stat_t ipsst, *ipsstp; + static ipfrstat_t ifrst, *ifrstp; + static friostat_t fio, *fiop; + int temp; + + void *rules[2][2]; + struct nlist deadlist[44] = { + { "ipf_auth_stats", 0, 0, 0, 0 }, /* 0 */ + { "fae_list", 0, 0, 0, 0 }, + { "ipauth", 0, 0, 0, 0 }, + { "ipf_auth_list", 0, 0, 0, 0 }, + { "ipf_auth_start", 0, 0, 0, 0 }, + { "ipf_auth_end", 0, 0, 0, 0 }, /* 5 */ + { "ipf_auth_next", 0, 0, 0, 0 }, + { "ipf_auth", 0, 0, 0, 0 }, + { "ipf_auth_used", 0, 0, 0, 0 }, + { "ipf_auth_size", 0, 0, 0, 0 }, + { "ipf_auth_defaultage", 0, 0, 0, 0 }, /* 10 */ + { "ipf_auth_pkts", 0, 0, 0, 0 }, + { "ipf_auth_lock", 0, 0, 0, 0 }, + { "frstats", 0, 0, 0, 0 }, + { "ips_stats", 0, 0, 0, 0 }, + { "ips_num", 0, 0, 0, 0 }, /* 15 */ + { "ips_wild", 0, 0, 0, 0 }, + { "ips_list", 0, 0, 0, 0 }, + { "ips_table", 0, 0, 0, 0 }, + { "ipf_state_max", 0, 0, 0, 0 }, + { "ipf_state_size", 0, 0, 0, 0 }, /* 20 */ + { "ipf_state_doflush", 0, 0, 0, 0 }, + { "ipf_state_lock", 0, 0, 0, 0 }, + { "ipfr_heads", 0, 0, 0, 0 }, + { "ipfr_nattab", 0, 0, 0, 0 }, + { "ipfr_stats", 0, 0, 0, 0 }, /* 25 */ + { "ipfr_inuse", 0, 0, 0, 0 }, + { "ipf_ipfrttl", 0, 0, 0, 0 }, + { "ipf_frag_lock", 0, 0, 0, 0 }, + { "ipfr_timer_id", 0, 0, 0, 0 }, + { "ipf_nat_lock", 0, 0, 0, 0 }, /* 30 */ + { "ipf_rules", 0, 0, 0, 0 }, + { "ipf_acct", 0, 0, 0, 0 }, + { "ipl_frouteok", 0, 0, 0, 0 }, + { "ipf_running", 0, 0, 0, 0 }, + { "ipf_groups", 0, 0, 0, 0 }, /* 35 */ + { "ipf_active", 0, 0, 0, 0 }, + { "ipf_pass", 0, 0, 0, 0 }, + { "ipf_flags", 0, 0, 0, 0 }, + { "ipf_state_logging", 0, 0, 0, 0 }, + { "ips_tqtqb", 0, 0, 0, 0 }, /* 40 */ + { NULL, 0, 0, 0, 0 } + }; + + + frauthstp = &frauthst; + ipsstp = &ipsst; + ifrstp = &ifrst; + fiop = &fio; + + *frfp = 0; + *fiopp = fiop; + *ipsstpp = ipsstp; + *ifrstpp = ifrstp; + *frauthstpp = frauthstp; + + bzero((char *)fiop, sizeof(*fiop)); + bzero((char *)ipsstp, sizeof(*ipsstp)); + bzero((char *)ifrstp, sizeof(*ifrstp)); + bzero((char *)frauthstp, sizeof(*frauthstp)); + + if (nlist(kernel, deadlist) == -1) { + fprintf(stderr, "nlist error\n"); + return; + } + + /* + * This is for SIOCGETFF. + */ + kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp)); + + /* + * f_locks is a combination of the lock variable from each part of + * ipfilter (state, auth, nat, fragments). + */ + kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop)); + kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value, + sizeof(fiop->f_locks[0])); + kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value, + sizeof(fiop->f_locks[1])); + kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value, + sizeof(fiop->f_locks[2])); + kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value, + sizeof(fiop->f_locks[3])); + + /* + * Get pointers to each list of rules (active, inactive, in, out) + */ + kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules)); + fiop->f_fin[0] = rules[0][0]; + fiop->f_fin[1] = rules[0][1]; + fiop->f_fout[0] = rules[1][0]; + fiop->f_fout[1] = rules[1][1]; + + /* + * Now get accounting rules pointers. + */ + kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules)); + fiop->f_acctin[0] = rules[0][0]; + fiop->f_acctin[1] = rules[0][1]; + fiop->f_acctout[0] = rules[1][0]; + fiop->f_acctout[1] = rules[1][1]; + + /* + * A collection of "global" variables used inside the kernel which + * are all collected in friostat_t via ioctl. + */ + kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[33].n_value, + sizeof(fiop->f_froute)); + kmemcpy((char *)&fiop->f_running, (u_long)deadlist[34].n_value, + sizeof(fiop->f_running)); + kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[35].n_value, + sizeof(fiop->f_groups)); + kmemcpy((char *)&fiop->f_active, (u_long)deadlist[36].n_value, + sizeof(fiop->f_active)); + kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[37].n_value, + sizeof(fiop->f_defpass)); + + /* + * Build up the state information stats structure. + */ + kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp)); + kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp)); + kmemcpy((char *)ipstcptab, (u_long)deadlist[40].n_value, + sizeof(ipstcptab)); + ipsstp->iss_active = temp; + ipsstp->iss_table = (void *)deadlist[18].n_value; + ipsstp->iss_list = (void *)deadlist[17].n_value; + ipsstp->iss_tcptab = ipstcptab; + + /* + * Build up the authentiation information stats structure. + */ + kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value, + sizeof(*frauthstp)); + frauthstp->fas_faelist = (void *)deadlist[1].n_value; + + /* + * Build up the fragment information stats structure. + */ + kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value, + sizeof(*ifrstp)); + ifrstp->ifs_table = (void *)deadlist[23].n_value; + ifrstp->ifs_nattab = (void *)deadlist[24].n_value; + kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value, + sizeof(ifrstp->ifs_inuse)); + + /* + * Get logging on/off switches + */ + kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value, + sizeof(state_logging)); +} + + +static void printside(side, frs) + char *side; + ipf_statistics_t *frs; +{ + int i; + + PRINTF("%lu\t%s bad packets\n", frs->fr_bad, side); +#ifdef USE_INET6 + PRINTF("%lu\t%s IPv6 packets\n", frs->fr_ipv6, side); +#endif + PRINTF("%lu\t%s packets blocked\n", frs->fr_block, side); + PRINTF("%lu\t%s packets passed\n", frs->fr_pass, side); + PRINTF("%lu\t%s packets not matched\n", frs->fr_nom, side); + PRINTF("%lu\t%s packets counted\n", frs->fr_acct, side); + PRINTF("%lu\t%s packets short\n", frs->fr_short, side); + PRINTF("%lu\t%s packets logged and blocked\n", frs->fr_bpkl, side); + PRINTF("%lu\t%s packets logged and passed\n", frs->fr_ppkl, side); + PRINTF("%lu\t%s fragment state kept\n", frs->fr_nfr, side); + PRINTF("%lu\t%s fragment state lost\n", frs->fr_bnfr, side); + PRINTF("%lu\t%s packet state kept\n", frs->fr_ads, side); + PRINTF("%lu\t%s packet state lost\n", frs->fr_bads, side); + PRINTF("%lu\t%s invalid source\n", frs->fr_v4_badsrc, side); + PRINTF("%lu\t%s cache hits\n", frs->fr_chit, side); + PRINTF("%lu\t%s cache misses\n", frs->fr_cmiss, side); + PRINTF("%lu\t%s bad coalesces\n", frs->fr_badcoalesces, side); + PRINTF("%lu\t%s pullups succeeded\n", frs->fr_pull[0], side); + PRINTF("%lu\t%s pullups failed\n", frs->fr_pull[1], side); + PRINTF("%lu\t%s TCP checksum failures\n", frs->fr_tcpbad, side); + for (i = 0; i <= FRB_MAX_VALUE; i++) + PRINTF("%lu\t%s block reason %s\n", + frs->fr_blocked[i], side, blockreasons[i]); +} + + +/* + * Display the kernel stats for packets blocked and passed and other + * associated running totals which are kept. + */ +static void showstats(fp, frf) + struct friostat *fp; + u_32_t frf; +{ + printside("input", &fp->f_st[0]); + printside("output", &fp->f_st[1]); + + PRINTF("%lu\tpackets logged\n", fp->f_log_ok); + PRINTF("%lu\tlog failures\n", fp->f_log_fail); + PRINTF("%lu\tred-black no memory\n", fp->f_rb_no_mem); + PRINTF("%lu\tred-black node maximum\n", fp->f_rb_node_max); + PRINTF("%lu\tICMP replies sent\n", fp->f_st[0].fr_ret); + PRINTF("%lu\tTCP RSTs sent\n", fp->f_st[1].fr_ret); + PRINTF("%lu\tfastroute successes\n", fp->f_froute[0]); + PRINTF("%lu\tfastroute failures\n", fp->f_froute[1]); + PRINTF("%u\tIPF Ticks\n", fp->f_ticks); + + PRINTF("%x\tPacket log flags set:\n", frf); + if (frf & FF_LOGPASS) + PRINTF("\tpackets passed through filter\n"); + if (frf & FF_LOGBLOCK) + PRINTF("\tpackets blocked by filter\n"); + if (frf & FF_LOGNOMATCH) + PRINTF("\tpackets not matched by filter\n"); + if (!frf) + PRINTF("\tnone\n"); +} + + +/* + * Print out a list of rules from the kernel, starting at the one passed. + */ +static int +printlivelist(fiop, out, set, fp, group, comment) + struct friostat *fiop; + int out, set; + frentry_t *fp; + char *group, *comment; +{ + struct frentry fb; + ipfruleiter_t rule; + frentry_t zero; + frgroup_t *g; + ipfobj_t obj; + int rules; + int num; + + rules = 0; + + rule.iri_inout = out; + rule.iri_active = set; + rule.iri_rule = &fb; + rule.iri_nrules = 1; + if (group != NULL) + strncpy(rule.iri_group, group, FR_GROUPLEN); + else + rule.iri_group[0] = '\0'; + + bzero((char *)&zero, sizeof(zero)); + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_IPFITER; + obj.ipfo_size = sizeof(rule); + obj.ipfo_ptr = &rule; + + while (rule.iri_rule != NULL) { + u_long array[1000]; + + memset(array, 0xff, sizeof(array)); + fp = (frentry_t *)array; + rule.iri_rule = fp; + if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) { + ipferror(ipf_fd, "ioctl(SIOCIPFITER)"); + num = IPFGENITER_IPF; + (void) ioctl(ipf_fd,SIOCIPFDELTOK, &num); + return rules; + } + if (bcmp(fp, &zero, sizeof(zero)) == 0) + break; + if (rule.iri_rule == NULL) + break; +#ifdef USE_INET6 + if (use_inet6 != 0) { + if (fp->fr_family != 0 && fp->fr_family != AF_INET6) + continue; + } else +#endif + { + if (fp->fr_family != 0 && fp->fr_family != AF_INET) + continue; + } + if (fp->fr_data != NULL) + fp->fr_data = (char *)fp + fp->fr_size; + + rules++; + + if (opts & (OPT_HITS|OPT_DEBUG)) +#ifdef USE_QUAD_T + PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_hits); +#else + PRINTF("%lu ", fp->fr_hits); +#endif + if (opts & (OPT_ACCNT|OPT_DEBUG)) +#ifdef USE_QUAD_T + PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_bytes); +#else + PRINTF("%lu ", fp->fr_bytes); +#endif + if (opts & OPT_SHOWLINENO) + PRINTF("@%d ", rules); + + if (fp->fr_die != 0) + fp->fr_die -= fiop->f_ticks; + + printfr(fp, ioctl); + if (opts & OPT_DEBUG) { + binprint(fp, fp->fr_size); + if (fp->fr_data != NULL && fp->fr_dsize > 0) + binprint(fp->fr_data, fp->fr_dsize); + } + if (fp->fr_grhead != -1) { + for (g = grtop; g != NULL; g = g->fg_next) { + if (!strncmp(fp->fr_names + fp->fr_grhead, + g->fg_name, + FR_GROUPLEN)) + break; + } + if (g == NULL) { + g = calloc(1, sizeof(*g)); + + if (g != NULL) { + strncpy(g->fg_name, + fp->fr_names + fp->fr_grhead, + FR_GROUPLEN); + if (grtop == NULL) { + grtop = g; + grtail = g; + } else { + grtail->fg_next = g; + grtail = g; + } + } + } + } + if (fp->fr_type == FR_T_CALLFUNC) { + rules += printlivelist(fiop, out, set, fp->fr_data, + group, "# callfunc: "); + } + } + + num = IPFGENITER_IPF; + (void) ioctl(ipf_fd,SIOCIPFDELTOK, &num); + + return rules; +} + + +static void printdeadlist(fiop, out, set, fp, group, comment) + friostat_t *fiop; + int out, set; + frentry_t *fp; + char *group, *comment; +{ + frgroup_t *grtop, *grtail, *g; + struct frentry fb; + char *data; + u_32_t type; + int n; + + fb.fr_next = fp; + n = 0; + grtop = NULL; + grtail = NULL; + + for (n = 1; fp; fp = fb.fr_next, n++) { + if (kmemcpy((char *)&fb, (u_long)fb.fr_next, + fb.fr_size) == -1) { + perror("kmemcpy"); + return; + } + fp = &fb; + if (use_inet6 != 0) { + if (fp->fr_family != 0 && fp->fr_family != 6) + continue; + } else { + if (fp->fr_family != 0 && fp->fr_family != 4) + continue; + } + + data = NULL; + type = fb.fr_type & ~FR_T_BUILTIN; + if (type == FR_T_IPF || type == FR_T_BPFOPC) { + if (fb.fr_dsize) { + data = malloc(fb.fr_dsize); + + if (kmemcpy(data, (u_long)fb.fr_data, + fb.fr_dsize) == -1) { + perror("kmemcpy"); + return; + } + fb.fr_data = data; + } + } + + if (opts & OPT_HITS) +#ifdef USE_QUAD_T + PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_hits); +#else + PRINTF("%lu ", fb.fr_hits); +#endif + if (opts & OPT_ACCNT) +#ifdef USE_QUAD_T + PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_bytes); +#else + PRINTF("%lu ", fb.fr_bytes); +#endif + if (opts & OPT_SHOWLINENO) + PRINTF("@%d ", n); + + printfr(fp, ioctl); + if (opts & OPT_DEBUG) { + binprint(fp, fp->fr_size); + if (fb.fr_data != NULL && fb.fr_dsize > 0) + binprint(fb.fr_data, fb.fr_dsize); + } + if (data != NULL) + free(data); + if (fb.fr_grhead != -1) { + g = calloc(1, sizeof(*g)); + + if (g != NULL) { + strncpy(g->fg_name, fb.fr_names + fb.fr_grhead, + FR_GROUPLEN); + if (grtop == NULL) { + grtop = g; + grtail = g; + } else { + grtail->fg_next = g; + grtail = g; + } + } + } + if (type == FR_T_CALLFUNC) { + printdeadlist(fiop, out, set, fb.fr_data, group, + "# callfunc: "); + } + } + + while ((g = grtop) != NULL) { + printdeadlist(fiop, out, set, NULL, g->fg_name, comment); + grtop = g->fg_next; + free(g); + } +} + +/* + * print out all of the asked for rule sets, using the stats struct as + * the base from which to get the pointers. + */ +static void showlist(fiop) + struct friostat *fiop; +{ + struct frentry *fp = NULL; + int i, set; + + set = fiop->f_active; + if (opts & OPT_INACTIVE) + set = 1 - set; + if (opts & OPT_ACCNT) { + if (opts & OPT_OUTQUE) { + i = F_ACOUT; + fp = (struct frentry *)fiop->f_acctout[set]; + } else if (opts & OPT_INQUE) { + i = F_ACIN; + fp = (struct frentry *)fiop->f_acctin[set]; + } else { + FPRINTF(stderr, "No -i or -o given with -a\n"); + return; + } + } else { + if (opts & OPT_OUTQUE) { + i = F_OUT; + fp = (struct frentry *)fiop->f_fout[set]; + } else if (opts & OPT_INQUE) { + i = F_IN; + fp = (struct frentry *)fiop->f_fin[set]; + } else + return; + } + if (opts & OPT_DEBUG) + FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); + + if (opts & OPT_DEBUG) + PRINTF("fp %p set %d\n", fp, set); + + if (live_kernel == 1) { + int printed; + + printed = printlivelist(fiop, i, set, fp, NULL, NULL); + if (printed == 0) { + FPRINTF(stderr, "# empty list for %s%s\n", + (opts & OPT_INACTIVE) ? "inactive " : "", + filters[i]); + } + } else { + if (!fp) { + FPRINTF(stderr, "# empty list for %s%s\n", + (opts & OPT_INACTIVE) ? "inactive " : "", + filters[i]); + } else { + printdeadlist(fiop, i, set, fp, NULL, NULL); + } + } +} + + +/* + * Display ipfilter stateful filtering information + */ +static void showipstates(ipsp, filter) + ips_stat_t *ipsp; + int *filter; +{ + ipstate_t *is; + int i; + + /* + * If a list of states hasn't been asked for, only print out stats + */ + if (!(opts & OPT_SHOWLIST)) { + showstatestats(ipsp); + return; + } + + if ((state_fields != NULL) && (nohdrfields == 0)) { + for (i = 0; state_fields[i].w_value != 0; i++) { + printfieldhdr(statefields, state_fields + i); + if (state_fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } + + /* + * Print out all the state information currently held in the kernel. + */ + for (is = ipsp->iss_list; is != NULL; ) { + ipstate_t ips; + + is = fetchstate(is, &ips); + + if (is == NULL) + break; + + is = ips.is_next; + if ((filter != NULL) && + (state_matcharray(&ips, filter) == 0)) { + continue; + } + if (state_fields != NULL) { + for (i = 0; state_fields[i].w_value != 0; i++) { + printstatefield(&ips, state_fields[i].w_value); + if (state_fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } else { + printstate(&ips, opts, ipsp->iss_ticks); + } + } +} + + +static void showstatestats(ipsp) + ips_stat_t *ipsp; +{ + int minlen, maxlen, totallen; + ipftable_t table; + u_int *buckets; + ipfobj_t obj; + int i, sz; + + /* + * If a list of states hasn't been asked for, only print out stats + */ + + sz = sizeof(*buckets) * ipsp->iss_state_size; + buckets = (u_int *)malloc(sz); + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_GTABLE; + obj.ipfo_size = sizeof(table); + obj.ipfo_ptr = &table; + + table.ita_type = IPFTABLE_BUCKETS; + table.ita_table = buckets; + + if (live_kernel == 1) { + if (ioctl(state_fd, SIOCGTABL, &obj) != 0) { + free(buckets); + return; + } + } else { + if (kmemcpy((char *)buckets, + (u_long)ipsp->iss_bucketlen, sz)) { + free(buckets); + return; + } + } + + PRINTF("%u\tactive state table entries\n",ipsp->iss_active); + PRINTF("%lu\tadd bad\n", ipsp->iss_add_bad); + PRINTF("%lu\tadd duplicate\n", ipsp->iss_add_dup); + PRINTF("%lu\tadd locked\n", ipsp->iss_add_locked); + PRINTF("%lu\tadd oow\n", ipsp->iss_add_oow); + PRINTF("%lu\tbucket full\n", ipsp->iss_bucket_full); + PRINTF("%lu\tcheck bad\n", ipsp->iss_check_bad); + PRINTF("%lu\tcheck miss\n", ipsp->iss_check_miss); + PRINTF("%lu\tcheck nattag\n", ipsp->iss_check_nattag); + PRINTF("%lu\tclone nomem\n", ipsp->iss_clone_nomem); + PRINTF("%lu\tcheck notag\n", ipsp->iss_check_notag); + PRINTF("%lu\tcheck success\n", ipsp->iss_hits); + PRINTF("%lu\tcloned\n", ipsp->iss_cloned); + PRINTF("%lu\texpired\n", ipsp->iss_expire); + PRINTF("%lu\tflush all\n", ipsp->iss_flush_all); + PRINTF("%lu\tflush closing\n", ipsp->iss_flush_closing); + PRINTF("%lu\tflush queue\n", ipsp->iss_flush_queue); + PRINTF("%lu\tflush state\n", ipsp->iss_flush_state); + PRINTF("%lu\tflush timeout\n", ipsp->iss_flush_timeout); + PRINTF("%u\thash buckets in use\n", ipsp->iss_inuse); + PRINTF("%lu\tICMP bad\n", ipsp->iss_icmp_bad); + PRINTF("%lu\tICMP banned\n", ipsp->iss_icmp_banned); + PRINTF("%lu\tICMP errors\n", ipsp->iss_icmp_icmperr); + PRINTF("%lu\tICMP head block\n", ipsp->iss_icmp_headblock); + PRINTF("%lu\tICMP hits\n", ipsp->iss_icmp_hits); + PRINTF("%lu\tICMP not query\n", ipsp->iss_icmp_notquery); + PRINTF("%lu\tICMP short\n", ipsp->iss_icmp_short); + PRINTF("%lu\tICMP too many\n", ipsp->iss_icmp_toomany); + PRINTF("%lu\tICMPv6 errors\n", ipsp->iss_icmp6_icmperr); + PRINTF("%lu\tICMPv6 miss\n", ipsp->iss_icmp6_miss); + PRINTF("%lu\tICMPv6 not info\n", ipsp->iss_icmp6_notinfo); + PRINTF("%lu\tICMPv6 not query\n", ipsp->iss_icmp6_notquery); + PRINTF("%lu\tlog fail\n", ipsp->iss_log_fail); + PRINTF("%lu\tlog ok\n", ipsp->iss_log_ok); + PRINTF("%lu\tlookup interface mismatch\n", ipsp->iss_lookup_badifp); + PRINTF("%lu\tlookup mask mismatch\n", ipsp->iss_miss_mask); + PRINTF("%lu\tlookup port mismatch\n", ipsp->iss_lookup_badport); + PRINTF("%lu\tlookup miss\n", ipsp->iss_lookup_miss); + PRINTF("%lu\tmaximum rule references\n", ipsp->iss_max_ref); + PRINTF("%lu\tmaximum hosts per rule\n", ipsp->iss_max_track); + PRINTF("%lu\tno memory\n", ipsp->iss_nomem); + PRINTF("%lu\tout of window\n", ipsp->iss_oow); + PRINTF("%lu\torphans\n", ipsp->iss_orphan); + PRINTF("%lu\tscan block\n", ipsp->iss_scan_block); + PRINTF("%lu\tstate table maximum reached\n", ipsp->iss_max); + PRINTF("%lu\tTCP closing\n", ipsp->iss_tcp_closing); + PRINTF("%lu\tTCP OOW\n", ipsp->iss_tcp_oow); + PRINTF("%lu\tTCP RST add\n", ipsp->iss_tcp_rstadd); + PRINTF("%lu\tTCP too small\n", ipsp->iss_tcp_toosmall); + PRINTF("%lu\tTCP bad options\n", ipsp->iss_tcp_badopt); + PRINTF("%lu\tTCP removed\n", ipsp->iss_fin); + PRINTF("%lu\tTCP FSM\n", ipsp->iss_tcp_fsm); + PRINTF("%lu\tTCP strict\n", ipsp->iss_tcp_strict); + PRINTF("%lu\tTCP wild\n", ipsp->iss_wild); + PRINTF("%lu\tMicrosoft Windows SACK\n", ipsp->iss_winsack); + + PRINTF("State logging %sabled\n", state_logging ? "en" : "dis"); + + PRINTF("IP states added:\n"); + for (i = 0; i < 256; i++) { + if (ipsp->iss_proto[i] != 0) { + struct protoent *proto; + + proto = getprotobynumber(i); + PRINTF("%lu", ipsp->iss_proto[i]); + if (proto != NULL) + PRINTF("\t%s\n", proto->p_name); + else + PRINTF("\t%d\n", i); + } + } + + PRINTF("\nState table bucket statistics:\n"); + PRINTF("%u\tin use\n", ipsp->iss_inuse); + + minlen = ipsp->iss_max; + totallen = 0; + maxlen = 0; + + for (i = 0; i < ipsp->iss_state_size; i++) { + if (buckets[i] > maxlen) + maxlen = buckets[i]; + if (buckets[i] < minlen) + minlen = buckets[i]; + totallen += buckets[i]; + } + + PRINTF("%d\thash efficiency\n", + totallen ? ipsp->iss_inuse * 100 / totallen : 0); + PRINTF("%2.2f%%\tbucket usage\n%u\tminimal length\n", + ((float)ipsp->iss_inuse / ipsp->iss_state_size) * 100.0, + minlen); + PRINTF("%u\tmaximal length\n%.3f\taverage length\n", + maxlen, + ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse : + 0.0); + +#define ENTRIES_PER_LINE 5 + + if (opts & OPT_VERBOSE) { + PRINTF("\nCurrent bucket sizes :\n"); + for (i = 0; i < ipsp->iss_state_size; i++) { + if ((i % ENTRIES_PER_LINE) == 0) + PRINTF("\t"); + PRINTF("%4d -> %4u", i, buckets[i]); + if ((i % ENTRIES_PER_LINE) == + (ENTRIES_PER_LINE - 1)) + PRINTF("\n"); + else + PRINTF(" "); + } + PRINTF("\n"); + } + PRINTF("\n"); + + free(buckets); + + if (live_kernel == 1) { + showtqtable_live(state_fd); + } else { + printtqtable(ipsp->iss_tcptab); + } +} + + +#ifdef STATETOP +static int handle_resize = 0, handle_break = 0; + +static void topipstates(saddr, daddr, sport, dport, protocol, ver, + refreshtime, topclosed, filter) + i6addr_t saddr; + i6addr_t daddr; + int sport; + int dport; + int protocol; + int ver; + int refreshtime; + int topclosed; + int *filter; +{ + char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; + int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; + int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0; + int len, srclen, dstlen, forward = 1, c = 0; + ips_stat_t ipsst, *ipsstp = &ipsst; + int token_type = IPFGENITER_STATE; + statetop_t *tstable = NULL, *tp; + const char *errstr = ""; + ipstate_t ips; + ipfobj_t ipfo; + struct timeval selecttimeout; + char hostnm[HOSTNMLEN]; + struct protoent *proto; + fd_set readfd; + time_t t; + + /* install signal handlers */ + signal(SIGINT, sig_break); + signal(SIGQUIT, sig_break); + signal(SIGTERM, sig_break); + signal(SIGWINCH, sig_resize); + + /* init ncurses stuff */ + initscr(); + cbreak(); + noecho(); + curs_set(0); + timeout(0); + getmaxyx(stdscr, maxy, maxx); + + /* init hostname */ + gethostname(hostnm, sizeof(hostnm) - 1); + hostnm[sizeof(hostnm) - 1] = '\0'; + + /* init ipfobj_t stuff */ + bzero((caddr_t)&ipfo, sizeof(ipfo)); + ipfo.ipfo_rev = IPFILTER_VERSION; + ipfo.ipfo_type = IPFOBJ_STATESTAT; + ipfo.ipfo_size = sizeof(*ipsstp); + ipfo.ipfo_ptr = (void *)ipsstp; + + /* repeat until user aborts */ + while ( 1 ) { + + /* get state table */ + bzero((char *)&ipsst, sizeof(ipsst)); + if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { + errstr = "ioctl(SIOCGETFS)"; + ret = -1; + goto out; + } + + /* clear the history */ + tsentry = -1; + + /* reset max str len */ + srclen = dstlen = 0; + + /* read the state table and store in tstable */ + for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) { + + ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips); + if (ipsstp->iss_list == NULL) + break; + + if (ips.is_v != ver) + continue; + + if ((filter != NULL) && + (state_matcharray(&ips, filter) == 0)) + continue; + + /* check v4 src/dest addresses */ + if (ips.is_v == 4) { + if ((saddr.in4.s_addr != INADDR_ANY && + saddr.in4.s_addr != ips.is_saddr) || + (daddr.in4.s_addr != INADDR_ANY && + daddr.in4.s_addr != ips.is_daddr)) + continue; + } +#ifdef USE_INET6 + /* check v6 src/dest addresses */ + if (ips.is_v == 6) { + if ((IP6_NEQ(&saddr, &in6addr_any) && + IP6_NEQ(&saddr, &ips.is_src)) || + (IP6_NEQ(&daddr, &in6addr_any) && + IP6_NEQ(&daddr, &ips.is_dst))) + continue; + } +#endif + /* check protocol */ + if (protocol > 0 && protocol != ips.is_p) + continue; + + /* check ports if protocol is TCP or UDP */ + if (((ips.is_p == IPPROTO_TCP) || + (ips.is_p == IPPROTO_UDP)) && + (((sport > 0) && (htons(sport) != ips.is_sport)) || + ((dport > 0) && (htons(dport) != ips.is_dport)))) + continue; + + /* show closed TCP sessions ? */ + if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) && + (ips.is_state[0] >= IPF_TCPS_LAST_ACK) && + (ips.is_state[1] >= IPF_TCPS_LAST_ACK)) + continue; + + /* + * if necessary make room for this state + * entry + */ + tsentry++; + if (!maxtsentries || tsentry == maxtsentries) { + maxtsentries += STGROWSIZE; + tstable = realloc(tstable, + maxtsentries * sizeof(statetop_t)); + if (tstable == NULL) { + perror("realloc"); + exit(-1); + } + } + + /* get max src/dest address string length */ + len = strlen(getip(ips.is_v, &ips.is_src)); + if (srclen < len) + srclen = len; + len = strlen(getip(ips.is_v, &ips.is_dst)); + if (dstlen < len) + dstlen = len; + + /* fill structure */ + tp = tstable + tsentry; + tp->st_src = ips.is_src; + tp->st_dst = ips.is_dst; + tp->st_p = ips.is_p; + tp->st_v = ips.is_v; + tp->st_state[0] = ips.is_state[0]; + tp->st_state[1] = ips.is_state[1]; + if (forward) { + tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1]; + tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1]; + } else { + tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3]; + tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3]; + } + tp->st_age = ips.is_die - ipsstp->iss_ticks; + if ((ips.is_p == IPPROTO_TCP) || + (ips.is_p == IPPROTO_UDP)) { + tp->st_sport = ips.is_sport; + tp->st_dport = ips.is_dport; + } + } + + (void) ioctl(state_fd, SIOCIPFDELTOK, &token_type); + + /* sort the array */ + if (tsentry != -1) { + switch (sorting) + { + case STSORT_PR: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_p); + break; + case STSORT_PKTS: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_pkts); + break; + case STSORT_BYTES: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_bytes); + break; + case STSORT_TTL: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_ttl); + break; + case STSORT_SRCIP: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_srcip); + break; + case STSORT_SRCPT: + qsort(tstable, tsentry +1, + sizeof(statetop_t), sort_srcpt); + break; + case STSORT_DSTIP: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_dstip); + break; + case STSORT_DSTPT: + qsort(tstable, tsentry + 1, + sizeof(statetop_t), sort_dstpt); + break; + default: + break; + } + } + + /* handle window resizes */ + if (handle_resize) { + endwin(); + initscr(); + cbreak(); + noecho(); + curs_set(0); + timeout(0); + getmaxyx(stdscr, maxy, maxx); + redraw = 1; + handle_resize = 0; + } + + /* stop program? */ + if (handle_break) + break; + + /* print title */ + erase(); + attron(A_BOLD); + winy = 0; + move(winy,0); + sprintf(str1, "%s - %s - state top", hostnm, IPL_VERSION); + for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++) + printw(" "); + printw("%s", str1); + attroff(A_BOLD); + + /* just for fun add a clock */ + move(winy, maxx - 8); + t = time(NULL); + strftime(str1, 80, "%T", localtime(&t)); + printw("%s\n", str1); + + /* + * print the display filters, this is placed in the loop, + * because someday I might add code for changing these + * while the programming is running :-) + */ + if (sport >= 0) + sprintf(str1, "%s,%d", getip(ver, &saddr), sport); + else + sprintf(str1, "%s", getip(ver, &saddr)); + + if (dport >= 0) + sprintf(str2, "%s,%d", getip(ver, &daddr), dport); + else + sprintf(str2, "%s", getip(ver, &daddr)); + + if (protocol < 0) + strcpy(str3, "any"); + else if ((proto = getprotobynumber(protocol)) != NULL) + sprintf(str3, "%s", proto->p_name); + else + sprintf(str3, "%d", protocol); + + switch (sorting) + { + case STSORT_PR: + sprintf(str4, "proto"); + break; + case STSORT_PKTS: + sprintf(str4, "# pkts"); + break; + case STSORT_BYTES: + sprintf(str4, "# bytes"); + break; + case STSORT_TTL: + sprintf(str4, "ttl"); + break; + case STSORT_SRCIP: + sprintf(str4, "src ip"); + break; + case STSORT_SRCPT: + sprintf(str4, "src port"); + break; + case STSORT_DSTIP: + sprintf(str4, "dest ip"); + break; + case STSORT_DSTPT: + sprintf(str4, "dest port"); + break; + default: + sprintf(str4, "unknown"); + break; + } + + if (reverse) + strcat(str4, " (reverse)"); + + winy += 2; + move(winy,0); + printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n", + str1, str2, str3, str4); + + /* + * For an IPv4 IP address we need at most 15 characters, + * 4 tuples of 3 digits, separated by 3 dots. Enforce this + * length, so the colums do not change positions based + * on the size of the IP address. This length makes the + * output fit in a 80 column terminal. + * We are lacking a good solution for IPv6 addresses (that + * can be longer that 15 characters), so we do not enforce + * a maximum on the IP field size. + */ + if (srclen < 15) + srclen = 15; + if (dstlen < 15) + dstlen = 15; + + /* print column description */ + winy += 2; + move(winy,0); + attron(A_BOLD); + printw("%-*s %-*s %3s %4s %7s %9s %9s\n", + srclen + 6, "Source IP", dstlen + 6, "Destination IP", + "ST", "PR", "#pkts", "#bytes", "ttl"); + attroff(A_BOLD); + + /* print all the entries */ + tp = tstable; + if (reverse) + tp += tsentry; + + if (tsentry > maxy - 6) + tsentry = maxy - 6; + for (i = 0; i <= tsentry; i++) { + /* print src/dest and port */ + if ((tp->st_p == IPPROTO_TCP) || + (tp->st_p == IPPROTO_UDP)) { + sprintf(str1, "%s,%hu", + getip(tp->st_v, &tp->st_src), + ntohs(tp->st_sport)); + sprintf(str2, "%s,%hu", + getip(tp->st_v, &tp->st_dst), + ntohs(tp->st_dport)); + } else { + sprintf(str1, "%s", getip(tp->st_v, + &tp->st_src)); + sprintf(str2, "%s", getip(tp->st_v, + &tp->st_dst)); + } + winy++; + move(winy, 0); + printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2); + + /* print state */ + sprintf(str1, "%X/%X", tp->st_state[0], + tp->st_state[1]); + printw(" %3s", str1); + + /* print protocol */ + proto = getprotobynumber(tp->st_p); + if (proto) { + strncpy(str1, proto->p_name, 4); + str1[4] = '\0'; + } else { + sprintf(str1, "%d", tp->st_p); + } + /* just print icmp for IPv6-ICMP */ + if (tp->st_p == IPPROTO_ICMPV6) + strcpy(str1, "icmp"); + printw(" %4s", str1); + + /* print #pkt/#bytes */ +#ifdef USE_QUAD_T + printw(" %7qu %9qu", (unsigned long long) tp->st_pkts, + (unsigned long long) tp->st_bytes); +#else + printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes); +#endif + printw(" %9s", ttl_to_string(tp->st_age)); + + if (reverse) + tp--; + else + tp++; + } + + /* screen data structure is filled, now update the screen */ + if (redraw) + clearok(stdscr,1); + + if (refresh() == ERR) + break; + if (redraw) { + clearok(stdscr,0); + redraw = 0; + } + + /* wait for key press or a 1 second time out period */ + selecttimeout.tv_sec = refreshtime; + selecttimeout.tv_usec = 0; + FD_ZERO(&readfd); + FD_SET(0, &readfd); + select(1, &readfd, NULL, NULL, &selecttimeout); + + /* if key pressed, read all waiting keys */ + if (FD_ISSET(0, &readfd)) { + c = wgetch(stdscr); + if (c == ERR) + continue; + + if (ISALPHA(c) && ISUPPER(c)) + c = TOLOWER(c); + if (c == 'l') { + redraw = 1; + } else if (c == 'q') { + break; + } else if (c == 'r') { + reverse = !reverse; + } else if (c == 'b') { + forward = 0; + } else if (c == 'f') { + forward = 1; + } else if (c == 's') { + if (++sorting > STSORT_MAX) + sorting = 0; + } + } + } /* while */ + +out: + printw("\n"); + curs_set(1); + /* nocbreak(); XXX - endwin() should make this redundant */ + endwin(); + + free(tstable); + if (ret != 0) + perror(errstr); +} +#endif + + +/* + * Show fragment cache information that's held in the kernel. + */ +static void showfrstates(ifsp, ticks) + ipfrstat_t *ifsp; + u_long ticks; +{ + struct ipfr *ipfrtab[IPFT_SIZE], ifr; + int i; + + /* + * print out the numeric statistics + */ + PRINTF("IP fragment states:\n%lu\tnew\n%lu\texpired\n%lu\thits\n", + ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits); + PRINTF("%lu\tretrans\n%lu\ttoo short\n", + ifsp->ifs_retrans0, ifsp->ifs_short); + PRINTF("%lu\tno memory\n%lu\talready exist\n", + ifsp->ifs_nomem, ifsp->ifs_exists); + PRINTF("%lu\tinuse\n", ifsp->ifs_inuse); + PRINTF("\n"); + + if (live_kernel == 0) { + if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, + sizeof(ipfrtab))) + return; + } + + /* + * Print out the contents (if any) of the fragment cache table. + */ + if (live_kernel == 1) { + do { + if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0) + break; + if (ifr.ipfr_ifp == NULL) + break; + ifr.ipfr_ttl -= ticks; + printfraginfo("", &ifr); + } while (ifr.ipfr_next != NULL); + } else { + for (i = 0; i < IPFT_SIZE; i++) + while (ipfrtab[i] != NULL) { + if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], + sizeof(ifr)) == -1) + break; + printfraginfo("", &ifr); + ipfrtab[i] = ifr.ipfr_next; + } + } + /* + * Print out the contents (if any) of the NAT fragment cache table. + */ + + if (live_kernel == 0) { + if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab, + sizeof(ipfrtab))) + return; + } + + if (live_kernel == 1) { + do { + if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0) + break; + if (ifr.ipfr_ifp == NULL) + break; + ifr.ipfr_ttl -= ticks; + printfraginfo("NAT: ", &ifr); + } while (ifr.ipfr_next != NULL); + } else { + for (i = 0; i < IPFT_SIZE; i++) + while (ipfrtab[i] != NULL) { + if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], + sizeof(ifr)) == -1) + break; + printfraginfo("NAT: ", &ifr); + ipfrtab[i] = ifr.ipfr_next; + } + } +} + + +/* + * Show stats on how auth within IPFilter has been used + */ +static void showauthstates(asp) + ipf_authstat_t *asp; +{ + frauthent_t *frap, fra; + ipfgeniter_t auth; + ipfobj_t obj; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_GENITER; + obj.ipfo_size = sizeof(auth); + obj.ipfo_ptr = &auth; + + auth.igi_type = IPFGENITER_AUTH; + auth.igi_nitems = 1; + auth.igi_data = &fra; + +#ifdef USE_QUAD_T + printf("Authorisation hits: %"PRIu64"\tmisses %"PRIu64"\n", + (unsigned long long) asp->fas_hits, + (unsigned long long) asp->fas_miss); +#else + printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits, + asp->fas_miss); +#endif + printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n", + asp->fas_nospace, asp->fas_added, asp->fas_sendfail, + asp->fas_sendok); + printf("queok %ld\nquefail %ld\nexpire %ld\n", + asp->fas_queok, asp->fas_quefail, asp->fas_expire); + + frap = asp->fas_faelist; + while (frap) { + if (live_kernel == 1) { + if (ioctl(auth_fd, SIOCGENITER, &obj)) + break; + } else { + if (kmemcpy((char *)&fra, (u_long)frap, + sizeof(fra)) == -1) + break; + } + printf("age %ld\t", fra.fae_age); + printfr(&fra.fae_fr, ioctl); + frap = fra.fae_next; + } +} + + +/* + * Display groups used for each of filter rules, accounting rules and + * authentication, separately. + */ +static void showgroups(fiop) + struct friostat *fiop; +{ + static char *gnames[3] = { "Filter", "Accounting", "Authentication" }; + static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH }; + frgroup_t *fp, grp; + int on, off, i; + + on = fiop->f_active; + off = 1 - on; + + for (i = 0; i < 3; i++) { + printf("%s groups (active):\n", gnames[i]); + for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL; + fp = grp.fg_next) + if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) + break; + else + printf("%s\n", grp.fg_name); + printf("%s groups (inactive):\n", gnames[i]); + for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL; + fp = grp.fg_next) + if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) + break; + else + printf("%s\n", grp.fg_name); + } +} + + +static void parse_ipportstr(argument, ip, port) + const char *argument; + i6addr_t *ip; + int *port; +{ + char *s, *comma; + int ok = 0; + + /* make working copy of argument, Theoretically you must be able + * to write to optarg, but that seems very ugly to me.... + */ + s = strdup(argument); + if (s == NULL) + return; + + /* get port */ + if ((comma = strchr(s, ',')) != NULL) { + if (!strcasecmp(comma + 1, "any")) { + *port = -1; + } else if (!sscanf(comma + 1, "%d", port) || + (*port < 0) || (*port > 65535)) { + fprintf(stderr, "Invalid port specification in %s\n", + argument); + free(s); + exit(-2); + } + *comma = '\0'; + } + + + /* get ip address */ + if (!strcasecmp(s, "any")) { + ip->in4.s_addr = INADDR_ANY; + ok = 1; +#ifdef USE_INET6 + ip->in6 = in6addr_any; + } else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) { + ok = 1; +#endif + } else if (inet_aton(s, &ip->in4)) + ok = 1; + + if (ok == 0) { + fprintf(stderr, "Invalid IP address: %s\n", s); + free(s); + exit(-2); + } + + /* free allocated memory */ + free(s); +} + + +#ifdef STATETOP +static void sig_resize(s) + int s; +{ + handle_resize = 1; +} + +static void sig_break(s) + int s; +{ + handle_break = 1; +} + +static char *getip(v, addr) + int v; + i6addr_t *addr; +{ +#ifdef USE_INET6 + static char hostbuf[MAXHOSTNAMELEN+1]; +#endif + + if (v == 4) + return inet_ntoa(addr->in4); + +#ifdef USE_INET6 + (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1); + hostbuf[MAXHOSTNAMELEN] = '\0'; + return hostbuf; +#else + return "IPv6"; +#endif +} + + +static char *ttl_to_string(ttl) + long int ttl; +{ + static char ttlbuf[STSTRSIZE]; + int hours, minutes, seconds; + + /* ttl is in half seconds */ + ttl /= 2; + + hours = ttl / 3600; + ttl = ttl % 3600; + minutes = ttl / 60; + seconds = ttl % 60; + + if (hours > 0) + sprintf(ttlbuf, "%2d:%02d:%02d", hours, minutes, seconds); + else + sprintf(ttlbuf, "%2d:%02d", minutes, seconds); + return ttlbuf; +} + + +static int sort_pkts(a, b) + const void *a; + const void *b; +{ + + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (ap->st_pkts == bp->st_pkts) + return 0; + else if (ap->st_pkts < bp->st_pkts) + return 1; + return -1; +} + + +static int sort_bytes(a, b) + const void *a; + const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (ap->st_bytes == bp->st_bytes) + return 0; + else if (ap->st_bytes < bp->st_bytes) + return 1; + return -1; +} + + +static int sort_p(a, b) + const void *a; + const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (ap->st_p == bp->st_p) + return 0; + else if (ap->st_p < bp->st_p) + return 1; + return -1; +} + + +static int sort_ttl(a, b) + const void *a; + const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (ap->st_age == bp->st_age) + return 0; + else if (ap->st_age < bp->st_age) + return 1; + return -1; +} + +static int sort_srcip(a, b) + const void *a; + const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + +#ifdef USE_INET6 + if (use_inet6) { + if (IP6_EQ(&ap->st_src, &bp->st_src)) + return 0; + else if (IP6_GT(&ap->st_src, &bp->st_src)) + return 1; + } else +#endif + { + if (ntohl(ap->st_src.in4.s_addr) == + ntohl(bp->st_src.in4.s_addr)) + return 0; + else if (ntohl(ap->st_src.in4.s_addr) > + ntohl(bp->st_src.in4.s_addr)) + return 1; + } + return -1; +} + +static int sort_srcpt(a, b) + const void *a; + const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (htons(ap->st_sport) == htons(bp->st_sport)) + return 0; + else if (htons(ap->st_sport) > htons(bp->st_sport)) + return 1; + return -1; +} + +static int sort_dstip(a, b) + const void *a; + const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + +#ifdef USE_INET6 + if (use_inet6) { + if (IP6_EQ(&ap->st_dst, &bp->st_dst)) + return 0; + else if (IP6_GT(&ap->st_dst, &bp->st_dst)) + return 1; + } else +#endif + { + if (ntohl(ap->st_dst.in4.s_addr) == + ntohl(bp->st_dst.in4.s_addr)) + return 0; + else if (ntohl(ap->st_dst.in4.s_addr) > + ntohl(bp->st_dst.in4.s_addr)) + return 1; + } + return -1; +} + +static int sort_dstpt(a, b) + const void *a; + const void *b; +{ + register const statetop_t *ap = a; + register const statetop_t *bp = b; + + if (htons(ap->st_dport) == htons(bp->st_dport)) + return 0; + else if (htons(ap->st_dport) > htons(bp->st_dport)) + return 1; + return -1; +} + +#endif + + +ipstate_t *fetchstate(src, dst) + ipstate_t *src, *dst; +{ + + if (live_kernel == 1) { + ipfgeniter_t state; + ipfobj_t obj; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_GENITER; + obj.ipfo_size = sizeof(state); + obj.ipfo_ptr = &state; + + state.igi_type = IPFGENITER_STATE; + state.igi_nitems = 1; + state.igi_data = dst; + + if (ioctl(state_fd, SIOCGENITER, &obj) != 0) + return NULL; + if (dst->is_next == NULL) { + int n = IPFGENITER_STATE; + (void) ioctl(ipf_fd,SIOCIPFDELTOK, &n); + } + } else { + if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst))) + return NULL; + } + return dst; +} + + +static int fetchfrag(fd, type, frp) + int fd, type; + ipfr_t *frp; +{ + ipfgeniter_t frag; + ipfobj_t obj; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_GENITER; + obj.ipfo_size = sizeof(frag); + obj.ipfo_ptr = &frag; + + frag.igi_type = type; + frag.igi_nitems = 1; + frag.igi_data = frp; + + if (ioctl(fd, SIOCGENITER, &obj)) + return EFAULT; + return 0; +} + + +static int state_matcharray(stp, array) + ipstate_t *stp; + int *array; +{ + int i, n, *x, rv, p; + ipfexp_t *e; + + rv = 0; + + for (n = array[0], x = array + 1; n > 0; x += e->ipfe_size) { + e = (ipfexp_t *)x; + if (e->ipfe_cmd == IPF_EXP_END) + break; + n -= e->ipfe_size; + + rv = 0; + /* + * The upper 16 bits currently store the protocol value. + * This is currently used with TCP and UDP port compares and + * allows "tcp.port = 80" without requiring an explicit + " "ip.pr = tcp" first. + */ + p = e->ipfe_cmd >> 16; + if ((p != 0) && (p != stp->is_p)) + break; + + switch (e->ipfe_cmd) + { + case IPF_EXP_IP_PR : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (stp->is_p == e->ipfe_arg0[i]); + } + break; + + case IPF_EXP_IP_SRCADDR : + if (stp->is_v != 4) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= ((stp->is_saddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]); + } + break; + + case IPF_EXP_IP_DSTADDR : + if (stp->is_v != 4) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= ((stp->is_daddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]); + } + break; + + case IPF_EXP_IP_ADDR : + if (stp->is_v != 4) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= ((stp->is_saddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]) || + ((stp->is_daddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]); + } + break; + +#ifdef USE_INET6 + case IPF_EXP_IP6_SRCADDR : + if (stp->is_v != 6) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= IP6_MASKEQ(&stp->is_src, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]); + } + break; + + case IPF_EXP_IP6_DSTADDR : + if (stp->is_v != 6) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= IP6_MASKEQ(&stp->is_dst, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]); + } + break; + + case IPF_EXP_IP6_ADDR : + if (stp->is_v != 6) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= IP6_MASKEQ(&stp->is_src, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]) || + IP6_MASKEQ(&stp->is_dst, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]); + } + break; +#endif + + case IPF_EXP_UDP_PORT : + case IPF_EXP_TCP_PORT : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (stp->is_sport == e->ipfe_arg0[i]) || + (stp->is_dport == e->ipfe_arg0[i]); + } + break; + + case IPF_EXP_UDP_SPORT : + case IPF_EXP_TCP_SPORT : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (stp->is_sport == e->ipfe_arg0[i]); + } + break; + + case IPF_EXP_UDP_DPORT : + case IPF_EXP_TCP_DPORT : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (stp->is_dport == e->ipfe_arg0[i]); + } + break; + + case IPF_EXP_IDLE_GT : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (stp->is_die < e->ipfe_arg0[i]); + } + break; + + case IPF_EXP_TCP_STATE : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (stp->is_state[0] == e->ipfe_arg0[i]) || + (stp->is_state[1] == e->ipfe_arg0[i]); + } + break; + } + rv ^= e->ipfe_not; + + if (rv == 0) + break; + } + + return rv; +} + + +static void showtqtable_live(fd) + int fd; +{ + ipftq_t table[IPF_TCP_NSTATES]; + ipfobj_t obj; + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = sizeof(table); + obj.ipfo_ptr = (void *)table; + obj.ipfo_type = IPFOBJ_STATETQTAB; + + if (ioctl(fd, SIOCGTQTAB, &obj) == 0) { + printtqtable(table); + } +} diff --git a/contrib/ipfilter/tools/ipfsyncd.c b/contrib/ipfilter/tools/ipfsyncd.c new file mode 100644 index 0000000..d4671e4 --- /dev/null +++ b/contrib/ipfilter/tools/ipfsyncd.c @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ipfsyncd.c,v 1.1.2.2 2012/07/22 08:04:24 darren_r Exp $"; +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/sockio.h> +#include <sys/errno.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <syslog.h> +#include <signal.h> + +#include "ipf.h" +#include "opts.h" + + +#define R_IO_ERROR -1 +#define R_OKAY 0 +#define R_MORE 1 +#define R_SKIP 2 +#if defined(sun) && !defined(SOLARIS2) +# define STRERROR(x) sys_errlist[x] +extern char *sys_errlist[]; +#else +# define STRERROR(x) strerror(x) +#endif + + +int main __P((int, char *[])); +void usage __P((char *)); +void printsynchdr __P((synchdr_t *)); +void printtable __P((int)); +void printsmcproto __P((char *)); +void printcommand __P((int)); +int do_kbuff __P((int, char *, int *)); +int do_packet __P((int, char *)); +int buildsocket __P((char *, struct sockaddr_in *)); +void do_io __P((void)); +void handleterm __P((int)); + +int terminate = 0; +int igmpfd = -1; +int nfd = -1; +int lfd = -1; +int opts = 0; + +void +usage(progname) + char *progname; +{ + fprintf(stderr, + "Usage: %s [-d] [-p port] [-i address] -I <interface>\n", + progname); +} + +void +handleterm(sig) + int sig; +{ + terminate = sig; +} + + +/* should be large enough to hold header + any datatype */ +#define BUFFERLEN 1400 + +int +main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin; + char *interface; + char *progname; + int opt, tries; + + progname = strrchr(argv[0], '/'); + if (progname) { + progname++; + } else { + progname = argv[0]; + } + + opts = 0; + tries = 0; + interface = NULL; + + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(0xaf6c); + sin.sin_addr.s_addr = htonl(INADDR_UNSPEC_GROUP | 0x697066); + + while ((opt = getopt(argc, argv, "di:I:p:")) != -1) + switch (opt) + { + case 'd' : + debuglevel++; + break; + case 'I' : + interface = optarg; + break; + case 'i' : + sin.sin_addr.s_addr = inet_addr(optarg); + break; + case 'p' : + sin.sin_port = htons(atoi(optarg)); + break; + } + + if (interface == NULL) { + usage(progname); + exit(1); + } + + if (!debuglevel) { + +#if BSD >= 199306 + daemon(0, 0); +#else + int fd = open("/dev/null", O_RDWR); + + switch (fork()) + { + case 0 : + break; + + case -1 : + fprintf(stderr, "%s: fork() failed: %s\n", + argv[0], STRERROR(errno)); + exit(1); + /* NOTREACHED */ + + default : + exit(0); + /* NOTREACHED */ + } + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + close(fd); + + setsid(); +#endif + } + + signal(SIGHUP, handleterm); + signal(SIGINT, handleterm); + signal(SIGTERM, handleterm); + + openlog(progname, LOG_PID, LOG_SECURITY); + + while (!terminate) { + if (lfd != -1) { + close(lfd); + lfd = -1; + } + if (nfd != -1) { + close(nfd); + nfd = -1; + } + if (igmpfd != -1) { + close(igmpfd); + igmpfd = -1; + } + + if (buildsocket(interface, &sin) == -1) + goto tryagain; + + lfd = open(IPSYNC_NAME, O_RDWR); + if (lfd == -1) { + syslog(LOG_ERR, "open(%s):%m", IPSYNC_NAME); + debug(1, "open(%s): %s\n", IPSYNC_NAME, + STRERROR(errno)); + goto tryagain; + } + + tries = -1; + do_io(); +tryagain: + tries++; + syslog(LOG_INFO, "retry in %d seconds", 1 << tries); + debug(1, "wait %d seconds\n", 1 << tries); + sleep(1 << tries); + } + + + /* terminate */ + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + syslog(LOG_ERR, "signal %d received, exiting...", terminate); + debug(1, "signal %d received, exiting...", terminate); + + exit(1); +} + + +void +do_io() +{ + char nbuff[BUFFERLEN]; + char buff[BUFFERLEN]; + fd_set mrd, rd; + int maxfd; + int inbuf; + int n1; + int left; + + FD_ZERO(&mrd); + FD_SET(lfd, &mrd); + FD_SET(nfd, &mrd); + maxfd = nfd; + if (lfd > maxfd) + maxfd = lfd; + debug(2, "nfd %d lfd %d maxfd %d\n", nfd, lfd, maxfd); + + inbuf = 0; + /* + * A threaded approach to this loop would have one thread + * work on reading lfd (only) all the time and another thread + * working on reading nfd all the time. + */ + while (!terminate) { + int n; + + rd = mrd; + + n = select(maxfd + 1, &rd, NULL, NULL, NULL); + if (n < 0) { + switch (errno) + { + case EINTR : + continue; + default : + syslog(LOG_ERR, "select error: %m"); + debug(1, "select error: %s\n", STRERROR(errno)); + return; + } + } + + if (FD_ISSET(lfd, &rd)) { + n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf); + + debug(3, "read(K):%d\n", n1); + + if (n1 <= 0) { + syslog(LOG_ERR, "read error (k-header): %m"); + debug(1, "read error (k-header): %s\n", + STRERROR(errno)); + return; + } + + left = 0; + + switch (do_kbuff(n1, buff, &left)) + { + case R_IO_ERROR : + return; + case R_MORE : + inbuf += left; + break; + default : + inbuf = 0; + break; + } + } + + if (FD_ISSET(nfd, &rd)) { + n1 = recv(nfd, nbuff, sizeof(nbuff), 0); + + debug(3, "read(N):%d\n", n1); + + if (n1 <= 0) { + syslog(LOG_ERR, "read error (n-header): %m"); + debug(1, "read error (n-header): %s\n", + STRERROR(errno)); + return; + } + + switch (do_packet(n1, nbuff)) + { + case R_IO_ERROR : + return; + default : + break; + } + } + } +} + + +int +buildsocket(nicname, sinp) + char *nicname; + struct sockaddr_in *sinp; +{ + struct sockaddr_in *reqip; + struct ifreq req; + char opt; + + debug(2, "binding to %s:%s\n", nicname, inet_ntoa(sinp->sin_addr)); + + if (IN_MULTICAST(ntohl(sinp->sin_addr.s_addr))) { + struct in_addr addr; + struct ip_mreq mreq; + + igmpfd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); + if (igmpfd == -1) { + syslog(LOG_ERR, "socket:%m"); + debug(1, "socket:%s\n", STRERROR(errno)); + return -1; + } + + bzero((char *)&req, sizeof(req)); + strncpy(req.ifr_name, nicname, sizeof(req.ifr_name)); + req.ifr_name[sizeof(req.ifr_name) - 1] = '\0'; + if (ioctl(igmpfd, SIOCGIFADDR, &req) == -1) { + syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m"); + debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno)); + close(igmpfd); + igmpfd = -1; + return -1; + } + reqip = (struct sockaddr_in *)&req.ifr_addr; + + addr = reqip->sin_addr; + if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&addr, sizeof(addr)) == -1) { + syslog(LOG_ERR, "setsockopt(IP_MULTICAST_IF(%s)):%m", + inet_ntoa(addr)); + debug(1, "setsockopt(IP_MULTICAST_IF(%s)):%s\n", + inet_ntoa(addr), STRERROR(errno)); + close(igmpfd); + igmpfd = -1; + return -1; + } + + opt = 0; + if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_LOOP, + (char *)&opt, sizeof(opt)) == -1) { + syslog(LOG_ERR, "setsockopt(IP_MULTICAST_LOOP=0):%m"); + debug(1, "setsockopt(IP_MULTICAST_LOOP=0):%s\n", + STRERROR(errno)); + close(igmpfd); + igmpfd = -1; + return -1; + } + + opt = 63; + if (setsockopt(igmpfd, IPPROTO_IP, IP_MULTICAST_TTL, + (char *)&opt, sizeof(opt)) == -1) { + syslog(LOG_ERR, "setsockopt(IP_MULTICAST_TTL=%d):%m", + opt); + debug(1, "setsockopt(IP_MULTICAST_TTL=%d):%s\n", opt, + STRERROR(errno)); + close(igmpfd); + igmpfd = -1; + return -1; + } + + mreq.imr_multiaddr.s_addr = sinp->sin_addr.s_addr; + mreq.imr_interface.s_addr = reqip->sin_addr.s_addr; + + if (setsockopt(igmpfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&mreq, sizeof(mreq)) == -1) { + char buffer[80]; + + sprintf(buffer, "%s,", inet_ntoa(sinp->sin_addr)); + strcat(buffer, inet_ntoa(reqip->sin_addr)); + + syslog(LOG_ERR, + "setsockpt(IP_ADD_MEMBERSHIP,%s):%m", buffer); + debug(1, "setsockpt(IP_ADD_MEMBERSHIP,%s):%s\n", + buffer, STRERROR(errno)); + close(igmpfd); + igmpfd = -1; + return -1; + } + } + nfd = socket(AF_INET, SOCK_DGRAM, 0); + if (nfd == -1) { + syslog(LOG_ERR, "socket:%m"); + if (igmpfd != -1) { + close(igmpfd); + igmpfd = -1; + } + return -1; + } + bzero((char *)&req, sizeof(req)); + strncpy(req.ifr_name, nicname, sizeof(req.ifr_name)); + req.ifr_name[sizeof(req.ifr_name) - 1] = '\0'; + if (ioctl(nfd, SIOCGIFADDR, &req) == -1) { + syslog(LOG_ERR, "ioctl(SIOCGIFADDR):%m"); + debug(1, "ioctl(SIOCGIFADDR):%s\n", STRERROR(errno)); + close(igmpfd); + igmpfd = -1; + return -1; + } + + if (bind(nfd, (struct sockaddr *)&req.ifr_addr, + sizeof(req.ifr_addr)) == -1) { + syslog(LOG_ERR, "bind:%m"); + debug(1, "bind:%s\n", STRERROR(errno)); + close(nfd); + if (igmpfd != -1) { + close(igmpfd); + igmpfd = -1; + } + nfd = -1; + return -1; + } + + if (connect(nfd, (struct sockaddr *)sinp, sizeof(*sinp)) == -1) { + syslog(LOG_ERR, "connect:%m"); + debug(1, "connect:%s\n", STRERROR(errno)); + close(nfd); + if (igmpfd != -1) { + close(igmpfd); + igmpfd = -1; + } + nfd = -1; + return -1; + } + syslog(LOG_INFO, "Sending data to %s", inet_ntoa(sinp->sin_addr)); + debug(3, "Sending data to %s\n", inet_ntoa(sinp->sin_addr)); + + return nfd; +} + + +int +do_packet(pklen, buff) + int pklen; + char *buff; +{ + synchdr_t *sh; + u_32_t magic; + int len; + int n2; + int n3; + + while (pklen > 0) { + if (pklen < sizeof(*sh)) { + syslog(LOG_ERR, "packet length too short:%d", pklen); + debug(2, "packet length too short:%d\n", pklen); + return R_SKIP; + } + + sh = (synchdr_t *)buff; + len = ntohl(sh->sm_len); + magic = ntohl(sh->sm_magic); + + if (magic != SYNHDRMAGIC) { + syslog(LOG_ERR, "invalid header magic %x", magic); + debug(2, "invalid header magic %x\n", magic); + return R_SKIP; + } + + if (pklen < len + sizeof(*sh)) { + syslog(LOG_ERR, "packet length too short:%d", pklen); + debug(2, "packet length too short:%d\n", pklen); + return R_SKIP; + } + + if (debuglevel > 3) { + printsynchdr(sh); + printcommand(sh->sm_cmd); + printtable(sh->sm_table); + printsmcproto(buff); + } + + n2 = sizeof(*sh) + len; + + do { + n3 = write(lfd, buff, n2); + if (n3 <= 0) { + syslog(LOG_ERR, "write error: %m"); + debug(1, "write error: %s\n", STRERROR(errno)); + return R_IO_ERROR; + } + + n2 -= n3; + buff += n3; + pklen -= n3; + } while (n3 != 0); + } + + return R_OKAY; +} + + + +int +do_kbuff(inbuf, buf, left) + int inbuf, *left; + char *buf; +{ + synchdr_t *sh; + u_32_t magic; + int complete; + int sendlen; + int error; + int bytes; + int len; + int n2; + int n3; + + sendlen = 0; + bytes = inbuf; + error = R_OKAY; + sh = (synchdr_t *)buf; + + for (complete = 0; bytes > 0; complete++) { + len = ntohl(sh->sm_len); + magic = ntohl(sh->sm_magic); + + if (magic != SYNHDRMAGIC) { + syslog(LOG_ERR, + "read invalid header magic 0x%x, flushing", + magic); + debug(2, "read invalid header magic 0x%x, flushing\n", + magic); + n2 = SMC_RLOG; + (void) ioctl(lfd, SIOCIPFFL, &n2); + break; + } + + if (debuglevel > 3) { + printsynchdr(sh); + printcommand(sh->sm_cmd); + printtable(sh->sm_table); + putchar('\n'); + } + + if (bytes < sizeof(*sh) + len) { + debug(3, "Not enough bytes %d < %d\n", bytes, + sizeof(*sh) + len); + error = R_MORE; + break; + } + + if (debuglevel > 3) { + printsmcproto(buf); + } + + sendlen += len + sizeof(*sh); + sh = (synchdr_t *)(buf + sendlen); + bytes -= sendlen; + } + + if (complete) { + n3 = send(nfd, buf, sendlen, 0); + if (n3 <= 0) { + syslog(LOG_ERR, "write error: %m"); + debug(1, "write error: %s\n", STRERROR(errno)); + return R_IO_ERROR; + } + debug(3, "send on %d len %d = %d\n", nfd, sendlen, n3); + error = R_OKAY; + } + + /* move buffer to the front,we might need to make + * this more efficient, by using a rolling pointer + * over the buffer and only copying it, when + * we are reaching the end + */ + if (bytes > 0) { + bcopy(buf + bytes, buf, bytes); + error = R_MORE; + } + debug(4, "complete %d bytes %d error %d\n", complete, bytes, error); + + *left = bytes; + + return error; +} + + +void +printcommand(cmd) + int cmd; +{ + + switch (cmd) + { + case SMC_CREATE : + printf(" cmd:CREATE"); + break; + case SMC_UPDATE : + printf(" cmd:UPDATE"); + break; + default : + printf(" cmd:Unknown(%d)", cmd); + break; + } +} + + +void +printtable(table) + int table; +{ + switch (table) + { + case SMC_NAT : + printf(" table:NAT"); + break; + case SMC_STATE : + printf(" table:STATE"); + break; + default : + printf(" table:Unknown(%d)", table); + break; + } +} + + +void +printsmcproto(buff) + char *buff; +{ + syncupdent_t *su; + synchdr_t *sh; + + sh = (synchdr_t *)buff; + + if (sh->sm_cmd == SMC_CREATE) { + ; + + } else if (sh->sm_cmd == SMC_UPDATE) { + su = (syncupdent_t *)buff; + if (sh->sm_p == IPPROTO_TCP) { + printf(" TCP Update: age %lu state %d/%d\n", + su->sup_tcp.stu_age, + su->sup_tcp.stu_state[0], + su->sup_tcp.stu_state[1]); + } + } else { + printf("Unknown command\n"); + } +} + + +void +printsynchdr(sh) + synchdr_t *sh; +{ + + printf("v:%d p:%d num:%d len:%d magic:%x", sh->sm_v, sh->sm_p, + ntohl(sh->sm_num), ntohl(sh->sm_len), ntohl(sh->sm_magic)); +} diff --git a/contrib/ipfilter/tools/ipftest.c b/contrib/ipfilter/tools/ipftest.c new file mode 100644 index 0000000..378523d --- /dev/null +++ b/contrib/ipfilter/tools/ipftest.c @@ -0,0 +1,874 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#include "ipf.h" +#include "ipt.h" +#include <sys/ioctl.h> +#include <sys/file.h> + +#if !defined(lint) +static const char sccsid[] = "@(#)ipt.c 1.19 6/3/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + +extern char *optarg; +extern struct ipread pcap, iptext, iphex; +extern struct ifnet *get_unit __P((char *, int)); +extern void init_ifp __P((void)); +extern ipnat_t *natparse __P((char *, int)); +extern hostmap_t **ipf_hm_maptable; +extern hostmap_t *ipf_hm_maplist; + +ipfmutex_t ipl_mutex, ipf_auth_mx, ipf_rw, ipf_stinsert; +ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; +ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ip_poolrw, ipf_frcache; +ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_authlk; +ipfrwlock_t ipf_tokens; +int opts = OPT_DONTOPEN; +int use_inet6 = 0; +int docksum = 0; +int pfil_delayed_copy = 0; +int main __P((int, char *[])); +int loadrules __P((char *, int)); +int kmemcpy __P((char *, long, int)); +int kstrncpy __P((char *, long, int n)); +int blockreason; +void dumpnat __P((void *)); +void dumpgroups __P((ipf_main_softc_t *)); +void dumprules __P((frentry_t *)); +void drain_log __P((char *)); +void fixv4sums __P((mb_t *, ip_t *)); + +#if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ + defined(__osf__) || defined(linux) +int ipftestioctl __P((int, ioctlcmd_t, ...)); +int ipnattestioctl __P((int, ioctlcmd_t, ...)); +int ipstatetestioctl __P((int, ioctlcmd_t, ...)); +int ipauthtestioctl __P((int, ioctlcmd_t, ...)); +int ipscantestioctl __P((int, ioctlcmd_t, ...)); +int ipsynctestioctl __P((int, ioctlcmd_t, ...)); +int ipooltestioctl __P((int, ioctlcmd_t, ...)); +#else +int ipftestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipnattestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipstatetestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipauthtestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipsynctestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipscantestioctl __P((dev_t, ioctlcmd_t, void *)); +int ipooltestioctl __P((dev_t, ioctlcmd_t, void *)); +#endif + +static ioctlfunc_t iocfunctions[IPL_LOGSIZE] = { ipftestioctl, + ipnattestioctl, + ipstatetestioctl, + ipauthtestioctl, + ipsynctestioctl, + ipscantestioctl, + ipooltestioctl, + NULL }; +static ipf_main_softc_t *softc = NULL; + + +int +main(argc,argv) + int argc; + char *argv[]; +{ + char *datain, *iface, *ifname, *logout; + int fd, i, dir, c, loaded, dump, hlen; + struct in_addr sip; + struct ifnet *ifp; + struct ipread *r; + mb_t mb, *m, *n; + ip_t *ip; + + m = &mb; + dir = 0; + dump = 0; + hlen = 0; + loaded = 0; + r = &iptext; + iface = NULL; + logout = NULL; + datain = NULL; + sip.s_addr = 0; + ifname = "anon0"; + + initparse(); + + ipf_load_all(); + + softc = ipf_create_all(NULL); + if (softc == NULL) + exit(1); + + if (ipf_init_all(softc) == -1) + exit(1); + + i = 1; + if (ipftestioctl(IPL_LOGIPF, SIOCFRENB, &i) != 0) + exit(1); + + while ((c = getopt(argc, argv, "6bCdDF:i:I:l:N:P:or:RS:T:vxX")) != -1) + switch (c) + { + case '6' : +#ifdef USE_INET6 + use_inet6 = 1; +#else + fprintf(stderr, "IPv6 not supported\n"); + exit(1); +#endif + break; + case 'b' : + opts |= OPT_BRIEF; + break; + case 'd' : + opts |= OPT_DEBUG; + break; + case 'C' : + docksum = 1; + break; + case 'D' : + dump = 1; + break; + case 'F' : + if (strcasecmp(optarg, "pcap") == 0) + r = &pcap; + else if (strcasecmp(optarg, "hex") == 0) + r = &iphex; + else if (strcasecmp(optarg, "text") == 0) + r = &iptext; + break; + case 'i' : + datain = optarg; + break; + case 'I' : + ifname = optarg; + break; + case 'l' : + logout = optarg; + break; + case 'N' : + if (ipnat_parsefile(-1, ipnat_addrule, ipnattestioctl, + optarg) == -1) + return -1; + loaded = 1; + opts |= OPT_NAT; + break; + case 'o' : + opts |= OPT_SAVEOUT; + break; + case 'P' : + if (ippool_parsefile(-1, optarg, ipooltestioctl) == -1) + return -1; + loaded = 1; + break; + case 'r' : + if (ipf_parsefile(-1, ipf_addrule, iocfunctions, + optarg) == -1) + return -1; + loaded = 1; + break; + case 'S' : + sip.s_addr = inet_addr(optarg); + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'T' : + ipf_dotuning(-1, optarg, ipftestioctl); + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + case 'x' : + opts |= OPT_HEX; + break; + } + + if (loaded == 0) { + (void)fprintf(stderr,"no rules loaded\n"); + exit(-1); + } + + if (opts & OPT_SAVEOUT) + init_ifp(); + + if (datain) + fd = (*r->r_open)(datain); + else + fd = (*r->r_open)("-"); + + if (fd < 0) { + perror("error opening input"); + exit(-1); + } + + m->m_data = (char *)m->mb_buf; + while ((i = (*r->r_readip)(m, &iface, &dir)) > 0) { + + if ((iface == NULL) || (*iface == '\0')) + iface = ifname; + + ip = MTOD(m, ip_t *); + ifp = get_unit(iface, IP_V(ip)); + + if (IP_V(ip) == 4) { + if ((r->r_flags & R_DO_CKSUM) || docksum) + fixv4sums(m, ip); + hlen = IP_HL(ip) << 2; + if (sip.s_addr) + dir = !(sip.s_addr == ip->ip_src.s_addr); + } +#ifdef USE_INET6 + else + hlen = sizeof(ip6_t); +#endif + /* ipfr_slowtimer(); */ + blockreason = 0; + m = &mb; + m->mb_ifp = ifp; + m->mb_len = i; + i = ipf_check(softc, ip, hlen, ifp, dir, &m); + if ((opts & OPT_NAT) == 0) + switch (i) + { + case -4 : + (void)printf("preauth"); + break; + case -3 : + (void)printf("account"); + break; + case -2 : + (void)printf("auth"); + break; + case -1 : + (void)printf("block"); + break; + case 0 : + (void)printf("pass"); + break; + case 1 : + if (m == NULL) + (void)printf("bad-packet"); + else + (void)printf("nomatch"); + break; + case 3 : + (void)printf("block return-rst"); + break; + case 4 : + (void)printf("block return-icmp"); + break; + case 5 : + (void)printf("block return-icmp-as-dest"); + break; + default : + (void)printf("recognised return %#x\n", i); + break; + } + + if (!(opts & OPT_BRIEF)) { + putchar(' '); + if (m != NULL) + printpacket(dir, m); + else + printpacket(dir, &mb); + printf("--------------"); + } else if ((opts & (OPT_BRIEF|OPT_NAT)) == + (OPT_NAT|OPT_BRIEF)) { + if (m != NULL) + printpacket(dir, m); + else + PRINTF("%d\n", blockreason); + } + + ipf_state_flush(softc, 1, 0); + + if (dir && (ifp != NULL) && IP_V(ip) && (m != NULL)) +#if defined(__sgi) && (IRIX < 60500) + (*ifp->if_output)(ifp, (void *)m, NULL); +#else +# if TRU64 >= 1885 + (*ifp->if_output)(ifp, (void *)m, NULL, 0, 0); +# else + (*ifp->if_output)(ifp, (void *)m, NULL, 0); +# endif +#endif + + while ((m != NULL) && (m != &mb)) { + n = m->mb_next; + freembt(m); + m = n; + } + + if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF)) + putchar('\n'); + dir = 0; + if (iface != ifname) { + free(iface); + iface = ifname; + } + m = &mb; + m->mb_data = (char *)m->mb_buf; + } + + if (i != 0) + fprintf(stderr, "readip failed: %d\n", i); + (*r->r_close)(); + + if (logout != NULL) { + drain_log(logout); + } + + if (dump == 1) { + dumpnat(softc->ipf_nat_soft); + ipf_state_dump(softc, softc->ipf_state_soft); + ipf_lookup_dump(softc, softc->ipf_state_soft); + dumpgroups(softc); + } + + ipf_fini_all(softc); + + ipf_destroy_all(softc); + + ipf_unload_all(); + + ipf_mutex_clean(); + ipf_rwlock_clean(); + + if (getenv("FINDLEAKS")) { + fflush(stdout); + abort(); + } + return 0; +} + + +#if defined(__NetBSD__) || defined(__OpenBSD__) || SOLARIS || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) || \ + defined(__osf__) || defined(linux) +int ipftestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + dev = dev; /* gcc -Wextra */ + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = ipfioctl(softc, IPL_LOGIPF, cmd, data, FWRITE|FREAD); + if (opts & OPT_DEBUG) + fprintf(stderr, "ipfioctl(IPF,%#x,%p) = %d (%d)\n", + (u_int)cmd, data, i, softc->ipf_interror); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipnattestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + dev = dev; /* gcc -Wextra */ + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = ipfioctl(softc, IPL_LOGNAT, cmd, data, FWRITE|FREAD); + if (opts & OPT_DEBUG) + fprintf(stderr, "ipfioctl(NAT,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipstatetestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + dev = dev; /* gcc -Wextra */ + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = ipfioctl(softc, IPL_LOGSTATE, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(STATE,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipauthtestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + dev = dev; /* gcc -Wextra */ + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = ipfioctl(softc, IPL_LOGAUTH, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(AUTH,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipscantestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + dev = dev; /* gcc -Wextra */ + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = ipfioctl(softc, IPL_LOGSCAN, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(SCAN,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipsynctestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + dev = dev; /* gcc -Wextra */ + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = ipfioctl(softc, IPL_LOGSYNC, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(SYNC,%#x,%p) = %d\n", + (u_int)cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipooltestioctl(int dev, ioctlcmd_t cmd, ...) +{ + caddr_t data; + va_list ap; + int i; + + dev = dev; /* gcc -Wextra */ + va_start(ap, cmd); + data = va_arg(ap, caddr_t); + va_end(ap); + + i = ipfioctl(softc, IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(POOL,%#x,%p) = %d (%d)\n", + (u_int)cmd, data, i, softc->ipf_interror); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} +#else +int ipftestioctl(dev, cmd, data) + dev_t dev; + ioctlcmd_t cmd; + void *data; +{ + int i; + + dev = dev; /* gcc -Wextra */ + i = ipfioctl(softc, IPL_LOGIPF, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(IPF,%#x,%p) = %d (%d)\n", + cmd, data, i, softc->ipf_interror); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipnattestioctl(dev, cmd, data) + dev_t dev; + ioctlcmd_t cmd; + void *data; +{ + int i; + + dev = dev; /* gcc -Wextra */ + i = ipfioctl(softc, IPL_LOGNAT, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(NAT,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipstatetestioctl(dev, cmd, data) + dev_t dev; + ioctlcmd_t cmd; + void *data; +{ + int i; + + dev = dev; /* gcc -Wextra */ + i = ipfioctl(softc, IPL_LOGSTATE, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(STATE,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipauthtestioctl(dev, cmd, data) + dev_t dev; + ioctlcmd_t cmd; + void *data; +{ + int i; + + dev = dev; /* gcc -Wextra */ + i = ipfioctl(softc, IPL_LOGAUTH, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(AUTH,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipsynctestioctl(dev, cmd, data) + dev_t dev; + ioctlcmd_t cmd; + void *data; +{ + int i; + + dev = dev; /* gcc -Wextra */ + i = ipfioctl(softc, IPL_LOGSYNC, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(SYNC,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipscantestioctl(dev, cmd, data) + dev_t dev; + ioctlcmd_t cmd; + void *data; +{ + int i; + + dev = dev; /* gcc -Wextra */ + i = ipfioctl(softc, IPL_LOGSCAN, cmd, data, FWRITE|FREAD); + if ((opts & OPT_DEBUG) || (i != 0)) + fprintf(stderr, "ipfioctl(SCAN,%#x,%p) = %d\n", cmd, data, i); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} + + +int ipooltestioctl(dev, cmd, data) + dev_t dev; + ioctlcmd_t cmd; + void *data; +{ + int i; + + dev = dev; /* gcc -Wextra */ + i = ipfioctl(softc, IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); + if (opts & OPT_DEBUG) + fprintf(stderr, "ipfioctl(POOL,%#x,%p) = %d (%d)\n", + cmd, data, i, softc->ipf_interror); + if (i != 0) { + errno = i; + return -1; + } + return 0; +} +#endif + + +int kmemcpy(addr, offset, size) + char *addr; + long offset; + int size; +{ + bcopy((char *)offset, addr, size); + return 0; +} + + +int kstrncpy(buf, pos, n) + char *buf; + long pos; + int n; +{ + char *ptr; + + ptr = (char *)pos; + + while ((n > 0) && (*buf++ = *ptr++)) + ; + return 0; +} + + +/* + * Display the built up NAT table rules and mapping entries. + */ +void dumpnat(arg) + void *arg; +{ + ipf_nat_softc_t *softn = arg; + hostmap_t *hm; + ipnat_t *ipn; + nat_t *nat; + + printf("List of active MAP/Redirect filters:\n"); + for (ipn = softn->ipf_nat_list; ipn != NULL; ipn = ipn->in_next) + printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); + printf("\nList of active sessions:\n"); + for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) { + printactivenat(nat, opts, 0); + if (nat->nat_aps) + printf("\tproxy active\n"); + } + + printf("\nHostmap table:\n"); + for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) + printhostmap(hm, hm->hm_hv); +} + + +void dumpgroups(softc) + ipf_main_softc_t *softc; +{ + frgroup_t *fg; + int i; + + printf("List of groups configured (set 0)\n"); + for (i = 0; i < IPL_LOGSIZE; i++) + for (fg = softc->ipf_groups[i][0]; fg != NULL; + fg = fg->fg_next) { + printf("Dev.%d. Group %s Ref %d Flags %#x\n", + i, fg->fg_name, fg->fg_ref, fg->fg_flags); + dumprules(fg->fg_start); + } + + printf("List of groups configured (set 1)\n"); + for (i = 0; i < IPL_LOGSIZE; i++) + for (fg = softc->ipf_groups[i][1]; fg != NULL; + fg = fg->fg_next) { + printf("Dev.%d. Group %s Ref %d Flags %#x\n", + i, fg->fg_name, fg->fg_ref, fg->fg_flags); + dumprules(fg->fg_start); + } + + printf("Rules configured (set 0, in)\n"); + dumprules(softc->ipf_rules[0][0]); + printf("Rules configured (set 0, out)\n"); + dumprules(softc->ipf_rules[1][0]); + printf("Rules configured (set 1, in)\n"); + dumprules(softc->ipf_rules[0][1]); + printf("Rules configured (set 1, out)\n"); + dumprules(softc->ipf_rules[1][1]); + + printf("Accounting rules configured (set 0, in)\n"); + dumprules(softc->ipf_acct[0][0]); + printf("Accounting rules configured (set 0, out)\n"); + dumprules(softc->ipf_acct[0][1]); + printf("Accounting rules configured (set 1, in)\n"); + dumprules(softc->ipf_acct[1][0]); + printf("Accounting rules configured (set 1, out)\n"); + dumprules(softc->ipf_acct[1][1]); +} + +void dumprules(rulehead) + frentry_t *rulehead; +{ + frentry_t *fr; + + for (fr = rulehead; fr != NULL; fr = fr->fr_next) { +#ifdef USE_QUAD_T + printf("%"PRIu64" ",(unsigned long long)fr->fr_hits); +#else + printf("%ld ", fr->fr_hits); +#endif + printfr(fr, ipftestioctl); + } +} + + +void drain_log(filename) + char *filename; +{ + char buffer[DEFAULT_IPFLOGSIZE]; + struct iovec iov; + struct uio uio; + size_t resid; + int fd, i; + + fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY, 0644); + if (fd == -1) { + perror("drain_log:open"); + return; + } + + for (i = 0; i <= IPL_LOGMAX; i++) + while (1) { + bzero((char *)&iov, sizeof(iov)); + iov.iov_base = buffer; + iov.iov_len = sizeof(buffer); + + bzero((char *)&uio, sizeof(uio)); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_resid = iov.iov_len; + resid = uio.uio_resid; + + if (ipf_log_read(softc, i, &uio) == 0) { + /* + * If nothing was read then break out. + */ + if (uio.uio_resid == resid) + break; + write(fd, buffer, resid - uio.uio_resid); + } else + break; + } + + close(fd); +} + + +void fixv4sums(m, ip) + mb_t *m; + ip_t *ip; +{ + u_char *csump, *hdr, p; + fr_info_t tmp; + int len; + + p = 0; + len = 0; + bzero((char *)&tmp, sizeof(tmp)); + + csump = (u_char *)ip; + if (IP_V(ip) == 4) { + ip->ip_sum = 0; + ip->ip_sum = ipf_cksum((u_short *)ip, IP_HL(ip) << 2); + tmp.fin_hlen = IP_HL(ip) << 2; + csump += IP_HL(ip) << 2; + p = ip->ip_p; + len = ntohs(ip->ip_len); +#ifdef USE_INET6 + } else if (IP_V(ip) == 6) { + tmp.fin_hlen = sizeof(ip6_t); + csump += sizeof(ip6_t); + p = ((ip6_t *)ip)->ip6_nxt; + len = ntohs(((ip6_t *)ip)->ip6_plen); + len += sizeof(ip6_t); +#endif + } + tmp.fin_plen = len; + tmp.fin_dlen = len - tmp.fin_hlen; + + switch (p) + { + case IPPROTO_TCP : + hdr = csump; + csump += offsetof(tcphdr_t, th_sum); + break; + case IPPROTO_UDP : + hdr = csump; + csump += offsetof(udphdr_t, uh_sum); + break; + case IPPROTO_ICMP : + hdr = csump; + csump += offsetof(icmphdr_t, icmp_cksum); + break; + default : + csump = NULL; + hdr = NULL; + break; + } + if (hdr != NULL) { + tmp.fin_m = m; + tmp.fin_mp = &m; + tmp.fin_dp = hdr; + tmp.fin_ip = ip; + tmp.fin_plen = len; + *csump = 0; + *(u_short *)csump = fr_cksum(&tmp, ip, p, hdr); + } +} + +void +ip_fillid(struct ip *ip) +{ + static uint16_t ip_id; + + ip->ip_id = ip_id++; +} diff --git a/contrib/ipfilter/tools/ipmon.c b/contrib/ipfilter/tools/ipmon.c new file mode 100644 index 0000000..1c52e7f --- /dev/null +++ b/contrib/ipfilter/tools/ipmon.c @@ -0,0 +1,1910 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#include "ipf.h" +#include "ipmon.h" +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <syslog.h> +#include <ctype.h> +#include <fcntl.h> +#include <signal.h> + +#if !defined(lint) +static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + + +#if defined(sun) && !defined(SOLARIS2) +#define STRERROR(x) sys_errlist[x] +extern char *sys_errlist[]; +#else +#define STRERROR(x) strerror(x) +#endif + +extern int optind; +extern char *optarg; + +extern ipmon_saver_t executesaver; +extern ipmon_saver_t filesaver; +extern ipmon_saver_t nothingsaver; +extern ipmon_saver_t snmpv1saver; +extern ipmon_saver_t snmpv2saver; +extern ipmon_saver_t syslogsaver; + + +struct flags { + int value; + char flag; +}; + +typedef struct logsource { + int fd; + int logtype; + char *file; + int regular; + size_t size; +} logsource_t; + +typedef struct config { + int opts; + int maxfd; + logsource_t logsrc[3]; + fd_set fdmr; + FILE *blog; + char *bfile; + FILE *log; + char *file; + char *cfile; +} config_t; + +typedef struct icmp_subtype { + int ist_val; + char *ist_name; +} icmp_subtype_t; + +typedef struct icmp_type { + int it_val; + struct icmp_subtype *it_subtable; + size_t it_stsize; + char *it_name; +} icmp_type_t; + + +#define IST_SZ(x) (sizeof(x)/sizeof(icmp_subtype_t)) + + +struct flags tcpfl[] = { + { TH_ACK, 'A' }, + { TH_RST, 'R' }, + { TH_SYN, 'S' }, + { TH_FIN, 'F' }, + { TH_URG, 'U' }, + { TH_PUSH,'P' }, + { TH_ECN, 'E' }, + { TH_CWR, 'C' }, + { 0, '\0' } +}; + +char *reasons[] = { + "filter-rule", + "log-or-block_1", + "pps-rate", + "jumbogram", + "makefrip-fail", + "state_add-fail", + "updateipid-fail", + "log-or-block_2", + "decap-fail", + "auth_new-fail", + "auth_captured", + "coalesce-fail", + "pullup-fail", + "auth-feedback", + "bad-frag", + "natv4_out-fail", + "natv4_in-fail", + "natv6_out-fail", + "natv6_in-fail", +}; + +#ifdef MENTAT +static char *pidfile = "/etc/opt/ipf/ipmon.pid"; +#else +# if BSD >= 199306 +static char *pidfile = "/var/run/ipmon.pid"; +# else +static char *pidfile = "/etc/ipmon.pid"; +# endif +#endif + +static char line[2048]; +static int donehup = 0; +static void usage __P((char *)); +static void handlehup __P((int)); +static void flushlogs __P((char *, FILE *)); +static void print_log __P((config_t *, logsource_t *, char *, int)); +static void print_ipflog __P((config_t *, char *, int)); +static void print_natlog __P((config_t *, char *, int)); +static void print_statelog __P((config_t *, char *, int)); +static int read_log __P((int, int *, char *, int)); +static void write_pid __P((char *)); +static char *icmpname __P((u_int, u_int)); +static char *icmpname6 __P((u_int, u_int)); +static icmp_type_t *find_icmptype __P((int, icmp_type_t *, size_t)); +static icmp_subtype_t *find_icmpsubtype __P((int, icmp_subtype_t *, size_t)); +#ifdef __hpux +static struct tm *get_tm __P((u_32_t)); +#else +static struct tm *get_tm __P((time_t)); +#endif + +char *portlocalname __P((int, char *, u_int)); +int main __P((int, char *[])); + +static void logopts __P((int, char *)); +static void init_tabs __P((void)); +static char *getlocalproto __P((u_int)); +static void openlogs __P((config_t *conf)); +static int read_loginfo __P((config_t *conf)); +static void initconfig __P((config_t *conf)); + +static char **protocols = NULL; +static char **udp_ports = NULL; +static char **tcp_ports = NULL; + + +#define HOSTNAMEV4(b) hostname(AF_INET, (u_32_t *)&(b)) + +#ifndef LOGFAC +#define LOGFAC LOG_LOCAL0 +#endif +int logfac = LOGFAC; +int ipmonopts = 0; +int opts = OPT_NORESOLVE; +int use_inet6 = 0; + + +static icmp_subtype_t icmpunreachnames[] = { + { ICMP_UNREACH_NET, "net" }, + { ICMP_UNREACH_HOST, "host" }, + { ICMP_UNREACH_PROTOCOL, "protocol" }, + { ICMP_UNREACH_PORT, "port" }, + { ICMP_UNREACH_NEEDFRAG, "needfrag" }, + { ICMP_UNREACH_SRCFAIL, "srcfail" }, + { ICMP_UNREACH_NET_UNKNOWN, "net_unknown" }, + { ICMP_UNREACH_HOST_UNKNOWN, "host_unknown" }, + { ICMP_UNREACH_NET, "isolated" }, + { ICMP_UNREACH_NET_PROHIB, "net_prohib" }, + { ICMP_UNREACH_NET_PROHIB, "host_prohib" }, + { ICMP_UNREACH_TOSNET, "tosnet" }, + { ICMP_UNREACH_TOSHOST, "toshost" }, + { ICMP_UNREACH_ADMIN_PROHIBIT, "admin_prohibit" }, + { -2, NULL } +}; + +static icmp_subtype_t redirectnames[] = { + { ICMP_REDIRECT_NET, "net" }, + { ICMP_REDIRECT_HOST, "host" }, + { ICMP_REDIRECT_TOSNET, "tosnet" }, + { ICMP_REDIRECT_TOSHOST, "toshost" }, + { -2, NULL } +}; + +static icmp_subtype_t timxceednames[] = { + { ICMP_TIMXCEED_INTRANS, "transit" }, + { ICMP_TIMXCEED_REASS, "reassem" }, + { -2, NULL } +}; + +static icmp_subtype_t paramnames[] = { + { ICMP_PARAMPROB_ERRATPTR, "errata_pointer" }, + { ICMP_PARAMPROB_OPTABSENT, "optmissing" }, + { ICMP_PARAMPROB_LENGTH, "length" }, + { -2, NULL } +}; + +static icmp_type_t icmptypes4[] = { + { ICMP_ECHOREPLY, NULL, 0, "echoreply" }, + { -1, NULL, 0, NULL }, + { -1, NULL, 0, NULL }, + { ICMP_UNREACH, icmpunreachnames, + IST_SZ(icmpunreachnames),"unreach" }, + { ICMP_SOURCEQUENCH, NULL, 0, "sourcequench" }, + { ICMP_REDIRECT, redirectnames, + IST_SZ(redirectnames), "redirect" }, + { -1, NULL, 0, NULL }, + { -1, NULL, 0, NULL }, + { ICMP_ECHO, NULL, 0, "echo" }, + { ICMP_ROUTERADVERT, NULL, 0, "routeradvert" }, + { ICMP_ROUTERSOLICIT, NULL, 0, "routersolicit" }, + { ICMP_TIMXCEED, timxceednames, + IST_SZ(timxceednames), "timxceed" }, + { ICMP_PARAMPROB, paramnames, + IST_SZ(paramnames), "paramprob" }, + { ICMP_TSTAMP, NULL, 0, "timestamp" }, + { ICMP_TSTAMPREPLY, NULL, 0, "timestampreply" }, + { ICMP_IREQ, NULL, 0, "inforeq" }, + { ICMP_IREQREPLY, NULL, 0, "inforeply" }, + { ICMP_MASKREQ, NULL, 0, "maskreq" }, + { ICMP_MASKREPLY, NULL, 0, "maskreply" }, + { -2, NULL, 0, NULL } +}; + +static icmp_subtype_t icmpredirect6[] = { + { ICMP6_DST_UNREACH_NOROUTE, "noroute" }, + { ICMP6_DST_UNREACH_ADMIN, "admin" }, + { ICMP6_DST_UNREACH_NOTNEIGHBOR, "neighbour" }, + { ICMP6_DST_UNREACH_ADDR, "address" }, + { ICMP6_DST_UNREACH_NOPORT, "noport" }, + { -2, NULL } +}; + +static icmp_subtype_t icmptimexceed6[] = { + { ICMP6_TIME_EXCEED_TRANSIT, "intransit" }, + { ICMP6_TIME_EXCEED_REASSEMBLY, "reassem" }, + { -2, NULL } +}; + +static icmp_subtype_t icmpparamprob6[] = { + { ICMP6_PARAMPROB_HEADER, "header" }, + { ICMP6_PARAMPROB_NEXTHEADER, "nextheader" }, + { ICMP6_PARAMPROB_OPTION, "option" }, + { -2, NULL } +}; + +static icmp_subtype_t icmpquerysubject6[] = { + { ICMP6_NI_SUBJ_IPV6, "ipv6" }, + { ICMP6_NI_SUBJ_FQDN, "fqdn" }, + { ICMP6_NI_SUBJ_IPV4, "ipv4" }, + { -2, NULL }, +}; + +static icmp_subtype_t icmpnodeinfo6[] = { + { ICMP6_NI_SUCCESS, "success" }, + { ICMP6_NI_REFUSED, "refused" }, + { ICMP6_NI_UNKNOWN, "unknown" }, + { -2, NULL } +}; + +static icmp_subtype_t icmprenumber6[] = { + { ICMP6_ROUTER_RENUMBERING_COMMAND, "command" }, + { ICMP6_ROUTER_RENUMBERING_RESULT, "result" }, + { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "seqnum_reset" }, + { -2, NULL } +}; + +static icmp_type_t icmptypes6[] = { + { 0, NULL, 0, NULL }, + { ICMP6_DST_UNREACH, icmpredirect6, + IST_SZ(icmpredirect6), "unreach" }, + { ICMP6_PACKET_TOO_BIG, NULL, 0, "toobig" }, + { ICMP6_TIME_EXCEEDED, icmptimexceed6, + IST_SZ(icmptimexceed6), "timxceed" }, + { ICMP6_PARAM_PROB, icmpparamprob6, + IST_SZ(icmpparamprob6), "paramprob" }, + { ICMP6_ECHO_REQUEST, NULL, 0, "echo" }, + { ICMP6_ECHO_REPLY, NULL, 0, "echoreply" }, + { ICMP6_MEMBERSHIP_QUERY, icmpquerysubject6, + IST_SZ(icmpquerysubject6), "groupmemberquery" }, + { ICMP6_MEMBERSHIP_REPORT,NULL, 0, "groupmemberreport" }, + { ICMP6_MEMBERSHIP_REDUCTION,NULL, 0, "groupmemberterm" }, + { ND_ROUTER_SOLICIT, NULL, 0, "routersolicit" }, + { ND_ROUTER_ADVERT, NULL, 0, "routeradvert" }, + { ND_NEIGHBOR_SOLICIT, NULL, 0, "neighborsolicit" }, + { ND_NEIGHBOR_ADVERT, NULL, 0, "neighboradvert" }, + { ND_REDIRECT, NULL, 0, "redirect" }, + { ICMP6_ROUTER_RENUMBERING, icmprenumber6, + IST_SZ(icmprenumber6), "routerrenumber" }, + { ICMP6_WRUREQUEST, NULL, 0, "whoareyourequest" }, + { ICMP6_WRUREPLY, NULL, 0, "whoareyoureply" }, + { ICMP6_FQDN_QUERY, NULL, 0, "fqdnquery" }, + { ICMP6_FQDN_REPLY, NULL, 0, "fqdnreply" }, + { ICMP6_NI_QUERY, icmpnodeinfo6, + IST_SZ(icmpnodeinfo6), "nodeinforequest" }, + { ICMP6_NI_REPLY, NULL, 0, "nodeinforeply" }, + { MLD6_MTRACE_RESP, NULL, 0, "mtraceresponse" }, + { MLD6_MTRACE, NULL, 0, "mtracerequest" }, + { -2, NULL, 0, NULL } +}; + +static icmp_subtype_t *find_icmpsubtype(type, table, tablesz) + int type; + icmp_subtype_t *table; + size_t tablesz; +{ + icmp_subtype_t *ist; + int i; + + if (tablesz < 2) + return NULL; + + if ((type < 0) || (type > table[tablesz - 2].ist_val)) + return NULL; + + i = type; + if (table[type].ist_val == type) + return table + type; + + for (i = 0, ist = table; ist->ist_val != -2; i++, ist++) + if (ist->ist_val == type) + return ist; + return NULL; +} + + +static icmp_type_t *find_icmptype(type, table, tablesz) + int type; + icmp_type_t *table; + size_t tablesz; +{ + icmp_type_t *it; + int i; + + if (tablesz < 2) + return NULL; + + if ((type < 0) || (type > table[tablesz - 2].it_val)) + return NULL; + + i = type; + if (table[type].it_val == type) + return table + type; + + for (i = 0, it = table; it->it_val != -2; i++, it++) + if (it->it_val == type) + return it; + return NULL; +} + + +static void handlehup(sig) + int sig; +{ + signal(SIGHUP, handlehup); + donehup = 1; +} + + +static void init_tabs() +{ + struct protoent *p; + struct servent *s; + char *name, **tab; + int port, i; + + if (protocols != NULL) { + for (i = 0; i < 256; i++) + if (protocols[i] != NULL) { + free(protocols[i]); + protocols[i] = NULL; + } + free(protocols); + protocols = NULL; + } + protocols = (char **)malloc(256 * sizeof(*protocols)); + if (protocols != NULL) { + bzero((char *)protocols, 256 * sizeof(*protocols)); + + setprotoent(1); + while ((p = getprotoent()) != NULL) + if (p->p_proto >= 0 && p->p_proto <= 255 && + p->p_name != NULL && protocols[p->p_proto] == NULL) + protocols[p->p_proto] = strdup(p->p_name); + endprotoent(); + if (protocols[0]) + free(protocols[0]); + protocols[0] = strdup("ip"); +#if defined(_AIX51) + if (protocols[252]) + free(protocols[252]); + protocols[252] = NULL; +#endif + } + + if (udp_ports != NULL) { + for (i = 0; i < 65536; i++) + if (udp_ports[i] != NULL) { + free(udp_ports[i]); + udp_ports[i] = NULL; + } + free(udp_ports); + udp_ports = NULL; + } + udp_ports = (char **)malloc(65536 * sizeof(*udp_ports)); + if (udp_ports != NULL) + bzero((char *)udp_ports, 65536 * sizeof(*udp_ports)); + + if (tcp_ports != NULL) { + for (i = 0; i < 65536; i++) + if (tcp_ports[i] != NULL) { + free(tcp_ports[i]); + tcp_ports[i] = NULL; + } + free(tcp_ports); + tcp_ports = NULL; + } + tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports)); + if (tcp_ports != NULL) + bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports)); + + setservent(1); + while ((s = getservent()) != NULL) { + if (s->s_proto == NULL) + continue; + else if (!strcmp(s->s_proto, "tcp")) { + port = ntohs(s->s_port); + name = s->s_name; + tab = tcp_ports; + } else if (!strcmp(s->s_proto, "udp")) { + port = ntohs(s->s_port); + name = s->s_name; + tab = udp_ports; + } else + continue; + if ((port < 0 || port > 65535) || (name == NULL)) + continue; + if (tab != NULL) + tab[port] = strdup(name); + } + endservent(); +} + + +static char *getlocalproto(p) + u_int p; +{ + static char pnum[4]; + char *s; + + p &= 0xff; + s = protocols ? protocols[p] : NULL; + if (s == NULL) { + sprintf(pnum, "%u", p); + s = pnum; + } + return s; +} + + +static int read_log(fd, lenp, buf, bufsize) + int fd, bufsize, *lenp; + char *buf; +{ + int nr; + + if (bufsize > IPFILTER_LOGSIZE) + bufsize = IPFILTER_LOGSIZE; + + nr = read(fd, buf, bufsize); + if (!nr) + return 2; + if ((nr < 0) && (errno != EINTR)) + return -1; + *lenp = nr; + return 0; +} + + +char *portlocalname(res, proto, port) + int res; + char *proto; + u_int port; +{ + static char pname[8]; + char *s; + + port = ntohs(port); + port &= 0xffff; + sprintf(pname, "%u", port); + if (!res || (ipmonopts & IPMON_PORTNUM)) + return pname; + s = NULL; + if (!strcmp(proto, "tcp")) + s = tcp_ports[port]; + else if (!strcmp(proto, "udp")) + s = udp_ports[port]; + if (s == NULL) + s = pname; + return s; +} + + +static char *icmpname(type, code) + u_int type; + u_int code; +{ + static char name[80]; + icmp_subtype_t *ist; + icmp_type_t *it; + char *s; + + s = NULL; + it = find_icmptype(type, icmptypes4, sizeof(icmptypes4) / sizeof(*it)); + if (it != NULL) + s = it->it_name; + + if (s == NULL) + sprintf(name, "icmptype(%d)/", type); + else + sprintf(name, "%s/", s); + + ist = NULL; + if (it != NULL && it->it_subtable != NULL) + ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); + + if (ist != NULL && ist->ist_name != NULL) + strcat(name, ist->ist_name); + else + sprintf(name + strlen(name), "%d", code); + + return name; +} + +static char *icmpname6(type, code) + u_int type; + u_int code; +{ + static char name[80]; + icmp_subtype_t *ist; + icmp_type_t *it; + char *s; + + s = NULL; + it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it)); + if (it != NULL) + s = it->it_name; + + if (s == NULL) + sprintf(name, "icmpv6type(%d)/", type); + else + sprintf(name, "%s/", s); + + ist = NULL; + if (it != NULL && it->it_subtable != NULL) + ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); + + if (ist != NULL && ist->ist_name != NULL) + strcat(name, ist->ist_name); + else + sprintf(name + strlen(name), "%d", code); + + return name; +} + + +void dumphex(log, dopts, buf, len) + FILE *log; + int dopts; + char *buf; + int len; +{ + char hline[80]; + int i, j, k; + u_char *s = (u_char *)buf, *t = (u_char *)hline; + + if (buf == NULL || len == 0) + return; + + *hline = '\0'; + + for (i = len, j = 0; i; i--, j++, s++) { + if (j && !(j & 0xf)) { + *t++ = '\n'; + *t = '\0'; + if ((dopts & IPMON_SYSLOG)) + syslog(LOG_INFO, "%s", hline); + else if (log != NULL) + fputs(hline, log); + t = (u_char *)hline; + *t = '\0'; + } + sprintf((char *)t, "%02x", *s & 0xff); + t += 2; + if (!((j + 1) & 0xf)) { + s -= 15; + sprintf((char *)t, " "); + t += 8; + for (k = 16; k; k--, s++) + *t++ = (isprint(*s) ? *s : '.'); + s--; + } + + if ((j + 1) & 0xf) + *t++ = ' ';; + } + + if (j & 0xf) { + for (k = 16 - (j & 0xf); k; k--) { + *t++ = ' '; + *t++ = ' '; + *t++ = ' '; + } + sprintf((char *)t, " "); + t += 7; + s -= j & 0xf; + for (k = j & 0xf; k; k--, s++) + *t++ = (isprint(*s) ? *s : '.'); + *t++ = '\n'; + *t = '\0'; + } + if ((dopts & IPMON_SYSLOG) != 0) + syslog(LOG_INFO, "%s", hline); + else if (log != NULL) { + fputs(hline, log); + fflush(log); + } +} + + +static struct tm *get_tm(sec) +#ifdef __hpux + u_32_t sec; +#else + time_t sec; +#endif +{ + struct tm *tm; + time_t t; + + t = sec; + tm = localtime(&t); + return tm; +} + +static void print_natlog(conf, buf, blen) + config_t *conf; + char *buf; + int blen; +{ + static u_32_t seqnum = 0; + int res, i, len, family; + struct natlog *nl; + struct tm *tm; + iplog_t *ipl; + char *proto; + int simple; + char *t; + + t = line; + simple = 0; + ipl = (iplog_t *)buf; + if (ipl->ipl_seqnum != seqnum) { + if ((ipmonopts & IPMON_SYSLOG) != 0) { + syslog(LOG_WARNING, + "missed %u NAT log entries: %u %u", + ipl->ipl_seqnum - seqnum, seqnum, + ipl->ipl_seqnum); + } else { + (void) fprintf(conf->log, + "missed %u NAT log entries: %u %u\n", + ipl->ipl_seqnum - seqnum, seqnum, + ipl->ipl_seqnum); + } + } + seqnum = ipl->ipl_seqnum + ipl->ipl_count; + + nl = (struct natlog *)((char *)ipl + sizeof(*ipl)); + res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; + tm = get_tm(ipl->ipl_sec); + len = sizeof(line); + + if (!(ipmonopts & IPMON_SYSLOG)) { + (void) strftime(t, len, "%d/%m/%Y ", tm); + i = strlen(t); + len -= i; + t += i; + } + (void) strftime(t, len, "%T", tm); + t += strlen(t); + sprintf(t, ".%-.6ld @%hd ", (long)ipl->ipl_usec, nl->nl_rule + 1); + t += strlen(t); + + switch (nl->nl_action) + { + case NL_NEW : + strcpy(t, "NAT:NEW"); + break; + + case NL_FLUSH : + strcpy(t, "NAT:FLUSH"); + break; + + case NL_CLONE : + strcpy(t, "NAT:CLONE"); + break; + + case NL_EXPIRE : + strcpy(t, "NAT:EXPIRE"); + break; + + case NL_DESTROY : + strcpy(t, "NAT:DESTROY"); + break; + + case NL_PURGE : + strcpy(t, "NAT:PURGE"); + break; + + default : + sprintf(t, "NAT:Action(%d)", nl->nl_action); + break; + } + t += strlen(t); + + + switch (nl->nl_type) + { + case NAT_MAP : + strcpy(t, "-MAP "); + simple = 1; + break; + + case NAT_REDIRECT : + strcpy(t, "-RDR "); + simple = 1; + break; + + case NAT_BIMAP : + strcpy(t, "-BIMAP "); + simple = 1; + break; + + case NAT_MAPBLK : + strcpy(t, "-MAPBLOCK "); + simple = 1; + break; + + case NAT_REWRITE|NAT_MAP : + strcpy(t, "-RWR_MAP "); + break; + + case NAT_REWRITE|NAT_REDIRECT : + strcpy(t, "-RWR_RDR "); + break; + + case NAT_ENCAP|NAT_MAP : + strcpy(t, "-ENC_MAP "); + break; + + case NAT_ENCAP|NAT_REDIRECT : + strcpy(t, "-ENC_RDR "); + break; + + case NAT_DIVERTUDP|NAT_MAP : + strcpy(t, "-DIV_MAP "); + break; + + case NAT_DIVERTUDP|NAT_REDIRECT : + strcpy(t, "-DIV_RDR "); + break; + + default : + sprintf(t, "-Type(%d) ", nl->nl_type); + break; + } + t += strlen(t); + + proto = getlocalproto(nl->nl_p[0]); + + family = vtof(nl->nl_v[0]); + + if (simple == 1) { + sprintf(t, "%s,%s <- -> ", hostname(family, nl->nl_osrcip.i6), + portlocalname(res, proto, (u_int)nl->nl_osrcport)); + t += strlen(t); + sprintf(t, "%s,%s ", hostname(family, nl->nl_nsrcip.i6), + portlocalname(res, proto, (u_int)nl->nl_nsrcport)); + t += strlen(t); + sprintf(t, "[%s,%s] ", hostname(family, nl->nl_odstip.i6), + portlocalname(res, proto, (u_int)nl->nl_odstport)); + } else { + sprintf(t, "%s,%s ", hostname(family, nl->nl_osrcip.i6), + portlocalname(res, proto, (u_int)nl->nl_osrcport)); + t += strlen(t); + sprintf(t, "%s,%s <- -> ", hostname(family, nl->nl_odstip.i6), + portlocalname(res, proto, (u_int)nl->nl_odstport)); + t += strlen(t); + sprintf(t, "%s,%s ", hostname(family, nl->nl_nsrcip.i6), + portlocalname(res, proto, (u_int)nl->nl_nsrcport)); + t += strlen(t); + sprintf(t, "%s,%s ", hostname(family, nl->nl_ndstip.i6), + portlocalname(res, proto, (u_int)nl->nl_ndstport)); + } + t += strlen(t); + + strcpy(t, getlocalproto(nl->nl_p[0])); + t += strlen(t); + + if (nl->nl_action == NL_EXPIRE || nl->nl_action == NL_FLUSH) { +#ifdef USE_QUAD_T +# ifdef PRId64 + sprintf(t, " Pkts %" PRId64 "/%" PRId64 " Bytes %" PRId64 "/%" + PRId64, +# else + sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd", +# endif +#else + sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld", +#endif + nl->nl_pkts[0], nl->nl_pkts[1], + nl->nl_bytes[0], nl->nl_bytes[1]); + t += strlen(t); + } + + *t++ = '\n'; + *t++ = '\0'; + if (ipmonopts & IPMON_SYSLOG) + syslog(LOG_INFO, "%s", line); + else if (conf->log != NULL) + (void) fprintf(conf->log, "%s", line); +} + + +static void print_statelog(conf, buf, blen) + config_t *conf; + char *buf; + int blen; +{ + static u_32_t seqnum = 0; + int res, i, len, family; + struct ipslog *sl; + char *t, *proto; + struct tm *tm; + iplog_t *ipl; + + t = line; + ipl = (iplog_t *)buf; + if (ipl->ipl_seqnum != seqnum) { + if ((ipmonopts & IPMON_SYSLOG) != 0) { + syslog(LOG_WARNING, + "missed %u state log entries: %u %u", + ipl->ipl_seqnum - seqnum, seqnum, + ipl->ipl_seqnum); + } else { + (void) fprintf(conf->log, + "missed %u state log entries: %u %u\n", + ipl->ipl_seqnum - seqnum, seqnum, + ipl->ipl_seqnum); + } + } + seqnum = ipl->ipl_seqnum + ipl->ipl_count; + + sl = (struct ipslog *)((char *)ipl + sizeof(*ipl)); + res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; + tm = get_tm(ipl->ipl_sec); + len = sizeof(line); + if (!(ipmonopts & IPMON_SYSLOG)) { + (void) strftime(t, len, "%d/%m/%Y ", tm); + i = strlen(t); + len -= i; + t += i; + } + (void) strftime(t, len, "%T", tm); + t += strlen(t); + sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec); + t += strlen(t); + + family = vtof(sl->isl_v); + + switch (sl->isl_type) + { + case ISL_NEW : + strcpy(t, "STATE:NEW "); + break; + + case ISL_CLONE : + strcpy(t, "STATE:CLONED "); + break; + + case ISL_EXPIRE : + if ((sl->isl_p == IPPROTO_TCP) && + (sl->isl_state[0] > IPF_TCPS_ESTABLISHED || + sl->isl_state[1] > IPF_TCPS_ESTABLISHED)) + strcpy(t, "STATE:CLOSE "); + else + strcpy(t, "STATE:EXPIRE "); + break; + + case ISL_FLUSH : + strcpy(t, "STATE:FLUSH "); + break; + + case ISL_INTERMEDIATE : + strcpy(t, "STATE:INTERMEDIATE "); + break; + + case ISL_REMOVE : + strcpy(t, "STATE:REMOVE "); + break; + + case ISL_KILLED : + strcpy(t, "STATE:KILLED "); + break; + + case ISL_UNLOAD : + strcpy(t, "STATE:UNLOAD "); + break; + + default : + sprintf(t, "Type: %d ", sl->isl_type); + break; + } + t += strlen(t); + + proto = getlocalproto(sl->isl_p); + + if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { + sprintf(t, "%s,%s -> ", + hostname(family, (u_32_t *)&sl->isl_src), + portlocalname(res, proto, (u_int)sl->isl_sport)); + t += strlen(t); + sprintf(t, "%s,%s PR %s", + hostname(family, (u_32_t *)&sl->isl_dst), + portlocalname(res, proto, (u_int)sl->isl_dport), proto); + } else if (sl->isl_p == IPPROTO_ICMP) { + sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); + t += strlen(t); + sprintf(t, "%s PR icmp %d", + hostname(family, (u_32_t *)&sl->isl_dst), + sl->isl_itype); + } else if (sl->isl_p == IPPROTO_ICMPV6) { + sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); + t += strlen(t); + sprintf(t, "%s PR icmpv6 %d", + hostname(family, (u_32_t *)&sl->isl_dst), + sl->isl_itype); + } else { + sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); + t += strlen(t); + sprintf(t, "%s PR %s", + hostname(family, (u_32_t *)&sl->isl_dst), proto); + } + t += strlen(t); + if (sl->isl_tag != FR_NOLOGTAG) { + sprintf(t, " tag %u", sl->isl_tag); + t += strlen(t); + } + if (sl->isl_type != ISL_NEW) { + sprintf(t, +#ifdef USE_QUAD_T +#ifdef PRId64 + " Forward: Pkts in %" PRId64 " Bytes in %" PRId64 + " Pkts out %" PRId64 " Bytes out %" PRId64 + " Backward: Pkts in %" PRId64 " Bytes in %" PRId64 + " Pkts out %" PRId64 " Bytes out %" PRId64, +#else + " Forward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd Backward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd", +#endif /* PRId64 */ +#else + " Forward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld Backward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld", +#endif + sl->isl_pkts[0], sl->isl_bytes[0], + sl->isl_pkts[1], sl->isl_bytes[1], + sl->isl_pkts[2], sl->isl_bytes[2], + sl->isl_pkts[3], sl->isl_bytes[3]); + + t += strlen(t); + } + + *t++ = '\n'; + *t++ = '\0'; + if (ipmonopts & IPMON_SYSLOG) + syslog(LOG_INFO, "%s", line); + else if (conf->log != NULL) + (void) fprintf(conf->log, "%s", line); +} + + +static void print_log(conf, log, buf, blen) + config_t *conf; + logsource_t *log; + char *buf; + int blen; +{ + char *bp, *bpo; + iplog_t *ipl; + int psize; + + bp = NULL; + bpo = NULL; + + while (blen > 0) { + ipl = (iplog_t *)buf; + if ((u_long)ipl & (sizeof(long)-1)) { + if (bp) + bpo = bp; + bp = (char *)malloc(blen); + bcopy((char *)ipl, bp, blen); + if (bpo) { + free(bpo); + bpo = NULL; + } + buf = bp; + continue; + } + + psize = ipl->ipl_dsize; + if (psize > blen) + break; + + if (conf->blog != NULL) { + fwrite(buf, psize, 1, conf->blog); + fflush(conf->blog); + } + + if (log->logtype == IPL_LOGIPF) { + if (ipl->ipl_magic == IPL_MAGIC) + print_ipflog(conf, buf, psize); + + } else if (log->logtype == IPL_LOGNAT) { + if (ipl->ipl_magic == IPL_MAGIC_NAT) + print_natlog(conf, buf, psize); + + } else if (log->logtype == IPL_LOGSTATE) { + if (ipl->ipl_magic == IPL_MAGIC_STATE) + print_statelog(conf, buf, psize); + } + + blen -= psize; + buf += psize; + } + if (bp) + free(bp); + return; +} + + +static void print_ipflog(conf, buf, blen) + config_t *conf; + char *buf; + int blen; +{ + static u_32_t seqnum = 0; + int i, f, lvl, res, len, off, plen, ipoff, defaction; + struct icmp *icmp; + struct icmp *ic; + char *t, *proto; + ip_t *ipc, *ip; + struct tm *tm; + u_32_t *s, *d; + u_short hl, p; + ipflog_t *ipf; + iplog_t *ipl; + tcphdr_t *tp; +#ifdef USE_INET6 + struct ip6_ext *ehp; + u_short ehl; + ip6_t *ip6; + int go; +#endif + + ipl = (iplog_t *)buf; + if (ipl->ipl_seqnum != seqnum) { + if ((ipmonopts & IPMON_SYSLOG) != 0) { + syslog(LOG_WARNING, + "missed %u ipf log entries: %u %u", + ipl->ipl_seqnum - seqnum, seqnum, + ipl->ipl_seqnum); + } else { + (void) fprintf(conf->log, + "missed %u ipf log entries: %u %u\n", + ipl->ipl_seqnum - seqnum, seqnum, + ipl->ipl_seqnum); + } + } + seqnum = ipl->ipl_seqnum + ipl->ipl_count; + + ipf = (ipflog_t *)((char *)buf + sizeof(*ipl)); + ip = (ip_t *)((char *)ipf + sizeof(*ipf)); + f = ipf->fl_family; + res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; + t = line; + *t = '\0'; + tm = get_tm(ipl->ipl_sec); + + len = sizeof(line); + if (!(ipmonopts & IPMON_SYSLOG)) { + (void) strftime(t, len, "%d/%m/%Y ", tm); + i = strlen(t); + len -= i; + t += i; + } + (void) strftime(t, len, "%T", tm); + t += strlen(t); + sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec); + t += strlen(t); + if (ipl->ipl_count > 1) { + sprintf(t, "%dx ", ipl->ipl_count); + t += strlen(t); + } +#if (defined(MENTAT) || \ + (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ + (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux) + { + char ifname[sizeof(ipf->fl_ifname) + 1]; + + strncpy(ifname, ipf->fl_ifname, sizeof(ipf->fl_ifname)); + ifname[sizeof(ipf->fl_ifname)] = '\0'; + sprintf(t, "%s", ifname); + t += strlen(t); +# if defined(MENTAT) || defined(linux) +# if defined(linux) + /* + * On Linux, the loopback interface is just "lo", not "lo0". + */ + if (strcmp(ifname, "lo") != 0) +# endif + if (ISALPHA(*(t - 1))) { + sprintf(t, "%d", ipf->fl_unit); + t += strlen(t); + } +# endif + } +#else + for (len = 0; len < 3; len++) + if (ipf->fl_ifname[len] == '\0') + break; + if (ipf->fl_ifname[len]) + len++; + sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit); + t += strlen(t); +#endif + if ((ipf->fl_group[0] == (char)~0) && (ipf->fl_group[1] == '\0')) + strcat(t, " @-1:"); + else if (ipf->fl_group[0] == '\0') + (void) strcpy(t, " @0:"); + else + sprintf(t, " @%s:", ipf->fl_group); + t += strlen(t); + if (ipf->fl_rule == 0xffffffff) + strcat(t, "-1 "); + else + sprintf(t, "%u ", ipf->fl_rule + 1); + t += strlen(t); + + lvl = LOG_NOTICE; + + if (ipf->fl_lflags & FI_SHORT) { + *t++ = 'S'; + lvl = LOG_ERR; + } + + if (FR_ISPASS(ipf->fl_flags)) { + if (ipf->fl_flags & FR_LOGP) + *t++ = 'p'; + else + *t++ = 'P'; + } else if (FR_ISBLOCK(ipf->fl_flags)) { + if (ipf->fl_flags & FR_LOGB) + *t++ = 'b'; + else + *t++ = 'B'; + lvl = LOG_WARNING; + } else if ((ipf->fl_flags & FR_LOGMASK) == FR_LOG) { + *t++ = 'L'; + lvl = LOG_INFO; + } else if (ipf->fl_flags & FF_LOGNOMATCH) { + *t++ = 'n'; + } else { + *t++ = '?'; + lvl = LOG_EMERG; + } + if (ipf->fl_loglevel != 0xffff) + lvl = ipf->fl_loglevel; + *t++ = ' '; + *t = '\0'; + + if (f == AF_INET) { + hl = IP_HL(ip) << 2; + ipoff = ntohs(ip->ip_off); + off = ipoff & IP_OFFMASK; + p = (u_short)ip->ip_p; + s = (u_32_t *)&ip->ip_src; + d = (u_32_t *)&ip->ip_dst; + plen = ntohs(ip->ip_len); + } else +#ifdef USE_INET6 + if (f == AF_INET6) { + off = 0; + ipoff = 0; + hl = sizeof(ip6_t); + ip6 = (ip6_t *)ip; + p = (u_short)ip6->ip6_nxt; + s = (u_32_t *)&ip6->ip6_src; + d = (u_32_t *)&ip6->ip6_dst; + plen = hl + ntohs(ip6->ip6_plen); + go = 1; + ehp = (struct ip6_ext *)((char *)ip6 + hl); + while (go == 1) { + switch (p) + { + case IPPROTO_HOPOPTS : + case IPPROTO_MOBILITY : + case IPPROTO_DSTOPTS : + case IPPROTO_ROUTING : + case IPPROTO_AH : + p = ehp->ip6e_nxt; + ehl = 8 + (ehp->ip6e_len << 3); + hl += ehl; + ehp = (struct ip6_ext *)((char *)ehp + ehl); + break; + case IPPROTO_FRAGMENT : + hl += sizeof(struct ip6_frag); + /* FALLTHROUGH */ + default : + go = 0; + break; + } + } + } else +#endif + { + goto printipflog; + } + proto = getlocalproto(p); + + if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { + tp = (tcphdr_t *)((char *)ip + hl); + if (!(ipf->fl_lflags & FI_SHORT)) { + sprintf(t, "%s,%s -> ", hostname(f, s), + portlocalname(res, proto, (u_int)tp->th_sport)); + t += strlen(t); + sprintf(t, "%s,%s PR %s len %hu %hu", + hostname(f, d), + portlocalname(res, proto, (u_int)tp->th_dport), + proto, hl, plen); + t += strlen(t); + + if (p == IPPROTO_TCP) { + *t++ = ' '; + *t++ = '-'; + for (i = 0; tcpfl[i].value; i++) + if (tp->th_flags & tcpfl[i].value) + *t++ = tcpfl[i].flag; + if (ipmonopts & IPMON_VERBOSE) { + sprintf(t, " %lu %lu %hu", + (u_long)(ntohl(tp->th_seq)), + (u_long)(ntohl(tp->th_ack)), + ntohs(tp->th_win)); + t += strlen(t); + } + } + *t = '\0'; + } else { + sprintf(t, "%s -> ", hostname(f, s)); + t += strlen(t); + sprintf(t, "%s PR %s len %hu %hu", + hostname(f, d), proto, hl, plen); + } +#if defined(AF_INET6) && defined(IPPROTO_ICMPV6) + } else if ((p == IPPROTO_ICMPV6) && !off && (f == AF_INET6)) { + ic = (struct icmp *)((char *)ip + hl); + sprintf(t, "%s -> ", hostname(f, s)); + t += strlen(t); + sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s", + hostname(f, d), hl, plen, + icmpname6(ic->icmp_type, ic->icmp_code)); +#endif + } else if ((p == IPPROTO_ICMP) && !off && (f == AF_INET)) { + ic = (struct icmp *)((char *)ip + hl); + sprintf(t, "%s -> ", hostname(f, s)); + t += strlen(t); + sprintf(t, "%s PR icmp len %hu %hu icmp %s", + hostname(f, d), hl, plen, + icmpname(ic->icmp_type, ic->icmp_code)); + if (ic->icmp_type == ICMP_UNREACH || + ic->icmp_type == ICMP_SOURCEQUENCH || + ic->icmp_type == ICMP_PARAMPROB || + ic->icmp_type == ICMP_REDIRECT || + ic->icmp_type == ICMP_TIMXCEED) { + ipc = &ic->icmp_ip; + i = ntohs(ipc->ip_len); + /* + * XXX - try to guess endian of ip_len in ICMP + * returned data. + */ + if (i > 1500) + i = ipc->ip_len; + ipoff = ntohs(ipc->ip_off); + proto = getlocalproto(ipc->ip_p); + + if (!(ipoff & IP_OFFMASK) && + ((ipc->ip_p == IPPROTO_TCP) || + (ipc->ip_p == IPPROTO_UDP))) { + tp = (tcphdr_t *)((char *)ipc + hl); + t += strlen(t); + sprintf(t, " for %s,%s -", + HOSTNAMEV4(ipc->ip_src), + portlocalname(res, proto, + (u_int)tp->th_sport)); + t += strlen(t); + sprintf(t, " %s,%s PR %s len %hu %hu", + HOSTNAMEV4(ipc->ip_dst), + portlocalname(res, proto, + (u_int)tp->th_dport), + proto, IP_HL(ipc) << 2, i); + } else if (!(ipoff & IP_OFFMASK) && + (ipc->ip_p == IPPROTO_ICMP)) { + icmp = (icmphdr_t *)((char *)ipc + hl); + + t += strlen(t); + sprintf(t, " for %s -", + HOSTNAMEV4(ipc->ip_src)); + t += strlen(t); + sprintf(t, + " %s PR icmp len %hu %hu icmp %d/%d", + HOSTNAMEV4(ipc->ip_dst), + IP_HL(ipc) << 2, i, + icmp->icmp_type, icmp->icmp_code); + } else { + t += strlen(t); + sprintf(t, " for %s -", + HOSTNAMEV4(ipc->ip_src)); + t += strlen(t); + sprintf(t, " %s PR %s len %hu (%hu)", + HOSTNAMEV4(ipc->ip_dst), proto, + IP_HL(ipc) << 2, i); + t += strlen(t); + if (ipoff & IP_OFFMASK) { + sprintf(t, "(frag %d:%hu@%hu%s%s)", + ntohs(ipc->ip_id), + i - (IP_HL(ipc) << 2), + (ipoff & IP_OFFMASK) << 3, + ipoff & IP_MF ? "+" : "", + ipoff & IP_DF ? "-" : ""); + } + } + + } + } else { + sprintf(t, "%s -> ", hostname(f, s)); + t += strlen(t); + sprintf(t, "%s PR %s len %hu (%hu)", + hostname(f, d), proto, hl, plen); + t += strlen(t); + if (off & IP_OFFMASK) + sprintf(t, " (frag %d:%hu@%hu%s%s)", + ntohs(ip->ip_id), + plen - hl, (off & IP_OFFMASK) << 3, + ipoff & IP_MF ? "+" : "", + ipoff & IP_DF ? "-" : ""); + } + t += strlen(t); + +printipflog: + if (ipf->fl_flags & FR_KEEPSTATE) { + (void) strcpy(t, " K-S"); + t += strlen(t); + } + + if (ipf->fl_flags & FR_KEEPFRAG) { + (void) strcpy(t, " K-F"); + t += strlen(t); + } + + if (ipf->fl_dir == 0) + strcpy(t, " IN"); + else if (ipf->fl_dir == 1) + strcpy(t, " OUT"); + t += strlen(t); + if (ipf->fl_logtag != 0) { + sprintf(t, " log-tag %d", ipf->fl_logtag); + t += strlen(t); + } + if (ipf->fl_nattag.ipt_num[0] != 0) { + strcpy(t, " nat-tag "); + t += strlen(t); + strncpy(t, ipf->fl_nattag.ipt_tag, sizeof(ipf->fl_nattag)); + t += strlen(t); + } + if ((ipf->fl_lflags & FI_LOWTTL) != 0) { + strcpy(t, " low-ttl"); + t += 8; + } + if ((ipf->fl_lflags & FI_OOW) != 0) { + strcpy(t, " OOW"); + t += 4; + } + if ((ipf->fl_lflags & FI_BAD) != 0) { + strcpy(t, " bad"); + t += 4; + } + if ((ipf->fl_lflags & FI_NATED) != 0) { + strcpy(t, " NAT"); + t += 4; + } + if ((ipf->fl_lflags & FI_BADNAT) != 0) { + strcpy(t, " bad-NAT"); + t += 8; + } + if ((ipf->fl_lflags & FI_BADSRC) != 0) { + strcpy(t, " bad-src"); + t += 8; + } + if ((ipf->fl_lflags & FI_MULTICAST) != 0) { + strcpy(t, " multicast"); + t += 10; + } + if ((ipf->fl_lflags & FI_BROADCAST) != 0) { + strcpy(t, " broadcast"); + t += 10; + } + if ((ipf->fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) == + FI_MBCAST) { + strcpy(t, " mbcast"); + t += 7; + } + if (ipf->fl_breason != 0) { + strcpy(t, " reason:"); + t += 8; + strcpy(t, reasons[ipf->fl_breason]); + t += strlen(reasons[ipf->fl_breason]); + } + *t++ = '\n'; + *t++ = '\0'; + defaction = 0; + if (conf->cfile != NULL) + defaction = check_action(buf, line, ipmonopts, lvl); + + if (defaction == 0) { + if (ipmonopts & IPMON_SYSLOG) { + syslog(lvl, "%s", line); + } else if (conf->log != NULL) { + (void) fprintf(conf->log, "%s", line); + } + + if (ipmonopts & IPMON_HEXHDR) { + dumphex(conf->log, ipmonopts, buf, + sizeof(iplog_t) + sizeof(*ipf)); + } + if (ipmonopts & IPMON_HEXBODY) { + dumphex(conf->log, ipmonopts, (char *)ip, + ipf->fl_plen + ipf->fl_hlen); + } else if ((ipmonopts & IPMON_LOGBODY) && + (ipf->fl_flags & FR_LOGBODY)) { + dumphex(conf->log, ipmonopts, (char *)ip + ipf->fl_hlen, + ipf->fl_plen); + } + } +} + + +static void usage(prog) + char *prog; +{ + fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\n", prog); + exit(1); +} + + +static void write_pid(file) + char *file; +{ + FILE *fp = NULL; + int fd; + + if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) { + fp = fdopen(fd, "w"); + if (fp == NULL) { + close(fd); + fprintf(stderr, + "unable to open/create pid file: %s\n", file); + return; + } + fprintf(fp, "%d", getpid()); + fclose(fp); + } +} + + +static void flushlogs(file, log) + char *file; + FILE *log; +{ + int fd, flushed = 0; + + if ((fd = open(file, O_RDWR)) == -1) { + (void) fprintf(stderr, "%s: open: %s\n", + file, STRERROR(errno)); + exit(1); + } + + if (ioctl(fd, SIOCIPFFB, &flushed) == 0) { + printf("%d bytes flushed from log buffer\n", + flushed); + fflush(stdout); + } else + ipferror(fd, "SIOCIPFFB"); + (void) close(fd); + + if (flushed) { + if (ipmonopts & IPMON_SYSLOG) { + syslog(LOG_INFO, "%d bytes flushed from log\n", + flushed); + } else if ((log != stdout) && (log != NULL)) { + fprintf(log, "%d bytes flushed from log\n", flushed); + } + } +} + + +static void logopts(turnon, options) + int turnon; + char *options; +{ + int flags = 0; + char *s; + + for (s = options; *s; s++) + { + switch (*s) + { + case 'N' : + flags |= IPMON_NAT; + break; + case 'S' : + flags |= IPMON_STATE; + break; + case 'I' : + flags |= IPMON_FILTER; + break; + default : + fprintf(stderr, "Unknown log option %c\n", *s); + exit(1); + } + } + + if (turnon) + ipmonopts |= flags; + else + ipmonopts &= ~(flags); +} + +static void initconfig(config_t *conf) +{ + int i; + + memset(conf, 0, sizeof(*conf)); + + conf->log = stdout; + conf->maxfd = -1; + + for (i = 0; i < 3; i++) { + conf->logsrc[i].fd = -1; + conf->logsrc[i].logtype = -1; + conf->logsrc[i].regular = -1; + } + + conf->logsrc[0].file = IPL_NAME; + conf->logsrc[1].file = IPNAT_NAME; + conf->logsrc[2].file = IPSTATE_NAME; + + add_doing(&executesaver); + add_doing(&snmpv1saver); + add_doing(&snmpv2saver); + add_doing(&syslogsaver); + add_doing(&filesaver); + add_doing(¬hingsaver); +} + + +int main(argc, argv) + int argc; + char *argv[]; +{ + int doread, c, make_daemon = 0; + char *prog; + config_t config; + + prog = strrchr(argv[0], '/'); + if (prog == NULL) + prog = argv[0]; + else + prog++; + + initconfig(&config); + + while ((c = getopt(argc, argv, + "?abB:C:Df:FhL:nN:o:O:pP:sS:tvxX")) != -1) + switch (c) + { + case 'a' : + ipmonopts |= IPMON_LOGALL; + config.logsrc[0].logtype = IPL_LOGIPF; + config.logsrc[1].logtype = IPL_LOGNAT; + config.logsrc[2].logtype = IPL_LOGSTATE; + break; + case 'b' : + ipmonopts |= IPMON_LOGBODY; + break; + case 'B' : + config.bfile = optarg; + config.blog = fopen(optarg, "a"); + break; + case 'C' : + config.cfile = optarg; + break; + case 'D' : + make_daemon = 1; + break; + case 'f' : case 'I' : + ipmonopts |= IPMON_FILTER; + config.logsrc[0].logtype = IPL_LOGIPF; + config.logsrc[0].file = optarg; + break; + case 'F' : + flushlogs(config.logsrc[0].file, config.log); + flushlogs(config.logsrc[1].file, config.log); + flushlogs(config.logsrc[2].file, config.log); + break; + case 'L' : + logfac = fac_findname(optarg); + if (logfac == -1) { + fprintf(stderr, + "Unknown syslog facility '%s'\n", + optarg); + exit(1); + } + break; + case 'n' : + ipmonopts |= IPMON_RESOLVE; + opts &= ~OPT_NORESOLVE; + break; + case 'N' : + ipmonopts |= IPMON_NAT; + config.logsrc[1].logtype = IPL_LOGNAT; + config.logsrc[1].file = optarg; + break; + case 'o' : case 'O' : + logopts(c == 'o', optarg); + if (ipmonopts & IPMON_FILTER) + config.logsrc[0].logtype = IPL_LOGIPF; + if (ipmonopts & IPMON_NAT) + config.logsrc[1].logtype = IPL_LOGNAT; + if (ipmonopts & IPMON_STATE) + config.logsrc[2].logtype = IPL_LOGSTATE; + break; + case 'p' : + ipmonopts |= IPMON_PORTNUM; + break; + case 'P' : + pidfile = optarg; + break; + case 's' : + ipmonopts |= IPMON_SYSLOG; + config.log = NULL; + break; + case 'S' : + ipmonopts |= IPMON_STATE; + config.logsrc[2].logtype = IPL_LOGSTATE; + config.logsrc[2].file = optarg; + break; + case 't' : + ipmonopts |= IPMON_TAIL; + break; + case 'v' : + ipmonopts |= IPMON_VERBOSE; + break; + case 'x' : + ipmonopts |= IPMON_HEXBODY; + break; + case 'X' : + ipmonopts |= IPMON_HEXHDR; + break; + default : + case 'h' : + case '?' : + usage(argv[0]); + } + + if (ipmonopts & IPMON_SYSLOG) + openlog(prog, LOG_NDELAY|LOG_PID, logfac); + + init_tabs(); + if (config.cfile) + if (load_config(config.cfile) == -1) { + unload_config(); + exit(1); + } + + /* + * Default action is to only open the filter log file. + */ + if ((config.logsrc[0].logtype == -1) && + (config.logsrc[0].logtype == -1) && + (config.logsrc[0].logtype == -1)) + config.logsrc[0].logtype = IPL_LOGIPF; + + openlogs(&config); + + if (!(ipmonopts & IPMON_SYSLOG)) { + config.file = argv[optind]; + config.log = config.file ? fopen(config.file, "a") : stdout; + if (config.log == NULL) { + (void) fprintf(stderr, "%s: fopen: %s\n", + argv[optind], STRERROR(errno)); + exit(1); + /* NOTREACHED */ + } + setvbuf(config.log, NULL, _IONBF, 0); + } else { + config.log = NULL; + } + + if (make_daemon && + ((config.log != stdout) || (ipmonopts & IPMON_SYSLOG))) { +#if BSD >= 199306 + daemon(0, !(ipmonopts & IPMON_SYSLOG)); +#else + int pid; + + switch (fork()) + { + case -1 : + (void) fprintf(stderr, "%s: fork() failed: %s\n", + argv[0], STRERROR(errno)); + exit(1); + /* NOTREACHED */ + case 0 : + break; + default : + exit(0); + } + + setsid(); + if ((ipmonopts & IPMON_SYSLOG)) + close(2); +#endif /* !BSD */ + close(0); + close(1); + write_pid(pidfile); + } + + signal(SIGHUP, handlehup); + + for (doread = 1; doread; ) + doread = read_loginfo(&config); + + unload_config(); + + return(0); + /* NOTREACHED */ +} + + +static void openlogs(config_t *conf) +{ + logsource_t *l; + struct stat sb; + int i; + + for (i = 0; i < 3; i++) { + l = &conf->logsrc[i]; + if (l->logtype == -1) + continue; + if (!strcmp(l->file, "-")) + l->fd = 0; + else { + if ((l->fd= open(l->file, O_RDONLY)) == -1) { + (void) fprintf(stderr, + "%s: open: %s\n", l->file, + STRERROR(errno)); + exit(1); + /* NOTREACHED */ + } + + if (fstat(l->fd, &sb) == -1) { + (void) fprintf(stderr, "%d: fstat: %s\n", + l->fd, STRERROR(errno)); + exit(1); + /* NOTREACHED */ + } + + l->regular = !S_ISCHR(sb.st_mode); + if (l->regular) + l->size = sb.st_size; + + FD_SET(l->fd, &conf->fdmr); + if (l->fd > conf->maxfd) + conf->maxfd = l->fd; + } + } +} + + +static int read_loginfo(config_t *conf) +{ + iplog_t buf[DEFAULT_IPFLOGSIZE/sizeof(iplog_t)+1]; + int n, tr, nr, i; + logsource_t *l; + fd_set fdr; + + fdr = conf->fdmr; + + n = select(conf->maxfd + 1, &fdr, NULL, NULL, NULL); + if (n == 0) + return 1; + if (n == -1) { + if (errno == EINTR) + return 1; + return -1; + } + + for (i = 0, nr = 0; i < 3; i++) { + l = &conf->logsrc[i]; + + if ((l->logtype == -1) || !FD_ISSET(l->fd, &fdr)) + continue; + + tr = 0; + if (l->regular) { + tr = (lseek(l->fd, 0, SEEK_CUR) < l->size); + if (!tr && !(ipmonopts & IPMON_TAIL)) + return 0; + } + + n = 0; + tr = read_log(l->fd, &n, (char *)buf, sizeof(buf)); + if (donehup) { + if (conf->file != NULL) { + if (conf->log != NULL) { + fclose(conf->log); + conf->log = NULL; + } + conf->log = fopen(conf->file, "a"); + } + + if (conf->bfile != NULL) { + if (conf->blog != NULL) { + fclose(conf->blog); + conf->blog = NULL; + } + conf->blog = fopen(conf->bfile, "a"); + } + + init_tabs(); + if (conf->cfile != NULL) + load_config(conf->cfile); + donehup = 0; + } + + switch (tr) + { + case -1 : + if (ipmonopts & IPMON_SYSLOG) + syslog(LOG_CRIT, "read: %m\n"); + else { + ipferror(l->fd, "read"); + } + return 0; + case 1 : + if (ipmonopts & IPMON_SYSLOG) + syslog(LOG_CRIT, "aborting logging\n"); + else if (conf->log != NULL) + fprintf(conf->log, "aborting logging\n"); + return 0; + case 2 : + break; + case 0 : + nr += tr; + if (n > 0) { + print_log(conf, l, (char *)buf, n); + if (!(ipmonopts & IPMON_SYSLOG)) + fflush(conf->log); + } + break; + } + } + + if (!nr && (ipmonopts & IPMON_TAIL)) + sleep(1); + + return 1; +} diff --git a/contrib/ipfilter/tools/ipmon_y.y b/contrib/ipfilter/tools/ipmon_y.y new file mode 100644 index 0000000..f14180d --- /dev/null +++ b/contrib/ipfilter/tools/ipmon_y.y @@ -0,0 +1,1052 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +%{ +#include "ipf.h" +#include <syslog.h> +#undef OPT_NAT +#undef OPT_VERBOSE +#include "ipmon_l.h" +#include "ipmon.h" + +#include <dlfcn.h> + +#define YYDEBUG 1 + +extern void yyerror __P((char *)); +extern int yyparse __P((void)); +extern int yylex __P((void)); +extern int yydebug; +extern FILE *yyin; +extern int yylineNum; +extern int ipmonopts; + +typedef struct opt_s { + struct opt_s *o_next; + int o_line; + int o_type; + int o_num; + char *o_str; + struct in_addr o_ip; + int o_logfac; + int o_logpri; +} opt_t; + +static void build_action __P((opt_t *, ipmon_doing_t *)); +static opt_t *new_opt __P((int)); +static void free_action __P((ipmon_action_t *)); +static void print_action __P((ipmon_action_t *)); +static int find_doing __P((char *)); +static ipmon_doing_t *build_doing __P((char *, char *)); +static void print_match __P((ipmon_action_t *)); +static int install_saver __P((char *, char *)); + +static ipmon_action_t *alist = NULL; + +ipmon_saver_int_t *saverlist = NULL; +%} + +%union { + char *str; + u_32_t num; + struct in_addr addr; + struct opt_s *opt; + union i6addr ip6; + struct ipmon_doing_s *ipmd; +} + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token <ip6> YY_IPV6 +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN + +%token IPM_MATCH IPM_BODY IPM_COMMENT IPM_DIRECTION IPM_DSTIP IPM_DSTPORT +%token IPM_EVERY IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT IPM_LOADACTION +%token IPM_PACKET IPM_PACKETS IPM_POOL IPM_PROTOCOL IPM_RESULT IPM_RULE +%token IPM_SECOND IPM_SECONDS IPM_SRCIP IPM_SRCPORT IPM_LOGTAG IPM_WITH +%token IPM_DO IPM_DOING IPM_TYPE IPM_NAT +%token IPM_STATE IPM_NATTAG IPM_IPF +%type <addr> ipv4 +%type <opt> direction dstip dstport every group interface +%type <opt> protocol result rule srcip srcport logtag matching +%type <opt> matchopt nattag type +%type <num> typeopt +%type <ipmd> doopt doing + +%% +file: action + | file action + ; + +action: line ';' + | assign ';' + | IPM_COMMENT + | YY_COMMENT + ; + +line: IPM_MATCH '{' matching ';' '}' IPM_DO '{' doing ';' '}' + { build_action($3, $8); + resetlexer(); + } + | IPM_LOADACTION YY_STR YY_STR { if (install_saver($2, $3)) + yyerror("install saver"); + } + ; + +assign: YY_STR assigning YY_STR { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + yyvarnext = 0; + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +matching: + matchopt { $$ = $1; } + | matchopt ',' matching { $1->o_next = $3; $$ = $1; } + ; + +matchopt: + direction { $$ = $1; } + | dstip { $$ = $1; } + | dstport { $$ = $1; } + | every { $$ = $1; } + | group { $$ = $1; } + | interface { $$ = $1; } + | protocol { $$ = $1; } + | result { $$ = $1; } + | rule { $$ = $1; } + | srcip { $$ = $1; } + | srcport { $$ = $1; } + | logtag { $$ = $1; } + | nattag { $$ = $1; } + | type { $$ = $1; } + ; + +doing: + doopt { $$ = $1; } + | doopt ',' doing { $1->ipmd_next = $3; $$ = $1; } + ; + +doopt: + YY_STR { if (find_doing($1) != IPM_DOING) + yyerror("unknown action"); + } + '(' YY_STR ')' { $$ = build_doing($1, $4); + if ($$ == NULL) + yyerror("action building"); + } + | YY_STR { if (find_doing($1) == IPM_DOING) + $$ = build_doing($1, NULL); + } + ; + +direction: + IPM_DIRECTION '=' IPM_IN { $$ = new_opt(IPM_DIRECTION); + $$->o_num = IPM_IN; } + | IPM_DIRECTION '=' IPM_OUT { $$ = new_opt(IPM_DIRECTION); + $$->o_num = IPM_OUT; } + ; + +dstip: IPM_DSTIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_DSTIP); + $$->o_ip = $3; + $$->o_num = $5; } + ; + +dstport: + IPM_DSTPORT '=' YY_NUMBER { $$ = new_opt(IPM_DSTPORT); + $$->o_num = $3; } + | IPM_DSTPORT '=' YY_STR { $$ = new_opt(IPM_DSTPORT); + $$->o_str = $3; } + ; + +every: IPM_EVERY IPM_SECOND { $$ = new_opt(IPM_SECOND); + $$->o_num = 1; } + | IPM_EVERY YY_NUMBER IPM_SECONDS { $$ = new_opt(IPM_SECOND); + $$->o_num = $2; } + | IPM_EVERY IPM_PACKET { $$ = new_opt(IPM_PACKET); + $$->o_num = 1; } + | IPM_EVERY YY_NUMBER IPM_PACKETS { $$ = new_opt(IPM_PACKET); + $$->o_num = $2; } + ; + +group: IPM_GROUP '=' YY_NUMBER { $$ = new_opt(IPM_GROUP); + $$->o_num = $3; } + | IPM_GROUP '=' YY_STR { $$ = new_opt(IPM_GROUP); + $$->o_str = $3; } + ; + +interface: + IPM_INTERFACE '=' YY_STR { $$ = new_opt(IPM_INTERFACE); + $$->o_str = $3; } + ; + +logtag: IPM_LOGTAG '=' YY_NUMBER { $$ = new_opt(IPM_LOGTAG); + $$->o_num = $3; } + ; + +nattag: IPM_NATTAG '=' YY_STR { $$ = new_opt(IPM_NATTAG); + $$->o_str = $3; } + ; + +protocol: + IPM_PROTOCOL '=' YY_NUMBER { $$ = new_opt(IPM_PROTOCOL); + $$->o_num = $3; } + | IPM_PROTOCOL '=' YY_STR { $$ = new_opt(IPM_PROTOCOL); + $$->o_num = getproto($3); + free($3); + } + ; + +result: IPM_RESULT '=' YY_STR { $$ = new_opt(IPM_RESULT); + $$->o_str = $3; } + ; + +rule: IPM_RULE '=' YY_NUMBER { $$ = new_opt(IPM_RULE); + $$->o_num = YY_NUMBER; } + ; + +srcip: IPM_SRCIP '=' ipv4 '/' YY_NUMBER { $$ = new_opt(IPM_SRCIP); + $$->o_ip = $3; + $$->o_num = $5; } + ; + +srcport: + IPM_SRCPORT '=' YY_NUMBER { $$ = new_opt(IPM_SRCPORT); + $$->o_num = $3; } + | IPM_SRCPORT '=' YY_STR { $$ = new_opt(IPM_SRCPORT); + $$->o_str = $3; } + ; + +type: IPM_TYPE '=' typeopt { $$ = new_opt(IPM_TYPE); + $$->o_num = $3; } + ; + +typeopt: + IPM_IPF { $$ = IPL_MAGIC; } + | IPM_NAT { $$ = IPL_MAGIC_NAT; } + | IPM_STATE { $$ = IPL_MAGIC_STATE; } + ; + + + +ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER + { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; + $$.s_addr = htonl($$.s_addr); + } +%% +static struct wordtab yywords[] = { + { "body", IPM_BODY }, + { "direction", IPM_DIRECTION }, + { "do", IPM_DO }, + { "dstip", IPM_DSTIP }, + { "dstport", IPM_DSTPORT }, + { "every", IPM_EVERY }, + { "group", IPM_GROUP }, + { "in", IPM_IN }, + { "interface", IPM_INTERFACE }, + { "ipf", IPM_IPF }, + { "load_action",IPM_LOADACTION }, + { "logtag", IPM_LOGTAG }, + { "match", IPM_MATCH }, + { "nat", IPM_NAT }, + { "nattag", IPM_NATTAG }, + { "no", IPM_NO }, + { "out", IPM_OUT }, + { "packet", IPM_PACKET }, + { "packets", IPM_PACKETS }, + { "protocol", IPM_PROTOCOL }, + { "result", IPM_RESULT }, + { "rule", IPM_RULE }, + { "second", IPM_SECOND }, + { "seconds", IPM_SECONDS }, + { "srcip", IPM_SRCIP }, + { "srcport", IPM_SRCPORT }, + { "state", IPM_STATE }, + { "with", IPM_WITH }, + { NULL, 0 } +}; + +static int macflags[17][2] = { + { IPM_DIRECTION, IPMAC_DIRECTION }, + { IPM_DSTIP, IPMAC_DSTIP }, + { IPM_DSTPORT, IPMAC_DSTPORT }, + { IPM_GROUP, IPMAC_GROUP }, + { IPM_INTERFACE, IPMAC_INTERFACE }, + { IPM_LOGTAG, IPMAC_LOGTAG }, + { IPM_NATTAG, IPMAC_NATTAG }, + { IPM_PACKET, IPMAC_EVERY }, + { IPM_PROTOCOL, IPMAC_PROTOCOL }, + { IPM_RESULT, IPMAC_RESULT }, + { IPM_RULE, IPMAC_RULE }, + { IPM_SECOND, IPMAC_EVERY }, + { IPM_SRCIP, IPMAC_SRCIP }, + { IPM_SRCPORT, IPMAC_SRCPORT }, + { IPM_TYPE, IPMAC_TYPE }, + { IPM_WITH, IPMAC_WITH }, + { 0, 0 } +}; + +static opt_t * +new_opt(type) + int type; +{ + opt_t *o; + + o = (opt_t *)calloc(1, sizeof(*o)); + o->o_type = type; + o->o_line = yylineNum; + o->o_logfac = -1; + o->o_logpri = -1; + return o; +} + +static void +build_action(olist, todo) + opt_t *olist; + ipmon_doing_t *todo; +{ + ipmon_action_t *a; + opt_t *o; + int i; + + a = (ipmon_action_t *)calloc(1, sizeof(*a)); + if (a == NULL) + return; + + while ((o = olist) != NULL) { + /* + * Check to see if the same comparator is being used more than + * once per matching statement. + */ + for (i = 0; macflags[i][0]; i++) + if (macflags[i][0] == o->o_type) + break; + if (macflags[i][1] & a->ac_mflag) { + fprintf(stderr, "%s redfined on line %d\n", + yykeytostr(o->o_type), yylineNum); + if (o->o_str != NULL) + free(o->o_str); + olist = o->o_next; + free(o); + continue; + } + + a->ac_mflag |= macflags[i][1]; + + switch (o->o_type) + { + case IPM_DIRECTION : + a->ac_direction = o->o_num; + break; + case IPM_DSTIP : + a->ac_dip = o->o_ip.s_addr; + a->ac_dmsk = htonl(0xffffffff << (32 - o->o_num)); + break; + case IPM_DSTPORT : + a->ac_dport = htons(o->o_num); + break; + case IPM_INTERFACE : + a->ac_iface = o->o_str; + o->o_str = NULL; + break; + case IPM_GROUP : + if (o->o_str != NULL) + strncpy(a->ac_group, o->o_str, FR_GROUPLEN); + else + sprintf(a->ac_group, "%d", o->o_num); + break; + case IPM_LOGTAG : + a->ac_logtag = o->o_num; + break; + case IPM_NATTAG : + strncpy(a->ac_nattag, o->o_str, sizeof(a->ac_nattag)); + break; + case IPM_PACKET : + a->ac_packet = o->o_num; + break; + case IPM_PROTOCOL : + a->ac_proto = o->o_num; + break; + case IPM_RULE : + a->ac_rule = o->o_num; + break; + case IPM_RESULT : + if (!strcasecmp(o->o_str, "pass")) + a->ac_result = IPMR_PASS; + else if (!strcasecmp(o->o_str, "block")) + a->ac_result = IPMR_BLOCK; + else if (!strcasecmp(o->o_str, "nomatch")) + a->ac_result = IPMR_NOMATCH; + else if (!strcasecmp(o->o_str, "log")) + a->ac_result = IPMR_LOG; + break; + case IPM_SECOND : + a->ac_second = o->o_num; + break; + case IPM_SRCIP : + a->ac_sip = o->o_ip.s_addr; + a->ac_smsk = htonl(0xffffffff << (32 - o->o_num)); + break; + case IPM_SRCPORT : + a->ac_sport = htons(o->o_num); + break; + case IPM_TYPE : + a->ac_type = o->o_num; + break; + case IPM_WITH : + break; + default : + break; + } + + olist = o->o_next; + if (o->o_str != NULL) + free(o->o_str); + free(o); + } + + a->ac_doing = todo; + a->ac_next = alist; + alist = a; + + if (ipmonopts & IPMON_VERBOSE) + print_action(a); +} + + +int +check_action(buf, log, opts, lvl) + char *buf, *log; + int opts, lvl; +{ + ipmon_action_t *a; + struct timeval tv; + ipmon_doing_t *d; + ipmon_msg_t msg; + ipflog_t *ipf; + tcphdr_t *tcp; + iplog_t *ipl; + int matched; + u_long t1; + ip_t *ip; + + matched = 0; + ipl = (iplog_t *)buf; + ipf = (ipflog_t *)(ipl +1); + ip = (ip_t *)(ipf + 1); + tcp = (tcphdr_t *)((char *)ip + (IP_HL(ip) << 2)); + + msg.imm_data = ipl; + msg.imm_dsize = ipl->ipl_dsize; + msg.imm_when = ipl->ipl_time.tv_sec; + msg.imm_msg = log; + msg.imm_msglen = strlen(log); + msg.imm_loglevel = lvl; + + for (a = alist; a != NULL; a = a->ac_next) { + verbose(0, "== checking config rule\n"); + if ((a->ac_mflag & IPMAC_DIRECTION) != 0) { + if (a->ac_direction == IPM_IN) { + if ((ipf->fl_flags & FR_INQUE) == 0) { + verbose(8, "-- direction not in\n"); + continue; + } + } else if (a->ac_direction == IPM_OUT) { + if ((ipf->fl_flags & FR_OUTQUE) == 0) { + verbose(8, "-- direction not out\n"); + continue; + } + } + } + + if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) { + verbose(8, "-- type mismatch\n"); + continue; + } + + if ((a->ac_mflag & IPMAC_EVERY) != 0) { + gettimeofday(&tv, NULL); + t1 = tv.tv_sec - a->ac_lastsec; + if (tv.tv_usec <= a->ac_lastusec) + t1--; + if (a->ac_second != 0) { + if (t1 < a->ac_second) { + verbose(8, "-- too soon\n"); + continue; + } + a->ac_lastsec = tv.tv_sec; + a->ac_lastusec = tv.tv_usec; + } + + if (a->ac_packet != 0) { + if (a->ac_pktcnt == 0) + a->ac_pktcnt++; + else if (a->ac_pktcnt == a->ac_packet) { + a->ac_pktcnt = 0; + verbose(8, "-- packet count\n"); + continue; + } else { + a->ac_pktcnt++; + verbose(8, "-- packet count\n"); + continue; + } + } + } + + if ((a->ac_mflag & IPMAC_DSTIP) != 0) { + if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) { + verbose(8, "-- dstip wrong\n"); + continue; + } + } + + if ((a->ac_mflag & IPMAC_DSTPORT) != 0) { + if (ip->ip_p != IPPROTO_UDP && + ip->ip_p != IPPROTO_TCP) { + verbose(8, "-- not port protocol\n"); + continue; + } + if (tcp->th_dport != a->ac_dport) { + verbose(8, "-- dport mismatch\n"); + continue; + } + } + + if ((a->ac_mflag & IPMAC_GROUP) != 0) { + if (strncmp(a->ac_group, ipf->fl_group, + FR_GROUPLEN) != 0) { + verbose(8, "-- group mismatch\n"); + continue; + } + } + + if ((a->ac_mflag & IPMAC_INTERFACE) != 0) { + if (strcmp(a->ac_iface, ipf->fl_ifname)) { + verbose(8, "-- ifname mismatch\n"); + continue; + } + } + + if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) { + if (a->ac_proto != ip->ip_p) { + verbose(8, "-- protocol mismatch\n"); + continue; + } + } + + if ((a->ac_mflag & IPMAC_RESULT) != 0) { + if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) { + if (a->ac_result != IPMR_NOMATCH) { + verbose(8, "-- ff-flags mismatch\n"); + continue; + } + } else if (FR_ISPASS(ipf->fl_flags)) { + if (a->ac_result != IPMR_PASS) { + verbose(8, "-- pass mismatch\n"); + continue; + } + } else if (FR_ISBLOCK(ipf->fl_flags)) { + if (a->ac_result != IPMR_BLOCK) { + verbose(8, "-- block mismatch\n"); + continue; + } + } else { /* Log only */ + if (a->ac_result != IPMR_LOG) { + verbose(8, "-- log mismatch\n"); + continue; + } + } + } + + if ((a->ac_mflag & IPMAC_RULE) != 0) { + if (a->ac_rule != ipf->fl_rule) { + verbose(8, "-- rule mismatch\n"); + continue; + } + } + + if ((a->ac_mflag & IPMAC_SRCIP) != 0) { + if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) { + verbose(8, "-- srcip mismatch\n"); + continue; + } + } + + if ((a->ac_mflag & IPMAC_SRCPORT) != 0) { + if (ip->ip_p != IPPROTO_UDP && + ip->ip_p != IPPROTO_TCP) { + verbose(8, "-- port protocol mismatch\n"); + continue; + } + if (tcp->th_sport != a->ac_sport) { + verbose(8, "-- sport mismatch\n"); + continue; + } + } + + if ((a->ac_mflag & IPMAC_LOGTAG) != 0) { + if (a->ac_logtag != ipf->fl_logtag) { + verbose(8, "-- logtag %d != %d\n", + a->ac_logtag, ipf->fl_logtag); + continue; + } + } + + if ((a->ac_mflag & IPMAC_NATTAG) != 0) { + if (strncmp(a->ac_nattag, ipf->fl_nattag.ipt_tag, + IPFTAG_LEN) != 0) { + verbose(8, "-- nattag mismatch\n"); + continue; + } + } + + matched = 1; + verbose(8, "++ matched\n"); + + /* + * It matched so now perform the saves + */ + for (d = a->ac_doing; d != NULL; d = d->ipmd_next) + (*d->ipmd_store)(d->ipmd_token, &msg); + } + + return matched; +} + + +static void +free_action(a) + ipmon_action_t *a; +{ + ipmon_doing_t *d; + + while ((d = a->ac_doing) != NULL) { + a->ac_doing = d->ipmd_next; + (*d->ipmd_saver->ims_destroy)(d->ipmd_token); + free(d); + } + + if (a->ac_iface != NULL) { + free(a->ac_iface); + a->ac_iface = NULL; + } + a->ac_next = NULL; + free(a); +} + + +int +load_config(file) + char *file; +{ + FILE *fp; + char *s; + + unload_config(); + + s = getenv("YYDEBUG"); + if (s != NULL) + yydebug = atoi(s); + else + yydebug = 0; + + yylineNum = 1; + + (void) yysettab(yywords); + + fp = fopen(file, "r"); + if (!fp) { + perror("load_config:fopen:"); + return -1; + } + yyin = fp; + while (!feof(fp)) + yyparse(); + fclose(fp); + return 0; +} + + +void +unload_config() +{ + ipmon_saver_int_t *sav, **imsip; + ipmon_saver_t *is; + ipmon_action_t *a; + + while ((a = alist) != NULL) { + alist = a->ac_next; + free_action(a); + } + + /* + * Look for savers that have been added in dynamically from the + * configuration file. + */ + for (imsip = &saverlist; (sav = *imsip) != NULL; ) { + if (sav->imsi_handle == NULL) + imsip = &sav->imsi_next; + else { + dlclose(sav->imsi_handle); + + *imsip = sav->imsi_next; + is = sav->imsi_stor; + free(sav); + + free(is->ims_name); + free(is); + } + } +} + + +void +dump_config() +{ + ipmon_action_t *a; + + for (a = alist; a != NULL; a = a->ac_next) { + print_action(a); + + printf("#\n"); + } +} + + +static void +print_action(a) + ipmon_action_t *a; +{ + ipmon_doing_t *d; + + printf("match { "); + print_match(a); + printf("; }\n"); + printf("do {"); + for (d = a->ac_doing; d != NULL; d = d->ipmd_next) { + printf("%s", d->ipmd_saver->ims_name); + if (d->ipmd_saver->ims_print != NULL) { + printf("(\""); + (*d->ipmd_saver->ims_print)(d->ipmd_token); + printf("\")"); + } + printf(";"); + } + printf("};\n"); +} + + +void * +add_doing(saver) + ipmon_saver_t *saver; +{ + ipmon_saver_int_t *it; + + if (find_doing(saver->ims_name) == IPM_DOING) + return NULL; + + it = calloc(1, sizeof(*it)); + if (it == NULL) + return NULL; + it->imsi_stor = saver; + it->imsi_next = saverlist; + saverlist = it; + return it; +} + + +static int +find_doing(string) + char *string; +{ + ipmon_saver_int_t *it; + + for (it = saverlist; it != NULL; it = it->imsi_next) { + if (!strcmp(it->imsi_stor->ims_name, string)) + return IPM_DOING; + } + return 0; +} + + +static ipmon_doing_t * +build_doing(target, options) + char *target; + char *options; +{ + ipmon_saver_int_t *it; + char *strarray[2]; + ipmon_doing_t *d, *d1; + ipmon_action_t *a; + ipmon_saver_t *save; + + d = calloc(1, sizeof(*d)); + if (d == NULL) + return NULL; + + for (it = saverlist; it != NULL; it = it->imsi_next) { + if (!strcmp(it->imsi_stor->ims_name, target)) + break; + } + if (it == NULL) { + free(d); + return NULL; + } + + strarray[0] = options; + strarray[1] = NULL; + + d->ipmd_token = (*it->imsi_stor->ims_parse)(strarray); + if (d->ipmd_token == NULL) { + free(d); + return NULL; + } + + save = it->imsi_stor; + d->ipmd_saver = save; + d->ipmd_store = it->imsi_stor->ims_store; + + /* + * Look for duplicate do-things that need to be dup'd + */ + for (a = alist; a != NULL; a = a->ac_next) { + for (d1 = a->ac_doing; d1 != NULL; d1 = d1->ipmd_next) { + if (save != d1->ipmd_saver) + continue; + if (save->ims_match == NULL || save->ims_dup == NULL) + continue; + if ((*save->ims_match)(d->ipmd_token, d1->ipmd_token)) + continue; + + (*d->ipmd_saver->ims_destroy)(d->ipmd_token); + d->ipmd_token = (*save->ims_dup)(d1->ipmd_token); + break; + } + } + + return d; +} + + +static void +print_match(a) + ipmon_action_t *a; +{ + char *coma = ""; + + if ((a->ac_mflag & IPMAC_DIRECTION) != 0) { + printf("direction = "); + if (a->ac_direction == IPM_IN) + printf("in"); + else if (a->ac_direction == IPM_OUT) + printf("out"); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_DSTIP) != 0) { + printf("%sdstip = ", coma); + printhostmask(AF_INET, &a->ac_dip, &a->ac_dmsk); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_DSTPORT) != 0) { + printf("%sdstport = %hu", coma, ntohs(a->ac_dport)); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_GROUP) != 0) { + char group[FR_GROUPLEN+1]; + + strncpy(group, a->ac_group, FR_GROUPLEN); + group[FR_GROUPLEN] = '\0'; + printf("%sgroup = %s", coma, group); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_INTERFACE) != 0) { + printf("%siface = %s", coma, a->ac_iface); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_LOGTAG) != 0) { + printf("%slogtag = %u", coma, a->ac_logtag); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_NATTAG) != 0) { + char tag[17]; + + strncpy(tag, a->ac_nattag, 16); + tag[16] = '\0'; + printf("%snattag = %s", coma, tag); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) { + printf("%sprotocol = %u", coma, a->ac_proto); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_RESULT) != 0) { + printf("%sresult = ", coma); + switch (a->ac_result) + { + case IPMR_LOG : + printf("log"); + break; + case IPMR_PASS : + printf("pass"); + break; + case IPMR_BLOCK : + printf("block"); + break; + case IPMR_NOMATCH : + printf("nomatch"); + break; + } + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_RULE) != 0) { + printf("%srule = %u", coma, a->ac_rule); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_EVERY) != 0) { + if (a->ac_packet > 1) { + printf("%severy %d packets", coma, a->ac_packet); + coma = ", "; + } else if (a->ac_packet == 1) { + printf("%severy packet", coma); + coma = ", "; + } + if (a->ac_second > 1) { + printf("%severy %d seconds", coma, a->ac_second); + coma = ", "; + } else if (a->ac_second == 1) { + printf("%severy second", coma); + coma = ", "; + } + } + + if ((a->ac_mflag & IPMAC_SRCIP) != 0) { + printf("%ssrcip = ", coma); + printhostmask(AF_INET, &a->ac_sip, &a->ac_smsk); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_SRCPORT) != 0) { + printf("%ssrcport = %hu", coma, ntohs(a->ac_sport)); + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_TYPE) != 0) { + printf("%stype = ", coma); + switch (a->ac_type) + { + case IPL_LOGIPF : + printf("ipf"); + break; + case IPL_LOGSTATE : + printf("state"); + break; + case IPL_LOGNAT : + printf("nat"); + break; + } + coma = ", "; + } + + if ((a->ac_mflag & IPMAC_WITH) != 0) { + printf("%swith ", coma); + coma = ", "; + } +} + + +static int +install_saver(name, path) + char *name, *path; +{ + ipmon_saver_int_t *isi; + ipmon_saver_t *is; + char nbuf[80]; + + if (find_doing(name) == IPM_DOING) + return -1; + + isi = calloc(1, sizeof(*isi)); + if (isi == NULL) + return -1; + + is = calloc(1, sizeof(*is)); + if (is == NULL) + goto loaderror; + + is->ims_name = name; + +#ifdef RTLD_LAZY + isi->imsi_handle = dlopen(path, RTLD_LAZY); +#endif +#ifdef DL_LAZY + isi->imsi_handle = dlopen(path, DL_LAZY); +#endif + + if (isi->imsi_handle == NULL) + goto loaderror; + + snprintf(nbuf, sizeof(nbuf), "%sdup", name); + is->ims_dup = (ims_dup_func_t)dlsym(isi->imsi_handle, nbuf); + + snprintf(nbuf, sizeof(nbuf), "%sdestroy", name); + is->ims_destroy = (ims_destroy_func_t)dlsym(isi->imsi_handle, nbuf); + if (is->ims_destroy == NULL) + goto loaderror; + + snprintf(nbuf, sizeof(nbuf), "%smatch", name); + is->ims_match = (ims_match_func_t)dlsym(isi->imsi_handle, nbuf); + + snprintf(nbuf, sizeof(nbuf), "%sparse", name); + is->ims_parse = (ims_parse_func_t)dlsym(isi->imsi_handle, nbuf); + if (is->ims_parse == NULL) + goto loaderror; + + snprintf(nbuf, sizeof(nbuf), "%sprint", name); + is->ims_print = (ims_print_func_t)dlsym(isi->imsi_handle, nbuf); + if (is->ims_print == NULL) + goto loaderror; + + snprintf(nbuf, sizeof(nbuf), "%sstore", name); + is->ims_store = (ims_store_func_t)dlsym(isi->imsi_handle, nbuf); + if (is->ims_store == NULL) + goto loaderror; + + isi->imsi_stor = is; + isi->imsi_next = saverlist; + saverlist = isi; + + return 0; + +loaderror: + if (isi->imsi_handle != NULL) + dlclose(isi->imsi_handle); + free(isi); + if (is != NULL) + free(is); + return -1; +} diff --git a/contrib/ipfilter/tools/ipnat.c b/contrib/ipfilter/tools/ipnat.c new file mode 100644 index 0000000..c3a7156 --- /dev/null +++ b/contrib/ipfilter/tools/ipnat.c @@ -0,0 +1,855 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + * + * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) + */ +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#if !defined(__SVR4) && !defined(__svr4__) +#include <strings.h> +#else +#include <sys/byteorder.h> +#endif +#include <sys/time.h> +#include <sys/param.h> +#include <stdlib.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/file.h> +#define _KERNEL +#include <sys/uio.h> +#undef _KERNEL +#include <sys/socket.h> +#include <sys/ioctl.h> +#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) +# include <sys/ioccom.h> +# include <sys/sysmacros.h> +#endif +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> +#include <net/if.h> +#include <netdb.h> +#include <arpa/nameser.h> +#include <arpa/inet.h> +#include <resolv.h> +#include <ctype.h> +#if defined(linux) +# include <linux/a.out.h> +#else +# include <nlist.h> +#endif +#include "ipf.h" +#include "netinet/ipl.h" +#include "kmem.h" + +#ifdef __hpux +# define nlist nlist64 +#endif + +#if defined(sun) && !SOLARIS2 +# define STRERROR(x) sys_errlist[x] +extern char *sys_errlist[]; +#else +# define STRERROR(x) strerror(x) +#endif + +#if !defined(lint) +static const char sccsid[] ="@(#)ipnat.c 1.9 6/5/96 (C) 1993 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif + + +#if SOLARIS +#define bzero(a,b) memset(a,0,b) +#endif +int use_inet6 = 0; +char thishost[MAXHOSTNAMELEN]; + +extern char *optarg; + +void dostats __P((int, natstat_t *, int, int, int *)); +void dotable __P((natstat_t *, int, int, int, char *)); +void flushtable __P((int, int, int *)); +void usage __P((char *)); +int main __P((int, char*[])); +void showhostmap __P((natstat_t *nsp)); +void natstat_dead __P((natstat_t *, char *)); +void dostats_live __P((int, natstat_t *, int, int *)); +void showhostmap_dead __P((natstat_t *)); +void showhostmap_live __P((int, natstat_t *)); +void dostats_dead __P((natstat_t *, int, int *)); +int nat_matcharray __P((nat_t *, int *)); + +int opts; +int nohdrfields = 0; +wordtab_t *nat_fields = NULL; + +void usage(name) + char *name; +{ + fprintf(stderr, "Usage: %s [-CFhlnrRsv] [-f filename]\n", name); + exit(1); +} + + +int main(argc, argv) + int argc; + char *argv[]; +{ + int fd, c, mode, *natfilter; + char *file, *core, *kernel; + natstat_t ns, *nsp; + ipfobj_t obj; + + fd = -1; + opts = 0; + nsp = &ns; + file = NULL; + core = NULL; + kernel = NULL; + mode = O_RDWR; + natfilter = NULL; + + assigndefined(getenv("IPNAT_PREDEFINED")); + + while ((c = getopt(argc, argv, "CdFf:hlm:M:N:nO:prRsv")) != -1) + switch (c) + { + case 'C' : + opts |= OPT_CLEAR; + break; + case 'd' : + opts |= OPT_DEBUG; + break; + case 'f' : + file = optarg; + break; + case 'F' : + opts |= OPT_FLUSH; + break; + case 'h' : + opts |=OPT_HITS; + break; + case 'l' : + opts |= OPT_LIST; + mode = O_RDONLY; + break; + case 'm' : + natfilter = parseipfexpr(optarg, NULL); + break; + case 'M' : + core = optarg; + break; + case 'N' : + kernel = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING|OPT_DONTOPEN; + mode = O_RDONLY; + break; + case 'O' : + nat_fields = parsefields(natfields, optarg); + break; + case 'p' : + opts |= OPT_PURGE; + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'r' : + opts |= OPT_REMOVE; + break; + case 's' : + opts |= OPT_STAT; + mode = O_RDONLY; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + default : + usage(argv[0]); + } + + if (((opts & OPT_PURGE) != 0) && ((opts & OPT_REMOVE) == 0)) { + (void) fprintf(stderr, "%s: -p must be used with -r\n", + argv[0]); + exit(1); + } + + initparse(); + + if ((kernel != NULL) || (core != NULL)) { + (void) setgid(getgid()); + (void) setuid(getuid()); + } + + if (!(opts & OPT_DONOTHING)) { + if (((fd = open(IPNAT_NAME, mode)) == -1) && + ((fd = open(IPNAT_NAME, O_RDONLY)) == -1)) { + (void) fprintf(stderr, "%s: open: %s\n", IPNAT_NAME, + STRERROR(errno)); + exit(1); + } + } + + bzero((char *)&ns, sizeof(ns)); + + if ((opts & OPT_DONOTHING) == 0) { + if (checkrev(IPL_NAME) == -1) { + fprintf(stderr, "User/kernel version check failed\n"); + exit(1); + } + } + + if (!(opts & OPT_DONOTHING) && (kernel == NULL) && (core == NULL)) { + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_NATSTAT; + obj.ipfo_size = sizeof(*nsp); + obj.ipfo_ptr = (void *)nsp; + if (ioctl(fd, SIOCGNATS, &obj) == -1) { + ipferror(fd, "ioctl(SIOCGNATS)"); + exit(1); + } + (void) setgid(getgid()); + (void) setuid(getuid()); + } else if ((kernel != NULL) || (core != NULL)) { + if (openkmem(kernel, core) == -1) + exit(1); + + natstat_dead(nsp, kernel); + if (opts & (OPT_LIST|OPT_STAT)) + dostats(fd, nsp, opts, 0, natfilter); + exit(0); + } + + if (opts & (OPT_FLUSH|OPT_CLEAR)) + flushtable(fd, opts, natfilter); + if (file) { + return ipnat_parsefile(fd, ipnat_addrule, ioctl, file); + } + if (opts & (OPT_LIST|OPT_STAT)) + dostats(fd, nsp, opts, 1, natfilter); + return 0; +} + + +/* + * Read NAT statistic information in using a symbol table and memory file + * rather than doing ioctl's. + */ +void natstat_dead(nsp, kernel) + natstat_t *nsp; + char *kernel; +{ + struct nlist nat_nlist[10] = { + { "nat_table" }, /* 0 */ + { "nat_list" }, + { "maptable" }, + { "ipf_nattable_sz" }, + { "ipf_natrules_sz" }, + { "ipf_rdrrules_sz" }, /* 5 */ + { "ipf_hostmap_sz" }, + { "nat_instances" }, + { NULL } + }; + void *tables[2]; + + if (nlist(kernel, nat_nlist) == -1) { + fprintf(stderr, "nlist error\n"); + return; + } + + /* + * Normally the ioctl copies all of these values into the structure + * for us, before returning it to userland, so here we must copy each + * one in individually. + */ + kmemcpy((char *)&tables, nat_nlist[0].n_value, sizeof(tables)); + nsp->ns_side[0].ns_table = tables[0]; + nsp->ns_side[1].ns_table = tables[1]; + + kmemcpy((char *)&nsp->ns_list, nat_nlist[1].n_value, + sizeof(nsp->ns_list)); + kmemcpy((char *)&nsp->ns_maptable, nat_nlist[2].n_value, + sizeof(nsp->ns_maptable)); + kmemcpy((char *)&nsp->ns_nattab_sz, nat_nlist[3].n_value, + sizeof(nsp->ns_nattab_sz)); + kmemcpy((char *)&nsp->ns_rultab_sz, nat_nlist[4].n_value, + sizeof(nsp->ns_rultab_sz)); + kmemcpy((char *)&nsp->ns_rdrtab_sz, nat_nlist[5].n_value, + sizeof(nsp->ns_rdrtab_sz)); + kmemcpy((char *)&nsp->ns_hostmap_sz, nat_nlist[6].n_value, + sizeof(nsp->ns_hostmap_sz)); + kmemcpy((char *)&nsp->ns_instances, nat_nlist[7].n_value, + sizeof(nsp->ns_instances)); +} + + +/* + * Issue an ioctl to flush either the NAT rules table or the active mapping + * table or both. + */ +void flushtable(fd, opts, match) + int fd, opts, *match; +{ + int n = 0; + + if (opts & OPT_FLUSH) { + n = 0; + if (!(opts & OPT_DONOTHING)) { + if (match != NULL) { + ipfobj_t obj; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = match[0] * sizeof(int); + obj.ipfo_type = IPFOBJ_IPFEXPR; + obj.ipfo_ptr = match; + if (ioctl(fd, SIOCMATCHFLUSH, &obj) == -1) { + ipferror(fd, "ioctl(SIOCMATCHFLUSH)"); + n = -1; + } else { + n = obj.ipfo_retval; + } + } else if (ioctl(fd, SIOCIPFFL, &n) == -1) { + ipferror(fd, "ioctl(SIOCIPFFL)"); + n = -1; + } + } + if (n >= 0) + printf("%d entries flushed from NAT table\n", n); + } + + if (opts & OPT_CLEAR) { + n = 1; + if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) + ipferror(fd, "ioctl(SIOCCNATL)"); + else + printf("%d entries flushed from NAT list\n", n); + } +} + + +/* + * Display NAT statistics. + */ +void dostats_dead(nsp, opts, filter) + natstat_t *nsp; + int opts, *filter; +{ + nat_t *np, nat; + ipnat_t ipn; + int i; + + if (nat_fields == NULL) { + printf("List of active MAP/Redirect filters:\n"); + while (nsp->ns_list) { + if (kmemcpy((char *)&ipn, (long)nsp->ns_list, + sizeof(ipn))) { + perror("kmemcpy"); + break; + } + if (opts & OPT_HITS) + printf("%lu ", ipn.in_hits); + printnat(&ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); + nsp->ns_list = ipn.in_next; + } + } + + if (nat_fields == NULL) { + printf("\nList of active sessions:\n"); + + } else if (nohdrfields == 0) { + for (i = 0; nat_fields[i].w_value != 0; i++) { + printfieldhdr(natfields, nat_fields + i); + if (nat_fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } + + for (np = nsp->ns_instances; np; np = nat.nat_next) { + if (kmemcpy((char *)&nat, (long)np, sizeof(nat))) + break; + if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0)) + continue; + if (nat_fields != NULL) { + for (i = 0; nat_fields[i].w_value != 0; i++) { + printnatfield(&nat, nat_fields[i].w_value); + if (nat_fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } else { + printactivenat(&nat, opts, nsp->ns_ticks); + if (nat.nat_aps) { + int proto; + + if (nat.nat_dir & NAT_OUTBOUND) + proto = nat.nat_pr[1]; + else + proto = nat.nat_pr[0]; + printaps(nat.nat_aps, opts, proto); + } + } + } + + if (opts & OPT_VERBOSE) + showhostmap_dead(nsp); +} + + +void dotable(nsp, fd, alive, which, side) + natstat_t *nsp; + int fd, alive, which; + char *side; +{ + int sz, i, used, maxlen, minlen, totallen; + ipftable_t table; + u_int *buckets; + ipfobj_t obj; + + sz = sizeof(*buckets) * nsp->ns_nattab_sz; + buckets = (u_int *)malloc(sz); + if (buckets == NULL) { + fprintf(stderr, + "cannot allocate memory (%d) for buckets\n", sz); + return; + } + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_GTABLE; + obj.ipfo_size = sizeof(table); + obj.ipfo_ptr = &table; + + if (which == 0) { + table.ita_type = IPFTABLE_BUCKETS_NATIN; + } else if (which == 1) { + table.ita_type = IPFTABLE_BUCKETS_NATOUT; + } + table.ita_table = buckets; + + if (alive) { + if (ioctl(fd, SIOCGTABL, &obj) != 0) { + ipferror(fd, "SIOCFTABL"); + free(buckets); + return; + } + } else { + if (kmemcpy((char *)buckets, (u_long)nsp->ns_nattab_sz, sz)) { + free(buckets); + return; + } + } + + minlen = nsp->ns_side[which].ns_inuse; + totallen = 0; + maxlen = 0; + used = 0; + + for (i = 0; i < nsp->ns_nattab_sz; i++) { + if (buckets[i] > maxlen) + maxlen = buckets[i]; + if (buckets[i] < minlen) + minlen = buckets[i]; + if (buckets[i] != 0) + used++; + totallen += buckets[i]; + } + + printf("%d%%\thash efficiency %s\n", + totallen ? used * 100 / totallen : 0, side); + printf("%2.2f%%\tbucket usage %s\n", + ((float)used / nsp->ns_nattab_sz) * 100.0, side); + printf("%d\tminimal length %s\n", minlen, side); + printf("%d\tmaximal length %s\n", maxlen, side); + printf("%.3f\taverage length %s\n", + used ? ((float)totallen / used) : 0.0, side); + + free(buckets); +} + + +void dostats(fd, nsp, opts, alive, filter) + natstat_t *nsp; + int fd, opts, alive, *filter; +{ + /* + * Show statistics ? + */ + if (opts & OPT_STAT) { + printnatside("in", &nsp->ns_side[0]); + dotable(nsp, fd, alive, 0, "in"); + + printnatside("out", &nsp->ns_side[1]); + dotable(nsp, fd, alive, 1, "out"); + + printf("%lu\tlog successes\n", nsp->ns_side[0].ns_log); + printf("%lu\tlog failures\n", nsp->ns_side[1].ns_log); + printf("%lu\tadded in\n%lu\tadded out\n", + nsp->ns_side[0].ns_added, + nsp->ns_side[1].ns_added); + printf("%u\tactive\n", nsp->ns_active); + printf("%lu\ttransparent adds\n", nsp->ns_addtrpnt); + printf("%lu\tdivert build\n", nsp->ns_divert_build); + printf("%lu\texpired\n", nsp->ns_expire); + printf("%lu\tflush all\n", nsp->ns_flush_all); + printf("%lu\tflush closing\n", nsp->ns_flush_closing); + printf("%lu\tflush queue\n", nsp->ns_flush_queue); + printf("%lu\tflush state\n", nsp->ns_flush_state); + printf("%lu\tflush timeout\n", nsp->ns_flush_timeout); + printf("%lu\thostmap new\n", nsp->ns_hm_new); + printf("%lu\thostmap fails\n", nsp->ns_hm_newfail); + printf("%lu\thostmap add\n", nsp->ns_hm_addref); + printf("%lu\thostmap NULL rule\n", nsp->ns_hm_nullnp); + printf("%lu\tlog ok\n", nsp->ns_log_ok); + printf("%lu\tlog fail\n", nsp->ns_log_fail); + printf("%u\torphan count\n", nsp->ns_orphans); + printf("%u\trule count\n", nsp->ns_rules); + printf("%u\tmap rules\n", nsp->ns_rules_map); + printf("%u\trdr rules\n", nsp->ns_rules_rdr); + printf("%u\twilds\n", nsp->ns_wilds); + if (opts & OPT_VERBOSE) + printf("list %p\n", nsp->ns_list); + } + + if (opts & OPT_LIST) { + if (alive) + dostats_live(fd, nsp, opts, filter); + else + dostats_dead(nsp, opts, filter); + } +} + + +/* + * Display NAT statistics. + */ +void dostats_live(fd, nsp, opts, filter) + natstat_t *nsp; + int fd, opts, *filter; +{ + ipfgeniter_t iter; + char buffer[2000]; + ipfobj_t obj; + ipnat_t *ipn; + nat_t nat; + int i; + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_GENITER; + obj.ipfo_size = sizeof(iter); + obj.ipfo_ptr = &iter; + + iter.igi_type = IPFGENITER_IPNAT; + iter.igi_nitems = 1; + iter.igi_data = buffer; + ipn = (ipnat_t *)buffer; + + /* + * Show list of NAT rules and NAT sessions ? + */ + if (nat_fields == NULL) { + printf("List of active MAP/Redirect filters:\n"); + while (nsp->ns_list) { + if (ioctl(fd, SIOCGENITER, &obj) == -1) + break; + if (opts & OPT_HITS) + printf("%lu ", ipn->in_hits); + printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); + nsp->ns_list = ipn->in_next; + } + } + + if (nat_fields == NULL) { + printf("\nList of active sessions:\n"); + + } else if (nohdrfields == 0) { + for (i = 0; nat_fields[i].w_value != 0; i++) { + printfieldhdr(natfields, nat_fields + i); + if (nat_fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } + + i = IPFGENITER_IPNAT; + (void) ioctl(fd,SIOCIPFDELTOK, &i); + + + iter.igi_type = IPFGENITER_NAT; + iter.igi_nitems = 1; + iter.igi_data = &nat; + + while (nsp->ns_instances != NULL) { + if (ioctl(fd, SIOCGENITER, &obj) == -1) + break; + if ((filter != NULL) && (nat_matcharray(&nat, filter) == 0)) + continue; + if (nat_fields != NULL) { + for (i = 0; nat_fields[i].w_value != 0; i++) { + printnatfield(&nat, nat_fields[i].w_value); + if (nat_fields[i + 1].w_value != 0) + printf("\t"); + } + printf("\n"); + } else { + printactivenat(&nat, opts, nsp->ns_ticks); + if (nat.nat_aps) { + int proto; + + if (nat.nat_dir & NAT_OUTBOUND) + proto = nat.nat_pr[1]; + else + proto = nat.nat_pr[0]; + printaps(nat.nat_aps, opts, proto); + } + } + nsp->ns_instances = nat.nat_next; + } + + if (opts & OPT_VERBOSE) + showhostmap_live(fd, nsp); + + i = IPFGENITER_NAT; + (void) ioctl(fd,SIOCIPFDELTOK, &i); +} + + +/* + * Display the active host mapping table. + */ +void showhostmap_dead(nsp) + natstat_t *nsp; +{ + hostmap_t hm, *hmp, **maptable; + u_int hv; + + printf("\nList of active host mappings:\n"); + + maptable = (hostmap_t **)malloc(sizeof(hostmap_t *) * + nsp->ns_hostmap_sz); + if (kmemcpy((char *)maptable, (u_long)nsp->ns_maptable, + sizeof(hostmap_t *) * nsp->ns_hostmap_sz)) { + perror("kmemcpy (maptable)"); + return; + } + + for (hv = 0; hv < nsp->ns_hostmap_sz; hv++) { + hmp = maptable[hv]; + + while (hmp) { + if (kmemcpy((char *)&hm, (u_long)hmp, sizeof(hm))) { + perror("kmemcpy (hostmap)"); + return; + } + + printhostmap(&hm, hv); + hmp = hm.hm_next; + } + } + free(maptable); +} + + +/* + * Display the active host mapping table. + */ +void showhostmap_live(fd, nsp) + int fd; + natstat_t *nsp; +{ + ipfgeniter_t iter; + hostmap_t hm; + ipfobj_t obj; + int i; + + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_GENITER; + obj.ipfo_size = sizeof(iter); + obj.ipfo_ptr = &iter; + + iter.igi_type = IPFGENITER_HOSTMAP; + iter.igi_nitems = 1; + iter.igi_data = &hm; + + printf("\nList of active host mappings:\n"); + + while (nsp->ns_maplist != NULL) { + if (ioctl(fd, SIOCGENITER, &obj) == -1) + break; + printhostmap(&hm, hm.hm_hv); + nsp->ns_maplist = hm.hm_next; + } + + i = IPFGENITER_HOSTMAP; + (void) ioctl(fd,SIOCIPFDELTOK, &i); +} + + +int nat_matcharray(nat, array) + nat_t *nat; + int *array; +{ + int i, n, *x, rv, p; + ipfexp_t *e; + + rv = 0; + n = array[0]; + x = array + 1; + + for (; n > 0; x += 3 + x[3], rv = 0) { + e = (ipfexp_t *)x; + if (e->ipfe_cmd == IPF_EXP_END) + break; + n -= e->ipfe_size; + + p = e->ipfe_cmd >> 16; + if ((p != 0) && (p != nat->nat_pr[1])) + break; + + switch (e->ipfe_cmd) + { + case IPF_EXP_IP_PR : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (nat->nat_pr[1] == e->ipfe_arg0[i]); + } + break; + + case IPF_EXP_IP_SRCADDR : + if (nat->nat_v[0] != 4) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= ((nat->nat_osrcaddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]) || + ((nat->nat_nsrcaddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]); + } + break; + + case IPF_EXP_IP_DSTADDR : + if (nat->nat_v[0] != 4) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= ((nat->nat_odstaddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]) || + ((nat->nat_ndstaddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]); + } + break; + + case IPF_EXP_IP_ADDR : + if (nat->nat_v[0] != 4) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= ((nat->nat_osrcaddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]) || + ((nat->nat_nsrcaddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]) || + ((nat->nat_odstaddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]) || + ((nat->nat_ndstaddr & + e->ipfe_arg0[i * 2 + 1]) == + e->ipfe_arg0[i * 2]); + } + break; + +#ifdef USE_INET6 + case IPF_EXP_IP6_SRCADDR : + if (nat->nat_v[0] != 6) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= IP6_MASKEQ(&nat->nat_osrc6, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]) || + IP6_MASKEQ(&nat->nat_nsrc6, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]); + } + break; + + case IPF_EXP_IP6_DSTADDR : + if (nat->nat_v[0] != 6) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= IP6_MASKEQ(&nat->nat_odst6, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]) || + IP6_MASKEQ(&nat->nat_ndst6, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]); + } + break; + + case IPF_EXP_IP6_ADDR : + if (nat->nat_v[0] != 6) + break; + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= IP6_MASKEQ(&nat->nat_osrc6, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]) || + IP6_MASKEQ(&nat->nat_nsrc6, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]) || + IP6_MASKEQ(&nat->nat_odst6, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]) || + IP6_MASKEQ(&nat->nat_ndst6, + &e->ipfe_arg0[i * 8 + 4], + &e->ipfe_arg0[i * 8]); + } + break; +#endif + + case IPF_EXP_UDP_PORT : + case IPF_EXP_TCP_PORT : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (nat->nat_osport == e->ipfe_arg0[i]) || + (nat->nat_nsport == e->ipfe_arg0[i]) || + (nat->nat_odport == e->ipfe_arg0[i]) || + (nat->nat_ndport == e->ipfe_arg0[i]); + } + break; + + case IPF_EXP_UDP_SPORT : + case IPF_EXP_TCP_SPORT : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (nat->nat_osport == e->ipfe_arg0[i]) || + (nat->nat_nsport == e->ipfe_arg0[i]); + } + break; + + case IPF_EXP_UDP_DPORT : + case IPF_EXP_TCP_DPORT : + for (i = 0; !rv && i < e->ipfe_narg; i++) { + rv |= (nat->nat_odport == e->ipfe_arg0[i]) || + (nat->nat_ndport == e->ipfe_arg0[i]); + } + break; + } + rv ^= e->ipfe_not; + + if (rv == 0) + break; + } + + return rv; +} diff --git a/contrib/ipfilter/tools/ipnat_y.y b/contrib/ipfilter/tools/ipnat_y.y new file mode 100644 index 0000000..39e6a92 --- /dev/null +++ b/contrib/ipfilter/tools/ipnat_y.y @@ -0,0 +1,1782 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +%{ +#ifdef __FreeBSD__ +# ifndef __FreeBSD_cc_version +# include <osreldate.h> +# else +# if __FreeBSD_cc_version < 430000 +# include <osreldate.h> +# endif +# endif +#endif +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#if !defined(__SVR4) && !defined(__GNUC__) +#include <strings.h> +#endif +#include <sys/types.h> +#include <sys/param.h> +#include <sys/file.h> +#include <stdlib.h> +#include <stddef.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <sys/time.h> +#include <syslog.h> +#include <net/if.h> +#include <netdb.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include "ipf.h" +#include "netinet/ipl.h" +#include "ipnat_l.h" + +#define YYDEBUG 1 + +extern void yyerror __P((char *)); +extern int yyparse __P((void)); +extern int yylex __P((void)); +extern int yydebug; +extern FILE *yyin; +extern int yylineNum; + +static ipnat_t *nattop = NULL; +static ipnat_t *nat = NULL; +static int natfd = -1; +static ioctlfunc_t natioctlfunc = NULL; +static addfunc_t nataddfunc = NULL; +static int suggest_port = 0; +static proxyrule_t *prules = NULL; +static int parser_error = 0; + +static void newnatrule __P((void)); +static void setnatproto __P((int)); +static void setmapifnames __P((void)); +static void setrdrifnames __P((void)); +static void proxy_setconfig __P((int)); +static void proxy_unsetconfig __P((void)); +static namelist_t *proxy_dns_add_pass __P((char *, char *)); +static namelist_t *proxy_dns_add_block __P((char *, char *)); +static void proxy_addconfig __P((char *, int, char *, namelist_t *)); +static void proxy_loadconfig __P((int, ioctlfunc_t, char *, int, + char *, namelist_t *)); +static void proxy_loadrules __P((int, ioctlfunc_t, proxyrule_t *)); +static void setmapifnames __P((void)); +static void setrdrifnames __P((void)); +static void setifname __P((ipnat_t **, int, char *)); +static int addname __P((ipnat_t **, char *)); +%} +%union { + char *str; + u_32_t num; + struct { + i6addr_t a; + int f; + } ipa; + frentry_t fr; + frtuc_t *frt; + u_short port; + struct { + int p1; + int p2; + int pc; + } pc; + struct { + i6addr_t a; + i6addr_t m; + int t; /* Address type */ + int u; + int f; /* Family */ + int v; /* IP version */ + int s; /* 0 = number, 1 = text */ + int n; /* number */ + } ipp; + union i6addr ip6; + namelist_t *names; +}; + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN +%token <ip6> YY_IPV6 + +%token IPNY_MAPBLOCK IPNY_RDR IPNY_PORT IPNY_PORTS IPNY_AUTO IPNY_RANGE +%token IPNY_MAP IPNY_BIMAP IPNY_FROM IPNY_TO IPNY_MASK IPNY_PORTMAP IPNY_ANY +%token IPNY_ROUNDROBIN IPNY_FRAG IPNY_AGE IPNY_ICMPIDMAP IPNY_PROXY +%token IPNY_TCP IPNY_UDP IPNY_TCPUDP IPNY_STICKY IPNY_MSSCLAMP IPNY_TAG +%token IPNY_TLATE IPNY_POOL IPNY_HASH IPNY_NO IPNY_REWRITE IPNY_PROTO +%token IPNY_ON IPNY_SRC IPNY_DST IPNY_IN IPNY_OUT IPNY_DIVERT +%token IPNY_CONFIG IPNY_ALLOW IPNY_DENY IPNY_DNS IPNY_INET IPNY_INET6 +%token IPNY_SEQUENTIAL IPNY_DSTLIST IPNY_PURGE +%type <port> portspec +%type <num> hexnumber compare range proto +%type <num> saddr daddr sobject dobject mapfrom rdrfrom dip +%type <ipa> hostname ipv4 ipaddr +%type <ipp> addr rhsaddr rhdaddr erhdaddr +%type <pc> portstuff portpair comaports srcports dstports +%type <names> dnslines dnsline +%% +file: line + | assign + | file line + | file assign + | file pconf ';' + ; + +line: xx rule { int err; + while ((nat = nattop) != NULL) { + if (nat->in_v[0] == 0) + nat->in_v[0] = 4; + if (nat->in_v[1] == 0) + nat->in_v[1] = nat->in_v[0]; + nattop = nat->in_next; + err = (*nataddfunc)(natfd, natioctlfunc, nat); + free(nat); + if (err != 0) { + parser_error = err; + break; + } + } + if (parser_error == 0 && prules != NULL) { + proxy_loadrules(natfd, natioctlfunc, prules); + prules = NULL; + } + resetlexer(); + } + | YY_COMMENT + ; + +assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + yyvarnext = 0; + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +xx: { newnatrule(); } + ; + +rule: map eol + | mapblock eol + | redir eol + | rewrite ';' + | divert ';' + ; + +no: IPNY_NO { nat->in_flags |= IPN_NO; } + ; + +eol: | ';' + ; + +map: mapit ifnames addr tlate rhsaddr proxy mapoptions + { if ($3.f != 0 && $3.f != $5.f && $5.f != 0) + yyerror("3.address family mismatch"); + if (nat->in_v[0] == 0 && $5.v != 0) + nat->in_v[0] = $5.v; + else if (nat->in_v[0] == 0 && $3.v != 0) + nat->in_v[0] = $3.v; + if (nat->in_v[1] == 0 && $5.v != 0) + nat->in_v[1] = $5.v; + else if (nat->in_v[1] == 0 && $3.v != 0) + nat->in_v[1] = $3.v; + nat->in_osrcatype = $3.t; + bcopy(&$3.a, &nat->in_osrc.na_addr[0], + sizeof($3.a)); + bcopy(&$3.m, &nat->in_osrc.na_addr[1], + sizeof($3.a)); + nat->in_nsrcatype = $5.t; + nat->in_nsrcafunc = $5.u; + bcopy(&$5.a, &nat->in_nsrc.na_addr[0], + sizeof($5.a)); + bcopy(&$5.m, &nat->in_nsrc.na_addr[1], + sizeof($5.a)); + + setmapifnames(); + } + | mapit ifnames addr tlate rhsaddr mapport mapoptions + { if ($3.f != $5.f && $3.f != 0 && $5.f != 0) + yyerror("4.address family mismatch"); + if (nat->in_v[1] == 0 && $5.v != 0) + nat->in_v[1] = $5.v; + else if (nat->in_v[0] == 0 && $3.v != 0) + nat->in_v[0] = $3.v; + if (nat->in_v[0] == 0 && $5.v != 0) + nat->in_v[0] = $5.v; + else if (nat->in_v[1] == 0 && $3.v != 0) + nat->in_v[1] = $3.v; + nat->in_osrcatype = $3.t; + bcopy(&$3.a, &nat->in_osrc.na_addr[0], + sizeof($3.a)); + bcopy(&$3.m, &nat->in_osrc.na_addr[1], + sizeof($3.a)); + nat->in_nsrcatype = $5.t; + nat->in_nsrcafunc = $5.u; + bcopy(&$5.a, &nat->in_nsrc.na_addr[0], + sizeof($5.a)); + bcopy(&$5.m, &nat->in_nsrc.na_addr[1], + sizeof($5.a)); + + setmapifnames(); + } + | no mapit ifnames addr setproto ';' + { if (nat->in_v[0] == 0) + nat->in_v[0] = $4.v; + nat->in_osrcatype = $4.t; + bcopy(&$4.a, &nat->in_osrc.na_addr[0], + sizeof($4.a)); + bcopy(&$4.m, &nat->in_osrc.na_addr[1], + sizeof($4.a)); + + setmapifnames(); + } + | mapit ifnames mapfrom tlate rhsaddr proxy mapoptions + { if ($3 != 0 && $5.f != 0 && $3 != $5.f) + yyerror("5.address family mismatch"); + if (nat->in_v[0] == 0 && $5.v != 0) + nat->in_v[0] = $5.v; + else if (nat->in_v[0] == 0 && $3 != 0) + nat->in_v[0] = ftov($3); + if (nat->in_v[1] == 0 && $5.v != 0) + nat->in_v[1] = $5.v; + else if (nat->in_v[1] == 0 && $3 != 0) + nat->in_v[1] = ftov($3); + nat->in_nsrcatype = $5.t; + nat->in_nsrcafunc = $5.u; + bcopy(&$5.a, &nat->in_nsrc.na_addr[0], + sizeof($5.a)); + bcopy(&$5.m, &nat->in_nsrc.na_addr[1], + sizeof($5.a)); + + setmapifnames(); + } + | no mapit ifnames mapfrom setproto ';' + { nat->in_v[0] = ftov($4); + setmapifnames(); + } + | mapit ifnames mapfrom tlate rhsaddr mapport mapoptions + { if ($3 != 0 && $5.f != 0 && $3 != $5.f) + yyerror("6.address family mismatch"); + if (nat->in_v[0] == 0 && $5.v != 0) + nat->in_v[0] = $5.v; + else if (nat->in_v[0] == 0 && $3 != 0) + nat->in_v[0] = ftov($3); + if (nat->in_v[1] == 0 && $5.v != 0) + nat->in_v[1] = $5.v; + else if (nat->in_v[1] == 0 && $3 != 0) + nat->in_v[1] = ftov($3); + nat->in_nsrcatype = $5.t; + nat->in_nsrcafunc = $5.u; + bcopy(&$5.a, &nat->in_nsrc.na_addr[0], + sizeof($5.a)); + bcopy(&$5.m, &nat->in_nsrc.na_addr[1], + sizeof($5.a)); + + setmapifnames(); + } + ; + +mapblock: + mapblockit ifnames addr tlate addr ports mapoptions + { if ($3.f != 0 && $5.f != 0 && $3.f != $5.f) + yyerror("7.address family mismatch"); + if (nat->in_v[0] == 0 && $5.v != 0) + nat->in_v[0] = $5.v; + else if (nat->in_v[0] == 0 && $3.v != 0) + nat->in_v[0] = $3.v; + if (nat->in_v[1] == 0 && $5.v != 0) + nat->in_v[1] = $5.v; + else if (nat->in_v[1] == 0 && $3.v != 0) + nat->in_v[1] = $3.v; + nat->in_osrcatype = $3.t; + bcopy(&$3.a, &nat->in_osrc.na_addr[0], + sizeof($3.a)); + bcopy(&$3.m, &nat->in_osrc.na_addr[1], + sizeof($3.a)); + nat->in_nsrcatype = $5.t; + nat->in_nsrcafunc = $5.u; + bcopy(&$5.a, &nat->in_nsrc.na_addr[0], + sizeof($5.a)); + bcopy(&$5.m, &nat->in_nsrc.na_addr[1], + sizeof($5.a)); + + setmapifnames(); + } + | no mapblockit ifnames { yyexpectaddr = 1; } addr setproto ';' + { if (nat->in_v[0] == 0) + nat->in_v[0] = $5.v; + if (nat->in_v[1] == 0) + nat->in_v[1] = $5.v; + nat->in_osrcatype = $5.t; + bcopy(&$5.a, &nat->in_osrc.na_addr[0], + sizeof($5.a)); + bcopy(&$5.m, &nat->in_osrc.na_addr[1], + sizeof($5.a)); + + setmapifnames(); + } + ; + +redir: rdrit ifnames addr dport tlate dip nport setproto rdroptions + { if ($6 != 0 && $3.f != 0 && $6 != $3.f) + yyerror("21.address family mismatch"); + if (nat->in_v[0] == 0) { + if ($3.v != AF_UNSPEC) + nat->in_v[0] = ftov($3.f); + else + nat->in_v[0] = ftov($6); + } + nat->in_odstatype = $3.t; + bcopy(&$3.a, &nat->in_odst.na_addr[0], + sizeof($3.a)); + bcopy(&$3.m, &nat->in_odst.na_addr[1], + sizeof($3.a)); + + setrdrifnames(); + } + | no rdrit ifnames addr dport setproto ';' + { if (nat->in_v[0] == 0) + nat->in_v[0] = ftov($4.f); + nat->in_odstatype = $4.t; + bcopy(&$4.a, &nat->in_odst.na_addr[0], + sizeof($4.a)); + bcopy(&$4.m, &nat->in_odst.na_addr[1], + sizeof($4.a)); + + setrdrifnames(); + } + | rdrit ifnames rdrfrom tlate dip nport setproto rdroptions + { if ($5 != 0 && $3 != 0 && $5 != $3) + yyerror("20.address family mismatch"); + if (nat->in_v[0] == 0) { + if ($3 != AF_UNSPEC) + nat->in_v[0] = ftov($3); + else + nat->in_v[0] = ftov($5); + } + setrdrifnames(); + } + | no rdrit ifnames rdrfrom setproto ';' + { nat->in_v[0] = ftov($4); + + setrdrifnames(); + } + ; + +rewrite: + IPNY_REWRITE oninout rwrproto mapfrom tlate newdst newopts + { if (nat->in_v[0] == 0) + nat->in_v[0] = ftov($4); + if (nat->in_redir & NAT_MAP) + setmapifnames(); + else + setrdrifnames(); + nat->in_redir |= NAT_REWRITE; + } + ; + +divert: IPNY_DIVERT oninout rwrproto mapfrom tlate divdst newopts + { if (nat->in_v[0] == 0) + nat->in_v[0] = ftov($4); + if (nat->in_redir & NAT_MAP) { + setmapifnames(); + nat->in_pr[0] = IPPROTO_UDP; + } else { + setrdrifnames(); + nat->in_pr[1] = IPPROTO_UDP; + } + nat->in_flags &= ~IPN_TCP; + } + ; + +tlate: IPNY_TLATE { yyexpectaddr = 1; } + ; + +pconf: IPNY_PROXY { yysetdict(proxies); } + IPNY_DNS '/' proto IPNY_CONFIG YY_STR '{' + { proxy_setconfig(IPNY_DNS); } + dnslines ';' '}' + { proxy_addconfig("dns", $5, $7, $10); + proxy_unsetconfig(); + } + ; + +dnslines: + dnsline { $$ = $1; } + | dnslines ';' dnsline { $$ = $1; $1->na_next = $3; } + ; + +dnsline: + IPNY_ALLOW YY_STR { $$ = proxy_dns_add_pass(NULL, $2); } + | IPNY_DENY YY_STR { $$ = proxy_dns_add_block(NULL, $2); } + | IPNY_ALLOW '.' YY_STR { $$ = proxy_dns_add_pass(".", $3); } + | IPNY_DENY '.' YY_STR { $$ = proxy_dns_add_block(".", $3); } + ; + +oninout: + inout IPNY_ON ifnames { ; } + ; + +inout: IPNY_IN { nat->in_redir = NAT_REDIRECT; } + | IPNY_OUT { nat->in_redir = NAT_MAP; } + ; + +rwrproto: + | IPNY_PROTO setproto + ; + +newdst: src rhsaddr srcports dst erhdaddr dstports + { nat->in_nsrc.na_addr[0] = $2.a; + nat->in_nsrc.na_addr[1] = $2.m; + nat->in_nsrc.na_atype = $2.t; + if ($2.t == FRI_LOOKUP) { + nat->in_nsrc.na_type = $2.u; + nat->in_nsrc.na_subtype = $2.s; + nat->in_nsrc.na_num = $2.n; + } + nat->in_nsports[0] = $3.p1; + nat->in_nsports[1] = $3.p2; + nat->in_ndst.na_addr[0] = $5.a; + nat->in_ndst.na_addr[1] = $5.m; + nat->in_ndst.na_atype = $5.t; + if ($5.t == FRI_LOOKUP) { + nat->in_ndst.na_type = $5.u; + nat->in_ndst.na_subtype = $5.s; + nat->in_ndst.na_num = $5.n; + } + nat->in_ndports[0] = $6.p1; + nat->in_ndports[1] = $6.p2; + } + ; + +divdst: src addr ',' portspec dst addr ',' portspec IPNY_UDP + { nat->in_nsrc.na_addr[0] = $2.a; + if ($2.m.in4.s_addr != 0xffffffff) + yyerror("divert must have /32 dest"); + nat->in_nsrc.na_addr[1] = $2.m; + nat->in_nsports[0] = $4; + nat->in_nsports[1] = $4; + + nat->in_ndst.na_addr[0] = $6.a; + nat->in_ndst.na_addr[1] = $6.m; + if ($6.m.in4.s_addr != 0xffffffff) + yyerror("divert must have /32 dest"); + nat->in_ndports[0] = $8; + nat->in_ndports[1] = $8; + + nat->in_redir |= NAT_DIVERTUDP; + } + ; + +src: IPNY_SRC { yyexpectaddr = 1; } + ; + +dst: IPNY_DST { yyexpectaddr = 1; } + ; + +srcports: + comaports { $$.p1 = $1.p1; + $$.p2 = $1.p2; + } + | IPNY_PORT '=' portspec + { $$.p1 = $3; + $$.p2 = $3; + nat->in_flags |= IPN_FIXEDSPORT; + } + ; + +dstports: + comaports { $$.p1 = $1.p1; + $$.p2 = $1.p2; + } + | IPNY_PORT '=' portspec + { $$.p1 = $3; + $$.p2 = $3; + nat->in_flags |= IPN_FIXEDDPORT; + } + ; + +comaports: + { $$.p1 = 0; + $$.p2 = 0; + } + | ',' { if (!(nat->in_flags & IPN_TCPUDP)) + yyerror("must be TCP/UDP for ports"); + } + portpair { $$.p1 = $3.p1; + $$.p2 = $3.p2; + } + ; + +proxy: | IPNY_PROXY port portspec YY_STR '/' proto + { int pos; + pos = addname(&nat, $4); + nat->in_plabel = pos; + if (nat->in_dcmp == 0) { + nat->in_odport = $3; + } else if ($3 != nat->in_odport) { + yyerror("proxy port numbers not consistant"); + } + nat->in_ndport = $3; + setnatproto($6); + free($4); + } + | IPNY_PROXY port YY_STR YY_STR '/' proto + { int pnum, pos; + pos = addname(&nat, $4); + nat->in_plabel = pos; + pnum = getportproto($3, $6); + if (pnum == -1) + yyerror("invalid port number"); + nat->in_odport = ntohs(pnum); + nat->in_ndport = ntohs(pnum); + setnatproto($6); + free($3); + free($4); + } + | IPNY_PROXY port portspec YY_STR '/' proto IPNY_CONFIG YY_STR + { int pos; + pos = addname(&nat, $4); + nat->in_plabel = pos; + if (nat->in_dcmp == 0) { + nat->in_odport = $3; + } else if ($3 != nat->in_odport) { + yyerror("proxy port numbers not consistant"); + } + nat->in_ndport = $3; + setnatproto($6); + nat->in_pconfig = addname(&nat, $8); + free($4); + free($8); + } + | IPNY_PROXY port YY_STR YY_STR '/' proto IPNY_CONFIG YY_STR + { int pnum, pos; + pos = addname(&nat, $4); + nat->in_plabel = pos; + pnum = getportproto($3, $6); + if (pnum == -1) + yyerror("invalid port number"); + nat->in_odport = ntohs(pnum); + nat->in_ndport = ntohs(pnum); + setnatproto($6); + pos = addname(&nat, $8); + nat->in_pconfig = pos; + free($3); + free($4); + free($8); + } + ; +setproto: + | proto { if (nat->in_pr[0] != 0 || + nat->in_pr[1] != 0 || + nat->in_flags & IPN_TCPUDP) + yyerror("protocol set twice"); + setnatproto($1); + } + | IPNY_TCPUDP { if (nat->in_pr[0] != 0 || + nat->in_pr[1] != 0 || + nat->in_flags & IPN_TCPUDP) + yyerror("protocol set twice"); + nat->in_flags |= IPN_TCPUDP; + nat->in_pr[0] = 0; + nat->in_pr[1] = 0; + } + | IPNY_TCP '/' IPNY_UDP { if (nat->in_pr[0] != 0 || + nat->in_pr[1] != 0 || + nat->in_flags & IPN_TCPUDP) + yyerror("protocol set twice"); + nat->in_flags |= IPN_TCPUDP; + nat->in_pr[0] = 0; + nat->in_pr[1] = 0; + } + ; + +rhsaddr: + addr { $$ = $1; + yyexpectaddr = 0; + } + | hostname '-' { yyexpectaddr = 1; } hostname + { $$.t = FRI_RANGE; + if ($1.f != $4.f) + yyerror("8.address family " + "mismatch"); + $$.f = $1.f; + $$.v = ftov($1.f); + $$.a = $1.a; + $$.m = $4.a; + nat->in_flags |= IPN_SIPRANGE; + yyexpectaddr = 0; + } + | IPNY_RANGE hostname '-' { yyexpectaddr = 1; } hostname + { $$.t = FRI_RANGE; + if ($2.f != $5.f) + yyerror("9.address family " + "mismatch"); + $$.f = $2.f; + $$.v = ftov($2.f); + $$.a = $2.a; + $$.m = $5.a; + nat->in_flags |= IPN_SIPRANGE; + yyexpectaddr = 0; + } + ; + +dip: + hostname ',' { yyexpectaddr = 1; } hostname + { nat->in_flags |= IPN_SPLIT; + if ($1.f != $4.f) + yyerror("10.address family " + "mismatch"); + $$ = $1.f; + nat->in_ndstip6 = $1.a; + nat->in_ndstmsk6 = $4.a; + nat->in_ndstatype = FRI_SPLIT; + yyexpectaddr = 0; + } + | rhdaddr { int bits; + nat->in_ndstip6 = $1.a; + nat->in_ndstmsk6 = $1.m; + nat->in_ndst.na_atype = $1.t; + yyexpectaddr = 0; + if ($1.f == AF_INET) + bits = count4bits($1.m.in4.s_addr); + else + bits = count6bits($1.m.i6); + if (($1.f == AF_INET) && (bits != 0) && + (bits != 32)) { + yyerror("dest ip bitmask not /32"); + } else if (($1.f == AF_INET6) && + (bits != 0) && (bits != 128)) { + yyerror("dest ip bitmask not /128"); + } + $$ = $1.f; + } + ; + +rhdaddr: + addr { $$ = $1; + yyexpectaddr = 0; + } + | hostname '-' hostname { bzero(&$$, sizeof($$)); + $$.t = FRI_RANGE; + if ($1.f != 0 && $3.f != 0 && + $1.f != $3.f) + yyerror("11.address family " + "mismatch"); + $$.a = $1.a; + $$.m = $3.a; + nat->in_flags |= IPN_DIPRANGE; + yyexpectaddr = 0; + } + | IPNY_RANGE hostname '-' hostname + { bzero(&$$, sizeof($$)); + $$.t = FRI_RANGE; + if ($2.f != 0 && $4.f != 0 && + $2.f != $4.f) + yyerror("12.address family " + "mismatch"); + $$.a = $2.a; + $$.m = $4.a; + nat->in_flags |= IPN_DIPRANGE; + yyexpectaddr = 0; + } + ; + +erhdaddr: + rhdaddr { $$ = $1; } + | IPNY_DSTLIST '/' YY_NUMBER { $$.t = FRI_LOOKUP; + $$.u = IPLT_DSTLIST; + $$.s = 0; + $$.n = $3; + } + | IPNY_DSTLIST '/' YY_STR { $$.t = FRI_LOOKUP; + $$.u = IPLT_DSTLIST; + $$.s = 1; + $$.n = addname(&nat, $3); + } + ; + +port: IPNY_PORT { suggest_port = 1; } + ; + +portspec: + YY_NUMBER { if ($1 > 65535) /* Unsigned */ + yyerror("invalid port number"); + else + $$ = $1; + } + | YY_STR { if (getport(NULL, $1, + &($$), NULL) == -1) + yyerror("invalid port number"); + $$ = ntohs($$); + } + ; + +portpair: + portspec { $$.p1 = $1; $$.p2 = $1; } + | portspec '-' portspec { $$.p1 = $1; $$.p2 = $3; } + | portspec ':' portspec { $$.p1 = $1; $$.p2 = $3; } + ; + +dport: | port portpair { nat->in_odport = $2.p1; + if ($2.p2 == 0) + nat->in_dtop = $2.p1; + else + nat->in_dtop = $2.p2; + } + ; + +nport: | port portpair { nat->in_dpmin = $2.p1; + nat->in_dpnext = $2.p1; + nat->in_dpmax = $2.p2; + nat->in_ndport = $2.p1; + if (nat->in_dtop == 0) + nat->in_dtop = $2.p2; + } + | port '=' portspec { nat->in_dpmin = $3; + nat->in_dpnext = $3; + nat->in_ndport = $3; + if (nat->in_dtop == 0) + nat->in_dtop = nat->in_odport; + nat->in_flags |= IPN_FIXEDDPORT; + } + ; + +ports: | IPNY_PORTS YY_NUMBER { nat->in_spmin = $2; } + | IPNY_PORTS IPNY_AUTO { nat->in_flags |= IPN_AUTOPORTMAP; } + ; + +mapit: IPNY_MAP { nat->in_redir = NAT_MAP; } + | IPNY_BIMAP { nat->in_redir = NAT_BIMAP; } + ; + +rdrit: IPNY_RDR { nat->in_redir = NAT_REDIRECT; } + ; + +mapblockit: + IPNY_MAPBLOCK { nat->in_redir = NAT_MAPBLK; } + ; + +mapfrom: + from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4) + yyerror("13.address family " + "mismatch"); + $$ = $2; + } + | from sobject '!' to dobject + { if ($2 != 0 && $5 != 0 && $2 != $5) + yyerror("14.address family " + "mismatch"); + nat->in_flags |= IPN_NOTDST; + $$ = $2; + } + | from sobject to '!' dobject + { if ($2 != 0 && $5 != 0 && $2 != $5) + yyerror("15.address family " + "mismatch"); + nat->in_flags |= IPN_NOTDST; + $$ = $2; + } + ; + +rdrfrom: + from sobject to dobject { if ($2 != 0 && $4 != 0 && $2 != $4) + yyerror("16.address family " + "mismatch"); + $$ = $2; + } + | '!' from sobject to dobject + { if ($3 != 0 && $5 != 0 && $3 != $5) + yyerror("17.address family " + "mismatch"); + nat->in_flags |= IPN_NOTSRC; + $$ = $3; + } + | from '!' sobject to dobject + { if ($3 != 0 && $5 != 0 && $3 != $5) + yyerror("18.address family " + "mismatch"); + nat->in_flags |= IPN_NOTSRC; + $$ = $3; + } + ; + +from: IPNY_FROM { nat->in_flags |= IPN_FILTER; + yyexpectaddr = 1; + } + ; + +to: IPNY_TO { yyexpectaddr = 1; } + ; + +ifnames: + ifname family { yyexpectaddr = 1; } + | ifname ',' otherifname family { yyexpectaddr = 1; } + ; + +ifname: YY_STR { setifname(&nat, 0, $1); + free($1); + } + ; + +family: | IPNY_INET { nat->in_v[0] = 4; nat->in_v[1] = 4; } + | IPNY_INET6 { nat->in_v[0] = 6; nat->in_v[1] = 6; } + ; + +otherifname: + YY_STR { setifname(&nat, 1, $1); + free($1); + } + ; + +mapport: + IPNY_PORTMAP tcpudp portpair sequential + { nat->in_spmin = $3.p1; + nat->in_spmax = $3.p2; + } + | IPNY_PORTMAP portpair tcpudp sequential + { nat->in_spmin = $2.p1; + nat->in_spmax = $2.p2; + } + | IPNY_PORTMAP tcpudp IPNY_AUTO sequential + { nat->in_flags |= IPN_AUTOPORTMAP; + nat->in_spmin = 1024; + nat->in_spmax = 65535; + } + | IPNY_ICMPIDMAP YY_STR portpair sequential + { if (strcmp($2, "icmp") != 0 && + strcmp($2, "ipv6-icmp") != 0) { + yyerror("icmpidmap not followed by icmp"); + } + free($2); + if ($3.p1 < 0 || $3.p1 > 65535) + yyerror("invalid 1st ICMP Id number"); + if ($3.p2 < 0 || $3.p2 > 65535) + yyerror("invalid 2nd ICMP Id number"); + if (strcmp($2, "ipv6-icmp") == 0) { + nat->in_pr[0] = IPPROTO_ICMPV6; + nat->in_pr[1] = IPPROTO_ICMPV6; + } else { + nat->in_pr[0] = IPPROTO_ICMP; + nat->in_pr[1] = IPPROTO_ICMP; + } + nat->in_flags = IPN_ICMPQUERY; + nat->in_spmin = $3.p1; + nat->in_spmax = $3.p2; + } + ; + +sobject: + saddr { $$ = $1; } + | saddr port portstuff { nat->in_osport = $3.p1; + nat->in_stop = $3.p2; + nat->in_scmp = $3.pc; + $$ = $1; + } + ; + +saddr: addr { nat->in_osrcatype = $1.t; + bcopy(&$1.a, + &nat->in_osrc.na_addr[0], + sizeof($1.a)); + bcopy(&$1.m, + &nat->in_osrc.na_addr[1], + sizeof($1.m)); + $$ = $1.f; + } + ; + +dobject: + daddr { $$ = $1; } + | daddr port portstuff { nat->in_odport = $3.p1; + nat->in_dtop = $3.p2; + nat->in_dcmp = $3.pc; + $$ = $1; + } + ; + +daddr: addr { nat->in_odstatype = $1.t; + bcopy(&$1.a, + &nat->in_odst.na_addr[0], + sizeof($1.a)); + bcopy(&$1.m, + &nat->in_odst.na_addr[1], + sizeof($1.m)); + $$ = $1.f; + } + ; + +addr: IPNY_ANY { yyexpectaddr = 0; + bzero(&$$, sizeof($$)); + $$.t = FRI_NORMAL; + } + | hostname { bzero(&$$, sizeof($$)); + $$.a = $1.a; + $$.t = FRI_NORMAL; + $$.v = ftov($1.f); + $$.f = $1.f; + if ($$.f == AF_INET) { + $$.m.in4.s_addr = 0xffffffff; + } else if ($$.f == AF_INET6) { + $$.m.i6[0] = 0xffffffff; + $$.m.i6[1] = 0xffffffff; + $$.m.i6[2] = 0xffffffff; + $$.m.i6[3] = 0xffffffff; + } + yyexpectaddr = 0; + } + | hostname slash YY_NUMBER + { bzero(&$$, sizeof($$)); + $$.a = $1.a; + $$.f = $1.f; + $$.v = ftov($1.f); + $$.t = FRI_NORMAL; + ntomask($$.f, $3, (u_32_t *)&$$.m); + $$.a.i6[0] &= $$.m.i6[0]; + $$.a.i6[1] &= $$.m.i6[1]; + $$.a.i6[2] &= $$.m.i6[2]; + $$.a.i6[3] &= $$.m.i6[3]; + yyexpectaddr = 0; + } + | hostname slash ipaddr { bzero(&$$, sizeof($$)); + if ($1.f != $3.f) { + yyerror("1.address family " + "mismatch"); + } + $$.a = $1.a; + $$.m = $3.a; + $$.t = FRI_NORMAL; + $$.a.i6[0] &= $$.m.i6[0]; + $$.a.i6[1] &= $$.m.i6[1]; + $$.a.i6[2] &= $$.m.i6[2]; + $$.a.i6[3] &= $$.m.i6[3]; + $$.f = $1.f; + $$.v = ftov($1.f); + yyexpectaddr = 0; + } + | hostname slash hexnumber { bzero(&$$, sizeof($$)); + $$.a = $1.a; + $$.m.in4.s_addr = htonl($3); + $$.t = FRI_NORMAL; + $$.a.in4.s_addr &= $$.m.in4.s_addr; + $$.f = $1.f; + $$.v = ftov($1.f); + if ($$.f == AF_INET6) + yyerror("incorrect inet6 mask"); + } + | hostname mask ipaddr { bzero(&$$, sizeof($$)); + if ($1.f != $3.f) { + yyerror("2.address family " + "mismatch"); + } + $$.a = $1.a; + $$.m = $3.a; + $$.t = FRI_NORMAL; + $$.a.i6[0] &= $$.m.i6[0]; + $$.a.i6[1] &= $$.m.i6[1]; + $$.a.i6[2] &= $$.m.i6[2]; + $$.a.i6[3] &= $$.m.i6[3]; + $$.f = $1.f; + $$.v = ftov($1.f); + yyexpectaddr = 0; + } + | hostname mask hexnumber { bzero(&$$, sizeof($$)); + $$.a = $1.a; + $$.m.in4.s_addr = htonl($3); + $$.t = FRI_NORMAL; + $$.a.in4.s_addr &= $$.m.in4.s_addr; + $$.f = AF_INET; + $$.v = 4; + } + | pool slash YY_NUMBER { bzero(&$$, sizeof($$)); + $$.a.iplookupnum = $3; + $$.a.iplookuptype = IPLT_POOL; + $$.a.iplookupsubtype = 0; + $$.t = FRI_LOOKUP; + } + | pool slash YY_STR { bzero(&$$, sizeof($$)); + $$.a.iplookupname = addname(&nat,$3); + $$.a.iplookuptype = IPLT_POOL; + $$.a.iplookupsubtype = 1; + $$.t = FRI_LOOKUP; + } + | hash slash YY_NUMBER { bzero(&$$, sizeof($$)); + $$.a.iplookupnum = $3; + $$.a.iplookuptype = IPLT_HASH; + $$.a.iplookupsubtype = 0; + $$.t = FRI_LOOKUP; + } + | hash slash YY_STR { bzero(&$$, sizeof($$)); + $$.a.iplookupname = addname(&nat,$3); + $$.a.iplookuptype = IPLT_HASH; + $$.a.iplookupsubtype = 1; + $$.t = FRI_LOOKUP; + } + ; + +slash: '/' { yyexpectaddr = 0; } + ; + +mask: IPNY_MASK { yyexpectaddr = 0; } + ; + +pool: IPNY_POOL { if (!(nat->in_flags & IPN_FILTER)) { + yyerror("Can only use pool with from/to rules\n"); + } + yyexpectaddr = 0; + yyresetdict(); + } + ; + +hash: IPNY_HASH { if (!(nat->in_flags & IPN_FILTER)) { + yyerror("Can only use hash with from/to rules\n"); + } + yyexpectaddr = 0; + yyresetdict(); + } + ; + +portstuff: + compare portspec { $$.pc = $1; $$.p1 = $2; $$.p2 = 0; } + | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; } + ; + +mapoptions: + rr frag age mssclamp nattag setproto purge + ; + +rdroptions: + rr frag age sticky mssclamp rdrproxy nattag purge + ; + +nattag: | IPNY_TAG YY_STR { strncpy(nat->in_tag.ipt_tag, $2, + sizeof(nat->in_tag.ipt_tag)); + } +rr: | IPNY_ROUNDROBIN { nat->in_flags |= IPN_ROUNDR; } + ; + +frag: | IPNY_FRAG { nat->in_flags |= IPN_FRAG; } + ; + +age: | IPNY_AGE YY_NUMBER { nat->in_age[0] = $2; + nat->in_age[1] = $2; } + | IPNY_AGE YY_NUMBER '/' YY_NUMBER { nat->in_age[0] = $2; + nat->in_age[1] = $4; } + ; + +sticky: | IPNY_STICKY { if (!(nat->in_flags & IPN_ROUNDR) && + !(nat->in_flags & IPN_SPLIT)) { + FPRINTF(stderr, + "'sticky' for use with round-robin/IP splitting only\n"); + } else + nat->in_flags |= IPN_STICKY; + } + ; + +mssclamp: + | IPNY_MSSCLAMP YY_NUMBER { nat->in_mssclamp = $2; } + ; + +tcpudp: IPNY_TCP { setnatproto(IPPROTO_TCP); } + | IPNY_UDP { setnatproto(IPPROTO_UDP); } + | IPNY_TCPUDP { nat->in_flags |= IPN_TCPUDP; + nat->in_pr[0] = 0; + nat->in_pr[1] = 0; + } + | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP; + nat->in_pr[0] = 0; + nat->in_pr[1] = 0; + } + ; + +sequential: + | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; } + ; + +purge: + | IPNY_PURGE { nat->in_flags |= IPN_PURGE; } + ; + +rdrproxy: + IPNY_PROXY YY_STR + { int pos; + pos = addname(&nat, $2); + nat->in_plabel = pos; + nat->in_odport = nat->in_dpnext; + nat->in_dtop = nat->in_odport; + free($2); + } + | proxy { if (nat->in_plabel != -1) { + nat->in_ndport = nat->in_odport; + nat->in_dpmin = nat->in_odport; + nat->in_dpmax = nat->in_dpmin; + nat->in_dtop = nat->in_dpmin; + nat->in_dpnext = nat->in_dpmin; + } + } + ; + +newopts: + | IPNY_PURGE { nat->in_flags |= IPN_PURGE; } + ; + +proto: YY_NUMBER { $$ = $1; + if ($$ != IPPROTO_TCP && + $$ != IPPROTO_UDP) + suggest_port = 0; + } + | IPNY_TCP { $$ = IPPROTO_TCP; } + | IPNY_UDP { $$ = IPPROTO_UDP; } + | YY_STR { $$ = getproto($1); + free($1); + if ($$ == -1) + yyerror("unknown protocol"); + if ($$ != IPPROTO_TCP && + $$ != IPPROTO_UDP) + suggest_port = 0; + } + ; + +hexnumber: + YY_HEX { $$ = $1; } + ; + +hostname: + YY_STR { i6addr_t addr; + int family; + +#ifdef USE_INET6 + if (nat->in_v[0] == 6) + family = AF_INET6; + else +#endif + family = AF_INET; + memset(&($$), 0, sizeof($$)); + memset(&addr, 0, sizeof(addr)); + $$.f = family; + if (gethost(family, $1, + &addr) == 0) { + $$.a = addr; + } else { + FPRINTF(stderr, + "Unknown host '%s'\n", + $1); + } + free($1); + } + | YY_NUMBER { memset(&($$), 0, sizeof($$)); + $$.a.in4.s_addr = htonl($1); + if ($$.a.in4.s_addr != 0) + $$.f = AF_INET; + } + | ipv4 { $$ = $1; } + | YY_IPV6 { memset(&($$), 0, sizeof($$)); + $$.a = $1; + $$.f = AF_INET6; + } + | YY_NUMBER YY_IPV6 { memset(&($$), 0, sizeof($$)); + $$.a = $2; + $$.f = AF_INET6; + } + ; + +compare: + '=' { $$ = FR_EQUAL; } + | YY_CMP_EQ { $$ = FR_EQUAL; } + | YY_CMP_NE { $$ = FR_NEQUAL; } + | YY_CMP_LT { $$ = FR_LESST; } + | YY_CMP_LE { $$ = FR_LESSTE; } + | YY_CMP_GT { $$ = FR_GREATERT; } + | YY_CMP_GE { $$ = FR_GREATERTE; } + +range: + YY_RANGE_OUT { $$ = FR_OUTRANGE; } + | YY_RANGE_IN { $$ = FR_INRANGE; } + | ':' { $$ = FR_INCRANGE; } + ; + +ipaddr: ipv4 { $$ = $1; } + | YY_IPV6 { $$.a = $1; + $$.f = AF_INET6; + } + ; + +ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER + { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + bzero((char *)&$$, sizeof($$)); + $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; + $$.a.in4.s_addr = htonl($$.a.in4.s_addr); + $$.f = AF_INET; + } + ; + +%% + + +static wordtab_t proxies[] = { + { "dns", IPNY_DNS } +}; + +static wordtab_t dnswords[] = { + { "allow", IPNY_ALLOW }, + { "block", IPNY_DENY }, + { "deny", IPNY_DENY }, + { "drop", IPNY_DENY }, + { "pass", IPNY_ALLOW }, + +}; + +static wordtab_t yywords[] = { + { "age", IPNY_AGE }, + { "any", IPNY_ANY }, + { "auto", IPNY_AUTO }, + { "bimap", IPNY_BIMAP }, + { "config", IPNY_CONFIG }, + { "divert", IPNY_DIVERT }, + { "dst", IPNY_DST }, + { "dstlist", IPNY_DSTLIST }, + { "frag", IPNY_FRAG }, + { "from", IPNY_FROM }, + { "hash", IPNY_HASH }, + { "icmpidmap", IPNY_ICMPIDMAP }, + { "in", IPNY_IN }, + { "inet", IPNY_INET }, + { "inet6", IPNY_INET6 }, + { "mask", IPNY_MASK }, + { "map", IPNY_MAP }, + { "map-block", IPNY_MAPBLOCK }, + { "mssclamp", IPNY_MSSCLAMP }, + { "netmask", IPNY_MASK }, + { "no", IPNY_NO }, + { "on", IPNY_ON }, + { "out", IPNY_OUT }, + { "pool", IPNY_POOL }, + { "port", IPNY_PORT }, + { "portmap", IPNY_PORTMAP }, + { "ports", IPNY_PORTS }, + { "proto", IPNY_PROTO }, + { "proxy", IPNY_PROXY }, + { "purge", IPNY_PURGE }, + { "range", IPNY_RANGE }, + { "rewrite", IPNY_REWRITE }, + { "rdr", IPNY_RDR }, + { "round-robin",IPNY_ROUNDROBIN }, + { "sequential", IPNY_SEQUENTIAL }, + { "src", IPNY_SRC }, + { "sticky", IPNY_STICKY }, + { "tag", IPNY_TAG }, + { "tcp", IPNY_TCP }, + { "tcpudp", IPNY_TCPUDP }, + { "to", IPNY_TO }, + { "udp", IPNY_UDP }, + { "-", '-' }, + { "->", IPNY_TLATE }, + { "eq", YY_CMP_EQ }, + { "ne", YY_CMP_NE }, + { "lt", YY_CMP_LT }, + { "gt", YY_CMP_GT }, + { "le", YY_CMP_LE }, + { "ge", YY_CMP_GE }, + { NULL, 0 } +}; + + +int +ipnat_parsefile(fd, addfunc, ioctlfunc, filename) + int fd; + addfunc_t addfunc; + ioctlfunc_t ioctlfunc; + char *filename; +{ + FILE *fp = NULL; + int rval; + char *s; + + yylineNum = 1; + + (void) yysettab(yywords); + + s = getenv("YYDEBUG"); + if (s) + yydebug = atoi(s); + else + yydebug = 0; + + if (strcmp(filename, "-")) { + fp = fopen(filename, "r"); + if (!fp) { + FPRINTF(stderr, "fopen(%s) failed: %s\n", filename, + STRERROR(errno)); + return -1; + } + } else + fp = stdin; + + while ((rval = ipnat_parsesome(fd, addfunc, ioctlfunc, fp)) == 0) + ; + if (fp != NULL) + fclose(fp); + if (rval == -1) + rval = 0; + else if (rval != 0) + rval = 1; + return rval; +} + + +int +ipnat_parsesome(fd, addfunc, ioctlfunc, fp) + int fd; + addfunc_t addfunc; + ioctlfunc_t ioctlfunc; + FILE *fp; +{ + char *s; + int i; + + natfd = fd; + parser_error = 0; + nataddfunc = addfunc; + natioctlfunc = ioctlfunc; + + if (feof(fp)) + return -1; + i = fgetc(fp); + if (i == EOF) + return -1; + if (ungetc(i, fp) == EOF) + return -1; + if (feof(fp)) + return -1; + s = getenv("YYDEBUG"); + if (s) + yydebug = atoi(s); + else + yydebug = 0; + + yyin = fp; + yyparse(); + return parser_error; +} + + +static void +newnatrule() +{ + ipnat_t *n; + + n = calloc(1, sizeof(*n)); + if (n == NULL) + return; + + if (nat == NULL) { + nattop = nat = n; + n->in_pnext = &nattop; + } else { + nat->in_next = n; + n->in_pnext = &nat->in_next; + nat = n; + } + + n->in_flineno = yylineNum; + n->in_ifnames[0] = -1; + n->in_ifnames[1] = -1; + n->in_plabel = -1; + n->in_pconfig = -1; + n->in_size = sizeof(*n); + + suggest_port = 0; +} + + +static void +setnatproto(p) + int p; +{ + nat->in_pr[0] = p; + nat->in_pr[1] = p; + + switch (p) + { + case IPPROTO_TCP : + nat->in_flags |= IPN_TCP; + nat->in_flags &= ~IPN_UDP; + break; + case IPPROTO_UDP : + nat->in_flags |= IPN_UDP; + nat->in_flags &= ~IPN_TCP; + break; +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : +#endif + case IPPROTO_ICMP : + nat->in_flags &= ~IPN_TCPUDP; + if (!(nat->in_flags & IPN_ICMPQUERY) && + !(nat->in_redir & NAT_DIVERTUDP)) { + nat->in_dcmp = 0; + nat->in_scmp = 0; + nat->in_dpmin = 0; + nat->in_dpmax = 0; + nat->in_dpnext = 0; + nat->in_spmin = 0; + nat->in_spmax = 0; + nat->in_spnext = 0; + } + break; + default : + if ((nat->in_redir & NAT_MAPBLK) == 0) { + nat->in_flags &= ~IPN_TCPUDP; + nat->in_dcmp = 0; + nat->in_scmp = 0; + nat->in_dpmin = 0; + nat->in_dpmax = 0; + nat->in_dpnext = 0; + nat->in_spmin = 0; + nat->in_spmax = 0; + nat->in_spnext = 0; + } + break; + } + + if ((nat->in_flags & (IPN_TCP|IPN_UDP)) == 0) { + nat->in_stop = 0; + nat->in_dtop = 0; + nat->in_osport = 0; + nat->in_odport = 0; + nat->in_stop = 0; + nat->in_osport = 0; + nat->in_dtop = 0; + nat->in_odport = 0; + } + if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT) + nat->in_flags &= ~IPN_FIXEDDPORT; +} + + +int +ipnat_addrule(fd, ioctlfunc, ptr) + int fd; + ioctlfunc_t ioctlfunc; + void *ptr; +{ + ioctlcmd_t add, del; + ipfobj_t obj; + ipnat_t *ipn; + + ipn = ptr; + bzero((char *)&obj, sizeof(obj)); + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_size = ipn->in_size; + obj.ipfo_type = IPFOBJ_IPNAT; + obj.ipfo_ptr = ptr; + + if ((opts & OPT_DONOTHING) != 0) + fd = -1; + + if (opts & OPT_ZERORULEST) { + add = SIOCZRLST; + del = 0; + } else if (opts & OPT_PURGE) { + add = 0; + del = SIOCPURGENAT; + } else { + add = SIOCADNAT; + del = SIOCRMNAT; + } + + if ((opts & OPT_VERBOSE) != 0) + printnat(ipn, opts); + + if (opts & OPT_DEBUG) + binprint(ipn, ipn->in_size); + + if ((opts & OPT_ZERORULEST) != 0) { + if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + sprintf(msg, "%d:ioctl(zero nat rule)", + ipn->in_flineno); + return ipf_perror_fd(fd, ioctlfunc, msg); + } + } else { + PRINTF("hits %lu ", ipn->in_hits); +#ifdef USE_QUAD_T + PRINTF("bytes %"PRIu64" ", + ipn->in_bytes[0] + ipn->in_bytes[1]); +#else + PRINTF("bytes %lu ", + ipn->in_bytes[0] + ipn->in_bytes[1]); +#endif + printnat(ipn, opts); + } + } else if ((opts & OPT_REMOVE) != 0) { + if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + sprintf(msg, "%d:ioctl(delete nat rule)", + ipn->in_flineno); + return ipf_perror_fd(fd, ioctlfunc, msg); + } + } + } else { + if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + sprintf(msg, "%d:ioctl(add/insert nat rule)", + ipn->in_flineno); + if (errno == EEXIST) { + sprintf(msg + strlen(msg), "(line %d)", + ipn->in_flineno); + } + return ipf_perror_fd(fd, ioctlfunc, msg); + } + } + } + return 0; +} + + +static void +setmapifnames() +{ + if (nat->in_ifnames[1] == -1) + nat->in_ifnames[1] = nat->in_ifnames[0]; + + if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0) + nat->in_flags |= IPN_TCPUDP; + + if ((nat->in_flags & IPN_TCPUDP) == 0) + setnatproto(nat->in_pr[1]); + + if (((nat->in_redir & NAT_MAPBLK) != 0) || + ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) + nat_setgroupmap(nat); +} + + +static void +setrdrifnames() +{ + if ((suggest_port == 1) && (nat->in_flags & IPN_TCPUDP) == 0) + nat->in_flags |= IPN_TCPUDP; + + if ((nat->in_pr[0] == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) && + (nat->in_dpmin != 0 || nat->in_dpmax != 0 || nat->in_dpnext != 0)) + setnatproto(IPPROTO_TCP); + + if (nat->in_ifnames[1] == -1) + nat->in_ifnames[1] = nat->in_ifnames[0]; +} + + +static void +proxy_setconfig(proxy) + int proxy; +{ + if (proxy == IPNY_DNS) { + yysetfixeddict(dnswords); + } +} + + +static void +proxy_unsetconfig() +{ + yyresetdict(); +} + + +static namelist_t * +proxy_dns_add_pass(prefix, name) + char *prefix, *name; +{ + namelist_t *n; + + n = calloc(1, sizeof(*n)); + if (n != NULL) { + if (prefix == NULL || *prefix == '\0') { + n->na_name = strdup(name); + } else { + n->na_name = malloc(strlen(name) + strlen(prefix) + 1); + strcpy(n->na_name, prefix); + strcat(n->na_name, name); + } + } + return n; +} + + +static namelist_t * +proxy_dns_add_block(prefix, name) + char *prefix, *name; +{ + namelist_t *n; + + n = calloc(1, sizeof(*n)); + if (n != NULL) { + if (prefix == NULL || *prefix == '\0') { + n->na_name = strdup(name); + } else { + n->na_name = malloc(strlen(name) + strlen(prefix) + 1); + strcpy(n->na_name, prefix); + strcat(n->na_name, name); + } + n->na_value = 1; + } + return n; +} + + +static void +proxy_addconfig(proxy, proto, conf, list) + char *proxy, *conf; + int proto; + namelist_t *list; +{ + proxyrule_t *pr; + + pr = calloc(1, sizeof(*pr)); + if (pr != NULL) { + pr->pr_proto = proto; + pr->pr_proxy = proxy; + pr->pr_conf = conf; + pr->pr_names = list; + pr->pr_next = prules; + prules = pr; + } +} + + +static void +proxy_loadrules(fd, ioctlfunc, rules) + int fd; + ioctlfunc_t ioctlfunc; + proxyrule_t *rules; +{ + proxyrule_t *pr; + + while ((pr = rules) != NULL) { + proxy_loadconfig(fd, ioctlfunc, pr->pr_proxy, pr->pr_proto, + pr->pr_conf, pr->pr_names); + rules = pr->pr_next; + free(pr->pr_conf); + free(pr); + } +} + + +static void +proxy_loadconfig(fd, ioctlfunc, proxy, proto, conf, list) + int fd; + ioctlfunc_t ioctlfunc; + char *proxy, *conf; + int proto; + namelist_t *list; +{ + namelist_t *na; + ipfobj_t obj; + ap_ctl_t pcmd; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_PROXYCTL; + obj.ipfo_size = sizeof(pcmd); + obj.ipfo_ptr = &pcmd; + + while ((na = list) != NULL) { + if ((opts & OPT_REMOVE) != 0) + pcmd.apc_cmd = APC_CMD_DEL; + else + pcmd.apc_cmd = APC_CMD_ADD; + pcmd.apc_dsize = strlen(na->na_name) + 1; + pcmd.apc_data = na->na_name; + pcmd.apc_arg = na->na_value; + pcmd.apc_p = proto; + + strncpy(pcmd.apc_label, proxy, APR_LABELLEN); + pcmd.apc_label[APR_LABELLEN - 1] = '\0'; + + strncpy(pcmd.apc_config, conf, APR_LABELLEN); + pcmd.apc_config[APR_LABELLEN - 1] = '\0'; + + if ((*ioctlfunc)(fd, SIOCPROXY, (void *)&obj) == -1) { + if ((opts & OPT_DONOTHING) == 0) { + char msg[80]; + + sprintf(msg, "%d:ioctl(add/remove proxy rule)", + yylineNum); + ipf_perror_fd(fd, ioctlfunc, msg); + return; + } + } + + list = na->na_next; + free(na->na_name); + free(na); + } +} + + +static void +setifname(np, idx, name) + ipnat_t **np; + int idx; + char *name; +{ + int pos; + + pos = addname(np, name); + if (pos == -1) + return; + (*np)->in_ifnames[idx] = pos; +} + + +static int +addname(np, name) + ipnat_t **np; + char *name; +{ + ipnat_t *n; + int nlen; + int pos; + + nlen = strlen(name) + 1; + n = realloc(*np, (*np)->in_size + nlen); + if (*np == nattop) + nattop = n; + *np = n; + if (n == NULL) + return -1; + if (n->in_pnext != NULL) + *n->in_pnext = n; + n->in_size += nlen; + pos = n->in_namelen; + n->in_namelen += nlen; + strcpy(n->in_names + pos, name); + n->in_names[n->in_namelen] = '\0'; + return pos; +} diff --git a/contrib/ipfilter/tools/ippool.c b/contrib/ipfilter/tools/ippool.c new file mode 100644 index 0000000..243932c --- /dev/null +++ b/contrib/ipfilter/tools/ippool.c @@ -0,0 +1,1073 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <sys/socket.h> +#if defined(BSD) && (BSD >= 199306) +# include <sys/cdefs.h> +#endif +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <ctype.h> +#include <unistd.h> +#ifdef linux +# include <linux/a.out.h> +#else +# include <nlist.h> +#endif + +#include "ipf.h" +#include "netinet/ipl.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#include "kmem.h" + + +extern int ippool_yyparse __P((void)); +extern int ippool_yydebug; +extern FILE *ippool_yyin; +extern char *optarg; +extern int lineNum; + +void usage __P((char *)); +int main __P((int, char **)); +int poolcommand __P((int, int, char *[])); +int poolnodecommand __P((int, int, char *[])); +int loadpoolfile __P((int, char *[], char *)); +int poollist __P((int, char *[])); +void poollist_dead __P((int, char *, int, char *, char *)); +void poollist_live __P((int, char *, int, int)); +int poolflush __P((int, char *[])); +int poolstats __P((int, char *[])); +int gettype __P((char *, u_int *)); +int getrole __P((char *)); +int setnodeaddr __P((int, int, void *ptr, char *arg)); +void showpools_live __P((int, int, ipf_pool_stat_t *, char *)); +void showhashs_live __P((int, int, iphtstat_t *, char *)); +void showdstls_live __P((int, int, ipf_dstl_stat_t *, char *)); + +int opts = 0; +int fd = -1; +int use_inet6 = 0; +wordtab_t *pool_fields = NULL; +int nohdrfields = 0; + + +void +usage(prog) + char *prog; +{ + fprintf(stderr, "Usage:\t%s\n", prog); + fprintf(stderr, "\t-a [-dnv] [-m <name>] [-o <role>] [-t type] [-T ttl] -i <ipaddr>[/netmask]\n"); + fprintf(stderr, "\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n"); + fprintf(stderr, "\t-f <file> [-dnuv]\n"); + fprintf(stderr, "\t-F [-dv] [-o <role>] [-t <type>]\n"); + fprintf(stderr, "\t-l [-dv] [-m <name>] [-t <type>] [-O <fields>]\n"); + fprintf(stderr, "\t-r [-dnv] [-m <name>] [-o <role>] [-t type] -i <ipaddr>[/netmask]\n"); + fprintf(stderr, "\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n"); + fprintf(stderr, "\t-s [-dtv] [-M <core>] [-N <namelist>]\n"); + exit(1); +} + + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int err = 1; + + if (argc < 2) + usage(argv[0]); + + assigndefined(getenv("IPPOOL_PREDEFINED")); + + switch (getopt(argc, argv, "aAf:FlnrRsv")) + { + case 'a' : + err = poolnodecommand(0, argc, argv); + break; + case 'A' : + err = poolcommand(0, argc, argv); + break; + case 'f' : + err = loadpoolfile(argc, argv, optarg); + break; + case 'F' : + err = poolflush(argc, argv); + break; + case 'l' : + err = poollist(argc, argv); + break; + case 'n' : + opts |= OPT_DONOTHING|OPT_DONTOPEN; + break; + case 'r' : + err = poolnodecommand(1, argc, argv); + break; + case 'R' : + err = poolcommand(1, argc, argv); + break; + case 's' : + err = poolstats(argc, argv); + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + default : + exit(1); + } + + if (err != 0) + exit(1); + return 0; +} + + +int +poolnodecommand(remove, argc, argv) + int remove, argc; + char *argv[]; +{ + int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0; + char *poolname = NULL; + ip_pool_node_t pnode; + iphtent_t hnode; + void *ptr = &pnode; + + ipset = 0; + role = IPL_LOGIPF; + bzero((char *)&pnode, sizeof(pnode)); + bzero((char *)&hnode, sizeof(hnode)); + + while ((c = getopt(argc, argv, "di:m:no:Rt:T:v")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + ippool_yydebug++; + break; + case 'i' : + if (setnodeaddr(type, role, ptr, optarg) == 0) + ipset = 1; + break; + case 'm' : + poolname = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING|OPT_DONTOPEN; + break; + case 'o' : + if (ipset == 1) { + fprintf(stderr, + "cannot set role after ip address\n"); + return -1; + } + role = getrole(optarg); + if (role == IPL_LOGNONE) + return -1; + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 't' : + if (ipset == 1) { + fprintf(stderr, + "cannot set type after ip address\n"); + return -1; + } + type = gettype(optarg, NULL); + switch (type) { + case IPLT_NONE : + fprintf(stderr, "unknown type '%s'\n", optarg); + return -1; + case IPLT_HASH : + ptr = &hnode; + break; + case IPLT_POOL : + default : + break; + } + break; + case 'T' : + ttl = atoi(optarg); + if (ttl < 0) { + fprintf(stderr, "cannot set negative ttl\n"); + return -1; + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (argv[optind] != NULL && ipset == 0) { + if (setnodeaddr(type, role, ptr, argv[optind]) == 0) + ipset = 1; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poolnodecommand: opts = %#x\n", opts); + + if (ipset == 0) { + fprintf(stderr, "no IP address given with -i\n"); + return -1; + } + + if (poolname == NULL) { + fprintf(stderr, "poolname not given with add/remove node\n"); + return -1; + } + + switch (type) { + case IPLT_POOL : + if (remove == 0) + err = load_poolnode(role, poolname, &pnode, ttl, ioctl); + else + err = remove_poolnode(role, poolname, &pnode, ioctl); + break; + case IPLT_HASH : + if (remove == 0) + err = load_hashnode(role, poolname, &hnode, ttl, ioctl); + else + err = remove_hashnode(role, poolname, &hnode, ioctl); + break; + default : + break; + } + return err; +} + + +int +poolcommand(remove, argc, argv) + int remove, argc; + char *argv[]; +{ + int type, role, c, err; + char *poolname; + iphtable_t iph; + ip_pool_t pool; + + err = 1; + role = 0; + type = 0; + poolname = NULL; + role = IPL_LOGIPF; + bzero((char *)&iph, sizeof(iph)); + bzero((char *)&pool, sizeof(pool)); + + while ((c = getopt(argc, argv, "dm:no:RSv")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + ippool_yydebug++; + break; + case 'm' : + poolname = optarg; + break; + case 'n' : + opts |= OPT_DONOTHING|OPT_DONTOPEN; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) { + fprintf(stderr, "unknown role '%s'\n", optarg); + return -1; + } + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'S' : + iph.iph_seed = atoi(optarg); + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poolcommand: opts = %#x\n", opts); + + if (poolname == NULL) { + fprintf(stderr, "poolname not given with add/remove pool\n"); + return -1; + } + + type = gettype(argv[optind], &iph.iph_type); + if (type == IPLT_NONE) { + fprintf(stderr, "unknown type '%s'\n", argv[optind]); + return -1; + } + + if (type == IPLT_HASH) { + strncpy(iph.iph_name, poolname, sizeof(iph.iph_name)); + iph.iph_name[sizeof(iph.iph_name) - 1] = '\0'; + iph.iph_unit = role; + } else if (type == IPLT_POOL) { + strncpy(pool.ipo_name, poolname, sizeof(pool.ipo_name)); + pool.ipo_name[sizeof(pool.ipo_name) - 1] = '\0'; + pool.ipo_unit = role; + } + + if (remove == 0) { + switch (type) + { + case IPLT_HASH : + err = load_hash(&iph, NULL, ioctl); + break; + case IPLT_POOL : + err = load_pool(&pool, ioctl); + break; + } + } else { + switch (type) + { + case IPLT_HASH : + err = remove_hash(&iph, ioctl); + break; + case IPLT_POOL : + err = remove_pool(&pool, ioctl); + break; + } + } + return err; +} + + +int +loadpoolfile(argc, argv, infile) + int argc; + char *argv[], *infile; +{ + int c; + + infile = optarg; + + while ((c = getopt(argc, argv, "dnRuv")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + ippool_yydebug++; + break; + case 'n' : + opts |= OPT_DONOTHING|OPT_DONTOPEN; + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 'u' : + opts |= OPT_REMOVE; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "loadpoolfile: opts = %#x\n", opts); + + if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) { + fd = open(IPLOOKUP_NAME, O_RDWR); + if (fd == -1) { + perror("open(IPLOOKUP_NAME)"); + exit(1); + } + } + + if (ippool_parsefile(fd, infile, ioctl) != 0) + return -1; + return 0; +} + + +int +poolstats(argc, argv) + int argc; + char *argv[]; +{ + int c, type, role, live_kernel; + ipf_pool_stat_t plstat; + ipf_dstl_stat_t dlstat; + char *kernel, *core; + iphtstat_t htstat; + iplookupop_t op; + + core = NULL; + kernel = NULL; + live_kernel = 1; + type = IPLT_ALL; + role = IPL_LOGALL; + + bzero((char *)&op, sizeof(op)); + + while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + break; + case 'M' : + live_kernel = 0; + core = optarg; + break; + case 'N' : + live_kernel = 0; + kernel = optarg; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) { + fprintf(stderr, "unknown role '%s'\n", optarg); + return -1; + } + break; + case 't' : + type = gettype(optarg, NULL); + if (type != IPLT_POOL) { + fprintf(stderr, + "-s not supported for this type yet\n"); + return -1; + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poolstats: opts = %#x\n", opts); + + if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) { + fd = open(IPLOOKUP_NAME, O_RDWR); + if (fd == -1) { + perror("open(IPLOOKUP_NAME)"); + exit(1); + } + } + + if (type == IPLT_ALL || type == IPLT_POOL) { + op.iplo_type = IPLT_POOL; + op.iplo_struct = &plstat; + op.iplo_size = sizeof(plstat); + if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) { + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)"); + return -1; + } + printf("%lu\taddress pools\n", plstat.ipls_pools); + printf("%lu\taddress pool nodes\n", plstat.ipls_nodes); + } + } + + if (type == IPLT_ALL || type == IPLT_HASH) { + op.iplo_type = IPLT_HASH; + op.iplo_struct = &htstat; + op.iplo_size = sizeof(htstat); + if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) { + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); + return -1; + } + printf("%lu\thash tables\n", htstat.iphs_numtables); + printf("%lu\thash table nodes\n", htstat.iphs_numnodes); + printf("%lu\thash table no memory \n", + htstat.iphs_nomem); + } + } + + if (type == IPLT_ALL || type == IPLT_DSTLIST) { + op.iplo_type = IPLT_DSTLIST; + op.iplo_struct = &dlstat; + op.iplo_size = sizeof(dlstat); + if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) { + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); + return -1; + } + printf("%u\tdestination lists\n", + dlstat.ipls_numlists); + printf("%u\tdestination list nodes\n", + dlstat.ipls_numnodes); + printf("%lu\tdestination list no memory\n", + dlstat.ipls_nomem); + printf("%u\tdestination list zombies\n", + dlstat.ipls_numdereflists); + printf("%u\tdesetination list node zombies\n", + dlstat.ipls_numderefnodes); + } + } + return 0; +} + + +int +poolflush(argc, argv) + int argc; + char *argv[]; +{ + int c, role, type, arg; + iplookupflush_t flush; + + arg = IPLT_ALL; + type = IPLT_ALL; + role = IPL_LOGALL; + + while ((c = getopt(argc, argv, "do:t:v")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) { + fprintf(stderr, "unknown role '%s'\n", optarg); + return -1; + } + break; + case 't' : + type = gettype(optarg, NULL); + if (type == IPLT_NONE) { + fprintf(stderr, "unknown type '%s'\n", optarg); + return -1; + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poolflush: opts = %#x\n", opts); + + if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) { + fd = open(IPLOOKUP_NAME, O_RDWR); + if (fd == -1) { + perror("open(IPLOOKUP_NAME)"); + exit(1); + } + } + + bzero((char *)&flush, sizeof(flush)); + flush.iplf_type = type; + flush.iplf_unit = role; + flush.iplf_arg = arg; + + if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) { + if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)"); + exit(1); + } + + } + printf("%u object%s flushed\n", flush.iplf_count, + (flush.iplf_count == 1) ? "" : "s"); + + return 0; +} + + +int +getrole(rolename) + char *rolename; +{ + int role; + + if (!strcasecmp(rolename, "ipf")) { + role = IPL_LOGIPF; +#if 0 + } else if (!strcasecmp(rolename, "nat")) { + role = IPL_LOGNAT; + } else if (!strcasecmp(rolename, "state")) { + role = IPL_LOGSTATE; + } else if (!strcasecmp(rolename, "auth")) { + role = IPL_LOGAUTH; + } else if (!strcasecmp(rolename, "sync")) { + role = IPL_LOGSYNC; + } else if (!strcasecmp(rolename, "scan")) { + role = IPL_LOGSCAN; + } else if (!strcasecmp(rolename, "pool")) { + role = IPL_LOGLOOKUP; + } else if (!strcasecmp(rolename, "count")) { + role = IPL_LOGCOUNT; +#endif + } else { + role = IPL_LOGNONE; + } + + return role; +} + + +int +gettype(typename, minor) + char *typename; + u_int *minor; +{ + int type; + + if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) { + type = IPLT_POOL; + } else if (!strcasecmp(typename, "hash")) { + type = IPLT_HASH; + if (minor != NULL) + *minor = IPHASH_LOOKUP; + } else if (!strcasecmp(typename, "group-map")) { + type = IPLT_HASH; + if (minor != NULL) + *minor = IPHASH_GROUPMAP; + } else { + type = IPLT_NONE; + } + return type; +} + + +int +poollist(argc, argv) + int argc; + char *argv[]; +{ + char *kernel, *core, *poolname; + int c, role, type, live_kernel; + iplookupop_t op; + + core = NULL; + kernel = NULL; + live_kernel = 1; + type = IPLT_ALL; + poolname = NULL; + role = IPL_LOGALL; + + while ((c = getopt(argc, argv, "dm:M:N:o:Rt:v")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + break; + case 'm' : + poolname = optarg; + break; + case 'M' : + live_kernel = 0; + core = optarg; + break; + case 'N' : + live_kernel = 0; + kernel = optarg; + break; + case 'o' : + role = getrole(optarg); + if (role == IPL_LOGNONE) { + fprintf(stderr, "unknown role '%s'\n", optarg); + return -1; + } + break; + case 'O' : + pool_fields = parsefields(poolfields, optarg); + break; + case 'R' : + opts |= OPT_NORESOLVE; + break; + case 't' : + type = gettype(optarg, NULL); + if (type == IPLT_NONE) { + fprintf(stderr, "unknown type '%s'\n", optarg); + return -1; + } + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (opts & OPT_DEBUG) + fprintf(stderr, "poollist: opts = %#x\n", opts); + + if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) { + fd = open(IPLOOKUP_NAME, O_RDWR); + if (fd == -1) { + perror("open(IPLOOKUP_NAME)"); + exit(1); + } + } + + bzero((char *)&op, sizeof(op)); + if (poolname != NULL) { + strncpy(op.iplo_name, poolname, sizeof(op.iplo_name)); + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; + } + op.iplo_unit = role; + + if (live_kernel) + poollist_live(role, poolname, type, fd); + else + poollist_dead(role, poolname, type, kernel, core); + return 0; +} + + +void +poollist_dead(role, poolname, type, kernel, core) + int role, type; + char *poolname, *kernel, *core; +{ + iphtable_t *hptr; + ip_pool_t *ptr; + + if (openkmem(kernel, core) == -1) + exit(-1); + + if (type == IPLT_ALL || type == IPLT_POOL) { + ip_pool_t *pools[IPL_LOGSIZE]; + struct nlist names[2] = { { "ip_pool_list" } , { "" } }; + + if (nlist(kernel, names) != 1) + return; + + bzero(&pools, sizeof(pools)); + if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools))) + return; + + if (role != IPL_LOGALL) { + ptr = pools[role]; + while (ptr != NULL) { + ptr = printpool(ptr, kmemcpywrap, poolname, + opts, pool_fields); + } + } else { + for (role = 0; role <= IPL_LOGMAX; role++) { + ptr = pools[role]; + while (ptr != NULL) { + ptr = printpool(ptr, kmemcpywrap, + poolname, opts, + pool_fields); + } + } + role = IPL_LOGALL; + } + } + if (type == IPLT_ALL || type == IPLT_HASH) { + iphtable_t *tables[IPL_LOGSIZE]; + struct nlist names[2] = { { "ipf_htables" } , { "" } }; + + if (nlist(kernel, names) != 1) + return; + + bzero(&tables, sizeof(tables)); + if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables))) + return; + + if (role != IPL_LOGALL) { + hptr = tables[role]; + while (hptr != NULL) { + hptr = printhash(hptr, kmemcpywrap, + poolname, opts, pool_fields); + } + } else { + for (role = 0; role <= IPL_LOGMAX; role++) { + hptr = tables[role]; + while (hptr != NULL) { + hptr = printhash(hptr, kmemcpywrap, + poolname, opts, + pool_fields); + } + } + } + } +} + + +void +poollist_live(role, poolname, type, fd) + int role, type, fd; + char *poolname; +{ + ipf_pool_stat_t plstat; + iplookupop_t op; + int c; + + if (type == IPLT_ALL || type == IPLT_POOL) { + op.iplo_type = IPLT_POOL; + op.iplo_size = sizeof(plstat); + op.iplo_struct = &plstat; + op.iplo_name[0] = '\0'; + op.iplo_arg = 0; + + if (role != IPL_LOGALL) { + op.iplo_unit = role; + + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); + return; + } + + showpools_live(fd, role, &plstat, poolname); + } else { + for (role = -1; role <= IPL_LOGMAX; role++) { + op.iplo_unit = role; + + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); + return; + } + + showpools_live(fd, role, &plstat, poolname); + } + + role = IPL_LOGALL; + } + } + + if (type == IPLT_ALL || type == IPLT_HASH) { + iphtstat_t htstat; + + op.iplo_type = IPLT_HASH; + op.iplo_size = sizeof(htstat); + op.iplo_struct = &htstat; + op.iplo_name[0] = '\0'; + op.iplo_arg = 0; + + if (role != IPL_LOGALL) { + op.iplo_unit = role; + + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); + return; + } + showhashs_live(fd, role, &htstat, poolname); + } else { + for (role = 0; role <= IPL_LOGMAX; role++) { + + op.iplo_unit = role; + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); + return; + } + + showhashs_live(fd, role, &htstat, poolname); + } + role = IPL_LOGALL; + } + } + + if (type == IPLT_ALL || type == IPLT_DSTLIST) { + ipf_dstl_stat_t dlstat; + + op.iplo_type = IPLT_DSTLIST; + op.iplo_size = sizeof(dlstat); + op.iplo_struct = &dlstat; + op.iplo_name[0] = '\0'; + op.iplo_arg = 0; + + if (role != IPL_LOGALL) { + op.iplo_unit = role; + + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); + return; + } + showdstls_live(fd, role, &dlstat, poolname); + } else { + for (role = 0; role <= IPL_LOGMAX; role++) { + + op.iplo_unit = role; + c = ioctl(fd, SIOCLOOKUPSTAT, &op); + if (c == -1) { + ipferror(fd, "ioctl(SIOCLOOKUPSTAT)"); + return; + } + + showdstls_live(fd, role, &dlstat, poolname); + } + role = IPL_LOGALL; + } + } +} + + +void +showpools_live(fd, role, plstp, poolname) + int fd, role; + ipf_pool_stat_t *plstp; + char *poolname; +{ + ipflookupiter_t iter; + ip_pool_t pool; + ipfobj_t obj; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_LOOKUPITER; + obj.ipfo_size = sizeof(iter); + obj.ipfo_ptr = &iter; + + iter.ili_type = IPLT_POOL; + iter.ili_otype = IPFLOOKUPITER_LIST; + iter.ili_ival = IPFGENITER_LOOKUP; + iter.ili_nitems = 1; + iter.ili_data = &pool; + iter.ili_unit = role; + *iter.ili_name = '\0'; + + bzero((char *)&pool, sizeof(pool)); + + while (plstp->ipls_list[role + 1] != NULL) { + if (ioctl(fd, SIOCLOOKUPITER, &obj)) { + ipferror(fd, "ioctl(SIOCLOOKUPITER)"); + break; + } + if (((pool.ipo_flags & IPOOL_DELETE) == 0) || + ((opts & OPT_DEBUG) != 0)) + printpool_live(&pool, fd, poolname, opts, pool_fields); + + plstp->ipls_list[role + 1] = pool.ipo_next; + } +} + + +void +showhashs_live(fd, role, htstp, poolname) + int fd, role; + iphtstat_t *htstp; + char *poolname; +{ + ipflookupiter_t iter; + iphtable_t table; + ipfobj_t obj; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_LOOKUPITER; + obj.ipfo_size = sizeof(iter); + obj.ipfo_ptr = &iter; + + iter.ili_type = IPLT_HASH; + iter.ili_otype = IPFLOOKUPITER_LIST; + iter.ili_ival = IPFGENITER_LOOKUP; + iter.ili_nitems = 1; + iter.ili_data = &table; + iter.ili_unit = role; + *iter.ili_name = '\0'; + + while (htstp->iphs_tables != NULL) { + if (ioctl(fd, SIOCLOOKUPITER, &obj)) { + ipferror(fd, "ioctl(SIOCLOOKUPITER)"); + break; + } + + printhash_live(&table, fd, poolname, opts, pool_fields); + + htstp->iphs_tables = table.iph_next; + } +} + + +void +showdstls_live(fd, role, dlstp, poolname) + int fd, role; + ipf_dstl_stat_t *dlstp; + char *poolname; +{ + ipflookupiter_t iter; + ippool_dst_t table; + ipfobj_t obj; + + obj.ipfo_rev = IPFILTER_VERSION; + obj.ipfo_type = IPFOBJ_LOOKUPITER; + obj.ipfo_size = sizeof(iter); + obj.ipfo_ptr = &iter; + + iter.ili_type = IPLT_DSTLIST; + iter.ili_otype = IPFLOOKUPITER_LIST; + iter.ili_ival = IPFGENITER_LOOKUP; + iter.ili_nitems = 1; + iter.ili_data = &table; + iter.ili_unit = role; + *iter.ili_name = '\0'; + + while (dlstp->ipls_list[role] != NULL) { + if (ioctl(fd, SIOCLOOKUPITER, &obj)) { + ipferror(fd, "ioctl(SIOCLOOKUPITER)"); + break; + } + + printdstl_live(&table, fd, poolname, opts, pool_fields); + + dlstp->ipls_list[role] = table.ipld_next; + } +} + + +int +setnodeaddr(int type, int role, void *ptr, char *arg) +{ + struct in_addr mask; + char *s; + + s = strchr(arg, '/'); + if (s == NULL) + mask.s_addr = 0xffffffff; + else if (strchr(s, '.') == NULL) { + if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0) + return -1; + } else { + mask.s_addr = inet_addr(s + 1); + } + if (s != NULL) + *s = '\0'; + + if (type == IPLT_POOL) { + ip_pool_node_t *node = ptr; + + if (node->ipn_addr.adf_family == AF_INET) + node->ipn_addr.adf_len = offsetof(addrfamily_t, + adf_addr) + + sizeof(struct in_addr); +#ifdef USE_INET6 + else + node->ipn_addr.adf_len = offsetof(addrfamily_t, + adf_addr) + + sizeof(struct in6_addr); +#endif + node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg); + node->ipn_mask.adf_len = node->ipn_addr.adf_len; + node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr; + } else if (type == IPLT_HASH) { + iphtent_t *node = ptr; + + node->ipe_addr.in4.s_addr = inet_addr(arg); + node->ipe_mask.in4.s_addr = mask.s_addr; + node->ipe_family = AF_INET; + node->ipe_unit = role; + } + + return 0; +} diff --git a/contrib/ipfilter/tools/ippool_y.y b/contrib/ipfilter/tools/ippool_y.y new file mode 100644 index 0000000..93593ce --- /dev/null +++ b/contrib/ipfilter/tools/ippool_y.y @@ -0,0 +1,818 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +%{ +#include <sys/types.h> +#include <sys/time.h> +#include <sys/param.h> +#include <sys/socket.h> +#if defined(BSD) && (BSD >= 199306) +# include <sys/cdefs.h> +#endif +#include <sys/ioctl.h> + +#include <net/if.h> +#include <netinet/in.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <netdb.h> +#include <ctype.h> +#include <unistd.h> + +#include "ipf.h" +#include "netinet/ip_lookup.h" +#include "netinet/ip_pool.h" +#include "netinet/ip_htable.h" +#include "netinet/ip_dstlist.h" +#include "ippool_l.h" +#include "kmem.h" + +#define YYDEBUG 1 +#define YYSTACKSIZE 0x00ffffff + +extern int yyparse __P((void)); +extern int yydebug; +extern FILE *yyin; + +static iphtable_t ipht; +static iphtent_t iphte; +static ip_pool_t iplo; +static ippool_dst_t ipld; +static ioctlfunc_t poolioctl = NULL; +static char poolname[FR_GROUPLEN]; + +static iphtent_t *add_htablehosts __P((char *)); +static ip_pool_node_t *add_poolhosts __P((char *)); +static ip_pool_node_t *read_whoisfile __P((char *)); +static void setadflen __P((addrfamily_t *)); + +%} + +%union { + char *str; + u_32_t num; + struct in_addr ip4; + struct alist_s *alist; + addrfamily_t adrmsk[2]; + iphtent_t *ipe; + ip_pool_node_t *ipp; + ipf_dstnode_t *ipd; + addrfamily_t ipa; + i6addr_t ip6; +} + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token <ip6> YY_IPV6 +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN +%token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT IPT_ALL +%token IPT_TABLE IPT_GROUPMAP IPT_HASH IPT_SRCHASH IPT_DSTHASH +%token IPT_ROLE IPT_TYPE IPT_TREE +%token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME IPT_POLICY +%token IPT_POOL IPT_DSTLIST IPT_ROUNDROBIN +%token IPT_WEIGHTED IPT_RANDOM IPT_CONNECTION +%token IPT_WHOIS IPT_FILE +%type <num> role table inout unit dstopts weighting +%type <ipp> ipftree range addrlist +%type <adrmsk> addrmask +%type <ipe> ipfgroup ipfhash hashlist hashentry +%type <ipe> groupentry setgrouplist grouplist +%type <ipa> ipaddr mask +%type <ip4> ipv4 +%type <str> number setgroup name +%type <ipd> dstentry dstentries dstlist + +%% +file: line + | assign + | file line + | file assign + ; + +line: table role ipftree eol { ip_pool_node_t *n; + iplo.ipo_unit = $2; + iplo.ipo_list = $3; + load_pool(&iplo, poolioctl); + while ((n = $3) != NULL) { + $3 = n->ipn_next; + free(n); + } + resetlexer(); + use_inet6 = 0; + } + | table role ipfhash eol { iphtent_t *h; + ipht.iph_unit = $2; + ipht.iph_type = IPHASH_LOOKUP; + load_hash(&ipht, $3, poolioctl); + while ((h = $3) != NULL) { + $3 = h->ipe_next; + free(h); + } + resetlexer(); + use_inet6 = 0; + } + | groupmap role number ipfgroup eol + { iphtent_t *h; + ipht.iph_unit = $2; + strncpy(ipht.iph_name, $3, + sizeof(ipht.iph_name)); + ipht.iph_type = IPHASH_GROUPMAP; + load_hash(&ipht, $4, poolioctl); + while ((h = $4) != NULL) { + $4 = h->ipe_next; + free(h); + } + resetlexer(); + use_inet6 = 0; + } + | YY_COMMENT + | poolline eol + ; + +eol: ';' + ; + +assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + yyvarnext = 0; + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht)); + bzero((char *)&iphte, sizeof(iphte)); + bzero((char *)&iplo, sizeof(iplo)); + bzero((char *)&ipld, sizeof(ipld)); + *ipht.iph_name = '\0'; + iplo.ipo_flags = IPHASH_ANON; + iplo.ipo_name[0] = '\0'; + } + ; + +groupmap: + IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht)); + bzero((char *)&iphte, sizeof(iphte)); + *ipht.iph_name = '\0'; + ipht.iph_unit = IPHASH_GROUPMAP; + ipht.iph_flags = $2; + } + ; + +inout: IPT_IN { $$ = FR_INQUE; } + | IPT_OUT { $$ = FR_OUTQUE; } + ; + +role: IPT_ROLE '=' unit { $$ = $3; } + ; + +unit: IPT_IPF { $$ = IPL_LOGIPF; } + | IPT_NAT { $$ = IPL_LOGNAT; } + | IPT_AUTH { $$ = IPL_LOGAUTH; } + | IPT_COUNT { $$ = IPL_LOGCOUNT; } + | IPT_ALL { $$ = IPL_LOGALL; } + ; + +ipftree: + IPT_TYPE '=' IPT_TREE number start addrlist end + { strncpy(iplo.ipo_name, $4, + sizeof(iplo.ipo_name)); + $$ = $6; + } + ; + +ipfhash: + IPT_TYPE '=' IPT_HASH number hashopts start hashlist end + { strncpy(ipht.iph_name, $4, + sizeof(ipht.iph_name)); + $$ = $7; + } + ; + +ipfgroup: + setgroup hashopts start grouplist end + { iphtent_t *e; + for (e = $4; e != NULL; + e = e->ipe_next) + if (e->ipe_group[0] == '\0') + strncpy(e->ipe_group, + $1, + FR_GROUPLEN); + $$ = $4; + free($1); + } + | hashopts start setgrouplist end + { $$ = $3; } + ; + +number: IPT_NUM '=' YY_NUMBER { sprintf(poolname, "%u", $3); + $$ = poolname; + } + | IPT_NAME '=' YY_STR { strncpy(poolname, $3, + FR_GROUPLEN); + poolname[FR_GROUPLEN-1]='\0'; + free($3); + $$ = poolname; + } + | { $$ = ""; } + ; + +setgroup: + IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1]; + strncpy(tmp, $3, FR_GROUPLEN); + $$ = strdup(tmp); + free($3); + } + | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1]; + sprintf(tmp, "%u", $3); + $$ = strdup(tmp); + } + ; + +hashopts: + | size + | seed + | size seed + ; + +addrlist: + ';' { $$ = NULL; } + | range next addrlist { $$ = $1; + while ($1->ipn_next != NULL) + $1 = $1->ipn_next; + $1->ipn_next = $3; + } + | range next { $$ = $1; } + ; + +grouplist: + ';' { $$ = NULL; } + | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; } + | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t)); + $$->ipe_addr = $1[0].adf_addr; + $$->ipe_mask = $1[1].adf_addr; + $$->ipe_family = $1[0].adf_family; + $$->ipe_next = $3; + } + | groupentry next { $$ = $1; } + | addrmask next { $$ = calloc(1, sizeof(iphtent_t)); + $$->ipe_addr = $1[0].adf_addr; + $$->ipe_mask = $1[1].adf_addr; +#ifdef AF_INET6 + if (use_inet6) + $$->ipe_family = AF_INET6; + else +#endif + $$->ipe_family = AF_INET; + } + | YY_STR { $$ = add_htablehosts($1); + free($1); + } + ; + +setgrouplist: + ';' { $$ = NULL; } + | groupentry next { $$ = $1; } + | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; } + ; + +groupentry: + addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t)); + $$->ipe_addr = $1[0].adf_addr; + $$->ipe_mask = $1[1].adf_addr; + strncpy($$->ipe_group, $3, + FR_GROUPLEN); +#ifdef AF_INET6 + if (use_inet6) + $$->ipe_family = AF_INET6; + else +#endif + $$->ipe_family = AF_INET; + free($3); + } + ; + +range: addrmask { $$ = calloc(1, sizeof(*$$)); + $$->ipn_info = 0; + $$->ipn_addr = $1[0]; + $$->ipn_mask = $1[1]; + } + | '!' addrmask { $$ = calloc(1, sizeof(*$$)); + $$->ipn_info = 1; + $$->ipn_addr = $2[0]; + $$->ipn_mask = $2[1]; + } + | YY_STR { $$ = add_poolhosts($1); + free($1); + } + | IPT_WHOIS IPT_FILE YY_STR { $$ = read_whoisfile($3); + free($3); + } + ; + +hashlist: + ';' { $$ = NULL; } + | hashentry next { $$ = $1; } + | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; } + ; + +hashentry: + addrmask { $$ = calloc(1, sizeof(iphtent_t)); + $$->ipe_addr = $1[0].adf_addr; + $$->ipe_mask = $1[1].adf_addr; +#ifdef USE_INET6 + if (use_inet6) + $$->ipe_family = AF_INET6; + else +#endif + $$->ipe_family = AF_INET; + } + | YY_STR { $$ = add_htablehosts($1); + free($1); + } + ; + +addrmask: + ipaddr '/' mask { $$[0] = $1; + setadflen(&$$[0]); + $$[1] = $3; + $$[1].adf_len = $$[0].adf_len; + } + | ipaddr { $$[0] = $1; + setadflen(&$$[1]); + $$[1].adf_len = $$[0].adf_len; +#ifdef USE_INET6 + if (use_inet6) + memset(&$$[1].adf_addr, 0xff, + sizeof($$[1].adf_addr.in6)); + else +#endif + memset(&$$[1].adf_addr, 0xff, + sizeof($$[1].adf_addr.in4)); + } + ; + +ipaddr: ipv4 { $$.adf_addr.in4 = $1; + $$.adf_family = AF_INET; + setadflen(&$$); + use_inet6 = 0; + } + | YY_NUMBER { $$.adf_addr.in4.s_addr = htonl($1); + $$.adf_family = AF_INET; + setadflen(&$$); + use_inet6 = 0; + } + | YY_IPV6 { $$.adf_addr = $1; + $$.adf_family = AF_INET6; + setadflen(&$$); + use_inet6 = 1; + } + ; + +mask: YY_NUMBER { bzero(&$$, sizeof($$)); + if (use_inet6) { + if (ntomask(AF_INET6, $1, + (u_32_t *)&$$.adf_addr) == -1) + yyerror("bad bitmask"); + } else { + if (ntomask(AF_INET, $1, + (u_32_t *)&$$.adf_addr.in4) == -1) + yyerror("bad bitmask"); + } + } + | ipv4 { bzero(&$$, sizeof($$)); + $$.adf_addr.in4 = $1; + } + | YY_IPV6 { bzero(&$$, sizeof($$)); + $$.adf_addr = $1; + } + ; + +size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; } + ; + +seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; } + ; + +ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER + { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) { + yyerror("Invalid octet string for IP address"); + return 0; + } + $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; + $$.s_addr = htonl($$.s_addr); + } + ; + +next: ';' { yyexpectaddr = 1; } + ; + +start: '{' { yyexpectaddr = 1; } + ; + +end: '}' { yyexpectaddr = 0; } + ; + +poolline: + IPT_POOL unit '/' IPT_DSTLIST '(' name ';' dstopts ')' + start dstlist end + { bzero((char *)&ipld, sizeof(ipld)); + strncpy(ipld.ipld_name, $6, + sizeof(ipld.ipld_name)); + ipld.ipld_unit = $2; + ipld.ipld_policy = $8; + load_dstlist(&ipld, poolioctl, $11); + resetlexer(); + use_inet6 = 0; + free($6); + } + | IPT_POOL unit '/' IPT_TREE '(' name ';' ')' + start addrlist end + { bzero((char *)&iplo, sizeof(iplo)); + strncpy(iplo.ipo_name, $6, + sizeof(iplo.ipo_name)); + iplo.ipo_list = $10; + iplo.ipo_unit = $2; + load_pool(&iplo, poolioctl); + resetlexer(); + use_inet6 = 0; + free($6); + } + | IPT_POOL '(' name ';' ')' start addrlist end + { bzero((char *)&iplo, sizeof(iplo)); + strncpy(iplo.ipo_name, $3, + sizeof(iplo.ipo_name)); + iplo.ipo_list = $7; + iplo.ipo_unit = IPL_LOGALL; + load_pool(&iplo, poolioctl); + resetlexer(); + use_inet6 = 0; + free($3); + } + | IPT_POOL unit '/' IPT_HASH '(' name ';' hashoptlist ')' + start hashlist end + { iphtent_t *h; + bzero((char *)&ipht, sizeof(ipht)); + strncpy(ipht.iph_name, $6, + sizeof(ipht.iph_name)); + ipht.iph_unit = $2; + load_hash(&ipht, $11, poolioctl); + while ((h = ipht.iph_list) != NULL) { + ipht.iph_list = h->ipe_next; + free(h); + } + resetlexer(); + use_inet6 = 0; + free($6); + } + | IPT_GROUPMAP '(' name ';' inout ';' ')' + start setgrouplist end + { iphtent_t *h; + bzero((char *)&ipht, sizeof(ipht)); + strncpy(ipht.iph_name, $3, + sizeof(ipht.iph_name)); + ipht.iph_type = IPHASH_GROUPMAP; + ipht.iph_unit = IPL_LOGIPF; + ipht.iph_flags = $5; + load_hash(&ipht, $9, poolioctl); + while ((h = ipht.iph_list) != NULL) { + ipht.iph_list = h->ipe_next; + free(h); + } + resetlexer(); + use_inet6 = 0; + free($3); + } + ; + +name: IPT_NAME YY_STR { $$ = $2; } + | IPT_NUM YY_NUMBER { char name[80]; + sprintf(name, "%d", $2); + $$ = strdup(name); + } + ; + +hashoptlist: + | hashopt ';' + | hashoptlist ';' hashopt ';' + ; +hashopt: + IPT_SIZE YY_NUMBER + | IPT_SEED YY_NUMBER + ; + +dstlist: + dstentries { $$ = $1; } + | ';' { $$ = NULL; } + ; + +dstentries: + dstentry next { $$ = $1; } + | dstentry next dstentries { $1->ipfd_next = $3; $$ = $1; } + ; + +dstentry: + YY_STR ':' ipaddr { int size = sizeof(*$$) + strlen($1) + 1; + $$ = calloc(1, size); + if ($$ != NULL) { + $$->ipfd_dest.fd_name = strlen($1) + 1; + bcopy($1, $$->ipfd_names, + $$->ipfd_dest.fd_name); + $$->ipfd_dest.fd_addr = $3; + $$->ipfd_size = size; + } + free($1); + } + | ipaddr { $$ = calloc(1, sizeof(*$$)); + if ($$ != NULL) { + $$->ipfd_dest.fd_name = -1; + $$->ipfd_dest.fd_addr = $1; + $$->ipfd_size = sizeof(*$$); + } + } + ; + +dstopts: + { $$ = IPLDP_NONE; } + | IPT_POLICY IPT_ROUNDROBIN ';' { $$ = IPLDP_ROUNDROBIN; } + | IPT_POLICY IPT_WEIGHTED weighting ';' { $$ = $3; } + | IPT_POLICY IPT_RANDOM ';' { $$ = IPLDP_RANDOM; } + | IPT_POLICY IPT_HASH ';' { $$ = IPLDP_HASHED; } + | IPT_POLICY IPT_SRCHASH ';' { $$ = IPLDP_SRCHASH; } + | IPT_POLICY IPT_DSTHASH ';' { $$ = IPLDP_DSTHASH; } + ; + +weighting: + IPT_CONNECTION { $$ = IPLDP_CONNECTION; } + ; +%% +static wordtab_t yywords[] = { + { "all", IPT_ALL }, + { "auth", IPT_AUTH }, + { "connection", IPT_CONNECTION }, + { "count", IPT_COUNT }, + { "dst-hash", IPT_DSTHASH }, + { "dstlist", IPT_DSTLIST }, + { "file", IPT_FILE }, + { "group", IPT_GROUP }, + { "group-map", IPT_GROUPMAP }, + { "hash", IPT_HASH }, + { "in", IPT_IN }, + { "ipf", IPT_IPF }, + { "name", IPT_NAME }, + { "nat", IPT_NAT }, + { "number", IPT_NUM }, + { "out", IPT_OUT }, + { "policy", IPT_POLICY }, + { "pool", IPT_POOL }, + { "random", IPT_RANDOM }, + { "round-robin", IPT_ROUNDROBIN }, + { "role", IPT_ROLE }, + { "seed", IPT_SEED }, + { "size", IPT_SIZE }, + { "src-hash", IPT_SRCHASH }, + { "table", IPT_TABLE }, + { "tree", IPT_TREE }, + { "type", IPT_TYPE }, + { "weighted", IPT_WEIGHTED }, + { "whois", IPT_WHOIS }, + { NULL, 0 } +}; + + +int ippool_parsefile(fd, filename, iocfunc) +int fd; +char *filename; +ioctlfunc_t iocfunc; +{ + FILE *fp = NULL; + char *s; + + yylineNum = 1; + (void) yysettab(yywords); + + s = getenv("YYDEBUG"); + if (s) + yydebug = atoi(s); + else + yydebug = 0; + + if (strcmp(filename, "-")) { + fp = fopen(filename, "r"); + if (!fp) { + fprintf(stderr, "fopen(%s) failed: %s\n", filename, + STRERROR(errno)); + return -1; + } + } else + fp = stdin; + + while (ippool_parsesome(fd, fp, iocfunc) == 1) + ; + if (fp != NULL) + fclose(fp); + return 0; +} + + +int ippool_parsesome(fd, fp, iocfunc) +int fd; +FILE *fp; +ioctlfunc_t iocfunc; +{ + char *s; + int i; + + poolioctl = iocfunc; + + if (feof(fp)) + return 0; + i = fgetc(fp); + if (i == EOF) + return 0; + if (ungetc(i, fp) == EOF) + return 0; + if (feof(fp)) + return 0; + s = getenv("YYDEBUG"); + if (s) + yydebug = atoi(s); + else + yydebug = 0; + + yyin = fp; + yyparse(); + return 1; +} + + +static iphtent_t * +add_htablehosts(url) +char *url; +{ + iphtent_t *htop, *hbot, *h; + alist_t *a, *hlist; + + if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) { + hlist = load_url(url); + } else { + use_inet6 = 0; + + hlist = calloc(1, sizeof(*hlist)); + if (hlist == NULL) + return NULL; + + if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) { + yyerror("Unknown hostname"); + } + } + + hbot = NULL; + htop = NULL; + + for (a = hlist; a != NULL; a = a->al_next) { + h = calloc(1, sizeof(*h)); + if (h == NULL) + break; + + h->ipe_family = a->al_family; + h->ipe_addr = a->al_i6addr; + h->ipe_mask = a->al_i6mask; + + if (hbot != NULL) + hbot->ipe_next = h; + else + htop = h; + hbot = h; + } + + alist_free(hlist); + + return htop; +} + + +static ip_pool_node_t * +add_poolhosts(url) +char *url; +{ + ip_pool_node_t *ptop, *pbot, *p; + alist_t *a, *hlist; + + if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) { + hlist = load_url(url); + } else { + use_inet6 = 0; + + hlist = calloc(1, sizeof(*hlist)); + if (hlist == NULL) + return NULL; + + if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) { + yyerror("Unknown hostname"); + } + } + + pbot = NULL; + ptop = NULL; + + for (a = hlist; a != NULL; a = a->al_next) { + p = calloc(1, sizeof(*p)); + if (p == NULL) + break; + p->ipn_mask.adf_addr = a->al_i6mask; + + if (a->al_family == AF_INET) { + p->ipn_addr.adf_family = AF_INET; +#ifdef USE_INET6 + } else if (a->al_family == AF_INET6) { + p->ipn_addr.adf_family = AF_INET6; +#endif + } + setadflen(&p->ipn_addr); + p->ipn_addr.adf_addr = a->al_i6addr; + p->ipn_info = a->al_not; + p->ipn_mask.adf_len = p->ipn_addr.adf_len; + + if (pbot != NULL) + pbot->ipn_next = p; + else + ptop = p; + pbot = p; + } + + alist_free(hlist); + + return ptop; +} + + +ip_pool_node_t * +read_whoisfile(file) + char *file; +{ + ip_pool_node_t *ntop, *ipn, node, *last; + char line[1024]; + FILE *fp; + + fp = fopen(file, "r"); + if (fp == NULL) + return NULL; + + last = NULL; + ntop = NULL; + while (fgets(line, sizeof(line) - 1, fp) != NULL) { + line[sizeof(line) - 1] = '\0'; + + if (parsewhoisline(line, &node.ipn_addr, &node.ipn_mask)) + continue; + ipn = calloc(1, sizeof(*ipn)); + if (ipn == NULL) + continue; + ipn->ipn_addr = node.ipn_addr; + ipn->ipn_mask = node.ipn_mask; + if (last == NULL) + ntop = ipn; + else + last->ipn_next = ipn; + last = ipn; + } + fclose(fp); + return ntop; +} + + +static void +setadflen(afp) + addrfamily_t *afp; +{ + afp->adf_len = offsetof(addrfamily_t, adf_addr); + switch (afp->adf_family) + { + case AF_INET : + afp->adf_len += sizeof(struct in_addr); + break; +#ifdef USE_INET6 + case AF_INET6 : + afp->adf_len += sizeof(struct in6_addr); + break; +#endif + default : + break; + } +} diff --git a/contrib/ipfilter/tools/ipscan_y.y b/contrib/ipfilter/tools/ipscan_y.y new file mode 100644 index 0000000..d323f05 --- /dev/null +++ b/contrib/ipfilter/tools/ipscan_y.y @@ -0,0 +1,572 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +%{ +#include <sys/types.h> +#include <sys/ioctl.h> +#include "ipf.h" +#include "opts.h" +#include "kmem.h" +#include "ipscan_l.h" +#include "netinet/ip_scan.h" +#include <ctype.h> + +#define YYDEBUG 1 + +extern char *optarg; +extern void yyerror __P((char *)); +extern int yyparse __P((void)); +extern int yylex __P((void)); +extern int yydebug; +extern FILE *yyin; +extern int yylineNum; +extern void printbuf __P((char *, int, int)); + + +void printent __P((ipscan_t *)); +void showlist __P((void)); +int getportnum __P((char *)); +struct in_addr gethostip __P((char *)); +struct in_addr combine __P((int, int, int, int)); +char **makepair __P((char *, char *)); +void addtag __P((char *, char **, char **, struct action *)); +int cram __P((char *, char *)); +void usage __P((char *)); +int main __P((int, char **)); + +int opts = 0; +int fd = -1; + + +%} + +%union { + char *str; + char **astr; + u_32_t num; + struct in_addr ipa; + struct action act; + union i6addr ip6; +} + +%type <str> tag +%type <act> action redirect result +%type <ipa> ipaddr +%type <num> portnum +%type <astr> matchup onehalf twohalves + +%token <num> YY_NUMBER YY_HEX +%token <str> YY_STR +%token YY_COMMENT +%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT +%token YY_RANGE_OUT YY_RANGE_IN +%token <ip6> YY_IPV6 +%token IPSL_START IPSL_STARTGROUP IPSL_CONTENT + +%token IPSL_CLOSE IPSL_TRACK IPSL_EOF IPSL_REDIRECT IPSL_ELSE + +%% +file: line ';' + | assign ';' + | file line ';' + | file assign ';' + | YY_COMMENT + ; + +line: IPSL_START dline + | IPSL_STARTGROUP gline + | IPSL_CONTENT oline + ; + +dline: cline { resetlexer(); } + | sline { resetlexer(); } + | csline { resetlexer(); } + ; + +gline: YY_STR ':' glist '=' action + ; + +oline: cline + | sline + | csline + ; + +assign: YY_STR assigning YY_STR + { set_variable($1, $3); + resetlexer(); + free($1); + free($3); + yyvarnext = 0; + } + ; + +assigning: + '=' { yyvarnext = 1; } + ; + +cline: tag ':' matchup '=' action { addtag($1, $3, NULL, &$5); } + ; + +sline: tag ':' '(' ')' ',' matchup '=' action { addtag($1, NULL, $6, &$8); } + ; + +csline: tag ':' matchup ',' matchup '=' action { addtag($1, $3, $5, &$7); } + ; + +glist: YY_STR + | glist ',' YY_STR + ; + +tag: YY_STR { $$ = $1; } + ; + +matchup: + onehalf { $$ = $1; } + | twohalves { $$ = $1; } + ; + +action: result { $$.act_val = $1.act_val; + $$.act_ip = $1.act_ip; + $$.act_port = $1.act_port; } + | result IPSL_ELSE result { $$.act_val = $1.act_val; + $$.act_else = $3.act_val; + if ($1.act_val == IPSL_REDIRECT) { + $$.act_ip = $1.act_ip; + $$.act_port = $1.act_port; + } + if ($3.act_val == IPSL_REDIRECT) { + $$.act_eip = $3.act_eip; + $$.act_eport = $3.act_eport; + } + } + +result: IPSL_CLOSE { $$.act_val = IPSL_CLOSE; } + | IPSL_TRACK { $$.act_val = IPSL_TRACK; } + | redirect { $$.act_val = IPSL_REDIRECT; + $$.act_ip = $1.act_ip; + $$.act_port = $1.act_port; } + ; + +onehalf: + '(' YY_STR ')' { $$ = makepair($2, NULL); } + ; + +twohalves: + '(' YY_STR ',' YY_STR ')' { $$ = makepair($2, $4); } + ; + +redirect: + IPSL_REDIRECT '(' ipaddr ')' { $$.act_ip = $3; + $$.act_port = 0; } + | IPSL_REDIRECT '(' ipaddr ',' portnum ')' + { $$.act_ip = $3; + $$.act_port = $5; } + ; + + +ipaddr: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER + { $$ = combine($1,$3,$5,$7); } + | YY_STR { $$ = gethostip($1); + free($1); + } + ; + +portnum: + YY_NUMBER { $$ = htons($1); } + | YY_STR { $$ = getportnum($1); + free($1); + } + ; + +%% + + +static struct wordtab yywords[] = { + { "close", IPSL_CLOSE }, + { "content", IPSL_CONTENT }, + { "else", IPSL_ELSE }, + { "start-group", IPSL_STARTGROUP }, + { "redirect", IPSL_REDIRECT }, + { "start", IPSL_START }, + { "track", IPSL_TRACK }, + { NULL, 0 } +}; + + +int cram(dst, src) +char *dst; +char *src; +{ + char c, *s, *t, *u; + int i, j, k; + + c = *src; + s = src + 1; + t = strchr(s, c); + *t = '\0'; + for (u = dst, i = 0; (i <= ISC_TLEN) && (s < t); ) { + c = *s++; + if (c == '\\') { + if (s >= t) + break; + j = k = 0; + do { + c = *s++; + if (j && (!ISDIGIT(c) || (c > '7') || + (k >= 248))) { + *u++ = k, i++; + j = k = 0; + s--; + break; + } + i++; + + if (ISALPHA(c) || (c > '7')) { + switch (c) + { + case 'n' : + *u++ = '\n'; + break; + case 'r' : + *u++ = '\r'; + break; + case 't' : + *u++ = '\t'; + break; + default : + *u++ = c; + break; + } + } else if (ISDIGIT(c)) { + j = 1; + k <<= 3; + k |= (c - '0'); + i--; + } else + *u++ = c; + } while ((i <= ISC_TLEN) && (s <= t) && (j > 0)); + } else + *u++ = c, i++; + } + return i; +} + + +void printent(isc) +ipscan_t *isc; +{ + char buf[ISC_TLEN+1]; + u_char *u; + int i, j; + + buf[ISC_TLEN] = '\0'; + bcopy(isc->ipsc_ctxt, buf, ISC_TLEN); + printf("%s : (\"", isc->ipsc_tag); + printbuf(isc->ipsc_ctxt, isc->ipsc_clen, 0); + + bcopy(isc->ipsc_cmsk, buf, ISC_TLEN); + printf("\", \"%s\"), (\"", buf); + + printbuf(isc->ipsc_stxt, isc->ipsc_slen, 0); + + bcopy(isc->ipsc_smsk, buf, ISC_TLEN); + printf("\", \"%s\") = ", buf); + + switch (isc->ipsc_action) + { + case ISC_A_TRACK : + printf("track"); + break; + case ISC_A_REDIRECT : + printf("redirect"); + printf("(%s", inet_ntoa(isc->ipsc_ip)); + if (isc->ipsc_port) + printf(",%d", isc->ipsc_port); + printf(")"); + break; + case ISC_A_CLOSE : + printf("close"); + break; + default : + break; + } + + if (isc->ipsc_else != ISC_A_NONE) { + printf(" else "); + switch (isc->ipsc_else) + { + case ISC_A_TRACK : + printf("track"); + break; + case ISC_A_REDIRECT : + printf("redirect"); + printf("(%s", inet_ntoa(isc->ipsc_eip)); + if (isc->ipsc_eport) + printf(",%d", isc->ipsc_eport); + printf(")"); + break; + case ISC_A_CLOSE : + printf("close"); + break; + default : + break; + } + } + printf("\n"); + + if (opts & OPT_DEBUG) { + for (u = (u_char *)isc, i = sizeof(*isc); i; ) { + printf("#"); + for (j = 32; (j > 0) && (i > 0); j--, i--) + printf("%s%02x", (j & 7) ? "" : " ", *u++); + printf("\n"); + } + } + if (opts & OPT_VERBOSE) { + printf("# hits %d active %d fref %d sref %d\n", + isc->ipsc_hits, isc->ipsc_active, isc->ipsc_fref, + isc->ipsc_sref); + } +} + + +void addtag(tstr, cp, sp, act) +char *tstr; +char **cp, **sp; +struct action *act; +{ + ipscan_t isc, *iscp; + + bzero((char *)&isc, sizeof(isc)); + + strncpy(isc.ipsc_tag, tstr, sizeof(isc.ipsc_tag)); + isc.ipsc_tag[sizeof(isc.ipsc_tag) - 1] = '\0'; + + if (cp) { + isc.ipsc_clen = cram(isc.ipsc_ctxt, cp[0]); + if (cp[1]) { + if (cram(isc.ipsc_cmsk, cp[1]) != isc.ipsc_clen) { + fprintf(stderr, + "client text/mask strings different length\n"); + return; + } + } + } + + if (sp) { + isc.ipsc_slen = cram(isc.ipsc_stxt, sp[0]); + if (sp[1]) { + if (cram(isc.ipsc_smsk, sp[1]) != isc.ipsc_slen) { + fprintf(stderr, + "server text/mask strings different length\n"); + return; + } + } + } + + if (act->act_val == IPSL_CLOSE) { + isc.ipsc_action = ISC_A_CLOSE; + } else if (act->act_val == IPSL_TRACK) { + isc.ipsc_action = ISC_A_TRACK; + } else if (act->act_val == IPSL_REDIRECT) { + isc.ipsc_action = ISC_A_REDIRECT; + isc.ipsc_ip = act->act_ip; + isc.ipsc_port = act->act_port; + fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); + } + + if (act->act_else == IPSL_CLOSE) { + isc.ipsc_else = ISC_A_CLOSE; + } else if (act->act_else == IPSL_TRACK) { + isc.ipsc_else = ISC_A_TRACK; + } else if (act->act_else == IPSL_REDIRECT) { + isc.ipsc_else = ISC_A_REDIRECT; + isc.ipsc_eip = act->act_eip; + isc.ipsc_eport = act->act_eport; + fprintf(stderr, "%d: redirect unsupported\n", yylineNum + 1); + } + + if (!(opts & OPT_DONOTHING)) { + iscp = &isc; + if (opts & OPT_REMOVE) { + if (ioctl(fd, SIOCRMSCA, &iscp) == -1) + perror("SIOCADSCA"); + } else { + if (ioctl(fd, SIOCADSCA, &iscp) == -1) + perror("SIOCADSCA"); + } + } + + if (opts & OPT_VERBOSE) + printent(&isc); +} + + +char **makepair(s1, s2) +char *s1, *s2; +{ + char **a; + + a = malloc(sizeof(char *) * 2); + a[0] = s1; + a[1] = s2; + return a; +} + + +struct in_addr combine(a1, a2, a3, a4) +int a1, a2, a3, a4; +{ + struct in_addr in; + + a1 &= 0xff; + in.s_addr = a1 << 24; + a2 &= 0xff; + in.s_addr |= (a2 << 16); + a3 &= 0xff; + in.s_addr |= (a3 << 8); + a4 &= 0xff; + in.s_addr |= a4; + in.s_addr = htonl(in.s_addr); + return in; +} + + +struct in_addr gethostip(host) +char *host; +{ + struct hostent *hp; + struct in_addr in; + + in.s_addr = 0; + + hp = gethostbyname(host); + if (!hp) + return in; + bcopy(hp->h_addr, (char *)&in, sizeof(in)); + return in; +} + + +int getportnum(port) +char *port; +{ + struct servent *s; + + s = getservbyname(port, "tcp"); + if (s == NULL) + return -1; + return s->s_port; +} + + +void showlist() +{ + ipscanstat_t ipsc, *ipscp = &ipsc; + ipscan_t isc; + + if (ioctl(fd, SIOCGSCST, &ipscp) == -1) + perror("ioctl(SIOCGSCST)"); + else if (opts & OPT_SHOWLIST) { + while (ipsc.iscs_list != NULL) { + if (kmemcpy((char *)&isc, (u_long)ipsc.iscs_list, + sizeof(isc)) == -1) { + perror("kmemcpy"); + break; + } else { + printent(&isc); + ipsc.iscs_list = isc.ipsc_next; + } + } + } else { + printf("scan entries loaded\t%d\n", ipsc.iscs_entries); + printf("scan entries matches\t%ld\n", ipsc.iscs_acted); + printf("negative matches\t%ld\n", ipsc.iscs_else); + } +} + + +void usage(prog) +char *prog; +{ + fprintf(stderr, "Usage:\t%s [-dnrv] -f <filename>\n", prog); + fprintf(stderr, "\t%s [-dlv]\n", prog); + exit(1); +} + + +int main(argc, argv) +int argc; +char *argv[]; +{ + FILE *fp = NULL; + int c; + + (void) yysettab(yywords); + + if (argc < 2) + usage(argv[0]); + + while ((c = getopt(argc, argv, "df:lnrsv")) != -1) + switch (c) + { + case 'd' : + opts |= OPT_DEBUG; + yydebug++; + break; + case 'f' : + if (!strcmp(optarg, "-")) + fp = stdin; + else { + fp = fopen(optarg, "r"); + if (!fp) { + perror("open"); + exit(1); + } + } + yyin = fp; + break; + case 'l' : + opts |= OPT_SHOWLIST; + break; + case 'n' : + opts |= OPT_DONOTHING; + break; + case 'r' : + opts |= OPT_REMOVE; + break; + case 's' : + opts |= OPT_STAT; + break; + case 'v' : + opts |= OPT_VERBOSE; + break; + } + + if (!(opts & OPT_DONOTHING)) { + fd = open(IPL_SCAN, O_RDWR); + if (fd == -1) { + perror("open(IPL_SCAN)"); + exit(1); + } + } + + if (fp != NULL) { + yylineNum = 1; + + while (!feof(fp)) + yyparse(); + fclose(fp); + exit(0); + } + + if (opts & (OPT_SHOWLIST|OPT_STAT)) { + showlist(); + exit(0); + } + exit(1); +} diff --git a/contrib/ipfilter/tools/ipsyncm.c b/contrib/ipfilter/tools/ipsyncm.c new file mode 100644 index 0000000..41513fa --- /dev/null +++ b/contrib/ipfilter/tools/ipsyncm.c @@ -0,0 +1,256 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <syslog.h> +#include <signal.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_state.h" +#include "netinet/ip_sync.h" + + +int main __P((int, char *[])); +void usage __P((const char *)); + +int terminate = 0; + +void usage(const char *progname) { + fprintf(stderr, "Usage: %s <destination IP> <destination port>\n", progname); +} + +#if 0 +static void handleterm(int sig) +{ + terminate = sig; +} +#endif + + +/* should be large enough to hold header + any datatype */ +#define BUFFERLEN 1400 + +int main(argc, argv) + int argc; + char *argv[]; +{ + struct sockaddr_in sin; + char buff[BUFFERLEN]; + synclogent_t *sl; + syncupdent_t *su; + int nfd = -1, lfd = -1, n1, n2, n3, len; + int inbuf; + u_32_t magic; + synchdr_t *sh; + char *progname; + + progname = strrchr(argv[0], '/'); + if (progname) { + progname++; + } else { + progname = argv[0]; + } + + + if (argc < 2) { + usage(progname); + exit(1); + } + +#if 0 + signal(SIGHUP, handleterm); + signal(SIGINT, handleterm); + signal(SIGTERM, handleterm); +#endif + + openlog(progname, LOG_PID, LOG_SECURITY); + + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = inet_addr(argv[1]); + if (argc > 2) + sin.sin_port = htons(atoi(argv[2])); + else + sin.sin_port = htons(43434); + + while (1) { + + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + lfd = open(IPSYNC_NAME, O_RDONLY); + if (lfd == -1) { + syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); + goto tryagain; + } + + nfd = socket(AF_INET, SOCK_DGRAM, 0); + if (nfd == -1) { + syslog(LOG_ERR, "Socket :%m"); + goto tryagain; + } + + if (connect(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + syslog(LOG_ERR, "Connect: %m"); + goto tryagain; + } + + syslog(LOG_INFO, "Sending data to %s", + inet_ntoa(sin.sin_addr)); + + inbuf = 0; + while (1) { + + n1 = read(lfd, buff+inbuf, BUFFERLEN-inbuf); + + printf("header : %d bytes read (header = %d bytes)\n", + n1, (int) sizeof(*sh)); + + if (n1 < 0) { + syslog(LOG_ERR, "Read error (header): %m"); + goto tryagain; + } + + if (n1 == 0) { + /* XXX can this happen??? */ + syslog(LOG_ERR, + "Read error (header) : No data"); + sleep(1); + continue; + } + + inbuf += n1; + +moreinbuf: + if (inbuf < sizeof(*sh)) { + continue; /* need more data */ + } + + sh = (synchdr_t *)buff; + len = ntohl(sh->sm_len); + magic = ntohl(sh->sm_magic); + + if (magic != SYNHDRMAGIC) { + syslog(LOG_ERR, + "Invalid header magic %x", magic); + goto tryagain; + } + +#define IPSYNC_DEBUG +#ifdef IPSYNC_DEBUG + printf("v:%d p:%d len:%d magic:%x", sh->sm_v, + sh->sm_p, len, magic); + + if (sh->sm_cmd == SMC_CREATE) + printf(" cmd:CREATE"); + else if (sh->sm_cmd == SMC_UPDATE) + printf(" cmd:UPDATE"); + else + printf(" cmd:Unknown(%d)", sh->sm_cmd); + + if (sh->sm_table == SMC_NAT) + printf(" table:NAT"); + else if (sh->sm_table == SMC_STATE) + printf(" table:STATE"); + else + printf(" table:Unknown(%d)", sh->sm_table); + + printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num)); +#endif + + if (inbuf < sizeof(*sh) + len) { + continue; /* need more data */ + goto tryagain; + } + +#ifdef IPSYNC_DEBUG + if (sh->sm_cmd == SMC_CREATE) { + sl = (synclogent_t *)buff; + + } else if (sh->sm_cmd == SMC_UPDATE) { + su = (syncupdent_t *)buff; + if (sh->sm_p == IPPROTO_TCP) { + printf(" TCP Update: age %lu state %d/%d\n", + su->sup_tcp.stu_age, + su->sup_tcp.stu_state[0], + su->sup_tcp.stu_state[1]); + } + } else { + printf("Unknown command\n"); + } +#endif + + n2 = sizeof(*sh) + len; + n3 = write(nfd, buff, n2); + if (n3 <= 0) { + syslog(LOG_ERR, "Write error: %m"); + goto tryagain; + } + + + if (n3 != n2) { + syslog(LOG_ERR, "Incomplete write (%d/%d)", + n3, n2); + goto tryagain; + } + + /* signal received? */ + if (terminate) + break; + + /* move buffer to the front,we might need to make + * this more efficient, by using a rolling pointer + * over the buffer and only copying it, when + * we are reaching the end + */ + inbuf -= n2; + if (inbuf) { + bcopy(buff+n2, buff, inbuf); + printf("More data in buffer\n"); + goto moreinbuf; + } + } + + if (terminate) + break; +tryagain: + sleep(1); + } + + + /* terminate */ + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + syslog(LOG_ERR, "signal %d received, exiting...", terminate); + + exit(1); +} + diff --git a/contrib/ipfilter/tools/ipsyncs.c b/contrib/ipfilter/tools/ipsyncs.c new file mode 100644 index 0000000..43692cd --- /dev/null +++ b/contrib/ipfilter/tools/ipsyncs.c @@ -0,0 +1,274 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id$"; +#endif +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <net/if.h> + +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <syslog.h> +#include <errno.h> +#include <signal.h> + +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_state.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_sync.h" + +int main __P((int, char *[])); +void usage __P((const char *progname)); + +int terminate = 0; + +void usage(const char *progname) { + fprintf(stderr, + "Usage: %s <destination IP> <destination port> [remote IP]\n", + progname); +} + +#if 0 +static void handleterm(int sig) +{ + terminate = sig; +} +#endif + +#define BUFFERLEN 1400 + +int main(argc, argv) + int argc; + char *argv[]; +{ + int nfd = -1 , lfd = -1; + int n1, n2, n3, magic, len, inbuf; + struct sockaddr_in sin; + struct sockaddr_in in; + char buff[BUFFERLEN]; + synclogent_t *sl; + syncupdent_t *su; + synchdr_t *sh; + char *progname; + + progname = strrchr(argv[0], '/'); + if (progname) { + progname++; + } else { + progname = argv[0]; + } + + if (argc < 2) { + usage(progname); + exit(1); + } + +#if 0 + signal(SIGHUP, handleterm); + signal(SIGINT, handleterm); + signal(SIGTERM, handleterm); +#endif + + openlog(progname, LOG_PID, LOG_SECURITY); + + lfd = open(IPSYNC_NAME, O_WRONLY); + if (lfd == -1) { + syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); + exit(1); + } + + bzero((char *)&sin, sizeof(sin)); + sin.sin_family = AF_INET; + if (argc > 1) + sin.sin_addr.s_addr = inet_addr(argv[1]); + if (argc > 2) + sin.sin_port = htons(atoi(argv[2])); + else + sin.sin_port = htons(43434); + if (argc > 3) + in.sin_addr.s_addr = inet_addr(argv[3]); + else + in.sin_addr.s_addr = 0; + in.sin_port = 0; + + while(1) { + + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + lfd = open(IPSYNC_NAME, O_WRONLY); + if (lfd == -1) { + syslog(LOG_ERR, "Opening %s :%m", IPSYNC_NAME); + goto tryagain; + } + + nfd = socket(AF_INET, SOCK_DGRAM, 0); + if (nfd == -1) { + syslog(LOG_ERR, "Socket :%m"); + goto tryagain; + } + + n1 = 1; + setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &n1, sizeof(n1)); + + if (bind(nfd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + syslog(LOG_ERR, "Bind: %m"); + goto tryagain; + } + + syslog(LOG_INFO, "Listening to %s", inet_ntoa(sin.sin_addr)); + + inbuf = 0; + while (1) { + + + /* + * XXX currently we do not check the source address + * of a datagram, this can be a security risk + */ + n1 = read(nfd, buff+inbuf, BUFFERLEN-inbuf); + + printf("header : %d bytes read (header = %d bytes)\n", + n1, (int) sizeof(*sh)); + + if (n1 < 0) { + syslog(LOG_ERR, "Read error (header): %m"); + goto tryagain; + } + + if (n1 == 0) { + /* XXX can this happen??? */ + syslog(LOG_ERR, + "Read error (header) : No data"); + sleep(1); + continue; + } + + inbuf += n1; + +moreinbuf: + if (inbuf < sizeof(*sh)) { + continue; /* need more data */ + } + + sh = (synchdr_t *)buff; + len = ntohl(sh->sm_len); + magic = ntohl(sh->sm_magic); + + if (magic != SYNHDRMAGIC) { + syslog(LOG_ERR, "Invalid header magic %x", + magic); + goto tryagain; + } + +#define IPSYNC_DEBUG +#ifdef IPSYNC_DEBUG + printf("v:%d p:%d len:%d magic:%x", sh->sm_v, + sh->sm_p, len, magic); + + if (sh->sm_cmd == SMC_CREATE) + printf(" cmd:CREATE"); + else if (sh->sm_cmd == SMC_UPDATE) + printf(" cmd:UPDATE"); + else + printf(" cmd:Unknown(%d)", sh->sm_cmd); + + if (sh->sm_table == SMC_NAT) + printf(" table:NAT"); + else if (sh->sm_table == SMC_STATE) + printf(" table:STATE"); + else + printf(" table:Unknown(%d)", sh->sm_table); + + printf(" num:%d\n", (u_32_t)ntohl(sh->sm_num)); +#endif + + if (inbuf < sizeof(*sh) + len) { + continue; /* need more data */ + goto tryagain; + } + +#ifdef IPSYNC_DEBUG + if (sh->sm_cmd == SMC_CREATE) { + sl = (synclogent_t *)buff; + + } else if (sh->sm_cmd == SMC_UPDATE) { + su = (syncupdent_t *)buff; + if (sh->sm_p == IPPROTO_TCP) { + printf(" TCP Update: age %lu state %d/%d\n", + su->sup_tcp.stu_age, + su->sup_tcp.stu_state[0], + su->sup_tcp.stu_state[1]); + } + } else { + printf("Unknown command\n"); + } +#endif + + n2 = sizeof(*sh) + len; + n3 = write(lfd, buff, n2); + if (n3 <= 0) { + syslog(LOG_ERR, "%s: Write error: %m", + IPSYNC_NAME); + goto tryagain; + } + + + if (n3 != n2) { + syslog(LOG_ERR, "%s: Incomplete write (%d/%d)", + IPSYNC_NAME, n3, n2); + goto tryagain; + } + + /* signal received? */ + if (terminate) + break; + + /* move buffer to the front,we might need to make + * this more efficient, by using a rolling pointer + * over the buffer and only copying it, when + * we are reaching the end + */ + inbuf -= n2; + if (inbuf) { + bcopy(buff+n2, buff, inbuf); + printf("More data in buffer\n"); + goto moreinbuf; + } + } + + if (terminate) + break; +tryagain: + sleep(1); + } + + + /* terminate */ + if (lfd != -1) + close(lfd); + if (nfd != -1) + close(nfd); + + syslog(LOG_ERR, "signal %d received, exiting...", terminate); + + exit(1); +} diff --git a/contrib/ipfilter/tools/lex_var.h b/contrib/ipfilter/tools/lex_var.h new file mode 100644 index 0000000..eb59f58 --- /dev/null +++ b/contrib/ipfilter/tools/lex_var.h @@ -0,0 +1,60 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +extern long string_start; +extern long string_end; +extern char *string_val; +extern long pos; + +#define YY_INPUT(buf, result, max_size) \ + if (pos >= string_start && pos <= string_end) { \ + buf[0] = string_val[pos - string_start]; \ + pos++; \ + result = 1; \ + } else if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < 1 && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + pos++; \ + } \ + else if ( ((result = fread( buf, 1, 1, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); + +#ifdef input +# undef input +# define input() (((pos >= string_start) && (pos < string_end)) ? \ + yysptr = yysbuf, string_val[pos++ - string_start] : \ + ((yytchar = yysptr > yysbuf ? U(*--yysptr) : \ + getc(yyin)) == 10 ? (pos++, yylineno++, yytchar) : \ + yytchar) == EOF ? (pos++, 0) : (pos++, yytchar)) +#endif + +#ifdef lex_input +# undef lex_input +# define lex_input() (((pos >= string_start) && (pos < string_end)) ? \ + yysptr = yysbuf, string_val[pos++ - string_start] : \ + ((yytchar = yysptr > yysbuf ? U(*--yysptr) : \ + getc(yyin)) == 10 ? (pos++, yylineno++, yytchar) : \ + yytchar) == EOF ? (pos++, 0) : (pos++, yytchar)) +#endif + +#ifdef unput +# undef unput +# define unput(c) { if (pos > 0) pos--; \ + yytchar = (c); if (yytchar == '\n') yylineno--; \ + *yysptr++ = yytchar; } +#endif + diff --git a/contrib/ipfilter/tools/lexer.c b/contrib/ipfilter/tools/lexer.c new file mode 100644 index 0000000..41b7896 --- /dev/null +++ b/contrib/ipfilter/tools/lexer.c @@ -0,0 +1,735 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ +#include <ctype.h> +#include "ipf.h" +#ifdef IPFILTER_SCAN +# include "netinet/ip_scan.h" +#endif +#include <sys/ioctl.h> +#include <syslog.h> +#ifdef TEST_LEXER +# define NO_YACC +union { + int num; + char *str; + struct in_addr ipa; + i6addr_t ip6; +} yylval; +#endif +#include "lexer.h" +#include "y.tab.h" + +FILE *yyin; + +#define ishex(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \ + ((c) >= 'A' && (c) <= 'F')) +#define TOOLONG -3 + +extern int string_start; +extern int string_end; +extern char *string_val; +extern int pos; +extern int yydebug; + +char *yystr = NULL; +int yytext[YYBUFSIZ+1]; +char yychars[YYBUFSIZ+1]; +int yylineNum = 1; +int yypos = 0; +int yylast = -1; +int yydictfixed = 0; +int yyexpectaddr = 0; +int yybreakondot = 0; +int yyvarnext = 0; +int yytokentype = 0; +wordtab_t *yywordtab = NULL; +int yysavedepth = 0; +wordtab_t *yysavewords[30]; + + +static wordtab_t *yyfindkey __P((char *)); +static int yygetc __P((int)); +static void yyunputc __P((int)); +static int yyswallow __P((int)); +static char *yytexttostr __P((int, int)); +static void yystrtotext __P((char *)); +static char *yytexttochar __P((void)); + +static int yygetc(docont) + int docont; +{ + int c; + + if (yypos < yylast) { + c = yytext[yypos++]; + if (c == '\n') + yylineNum++; + return c; + } + + if (yypos == YYBUFSIZ) + return TOOLONG; + + if (pos >= string_start && pos <= string_end) { + c = string_val[pos - string_start]; + yypos++; + } else { + c = fgetc(yyin); + if (docont && (c == '\\')) { + c = fgetc(yyin); + if (c == '\n') { + yylineNum++; + c = fgetc(yyin); + } + } + } + if (c == '\n') + yylineNum++; + yytext[yypos++] = c; + yylast = yypos; + yytext[yypos] = '\0'; + + return c; +} + + +static void yyunputc(c) + int c; +{ + if (c == '\n') + yylineNum--; + yytext[--yypos] = c; +} + + +static int yyswallow(last) + int last; +{ + int c; + + while (((c = yygetc(0)) > '\0') && (c != last)) + ; + + if (c != EOF) + yyunputc(c); + if (c == last) + return 0; + return -1; +} + + +static char *yytexttochar() +{ + int i; + + for (i = 0; i < yypos; i++) + yychars[i] = (char)(yytext[i] & 0xff); + yychars[i] = '\0'; + return yychars; +} + + +static void yystrtotext(str) + char *str; +{ + int len; + char *s; + + len = strlen(str); + if (len > YYBUFSIZ) + len = YYBUFSIZ; + + for (s = str; *s != '\0' && len > 0; s++, len--) + yytext[yylast++] = *s; + yytext[yylast] = '\0'; +} + + +static char *yytexttostr(offset, max) + int offset, max; +{ + char *str; + int i; + + if ((yytext[offset] == '\'' || yytext[offset] == '"') && + (yytext[offset] == yytext[offset + max - 1])) { + offset++; + max--; + } + + if (max > yylast) + max = yylast; + str = malloc(max + 1); + if (str != NULL) { + for (i = offset; i < max; i++) + str[i - offset] = (char)(yytext[i] & 0xff); + str[i - offset] = '\0'; + } + return str; +} + + +int yylex() +{ + static int prior = 0; + static int priornum = 0; + int c, n, isbuilding, rval, lnext, nokey = 0; + char *name; + int triedv6 = 0; + + isbuilding = 0; + lnext = 0; + rval = 0; + + if (yystr != NULL) { + free(yystr); + yystr = NULL; + } + +nextchar: + c = yygetc(0); + if (yydebug > 1) + printf("yygetc = (%x) %c [%*.*s]\n", + c, c, yypos, yypos, yytexttochar()); + + switch (c) + { + case '\n' : + lnext = 0; + nokey = 0; + case '\t' : + case '\r' : + case ' ' : + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + if (yylast > yypos) { + bcopy(yytext + yypos, yytext, + sizeof(yytext[0]) * (yylast - yypos + 1)); + } + yylast -= yypos; + if (yyexpectaddr == 2) + yyexpectaddr = 0; + yypos = 0; + lnext = 0; + nokey = 0; + goto nextchar; + + case '\\' : + if (lnext == 0) { + lnext = 1; + if (yylast == yypos) { + yylast--; + yypos--; + } else + yypos--; + if (yypos == 0) + nokey = 1; + goto nextchar; + } + break; + } + + if (lnext == 1) { + lnext = 0; + if ((isbuilding == 0) && !ISALNUM(c)) { + prior = c; + return c; + } + goto nextchar; + } + + switch (c) + { + case '#' : + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + yyswallow('\n'); + rval = YY_COMMENT; + goto done; + + case '$' : + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + n = yygetc(0); + if (n == '{') { + if (yyswallow('}') == -1) { + rval = -2; + goto done; + } + (void) yygetc(0); + } else { + if (!ISALPHA(n)) { + yyunputc(n); + break; + } + do { + n = yygetc(1); + } while (ISALPHA(n) || ISDIGIT(n) || n == '_'); + yyunputc(n); + } + + name = yytexttostr(1, yypos); /* skip $ */ + + if (name != NULL) { + string_val = get_variable(name, NULL, yylineNum); + free(name); + if (string_val != NULL) { + name = yytexttostr(yypos, yylast); + if (name != NULL) { + yypos = 0; + yylast = 0; + yystrtotext(string_val); + yystrtotext(name); + free(string_val); + free(name); + goto nextchar; + } + free(string_val); + } + } + break; + + case '\'': + case '"' : + if (isbuilding == 1) { + goto done; + } + do { + n = yygetc(1); + if (n == EOF || n == TOOLONG) { + rval = -2; + goto done; + } + if (n == '\n') { + yyunputc(' '); + yypos++; + } + } while (n != c); + rval = YY_STR; + goto done; + /* NOTREACHED */ + + case EOF : + yylineNum = 1; + yypos = 0; + yylast = -1; + yyexpectaddr = 0; + yybreakondot = 0; + yyvarnext = 0; + yytokentype = 0; + if (yydebug) + fprintf(stderr, "reset at EOF\n"); + prior = 0; + return 0; + } + + if (strchr("=,/;{}()@", c) != NULL) { + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + rval = c; + goto done; + } else if (c == '.') { + if (isbuilding == 0) { + rval = c; + goto done; + } + if (yybreakondot != 0) { + yyunputc(c); + goto done; + } + } + + switch (c) + { + case '-' : + n = yygetc(0); + if (n == '>') { + isbuilding = 1; + goto done; + } + yyunputc(n); + if (yyexpectaddr) { + if (isbuilding == 1) + yyunputc(c); + else + rval = '-'; + goto done; + } + if (isbuilding == 1) + break; + rval = '-'; + goto done; + + case '!' : + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + n = yygetc(0); + if (n == '=') { + rval = YY_CMP_NE; + goto done; + } + yyunputc(n); + rval = '!'; + goto done; + + case '<' : + if (yyexpectaddr) + break; + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + n = yygetc(0); + if (n == '=') { + rval = YY_CMP_LE; + goto done; + } + if (n == '>') { + rval = YY_RANGE_OUT; + goto done; + } + yyunputc(n); + rval = YY_CMP_LT; + goto done; + + case '>' : + if (yyexpectaddr) + break; + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + n = yygetc(0); + if (n == '=') { + rval = YY_CMP_GE; + goto done; + } + if (n == '<') { + rval = YY_RANGE_IN; + goto done; + } + yyunputc(n); + rval = YY_CMP_GT; + goto done; + } + + /* + * Now for the reason this is here...IPv6 address parsing. + * The longest string we can expect is of this form: + * 0000:0000:0000:0000:0000:0000:000.000.000.000 + * not: + * 0000:0000:0000:0000:0000:0000:0000:0000 + */ +#ifdef USE_INET6 + if (yyexpectaddr != 0 && isbuilding == 0 && + (ishex(c) || isdigit(c) || c == ':')) { + char ipv6buf[45 + 1], *s, oc; + int start; + +buildipv6: + start = yypos; + s = ipv6buf; + oc = c; + + if (prior == YY_NUMBER && c == ':') { + sprintf(s, "%d", priornum); + s += strlen(s); + } + + /* + * Perhaps we should implement stricter controls on what we + * swallow up here, but surely it would just be duplicating + * the code in inet_pton() anyway. + */ + do { + *s++ = c; + c = yygetc(1); + } while ((ishex(c) || c == ':' || c == '.') && + (s - ipv6buf < 46)); + yyunputc(c); + *s = '\0'; + + if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) { + rval = YY_IPV6; + yyexpectaddr = 0; + goto done; + } + yypos = start; + c = oc; + } +#endif + + if ((c == ':') && (rval != YY_IPV6) && (triedv6 == 0)) { +#ifdef USE_INET6 + yystr = yytexttostr(0, yypos - 1); + if (yystr != NULL) { + char *s; + + for (s = yystr; *s && ishex(*s); s++) + ; + if (!*s && *yystr) { + isbuilding = 0; + c = *yystr; + free(yystr); + triedv6 = 1; + yypos = 1; + goto buildipv6; + } + free(yystr); + } +#endif + if (isbuilding == 1) { + yyunputc(c); + goto done; + } + rval = ':'; + goto done; + } + + if (isbuilding == 0 && c == '0') { + n = yygetc(0); + if (n == 'x') { + do { + n = yygetc(1); + } while (ishex(n)); + yyunputc(n); + rval = YY_HEX; + goto done; + } + yyunputc(n); + } + + /* + * No negative numbers with leading - sign.. + */ + if (isbuilding == 0 && ISDIGIT(c)) { + do { + n = yygetc(1); + } while (ISDIGIT(n)); + yyunputc(n); + rval = YY_NUMBER; + goto done; + } + + isbuilding = 1; + goto nextchar; + +done: + yystr = yytexttostr(0, yypos); + + if (yydebug) + printf("isbuilding %d yyvarnext %d nokey %d fixed %d addr %d\n", + isbuilding, yyvarnext, nokey, yydictfixed, yyexpectaddr); + if (isbuilding == 1) { + wordtab_t *w; + + w = NULL; + isbuilding = 0; + + if ((yyvarnext == 0) && (nokey == 0)) { + w = yyfindkey(yystr); + if (w == NULL && yywordtab != NULL && !yydictfixed) { + yyresetdict(); + w = yyfindkey(yystr); + } + } else + yyvarnext = 0; + if (w != NULL) + rval = w->w_value; + else + rval = YY_STR; + } + + if (rval == YY_STR) { + if (yysavedepth > 0 && !yydictfixed) + yyresetdict(); + if (yyexpectaddr != 0) + yyexpectaddr = 0; + } + + yytokentype = rval; + + if (yydebug) + printf("lexed(%s) %d,%d,%d [%d,%d,%d] => %d @%d\n", + yystr, isbuilding, yyexpectaddr, yysavedepth, + string_start, string_end, pos, rval, yysavedepth); + + switch (rval) + { + case YY_NUMBER : + sscanf(yystr, "%u", &yylval.num); + break; + + case YY_HEX : + sscanf(yystr, "0x%x", (u_int *)&yylval.num); + break; + + case YY_STR : + yylval.str = strdup(yystr); + break; + + default : + break; + } + + if (yylast > 0) { + bcopy(yytext + yypos, yytext, + sizeof(yytext[0]) * (yylast - yypos + 1)); + yylast -= yypos; + yypos = 0; + } + + if (rval == YY_NUMBER) + priornum = yylval.num; + prior = rval; + return rval; +} + + +static wordtab_t *yyfindkey(key) + char *key; +{ + wordtab_t *w; + + if (yywordtab == NULL) + return NULL; + + for (w = yywordtab; w->w_word != 0; w++) + if (strcasecmp(key, w->w_word) == 0) + return w; + return NULL; +} + + +char *yykeytostr(num) + int num; +{ + wordtab_t *w; + + if (yywordtab == NULL) + return "<unknown>"; + + for (w = yywordtab; w->w_word; w++) + if (w->w_value == num) + return w->w_word; + return "<unknown>"; +} + + +wordtab_t *yysettab(words) + wordtab_t *words; +{ + wordtab_t *save; + + save = yywordtab; + yywordtab = words; + return save; +} + + +void yyerror(msg) + char *msg; +{ + char *txt, letter[2]; + int freetxt = 0; + + if (yytokentype < 256) { + letter[0] = yytokentype; + letter[1] = '\0'; + txt = letter; + } else if (yytokentype == YY_STR || yytokentype == YY_HEX || + yytokentype == YY_NUMBER) { + if (yystr == NULL) { + txt = yytexttostr(yypos, YYBUFSIZ); + freetxt = 1; + } else + txt = yystr; + } else { + txt = yykeytostr(yytokentype); + } + fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum); + if (freetxt == 1) + free(txt); + exit(1); +} + + +void yysetfixeddict(newdict) + wordtab_t *newdict; +{ + if (yydebug) + printf("yysetfixeddict(%lx)\n", (u_long)newdict); + + if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { + fprintf(stderr, "%d: at maximum dictionary depth\n", + yylineNum); + return; + } + + yysavewords[yysavedepth++] = yysettab(newdict); + if (yydebug) + printf("yysavedepth++ => %d\n", yysavedepth); + yydictfixed = 1; +} + + +void yysetdict(newdict) + wordtab_t *newdict; +{ + if (yydebug) + printf("yysetdict(%lx)\n", (u_long)newdict); + + if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { + fprintf(stderr, "%d: at maximum dictionary depth\n", + yylineNum); + return; + } + + yysavewords[yysavedepth++] = yysettab(newdict); + if (yydebug) + printf("yysavedepth++ => %d\n", yysavedepth); +} + +void yyresetdict() +{ + if (yydebug) + printf("yyresetdict(%d)\n", yysavedepth); + if (yysavedepth > 0) { + yysettab(yysavewords[--yysavedepth]); + if (yydebug) + printf("yysavedepth-- => %d\n", yysavedepth); + } + yydictfixed = 0; +} + + + +#ifdef TEST_LEXER +int main(argc, argv) + int argc; + char *argv[]; +{ + int n; + + yyin = stdin; + + while ((n = yylex()) != 0) + printf("%d.n = %d [%s] %d %d\n", + yylineNum, n, yystr, yypos, yylast); +} +#endif diff --git a/contrib/ipfilter/tools/lexer.h b/contrib/ipfilter/tools/lexer.h new file mode 100644 index 0000000..cff24b4 --- /dev/null +++ b/contrib/ipfilter/tools/lexer.h @@ -0,0 +1,38 @@ +/* $FreeBSD$ */ + +/* + * Copyright (C) 2012 by Darren Reed. + * + * See the IPFILTER.LICENCE file for details on licencing. + */ + +#ifdef NO_YACC +#define YY_COMMENT 1000 +#define YY_CMP_NE 1001 +#define YY_CMP_LE 1002 +#define YY_RANGE_OUT 1003 +#define YY_CMP_GE 1004 +#define YY_RANGE_IN 1005 +#define YY_HEX 1006 +#define YY_NUMBER 1007 +#define YY_IPV6 1008 +#define YY_STR 1009 +#define YY_IPADDR 1010 +#endif + +#define YYBUFSIZ 8192 + +extern wordtab_t *yysettab __P((wordtab_t *)); +extern void yysetdict __P((wordtab_t *)); +extern void yysetfixeddict __P((wordtab_t *)); +extern int yylex __P((void)); +extern void yyerror __P((char *)); +extern char *yykeytostr __P((int)); +extern void yyresetdict __P((void)); + +extern FILE *yyin; +extern int yylineNum; +extern int yyexpectaddr; +extern int yybreakondot; +extern int yyvarnext; + |