2 * $Id: ipfwadm.c,v 1.6 2002-03-06 01:51:11 gerg Exp $
5 * ipfwadm -- IP firewall and accounting administration
7 * See the accompanying manual page ipfwadm(8) for information
8 * about proper usage of this program.
11 * Copyright (c) 1995,1996 by X/OS Experts in Open Systems BV.
12 * All rights reserved.
14 * Author: Jos Vos <jos@xos.nl>
16 * X/OS Experts in Open Systems BV
18 * NL-1098 VA Amsterdam
22 * WWW: http://www.xos.nl/
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.
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.
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.
41 * 1.1 First release of ipfwadm, which works in combination
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.
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.
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.
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).
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.
105 #include <netinet/in.h>
106 #include <netinet/ip.h>
108 #include <netinet/tcp.h>
109 #include <netinet/udp.h>
110 #include <netinet/ip_icmp.h>
112 #define __u32 u_int32_t
113 #define __u16 u_int16_t
114 #include <netinet/ip_fw.h>
115 #include <sys/param.h>
117 #ifndef IP_FW_F_REDIR
118 #define IPFWADM_NO_REDIR
119 #define IP_FW_F_REDIR 0
120 #endif /* ! IP_FW_F_REDIR */
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 */
128 #ifndef IP_FW_MASQ_TIMEOUTS
129 #define IPFWADM_NO_TIMEOUT
130 #define IP_FW_MASQ_TIMEOUTS 0
131 #endif /* ! IP_FW_MASQ_TIMEOUTS */
134 #define IP_OFFSET 0x1FFF
141 #define CHN_MASQ 4 /* only used for listing masquerading */
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
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
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
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 */
197 struct masq_timeout {
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";
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};
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"};
223 int chain = CHN_NONE;
224 int command = CMD_NONE;
225 long options = OPT_NONE;
229 struct ip_fw firewall;
231 char *sports[IP_FW_MAX_PORTS];
232 char *dports[IP_FW_MAX_PORTS];
234 char *shostnetworkmask, *dhostnetworkmask;
235 int nsaddrs, ndaddrs;
236 struct in_addr *saddrs, *daddrs;
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 *);
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);
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();
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);
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();
287 main(int argc, char *argv[])
289 int c, kind, ret = 0, policy, dummy;
293 while ((c = getopt(argc, argv, "AFIMOadilzfs:p:chP:S:D:V:W:bekmnort:vxy")) != -1)
296 if (chain != CHN_NONE)
297 exit_error(2, "multiple categories specified");
299 if (optind < argc && argv[optind][0] != '-')
300 parse_direction(argv[optind++]);
303 if (chain != CHN_NONE)
304 exit_error(2, "multiple categories specified");
308 if (chain != CHN_NONE)
309 exit_error(2, "multiple categories specified");
313 if (chain != CHN_NONE)
314 exit_error(2, "multiple categories specified");
318 if (chain != CHN_NONE)
319 exit_error(2, "multiple categories specified");
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;
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;
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;
350 if (command != CMD_NONE && command != CMD_RESET)
351 exit_error(2, "multiple commands specified");
355 if (command != CMD_NONE && command != CMD_LIST)
356 exit_error(2, "multiple commands specified");
357 command |= CMD_RESET;
360 if (command != CMD_NONE)
361 exit_error(2, "multiple commands specified");
365 if (command != CMD_NONE)
366 exit_error(2, "multiple commands specified");
367 command = CMD_POLICY;
368 parse_policy(optarg);
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++]);
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 */
390 if (command != CMD_NONE)
391 exit_error(2, "multiple commands specified");
396 /* we'll never reach this */
399 check_option(OPT_PROTOCOL, 'P');
400 parse_protocol(optarg);
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);
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);
417 check_option(OPT_VIAADDR, 'V');
418 parse_viahost(optarg);
421 check_option(OPT_VIANAME, 'W');
422 strncpy(firewall.fw_vianame, optarg, IFNAMSIZ);
425 check_option(OPT_BIDIR, 'b');
426 firewall.fw_flg |= IP_FW_F_BIDIR;
429 check_option(OPT_EXTENDED, 'e');
432 check_option(OPT_TCPACK, 'k');
433 firewall.fw_flg |= IP_FW_F_TCPACK;
436 check_option(OPT_MASQUERADE, 'm');
437 firewall.fw_flg |= IP_FW_F_MASQ;
440 check_option(OPT_NUMERIC, 'n');
443 check_option(OPT_PRINTK, 'o');
444 firewall.fw_flg |= IP_FW_F_PRN;
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++];
454 #else /* IPFWADM_NO_REDIR */
455 exit_error(2, "redirection not supported");
456 #endif /* IPFWADM_NO_REDIR */
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);
464 exit_error(2, "-t requires 2 hexbyte arguments");
467 check_option(OPT_VERBOSE, 'v');
470 check_option(OPT_EXPANDED, 'x');
473 check_option(OPT_TCPSYN, 'y');
474 firewall.fw_flg |= IP_FW_F_TCPSYN;
482 exit_error(2, "unknown arguments found on commandline");
484 exit_error(2, "no command specified");
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));
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");
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");
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;
532 if (command == CMD_CHECK && kind == IP_FW_F_ALL)
533 exit_error(2, "specific protocol required for check command");
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");
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");
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");
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);
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);
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);
604 firewall.fw_pts[firewall.fw_nsp + firewall.fw_ndp] =
605 parse_port(rport, kind);
608 if (!(options & OPT_TOS)) {
609 firewall.fw_tosand = 0xFF;
610 firewall.fw_tosxor = 0x00;
615 ret = add_delete_entries(ssocmd_insert[chain], chain);
618 ret = add_delete_entries(ssocmd_append[chain], chain);
621 ret = add_delete_entries(ssocmd_delete[chain], chain);
624 ret = check_entries(ssocmd_check[chain]);
627 ret = do_setsockopt(ssocmd_policy[chain], &policy, sizeof(int));
630 ret = do_setsockopt(ssocmd_flush[chain], &dummy, sizeof(dummy));
633 ret = do_setsockopt(ssocmd_zero[chain], &dummy, sizeof(dummy));
636 ret = do_setsockopt(IP_FW_MASQ_TIMEOUTS, &timeouts, sizeof(timeouts));
639 case CMD_LIST | CMD_RESET:
640 if (chain == CHN_MASQ)
643 ret = list_entries(chain, (command & CMD_RESET) ? "r+" : "r");
646 /* We should never reach this... */
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.
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.
665 parse_hostnetwork(char *name, int *naddrs)
667 struct in_addr *addrp, *addrptmp;
669 if ((addrptmp = dotted_to_addr(name)) != NULL) {
670 addrp = fw_malloc(sizeof(struct in_addr));
671 inaddrcpy(addrp, addrptmp);
674 } else if ((addrptmp = network_to_addr(name)) != NULL) {
675 addrp = fw_malloc(sizeof(struct in_addr));
676 inaddrcpy(addrp, addrptmp);
679 } else if ((addrp = host_to_addr(name, naddrs)) != NULL) {
682 fprintf(stderr, "%s: host/network \"%s\" not found\n",
685 /* make the compiler happy... */
691 parse_hostnetworkmask(char *name, struct in_addr **addrpp,
692 struct in_addr *maskp, int *naddrs)
694 struct in_addr *addrp;
699 strncpy(buf, name, sizeof(buf) - 1);
700 if ((p = strrchr(buf, '/')) != NULL) {
702 addrp = parse_mask(p + 1);
704 addrp = parse_mask(NULL);
705 inaddrcpy(maskp, addrp);
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");
711 addrp = *addrpp = parse_hostnetwork(buf, 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) {
726 parse_viahost(char *name)
728 struct in_addr *addrp;
731 if ((addrp = dotted_to_addr(name)) != NULL) {
732 inaddrcpy(&firewall.fw_via, addrp);
734 } else if ((addrp = host_to_addr(name, &naddrs)) != NULL) {
737 "%s: hostname \"%s\" does not specify a unique address\n",
741 inaddrcpy(&firewall.fw_via, addrp);
745 fprintf(stderr, "%s: host \"%s\" not found\n", program, name);
751 parse_mask(char *mask)
753 static struct in_addr maskaddr;
754 struct in_addr *addrp;
758 /* no mask at all defaults to 32 bits */
759 maskaddr.s_addr = 0xFFFFFFFF;
761 } else if ((addrp = dotted_to_addr(mask)) != NULL) {
762 /* dotted_to_addr already returns a network byte order addr */
764 } else if ((bits = string_to_number(mask, 0, 32)) == -1) {
765 fprintf(stderr, "%s: invalid mask \"%s\" specified\n", program, mask);
767 /* make the compiler happy... */
769 } else if (bits != 0) {
770 maskaddr.s_addr = htonl(0xFFFFFFFF << (32 - bits));
773 maskaddr.s_addr = 0L;
779 parse_direction(char *s)
781 unsigned short direction;
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)
798 fprintf(stderr, "%s: invalid direction \"%s\" specified\n", program, s);
800 /* make the compiler happy... */
803 firewall.fw_flg |= direction;
808 parse_policy(char *s)
810 unsigned short policy;
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;
823 fprintf(stderr, "%s: invalid policy \"%s\" specified\n", program, s);
825 /* make the compiler happy... */
828 firewall.fw_flg |= policy;
833 parse_protocol(char *s)
835 unsigned short protocol;
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;
846 fprintf(stderr, "%s: invalid protocol \"%s\" specified\n", program, s);
848 /* make the compiler happy... */
851 firewall.fw_flg |= protocol;
855 parse_all_ports(char **ports, unsigned short *portnumbers,
856 int nports, int range)
862 kind = firewall.fw_flg & IP_FW_F_KIND;
864 for (i = 0, j = (range ? 2 : 0); i < nports; i++) {
865 if (ports[i] == NULL)
867 strncpy(buf, ports[i], sizeof(buf) - 1);
868 if ((cp = strchr(buf, (int) ':')) == NULL)
869 portnumbers[j++] = parse_port(buf, kind);
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]);
884 parse_port(char *port, unsigned short kind)
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",
895 /* make the compiler happy... */
897 } else if ((portnum = service_to_port(port, kind)) != -1)
898 return (unsigned short) portnum;
900 fprintf(stderr, "%s: invalid port/service \"%s\" specified\n",
903 /* make the compiler happy... */
909 store_port(char *port, unsigned short *nports, int rangeflag, char *ports[])
911 /* to count the # ports, check whether this is a range or not */
912 if (strchr(port, (int) ':') == NULL)
914 else if (firewall.fw_flg & rangeflag)
915 exit_error(2, "multiple ranges not allowed");
918 firewall.fw_flg |= rangeflag;
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);
926 ports[*nports - 1] = port;
931 parse_hexbyte(char *s, unsigned char *b)
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;
942 fprintf(stderr, "%s: invalid hexbyte \"%s\" specified\n",
947 fprintf(stderr, "%s: invalid hexbyte \"%s\" specified\n",
954 parse_timeout(char *s)
958 if ((timeout = string_to_number(s, 0, INT_MAX)) != -1)
961 fprintf(stderr, "%s: invalid timeout value \"%s\" specified\n",
964 /* make the compiler happy... */
970 host_to_addr(char *name, int *naddr)
972 struct hostent *host;
973 struct in_addr *addr;
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)
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]);
988 return (struct in_addr *) NULL;
992 addr_to_host(struct in_addr *addr)
994 struct hostent *host;
996 if ((host = gethostbyaddr((char *) addr,
997 sizeof(struct in_addr), AF_INET)) != NULL)
998 return (char *) host->h_name;
1000 return (char *) NULL;
1004 network_to_addr(char *name)
1007 static struct in_addr addr;
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);
1017 return (struct in_addr *) NULL;
1021 addr_to_network(struct in_addr *addr)
1026 if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
1027 return (char *) net->n_name;
1030 return (char *) NULL;
1034 addr_to_anyname(struct in_addr *addr)
1038 if ((name = addr_to_host(addr)) != NULL)
1040 else if ((name = addr_to_network(addr)) != NULL)
1043 return addr_to_dotted(addr);
1047 dotted_to_addr(char *dotted)
1049 static struct in_addr addr;
1050 unsigned char *addrp;
1055 /* copy dotted string, because we need to modify it */
1056 strncpy(buf, dotted, sizeof(buf) - 1);
1057 addrp = (unsigned char *) &(addr.s_addr);
1060 for (i = 0; i < 3; i++) {
1061 if ((q = strchr(p, '.')) == NULL)
1062 return (struct in_addr *) NULL;
1065 if ((onebyte = string_to_number(p, 0, 255)) == -1)
1066 return (struct in_addr *) NULL;
1068 addrp[i] = (unsigned char) onebyte;
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;
1077 addrp[3] = (unsigned char) onebyte;
1083 addr_to_dotted(struct in_addr *addrp)
1085 static char buf[20];
1086 unsigned char *bytep;
1088 bytep = (unsigned char *) &(addrp->s_addr);
1089 sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
1094 mask_to_dotted(struct in_addr *mask)
1097 static char buf[20];
1098 __u32 maskaddr, bits;
1100 maskaddr = ntohl(mask->s_addr);
1102 if (maskaddr == 0xFFFFFFFFL)
1103 /* we don't want to see "/32" */
1108 while (--i >= 0 && maskaddr != bits)
1111 sprintf(buf, "/%d", i);
1113 /* mask was not a decent combination of 1's and 0's */
1114 sprintf(buf, "/%s", addr_to_dotted(mask));
1120 service_to_port(char *name, unsigned short kind)
1122 struct servent *service;
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);
1134 port_to_service(int port, unsigned short kind)
1136 struct servent *service;
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;
1145 return (char *) NULL;
1149 string_to_number(char *s, long min, long max)
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)
1166 policy_to_string(int policy)
1169 case IP_FW_F_ACCEPT:
1171 case IP_FW_F_ACCEPT | IP_FW_F_MASQ:
1172 return "accept/masquerade";
1173 case IP_FW_F_ICMPRPL:
1181 add_delete_entries(int cmd, int chain)
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));
1199 check_entries(int cmd)
1202 struct ip_fwpkt *packet;
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));
1219 list_entries(int chain, char *mode)
1225 struct ip_fw *fwlist;
1226 int ntotal = 0, nread, format;
1228 procfile = procfiles[chain];
1230 if ((fp = fopen(procfile, mode)) == NULL) {
1231 fprintf(stderr, "%s: cannot open file %s\n", program, procfile);
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",
1241 fprintf(stdout, "%s, default policy: %s\n", buf,
1242 policy_to_string(policy));
1244 if (fgets(buf, sizeof(buf), fp) == NULL) {
1245 fprintf(stderr, "%s: unexpected input from %s\n",
1251 fwlist = (struct ip_fw *) fw_malloc(16 * sizeof(struct ip_fw));
1252 while ((nread = read_procinfo(fp, &(fwlist[ntotal]), 16)) == 16) {
1254 fwlist = (struct ip_fw *) fw_realloc(fwlist,
1255 (ntotal + 16) * sizeof(struct ip_fw));
1260 if (chain == CHN_IN || chain == CHN_OUT || chain == CHN_FWD)
1261 if (!(options & OPT_EXTENDED))
1262 format |= FMT_NOCOUNTS;
1264 if (options & OPT_NUMERIC)
1265 format |= FMT_NUMERIC;
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;
1272 if (!(options & OPT_EXPANDED))
1273 format |= FMT_KILOMEGA;
1276 for (i = 0; i < ntotal; i++)
1277 print_firewall(stdout, &(fwlist[i]),
1278 (i) ? format : (format | FMT_HEADER));
1290 struct masq *mslist;
1291 int ntotal = 0, nread, format;
1293 procfile = procfiles[CHN_MASQ];
1295 if ((fp = fopen(procfile, "r")) == NULL) {
1296 fprintf(stderr, "%s: cannot open file %s\n", program, procfile);
1300 if (fgets(buf, sizeof(buf), fp) == NULL) {
1301 fprintf(stderr, "%s: unexpected input from %s\n",
1306 fputs("IP masquerading entries\n", stdout);
1308 mslist = (struct masq *) fw_malloc(16 * sizeof(struct masq));
1309 while ((nread = read_masqinfo(fp, &(mslist[ntotal]), 16)) == 16) {
1311 mslist = (struct masq *) fw_realloc(mslist,
1312 (ntotal + 16) * sizeof(struct masq));
1318 if (options & OPT_NUMERIC)
1319 format |= FMT_NUMERIC;
1321 if (options & OPT_EXTENDED)
1322 format |= FMT_DELTAS;
1325 for (i = 0; i < ntotal; i++)
1326 print_masq(stdout, &(mslist[i]),
1327 (i) ? format : (format | FMT_HEADER));
1333 print_firewall(FILE *fp, struct ip_fw *fw, int format)
1335 unsigned short flags, kind;
1336 unsigned long cnt, cntkb, cntmb;
1342 kind = flags & IP_FW_F_KIND;
1344 #define FMT(tab,notab) ((format & FMT_NOTABLE) ? notab : tab)
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");
1352 fprintf(fp, FMT("%8s ","%s "), "pkts");
1353 fprintf(fp, FMT("%10s ","%s "), "bytes");
1356 if (!(format & FMT_NOKIND)) {
1357 if (chain == CHN_ACCT)
1358 fprintf(fp, FMT("%-3s ","%s "), "dir");
1360 fprintf(fp, FMT("%-5s ","%s "), "type");
1363 if (format & FMT_OPTIONS)
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");
1371 fprintf(fp, FMT("%-20s ","%s "), "source");
1372 fprintf(fp, FMT("%-20s ","%s "), "destination");
1373 fputs("ports\n", fp);
1376 if (!(format & FMT_NOCOUNTS)) {
1378 if (format & FMT_KILOMEGA) {
1380 cntkb = (cnt + 500) / 1000;
1382 cntmb = (cnt + 500000) / 1000000;
1383 fprintf(fp, FMT("%4luM ","%luM "), cntmb);
1385 fprintf(fp, FMT("%4luK ","%luK "), cntkb);
1387 fprintf(fp, FMT("%5lu ","%lu "), cnt);
1389 fprintf(fp, FMT("%8lu ","%lu "), cnt);
1391 if (format & FMT_KILOMEGA) {
1393 cntkb = (cnt + 500) / 1000;
1395 cntmb = (cnt + 500000) / 1000000;
1396 fprintf(fp, FMT("%4luM ","%luM "), cntmb);
1398 fprintf(fp, FMT("%4luK ","%luK "), cntkb);
1400 fprintf(fp, FMT("%5lu ","%lu "), cnt);
1402 fprintf(fp, FMT("%10lu ","%lu "), cnt);
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");
1412 fprintf(fp, FMT("%-3s ", "%s "), "i/o");
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");
1423 fprintf(fp, FMT("%-5s ", "%s "), "deny");
1429 fprintf(fp, FMT("%-5s", "%s "), "tcp");
1432 fprintf(fp, FMT("%-5s", "%s "), "udp");
1435 fprintf(fp, FMT("%-5s", "%s "), "icmp");
1438 fprintf(fp, FMT("%-5s", "%s "), "all");
1441 if (format & FMT_OPTIONS) {
1442 if (format & FMT_NOTABLE)
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);
1451 if (format & FMT_TOS) {
1452 if (format & FMT_NOTABLE)
1454 fprintf(fp, "0x%02hX 0x%02hX ",
1455 (unsigned short) fw->fw_tosand,
1456 (unsigned short) fw->fw_tosxor);
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)));
1468 if (format & FMT_NOTABLE)
1471 if (fw->fw_smsk.s_addr == 0L && !(format & FMT_NUMERIC))
1472 fprintf(fp, FMT("%-20s ","%s "), "anywhere");
1474 if (format & FMT_NUMERIC)
1475 sprintf(buf, "%s", addr_to_dotted(&(fw->fw_src)));
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);
1482 if (fw->fw_dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
1483 fprintf(fp, FMT("%-20s","-> %s"), "anywhere");
1485 if (format & FMT_NUMERIC)
1486 sprintf(buf, "%s", addr_to_dotted(&(fw->fw_dst)));
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);
1493 if (format & FMT_NOTABLE)
1496 if (kind != IP_FW_F_TCP && kind != IP_FW_F_UDP && kind != IP_FW_F_ICMP) {
1498 if (!(format & FMT_NONEWLINE))
1503 if (fw->fw_nsp == 0)
1504 fputs((format & FMT_NUMERIC) ? " *" : " any", fp);
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],
1515 fprintf(fp, "%u", fw->fw_pts[i]);
1518 /* only source ports are interpreted as ICMP types */
1519 if (kind == IP_FW_F_ICMP) {
1520 if (!(format & FMT_NONEWLINE))
1527 if (fw->fw_ndp == 0)
1528 fputs((format & FMT_NUMERIC) ? " *" : " any", fp);
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)
1538 fprintf(fp, "%u", fw->fw_pts[i]);
1541 if (flags & IP_FW_F_REDIR) {
1542 i = fw->fw_nsp + fw->fw_ndp;
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);
1550 fprintf(fp, " => %u", fw->fw_pts[i]);
1553 if (!(format & FMT_NONEWLINE))
1558 print_masq(FILE *fp, struct masq *ms, int format)
1560 unsigned long minutes, seconds, sec100s;
1563 if (format & FMT_HEADER) {
1565 fprintf(fp, "%-8s ", "expire");
1566 if (format & FMT_DELTAS) {
1567 fprintf(fp, "%10s delta prevd ", "initseq");
1569 fprintf(fp, "%-20s ", "source");
1570 fprintf(fp, "%-20s ", "destination");
1571 fputs("ports\n", fp);
1576 fprintf(fp, "%-5s", "tcp");
1579 fprintf(fp, "%-5s", "udp");
1583 sec100s = ms->expires % HZ;
1584 seconds = (ms->expires / HZ) % 60;
1585 minutes = ms->expires / (60 * HZ);
1587 fprintf(fp, "%02ld:%02ld.%02ld ", minutes, seconds, sec100s);
1589 if (format & FMT_DELTAS) {
1590 fprintf(fp, "%10lu %5hd %5hd ", (unsigned long) ms->initseq,
1591 ms->delta, ms->pdelta);
1594 if (format & FMT_NUMERIC) {
1595 fprintf(fp, "%-20s ", addr_to_dotted(&(ms->src)));
1596 fprintf(fp, "%-20s ", addr_to_dotted(&(ms->dst)));
1598 fprintf(fp, "%-20s ", addr_to_anyname(&(ms->src)));
1599 fprintf(fp, "%-20s ", addr_to_anyname(&(ms->dst)));
1602 if (format & FMT_NUMERIC)
1603 fprintf(fp, "%u (%u) -> %u\n", ms->sport, ms->mport, ms->dport);
1605 if ((service = port_to_service(ms->sport, ms->kind)) != NULL)
1606 fprintf(fp, "%s (%u) -> ", service, ms->mport);
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);
1612 fprintf(fp, "%u\n", ms->dport);
1617 read_procinfo(FILE *fp, struct ip_fw *fwlist, int nfwlist)
1619 int i, n, nread = 0;
1621 unsigned short tosand, tosxor;
1622 unsigned long temp[5];
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)
1633 exit_error(1, "unexpected input data");
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;
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]);
1657 read_masqinfo(FILE *fp, struct masq *mslist, int nmslist)
1662 unsigned long temp[3];
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)
1672 exit_error(1, "unexpected input data");
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;
1679 exit_error(1, "unexpected input data");
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]);
1685 ms->initseq = (__u32) temp[2];
1691 fw_to_fwpkt(struct ip_fw *fw)
1694 static struct ip_fwpkt ipfwp;
1696 struct tcphdr *tcph;
1697 struct udphdr *udph;
1699 kind = (fw->fw_flg) & IP_FW_F_KIND;
1701 iph = &ipfwp.fwp_iph;
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);
1708 iph->saddr = fw->fw_src.s_addr;
1709 iph->daddr = fw->fw_dst.s_addr;
1711 inaddrcpy(&ipfwp.fwp_via, &fw->fw_via);
1712 strncpy(ipfwp.fwp_vianame, fw->fw_vianame, IFNAMSIZ);
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;
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]);
1729 iph->protocol = IPPROTO_ICMP;
1736 do_setsockopt(int cmd, void *data, int length)
1738 static int sockfd = -1;
1742 if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
1743 perror("ipfwadm: socket creation failed");
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) {
1752 perror("ipfwadm: setsockopt failed");
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");
1761 } else if (errno == ECONNREFUSED) {
1762 printf("packet rejected\n");
1765 perror("ipfwadm: setsockopt failed");
1772 check_option(long option, char name)
1774 if (options & option) {
1775 fprintf(stderr, "%s: multiple -%c flags not allowed\n",
1783 inaddrcpy(struct in_addr *dst, struct in_addr *src)
1785 /* memcpy(dst, src, sizeof(struct in_addr)); */
1786 dst->s_addr = src->s_addr;
1790 fw_malloc(size_t size)
1794 if ((p = malloc(size)) == NULL) {
1795 perror("ipfwadm: malloc failed");
1802 fw_calloc(size_t count, size_t size)
1806 if ((p = calloc(count, size)) == NULL) {
1807 perror("ipfwadm: calloc failed");
1814 fw_realloc(void *ptr, size_t size)
1818 if ((p = realloc(ptr, size)) == NULL) {
1819 perror("ipfwadm: realloc failed");
1826 exit_error(int status, char *msg)
1828 fprintf(stderr, "%s: %s\n", program, msg);
1829 exit_tryhelp(status);
1833 exit_tryhelp(int status)
1835 fprintf(stderr, "Try `%s -h' for more information.\n", program);
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,
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"
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");