aboutsummaryrefslogtreecommitdiff
path: root/sbin/ipf/ippool
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2021-12-15 21:45:47 +0000
committerCy Schubert <cy@FreeBSD.org>2021-12-20 14:16:33 +0000
commit41edb306f05651fcaf6c74f9e3557f59f80292e1 (patch)
tree27e88c81aa6f5219d79ccd2c24e11d5cddac6d29 /sbin/ipf/ippool
parent3b9b51fe464ebb91e894742a6a0e6417e256f03a (diff)
downloadsrc-41edb306f05651fcaf6c74f9e3557f59f80292e1.tar.gz
src-41edb306f05651fcaf6c74f9e3557f59f80292e1.zip
ipfilter: Move userland bits to sbin
Through fixes and improvements our ipfilter sources have diverged enough to warrant move from contrib into sbin/ipf. Now that I'm planning on implementing MSS clamping as in iptables it makes more sense to move ipfilter to sbin. This is the second of three commits of the ipfilter move. Suggested by glebius on two occaions. Suggested by and discussed with: glebius Reviewed by: glebius, kp (for #network) MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D33510
Diffstat (limited to 'sbin/ipf/ippool')
-rw-r--r--sbin/ipf/ippool/Makefile2
-rw-r--r--sbin/ipf/ippool/ippool.5320
-rw-r--r--sbin/ipf/ippool/ippool.8130
-rw-r--r--sbin/ipf/ippool/ippool.c1145
-rw-r--r--sbin/ipf/ippool/ippool_y.y832
5 files changed, 2428 insertions, 1 deletions
diff --git a/sbin/ipf/ippool/Makefile b/sbin/ipf/ippool/Makefile
index ab350f223f53..674978ed98c2 100644
--- a/sbin/ipf/ippool/Makefile
+++ b/sbin/ipf/ippool/Makefile
@@ -2,7 +2,7 @@
PACKAGE= ipf
PROG= ippool
-SRCS= ${GENHDRS} ippool_y.c ippool_l.c kmem.c ippool.c
+SRCS= ${GENHDRS} ippool_y.c ippool_l.c ippool.c
MAN= ippool.5 ippool.8
CFLAGS+= -I.
diff --git a/sbin/ipf/ippool/ippool.5 b/sbin/ipf/ippool/ippool.5
new file mode 100644
index 000000000000..4de19a4b3625
--- /dev/null
+++ b/sbin/ipf/ippool/ippool.5
@@ -0,0 +1,320 @@
+.\" $FreeBSD$
+.\"
+.TH IPPOOL 5
+.SH NAME
+ippool, ippool.conf \- IP Pool file format
+.SH DESCRIPTION
+The file ippool.conf is used with ippool(8) to configure address pools for
+use with ipnat(8) and ipf(8).
+.PP
+There are four different types of address pools that can be configured
+through ippool.conf. The various types are presented below with a brief
+description of how they are used:
+.HP
+dstlist
+.IP
+destination list - is a collection of IP addresses with an optional
+network interface name that can be used with either redirect (rdr) rules
+in ipnat.conf(5) or as the destination in ipf.conf(5) for policy based
+routing.
+.HP
+group-map
+.IP
+group maps - support the srcgrpmap and dstgrpmap call functions in
+ipf.conf(5) by providing a list of addresses or networks rule group
+numbers to start processing them with.
+.HP
+hash
+.IP
+hash tables - provide the means for performing a very efficient
+lookup address or network when there is expected to be only one
+exact match. These are best used with more static sets of addresses
+so they can be sized optimally.
+.HP
+pool
+.IP
+address pools - are an alternative to hash tables that can perform just
+as well in most circumstances. In addition, the address pools allow for
+heirarchical matching, so it is possible to define a subnet as matching
+but then exclude specific addresses from it.
+.SS
+Evolving Configuration
+.PP
+Over time the configuration syntax used by ippool.conf(5) has evolved.
+Originally the syntax used was more verbose about what a particular
+value was being used for, for example:
+.PP
+.nf
+table role = ipf type = tree number = 100
+ { 1.1.1.1/32; !2.2.0.0/16; 2.2.2.0/24; ef00::5/128; };
+.fi
+.PP
+This is rather long winded. The evolution of the configuration syntax
+has also replaced the use of numbers with names, although numbers can
+still be used as can be seen here:
+.PP
+.nf
+pool ipf/tree (name "100";)
+ { 1.1.1.1/32; !2.2.0.0/16; 2.2.2.0/24; ef00::5/128; };
+.fi
+.PP
+Both of the above examples produce the same configuration in the kernel
+for use with ipf.conf(5).
+.PP
+Newer options for use in ippool.conf(5) will only be offered in the new
+configuration syntax and all output using "ippool -l" will also be in the
+new configuration syntax.
+.SS
+IPFilter devices and pools
+.PP
+To cater to different administration styles, ipool.conf(5) allows you to
+tie a pool to a specific role in IPFilter. The recognised role names are:
+.HP
+ipf
+.IP
+pools defined for role "ipf" are available for use with all rules that are
+found in ipf.conf(5) except for auth rules.
+.HP
+nat
+.IP
+pools defined for role "nat" are available for use with all rules that are
+found in ipnat.conf(5).
+.HP
+auth
+.IP
+pools defined for role "auth" are available only for use with "auth" rules
+that are found in ipf.conf(5)
+.HP
+all
+.IP
+pools that are defined for the "all" role are available to all types of
+rules, be they NAT rules in ipnat.conf(5) or firewall rules in ipf.conf(5).
+.SH Address Pools
+.PP
+An address pool can be used in ipf.conf(5) and ipnat.conf(5) for matching
+the source or destination address of packets. They can be referred to either
+by name or number and can hold an arbitrary number of address patterns to
+match.
+.PP
+An address pool is considered to be a "tree type". In the older configuration
+style, it was necessary to have "type=tree" in ippool.conf(5). In the new
+style configuration, it follows the IPFilter device with which the pool
+is being configured.
+Now it is the default if left out.
+.PP
+For convenience, both IPv4 and IPv6 addresses can be stored in the same
+address pool. It should go without saying that either type of packet can
+only ever match an entry in a pool that is of the same address family.
+.PP
+The address pool searches the list of addresses configured for the best
+match. The "best match" is considered to be the match that has the highest
+number of bits set in the mask. Thus if both 2.2.0.0/16 and 2.2.2.0/24 are
+present in an address pool, the addres 2.2.2.1 will match 2.2.2.0/24 and
+2.2.1.1 will match 2.2.0.0/16. The reason for this is to allow exceptions
+to be added through the use of negative matching. In the following example,
+the pool contains "2.2.0.0/16" and "!2.2.2.0/24", meaning that all packets
+that match 2.2.0.0/16, except those that match 2.2.2.0/24, will be considered
+as a match for this pool.
+.PP
+table role = ipf type = tree number = 100
+ { 1.1.1.1/32; 2.2.0.0/16; !2.2.2.0/24; ef00::5/128; };
+.PP
+For the sake of clarity and to aid in managing large numbers of addresses
+inside address pools, it is possible to specify a location to load the
+addresses from. To do this simply use a "file://" URL where you would
+specify an actual IP address.
+.PP
+.nf
+pool ipf/tree (name rfc1918;) { file:///etc/ipf/rfc1918; };
+.fi
+.PP
+The contents of the file might look something like this:
+.PP
+.nf
+# RFC 1918 networks
+10.0.0.0/8
+!127.0.0.0/8
+172.16.0.0/12
+192.168.0.0/24
+.fi
+.PP
+In this example, the inclusion of the line "!127.0.0.0/8" is, strictly
+speaking not correct and serves only as an example to show that negative
+matching is also supported in this file.
+.PP
+Another format that ippool(8) recognises for input from a file is that
+from whois servers. In the following example, output from a query to a
+WHOIS server for information about which networks are associated with
+the name "microsoft" has been saved in a file named "ms-networks".
+There is no need to modify the output from the whois server, so using
+either the whois command or dumping data directly from it over a TCP
+connection works perfectly file as input.
+.PP
+.nf
+pool ipf/tree (name microsoft;) { whois file "/etc/ipf/ms-networks"; };
+.fi
+.PP
+And to then block all packets to/from networks defined in that file,
+a rule like this might be used:
+.PP
+.nf
+block in from pool/microsoft to any
+.fi
+.PP
+Note that there are limitations on the output returned by whois servers
+so be aware that their output may not be 100% perfect for your goal.
+.SH Destination Lists
+.PP
+Destination lists are provided for use primarily with NAT redirect rules
+(rdr). Their purpose is to allow more sophisticated methods of selecting
+which host to send traffic to next than the simple round-robin technique
+that is present with with "round-robin" rules in ipnat.conf(5).
+.PP
+When building a list of hosts to use as a redirection list, it is
+necessary to list each host to be used explicitly. Expressing a
+collection of hosts as a range or a subnet is not supported. With each
+address it is also possible to specify a network interface name. The
+network interface name is ignored by NAT when using destination lists.
+The network itnerface name is currently only used with policy based
+routing (use of "to"/"dup-to" in ipf.conf(5)).
+.PP
+Unlike the other directives that can be expressed in this file, destination
+lists must be written using the new configuration syntax. Each destination
+list must have a name associated with it and a next hop selection policy.
+Some policies have further options. The currently available selection
+policies are:
+.HP
+round-robin
+.IP
+steps through the list of hosts configured with the destination list
+one by one
+.HP
+random
+.IP
+the next hop is chosen by random selection from the list available
+.HP
+src-hash
+.IP
+a hash is made of the source address components of the packet
+(address and port number) and this is used to select which
+next hop address is used
+.HP
+dst-hash
+.IP
+a hash is made of the destination address components of the packet
+(address and port number) and this is used to select which
+next hop address is used
+.HP
+hash
+.IP
+a hash is made of all the address components in the packet
+(addresses and port numbers) and this is used to select which
+next hop address is used
+.HP
+weighted
+.IP
+selecting a weighted policy for destination selection needs further
+clarification as to what type of weighted selection will be used.
+The sub-options to a weighted policy are:
+.RS
+.HP
+connection
+.IP
+the host that has received the least number of connections is selected
+to be the next hop. When all hosts have the same connection count,
+the last one used will be the next address selected.
+.RE
+.PP
+The first example here shows 4 destinations that are used with a
+round-robin selection policy.
+.PP
+.nf
+pool nat/dstlist (name servers; policy round-robin;)
+ { 1.1.1.2; 1.1.1.4; 1.1.1.5; 1.1.1.9; };
+.fi
+.PP
+In the following example, the destination is chosen by whichever has
+had the least number of connections. By placing the interface name
+with each address and saying "all/dstlist", the destination list can
+be used with both ipnat.conf(5) and ipf.conf(5).
+.PP
+.nf
+pool all/dstlist (name servers; policy weighted connection;)
+ { bge0:1.1.1.2; bge0:1.1.1.4; bge1:1.1.1.5; bge1:1.1.1.9; };
+.fi
+.SH Group maps
+.PP
+Group maps are provided to allow more efficient processing of packets
+where there are a larger number of subnets and groups of rules for those
+subnets. Group maps are used with "call" rules in ipf.conf(5) that
+use the "srcgrpmap" and "dstgrpmap" functions.
+.PP
+A group map declaration must mention which group is the default group
+for all matching addresses to be applied to. Then inside the list of
+addresses and networks for the group, each one may optionally have
+a group number associated with it. A simple example like this, where
+the first two entries would map to group 2020 but 5.0.0.0/8 sends
+rule processing to group 2040.
+.PP
+.nf
+group-map out role = ipf number = 2010 group = 2020
+ { 2.2.2.2/32; 4.4.0.0/16; 5.0.0.0/8, group = 2040; };
+.fi
+.PP
+An example that outlines the real purpose of group maps is below,
+where each one of the 12 subnets is mapped to a different group
+number. This might be because each subnet has its own policy and
+rather than write a list of twelve rules in ipf.conf(5) that match
+the subnet and branch off with a head statement, a single rule can
+be used with this group map to achieve the same result.
+.PP
+.nf
+group-map ( name "2010"; in; )
+ { 192.168.1.0/24, group = 10010; 192.168.2.0/24, group = 10020;
+ 192.168.3.0/24, group = 10030; 192.168.4.0/24, group = 10040;
+ 192.168.5.0/24, group = 10050; 192.168.6.0/24, group = 10060;
+ 192.168.7.0/24, group = 10070; 192.168.8.0/24, group = 10080;
+ 192.168.9.0/24, group = 10090; 192.168.10.0/24, group = 10100;
+ 192.168.11.0/24, group = 10110; 192.168.12.0/24, group = 10120;
+ };
+.fi
+.PP
+The limitation with group maps is that only the source address or the
+destination address can be used to map the packet to the starting group,
+not both, in your ipf.conf(5) file.
+.SH Hash Tables
+.PP
+The hash table is operationally similar to the address pool. It is
+used as a store for a collection of address to match on, saving the
+need to write a lengthy list of rules. As with address pools, searching
+will attempt to find the best match - an address specification with the
+largest contiguous netmask.
+.PP
+Hash tables are best used where the list of addresses, subnets and
+networks is relatively static, which is something of a contrast to
+the address pool that can work with either static or changing
+address list sizes.
+.PP
+Further work is still needed to have IPFilter correctly size and tune
+the hash table to optimise searching. The goal is to allow for small to
+medium sized tables to achieve close to O(1) for either a positive or
+negative match, in contrast to the address pool, which is O(logn).
+.PP
+The following two examples build the same table in the kernel, using
+the old configuration format (first) and the new one (second).
+.PP
+.nf
+table role=all type=hash name=servers size=5
+ { 1.1.1.2/32; 1.1.1.3/32; 11.23.44.66/32; };
+
+pool all/hash (name servers; size 5;)
+ { 1.1.1.2; 1.1.1.3; 11.23.44.66; };
+.fi
+.SH FILES
+/dev/iplookup
+.br
+/etc/ippool.conf
+.br
+/etc/hosts
+.SH SEE ALSO
+ippool(8), hosts(5), ipf(5), ipf(8), ipnat(8)
diff --git a/sbin/ipf/ippool/ippool.8 b/sbin/ipf/ippool/ippool.8
new file mode 100644
index 000000000000..bcc8f3cbd71d
--- /dev/null
+++ b/sbin/ipf/ippool/ippool.8
@@ -0,0 +1,130 @@
+.\" $FreeBSD$
+.\"
+.TH IPPOOL 8
+.SH NAME
+ippool \- user interface to the IPFilter pools
+.SH SYNOPSIS
+.br
+.B ippool
+-a [-dnv] [-m <name>] [-o <role>] [-t <type>] [-T ttl] -i <ipaddr>[/<netmask>]
+.br
+.B ippool
+-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] -t <type>
+.br
+.B ippool
+-f <file> [-dnuvR] [-f <file [-dnuvR]] ...
+.br
+.B ippool
+-F [-dv] [-o <role>] [-t <type>]
+.br
+.B ippool
+-l [-dv] [-m <name>] [-t <type>] [-o <role>] [-M <core>] [-N <namelist>]
+.br
+.B ippool
+-r [-dnv] [-m <name>] [-o <role>] [-t <type>] -i <ipaddr>[/<netmask>]
+.br
+.B ippool
+-R [-dnv] [-m <name>] [-o <role>] -t <type>
+.br
+.B ippool
+-s [-dtv]
+.SH DESCRIPTION
+.PP
+.B Ippool
+is used to manage information stored in the IP pools subsystem of IPFilter.
+Configuration file information may be parsed and loaded into the kernel,
+currently configured pools removed or changed as well as inspected.
+.PP
+The command line options used are broken into two sections: the global
+options and the instance specific options.
+.SH GLOBAL OPTIONS
+.TP
+.B \-d
+Toggle debugging of processing the configuration file.
+.TP
+.B \-n
+This flag (no-change) prevents
+.B ippool
+from actually making any ioctl
+calls or doing anything which would alter the currently running kernel.
+.TP
+.B \-v
+Turn verbose mode on.
+.SH COMMAND OPTIONS
+.TP
+.B -a
+Add a new data node to an existing pool in the kernel.
+.TP
+.B -A
+Add a new (empty) pool to the kernel.
+.TP
+.B -f <file>
+Read in IP pool configuration information from the file and load it into
+the kernel.
+.TP
+.B -F
+Flush loaded pools from the kernel.
+.TP
+.B -l
+Display a list of pools currently loaded into the kernel.
+.TP
+.B -r
+Remove an existing data node from a pool in the kernel.
+.TP
+.B -R
+Remove an existing pool from within the kernel.
+.TP
+.B -s
+Display IP pool statistical information.
+.SH OPTIONS
+.TP
+.B -i <ipaddr>[/<netmask>]
+Sets the IP address for the operation being undertaken with an
+all-one's mask or, optionally, a specific netmask given in either
+the dotted-quad notation or a single integer.
+.TP
+.B -m <name>
+Sets the pool name for the current operation.
+.TP
+.B -M <core>
+Specify an alternative path to /dev/kmem to retrieve statistical information
+from.
+.TP
+.B -N <namelist>
+Specify an alternative path to lookup symbol name information from when
+retrieving statistical information.
+.TP
+.B -o <role>
+Sets the role with which this pool is to be used. Currently only
+.B ipf
+(the default) is accepted as arguments to this option.
+.TP
+.B -S <seed>
+Sets the hashing seed to the number specified. Only for use with
+.B hash
+type pools.
+.TP
+.B -t <type>
+Sets the type of pool being defined. Must be one of
+.B tree,
+.B hash,
+.B group-map.
+.TP
+.B -T <ttl>
+Sets the expiration of the node being added. The timeout is expressed
+as a number of seconds.
+.B tree,
+.B hash,
+.B group-map.
+.TP
+.B -u
+When parsing a configuration file, rather than load new pool data into the
+kernel, unload it.
+.TP
+.SH FILES
+.br
+/dev/iplookup
+.br
+/etc/ippool.conf
+.SH SEE ALSO
+ippool(5), ipf(8), ipfstat(8)
diff --git a/sbin/ipf/ippool/ippool.c b/sbin/ipf/ippool/ippool.c
new file mode 100644
index 000000000000..98666f9868fd
--- /dev/null
+++ b/sbin/ipf/ippool/ippool.c
@@ -0,0 +1,1145 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+# include <sys/cdefs.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <unistd.h>
+# include <nlist.h>
+
+#include "ipf.h"
+#include "netinet/ipl.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+#include "netinet/ip_htable.h"
+#include "kmem.h"
+
+
+extern int ippool_yyparse(void);
+extern int ippool_yydebug;
+extern FILE *ippool_yyin;
+extern char *optarg;
+extern int lineNum;
+
+void usage(char *);
+int main(int, char **);
+int poolcommand(int, int, char *[]);
+int poolnodecommand(int, int, char *[]);
+int loadpoolfile(int, char *[], char *);
+int poollist(int, char *[]);
+void poollist_dead(int, char *, int, char *, char *);
+void poollist_live(int, char *, int, int);
+int poolflush(int, char *[]);
+int poolstats(int, char *[]);
+int gettype(char *, u_int *);
+int getrole(char *);
+int setnodeaddr(int, int, void *ptr, char *arg);
+void showpools_live(int, int, ipf_pool_stat_t *, char *);
+void showhashs_live(int, int, iphtstat_t *, char *);
+void showdstls_live(int, int, ipf_dstl_stat_t *, char *);
+
+int opts = 0;
+int fd = -1;
+int use_inet6 = 0;
+wordtab_t *pool_fields = NULL;
+int nohdrfields = 0;
+
+
+void
+usage(prog)
+ char *prog;
+{
+ fprintf(stderr, "Usage:\t%s\n", prog);
+ fprintf(stderr, "\t-a [-dnv] -m <name> [-o <role>] [-t type] [-T ttl] -i <ipaddr>[/netmask]\n");
+ fprintf(stderr, "\t-A [-dnv] [-m <name>] [-o <role>] [-S <seed>] [-t <type>]\n");
+ fprintf(stderr, "\t-f <file> [-dnuvR]\n");
+ fprintf(stderr, "\t-F [-dv] [-o <role>] [-t <type>]\n");
+ fprintf(stderr, "\t-l [-dv] [-m <name>] [-t <type>] [-o <role>] [-M <core>] [-N <namelist>]\n");
+ fprintf(stderr, "\t-r [-dnv] [-m <name>] [-o <role>] [-t type] -i <ipaddr>[/netmask]\n");
+ fprintf(stderr, "\t-R [-dnv] [-m <name>] [-o <role>] [-t <type>]\n");
+ fprintf(stderr, "\t-s [-dtv]\n");
+ exit(1);
+}
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int err = 1;
+
+ if (argc < 2)
+ usage(argv[0]);
+
+ assigndefined(getenv("IPPOOL_PREDEFINED"));
+
+ switch (getopt(argc, argv, "aAf: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);
+ }
+
+ if (err != 0)
+ exit(1);
+ return 0;
+}
+
+
+int
+poolnodecommand(remove, argc, argv)
+ int remove, argc;
+ char *argv[];
+{
+ int err = 0, c, ipset, role, type = IPLT_POOL, ttl = 0;
+ char *poolname = NULL;
+ ip_pool_node_t pnode;
+ iphtent_t hnode;
+ void *ptr = &pnode;
+
+ ipset = 0;
+ role = IPL_LOGIPF;
+ bzero((char *)&pnode, sizeof(pnode));
+ bzero((char *)&hnode, sizeof(hnode));
+
+ while ((c = getopt(argc, argv, "di:m:no:t:T:v")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ ippool_yydebug++;
+ break;
+ case 'i' :
+ if (setnodeaddr(type, role, ptr, optarg) == 0)
+ ipset = 1;
+ break;
+ case 'm' :
+ poolname = optarg;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING|OPT_DONTOPEN;
+ break;
+ case 'o' :
+ if (ipset == 1) {
+ fprintf(stderr,
+ "cannot set role after ip address\n");
+ return -1;
+ }
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE)
+ return -1;
+ break;
+ case 't' :
+ if (ipset == 1) {
+ fprintf(stderr,
+ "cannot set type after ip address\n");
+ return -1;
+ }
+ type = gettype(optarg, NULL);
+ switch (type) {
+ case IPLT_NONE :
+ fprintf(stderr, "unknown type '%s'\n", optarg);
+ return -1;
+ case IPLT_HASH :
+ ptr = &hnode;
+ break;
+ case IPLT_POOL :
+ default :
+ break;
+ }
+ break;
+ case 'T' :
+ if (remove == 0) {
+ ttl = atoi(optarg);
+ if (ttl < 0) {
+ fprintf(stderr, "cannot set negative ttl\n");
+ return -1;
+ }
+ } else {
+ usage(argv[0]);
+ }
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ usage(argv[0]);
+ break; /* keep compiler happy */
+ }
+
+ if (argc - 1 - optind > 0)
+ usage(argv[0]);
+
+ if (argv[optind] != NULL && ipset == 0) {
+ if (setnodeaddr(type, role, ptr, argv[optind]) == 0)
+ ipset = 1;
+ }
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poolnodecommand: opts = %#x\n", opts);
+
+ if (ipset == 0) {
+ fprintf(stderr, "no IP address given with -i\n");
+ return -1;
+ }
+
+ if (poolname == NULL) {
+ fprintf(stderr, "poolname not given with add/remove node\n");
+ return -1;
+ }
+
+ switch (type) {
+ case IPLT_POOL :
+ if (remove == 0)
+ err = load_poolnode(role, poolname, &pnode, ttl, ioctl);
+ else
+ err = remove_poolnode(role, poolname, &pnode, ioctl);
+ break;
+ case IPLT_HASH :
+ if (remove == 0)
+ err = load_hashnode(role, poolname, &hnode, ttl, ioctl);
+ else
+ err = remove_hashnode(role, poolname, &hnode, ioctl);
+ break;
+ default :
+ break;
+ }
+ return err;
+}
+
+
+int
+poolcommand(remove, argc, argv)
+ int remove, argc;
+ char *argv[];
+{
+ int type, role, c, err;
+ char *poolname, *typearg = NULL;
+ iphtable_t iph;
+ ip_pool_t pool;
+
+ err = 1;
+ role = 0;
+ type = 0;
+ poolname = NULL;
+ role = IPL_LOGIPF;
+ bzero((char *)&iph, sizeof(iph));
+ bzero((char *)&pool, sizeof(pool));
+
+ while ((c = getopt(argc, argv, "dm:no:S:vt:")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ ippool_yydebug++;
+ break;
+ case 'm' :
+ poolname = optarg;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING|OPT_DONTOPEN;
+ break;
+ case 'o' :
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE) {
+ fprintf(stderr, "unknown role '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 'S' :
+ if (remove == 0)
+ iph.iph_seed = atoi(optarg);
+ else
+ usage(argv[0]);
+ break;
+ case 't' :
+ type = gettype(optarg, &iph.iph_type);
+ typearg = optarg;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ usage(argv[0]);
+ break; /* keep compiler happy */
+ }
+
+ if (argc - 1 - optind > 0)
+ usage(argv[0]);
+
+ 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_NONE && remove == 0) {
+ if (typearg == NULL) {
+ fprintf(stderr, "type must be specified\n");
+ usage(argv[0]);
+ } else {
+ fprintf(stderr, "unknown type '%s'\n", typearg);
+ }
+ return -1;
+ }
+
+ if (type == IPLT_HASH || (type == IPLT_NONE && remove == 1)) {
+ strncpy(iph.iph_name, poolname, sizeof(iph.iph_name));
+ iph.iph_name[sizeof(iph.iph_name) - 1] = '\0';
+ iph.iph_unit = role;
+ }
+ if (type == IPLT_POOL || (type == IPLT_NONE && remove == 1)) {
+ 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;
+ case IPLT_NONE :
+ err = 1;
+ {
+ int err_h, err_p;
+ err_h = remove_hash(&iph, ioctl);
+ err_p = remove_pool(&pool, ioctl);
+ if (err_h == 0 || err_p == 0)
+ err = 0;
+ }
+ break;
+ }
+ }
+ return err;
+}
+
+
+int
+loadpoolfile(argc, argv, infile)
+ int argc;
+ char *argv[], *infile;
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "dnuvf:")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ ippool_yydebug++;
+ break;
+ case 'f' :
+ if (loadpoolfile(argc, argv, optarg) != 0)
+ return(-1);
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING|OPT_DONTOPEN;
+ break;
+ case 'u' :
+ opts |= OPT_REMOVE;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ usage(argv[0]);
+ break; /* keep compiler happy */
+ }
+
+ if (argc - 1 - optind > 0)
+ usage(argv[0]);
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "loadpoolfile: opts = %#x\n", opts);
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
+ fd = open(IPLOOKUP_NAME, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPLOOKUP_NAME)");
+ exit(1);
+ }
+ }
+
+ if (ippool_parsefile(fd, infile, ioctl) != 0)
+ return -1;
+ return 0;
+}
+
+
+int
+poolstats(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, type, role;
+ ipf_pool_stat_t plstat;
+ ipf_dstl_stat_t dlstat;
+ iphtstat_t htstat;
+ iplookupop_t op;
+
+ type = IPLT_ALL;
+ role = IPL_LOGALL;
+
+ bzero((char *)&op, sizeof(op));
+
+ while ((c = getopt(argc, argv, "dM:N:o:t:v")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case '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;
+ default :
+ usage(argv[0]);
+ break; /* keep compiler happy */
+ }
+
+ if (argc - 1 - optind > 0)
+ usage(argv[0]);
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poolstats: opts = %#x\n", opts);
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
+ fd = open(IPLOOKUP_NAME, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPLOOKUP_NAME)");
+ exit(1);
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_POOL) {
+ op.iplo_type = IPLT_POOL;
+ op.iplo_struct = &plstat;
+ op.iplo_size = sizeof(plstat);
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(S0IOCLOOKUPSTAT)");
+ return -1;
+ }
+ printf("%lu\taddress pools\n", plstat.ipls_pools);
+ printf("%lu\taddress pool nodes\n", plstat.ipls_nodes);
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_HASH) {
+ op.iplo_type = IPLT_HASH;
+ op.iplo_struct = &htstat;
+ op.iplo_size = sizeof(htstat);
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return -1;
+ }
+ printf("%lu\thash tables\n", htstat.iphs_numtables);
+ printf("%lu\thash table nodes\n", htstat.iphs_numnodes);
+ printf("%lu\thash table no memory \n",
+ htstat.iphs_nomem);
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_DSTLIST) {
+ op.iplo_type = IPLT_DSTLIST;
+ op.iplo_struct = &dlstat;
+ op.iplo_size = sizeof(dlstat);
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return -1;
+ }
+ printf("%u\tdestination lists\n",
+ dlstat.ipls_numlists);
+ printf("%u\tdestination list nodes\n",
+ dlstat.ipls_numnodes);
+ printf("%lu\tdestination list no memory\n",
+ dlstat.ipls_nomem);
+ printf("%u\tdestination list zombies\n",
+ dlstat.ipls_numdereflists);
+ printf("%u\tdesetination list node zombies\n",
+ dlstat.ipls_numderefnodes);
+ }
+ }
+ return 0;
+}
+
+
+int
+poolflush(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c, role, type, arg;
+ iplookupflush_t flush;
+
+ arg = IPLT_ALL;
+ type = IPLT_ALL;
+ role = IPL_LOGALL;
+
+ while ((c = getopt(argc, argv, "do:t:v")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'o' :
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE) {
+ fprintf(stderr, "unknown role '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 't' :
+ type = gettype(optarg, NULL);
+ if (type == IPLT_NONE) {
+ fprintf(stderr, "unknown type '%s'\n", optarg);
+ return -1;
+ }
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ default :
+ usage(argv[0]);
+ break; /* keep compiler happy */
+ }
+
+ if (argc - optind > 0)
+ usage(argv[0]);
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poolflush: opts = %#x\n", opts);
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
+ fd = open(IPLOOKUP_NAME, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPLOOKUP_NAME)");
+ exit(1);
+ }
+ }
+
+ bzero((char *)&flush, sizeof(flush));
+ flush.iplf_type = type;
+ flush.iplf_unit = role;
+ flush.iplf_arg = arg;
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN))) {
+ if (ioctl(fd, SIOCLOOKUPFLUSH, &flush) == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPFLUSH)");
+ exit(1);
+ }
+
+ }
+ printf("%u object%s flushed\n", flush.iplf_count,
+ (flush.iplf_count == 1) ? "" : "s");
+
+ return 0;
+}
+
+
+int
+getrole(rolename)
+ char *rolename;
+{
+ int role;
+
+ if (!strcasecmp(rolename, "ipf")) {
+ role = IPL_LOGIPF;
+#if 0
+ } else if (!strcasecmp(rolename, "nat")) {
+ role = IPL_LOGNAT;
+ } else if (!strcasecmp(rolename, "state")) {
+ role = IPL_LOGSTATE;
+ } else if (!strcasecmp(rolename, "auth")) {
+ role = IPL_LOGAUTH;
+ } else if (!strcasecmp(rolename, "sync")) {
+ role = IPL_LOGSYNC;
+ } else if (!strcasecmp(rolename, "scan")) {
+ role = IPL_LOGSCAN;
+ } else if (!strcasecmp(rolename, "pool")) {
+ role = IPL_LOGLOOKUP;
+ } else if (!strcasecmp(rolename, "count")) {
+ role = IPL_LOGCOUNT;
+#endif
+ } else {
+ role = IPL_LOGNONE;
+ }
+
+ return role;
+}
+
+
+int
+gettype(typename, minor)
+ char *typename;
+ u_int *minor;
+{
+ int type;
+
+ if (!strcasecmp(typename, "tree") || !strcasecmp(typename, "pool")) {
+ type = IPLT_POOL;
+ } else if (!strcasecmp(typename, "hash")) {
+ type = IPLT_HASH;
+ if (minor != NULL)
+ *minor = IPHASH_LOOKUP;
+ } else if (!strcasecmp(typename, "group-map")) {
+ type = IPLT_HASH;
+ if (minor != NULL)
+ *minor = IPHASH_GROUPMAP;
+ } else {
+ type = IPLT_NONE;
+ }
+ return type;
+}
+
+
+int
+poollist(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *kernel, *core, *poolname;
+ int c, role, type, live_kernel;
+ iplookupop_t op;
+
+ core = NULL;
+ kernel = NULL;
+ live_kernel = 1;
+ type = IPLT_ALL;
+ poolname = NULL;
+ role = IPL_LOGALL;
+
+ while ((c = getopt(argc, argv, "dm:M:N:o:t:v")) != -1)
+ switch (c)
+ {
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'm' :
+ poolname = optarg;
+ break;
+ case 'M' :
+ live_kernel = 0;
+ core = optarg;
+ break;
+ case 'N' :
+ live_kernel = 0;
+ kernel = optarg;
+ break;
+ case 'o' :
+ role = getrole(optarg);
+ if (role == IPL_LOGNONE) {
+ fprintf(stderr, "unknown role '%s'\n", optarg);
+ return -1;
+ }
+ break;
+#if 0
+ case 'O' :
+ /* XXX This option does not work. This function as */
+ /* XXX used by state and nat can be used to format */
+ /* XXX output especially useful for scripting. It */
+ /* XXX is left here with the intention of making */
+ /* XXX it work for the same purpose at some point. */
+ pool_fields = parsefields(poolfields, optarg);
+ break;
+#endif
+ 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;
+ default :
+ usage(argv[0]);
+ break; /* keep compiler happy */
+ }
+
+ if (argc - optind > 0)
+ usage(argv[0]);
+
+ if (opts & OPT_DEBUG)
+ fprintf(stderr, "poollist: opts = %#x\n", opts);
+
+ if (!(opts & (OPT_DONOTHING|OPT_DONTOPEN)) && (fd == -1)) {
+ fd = open(IPLOOKUP_NAME, O_RDWR);
+ if (fd == -1) {
+ perror("open(IPLOOKUP_NAME)");
+ exit(1);
+ }
+ }
+
+ bzero((char *)&op, sizeof(op));
+ if (poolname != NULL) {
+ strncpy(op.iplo_name, poolname, sizeof(op.iplo_name));
+ op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
+ }
+ op.iplo_unit = role;
+
+ if (live_kernel)
+ poollist_live(role, poolname, type, fd);
+ else
+ poollist_dead(role, poolname, type, kernel, core);
+ return 0;
+}
+
+
+void
+poollist_dead(role, poolname, type, kernel, core)
+ int role, type;
+ char *poolname, *kernel, *core;
+{
+ iphtable_t *hptr;
+ ip_pool_t *ptr;
+
+ if (openkmem(kernel, core) == -1)
+ exit(-1);
+
+ if (type == IPLT_ALL || type == IPLT_POOL) {
+ ip_pool_t *pools[IPL_LOGSIZE];
+ struct nlist names[2] = { { "ip_pool_list" } , { "" } };
+
+ if (nlist(kernel, names) != 1)
+ return;
+
+ bzero(&pools, sizeof(pools));
+ if (kmemcpy((char *)&pools, names[0].n_value, sizeof(pools)))
+ return;
+
+ if (role != IPL_LOGALL) {
+ ptr = pools[role];
+ while (ptr != NULL) {
+ ptr = printpool(ptr, kmemcpywrap, poolname,
+ opts, pool_fields);
+ }
+ } else {
+ for (role = 0; role <= IPL_LOGMAX; role++) {
+ ptr = pools[role];
+ while (ptr != NULL) {
+ ptr = printpool(ptr, kmemcpywrap,
+ poolname, opts,
+ pool_fields);
+ }
+ }
+ role = IPL_LOGALL;
+ }
+ }
+ if (type == IPLT_ALL || type == IPLT_HASH) {
+ iphtable_t *tables[IPL_LOGSIZE];
+ struct nlist names[2] = { { "ipf_htables" } , { "" } };
+
+ if (nlist(kernel, names) != 1)
+ return;
+
+ bzero(&tables, sizeof(tables));
+ if (kmemcpy((char *)&tables, names[0].n_value, sizeof(tables)))
+ return;
+
+ if (role != IPL_LOGALL) {
+ hptr = tables[role];
+ while (hptr != NULL) {
+ hptr = printhash(hptr, kmemcpywrap,
+ poolname, opts, pool_fields);
+ }
+ } else {
+ for (role = 0; role <= IPL_LOGMAX; role++) {
+ hptr = tables[role];
+ while (hptr != NULL) {
+ hptr = printhash(hptr, kmemcpywrap,
+ poolname, opts,
+ pool_fields);
+ }
+ }
+ }
+ }
+}
+
+
+void
+poollist_live(role, poolname, type, fd)
+ int role, type, fd;
+ char *poolname;
+{
+ ipf_pool_stat_t plstat;
+ iplookupop_t op;
+ int c;
+
+ if (type == IPLT_ALL || type == IPLT_POOL) {
+ op.iplo_type = IPLT_POOL;
+ op.iplo_size = sizeof(plstat);
+ op.iplo_struct = &plstat;
+ op.iplo_name[0] = '\0';
+ op.iplo_arg = 0;
+
+ if (role != IPL_LOGALL) {
+ op.iplo_unit = role;
+
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+
+ showpools_live(fd, role, &plstat, poolname);
+ } else {
+ for (role = -1; role <= IPL_LOGMAX; role++) {
+ op.iplo_unit = role;
+
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+
+ showpools_live(fd, role, &plstat, poolname);
+ }
+
+ role = IPL_LOGALL;
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_HASH) {
+ iphtstat_t htstat;
+
+ op.iplo_type = IPLT_HASH;
+ op.iplo_size = sizeof(htstat);
+ op.iplo_struct = &htstat;
+ op.iplo_name[0] = '\0';
+ op.iplo_arg = 0;
+
+ if (role != IPL_LOGALL) {
+ op.iplo_unit = role;
+
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+ showhashs_live(fd, role, &htstat, poolname);
+ } else {
+ for (role = 0; role <= IPL_LOGMAX; role++) {
+
+ op.iplo_unit = role;
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+
+ showhashs_live(fd, role, &htstat, poolname);
+ }
+ role = IPL_LOGALL;
+ }
+ }
+
+ if (type == IPLT_ALL || type == IPLT_DSTLIST) {
+ ipf_dstl_stat_t dlstat;
+
+ op.iplo_type = IPLT_DSTLIST;
+ op.iplo_size = sizeof(dlstat);
+ op.iplo_struct = &dlstat;
+ op.iplo_name[0] = '\0';
+ op.iplo_arg = 0;
+
+ if (role != IPL_LOGALL) {
+ op.iplo_unit = role;
+
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+ showdstls_live(fd, role, &dlstat, poolname);
+ } else {
+ for (role = 0; role <= IPL_LOGMAX; role++) {
+
+ op.iplo_unit = role;
+ c = ioctl(fd, SIOCLOOKUPSTAT, &op);
+ if (c == -1) {
+ ipferror(fd, "ioctl(SIOCLOOKUPSTAT)");
+ return;
+ }
+
+ showdstls_live(fd, role, &dlstat, poolname);
+ }
+ role = IPL_LOGALL;
+ }
+ }
+}
+
+
+void
+showpools_live(fd, role, plstp, poolname)
+ int fd, role;
+ ipf_pool_stat_t *plstp;
+ char *poolname;
+{
+ ipflookupiter_t iter;
+ ip_pool_t pool;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_size = sizeof(iter);
+ obj.ipfo_ptr = &iter;
+
+ iter.ili_type = IPLT_POOL;
+ iter.ili_otype = IPFLOOKUPITER_LIST;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_nitems = 1;
+ iter.ili_data = &pool;
+ iter.ili_unit = role;
+ *iter.ili_name = '\0';
+
+ bzero((char *)&pool, sizeof(pool));
+
+ while (plstp->ipls_list[role + 1] != NULL) {
+ if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
+ ipferror(fd, "ioctl(SIOCLOOKUPITER)");
+ break;
+ }
+ if (((pool.ipo_flags & IPOOL_DELETE) == 0) ||
+ ((opts & OPT_DEBUG) != 0))
+ printpool_live(&pool, fd, poolname, opts, pool_fields);
+
+ plstp->ipls_list[role + 1] = pool.ipo_next;
+ }
+}
+
+
+void
+showhashs_live(fd, role, htstp, poolname)
+ int fd, role;
+ iphtstat_t *htstp;
+ char *poolname;
+{
+ ipflookupiter_t iter;
+ iphtable_t table;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_size = sizeof(iter);
+ obj.ipfo_ptr = &iter;
+
+ iter.ili_type = IPLT_HASH;
+ iter.ili_otype = IPFLOOKUPITER_LIST;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_nitems = 1;
+ iter.ili_data = &table;
+ iter.ili_unit = role;
+ *iter.ili_name = '\0';
+
+ while (htstp->iphs_tables != NULL) {
+ if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
+ ipferror(fd, "ioctl(SIOCLOOKUPITER)");
+ break;
+ }
+
+ printhash_live(&table, fd, poolname, opts, pool_fields);
+
+ htstp->iphs_tables = table.iph_next;
+ }
+}
+
+
+void
+showdstls_live(fd, role, dlstp, poolname)
+ int fd, role;
+ ipf_dstl_stat_t *dlstp;
+ char *poolname;
+{
+ ipflookupiter_t iter;
+ ippool_dst_t table;
+ ipfobj_t obj;
+
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_type = IPFOBJ_LOOKUPITER;
+ obj.ipfo_size = sizeof(iter);
+ obj.ipfo_ptr = &iter;
+
+ iter.ili_type = IPLT_DSTLIST;
+ iter.ili_otype = IPFLOOKUPITER_LIST;
+ iter.ili_ival = IPFGENITER_LOOKUP;
+ iter.ili_nitems = 1;
+ iter.ili_data = &table;
+ iter.ili_unit = role;
+ *iter.ili_name = '\0';
+
+ while (dlstp->ipls_list[role] != NULL) {
+ if (ioctl(fd, SIOCLOOKUPITER, &obj)) {
+ ipferror(fd, "ioctl(SIOCLOOKUPITER)");
+ break;
+ }
+
+ printdstl_live(&table, fd, poolname, opts, pool_fields);
+
+ dlstp->ipls_list[role] = table.ipld_next;
+ }
+}
+
+
+int
+setnodeaddr(int type, int role, void *ptr, char *arg)
+{
+ struct in_addr mask;
+ sa_family_t family;
+ char *s;
+
+ if (strchr(arg, ':') == NULL) {
+ family = AF_INET;
+ s = strchr(arg, '/');
+ if (s == NULL)
+ mask.s_addr = 0xffffffff;
+ else if (strchr(s, '.') == NULL) {
+ if (ntomask(AF_INET, atoi(s + 1), &mask.s_addr) != 0)
+ return -1;
+ } else {
+ mask.s_addr = inet_addr(s + 1);
+ }
+ if (s != NULL)
+ *s = '\0';
+ } else {
+ family = AF_INET6;
+
+ /* XXX for now we use mask for IPv6 prefix length */
+ /* XXX mask should be a union with prefix */
+ /* XXX Currently address handling is sloppy. */
+
+ if ((s = strchr(arg, '/')) == NULL)
+ mask.s_addr = 128;
+ else
+ mask.s_addr = atoi(s + 1);
+ }
+
+ if (type == IPLT_POOL) {
+ ip_pool_node_t *node = ptr;
+
+ node->ipn_addr.adf_family = family;
+
+#ifdef USE_INET6
+ if (node->ipn_addr.adf_family == AF_INET) {
+#endif
+ node->ipn_addr.adf_len = offsetof(addrfamily_t,
+ adf_addr) +
+ sizeof(struct in_addr);
+ node->ipn_addr.adf_addr.in4.s_addr = inet_addr(arg);
+#ifdef USE_INET6
+ } else {
+ node->ipn_addr.adf_len = offsetof(addrfamily_t,
+ adf_addr) +
+ sizeof(struct in6_addr);
+ inet_pton(AF_INET6, arg,
+ &node->ipn_addr.adf_addr.in6.s6_addr);
+ }
+#endif
+ node->ipn_mask.adf_len = node->ipn_addr.adf_len;
+ node->ipn_mask.adf_addr.in4.s_addr = mask.s_addr;
+ } else if (type == IPLT_HASH) {
+ iphtent_t *node = ptr;
+
+ node->ipe_family = family;
+ node->ipe_unit = role;
+
+#ifdef USE_INET6
+ if (node->ipe_family == AF_INET) {
+#endif
+ node->ipe_addr.in4.s_addr = inet_addr(arg);
+ node->ipe_mask.in4.s_addr = mask.s_addr;
+#ifdef USE_INET6
+ } else {
+ inet_pton(AF_INET6, arg,
+ &node->ipe_addr.in6.__u6_addr.__u6_addr32);
+ node->ipe_mask.in6.__u6_addr.__u6_addr32[0] =
+ mask.s_addr;
+ node->ipe_mask.in6.__u6_addr.__u6_addr32[1] =
+ node->ipe_mask.in6.__u6_addr.__u6_addr32[2] =
+ node->ipe_mask.in6.__u6_addr.__u6_addr32[3] = 0;
+ }
+#endif
+ }
+
+ return 0;
+}
diff --git a/sbin/ipf/ippool/ippool_y.y b/sbin/ipf/ippool/ippool_y.y
new file mode 100644
index 000000000000..03ee1731f24f
--- /dev/null
+++ b/sbin/ipf/ippool/ippool_y.y
@@ -0,0 +1,832 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+%{
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+# include <sys/cdefs.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include "ipf.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_pool.h"
+#include "netinet/ip_htable.h"
+#include "netinet/ip_dstlist.h"
+#include "ippool_l.h"
+#include "kmem.h"
+
+#define YYDEBUG 1
+#define YYSTACKSIZE 0x00ffffff
+
+extern int yyparse(void);
+extern int yydebug;
+extern FILE *yyin;
+
+static iphtable_t ipht;
+static iphtent_t iphte;
+static ip_pool_t iplo;
+static ippool_dst_t ipld;
+static ioctlfunc_t poolioctl = NULL;
+static char poolname[FR_GROUPLEN];
+
+static iphtent_t *add_htablehosts(char *);
+static ip_pool_node_t *add_poolhosts(char *);
+static ip_pool_node_t *read_whoisfile(char *);
+static void setadflen(addrfamily_t *);
+
+%}
+
+%union {
+ char *str;
+ u_32_t num;
+ struct in_addr ip4;
+ struct alist_s *alist;
+ addrfamily_t adrmsk[2];
+ iphtent_t *ipe;
+ ip_pool_node_t *ipp;
+ ipf_dstnode_t *ipd;
+ addrfamily_t ipa;
+ i6addr_t ip6;
+}
+
+%token <num> YY_NUMBER YY_HEX
+%token <str> YY_STR
+%token <ip6> YY_IPV6
+%token YY_COMMENT
+%token YY_CMP_EQ YY_CMP_NE YY_CMP_LE YY_CMP_GE YY_CMP_LT YY_CMP_GT
+%token YY_RANGE_OUT YY_RANGE_IN
+%token IPT_IPF IPT_NAT IPT_COUNT IPT_AUTH IPT_IN IPT_OUT IPT_ALL
+%token IPT_TABLE IPT_GROUPMAP IPT_HASH IPT_SRCHASH IPT_DSTHASH
+%token IPT_ROLE IPT_TYPE IPT_TREE
+%token IPT_GROUP IPT_SIZE IPT_SEED IPT_NUM IPT_NAME IPT_POLICY
+%token IPT_POOL IPT_DSTLIST IPT_ROUNDROBIN
+%token IPT_WEIGHTED IPT_RANDOM IPT_CONNECTION
+%token IPT_WHOIS IPT_FILE
+%type <num> role table inout unit dstopts weighting
+%type <ipp> ipftree range addrlist
+%type <adrmsk> addrmask
+%type <ipe> ipfgroup ipfhash hashlist hashentry
+%type <ipe> groupentry setgrouplist grouplist
+%type <ipa> ipaddr mask
+%type <ip4> ipv4
+%type <str> number setgroup name
+%type <ipd> dstentry dstentries dstlist
+
+%%
+file: line
+ | assign
+ | file line
+ | file assign
+ ;
+
+line: table role ipftree eol { ip_pool_node_t *n;
+ iplo.ipo_unit = $2;
+ iplo.ipo_list = $3;
+ load_pool(&iplo, poolioctl);
+ while ((n = $3) != NULL) {
+ $3 = n->ipn_next;
+ free(n);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ }
+ | table role ipfhash eol { iphtent_t *h;
+ ipht.iph_unit = $2;
+ ipht.iph_type = IPHASH_LOOKUP;
+ load_hash(&ipht, $3, poolioctl);
+ while ((h = $3) != NULL) {
+ $3 = h->ipe_next;
+ free(h);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ }
+ | groupmap role number ipfgroup eol
+ { iphtent_t *h;
+ ipht.iph_unit = $2;
+ strncpy(ipht.iph_name, $3,
+ sizeof(ipht.iph_name));
+ ipht.iph_type = IPHASH_GROUPMAP;
+ load_hash(&ipht, $4, poolioctl);
+ while ((h = $4) != NULL) {
+ $4 = h->ipe_next;
+ free(h);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ }
+ | YY_COMMENT
+ | poolline eol
+ ;
+
+eol: ';'
+ ;
+
+assign: YY_STR assigning YY_STR ';' { set_variable($1, $3);
+ resetlexer();
+ free($1);
+ free($3);
+ yyvarnext = 0;
+ }
+ ;
+
+assigning:
+ '=' { yyvarnext = 1; }
+ ;
+
+table: IPT_TABLE { bzero((char *)&ipht, sizeof(ipht));
+ bzero((char *)&iphte, sizeof(iphte));
+ bzero((char *)&iplo, sizeof(iplo));
+ bzero((char *)&ipld, sizeof(ipld));
+ *ipht.iph_name = '\0';
+ iplo.ipo_flags = IPHASH_ANON;
+ iplo.ipo_name[0] = '\0';
+ }
+ ;
+
+groupmap:
+ IPT_GROUPMAP inout { bzero((char *)&ipht, sizeof(ipht));
+ bzero((char *)&iphte, sizeof(iphte));
+ *ipht.iph_name = '\0';
+ ipht.iph_unit = IPHASH_GROUPMAP;
+ ipht.iph_flags = $2;
+ }
+ ;
+
+inout: IPT_IN { $$ = FR_INQUE; }
+ | IPT_OUT { $$ = FR_OUTQUE; }
+ ;
+
+role: IPT_ROLE '=' unit { $$ = $3; }
+ ;
+
+unit: IPT_IPF { $$ = IPL_LOGIPF; }
+ | IPT_NAT { $$ = IPL_LOGNAT; }
+ | IPT_AUTH { $$ = IPL_LOGAUTH; }
+ | IPT_COUNT { $$ = IPL_LOGCOUNT; }
+ | IPT_ALL { $$ = IPL_LOGALL; }
+ ;
+
+ipftree:
+ IPT_TYPE '=' IPT_TREE number start addrlist end
+ { strncpy(iplo.ipo_name, $4,
+ sizeof(iplo.ipo_name));
+ $$ = $6;
+ }
+ ;
+
+ipfhash:
+ IPT_TYPE '=' IPT_HASH number hashopts start hashlist end
+ { strncpy(ipht.iph_name, $4,
+ sizeof(ipht.iph_name));
+ $$ = $7;
+ }
+ ;
+
+ipfgroup:
+ setgroup hashopts start grouplist end
+ { iphtent_t *e;
+ for (e = $4; e != NULL;
+ e = e->ipe_next)
+ if (e->ipe_group[0] == '\0')
+ strncpy(e->ipe_group,
+ $1,
+ FR_GROUPLEN);
+ $$ = $4;
+ free($1);
+ }
+ | hashopts start setgrouplist end
+ { $$ = $3; }
+ ;
+
+number: IPT_NUM '=' YY_NUMBER { snprintf(poolname, sizeof(poolname), "%u", $3);
+ $$ = poolname;
+ }
+ | IPT_NAME '=' YY_STR { strncpy(poolname, $3,
+ FR_GROUPLEN);
+ poolname[FR_GROUPLEN-1]='\0';
+ free($3);
+ $$ = poolname;
+ }
+ | { $$ = ""; }
+ ;
+
+setgroup:
+ IPT_GROUP '=' YY_STR { char tmp[FR_GROUPLEN+1];
+ strncpy(tmp, $3, FR_GROUPLEN);
+ $$ = strdup(tmp);
+ free($3);
+ }
+ | IPT_GROUP '=' YY_NUMBER { char tmp[FR_GROUPLEN+1];
+ snprintf(tmp, sizeof(tmp), "%u", $3);
+ $$ = strdup(tmp);
+ }
+ ;
+
+hashopts:
+ | size
+ | seed
+ | size seed
+ ;
+
+addrlist:
+ ';' { $$ = NULL; }
+ | range next addrlist { $$ = $1;
+ while ($1->ipn_next != NULL)
+ $1 = $1->ipn_next;
+ $1->ipn_next = $3;
+ }
+ | range next { $$ = $1; }
+ ;
+
+grouplist:
+ ';' { $$ = NULL; }
+ | groupentry next grouplist { $$ = $1; $1->ipe_next = $3; }
+ | addrmask next grouplist { $$ = calloc(1, sizeof(iphtent_t));
+ $$->ipe_addr = $1[0].adf_addr;
+ $$->ipe_mask = $1[1].adf_addr;
+ $$->ipe_family = $1[0].adf_family;
+ $$->ipe_next = $3;
+ }
+ | groupentry next { $$ = $1; }
+ | addrmask next { $$ = calloc(1, sizeof(iphtent_t));
+ $$->ipe_addr = $1[0].adf_addr;
+ $$->ipe_mask = $1[1].adf_addr;
+#ifdef USE_INET6
+ if (use_inet6)
+ $$->ipe_family = AF_INET6;
+ else
+#endif
+ $$->ipe_family = AF_INET;
+ }
+ | YY_STR { $$ = add_htablehosts($1);
+ free($1);
+ }
+ ;
+
+setgrouplist:
+ ';' { $$ = NULL; }
+ | groupentry next { $$ = $1; }
+ | groupentry next setgrouplist { $1->ipe_next = $3; $$ = $1; }
+ ;
+
+groupentry:
+ addrmask ',' setgroup { $$ = calloc(1, sizeof(iphtent_t));
+ $$->ipe_addr = $1[0].adf_addr;
+ $$->ipe_mask = $1[1].adf_addr;
+ strncpy($$->ipe_group, $3,
+ FR_GROUPLEN);
+#ifdef USE_INET6
+ if (use_inet6)
+ $$->ipe_family = AF_INET6;
+ else
+#endif
+ $$->ipe_family = AF_INET;
+ free($3);
+ }
+ ;
+
+range: addrmask { $$ = calloc(1, sizeof(*$$));
+ $$->ipn_info = 0;
+ $$->ipn_addr = $1[0];
+ $$->ipn_mask = $1[1];
+#ifdef USE_INET6
+ if (use_inet6)
+ $$->ipn_addr.adf_family =
+ AF_INET6;
+ else
+#endif
+ $$->ipn_addr.adf_family =
+ AF_INET;
+ }
+ | '!' addrmask { $$ = calloc(1, sizeof(*$$));
+ $$->ipn_info = 1;
+ $$->ipn_addr = $2[0];
+ $$->ipn_mask = $2[1];
+#ifdef USE_INET6
+ if (use_inet6)
+ $$->ipn_addr.adf_family =
+ AF_INET6;
+ else
+#endif
+ $$->ipn_addr.adf_family =
+ AF_INET;
+ }
+ | YY_STR { $$ = add_poolhosts($1);
+ free($1);
+ }
+ | IPT_WHOIS IPT_FILE YY_STR { $$ = read_whoisfile($3);
+ free($3);
+ }
+ ;
+
+hashlist:
+ ';' { $$ = NULL; }
+ | hashentry next { $$ = $1; }
+ | hashentry next hashlist { $1->ipe_next = $3; $$ = $1; }
+ ;
+
+hashentry:
+ addrmask { $$ = calloc(1, sizeof(iphtent_t));
+ $$->ipe_addr = $1[0].adf_addr;
+ $$->ipe_mask = $1[1].adf_addr;
+#ifdef USE_INET6
+ if (use_inet6)
+ $$->ipe_family = AF_INET6;
+ else
+#endif
+ $$->ipe_family = AF_INET;
+ }
+ | YY_STR { $$ = add_htablehosts($1);
+ free($1);
+ }
+ ;
+
+addrmask:
+ ipaddr '/' mask { $$[0] = $1;
+ setadflen(&$$[0]);
+ $$[1] = $3;
+ $$[1].adf_len = $$[0].adf_len;
+ }
+ | ipaddr { $$[0] = $1;
+ setadflen(&$$[1]);
+ $$[1].adf_len = $$[0].adf_len;
+#ifdef USE_INET6
+ if (use_inet6)
+ memset(&$$[1].adf_addr, 0xff,
+ sizeof($$[1].adf_addr.in6));
+ else
+#endif
+ memset(&$$[1].adf_addr, 0xff,
+ sizeof($$[1].adf_addr.in4));
+ }
+ ;
+
+ipaddr: ipv4 { $$.adf_addr.in4 = $1;
+ $$.adf_family = AF_INET;
+ setadflen(&$$);
+ use_inet6 = 0;
+ }
+ | YY_NUMBER { $$.adf_addr.in4.s_addr = htonl($1);
+ $$.adf_family = AF_INET;
+ setadflen(&$$);
+ use_inet6 = 0;
+ }
+ | YY_IPV6 { $$.adf_addr = $1;
+ $$.adf_family = AF_INET6;
+ setadflen(&$$);
+ use_inet6 = 1;
+ }
+ ;
+
+mask: YY_NUMBER { bzero(&$$, sizeof($$));
+ if (use_inet6) {
+ if (ntomask(AF_INET6, $1,
+ (u_32_t *)&$$.adf_addr) == -1)
+ yyerror("bad bitmask");
+ } else {
+ if (ntomask(AF_INET, $1,
+ (u_32_t *)&$$.adf_addr.in4) == -1)
+ yyerror("bad bitmask");
+ }
+ }
+ | ipv4 { bzero(&$$, sizeof($$));
+ $$.adf_addr.in4 = $1;
+ }
+ | YY_IPV6 { bzero(&$$, sizeof($$));
+ $$.adf_addr = $1;
+ }
+ ;
+
+size: IPT_SIZE '=' YY_NUMBER { ipht.iph_size = $3; }
+ ;
+
+seed: IPT_SEED '=' YY_NUMBER { ipht.iph_seed = $3; }
+ ;
+
+ipv4: YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER '.' YY_NUMBER
+ { if ($1 > 255 || $3 > 255 || $5 > 255 || $7 > 255) {
+ yyerror("Invalid octet string for IP address");
+ return 0;
+ }
+ $$.s_addr = ($1 << 24) | ($3 << 16) | ($5 << 8) | $7;
+ $$.s_addr = htonl($$.s_addr);
+ }
+ ;
+
+next: ';' { yyexpectaddr = 1; }
+ ;
+
+start: '{' { yyexpectaddr = 1; }
+ ;
+
+end: '}' { yyexpectaddr = 0; }
+ ;
+
+poolline:
+ IPT_POOL unit '/' IPT_DSTLIST '(' name ';' dstopts ')'
+ start dstlist end
+ { bzero((char *)&ipld, sizeof(ipld));
+ strncpy(ipld.ipld_name, $6,
+ sizeof(ipld.ipld_name));
+ ipld.ipld_unit = $2;
+ ipld.ipld_policy = $8;
+ load_dstlist(&ipld, poolioctl, $11);
+ resetlexer();
+ use_inet6 = 0;
+ free($6);
+ }
+ | IPT_POOL unit '/' IPT_TREE '(' name ';' ')'
+ start addrlist end
+ { bzero((char *)&iplo, sizeof(iplo));
+ strncpy(iplo.ipo_name, $6,
+ sizeof(iplo.ipo_name));
+ iplo.ipo_list = $10;
+ iplo.ipo_unit = $2;
+ load_pool(&iplo, poolioctl);
+ resetlexer();
+ use_inet6 = 0;
+ free($6);
+ }
+ | IPT_POOL '(' name ';' ')' start addrlist end
+ { bzero((char *)&iplo, sizeof(iplo));
+ strncpy(iplo.ipo_name, $3,
+ sizeof(iplo.ipo_name));
+ iplo.ipo_list = $7;
+ iplo.ipo_unit = IPL_LOGALL;
+ load_pool(&iplo, poolioctl);
+ resetlexer();
+ use_inet6 = 0;
+ free($3);
+ }
+ | IPT_POOL unit '/' IPT_HASH '(' name ';' hashoptlist ')'
+ start hashlist end
+ { iphtent_t *h;
+ bzero((char *)&ipht, sizeof(ipht));
+ strncpy(ipht.iph_name, $6,
+ sizeof(ipht.iph_name));
+ ipht.iph_unit = $2;
+ load_hash(&ipht, $11, poolioctl);
+ while ((h = ipht.iph_list) != NULL) {
+ ipht.iph_list = h->ipe_next;
+ free(h);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ free($6);
+ }
+ | IPT_GROUPMAP '(' name ';' inout ';' ')'
+ start setgrouplist end
+ { iphtent_t *h;
+ bzero((char *)&ipht, sizeof(ipht));
+ strncpy(ipht.iph_name, $3,
+ sizeof(ipht.iph_name));
+ ipht.iph_type = IPHASH_GROUPMAP;
+ ipht.iph_unit = IPL_LOGIPF;
+ ipht.iph_flags = $5;
+ load_hash(&ipht, $9, poolioctl);
+ while ((h = ipht.iph_list) != NULL) {
+ ipht.iph_list = h->ipe_next;
+ free(h);
+ }
+ resetlexer();
+ use_inet6 = 0;
+ free($3);
+ }
+ ;
+
+name: IPT_NAME YY_STR { $$ = $2; }
+ | IPT_NUM YY_NUMBER { char name[80];
+ snprintf(name, sizeof(name), "%d", $2);
+ $$ = strdup(name);
+ }
+ ;
+
+hashoptlist:
+ | hashopt ';'
+ | hashoptlist ';' hashopt ';'
+ ;
+hashopt:
+ IPT_SIZE YY_NUMBER
+ | IPT_SEED YY_NUMBER
+ ;
+
+dstlist:
+ dstentries { $$ = $1; }
+ | ';' { $$ = NULL; }
+ ;
+
+dstentries:
+ dstentry next { $$ = $1; }
+ | dstentry next dstentries { $1->ipfd_next = $3; $$ = $1; }
+ ;
+
+dstentry:
+ YY_STR ':' ipaddr { int size = sizeof(*$$) + strlen($1) + 1;
+ $$ = calloc(1, size);
+ if ($$ != NULL) {
+ $$->ipfd_dest.fd_name = strlen($1) + 1;
+ bcopy($1, $$->ipfd_names,
+ $$->ipfd_dest.fd_name);
+ $$->ipfd_dest.fd_addr = $3;
+ $$->ipfd_size = size;
+ }
+ free($1);
+ }
+ | ipaddr { $$ = calloc(1, sizeof(*$$));
+ if ($$ != NULL) {
+ $$->ipfd_dest.fd_name = -1;
+ $$->ipfd_dest.fd_addr = $1;
+ $$->ipfd_size = sizeof(*$$);
+ }
+ }
+ ;
+
+dstopts:
+ { $$ = IPLDP_NONE; }
+ | IPT_POLICY IPT_ROUNDROBIN ';' { $$ = IPLDP_ROUNDROBIN; }
+ | IPT_POLICY IPT_WEIGHTED weighting ';' { $$ = $3; }
+ | IPT_POLICY IPT_RANDOM ';' { $$ = IPLDP_RANDOM; }
+ | IPT_POLICY IPT_HASH ';' { $$ = IPLDP_HASHED; }
+ | IPT_POLICY IPT_SRCHASH ';' { $$ = IPLDP_SRCHASH; }
+ | IPT_POLICY IPT_DSTHASH ';' { $$ = IPLDP_DSTHASH; }
+ ;
+
+weighting:
+ IPT_CONNECTION { $$ = IPLDP_CONNECTION; }
+ ;
+%%
+static wordtab_t yywords[] = {
+ { "all", IPT_ALL },
+ { "auth", IPT_AUTH },
+ { "connection", IPT_CONNECTION },
+ { "count", IPT_COUNT },
+ { "dst-hash", IPT_DSTHASH },
+ { "dstlist", IPT_DSTLIST },
+ { "file", IPT_FILE },
+ { "group", IPT_GROUP },
+ { "group-map", IPT_GROUPMAP },
+ { "hash", IPT_HASH },
+ { "in", IPT_IN },
+ { "ipf", IPT_IPF },
+ { "name", IPT_NAME },
+ { "nat", IPT_NAT },
+ { "number", IPT_NUM },
+ { "out", IPT_OUT },
+ { "policy", IPT_POLICY },
+ { "pool", IPT_POOL },
+ { "random", IPT_RANDOM },
+ { "round-robin", IPT_ROUNDROBIN },
+ { "role", IPT_ROLE },
+ { "seed", IPT_SEED },
+ { "size", IPT_SIZE },
+ { "src-hash", IPT_SRCHASH },
+ { "table", IPT_TABLE },
+ { "tree", IPT_TREE },
+ { "type", IPT_TYPE },
+ { "weighted", IPT_WEIGHTED },
+ { "whois", IPT_WHOIS },
+ { NULL, 0 }
+};
+
+
+int ippool_parsefile(fd, filename, iocfunc)
+int fd;
+char *filename;
+ioctlfunc_t iocfunc;
+{
+ FILE *fp = NULL;
+ char *s;
+
+ yylineNum = 1;
+ (void) yysettab(yywords);
+
+ s = getenv("YYDEBUG");
+ if (s)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ if (strcmp(filename, "-")) {
+ fp = fopen(filename, "r");
+ if (!fp) {
+ fprintf(stderr, "fopen(%s) failed: %s\n", filename,
+ STRERROR(errno));
+ return -1;
+ }
+ } else
+ fp = stdin;
+
+ while (ippool_parsesome(fd, fp, iocfunc) == 1)
+ ;
+ if (fp != NULL)
+ fclose(fp);
+ return 0;
+}
+
+
+int ippool_parsesome(fd, fp, iocfunc)
+int fd;
+FILE *fp;
+ioctlfunc_t iocfunc;
+{
+ char *s;
+ int i;
+
+ poolioctl = iocfunc;
+
+ if (feof(fp))
+ return 0;
+ i = fgetc(fp);
+ if (i == EOF)
+ return 0;
+ if (ungetc(i, fp) == EOF)
+ return 0;
+ if (feof(fp))
+ return 0;
+ s = getenv("YYDEBUG");
+ if (s)
+ yydebug = atoi(s);
+ else
+ yydebug = 0;
+
+ yyin = fp;
+ yyparse();
+ return 1;
+}
+
+
+static iphtent_t *
+add_htablehosts(url)
+char *url;
+{
+ iphtent_t *htop, *hbot, *h;
+ alist_t *a, *hlist;
+
+ if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) {
+ hlist = load_url(url);
+ } else {
+ use_inet6 = 0;
+
+ hlist = calloc(1, sizeof(*hlist));
+ if (hlist == NULL)
+ return NULL;
+
+ if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) {
+ yyerror("Unknown hostname");
+ }
+ }
+
+ hbot = NULL;
+ htop = NULL;
+
+ for (a = hlist; a != NULL; a = a->al_next) {
+ h = calloc(1, sizeof(*h));
+ if (h == NULL)
+ break;
+
+ h->ipe_family = a->al_family;
+ h->ipe_addr = a->al_i6addr;
+ h->ipe_mask = a->al_i6mask;
+
+ if (hbot != NULL)
+ hbot->ipe_next = h;
+ else
+ htop = h;
+ hbot = h;
+ }
+
+ alist_free(hlist);
+
+ return htop;
+}
+
+
+static ip_pool_node_t *
+add_poolhosts(url)
+char *url;
+{
+ ip_pool_node_t *ptop, *pbot, *p;
+ alist_t *a, *hlist;
+
+ if (!strncmp(url, "file://", 7) || !strncmp(url, "http://", 7)) {
+ hlist = load_url(url);
+ } else {
+ use_inet6 = 0;
+
+ hlist = calloc(1, sizeof(*hlist));
+ if (hlist == NULL)
+ return NULL;
+
+ if (gethost(hlist->al_family, url, &hlist->al_i6addr) == -1) {
+ yyerror("Unknown hostname");
+ }
+ }
+
+ pbot = NULL;
+ ptop = NULL;
+
+ for (a = hlist; a != NULL; a = a->al_next) {
+ p = calloc(1, sizeof(*p));
+ if (p == NULL)
+ break;
+ p->ipn_mask.adf_addr = a->al_i6mask;
+
+ if (a->al_family == AF_INET) {
+ p->ipn_addr.adf_family = AF_INET;
+#ifdef USE_INET6
+ } else if (a->al_family == AF_INET6) {
+ p->ipn_addr.adf_family = AF_INET6;
+#endif
+ }
+ setadflen(&p->ipn_addr);
+ p->ipn_addr.adf_addr = a->al_i6addr;
+ p->ipn_info = a->al_not;
+ p->ipn_mask.adf_len = p->ipn_addr.adf_len;
+
+ if (pbot != NULL)
+ pbot->ipn_next = p;
+ else
+ ptop = p;
+ pbot = p;
+ }
+
+ alist_free(hlist);
+
+ return ptop;
+}
+
+
+ip_pool_node_t *
+read_whoisfile(file)
+ char *file;
+{
+ ip_pool_node_t *ntop, *ipn, node, *last;
+ char line[1024];
+ FILE *fp;
+
+ fp = fopen(file, "r");
+ if (fp == NULL)
+ return NULL;
+
+ last = NULL;
+ ntop = NULL;
+ while (fgets(line, sizeof(line) - 1, fp) != NULL) {
+ line[sizeof(line) - 1] = '\0';
+
+ if (parsewhoisline(line, &node.ipn_addr, &node.ipn_mask))
+ continue;
+ ipn = calloc(1, sizeof(*ipn));
+ if (ipn == NULL)
+ continue;
+ ipn->ipn_addr = node.ipn_addr;
+ ipn->ipn_mask = node.ipn_mask;
+ if (last == NULL)
+ ntop = ipn;
+ else
+ last->ipn_next = ipn;
+ last = ipn;
+ }
+ fclose(fp);
+ return ntop;
+}
+
+
+static void
+setadflen(afp)
+ addrfamily_t *afp;
+{
+ afp->adf_len = offsetof(addrfamily_t, adf_addr);
+ switch (afp->adf_family)
+ {
+ case AF_INET :
+ afp->adf_len += sizeof(struct in_addr);
+ break;
+#ifdef USE_INET6
+ case AF_INET6 :
+ afp->adf_len += sizeof(struct in6_addr);
+ break;
+#endif
+ default :
+ break;
+ }
+}