ip_fw_sockopt.c revision 200601
1/*-
2 * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_sockopt.c 200601 2009-12-16 10:48:40Z luigi $");
28
29#define        DEB(x)
30#define        DDB(x) x
31
32/*
33 * Sockopt support for ipfw. The routines here implement
34 * the upper half of the ipfw code.
35 */
36
37#if !defined(KLD_MODULE)
38#include "opt_ipfw.h"
39#include "opt_ipdivert.h"
40#include "opt_ipdn.h"
41#include "opt_inet.h"
42#ifndef INET
43#error IPFIREWALL requires INET.
44#endif /* INET */
45#endif
46#include "opt_inet6.h"
47#include "opt_ipsec.h"
48
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/malloc.h>
52#include <sys/kernel.h>
53#include <sys/lock.h>
54#include <sys/priv.h>
55#include <sys/proc.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>
61#include <net/if.h>
62#include <net/route.h>
63#include <net/vnet.h>
64
65#include <netinet/in.h>
66#include <netinet/ip_fw.h>
67#include <netinet/ipfw/ip_fw_private.h>
68#include <netinet/ip_divert.h>
69
70#include <netgraph/ng_ipfw.h>
71
72#ifdef MAC
73#include <security/mac/mac_framework.h>
74#endif
75
76MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
77
78/*
79 * static variables followed by global ones
80 */
81
82static VNET_DEFINE(u_int32_t, static_count);	/* # of static rules */
83static VNET_DEFINE(u_int32_t, static_len);	/* bytes of static rules */
84#define	V_static_count			VNET(static_count)
85#define	V_static_len			VNET(static_len)
86
87#ifdef SYSCTL_NODE
88SYSCTL_DECL(_net_inet_ip_fw);
89SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step,
90    CTLFLAG_RW, &VNET_NAME(autoinc_step), 0,
91    "Rule number auto-increment step");
92SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count,
93    CTLFLAG_RD, &VNET_NAME(static_count), 0,
94    "Number of static rules");
95
96#endif /* SYSCTL_NODE */
97
98/*
99 * When a rule is added/deleted, clear the next_rule pointers in all rules.
100 * These will be reconstructed on the fly as packets are matched.
101 */
102static void
103flush_rule_ptrs(struct ip_fw_chain *chain)
104{
105	struct ip_fw *rule;
106
107	IPFW_WLOCK_ASSERT(chain);
108
109	chain->id++;
110
111	for (rule = chain->rules; rule; rule = rule->next)
112		rule->next_rule = NULL;
113}
114
115/*
116 * Add a new rule to the list. Copy the rule into a malloc'ed area, then
117 * possibly create a rule number and add the rule to the list.
118 * Update the rule_number in the input struct so the caller knows it as well.
119 */
120int
121ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule)
122{
123	struct ip_fw *rule, *f, *prev;
124	int l = RULESIZE(input_rule);
125
126	if (chain->rules == NULL && input_rule->rulenum != IPFW_DEFAULT_RULE)
127		return (EINVAL);
128
129	rule = malloc(l, M_IPFW, M_NOWAIT | M_ZERO);
130	if (rule == NULL)
131		return (ENOSPC);
132
133	bcopy(input_rule, rule, l);
134
135	rule->next = NULL;
136	rule->next_rule = NULL;
137
138	rule->pcnt = 0;
139	rule->bcnt = 0;
140	rule->timestamp = 0;
141
142	IPFW_WLOCK(chain);
143
144	if (chain->rules == NULL) {	/* default rule */
145		chain->rules = rule;
146		rule->id = ++chain->id;
147		goto done;
148        }
149
150	/*
151	 * If rulenum is 0, find highest numbered rule before the
152	 * default rule, and add autoinc_step
153	 */
154	if (V_autoinc_step < 1)
155		V_autoinc_step = 1;
156	else if (V_autoinc_step > 1000)
157		V_autoinc_step = 1000;
158	if (rule->rulenum == 0) {
159		/*
160		 * locate the highest numbered rule before default
161		 */
162		for (f = chain->rules; f; f = f->next) {
163			if (f->rulenum == IPFW_DEFAULT_RULE)
164				break;
165			rule->rulenum = f->rulenum;
166		}
167		if (rule->rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
168			rule->rulenum += V_autoinc_step;
169		input_rule->rulenum = rule->rulenum;
170	}
171
172	/*
173	 * Now insert the new rule in the right place in the sorted list.
174	 */
175	for (prev = NULL, f = chain->rules; f; prev = f, f = f->next) {
176		if (f->rulenum > rule->rulenum) { /* found the location */
177			if (prev) {
178				rule->next = f;
179				prev->next = rule;
180			} else { /* head insert */
181				rule->next = chain->rules;
182				chain->rules = rule;
183			}
184			break;
185		}
186	}
187	flush_rule_ptrs(chain);
188	/* chain->id incremented inside flush_rule_ptrs() */
189	rule->id = chain->id;
190done:
191	V_static_count++;
192	V_static_len += l;
193	IPFW_WUNLOCK(chain);
194	DEB(printf("ipfw: installed rule %d, static count now %d\n",
195		rule->rulenum, V_static_count);)
196	return (0);
197}
198
199/**
200 * Remove a static rule (including derived * dynamic rules)
201 * and place it on the ``reap list'' for later reclamation.
202 * The caller is in charge of clearing rule pointers to avoid
203 * dangling pointers.
204 * @return a pointer to the next entry.
205 * Arguments are not checked, so they better be correct.
206 */
207static struct ip_fw *
208remove_rule(struct ip_fw_chain *chain, struct ip_fw *rule,
209    struct ip_fw *prev)
210{
211	struct ip_fw *n;
212	int l = RULESIZE(rule);
213
214	IPFW_WLOCK_ASSERT(chain);
215
216	n = rule->next;
217	ipfw_remove_dyn_children(rule);
218	if (prev == NULL)
219		chain->rules = n;
220	else
221		prev->next = n;
222	V_static_count--;
223	V_static_len -= l;
224
225	rule->next = chain->reap;
226	chain->reap = rule;
227
228	return n;
229}
230
231/*
232 * Reclaim storage associated with a list of rules.  This is
233 * typically the list created using remove_rule.
234 * A NULL pointer on input is handled correctly.
235 */
236void
237ipfw_reap_rules(struct ip_fw *head)
238{
239	struct ip_fw *rule;
240
241	while ((rule = head) != NULL) {
242		head = head->next;
243		free(rule, M_IPFW);
244	}
245}
246
247/*
248 * Remove all rules from a chain (except rules in set RESVD_SET
249 * unless kill_default = 1).  The caller is responsible for
250 * reclaiming storage for the rules left in chain->reap.
251 */
252void
253ipfw_free_chain(struct ip_fw_chain *chain, int kill_default)
254{
255	struct ip_fw *prev, *rule;
256
257	IPFW_WLOCK_ASSERT(chain);
258
259	chain->reap = NULL;
260	flush_rule_ptrs(chain); /* more efficient to do outside the loop */
261	for (prev = NULL, rule = chain->rules; rule ; )
262		if (kill_default || rule->set != RESVD_SET)
263			rule = remove_rule(chain, rule, prev);
264		else {
265			prev = rule;
266			rule = rule->next;
267		}
268}
269
270/**
271 * Remove all rules with given number, and also do set manipulation.
272 * Assumes chain != NULL && *chain != NULL.
273 *
274 * The argument is an u_int32_t. The low 16 bit are the rule or set number,
275 * the next 8 bits are the new set, the top 8 bits are the command:
276 *
277 *	0	delete rules with given number
278 *	1	delete rules with given set number
279 *	2	move rules with given number to new set
280 *	3	move rules with given set number to new set
281 *	4	swap sets with given numbers
282 *	5	delete rules with given number and with given set number
283 */
284static int
285del_entry(struct ip_fw_chain *chain, u_int32_t arg)
286{
287	struct ip_fw *prev = NULL, *rule;
288	u_int16_t rulenum;	/* rule or old_set */
289	u_int8_t cmd, new_set;
290
291	rulenum = arg & 0xffff;
292	cmd = (arg >> 24) & 0xff;
293	new_set = (arg >> 16) & 0xff;
294
295	if (cmd > 5 || new_set > RESVD_SET)
296		return EINVAL;
297	if (cmd == 0 || cmd == 2 || cmd == 5) {
298		if (rulenum >= IPFW_DEFAULT_RULE)
299			return EINVAL;
300	} else {
301		if (rulenum > RESVD_SET)	/* old_set */
302			return EINVAL;
303	}
304
305	IPFW_WLOCK(chain);
306	rule = chain->rules;	/* common starting point */
307	chain->reap = NULL;	/* prepare for deletions */
308	switch (cmd) {
309	case 0:	/* delete rules with given number */
310		/*
311		 * locate first rule to delete
312		 */
313		for (; rule->rulenum < rulenum; prev = rule, rule = rule->next)
314			;
315		if (rule->rulenum != rulenum) {
316			IPFW_WUNLOCK(chain);
317			return EINVAL;
318		}
319
320		/*
321		 * flush pointers outside the loop, then delete all matching
322		 * rules. prev remains the same throughout the cycle.
323		 */
324		flush_rule_ptrs(chain);
325		while (rule->rulenum == rulenum)
326			rule = remove_rule(chain, rule, prev);
327		break;
328
329	case 1:	/* delete all rules with given set number */
330		flush_rule_ptrs(chain);
331		while (rule->rulenum < IPFW_DEFAULT_RULE) {
332			if (rule->set == rulenum)
333				rule = remove_rule(chain, rule, prev);
334			else {
335				prev = rule;
336				rule = rule->next;
337			}
338		}
339		break;
340
341	case 2:	/* move rules with given number to new set */
342		for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next)
343			if (rule->rulenum == rulenum)
344				rule->set = new_set;
345		break;
346
347	case 3: /* move rules with given set number to new set */
348		for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next)
349			if (rule->set == rulenum)
350				rule->set = new_set;
351		break;
352
353	case 4: /* swap two sets */
354		for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next)
355			if (rule->set == rulenum)
356				rule->set = new_set;
357			else if (rule->set == new_set)
358				rule->set = rulenum;
359		break;
360
361	case 5: /* delete rules with given number and with given set number.
362		 * rulenum - given rule number;
363		 * new_set - given set number.
364		 */
365		for (; rule->rulenum < rulenum; prev = rule, rule = rule->next)
366			;
367		if (rule->rulenum != rulenum) {
368			IPFW_WUNLOCK(chain);
369			return (EINVAL);
370		}
371		flush_rule_ptrs(chain);
372		while (rule->rulenum == rulenum) {
373			if (rule->set == new_set)
374				rule = remove_rule(chain, rule, prev);
375			else {
376				prev = rule;
377				rule = rule->next;
378			}
379		}
380	}
381	/*
382	 * Look for rules to reclaim.  We grab the list before
383	 * releasing the lock then reclaim them w/o the lock to
384	 * avoid a LOR with dummynet.
385	 */
386	rule = chain->reap;
387	IPFW_WUNLOCK(chain);
388	ipfw_reap_rules(rule);
389	return 0;
390}
391
392/*
393 * Clear counters for a specific rule.
394 * The enclosing "table" is assumed locked.
395 */
396static void
397clear_counters(struct ip_fw *rule, int log_only)
398{
399	ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule);
400
401	if (log_only == 0) {
402		rule->bcnt = rule->pcnt = 0;
403		rule->timestamp = 0;
404	}
405	if (l->o.opcode == O_LOG)
406		l->log_left = l->max_log;
407}
408
409/**
410 * Reset some or all counters on firewall rules.
411 * The argument `arg' is an u_int32_t. The low 16 bit are the rule number,
412 * the next 8 bits are the set number, the top 8 bits are the command:
413 *	0	work with rules from all set's;
414 *	1	work with rules only from specified set.
415 * Specified rule number is zero if we want to clear all entries.
416 * log_only is 1 if we only want to reset logs, zero otherwise.
417 */
418static int
419zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only)
420{
421	struct ip_fw *rule;
422	char *msg;
423
424	uint16_t rulenum = arg & 0xffff;
425	uint8_t set = (arg >> 16) & 0xff;
426	uint8_t cmd = (arg >> 24) & 0xff;
427
428	if (cmd > 1)
429		return (EINVAL);
430	if (cmd == 1 && set > RESVD_SET)
431		return (EINVAL);
432
433	IPFW_WLOCK(chain);
434	if (rulenum == 0) {
435		V_norule_counter = 0;
436		for (rule = chain->rules; rule; rule = rule->next) {
437			/* Skip rules from another set. */
438			if (cmd == 1 && rule->set != set)
439				continue;
440			clear_counters(rule, log_only);
441		}
442		msg = log_only ? "All logging counts reset" :
443		    "Accounting cleared";
444	} else {
445		int cleared = 0;
446		/*
447		 * We can have multiple rules with the same number, so we
448		 * need to clear them all.
449		 */
450		for (rule = chain->rules; rule; rule = rule->next)
451			if (rule->rulenum == rulenum) {
452				while (rule && rule->rulenum == rulenum) {
453					if (cmd == 0 || rule->set == set)
454						clear_counters(rule, log_only);
455					rule = rule->next;
456				}
457				cleared = 1;
458				break;
459			}
460		if (!cleared) {	/* we did not find any matching rules */
461			IPFW_WUNLOCK(chain);
462			return (EINVAL);
463		}
464		msg = log_only ? "logging count reset" : "cleared";
465	}
466	IPFW_WUNLOCK(chain);
467
468	if (V_fw_verbose) {
469		int lev = LOG_SECURITY | LOG_NOTICE;
470
471		if (rulenum)
472			log(lev, "ipfw: Entry %d %s.\n", rulenum, msg);
473		else
474			log(lev, "ipfw: %s.\n", msg);
475	}
476	return (0);
477}
478
479/*
480 * Check validity of the structure before insert.
481 * Rules are simple, so this mostly need to check rule sizes.
482 */
483static int
484check_ipfw_struct(struct ip_fw *rule, int size)
485{
486	int l, cmdlen = 0;
487	int have_action=0;
488	ipfw_insn *cmd;
489
490	if (size < sizeof(*rule)) {
491		printf("ipfw: rule too short\n");
492		return (EINVAL);
493	}
494	/* first, check for valid size */
495	l = RULESIZE(rule);
496	if (l != size) {
497		printf("ipfw: size mismatch (have %d want %d)\n", size, l);
498		return (EINVAL);
499	}
500	if (rule->act_ofs >= rule->cmd_len) {
501		printf("ipfw: bogus action offset (%u > %u)\n",
502		    rule->act_ofs, rule->cmd_len - 1);
503		return (EINVAL);
504	}
505	/*
506	 * Now go for the individual checks. Very simple ones, basically only
507	 * instruction sizes.
508	 */
509	for (l = rule->cmd_len, cmd = rule->cmd ;
510			l > 0 ; l -= cmdlen, cmd += cmdlen) {
511		cmdlen = F_LEN(cmd);
512		if (cmdlen > l) {
513			printf("ipfw: opcode %d size truncated\n",
514			    cmd->opcode);
515			return EINVAL;
516		}
517		DEB(printf("ipfw: opcode %d\n", cmd->opcode);)
518		switch (cmd->opcode) {
519		case O_PROBE_STATE:
520		case O_KEEP_STATE:
521		case O_PROTO:
522		case O_IP_SRC_ME:
523		case O_IP_DST_ME:
524		case O_LAYER2:
525		case O_IN:
526		case O_FRAG:
527		case O_DIVERTED:
528		case O_IPOPT:
529		case O_IPTOS:
530		case O_IPPRECEDENCE:
531		case O_IPVER:
532		case O_TCPWIN:
533		case O_TCPFLAGS:
534		case O_TCPOPTS:
535		case O_ESTAB:
536		case O_VERREVPATH:
537		case O_VERSRCREACH:
538		case O_ANTISPOOF:
539		case O_IPSEC:
540#ifdef INET6
541		case O_IP6_SRC_ME:
542		case O_IP6_DST_ME:
543		case O_EXT_HDR:
544		case O_IP6:
545#endif
546		case O_IP4:
547		case O_TAG:
548			if (cmdlen != F_INSN_SIZE(ipfw_insn))
549				goto bad_size;
550			break;
551
552		case O_FIB:
553			if (cmdlen != F_INSN_SIZE(ipfw_insn))
554				goto bad_size;
555			if (cmd->arg1 >= rt_numfibs) {
556				printf("ipfw: invalid fib number %d\n",
557					cmd->arg1);
558				return EINVAL;
559			}
560			break;
561
562		case O_SETFIB:
563			if (cmdlen != F_INSN_SIZE(ipfw_insn))
564				goto bad_size;
565			if (cmd->arg1 >= rt_numfibs) {
566				printf("ipfw: invalid fib number %d\n",
567					cmd->arg1);
568				return EINVAL;
569			}
570			goto check_action;
571
572		case O_UID:
573		case O_GID:
574		case O_JAIL:
575		case O_IP_SRC:
576		case O_IP_DST:
577		case O_TCPSEQ:
578		case O_TCPACK:
579		case O_PROB:
580		case O_ICMPTYPE:
581			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32))
582				goto bad_size;
583			break;
584
585		case O_LIMIT:
586			if (cmdlen != F_INSN_SIZE(ipfw_insn_limit))
587				goto bad_size;
588			break;
589
590		case O_LOG:
591			if (cmdlen != F_INSN_SIZE(ipfw_insn_log))
592				goto bad_size;
593
594			((ipfw_insn_log *)cmd)->log_left =
595			    ((ipfw_insn_log *)cmd)->max_log;
596
597			break;
598
599		case O_IP_SRC_MASK:
600		case O_IP_DST_MASK:
601			/* only odd command lengths */
602			if ( !(cmdlen & 1) || cmdlen > 31)
603				goto bad_size;
604			break;
605
606		case O_IP_SRC_SET:
607		case O_IP_DST_SET:
608			if (cmd->arg1 == 0 || cmd->arg1 > 256) {
609				printf("ipfw: invalid set size %d\n",
610					cmd->arg1);
611				return EINVAL;
612			}
613			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
614			    (cmd->arg1+31)/32 )
615				goto bad_size;
616			break;
617
618		case O_IP_SRC_LOOKUP:
619		case O_IP_DST_LOOKUP:
620			if (cmd->arg1 >= IPFW_TABLES_MAX) {
621				printf("ipfw: invalid table number %d\n",
622				    cmd->arg1);
623				return (EINVAL);
624			}
625			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
626			    cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
627			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
628				goto bad_size;
629			break;
630
631		case O_MACADDR2:
632			if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
633				goto bad_size;
634			break;
635
636		case O_NOP:
637		case O_IPID:
638		case O_IPTTL:
639		case O_IPLEN:
640		case O_TCPDATALEN:
641		case O_TAGGED:
642			if (cmdlen < 1 || cmdlen > 31)
643				goto bad_size;
644			break;
645
646		case O_MAC_TYPE:
647		case O_IP_SRCPORT:
648		case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
649			if (cmdlen < 2 || cmdlen > 31)
650				goto bad_size;
651			break;
652
653		case O_RECV:
654		case O_XMIT:
655		case O_VIA:
656			if (cmdlen != F_INSN_SIZE(ipfw_insn_if))
657				goto bad_size;
658			break;
659
660		case O_ALTQ:
661			if (cmdlen != F_INSN_SIZE(ipfw_insn_altq))
662				goto bad_size;
663			break;
664
665		case O_PIPE:
666		case O_QUEUE:
667			if (cmdlen != F_INSN_SIZE(ipfw_insn))
668				goto bad_size;
669			goto check_action;
670
671		case O_FORWARD_IP:
672#ifdef	IPFIREWALL_FORWARD
673			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa))
674				goto bad_size;
675			goto check_action;
676#else
677			return EINVAL;
678#endif
679
680		case O_DIVERT:
681		case O_TEE:
682			if (ip_divert_ptr == NULL)
683				return EINVAL;
684			else
685				goto check_size;
686		case O_NETGRAPH:
687		case O_NGTEE:
688			if (!NG_IPFW_LOADED)
689				return EINVAL;
690			else
691				goto check_size;
692		case O_NAT:
693			if (!IPFW_NAT_LOADED)
694				return EINVAL;
695			if (cmdlen != F_INSN_SIZE(ipfw_insn_nat))
696 				goto bad_size;
697 			goto check_action;
698		case O_FORWARD_MAC: /* XXX not implemented yet */
699		case O_CHECK_STATE:
700		case O_COUNT:
701		case O_ACCEPT:
702		case O_DENY:
703		case O_REJECT:
704#ifdef INET6
705		case O_UNREACH6:
706#endif
707		case O_SKIPTO:
708		case O_REASS:
709check_size:
710			if (cmdlen != F_INSN_SIZE(ipfw_insn))
711				goto bad_size;
712check_action:
713			if (have_action) {
714				printf("ipfw: opcode %d, multiple actions"
715					" not allowed\n",
716					cmd->opcode);
717				return EINVAL;
718			}
719			have_action = 1;
720			if (l != cmdlen) {
721				printf("ipfw: opcode %d, action must be"
722					" last opcode\n",
723					cmd->opcode);
724				return EINVAL;
725			}
726			break;
727#ifdef INET6
728		case O_IP6_SRC:
729		case O_IP6_DST:
730			if (cmdlen != F_INSN_SIZE(struct in6_addr) +
731			    F_INSN_SIZE(ipfw_insn))
732				goto bad_size;
733			break;
734
735		case O_FLOW6ID:
736			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
737			    ((ipfw_insn_u32 *)cmd)->o.arg1)
738				goto bad_size;
739			break;
740
741		case O_IP6_SRC_MASK:
742		case O_IP6_DST_MASK:
743			if ( !(cmdlen & 1) || cmdlen > 127)
744				goto bad_size;
745			break;
746		case O_ICMP6TYPE:
747			if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
748				goto bad_size;
749			break;
750#endif
751
752		default:
753			switch (cmd->opcode) {
754#ifndef INET6
755			case O_IP6_SRC_ME:
756			case O_IP6_DST_ME:
757			case O_EXT_HDR:
758			case O_IP6:
759			case O_UNREACH6:
760			case O_IP6_SRC:
761			case O_IP6_DST:
762			case O_FLOW6ID:
763			case O_IP6_SRC_MASK:
764			case O_IP6_DST_MASK:
765			case O_ICMP6TYPE:
766				printf("ipfw: no IPv6 support in kernel\n");
767				return EPROTONOSUPPORT;
768#endif
769			default:
770				printf("ipfw: opcode %d, unknown opcode\n",
771					cmd->opcode);
772				return EINVAL;
773			}
774		}
775	}
776	if (have_action == 0) {
777		printf("ipfw: missing action\n");
778		return EINVAL;
779	}
780	return 0;
781
782bad_size:
783	printf("ipfw: opcode %d size %d wrong\n",
784		cmd->opcode, cmdlen);
785	return EINVAL;
786}
787
788/*
789 * Copy the static and dynamic rules to the supplied buffer
790 * and return the amount of space actually used.
791 */
792static size_t
793ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
794{
795	char *bp = buf;
796	char *ep = bp + space;
797	struct ip_fw *rule;
798	int i;
799	time_t	boot_seconds;
800
801        boot_seconds = boottime.tv_sec;
802	/* XXX this can take a long time and locking will block packet flow */
803	IPFW_RLOCK(chain);
804	for (rule = chain->rules; rule ; rule = rule->next) {
805		/*
806		 * Verify the entry fits in the buffer in case the
807		 * rules changed between calculating buffer space and
808		 * now.  This would be better done using a generation
809		 * number but should suffice for now.
810		 */
811		i = RULESIZE(rule);
812		if (bp + i <= ep) {
813			bcopy(rule, bp, i);
814			/*
815			 * XXX HACK. Store the disable mask in the "next"
816			 * pointer in a wild attempt to keep the ABI the same.
817			 * Why do we do this on EVERY rule?
818			 */
819			bcopy(&V_set_disable,
820			    &(((struct ip_fw *)bp)->next_rule),
821			    sizeof(V_set_disable));
822			if (((struct ip_fw *)bp)->timestamp)
823				((struct ip_fw *)bp)->timestamp += boot_seconds;
824			bp += i;
825		}
826	}
827	IPFW_RUNLOCK(chain);
828	ipfw_get_dynamic(&bp, ep); /* protected by the dynamic lock */
829	return (bp - (char *)buf);
830}
831
832
833/**
834 * {set|get}sockopt parser.
835 */
836int
837ipfw_ctl(struct sockopt *sopt)
838{
839#define	RULE_MAXSIZE	(256*sizeof(u_int32_t))
840	int error;
841	size_t size;
842	struct ip_fw *buf, *rule;
843	u_int32_t rulenum[2];
844
845	error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
846	if (error)
847		return (error);
848
849	/*
850	 * Disallow modifications in really-really secure mode, but still allow
851	 * the logging counters to be reset.
852	 */
853	if (sopt->sopt_name == IP_FW_ADD ||
854	    (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) {
855		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
856		if (error)
857			return (error);
858	}
859
860	error = 0;
861
862	switch (sopt->sopt_name) {
863	case IP_FW_GET:
864		/*
865		 * pass up a copy of the current rules. Static rules
866		 * come first (the last of which has number IPFW_DEFAULT_RULE),
867		 * followed by a possibly empty list of dynamic rule.
868		 * The last dynamic rule has NULL in the "next" field.
869		 *
870		 * Note that the calculated size is used to bound the
871		 * amount of data returned to the user.  The rule set may
872		 * change between calculating the size and returning the
873		 * data in which case we'll just return what fits.
874		 */
875		size = V_static_len;	/* size of static rules */
876		size += ipfw_dyn_len();
877
878		if (size >= sopt->sopt_valsize)
879			break;
880		/*
881		 * XXX todo: if the user passes a short length just to know
882		 * how much room is needed, do not bother filling up the
883		 * buffer, just jump to the sooptcopyout.
884		 */
885		buf = malloc(size, M_TEMP, M_WAITOK);
886		error = sooptcopyout(sopt, buf,
887				ipfw_getrules(&V_layer3_chain, buf, size));
888		free(buf, M_TEMP);
889		break;
890
891	case IP_FW_FLUSH:
892		/*
893		 * Normally we cannot release the lock on each iteration.
894		 * We could do it here only because we start from the head all
895		 * the times so there is no risk of missing some entries.
896		 * On the other hand, the risk is that we end up with
897		 * a very inconsistent ruleset, so better keep the lock
898		 * around the whole cycle.
899		 *
900		 * XXX this code can be improved by resetting the head of
901		 * the list to point to the default rule, and then freeing
902		 * the old list without the need for a lock.
903		 */
904
905		IPFW_WLOCK(&V_layer3_chain);
906		ipfw_free_chain(&V_layer3_chain, 0 /* keep default rule */);
907		rule = V_layer3_chain.reap;
908		IPFW_WUNLOCK(&V_layer3_chain);
909		ipfw_reap_rules(rule);
910		break;
911
912	case IP_FW_ADD:
913		rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);
914		error = sooptcopyin(sopt, rule, RULE_MAXSIZE,
915			sizeof(struct ip_fw) );
916		if (error == 0)
917			error = check_ipfw_struct(rule, sopt->sopt_valsize);
918		if (error == 0) {
919			error = ipfw_add_rule(&V_layer3_chain, rule);
920			size = RULESIZE(rule);
921			if (!error && sopt->sopt_dir == SOPT_GET)
922				error = sooptcopyout(sopt, rule, size);
923		}
924		free(rule, M_TEMP);
925		break;
926
927	case IP_FW_DEL:
928		/*
929		 * IP_FW_DEL is used for deleting single rules or sets,
930		 * and (ab)used to atomically manipulate sets. Argument size
931		 * is used to distinguish between the two:
932		 *    sizeof(u_int32_t)
933		 *	delete single rule or set of rules,
934		 *	or reassign rules (or sets) to a different set.
935		 *    2*sizeof(u_int32_t)
936		 *	atomic disable/enable sets.
937		 *	first u_int32_t contains sets to be disabled,
938		 *	second u_int32_t contains sets to be enabled.
939		 */
940		error = sooptcopyin(sopt, rulenum,
941			2*sizeof(u_int32_t), sizeof(u_int32_t));
942		if (error)
943			break;
944		size = sopt->sopt_valsize;
945		if (size == sizeof(u_int32_t))	/* delete or reassign */
946			error = del_entry(&V_layer3_chain, rulenum[0]);
947		else if (size == 2*sizeof(u_int32_t)) /* set enable/disable */
948			V_set_disable =
949			    (V_set_disable | rulenum[0]) & ~rulenum[1] &
950			    ~(1<<RESVD_SET); /* set RESVD_SET always enabled */
951		else
952			error = EINVAL;
953		break;
954
955	case IP_FW_ZERO:
956	case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */
957		rulenum[0] = 0;
958		if (sopt->sopt_val != 0) {
959		    error = sooptcopyin(sopt, rulenum,
960			    sizeof(u_int32_t), sizeof(u_int32_t));
961		    if (error)
962			break;
963		}
964		error = zero_entry(&V_layer3_chain, rulenum[0],
965			sopt->sopt_name == IP_FW_RESETLOG);
966		break;
967
968	case IP_FW_TABLE_ADD:
969		{
970			ipfw_table_entry ent;
971
972			error = sooptcopyin(sopt, &ent,
973			    sizeof(ent), sizeof(ent));
974			if (error)
975				break;
976			error = ipfw_add_table_entry(&V_layer3_chain, ent.tbl,
977			    ent.addr, ent.masklen, ent.value);
978		}
979		break;
980
981	case IP_FW_TABLE_DEL:
982		{
983			ipfw_table_entry ent;
984
985			error = sooptcopyin(sopt, &ent,
986			    sizeof(ent), sizeof(ent));
987			if (error)
988				break;
989			error = ipfw_del_table_entry(&V_layer3_chain, ent.tbl,
990			    ent.addr, ent.masklen);
991		}
992		break;
993
994	case IP_FW_TABLE_FLUSH:
995		{
996			u_int16_t tbl;
997
998			error = sooptcopyin(sopt, &tbl,
999			    sizeof(tbl), sizeof(tbl));
1000			if (error)
1001				break;
1002			IPFW_WLOCK(&V_layer3_chain);
1003			error = ipfw_flush_table(&V_layer3_chain, tbl);
1004			IPFW_WUNLOCK(&V_layer3_chain);
1005		}
1006		break;
1007
1008	case IP_FW_TABLE_GETSIZE:
1009		{
1010			u_int32_t tbl, cnt;
1011
1012			if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
1013			    sizeof(tbl))))
1014				break;
1015			IPFW_RLOCK(&V_layer3_chain);
1016			error = ipfw_count_table(&V_layer3_chain, tbl, &cnt);
1017			IPFW_RUNLOCK(&V_layer3_chain);
1018			if (error)
1019				break;
1020			error = sooptcopyout(sopt, &cnt, sizeof(cnt));
1021		}
1022		break;
1023
1024	case IP_FW_TABLE_LIST:
1025		{
1026			ipfw_table *tbl;
1027
1028			if (sopt->sopt_valsize < sizeof(*tbl)) {
1029				error = EINVAL;
1030				break;
1031			}
1032			size = sopt->sopt_valsize;
1033			tbl = malloc(size, M_TEMP, M_WAITOK);
1034			error = sooptcopyin(sopt, tbl, size, sizeof(*tbl));
1035			if (error) {
1036				free(tbl, M_TEMP);
1037				break;
1038			}
1039			tbl->size = (size - sizeof(*tbl)) /
1040			    sizeof(ipfw_table_entry);
1041			IPFW_RLOCK(&V_layer3_chain);
1042			error = ipfw_dump_table(&V_layer3_chain, tbl);
1043			IPFW_RUNLOCK(&V_layer3_chain);
1044			if (error) {
1045				free(tbl, M_TEMP);
1046				break;
1047			}
1048			error = sooptcopyout(sopt, tbl, size);
1049			free(tbl, M_TEMP);
1050		}
1051		break;
1052
1053	case IP_FW_NAT_CFG:
1054		if (IPFW_NAT_LOADED)
1055			error = ipfw_nat_cfg_ptr(sopt);
1056		else {
1057			printf("IP_FW_NAT_CFG: %s\n",
1058			    "ipfw_nat not present, please load it");
1059			error = EINVAL;
1060		}
1061		break;
1062
1063	case IP_FW_NAT_DEL:
1064		if (IPFW_NAT_LOADED)
1065			error = ipfw_nat_del_ptr(sopt);
1066		else {
1067			printf("IP_FW_NAT_DEL: %s\n",
1068			    "ipfw_nat not present, please load it");
1069			error = EINVAL;
1070		}
1071		break;
1072
1073	case IP_FW_NAT_GET_CONFIG:
1074		if (IPFW_NAT_LOADED)
1075			error = ipfw_nat_get_cfg_ptr(sopt);
1076		else {
1077			printf("IP_FW_NAT_GET_CFG: %s\n",
1078			    "ipfw_nat not present, please load it");
1079			error = EINVAL;
1080		}
1081		break;
1082
1083	case IP_FW_NAT_GET_LOG:
1084		if (IPFW_NAT_LOADED)
1085			error = ipfw_nat_get_log_ptr(sopt);
1086		else {
1087			printf("IP_FW_NAT_GET_LOG: %s\n",
1088			    "ipfw_nat not present, please load it");
1089			error = EINVAL;
1090		}
1091		break;
1092
1093	default:
1094		printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);
1095		error = EINVAL;
1096	}
1097
1098	return (error);
1099#undef RULE_MAXSIZE
1100}
1101/* end of file */
1102