OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / user / ipfwadm / ipfwadm.c
1 /*
2  *      $Id: ipfwadm.c,v 1.6 2002-03-06 01:51:11 gerg Exp $
3  *
4  *
5  *      ipfwadm -- IP firewall and accounting administration
6  *
7  *      See the accompanying manual page ipfwadm(8) for information
8  *      about proper usage of this program.
9  *
10  *
11  *      Copyright (c) 1995,1996 by X/OS Experts in Open Systems BV.
12  *      All rights reserved.
13  *
14  *      Author: Jos Vos <jos@xos.nl>
15  *
16  *              X/OS Experts in Open Systems BV
17  *              Kruislaan 419
18  *              NL-1098 VA  Amsterdam
19  *              The Netherlands
20  *
21  *              E-mail: info@xos.nl
22  *              WWW:    http://www.xos.nl/
23  *
24  *
25  *      This program is free software; you can redistribute it and/or modify
26  *      it under the terms of the GNU General Public License as published by
27  *      the Free Software Foundation; either version 2 of the License, or
28  *      (at your option) any later version.
29  *
30  *      This program is distributed in the hope that it will be useful,
31  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
32  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  *      GNU General Public License for more details.
34  *
35  *      You should have received a copy of the GNU General Public License
36  *      along with this program; if not, write to the Free Software
37  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
38  *
39  *
40  *      Change history:
41  *      1.1     First release of ipfwadm, which works in combination
42  *              with Linux 1.2.1.
43  *      1.2     Various changes in error messages, print format, comment.
44  *      1.3     Add colon to 'p' in getopt string.
45  *              Correct bug in printing range of destination port.
46  *      1.4     Change the usage messages and add a large help text for -h.
47  *      1.5     Change code to make "gcc -Wall" happy (and a few of these
48  *              warnings were really serious ...).
49  *      1.6     Port to 1.3.x Linux kernel (1.3.57 as reference).
50  *              Rename -k option to -o (kernel packet logging).
51  *              Support new TCPACK option with new -k option.
52  *              Add support for masquerading rules (policy added).
53  *              List active masquerading entries (via -M flag).
54  *      1.7     Add some extra command/option checks and fix some typos.
55  *              Allow specification of ICMP types (given as port numbers) and
56  *              show source port numbers (ICMP types) when listing ICMP rules.
57  *              Eliminate warnings due to new 1.3.x. IP-related include files.
58  *      1.8     Major changes:
59  *              Support separate input/output chains, socket option renaming,
60  *              new -t flag for specifying TOS masks, and more...
61  *              Works (only!) on Linux 1.3.61 and higher.
62  *      1.9     Support matching with interface names (using option -W).
63  *      1.10    Change layout of listing of active masqueraded sessions.
64  *              Port to AXP (64-bit issues), untested.
65  *      1.11    Fix bugs introduced in 1.10.
66  *              [ipfwadm 2.0]
67  *      1.12    Add support for port redirection (for supporting transparent
68  *              proxying) via the -r flag.
69  *              Support input/output only accounting rules by recognizing
70  *              a direction (in/out/both) after the -A flag.
71  *              Add -m option to use masquerading with policy accept
72  *              (as a replacement of the masquerade policy, which is still
73  *              supported for backwards compatibility).
74  *              Slightly change the layout of the rule listings.
75  *              Remove check for TCP protocol when using -k or -y.
76  *      1.13    Also support kernels 1.3.66 up to 1.99.6 (untested).
77  *              Check on missing command.
78  *              [ipfwadm 2.1]
79  *      1.14    Add <errno.h> to make new compile environments happy.
80  *              Allow -r without a port number (use 0 as default value).
81  *              Add -s command for setting timeout values (masquerading).
82  *              [ipfwadm 2.2]
83  *      1.15    Fill in packet length when checking packets (-c command).
84  *              Do getnetbyname() before gethostbyname() to avoid DNS
85  *              lookups (and timeouts) when specifying a known network name.
86  *              Make "0.0.0.0/0" the default value for the -S and -D options,
87  *              except when used in combination with the -c (check) command.
88  *              Enforce correct use of the -W option (required for checking).
89  *              Ignore the hostname when specifying a zero-mask, so that
90  *              "any/0" (or whatever) can be used to specify "any" address.
91  *              Include <sys/param.h> instead of <asm/param.h> and use HZ
92  *              instead of 100 when reading the masquerading timeout values.
93  *              [ipfwadm 2.3.0]
94  *              
95  */
96
97 #include <stdio.h>
98 #include <errno.h>
99 #include <limits.h>
100 #include <string.h>
101 #include <stdlib.h>
102 #include <unistd.h>
103 #include <getopt.h>
104 #include <netdb.h>
105 #include <netinet/in.h>
106 #include <netinet/ip.h>
107 #define __USE_MISC
108 #include <netinet/tcp.h>
109 #include <netinet/udp.h>
110 #include <netinet/ip_icmp.h>
111 #include <net/if.h>
112 #define __u32 u_int32_t
113 #define __u16 u_int16_t
114 #include <netinet/ip_fw.h>
115 #include <sys/param.h>
116
117 #ifndef IP_FW_F_REDIR
118 #define IPFWADM_NO_REDIR
119 #define IP_FW_F_REDIR           0
120 #endif  /* ! IP_FW_F_REDIR */
121
122 #if     !defined(IP_FW_F_ACCTIN) || !defined(IP_FW_F_ACCTOUT)
123 #define IPFWADM_NO_ACCTDIR
124 #define IP_FW_F_ACCTIN          0
125 #define IP_FW_F_ACCTOUT         0
126 #endif  /* ! IP_FW_F_REDIR */
127
128 #ifndef IP_FW_MASQ_TIMEOUTS
129 #define IPFWADM_NO_TIMEOUT
130 #define IP_FW_MASQ_TIMEOUTS     0
131 #endif  /* ! IP_FW_MASQ_TIMEOUTS */
132
133 #define IP_VERSION      4
134 #define IP_OFFSET       0x1FFF
135
136 #define CHN_NONE        -1
137 #define CHN_FWD         0
138 #define CHN_IN          1
139 #define CHN_OUT         2
140 #define CHN_ACCT        3
141 #define CHN_MASQ        4       /* only used for listing masquerading */
142
143 #define CMD_NONE        0x0000
144 #define CMD_LIST        0x0001
145 #define CMD_APPEND      0x0002
146 #define CMD_DELETE      0x0004
147 #define CMD_FLUSH       0x0008
148 #define CMD_RESET       0x0010
149 #define CMD_POLICY      0x0020
150 #define CMD_CHECK       0x0040
151 #define CMD_HELP        0x0080
152 #define CMD_INSERT      0x0100
153 #define CMD_TIMEOUT     0x0200
154
155 #define OPT_NONE        0x000000
156 #define OPT_EXTENDED    0x000001
157 #define OPT_NUMERIC     0x000002
158 #define OPT_SOURCE      0x000004
159 #define OPT_DESTINATION 0x000008
160 #define OPT_PROTOCOL    0x000010
161 #define OPT_VIAADDR     0x000020
162 #define OPT_POLICY      0x000040
163 #define OPT_TCPSYN      0x000080
164 #define OPT_BIDIR       0x000100
165 #define OPT_VERBOSE     0x000200
166 #define OPT_PRINTK      0x000400
167 #define OPT_EXPANDED    0x000800
168 #define OPT_TCPACK      0x001000
169 #define OPT_TOS         0x002000
170 #define OPT_VIANAME     0x004000
171 #define OPT_REDIRECT    0x008000
172 #define OPT_MASQUERADE  0x010000
173
174 #define FMT_NUMERIC     0x0001
175 #define FMT_NOCOUNTS    0x0002
176 #define FMT_KILOMEGA    0x0004
177 #define FMT_OPTIONS     0x0008
178 #define FMT_NOTABLE     0x0010
179 #define FMT_HEADER      0x0020
180 #define FMT_NOKIND      0x0040
181 #define FMT_VIA         0x0080
182 #define FMT_NONEWLINE   0x0100
183 #define FMT_DELTAS      0x0200
184 #define FMT_TOS         0x0400
185
186 struct masq {
187         unsigned long   expires;        /* Expiration timer */
188         unsigned short  kind;           /* Which protocol are we talking? */
189         struct in_addr  src, dst;       /* Source and destination IP addresses */
190         unsigned short  sport, dport;   /* Source and destination ports */
191         unsigned short  mport;          /* Masqueraded port */
192         __u32           initseq;        /* Add delta from this seq. on */
193         short           delta;          /* Delta in sequence numbers */
194         short           pdelta;         /* Delta in sequence numbers before last */
195 };
196
197 struct masq_timeout {
198         int     tcp_timeout;
199         int     tcp_fin_timeout;
200         int     udp_timeout;
201 } timeouts;
202
203 char ipfwadm_version[] = "$Id: ipfwadm.c,v 1.6 2002-03-06 01:51:11 gerg Exp $";
204 char package_version[] = "ipfwadm 2.3.0, 1996/07/30";
205
206 int ssocmd_insert[4] =
207         {IP_FW_INSERT_FWD, IP_FW_INSERT_IN, IP_FW_INSERT_OUT, IP_ACCT_INSERT};
208 int ssocmd_append[4] =
209         {IP_FW_APPEND_FWD, IP_FW_APPEND_IN, IP_FW_APPEND_OUT, IP_ACCT_APPEND};
210 int ssocmd_delete[4] =
211         {IP_FW_DELETE_FWD, IP_FW_DELETE_IN, IP_FW_DELETE_OUT, IP_ACCT_DELETE};
212 int ssocmd_check[4] =
213         {IP_FW_CHECK_FWD, IP_FW_CHECK_IN, IP_FW_CHECK_OUT, -1};
214 int ssocmd_policy[4] =
215         {IP_FW_POLICY_FWD, IP_FW_POLICY_IN, IP_FW_POLICY_OUT, -1};
216 int ssocmd_flush[4] =
217         {IP_FW_FLUSH_FWD, IP_FW_FLUSH_IN, IP_FW_FLUSH_OUT, IP_ACCT_FLUSH};
218 int ssocmd_zero[4] =
219         {IP_FW_ZERO_FWD, IP_FW_ZERO_IN, IP_FW_ZERO_OUT, IP_ACCT_ZERO};
220 char *procfiles[5] = {"/proc/net/ip_forward", "/proc/net/ip_input",
221         "/proc/net/ip_output", "/proc/net/ip_acct", "/proc/net/ip_masquerade"};
222
223 int chain = CHN_NONE;
224 int command = CMD_NONE;
225 long options = OPT_NONE;
226
227 char *program;
228
229 struct ip_fw firewall;
230
231 char *sports[IP_FW_MAX_PORTS];
232 char *dports[IP_FW_MAX_PORTS];
233 char *rport;
234 char *shostnetworkmask, *dhostnetworkmask;
235 int nsaddrs, ndaddrs;
236 struct in_addr *saddrs, *daddrs;
237
238 extern struct in_addr *parse_hostnetwork(char *, int *);
239 extern void parse_hostnetworkmask(char *, struct in_addr **,
240         struct in_addr *, int *);
241 extern void parse_viahost(char *);
242 extern struct in_addr *parse_mask(char *);
243 extern void parse_direction(char *);
244 extern void parse_policy(char *);
245 extern void parse_protocol(char *);
246 extern void parse_all_ports(char **, unsigned short *, int, int);
247 extern unsigned short parse_port(char *, unsigned short);
248 extern void store_port(char *, unsigned short *, int, char *[]);
249 extern void parse_hexbyte(char *, unsigned char *);
250 extern int parse_timeout(char *);
251
252 extern struct in_addr *host_to_addr(char *, int *);
253 extern char *addr_to_host(struct in_addr *);
254 extern struct in_addr *network_to_addr(char *);
255 extern char *addr_to_network(struct in_addr *);
256 extern char *addr_to_anyname(struct in_addr *);
257 extern struct in_addr *dotted_to_addr(char *);
258 extern char *addr_to_dotted(struct in_addr *);
259 extern char *mask_to_dotted(struct in_addr *);
260 extern int service_to_port(char *, unsigned short);
261 extern char *port_to_service(int, unsigned short);
262 extern long string_to_number(char *, long, long);
263 extern char *policy_to_string(int);
264
265 extern int add_delete_entries(int, int);
266 extern int check_entries(int);
267 extern int list_entries(int, char *);
268 extern int list_masq();
269
270 extern void print_firewall(FILE *, struct ip_fw *, int);
271 extern void print_masq(FILE *, struct masq *, int);
272 extern int read_procinfo(FILE *, struct ip_fw *, int);
273 extern int read_masqinfo(FILE *, struct masq *, int);
274 extern struct ip_fwpkt *fw_to_fwpkt(struct ip_fw *);
275 extern int do_setsockopt(int, void *, int);
276
277 extern void check_option(long, char);
278 extern void inaddrcpy(struct in_addr *, struct in_addr *);
279 extern void *fw_malloc(size_t);
280 extern void *fw_calloc(size_t, size_t);
281 extern void *fw_realloc(void *, size_t);
282 extern void exit_error(int, char *);
283 extern void exit_tryhelp(int);
284 extern void exit_printhelp();
285
286 int
287 main(int argc, char *argv[])
288 {
289         int c, kind, ret = 0, policy, dummy;
290
291         program = argv[0];
292
293         while ((c = getopt(argc, argv, "AFIMOadilzfs:p:chP:S:D:V:W:bekmnort:vxy")) != -1)
294                 switch (c) {
295                 case 'A':
296                         if (chain != CHN_NONE)
297                                 exit_error(2, "multiple categories specified");
298                         chain = CHN_ACCT;
299                         if (optind < argc && argv[optind][0] != '-')
300                                 parse_direction(argv[optind++]);
301                         break;
302                 case 'F':
303                         if (chain != CHN_NONE)
304                                 exit_error(2, "multiple categories specified");
305                         chain = CHN_FWD;
306                         break;
307                 case 'I':
308                         if (chain != CHN_NONE)
309                                 exit_error(2, "multiple categories specified");
310                         chain = CHN_IN;
311                         break;
312                 case 'M':
313                         if (chain != CHN_NONE)
314                                 exit_error(2, "multiple categories specified");
315                         chain = CHN_MASQ;
316                         break;
317                 case 'O':
318                         if (chain != CHN_NONE)
319                                 exit_error(2, "multiple categories specified");
320                         chain = CHN_OUT;
321                         break;
322                 case 'a':
323                         if (command != CMD_NONE)
324                                 exit_error(2, "multiple commands specified");
325                         command = CMD_APPEND;
326                         if (optind < argc && argv[optind][0] != '-') {
327                                 parse_policy(argv[optind++]);
328                                 options |= OPT_POLICY;
329                         }
330                         break;
331                 case 'd':
332                         if (command != CMD_NONE)
333                                 exit_error(2, "multiple commands specified");
334                         command = CMD_DELETE;
335                         if (optind < argc && argv[optind][0] != '-') {
336                                 parse_policy(argv[optind++]);
337                                 options |= OPT_POLICY;
338                         }
339                         break;
340                 case 'i':
341                         if (command != CMD_NONE)
342                                 exit_error(2, "multiple commands specified");
343                         command = CMD_INSERT;
344                         if (optind < argc && argv[optind][0] != '-') {
345                                 parse_policy(argv[optind++]);
346                                 options |= OPT_POLICY;
347                         }
348                         break;
349                 case 'l':
350                         if (command != CMD_NONE && command != CMD_RESET)
351                                 exit_error(2, "multiple commands specified");
352                         command |= CMD_LIST;
353                         break;
354                 case 'z':
355                         if (command != CMD_NONE && command != CMD_LIST)
356                                 exit_error(2, "multiple commands specified");
357                         command |= CMD_RESET;
358                         break;
359                 case 'f':
360                         if (command != CMD_NONE)
361                                 exit_error(2, "multiple commands specified");
362                         command = CMD_FLUSH;
363                         break;
364                 case 'p':
365                         if (command != CMD_NONE)
366                                 exit_error(2, "multiple commands specified");
367                         command = CMD_POLICY;
368                         parse_policy(optarg);
369                         break;
370                 case 's':
371 #ifndef IPFWADM_NO_TIMEOUT
372                         if (command != CMD_NONE)
373                                 exit_error(2, "multiple commands specified");
374                         command = CMD_TIMEOUT;
375                         if (optind + 1 < argc && argv[optind][0] != '-' &&
376                                         argv[optind+1][0] != '-') {
377                                 timeouts.tcp_timeout =
378                                         HZ * parse_timeout(optarg);
379                                 timeouts.tcp_fin_timeout =
380                                         HZ * parse_timeout(argv[optind++]);
381                                 timeouts.udp_timeout =
382                                         HZ * parse_timeout(argv[optind++]);
383                         } else
384                                 exit_error(2, "-s requires 3 timeout values");
385 #else   /* IPFWADM_NO_TIMEOUT */
386                         exit_error(2, "setting masquerading timeouts not supported");
387 #endif  /* IPFWADM_NO_TIMEOUT */
388                         break;
389                 case 'c':
390                         if (command != CMD_NONE)
391                                 exit_error(2, "multiple commands specified");
392                         command = CMD_CHECK;
393                         break;
394                 case 'h':
395                         exit_printhelp();
396                         /* we'll never reach this */
397                         break;
398                 case 'P':
399                         check_option(OPT_PROTOCOL, 'P');
400                         parse_protocol(optarg);
401                         break;
402                 case 'S':
403                         check_option(OPT_SOURCE, 'S');
404                         shostnetworkmask = optarg;
405                         while (optind < argc && argv[optind][0] != '-')
406                                 store_port(argv[optind++], &firewall.fw_nsp,
407                                         IP_FW_F_SRNG, sports);
408                         break;
409                 case 'D':
410                         check_option(OPT_DESTINATION, 'D');
411                         dhostnetworkmask = optarg;
412                         while (optind < argc && argv[optind][0] != '-')
413                                 store_port(argv[optind++], &firewall.fw_ndp,
414                                         IP_FW_F_DRNG, dports);
415                         break;
416                 case 'V':
417                         check_option(OPT_VIAADDR, 'V');
418                         parse_viahost(optarg);
419                         break;
420                 case 'W':
421                         check_option(OPT_VIANAME, 'W');
422                         strncpy(firewall.fw_vianame, optarg, IFNAMSIZ);
423                         break;
424                 case 'b':
425                         check_option(OPT_BIDIR, 'b');
426                         firewall.fw_flg |= IP_FW_F_BIDIR;
427                         break;
428                 case 'e':
429                         check_option(OPT_EXTENDED, 'e');
430                         break;
431                 case 'k':
432                         check_option(OPT_TCPACK, 'k');
433                         firewall.fw_flg |= IP_FW_F_TCPACK;
434                         break;
435                 case 'm':
436                         check_option(OPT_MASQUERADE, 'm');
437                         firewall.fw_flg |= IP_FW_F_MASQ;
438                         break;
439                 case 'n':
440                         check_option(OPT_NUMERIC, 'n');
441                         break;
442                 case 'o':
443                         check_option(OPT_PRINTK, 'o');
444                         firewall.fw_flg |= IP_FW_F_PRN;
445                         break;
446                 case 'r':
447 #ifndef IPFWADM_NO_REDIR
448                         check_option(OPT_REDIRECT, 'r');
449                         firewall.fw_flg |= IP_FW_F_REDIR;
450                         if (optind < argc && argv[optind][0] != '-')
451                                 rport = argv[optind++];
452                         else
453                                 rport = "0";
454 #else   /* IPFWADM_NO_REDIR */
455                         exit_error(2, "redirection not supported");
456 #endif  /* IPFWADM_NO_REDIR */
457                         break;
458                 case 't':
459                         check_option(OPT_TOS, 't');
460                         if (optind < argc && argv[optind][0] != '-') {
461                                 parse_hexbyte(optarg, &firewall.fw_tosand);
462                                 parse_hexbyte(argv[optind++], &firewall.fw_tosxor);
463                         } else
464                                 exit_error(2, "-t requires 2 hexbyte arguments");
465                         break;
466                 case 'v':
467                         check_option(OPT_VERBOSE, 'v');
468                         break;
469                 case 'x':
470                         check_option(OPT_EXPANDED, 'x');
471                         break;
472                 case 'y':
473                         check_option(OPT_TCPSYN, 'y');
474                         firewall.fw_flg |= IP_FW_F_TCPSYN;
475                         break;
476                 case '?':
477                 default:
478                         exit_tryhelp(2);
479                 }
480
481         if (optind < argc)
482                 exit_error(2, "unknown arguments found on commandline");
483         else if (!command)
484                 exit_error(2, "no command specified");
485
486         kind = firewall.fw_flg & IP_FW_F_KIND;
487         policy = (int) (firewall.fw_flg &
488                 (IP_FW_F_ACCEPT | IP_FW_F_ICMPRPL | IP_FW_F_MASQ));
489
490         if (chain == CHN_NONE)
491                 exit_error(2, "missing -A, -F, -I, -O, or -M flag");
492         else if (chain != CHN_IN && chain != CHN_OUT && chain != CHN_FWD &&
493                         command == CMD_CHECK)
494                 exit_error(2, "specify either -F, -I, or -O for checking a packet");
495         else if (chain != CHN_IN && chain != CHN_OUT && chain != CHN_FWD &&
496                         command == CMD_POLICY)
497                 exit_error(2, "specify either -F, -I, or -O for changing the policy");
498         else if ((chain == CHN_IN || chain == CHN_OUT || chain == CHN_FWD) &&
499                         !(options & OPT_POLICY) &&
500                         (command & (CMD_INSERT | CMD_APPEND | CMD_DELETE)))
501                 exit_error(2, "policy required for firewall entries");
502         else if (chain != CHN_IN && chain != CHN_OUT && chain != CHN_FWD &&
503                         options & OPT_POLICY)
504                 /* command is CMD_INSERT, CMD_APPEND, or CMD_DELETE */
505                 exit_error(2, "no policy allowed with non-firewall entries");
506         else if (chain == CHN_MASQ && !(command & CMD_TIMEOUT) && !(command & CMD_LIST))
507                 exit_error(2, "-M only allowed in combination with -s or -l command");
508         else if (chain != CHN_MASQ && command & CMD_TIMEOUT)
509                 exit_error(2, "setting masquerading timeouts requires -M flag");
510
511         if ((options & OPT_BIDIR) &&
512                         !(command & (CMD_INSERT | CMD_APPEND | CMD_DELETE)))
513                 exit_error(2, "bidirectional flag (-b) only allowed with insert/append/delete");
514         else if ((options & OPT_PRINTK) &&
515                         !(command & (CMD_INSERT | CMD_APPEND | CMD_DELETE)))
516                 exit_error(2, "kernel print flag (-o) only allowed with insert/append/delete");
517         else if ((options & OPT_REDIRECT) &&
518                         !(command & (CMD_INSERT | CMD_APPEND | CMD_DELETE)))
519                 exit_error(2, "port redirection (-r) only allowed with insert/append/delete");
520         else if ((options & OPT_TOS) &&
521                         !(command & (CMD_INSERT | CMD_APPEND | CMD_DELETE)))
522                 exit_error(2, "tos values (-t) only allowed with insert/append/delete");
523
524         if ((options & OPT_PROTOCOL) && (command & (CMD_LIST | CMD_FLUSH |
525                         CMD_RESET | CMD_POLICY)))
526                 exit_error(2, "no protocol (-P) allowed with this command");
527         else if (!(options & OPT_PROTOCOL) && command == CMD_CHECK)
528                 exit_error(2, "protocol (-P) required for this command");
529         else if (!(options & OPT_PROTOCOL))
530                 firewall.fw_flg |= IP_FW_F_ALL;
531
532         if (command == CMD_CHECK && kind == IP_FW_F_ALL)
533                 exit_error(2, "specific protocol required for check command");
534
535         if ((options & OPT_VIAADDR) && (command & (CMD_LIST | CMD_FLUSH |
536                         CMD_RESET | CMD_POLICY)))
537                 exit_error(2, "no interface address (-V) allowed with this command");
538         if (!(options & OPT_VIAADDR) && (command & CMD_CHECK))
539                 exit_error(2, "interface address (-V) required for this command");
540
541         if ((options & OPT_VIANAME) && (command & (CMD_LIST | CMD_FLUSH |
542                         CMD_RESET | CMD_POLICY)))
543                 exit_error(2, "no interface name (-W) allowed with this command");
544         if (!(options & OPT_VIANAME) && (command & CMD_CHECK))
545                 exit_error(2, "interface name (-W) required for this command");
546
547         if (kind == IP_FW_F_ICMP && firewall.fw_ndp != 0)
548                 exit_error(2, "ICMP types only allowed with -S, not with -D");
549         else if (kind == IP_FW_F_ALL && (firewall.fw_nsp != 0 || firewall.fw_ndp != 0))
550                 exit_error(2, "no ports allowed without specific protocol");
551         else if (command == CMD_CHECK && kind != IP_FW_F_ICMP &&
552                         (firewall.fw_nsp != 1 || firewall.fw_ndp != 1))
553                 exit_error(2, "one port required with source/destination address");
554         else if (command == CMD_CHECK && kind == IP_FW_F_ICMP &&
555                         (firewall.fw_nsp != 1 || firewall.fw_ndp != 0))
556                 exit_error(2, "ICMP type required after source address");
557         else if (options & OPT_REDIRECT && chain != CHN_IN)
558                 exit_error(2, "redirecting only allowed in combination with -I");
559         else if (kind == IP_FW_F_ICMP && options & OPT_REDIRECT)
560                 exit_error(2, "redirecting not allowed with protocol ICMP");
561         else if (options & OPT_MASQUERADE && chain != CHN_FWD)
562                 exit_error(2, "masquerading only allowed in combination with -F");
563         else if (kind == IP_FW_F_ICMP && options & OPT_MASQUERADE)
564                 exit_error(2, "masquerading not allowed with protocol ICMP");
565         else if (options & OPT_MASQUERADE && !(policy & IP_FW_F_ACCEPT))
566                 exit_error(2, "masquerading only allowed with policy accept");
567
568         if ((options & OPT_SOURCE) && (command & (CMD_LIST | CMD_FLUSH |
569                         CMD_RESET | CMD_POLICY)))
570                 exit_error(2, "no source address (-S) allowed with this command");
571         else if (!(options & OPT_SOURCE) && (command & CMD_CHECK))
572                 exit_error(2, "source address (-S) required for this command");
573         else if (!(options & OPT_SOURCE) && (command &
574                         (CMD_INSERT | CMD_APPEND | CMD_DELETE)))
575                 shostnetworkmask = "0.0.0.0/0";
576         if (shostnetworkmask) {
577                 parse_hostnetworkmask(shostnetworkmask, &saddrs,
578                         &(firewall.fw_smsk), &nsaddrs);
579                 parse_all_ports(sports, &(firewall.fw_pts[0]),
580                         (int) firewall.fw_nsp, firewall.fw_flg & IP_FW_F_SRNG);
581         }
582
583         if ((options & OPT_DESTINATION) && (command & (CMD_LIST | CMD_FLUSH |
584                         CMD_RESET | CMD_POLICY)))
585                 exit_error(2, "no destination address (-D) allowed with this command");
586         else if (!(options & OPT_DESTINATION) && (command & CMD_CHECK))
587                 exit_error(2, "destination address (-D) required for this command");
588         else if (!(options & OPT_DESTINATION) && (command &
589                         (CMD_INSERT | CMD_APPEND | CMD_DELETE)))
590                 dhostnetworkmask = "0.0.0.0/0";
591         if (dhostnetworkmask) {
592                 parse_hostnetworkmask(dhostnetworkmask, &daddrs,
593                         &(firewall.fw_dmsk), &ndaddrs);
594                 parse_all_ports(dports, &(firewall.fw_pts[firewall.fw_nsp]),
595                         (int) firewall.fw_ndp, firewall.fw_flg & IP_FW_F_DRNG);
596         }
597
598         if (options & OPT_REDIRECT) {
599                 if (firewall.fw_nsp + firewall.fw_ndp >= IP_FW_MAX_PORTS) {
600                         fprintf(stderr, "%s: too many ports specified (maximum %d when using -r option)\n",
601                                 program, IP_FW_MAX_PORTS - 1);
602                         exit_tryhelp(2);
603                 }
604                 firewall.fw_pts[firewall.fw_nsp + firewall.fw_ndp] =
605                         parse_port(rport, kind);
606         }
607
608         if (!(options & OPT_TOS)) {
609                 firewall.fw_tosand = 0xFF;
610                 firewall.fw_tosxor = 0x00;
611         }
612
613         switch (command) {
614         case CMD_INSERT:
615                 ret = add_delete_entries(ssocmd_insert[chain], chain);
616                 break;
617         case CMD_APPEND:
618                 ret = add_delete_entries(ssocmd_append[chain], chain);
619                 break;
620         case CMD_DELETE:
621                 ret = add_delete_entries(ssocmd_delete[chain], chain);
622                 break;
623         case CMD_CHECK:
624                 ret = check_entries(ssocmd_check[chain]);
625                 break;
626         case CMD_POLICY:
627                 ret = do_setsockopt(ssocmd_policy[chain], &policy, sizeof(int));
628                 break;
629         case CMD_FLUSH:
630                 ret = do_setsockopt(ssocmd_flush[chain], &dummy, sizeof(dummy));
631                 break;
632         case CMD_RESET:
633                 ret = do_setsockopt(ssocmd_zero[chain], &dummy, sizeof(dummy));
634                 break;
635         case CMD_TIMEOUT:
636                 ret = do_setsockopt(IP_FW_MASQ_TIMEOUTS, &timeouts, sizeof(timeouts));
637                 break;
638         case CMD_LIST:
639         case CMD_LIST | CMD_RESET:
640                 if (chain == CHN_MASQ)
641                         ret = list_masq();
642                 else
643                         ret = list_entries(chain, (command & CMD_RESET) ? "r+" : "r");
644                 break;
645         default:
646                 /* We should never reach this... */
647                 exit_tryhelp(2);
648         }
649         exit(ret);
650 }
651
652 /*
653  *      All functions starting with "parse" should succeed, otherwise
654  *      the program fails.  These routines will modify the global
655  *      ip_fw stucture "firewall" and/or they modify one of the other
656  *      global variables used to save the specified parameters.
657  *
658  *      Most routines return pointers to static data that may change
659  *      between calls to the same or other routines with a few exceptions:
660  *      "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask"
661  *      return global static data.
662 */
663
664 struct in_addr *
665 parse_hostnetwork(char *name, int *naddrs)
666 {
667         struct in_addr *addrp, *addrptmp;
668
669         if ((addrptmp = dotted_to_addr(name)) != NULL) {
670                 addrp = fw_malloc(sizeof(struct in_addr));
671                 inaddrcpy(addrp, addrptmp);
672                 *naddrs = 1;
673                 return addrp;
674         } else if ((addrptmp = network_to_addr(name)) != NULL) {
675                 addrp = fw_malloc(sizeof(struct in_addr));
676                 inaddrcpy(addrp, addrptmp);
677                 *naddrs = 1;
678                 return addrp;
679         } else if ((addrp = host_to_addr(name, naddrs)) != NULL) {
680                 return addrp;
681         } else {
682                 fprintf(stderr, "%s: host/network \"%s\" not found\n",
683                         program, name);
684                 exit_tryhelp(2);
685                 /* make the compiler happy... */
686                 return NULL;
687         }
688 }
689
690 void
691 parse_hostnetworkmask(char *name, struct in_addr **addrpp,
692                 struct in_addr *maskp, int *naddrs)
693 {
694         struct in_addr *addrp;
695         char buf[256];
696         char *p;
697         int i, j, k, n;
698
699         strncpy(buf, name, sizeof(buf) - 1);
700         if ((p = strrchr(buf, '/')) != NULL) {
701                 *p = '\0';
702                 addrp = parse_mask(p + 1);
703         } else
704                 addrp = parse_mask(NULL);
705         inaddrcpy(maskp, addrp);
706
707         /* if a null mask is given, the name is ignored, like in "any/0" */
708         if (maskp->s_addr == 0L)
709                 strcpy(buf, "0.0.0.0");
710
711         addrp = *addrpp = parse_hostnetwork(buf, naddrs);
712         n = *naddrs;
713         for (i = 0, j = 0; i < n; i++) {
714                 addrp[j++].s_addr &= maskp->s_addr;
715                 for (k = 0; k < j - 1; k++) {
716                         if (addrp[k].s_addr == addrp[j - 1].s_addr) {
717                                 (*naddrs)--;
718                                 j--;
719                                 break;
720                         }
721                 }
722         }
723 }
724
725 void
726 parse_viahost(char *name)
727 {
728         struct in_addr *addrp;
729         int naddrs;
730
731         if ((addrp = dotted_to_addr(name)) != NULL) {
732                 inaddrcpy(&firewall.fw_via, addrp);
733                 return;
734         } else if ((addrp = host_to_addr(name, &naddrs)) != NULL) {
735                 if (naddrs != 1) {
736                         fprintf(stderr,
737                                 "%s: hostname \"%s\" does not specify a unique address\n",
738                                 program, name);
739                         exit_tryhelp(2);
740                 } else {
741                         inaddrcpy(&firewall.fw_via, addrp);
742                         return;
743                 }
744         } else {
745                 fprintf(stderr, "%s: host \"%s\" not found\n", program, name);
746                 exit_tryhelp(2);
747         }
748 }
749
750 struct in_addr *
751 parse_mask(char *mask)
752 {
753         static struct in_addr maskaddr;
754         struct in_addr *addrp;
755         int bits;
756
757         if (mask == NULL) {
758                 /* no mask at all defaults to 32 bits */
759                 maskaddr.s_addr = 0xFFFFFFFF;
760                 return &maskaddr;
761         } else if ((addrp = dotted_to_addr(mask)) != NULL) {
762                 /* dotted_to_addr already returns a network byte order addr */
763                 return addrp;
764         } else if ((bits = string_to_number(mask, 0, 32)) == -1) {
765                 fprintf(stderr, "%s: invalid mask \"%s\" specified\n", program, mask);
766                 exit_tryhelp(2);
767                 /* make the compiler happy... */
768                 return NULL;
769         } else if (bits != 0) {
770                 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
771                 return &maskaddr;
772         } else {
773                 maskaddr.s_addr = 0L;
774                 return &maskaddr;
775         }
776 }
777
778 void
779 parse_direction(char *s)
780 {
781         unsigned short direction;
782
783         if (strncmp("in", s, strlen(s)) == 0)
784 #ifndef IPFWADM_NO_ACCTDIR
785                 direction = IP_FW_F_ACCTIN;
786 #else   /* IPFWADM_NO_ACCTDIR */
787                 exit_error(2, "accounting direction \"in\" not supported");
788 #endif  /* IPFWADM_NO_ACCTDIR */
789         else if (strncmp("out", s, strlen(s)) == 0)
790 #ifndef IPFWADM_NO_ACCTDIR
791                 direction = IP_FW_F_ACCTOUT;
792 #else   /* IPFWADM_NO_ACCTDIR */
793                 exit_error(2, "accounting direction \"out\" not supported");
794 #endif  /* IPFWADM_NO_ACCTDIR */
795         else if (strncmp("both", s, strlen(s)) == 0)
796                 direction = 0;
797         else {
798                 fprintf(stderr, "%s: invalid direction \"%s\" specified\n", program, s);
799                 exit_tryhelp(2);
800                 /* make the compiler happy... */
801                 return;
802         }
803         firewall.fw_flg |= direction;
804         return;
805 }
806
807 void
808 parse_policy(char *s)
809 {
810         unsigned short policy;
811
812         if (strncmp("accept", s, strlen(s)) == 0)
813                 policy = IP_FW_F_ACCEPT;
814         else if (strncmp("deny", s, strlen(s)) == 0)
815                 policy = 0; /* as opposed to IP_FW_F_ACCEPT */
816         else if (strncmp("reject", s, strlen(s)) == 0)
817                 policy = IP_FW_F_ICMPRPL;
818         else if (strncmp("masquerade", s, strlen(s)) == 0) {
819                 /* for backwards compatibility, better use "accept" and "-m" */
820                 check_option(OPT_MASQUERADE, 'm');
821                 policy = IP_FW_F_ACCEPT | IP_FW_F_MASQ;
822         } else {
823                 fprintf(stderr, "%s: invalid policy \"%s\" specified\n", program, s);
824                 exit_tryhelp(2);
825                 /* make the compiler happy... */
826                 return;
827         }
828         firewall.fw_flg |= policy;
829         return;
830 }
831
832 void
833 parse_protocol(char *s)
834 {
835         unsigned short protocol;
836
837         if (strncmp("all", s, strlen(s)) == 0)
838                 protocol = IP_FW_F_ALL;
839         else if (strncmp("tcp", s, strlen(s)) == 0)
840                 protocol = IP_FW_F_TCP;
841         else if (strncmp("udp", s, strlen(s)) == 0)
842                 protocol = IP_FW_F_UDP;
843         else if (strncmp("icmp", s, strlen(s)) == 0)
844                 protocol = IP_FW_F_ICMP;
845         else {
846                 fprintf(stderr, "%s: invalid protocol \"%s\" specified\n", program, s);
847                 exit_tryhelp(2);
848                 /* make the compiler happy... */
849                 return;
850         }
851         firewall.fw_flg |= protocol;
852 }
853
854 void
855 parse_all_ports(char **ports, unsigned short *portnumbers,
856                 int nports, int range)
857 {
858         int i, j;
859         unsigned short kind;
860         char buf[256], *cp;
861
862         kind = firewall.fw_flg & IP_FW_F_KIND;
863
864         for (i = 0, j = (range ? 2 : 0); i < nports; i++) {
865                 if (ports[i] == NULL)
866                         continue;
867                 strncpy(buf, ports[i], sizeof(buf) - 1);
868                 if ((cp = strchr(buf, (int) ':')) == NULL)
869                         portnumbers[j++] = parse_port(buf, kind);
870                 else {
871                         *cp = '\0';
872                         portnumbers[0] = parse_port(buf, kind);
873                         portnumbers[1] = parse_port(cp + 1, kind);
874                         if (portnumbers[0] > portnumbers[1]) {
875                                 fprintf(stderr, "%s: invalid range of ports (%u > %u)\n",
876                                         program, portnumbers[0], portnumbers[1]);
877                                 exit_tryhelp(2);
878                         }
879                 }
880         }
881 }
882
883 unsigned short
884 parse_port(char *port, unsigned short kind)
885 {
886         int portnum;
887
888         if ((portnum = string_to_number(port, 0, 65535)) != -1)
889                 return (unsigned short) portnum;
890         else if (kind == IP_FW_F_ICMP) {
891                 /* ICMP types (given as port numbers) must be numeric! */
892                 fprintf(stderr, "%s: invalid ICMP type \"%s\" specified\n",
893                         program, port);
894                 exit_tryhelp(2);
895                 /* make the compiler happy... */
896                 return 0;
897         } else if ((portnum = service_to_port(port, kind)) != -1)
898                 return (unsigned short) portnum;
899         else {
900                 fprintf(stderr, "%s: invalid port/service \"%s\" specified\n",
901                         program, port);
902                 exit_tryhelp(2);
903                 /* make the compiler happy... */
904                 return 0;
905         }
906 }
907
908 void
909 store_port(char *port, unsigned short *nports, int rangeflag, char *ports[])
910 {
911         /* to count the # ports, check whether this is a range or not */
912         if (strchr(port, (int) ':') == NULL)
913                 *nports += 1;
914         else if (firewall.fw_flg & rangeflag)
915                 exit_error(2, "multiple ranges not allowed");
916         else {
917                 *nports += 2;
918                 firewall.fw_flg |= rangeflag;
919         }
920
921         if (firewall.fw_nsp + firewall.fw_ndp > IP_FW_MAX_PORTS) {
922                 fprintf(stderr, "%s: too many ports specified (maximum %d)\n",
923                         program, IP_FW_MAX_PORTS);
924                 exit_tryhelp(2);
925         }
926         ports[*nports - 1] = port;
927         return;
928 }
929
930 void
931 parse_hexbyte(char *s, unsigned char *b)
932 {
933         long number;
934         char *end;
935
936         number = strtol(s, &end, 16);
937         if (*end == '\0' && end != s) {
938                 /* we parsed a number, let's see if we want this */
939                 if (0 <= number && number <= 255)
940                         *b = (unsigned char) number;
941                 else {
942                         fprintf(stderr, "%s: invalid hexbyte \"%s\" specified\n",
943                                 program, s);
944                         exit_tryhelp(2);
945                 }
946         } else {
947                 fprintf(stderr, "%s: invalid hexbyte \"%s\" specified\n",
948                         program, s);
949                 exit_tryhelp(2);
950         }
951 }
952
953 int
954 parse_timeout(char *s)
955 {
956         int timeout;
957
958         if ((timeout = string_to_number(s, 0, INT_MAX)) != -1)
959                 return timeout;
960         else {
961                 fprintf(stderr, "%s: invalid timeout value \"%s\" specified\n",
962                         program, s);
963                 exit_tryhelp(2);
964                 /* make the compiler happy... */
965                 return 0;
966         }
967 }
968
969 struct in_addr *
970 host_to_addr(char *name, int *naddr)
971 {
972         struct hostent *host;
973         struct in_addr *addr;
974         int i;
975
976         *naddr = 0;
977         if ((host = gethostbyname(name)) != NULL) {
978                 if (host->h_addrtype != AF_INET ||
979                                 host->h_length != sizeof(struct in_addr))
980                         return (struct in_addr *) NULL;
981                 while (host->h_addr_list[*naddr] != (char *) NULL)
982                         (*naddr)++;
983                 addr = fw_calloc(*naddr, sizeof(struct in_addr));
984                 for (i = 0; i < *naddr; i++)
985                         inaddrcpy(&(addr[i]), (struct in_addr *) host->h_addr_list[i]);
986                 return addr;
987         } else
988                 return (struct in_addr *) NULL;
989 }
990
991 char *
992 addr_to_host(struct in_addr *addr)
993 {
994         struct hostent *host;
995
996         if ((host = gethostbyaddr((char *) addr,
997                         sizeof(struct in_addr), AF_INET)) != NULL)
998                 return (char *) host->h_name;
999         else
1000                 return (char *) NULL;
1001 }
1002
1003 struct in_addr *
1004 network_to_addr(char *name)
1005 {
1006         struct netent *net;
1007         static struct in_addr addr;
1008
1009 #ifndef EMBED
1010         if ((net = getnetbyname(name)) != NULL) {
1011                 if (net->n_addrtype != AF_INET)
1012                         return (struct in_addr *) NULL;
1013                 addr.s_addr = htonl((unsigned long) net->n_net);
1014                 return &addr;
1015         } else
1016 #endif
1017                 return (struct in_addr *) NULL;
1018 }
1019
1020 char *
1021 addr_to_network(struct in_addr *addr)
1022 {
1023         struct netent *net;
1024  
1025 #ifndef EMBED
1026         if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
1027                 return (char *) net->n_name;
1028         else
1029 #endif
1030                 return (char *) NULL;
1031 }
1032
1033 char *
1034 addr_to_anyname(struct in_addr *addr)
1035 {
1036         char *name;
1037
1038         if ((name = addr_to_host(addr)) != NULL)
1039                 return name;
1040         else if ((name = addr_to_network(addr)) != NULL)
1041                 return name;
1042         else
1043                 return addr_to_dotted(addr);
1044 }
1045
1046 struct in_addr *
1047 dotted_to_addr(char *dotted)
1048 {
1049         static struct in_addr addr;
1050         unsigned char *addrp;
1051         char *p, *q;
1052         int onebyte, i;
1053         char buf[20];
1054
1055         /* copy dotted string, because we need to modify it */
1056         strncpy(buf, dotted, sizeof(buf) - 1);
1057         addrp = (unsigned char *) &(addr.s_addr);
1058
1059         p = buf;
1060         for (i = 0; i < 3; i++) {
1061                 if ((q = strchr(p, '.')) == NULL)
1062                         return (struct in_addr *) NULL;
1063                 else {
1064                         *q = '\0';
1065                         if ((onebyte = string_to_number(p, 0, 255)) == -1)
1066                                 return (struct in_addr *) NULL;
1067                         else
1068                                 addrp[i] = (unsigned char) onebyte;
1069                 }
1070                 p = q + 1;
1071         }
1072
1073         /* we've checked 3 bytes, now we check the last one */
1074         if ((onebyte = string_to_number(p, 0, 255)) == -1)
1075                 return (struct in_addr *) NULL;
1076         else
1077                 addrp[3] = (unsigned char) onebyte;
1078                 
1079         return &addr;
1080 }
1081
1082 char *
1083 addr_to_dotted(struct in_addr *addrp)
1084 {
1085         static char buf[20];
1086         unsigned char *bytep;
1087
1088         bytep = (unsigned char *) &(addrp->s_addr);
1089         sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
1090         return buf;
1091 }
1092
1093 char *
1094 mask_to_dotted(struct in_addr *mask)
1095 {
1096         int i;
1097         static char buf[20];
1098         __u32 maskaddr, bits;
1099
1100         maskaddr = ntohl(mask->s_addr);
1101
1102         if (maskaddr == 0xFFFFFFFFL)
1103                 /* we don't want to see "/32" */
1104                 return "";
1105         else {
1106                 i = 32;
1107                 bits = 0xFFFFFFFEL;
1108                 while (--i >= 0 && maskaddr != bits)
1109                         bits <<= 1;
1110                 if (i >= 0)
1111                         sprintf(buf, "/%d", i);
1112                 else
1113                         /* mask was not a decent combination of 1's and 0's */
1114                         sprintf(buf, "/%s", addr_to_dotted(mask));
1115                 return buf;
1116         }
1117 }
1118
1119 int
1120 service_to_port(char *name, unsigned short kind)
1121 {
1122         struct servent *service;
1123
1124         if (kind == IP_FW_F_TCP && (service = getservbyname(name, "tcp")) != NULL)
1125                 return ntohs((unsigned short) service->s_port);
1126         else if (kind == IP_FW_F_UDP &&
1127                         (service = getservbyname(name, "udp")) != NULL)
1128                 return ntohs((unsigned short) service->s_port);
1129         else
1130                 return -1;
1131 }
1132
1133 char *
1134 port_to_service(int port, unsigned short kind)
1135 {
1136         struct servent *service;
1137
1138         if (kind == IP_FW_F_TCP &&
1139                         (service = getservbyport(htons(port), "tcp")) != NULL)
1140                 return service->s_name;
1141         else if (kind == IP_FW_F_UDP &&
1142                         (service = getservbyport(htons(port), "udp")) != NULL)
1143                 return service->s_name;
1144         else
1145                 return (char *) NULL;
1146 }
1147
1148 long
1149 string_to_number(char *s, long min, long max)
1150 {
1151         long number;
1152         char *end;
1153
1154         number = strtol(s, &end, 10);
1155         if (*end == '\0' && end != s) {
1156                 /* we parsed a number, let's see if we want this */
1157                 if (min <= number && number <= max)
1158                         return number;
1159                 else
1160                         return -1;
1161         } else
1162                 return -1;
1163 }
1164
1165 char *
1166 policy_to_string(int policy)
1167 {
1168         switch (policy) {
1169         case IP_FW_F_ACCEPT:
1170                 return "accept";
1171         case IP_FW_F_ACCEPT | IP_FW_F_MASQ:
1172                 return "accept/masquerade";
1173         case IP_FW_F_ICMPRPL:
1174                 return "reject";
1175         default:
1176                 return "deny";
1177         }
1178 }
1179
1180 int
1181 add_delete_entries(int cmd, int chain)
1182 {
1183         int ret = 0, i, j;
1184
1185         for (i = 0; i < nsaddrs; i++) {
1186                 firewall.fw_src.s_addr = saddrs[i].s_addr;
1187                 for (j = 0; j < ndaddrs; j++) {
1188                         firewall.fw_dst.s_addr = daddrs[j].s_addr;
1189                         if (options & OPT_VERBOSE)
1190                                 print_firewall(stdout, &firewall, FMT_NOCOUNTS | FMT_OPTIONS |
1191                                         FMT_TOS | FMT_VIA | FMT_NUMERIC | FMT_NOTABLE);
1192                         ret |= do_setsockopt(cmd, &firewall, sizeof(firewall));
1193                 }
1194         }
1195         return ret;
1196 }
1197
1198 int
1199 check_entries(int cmd)
1200 {
1201         int ret = 0, i, j;
1202         struct ip_fwpkt *packet;
1203
1204         for (i = 0; i < nsaddrs; i++) {
1205                 firewall.fw_src.s_addr = saddrs[i].s_addr;
1206                 for (j = 0; j < ndaddrs; j++) {
1207                         firewall.fw_dst.s_addr = daddrs[j].s_addr;
1208                         if (options & OPT_VERBOSE)
1209                                 print_firewall(stdout, &firewall, FMT_NOCOUNTS | FMT_NOKIND |
1210                                         FMT_VIA | FMT_NUMERIC | FMT_NOTABLE);
1211                         packet = fw_to_fwpkt(&firewall);
1212                         ret |= do_setsockopt(cmd, packet, sizeof(struct ip_fwpkt));
1213                 }
1214         }
1215         return ret;
1216 }
1217
1218 int
1219 list_entries(int chain, char *mode)
1220 {
1221         FILE *fp;
1222         char *procfile;
1223         int policy, i;
1224         char buf[256];
1225         struct ip_fw *fwlist;
1226         int ntotal = 0, nread, format;
1227
1228         procfile = procfiles[chain];
1229
1230         if ((fp = fopen(procfile, mode)) == NULL) {
1231                 fprintf(stderr, "%s: cannot open file %s\n", program, procfile);
1232                 exit(1);
1233         }
1234
1235         if (chain == CHN_IN || chain == CHN_OUT || chain == CHN_FWD) {
1236                 if (fscanf(fp, "%[^,], default %d", buf, &policy) != 2) {
1237                         fprintf(stderr, "%s: unexpected input from %s\n",
1238                                 program, procfile);
1239                         exit(2);
1240                 }
1241                 fprintf(stdout, "%s, default policy: %s\n", buf,
1242                         policy_to_string(policy));
1243         } else
1244                 if (fgets(buf, sizeof(buf), fp) == NULL) {
1245                         fprintf(stderr, "%s: unexpected input from %s\n",
1246                                 program, procfile);
1247                         exit(2);
1248                 } else
1249                         fputs(buf, stdout);
1250
1251         fwlist = (struct ip_fw *) fw_malloc(16 * sizeof(struct ip_fw));
1252         while ((nread = read_procinfo(fp, &(fwlist[ntotal]), 16)) == 16) {
1253                 ntotal += nread;
1254                 fwlist = (struct ip_fw *) fw_realloc(fwlist,
1255                         (ntotal + 16) * sizeof(struct ip_fw));
1256         }
1257         ntotal += nread;
1258
1259         format = 0;
1260         if (chain == CHN_IN || chain == CHN_OUT || chain == CHN_FWD)
1261                 if (!(options & OPT_EXTENDED))
1262                         format |= FMT_NOCOUNTS;
1263
1264         if (options & OPT_NUMERIC)
1265                 format |= FMT_NUMERIC;
1266
1267         if (options & OPT_EXTENDED && chain != CHN_ACCT)
1268                 format |= FMT_OPTIONS | FMT_TOS | FMT_VIA;
1269         else if (options & OPT_EXTENDED)
1270                 format |= FMT_OPTIONS | FMT_VIA;
1271
1272         if (!(options & OPT_EXPANDED))
1273                 format |= FMT_KILOMEGA;
1274
1275         if (ntotal > 0)
1276                 for (i = 0; i < ntotal; i++)
1277                         print_firewall(stdout, &(fwlist[i]),
1278                                 (i) ? format : (format | FMT_HEADER));
1279
1280         return 0;
1281 }
1282
1283 int
1284 list_masq()
1285 {
1286         FILE *fp;
1287         char *procfile;
1288         int i;
1289         char buf[256];
1290         struct masq *mslist;
1291         int ntotal = 0, nread, format;
1292
1293         procfile = procfiles[CHN_MASQ];
1294
1295         if ((fp = fopen(procfile, "r")) == NULL) {
1296                 fprintf(stderr, "%s: cannot open file %s\n", program, procfile);
1297                 exit(1);
1298         }
1299
1300         if (fgets(buf, sizeof(buf), fp) == NULL) {
1301                 fprintf(stderr, "%s: unexpected input from %s\n",
1302                         program, procfile);
1303                 exit(2);
1304         }
1305
1306         fputs("IP masquerading entries\n", stdout);
1307
1308         mslist = (struct masq *) fw_malloc(16 * sizeof(struct masq));
1309         while ((nread = read_masqinfo(fp, &(mslist[ntotal]), 16)) == 16) {
1310                 ntotal += nread;
1311                 mslist = (struct masq *) fw_realloc(mslist,
1312                         (ntotal + 16) * sizeof(struct masq));
1313         }
1314         ntotal += nread;
1315
1316         format = 0;
1317
1318         if (options & OPT_NUMERIC)
1319                 format |= FMT_NUMERIC;
1320
1321         if (options & OPT_EXTENDED)
1322                 format |= FMT_DELTAS;
1323
1324         if (ntotal > 0)
1325                 for (i = 0; i < ntotal; i++)
1326                         print_masq(stdout, &(mslist[i]),
1327                                 (i) ? format : (format | FMT_HEADER));
1328
1329         return 0;
1330 }
1331
1332 void
1333 print_firewall(FILE *fp, struct ip_fw *fw, int format)
1334 {
1335         unsigned short flags, kind;
1336         unsigned long cnt, cntkb, cntmb;
1337         char buf[BUFSIZ];
1338         char *service;
1339         int i;
1340
1341         flags = fw->fw_flg;
1342         kind = flags & IP_FW_F_KIND;
1343
1344 #define FMT(tab,notab) ((format & FMT_NOTABLE) ? notab : tab)
1345
1346         if (format & FMT_HEADER) {
1347                 if (!(format & FMT_NOCOUNTS)) {
1348                         if (format & FMT_KILOMEGA) {
1349                                 fprintf(fp, FMT("%5s ","%s "), "pkts");
1350                                 fprintf(fp, FMT("%5s ","%s "), "bytes");
1351                         } else {
1352                                 fprintf(fp, FMT("%8s ","%s "), "pkts");
1353                                 fprintf(fp, FMT("%10s ","%s "), "bytes");
1354                         }
1355                 }
1356                 if (!(format & FMT_NOKIND)) {
1357                         if (chain == CHN_ACCT)
1358                                 fprintf(fp, FMT("%-3s ","%s "), "dir");
1359                         else
1360                                 fprintf(fp, FMT("%-5s ","%s "), "type");
1361                 }
1362                 fputs("prot ", fp);
1363                 if (format & FMT_OPTIONS)
1364                         fputs("opt  ", fp);
1365                 if (format & FMT_TOS)
1366                         fputs("tosa tosx ", fp);
1367                 if (format & FMT_VIA) {
1368                         fprintf(fp, FMT("%-7s ","(%s "), "ifname");
1369                         fprintf(fp, FMT("%-15s ","%s) "), "ifaddress");
1370                 }
1371                 fprintf(fp, FMT("%-20s ","%s "), "source");
1372                 fprintf(fp, FMT("%-20s ","%s "), "destination");
1373                 fputs("ports\n", fp);
1374         }
1375
1376         if (!(format & FMT_NOCOUNTS)) {
1377                 cnt = fw->fw_pcnt;
1378                 if (format & FMT_KILOMEGA) {
1379                         if (cnt > 99999) {
1380                                 cntkb = (cnt + 500) / 1000;
1381                                 if (cntkb > 9999) {
1382                                         cntmb = (cnt + 500000) / 1000000;
1383                                         fprintf(fp, FMT("%4luM ","%luM "), cntmb);
1384                                 } else
1385                                         fprintf(fp, FMT("%4luK ","%luK "), cntkb);
1386                         } else
1387                                 fprintf(fp, FMT("%5lu ","%lu "), cnt);
1388                 } else
1389                         fprintf(fp, FMT("%8lu ","%lu "), cnt);
1390                 cnt = fw->fw_bcnt;
1391                 if (format & FMT_KILOMEGA) {
1392                         if (cnt > 99999) {
1393                                 cntkb = (cnt + 500) / 1000;
1394                                 if (cntkb > 9999) {
1395                                         cntmb = (cnt + 500000) / 1000000;
1396                                         fprintf(fp, FMT("%4luM ","%luM "), cntmb);
1397                                 } else
1398                                         fprintf(fp, FMT("%4luK ","%luK "), cntkb);
1399                         } else
1400                                 fprintf(fp, FMT("%5lu ","%lu "), cnt);
1401                 } else
1402                         fprintf(fp, FMT("%10lu ","%lu "), cnt);
1403         }
1404
1405         if (!(format & FMT_NOKIND)) {
1406                 if (chain == CHN_ACCT) {
1407                         if (flags & IP_FW_F_ACCTIN)
1408                                 fprintf(fp, FMT("%-3s ", "%s "), "in");
1409                         else if (flags & IP_FW_F_ACCTOUT)
1410                                 fprintf(fp, FMT("%-3s ", "%s "), "out");
1411                         else
1412                                 fprintf(fp, FMT("%-3s ", "%s "), "i/o");
1413                 } else {
1414                         if (flags & IP_FW_F_REDIR)
1415                                 fprintf(fp, FMT("%-5s ", "%s "), "acc/r");
1416                         else if (flags & IP_FW_F_MASQ)
1417                                 fprintf(fp, FMT("%-5s ", "%s "), "acc/m");
1418                         else if (flags & IP_FW_F_ACCEPT)
1419                                 fprintf(fp, FMT("%-5s ", "%s "), "acc");
1420                         else if (flags & IP_FW_F_ICMPRPL)
1421                                 fprintf(fp, FMT("%-5s ", "%s "), "rej");
1422                         else
1423                                 fprintf(fp, FMT("%-5s ", "%s "), "deny");
1424                 }
1425         }
1426
1427         switch (kind) {
1428         case IP_FW_F_TCP:
1429                 fprintf(fp, FMT("%-5s", "%s "), "tcp");
1430                 break;
1431         case IP_FW_F_UDP:
1432                 fprintf(fp, FMT("%-5s", "%s "), "udp");
1433                 break;
1434         case IP_FW_F_ICMP:
1435                 fprintf(fp, FMT("%-5s", "%s "), "icmp");
1436                 break;
1437         default:
1438                 fprintf(fp, FMT("%-5s", "%s "), "all");
1439         }
1440
1441         if (format & FMT_OPTIONS) {
1442                 if (format & FMT_NOTABLE)
1443                         fputs("opt ", fp);
1444                 fputc((flags & IP_FW_F_BIDIR) ? 'b' : '-', fp);
1445                 fputc((flags & IP_FW_F_TCPACK) ? 'k' : '-', fp);
1446                 fputc((flags & IP_FW_F_TCPSYN) ? 'y' : '-', fp);
1447                 fputc((flags & IP_FW_F_PRN) ? 'o' : '-', fp);
1448                 fputc(' ', fp);
1449         }
1450
1451         if (format & FMT_TOS) {
1452                 if (format & FMT_NOTABLE)
1453                         fputs("tos ", fp);
1454                 fprintf(fp, "0x%02hX 0x%02hX ",
1455                         (unsigned short) fw->fw_tosand,
1456                         (unsigned short) fw->fw_tosxor);
1457         }
1458
1459         if (format & FMT_VIA) {
1460                 fprintf(fp, FMT("%-7.16s ","via %.16s "),
1461                         (fw->fw_vianame)[0] ? fw->fw_vianame :
1462                                 ((format & FMT_NUMERIC) ? "*" : "any"));
1463                 fprintf(fp, FMT("%-15s ","%s "), (fw->fw_via.s_addr == 0L &&
1464                         !(format & FMT_NUMERIC)) ? "any" :
1465                         addr_to_dotted(&(fw->fw_via)));
1466         }
1467
1468         if (format & FMT_NOTABLE)
1469                 fputs("  ", fp);
1470
1471         if (fw->fw_smsk.s_addr == 0L && !(format & FMT_NUMERIC))
1472                 fprintf(fp, FMT("%-20s ","%s "), "anywhere");
1473         else {
1474                 if (format & FMT_NUMERIC)
1475                         sprintf(buf, "%s", addr_to_dotted(&(fw->fw_src)));
1476                 else
1477                         sprintf(buf, "%s", addr_to_anyname(&(fw->fw_src)));
1478                 strcat(buf, mask_to_dotted(&(fw->fw_smsk)));
1479                 fprintf(fp, FMT("%-20s ","%s "), buf);
1480         }
1481
1482         if (fw->fw_dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
1483                 fprintf(fp, FMT("%-20s","-> %s"), "anywhere");
1484         else {
1485                 if (format & FMT_NUMERIC)
1486                         sprintf(buf, "%s", addr_to_dotted(&(fw->fw_dst)));
1487                 else
1488                         sprintf(buf, "%s", addr_to_anyname(&(fw->fw_dst)));
1489                 strcat(buf, mask_to_dotted(&(fw->fw_dmsk)));
1490                 fprintf(fp, FMT("%-20s","-> %s"), buf);
1491         }
1492
1493         if (format & FMT_NOTABLE)
1494                 fputs("  ", fp);
1495
1496         if (kind != IP_FW_F_TCP && kind != IP_FW_F_UDP && kind != IP_FW_F_ICMP) {
1497                 fputs(" n/a", fp);
1498                 if (!(format & FMT_NONEWLINE))
1499                         putc('\n', fp);
1500                 return;
1501         }
1502
1503         if (fw->fw_nsp == 0)
1504                 fputs((format & FMT_NUMERIC) ? " *" : " any", fp);
1505         else
1506                 for (i = 0; i < fw->fw_nsp; i++) {
1507                         fputc((i == 0) ? ' ' :
1508                                 ((flags & IP_FW_F_SRNG && i == 1) ? ':' : ','), fp);
1509                         if (format & FMT_NUMERIC)
1510                                 fprintf(fp, "%u", fw->fw_pts[i]);
1511                         else if ((service = port_to_service(fw->fw_pts[i],
1512                                         kind)) != NULL)
1513                                 fputs(service, fp);
1514                         else
1515                                 fprintf(fp, "%u", fw->fw_pts[i]);
1516                 }
1517
1518         /* only source ports are interpreted as ICMP types */
1519         if (kind == IP_FW_F_ICMP) {
1520                 if (!(format & FMT_NONEWLINE))
1521                         putc('\n', fp);
1522                 return;
1523         }
1524
1525         fputs(" ->", fp);
1526
1527         if (fw->fw_ndp == 0)
1528                 fputs((format & FMT_NUMERIC) ? " *" : " any", fp);
1529         else
1530                 for (i = fw->fw_nsp; i < fw->fw_nsp + fw->fw_ndp; i++) {
1531                         fputc((i == fw->fw_nsp) ? ' ' : ((flags & IP_FW_F_DRNG &&
1532                                 i == (fw->fw_nsp + 1)) ? ':' : ','), fp);
1533                         if (format & FMT_NUMERIC)
1534                                 fprintf(fp, "%u", fw->fw_pts[i]);
1535                         else if ((service = port_to_service(fw->fw_pts[i], kind)) != NULL)
1536                                 fputs(service, fp);
1537                         else
1538                                 fprintf(fp, "%u", fw->fw_pts[i]);
1539                 }
1540
1541         if (flags & IP_FW_F_REDIR) {
1542                 i = fw->fw_nsp + fw->fw_ndp;
1543                 if (!fw->fw_pts[i])
1544                         fputs((format & FMT_NUMERIC) ? " => *" : " => any", fp);
1545                 else if (format & FMT_NUMERIC)
1546                         fprintf(fp, " => %u", fw->fw_pts[i]);
1547                 else if ((service = port_to_service(fw->fw_pts[i], kind)) != NULL)
1548                         fprintf(fp, " => %s", service);
1549                 else
1550                         fprintf(fp, " => %u", fw->fw_pts[i]);
1551         }
1552
1553         if (!(format & FMT_NONEWLINE))
1554                 putc('\n', fp);
1555 }
1556
1557 void
1558 print_masq(FILE *fp, struct masq *ms, int format)
1559 {
1560         unsigned long minutes, seconds, sec100s;
1561         char *service;
1562
1563         if (format & FMT_HEADER) {
1564                 fputs("prot ", fp);
1565                 fprintf(fp, "%-8s ", "expire");
1566                 if (format & FMT_DELTAS) {
1567                         fprintf(fp, "%10s delta prevd ", "initseq");
1568                 }
1569                 fprintf(fp, "%-20s ", "source");
1570                 fprintf(fp, "%-20s ", "destination");
1571                 fputs("ports\n", fp);
1572         }
1573
1574         switch (ms->kind) {
1575         case IP_FW_F_TCP:
1576                 fprintf(fp, "%-5s", "tcp");
1577                 break;
1578         case IP_FW_F_UDP:
1579                 fprintf(fp, "%-5s", "udp");
1580                 break;
1581         }
1582
1583         sec100s = ms->expires % HZ;
1584         seconds = (ms->expires / HZ) % 60;
1585         minutes = ms->expires / (60 * HZ);
1586
1587         fprintf(fp, "%02ld:%02ld.%02ld ", minutes, seconds, sec100s);
1588
1589         if (format & FMT_DELTAS) {
1590                 fprintf(fp, "%10lu %5hd %5hd ", (unsigned long) ms->initseq,
1591                         ms->delta, ms->pdelta);
1592         }
1593
1594         if (format & FMT_NUMERIC) {
1595                 fprintf(fp, "%-20s ", addr_to_dotted(&(ms->src)));
1596                 fprintf(fp, "%-20s ", addr_to_dotted(&(ms->dst)));
1597         } else {
1598                 fprintf(fp, "%-20s ", addr_to_anyname(&(ms->src)));
1599                 fprintf(fp, "%-20s ", addr_to_anyname(&(ms->dst)));
1600         }
1601
1602         if (format & FMT_NUMERIC)
1603                 fprintf(fp, "%u (%u) -> %u\n", ms->sport, ms->mport, ms->dport);
1604         else {
1605                 if ((service = port_to_service(ms->sport, ms->kind)) != NULL)
1606                         fprintf(fp, "%s (%u) -> ", service, ms->mport);
1607                 else
1608                         fprintf(fp, "%u (%u) -> ", ms->sport, ms->mport);
1609                 if ((service = port_to_service(ms->dport, ms->kind)) != NULL)
1610                         fprintf(fp, "%s\n", service);
1611                 else
1612                         fprintf(fp, "%u\n", ms->dport);
1613         }
1614 }
1615
1616 int
1617 read_procinfo(FILE *fp, struct ip_fw *fwlist, int nfwlist)
1618 {
1619         int i, n, nread = 0;
1620         struct ip_fw *fw;
1621         unsigned short tosand, tosxor;
1622         unsigned long temp[5];
1623
1624         for (nread = 0; nread < nfwlist; nread++) {
1625                 fw = &fwlist[nread];
1626                 if ((n = fscanf(fp, "%lX/%lX->%lX/%lX %16s %lX %hX %hu %hu %lu %lu",
1627                                 &temp[0], &temp[1], &temp[2], &temp[3],
1628                                 fw->fw_vianame, &temp[4],
1629                                 &fw->fw_flg, &fw->fw_nsp, &fw->fw_ndp,
1630                                 &fw->fw_pcnt, &fw->fw_bcnt)) == -1)
1631                         return nread;
1632                 else if (n != 11)
1633                         exit_error(1, "unexpected input data");
1634                 else {
1635                         for (i = 0; i < IP_FW_MAX_PORTS; i++)
1636                                 if (fscanf(fp, "%hu", &fw->fw_pts[i]) != 1)
1637                                         exit_error(1, "unexpected input data");
1638                         if (fscanf(fp, " A%hX X%hX", &tosand, &tosxor) != 2)
1639                                 exit_error(1, "unexpected input data");
1640                         if (!strcmp("-", fw->fw_vianame))
1641                                 (fw->fw_vianame)[0] = '\0';
1642                         fw->fw_tosand = (unsigned char) tosand;
1643                         fw->fw_tosxor = (unsigned char) tosxor;
1644                 }
1645
1646                 /* we always keep these addresses in network byte order */
1647                 fw->fw_src.s_addr = (__u32) htonl(temp[0]);
1648                 fw->fw_dst.s_addr = (__u32) htonl(temp[2]);
1649                 fw->fw_via.s_addr = (__u32) htonl(temp[4]);
1650                 fw->fw_smsk.s_addr = (__u32) htonl(temp[1]);
1651                 fw->fw_dmsk.s_addr = (__u32) htonl(temp[3]);
1652         }
1653         return nread;
1654 }
1655
1656 int
1657 read_masqinfo(FILE *fp, struct masq *mslist, int nmslist)
1658 {
1659         int n, nread = 0;
1660         struct masq *ms;
1661         char buf[256];
1662         unsigned long temp[3];
1663
1664         for (nread = 0; nread < nmslist; nread++) {
1665                 ms = &mslist[nread];
1666                 if ((n = fscanf(fp, " %s %lX:%hX %lX:%hX %hX %lX %hd %hd %lu",
1667                                 buf, &temp[0], &ms->sport, &temp[1], &ms->dport,
1668                                 &ms->mport, &temp[2], &ms->delta,
1669                                 &ms->pdelta, &ms->expires)) == -1)
1670                         return nread;
1671                 else if (n != 10)
1672                         exit_error(1, "unexpected input data");
1673
1674                 if (strcmp("TCP", buf) == 0)
1675                         ms->kind = IP_FW_F_TCP;
1676                 else if (strcmp("UDP", buf) == 0)
1677                         ms->kind = IP_FW_F_UDP;
1678                 else
1679                         exit_error(1, "unexpected input data");
1680
1681                 /* we always keep these addresses in network byte order */
1682                 ms->src.s_addr = (__u32) htonl(temp[0]);
1683                 ms->dst.s_addr = (__u32) htonl(temp[1]);
1684
1685                 ms->initseq = (__u32) temp[2];
1686         }
1687         return nread;
1688 }
1689
1690 struct ip_fwpkt *
1691 fw_to_fwpkt(struct ip_fw *fw)
1692 {
1693         int kind;
1694         static struct ip_fwpkt ipfwp;
1695         struct iphdr *iph;
1696         struct tcphdr *tcph;
1697         struct udphdr *udph;
1698
1699         kind = (fw->fw_flg) & IP_FW_F_KIND;
1700
1701         iph = &ipfwp.fwp_iph;
1702
1703         iph->version = IP_VERSION;
1704         iph->ihl = sizeof(struct iphdr) / 4;
1705         iph->tot_len = sizeof(struct ip_fwpkt);
1706         iph->frag_off &= htons(~IP_OFFSET);
1707
1708         iph->saddr = fw->fw_src.s_addr;
1709         iph->daddr = fw->fw_dst.s_addr;
1710
1711         inaddrcpy(&ipfwp.fwp_via, &fw->fw_via);
1712         strncpy(ipfwp.fwp_vianame, fw->fw_vianame, IFNAMSIZ);
1713
1714         switch (kind) {
1715         case IP_FW_F_TCP:
1716                 iph->protocol = IPPROTO_TCP;
1717                 tcph = &ipfwp.fwp_protoh.fwp_tcph;
1718                 tcph->source = htons(fw->fw_pts[0]);
1719                 tcph->dest = htons(fw->fw_pts[1]);
1720                 tcph->syn = (fw->fw_flg & IP_FW_F_TCPSYN) ? 1 : 0;
1721                 break;
1722         case IP_FW_F_UDP:
1723                 iph->protocol = IPPROTO_UDP;
1724                 udph = &ipfwp.fwp_protoh.fwp_udph;
1725                 udph->source = htons(fw->fw_pts[0]);
1726                 udph->dest = htons(fw->fw_pts[1]);
1727                 break;
1728         case IP_FW_F_ICMP:
1729                 iph->protocol = IPPROTO_ICMP;
1730         }
1731
1732         return &ipfwp;
1733 }
1734
1735 int
1736 do_setsockopt(int cmd, void *data, int length)
1737 {
1738         static int sockfd = -1;
1739         int ret;
1740
1741         if (sockfd == -1) {
1742                 if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
1743                         perror("ipfwadm: socket creation failed");
1744                         exit(1);
1745                 }
1746         }
1747         
1748         ret = setsockopt(sockfd, IPPROTO_IP, cmd, (char *) data, length);
1749         if (cmd != IP_FW_CHECK_IN && cmd != IP_FW_CHECK_OUT &&
1750                                                 cmd != IP_FW_CHECK_FWD) {
1751                 if (ret)
1752                         perror("ipfwadm: setsockopt failed");
1753         } else {
1754                 if (!ret)
1755                         printf("packet accepted\n");
1756                 else if (errno == ECONNRESET)
1757                         printf("packet masqueraded\n");
1758                 else if (errno == ETIMEDOUT) {
1759                         printf("packet denied\n");
1760                         ret = 0;
1761                 } else if (errno == ECONNREFUSED) {
1762                         printf("packet rejected\n");
1763                         ret = 0;
1764                 } else
1765                         perror("ipfwadm: setsockopt failed");
1766         }
1767
1768         return ret;
1769 }
1770
1771 void
1772 check_option(long option, char name)
1773 {
1774         if (options & option) {
1775                 fprintf(stderr, "%s: multiple -%c flags not allowed\n",
1776                         program, name);
1777                 exit_tryhelp(2);
1778         }
1779         options |= option;
1780 }
1781
1782 void
1783 inaddrcpy(struct in_addr *dst, struct in_addr *src)
1784 {
1785         /* memcpy(dst, src, sizeof(struct in_addr)); */
1786         dst->s_addr = src->s_addr;
1787 }
1788
1789 void *
1790 fw_malloc(size_t size)
1791 {
1792         void *p;
1793
1794         if ((p = malloc(size)) == NULL) {
1795                 perror("ipfwadm: malloc failed");
1796                 exit(1);
1797         } else
1798                 return p;
1799 }
1800
1801 void *
1802 fw_calloc(size_t count, size_t size)
1803 {
1804         void *p;
1805
1806         if ((p = calloc(count, size)) == NULL) {
1807                 perror("ipfwadm: calloc failed");
1808                 exit(1);
1809         } else
1810                 return p;
1811 }
1812
1813 void *
1814 fw_realloc(void *ptr, size_t size)
1815 {
1816         void *p;
1817
1818         if ((p = realloc(ptr, size)) == NULL) {
1819                 perror("ipfwadm: realloc failed");
1820                 exit(1);
1821         } else
1822                 return p;
1823 }
1824
1825 void
1826 exit_error(int status, char *msg)
1827 {
1828         fprintf(stderr, "%s: %s\n", program, msg);
1829         exit_tryhelp(status);
1830 }
1831
1832 void
1833 exit_tryhelp(int status)
1834 {
1835         fprintf(stderr, "Try `%s -h' for more information.\n", program);
1836         exit(status);
1837 }
1838
1839 void
1840 exit_printhelp()
1841 {
1842         printf("%s\n\n"
1843                 "Usage: %s -A [direction] command [options] (accounting)\n"
1844                 "       %s -F command [options] (forwarding firewall)\n"
1845                 "       %s -I command [options] (input firewall)\n"
1846                 "       %s -O command [options] (output firewall)\n"
1847                 "       %s -M [-s | -l] [options] (masquerading entries)\n"
1848                 "       %s -h (print this help information))\n\n",
1849                 package_version, program, program, program, program,
1850                 program, program);
1851
1852         printf("Commands:\n"
1853                 "  -i [policy]  insert rule (no policy for accounting rules)\n"
1854                 "  -a [policy]  append rule (no policy for accounting rules)\n"
1855                 "  -d [policy]  delete rule (no policy for accounting rules)\n"
1856                 "  -l           list all rules of this category\n"
1857                 "  -z           reset packet/byte counters of all rules of this category\n"
1858                 "  -f           remove all rules of this category\n"
1859                 "  -p policy    change default policy (accept/deny/reject)\n"
1860                 "  -s tcp tcpfin udp\n"
1861                 "               set masuerading timeout values\n"
1862                 "  -c           check acceptance of IP packet\n\n"
1863                 "Options:\n"
1864                 "  -P           protocol (either tcp, udp, icmp, or all)\n"
1865                 "  -S address[/mask] [port ...]\n"
1866                 "               source specification\n"
1867                 "  -D address[/mask] [port ...]\n"
1868                 "               destination specification\n"
1869                 "  -V address   network interface address\n"
1870                 "  -W name      network interface name\n"
1871                 "  -b           bidirectional match\n"
1872                 "  -e           extended output mode\n"
1873                 "  -k           match TCP packets only when ACK set\n"
1874                 "  -m           masquerade packets as coming from local host\n"
1875                 "  -n           numeric output of addresses and ports\n"
1876                 "  -o           turn on kernel logging for matching packets\n"
1877                 "  -r [port]    redirect packets to local port (transparent proxying)\n"
1878                 "  -t and xor   and/xor masks for TOS field\n"
1879                 "  -v           verbose mode\n"
1880                 "  -x           expand numbers (display exact values)\n"
1881                 "  -y           match TCP packets only when SYN set and ACK cleared\n");
1882
1883         exit(0);
1884 }