2 * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
4 * Supported by: Valeria Paoli
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_sockopt.c 200601 2009-12-16 10:48:40Z luigi $");
32 * Sockopt support for ipfw. The routines here implement
33 * the upper half of the ipfw code.
36 #if !defined(KLD_MODULE)
38 #include "opt_ipdivert.h"
42 #error IPFIREWALL requires INET.
45 #include "opt_inet6.h"
46 #include "opt_ipsec.h"
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/malloc.h>
51 #include <sys/mbuf.h> /* struct m_tag used by nested headers */
52 #include <sys/kernel.h>
56 #include <sys/rwlock.h>
57 #include <sys/socket.h>
58 #include <sys/socketvar.h>
59 #include <sys/sysctl.h>
60 #include <sys/syslog.h>
62 #include <net/route.h>
65 #include <netinet/in.h>
66 #include <netinet/ip_fw.h>
67 #include <netinet/ipfw/ip_fw_private.h>
70 #include <security/mac/mac_framework.h>
73 MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
76 * static variables followed by global ones (none in this file)
80 * Find the smallest rule >= key, id.
81 * We could use bsearch but it is so simple that we code it directly
84 ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id)
89 for (lo = 0, hi = chain->n_rules - 1; lo < hi;) {
93 lo = i + 1; /* continue from the next one */
94 else if (r->rulenum > key)
95 hi = i; /* this might be good */
97 lo = i + 1; /* continue from the next one */
98 else /* r->id >= id */
99 hi = i; /* this might be good */
105 * allocate a new map, returns the chain locked. extra is the number
106 * of entries to add or delete.
108 static struct ip_fw **
109 get_map(struct ip_fw_chain *chain, int extra, int locked)
116 i = chain->n_rules + extra;
117 map = malloc(i * sizeof(struct ip_fw *), M_IPFW, M_WAITOK);
119 printf("%s: cannot allocate map\n", __FUNCTION__);
123 IPFW_UH_WLOCK(chain);
124 if (i >= chain->n_rules + extra) /* good */
126 /* otherwise we lost the race, free and retry */
128 IPFW_UH_WUNLOCK(chain);
134 * swap the maps. It is supposed to be called with IPFW_UH_WLOCK
136 static struct ip_fw **
137 swap_map(struct ip_fw_chain *chain, struct ip_fw **new_map, int new_len)
139 struct ip_fw **old_map;
143 chain->n_rules = new_len;
144 old_map = chain->map;
145 chain->map = new_map;
151 * Add a new rule to the list. Copy the rule into a malloc'ed area, then
152 * possibly create a rule number and add the rule to the list.
153 * Update the rule_number in the input struct so the caller knows it as well.
154 * XXX DO NOT USE FOR THE DEFAULT RULE.
155 * Must be called without IPFW_UH held
158 ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
161 int i, l, insert_before;
162 struct ip_fw **map; /* the new array of pointers */
164 if (chain->rules == NULL || input_rule->rulenum > IPFW_DEFAULT_RULE-1)
167 l = RULESIZE(input_rule);
168 rule = malloc(l, M_IPFW, M_WAITOK | M_ZERO);
171 /* get_map returns with IPFW_UH_WLOCK if successful */
172 map = get_map(chain, 1, 0 /* not locked */);
178 bcopy(input_rule, rule, l);
179 /* clear fields not settable from userland */
181 rule->next_rule = NULL;
186 if (V_autoinc_step < 1)
188 else if (V_autoinc_step > 1000)
189 V_autoinc_step = 1000;
190 /* find the insertion point, we will insert before */
191 insert_before = rule->rulenum ? rule->rulenum + 1 : IPFW_DEFAULT_RULE;
192 i = ipfw_find_rule(chain, insert_before, 0);
193 /* duplicate first part */
195 bcopy(chain->map, map, i * sizeof(struct ip_fw *));
197 /* duplicate remaining part, we always have the default rule */
198 bcopy(chain->map + i, map + i + 1,
199 sizeof(struct ip_fw *) *(chain->n_rules - i));
200 if (rule->rulenum == 0) {
201 /* write back the number */
202 rule->rulenum = i > 0 ? map[i-1]->rulenum : 0;
203 if (rule->rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
204 rule->rulenum += V_autoinc_step;
205 input_rule->rulenum = rule->rulenum;
208 rule->id = chain->id + 1;
209 map = swap_map(chain, map, chain->n_rules + 1);
210 chain->static_len += l;
211 IPFW_UH_WUNLOCK(chain);
218 * Reclaim storage associated with a list of rules. This is
219 * typically the list created using remove_rule.
220 * A NULL pointer on input is handled correctly.
223 ipfw_reap_rules(struct ip_fw *head)
227 while ((rule = head) != NULL) {
234 * Remove all rules with given number, and also do set manipulation.
235 * Assumes chain != NULL && *chain != NULL.
237 * The argument is an u_int32_t. The low 16 bit are the rule or set number,
238 * the next 8 bits are the new set, the top 8 bits are the command:
240 * 0 delete rules with given number
241 * 1 delete rules with given set number
242 * 2 move rules with given number to new set
243 * 3 move rules with given set number to new set
244 * 4 swap sets with given numbers
245 * 5 delete rules with given number and with given set number
248 del_entry(struct ip_fw_chain *chain, u_int32_t arg)
251 uint32_t rulenum; /* rule or old_set */
252 uint8_t cmd, new_set;
253 int start, end = 0, i, ofs, n;
254 struct ip_fw **map = NULL;
257 rulenum = arg & 0xffff;
258 cmd = (arg >> 24) & 0xff;
259 new_set = (arg >> 16) & 0xff;
261 if (cmd > 5 || new_set > RESVD_SET)
263 if (cmd == 0 || cmd == 2 || cmd == 5) {
264 if (rulenum >= IPFW_DEFAULT_RULE)
267 if (rulenum > RESVD_SET) /* old_set */
271 IPFW_UH_WLOCK(chain); /* prevent conflicts among the writers */
272 chain->reap = NULL; /* prepare for deletions */
275 case 0: /* delete rules with given number (0 is special means all) */
276 case 1: /* delete all rules with given set number, rule->set == rulenum */
277 case 5: /* delete rules with given number and with given set number.
278 * rulenum - given rule number;
279 * new_set - given set number.
281 /* locate first rule to delete (start), the one after the
282 * last one (end), and count how many rules to delete (n)
285 if (cmd == 1) { /* look for a specific set, must scan all */
286 for (start = -1, i = 0; i < chain->n_rules; i++) {
287 if (chain->map[start]->set != rulenum)
294 end++; /* first non-matching */
296 start = ipfw_find_rule(chain, rulenum, 0);
297 for (end = start; end < chain->n_rules; end++) {
298 rule = chain->map[end];
299 if (rulenum > 0 && rule->rulenum != rulenum)
301 if (rule->set != RESVD_SET &&
302 (cmd == 0 || rule->set == new_set) )
306 if (n == 0 && arg == 0)
307 break; /* special case, flush on empty ruleset */
308 /* allocate the map, if needed */
310 map = get_map(chain, -n, 1 /* locked */);
311 if (n == 0 || map == NULL) {
315 /* copy the initial part of the map */
317 bcopy(chain->map, map, start * sizeof(struct ip_fw *));
318 /* copy active rules between start and end */
319 for (i = ofs = start; i < end; i++) {
320 rule = chain->map[i];
321 if (!(rule->set != RESVD_SET &&
322 (cmd == 0 || rule->set == new_set) ))
323 map[ofs++] = chain->map[i];
325 /* finally the tail */
326 bcopy(chain->map + end, map + ofs,
327 (chain->n_rules - end) * sizeof(struct ip_fw *));
328 map = swap_map(chain, map, chain->n_rules - n);
329 /* now remove the rules deleted */
330 for (i = start; i < end; i++) {
332 if (rule->set != RESVD_SET &&
333 (cmd == 0 || rule->set == new_set) ) {
334 int l = RULESIZE(rule);
336 chain->static_len -= l;
337 ipfw_remove_dyn_children(rule);
338 rule->x_next = chain->reap;
344 case 2: /* move rules with given number to new set */
345 IPFW_UH_WLOCK(chain);
346 for (i = 0; i < chain->n_rules; i++) {
347 rule = chain->map[i];
348 if (rule->rulenum == rulenum)
351 IPFW_UH_WUNLOCK(chain);
354 case 3: /* move rules with given set number to new set */
355 IPFW_UH_WLOCK(chain);
356 for (i = 0; i < chain->n_rules; i++) {
357 rule = chain->map[i];
358 if (rule->set == rulenum)
361 IPFW_UH_WUNLOCK(chain);
364 case 4: /* swap two sets */
365 IPFW_UH_WLOCK(chain);
366 for (i = 0; i < chain->n_rules; i++) {
367 rule = chain->map[i];
368 if (rule->set == rulenum)
370 else if (rule->set == new_set)
373 IPFW_UH_WUNLOCK(chain);
378 IPFW_UH_WUNLOCK(chain);
379 ipfw_reap_rules(rule);
386 * Clear counters for a specific rule.
387 * Normally run under IPFW_UH_RLOCK, but these are idempotent ops
388 * so we only care that rules do not disappear.
391 clear_counters(struct ip_fw *rule, int log_only)
393 ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule);
396 rule->bcnt = rule->pcnt = 0;
399 if (l->o.opcode == O_LOG)
400 l->log_left = l->max_log;
404 * Reset some or all counters on firewall rules.
405 * The argument `arg' is an u_int32_t. The low 16 bit are the rule number,
406 * the next 8 bits are the set number, the top 8 bits are the command:
407 * 0 work with rules from all set's;
408 * 1 work with rules only from specified set.
409 * Specified rule number is zero if we want to clear all entries.
410 * log_only is 1 if we only want to reset logs, zero otherwise.
413 zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only)
419 uint16_t rulenum = arg & 0xffff;
420 uint8_t set = (arg >> 16) & 0xff;
421 uint8_t cmd = (arg >> 24) & 0xff;
425 if (cmd == 1 && set > RESVD_SET)
428 IPFW_UH_RLOCK(chain);
430 V_norule_counter = 0;
431 for (i = 0; i < chain->n_rules; i++) {
432 rule = chain->map[i];
433 /* Skip rules not in our set. */
434 if (cmd == 1 && rule->set != set)
436 clear_counters(rule, log_only);
438 msg = log_only ? "All logging counts reset" :
439 "Accounting cleared";
442 for (i = 0; i < chain->n_rules; i++) {
443 rule = chain->map[i];
444 if (rule->rulenum == rulenum) {
445 if (cmd == 0 || rule->set == set)
446 clear_counters(rule, log_only);
449 if (rule->rulenum > rulenum)
452 if (!cleared) { /* we did not find any matching rules */
456 msg = log_only ? "logging count reset" : "cleared";
458 IPFW_UH_RUNLOCK(chain);
461 int lev = LOG_SECURITY | LOG_NOTICE;
464 log(lev, "ipfw: Entry %d %s.\n", rulenum, msg);
466 log(lev, "ipfw: %s.\n", msg);
472 * Check validity of the structure before insert.
473 * Rules are simple, so this mostly need to check rule sizes.
476 check_ipfw_struct(struct ip_fw *rule, int size)
482 if (size < sizeof(*rule)) {
483 printf("ipfw: rule too short\n");
486 /* first, check for valid size */
489 printf("ipfw: size mismatch (have %d want %d)\n", size, l);
492 if (rule->act_ofs >= rule->cmd_len) {
493 printf("ipfw: bogus action offset (%u > %u)\n",
494 rule->act_ofs, rule->cmd_len - 1);
498 * Now go for the individual checks. Very simple ones, basically only
501 for (l = rule->cmd_len, cmd = rule->cmd ;
502 l > 0 ; l -= cmdlen, cmd += cmdlen) {
505 printf("ipfw: opcode %d size truncated\n",
509 switch (cmd->opcode) {
539 if (cmdlen != F_INSN_SIZE(ipfw_insn))
544 if (cmdlen != F_INSN_SIZE(ipfw_insn))
546 if (cmd->arg1 >= rt_numfibs) {
547 printf("ipfw: invalid fib number %d\n",
554 if (cmdlen != F_INSN_SIZE(ipfw_insn))
556 if (cmd->arg1 >= rt_numfibs) {
557 printf("ipfw: invalid fib number %d\n",
572 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32))
577 if (cmdlen != F_INSN_SIZE(ipfw_insn_limit))
582 if (cmdlen != F_INSN_SIZE(ipfw_insn_log))
585 ((ipfw_insn_log *)cmd)->log_left =
586 ((ipfw_insn_log *)cmd)->max_log;
592 /* only odd command lengths */
593 if ( !(cmdlen & 1) || cmdlen > 31)
599 if (cmd->arg1 == 0 || cmd->arg1 > 256) {
600 printf("ipfw: invalid set size %d\n",
604 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
609 case O_IP_SRC_LOOKUP:
610 case O_IP_DST_LOOKUP:
611 if (cmd->arg1 >= IPFW_TABLES_MAX) {
612 printf("ipfw: invalid table number %d\n",
616 if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
617 cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
618 cmdlen != F_INSN_SIZE(ipfw_insn_u32))
623 if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
633 if (cmdlen < 1 || cmdlen > 31)
639 case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
640 if (cmdlen < 2 || cmdlen > 31)
647 if (cmdlen != F_INSN_SIZE(ipfw_insn_if))
652 if (cmdlen != F_INSN_SIZE(ipfw_insn_altq))
658 if (cmdlen != F_INSN_SIZE(ipfw_insn))
663 #ifdef IPFIREWALL_FORWARD
664 if (cmdlen != F_INSN_SIZE(ipfw_insn_sa))
673 if (ip_divert_ptr == NULL)
684 if (!IPFW_NAT_LOADED)
686 if (cmdlen != F_INSN_SIZE(ipfw_insn_nat))
689 case O_FORWARD_MAC: /* XXX not implemented yet */
701 if (cmdlen != F_INSN_SIZE(ipfw_insn))
705 printf("ipfw: opcode %d, multiple actions"
712 printf("ipfw: opcode %d, action must be"
721 if (cmdlen != F_INSN_SIZE(struct in6_addr) +
722 F_INSN_SIZE(ipfw_insn))
727 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
728 ((ipfw_insn_u32 *)cmd)->o.arg1)
734 if ( !(cmdlen & 1) || cmdlen > 127)
738 if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
744 switch (cmd->opcode) {
757 printf("ipfw: no IPv6 support in kernel\n");
758 return EPROTONOSUPPORT;
761 printf("ipfw: opcode %d, unknown opcode\n",
767 if (have_action == 0) {
768 printf("ipfw: missing action\n");
774 printf("ipfw: opcode %d size %d wrong\n",
775 cmd->opcode, cmdlen);
780 * Copy the static and dynamic rules to the supplied buffer
781 * and return the amount of space actually used.
782 * Must be run under IPFW_UH_RLOCK
785 ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
788 char *ep = bp + space;
789 struct ip_fw *rule, *dst;
793 boot_seconds = boottime.tv_sec;
794 for (i = 0; i < chain->n_rules; i++) {
795 rule = chain->map[i];
797 if (bp + l > ep) { /* should not happen */
798 printf("overflow dumping static rules\n");
801 dst = (struct ip_fw *)bp;
804 * XXX HACK. Store the disable mask in the "next"
805 * pointer in a wild attempt to keep the ABI the same.
806 * Why do we do this on EVERY rule?
808 bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable));
810 dst->timestamp += boot_seconds;
813 ipfw_get_dynamic(&bp, ep); /* protected by the dynamic lock */
814 return (bp - (char *)buf);
819 * {set|get}sockopt parser.
822 ipfw_ctl(struct sockopt *sopt)
824 #define RULE_MAXSIZE (256*sizeof(u_int32_t))
827 struct ip_fw *buf, *rule;
828 struct ip_fw_chain *chain;
829 u_int32_t rulenum[2];
831 error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
836 * Disallow modifications in really-really secure mode, but still allow
837 * the logging counters to be reset.
839 if (sopt->sopt_name == IP_FW_ADD ||
840 (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) {
841 error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
846 chain = &V_layer3_chain;
849 switch (sopt->sopt_name) {
852 * pass up a copy of the current rules. Static rules
853 * come first (the last of which has number IPFW_DEFAULT_RULE),
854 * followed by a possibly empty list of dynamic rule.
855 * The last dynamic rule has NULL in the "next" field.
857 * Note that the calculated size is used to bound the
858 * amount of data returned to the user. The rule set may
859 * change between calculating the size and returning the
860 * data in which case we'll just return what fits.
865 size = chain->static_len;
866 size += ipfw_dyn_len();
867 if (size >= sopt->sopt_valsize)
869 buf = malloc(size, M_TEMP, M_WAITOK);
872 IPFW_UH_RLOCK(chain);
873 /* check again how much space we need */
874 want = chain->static_len + ipfw_dyn_len();
876 len = ipfw_getrules(chain, buf, size);
877 IPFW_UH_RUNLOCK(chain);
879 error = sooptcopyout(sopt, buf, len);
887 /* locking is done within del_entry() */
888 error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
892 rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);
893 error = sooptcopyin(sopt, rule, RULE_MAXSIZE,
894 sizeof(struct ip_fw) );
896 error = check_ipfw_struct(rule, sopt->sopt_valsize);
898 /* locking is done within ipfw_add_rule() */
899 error = ipfw_add_rule(chain, rule);
900 size = RULESIZE(rule);
901 if (!error && sopt->sopt_dir == SOPT_GET)
902 error = sooptcopyout(sopt, rule, size);
909 * IP_FW_DEL is used for deleting single rules or sets,
910 * and (ab)used to atomically manipulate sets. Argument size
911 * is used to distinguish between the two:
913 * delete single rule or set of rules,
914 * or reassign rules (or sets) to a different set.
915 * 2*sizeof(u_int32_t)
916 * atomic disable/enable sets.
917 * first u_int32_t contains sets to be disabled,
918 * second u_int32_t contains sets to be enabled.
920 error = sooptcopyin(sopt, rulenum,
921 2*sizeof(u_int32_t), sizeof(u_int32_t));
924 size = sopt->sopt_valsize;
925 if (size == sizeof(u_int32_t) && rulenum[0] != 0) {
926 /* delete or reassign, locking done in del_entry() */
927 error = del_entry(chain, rulenum[0]);
928 } else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */
929 IPFW_UH_WLOCK(chain);
931 (V_set_disable | rulenum[0]) & ~rulenum[1] &
932 ~(1<<RESVD_SET); /* set RESVD_SET always enabled */
933 IPFW_UH_WUNLOCK(chain);
939 case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */
941 if (sopt->sopt_val != 0) {
942 error = sooptcopyin(sopt, rulenum,
943 sizeof(u_int32_t), sizeof(u_int32_t));
947 error = zero_entry(chain, rulenum[0],
948 sopt->sopt_name == IP_FW_RESETLOG);
951 /*--- TABLE manipulations are protected by the IPFW_LOCK ---*/
952 case IP_FW_TABLE_ADD:
954 ipfw_table_entry ent;
956 error = sooptcopyin(sopt, &ent,
957 sizeof(ent), sizeof(ent));
960 error = ipfw_add_table_entry(chain, ent.tbl,
961 ent.addr, ent.masklen, ent.value);
965 case IP_FW_TABLE_DEL:
967 ipfw_table_entry ent;
969 error = sooptcopyin(sopt, &ent,
970 sizeof(ent), sizeof(ent));
973 error = ipfw_del_table_entry(chain, ent.tbl,
974 ent.addr, ent.masklen);
978 case IP_FW_TABLE_FLUSH:
982 error = sooptcopyin(sopt, &tbl,
983 sizeof(tbl), sizeof(tbl));
987 error = ipfw_flush_table(chain, tbl);
992 case IP_FW_TABLE_GETSIZE:
996 if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
1000 error = ipfw_count_table(chain, tbl, &cnt);
1001 IPFW_RUNLOCK(chain);
1004 error = sooptcopyout(sopt, &cnt, sizeof(cnt));
1008 case IP_FW_TABLE_LIST:
1012 if (sopt->sopt_valsize < sizeof(*tbl)) {
1016 size = sopt->sopt_valsize;
1017 tbl = malloc(size, M_TEMP, M_WAITOK);
1018 error = sooptcopyin(sopt, tbl, size, sizeof(*tbl));
1023 tbl->size = (size - sizeof(*tbl)) /
1024 sizeof(ipfw_table_entry);
1026 error = ipfw_dump_table(chain, tbl);
1027 IPFW_RUNLOCK(chain);
1032 error = sooptcopyout(sopt, tbl, size);
1037 /*--- NAT operations are protected by the IPFW_LOCK ---*/
1039 if (IPFW_NAT_LOADED)
1040 error = ipfw_nat_cfg_ptr(sopt);
1042 printf("IP_FW_NAT_CFG: %s\n",
1043 "ipfw_nat not present, please load it");
1049 if (IPFW_NAT_LOADED)
1050 error = ipfw_nat_del_ptr(sopt);
1052 printf("IP_FW_NAT_DEL: %s\n",
1053 "ipfw_nat not present, please load it");
1058 case IP_FW_NAT_GET_CONFIG:
1059 if (IPFW_NAT_LOADED)
1060 error = ipfw_nat_get_cfg_ptr(sopt);
1062 printf("IP_FW_NAT_GET_CFG: %s\n",
1063 "ipfw_nat not present, please load it");
1068 case IP_FW_NAT_GET_LOG:
1069 if (IPFW_NAT_LOADED)
1070 error = ipfw_nat_get_log_ptr(sopt);
1072 printf("IP_FW_NAT_GET_LOG: %s\n",
1073 "ipfw_nat not present, please load it");
1079 printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);