# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # SUBDIRS= etc examples \ lib .WAIT \ tools LINTCLEAN= LINTSUBDIRS= include ../Makefile.cmd all: TARGET= all install: TARGET= install clean: TARGET= clean clobber: TARGET= clobber lint: TARGET= lint .KEEP_STATE: .PARALLEL: $(SUBDIRS) all lint clean clobber: $(SUBDIRS) install: $(SUBDIRS) $(filter-out .WAIT,$(SUBDIRS)): FRC cd $@; pwd; $(MAKE) $(TARGET) FRC: check: # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. LIBIPF= ../lib/libipf.a COMMONIPF= $(SRC)/uts/common/inet/ipf KERNELIPF= $(SRC)/uts/common/inet/pfil CPPFLAGS += -I$(COMMONIPF) -I$(KERNELIPF) -DSUNDDI -DUSE_INET6 \ -DSOLARIS2=$(RELEASE_MINOR) CERRWARN += -Wno-unused-variable CERRWARN += -Wno-type-limits CERRWARN += $(CNOWARN_UNINIT) CERRWARN += -Wno-parentheses CERRWARN += -Wno-unused-function CERRWARN += -Wno-empty-body # not linted SMATCH=off # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #cmd/ipf/etc/Makefile # IPFCONF= ipf.conf IPFPROG= $(IPFCONF) include ../../Makefile.cmd ETCIPF= $(ROOTETC)/ipf DIRS= $(ETCIPF) ETCIPFPROG= $(IPFPROG:%=$(ETCIPF)/%) $(ETCIPFPROG): FILEMODE= 0644 .KEEP_STATE: all: $(IPFPROG) $(DIRS) $(ETCIPFPROG) install: all $(DIRS) $(PFILAP): $(SH) $@.sh $(ETCIPF)/% : % $(ETCIPF) $(INS.file) $(DIRS): $(INS.dir) clean: clobber: lint: .PARALLEL: # # ipf.conf # # IP Filter rules to be loaded during startup # # See ipf(5) manpage for more information on # IP Filter rules syntax. #!/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 #!/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 #!/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 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #cmd/ipf/examples/Makefile # SHPROG= mkfilters EXAMPLES= BASIC.NAT BASIC_1.FW BASIC_2.FW \ example.1 example.2 example.3 example.4 \ example.5 example.6 example.7 example.8 \ example.9 example.10 example.11 example.12 \ example.13 example.sr firewall ftp-proxy \ ftppxy ip_rules nat-setup nat.eg \ pool.conf server tcpstate SHSRCS= $(SHPROG:%=%.sh) include ../../Makefile.cmd CLOBBERFILES = $(SHPROG) SHAREIPF= $(ROOT)/usr/share/ipfilter SHAREIPFX= $(SHAREIPF)/examples IPFEXAMPLES= $(EXAMPLES:%=$(SHAREIPFX)/%) IPFEXSHPROG= $(SHPROG:%=$(SHAREIPFX)/%) FILEMODE= 0644 $(IPFEXSHPROG): FILEMODE= 0755 $(SHAREIPFX)/% : % $(SHAREIPFX) $(INS.file) $(SHAREIPF): $(INS.dir) $(SHAREIPFX): $(INS.dir) .KEEP_STATE: all: $(SHPROG) clean: install: all $(SHAREIPF) $(SHAREIPFX) \ $(IPFEXAMPLES) $(IPFEXSHPROG) lint: include ../../Makefile.targ .PARALLEL: # # 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 # # 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 # # 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 # # 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 # # 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 # # 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 # # 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 # # block all ICMP packets. # block in proto icmp from any to any # # 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 # # 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 # 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 # # 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 # # 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 # # 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 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 proto tcp from to any port 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. 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. #!/bin/sh # The proxy bit is as follows: # proxy [port ] / # the 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 - # Used to generate ../ip_rules.c and ../ip_rules.h pass in all pass out all #!/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 = )) { 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 () { 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/; } } } 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: [pc] [pc] | | +-+---------+------+ | [firewall] | | Internet 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 # 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 # # # ippool sample configuration file # table role = ipf type = tree number = 0 { !10.0.0.0/8, 10.1.0.0/16, 10.1.1.0/24, !10.2.0.0/24, !10.2.1.0/24, !10.2.2.0/24, 10.1.2.3/32, 10.1.2.15/32 }; # # 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 # # 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 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # LIBRARY= libipf.a VERS= .1 OBJECTS= addicmp.o addipopt.o bcopywrap.o \ binprint.o buildopts.o checkrev.o count6bits.o \ count4bits.o debug.o extras.o facpri.o flags.o \ fill6bits.o genmask.o gethost.o getifname.o \ getline.o getnattype.o getport.o getportproto.o \ getproto.o getsumd.o hostname.o \ icmpcode.o inet_addr.o initparse.o \ ionames.o v6ionames.o ipoptsec.o ipf_dotuning.o \ ipft_ef.o ipft_hx.o ipft_pc.o ipft_sn.o ipft_td.o \ ipft_tx.o kmem.o kmemcpywrap.o kvatoname.o \ load_hash.o load_pool.o load_hashnode.o \ load_poolnode.o loglevel.o mutex_emul.o nametokva.o \ nat_setgroupmap.o ntomask.o optname.o optprint.o \ optprintv6.o optvalue.o \ portname.o portnum.o ports.o print_toif.o \ printactivenat.o printaps.o printbuf.o printhash.o \ printhashnode.o printip.o printpool.o \ printpoolnode.o printfr.o printfraginfo.o \ printhostmap.o printifname.o printhostmask.o \ printlog.o printlookup.o printmask.o printnat.o printpacket.o \ printpacket6.o printportcmp.o printproto.o \ printsbuf.o printstate.o printtunable.o ratoi.o \ remove_pool.o remove_poolnode.o remove_hash.o \ remove_hashnode.o resetlexer.o rwlock_emul.o \ tcpflags.o var.o verbose.o \ v6ionames.o v6optvalue.o printpool_live.o \ printpooldata.o printhash_live.o printhashdata.o \ printactiveaddr.o printactivenat.o printaddr.o include $(SRC)/lib/Makefile.lib include $(SRC)/lib/Makefile.lib.64 include ../Makefile.ipf LIBS= $(LIBRARY) CPPFLAGS += -I../tools .KEEP_STATE: all: $(LIBS) install: all include $(SRC)/lib/Makefile.targ /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: addicmp.c,v 1.10.2.1 2004/12/09 19:41:16 darrenr Exp $ */ #include #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" }; /* * set the icmp field to the correct type if "icmp" word is found */ int addicmp(cp, fp, linenum) char ***cp; struct frentry *fp; int linenum; { char **t; int i; (*cp)++; if (!**cp) return -1; if (!fp->fr_proto) /* to catch lusers */ fp->fr_proto = IPPROTO_ICMP; if (ISDIGIT(***cp)) { if (!ratoi(**cp, &i, 0, 255)) { fprintf(stderr, "%d: Invalid icmp-type (%s) specified\n", linenum, **cp); return -1; } } else { for (t = icmptypes, i = 0; ; t++, i++) { if (!*t) continue; if (!strcasecmp("END", *t)) { i = -1; break; } if (!strcasecmp(*t, **cp)) break; } if (i == -1) { fprintf(stderr, "%d: Unknown icmp-type (%s) specified\n", linenum, **cp); return -1; } } fp->fr_icmp = (u_short)(i << 8); fp->fr_icmpm = (u_short)0xff00; (*cp)++; if (!**cp) return 0; if (**cp && strcasecmp("code", **cp)) return 0; (*cp)++; if (ISDIGIT(***cp)) { if (!ratoi(**cp, &i, 0, 255)) { fprintf(stderr, "%d: Invalid icmp code (%s) specified\n", linenum, **cp); return -1; } } else { i = icmpcode(**cp); if (i == -1) { fprintf(stderr, "%d: Unknown icmp code (%s) specified\n", linenum, **cp); return -1; } } i &= 0xff; fp->fr_icmp |= (u_short)i; fp->fr_icmpm = (u_short)0xffff; (*cp)++; return 0; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: addipopt.c,v 1.7 2002/01/28 06:50:45 darrenr Exp $ */ #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_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; } } op += io->on_siz - 3; if (len & 3) { *op++ = IPOPT_NOP; len++; } } 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; } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # include ../Makefile.com include $(SRC)/lib/Makefile.lib.64 # # XX64 # work around the problem that gcc currently produces # buggy gcc -mcmodel=small code # CFLAGS64 += $(C_PICFLAGS64) install: all #include "ipf.h" int bcopywrap(from, to, size) void *from, *to; size_t size; { bcopy((caddr_t)from, (caddr_t)to, size); return 0; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: binprint.c,v 1.8 2002/05/14 15:18:56 darrenr Exp $ */ #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); } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: buildopts.c,v 1.6 2002/01/28 06:50:45 darrenr Exp $ */ #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'; 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; } } *op++ = IPOPT_EOL; len++; return len; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: checkrev.c,v 1.12.2.1 2004/03/09 14:44:39 darrenr Exp $ */ #include #include #include "ipf.h" #include "netinet/ipl.h" int checkrev(ipfname) char *ipfname; { static int vfd = -1; struct friostat fio, *fiop = &fio; ipfobj_t ipfo; bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(*fiop); ipfo.ipfo_ptr = (void *)fiop; ipfo.ipfo_type = IPFOBJ_IPFSTAT; if ((vfd == -1) && ((vfd = open(ipfname, O_RDONLY)) == -1)) { perror("open device"); return -1; } if (ioctl(vfd, SIOCGETFS, &ipfo)) { perror("ioctl(SIOCGETFS)"); close(vfd); vfd = -1; return -1; } if (strncmp(IPL_VERSION, fio.f_version, sizeof(fio.f_version))) { return -1; } return 0; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: count4bits.c,v 1.1 2002/06/15 04:46:39 darrenr Exp $ */ #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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: count6bits.c,v 1.4 2001/06/09 17:09:23 darrenr Exp $ */ #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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: debug.c,v 1.6 2001/06/09 17:09:24 darrenr Exp $ */ #if defined(__STDC__) # include #else # include #endif #include #include "ipt.h" #include "opts.h" #ifdef __STDC__ void debug(char *fmt, ...) #else void debug(fmt, va_alist) char *fmt; va_dcl #endif { va_list pvar; va_start(pvar, fmt); if (opts & OPT_DEBUG) vprintf(fmt, pvar); va_end(pvar); } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: extras.c,v 1.12 2002/07/13 12:06:49 darrenr Exp $ */ #include "ipf.h" /* * deal with extra bits on end of the line */ int extras(cp, fr, linenum) char ***cp; struct frentry *fr; int linenum; { u_short secmsk; u_long opts; int notopt; opts = 0; secmsk = 0; notopt = 0; (*cp)++; if (!**cp) return -1; while (**cp) { if (!strcasecmp(**cp, "not") || !strcasecmp(**cp, "no")) { notopt = 1; (*cp)++; continue; } else if (!strncasecmp(**cp, "ipopt", 5)) { if (!notopt) fr->fr_flx |= FI_OPTIONS; fr->fr_mflx |= FI_OPTIONS; goto nextopt; } else if (!strcasecmp(**cp, "lowttl")) { if (!notopt) fr->fr_flx |= FI_LOWTTL; fr->fr_mflx |= FI_LOWTTL; goto nextopt; } else if (!strcasecmp(**cp, "bad-src")) { if (!notopt) fr->fr_flx |= FI_BADSRC; fr->fr_mflx |= FI_BADSRC; goto nextopt; } else if (!strncasecmp(**cp, "mbcast", 6)) { if (!notopt) fr->fr_flx |= FI_MBCAST; fr->fr_mflx |= FI_MBCAST; goto nextopt; } else if (!strncasecmp(**cp, "nat", 3)) { if (!notopt) fr->fr_flx |= FI_NATED; fr->fr_mflx |= FI_NATED; goto nextopt; } else if (!strncasecmp(**cp, "frag", 4)) { if (!notopt) fr->fr_flx |= FI_FRAG; fr->fr_mflx |= FI_FRAG; goto nextopt; } else if (!strncasecmp(**cp, "opt", 3)) { if (!*(*cp + 1)) { fprintf(stderr, "%d: opt missing arguements\n", linenum); return -1; } (*cp)++; if (!(opts = optname(cp, &secmsk, linenum))) return -1; if (notopt) { if (!secmsk) { fr->fr_optmask |= opts; } else { fr->fr_optmask |= (opts & ~0x0100); fr->fr_secmask |= secmsk; } fr->fr_secbits &= ~secmsk; fr->fr_optbits &= ~opts; } else { fr->fr_optmask |= opts; fr->fr_secmask |= secmsk; fr->fr_optbits |= opts; fr->fr_secbits |= secmsk; } } else if (!strncasecmp(**cp, "short", 5)) { if (fr->fr_tcpf) { fprintf(stderr, "%d: short cannot be used with TCP flags\n", linenum); return -1; } if (!notopt) fr->fr_flx |= FI_SHORT; fr->fr_mflx |= FI_SHORT; goto nextopt; } else return -1; nextopt: notopt = 0; opts = 0; secmsk = 0; (*cp)++; } return 0; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: facpri.c,v 1.6 2003/12/01 01:59:43 darrenr Exp $ */ #include #include #include #include #if !defined(__SVR4) && !defined(__svr4__) #include #endif #include #include #include #include #include "facpri.h" #if !defined(lint) static const char rcsid[] = "@(#)$Id: facpri.c,v 1.6 2003/12/01 01:59:43 darrenr Exp $"; #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 < 24) { 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 priority 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; } /* * Copyright (C) 1999-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: facpri.h,v 1.3 2001/06/09 17:19:50 darrenr Exp $ */ #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__ */ /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: fill6bits.c,v 1.5 2002/03/27 15:09:57 darrenr Exp $ */ #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)); } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: flags.c,v 1.4 2002/11/02 07:16:36 darrenr Exp $ */ #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 }; /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: genmask.c,v 1.7 2003/11/11 13:40:15 darrenr Exp $ */ #include "ipf.h" int genmask(msk, mskp) char *msk; u_32_t *mskp; { char *endptr = 0L; int bits; if (strchr(msk, '.') || strchr(msk, 'x') || strchr(msk, ':')) { /* possibly of the form xxx.xxx.xxx.xxx * or 0xYYYYYYYY */ #ifdef USE_INET6 if (use_inet6) { if (inet_pton(AF_INET6, msk, mskp) != 1) return -1; } else #endif if (inet_aton(msk, (struct in_addr *)mskp) == 0) return -1; } else { /* * set x most significant bits */ bits = (int)strtol(msk, &endptr, 0); #ifdef USE_INET6 if ((*endptr != '\0') || ((bits > 32) && !use_inet6) || (bits < 0) || ((bits > 128) && use_inet6)) #else if (*endptr != '\0' || bits > 32 || bits < 0) #endif return -1; #ifdef USE_INET6 if (use_inet6) fill6bits(bits, mskp); else #endif if (bits == 0) *mskp = 0; else *mskp = htonl(0xffffffff << (32 - bits)); } return 0; } /* * Copyright (C) 1993-2005 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" int gethost(name, hostp, use_inet6) char *name; i6addr_t *hostp; int use_inet6; { struct addrinfo hints, *ai; struct netent *n; int error; if (!strcmp(name, "test.host.dots")) { hostp->in4.s_addr = htonl(0xfedcba98); return 0; } if (!strcmp(name, "")) name = thishost; bzero(&hints, sizeof (hints)); if (use_inet6 == 0) hints.ai_family = AF_INET; else hints.ai_family = AF_INET6; error = getaddrinfo(name, NULL, &hints, &ai); if ((error == 0) && (ai != NULL) && (ai->ai_addr != NULL)) { switch (ai->ai_family) { case AF_INET: hostp->in4 = ((struct sockaddr_in *) ai->ai_addr)->sin_addr; break; case AF_INET6: hostp->in6 = ((struct sockaddr_in6 *) ai->ai_addr)->sin6_addr; break; default: break; } freeaddrinfo(ai); return 0; } if (ai != NULL) freeaddrinfo(ai); if (use_inet6 == 0) { n = getnetbyname(name); if (n != NULL) { hostp->in4.s_addr = htonl(n->n_net); return 0; } } return -1; } /* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #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. * * The same code is used to run in two different environments: in ipfstat * and in ipftest. In ipftest, kmemcpy is wrapper for bcopy but in ipfstat, * it is used as an interface to libkvm. */ char *getifname(ptr) struct ifnet *ptr; { # ifdef SOLARIS # include # include # endif # ifdef __hpux # include "compat.h" # endif # if defined(NetBSD) && (NetBSD >= 199905) && (NetBSD < 1991011) || \ defined(__OpenBSD__) || \ (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) #else char buf[32]; int len; # endif struct ifnet netif; #define SOLARIS_PFHOOKS 1 # ifdef SOLARIS_PFHOOKS if ((opts & OPT_DONOTHING) == 0) return "@"; # endif 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 } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: getline.c,v 1.3 2001/06/09 17:09:24 darrenr Exp $ */ #include #if !defined(__SVR4) && !defined(__GNUC__) #include #endif #include #include "ipf.h" /* * Similar to fgets(3) but can handle '\\' and NL is converted to NUL. * Returns NULL if error occured, EOF encounterd or input line is too long. */ char * getaline(char *str, size_t size, FILE *file, int *linenum) { char *p; int s, len; do { for (p = str, s = size; ; p += (len - 1), s -= (len - 1)) { /* * if an error occured, EOF was encounterd, or there * was no room to put NUL, return NULL. */ if (fgets(p, s, file) == NULL) return (NULL); len = strlen(p); if (p[len - 1] != '\n') { p[len] = '\0'; break; } (*linenum)++; p[len - 1] = '\0'; if (len < 2 || p[len - 2] != '\\') break; else /* * Convert '\\' to a space so words don't * run together */ p[len - 2] = ' '; } } while (*str == '\0'); return (str); } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #include "kmem.h" #if !defined(lint) static const char rcsid[] = "@(#)$Id: getnattype.c,v 1.3 2004/01/17 17:26:07 darrenr Exp $"; #endif /* * Get a nat filter type given its kernel address. */ char *getnattype(nat, alive) nat_t *nat; int alive; { static char unknownbuf[20]; ipnat_t *ipn, ipnatbuff; char *which; int type; if (!nat) return "???"; if (alive) { type = nat->nat_redir; } else { ipn = nat->nat_ptr; if (kmemcpy((char *)&ipnatbuff, (long)ipn, sizeof(ipnatbuff))) return "!!!"; type = ipnatbuff.in_redir; } switch (type) { case NAT_MAP : which = "MAP"; break; case NAT_MAPBLK : which = "MAP-BLOCK"; break; case NAT_REDIRECT : which = "RDR"; break; case NAT_BIMAP : which = "BIMAP"; break; default : sprintf(unknownbuf, "unknown(%04x)", type & 0xffffffff); which = unknownbuf; break; } return which; } /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ #include "ipf.h" int getport(fr, name, port) frentry_t *fr; char *name; u_short *port; { struct protoent *p; struct servent *s; u_short p1; if (fr == NULL || fr->fr_type != FR_T_IPF) { s = getservbyname(name, NULL); if (s != NULL) { *port = s->s_port; return 0; } return -1; } 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; } /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ #include #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; } /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ #include "ipf.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 */ if (!strcasecmp(name, "ip")) return 0; #endif p = getprotobyname(name); if (p != NULL) return p->p_proto; return -1; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" char *getsumd(sum) u_32_t sum; { static char sumdbuf[17]; sprintf(sumdbuf, "%#0x", sum); return sumdbuf; } /* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" char *hostname(v, ip) int v; void *ip; { static char hostbuf[MAXHOSTNAMELEN+1]; struct hostent *hp; struct in_addr ipa; struct netent *np; if (v == 4) { ipa.s_addr = *(u_32_t *)ip; if (ipa.s_addr == htonl(0xfedcba98)) return "test.host.dots"; } if ((opts & OPT_NORESOLVE) == 0) { if (v == 4) { 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 (v == 4) { 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 } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: icmpcode.c,v 1.7.2.1 2004/12/09 19:41:20 darrenr Exp $ */ #include #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 }; /* * Return the number for the associated ICMP unreachable code. */ int icmpcode(str) char *str; { char *s; int i, len; if ((s = strrchr(str, ')'))) *s = '\0'; if (ISDIGIT(*str)) { if (!ratoi(str, &i, 0, 255)) return -1; else return i; } len = strlen(str); for (i = 0; icmpcodes[i]; i++) if (!strncasecmp(str, icmpcodes[i], MIN(len, strlen(icmpcodes[i])) )) return i; return -1; } /* * ++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 #include #include #include #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 /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: initparse.c,v 1.6 2002/01/28 06:50:46 darrenr Exp $ */ #include "ipf.h" char thishost[MAXHOSTNAMELEN]; void initparse __P((void)) { gethostname(thishost, sizeof(thishost)); thishost[sizeof(thishost) - 1] = '\0'; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: ionames.c,v 1.7 2002/01/28 06:50:46 darrenr Exp $ */ #include "ipf.h" struct ipopt_names ionames[] ={ { IPOPT_NOP, 0x000001, 1, "nop" }, /* RFC791 */ { IPOPT_RR, 0x000002, 7, "rr" }, /* 1 route */ { IPOPT_ZSU, 0x000004, 3, "zsu" }, /* size ?? */ { IPOPT_MTUP, 0x000008, 3, "mtup" }, /* RFC1191 */ { IPOPT_MTUR, 0x000010, 3, "mtur" }, /* RFC1191 */ { IPOPT_ENCODE, 0x000020, 3, "encode" }, /* size ?? */ { IPOPT_TS, 0x000040, 8, "ts" }, /* 1 TS */ { IPOPT_TR, 0x000080, 3, "tr" }, /* RFC1393 */ { IPOPT_SECURITY,0x000100, 11, "sec" }, /* RFC1108 */ { IPOPT_SECURITY,0x000100, 11, "sec-class" }, /* RFC1108 */ { IPOPT_LSRR, 0x000200, 7, "lsrr" }, /* 1 route */ { IPOPT_E_SEC, 0x000400, 3, "e-sec" }, /* RFC1108 */ { IPOPT_CIPSO, 0x000800, 3, "cipso" }, /* size ?? */ { IPOPT_SATID, 0x001000, 4, "satid" }, /* RFC791 */ { IPOPT_SSRR, 0x002000, 7, "ssrr" }, /* 1 route */ { IPOPT_ADDEXT, 0x004000, 3, "addext" }, /* IPv7 ?? */ { IPOPT_VISA, 0x008000, 3, "visa" }, /* size ?? */ { IPOPT_IMITD, 0x010000, 3, "imitd" }, /* size ?? */ { IPOPT_EIP, 0x020000, 3, "eip" }, /* RFC1385 */ { IPOPT_FINN, 0x040000, 3, "finn" }, /* size ?? */ { IPOPT_DPS, 0x080000, 3, "dps" }, /* size ?? */ { IPOPT_SDB, 0x100000, 3, "sdb" }, /* size ?? */ { IPOPT_NSAPA, 0x200000, 3, "nsapa" }, /* size ?? */ { IPOPT_RTRALRT,0x400000, 3, "rtralrt" }, /* RFC2113 */ { IPOPT_UMP, 0x800000, 3, "ump" }, /* size ?? */ { 0, 0, 0, (char *)NULL } /* must be last */ }; /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ #include "ipf.h" #include "netinet/ipl.h" #include 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) { perror("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) { perror("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) { perror("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); } } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: ipft_ef.c,v 1.14 2004/01/08 13:34:31 darrenr Exp $ */ /* icmp type lnth proto source destination src port dst port etherfind -n 60 tcp 128.250.20.20 128.250.133.13 2419 telnet etherfind -n -t 0.32 91 04 131.170.1.10 128.250.133.13 0.33 566 udp 128.250.37.155 128.250.133.3 901 901 */ #include "ipf.h" #include "ipt.h" #ifndef linux #include #endif #include #if !defined(lint) static const char sccsid[] = "@(#)ipft_ef.c 1.6 2/4/96 (C)1995 Darren Reed"; static const char rcsid[] = "@(#)$Id: ipft_ef.c,v 1.14 2004/01/08 13:34:31 darrenr Exp $"; #endif static int etherf_open __P((char *)); static int etherf_close __P((void)); static int etherf_readip __P((char *, int, char **, int *)); struct ipread etherf = { etherf_open, etherf_close, etherf_readip, 0 }; static FILE *efp = NULL; static int efd = -1; static int etherf_open(fname) char *fname; { if (efd != -1) return efd; if (!strcmp(fname, "-")) { efd = 0; efp = stdin; } else { efd = open(fname, O_RDONLY); efp = fdopen(efd, "r"); } return efd; } static int etherf_close() { return close(efd); } static int etherf_readip(buf, cnt, ifn, dir) char *buf, **ifn; int cnt, *dir; { struct tcpiphdr pkt; ip_t *ip = (ip_t *)&pkt; char src[16], dst[16], sprt[16], dprt[16]; char lbuf[128], len[8], prot[8], time[8], *s; int slen, extra = 0, i; if (!fgets(lbuf, sizeof(lbuf) - 1, efp)) return 0; if ((s = strchr(lbuf, '\n'))) *s = '\0'; lbuf[sizeof(lbuf)-1] = '\0'; bzero(&pkt, sizeof(pkt)); if (sscanf(lbuf, "%7s %7s %15s %15s %15s %15s", len, prot, src, dst, sprt, dprt) != 6) if (sscanf(lbuf, "%7s %7s %7s %15s %15s %15s %15s", time, len, prot, src, dst, sprt, dprt) != 7) return -1; ip->ip_p = getproto(prot); switch (ip->ip_p) { case IPPROTO_TCP : case IPPROTO_UDP : s = strtok(NULL, " :"); ip->ip_len += atoi(s); if (ip->ip_p == IPPROTO_TCP) extra = sizeof(struct tcphdr); else if (ip->ip_p == IPPROTO_UDP) extra = sizeof(struct udphdr); break; #ifdef IGMP case IPPROTO_IGMP : extra = sizeof(struct igmp); break; #endif case IPPROTO_ICMP : extra = sizeof(struct icmp); break; default : break; } (void) inet_aton(src, &ip->ip_src); (void) inet_aton(dst, &ip->ip_dst); ip->ip_len = atoi(len); IP_HL_A(ip, sizeof(ip_t)); slen = IP_HL(ip) + extra; i = MIN(cnt, slen); bcopy((char *)&pkt, buf, i); return i; } /* * Copyright (C) 1995-2001 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: ipft_hx.c,v 1.11.4.1 2004/12/09 19:41:20 darrenr Exp $"; #endif #include #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((char *, int, 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(buf, cnt, ifn, dir) char *buf, **ifn; int cnt, *dir; { register char *s, *t, *u; char line[513]; ip_t *ip; /* * 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) return (char *)ip - buf; *s = '\0'; } if ((s = strchr(line, '#'))) *s = '\0'; if (!*line) continue; if (!(opts & OPT_BRIEF)) { 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; } } else s = line; t = (char *)ip; ip = (ip_t *)readhex(s, (char *)ip); if (!(opts & OPT_BRIEF)) { if (opts & OPT_ASCII) { if (t < (char *)ip) putchar('\t'); while (t < (char *)ip) { if (ISPRINT(*t) && ISASCII(*t)) putchar(*t); else putchar('.'); t++; } } putchar('\n'); fflush(stdout); } } 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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: ipft_pc.c,v 1.10 2004/02/07 18:17:40 darrenr Exp $ */ #include "ipf.h" #include "pcap-ipf.h" #include "bpf-ipf.h" #include "ipt.h" #if !defined(lint) static const char rcsid[] = "@(#)$Id: ipft_pc.c,v 1.10 2004/02/07 18:17:40 darrenr Exp $"; #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[] = { { DLT_NULL, 0, 0, 0 }, { DLT_EN10MB, 14, 12, 2 }, { DLT_EN3MB, 0, 0, 0 }, { DLT_AX25, 0, 0, 0 }, { DLT_PRONET, 0, 0, 0 }, { DLT_CHAOS, 0, 0, 0 }, { DLT_IEEE802, 0, 0, 0 }, { DLT_ARCNET, 0, 0, 0 }, { DLT_SLIP, 0, 0, 0 }, { DLT_PPP, 0, 0, 0 }, { DLT_FDDI, 0, 0, 0 }, #ifdef DLT_ATMRFC1483 { DLT_ATMRFC1483, 0, 0, 0 }, #endif { DLT_RAW, 0, 0, 0 }, #ifdef DLT_ENC { DLT_ENC, 0, 0, 0 }, #endif #ifdef DLT_SLIP_BSDOS { DLT_SLIP_BSDOS, 0, 0, 0 }, #endif #ifdef DLT_PPP_BSDOS { DLT_PPP_BSDOS, 0, 0, 0 }, #endif #ifdef DLT_HIPPI { DLT_HIPPI, 0, 0, 0 }, #endif #ifdef DLT_HDLC { DLT_HDLC, 0, 0, 0 }, #endif #ifdef DLT_PPP_SERIAL { DLT_PPP_SERIAL, 4, 4, 0 }, #endif #ifdef DLT_PPP_ETHER { DLT_PPP_ETHER, 8, 8, 0 }, #endif #ifdef DLT_ECONET { DLT_ECONET, 0, 0, 0 }, #endif { -1, -1, -1, -1 } }; static int pcap_open __P((char *)); static int pcap_close __P((void)); static int pcap_readip __P((char *, int, char **, int *)); static void swap_hdr __P((pcaphdr_t *)); static int pcap_read_rec __P((struct pcap_pkthdr *)); static int pfd = -1, swapped = 0; static struct llc *llcp = NULL; struct ipread pcap = { pcap_open, pcap_close, pcap_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 swap_hdr(p) pcaphdr_t *p; { p->pc_v_maj = SWAPSHORT(p->pc_v_maj); p->pc_v_min = SWAPSHORT(p->pc_v_min); p->pc_zone = SWAPLONG(p->pc_zone); p->pc_sigfigs = SWAPLONG(p->pc_sigfigs); p->pc_slen = SWAPLONG(p->pc_slen); p->pc_type = SWAPLONG(p->pc_type); } static int pcap_open(fname) char *fname; { pcaphdr_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.pc_id != TCPDUMP_MAGIC) { if (SWAPLONG(ph.pc_id) != TCPDUMP_MAGIC) { (void) close(fd); return -2; } swapped = 1; swap_hdr(&ph); } if (ph.pc_v_maj != PCAP_VERSION_MAJ) { (void) close(fd); return -2; } for (i = 0; llcs[i].lc_type != -1; i++) if (llcs[i].lc_type == ph.pc_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.pc_id, ph.pc_v_maj, ph.pc_v_min, ph.pc_type, ph.pc_slen); return fd; } static int pcap_close() { return close(pfd); } /* * read in the header (and validate) which should be the first record * in a pcap file. */ static int pcap_read_rec(rec) struct pcap_pkthdr *rec; { int n, p; if (read(pfd, (char *)rec, sizeof(*rec)) != sizeof(*rec)) return -2; if (swapped) { rec->ph_clen = SWAPLONG(rec->ph_clen); rec->ph_len = SWAPLONG(rec->ph_len); rec->ph_ts.tv_sec = SWAPLONG(rec->ph_ts.tv_sec); rec->ph_ts.tv_usec = SWAPLONG(rec->ph_ts.tv_usec); } p = rec->ph_clen; n = MIN(p, rec->ph_len); if (!n || n < 0) return -3; 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 pcap_read(buf, cnt) char *buf; int cnt; { struct pcap_pkthdr rec; static char *bufp = NULL; int i, n; if ((i = pcap_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 pcap_readip(buf, cnt, ifn, dir) char *buf, **ifn; int cnt, *dir; { static char *bufp = NULL; struct pcap_pkthdr rec; struct llc *l; char *s, ty[4]; int i, n; l = llcp; /* do { */ if ((i = pcap_read_rec(&rec)) <= 0) return i; if (!bufp) bufp = malloc(i); else bufp = realloc(bufp, i); s = bufp; if (read(pfd, s, i) != i) return -2; 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); return n; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: ipft_sn.c,v 1.7 2003/02/16 02:32:36 darrenr Exp $ */ /* * Written to comply with the recent RFC 1761 from Sun. */ #include "ipf.h" #include "snoop.h" #include "ipt.h" #if !defined(lint) static const char rcsid[] = "@(#)$Id: ipft_sn.c,v 1.7 2003/02/16 02:32:36 darrenr Exp $"; #endif struct llc { 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[SDL_MAX+1] = { { 0, 0, 0 }, /* SDL_8023 */ { 0, 0, 0 }, /* SDL_8024 */ { 0, 0, 0 }, /* SDL_8025 */ { 0, 0, 0 }, /* SDL_8026 */ { 14, 12, 2 }, /* SDL_ETHER */ { 0, 0, 0 }, /* SDL_HDLC */ { 0, 0, 0 }, /* SDL_CHSYNC */ { 0, 0, 0 }, /* SDL_IBMCC */ { 0, 0, 0 }, /* SDL_FDDI */ { 0, 0, 0 }, /* SDL_OTHER */ }; static int snoop_open __P((char *)); static int snoop_close __P((void)); static int snoop_readip __P((char *, int, char **, int *)); static int sfd = -1, s_type = -1; static int snoop_read_rec __P((struct snooppkt *)); struct ipread snoop = { snoop_open, snoop_close, snoop_readip, 0 }; static int snoop_open(fname) char *fname; { struct snoophdr sh; int fd; int s_v; if (sfd != -1) return sfd; if (!strcmp(fname, "-")) fd = 0; else if ((fd = open(fname, O_RDONLY)) == -1) return -1; if (read(fd, (char *)&sh, sizeof(sh)) != sizeof(sh)) return -2; s_v = (int)ntohl(sh.s_v); s_type = (int)ntohl(sh.s_type); if (s_v != SNOOP_VERSION || s_type < 0 || s_type > SDL_MAX) { (void) close(fd); return -2; } sfd = fd; printf("opened snoop file %s:\n", fname); printf("\tid: %8.8s version: %d type: %d\n", sh.s_id, s_v, s_type); return fd; } static int snoop_close() { return close(sfd); } /* * read in the header (and validate) which should be the first record * in a snoop file. */ static int snoop_read_rec(rec) struct snooppkt *rec; { int n, plen, ilen; if (read(sfd, (char *)rec, sizeof(*rec)) != sizeof(*rec)) return -2; ilen = (int)ntohl(rec->sp_ilen); plen = (int)ntohl(rec->sp_plen); if (ilen > plen || plen < sizeof(*rec)) return -2; plen -= sizeof(*rec); n = MIN(plen, ilen); if (!n || n < 0) return -3; return plen; } #ifdef notyet /* * read an entire snoop packet record. only the data part is copied into * the available buffer, with the number of bytes copied returned. */ static int snoop_read(buf, cnt) char *buf; int cnt; { struct snooppkt rec; static char *bufp = NULL; int i, n; if ((i = snoop_read_rec(&rec)) <= 0) return i; if (!bufp) bufp = malloc(i); else bufp = realloc(bufp, i); if (read(sfd, 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 snoop_readip(buf, cnt, ifn, dir) char *buf, **ifn; int cnt, *dir; { static char *bufp = NULL; struct snooppkt rec; struct llc *l; char ty[4], *s; int i, n; do { if ((i = snoop_read_rec(&rec)) <= 0) return i; if (!bufp) bufp = malloc(i); else bufp = realloc(bufp, i); s = bufp; if (read(sfd, s, i) != i) return -2; l = &llcs[s_type]; i -= l->lc_to; s += l->lc_to; /* * XXX - bogus assumption here on the part of the time field * that it won't be greater than 4 bytes and the 1st two will * have the values 8 and 0 for IP. Should be a table of * these too somewhere. Really only works for SDL_ETHER. */ bcopy(s, ty, l->lc_tl); } while (ty[0] != 0x8 && ty[1] != 0); i -= l->lc_tl; s += l->lc_tl; n = MIN(i, cnt); bcopy(s, buf, n); return n; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: ipft_td.c,v 1.15 2004/01/08 13:34:31 darrenr Exp $ */ /* tcpdump -n 00:05:47.816843 128.231.76.76.3291 > 224.2.252.231.36573: udp 36 (encap) tcpdump -nq 00:33:48.410771 192.73.213.11.1463 > 224.2.248.153.59360: udp 31 (encap) tcpdump -nqt 128.250.133.13.23 > 128.250.20.20.2419: tcp 27 tcpdump -nqtt 123456789.1234567 128.250.133.13.23 > 128.250.20.20.2419: tcp 27 tcpdump -nqte 8:0:20:f:65:f7 0:0:c:1:8a:c5 81: 128.250.133.13.23 > 128.250.20.20.2419: tcp 27 */ #include "ipf.h" #include "ipt.h" #ifndef linux #include #endif #include #if !defined(lint) static const char sccsid[] = "@(#)ipft_td.c 1.8 2/4/96 (C)1995 Darren Reed"; static const char rcsid[] = "@(#)$Id: ipft_td.c,v 1.15 2004/01/08 13:34:31 darrenr Exp $"; #endif static int tcpd_open __P((char *)); static int tcpd_close __P((void)); static int tcpd_readip __P((char *, int, char **, int *)); static int count_dots __P((char *)); struct ipread tcpd = { tcpd_open, tcpd_close, tcpd_readip, 0 }; static FILE *tfp = NULL; static int tfd = -1; static int tcpd_open(fname) char *fname; { if (tfd != -1) return tfd; if (!strcmp(fname, "-")) { tfd = 0; tfp = stdin; } else { tfd = open(fname, O_RDONLY); tfp = fdopen(tfd, "r"); } return tfd; } static int tcpd_close() { (void) fclose(tfp); return close(tfd); } static int count_dots(str) char *str; { int i = 0; while (*str) if (*str++ == '.') i++; return i; } static int tcpd_readip(buf, cnt, ifn, dir) char *buf, **ifn; int cnt, *dir; { struct tcpiphdr pkt; ip_t *ip = (ip_t *)&pkt; char src[32], dst[32], misc[256], time[32], link1[32], link2[32]; char lbuf[160], *s; int n, slen, extra = 0; if (!fgets(lbuf, sizeof(lbuf) - 1, tfp)) return 0; if ((s = strchr(lbuf, '\n'))) *s = '\0'; lbuf[sizeof(lbuf)-1] = '\0'; bzero(&pkt, sizeof(pkt)); if ((n = sscanf(lbuf, "%31s > %31s: %255s", src, dst, misc)) != 3) if ((n = sscanf(lbuf, "%31s %31s > %31s: %255s", time, src, dst, misc)) != 4) if ((n = sscanf(lbuf, "%31s %31s: %31s > %31s: %255s", link1, link2, src, dst, misc)) != 5) { n = sscanf(lbuf, "%31s %31s %31s: %31s > %31s: %255s", time, link1, link2, src, dst, misc); if (n != 6) return -1; } if (count_dots(dst) == 4) { s = strrchr(src, '.'); *s++ = '\0'; (void) inet_aton(src, &ip->ip_src); pkt.ti_sport = htons(atoi(s)); *--s = '.'; s = strrchr(dst, '.'); *s++ = '\0'; (void) inet_aton(src, &ip->ip_dst); pkt.ti_dport = htons(atoi(s)); *--s = '.'; } else { (void) inet_aton(src, &ip->ip_src); (void) inet_aton(src, &ip->ip_dst); } ip->ip_len = sizeof(ip_t); IP_HL_A(ip, sizeof(ip_t)); s = strtok(misc, " :"); ip->ip_p = getproto(s); switch (ip->ip_p) { case IPPROTO_TCP : case IPPROTO_UDP : s = strtok(NULL, " :"); ip->ip_len += atoi(s); if (ip->ip_p == IPPROTO_TCP) extra = sizeof(struct tcphdr); else if (ip->ip_p == IPPROTO_UDP) extra = sizeof(struct udphdr); break; #ifdef IGMP case IPPROTO_IGMP : extra = sizeof(struct igmp); break; #endif case IPPROTO_ICMP : extra = sizeof(struct icmp); break; default : break; } slen = IP_HL(ip) + extra + ip->ip_len; return slen; } /* * Copyright (C) 1995-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #if !defined(lint) static const char sccsid[] = "@(#)ipft_tx.c 1.7 6/5/96 (C) 1993 Darren Reed"; static const char rcsid[] = "@(#)$Id: ipft_tx.c,v 1.15.2.3 2005/06/18 02:41:34 darrenr Exp $"; #endif #include #include "ipf.h" #include "ipt.h" #ifndef linux #include #endif #include extern int opts; static char *tx_proto = ""; static int text_open __P((char *)), text_close __P((void)); static int text_readip __P((char *, int, 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 *)); /* * 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(host, &ipa, 0) == -1) { *resolved = -1; fprintf(stderr, "can't resolve hostname: %s\n", host); return 0; } return ipa.in4_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, *sp2; u_short p1 = 0; if (ISDIGIT(*name)) return (u_short)atoi(name); if (!tx_proto) tx_proto = "tcp/udp"; if (strcasecmp(tx_proto, "tcp/udp")) { sp = getservbyname(name, tx_proto); if (sp) return ntohs(sp->s_port); (void) fprintf(stderr, "unknown service \"%s\".\n", name); return 0; } sp = getservbyname(name, "tcp"); if (sp) p1 = sp->s_port; sp2 = getservbyname(name, "udp"); if (!sp || !sp2) { (void) fprintf(stderr, "unknown tcp/udp service \"%s\".\n", name); return 0; } if (p1 != sp2->s_port) { (void) fprintf(stderr, "%s %d/tcp is a different port to ", name, p1); (void) fprintf(stderr, "%s %d/udp\n", name, sp->s_port); return 0; } return ntohs(p1); } char *tx_icmptypes[] = { "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", "redir", (char *)NULL, (char *)NULL, "echo", "routerad", "routersol", "timex", "paramprob", "timest", "timestrep", "inforeq", "inforep", "maskreq", "maskrep", "END" }; 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(buf, cnt, ifn, dir) char *buf, **ifn; int cnt, *dir; { register char *s; char line[513]; *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_BRIEF)) printf("input: %s\n", line); *ifn = NULL; *dir = 0; if (!parseline(line, (ip_t *)buf, ifn, dir)) #if 0 return sizeof(ip_t) + sizeof(tcphdr_t); #else return sizeof(ip_t); #endif } 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); 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; } *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 (*cpp && ip->ip_p == IPPROTO_TCP) { 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 == 0) abort(); if (tcp->th_flags & TH_URG) tcp->th_urp = htons(1); } else if (*cpp && ip->ip_p == IPPROTO_ICMP) { extern char *tx_icmptypes[]; char **s, *t; int i; for (s = tx_icmptypes, i = 0; !*s || strcmp(*s, "END"); s++, i++) if (*s && !strncasecmp(*cpp, *s, strlen(*s))) { ic->icmp_type = i; if ((t = strchr(*cpp, ','))) ic->icmp_code = atoi(t+1); cpp++; break; } } 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)); } } 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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: ipoptsec.c,v 1.2 2002/01/28 06:50:46 darrenr Exp $ */ #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; 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; } /* * Copyright (C) 1993-2001 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. */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(_AIX51) #include #endif #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 300000 # include #endif #if defined(linux) || defined(__osf__) || defined(__sgi) || defined(__hpux) # include #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: kmem.c,v 1.16.2.2 2005/06/12 07:18:41 darrenr Exp $"; #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) { close(fd); 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; } #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; } #include "ipf.h" #include #include 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_DONOTHING) == 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; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: load_hash.c,v 1.11.2.2 2005/02/01 02:44:05 darrenr Exp $ * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_htable.h" #include "ipfzone.h" static int hashfd = -1; 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 ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) hashfd = open(IPLOOKUP_NAME, O_RDWR); if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) return -1; if (setzone(hashfd) != 0) { close(hashfd); return -1; } for (n = 0, a = list; a != NULL; a = a->ipe_next) n++; 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.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 (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_seed = iphp->iph_seed; iph.iph_table = NULL; iph.iph_ref = 0; if ((opts & OPT_REMOVE) == 0) { if ((*iocfunc)(hashfd, SIOCLOOKUPADDTABLE, &op)) if ((opts & OPT_DONOTHING) == 0) { perror("load_hash:SIOCLOOKUPADDTABLE"); return -1; } } strncpy(op.iplo_name, iph.iph_name, sizeof(op.iplo_name)); strncpy(iphp->iph_name, iph.iph_name, sizeof(op.iplo_name)); if (opts & OPT_VERBOSE) { for (a = list; a != NULL; a = a->ipe_next) { if (a->ipe_family == AF_INET) { a->ipe_addr.in4_addr = ntohl(a->ipe_addr.in4_addr); a->ipe_mask.in4_addr = ntohl(a->ipe_mask.in4_addr); } } 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_table[0] = list; printhash(&iph, bcopywrap, iph.iph_name, opts); free(iph.iph_table); for (a = list; a != NULL; a = a->ipe_next) { if (a->ipe_family == AF_INET) { 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, iocfunc); if ((opts & OPT_REMOVE) != 0) { if ((*iocfunc)(hashfd, SIOCLOOKUPDELTABLE, &op)) if ((opts & OPT_DONOTHING) == 0) { perror("load_hash:SIOCLOOKUPDELTABLE"); return -1; } } return 0; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: load_hashnode.c,v 1.2.4.1 2004/03/06 14:33:28 darrenr Exp $ * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_htable.h" #include "ipfzone.h" static int hashfd = -1; int load_hashnode(unit, name, node, iocfunc) int unit; char *name; iphtent_t *node; ioctlfunc_t iocfunc; { iplookupop_t op; iphtent_t ipe; int err; if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) hashfd = open(IPLOOKUP_NAME, O_RDWR); if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) return -1; if (setzone(hashfd) != 0) { close(hashfd); 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; 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) err = (*iocfunc)(hashfd, SIOCLOOKUPADDNODE, &op); else err = (*iocfunc)(hashfd, SIOCLOOKUPDELNODE, &op); if (err != 0) if (!(opts & OPT_DONOTHING)) { perror("load_hash:SIOCLOOKUP*NODE"); return -1; } return 0; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: load_pool.c,v 1.14.2.2 2005/02/01 02:44:06 darrenr Exp $ * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "ipfzone.h" static int poolfd = -1; 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 ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) poolfd = open(IPLOOKUP_NAME, O_RDWR); if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) return -1; if (setzone(poolfd) != 0) { close(poolfd); 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)); strncpy(pool.ipo_name, plp->ipo_name, sizeof(pool.ipo_name)); if (*plp->ipo_name == '\0') op.iplo_arg |= IPOOL_ANON; if ((opts & OPT_REMOVE) == 0) { if ((*iocfunc)(poolfd, SIOCLOOKUPADDTABLE, &op)) if ((opts & OPT_DONOTHING) == 0) { perror("load_pool:SIOCLOOKUPADDTABLE"); return -1; } } if ((opts & OPT_VERBOSE) != 0) { pool.ipo_list = plp->ipo_list; printpool(&pool, bcopywrap, pool.ipo_name, opts); pool.ipo_list = NULL; } for (a = plp->ipo_list; a != NULL; a = a->ipn_next) load_poolnode(plp->ipo_unit, plp->ipo_name, a, iocfunc); if ((opts & OPT_REMOVE) != 0) { if ((*iocfunc)(poolfd, SIOCLOOKUPDELTABLE, &op)) if ((opts & OPT_DONOTHING) == 0) { perror("load_pool:SIOCLOOKUPDELTABLE"); return -1; } } return 0; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: load_poolnode.c,v 1.3.2.1 2004/03/06 14:33:29 darrenr Exp $ * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "ipfzone.h" static int poolfd = -1; int load_poolnode(role, name, node, iocfunc) int role; char *name; ip_pool_node_t *node; ioctlfunc_t iocfunc; { ip_pool_node_t pn; iplookupop_t op; int err; if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) poolfd = open(IPLOOKUP_NAME, O_RDWR); if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) return -1; if (setzone(poolfd) != 0) { close(poolfd); 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; strncpy(pn.ipn_name, node->ipn_name, sizeof(pn.ipn_name)); if ((opts & OPT_REMOVE) == 0) err = (*iocfunc)(poolfd, SIOCLOOKUPADDNODE, &op); else err = (*iocfunc)(poolfd, SIOCLOOKUPDELNODE, &op); if (err != 0) { if ((opts & OPT_DONOTHING) == 0) { perror("load_pool:SIOCLOOKUP*NODE"); return -1; } } return 0; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: loglevel.c,v 1.5 2001/06/09 17:09:24 darrenr Exp $ */ #include "ipf.h" int loglevel(cpp, facpri, linenum) char **cpp; u_int *facpri; int linenum; { int fac, pri; char *s; fac = 0; pri = 0; if (!*++cpp) { fprintf(stderr, "%d: %s\n", linenum, "missing identifier after level"); return -1; } s = strchr(*cpp, '.'); if (s) { *s++ = '\0'; fac = fac_findname(*cpp); if (fac == -1) { fprintf(stderr, "%d: %s %s\n", linenum, "Unknown facility", *cpp); return -1; } pri = pri_findname(s); if (pri == -1) { fprintf(stderr, "%d: %s %s\n", linenum, "Unknown priority", s); return -1; } } else { pri = pri_findname(*cpp); if (pri == -1) { fprintf(stderr, "%d: %s %s\n", linenum, "Unknown priority", *cpp); return -1; } } *facpri = fac|pri; return 0; } #include "ipf.h" #define EMM_MAGIC 0x9d7adba3 void eMmutex_enter(mtx, file, line) eMmutex_t *mtx; char *file; int line; { 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) eMmutex_t *mtx; { 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) eMmutex_t *mtx; char *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; } void eMmutex_destroy(mtx) eMmutex_t *mtx; { 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(); } memset(mtx, 0xa5, sizeof(*mtx)); } #include "ipf.h" #include #include 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_DONOTHING) == 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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" void nat_setgroupmap(n) ipnat_t *n; { if (n->in_outmsk == n->in_inmsk) n->in_ippip = 1; else if (n->in_flags & IPN_AUTOPORTMAP) { n->in_ippip = ~ntohl(n->in_inmsk); if (n->in_outmsk != 0xffffffff) n->in_ippip /= (~ntohl(n->in_outmsk) + 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_outmsk); n->in_nip = 0; if (!(n->in_ppip = n->in_pmin)) n->in_ppip = 1; n->in_ippip = USABLE_PORTS / n->in_ppip; } } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" int ntomask(v, nbits, ap) int v, nbits; u_32_t *ap; { u_32_t mask; if (nbits < 0) return -1; switch (v) { case 4 : if (nbits > 32 || use_inet6 != 0) return -1; if (nbits == 0) { mask = 0; } else { mask = 0xffffffff; mask <<= (32 - nbits); } *ap = htonl(mask); break; case 6 : if (nbits > 128) return -1; fill6bits(nbits, ap); break; default : return -1; } return 0; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: optname.c,v 1.3 2001/06/09 17:09:24 darrenr Exp $ */ #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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: optprint.c,v 1.6 2002/07/13 15:59:49 darrenr Exp $ */ #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); 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 = ","; } } } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: optprintv6.c,v 1.2 2003/04/30 00:39:39 darrenr Exp $ */ #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 = " v6hdrs "; 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 /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: optvalue.c,v 1.2 2002/01/28 06:50:47 darrenr Exp $ */ #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; } /* * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * 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; /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: portname.c,v 1.7 2003/08/14 14:27:43 darrenr Exp $ */ #include "ipf.h" char *portname(pr, port) int pr, port; { static char buf[32]; struct protoent *p = NULL; struct servent *sv = NULL, *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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * * $Id: portnum.c,v 1.6.4.1 2004/12/09 19:41:22 darrenr Exp $ */ #include #include "ipf.h" /* * find the port number given by the name, either from getservbyname() or * straight atoi(). Return 1 on success, 0 on failure */ int portnum(name, proto, port, linenum) char *name, *proto; u_short *port; int linenum; { struct servent *sp, *sp2; u_short p1 = 0; int i; if (ISDIGIT(*name)) { if (ratoi(name, &i, 0, USHRT_MAX)) { *port = (u_short)i; return 1; } fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name); return 0; } if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) { sp = getservbyname(name, proto); if (sp) { *port = ntohs(sp->s_port); return 1; } fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name); return 0; } sp = getservbyname(name, "tcp"); if (sp) p1 = sp->s_port; sp2 = getservbyname(name, "udp"); if (!sp || !sp2) { fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n", linenum, name); return 0; } if (p1 != sp2->s_port) { fprintf(stderr, "%d: %s %d/tcp is a different port to ", linenum, name, p1); fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port); return 0; } *port = ntohs(p1); return 1; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: ports.c,v 1.9.4.1 2004/12/09 19:41:22 darrenr Exp $ */ #include #include "ipf.h" /* * check for possible presence of the port fields in the line */ int ports(seg, proto, pp, cp, tp, linenum) char ***seg; char *proto; u_short *pp; int *cp; u_short *tp; int linenum; { int comp = -1; if (!*seg || !**seg || !***seg) return 0; if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) { (*seg)++; if (ISALNUM(***seg) && *(*seg + 2)) { if (portnum(**seg, proto, pp, linenum) == 0) return -1; (*seg)++; if (!strcmp(**seg, "<>")) comp = FR_OUTRANGE; else if (!strcmp(**seg, "><")) comp = FR_INRANGE; else { fprintf(stderr, "%d: unknown range operator (%s)\n", linenum, **seg); return -1; } (*seg)++; if (**seg == NULL) { fprintf(stderr, "%d: missing 2nd port value\n", linenum); return -1; } if (portnum(**seg, proto, tp, linenum) == 0) return -1; } else if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq")) comp = FR_EQUAL; else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne")) comp = FR_NEQUAL; else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt")) comp = FR_LESST; else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt")) comp = FR_GREATERT; else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le")) comp = FR_LESSTE; else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge")) comp = FR_GREATERTE; else { fprintf(stderr, "%d: unknown comparator (%s)\n", linenum, **seg); return -1; } if (comp != FR_OUTRANGE && comp != FR_INRANGE) { (*seg)++; if (portnum(**seg, proto, pp, linenum) == 0) return -1; } *cp = comp; (*seg)++; } return 0; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: print_toif.c,v 1.8 2002/01/28 06:50:47 darrenr Exp $ * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" void print_toif(tag, fdp) char *tag; frdest_t *fdp; { printf("%s %s", tag, fdp->fd_ifname); if (opts & OPT_UNDEF) { if (!fdp->fd_ifp) printf("(!)"); } #ifdef USE_INET6 if (use_inet6 && IP6_NOTZERO(&fdp->fd_ip6.in6)) { char ipv6addr[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &fdp->fd_ip6, ipv6addr, sizeof(ipv6addr)); printf(":%s", ipv6addr); } else #endif if (fdp->fd_ip.s_addr) printf(":%s", inet_ntoa(fdp->fd_ip)); putchar(' '); } /* * Copyright (C) 2002-2004 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.1 2008/02/12 16:11:49 darren_r Exp $"; #endif void printactiveaddress(v, fmt, addr, ifname) int v; char *fmt; i6addr_t *addr; char *ifname; { switch (v) { case 4 : printf(fmt, inet_ntoa(addr->in4)); break; #ifdef USE_INET6 case 6 : printaddr(v, FRI_NORMAL, ifname, (u_32_t *)&addr->in6, NULL); break; #endif default : break; } } /* * Copyright (C) 2002-2004 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ #include "ipf.h" #if !defined(lint) static const char rcsid[] = "@(#)$Id: printactivenat.c,v 1.3.2.4 2004/05/11 16:07:32 darrenr Exp $"; #endif void printactivenat(nat, opts, alive) nat_t *nat; int opts, alive; { printf("%s", getnattype(nat, alive)); if (nat->nat_flags & SI_CLONE) printf(" CLONE"); printactiveaddress(nat->nat_v, " %-15s", &nat->nat_inip6, nat->nat_ifnames[0]); if ((nat->nat_flags & IPN_TCPUDP) != 0) printf(" %-5hu", ntohs(nat->nat_inport)); printf(" <- -> "); printactiveaddress(nat->nat_v, "%-15s", &nat->nat_outip6, nat->nat_ifnames[0]); if ((nat->nat_flags & IPN_TCPUDP) != 0) printf(" %-5hu", ntohs(nat->nat_outport)); printf(" ["); printactiveaddress(nat->nat_v, "%s", &nat->nat_oip6, nat->nat_ifnames[0]); if ((nat->nat_flags & IPN_TCPUDP) != 0) printf(" %hu", ntohs(nat->nat_oport)); printf("]"); if (opts & OPT_VERBOSE) { printf("\n\tage %lu use %hu sumd %s/", nat->nat_age, nat->nat_use, getsumd(nat->nat_sumd[0])); printf("%s pr %u bkt %d/%d flags %x\n", getsumd(nat->nat_sumd[1]), nat->nat_p, 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 %qu/%qu pkts %qu/%qu", (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 %ld touched %ld 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'); } /* * Copyright (C) 2005 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * */ #include "ipf.h" void printaddr(v, type, ifname, addr, mask) int v, type; char *ifname; u_32_t *addr, *mask; { char *suffix; switch (type) { case FRI_BROADCAST : suffix = "/bcast"; break; case FRI_DYNAMIC : printf("%s", ifname); printmask(v, 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((i6addr_t *)addr, (i6addr_t *)mask); break; case FRI_NORMAL : printhostmask(v, addr, mask); suffix = NULL; break; default : printf("<%d>", type); printmask(v, mask); suffix = NULL; break; } if (suffix != NULL) { printf("%s/%s", ifname, suffix); } } /* * Copyright (C) 1993-2001 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: printaps.c,v 1.4 2004/01/08 13:34:32 darrenr Exp $"; #endif void printaps(aps, opts) ap_session_t *aps; int opts; { 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); printf("\t\tproto %d flags %#x bytes ", ap.aps_p, ap.aps_flags); #ifdef USE_QUAD_T printf("%qu pkts %qu", (unsigned long long)ap.aps_bytes, (unsigned long long)ap.aps_pkts); #else printf("%lu pkts %lu", ap.aps_bytes, ap.aps_pkts); #endif printf(" data %s size %d\n", ap.aps_data ? "YES" : "NO", ap.aps_psiz); if ((ap.aps_p == 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)"); } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printbuf.c,v 1.5.4.1 2004/12/09 19:41:22 darrenr Exp $ */ #include #include "ipf.h" void printbuf(buf, len, zend) char *buf; int len, zend; { char *s, 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; } } /* * Copyright (C) 2000-2005 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printfr.c,v 1.43.2.12 2005/06/12 07:18:42 darrenr Exp $ * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #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; u_char *t; char *s; int pr; 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"); 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"); } 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_ISSKIP(fp->fr_flags)) printf("skip %u", fp->fr_arg); else { printf("%x", fp->fr_flags); } if (fp->fr_flags & FR_OUTQUE) printf(" out "); else 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_ifname) { printifname("on ", fp->fr_ifname, fp->fr_ifa); if (*fp->fr_ifnames[1] && strcmp(fp->fr_ifnames[1], "*")) printifname(",", fp->fr_ifnames[1], fp->fr_ifas[1]); putchar(' '); } if (*fp->fr_dif.fd_ifname || (fp->fr_flags & FR_DUP)) print_toif("dup-to", &fp->fr_dif); if (*fp->fr_tif.fd_ifname) print_toif("to", &fp->fr_tif); if (*fp->fr_rif.fd_ifname) print_toif("reply-to", &fp->fr_rif); if (fp->fr_flags & FR_FASTROUTE) printf("fastroute "); if ((*fp->fr_ifnames[2] && strcmp(fp->fr_ifnames[2], "*")) || (*fp->fr_ifnames[3] && strcmp(fp->fr_ifnames[3], "*"))) { if (fp->fr_flags & FR_OUTQUE) printf("in-via "); else printf("out-via "); if (*fp->fr_ifnames[2]) { printifname("", fp->fr_ifnames[2], fp->fr_ifas[2]); putchar(' '); if (*fp->fr_ifnames[3]) { printifname(",", fp->fr_ifnames[3], fp->fr_ifas[3]); } } } 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(' '); } } if (type == FR_T_NONE) { printf("all"); } else if (type == FR_T_IPF) { printf("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : ""); printaddr(fp->fr_v, fp->fr_satype, fp->fr_ifname, &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(fp->fr_v, fp->fr_datype, fp->fr_ifname, &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 #ifdef USE_INET6 || fp->fr_proto == IPPROTO_ICMPV6 #endif ) && fp->fr_icmpm) { int type = fp->fr_icmp, code; type = ntohs(fp->fr_icmp); code = type & 0xff; type /= 256; if (type < (sizeof(icmptypes) / sizeof(char *) - 1) && icmptypes[type] && fp->fr_proto == IPPROTO_ICMP) printf(" icmp-type %s", icmptypes[type]); else printf(" icmp-type %d", type); if (ntohs(fp->fr_icmpm) & 0xff) printf(" code %d", code); } if ((fp->fr_proto == IPPROTO_TCP) && (fp->fr_tcpf || fp->fr_tcpfm)) { printf(" flags "); if (fp->fr_tcpf & ~TCPF_ALL) printf("0x%x", fp->fr_tcpf); else for (s = flagset, t = flags; *s; s++, t++) if (fp->fr_tcpf & *t) (void)putchar(*s); if (fp->fr_tcpfm) { (void)putchar('/'); if (fp->fr_tcpfm & ~TCPF_ALL) printf("0x%x", fp->fr_tcpfm); else for (s = flagset, t = flags; *s; s++, t++) if (fp->fr_tcpfm & *t) (void)putchar(*s); } } } else if (type == FR_T_BPFOPC) { fakebpf_t *fb; int i; printf("bpf-v%d { \"", fp->fr_v); 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("\" }"); } else if (type == FR_T_COMPIPF) { ; } else if (type == FR_T_CALLFUNC) { printf("call function at %p", fp->fr_data); } else { printf("[unknown filter type %#x]", fp->fr_type); } 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_v == 4) 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"); } 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_BROADCAST) { fputs(comma, stdout); if (!(fp->fr_flx & FI_BROADCAST)) printf("not "); printf("bcast"); 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_STATE) { fputs(comma, stdout); if (!(fp->fr_flx & FI_STATE)) printf("not "); printf("state"); comma = ","; } } if (fp->fr_flags & FR_KEEPSTATE) { printf(" keep state"); if ((fp->fr_flags & (FR_STSTRICT|FR_NEWISN|FR_NOICMPERR|FR_STATESYNC)) || (fp->fr_statemax != 0) || (fp->fr_age[0] != 0)) { char *comma = ""; printf(" ("); if (fp->fr_statemax != 0) { printf("limit %u", fp->fr_statemax); comma = ","; } if (fp->fr_flags & FR_STSTRICT) { printf("%sstrict", 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[0]) printf(" scan %s", fp->fr_isctag); else printf(" scan *"); } if (*fp->fr_grhead != '\0') printf(" head %s", fp->fr_grhead); if (*fp->fr_group != '\0') printf(" group %s", 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); (void)putchar('\n'); } /* * Copyright (C) 2004 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printfraginfo.c,v 1.1.2.2 2004/03/23 15:15:45 darrenr Exp $ */ #include "ipf.h" #include "kmem.h" void printfraginfo(prefix, ifr) char *prefix; struct ipfr *ifr; { frentry_t fr; fr.fr_flags = 0xffffffff; printf("%s%s -> ", prefix, hostname(4, &ifr->ipfr_src)); if (kmemcpy((char *)&fr, (u_long)ifr->ipfr_rule, sizeof(fr)) == -1) return; printf("%s id %d ttl %d pr %d seen0 %d ifp %p tos %#02x = %#x\n", hostname(4, &ifr->ipfr_dst), ifr->ipfr_id, ifr->ipfr_ttl, ifr->ipfr_p, ifr->ipfr_seen0, ifr->ipfr_ifp, ifr->ipfr_tos, fr.fr_flags); } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #define PRINTF (void)printf #define FPRINTF (void)fprintf iphtable_t *printhash(hp, copyfunc, name, opts) iphtable_t *hp; copyfunc_t copyfunc; char *name; int opts; { iphtent_t *ipep, **table; iphtable_t iph; int i, 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 ((opts & OPT_DEBUG) == 0) { if ((iph.iph_type & IPHASH_ANON) == IPHASH_ANON) PRINTF("# 'anonymous' table\n"); switch (iph.iph_type & ~IPHASH_ANON) { case IPHASH_LOOKUP : PRINTF("table"); break; case IPHASH_GROUPMAP : PRINTF("group-map"); if (iph.iph_flags & FR_INQUE) PRINTF(" in"); else if (iph.iph_flags & FR_OUTQUE) PRINTF(" out"); else PRINTF(" ???"); break; default : PRINTF("%#x", iph.iph_type); break; } PRINTF(" role = "); } else { PRINTF("Hash Table Number: %s", iph.iph_name); if ((iph.iph_type & IPHASH_ANON) == IPHASH_ANON) PRINTF("(anon)"); putchar(' '); PRINTF("Role: "); } switch (iph.iph_unit) { case IPL_LOGNAT : PRINTF("nat"); break; case IPL_LOGIPF : PRINTF("ipf"); break; case IPL_LOGAUTH : PRINTF("auth"); break; case IPL_LOGCOUNT : PRINTF("count"); break; default : PRINTF("#%d", iph.iph_unit); break; } if ((opts & OPT_DEBUG) == 0) { if ((iph.iph_type & ~IPHASH_ANON) == IPHASH_LOOKUP) PRINTF(" type = hash"); PRINTF(" number = %s size = %lu", iph.iph_name, (u_long)iph.iph_size); if (iph.iph_seed != 0) PRINTF(" seed = %lu", iph.iph_seed); putchar('\n'); } else { PRINTF(" Type: "); switch (iph.iph_type & ~IPHASH_ANON) { case IPHASH_LOOKUP : PRINTF("lookup"); break; case IPHASH_GROUPMAP : PRINTF("groupmap Group. %s", iph.iph_name); break; default : break; } putchar('\n'); PRINTF("\t\tSize: %lu\tSeed: %lu", (u_long)iph.iph_size, iph.iph_seed); PRINTF("\tRef. Count: %d\tMasks: %#x\n", iph.iph_ref, iph.iph_masks[3]); } if ((opts & OPT_DEBUG) != 0) { struct in_addr m; for (i = 0; i < 32; i++) { if ((1 << i) & iph.iph_masks[3]) { ntomask(4, i, &m.s_addr); PRINTF("\t\tMask: %s\n", inet_ntoa(m)); } } } 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 (i = 0, printed = 0; i < iph.iph_size; i++) { for (ipep = table[i]; ipep != NULL; ) { ipep = printhashnode(&iph, ipep, copyfunc, opts); printed++; } } if (printed == 0) putchar(';'); free(table); if ((opts & OPT_DEBUG) == 0) PRINTF(" };\n"); return iph.iph_next; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "ipf.h" #include "netinet/ipl.h" #define PRINTF (void)printf #define FPRINTF (void)fprintf iphtable_t *printhash_live(hp, fd, name, opts) iphtable_t *hp; int fd; char *name; int opts; { iphtent_t entry, *top, *node; ipflookupiter_t iter; int i, printed = 0, last; ipfobj_t obj; if ((name != NULL) && strncmp(name, hp->iph_name, FR_GROUPLEN)) return hp->iph_next; printhashdata(hp, opts); 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; top = NULL; while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) { if (entry.ipe_snext == NULL) last = 1; entry.ipe_snext = top; top = malloc(sizeof(*top)); if (top == NULL) break; bcopy(&entry, top, sizeof(entry)); } while (top != NULL) { node = top; (void) printhashnode(hp, node, bcopywrap, opts); top = node->ipe_snext; free(node); printed++; if ((opts & OPT_DEBUG) == 0) putchar(';'); } if (printed == 0) putchar(';'); if ((opts & OPT_DEBUG) == 0) PRINTF(" };\n"); return hp->iph_next; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #define PRINTF (void)printf #define FPRINTF (void)fprintf 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\n"); 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 Number: %s", hp->iph_name); if ((hp->iph_type & IPHASH_ANON) == IPHASH_ANON) PRINTF("(anon)"); putchar(' '); PRINTF("Role: "); } switch (hp->iph_unit) { case IPL_LOGNAT : PRINTF("nat"); break; case IPL_LOGIPF : PRINTF("ipf"); break; case IPL_LOGAUTH : PRINTF("auth"); break; case IPL_LOGCOUNT : PRINTF("count"); break; default : PRINTF("#%d", hp->iph_unit); break; } if ((opts & OPT_DEBUG) == 0) { if ((hp->iph_type & ~IPHASH_ANON) == IPHASH_LOOKUP) PRINTF(" type = hash"); PRINTF(" number = %s size = %lu", 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_masks[0]); } if ((opts & OPT_DEBUG) != 0) { struct in_addr m; int i; for (i = 0; i < 32; i++) { if ((1 << i) & hp->iph_masks[0]) { ntomask(4, i, &m.s_addr); PRINTF("\t\tMask: %s\n", inet_ntoa(m)); } } } } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include "ipf.h" #define PRINTF (void)printf #define FPRINTF (void)fprintf iphtent_t *printhashnode(iph, ipep, copyfunc, opts) iphtable_t *iph; iphtent_t *ipep; copyfunc_t copyfunc; int opts; { iphtent_t ipe; if ((*copyfunc)(ipep, &ipe, sizeof(ipe))) return NULL; if (ipe.ipe_family == AF_INET) { ipe.ipe_addr.in4_addr = htonl(ipe.ipe_addr.in4_addr); ipe.ipe_mask.in4_addr = htonl(ipe.ipe_mask.in4_addr); } if ((opts & OPT_DEBUG) != 0) { #ifdef USE_INET6 char addinfo[INET6_ADDRSTRLEN]; PRINTF("\tAddress: %s", inet_ntop(ipe.ipe_family, (void *)&ipe.ipe_addr.in4, addinfo, sizeof(addinfo))); #else PRINTF("\tAddress: %s", inet_ntoa(ipe.ipe_addr.in4)); #endif #ifdef USE_INET6 if (ipe.ipe_family == AF_INET6) printmask(6, (u_32_t *)&ipe.ipe_mask.in6); else #endif printmask(4, (u_32_t *)&ipe.ipe_mask.in4_addr); #ifdef USE_QUAD_T PRINTF("\tHits %qu\tBytes %qu", ipe.ipe_hits, ipe.ipe_bytes); #else PRINTF("\tHits %lu\tBytes %lu", ipe.ipe_hits, ipe.ipe_bytes); #endif PRINTF("\tRef. Count: %d\tGroup: %s\n", ipe.ipe_ref, ipe.ipe_group); } else { putchar(' '); #ifdef USE_INET6 if (ipe.ipe_family == AF_INET6) printhostmask(6, (u_32_t *)&ipe.ipe_addr.in6, (u_32_t *)&ipe.ipe_mask.in6); else #endif { printip((u_32_t *)&ipe.ipe_addr.in4_addr); printmask(4, (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; } #include "ipf.h" void printhostmap(hmp, hv) hostmap_t *hmp; u_int hv; { printf("%s,", inet_ntoa(hmp->hm_srcip)); printf("%s -> ", inet_ntoa(hmp->hm_dstip)); printf("%s ", inet_ntoa(hmp->hm_mapip)); printf("(use = %d hv = %u)\n", hmp->hm_ref, hv); } /* * Copyright (C) 2000-2005 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printhostmask.c,v 1.8 2002/04/11 15:01:19 darrenr Exp $ * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" void printhostmask(v, addr, mask) int v; u_32_t *addr, *mask; { #ifdef USE_INET6 char ipbuf[INET6_ADDRSTRLEN]; #else struct in_addr ipa; #endif if ((v == 4) && (!*addr) && (!*mask)) printf("any"); else { #ifdef USE_INET6 void *ptr = addr; int af; if (v == 4) af = AF_INET; else if (v == 6) af = AF_INET6; else af = 0; printf("%s", inet_ntop(af, ptr, ipbuf, sizeof(ipbuf))); #else ipa.s_addr = *addr; printf("%s", inet_ntoa(ipa)); #endif if (mask != NULL) printmask(v, mask); } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printifname.c,v 1.2 2002/01/28 06:50:47 darrenr Exp $ * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" void printifname(format, name, ifp) char *format, *name; void *ifp; { printf("%s%s", format, name); if (opts & OPT_UNDEF) { if ((ifp == NULL) && strcmp(name, "-") && strcmp(name, "*")) { printf("(!)"); } } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printip.c,v 1.3 2002/07/13 12:10:27 darrenr Exp $ */ #include "ipf.h" void printip(addr) u_32_t *addr; { struct in_addr ipa; ipa.s_addr = *addr; if (ntohl(ipa.s_addr) < 256) printf("%lu", (u_long)ntohl(ipa.s_addr)); else printf("%s", inet_ntoa(ipa)); } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printlog.c,v 1.6 2002/01/28 06:50:47 darrenr Exp $ */ #include "ipf.h" #include 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 "); if (fp->fr_loglevel & LOG_FACMASK) { s = fac_toname(fp->fr_loglevel); if (s == NULL) s = "!!!"; } else s = ""; u = pri_toname(fp->fr_loglevel); if (u == NULL) u = "!!!"; if (*s) printf("%s.%s", s, u); else printf("%s", u); } } /* * Copyright (C) 2005 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * */ #include "ipf.h" void printlookup(addr, mask) i6addr_t *addr, *mask; { switch (addr->iplookuptype) { case IPLT_POOL : printf("pool/"); break; case IPLT_HASH : printf("hash/"); break; default : printf("lookup(%x)=", addr->iplookuptype); break; } printf("%u", addr->iplookupnum); if (opts & OPT_UNDEF) { if (mask->iplookupptr == NULL) printf("(!)"); } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printmask.c,v 1.5 2002/06/15 04:48:33 darrenr Exp $ * * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" void printmask(v, mask) int v; u_32_t *mask; { struct in_addr ipa; int ones; #ifdef USE_INET6 if (v == 6) printf("/%d", count6bits(mask)); else #endif if ((ones = count4bits(*mask)) == -1) { ipa.s_addr = *mask; printf("/%s", inet_ntoa(ipa)); } else printf("/%d", ones); } /* * Copyright (C) 2002-2005 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #include "kmem.h" #if !defined(lint) static const char rcsid[] = "@(#)$Id: printnat.c,v 1.22.2.9 2005/06/12 07:18:43 darrenr Exp $"; #endif /* * Print out a NAT rule */ void printnat(np, opts) ipnat_t *np; int opts; { struct protoent *pr; int bits, af; char ipbuf[INET6_ADDRSTRLEN]; void *ptr; pr = getprotobynumber(np->in_p); switch (np->in_redir) { case NAT_REDIRECT : printf("rdr"); break; case NAT_MAP : printf("map"); break; case NAT_MAPBLK : printf("map-block"); break; case NAT_BIMAP : printf("bimap"); break; default : fprintf(stderr, "unknown value for in_redir: %#x\n", np->in_redir); break; } printf(" %s", np->in_ifnames[0]); if ((np->in_ifnames[1][0] != '\0') && (strncmp(np->in_ifnames[0], np->in_ifnames[1], LIFNAMSIZ) != 0)) { printf(",%s ", np->in_ifnames[1]); } putchar(' '); if (np->in_flags & IPN_FILTER) { if (np->in_flags & IPN_NOTSRC) printf("! "); printf("from "); if (np->in_redir == NAT_REDIRECT) { printhostmask(np->in_v, (u_32_t *)&np->in_src[0], (u_32_t *)&np->in_src[1]); } else { printhostmask(np->in_v, (u_32_t *)&np->in_in[0], (u_32_t *)&np->in_in[1]); } if (np->in_scmp) printportcmp(np->in_p, &np->in_tuc.ftu_src); if (np->in_flags & IPN_NOTDST) printf(" !"); printf(" to "); if (np->in_redir == NAT_REDIRECT) { printhostmask(np->in_v, (u_32_t *)&np->in_out[0], (u_32_t *)&np->in_out[1]); } else { printhostmask(np->in_v, (u_32_t *)&np->in_src[0], (u_32_t *)&np->in_src[1]); } if (np->in_dcmp) printportcmp(np->in_p, &np->in_tuc.ftu_dst); } if (np->in_v == 4) af = AF_INET; else if (np->in_v == 6) af = AF_INET6; else af = 0; if (np->in_redir == NAT_REDIRECT) { if (!(np->in_flags & IPN_FILTER)) { ptr = (void *)(u_32_t *)&np->in_out[0]; printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf))); printmask(np->in_v, (u_32_t *)&np->in_out[1]); if (np->in_flags & IPN_TCPUDP) { printf(" port %d", ntohs(np->in_pmin)); if (np->in_pmax != np->in_pmin) printf("-%d", ntohs(np->in_pmax)); } } printf(" -> "); ptr = (void *)(u_32_t *)&np->in_in[0]; printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf))); if (np->in_flags & IPN_SPLIT) { printf(","); ptr = (void *)(u_32_t *)&np->in_in[1]; printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf))); } if (((np->in_v == 4) && (np->in_inip == 0)) || ((np->in_v == 6) && IP6_ISZERO(&np->in_in[0]))) printmask(np->in_v, (u_32_t *)&np->in_in[1]); if (np->in_flags & IPN_TCPUDP) { if ((np->in_flags & IPN_FIXEDDPORT) != 0) printf(" port = %d", ntohs(np->in_pnext)); else printf(" port %d", ntohs(np->in_pnext)); } putchar(' '); printproto(pr, np->in_p, 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 != '\0') printf(" proxy %.*s", (int)sizeof (np->in_plabel), np->in_plabel); if (np->in_tag.ipt_tag[0] != '\0') printf(" tag %-.*s", IPFTAG_LEN, np->in_tag.ipt_tag); printf("\n"); if (opts & OPT_DEBUG) printf("\tpmax %u\n", np->in_pmax); } else { if (!(np->in_flags & IPN_FILTER)) { ptr = (void *)(u_32_t *)&np->in_in[0]; printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf))); printmask(np->in_v, (u_32_t *)&np->in_in[1]); } printf(" -> "); if (np->in_flags & IPN_IPRANGE) { printf("range "); ptr = (void *)(u_32_t *)&np->in_out[0]; printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf))); printf("-"); ptr = (void *)(u_32_t *)&np->in_out[1]; printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf))); } else { ptr = (void *)(u_32_t *)&np->in_out[0]; printf("%s", inet_ntop(af, ptr, ipbuf, sizeof (ipbuf))); printmask(np->in_v, (u_32_t *)&np->in_out[1]); } if (*np->in_plabel != '\0') { printf(" proxy port "); if (np->in_dcmp != 0) np->in_dport = htons(np->in_dport); if (np->in_dport != 0) { char *s; s = portname(np->in_p, ntohs(np->in_dport)); if (s != NULL) fputs(s, stdout); else fputs("???", stdout); } printf(" %.*s/", (int)sizeof (np->in_plabel), np->in_plabel); printproto(pr, np->in_p, NULL); } else if (np->in_redir == NAT_MAPBLK) { if ((np->in_pmin == 0) && (np->in_flags & IPN_AUTOPORTMAP)) printf(" ports auto"); else printf(" ports %d", np->in_pmin); if (opts & OPT_DEBUG) printf("\n\tip modulous %d", np->in_pmax); } else if (np->in_pmin || np->in_pmax) { if (np->in_flags & IPN_ICMPQUERY) { printf(" icmpidmap "); } else { printf(" portmap "); } printproto(pr, np->in_p, np); if (np->in_flags & IPN_AUTOPORTMAP) { printf(" auto"); if (opts & OPT_DEBUG) printf(" [%d:%d %d %d]", ntohs(np->in_pmin), ntohs(np->in_pmax), np->in_ippip, np->in_ppip); } else { printf(" %d:%d", ntohs(np->in_pmin), ntohs(np->in_pmax)); } } else if (np->in_flags & IPN_TCPUDP || np->in_p) { putchar(' '); printproto(pr, np->in_p, np); } 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 (np->in_flags & IPN_SEQUENTIAL) printf(" sequential"); printf("\n"); if (opts & OPT_DEBUG) { struct in_addr nip; nip.s_addr = htonl(np->in_nextip.s_addr); printf("\tnextip %s pnext %d\n", inet_ntoa(nip), np->in_pnext); } } if (opts & OPT_DEBUG) { printf("\tspace %lu use %u hits %lu flags %#x proto %d hv %d\n", np->in_space, np->in_use, np->in_hits, np->in_flags, np->in_p, np->in_hv); 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); } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printpacket.c,v 1.12.4.1 2005/02/21 05:09:24 darrenr Exp $ */ #include "ipf.h" #ifndef IP_OFFMASK # define IP_OFFMASK 0x3fff #endif void printpacket(ip) struct ip *ip; { struct tcphdr *tcp; u_short len; u_short off; if (IP_V(ip) == 6) { off = 0; len = ntohs(((u_short *)ip)[2]) + 40; } else { off = ntohs(ip->ip_off); len = ntohs(ip->ip_len); } if ((opts & OPT_HEX) == OPT_HEX) { u_char *s; int i; for (s = (u_char *)ip, i = 0; i < len; i++) { printf("%02x", *s++ & 0xff); if (len - i > 1) { i++; printf("%02x", *s++ & 0xff); } putchar(' '); } putchar('\n'); return; } if (IP_V(ip) == 6) { printpacket6(ip); return; } tcp = (struct tcphdr *)((char *)ip + (IP_HL(ip) << 2)); printf("ip %d(%d) %d", 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'); } #include "ipf.h" /* * This is meant to work without the IPv6 header files being present or * the inet_ntop() library. */ void printpacket6(ip) struct ip *ip; { u_char *buf, p; u_short plen, *addrs; tcphdr_t *tcp; u_32_t flow; buf = (u_char *)ip; 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; printf("ip6/%d %d %#x %d", buf[0] & 0xf, plen, flow, p); printf(" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 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(" %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 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_dport)); putchar('\n'); } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #define PRINTF (void)printf #define FPRINTF (void)fprintf ip_pool_t *printpool(pp, copyfunc, name, opts) ip_pool_t *pp; copyfunc_t copyfunc; char *name; int opts; { ip_pool_node_t *ipnp, *ipnpn, ipn; 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; if ((opts & OPT_DEBUG) == 0) { if ((ipp.ipo_flags & IPOOL_ANON) != 0) PRINTF("# 'anonymous' tree %s\n", ipp.ipo_name); PRINTF("table role = "); } else { PRINTF("Name: %s", ipp.ipo_name); if ((ipp.ipo_flags & IPOOL_ANON) == IPOOL_ANON) PRINTF("(anon)"); putchar(' '); PRINTF("Role: "); } switch (ipp.ipo_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; default : printf("unknown(%d)", ipp.ipo_unit); } if ((opts & OPT_DEBUG) == 0) { PRINTF(" type = tree number = %s\n", ipp.ipo_name); PRINTF("\t{"); } else { putchar(' '); PRINTF("\tReferences: %d\tHits: %lu\n", ipp.ipo_ref, ipp.ipo_hits); PRINTF("\tNodes Starting at %p\n", ipp.ipo_list); } ipnpn = ipp.ipo_list; ipp.ipo_list = NULL; while (ipnpn != NULL) { ipnp = (ip_pool_node_t *)malloc(sizeof(*ipnp)); (*copyfunc)(ipnpn, ipnp, sizeof(ipn)); ipnpn = ipnp->ipn_next; ipnp->ipn_next = ipp.ipo_list; ipp.ipo_list = ipnp; } if (ipp.ipo_list == NULL) { putchar(';'); } else { for (ipnp = ipp.ipo_list; ipnp != NULL; ) { ipnp = printpoolnode(ipnp, opts); if ((opts & OPT_DEBUG) == 0) { putchar(';'); } } } if ((opts & OPT_DEBUG) == 0) PRINTF(" };\n"); return ipp.ipo_next; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "ipf.h" #include "netinet/ipl.h" #define PRINTF (void)printf #define FPRINTF (void)fprintf ip_pool_t *printpool_live(pool, fd, name, opts) ip_pool_t *pool; int fd; char *name; int opts; { ip_pool_node_t entry, *top, *node; ipflookupiter_t iter; int i, printed = 0, last; ipfobj_t obj; if ((name != NULL) && strncmp(name, pool->ipo_name, FR_GROUPLEN)) return pool->ipo_next; printpooldata(pool, opts); 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; top = NULL; while (!last && (ioctl(fd, SIOCLOOKUPITER, &obj) == 0)) { if (entry.ipn_next == NULL) last = 1; entry.ipn_next = top; top = malloc(sizeof(*top)); if (top == NULL) break; bcopy(&entry, top, sizeof(entry)); } while (top != NULL) { node = top; (void) printpoolnode(node, opts); top = node->ipn_next; free(node); printed++; if ((opts & OPT_DEBUG) == 0) putchar(';'); } if (printed == 0) putchar(';'); if ((opts & OPT_DEBUG) == 0) PRINTF(" };\n"); return pool->ipo_next; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #define PRINTF (void)printf #define FPRINTF (void)fprintf 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); PRINTF("table role = "); } else { PRINTF("Name: %s", pool->ipo_name); if ((pool->ipo_flags & IPOOL_ANON) == IPOOL_ANON) PRINTF("(anon)"); putchar(' '); PRINTF("Role: "); } switch (pool->ipo_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; default : PRINTF("unknown(%d)", pool->ipo_unit); } if ((opts & OPT_DEBUG) == 0) { PRINTF(" type = tree number = %s\n", pool->ipo_name); } else { putchar(' '); PRINTF("\tReferences: %d\tHits: %lu\n", pool->ipo_ref, pool->ipo_hits); PRINTF("\tNodes Starting at %p\n", pool->ipo_list); } } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. */ #include "ipf.h" #define PRINTF (void)printf ip_pool_node_t *printpoolnode(np, opts) ip_pool_node_t *np; int opts; { if ((opts & OPT_DEBUG) == 0) PRINTF(" %s", np->ipn_info ? "! " : ""); else PRINTF("\tAddress: %s", np->ipn_info ? "! " : ""); #ifdef USE_INET6 if (np->ipn_addr.adf_family == AF_INET6) printhostmask(6, (u_32_t *)&np->ipn_addr.adf_addr.in6, (u_32_t *)&np->ipn_mask.adf_addr); else #endif { printip((u_32_t *)&np->ipn_addr.adf_addr.in4); printmask(4, (u_32_t *)&np->ipn_mask.adf_addr); } if ((opts & OPT_DEBUG) != 0) #ifdef USE_QUAD_T PRINTF("\t\tHits %qu\t\tBytes %qu\t\tName %s\n", np->ipn_hits, np->ipn_bytes, np->ipn_name); #else PRINTF("\t\tHits %lu\t\tBytes %lu\t\tName %s\n", np->ipn_hits, np->ipn_bytes, np->ipn_name); #endif return np->ipn_next; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: printportcmp.c,v 1.7 2003/02/16 02:31:05 darrenr Exp $ */ #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)); } /* * Copyright (C) 1993-2005 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ #include "ipf.h" #if !defined(lint) static const char rcsid[] = "@(#)$Id: printproto.c,v 1.1.2.1 2005/06/12 07:21:53 darrenr Exp $"; #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 */ else if (np->in_p == 0) printf("ip"); #endif else if (pr != NULL) printf("%s", pr->p_name); else printf("%d", np->in_p); } else { #ifdef _AIX51 if (p == 0) printf("ip"); else #endif if (pr != NULL) printf("%s", pr->p_name); else printf("%d", p); } } /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ #ifdef IPFILTER_SCAN #include #include #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); } } #endif /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ #include "ipf.h" #include "kmem.h" #define PRINTF (void)printf #define FPRINTF (void)fprintf ipstate_t *printstate(sp, opts, now) ipstate_t *sp; int opts; u_long now; { ipstate_t ips; #ifdef IPFILTER_SYNC synclist_t ipsync; #endif if (kmemcpy((char *)&ips, (u_long)sp, sizeof(ips))) return NULL; PRINTF("%s -> ", hostname(ips.is_v, &ips.is_src.in4)); PRINTF("%s pass %#x pr %d state %d/%d bkt %d\n", hostname(ips.is_v, &ips.is_dst.in4), ips.is_pass, ips.is_p, ips.is_state[0], ips.is_state[1], ips.is_hv); PRINTF("\ttag %u ttl %lu", ips.is_tag, ips.is_die - now); if (ips.is_p == IPPROTO_TCP) { PRINTF("\n\t%hu -> %hu %x:%x %hu<<%d:%hu<<%d\n", ntohs(ips.is_sport), ntohs(ips.is_dport), ips.is_send, ips.is_dend, ips.is_maxswin, ips.is_swinscale, ips.is_maxdwin, ips.is_dwinscale); PRINTF("\tcmsk %04x smsk %04x isc %p s0 %08x/%08x\n", ips.is_smsk[0], ips.is_smsk[1], ips.is_isc, ips.is_s0[0], ips.is_s0[1]); PRINTF("\tFWD:ISN inc %x sumd %x\n", ips.is_isninc[0], ips.is_sumd[0]); PRINTF("\tREV:ISN inc %x sumd %x\n", ips.is_isninc[1], ips.is_sumd[1]); #ifdef IPFILTER_SCAN PRINTF("\tsbuf[0] ["); printsbuf(ips.is_sbuf[0]); PRINTF("] sbuf[1] ["); printsbuf(ips.is_sbuf[1]); PRINTF("]\n"); #endif } else if (ips.is_p == IPPROTO_UDP) { PRINTF(" %hu -> %hu\n", ntohs(ips.is_sport), ntohs(ips.is_dport)); } else if (ips.is_p == IPPROTO_GRE) { PRINTF(" call %hx/%hx\n", ntohs(ips.is_gre.gs_call[0]), ntohs(ips.is_gre.gs_call[1])); } else if (ips.is_p == IPPROTO_ICMP #ifdef USE_INET6 || ips.is_p == IPPROTO_ICMPV6 #endif ) PRINTF(" id %hu seq %hu type %d\n", ntohs(ips.is_icmp.ici_id), ntohs(ips.is_icmp.ici_seq), ips.is_icmp.ici_type); #ifdef USE_QUAD_T PRINTF("\tforward: pkts in %qd bytes in %qd pkts out %qd bytes out %qd\n\tbackward: pkts in %qd bytes in %qd pkts out %qd bytes out %qd\n", ips.is_pkts[0], ips.is_bytes[0], ips.is_pkts[1], ips.is_bytes[1], ips.is_pkts[2], ips.is_bytes[2], ips.is_pkts[3], ips.is_bytes[3]); #else PRINTF("\tforward: pkts in %ld bytes in %ld pkts out %ld bytes out %ld\n\tbackward: pkts in %ld bytes in %ld pkts out %ld bytes out %ld\n", ips.is_pkts[0], ips.is_bytes[0], ips.is_pkts[1], ips.is_bytes[1], ips.is_pkts[2], ips.is_bytes[2], ips.is_pkts[3], ips.is_bytes[3]); #endif PRINTF("\t"); /* * Print out bits set in the result code for the state being * kept as they would for a rule. */ if (FR_ISPASS(ips.is_pass)) { PRINTF("pass"); } else if (FR_ISBLOCK(ips.is_pass)) { PRINTF("block"); switch (ips.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 ((ips.is_pass & FR_LOGMASK) == FR_LOG) { PRINTF("log"); if (ips.is_pass & FR_LOGBODY) PRINTF(" body"); if (ips.is_pass & FR_LOGFIRST) PRINTF(" first"); } else if (FR_ISACCOUNT(ips.is_pass)) { PRINTF("count"); } else if (FR_ISPREAUTH(ips.is_pass)) { PRINTF("preauth"); } else if (FR_ISAUTH(ips.is_pass)) PRINTF("auth"); if (ips.is_pass & FR_OUTQUE) PRINTF(" out"); else PRINTF(" in"); if ((ips.is_pass & FR_LOG) != 0) { PRINTF(" log"); if (ips.is_pass & FR_LOGBODY) PRINTF(" body"); if (ips.is_pass & FR_LOGFIRST) PRINTF(" first"); if (ips.is_pass & FR_LOGORBLOCK) PRINTF(" or-block"); } if (ips.is_pass & FR_QUICK) PRINTF(" quick"); if (ips.is_pass & FR_KEEPFRAG) PRINTF(" keep frags"); /* a given; no? */ if (ips.is_pass & FR_KEEPSTATE) { PRINTF(" keep state"); if (ips.is_pass & FR_STATESYNC) PRINTF(" ( sync )"); } PRINTF("\tIPv%d", ips.is_v); PRINTF("\n"); PRINTF("\tpkt_flags & %x(%x) = %x,\t", ips.is_flags & 0xf, ips.is_flags, ips.is_flags >> 4); PRINTF("\tpkt_options & %x = %x, %x = %x \n", ips.is_optmsk[0], ips.is_opt[0], ips.is_optmsk[1], ips.is_opt[1]); PRINTF("\tpkt_security & %x = %x, pkt_auth & %x = %x\n", ips.is_secmsk, ips.is_sec, ips.is_authmsk, ips.is_auth); PRINTF("\tis_flx %#x %#x %#x %#x\n", ips.is_flx[0][0], ips.is_flx[0][1], ips.is_flx[1][0], ips.is_flx[1][1]); PRINTF("\tinterfaces: in %s[%s", getifname(ips.is_ifp[0]), ips.is_ifname[0]); if (opts & OPT_DEBUG) PRINTF("/%p", ips.is_ifp[0]); putchar(']'); PRINTF(",%s[%s", getifname(ips.is_ifp[1]), ips.is_ifname[1]); if (opts & OPT_DEBUG) PRINTF("/%p", ips.is_ifp[1]); putchar(']'); PRINTF(" out %s[%s", getifname(ips.is_ifp[2]), ips.is_ifname[2]); if (opts & OPT_DEBUG) PRINTF("/%p", ips.is_ifp[2]); putchar(']'); PRINTF(",%s[%s", getifname(ips.is_ifp[3]), ips.is_ifname[3]); if (opts & OPT_DEBUG) PRINTF("/%p", ips.is_ifp[3]); PRINTF("]\n"); #ifdef IPFILTER_SYNC if (ips.is_sync != NULL) { if (kmemcpy((char *)&ipsync, (u_long)ips.is_sync, sizeof(ipsync))) { PRINTF("\tSync status: status could not be retrieved\n"); return NULL; } PRINTF("\tSync status: 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("\tSync status: not synchronized\n"); } #endif return ips.is_next; } /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ #include "ipf.h" void printtunable(tup) ipftune_t *tup; { printf("%s\tmin %#lx\tmax %#lx\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); } } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: ratoi.c,v 1.4 2001/06/09 17:09:25 darrenr Exp $ */ #include "ipf.h" int ratoi(ps, pi, min, max) char *ps; int *pi, min, max; { int i; char *pe; i = (int)strtol(ps, &pe, 0); if (*pe != '\0' || i < min || i > max) return 0; *pi = i; return 1; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: remove_hash.c,v 1.1 2003/04/13 06:40:14 darrenr Exp $ */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_htable.h" static int hashfd = -1; int remove_hash(iphp, iocfunc) iphtable_t *iphp; ioctlfunc_t iocfunc; { iplookupop_t op; iphtable_t iph; if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) hashfd = open(IPLOOKUP_NAME, O_RDWR); if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) 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 ((*iocfunc)(hashfd, SIOCLOOKUPDELTABLE, &op)) if ((opts & OPT_DONOTHING) == 0) { perror("remove_hash:SIOCLOOKUPDELTABLE"); return -1; } return 0; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: remove_hashnode.c,v 1.1 2003/04/13 06:40:14 darrenr Exp $ */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_htable.h" static int hashfd = -1; int remove_hashnode(unit, name, node, iocfunc) int unit; char *name; iphtent_t *node; ioctlfunc_t iocfunc; { iplookupop_t op; iphtent_t ipe; if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) hashfd = open(IPLOOKUP_NAME, O_RDWR); if ((hashfd == -1) && ((opts & OPT_DONOTHING) == 0)) 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 ((*iocfunc)(hashfd, SIOCLOOKUPDELNODE, &op)) if (!(opts & OPT_DONOTHING)) { perror("remove_hash:SIOCLOOKUPDELNODE"); return -1; } return 0; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: remove_pool.c,v 1.1 2003/04/13 06:40:14 darrenr Exp $ */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_htable.h" static int poolfd = -1; int remove_pool(poolp, iocfunc) ip_pool_t *poolp; ioctlfunc_t iocfunc; { iplookupop_t op; ip_pool_t pool; if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) poolfd = open(IPLOOKUP_NAME, O_RDWR); if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) 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 ((*iocfunc)(poolfd, SIOCLOOKUPDELTABLE, &op)) if ((opts & OPT_DONOTHING) == 0) { perror("remove_pool:SIOCLOOKUPDELTABLE"); return -1; } return 0; } /* * Copyright (C) 2002 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: remove_poolnode.c,v 1.3 2003/11/22 10:14:36 darrenr Exp $ */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" static int poolfd = -1; 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 ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) poolfd = open(IPLOOKUP_NAME, O_RDWR); if ((poolfd == -1) && ((opts & OPT_DONOTHING) == 0)) 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 ((*iocfunc)(poolfd, SIOCLOOKUPDELNODE, &op)) { if ((opts & OPT_DONOTHING) == 0) { perror("remove_pool:SIOCLOOKUPDELNODE"); return -1; } } return 0; } #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; } #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; } 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; } 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(); } memset(rw, 0xa5, sizeof(*rw)); } /* * Copyright (C) 1993-2001 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: snoop.h,v 2.3 2001/06/09 17:09:23 darrenr Exp $ */ 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__ */ /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: tcpflags.c,v 1.3 2002/11/02 07:18:01 darrenr Exp $ */ #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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: v6ionames.c,v 1.1.4.1 2005/01/02 13:08:49 darrenr Exp $ */ #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" }, { 0, 0, 0, (char *)NULL } }; #endif /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: v6optvalue.c,v 1.1 2003/04/26 04:55:58 darrenr Exp $ */ #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; } /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ #include #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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: verbose.c,v 1.6 2001/06/09 17:09:25 darrenr Exp $ */ #if defined(__STDC__) # include #else # include #endif #include #include "ipt.h" #include "opts.h" #if defined(__STDC__) void verbose(char *fmt, ...) #else void verbose(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); } IP Filter Licence ----------------- /* * Copyright (C) 1993-2003 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, with or without modification, in source and binary * forms, are permitted provided that this notice is preserved in its entirety * and due credit is given to the original author and the contributors. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied, in part or in whole, and put under another distribution licence * [including the GNU Public Licence.] * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. * * I hate legalese, don't you ? */ IP FILTER SOFTWARE # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2013 Nexenta Systems, Inc. All rights reserved. # # Copyright (c) 2012, Joyent Inc. All rights reserved. # # cmd/ipf/tools/Makefile # # include ../../Makefile.cmd include ../../Makefile.cmd.64 include ../Makefile.ipf include ../../Makefile.ctf LICENCE= IPFILTER.LICENCE PROG= ipf ipfs ipmon ipnat ippool ipfstat IPFPROG= ipftest IPF_OBJS= ipf.o ipfcomp.o ipfzone.o ipf_y.o ipf_l.o IPFS_OBJS= ipfs.o ipfzone.o IPFSTAT_OBJS= ipfstat.o ipfzone.o IPMON_OBJS= ipmon.o ipfzone.o ipmon_y.o ipmon_l.o IPNAT_OBJS= ipnat.o ipfzone.o ipnat_y.o ipnat_l.o IPPOOL_OBJS= ippool.o ipfzone.o ippool_y.o ippool_l.o IPFTEST_OBJS= ipftest.o ipfzone.o \ ip_fil.o ip_state.o ip_compat.o \ ip_frag.o ip_nat.o ip_nat6.o fil.o \ ip_htable.o ip_lookup.o \ ip_proxy.o ip_auth.o ip_log.o \ ipf_y.o ipf_l.o \ ipnat_y.o ipnat_l.o \ ippool_y.o ippool_l.o \ ip_pool.o radix.o USRLIBIPF= $(ROOTLIB)/ipf USRLIBIPFLICENCE= $(LICENCE:%=$(USRLIBIPF)/%) $(USRLIBIPFLICENCE): FILEMODE= 0644 CFLAGS += -D_ELF64 LDLIBS += -L ../lib -lipf LDLIBS += $(LIBBPF) LDFLAGS += $(MAPFILE.NGB:%=-Wl,-M%) CPPFLAGS += -I. -DIPFILTER_LOOKUP -DIPFILTER_LOG ipfstat.o : CPPFLAGS += -DSTATETOP ipfstat : LDLIBS += -lcurses ipf : LDLIBS += -lsocket -lnsl ipf : OBJS += $(IPF_OBJS) ipfs : OBJS += $(IPFS_OBJS) ipftest : LDLIBS += -lsocket -lnsl -lmd ipftest : OBJS += $(IPFTEST_OBJS) ipfstat : LDLIBS += -lsocket -lnsl -lkvm -lelf ipfstat : OBJS += $(IPFSTAT_OBJS) ipmon : LDLIBS += -lsocket -lnsl ipmon : OBJS += $(IPMON_OBJS) ipnat : LDLIBS += -lsocket -lnsl -lkvm -lelf ipnat : OBJS += $(IPNAT_OBJS) ippool : LDLIBS += -lsocket -lnsl -lkvm -lelf ippool : OBJS += $(IPPOOL_OBJS) # because of labels from yacc ipf_y.o : CERRWARN += -Wno-unused-label ipmon_y.o : CERRWARN += -Wno-unused-label ipnat_y.o : CERRWARN += -Wno-unused-label ippool_y.o : CERRWARN += -Wno-unused-label CLEANFILES += $(IPF_OBJS) $(IPFS_OBJS) $(IPFTEST_OBJS) $(IPFSTAT_OBJS) CLEANFILES += $(IPMON_OBJS) $(IPNAT_OBJS) $(IPPOOL_OBJS) CLOBBERFILES += $(IPFPROG) ROOTIPF= $(ROOTLIB)/ipf ROOTIPFPROG= $(IPFPROG:%=$(ROOTIPF)/%) .KEEP_STATE: all: $(PROG) $(IPFPROG) install: all install_local $(ROOTIPF) $(ROOTUSRSBINPROG) $(ROOTIPFPROG) $(USRLIBIPF): $(INS.dir) $(USRLIBIPF)/% : % $(INS.file) $(ROOTIPF)/%: % $(INS.file) ipf: $(IPF_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) -o ipf $(IPF_OBJS) $(LDLIBS) $(POST_PROCESS) ipf_y.o: ipf_y.c $(COMMONIPF)/netinet/ip_fil.h $(COMMONIPF)/ipf.h \ ipf_y.c ipf_l.h ipf_y.c ipf_y.h: ipf_y.y $(YACC) -d -b ipf ipf_y.y sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.c/' \ ipf.tab.c > ipf_y.c sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' \ ipf.tab.h > ipf_y.h CLEANFILES += ipf.tab.c ipf.tab.h CLEANFILES += ipf_y.c ipf_y.h ipf_l.o: ipf_l.c $(COMMONIPF)/netinet/ip_fil.h $(COMMONIPF)/ipf.h \ ipf_y.h ipf_l.h ipf_l.c: lexer.c $(COMMONIPF)/ipf.h $(COMMONIPF)/netinet/ip_fil.h sed -e 's/yy/ipf_yy/g' -e 's/y.tab.h/ipf_y.h/' \ -e 's/lexer.h/ipf_l.h/' lexer.c > $@ ipf_l.h: lexer.h sed -e 's/yy/ipf_yy/g' lexer.h > $@ CLEANFILES += ipf_l.c ipf_l.h ipfs: $(IPFS_OBJS) $(LINK.c) -o ipfs $(IPFS_OBJS) $(LDLIBS) $(POST_PROCESS) ipfstat: $(IPFSTAT_OBJS) $(MAPFILE.NGB) $(LINK.c) -o ipfstat $(IPFSTAT_OBJS) $(LDLIBS) $(POST_PROCESS) ipmon: $(IPMON_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) -o ipmon $(IPMON_OBJS) $(LDLIBS) $(POST_PROCESS) ipmon_y.o: ipmon_y.c $(COMMONIPF)/ipmon.h ipmon_y.h ipmon_l.h ipmon_y.c ipmon_y.h: ipmon_y.y $(YACC) -d -b ipmon ipmon_y.y sed -e 's/yy/ipmon_yy/g' \ -e 's/extern [a-z]* .*();//' \ -e 's/^\(static [a-z]* .*\)();/\1(void);/' \ ipmon.tab.c > ipmon_y.c sed -e 's/yy/ipmon_yy/g' -e 's/y.tab.h/ipmon_y.h/' \ ipmon.tab.h > ipmon_y.h CLEANFILES += ipmon.tab.c ipmon.tab.h CLEANFILES += ipmon_y.c ipmon_y.h ipmon_l.o: ipmon_l.c $(COMMONIPF)/ipmon.h ipmon_y.h ipmon_l.h ipmon_l.c: lexer.c $(COMMONIPF)/ipmon.h sed -e 's/yy/ipmon_yy/g' -e 's/y.tab.h/ipmon_y.h/' \ -e 's/lexer.h/ipmon_l.h/' lexer.c > $@ ipmon_l.h: lexer.h sed -e 's/yy/ipmon_yy/g' lexer.h > $@ CLEANFILES += ipmon_l.c ipmon_l.h ipnat: $(IPNAT_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) -o ipnat $(IPNAT_OBJS) $(LDLIBS) $(POST_PROCESS) ipnat_y.o: ipnat_y.c $(COMMONIPF)/netinet/ip_nat.h ipnat_y.h ipnat_l.h ipnat_y.c ipnat_y.h: ipnat_y.y $(YACC) -d -b ipnat ipnat_y.y sed -e 's/yy/ipnat_yy/g' \ -e 's/extern [a-z]* .*();//' \ -e 's/^\(static [a-z]* .*\)();/\1(void);/' \ ipnat.tab.c > ipnat_y.c sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \ ipnat.tab.h > ipnat_y.h CLEANFILES += ipnat.tab.c ipnat.tab.h CLEANFILES += ipnat_y.c ipnat_y.h ipnat_l.o: ipnat_l.c $(COMMONIPF)/netinet/ip_nat.h ipnat_l.h ipnat_l.c: lexer.c $(COMMONIPF)/netinet/ip_nat.h sed -e 's/yy/ipnat_yy/g' -e 's/y.tab.h/ipnat_y.h/' \ -e 's/lexer.h/ipnat_l.h/' lexer.c > $@ ipnat_l.h: lexer.h sed -e 's/yy/ipnat_yy/g' lexer.h > $@ CLEANFILES += ipnat_l.c ipnat_l.h ippool: $(IPPOOL_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) -o ippool $(IPPOOL_OBJS) $(LDLIBS) $(POST_PROCESS) ippool_y.o: ippool_y.c $(COMMONIPF)/netinet/ip_pool.h ippool_y.h ippool_l.h ippool_y.c ippool_y.h: ippool_y.y $(YACC) -d -b ippool ippool_y.y sed -e 's/yy/ippool_yy/g' \ -e 's/extern [a-z]* .*();//' \ -e 's/^\(static [a-z]* .*\)();/\1(void);/' \ ippool.tab.c > ippool_y.c sed -e 's/yy/ippool_yy/g' -e 's/y.tab.h/ippool_y.h/' \ ippool.tab.h > ippool_y.h CLEANFILES += ippool.tab.c ippool.tab.h CLEANFILES += ippool_y.c ippool_y.h ippool_l.o: ippool_l.c $(COMMONIPF)/netinet/ip_pool.h ippool_l.h ippool_l.c: lexer.c $(COMMONIPF)/netinet/ip_pool.h sed -e 's/yy/ippool_yy/g' -e 's/y.tab.h/ippool_y.h/' \ -e 's/lexer.h/ippool_l.h/' lexer.c > $@ ippool_l.h: lexer.h sed -e 's/yy/ippool_yy/g' lexer.h > $@ CLEANFILES += ippool_l.c ippool_l.h ipftest: $(IPFTEST_OBJS) $(LIBIPF) $(MAPFILE.NGB) $(LINK.c) $(ZIGNORE) -o ipftest $(IPFTEST_OBJS) $(LDLIBS) $(POST_PROCESS) clean: -$(RM) $(CLEANFILES) # # NOTE: all rules must use relative paths otherwise absolute paths will be # embedded into the binaries making them false positives and # reported by wsdiff # %.o: ../../../uts/common/inet/ipf/%.c $(COMPILE.c) $< $(POST_PROCESS_O) %.o: ../../../common/net/patricia/%.c $(COMPILE.c) $< $(POST_PROCESS_O) install_local: $(USRLIBIPF) $(USRLIBIPFLICENCE) include ../../Makefile.targ /* * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifdef SOLARIS #undef SOLARIS #endif #if (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #define SOLARIS (1) #else #define SOLARIS (0) #endif #include #if defined(__FreeBSD__) && !defined(__FreeBSD_version) # if defined(IPFILTER_LKM) # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif # endif #endif #include #if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL) # include #endif #include #define _KERNEL #define KERNEL #ifdef __OpenBSD__ struct file; #endif #include #undef _KERNEL #undef KERNEL #include #include #ifdef __sgi # include #endif #include #if !defined(SOLARIS) # if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include # else # include # endif #else # include #endif #ifndef linux # include #endif #include #include #include #include #include #include #include #include #ifdef __hpux # define _NET_ROUTE_INCLUDED #endif #include #ifdef sun # include #endif #if __FreeBSD_version >= 300000 # include #endif #ifdef __sgi #include # ifdef IFF_DRVRLOCK /* IRIX6 */ #include # endif #endif #if defined(__FreeBSD__) # include "radix_ipf.h" #endif #include #include #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ && \ !defined(__hpux) && !defined(linux) # include #endif #include #include #if !defined(linux) # include #endif #include #if defined(__osf__) # include #endif #if defined(__osf__) || defined(__hpux) || defined(__sgi) # include "radix_ipf_local.h" # define _RADIX_H_ #endif #include #include #include #include #include #ifdef __hpux # undef _NET_ROUTE_INCLUDED #endif #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" #ifdef IPFILTER_SYNC #include "netinet/ip_sync.h" #endif #ifdef IPFILTER_SCAN #include "netinet/ip_scan.h" #endif #include "netinet/ip_pool.h" #ifdef IPFILTER_COMPILED # include "netinet/ip_rules.h" #endif #include "netinet/ipf_stack.h" #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) # include #endif #ifdef __hpux struct rtentry; #endif #include "md5.h" #if !defined(__osf__) extern struct protosw inetsw[]; #endif #include "ipt.h" static struct ifnet **ifneta = NULL; static int nifs = 0; static int frzerostats __P((caddr_t, ipf_stack_t *ifs)); static void fr_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 int iplattach(ifs) ipf_stack_t *ifs; { ifs->ifs_fr_running = 1; return 0; } int ipldetach(ifs) ipf_stack_t *ifs; { ifs->ifs_fr_running = -1; return 0; } static int frzerostats(data, ifs) caddr_t data; ipf_stack_t *ifs; { friostat_t fio; int error; fr_getstat(&fio, ifs); error = copyoutptr(&fio, data, sizeof(fio)); if (error) return EFAULT; bzero((char *)ifs->ifs_frstats, sizeof(*ifs->ifs_frstats) * 2); return 0; } /* * Filter ioctl interface. */ int iplioctl(dev, cmd, data, mode) int dev; ioctlcmd_t cmd; caddr_t data; int mode; { int error = 0, unit = 0, tmp, uid; friostat_t fio; ipf_stack_t *ifs; extern ipf_stack_t *get_ifs(); unit = dev; uid = getuid(); ifs = get_ifs(); SPL_NET(s); if (unit == IPL_LOGNAT) { if (ifs->ifs_fr_running > 0) error = fr_nat_ioctl(data, cmd, mode, uid, NULL, ifs); else error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSTATE) { if (ifs->ifs_fr_running > 0) error = fr_state_ioctl(data, cmd, mode, uid, NULL, ifs); else error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGAUTH) { if (ifs->ifs_fr_running > 0) { if ((cmd == (ioctlcmd_t)SIOCADAFR) || (cmd == (ioctlcmd_t)SIOCRMAFR)) { if (!(mode & FWRITE)) { error = EPERM; } else { error = frrequest(unit, cmd, data, ifs->ifs_fr_active, 1, ifs); } } else { error = fr_auth_ioctl(data, cmd, mode, uid, NULL, ifs); } } else error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSYNC) { #ifdef IPFILTER_SYNC if (ifs->ifs_fr_running > 0) error = fr_sync_ioctl(data, cmd, mode); else #endif error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSCAN) { #ifdef IPFILTER_SCAN if (ifs->ifs_fr_running > 0) error = fr_scan_ioctl(data, cmd, mode); else #endif error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGLOOKUP) { if (ifs->ifs_fr_running > 0) error = ip_lookup_ioctl(data, cmd, mode, uid, NULL, ifs); else error = EIO; SPL_X(s); return error; } switch (cmd) { case FIONREAD : #ifdef IPFILTER_LOG error = COPYOUT(&ifs->ifs_iplused[IPL_LOGIPF], (caddr_t)data, sizeof(ifs->ifs_iplused[IPL_LOGIPF])); #endif break; case SIOCFRENB : if (!(mode & FWRITE)) error = EPERM; else { error = COPYIN(data, &tmp, sizeof(tmp)); if (error) break; if (tmp) error = iplattach(ifs); else error = ipldetach(ifs); } break; case SIOCIPFSET : if (!(mode & FWRITE)) { error = EPERM; break; } /* FALLTHROUGH */ case SIOCIPFGETNEXT : case SIOCIPFGET : error = fr_ipftune(cmd, (void *)data, ifs); break; case SIOCSETFF : if (!(mode & FWRITE)) error = EPERM; else error = COPYIN(data, &ifs->ifs_fr_flags, sizeof(ifs->ifs_fr_flags)); break; case SIOCGETFF : error = COPYOUT(&ifs->ifs_fr_flags, data, sizeof(ifs->ifs_fr_flags)); break; case SIOCFUNCL : error = fr_resolvefunc(data); break; case SIOCINAFR : case SIOCRMAFR : case SIOCADAFR : case SIOCZRLST : if (!(mode & FWRITE)) error = EPERM; else error = frrequest(unit, cmd, data, ifs->ifs_fr_active, 1, ifs); break; case SIOCINIFR : case SIOCRMIFR : case SIOCADIFR : if (!(mode & FWRITE)) error = EPERM; else error = frrequest(unit, cmd, data, 1 - ifs->ifs_fr_active, 1, ifs); break; case SIOCSWAPA : if (!(mode & FWRITE)) error = EPERM; else { *(u_int *)data = ifs->ifs_fr_active; ifs->ifs_fr_active = 1 - ifs->ifs_fr_active; } break; case SIOCGETFS : fr_getstat(&fio, ifs); error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT); break; case SIOCFRZST : if (!(mode & FWRITE)) error = EPERM; else error = frzerostats(data, ifs); break; case SIOCIPFFL : if (!(mode & FWRITE)) error = EPERM; else { error = COPYIN(data, &tmp, sizeof(tmp)); if (!error) { tmp = frflush(unit, 4, tmp, ifs); error = COPYOUT(&tmp, data, sizeof(tmp)); } } break; #ifdef USE_INET6 case SIOCIPFL6 : if (!(mode & FWRITE)) error = EPERM; else { error = COPYIN(data, &tmp, sizeof(tmp)); if (!error) { tmp = frflush(unit, 6, tmp, ifs); error = COPYOUT(&tmp, data, sizeof(tmp)); } } break; #endif case SIOCSTLCK : error = COPYIN(data, &tmp, sizeof(tmp)); if (error == 0) { ifs->ifs_fr_state_lock = tmp; ifs->ifs_fr_nat_lock = tmp; ifs->ifs_fr_frag_lock = tmp; ifs->ifs_fr_auth_lock = tmp; } else error = EFAULT; break; #ifdef IPFILTER_LOG case SIOCIPFFB : if (!(mode & FWRITE)) error = EPERM; else *(int *)data = ipflog_clear(unit, ifs); break; #endif /* IPFILTER_LOG */ case SIOCGFRST : error = fr_outobj(data, fr_fragstats(ifs), IPFOBJ_FRAGSTAT); break; case SIOCFRSYN : if (!(mode & FWRITE)) error = EPERM; else { frsync(IPFSYNC_RESYNC, IPFSYNC_RESYNC, NULL, NULL, ifs); } break; default : error = EINVAL; break; } SPL_X(s); return error; } void fr_forgetifp(ifp, ifs) void *ifp; ipf_stack_t *ifs; { register frentry_t *f; WRITE_ENTER(&ifs->ifs_ipf_mutex); for (f = ifs->ifs_ipacct[0][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipacct[1][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipfilter[0][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipfilter[1][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; #ifdef USE_INET6 for (f = ifs->ifs_ipacct6[0][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipacct6[1][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipfilter6[0][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; for (f = ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]; (f != NULL); f = f->fr_next) if (f->fr_ifa == ifp) f->fr_ifa = (void *)-1; #endif RWLOCK_EXIT(&ifs->ifs_ipf_mutex); fr_natifpsync(IPFSYNC_OLDIFP, 4, ifp, NULL, ifs); fr_natifpsync(IPFSYNC_OLDIFP, 6, ifp, NULL, ifs); } void fr_resolvedest(fdp, v, ifs) frdest_t *fdp; int v; ipf_stack_t *ifs; { fdp->fd_ifp = NULL; if (*fdp->fd_ifname) { fdp->fd_ifp = GETIFP(fdp->fd_ifname, v, ifs); if (!fdp->fd_ifp) fdp->fd_ifp = (struct ifnet *)-1; } } #if defined(__sgi) && (IRIX < 60500) static int no_output(ifp, m, s) #else # if TRU64 >= 1885 static int no_output (ifp, m, s, rt, cp) char *cp; # else static int no_output(ifp, m, s, rt) # endif struct rtentry *rt; #endif struct ifnet *ifp; struct mbuf *m; struct sockaddr *s; { return 0; } #if defined(__sgi) && (IRIX < 60500) static int write_output(ifp, m, s) #else # if TRU64 >= 1885 static int write_output (ifp, m, s, rt, cp) char *cp; # else static int 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 fr_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 sin->sin_addr.s_addr = inet_addr(addr); if (sin->sin_addr.s_addr == 0) abort(); } } /*ARGSUSED*/ struct ifnet *get_unit(name, v, ifs) char *name; int v; ipf_stack_t *ifs; { 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 == 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) fr_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(ifp, ifname, 0); if (!strcmp(name, ifname)) { if (addr != NULL) fr_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) && (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 for (s = name; *s && !ISDIGIT(*s); s++) ; if (*s && ISDIGIT(*s)) { ifp->if_unit = atoi(s); ifp->if_name = (char *)malloc(s - name + 1); if (ifp->if_name == NULL) { /* * XXX do it more elegantly: free up mem, * return NULL */ perror("malloc"); exit(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 = no_output; if (addr != NULL) { fr_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 sprintf(ifname, "%s%d", ifp->if_name, ifp->if_unit); #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 = 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 = 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 fr_fastroute(m, mpp, fin, fdp) mb_t *m, **mpp; fr_info_t *fin; frdest_t *fdp; { struct ifnet *ifp = fdp->fd_ifp; ip_t *ip = fin->fin_ip; if (!ifp) return 0; /* no routing table out here */ ip->ip_len = htons((u_short)ip->ip_len); ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); ip->ip_sum = 0; #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 return 0; } int fr_send_reset(fin) fr_info_t *fin; { verbose("- TCP RST sent\n"); return 0; } int fr_send_icmp_err(type, fin, dst) int type; fr_info_t *fin; int dst; { verbose("- ICMP unreachable sent\n"); return 0; } void frsync(command, version, nic, data, ifs) int command, version; void *nic; char *data; ipf_stack_t *ifs; { return; } 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 fr_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: fr_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 fr_nextipid(fin) fr_info_t *fin; { static u_short ipid = 0; u_short id; ipf_stack_t *ifs = fin->fin_ifs; MUTEX_ENTER(&ifs->ifs_ipf_rw); id = ipid++; MUTEX_EXIT(&ifs->ifs_ipf_rw); return id; } INLINE void fr_checkv4sum(fin) fr_info_t *fin; { if (fr_checkl4sum(fin) == -1) fin->fin_flx |= FI_BAD; } #ifdef USE_INET6 INLINE void fr_checkv6sum(fin) fr_info_t *fin; { if (fr_checkl4sum(fin) == -1) fin->fin_flx |= FI_BAD; } #endif /* * See above for description, except that all addressing is in user space. */ int copyoutptr(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; } /* * return the first IP Address associated with an interface */ int fr_ifpaddr(v, atype, ifptr, inp, inpmask, ifs) int v, atype; void *ifptr; struct in_addr *inp, *inpmask; ipf_stack_t *ifs; { 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) { 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 fr_ifpfillv4addr(atype, sin, &mask, inp, inpmask); } 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 u_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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include "ipf.h" #include #include #include "netinet/ipl.h" #include "ipfzone.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: ipf.c,v 1.35.2.3 2004/12/15 18:27:17 darrenr Exp $"; #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; static void procfile __P((char *, char *)), flushfilter __P((char *)); static void set_state __P((u_int)), showstats __P((friostat_t *)); static void packetlogon __P((char *)), 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 void 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 }; static void usage() { fprintf(stderr, "usage: ipf [-6AdDEGInoPrRsvVyzZ] %s %s %s", "[-l block|pass|nomatch|state|nat]", "[-cc] [-F i|o|a|s|S|u]", "[-f filename] [-T ] [zonename]\n"); exit(1); } int main(argc,argv) int argc; char *argv[]; { int c; const char *optstr = "6Ac:dDEf:F:GIl:noPrRsT:vVyzZ"; if (argc < 2) usage(); /* * We need to set the zone name before calling the functions * in the switch statement below. Note that ipf.c differs from the other * tools in the ipfilter suite: the zone name is specified as the * last argument, while the other tools use the -z option. ipf * already has a -z option, so the last argument is used instead. */ getzonearg(argc, argv, optstr); while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case '?' : usage(); break; #ifdef USE_INET6 case '6' : use_inet6 = 1; break; #endif 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(argv[0], optarg); break; case 'F' : flushfilter(optarg); break; case 'G' : /* Already handled by getzonearg() above */ break; case 'I' : opts ^= OPT_INACTIVE; break; case 'l' : packetlogon(optarg); break; case 'n' : opts ^= OPT_DONOTHING; 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(0); /* 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) perror("open device"); if (setzone(fd) != 0) { close(fd); return -2; } return fd; } static void closedevice() { close(fd); fd = -1; } static int get_flags() { int i; if ((opendevice(ipfname, 1) != -2) && (ioctl(fd, SIOCGETFF, &i) == -1)) { perror("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 perror("SIOCFRENB"); } return; } static void procfile(name, file) char *name, *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 void ipf_interceptadd(fd, ioctlfunc, ptr) int fd; ioctlfunc_t ioctlfunc; void *ptr; { if (outputc) printc(ptr); ipf_addrule(fd, ioctlfunc, ptr); } 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") || index(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)) perror("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 && setzone(xfd) != 0) { close(xfd); xfd = -1; } if (xfd >= 0) { logopt = 0; if (ioctl(xfd, SIOCGETLG, &logopt)) perror("ioctl(SIOCGETLG)"); else { logopt = 1 - logopt; if (ioctl(xfd, SIOCSETLG, &logopt)) perror("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 && setzone(xfd) != 0) { close(xfd); xfd = -1; } if (xfd >= 0) { logopt = 0; if (ioctl(xfd, SIOCGETLG, &logopt)) perror("ioctl(SIOCGETLG)"); else { logopt = 1 - logopt; if (ioctl(xfd, SIOCSETLG, &logopt)) perror("ioctl(SIOCSETLG)"); } close(xfd); } } } static void flushfilter(arg) char *arg; { int fl = 0, rem; if (!arg || !*arg) return; if (!strcmp(arg, "s") || !strcmp(arg, "S")) { if (*arg == 'S') fl = FLUSH_TABLE_ALL; else fl = FLUSH_TABLE_CLOSING; rem = fl; closedevice(); if (opendevice(IPSTATE_NAME, 1) == -2) exit(1); if (!(opts & OPT_DONOTHING)) { if (use_inet6) { if (ioctl(fd, SIOCIPFL6, &fl) == -1) { perror("ioctl(SIOCIPFL6)"); exit(1); } } else { if (ioctl(fd, SIOCIPFFL, &fl) == -1) { perror("ioctl(SIOCIPFFL)"); exit(1); } } } if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { printf("remove flags %s (%d)\n", arg, rem); printf("removed %d filter rules\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) perror("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) { perror("ioctl(SIOCIPFL6)"); exit(1); } } else { if (ioctl(fd, SIOCIPFFL, &fl) == -1) { perror("ioctl(SIOCIPFFL)"); exit(1); } } } if ((opts & (OPT_DONOTHING|OPT_VERBOSE)) == OPT_VERBOSE) { printf("remove flags %s%s (%d)\n", (rem & FR_INQUE) ? "I" : "", (rem & FR_OUTQUE) ? "O" : "", rem); printf("removed %d filter rules\n", fl); } return; } static void swapactive() { int in = 2; if (opendevice(ipfname, 1) != -2 && ioctl(fd, SIOCSWAPA, &in) == -1) perror("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) perror("SIOCFRSYN"); else printf("filter sync'd\n"); } void zerostats() { friostat_t fio; friostat_t *fiop = &fio; if (opendevice(ipfname, 1) != -2) { if (ioctl(fd, SIOCFRZST, &fiop) == -1) { perror("ioctl(SIOCFRZST)"); exit(-1); } showstats(fiop); } } /* * 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); printf(" packets logged:\tinput %lu-%lu output %lu-%lu\n", fp->f_st[0].fr_pkl, fp->f_st[0].fr_skip, fp->f_st[1].fr_pkl, fp->f_st[1].fr_skip); } 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 (setzone(vfd) != 0) { close(vfd); return 1; } if (ioctl(vfd, SIOCGETFS, &ipfo)) { perror("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; } %{ /* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #include #include #ifdef IPFILTER_BPF # include "pcap-bpf.h" # define _NET_BPF_H_ # include #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 } #define OPTION_LOG 0x1 #define OPTION_QUICK 0x2 #define OPTION_DUP 0x4 #define OPTION_PROUTE 0x8 #define OPTION_ON 0x10 #define OPTION_REPLYTO 0x20 #define OPTION_FROUTE 0x40 extern int yyerror __P((const char *)); extern int yyparse __P((void)); extern int yylex __P((void)); extern int yydebug; extern FILE *yyin; extern int yylineNum; static void newrule __P((void)); static void setipftype __P((void)); static u_32_t lookuphost __P((char *, i6addr_t *)); static void dobpf __P((int, char *)); static void resetaddr __P((void)); static struct alist_s *newalist __P((struct alist_s *)); static u_int makehash __P((struct alist_s *)); static int makepool __P((struct alist_s *)); static frentry_t *addrule __P((void)); static void setsyslog __P((void)); static void unsetsyslog __P((void)); static void fillgroup __P((frentry_t *)); 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 ruleopts = 0; static int *yycont = 0; static ioctlfunc_t ipfioctl[IPL_LOGSIZE]; static addfunc_t ipfaddfunc = NULL; static struct wordtab ipfwords[96]; static struct wordtab addrwords[4]; static struct wordtab maskwords[5]; static struct wordtab icmpcodewords[17]; static struct wordtab icmptypewords[16]; static struct wordtab ipv4optwords[25]; static struct wordtab ipv4secwords[9]; static struct wordtab ipv6optwords[8]; static struct wordtab logwords[33]; static int set_ipv6_addr = 0; %} %union { char *str; u_32_t num; struct in_addr ipa; frentry_t fr; frtuc_t *frt; struct alist_s *alist; u_short port; struct { u_short p1; u_short p2; int pc; } pc; struct { union i6addr a; union i6addr m; } ipp; union i6addr ip6; }; %type portnum %type facility priority icmpcode seclevel secname icmptype %type opt compare range opttype flagset optlist ipv6hdrlist ipv6hdr %type portc porteq %type ipv4 ipv4_16 ipv4_24 %type hostname mask %type addr ipaddr %type servicename name interfacename %type portrange portcomp %type addrlist poollist %token YY_NUMBER YY_HEX %token 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 YY_IPV6 %token IPFY_PASS IPFY_BLOCK IPFY_COUNT IPFY_CALL %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 %token IPFY_HEAD IPFY_GROUP %token IPFY_AUTH IPFY_PREAUTH %token IPFY_LOG IPFY_BODY IPFY_FIRST IPFY_LEVEL IPFY_ORBLOCK %token IPFY_LOGTAG IPFY_MATCHTAG IPFY_SETTAG IPFY_SKIP %token IPFY_FROM IPFY_ALL IPFY_ANY IPFY_BPFV4 IPFY_BPFV6 IPFY_POOL IPFY_HASH %token IPFY_PPS %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_PORT %token IPFY_NOW %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 %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 %token IPF6_V6HDRS IPFY_IPV6OPT IPFY_IPV6OPT_DSTOPTS IPFY_IPV6OPT_HOPOPTS %token IPFY_IPV6OPT_IPV6 IPFY_IPV6OPT_NONE IPFY_IPV6OPT_ROUTING %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 %token IPFY_SET_LOOPBACK IPFY_SET %% file: line | assign | file line | file assign ; line: xx rule { while ((fr = frtop) != NULL) { frtop = fr->fr_next; fr->fr_next = NULL; (*ipfaddfunc)(ipffd, ipfioctl[IPL_LOGIPF], fr); fr->fr_next = frold; frold = fr; } resetlexer(); } | YY_COMMENT | set ; xx: { newrule(); } ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); yyvarnext = 0; } ; assigning: '=' { yyvarnext = 1; } ; set: IPFY_SET IPFY_SET_LOOPBACK YY_STR ';' { int data; if (frold != NULL) { yyerror("ipf rules before \"set\""); return 0; } if (!strcmp($3, "true")) data = 1; else if (!strcmp($3, "false")) data = 0; else { yyerror("invalid argument for ipf_loopback"); return 0; } if (((opts & OPT_DONOTHING) == 0) && (ioctl(ipffd, SIOCIPFLP, &data) == -1)) perror("ioctl(SIOCIPFLP)"); } ; rule: inrule eol | outrule eol ; eol: | ';' ; inrule: rulehead markin { ruleopts = 0; } inopts rulemain ruletail intag ruletail2 ; outrule: rulehead markout { ruleopts = 0; } outopts rulemain ruletail outtag ruletail2 ; rulehead: collection action | insert collection action ; markin: IPFY_IN { fr->fr_flags |= FR_INQUE; } ; markout: IPFY_OUT { fr->fr_flags |= FR_OUTQUE; } ; rulemain: ipfrule | bpfrule ; ipfrule: tos ttl proto ip ; bpfrule: IPFY_BPFV4 '{' YY_STR '}' { dobpf(4, $3); free($3); } | IPFY_BPFV6 '{' YY_STR '}' { dobpf(6, $3); free($3); } ; ruletail: with keep head group ; ruletail2: pps age new ; 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; } | log | IPFY_COUNT { fr->fr_flags |= FR_ACCOUNT; } | 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; } ; 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 IPFY_RETRST { fr->fr_flags |= (FR_AUTH|FR_RETRST);} | IPFY_PREAUTH { fr->fr_flags |= FR_PREAUTH; } ; func: YY_STR '/' YY_NUMBER { fr->fr_func = nametokva($1, ipfioctl[IPL_LOGIPF]); fr->fr_arg = $3; free($1); } ; inopts: | inopts inopt ; inopt: logopt { if ( ruleopts & OPTION_LOG ) yyerror("Duplicate log option"); ruleopts |= OPTION_LOG; } | quick { if ( ruleopts & OPTION_QUICK ) yyerror("Duplicate quick option"); ruleopts |= OPTION_QUICK; } | on { if ( ruleopts & OPTION_ON ) yyerror("Duplicate on option"); ruleopts |= OPTION_ON; } | dup { if ( ruleopts & OPTION_DUP ) yyerror("Duplicate dup option"); ruleopts |= OPTION_DUP; } | froute { if ( ruleopts & OPTION_FROUTE ) yyerror("Duplicate froute option"); ruleopts |= OPTION_FROUTE; } | proute { if ( ruleopts & OPTION_PROUTE ) yyerror("Duplicate proute option"); ruleopts |= OPTION_PROUTE; } | replyto { if ( ruleopts & OPTION_REPLYTO ) yyerror("Duplicate replyto option"); ruleopts |= OPTION_REPLYTO; } ; outopts: | outopts outopt ; outopt: logopt { if ( ruleopts & OPTION_LOG ) yyerror("Duplicate log option"); ruleopts |= OPTION_LOG; } | quick { if ( ruleopts & OPTION_QUICK ) yyerror("Duplicate quick option"); ruleopts |= OPTION_QUICK; } | on { if ( ruleopts & OPTION_ON ) yyerror("Duplicate on option"); ruleopts |= OPTION_ON; } | dup { if ( ruleopts & OPTION_DUP ) yyerror("Duplicate dup option"); ruleopts |= OPTION_DUP; } | proute { if ( ruleopts & OPTION_PROUTE ) yyerror("Duplicate proute option"); ruleopts |= OPTION_PROUTE; } | replyto { if ( ruleopts & OPTION_REPLYTO ) yyerror("Duplicate replyto option"); ruleopts |= OPTION_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 YY_STR { DOALL(strncpy(fr->fr_group, $2, \ FR_GROUPLEN); \ fillgroup(fr);); free($2); } | IPFY_GROUP YY_NUMBER { DOALL(sprintf(fr->fr_group, "%d", \ $2); \ fillgroup(fr);) } ; head: | IPFY_HEAD YY_STR { DOALL(strncpy(fr->fr_grhead, $2, \ FR_GROUPLEN);); free($2); } | IPFY_HEAD YY_NUMBER { DOALL(sprintf(fr->fr_grhead, "%d", \ $2);) } ; settagin: | IPFY_SETTAG '(' taginlist ')' ; taginlist: taginspec | taginlist ',' taginspec ; taginspec: logtag |nattag ; 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 ; savegroup: '{' ; restoregroup: '}' ; logopt: log ; quick: IPFY_QUICK { fr->fr_flags |= FR_QUICK; } ; on: IPFY_ON onname | IPFY_ON onname IPFY_INVIA vianame | IPFY_ON onname IPFY_OUTVIA vianame ; onname: interfacename { strncpy(fr->fr_ifnames[0], $1, sizeof(fr->fr_ifnames[0])); free($1); } | interfacename ',' interfacename { strncpy(fr->fr_ifnames[0], $1, sizeof(fr->fr_ifnames[0])); free($1); strncpy(fr->fr_ifnames[1], $3, sizeof(fr->fr_ifnames[1])); free($3); } ; vianame: name { strncpy(fr->fr_ifnames[2], $1, sizeof(fr->fr_ifnames[2])); free($1); } | name ',' name { strncpy(fr->fr_ifnames[2], $1, sizeof(fr->fr_ifnames[2])); free($1); strncpy(fr->fr_ifnames[3], $3, sizeof(fr->fr_ifnames[3])); free($3); } ; dup: IPFY_DUPTO name { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); free($2); fr->fr_flags |= FR_DUP; } | IPFY_DUPTO name duptoseparator hostname { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); if (use_inet6 == 0) fr->fr_dif.fd_ip = $4.in4; else bcopy(&$4, &fr->fr_dif.fd_ip6, sizeof(fr->fr_dif.fd_ip6)); yyexpectaddr = 0; fr->fr_flags |= FR_DUP; free($2); } | IPFY_DUPTO name duptoseparator YY_IPV6 { strncpy(fr->fr_dif.fd_ifname, $2, sizeof(fr->fr_dif.fd_ifname)); bcopy(&$4, &fr->fr_dif.fd_ip6, sizeof(fr->fr_dif.fd_ip6)); yyexpectaddr = 0; fr->fr_flags |= FR_DUP; free($2); } ; duptoseparator: ':' { yyexpectaddr = 1; yycont = &yyexpectaddr; resetaddr(); } ; froute: IPFY_FROUTE { fr->fr_flags |= FR_FASTROUTE; } ; proute: routeto name { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); free($2); } | routeto name duptoseparator hostname { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); if (use_inet6 == 0) fr->fr_tif.fd_ip = $4.in4; else bcopy(&$4, &fr->fr_tif.fd_ip6, sizeof(fr->fr_tif.fd_ip6)); yyexpectaddr = 0; free($2); } | routeto name duptoseparator YY_IPV6 { strncpy(fr->fr_tif.fd_ifname, $2, sizeof(fr->fr_tif.fd_ifname)); bcopy(&$4, &fr->fr_tif.fd_ip6, sizeof(fr->fr_tif.fd_ip6)); yyexpectaddr = 0; free($2); } ; routeto: IPFY_TO | IPFY_ROUTETO ; replyto: IPFY_REPLY_TO name { strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname)); free($2); } | IPFY_REPLY_TO name duptoseparator hostname { strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname)); if (use_inet6 == 0) fr->fr_rif.fd_ip = $4.in4; else bcopy(&$4, &fr->fr_rif.fd_ip6, sizeof(fr->fr_rif.fd_ip6)); yyexpectaddr = 0; free($2); } | IPFY_REPLY_TO name duptoseparator YY_IPV6 { strncpy(fr->fr_rif.fd_ifname, $2, sizeof(fr->fr_rif.fd_ifname)); bcopy(&$4, &fr->fr_rif.fd_ip6, sizeof(fr->fr_rif.fd_ip6)); yyexpectaddr = 0; 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 { DOREM(fr->fr_proto = $1; \ fr->fr_mproto = 0xff;) } | YY_STR { if (!strcmp($1, "tcp-udp")) { DOREM(fr->fr_flx |= FI_TCPUDP; \ fr->fr_mflx |= FI_TCPUDP;) } else { int p = getproto($1); if (p == -1) yyerror("protocol unknown"); DOREM(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 { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_src, sizeof($1.a)); \ bcopy(&($1.m), &fr->fr_mip.fi_src, sizeof($1.m)); \ if (dynamic != -1) { \ fr->fr_satype = ifpflag; \ fr->fr_ipf->fri_sifpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_satype = FRI_LOOKUP;) } | lstart srcaddrlist lend ; srcaddrlist: addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_src, sizeof($1.a)); \ bcopy(&($1.m), &fr->fr_mip.fi_src, sizeof($1.m)); \ if (dynamic != -1) { \ fr->fr_satype = ifpflag; \ fr->fr_ipf->fri_sifpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_satype = FRI_LOOKUP;) } | srcaddrlist lmore addr { DOREM(bcopy(&($3.a), &fr->fr_ip.fi_src, sizeof($3.a)); \ bcopy(&($3.m), &fr->fr_mip.fi_src, sizeof($3.m)); \ if (dynamic != -1) { \ fr->fr_satype = ifpflag; \ fr->fr_ipf->fri_sifpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_satype = FRI_LOOKUP;) } ; 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;) } | srcportlist lmore portnum { DOREM(fr->fr_scmp = FR_EQUAL; fr->fr_sport = $3;) } ; dstobject: { yyresetdict(); } toport | dstaddr dstport | '!' dstaddr dstport { DOALL(fr->fr_flags |= FR_NOTDSTIP;) } ; dstaddr: addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_dst, sizeof($1.a)); \ bcopy(&($1.m), &fr->fr_mip.fi_dst, sizeof($1.m)); \ if (dynamic != -1) { \ fr->fr_datype = ifpflag; \ fr->fr_ipf->fri_difpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_datype = FRI_LOOKUP;) } | lstart dstaddrlist lend ; dstaddrlist: addr { DOREM(bcopy(&($1.a), &fr->fr_ip.fi_dst, sizeof($1.a)); \ bcopy(&($1.m), &fr->fr_mip.fi_dst, sizeof($1.m)); \ if (dynamic != -1) { \ fr->fr_datype = ifpflag; \ fr->fr_ipf->fri_difpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_datype = FRI_LOOKUP;) } | dstaddrlist lmore addr { DOREM(bcopy(&($3.a), &fr->fr_ip.fi_dst, sizeof($3.a)); \ bcopy(&($3.m), &fr->fr_mip.fi_dst, sizeof($3.m)); \ if (dynamic != -1) { \ fr->fr_datype = ifpflag; \ fr->fr_ipf->fri_difpidx = dynamic; \ } else if (pooled || hashed) \ fr->fr_datype = FRI_LOOKUP;) } ; 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;) } | dstportlist lmore portnum { DOREM(fr->fr_dcmp = FR_EQUAL; fr->fr_dport = $3;) } ; addr: pool '/' YY_NUMBER { pooled = 1; yyexpectaddr = 0; $$.a.iplookuptype = IPLT_POOL; $$.a.iplookupnum = $3; } | pool '=' '(' poollist ')' { pooled = 1; yyexpectaddr = 0; $$.a.iplookuptype = IPLT_POOL; $$.a.iplookupnum = makepool($4); } | hash '/' YY_NUMBER { hashed = 1; yyexpectaddr = 0; $$.a.iplookuptype = IPLT_HASH; $$.a.iplookupnum = $3; } | hash '=' '(' addrlist ')' { hashed = 1; yyexpectaddr = 0; $$.a.iplookuptype = IPLT_HASH; $$.a.iplookupnum = makehash($4); } | ipaddr { bcopy(&$1, &$$, sizeof($$)); yyexpectaddr = 0; } ; ipaddr: IPFY_ANY { bzero(&($$), sizeof($$)); yyresetdict(); yyexpectaddr = 0; } | hostname { if (use_inet6 == 0) { $$.a.in4 = $1.in4; $$.m.in4_addr = 0xffffffff; } else { set_ipv6_addr = 1; bcopy(&$1, &$$.a, sizeof($$.a)); fill6bits(128, (u_32_t *)&$$.m); } yyexpectaddr = 0; } | hostname { yyresetdict(); if (use_inet6 == 0) $$.a.in4 = $1.in4; else { set_ipv6_addr = 1; bcopy(&$1, &$$.a, sizeof($$.a)); } } maskspace { yysetdict(maskwords); } mask { if (use_inet6 == 0) { $$.m.in4_addr = $5.in4.s_addr; $$.a.in4_addr &= $5.in4.s_addr; } else bcopy(&$5, &$$.m, sizeof($$.m)); yyresetdict(); yyexpectaddr = 0; } | YY_IPV6 { set_ipv6_addr = 1; bcopy(&$1, &$$.a, sizeof($$.a)); fill6bits(128, (u_32_t *)&$$.m); yyresetdict(); yyexpectaddr = 0; } | YY_IPV6 { set_ipv6_addr = 1; yyresetdict(); bcopy(&$1, &$$.a, sizeof($$.a)); } maskspace { yysetdict(maskwords); } mask { bcopy(&$5, &$$.m, sizeof($$.m)); yyresetdict(); yyexpectaddr = 0; } ; maskspace: '/' | IPFY_MASK ; mask: ipv4 { $$.in4 = $1; } | YY_HEX { $$.in4.s_addr = htonl($1); } | YY_NUMBER { if ((use_inet6 == 0) && ($1 <= 32)) ntomask(4, $1, (u_32_t *)&$$.in4); else if ((use_inet6 != 0) && ($1 <= 128)) ntomask(6, $1, $$.i6); else { yyerror("Bad value specified for netmask"); return 0; } } | IPFY_BROADCAST { if (ifpflag == FRI_DYNAMIC) { bzero(&$$, sizeof($$)); ifpflag = FRI_BROADCAST; } else YYERROR; } | IPFY_NETWORK { if (ifpflag == FRI_DYNAMIC) { bzero(&$$, sizeof($$)); ifpflag = FRI_NETWORK; } else YYERROR; } | IPFY_NETMASKED { if (ifpflag == FRI_DYNAMIC) { bzero(&$$, sizeof($$)); ifpflag = FRI_NETMASKED; } else YYERROR; } | IPFY_PEER { if (ifpflag == FRI_DYNAMIC) { bzero(&$$, sizeof($$)); ifpflag = FRI_PEERADDR; } else YYERROR; } ; hostname: ipv4 { $$.in4 = $1; } | YY_NUMBER { $$.in4.s_addr = $1; } | YY_HEX { $$.in4.s_addr = $1; } | YY_STR { if (lookuphost($1, &$$) == 1) free($1); else { free($1); if (ifpflag != FRI_DYNAMIC) yyerror("Unknown hostname"); } } ; addrlist: ipaddr { $$ = newalist(NULL); if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($1.a), &($$->al_i6addr), sizeof($1.a)); bcopy(&($1.m), &($$->al_i6mask), sizeof($1.m)); } | addrlist ',' ipaddr { $$ = newalist($1); if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($3.a), &($$->al_i6addr), sizeof($3.a)); bcopy(&($3.m), &($$->al_i6mask), sizeof($3.m)); } ; pool: IPFY_POOL { yyexpectaddr = 0; yycont = NULL; yyresetdict(); } ; hash: IPFY_HASH { yyexpectaddr = 0; yycont = NULL; yyresetdict(); } ; poollist: ipaddr { $$ = newalist(NULL); if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($1.a), &($$->al_i6addr), sizeof($1.a)); bcopy(&($1.m), &($$->al_i6mask), sizeof($1.m)); } | '!' ipaddr { $$ = newalist(NULL); $$->al_not = 1; if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($2.a), &($$->al_i6addr), sizeof($2.a)); bcopy(&($2.m), &($$->al_i6mask), sizeof($2.m)); } | poollist ',' ipaddr { $$ = newalist($1); if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($3.a), &($$->al_i6addr), sizeof($3.a)); bcopy(&($3.m), &($$->al_i6mask), sizeof($3.m)); } | poollist ',' '!' ipaddr { $$ = newalist($1); $$->al_not = 1; if (set_ipv6_addr) $$->al_family = AF_INET6; else $$->al_family = AF_INET; set_ipv6_addr = 0; bcopy(&($4.a), &($$->al_i6addr), sizeof($4.a)); bcopy(&($4.m), &($$->al_i6mask), sizeof($4.m)); } ; port: IPFY_PORT { yyexpectaddr = 0; yycont = NULL; } ; 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 { setipftype(); yysetdict(icmptypewords); } ; 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($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 | IPFY_KEEP keepfrag | IPFY_KEEP keepstate IPFY_KEEP keepfrag | IPFY_KEEP keepfrag IPFY_KEEP keepstate ; 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 \ fr->fr_flags |= FR_STSTRICT;) } | 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;) } ; portnum: servicename { if (getport(frc, $1, &($$)) == -1) yyerror("service unknown"); else $$ = ntohs($$); free($1); } | YY_NUMBER { if ($1 > 65535) /* Unsigned */ yyerror("invalid port number"); else $$ = $1; } ; withlist: withopt | withlist withopt | withlist ',' withopt ; 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(); } | startv6hdrs ipv6hdrs { yyresetdict(); } ; ipopt: IPFY_OPT { yysetdict(ipv4optwords); } ; startv6hdrs: IPF6_V6HDRS { if (use_inet6 == 0) 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; } ; ipopts: optlist { DOALL(fr->fr_mip.fi_optmsk |= $1; 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; } | IPFY_ICMPT_UNR { $$ = ICMP_UNREACH; } | IPFY_ICMPT_ECHO { $$ = ICMP_ECHO; } | IPFY_ICMPT_ECHOR { $$ = ICMP_ECHOREPLY; } | IPFY_ICMPT_SQUENCH { $$ = ICMP_SOURCEQUENCH; } | IPFY_ICMPT_REDIR { $$ = ICMP_REDIRECT; } | IPFY_ICMPT_TIMEX { $$ = ICMP_TIMXCEED; } | IPFY_ICMPT_PARAMP { $$ = ICMP_PARAMPROB; } | IPFY_ICMPT_TIMEST { $$ = ICMP_TSTAMP; } | IPFY_ICMPT_TIMESTREP { $$ = ICMP_TSTAMPREPLY; } | IPFY_ICMPT_INFOREQ { $$ = ICMP_IREQ; } | IPFY_ICMPT_INFOREP { $$ = ICMP_IREQREPLY; } | IPFY_ICMPT_MASKREQ { $$ = ICMP_MASKREQ; } | IPFY_ICMPT_MASKREP { $$ = ICMP_MASKREPLY; } | IPFY_ICMPT_ROUTERAD { $$ = ICMP_ROUTERADVERT; } | IPFY_ICMPT_ROUTERSOL { $$ = ICMP_ROUTERSOLICIT; } ; 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_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 (!nowith) fr->fr_ip.fi_secmsk |= $2;) $$ = 0; yyresetdict(); } ; setsecclass: IPFY_SECCLASS { yysetdict(ipv4secwords); } ; ipv6hdr: IPFY_AH { $$ = getv6optbyvalue(IPPROTO_AH); } | IPFY_IPV6OPT_DSTOPTS { $$ = getv6optbyvalue(IPPROTO_DSTOPTS); } | IPFY_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_FRAG { $$ = getv6optbyvalue(IPPROTO_FRAGMENT); } ; 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: YY_STR { $$ = $1; } | YY_STR ':' 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; } ; 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[96] = { { "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 }, { "count", IPFY_COUNT }, { "dup-to", IPFY_DUPTO }, { "eq", YY_CMP_EQ }, { "esp", IPFY_ESP }, { "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-type", IPFY_ICMPTYPE }, { "in", IPFY_IN }, { "in-via", IPFY_INVIA }, { "intercept_loopback", IPFY_SET_LOOPBACK }, { "ipopt", IPFY_IPOPTS }, { "ipopts", IPFY_IPOPTS }, { "keep", IPFY_KEEP }, { "le", YY_CMP_LE }, { "level", IPFY_LEVEL }, { "limit", IPFY_LIMIT }, { "log", IPFY_LOG }, { "lowttl", IPFY_LOWTTL }, { "lt", YY_CMP_LT }, { "mask", IPFY_MASK }, { "match-tag", IPFY_MATCHTAG }, { "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 }, { "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 }, { "sec-class", IPFY_SECCLASS }, { "set-tag", IPFY_SETTAG }, { "set", IPFY_SET }, { "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 }, { "v6hdrs", IPF6_V6HDRS }, { "with", IPFY_WITH }, { NULL, 0 } }; static struct wordtab addrwords[4] = { { "any", IPFY_ANY }, { "hash", IPFY_HASH }, { "pool", IPFY_POOL }, { NULL, 0 } }; static struct wordtab maskwords[5] = { { "broadcast", IPFY_BROADCAST }, { "netmasked", IPFY_NETMASKED }, { "network", IPFY_NETWORK }, { "peer", IPFY_PEER }, { NULL, 0 } }; static struct wordtab icmptypewords[16] = { { "echo", IPFY_ICMPT_ECHO }, { "echorep", IPFY_ICMPT_ECHOR }, { "inforeq", IPFY_ICMPT_INFOREQ }, { "inforep", IPFY_ICMPT_INFOREP }, { "maskrep", IPFY_ICMPT_MASKREP }, { "maskreq", IPFY_ICMPT_MASKREQ }, { "paramprob", IPFY_ICMPT_PARAMP }, { "redir", IPFY_ICMPT_REDIR }, { "unreach", IPFY_ICMPT_UNR }, { "routerad", IPFY_ICMPT_ROUTERAD }, { "routersol", IPFY_ICMPT_ROUTERSOL }, { "squench", IPFY_ICMPT_SQUENCH }, { "timest", IPFY_ICMPT_TIMEST }, { "timestrep", IPFY_ICMPT_TIMESTREP }, { "timex", IPFY_ICMPT_TIMEX }, { NULL, 0 }, }; static struct wordtab icmpcodewords[17] = { { "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[25] = { { "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[9] = { { "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[8] = { { "dstopts", IPFY_IPV6OPT_DSTOPTS }, { "esp", IPFY_ESP }, { "frag", IPFY_FRAG }, { "hopopts", IPFY_IPV6OPT_HOPOPTS }, { "ipv6", IPFY_IPV6OPT_IPV6 }, { "none", IPFY_IPV6OPT_NONE }, { "routing", IPFY_IPV6OPT_ROUTING }, { NULL, 0 }, }; static struct wordtab logwords[33] = { { "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++) ipfioctl[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 = (frentry_t *)calloc(1, sizeof(frentry_t)); if (frn == NULL) yyerror("sorry, out of memory"); for (fr = frtop; fr != NULL && fr->fr_next != NULL; fr = fr->fr_next) ; if (fr != NULL) fr->fr_next = frn; if (frtop == NULL) frtop = frn; fr = frn; frc = frn; fr->fr_loglevel = 0xffff; fr->fr_isc = (void *)-1; fr->fr_logtag = FR_NOLOGTAG; fr->fr_type = FR_T_NONE; if (use_inet6 != 0) fr->fr_v = 6; else fr->fr_v = 4; 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); if (fr->fr_data == NULL) yyerror("sorry, out of memory"); fr->fr_dsize = sizeof(fripf_t); fr->fr_ip.fi_v = frc->fr_v; 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; if (count == 0) { f = (frentry_t *)calloc(sizeof(*f), 1); if (f == NULL) yyerror("sorry, out of memory"); added++; f2->fr_next = f; bcopy(f2, f, sizeof(*f)); if (f2->fr_caddr != NULL) { f->fr_caddr = malloc(f->fr_dsize); if (f->fr_caddr == NULL) yyerror("sorry, out of memory"); bcopy(f2->fr_caddr, f->fr_caddr, f->fr_dsize); } f->fr_next = NULL; return f; } f = f2; for (f1 = frc; count > 0; count--, f1 = f1->fr_next) { f->fr_next = (frentry_t *)calloc(sizeof(*f), 1); if (f->fr_next == NULL) yyerror("sorry, out of memory"); added++; f = f->fr_next; bcopy(f1, f, sizeof(*f)); f->fr_next = NULL; if (f->fr_caddr != NULL) { f->fr_caddr = malloc(f->fr_dsize); if (f->fr_caddr == NULL) yyerror("sorry, out of memory"); bcopy(f1->fr_caddr, f->fr_caddr, f->fr_dsize); } } return f2->fr_next; } static u_32_t lookuphost(name, addr) char *name; i6addr_t *addr; { int i; hashed = 0; pooled = 0; dynamic = -1; for (i = 0; i < 4; i++) { if (strncmp(name, frc->fr_ifnames[i], sizeof(frc->fr_ifnames[i])) == 0) { ifpflag = FRI_DYNAMIC; dynamic = i; return 0; } } if (gethost(name, addr, use_inet6) == -1) { fprintf(stderr, "unknown name \"%s\"\n", name); return 0; } return 1; } 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_v = v; fr->fr_type = FR_T_BPFOPC; if (!strncmp(phrase, "\"0x", 2)) { phrase++; fb = malloc(sizeof(fakebpf_t)); if (fb == NULL) yyerror("sorry, out of memory"); 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)); if (fb == NULL) yyerror("sorry, out of memory"); 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); if (fr->fr_data == NULL) yyerror("sorry, out of memory"); 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) { n->ipn_addr.adf_family = a->al_family; n->ipn_mask.adf_family = a->al_family; (void *)bcopy((void *)&a->al_i6addr, (void *)&n->ipn_addr.adf_addr, sizeof(n->ipn_addr.adf_addr)); (void *)bcopy((void *)&a->al_i6mask, (void *)&n->ipn_mask.adf_addr, sizeof(n->ipn_mask.adf_addr)); n->ipn_info = a->al_not; if (a->al_next != NULL) { n->ipn_next = calloc(1, sizeof(*n)); if (n->ipn_next == NULL) yyerror("sorry, out of memory"); n = n->ipn_next; } } bzero((char *)&pool, sizeof(pool)); pool.ipo_unit = IPL_LOGIPF; pool.ipo_list = top; num = load_pool(&pool, ipfioctl[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) { n->ipe_family = a->al_family; (void *)bcopy((void *)&a->al_i6addr, (void *)&n->ipe_addr, sizeof(n->ipe_addr)); (void *)bcopy((void *)&a->al_i6mask, (void *)&n->ipe_mask, sizeof(n->ipe_mask)); n->ipe_value = 0; if (a->al_next != NULL) { n->ipe_next = calloc(1, sizeof(*n)); if (n->ipe_next == NULL) yyerror("sorry, out of memory"); 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, ipfioctl[IPL_LOGLOOKUP]) == 0) sscanf(iph.iph_name, "%u", &num); else num = 0; while ((n = top) != NULL) { top = n->ipe_next; free(n); } return num; } void ipf_addrule(fd, ioctlfunc, ptr) int fd; ioctlfunc_t ioctlfunc; void *ptr; { ioctlcmd_t add, del; frentry_t *fr; ipfobj_t obj; fr = ptr; add = 0; del = 0; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof(*fr); 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 (fr && (opts & OPT_OUTQUE)) fr->fr_flags |= FR_OUTQUE; if (fr->fr_hits) fr->fr_hits--; if (fr && (opts & OPT_VERBOSE)) printfr(fr, ioctlfunc); if (opts & OPT_DEBUG) { 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) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(SIOCZRLST)"); } } 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) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(delete rule)"); } } } else { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if (!(opts & OPT_DONOTHING)) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(add/insert rule)"); } } } } 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 (strncmp(f->fr_grhead, fr->fr_group, FR_GROUPLEN) == 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_v == 0 && f->fr_v != 0) fr->fr_v = f->fr_v; 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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2017 Gary Mills */ #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; { u_long *ulp; char *and; FILE *fp; int i; if (fr->fr_v != 4) 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; 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) 1993-2000 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 \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)\n"); fprintf(fp, "# include \n"); fprintf(fp, "#endif\n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux)\n"); fprintf(fp, "# include \n"); fprintf(fp, "#endif\n"); fprintf(fp, "#if defined(__FreeBSD__) && (__FreeBSD_version > 220000)\n"); fprintf(fp, "# include \n"); fprintf(fp, "#else\n"); fprintf(fp, "# include \n"); fprintf(fp, "#endif /* FreeBSD */\n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \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 \n"); fprintf(fp, "#endif /* _KERNEL */\n"); fprintf(fp, "\n"); fprintf(fp, "#ifdef IPFILTER_COMPILED\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 *and; int i; f = (frentry_t *)malloc(sizeof(*f)); if (f == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } bcopy((char *)fr, (char *)f, sizeof(*fr)); if (fr->fr_ipf) { f->fr_ipf = (fripf_t *)malloc(sizeof(*f->fr_ipf)); if (f->fr_ipf == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } bcopy((char *)fr->fr_ipf, (char *)f->fr_ipf, sizeof(*fr->fr_ipf)); } f->fr_next = NULL; for (g = groups; g != NULL; g = g->fg_next) if ((strncmp(g->fg_name, f->fr_group, FR_GROUPLEN) == 0) && (g->fg_flags == (f->fr_flags & FR_INOUT))) break; if (g == NULL) { g = (frgroup_t *)calloc(1, sizeof(*g)); if (g == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } g->fg_next = groups; groups = g; g->fg_head = f; bcopy(f->fr_group, g->fg_name, 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++; for (g = groups; g != NULL; g = g->fg_next) if ((strncmp(g->fg_name, f->fr_grhead, FR_GROUPLEN) == 0) && g->fg_flags == (f->fr_flags & FR_INOUT)) break; if (g == NULL) { g = (frgroup_t *)calloc(1, sizeof(*g)); if (g == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } g->fg_next = groups; groups = g; g->fg_head = f; bcopy(f->fr_grhead, g->fg_name, 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 (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", f->fr_group, i); if (i + 1 < incount) fprintf(fp, ", "); i++; } fprintf(fp, "\n};\n"); } if (num == -2 && dir == 1 && header[1] == 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", 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 (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_ifname) 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->fr_group, num); } else { fprintf(fp, "fr = (frentry_t *)&%s_rule_%s_%d;\n", fr->fr_flags & FR_INQUE ? "in" : "out", fr->fr_group, num); } if (n == NULL) { n = (mc_t *)malloc(sizeof(*n) * FRC_MAX); if (n == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } } 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); if (m == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } } 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_ifname, fr->fr_ifname)) { m[FRC_IFN].e++; m[FRC_IFN].n++; } else n &= ~0x0001; if ((n & 0x0002) && (fr1->fr_v == fr->fr_v)) { 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_group,\n\ ipf_rules_%s_%s[j]->fr_group,\n\ FR_GROUPLEN) == 0) {\n\ fp->fr_next = ipf_rules_%s_%s[j];\n\ break;\n\ }\n", instr, group, instr, group); if (dogrp) fprintf(fp, "\ \n\ if (fp->fr_grhead != 0) {\n\ fg = fr_addgroup(fp->fr_grhead, fp, FR_INQUE,\n\ 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|FR_T_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_v = 4;\n\ fp->fr_func = (ipfunc_t)ipfrule_match_%s_%s;\n\ err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_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(IPL_LOGIPF, SIOCDELFR,\n\ (caddr_t)&ipfrule_%s_%s, fr_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"); } /* * Copyright (C) 1999-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include #include #include #include #include #if !defined(__SVR4) && !defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include #include "ipf.h" #include "netinet/ipl.h" #include "ipfzone.h" #if !defined(lint) static const char rcsid[] = "@(#)Id: ipfs.c,v 1.12 2003/12/01 01:56:53 darrenr Exp"; #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() { const char *zoneopt = "[-G|-z zonename] "; fprintf(stderr, "usage: %s %s[-nv] -l\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] -u\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-d ] -R\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-d ] -W\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-N|-S] [-f ] -r\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-N|-S] [-f ] -w\n", progname, zoneopt); fprintf(stderr, "usage: %s %s[-nv] [-N|-S] -f -i ,\n", progname, zoneopt); 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 (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:G:lNnSRruvWwz:")) != -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 'G' : setzonename_global(optarg); 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 'z' : setzonename(optarg); 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"); if (setzone(fd) != 0) { close(fd); fd = -1; } 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"); close(sfd); return 1; } if (i == 0) break; if (i != sizeof(ips)) { fprintf(stderr, "state:incomplete read: %d != %d\n", i, (int)sizeof(ips)); close(sfd); return 1; } is = (ipstate_save_t *)malloc(sizeof(*is)); if(!is) { fprintf(stderr, "malloc failed\n"); return 1; } 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; for (is = ipshead; is; is = is->ips_next) { 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"); return 1; } 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; } } return 0; } 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"); close(nfd); return 1; } if (i == 0) break; if (i != sizeof(ipn)) { fprintf(stderr, "nat:incomplete read: %d != %d\n", i, (int)sizeof(ipn)); close(nfd); return 1; } in = (nat_save_t *)malloc(ipn.ipn_dsize); if (!in) break; 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); close(nfd); return 1; } } } 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; for (in = ipnhead; in; in = in->ipn_next) { 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; } } return 0; } 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; } /* * Copyright (C) 1993-2001, 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include #include #ifdef linux # include #else # include #endif #include #if defined(sun) && (defined(__svr4__) || defined(__SVR4)) # include #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 # else # undef STATETOP /* NOT supported on SunOS4 */ # endif # endif #endif #if defined(STATETOP) && !defined(linux) # include # include #endif #ifdef STATETOP # include # include # if defined(SOLARIS) || defined(__NetBSD__) || defined(_BSDI_VERSION) || \ defined(__sgi) # ifdef ERR # undef ERR # endif # undef ISASCII # undef ISPRINT # include # else /* SOLARIS */ # include # endif /* SOLARIS */ #endif /* STATETOP */ #include "kmem.h" #if defined(__NetBSD__) || (__OpenBSD__) # include #endif #include "ipfzone.h" #if !defined(lint) static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed"; static const char rcsid[] = "@(#)$Id: ipfstat.c,v 1.44.2.12 2005/06/12 07:18:46 darrenr Exp $"; #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; int opts = 0; int use_inet6 = 0; int live_kernel = 1; int state_fd = -1; int ipf_fd = -1; #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 void showstats __P((friostat_t *, u_32_t)); static void showfrstates __P((ipfrstat_t *, u_long)); static void showlist __P((friostat_t *)); static void showipstates __P((ips_stat_t *)); static void showauthstates __P((fr_authstat_t *)); static void showgroups __P((friostat_t *)); static void usage __P((char *)); static void printlivelist __P((int, int, frentry_t *, char *, char *)); static void printdeadlist __P((int, int, frentry_t *, char *, char *)); static void printlist __P((frentry_t *, char *)); static void parse_ipportstr __P((const char *, i6addr_t *, int *)); static void ipfstate_live __P((char *, friostat_t **, ips_stat_t **, ipfrstat_t **, fr_authstat_t **, u_32_t *)); static void ipfstate_dead __P((char *, friostat_t **, ips_stat_t **, ipfrstat_t **, fr_authstat_t **, u_32_t *)); #ifdef STATETOP static void topipstates __P((i6addr_t, i6addr_t, 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, "[-G|-z zonename] "); fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); exit(1); } int main(argc,argv) int argc; char *argv[]; { fr_authstat_t frauthst; fr_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 *device = IPL_NAME, *memf = NULL; char *options, *kern = NULL; int c, myoptind; 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 = "6aACdfgG:hIilnostvD:M:N:P:RS:T:z:"; #else options = "aACdfgG:hIilnostvD:M:N:P:RS:T:z:"; #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 four 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 'G' : setzonename_global(optarg); break; case 'M' : memf = optarg; live_kernel = 0; break; case 'N' : kern = optarg; live_kernel = 0; break; case 'z' : setzonename(optarg); break; } } optind = myoptind; if (live_kernel == 1) { if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) { perror("open(IPSTATE_NAME)"); exit(-1); } if (setzone(state_fd) != 0) { close(state_fd); exit(-1); } if ((ipf_fd = open(device, O_RDONLY)) == -1) { fprintf(stderr, "open(%s)", device); perror(""); exit(-1); } if (setzone(ipf_fd) != 0) { close(ipf_fd); exit(-1); } } if (kern != NULL || memf != NULL) { (void)setgid(getgid()); (void)setreuid(getuid(), getuid()); if (openkmem(kern, memf) == -1) exit(-1); } if (live_kernel == 1) (void) checkrev(device); (void)setgid(getgid()); (void)setreuid(getuid(), 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 'G' : /* Already handled by getzoneopt() above */ 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' : break; case 'N' : break; case 'n' : opts |= OPT_SHOWLINENO; break; case 'o' : opts |= OPT_OUTQUE|OPT_SHOWLIST; 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; opts |= OPT_UNDEF; break; case 'z' : /* Already handled by getzoneopt() above */ 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(device, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); } else ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); if (opts & OPT_IPSTATES) { showipstates(ipsstp); } 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); #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; fr_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_size = sizeof(friostat_t); ipfo.ipfo_ptr = (void *)*fiopp; ipfo.ipfo_type = IPFOBJ_IPFSTAT; if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) { perror("ioctl(ipf:SIOCGETFS)"); exit(-1); } if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1) perror("ioctl(SIOCGETFF)"); } if ((opts & OPT_IPSTATES) != 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(ips_stat_t); ipfo.ipfo_ptr = (void *)*ipsstpp; ipfo.ipfo_type = IPFOBJ_STATESTAT; if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { perror("ioctl(state:SIOCGETFS)"); exit(-1); } if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) { perror("ioctl(state:SIOCGETLG)"); exit(-1); } } if ((opts & OPT_FRSTATES) != 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(ipfrstat_t); ipfo.ipfo_ptr = (void *)*ifrstpp; ipfo.ipfo_type = IPFOBJ_FRAGSTAT; if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) { perror("ioctl(SIOCGFRST)"); exit(-1); } } if (opts & OPT_VERBOSE) PRINTF("opts %#x name %s\n", opts, device); if ((opts & OPT_AUTHSTATS) != 0) { if (ipf_fd >= 0) { close(ipf_fd); ipf_fd = -1; } device = IPAUTH_NAME; if ((ipf_fd = open(device, O_RDONLY)) == -1) { perror("open"); exit(-1); } if (setzone(ipf_fd) != 0) { close(ipf_fd); exit(-1); } bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_size = sizeof(fr_authstat_t); ipfo.ipfo_ptr = (void *)*frauthstpp; ipfo.ipfo_type = IPFOBJ_AUTHSTAT; if (ioctl(ipf_fd, SIOCATHST, &ipfo) == -1) { perror("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; fr_authstat_t **frauthstpp; u_32_t *frfp; { static fr_authstat_t frauthst, *frauthstp; 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[43] = { { "fr_authstats" }, /* 0 */ { "fae_list" }, { "ipauth" }, { "fr_authlist" }, { "fr_authstart" }, { "fr_authend" }, /* 5 */ { "fr_authnext" }, { "fr_auth" }, { "fr_authused" }, { "fr_authsize" }, { "fr_defaultauthage" }, /* 10 */ { "fr_authpkts" }, { "fr_auth_lock" }, { "frstats" }, { "ips_stats" }, { "ips_num" }, /* 15 */ { "ips_wild" }, { "ips_list" }, { "ips_table" }, { "fr_statemax" }, { "fr_statesize" }, /* 20 */ { "fr_state_doflush" }, { "fr_state_lock" }, { "ipfr_heads" }, { "ipfr_nattab" }, { "ipfr_stats" }, /* 25 */ { "ipfr_inuse" }, { "fr_ipfrttl" }, { "fr_frag_lock" }, { "ipfr_timer_id" }, { "fr_nat_lock" }, /* 30 */ { "ipfilter" }, { "ipfilter6" }, { "ipacct" }, { "ipacct6" }, { "ipl_frouteok" }, /* 35 */ { "fr_running" }, { "ipfgroups" }, { "fr_active" }, { "fr_pass" }, { "fr_flags" }, /* 40 */ { "ipstate_logging" }, { NULL } }; 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]; /* * Same for IPv6, except make them null if support for it is not * being compiled in. */ #ifdef USE_INET6 kmemcpy((char *)&rules, (u_long)deadlist[32].n_value, sizeof(rules)); fiop->f_fin6[0] = rules[0][0]; fiop->f_fin6[1] = rules[0][1]; fiop->f_fout6[0] = rules[1][0]; fiop->f_fout6[1] = rules[1][1]; #else fiop->f_fin6[0] = NULL; fiop->f_fin6[1] = NULL; fiop->f_fout6[0] = NULL; fiop->f_fout6[1] = NULL; #endif /* * 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]; #ifdef USE_INET6 kmemcpy((char *)&rules, (u_long)deadlist[34].n_value, sizeof(rules)); fiop->f_acctin6[0] = rules[0][0]; fiop->f_acctin6[1] = rules[0][1]; fiop->f_acctout6[0] = rules[1][0]; fiop->f_acctout6[1] = rules[1][1]; #else fiop->f_acctin6[0] = NULL; fiop->f_acctin6[1] = NULL; fiop->f_acctout6[0] = NULL; fiop->f_acctout6[1] = NULL; #endif /* * 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[35].n_value, sizeof(fiop->f_froute)); kmemcpy((char *)&fiop->f_running, (u_long)deadlist[36].n_value, sizeof(fiop->f_running)); kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[37].n_value, sizeof(fiop->f_groups)); kmemcpy((char *)&fiop->f_active, (u_long)deadlist[38].n_value, sizeof(fiop->f_active)); kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[39].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)); ipsstp->iss_active = temp; ipsstp->iss_table = (void *)deadlist[18].n_value; ipsstp->iss_list = (void *)deadlist[17].n_value; /* * 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)); } /* * 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; { PRINTF("bad packets:\t\tin %lu\tout %lu\n", fp->f_st[0].fr_bad, fp->f_st[1].fr_bad); #ifdef USE_INET6 PRINTF(" IPv6 packets:\t\tin %lu out %lu\n", fp->f_st[0].fr_ipv6, fp->f_st[1].fr_ipv6); #endif 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 short %lu\n", fp->f_st[0].fr_acct, fp->f_st[0].fr_short); 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 short %lu\n", fp->f_st[1].fr_acct, fp->f_st[1].fr_short); 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); PRINTF(" packets logged:\tinput %lu output %lu\n", fp->f_st[0].fr_pkl, fp->f_st[1].fr_pkl); PRINTF(" log failures:\t\tinput %lu output %lu\n", fp->f_st[0].fr_skip, fp->f_st[1].fr_skip); PRINTF("fragment state(in):\tkept %lu\tlost %lu\tnot fragmented %lu\n", fp->f_st[0].fr_nfr, fp->f_st[0].fr_bnfr, fp->f_st[0].fr_cfr); PRINTF("fragment state(out):\tkept %lu\tlost %lu\tnot fragmented %lu\n", fp->f_st[1].fr_nfr, fp->f_st[1].fr_bnfr, fp->f_st[0].fr_cfr); PRINTF("packet state(in):\tkept %lu\tlost %lu\n", fp->f_st[0].fr_ads, fp->f_st[0].fr_bads); PRINTF("packet state(out):\tkept %lu\tlost %lu\n", fp->f_st[1].fr_ads, fp->f_st[1].fr_bads); PRINTF("ICMP replies:\t%lu\tTCP RSTs sent:\t%lu\n", fp->f_st[0].fr_ret, fp->f_st[1].fr_ret); PRINTF("Invalid source(in):\t%lu\n", fp->f_st[0].fr_badsrc); PRINTF("Result cache hits(in):\t%lu\t(out):\t%lu\n", fp->f_st[0].fr_chit, fp->f_st[1].fr_chit); PRINTF("IN Pullups succeeded:\t%lu\tfailed:\t%lu\n", fp->f_st[0].fr_pull[0], fp->f_st[0].fr_pull[1]); PRINTF("OUT Pullups succeeded:\t%lu\tfailed:\t%lu\n", fp->f_st[1].fr_pull[0], fp->f_st[1].fr_pull[1]); PRINTF("Fastroute successes:\t%lu\tfailures:\t%lu\n", fp->f_froute[0], fp->f_froute[1]); PRINTF("TCP cksum fails(in):\t%lu\t(out):\t%lu\n", fp->f_st[0].fr_tcpbad, fp->f_st[1].fr_tcpbad); PRINTF("IPF Ticks:\t%lu\n", fp->f_ticks); PRINTF("Packet log flags set: (%#x)\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 void printlivelist(out, set, fp, group, comment) int out, set; frentry_t *fp; char *group, *comment; { frgroup_t *grtop, *grtail, *g; struct frentry fb, *fg; int n; ipfruleiter_t rule; ipfobj_t obj; u_long array[1000]; fb.fr_next = fp; n = 0; grtop = NULL; grtail = NULL; rule.iri_ver = use_inet6? AF_INET6 : AF_INET; rule.iri_inout = out; rule.iri_active = set; rule.iri_nrules = 1; rule.iri_rule = &fb; if (group != NULL) strncpy(rule.iri_group, group, FR_GROUPLEN); else rule.iri_group[0] = '\0'; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_IPFITER; obj.ipfo_size = sizeof(rule); obj.ipfo_ptr = &rule; do { memset(array, 0xff, sizeof(array)); fp = (frentry_t *)array; rule.iri_rule = fp; if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) { perror("ioctl(SIOCIPFITER)"); return; } if (fp->fr_data != NULL) fp->fr_data = (char *)fp + sizeof(*fp); n++; if (opts & (OPT_HITS|OPT_VERBOSE)) #ifdef USE_QUAD_T PRINTF("%qu ", (unsigned long long) fp->fr_hits); #else PRINTF("%lu ", fp->fr_hits); #endif if (opts & (OPT_ACCNT|OPT_VERBOSE)) #ifdef USE_QUAD_T PRINTF("%qu ", (unsigned long long) fp->fr_bytes); #else PRINTF("%lu ", fp->fr_bytes); #endif if (opts & OPT_SHOWLINENO) PRINTF("@%d ", n); printfr(fp, ioctl); if (opts & OPT_DEBUG) { binprint(fp, sizeof(*fp)); if (fp->fr_data != NULL && fp->fr_dsize > 0) binprint(fp->fr_data, fp->fr_dsize); } if (fp->fr_grhead[0] != '\0') { g = calloc(1, sizeof(*g)); if (g != NULL) { strncpy(g->fg_name, fp->fr_grhead, FR_GROUPLEN); if (grtop == NULL) { grtop = g; grtail = g; } else { grtail->fg_next = g; grtail = g; } } } } while (fp->fr_next != NULL); while ((g = grtop) != NULL) { printlivelist(out, set, NULL, g->fg_name, comment); grtop = g->fg_next; free(g); } } static void printdeadlist(out, set, fp, group, comment) int out, set; frentry_t *fp; char *group, *comment; { frgroup_t *grtop, *grtail, *g; struct frentry fb, *fg; char *data; u_32_t type; int n; fb.fr_next = fp; n = 0; grtop = NULL; grtail = NULL; do { fp = fb.fr_next; if (kmemcpy((char *)&fb, (u_long)fb.fr_next, sizeof(fb)) == -1) { perror("kmemcpy"); return; } 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; } } n++; if (opts & (OPT_HITS|OPT_VERBOSE)) #ifdef USE_QUAD_T PRINTF("%qu ", (unsigned long long) fb.fr_hits); #else PRINTF("%lu ", fb.fr_hits); #endif if (opts & (OPT_ACCNT|OPT_VERBOSE)) #ifdef USE_QUAD_T PRINTF("%qu ", (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, sizeof(*fp)); 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[0] != '\0') { g = calloc(1, sizeof(*g)); if (g != NULL) { strncpy(g->fg_name, 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(out, set, fb.fr_data, group, "# callfunc: "); } } while (fb.fr_next != NULL); while ((g = grtop) != NULL) { printdeadlist(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) { #ifdef USE_INET6 if ((use_inet6) && (opts & OPT_OUTQUE)) { i = F_ACOUT; fp = (struct frentry *)fiop->f_acctout6[set]; } else if ((use_inet6) && (opts & OPT_INQUE)) { i = F_ACIN; fp = (struct frentry *)fiop->f_acctin6[set]; } else #endif 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 { #ifdef USE_INET6 if ((use_inet6) && (opts & OPT_OUTQUE)) { i = F_OUT; fp = (struct frentry *)fiop->f_fout6[set]; } else if ((use_inet6) && (opts & OPT_INQUE)) { i = F_IN; fp = (struct frentry *)fiop->f_fin6[set]; } else #endif 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_VERBOSE) FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); if (opts & OPT_VERBOSE) PRINTF("fp %p set %d\n", fp, set); if (!fp) { FPRINTF(stderr, "empty list for %s%s\n", (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); return; } if (live_kernel == 1) printlivelist(i, set, fp, NULL, NULL); else printdeadlist(i, set, fp, NULL, NULL); } /* * Display ipfilter stateful filtering information */ static void showipstates(ipsp) ips_stat_t *ipsp; { u_long minlen, maxlen, totallen, *buckets; int i, sz; sz = sizeof(*buckets) * ipsp->iss_statesize; buckets = (u_long *)malloc(sz); if (buckets == NULL) { perror("malloc"); exit(1); } if (kmemcpy((char *)buckets, (u_long)ipsp->iss_bucketlen, sz)) { free(buckets); return; } /* * If a list of states hasn't been asked for, only print out stats */ if (!(opts & OPT_SHOWLIST)) { PRINTF("IP states added:\n\t%lu TCP\n\t%lu UDP\n\t%lu ICMP\n", ipsp->iss_tcp, ipsp->iss_udp, ipsp->iss_icmp); PRINTF("\t%lu hits\n\t%lu misses\n", ipsp->iss_hits, ipsp->iss_miss); PRINTF("\t%lu maximum\n\t%lu no memory\n", ipsp->iss_max, ipsp->iss_nomem); PRINTF("\t%lu active\n\t%lu expired\n", ipsp->iss_active, ipsp->iss_expire); PRINTF("\t%lu closed\n\t%u orphans\n", ipsp->iss_fin, ipsp->iss_orphans); PRINTF("State logging %sabled\n", state_logging ? "en" : "dis"); PRINTF("\nState table bucket statistics:\n"); PRINTF("\t%lu in use\n\t%lu max bucket\n", ipsp->iss_inuse, ipsp->iss_bucketfull); minlen = ipsp->iss_max; totallen = 0; maxlen = 0; for (i = 0; i < ipsp->iss_statesize; i++) { if (buckets[i] > maxlen) maxlen = buckets[i]; if (buckets[i] < minlen) minlen = buckets[i]; totallen += buckets[i]; } PRINTF("\t%2.2f%% bucket usage\n\t%lu minimal length\n", ((float)ipsp->iss_inuse / ipsp->iss_statesize) * 100.0, minlen); PRINTF("\t%lu maximal length\n\t%.3f average 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_statesize; i++) { if ((i % ENTRIES_PER_LINE) == 0) PRINTF("\t"); PRINTF("%4d -> %4lu", i, buckets[i]); if ((i % ENTRIES_PER_LINE) == (ENTRIES_PER_LINE - 1)) PRINTF("\n"); else PRINTF(" "); } PRINTF("\n"); } PRINTF("\n"); free(buckets); return; } /* * Print out all the state information currently held in the kernel. */ while (ipsp->iss_list != NULL) { ipsp->iss_list = printstate(ipsp->iss_list, opts, ipsp->iss_ticks); } free(buckets); } #ifdef STATETOP static int handle_resize = 0, handle_break = 0; static void topipstates(saddr, daddr, sport, dport, protocol, ver, refreshtime, topclosed) i6addr_t saddr; i6addr_t daddr; int sport; int dport; int protocol; int ver; int refreshtime; int topclosed; { 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; 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_size = sizeof(*ipsstp); ipfo.ipfo_ptr = (void *)ipsstp; ipfo.ipfo_type = IPFOBJ_STATESTAT; /* 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) { if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list, sizeof(ips))) break; if (ips.is_v != ver) 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; } } /* 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"); refresh(); 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\t%lu new\n\t%lu expired\n\t%lu hits\n", ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits); PRINTF("\t%lu retrans\n\t%lu too short\n", ifsp->ifs_retrans0, ifsp->ifs_short); PRINTF("\t%lu no memory\n\t%lu already exist\n", ifsp->ifs_nomem, ifsp->ifs_exists); PRINTF("\t%lu inuse\n", ifsp->ifs_inuse); if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab))) return; /* * Print out the contents (if any) of the fragment cache table. */ PRINTF("\n"); for (i = 0; i < IPFT_SIZE; i++) while (ipfrtab[i] != NULL) { if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], sizeof(ifr)) == -1) break; ifr.ipfr_ttl -= ticks; printfraginfo("", &ifr); ipfrtab[i] = ifr.ipfr_next; } /* * Print out the contents (if any) of the NAT fragment cache table. */ if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab,sizeof(ipfrtab))) return; for (i = 0; i < IPFT_SIZE; i++) while (ipfrtab[i] != NULL) { if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], sizeof(ifr)) == -1) break; ifr.ipfr_ttl -= ticks; printfraginfo("NAT: ", &ifr); ipfrtab[i] = ifr.ipfr_next; } } /* * Show stats on how auth within IPFilter has been used */ static void showauthstates(asp) fr_authstat_t *asp; { frauthent_t *frap, fra; #ifdef USE_QUAD_T printf("Authorisation hits: %qu\tmisses %qu\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 (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 specfication in %s\n", argument); free(s); exit(-2); } *comma = '\0'; } /* get ip address */ if (!strcasecmp(s, "any")) { ip->in4.s_addr = INADDR_ANY; #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 /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include "ipf.h" #include "ipt.h" #include #include extern char *optarg; extern struct frentry *ipfilter[2][2]; extern struct ipread snoop, etherf, tcpd, pcap, iptext, iphex; extern struct ifnet *get_unit __P((char *, int, ipf_stack_t *)); extern void init_ifp __P((void)); int opts = OPT_DONOTHING; int use_inet6 = 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)); void dumpnat __P((ipf_stack_t *ifs)); void dumpstate __P((ipf_stack_t *ifs)); void dumplookups __P((ipf_stack_t *ifs)); void dumpgroups __P((ipf_stack_t *ifs)); void drain_log __P((char *, ipf_stack_t *ifs)); void fixv4sums __P((mb_t *, ip_t *)); ipf_stack_t *get_ifs __P((void)); ipf_stack_t *create_ifs __P((void)); #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(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 }; int main(argc,argv) int argc; char *argv[]; { char *datain, *iface, *ifname, *logout; int fd, i, dir, c, loaded, dump, hlen; struct ifnet *ifp; struct ipread *r; mb_t mb, *m; ip_t *ip; ipf_stack_t *ifs; m = &mb; dir = 0; dump = 0; hlen = 0; loaded = 0; r = &iptext; iface = NULL; logout = NULL; ifname = "anon0"; datain = NULL; initparse(); ifs = create_ifs(); #if defined(IPFILTER_DEFAULT_BLOCK) ifs->ifs_fr_pass = FR_BLOCK|FR_NOMATCH; #else ifs->ifs_fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; #endif ipftuneable_alloc(ifs); MUTEX_INIT(&ifs->ifs_ipf_rw, "ipf rw mutex"); MUTEX_INIT(&ifs->ifs_ipf_timeoutlock, "ipf timeout lock"); RWLOCK_INIT(&ifs->ifs_ipf_global, "ipf filter load/unload mutex"); RWLOCK_INIT(&ifs->ifs_ipf_mutex, "ipf filter rwlock"); RWLOCK_INIT(&ifs->ifs_ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); RWLOCK_INIT(&ifs->ifs_ipf_frcache, "ipf rule cache rwlock"); fr_loginit(ifs); fr_authinit(ifs); fr_fraginit(ifs); fr_stateinit(ifs); fr_natinit(ifs); appr_init(ifs); ip_lookup_init(ifs); ifs->ifs_fr_running = 1; while ((c = getopt(argc, argv, "6bdDF:i:I:l:N:P:or:RT: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 'D' : dump = 1; break; case 'F' : if (strcasecmp(optarg, "pcap") == 0) r = &pcap; else if (strcasecmp(optarg, "etherfind") == 0) r = ðerf; else if (strcasecmp(optarg, "snoop") == 0) r = &snoop; else if (strcasecmp(optarg, "tcpdump") == 0) r = &tcpd; 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 'o' : opts |= OPT_SAVEOUT; break; case 'r' : if (ipf_parsefile(-1, ipf_addrule, iocfunctions, optarg) == -1) return -1; loaded = 1; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'v' : opts |= OPT_VERBOSE; break; case 'N' : if (ipnat_parsefile(-1, ipnat_addrule, ipnattestioctl, optarg) == -1) return -1; loaded = 1; opts |= OPT_NAT; break; case 'P' : if (ippool_parsefile(-1, optarg, ipooltestioctl) == -1) return -1; loaded = 1; break; case 'T' : ipf_dotuning(-1, optarg, ipftestioctl); 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) exit(-1); ip = MTOD(m, ip_t *); while ((i = (*r->r_readip)(MTOD(m, char *), sizeof(m->mb_buf), &iface, &dir)) > 0) { if (iface == NULL || *iface == '\0') iface = ifname; ifp = get_unit(iface, IP_V(ip), ifs); if (ifp == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } if (!use_inet6) { ip->ip_off = ntohs(ip->ip_off); ip->ip_len = ntohs(ip->ip_len); if (r->r_flags & R_DO_CKSUM) fixv4sums(m, ip); hlen = IP_HL(ip) << 2; } #ifdef USE_INET6 else hlen = sizeof(ip6_t); #endif /* ipfr_slowtimer(); */ m = &mb; m->mb_len = i; i = fr_check(ip, hlen, ifp, dir, &m, ifs); 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 : (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 (!use_inet6) { ip->ip_off = htons(ip->ip_off); ip->ip_len = htons(ip->ip_len); } if (!(opts & OPT_BRIEF)) { putchar(' '); printpacket(ip); printf("--------------"); } else if ((opts & (OPT_BRIEF|OPT_NAT)) == (OPT_NAT|OPT_BRIEF)) printpacket(ip); 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 if ((opts & (OPT_BRIEF|OPT_NAT)) != (OPT_NAT|OPT_BRIEF)) putchar('\n'); dir = 0; if (iface != ifname) { free(iface); iface = ifname; } m = &mb; } (*r->r_close)(); if (logout != NULL) { drain_log(logout, ifs); } if (dump == 1) { dumpnat(ifs); dumpstate(ifs); dumplookups(ifs); dumpgroups(ifs); } fr_deinitialise(ifs); return 0; } #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(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; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGIPF, cmd, data, FWRITE|FREAD); if (opts & OPT_DEBUG) fprintf(stderr, "iplioctl(IPF,%#x,%p) = %d\n", (u_int)cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipnattestioctl(int dev, ioctlcmd_t cmd, ...) { caddr_t data; va_list ap; int i; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGNAT, cmd, data, FWRITE|FREAD); if (opts & OPT_DEBUG) fprintf(stderr, "iplioctl(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; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGSTATE, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGAUTH, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGSCAN, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGSYNC, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; va_start(ap, cmd); data = va_arg(ap, caddr_t); va_end(ap); i = iplioctl(IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(POOL,%#x,%p) = %d\n", (u_int)cmd, data, i); 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; i = iplioctl(IPL_LOGIPF, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(IPF,%#x,%p) = %d\n", cmd, data, i); if (i != 0) { errno = i; return -1; } return 0; } int ipnattestioctl(dev, cmd, data) dev_t dev; ioctlcmd_t cmd; void *data; { int i; i = iplioctl(IPL_LOGNAT, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; i = iplioctl(IPL_LOGSTATE, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; i = iplioctl(IPL_LOGAUTH, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; i = iplioctl(IPL_LOGSYNC, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; i = iplioctl(IPL_LOGSCAN, cmd, data, FWRITE|FREAD); if ((opts & OPT_DEBUG) || (i != 0)) fprintf(stderr, "iplioctl(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; i = iplioctl(IPL_LOGLOOKUP, cmd, data, FWRITE|FREAD); if (opts & OPT_DEBUG) fprintf(stderr, "iplioctl(POOL,%#x,%p) = %d\n", cmd, data, i); 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(ifs) ipf_stack_t *ifs; { ipnat_t *ipn; nat_t *nat; printf("List of active MAP/Redirect filters:\n"); for (ipn = ifs->ifs_nat_list; ipn != NULL; ipn = ipn->in_next) printnat(ipn, opts & (OPT_DEBUG|OPT_VERBOSE)); printf("\nList of active sessions:\n"); for (nat = ifs->ifs_nat_instances; nat; nat = nat->nat_next) { printactivenat(nat, opts, 0); if (nat->nat_aps) printaps(nat->nat_aps, opts); } } /* * Display the built up state table rules and mapping entries. */ void dumpstate(ifs) ipf_stack_t *ifs; { ipstate_t *ips; printf("List of active state sessions:\n"); for (ips = ifs->ifs_ips_list; ips != NULL; ) ips = printstate(ips, opts & (OPT_DEBUG|OPT_VERBOSE), ifs->ifs_fr_ticks); } void dumplookups(ifs) ipf_stack_t *ifs; { iphtable_t *iph; ip_pool_t *ipl; int i; printf("List of configured pools\n"); for (i = 0; i < IPL_LOGSIZE; i++) for (ipl = ifs->ifs_ip_pool_list[i]; ipl != NULL; ipl = ipl->ipo_next) printpool(ipl, bcopywrap, NULL, opts); printf("List of configured hash tables\n"); for (i = 0; i < IPL_LOGSIZE; i++) for (iph = ifs->ifs_ipf_htables[i]; iph != NULL; iph = iph->iph_next) printhash(iph, bcopywrap, NULL, opts); } void dumpgroups(ifs) ipf_stack_t *ifs; { frgroup_t *fg; frentry_t *fr; int i; printf("List of groups configured (set 0)\n"); for (i = 0; i < IPL_LOGSIZE; i++) for (fg = ifs->ifs_ipfgroups[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); for (fr = fg->fg_start; fr != NULL; fr = fr->fr_next) { #ifdef USE_QUAD_T printf("%qu ",(unsigned long long)fr->fr_hits); #else printf("%ld ", fr->fr_hits); #endif printfr(fr, ipftestioctl); } } printf("List of groups configured (set 1)\n"); for (i = 0; i < IPL_LOGSIZE; i++) for (fg = ifs->ifs_ipfgroups[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); for (fr = fg->fg_start; fr != NULL; fr = fr->fr_next) { #ifdef USE_QUAD_T printf("%qu ",(unsigned long long)fr->fr_hits); #else printf("%ld ", fr->fr_hits); #endif printfr(fr, ipftestioctl); } } } void drain_log(filename, ifs) char *filename; ipf_stack_t *ifs; { 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 (ipflog_read(i, &uio, ifs) == 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; ip->ip_sum = 0; ip->ip_sum = ipf_cksum((u_short *)ip, IP_HL(ip) << 2); csump = (u_char *)ip; csump += IP_HL(ip) << 2; switch (ip->ip_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; default : csump = NULL; hdr = NULL; break; } if (hdr != NULL) { *csump = 0; *(u_short *)csump = fr_cksum(m, ip, ip->ip_p, hdr); } } ipf_stack_t *gifs; /* * Allocate and keep pointer for get_ifs() */ ipf_stack_t * create_ifs() { ipf_stack_t *ifs; KMALLOCS(ifs, ipf_stack_t *, sizeof (*ifs)); bzero(ifs, sizeof (*ifs)); gifs = ifs; return (ifs); } ipf_stack_t * get_ifs() { return (gifs); } /* * Copyright (c) 2014 Joyent, Inc. All rights reserved. * Use is subject to license terms. * * See the IPFILTER.LICENCE file for details on licensing. */ #include #include #include #include #include #include #include "netinet/ip_fil.h" #include "ipfzone.h" static ipfzoneobj_t ipzo; static boolean_t do_setzone = 0; static int num_setzones = 0; extern int errno; extern int opterr; extern int optind; extern char *optarg; /* * Get the zonename if it's the last argument and set the zonename * in ipfzo to it. This is used by ipf(8) only - all of the other tools * specify the zone with the -z option, and therefore use getzoneopt() below. */ void getzonearg(int argc, char *argv[], const char *optstr) { int c; /* * Don't warn about unknown options - let subsequent calls to * getopt() handle this. */ opterr = 0; /* * getopt is also used here to set optind so that we can * determine if the last argument belongs to a flag or is * actually a zonename. */ while ((c = getopt(argc, argv, optstr)) != -1) { if (c == 'G') ipzo.ipfz_gz = 1; } if (optind < argc) setzonename(argv[optind]); /* * Reset optind and opterr so the next getopt call will go through all * of argv again and warn about unknown options. */ optind = 1; opterr = 1; } /* * Get a -z option from argv and set the zonename in ipfzo accordingly */ void getzoneopt(int argc, char *argv[], const char *optstr) { int c; /* * Don't warn about unknown options - let subsequent calls to * getopt() handle this. */ opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { if (c == 'G') setzonename_global(optarg); if (c == 'z') setzonename(optarg); } /* * Reset optind and opterr so the next getopt call will go through all * of argv again and warn about unknown options. */ optind = 1; opterr = 1; } /* * Set the zonename in ipfzo to the given string: this is the zone all further * ioctls will act on. */ void setzonename(const char *zonename) { memcpy(ipzo.ipfz_zonename, zonename, sizeof (ipzo.ipfz_zonename)); do_setzone = B_TRUE; num_setzones++; } /* * Set the zonename in ipfo, and the gz flag. This indicates that we want all * further ioctls to act on the GZ-controlled stack for that zone. */ void setzonename_global(const char *zonename) { setzonename(zonename); ipzo.ipfz_gz = 1; } /* * Set the zone that all further ioctls will operate on. See the "GZ-controlled * and per-zone stacks" note at the top of ip_fil_solaris.c for further * explanation. */ int setzone(int fd) { if (!do_setzone) return (0); if (num_setzones > 1) { (void) fprintf(stderr, "Only one of -G and -z may be set\n"); return (-1); } if (ipzo.ipfz_gz == 1 && getzoneidbyname(ipzo.ipfz_zonename) == GLOBAL_ZONEID) { (void) fprintf(stderr, "-G cannot be used with the global zone\n"); return (-1); } if (ioctl(fd, SIOCIPFZONESET, &ipzo) == -1) { switch (errno) { case ENODEV: (void) fprintf(stderr, "Could not find running zone: %s\n", ipzo.ipfz_zonename); break; case EACCES: (void) fprintf(stderr, "Permission denied setting zone: %s\n", ipzo.ipfz_zonename); break; default: perror("Error setting zone"); } return (-1); } return (0); } /* * Copyright (c) 2013 Joyent, Inc. All rights reserved. * Use is subject to license terms. * * See the IPFILTER.LICENCE file for details on licensing. */ #ifndef __IPFZONE_H__ #define __IPFZONE_H__ void getzonearg(int, char *[], const char *); void getzoneopt(int, char *[], const char *); int setzone(int); void setzonename(const char *); void setzonename_global(const char *); #endif /* __IPFZONE_H__ */ /* * Copyright (C) 2001-2008 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #ifdef SOLARIS #undef SOLARIS #endif #if (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #define SOLARIS (1) #else #define SOLARIS (0) #endif #include #include #include #include #include #define _KERNEL #include #undef _KERNEL #include #include #include #include #include #include #include #include #if !defined(__SVR4) && !defined(__svr4__) # if (__FreeBSD_version >= 300000) # include # else # include # endif #else # include # include #endif #if !defined(__hpux) && (!defined(__SVR4) && !defined(__GNUC__)) # include #endif #include #include #include #include #include #include #include #if !defined(__hpux) && !defined(linux) # include #endif #include #include #include #ifdef __hpux # undef NOERROR #endif #include #if !defined(linux) # include # include #endif #include #include #include #include #include "netinet/ip_compat.h" #include #include "netinet/ip_fil.h" #include "netinet/ip_nat.h" #include "netinet/ip_state.h" #include "netinet/ip_proxy.h" #include "ipmon.h" #include "ipfzone.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: ipmon.c,v 1.33.2.10 2005/06/18 02:41:35 darrenr Exp $"; #endif #if defined(sun) && !defined(SOLARIS2) #define STRERROR(x) sys_errlist[x] extern char *sys_errlist[]; #else #define STRERROR(x) strerror(x) #endif struct flags { int value; char flag; }; 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' } }; #if defined(__hpux) || (defined(SOLARIS) && (SOLARIS2 < 10)) static char *pidfile = "/etc/ipf/ipmon.pid"; #else # if (BSD >= 199306) || defined(SOLARIS) static char *pidfile = "/var/run/ipmon.pid"; # else static char *pidfile = "/etc/ipmon.pid"; # endif #endif static char line[2048]; static int opts = 0; static char *logfile = NULL; static FILE *binarylog = NULL; static char *binarylogfile = NULL; 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((int, FILE *, char *, int)); static void print_ipflog __P((FILE *, char *, int)); static void print_natlog __P((FILE *, char *, int)); static void print_statelog __P((FILE *, 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 *hostname __P((int, int, u_32_t *)); char *portname __P((int, char *, u_int)); int main __P((int, char *[])); static void logopts __P((int, char *)); static void init_tabs __P((void)); static char *getproto __P((u_int)); static char **protocols = NULL; static char **udp_ports = NULL; static char **tcp_ports = NULL; static char *conf_file = NULL; #define OPT_SYSLOG 0x001 #define OPT_RESOLVE 0x002 #define OPT_HEXBODY 0x004 #define OPT_VERBOSE 0x008 #define OPT_HEXHDR 0x010 #define OPT_TAIL 0x020 #define OPT_NAT 0x080 #define OPT_STATE 0x100 #define OPT_FILTER 0x200 #define OPT_PORTNUM 0x400 #define OPT_LOGALL (OPT_NAT|OPT_STATE|OPT_FILTER) #define OPT_LOGBODY 0x800 #define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) #ifndef LOGFAC #define LOGFAC LOG_LOCAL0 #endif 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 icmptypes[] = { { 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 defined(_AIX51) if (protocols[0]) free(protocols[0]); if (protocols[252]) free(protocols[252]); protocols[0] = "ip"; 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 *getproto(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; nr = read(fd, buf, bufsize); if (!nr) return 2; if ((nr < 0) && (errno != EINTR)) return -1; *lenp = nr; return 0; } char *hostname(res, v, ip) int res, v; u_32_t *ip; { # define MAX_INETA 16 static char hname[MAXHOSTNAMELEN + MAX_INETA + 3]; #ifdef USE_INET6 static char hostbuf[MAXHOSTNAMELEN+1]; #endif struct hostent *hp; struct in_addr ipa; if (v == 4) { ipa.s_addr = *ip; if (!res) return inet_ntoa(ipa); hp = gethostbyaddr((char *)ip, sizeof(*ip), AF_INET); if (!hp) return inet_ntoa(ipa); sprintf(hname, "%.*s[%s]", MAXHOSTNAMELEN, hp->h_name, inet_ntoa(ipa)); return hname; } #ifdef USE_INET6 (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); hostbuf[MAXHOSTNAMELEN] = '\0'; return hostbuf; #else return "IPv6"; #endif } char *portname(res, proto, port) int res; char *proto; u_int port; { static char pname[8]; char *s; port = ntohs(port); port &= 0xffff; (void) sprintf(pname, "%u", port); if (!res || (opts & OPT_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, icmptypes, sizeof(icmptypes) / 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 & OPT_SYSLOG)) fputs(hline, log); else syslog(LOG_INFO, "%s", hline); 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 & OPT_SYSLOG)) { fputs(hline, log); fflush(log); } else syslog(LOG_INFO, "%s", hline); } 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(log, buf, blen) FILE *log; char *buf; int blen; { struct natlog *nl; iplog_t *ipl = (iplog_t *)buf; char *t = line; struct tm *tm; int res, i, len; char *proto; nl = (struct natlog *)((char *)ipl + sizeof(*ipl)); res = (opts & OPT_RESOLVE) ? 1 : 0; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(opts & OPT_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); (void) sprintf(t, ".%-.6ld @%hd ", ipl->ipl_usec, nl->nlg_rule + 1); t += strlen(t); if (nl->nlg_type == NL_NEWMAP) strcpy(t, "NAT:MAP "); else if (nl->nlg_type == NL_NEWRDR) strcpy(t, "NAT:RDR "); else if (nl->nlg_type == NL_FLUSH) strcpy(t, "NAT:FLUSH "); else if (nl->nlg_type == NL_EXPIRE) strcpy(t, "NAT:EXPIRE "); else if (nl->nlg_type == NL_NEWBIMAP) strcpy(t, "NAT:BIMAP "); else if (nl->nlg_type == NL_NEWBLOCK) strcpy(t, "NAT:MAPBLOCK "); else if (nl->nlg_type == NL_CLONE) strcpy(t, "NAT:CLONE "); else sprintf(t, "Type: %d ", nl->nlg_type); t += strlen(t); proto = getproto(nl->nlg_p); (void) sprintf(t, "%s,%s <- -> ", hostname(res, nl->nlg_v, (u_32_t *)&nl->nlg_inip), portname(res, proto, (u_int)nl->nlg_inport)); t += strlen(t); (void) sprintf(t, "%s,%s ", hostname(res, nl->nlg_v, (u_32_t *)&nl->nlg_outip), portname(res, proto, (u_int)nl->nlg_outport)); t += strlen(t); (void) sprintf(t, "[%s,%s]", hostname(res, nl->nlg_v, (u_32_t *)&nl->nlg_origip), portname(res, proto, (u_int)nl->nlg_origport)); t += strlen(t); if (nl->nlg_type == NL_EXPIRE) { #ifdef USE_QUAD_T (void) sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd", (long long)nl->nlg_pkts[0], (long long)nl->nlg_pkts[1], (long long)nl->nlg_bytes[0], (long long)nl->nlg_bytes[1]); #else (void) sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld", nl->nlg_pkts[0], nl->nlg_pkts[1], nl->nlg_bytes[0], nl->nlg_bytes[1]); #endif t += strlen(t); } *t++ = '\n'; *t++ = '\0'; if (opts & OPT_SYSLOG) syslog(LOG_INFO, "%s", line); else (void) fprintf(log, "%s", line); } static void print_statelog(log, buf, blen) FILE *log; char *buf; int blen; { struct ipslog *sl; iplog_t *ipl = (iplog_t *)buf; char *t = line, *proto; struct tm *tm; int res, i, len; sl = (struct ipslog *)((char *)ipl + sizeof(*ipl)); res = (opts & OPT_RESOLVE) ? 1 : 0; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(opts & OPT_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); (void) sprintf(t, ".%-.6ld ", ipl->ipl_usec); t += strlen(t); if (sl->isl_type == ISL_NEW) strcpy(t, "STATE:NEW "); else if (sl->isl_type == ISL_CLONE) strcpy(t, "STATE:CLONED "); else if (sl->isl_type == 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 "); } else if (sl->isl_type == ISL_FLUSH) strcpy(t, "STATE:FLUSH "); else if (sl->isl_type == ISL_INTERMEDIATE) strcpy(t, "STATE:INTERMEDIATE "); else if (sl->isl_type == ISL_REMOVE) strcpy(t, "STATE:REMOVE "); else if (sl->isl_type == ISL_KILLED) strcpy(t, "STATE:KILLED "); else sprintf(t, "Type: %d ", sl->isl_type); t += strlen(t); proto = getproto(sl->isl_p); if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { (void) sprintf(t, "%s,%s -> ", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src), portname(res, proto, (u_int)sl->isl_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), portname(res, proto, (u_int)sl->isl_dport), proto); } else if (sl->isl_p == IPPROTO_ICMP) { (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src)); t += strlen(t); (void) sprintf(t, "%s PR icmp %d", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), sl->isl_itype); } else if (sl->isl_p == IPPROTO_ICMPV6) { (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src)); t += strlen(t); (void) sprintf(t, "%s PR icmpv6 %d", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), sl->isl_itype); } else { (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src)); t += strlen(t); (void) sprintf(t, "%s PR %s", hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), proto); } t += strlen(t); if (sl->isl_tag != FR_NOLOGTAG) { (void) 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 (opts & OPT_SYSLOG) syslog(LOG_INFO, "%s", line); else (void) fprintf(log, "%s", line); } static void print_log(logtype, log, buf, blen) FILE *log; char *buf; int logtype, blen; { iplog_t *ipl; char *bp = NULL, *bpo = NULL; int psize; while (blen > 0) { ipl = (iplog_t *)buf; if ((u_long)ipl & (sizeof(long)-1)) { if (bp) bpo = bp; bp = (char *)malloc(blen); if (bp == NULL) { perror("malloc"); exit(1); } bcopy((char *)ipl, bp, blen); if (bpo) { free(bpo); bpo = NULL; } buf = bp; continue; } psize = ipl->ipl_dsize; if (psize > blen) break; if (binarylog) { fwrite(buf, psize, 1, binarylog); fflush(binarylog); } if (logtype == IPL_LOGIPF) { if (ipl->ipl_magic == IPL_MAGIC) print_ipflog(log, buf, psize); } else if (logtype == IPL_LOGNAT) { if (ipl->ipl_magic == IPL_MAGIC_NAT) print_natlog(log, buf, psize); } else if (logtype == IPL_LOGSTATE) { if (ipl->ipl_magic == IPL_MAGIC_STATE) print_statelog(log, buf, psize); } blen -= psize; buf += psize; } if (bp) free(bp); return; } static void print_ipflog(log, buf, blen) FILE *log; char *buf; int blen; { tcphdr_t *tp; struct icmp *ic; struct icmp *icmp; struct tm *tm; char *t, *proto; int i, v, lvl, res, len, off, plen, ipoff, defaction; ip_t *ipc, *ip; u_32_t *s, *d; u_short hl, p; ipflog_t *ipf; iplog_t *ipl; #ifdef USE_INET6 ip6_t *ip6; #endif ipl = (iplog_t *)buf; ipf = (ipflog_t *)((char *)buf + sizeof(*ipl)); ip = (ip_t *)((char *)ipf + sizeof(*ipf)); v = IP_V(ip); res = (opts & OPT_RESOLVE) ? 1 : 0; t = line; *t = '\0'; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(opts & OPT_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); (void) sprintf(t, ".%-.6ld ", ipl->ipl_usec); t += strlen(t); if (ipl->ipl_count > 1) { (void) 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'; (void) sprintf(t, "%s", ifname); t += strlen(t); # if defined(MENTAT) || defined(linux) 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++; (void) sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit); t += strlen(t); #endif #if defined(__sgi) || defined(_AIX51) || defined(__powerpc__) || \ defined(__arm__) if ((ipf->fl_group[0] == 255) && (ipf->fl_group[1] == '\0')) #else if ((ipf->fl_group[0] == -1) && (ipf->fl_group[1] == '\0')) #endif strcat(t, " @-1:"); else if (ipf->fl_group[0] == '\0') (void) strcpy(t, " @0:"); else (void) sprintf(t, " @%s:", ipf->fl_group); t += strlen(t); if (ipf->fl_rule == 0xffffffff) strcat(t, "-1 "); else (void) 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 (v == 6) { #ifdef USE_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); #else sprintf(t, "ipv6"); goto printipflog; #endif } else if (v == 4) { hl = IP_HL(ip) << 2; ipoff = 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 = ip->ip_len; } else { goto printipflog; } proto = getproto(p); if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { tp = (tcphdr_t *)((char *)ip + hl); if (!(ipf->fl_lflags & FI_SHORT)) { (void) sprintf(t, "%s,%s -> ", hostname(res, v, s), portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s len %hu %hu", hostname(res, v, d), portname(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 (opts & OPT_VERBOSE) { (void) 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 { (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR %s len %hu %hu", hostname(res, v, d), proto, hl, plen); } } else if ((p == IPPROTO_ICMPV6) && !off && (v == 6)) { ic = (struct icmp *)((char *)ip + hl); (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s", hostname(res, v, d), hl, plen, icmpname6(ic->icmp_type, ic->icmp_code)); } else if ((p == IPPROTO_ICMP) && !off && (v == 4)) { ic = (struct icmp *)((char *)ip + hl); (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR icmp len %hu %hu icmp %s", hostname(res, v, 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 = getproto(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); (void) sprintf(t, " for %s,%s -", HOSTNAME_V4(res, ipc->ip_src), portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, " %s,%s PR %s len %hu %hu", HOSTNAME_V4(res, ipc->ip_dst), portname(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); (void) sprintf(t, " for %s -", HOSTNAME_V4(res, ipc->ip_src)); t += strlen(t); (void) sprintf(t, " %s PR icmp len %hu %hu icmp %d/%d", HOSTNAME_V4(res, ipc->ip_dst), IP_HL(ipc) << 2, i, icmp->icmp_type, icmp->icmp_code); } else { t += strlen(t); (void) sprintf(t, " for %s -", HOSTNAME_V4(res, ipc->ip_src)); t += strlen(t); (void) sprintf(t, " %s PR %s len %hu (%hu)", HOSTNAME_V4(res, ipc->ip_dst), proto, IP_HL(ipc) << 2, i); t += strlen(t); if (ipoff & IP_OFFMASK) { (void) 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 { (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR %s len %hu (%hu)", hostname(res, v, d), proto, hl, plen); t += strlen(t); if (off & IP_OFFMASK) (void) 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) { if (ipf->fl_lflags & FI_NEG_OOW) { strcpy(t, " NEG_OOW"); t += sizeof (" NEG_OOW") - 1; } else { strcpy(t, " OOW"); t += sizeof (" OOW") - 1; } } 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; } *t++ = '\n'; *t++ = '\0'; defaction = 0; if (conf_file != NULL) defaction = check_action(buf, line, opts, lvl); if (defaction == 0) { if (opts & OPT_SYSLOG) syslog(lvl, "%s", line); else (void) fprintf(log, "%s", line); if (opts & OPT_HEXHDR) dumphex(log, opts, buf, sizeof(iplog_t) + sizeof(*ipf)); if (opts & OPT_HEXBODY) dumphex(log, opts, (char *)ip, ipf->fl_plen + ipf->fl_hlen); else if ((opts & OPT_LOGBODY) && (ipf->fl_flags & FR_LOGBODY)) dumphex(log, opts, (char *)ip + ipf->fl_hlen, ipf->fl_plen); } } static void usage(prog) char *prog; { fprintf(stderr, "%s: [-abDFhnpstvxX] %s %s %s %s %s %s %s\n", prog, "[-G|-z zonename]", "[-N device]", "[ [-o [NSI]] [-O [NSI]]", "[-P pidfile]", "[-S device]", "[-f device]", "filename"); 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 (setzone(fd) != 0) { close(fd); exit(1); } if (ioctl(fd, SIOCIPFFB, &flushed) == 0) { printf("%d bytes flushed from log buffer\n", flushed); fflush(stdout); } else perror("SIOCIPFFB"); (void) close(fd); if (flushed) { if (opts & OPT_SYSLOG) syslog(LOG_INFO, "%d bytes flushed from log\n", flushed); else if (log != stdout) 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 |= OPT_NAT; break; case 'S' : flags |= OPT_STATE; break; case 'I' : flags |= OPT_FILTER; break; default : fprintf(stderr, "Unknown log option %c\n", *s); exit(1); } } if (turnon) opts |= flags; else opts &= ~(flags); } int main(argc, argv) int argc; char *argv[]; { struct stat sb; FILE *log = stdout; FILE *fp; int fd[3], doread, n, i; int tr, nr, regular[3], c; int fdt[3], devices = 0, make_daemon = 0; char buf[DEFAULT_IPFLOGSIZE], *iplfile[3], *s; extern int optind; extern char *optarg; const char *optstr = "?abB:C:Df:G:FhnN:o:O:pP:sS:tvxXz:"; fd[0] = fd[1] = fd[2] = -1; fdt[0] = fdt[1] = fdt[2] = -1; iplfile[0] = IPL_NAME; iplfile[1] = IPNAT_NAME; iplfile[2] = IPSTATE_NAME; /* * We need to set the zone name before calling openlog in * the switch statement below */ getzoneopt(argc, argv, optstr); while ((c = getopt(argc, argv, optstr)) != -1) switch (c) { case 'a' : opts |= OPT_LOGALL; fdt[0] = IPL_LOGIPF; fdt[1] = IPL_LOGNAT; fdt[2] = IPL_LOGSTATE; break; case 'b' : opts |= OPT_LOGBODY; break; case 'B' : binarylogfile = optarg; binarylog = fopen(optarg, "a"); break; case 'C' : conf_file = optarg; break; case 'D' : make_daemon = 1; break; case 'f' : case 'I' : opts |= OPT_FILTER; fdt[0] = IPL_LOGIPF; iplfile[0] = optarg; break; case 'F' : flushlogs(iplfile[0], log); flushlogs(iplfile[1], log); flushlogs(iplfile[2], log); break; case 'G' : /* Already handled by getzoneopt() above */ break; case 'n' : opts |= OPT_RESOLVE; break; case 'N' : opts |= OPT_NAT; fdt[1] = IPL_LOGNAT; iplfile[1] = optarg; break; case 'o' : case 'O' : logopts(c == 'o', optarg); fdt[0] = fdt[1] = fdt[2] = -1; if (opts & OPT_FILTER) fdt[0] = IPL_LOGIPF; if (opts & OPT_NAT) fdt[1] = IPL_LOGNAT; if (opts & OPT_STATE) fdt[2] = IPL_LOGSTATE; break; case 'p' : opts |= OPT_PORTNUM; break; case 'P' : pidfile = optarg; break; case 's' : s = strrchr(argv[0], '/'); if (s == NULL) s = argv[0]; else s++; openlog(s, LOG_NDELAY|LOG_PID, LOGFAC); s = NULL; opts |= OPT_SYSLOG; log = NULL; break; case 'S' : opts |= OPT_STATE; fdt[2] = IPL_LOGSTATE; iplfile[2] = optarg; break; case 't' : opts |= OPT_TAIL; break; case 'v' : opts |= OPT_VERBOSE; break; case 'x' : opts |= OPT_HEXBODY; break; case 'X' : opts |= OPT_HEXHDR; break; case 'z' : /* Already handled by getzoneopt() above */ break; default : case 'h' : case '?' : usage(argv[0]); } init_tabs(); if (conf_file) if (load_config(conf_file) == -1) exit(1); /* * Default action is to only open the filter log file. */ if ((fdt[0] == -1) && (fdt[1] == -1) && (fdt[2] == -1)) fdt[0] = IPL_LOGIPF; for (i = 0; i < 3; i++) { if (fdt[i] == -1) continue; if (!strcmp(iplfile[i], "-")) fd[i] = 0; else { if ((fd[i] = open(iplfile[i], O_RDONLY)) == -1) { (void) fprintf(stderr, "%s: open: %s\n", iplfile[i], STRERROR(errno)); exit(1); /* NOTREACHED */ } if (fstat(fd[i], &sb) == -1) { (void) fprintf(stderr, "%d: fstat: %s\n", fd[i], STRERROR(errno)); exit(1); /* NOTREACHED */ } if (setzone(fd[i]) != 0) { close(fd[i]); exit(1); } if (!(regular[i] = !S_ISCHR(sb.st_mode))) devices++; } } if (!(opts & OPT_SYSLOG)) { logfile = argv[optind]; log = logfile ? fopen(logfile, "a") : stdout; if (log == NULL) { (void) fprintf(stderr, "%s: fopen: %s\n", argv[optind], STRERROR(errno)); exit(1); /* NOTREACHED */ } setvbuf(log, NULL, _IONBF, 0); } else log = NULL; if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) { #if BSD >= 199306 daemon(0, !(opts & OPT_SYSLOG)); #else int pid; if ((pid = fork()) > 0) exit(0); if (pid < 0) { (void) fprintf(stderr, "%s: fork() failed: %s\n", argv[0], STRERROR(errno)); exit(1); /* NOTREACHED */ } setsid(); if ((opts & OPT_SYSLOG)) close(2); #endif /* !BSD */ close(0); close(1); } write_pid(pidfile); signal(SIGHUP, handlehup); for (doread = 1; doread; ) { nr = 0; for (i = 0; i < 3; i++) { tr = 0; if (fdt[i] == -1) continue; if (!regular[i]) { if (ioctl(fd[i], FIONREAD, &tr) == -1) { if (opts & OPT_SYSLOG) syslog(LOG_CRIT, "ioctl(FIONREAD): %m"); else perror("ioctl(FIONREAD)"); exit(1); /* NOTREACHED */ } } else { tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size); if (!tr && !(opts & OPT_TAIL)) doread = 0; } if (!tr) continue; nr += tr; tr = read_log(fd[i], &n, buf, sizeof(buf)); if (donehup) { if (logfile && (fp = fopen(logfile, "a"))) { fclose(log); log = fp; } if (binarylogfile && (fp = fopen(binarylogfile, "a"))) { fclose(binarylog); binarylog = fp; } init_tabs(); if (conf_file != NULL) load_config(conf_file); donehup = 0; } switch (tr) { case -1 : if (opts & OPT_SYSLOG) syslog(LOG_CRIT, "read: %m\n"); else perror("read"); doread = 0; break; case 1 : if (opts & OPT_SYSLOG) syslog(LOG_CRIT, "aborting logging\n"); else fprintf(log, "aborting logging\n"); doread = 0; break; case 2 : break; case 0 : if (n > 0) { print_log(fdt[i], log, buf, n); if (!(opts & OPT_SYSLOG)) fflush(log); } break; } } if (!nr && ((opts & OPT_TAIL) || devices)) sleep(1); } return(0); /* NOTREACHED */ } /* * Copyright (C) 1993-2005 by Darren Reed. * See the IPFILTER.LICENCE file for details on licencing. */ %{ #include "ipf.h" #include #undef OPT_NAT #undef OPT_VERBOSE #include "ipmon_l.h" #include "ipmon.h" #define YYDEBUG 1 extern int yyerror __P((const char *)); extern int yyparse __P((void)); extern int yylex __P((void)); extern int yydebug; extern FILE *yyin; extern int yylineNum; typedef struct opt { struct opt *o_next; int o_line; int o_type; int o_num; char *o_str; struct in_addr o_ip; } opt_t; static void build_action __P((struct opt *)); static opt_t *new_opt __P((int)); static void free_action __P((ipmon_action_t *)); static ipmon_action_t *alist = NULL; %} %union { char *str; u_32_t num; struct in_addr addr; struct opt *opt; union i6addr ip6; } %token YY_NUMBER YY_HEX %token YY_STR %token 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_EXECUTE IPM_GROUP IPM_INTERFACE IPM_IN IPM_NO IPM_OUT %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_SAVE IPM_SYSLOG IPM_NOTHING IPM_RAW IPM_TYPE IPM_NAT %token IPM_STATE IPM_NATTAG IPM_IPF %type ipv4 %type direction dstip dstport every execute group interface %type protocol result rule srcip srcport logtag matching %type matchopt nattag type doopt doing save syslog nothing %type saveopts saveopt typeopt %% file: line | assign | file line | file assign ; line: IPM_MATCH '{' matching '}' IPM_DO '{' doing '}' ';' { build_action($3); resetlexer(); } | IPM_COMMENT | YY_COMMENT ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); } ; 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->o_next = $3; $$ = $1; } ; doopt: execute { $$ = $1; } | save { $$ = $1; } | syslog { $$ = $1; } | nothing { $$ = $1; } ; 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; } ; execute: IPM_EXECUTE YY_STR { $$ = new_opt(IPM_EXECUTE); $$->o_str = $2; } ; save: IPM_SAVE saveopts YY_STR { $$ = new_opt(IPM_SAVE); $$->o_num = $2; $$->o_str = $3; } ; saveopts: { $$ = 0; } | saveopt { $$ = $1; } | saveopt ',' saveopts { $$ = $1 | $3; } ; saveopt: IPM_RAW { $$ = IPMDO_SAVERAW; } ; syslog: IPM_SYSLOG { $$ = new_opt(IPM_SYSLOG); } ; nothing: IPM_NOTHING { $$ = 0; } ; 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 }, { "execute", IPM_EXECUTE }, { "group", IPM_GROUP }, { "in", IPM_IN }, { "interface", IPM_INTERFACE }, { "ipf", IPM_IPF }, { "logtag", IPM_LOGTAG }, { "match", IPM_MATCH }, { "nat", IPM_NAT }, { "nattag", IPM_NATTAG }, { "no", IPM_NO }, { "nothing", IPM_NOTHING }, { "out", IPM_OUT }, { "packet", IPM_PACKET }, { "packets", IPM_PACKETS }, { "protocol", IPM_PROTOCOL }, { "result", IPM_RESULT }, { "rule", IPM_RULE }, { "save", IPM_SAVE }, { "raw", IPM_RAW }, { "second", IPM_SECOND }, { "seconds", IPM_SECONDS }, { "srcip", IPM_SRCIP }, { "srcport", IPM_SRCPORT }, { "state", IPM_STATE }, { "syslog", IPM_SYSLOG }, { "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 *)malloc(sizeof(*o)); if (o == NULL) yyerror("sorry, out of memory"); o->o_type = type; o->o_line = yylineNum; o->o_num = 0; o->o_str = (char *)0; o->o_next = NULL; return o; } static void build_action(olist) opt_t *olist; { ipmon_action_t *a; opt_t *o; char c; 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_EXECUTE : a->ac_exec = o->o_str; c = *o->o_str; if (c== '"'|| c == '\'') { if (o->o_str[strlen(o->o_str) - 1] == c) { a->ac_run = strdup(o->o_str + 1); a->ac_run[strlen(a->ac_run) - 1] ='\0'; } else a->ac_run = o->o_str; } else a->ac_run = o->o_str; o->o_str = NULL; 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_SAVE : if (a->ac_savefile != NULL) { fprintf(stderr, "%s redfined on line %d\n", yykeytostr(o->o_type), yylineNum); break; } a->ac_savefile = strdup(o->o_str); a->ac_savefp = fopen(o->o_str, "a"); a->ac_dflag |= o->o_num & IPMDO_SAVERAW; break; case IPM_SYSLOG : if (a->ac_syslog != 0) { fprintf(stderr, "%s redfined on line %d\n", yykeytostr(o->o_type), yylineNum); break; } a->ac_syslog = 1; 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_next = alist; alist = a; } int check_action(buf, log, opts, lvl) char *buf, *log; int opts, lvl; { ipmon_action_t *a; struct timeval tv; 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)); for (a = alist; a != NULL; a = a->ac_next) { if ((a->ac_mflag & IPMAC_DIRECTION) != 0) { if (a->ac_direction == IPM_IN) { if ((ipf->fl_flags & FR_INQUE) == 0) continue; } else if (a->ac_direction == IPM_OUT) { if ((ipf->fl_flags & FR_OUTQUE) == 0) continue; } } if ((a->ac_type != 0) && (a->ac_type != ipl->ipl_magic)) 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) 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; continue; } else { a->ac_pktcnt++; continue; } } } if ((a->ac_mflag & IPMAC_DSTIP) != 0) { if ((ip->ip_dst.s_addr & a->ac_dmsk) != a->ac_dip) continue; } if ((a->ac_mflag & IPMAC_DSTPORT) != 0) { if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) continue; if (tcp->th_dport != a->ac_dport) continue; } if ((a->ac_mflag & IPMAC_GROUP) != 0) { if (strncmp(a->ac_group, ipf->fl_group, FR_GROUPLEN) != 0) continue; } if ((a->ac_mflag & IPMAC_INTERFACE) != 0) { if (strcmp(a->ac_iface, ipf->fl_ifname)) continue; } if ((a->ac_mflag & IPMAC_PROTOCOL) != 0) { if (a->ac_proto != ip->ip_p) continue; } if ((a->ac_mflag & IPMAC_RESULT) != 0) { if ((ipf->fl_flags & FF_LOGNOMATCH) != 0) { if (a->ac_result != IPMR_NOMATCH) continue; } else if (FR_ISPASS(ipf->fl_flags)) { if (a->ac_result != IPMR_PASS) continue; } else if (FR_ISBLOCK(ipf->fl_flags)) { if (a->ac_result != IPMR_BLOCK) continue; } else { /* Log only */ if (a->ac_result != IPMR_LOG) continue; } } if ((a->ac_mflag & IPMAC_RULE) != 0) { if (a->ac_rule != ipf->fl_rule) continue; } if ((a->ac_mflag & IPMAC_SRCIP) != 0) { if ((ip->ip_src.s_addr & a->ac_smsk) != a->ac_sip) continue; } if ((a->ac_mflag & IPMAC_SRCPORT) != 0) { if (ip->ip_p != IPPROTO_UDP && ip->ip_p != IPPROTO_TCP) continue; if (tcp->th_sport != a->ac_sport) continue; } if ((a->ac_mflag & IPMAC_LOGTAG) != 0) { if (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) continue; } matched = 1; /* * It matched so now execute the command */ if (a->ac_syslog != 0) { syslog(lvl, "%s", log); } if (a->ac_savefp != NULL) { if (a->ac_dflag & IPMDO_SAVERAW) fwrite(ipl, 1, ipl->ipl_dsize, a->ac_savefp); else fputs(log, a->ac_savefp); } if (a->ac_exec != NULL) { switch (fork()) { case 0 : { FILE *pi; pi = popen(a->ac_run, "w"); if (pi != NULL) { fprintf(pi, "%s\n", log); if ((opts & OPT_HEXHDR) != 0) { dumphex(pi, 0, buf, sizeof(*ipl) + sizeof(*ipf)); } if ((opts & OPT_HEXBODY) != 0) { dumphex(pi, 0, (char *)ip, ipf->fl_hlen + ipf->fl_plen); } pclose(pi); } exit(1); } case -1 : break; default : break; } } } return matched; } static void free_action(a) ipmon_action_t *a; { if (a->ac_savefile != NULL) { free(a->ac_savefile); a->ac_savefile = NULL; } if (a->ac_savefp != NULL) { fclose(a->ac_savefp); a->ac_savefp = NULL; } if (a->ac_exec != NULL) { free(a->ac_exec); if (a->ac_run == a->ac_exec) a->ac_run = NULL; a->ac_exec = NULL; } if (a->ac_run != NULL) { free(a->ac_run); a->ac_run = NULL; } 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; { ipmon_action_t *a; FILE *fp; char *s; s = getenv("YYDEBUG"); if (s != NULL) yydebug = atoi(s); else yydebug = 0; while ((a = alist) != NULL) { alist = a->ac_next; free_action(a); } 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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Added redirect stuff and a variety of bug fixes. (mcn@EnGarde.com) * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. */ #include #include #include #include #include #if !defined(__SVR4) && !defined(__svr4__) #include #else #include #endif #include #include #include #include #include #include #define _KERNEL #include #undef _KERNEL #include #include #if defined(sun) && (defined(__svr4__) || defined(__SVR4)) #include #include #endif #include #include #include #include #include #if __FreeBSD_version >= 300000 #include #endif #include #include #include #include #include #if defined(linux) #include #else #include #endif #include "ipf.h" #include "netinet/ipl.h" #include "kmem.h" #include "ipfzone.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 int use_inet6 = 0; extern char thishost[MAXHOSTNAMELEN]; extern char *optarg; void dostats __P((int, natstat_t *, int, int)); void flushtable __P((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)); void showhostmap_live __P((int, natstat_t *)); int opts; void usage(char *name) { fprintf(stderr, "Usage: %s [-CdFhlnrRsv] [-f filename]", name); fprintf(stderr, " [-G|-z zonename]\n"); exit(1); } int main(int argc, char *argv[]) { char *file, *core, *kernel; natstat_t ns, *nsp; int fd, c, mode; ipfobj_t obj; fd = -1; opts = 0; nsp = &ns; file = NULL; core = NULL; kernel = NULL; mode = O_RDWR; while ((c = getopt(argc, argv, "CdFf:G:hlM:N:nrRsvz:")) != -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 'G' : setzonename_global(optarg); break; case 'h' : opts |= OPT_HITS; break; case 'l' : opts |= OPT_LIST; mode = O_RDONLY; break; case 'M' : core = optarg; break; case 'N' : kernel = optarg; break; case 'n' : opts |= OPT_DONOTHING; mode = O_RDONLY; 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; case 'z' : setzonename(optarg); break; default : usage(argv[0]); } initparse(); if ((kernel != NULL) || (core != NULL)) { (void) setgid(getgid()); (void) setreuid(getuid(), getuid()); } 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)) { #ifdef notdef if (openkmem(kernel, core) == -1) exit(1); #endif 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); } if (setzone(fd) != 0) { close(fd); exit(1); } bzero((char *)&obj, sizeof (obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof (*nsp); obj.ipfo_type = IPFOBJ_NATSTAT; obj.ipfo_ptr = (void *)nsp; if (ioctl(fd, SIOCGNATS, &obj) == -1) { perror("ioctl(SIOCGNATS)"); exit(1); } (void) setgid(getgid()); (void) setreuid(getuid(), 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); exit(0); } if (opts & (OPT_FLUSH|OPT_CLEAR)) flushtable(fd, opts); if (file) { ipnat_parsefile(fd, ipnat_addrule, ioctl, file); } if (opts & (OPT_LIST|OPT_STAT)) dostats(fd, nsp, opts, 1); return (0); } /* * Read NAT statistic information in using a symbol table and memory file * rather than doing ioctl's. */ void natstat_dead(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" }, { "ap_sess_list" }, { 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_table[0] = tables[0]; nsp->ns_table[1] = 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)); kmemcpy((char *)&nsp->ns_apslist, nat_nlist[8].n_value, sizeof (nsp->ns_apslist)); } /* * Display NAT statistics. */ void dostats(int fd, natstat_t *nsp, int opts, int alive) { nat_t *np, nat; ipnat_t ipn; /* * Show statistics ? */ if (opts & OPT_STAT) { printf("mapped\tin\t%lu\tout\t%lu\n", nsp->ns_mapped[0], nsp->ns_mapped[1]); printf("added\t%lu\texpired\t%lu\n", nsp->ns_added, nsp->ns_expire); printf("no memory\t%lu\tbad nat\t%lu\n", nsp->ns_memfail, nsp->ns_badnat); printf("inuse\t%lu\norphans\t%u\nrules\t%lu\n", nsp->ns_inuse, nsp->ns_orphans, nsp->ns_rules); printf("wilds\t%u\n", nsp->ns_wilds); if (opts & OPT_VERBOSE) printf("table %p list %p\n", nsp->ns_table, nsp->ns_list); } /* * Show list of NAT rules and NAT sessions ? */ if (opts & OPT_LIST) { if (alive) { dostats_live(fd, nsp, opts); return; } 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; } printf("\nList of active sessions:\n"); for (np = nsp->ns_instances; np; np = nat.nat_next) { if (kmemcpy((char *)&nat, (long)np, sizeof (nat))) break; printactivenat(&nat, opts, 0); if (nat.nat_aps) printaps(nat.nat_aps, opts); } if (opts & OPT_VERBOSE) showhostmap(nsp); } } /* * Display the active host mapping table. */ void showhostmap(natstat_t *nsp) { hostmap_t hm, *hmp, **maptable; uint_t hv; printf("\nList of active host mappings:\n"); maptable = (hostmap_t **)malloc(sizeof (hostmap_t *) * nsp->ns_hostmap_sz); if (maptable == NULL) { perror("malloc"); exit(1); } if (kmemcpy((char *)maptable, (ulong_t)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, (ulong_t)hmp, sizeof (hm))) { perror("kmemcpy (hostmap)"); return; } printhostmap(&hm, hv); hmp = hm.hm_next; } } free(maptable); } /* * Issue an ioctl to flush either the NAT rules table or the active mapping * table or both. */ void flushtable(int fd, int opts) { int n = 0; if (opts & OPT_FLUSH) { n = FLUSH_TABLE_ALL; if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) perror("ioctl(SIOCFLNAT)"); else printf("%d entries flushed from NAT table\n", n); } if (opts & OPT_CLEAR) { n = FLUSH_LIST; if (!(opts & OPT_DONOTHING) && ioctl(fd, SIOCIPFFL, &n) == -1) perror("ioctl(SIOCCNATL)"); else printf("%d entries flushed from NAT list\n", n); } } /* * Display NAT statistics. */ void dostats_live(int fd, natstat_t *nsp, int opts) { ipfgeniter_t iter; ipfobj_t obj; ipnat_t ipn; nat_t nat; 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 = &ipn; /* * Show list of NAT rules and NAT sessions ? */ 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; } printf("\nList of active sessions:\n"); 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; printactivenat(&nat, opts, 1); if (nat.nat_aps) printaps(nat.nat_aps, opts); nsp->ns_instances = nat.nat_next; } if (opts & OPT_VERBOSE) showhostmap_live(fd, nsp); } /* * Display the active host mapping table. */ void showhostmap_live(int fd, natstat_t *nsp) { hostmap_t hm, *hmp; ipfgeniter_t iter; ipfobj_t obj; 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, 0); nsp->ns_maplist = hm.hm_next; } } %{ /* * Copyright (C) 2001-2008 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifdef __FreeBSD__ # ifndef __FreeBSD_cc_version # include # else # if __FreeBSD_cc_version < 430000 # include # endif # endif #endif #include #include #include #include #include #if !defined(__SVR4) && !defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include "ipf.h" #include "netinet/ipl.h" #include "ipnat_l.h" #define YYDEBUG 1 extern int yyerror __P((const 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 void newnatrule __P((void)); static void setnatproto __P((int)); %} %union { char *str; u_32_t num; struct { i6addr_t a; int v; } ipa; frentry_t fr; frtuc_t *frt; u_short port; struct { u_short p1; u_short p2; int pc; } pc; struct { i6addr_t a; i6addr_t m; int v; } ipp; union i6addr ip6; }; %token YY_NUMBER YY_HEX %token 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 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_SEQUENTIAL %type portspec %type hexnumber compare range proto %type saddr daddr sobject dobject mapfrom rdrfrom dip %type hostname ipv4 ipaddr %type addr rhaddr %type portstuff %% file: line | assign | file line | file assign ; line: xx rule { while ((nat = nattop) != NULL) { if (nat->in_v == 0) nat->in_v = 4; nattop = nat->in_next; (*nataddfunc)(natfd, natioctlfunc, nat); free(nat); } resetlexer(); } | YY_COMMENT ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); } ; assigning: '=' { yyvarnext = 1; } ; xx: { newnatrule(); } ; rule: map eol | mapblock eol | redir eol ; eol: | ';' ; map: mapit ifnames addr IPNY_TLATE rhaddr proxy mapoptions { if ($3.v != 0 && $3.v != $5.v && $5.v != 0) yyerror("1.address family mismatch"); bcopy(&$3.a, &nat->in_in[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_in[1], sizeof($3.a)); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDP) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } | mapit ifnames addr IPNY_TLATE rhaddr mapport mapoptions { if ($3.v != 0 && $3.v != $5.v && $5.v != 0) yyerror("2.address family mismatch"); bcopy(&$3.a, &nat->in_in[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_in[1], sizeof($3.a)); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } | mapit ifnames mapfrom IPNY_TLATE rhaddr proxy mapoptions { if ($3 != 0 && $3 != $5.v && $5.v != 0) yyerror("3.address family mismatch"); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDP) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } | mapit ifnames mapfrom IPNY_TLATE rhaddr mapport mapoptions { if ($3 != 0 && $3 != $5.v && $5.v != 0) yyerror("4.address family mismatch"); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDPICMPQ) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } ; mapblock: mapblockit ifnames addr IPNY_TLATE addr ports mapoptions { if ($3.v != 0 && $3.v != $5.v && $5.v != 0) yyerror("5.address family mismatch"); bcopy(&$3.a, &nat->in_in[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_in[1], sizeof($3.a)); bcopy(&$5.a, &nat->in_out[0], sizeof($5.a)); bcopy(&$5.m, &nat->in_out[1], sizeof($5.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_flags & IPN_TCPUDP) == 0) setnatproto(nat->in_p); if (((nat->in_redir & NAT_MAPBLK) != 0) || ((nat->in_flags & IPN_AUTOPORTMAP) != 0)) nat_setgroupmap(nat); } ; redir: rdrit ifnames addr dport IPNY_TLATE dip nport setproto rdroptions { if ($6 != 0 && $3.v != 0 && $6 != $3.v) yyerror("6.address family mismatch"); bcopy(&$3.a, &nat->in_out[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_out[1], sizeof($3.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); if ((nat->in_p == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) && (nat->in_pmin != 0 || nat->in_pmax != 0 || nat->in_pnext != 0)) setnatproto(IPPROTO_TCP); } | rdrit ifnames rdrfrom IPNY_TLATE dip nport setproto rdroptions { if ($5 != 0 && $3 != 0 && $5 != $3) yyerror("7.address family mismatch"); if ((nat->in_p == 0) && ((nat->in_flags & IPN_TCPUDP) == 0) && (nat->in_pmin != 0 || nat->in_pmax != 0 || nat->in_pnext != 0)) setnatproto(IPPROTO_TCP); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); } | rdrit ifnames addr IPNY_TLATE dip setproto rdroptions { if ($5 != 0 && $3.v != 0 && $5 != $3.v) yyerror("8.address family mismatch"); bcopy(&$3.a, &nat->in_out[0], sizeof($3.a)); bcopy(&$3.m, &nat->in_out[1], sizeof($3.a)); if (nat->in_ifnames[1][0] == '\0') strncpy(nat->in_ifnames[1], nat->in_ifnames[0], sizeof(nat->in_ifnames[0])); } ; proxy: | IPNY_PROXY IPNY_PORT portspec YY_STR '/' proto { strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel)); if (nat->in_dcmp == 0) { nat->in_dport = htons($3); } else if ($3 != nat->in_dport) { yyerror("proxy port numbers not consistant"); } setnatproto($6); free($4); } | IPNY_PROXY IPNY_PORT YY_STR YY_STR '/' proto { int pnum; strncpy(nat->in_plabel, $4, sizeof(nat->in_plabel)); pnum = getportproto($3, $6); if (pnum == -1) yyerror("invalid port number"); nat->in_dport = pnum; setnatproto($6); free($3); free($4); } ; setproto: | proto { if (nat->in_p != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); setnatproto($1); } | IPNY_TCPUDP { if (nat->in_p != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); nat->in_flags |= IPN_TCPUDP; nat->in_p = 0; } | IPNY_TCP '/' IPNY_UDP { if (nat->in_p != 0 || nat->in_flags & IPN_TCPUDP) yyerror("protocol set twice"); nat->in_flags |= IPN_TCPUDP; nat->in_p = 0; } ; rhaddr: addr { $$.a = $1.a; $$.m = $1.m; $$.v = $1.v; if ($$.v == 0) $$.v = nat->in_v; yyexpectaddr = 0; } | IPNY_RANGE hostname '-' hostname { if ($2.v != 0 && $4.v != 0 && $4.v != $2.v) yyerror("9.address family " "mismatch"); $$.v = $2.v; $$.a = $2.a; $$.m = $4.a; nat->in_flags |= IPN_IPRANGE; yyexpectaddr = 0; } ; dip: hostname { bcopy(&$1.a, &nat->in_in[0], sizeof($1.a)); if ($1.v == 0) $1.v = nat->in_v; if ($1.v == 4) { nat->in_inmsk = 0xffffffff; } else { nat->in_in[1].i6[0] = 0xffffffff; nat->in_in[1].i6[1] = 0xffffffff; nat->in_in[1].i6[2] = 0xffffffff; nat->in_in[1].i6[3] = 0xffffffff; } $$ = $1.v; } | hostname '/' YY_NUMBER { if ($1.v == 0) $1.v = nat->in_v; if ($1.v == 4 && ($1.a.in4.s_addr != 0 || ($3 != 0 && $3 != 32))) yyerror("Invalid mask for dip"); else if ($1.v == 6 && ($1.a.in4.s_addr != 0 || ($3 != 0 && $3 != 128))) yyerror("Invalid mask for dip"); else if ($1.v == 0 ) { if ($1.a.in4.s_addr == 0 && ($3 == 32 || $3 == 0)) $1.v = 4; else if ($3 == 128) $1.v = 6; } bcopy(&$1.a, &nat->in_in[0], sizeof($1.a)); ntomask($1.v, $3, (u_32_t *)&nat->in_in[1]); nat->in_in[0].i6[0] &= nat->in_in[1].i6[0]; nat->in_in[0].i6[0] &= nat->in_in[1].i6[1]; nat->in_in[0].i6[0] &= nat->in_in[1].i6[2]; nat->in_in[0].i6[0] &= nat->in_in[1].i6[3]; nat->in_v = $1.v; $$ = $1.v; } | hostname ',' { yyexpectaddr = 1; } hostname { if ($1.v != $4.v) yyerror("10.address family " "mismatch"); $$ = $1.v; nat->in_flags |= IPN_SPLIT; bcopy(&$1.a, &nat->in_in[0], sizeof($1.a)); bcopy(&$4.a, &nat->in_in[1], sizeof($4.a)); yyexpectaddr = 0; } ; portspec: YY_NUMBER { if ($1 > 65535) /* Unsigned */ yyerror("invalid port number"); else $$ = $1; } | YY_STR { if (getport(NULL, $1, &($$)) == -1) yyerror("invalid port number"); $$ = ntohs($$); } ; dport: | IPNY_PORT portspec { nat->in_pmin = htons($2); nat->in_pmax = htons($2); } | IPNY_PORT portspec '-' portspec { nat->in_pmin = htons($2); nat->in_pmax = htons($4); } | IPNY_PORT portspec ':' portspec { nat->in_pmin = htons($2); nat->in_pmax = htons($4); } ; nport: IPNY_PORT portspec { nat->in_pnext = htons($2); } | IPNY_PORT '=' portspec { nat->in_pnext = htons($3); nat->in_flags |= IPN_FIXEDDPORT; } ; ports: | IPNY_PORTS YY_NUMBER { nat->in_pmin = $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 IPNY_TO dobject { if ($2 != 0 && $4 != 0 && $2 != $4) yyerror("11.address family " "mismatch"); $$ = $2; } | from sobject '!' IPNY_TO dobject { if ($2 != 0 && $5 != 0 && $2 != $5) yyerror("12.address family " "mismatch"); nat->in_flags |= IPN_NOTDST; $$ = $2; } ; rdrfrom: from sobject IPNY_TO dobject { if ($2 != 0 && $4 != 0 && $2 != $4) yyerror("13.address family " "mismatch"); $$ = $2; } | '!' from sobject IPNY_TO dobject { if ($3 != 0 && $5 != 0 && $3 != $5) yyerror("14.address family " "mismatch"); nat->in_flags |= IPN_NOTSRC; $$ = $3; } ; from: IPNY_FROM { nat->in_flags |= IPN_FILTER; yyexpectaddr = 1; } ; ifnames: ifname { yyexpectaddr = 1; } | ifname ',' otherifname { yyexpectaddr = 1; } ; ifname: YY_STR { strncpy(nat->in_ifnames[0], $1, sizeof(nat->in_ifnames[0])); nat->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; free($1); } ; otherifname: YY_STR { strncpy(nat->in_ifnames[1], $1, sizeof(nat->in_ifnames[1])); nat->in_ifnames[1][LIFNAMSIZ - 1] = '\0'; free($1); } ; mapport: IPNY_PORTMAP tcpudp portspec ':' portspec randport { nat->in_pmin = htons($3); nat->in_pmax = htons($5); } | IPNY_PORTMAP tcpudp IPNY_AUTO randport { nat->in_flags |= IPN_AUTOPORTMAP; nat->in_pmin = htons(1024); nat->in_pmax = htons(65535); } | IPNY_ICMPIDMAP YY_STR YY_NUMBER ':' YY_NUMBER { if (strcmp($2, "icmp") != 0) { yyerror("icmpidmap not followed by icmp"); } free($2); if ($3 < 0 || $3 > 65535) yyerror("invalid ICMP Id number"); if ($5 < 0 || $5 > 65535) yyerror("invalid ICMP Id number"); nat->in_flags = IPN_ICMPQUERY; nat->in_pmin = htons($3); nat->in_pmax = htons($5); } ; randport: | IPNY_SEQUENTIAL { nat->in_flags |= IPN_SEQUENTIAL; } ; sobject: saddr { $$ = $1; } | saddr IPNY_PORT portstuff { nat->in_sport = $3.p1; nat->in_stop = $3.p2; nat->in_scmp = $3.pc; $$ = $1; } ; saddr: addr { if (nat->in_redir == NAT_REDIRECT) { bcopy(&$1.a, &nat->in_src[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_src[1], sizeof($1.a)); } else { bcopy(&$1.a, &nat->in_in[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_in[1], sizeof($1.a)); } $$ = $1.v; } ; dobject: daddr { $$ = $1; } | daddr IPNY_PORT portstuff { nat->in_dport = $3.p1; nat->in_dtop = $3.p2; nat->in_dcmp = $3.pc; if (nat->in_redir == NAT_REDIRECT) nat->in_pmin = htons($3.p1); } ; daddr: addr { if (nat->in_redir == NAT_REDIRECT) { bcopy(&$1.a, &nat->in_out[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_out[1], sizeof($1.a)); } else { bcopy(&$1.a, &nat->in_src[0], sizeof($1.a)); bcopy(&$1.m, &nat->in_src[1], sizeof($1.a)); } $$ = $1.v; } ; addr: IPNY_ANY { yyexpectaddr = 0; bzero(&$$.a, sizeof($$.a)); bzero(&$$.m, sizeof($$.a)); $$.v = nat->in_v; } | hostname { $$.a = $1.a; $$.v = $1.v; if ($$.v == 4) { $$.m.in4.s_addr = 0xffffffff; } else { $$.m.i6[0] = 0xffffffff; $$.m.i6[1] = 0xffffffff; $$.m.i6[2] = 0xffffffff; $$.m.i6[3] = 0xffffffff; } yyexpectaddr = 0; } | hostname '/' YY_NUMBER { $$.a = $1.a; if ($1.v == 0) { if ($1.a.in4.s_addr != 0) yyerror("invalid addr"); if ($3 == 0 || $3 == 32) $1.v = 4; else if ($3 == 128) $1.v = 6; else yyerror("invalid mask"); nat->in_v = $1.v; } ntomask($1.v, $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]; $$.v = $1.v; yyexpectaddr = 0; } | hostname '/' ipaddr { if ($1.v != $3.v) { yyerror("1.address family " "mismatch"); } $$.a = $1.a; $$.m = $3.a; $$.a.i6[0] &= $$.m.i6[0]; $$.a.i6[1] &= $$.m.i6[1]; $$.a.i6[2] &= $$.m.i6[2]; $$.a.i6[3] &= $$.m.i6[3]; $$.v = $1.v; yyexpectaddr = 0; } | hostname '/' hexnumber { $$.a = $1.a; $$.m.in4.s_addr = htonl($3); $$.a.in4.s_addr &= $$.m.in4.s_addr; $$.v = 4; } | hostname IPNY_MASK ipaddr { if ($1.v != $3.v) { yyerror("2.address family " "mismatch"); } $$.a = $1.a; $$.m = $3.a; $$.a.i6[0] &= $$.m.i6[0]; $$.a.i6[1] &= $$.m.i6[1]; $$.a.i6[2] &= $$.m.i6[2]; $$.a.i6[3] &= $$.m.i6[3]; $$.v = $1.v; yyexpectaddr = 0; } | hostname IPNY_MASK hexnumber { $$.a = $1.a; $$.m.in4.s_addr = htonl($3); $$.a.in4.s_addr &= $$.m.in4.s_addr; $$.v = 4; } ; portstuff: compare portspec { $$.pc = $1; $$.p1 = $2; } | portspec range portspec { $$.pc = $2; $$.p1 = $1; $$.p2 = $3; } ; mapoptions: rr frag age mssclamp nattag setproto ; rdroptions: rr frag age sticky mssclamp rdrproxy nattag ; 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_p = 0; } | IPNY_TCP '/' IPNY_UDP { nat->in_flags |= IPN_TCPUDP; nat->in_p = 0; } ; rdrproxy: IPNY_PROXY YY_STR { strncpy(nat->in_plabel, $2, sizeof(nat->in_plabel)); nat->in_dport = nat->in_pnext; nat->in_dport = htons(nat->in_dport); free($2); } | proxy { if (nat->in_plabel[0] != '\0') { nat->in_pmin = nat->in_dport; nat->in_pmax = nat->in_pmin; nat->in_pnext = nat->in_pmin; } } ; proto: YY_NUMBER { $$ = $1; } | IPNY_TCP { $$ = IPPROTO_TCP; } | IPNY_UDP { $$ = IPPROTO_UDP; } | YY_STR { $$ = getproto($1); free($1); } ; hexnumber: YY_HEX { $$ = $1; } ; hostname: YY_STR { i6addr_t addr; if (gethost($1, &addr, 0) == 0) { $$.a = addr; $$.v = 4; } else if (gethost($1, &addr, 1) == 0) { $$.a = addr; $$.v = 6; } else { yyerror("Unknown hostname"); } if ($$.v != 0) nat->in_v = $$.v; free($1); } | YY_NUMBER { bzero(&$$.a, sizeof($$.a)); $$.a.in4.s_addr = htonl($1); if ($$.a.in4.s_addr != 0) $$.v = 4; else $$.v = nat->in_v; if ($$.v != 0) nat->in_v = $$.v; } | ipv4 { $$ = $1; nat->in_v = 4; } | YY_IPV6 { $$.a = $1; $$.v = 6; nat->in_v = 6; } | YY_NUMBER YY_IPV6 { $$.a = $2; $$.v = 6; } ; 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; } ; ipaddr: ipv4 { $$ = $1; } | YY_IPV6 { $$.a = $1; $$.v = 6; } ; 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; } $$.a.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.a.in4.s_addr = htonl($$.a.in4.s_addr); $$.v = 4; } ; %% static wordtab_t yywords[] = { { "age", IPNY_AGE }, { "any", IPNY_ANY }, { "auto", IPNY_AUTO }, { "bimap", IPNY_BIMAP }, { "frag", IPNY_FRAG }, { "from", IPNY_FROM }, { "icmpidmap", IPNY_ICMPIDMAP }, { "mask", IPNY_MASK }, { "map", IPNY_MAP }, { "map-block", IPNY_MAPBLOCK }, { "mssclamp", IPNY_MSSCLAMP }, { "netmask", IPNY_MASK }, { "port", IPNY_PORT }, { "portmap", IPNY_PORTMAP }, { "ports", IPNY_PORTS }, { "proxy", IPNY_PROXY }, { "range", IPNY_RANGE }, { "rdr", IPNY_RDR }, { "round-robin",IPNY_ROUNDROBIN }, { "sequential", IPNY_SEQUENTIAL }, { "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; char *s; (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 (ipnat_parsesome(fd, addfunc, ioctlfunc, fp) == 1) ; if (fp != NULL) fclose(fp); return 0; } int ipnat_parsesome(fd, addfunc, ioctlfunc, fp) int fd; addfunc_t addfunc; ioctlfunc_t ioctlfunc; FILE *fp; { char *s; int i; yylineNum = 1; natfd = fd; nataddfunc = addfunc; natioctlfunc = ioctlfunc; 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 void newnatrule() { ipnat_t *n; n = calloc(1, sizeof(*n)); if (n == NULL) return; if (nat == NULL) nattop = nat = n; else { nat->in_next = n; nat = n; } } static void setnatproto(p) int p; { nat->in_p = 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; case IPPROTO_ICMP : nat->in_flags &= ~IPN_TCPUDP; if (!(nat->in_flags & IPN_ICMPQUERY)) { nat->in_dcmp = 0; nat->in_scmp = 0; nat->in_pmin = 0; nat->in_pmax = 0; nat->in_pnext = 0; } break; default : if ((nat->in_redir & NAT_MAPBLK) == 0) { /* Only reset dcmp/scmp in case dport/sport not set */ if (0 == nat->in_tuc.ftu_dport) nat->in_dcmp = 0; if (0 == nat->in_tuc.ftu_sport) nat->in_scmp = 0; nat->in_pmin = 0; nat->in_pmax = 0; nat->in_pnext = 0; nat->in_flags &= ~IPN_TCPUDP; } break; } if ((nat->in_flags & (IPN_TCPUDP|IPN_FIXEDDPORT)) == IPN_FIXEDDPORT) nat->in_flags &= ~IPN_FIXEDDPORT; } void 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 = sizeof(ipnat_t); obj.ipfo_type = IPFOBJ_IPNAT; obj.ipfo_ptr = ptr; add = 0; del = 0; if ((opts & OPT_DONOTHING) != 0) fd = -1; if (opts & OPT_ZERORULEST) { add = SIOCZRLST; } else if (opts & OPT_INACTIVE) { add = SIOCADNAT; del = SIOCRMNAT; } else { add = SIOCADNAT; del = SIOCRMNAT; } if (ipn && (opts & OPT_VERBOSE)) printnat(ipn, opts); if (opts & OPT_DEBUG) binprint(ipn, sizeof(*ipn)); if ((opts & OPT_ZERORULEST) != 0) { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(SIOCZRLST)"); } } 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 printnat(ipn, opts); } } else if ((opts & OPT_REMOVE) != 0) { if ((*ioctlfunc)(fd, del, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(delete nat rule)"); } } } else { if ((*ioctlfunc)(fd, add, (void *)&obj) == -1) { if ((opts & OPT_DONOTHING) == 0) { fprintf(stderr, "%d:", yylineNum); perror("ioctl(add/insert nat rule)"); } } } } /* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2014, Joyent, Inc. All rights reserved. * Copyright 2017 Gary Mills */ #include #include #include #include #if defined(BSD) && (BSD >= 199306) # include #endif #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include #include #include #include #include #include #include #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" #include "ipfzone.h" extern int ippool_yyparse __P((void)); extern int ippool_yydebug; extern FILE *ippool_yyin; extern char *optarg; extern int lineNum; void showpools __P((ip_pool_stat_t *)); 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 *[])); int poolflush __P((int, char *[])); int poolstats __P((int, char *[])); int gettype __P((char *, u_int *)); int getrole __P((char *)); void poollist_dead __P((int, char *, int, char *, char *)); void showpools_live(int, int, ip_pool_stat_t *, char *, int); void showhashs_live(int, int, iphtstat_t *, char *, int); int opts = 0; int fd = -1; int use_inet6 = 0; void usage(prog) char *prog; { const char *zoneopt = "[-G|-z zonename] "; fprintf(stderr, "Usage:\t%s\n", prog); fprintf(stderr, "\t\t\t-a [-dnv] %s[-m ] [-o ] -i [/netmask]\n", zoneopt); fprintf(stderr, "\t\t\t-A [-dnv] %s[-m ] [-o ] [-S ] [-t ]\n", zoneopt); fprintf(stderr, "\t\t\t-f %s[-dnuv]\n", zoneopt); fprintf(stderr, "\t\t\t-F [-dv] %s[-o ] [-t ]\n", zoneopt); fprintf(stderr, "\t\t\t-l [-dv] %s[-m ] [-t ]\n", zoneopt); fprintf(stderr, "\t\t\t-r [-dnv] %s[-m ] [-o ] -i [/netmask]\n", zoneopt); fprintf(stderr, "\t\t\t-R [-dnv] %s[-m ] [-o ] [-t ]\n", zoneopt); fprintf(stderr, "\t\t\t-s [-dtv] %s[-M ] [-N ]\n", zoneopt); exit(1); } int main(argc, argv) int argc; char *argv[]; { int err; if (argc < 2) usage(argv[0]); switch (getopt(argc, argv, "aAf:FlrRs")) { 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 'r' : err = poolnodecommand(1, argc, argv); break; case 'R' : err = poolcommand(1, argc, argv); break; case 's' : err = poolstats(argc, argv); break; default : exit(1); } return err; } int poolnodecommand(remove, argc, argv) int remove, argc; char *argv[]; { char *poolname = NULL, *s; int err, c, ipset, role; ip_pool_node_t node; struct in_addr mask; ipset = 0; role = IPL_LOGIPF; bzero((char *)&node, sizeof(node)); while ((c = getopt(argc, argv, "di:G:m:no:Rvz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'G' : setzonename_global(optarg); break; case 'i' : s = strchr(optarg, '/'); if (s == NULL) mask.s_addr = 0xffffffff; else if (strchr(s, '.') == NULL) { if (ntomask(4, atoi(s + 1), &mask.s_addr) != 0) return -1; } else { mask.s_addr = inet_addr(s + 1); } if (s != NULL) *s = '\0'; ipset = 1; node.ipn_addr.adf_len = sizeof(node.ipn_addr); node.ipn_addr.adf_addr.in4.s_addr = inet_addr(optarg); node.ipn_mask.adf_len = sizeof(node.ipn_mask); node.ipn_mask.adf_addr.in4.s_addr = mask.s_addr; break; case 'm' : poolname = optarg; break; case 'n' : opts |= OPT_DONOTHING; break; case 'o' : role = getrole(optarg); if (role == IPL_LOGNONE) return -1; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolnodecommand: opts = %#x\n", opts); if (ipset == 0) return -1; if (poolname == NULL) { fprintf(stderr, "poolname not given with add/remove node\n"); return -1; } if (remove == 0) err = load_poolnode(0, poolname, &node, ioctl); else err = remove_poolnode(0, poolname, &node, ioctl); 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, "dG:m:no:RS:t:vz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'G' : setzonename_global(optarg); break; case 'm' : poolname = optarg; break; case 'n' : opts |= OPT_DONOTHING; 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 't' : type = gettype(optarg, &iph.iph_type); if (type == IPLT_NONE) { fprintf(stderr, "unknown type '%s'\n", optarg); return -1; } break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); 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; } 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, "dG:nRuvz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; ippool_yydebug++; break; case 'G' : setzonename_global(optarg); break; case 'n' : opts |= OPT_DONOTHING; break; case 'R' : opts |= OPT_NORESOLVE; break; case 'u' : opts |= OPT_REMOVE; break; case 'v' : opts |= OPT_VERBOSE; break; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "loadpoolfile: opts = %#x\n", opts); if (!(opts & OPT_DONOTHING) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } if (setzone(fd) != 0) { close(fd); exit(1); } } if (ippool_parsefile(fd, infile, ioctl) != 0) return -1; return 0; } int poollist(argc, argv) int argc; char *argv[]; { char *kernel, *core, *poolname; int c, role, type, live_kernel; ip_pool_stat_t plstat; iphtstat_t htstat; iphtable_t *hptr; iplookupop_t op; ip_pool_t *ptr; core = NULL; kernel = NULL; live_kernel = 1; type = IPLT_ALL; poolname = NULL; role = IPL_LOGALL; while ((c = getopt(argc, argv, "dG:m:M:N:o:Rt:vz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; break; case 'G' : setzonename_global(optarg); 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 '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; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poollist: opts = %#x\n", opts); if (!(opts & OPT_DONOTHING) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } if (setzone(fd) != 0) { close(fd); 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 == 0) { poollist_dead(role, poolname, type, kernel, core); return (0); } 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) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } showpools_live(fd, role, &plstat, poolname, opts); } else { for (role = 0; role <= IPL_LOGMAX; role++) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } showpools_live(fd, role, &plstat, poolname, opts); } role = IPL_LOGALL; } } if (type == IPLT_ALL || type == IPLT_HASH) { 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) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } showhashs_live(fd, role, &htstat, poolname, opts); } else { for (role = 0; role <= IPL_LOGMAX; role++) { op.iplo_unit = role; c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } showhashs_live(fd, role, &htstat, poolname, opts); } } } 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); } } else { for (role = 0; role <= IPL_LOGMAX; role++) { ptr = pools[role]; while (ptr != NULL) { ptr = printpool(ptr, kmemcpywrap, poolname, opts); } } 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); } } else { for (role = 0; role <= IPL_LOGMAX; role++) { hptr = tables[role]; while (hptr != NULL) { hptr = printhash(hptr, kmemcpywrap, poolname, opts); } } } } } void showpools_live(fd, role, plstp, poolname, opts) int fd, role; ip_pool_stat_t *plstp; char *poolname; int opts; { 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_data = &pool; iter.ili_unit = role; *iter.ili_name = '\0'; while (plstp->ipls_list[role] != NULL) { if (ioctl(fd, SIOCLOOKUPITER, &obj)) { perror("ioctl(SIOCLOOKUPITER)"); break; } (void) printpool_live(&pool, fd, poolname, opts); plstp->ipls_list[role] = pool.ipo_next; } } int poolstats(argc, argv) int argc; char *argv[]; { int c, type, role; ip_pool_stat_t plstat; iphtstat_t htstat; iplookupop_t op; type = IPLT_ALL; role = IPL_LOGALL; bzero((char *)&op, sizeof(op)); while ((c = getopt(argc, argv, "dG:M:N:o:t:vz:")) != -1) switch (c) { case 'd' : opts |= OPT_DEBUG; break; case 'G' : setzonename_global(optarg); break; case 'M' : break; case 'N' : 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; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolstats: opts = %#x\n", opts); if (!(opts & OPT_DONOTHING) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } if (setzone(fd) != 0) { close(fd); 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)) { c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } printf("Pools:\t%lu\n", plstat.ipls_pools); printf("Nodes:\t%lu\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)) { c = ioctl(fd, SIOCLOOKUPSTAT, &op); if (c == -1) { perror("ioctl(SIOCLOOKUPSTAT)"); return -1; } printf("Hash Tables:\t%lu\n", htstat.iphs_numtables); printf("Nodes:\t%lu\n", htstat.iphs_numnodes); printf("Out of Memory:\t%lu\n", htstat.iphs_nomem); } } 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:vz:")) != -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; case 'z' : setzonename(optarg); break; } if (opts & OPT_DEBUG) fprintf(stderr, "poolflush: opts = %#x\n", opts); if (!(opts & OPT_DONOTHING) && (fd == -1)) { fd = open(IPLOOKUP_NAME, O_RDWR); if (fd == -1) { perror("open(IPLOOKUP_NAME)"); exit(1); } if (setzone(fd) != 0) { close(fd); exit(1); } } bzero((char *)&flush, sizeof(flush)); flush.iplf_type = type; flush.iplf_unit = role; flush.iplf_arg = arg; if (!(opts & OPT_DONOTHING)) { if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) { perror("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(optarg, "tree")) { type = IPLT_POOL; } else if (!strcasecmp(optarg, "hash")) { type = IPLT_HASH; if (minor != NULL) *minor = IPHASH_LOOKUP; } else if (!strcasecmp(optarg, "group-map")) { type = IPLT_HASH; if (minor != NULL) *minor = IPHASH_GROUPMAP; } else { type = IPLT_NONE; } return type; } void showhashs_live(fd, role, htstp, poolname, opts) int fd, role; iphtstat_t *htstp; char *poolname; int opts; { 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_data = &table; iter.ili_unit = role; *iter.ili_name = '\0'; while (htstp->iphs_tables != NULL) { if (ioctl(fd, SIOCLOOKUPITER, &obj)) { perror("ioctl(SIOCLOOKUPITER)"); break; } printhash_live(&table, fd, poolname, opts); htstp->iphs_tables = table.iph_next; } } %{ /* * Copyright (C) 2003 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #if defined(BSD) && (BSD >= 199306) # include #endif #include #include #if __FreeBSD_version >= 300000 # include #endif #include #include #include #include #include #include #include #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" #include "netinet/ip_htable.h" #include "ippool_l.h" #include "kmem.h" #define YYDEBUG 1 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 ioctlfunc_t poolioctl = NULL; static char poolname[FR_GROUPLEN]; static int set_ipv6_addr = 0; %} %union { char *str; u_32_t num; struct in_addr addr; struct alist_s *alist; union i6addr adrmsk[2]; iphtent_t *ipe; ip_pool_node_t *ipp; union i6addr ip6; } %token YY_NUMBER YY_HEX %token 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 YY_IPV6 %token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT %token IPT_TABLE IPT_GROUPMAP IPT_HASH %token IPT_ROLE IPT_TYPE IPT_TREE %token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME %type role table inout %type ipftree range addrlist %type addrmask %type ipfgroup ipfhash hashlist hashentry %type groupentry setgrouplist grouplist %type ipaddr mask ipv4 %type number setgroup %% file: line | assign | file line | file assign ; line: table role ipftree eol { iplo.ipo_unit = $2; iplo.ipo_list = $3; load_pool(&iplo, poolioctl); resetlexer(); } | table role ipfhash eol { ipht.iph_unit = $2; ipht.iph_type = IPHASH_LOOKUP; load_hash(&ipht, $3, poolioctl); resetlexer(); } | groupmap role number ipfgroup eol { ipht.iph_unit = $2; strncpy(ipht.iph_name, $3, sizeof(ipht.iph_name)); ipht.iph_type = IPHASH_GROUPMAP; load_hash(&ipht, $4, poolioctl); resetlexer(); } | YY_COMMENT ; eol: ';' ; assign: YY_STR assigning YY_STR ';' { set_variable($1, $3); resetlexer(); free($1); free($3); } ; assigning: '=' { yyvarnext = 1; } ; table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht)); bzero((char *)&iphte, sizeof(iphte)); bzero((char *)&iplo, sizeof(iplo)); *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 '=' IPT_IPF { $$ = IPL_LOGIPF; } | IPT_ROLE '=' IPT_NAT { $$ = IPL_LOGNAT; } | IPT_ROLE '=' IPT_AUTH { $$ = IPL_LOGAUTH; } | IPT_ROLE '=' IPT_COUNT { $$ = IPL_LOGCOUNT; } ; 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; } | hashopts start setgrouplist end { $$ = $3; } ; number: IPT_NUM '=' YY_NUMBER { snprintf(poolname, FR_GROUPLEN, "%u", $3); $$ = poolname; } | IPT_NAME '=' YY_STR { $$ = $3; } | { $$ = ""; } ; setgroup: IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1]; strncpy(tmp, $3, FR_GROUPLEN); $$ = strdup(tmp); } | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1]; snprintf(tmp, FR_GROUPLEN, "%u", $3); $$ = strdup(tmp); } ; hashopts: | size | seed | size seed ; addrlist: ';' { $$ = NULL; } | range next addrlist { $1->ipn_next = $3; $$ = $1; } | range next { $$ = $1; } | range ; grouplist: ';' { $$ = NULL; } | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; } | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t)); if ($$ == NULL) yyerror("sorry, out of memory"); if (set_ipv6_addr) $$->ipe_family = AF_INET6; else $$->ipe_family = AF_INET; bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); set_ipv6_addr = 0; $$->ipe_next = $3; } | groupentry next { $$ = $1; } | addrmask next { $$ = calloc(1, sizeof(iphtent_t)); if ($$ == NULL) yyerror("sorry, out of memory"); if (set_ipv6_addr) $$->ipe_family = AF_INET6; else $$->ipe_family = AF_INET; bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); set_ipv6_addr = 0; } ; setgrouplist: ';' { $$ = NULL; } | groupentry next { $$ = $1; } | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; } ; groupentry: addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t)); if ($$ == NULL) yyerror("sorry, out of memory"); if (set_ipv6_addr) $$->ipe_family = AF_INET6; else $$->ipe_family = AF_INET; bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); set_ipv6_addr = 0; strncpy($$->ipe_group, $3, FR_GROUPLEN); free($3); } ; range: addrmask { $$ = calloc(1, sizeof(*$$)); if ($$ == NULL) yyerror("sorry, out of memory"); $$->ipn_info = 0; $$->ipn_addr.adf_len = sizeof($$->ipn_addr); $$->ipn_mask.adf_len = sizeof($$->ipn_mask); if (set_ipv6_addr) { $$->ipn_addr.adf_family = AF_INET6; $$->ipn_addr.adf_addr = $1[0]; $$->ipn_mask.adf_addr = $1[1]; } else { $$->ipn_addr.adf_family = AF_INET; $$->ipn_addr.adf_addr.in4.s_addr = $1[0].in4.s_addr; $$->ipn_mask.adf_addr.in4.s_addr = $1[1].in4.s_addr; } set_ipv6_addr = 0; } | '!' addrmask { $$ = calloc(1, sizeof(*$$)); if ($$ == NULL) yyerror("sorry, out of memory"); $$->ipn_info = 1; $$->ipn_addr.adf_len = sizeof($$->ipn_addr); $$->ipn_mask.adf_len = sizeof($$->ipn_mask); if (set_ipv6_addr) { $$->ipn_addr.adf_family = AF_INET6; $$->ipn_addr.adf_addr = $2[0]; $$->ipn_mask.adf_addr = $2[1]; } else { $$->ipn_addr.adf_family = AF_INET; $$->ipn_addr.adf_addr.in4.s_addr = $2[0].in4.s_addr; $$->ipn_mask.adf_addr.in4.s_addr = $2[1].in4.s_addr; } set_ipv6_addr = 0; } hashlist: ';' { $$ = NULL; } | hashentry next { $$ = $1; } | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; } ; hashentry: addrmask { $$ = calloc(1, sizeof(iphtent_t)); if ($$ == NULL) yyerror("sorry, out of memory"); if (set_ipv6_addr) $$->ipe_family = AF_INET6; else $$->ipe_family = AF_INET; bcopy((char *)&($1[0]), (char *)&($$->ipe_addr), sizeof($$->ipe_addr)); bcopy((char *)&($1[1]), (char *)&($$->ipe_mask), sizeof($$->ipe_mask)); } ; addrmask: ipaddr '/' mask { $$[0] = $1; $$[1] = $3; yyexpectaddr = 0; } | ipaddr { $$[0] = $1; yyexpectaddr = 0; if (set_ipv6_addr) fill6bits(128, (u_32_t *)$$[1].in6.s6_addr); else $$[1].in4.s_addr = 0xffffffff; } ; ipaddr: ipv4 { $$ = $1; } | YY_NUMBER { $$.in4.s_addr = htonl($1); } | YY_IPV6 { set_ipv6_addr = 1; bcopy(&$1, &$$, sizeof($$)); yyexpectaddr = 0; } | YY_STR { if (gethost($1, &$$, 0) == -1) yyerror("Unknown hostname"); } ; mask: YY_NUMBER { if (set_ipv6_addr) ntomask(6, $1, (u_32_t *)$$.in6.s6_addr); else ntomask(4, $1, (u_32_t *)&$$.in4.s_addr); } | ipv4 { $$ = $1; } ; start: '{' { yyexpectaddr = 1; } ; end: '}' { yyexpectaddr = 0; } ; next: ',' { yyexpectaddr = 1; } | ';' { yyexpectaddr = 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; } $$.in4.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7; $$.in4.s_addr = htonl($$.in4.s_addr); } ; %% static wordtab_t yywords[] = { { "auth", IPT_AUTH }, { "count", IPT_COUNT }, { "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 }, { "role", IPT_ROLE }, { "seed", IPT_SEED }, { "size", IPT_SIZE }, { "table", IPT_TABLE }, { "tree", IPT_TREE }, { "type", IPT_TYPE }, { 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; } /* * Copyright (C) 1993-2001 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * $Id: kmem.h,v 2.5 2002/08/21 22:57:36 darrenr Exp $ */ #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 #endif #ifdef _PATH_KMEM # define KMEM _PATH_KMEM #else # define KMEM "/dev/kmem" #endif #endif /* __KMEM_H__ */ 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 /* * Copyright (C) 2002-2008 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include "ipf.h" #ifdef IPFILTER_SCAN #include "netinet/ip_scan.h" #endif #include #include #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 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(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(int c) { if (c == '\n') yylineNum--; yytext[--yypos] = c; } static int yyswallow(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(void) { int i; for (i = 0; i < yypos; i++) yychars[i] = (char)(yytext[i] & 0xff); yychars[i] = '\0'; return (yychars); } static void yystrtotext(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(int offset, int 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(void) { int c, n, isbuilding, rval, lnext, nokey = 0; char *name; 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; /* FALLTHROUGH */ 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; 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)) { 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; 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 '-' : if (yyexpectaddr) break; if (isbuilding == 1) break; n = yygetc(0); if (n == '>') { isbuilding = 1; goto done; } yyunputc(n); 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 (isbuilding == 0 && (ishex(c) || c == ':')) { char ipv6buf[45 + 1], *s, oc; int start; start = yypos; s = ipv6buf; oc = c; /* * 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 == ':') { 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\n", isbuilding, yyvarnext, nokey); if (isbuilding == 1) { wordtab_t *w; w = NULL; isbuilding = 0; if ((yyvarnext == 0) && (nokey == 0)) { w = yyfindkey(yystr); if (w == NULL && yywordtab != NULL) { yyresetdict(); w = yyfindkey(yystr); } } else yyvarnext = 0; if (w != NULL) rval = w->w_value; else rval = YY_STR; } if (rval == YY_STR && yysavedepth > 0) yyresetdict(); yytokentype = rval; if (yydebug) printf("lexed(%s) [%d,%d,%d] => %d @%d\n", yystr, 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", (uint_t *)&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; } return (rval); } static wordtab_t *yyfindkey(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(int num) { wordtab_t *w; if (yywordtab == NULL) return (""); for (w = yywordtab; w->w_word; w++) if (w->w_value == num) return (w->w_word); return (""); } wordtab_t * yysettab(wordtab_t *words) { wordtab_t *save; save = yywordtab; yywordtab = words; return (save); } int yyerror(const 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); if (txt == NULL) { fprintf(stderr, "sorry, out of memory," " bailing out\n"); exit(1); } freetxt = 1; } else txt = yystr; } else { txt = yykeytostr(yytokentype); if (txt == NULL) { fprintf(stderr, "sorry, out of memory," " bailing out\n"); exit(1); } } fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum); if (freetxt == 1) free(txt); exit(1); } void yysetdict(wordtab_t *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(void) { if (yydebug) printf("yyresetdict(%d)\n", yysavedepth); if (yysavedepth > 0) { yysettab(yysavewords[--yysavedepth]); if (yydebug) printf("yysavedepth-- => %d\n", yysavedepth); } } #ifdef TEST_LEXER int main(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 #ifndef LEXER_H #define LEXER_H typedef struct wordtab { char *w_word; int w_value; } wordtab_t; #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 int yylex __P((void)); extern int yyerror __P((const 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; #endif /* LEXER_H */