xref: /freebsd-11-stable/sys/netpfil/ipfw/ip_fw_sockopt.c (revision df69b3666ccf5e9f019ae0de8c93c2849b5b8225)
1 /*-
2  * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa
3  * Copyright (c) 2014 Yandex LLC
4  * Copyright (c) 2014 Alexander V. Chernikov
5  *
6  * Supported by: Valeria Paoli
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 /*
34  * Control socket and rule management routines for ipfw.
35  * Control is currently implemented via IP_FW3 setsockopt() code.
36  */
37 
38 #include "opt_ipfw.h"
39 #include "opt_inet.h"
40 #ifndef INET
41 #error IPFIREWALL requires INET.
42 #endif /* INET */
43 #include "opt_inet6.h"
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/malloc.h>
48 #include <sys/mbuf.h>	/* struct m_tag used by nested headers */
49 #include <sys/kernel.h>
50 #include <sys/lock.h>
51 #include <sys/priv.h>
52 #include <sys/proc.h>
53 #include <sys/rwlock.h>
54 #include <sys/rmlock.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
57 #include <sys/sysctl.h>
58 #include <sys/syslog.h>
59 #include <sys/fnv_hash.h>
60 #include <net/if.h>
61 #include <net/pfil.h>
62 #include <net/route.h>
63 #include <net/vnet.h>
64 #include <vm/vm.h>
65 #include <vm/vm_extern.h>
66 
67 #include <netinet/in.h>
68 #include <netinet/ip_var.h> /* hooks */
69 #include <netinet/ip_fw.h>
70 
71 #include <netpfil/ipfw/ip_fw_private.h>
72 #include <netpfil/ipfw/ip_fw_table.h>
73 
74 #ifdef MAC
75 #include <security/mac/mac_framework.h>
76 #endif
77 
78 static int ipfw_ctl(struct sockopt *sopt);
79 static int check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len,
80     struct rule_check_info *ci);
81 static int check_ipfw_rule1(struct ip_fw_rule *rule, int size,
82     struct rule_check_info *ci);
83 static int check_ipfw_rule0(struct ip_fw_rule0 *rule, int size,
84     struct rule_check_info *ci);
85 static int rewrite_rule_uidx(struct ip_fw_chain *chain,
86     struct rule_check_info *ci);
87 
88 #define	NAMEDOBJ_HASH_SIZE	32
89 
90 struct namedobj_instance {
91 	struct namedobjects_head	*names;
92 	struct namedobjects_head	*values;
93 	uint32_t nn_size;		/* names hash size */
94 	uint32_t nv_size;		/* number hash size */
95 	u_long *idx_mask;		/* used items bitmask */
96 	uint32_t max_blocks;		/* number of "long" blocks in bitmask */
97 	uint32_t count;			/* number of items */
98 	uint16_t free_off[IPFW_MAX_SETS];	/* first possible free offset */
99 	objhash_hash_f	*hash_f;
100 	objhash_cmp_f	*cmp_f;
101 };
102 #define	BLOCK_ITEMS	(8 * sizeof(u_long))	/* Number of items for ffsl() */
103 
104 static uint32_t objhash_hash_name(struct namedobj_instance *ni,
105     const void *key, uint32_t kopt);
106 static uint32_t objhash_hash_idx(struct namedobj_instance *ni, uint32_t val);
107 static int objhash_cmp_name(struct named_object *no, const void *name,
108     uint32_t set);
109 
110 MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's");
111 
112 static int dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
113     struct sockopt_data *sd);
114 static int add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
115     struct sockopt_data *sd);
116 static int del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
117     struct sockopt_data *sd);
118 static int clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
119     struct sockopt_data *sd);
120 static int move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
121     struct sockopt_data *sd);
122 static int manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
123     struct sockopt_data *sd);
124 static int dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
125     struct sockopt_data *sd);
126 static int dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
127     struct sockopt_data *sd);
128 
129 /* ctl3 handler data */
130 struct mtx ctl3_lock;
131 #define	CTL3_LOCK_INIT()	mtx_init(&ctl3_lock, "ctl3_lock", NULL, MTX_DEF)
132 #define	CTL3_LOCK_DESTROY()	mtx_destroy(&ctl3_lock)
133 #define	CTL3_LOCK()		mtx_lock(&ctl3_lock)
134 #define	CTL3_UNLOCK()		mtx_unlock(&ctl3_lock)
135 
136 static struct ipfw_sopt_handler *ctl3_handlers;
137 static size_t ctl3_hsize;
138 static uint64_t ctl3_refct, ctl3_gencnt;
139 #define	CTL3_SMALLBUF	4096			/* small page-size write buffer */
140 #define	CTL3_LARGEBUF	16 * 1024 * 1024	/* handle large rulesets */
141 
142 static int ipfw_flush_sopt_data(struct sockopt_data *sd);
143 
144 static struct ipfw_sopt_handler	scodes[] = {
145 	{ IP_FW_XGET,		0,	HDIR_GET,	dump_config },
146 	{ IP_FW_XADD,		0,	HDIR_BOTH,	add_rules },
147 	{ IP_FW_XDEL,		0,	HDIR_BOTH,	del_rules },
148 	{ IP_FW_XZERO,		0,	HDIR_SET,	clear_rules },
149 	{ IP_FW_XRESETLOG,	0,	HDIR_SET,	clear_rules },
150 	{ IP_FW_XMOVE,		0,	HDIR_SET,	move_rules },
151 	{ IP_FW_SET_SWAP,	0,	HDIR_SET,	manage_sets },
152 	{ IP_FW_SET_MOVE,	0,	HDIR_SET,	manage_sets },
153 	{ IP_FW_SET_ENABLE,	0,	HDIR_SET,	manage_sets },
154 	{ IP_FW_DUMP_SOPTCODES,	0,	HDIR_GET,	dump_soptcodes },
155 	{ IP_FW_DUMP_SRVOBJECTS,0,	HDIR_GET,	dump_srvobjects },
156 };
157 
158 static int
159 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule);
160 static struct opcode_obj_rewrite *find_op_rw(ipfw_insn *cmd,
161     uint16_t *puidx, uint8_t *ptype);
162 static int ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
163     struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti);
164 static int ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd,
165     struct tid_info *ti, struct obj_idx *pidx, int *unresolved);
166 static void unref_rule_objects(struct ip_fw_chain *chain, struct ip_fw *rule);
167 static void unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd,
168     struct obj_idx *oib, struct obj_idx *end);
169 static int export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
170     struct sockopt_data *sd);
171 
172 /*
173  * Opcode object rewriter variables
174  */
175 struct opcode_obj_rewrite *ctl3_rewriters;
176 static size_t ctl3_rsize;
177 
178 /*
179  * static variables followed by global ones
180  */
181 
182 static VNET_DEFINE(uma_zone_t, ipfw_cntr_zone);
183 #define	V_ipfw_cntr_zone		VNET(ipfw_cntr_zone)
184 
185 void
ipfw_init_counters()186 ipfw_init_counters()
187 {
188 
189 	V_ipfw_cntr_zone = uma_zcreate("IPFW counters",
190 	    IPFW_RULE_CNTR_SIZE, NULL, NULL, NULL, NULL,
191 	    UMA_ALIGN_PTR, UMA_ZONE_PCPU);
192 }
193 
194 void
ipfw_destroy_counters()195 ipfw_destroy_counters()
196 {
197 
198 	uma_zdestroy(V_ipfw_cntr_zone);
199 }
200 
201 struct ip_fw *
ipfw_alloc_rule(struct ip_fw_chain * chain,size_t rulesize)202 ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize)
203 {
204 	struct ip_fw *rule;
205 
206 	rule = malloc(rulesize, M_IPFW, M_WAITOK | M_ZERO);
207 	rule->cntr = uma_zalloc(V_ipfw_cntr_zone, M_WAITOK | M_ZERO);
208 	rule->refcnt = 1;
209 
210 	return (rule);
211 }
212 
213 void
ipfw_free_rule(struct ip_fw * rule)214 ipfw_free_rule(struct ip_fw *rule)
215 {
216 
217 	/*
218 	 * We don't release refcnt here, since this function
219 	 * can be called without any locks held. The caller
220 	 * must release reference under IPFW_UH_WLOCK, and then
221 	 * call this function if refcount becomes 1.
222 	 */
223 	if (rule->refcnt > 1)
224 		return;
225 	uma_zfree(V_ipfw_cntr_zone, rule->cntr);
226 	free(rule, M_IPFW);
227 }
228 
229 
230 /*
231  * Find the smallest rule >= key, id.
232  * We could use bsearch but it is so simple that we code it directly
233  */
234 int
ipfw_find_rule(struct ip_fw_chain * chain,uint32_t key,uint32_t id)235 ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id)
236 {
237 	int i, lo, hi;
238 	struct ip_fw *r;
239 
240   	for (lo = 0, hi = chain->n_rules - 1; lo < hi;) {
241 		i = (lo + hi) / 2;
242 		r = chain->map[i];
243 		if (r->rulenum < key)
244 			lo = i + 1;	/* continue from the next one */
245 		else if (r->rulenum > key)
246 			hi = i;		/* this might be good */
247 		else if (r->id < id)
248 			lo = i + 1;	/* continue from the next one */
249 		else /* r->id >= id */
250 			hi = i;		/* this might be good */
251 	}
252 	return hi;
253 }
254 
255 /*
256  * Builds skipto cache on rule set @map.
257  */
258 static void
update_skipto_cache(struct ip_fw_chain * chain,struct ip_fw ** map)259 update_skipto_cache(struct ip_fw_chain *chain, struct ip_fw **map)
260 {
261 	int *smap, rulenum;
262 	int i, mi;
263 
264 	IPFW_UH_WLOCK_ASSERT(chain);
265 
266 	mi = 0;
267 	rulenum = map[mi]->rulenum;
268 	smap = chain->idxmap_back;
269 
270 	if (smap == NULL)
271 		return;
272 
273 	for (i = 0; i < 65536; i++) {
274 		smap[i] = mi;
275 		/* Use the same rule index until i < rulenum */
276 		if (i != rulenum || i == 65535)
277 			continue;
278 		/* Find next rule with num > i */
279 		rulenum = map[++mi]->rulenum;
280 		while (rulenum == i)
281 			rulenum = map[++mi]->rulenum;
282 	}
283 }
284 
285 /*
286  * Swaps prepared (backup) index with current one.
287  */
288 static void
swap_skipto_cache(struct ip_fw_chain * chain)289 swap_skipto_cache(struct ip_fw_chain *chain)
290 {
291 	int *map;
292 
293 	IPFW_UH_WLOCK_ASSERT(chain);
294 	IPFW_WLOCK_ASSERT(chain);
295 
296 	map = chain->idxmap;
297 	chain->idxmap = chain->idxmap_back;
298 	chain->idxmap_back = map;
299 }
300 
301 /*
302  * Allocate and initialize skipto cache.
303  */
304 void
ipfw_init_skipto_cache(struct ip_fw_chain * chain)305 ipfw_init_skipto_cache(struct ip_fw_chain *chain)
306 {
307 	int *idxmap, *idxmap_back;
308 
309 	idxmap = malloc(65536 * sizeof(int), M_IPFW, M_WAITOK | M_ZERO);
310 	idxmap_back = malloc(65536 * sizeof(int), M_IPFW, M_WAITOK);
311 
312 	/*
313 	 * Note we may be called at any time after initialization,
314 	 * for example, on first skipto rule, so we need to
315 	 * provide valid chain->idxmap on return
316 	 */
317 
318 	IPFW_UH_WLOCK(chain);
319 	if (chain->idxmap != NULL) {
320 		IPFW_UH_WUNLOCK(chain);
321 		free(idxmap, M_IPFW);
322 		free(idxmap_back, M_IPFW);
323 		return;
324 	}
325 
326 	/* Set backup pointer first to permit building cache */
327 	chain->idxmap_back = idxmap_back;
328 	update_skipto_cache(chain, chain->map);
329 	IPFW_WLOCK(chain);
330 	/* It is now safe to set chain->idxmap ptr */
331 	chain->idxmap = idxmap;
332 	swap_skipto_cache(chain);
333 	IPFW_WUNLOCK(chain);
334 	IPFW_UH_WUNLOCK(chain);
335 }
336 
337 /*
338  * Destroys skipto cache.
339  */
340 void
ipfw_destroy_skipto_cache(struct ip_fw_chain * chain)341 ipfw_destroy_skipto_cache(struct ip_fw_chain *chain)
342 {
343 
344 	if (chain->idxmap != NULL)
345 		free(chain->idxmap, M_IPFW);
346 	if (chain->idxmap != NULL)
347 		free(chain->idxmap_back, M_IPFW);
348 }
349 
350 
351 /*
352  * allocate a new map, returns the chain locked. extra is the number
353  * of entries to add or delete.
354  */
355 static struct ip_fw **
get_map(struct ip_fw_chain * chain,int extra,int locked)356 get_map(struct ip_fw_chain *chain, int extra, int locked)
357 {
358 
359 	for (;;) {
360 		struct ip_fw **map;
361 		int i, mflags;
362 
363 		mflags = M_ZERO | ((locked != 0) ? M_NOWAIT : M_WAITOK);
364 
365 		i = chain->n_rules + extra;
366 		map = malloc(i * sizeof(struct ip_fw *), M_IPFW, mflags);
367 		if (map == NULL) {
368 			printf("%s: cannot allocate map\n", __FUNCTION__);
369 			return NULL;
370 		}
371 		if (!locked)
372 			IPFW_UH_WLOCK(chain);
373 		if (i >= chain->n_rules + extra) /* good */
374 			return map;
375 		/* otherwise we lost the race, free and retry */
376 		if (!locked)
377 			IPFW_UH_WUNLOCK(chain);
378 		free(map, M_IPFW);
379 	}
380 }
381 
382 /*
383  * swap the maps. It is supposed to be called with IPFW_UH_WLOCK
384  */
385 static struct ip_fw **
swap_map(struct ip_fw_chain * chain,struct ip_fw ** new_map,int new_len)386 swap_map(struct ip_fw_chain *chain, struct ip_fw **new_map, int new_len)
387 {
388 	struct ip_fw **old_map;
389 
390 	IPFW_WLOCK(chain);
391 	chain->id++;
392 	chain->n_rules = new_len;
393 	old_map = chain->map;
394 	chain->map = new_map;
395 	swap_skipto_cache(chain);
396 	IPFW_WUNLOCK(chain);
397 	return old_map;
398 }
399 
400 
401 static void
export_cntr1_base(struct ip_fw * krule,struct ip_fw_bcounter * cntr)402 export_cntr1_base(struct ip_fw *krule, struct ip_fw_bcounter *cntr)
403 {
404 	struct timeval boottime;
405 
406 	cntr->size = sizeof(*cntr);
407 
408 	if (krule->cntr != NULL) {
409 		cntr->pcnt = counter_u64_fetch(krule->cntr);
410 		cntr->bcnt = counter_u64_fetch(krule->cntr + 1);
411 		cntr->timestamp = krule->timestamp;
412 	}
413 	if (cntr->timestamp > 0) {
414 		getboottime(&boottime);
415 		cntr->timestamp += boottime.tv_sec;
416 	}
417 }
418 
419 static void
export_cntr0_base(struct ip_fw * krule,struct ip_fw_bcounter0 * cntr)420 export_cntr0_base(struct ip_fw *krule, struct ip_fw_bcounter0 *cntr)
421 {
422 	struct timeval boottime;
423 
424 	if (krule->cntr != NULL) {
425 		cntr->pcnt = counter_u64_fetch(krule->cntr);
426 		cntr->bcnt = counter_u64_fetch(krule->cntr + 1);
427 		cntr->timestamp = krule->timestamp;
428 	}
429 	if (cntr->timestamp > 0) {
430 		getboottime(&boottime);
431 		cntr->timestamp += boottime.tv_sec;
432 	}
433 }
434 
435 /*
436  * Copies rule @urule from v1 userland format (current).
437  * to kernel @krule.
438  * Assume @krule is zeroed.
439  */
440 static void
import_rule1(struct rule_check_info * ci)441 import_rule1(struct rule_check_info *ci)
442 {
443 	struct ip_fw_rule *urule;
444 	struct ip_fw *krule;
445 
446 	urule = (struct ip_fw_rule *)ci->urule;
447 	krule = (struct ip_fw *)ci->krule;
448 
449 	/* copy header */
450 	krule->act_ofs = urule->act_ofs;
451 	krule->cmd_len = urule->cmd_len;
452 	krule->rulenum = urule->rulenum;
453 	krule->set = urule->set;
454 	krule->flags = urule->flags;
455 
456 	/* Save rulenum offset */
457 	ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum);
458 
459 	/* Copy opcodes */
460 	memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t));
461 }
462 
463 /*
464  * Export rule into v1 format (Current).
465  * Layout:
466  * [ ipfw_obj_tlv(IPFW_TLV_RULE_ENT)
467  *     [ ip_fw_rule ] OR
468  *     [ ip_fw_bcounter ip_fw_rule] (depends on rcntrs).
469  * ]
470  * Assume @data is zeroed.
471  */
472 static void
export_rule1(struct ip_fw * krule,caddr_t data,int len,int rcntrs)473 export_rule1(struct ip_fw *krule, caddr_t data, int len, int rcntrs)
474 {
475 	struct ip_fw_bcounter *cntr;
476 	struct ip_fw_rule *urule;
477 	ipfw_obj_tlv *tlv;
478 
479 	/* Fill in TLV header */
480 	tlv = (ipfw_obj_tlv *)data;
481 	tlv->type = IPFW_TLV_RULE_ENT;
482 	tlv->length = len;
483 
484 	if (rcntrs != 0) {
485 		/* Copy counters */
486 		cntr = (struct ip_fw_bcounter *)(tlv + 1);
487 		urule = (struct ip_fw_rule *)(cntr + 1);
488 		export_cntr1_base(krule, cntr);
489 	} else
490 		urule = (struct ip_fw_rule *)(tlv + 1);
491 
492 	/* copy header */
493 	urule->act_ofs = krule->act_ofs;
494 	urule->cmd_len = krule->cmd_len;
495 	urule->rulenum = krule->rulenum;
496 	urule->set = krule->set;
497 	urule->flags = krule->flags;
498 	urule->id = krule->id;
499 
500 	/* Copy opcodes */
501 	memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t));
502 }
503 
504 
505 /*
506  * Copies rule @urule from FreeBSD8 userland format (v0)
507  * to kernel @krule.
508  * Assume @krule is zeroed.
509  */
510 static void
import_rule0(struct rule_check_info * ci)511 import_rule0(struct rule_check_info *ci)
512 {
513 	struct ip_fw_rule0 *urule;
514 	struct ip_fw *krule;
515 	int cmdlen, l;
516 	ipfw_insn *cmd;
517 	ipfw_insn_limit *lcmd;
518 	ipfw_insn_if *cmdif;
519 
520 	urule = (struct ip_fw_rule0 *)ci->urule;
521 	krule = (struct ip_fw *)ci->krule;
522 
523 	/* copy header */
524 	krule->act_ofs = urule->act_ofs;
525 	krule->cmd_len = urule->cmd_len;
526 	krule->rulenum = urule->rulenum;
527 	krule->set = urule->set;
528 	if ((urule->_pad & 1) != 0)
529 		krule->flags |= IPFW_RULE_NOOPT;
530 
531 	/* Save rulenum offset */
532 	ci->urule_numoff = offsetof(struct ip_fw_rule0, rulenum);
533 
534 	/* Copy opcodes */
535 	memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t));
536 
537 	/*
538 	 * Alter opcodes:
539 	 * 1) convert tablearg value from 65535 to 0
540 	 * 2) Add high bit to O_SETFIB/O_SETDSCP values (to make room
541 	 *    for targ).
542 	 * 3) convert table number in iface opcodes to u16
543 	 * 4) convert old `nat global` into new 65535
544 	 */
545 	l = krule->cmd_len;
546 	cmd = krule->cmd;
547 	cmdlen = 0;
548 
549 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
550 		cmdlen = F_LEN(cmd);
551 
552 		switch (cmd->opcode) {
553 		/* Opcodes supporting tablearg */
554 		case O_TAG:
555 		case O_TAGGED:
556 		case O_PIPE:
557 		case O_QUEUE:
558 		case O_DIVERT:
559 		case O_TEE:
560 		case O_SKIPTO:
561 		case O_CALLRETURN:
562 		case O_NETGRAPH:
563 		case O_NGTEE:
564 		case O_NAT:
565 			if (cmd->arg1 == IP_FW_TABLEARG)
566 				cmd->arg1 = IP_FW_TARG;
567 			else if (cmd->arg1 == 0)
568 				cmd->arg1 = IP_FW_NAT44_GLOBAL;
569 			break;
570 		case O_SETFIB:
571 		case O_SETDSCP:
572 			if (cmd->arg1 == IP_FW_TABLEARG)
573 				cmd->arg1 = IP_FW_TARG;
574 			else
575 				cmd->arg1 |= 0x8000;
576 			break;
577 		case O_LIMIT:
578 			lcmd = (ipfw_insn_limit *)cmd;
579 			if (lcmd->conn_limit == IP_FW_TABLEARG)
580 				lcmd->conn_limit = IP_FW_TARG;
581 			break;
582 		/* Interface tables */
583 		case O_XMIT:
584 		case O_RECV:
585 		case O_VIA:
586 			/* Interface table, possibly */
587 			cmdif = (ipfw_insn_if *)cmd;
588 			if (cmdif->name[0] != '\1')
589 				break;
590 
591 			cmdif->p.kidx = (uint16_t)cmdif->p.glob;
592 			break;
593 		}
594 	}
595 }
596 
597 /*
598  * Copies rule @krule from kernel to FreeBSD8 userland format (v0)
599  */
600 static void
export_rule0(struct ip_fw * krule,struct ip_fw_rule0 * urule,int len)601 export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len)
602 {
603 	int cmdlen, l;
604 	ipfw_insn *cmd;
605 	ipfw_insn_limit *lcmd;
606 	ipfw_insn_if *cmdif;
607 
608 	/* copy header */
609 	memset(urule, 0, len);
610 	urule->act_ofs = krule->act_ofs;
611 	urule->cmd_len = krule->cmd_len;
612 	urule->rulenum = krule->rulenum;
613 	urule->set = krule->set;
614 	if ((krule->flags & IPFW_RULE_NOOPT) != 0)
615 		urule->_pad |= 1;
616 
617 	/* Copy opcodes */
618 	memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t));
619 
620 	/* Export counters */
621 	export_cntr0_base(krule, (struct ip_fw_bcounter0 *)&urule->pcnt);
622 
623 	/*
624 	 * Alter opcodes:
625 	 * 1) convert tablearg value from 0 to 65535
626 	 * 2) Remove highest bit from O_SETFIB/O_SETDSCP values.
627 	 * 3) convert table number in iface opcodes to int
628 	 */
629 	l = urule->cmd_len;
630 	cmd = urule->cmd;
631 	cmdlen = 0;
632 
633 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
634 		cmdlen = F_LEN(cmd);
635 
636 		switch (cmd->opcode) {
637 		/* Opcodes supporting tablearg */
638 		case O_TAG:
639 		case O_TAGGED:
640 		case O_PIPE:
641 		case O_QUEUE:
642 		case O_DIVERT:
643 		case O_TEE:
644 		case O_SKIPTO:
645 		case O_CALLRETURN:
646 		case O_NETGRAPH:
647 		case O_NGTEE:
648 		case O_NAT:
649 			if (cmd->arg1 == IP_FW_TARG)
650 				cmd->arg1 = IP_FW_TABLEARG;
651 			else if (cmd->arg1 == IP_FW_NAT44_GLOBAL)
652 				cmd->arg1 = 0;
653 			break;
654 		case O_SETFIB:
655 		case O_SETDSCP:
656 			if (cmd->arg1 == IP_FW_TARG)
657 				cmd->arg1 = IP_FW_TABLEARG;
658 			else
659 				cmd->arg1 &= ~0x8000;
660 			break;
661 		case O_LIMIT:
662 			lcmd = (ipfw_insn_limit *)cmd;
663 			if (lcmd->conn_limit == IP_FW_TARG)
664 				lcmd->conn_limit = IP_FW_TABLEARG;
665 			break;
666 		/* Interface tables */
667 		case O_XMIT:
668 		case O_RECV:
669 		case O_VIA:
670 			/* Interface table, possibly */
671 			cmdif = (ipfw_insn_if *)cmd;
672 			if (cmdif->name[0] != '\1')
673 				break;
674 
675 			cmdif->p.glob = cmdif->p.kidx;
676 			break;
677 		}
678 	}
679 }
680 
681 /*
682  * Add new rule(s) to the list possibly creating rule number for each.
683  * Update the rule_number in the input struct so the caller knows it as well.
684  * Must be called without IPFW_UH held
685  */
686 static int
commit_rules(struct ip_fw_chain * chain,struct rule_check_info * rci,int count)687 commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count)
688 {
689 	int error, i, insert_before, tcount;
690 	uint16_t rulenum, *pnum;
691 	struct rule_check_info *ci;
692 	struct ip_fw *krule;
693 	struct ip_fw **map;	/* the new array of pointers */
694 
695 	/* Check if we need to do table/obj index remap */
696 	tcount = 0;
697 	for (ci = rci, i = 0; i < count; ci++, i++) {
698 		if (ci->object_opcodes == 0)
699 			continue;
700 
701 		/*
702 		 * Rule has some object opcodes.
703 		 * We need to find (and create non-existing)
704 		 * kernel objects, and reference existing ones.
705 		 */
706 		error = rewrite_rule_uidx(chain, ci);
707 		if (error != 0) {
708 
709 			/*
710 			 * rewrite failed, state for current rule
711 			 * has been reverted. Check if we need to
712 			 * revert more.
713 			 */
714 			if (tcount > 0) {
715 
716 				/*
717 				 * We have some more table rules
718 				 * we need to rollback.
719 				 */
720 
721 				IPFW_UH_WLOCK(chain);
722 				while (ci != rci) {
723 					ci--;
724 					if (ci->object_opcodes == 0)
725 						continue;
726 					unref_rule_objects(chain,ci->krule);
727 
728 				}
729 				IPFW_UH_WUNLOCK(chain);
730 
731 			}
732 
733 			return (error);
734 		}
735 
736 		tcount++;
737 	}
738 
739 	/* get_map returns with IPFW_UH_WLOCK if successful */
740 	map = get_map(chain, count, 0 /* not locked */);
741 	if (map == NULL) {
742 		if (tcount > 0) {
743 			/* Unbind tables */
744 			IPFW_UH_WLOCK(chain);
745 			for (ci = rci, i = 0; i < count; ci++, i++) {
746 				if (ci->object_opcodes == 0)
747 					continue;
748 
749 				unref_rule_objects(chain, ci->krule);
750 			}
751 			IPFW_UH_WUNLOCK(chain);
752 		}
753 
754 		return (ENOSPC);
755 	}
756 
757 	if (V_autoinc_step < 1)
758 		V_autoinc_step = 1;
759 	else if (V_autoinc_step > 1000)
760 		V_autoinc_step = 1000;
761 
762 	/* FIXME: Handle count > 1 */
763 	ci = rci;
764 	krule = ci->krule;
765 	rulenum = krule->rulenum;
766 
767 	/* find the insertion point, we will insert before */
768 	insert_before = rulenum ? rulenum + 1 : IPFW_DEFAULT_RULE;
769 	i = ipfw_find_rule(chain, insert_before, 0);
770 	/* duplicate first part */
771 	if (i > 0)
772 		bcopy(chain->map, map, i * sizeof(struct ip_fw *));
773 	map[i] = krule;
774 	/* duplicate remaining part, we always have the default rule */
775 	bcopy(chain->map + i, map + i + 1,
776 		sizeof(struct ip_fw *) *(chain->n_rules - i));
777 	if (rulenum == 0) {
778 		/* Compute rule number and write it back */
779 		rulenum = i > 0 ? map[i-1]->rulenum : 0;
780 		if (rulenum < IPFW_DEFAULT_RULE - V_autoinc_step)
781 			rulenum += V_autoinc_step;
782 		krule->rulenum = rulenum;
783 		/* Save number to userland rule */
784 		pnum = (uint16_t *)((caddr_t)ci->urule + ci->urule_numoff);
785 		*pnum = rulenum;
786 	}
787 
788 	krule->id = chain->id + 1;
789 	update_skipto_cache(chain, map);
790 	map = swap_map(chain, map, chain->n_rules + 1);
791 	chain->static_len += RULEUSIZE0(krule);
792 	IPFW_UH_WUNLOCK(chain);
793 	if (map)
794 		free(map, M_IPFW);
795 	return (0);
796 }
797 
798 int
ipfw_add_protected_rule(struct ip_fw_chain * chain,struct ip_fw * rule,int locked)799 ipfw_add_protected_rule(struct ip_fw_chain *chain, struct ip_fw *rule,
800     int locked)
801 {
802 	struct ip_fw **map;
803 
804 	map = get_map(chain, 1, locked);
805 	if (map == NULL)
806 		return (ENOMEM);
807 	if (chain->n_rules > 0)
808 		bcopy(chain->map, map,
809 		    chain->n_rules * sizeof(struct ip_fw *));
810 	map[chain->n_rules] = rule;
811 	rule->rulenum = IPFW_DEFAULT_RULE;
812 	rule->set = RESVD_SET;
813 	rule->id = chain->id + 1;
814 	/* We add rule in the end of chain, no need to update skipto cache */
815 	map = swap_map(chain, map, chain->n_rules + 1);
816 	chain->static_len += RULEUSIZE0(rule);
817 	IPFW_UH_WUNLOCK(chain);
818 	free(map, M_IPFW);
819 	return (0);
820 }
821 
822 /*
823  * Adds @rule to the list of rules to reap
824  */
825 void
ipfw_reap_add(struct ip_fw_chain * chain,struct ip_fw ** head,struct ip_fw * rule)826 ipfw_reap_add(struct ip_fw_chain *chain, struct ip_fw **head,
827     struct ip_fw *rule)
828 {
829 
830 	IPFW_UH_WLOCK_ASSERT(chain);
831 
832 	/* Unlink rule from everywhere */
833 	unref_rule_objects(chain, rule);
834 
835 	rule->next = *head;
836 	*head = rule;
837 }
838 
839 /*
840  * Reclaim storage associated with a list of rules.  This is
841  * typically the list created using remove_rule.
842  * A NULL pointer on input is handled correctly.
843  */
844 void
ipfw_reap_rules(struct ip_fw * head)845 ipfw_reap_rules(struct ip_fw *head)
846 {
847 	struct ip_fw *rule;
848 
849 	while ((rule = head) != NULL) {
850 		head = head->next;
851 		ipfw_free_rule(rule);
852 	}
853 }
854 
855 /*
856  * Rules to keep are
857  *	(default || reserved || !match_set || !match_number)
858  * where
859  *   default ::= (rule->rulenum == IPFW_DEFAULT_RULE)
860  *	// the default rule is always protected
861  *
862  *   reserved ::= (cmd == 0 && n == 0 && rule->set == RESVD_SET)
863  *	// RESVD_SET is protected only if cmd == 0 and n == 0 ("ipfw flush")
864  *
865  *   match_set ::= (cmd == 0 || rule->set == set)
866  *	// set number is ignored for cmd == 0
867  *
868  *   match_number ::= (cmd == 1 || n == 0 || n == rule->rulenum)
869  *	// number is ignored for cmd == 1 or n == 0
870  *
871  */
872 int
ipfw_match_range(struct ip_fw * rule,ipfw_range_tlv * rt)873 ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt)
874 {
875 
876 	/* Don't match default rule for modification queries */
877 	if (rule->rulenum == IPFW_DEFAULT_RULE &&
878 	    (rt->flags & IPFW_RCFLAG_DEFAULT) == 0)
879 		return (0);
880 
881 	/* Don't match rules in reserved set for flush requests */
882 	if ((rt->flags & IPFW_RCFLAG_ALL) != 0 && rule->set == RESVD_SET)
883 		return (0);
884 
885 	/* If we're filtering by set, don't match other sets */
886 	if ((rt->flags & IPFW_RCFLAG_SET) != 0 && rule->set != rt->set)
887 		return (0);
888 
889 	if ((rt->flags & IPFW_RCFLAG_RANGE) != 0 &&
890 	    (rule->rulenum < rt->start_rule || rule->rulenum > rt->end_rule))
891 		return (0);
892 
893 	return (1);
894 }
895 
896 struct manage_sets_args {
897 	uint16_t	set;
898 	uint8_t		new_set;
899 };
900 
901 static int
swap_sets_cb(struct namedobj_instance * ni,struct named_object * no,void * arg)902 swap_sets_cb(struct namedobj_instance *ni, struct named_object *no,
903     void *arg)
904 {
905 	struct manage_sets_args *args;
906 
907 	args = (struct manage_sets_args *)arg;
908 	if (no->set == (uint8_t)args->set)
909 		no->set = args->new_set;
910 	else if (no->set == args->new_set)
911 		no->set = (uint8_t)args->set;
912 	return (0);
913 }
914 
915 static int
move_sets_cb(struct namedobj_instance * ni,struct named_object * no,void * arg)916 move_sets_cb(struct namedobj_instance *ni, struct named_object *no,
917     void *arg)
918 {
919 	struct manage_sets_args *args;
920 
921 	args = (struct manage_sets_args *)arg;
922 	if (no->set == (uint8_t)args->set)
923 		no->set = args->new_set;
924 	return (0);
925 }
926 
927 static int
test_sets_cb(struct namedobj_instance * ni,struct named_object * no,void * arg)928 test_sets_cb(struct namedobj_instance *ni, struct named_object *no,
929     void *arg)
930 {
931 	struct manage_sets_args *args;
932 
933 	args = (struct manage_sets_args *)arg;
934 	if (no->set != (uint8_t)args->set)
935 		return (0);
936 	if (ipfw_objhash_lookup_name_type(ni, args->new_set,
937 	    no->etlv, no->name) != NULL)
938 		return (EEXIST);
939 	return (0);
940 }
941 
942 /*
943  * Generic function to handler moving and swapping sets.
944  */
945 int
ipfw_obj_manage_sets(struct namedobj_instance * ni,uint16_t type,uint16_t set,uint8_t new_set,enum ipfw_sets_cmd cmd)946 ipfw_obj_manage_sets(struct namedobj_instance *ni, uint16_t type,
947     uint16_t set, uint8_t new_set, enum ipfw_sets_cmd cmd)
948 {
949 	struct manage_sets_args args;
950 	struct named_object *no;
951 
952 	args.set = set;
953 	args.new_set = new_set;
954 	switch (cmd) {
955 	case SWAP_ALL:
956 		return (ipfw_objhash_foreach_type(ni, swap_sets_cb,
957 		    &args, type));
958 	case TEST_ALL:
959 		return (ipfw_objhash_foreach_type(ni, test_sets_cb,
960 		    &args, type));
961 	case MOVE_ALL:
962 		return (ipfw_objhash_foreach_type(ni, move_sets_cb,
963 		    &args, type));
964 	case COUNT_ONE:
965 		/*
966 		 * @set used to pass kidx.
967 		 * When @new_set is zero - reset object counter,
968 		 * otherwise increment it.
969 		 */
970 		no = ipfw_objhash_lookup_kidx(ni, set);
971 		if (new_set != 0)
972 			no->ocnt++;
973 		else
974 			no->ocnt = 0;
975 		return (0);
976 	case TEST_ONE:
977 		/* @set used to pass kidx */
978 		no = ipfw_objhash_lookup_kidx(ni, set);
979 		/*
980 		 * First check number of references:
981 		 * when it differs, this mean other rules are holding
982 		 * reference to given object, so it is not possible to
983 		 * change its set. Note that refcnt may account references
984 		 * to some going-to-be-added rules. Since we don't know
985 		 * their numbers (and even if they will be added) it is
986 		 * perfectly OK to return error here.
987 		 */
988 		if (no->ocnt != no->refcnt)
989 			return (EBUSY);
990 		if (ipfw_objhash_lookup_name_type(ni, new_set, type,
991 		    no->name) != NULL)
992 			return (EEXIST);
993 		return (0);
994 	case MOVE_ONE:
995 		/* @set used to pass kidx */
996 		no = ipfw_objhash_lookup_kidx(ni, set);
997 		no->set = new_set;
998 		return (0);
999 	}
1000 	return (EINVAL);
1001 }
1002 
1003 /*
1004  * Delete rules matching range @rt.
1005  * Saves number of deleted rules in @ndel.
1006  *
1007  * Returns 0 on success.
1008  */
1009 static int
delete_range(struct ip_fw_chain * chain,ipfw_range_tlv * rt,int * ndel)1010 delete_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int *ndel)
1011 {
1012 	struct ip_fw *reap, *rule, **map;
1013 	int end, start;
1014 	int i, n, ndyn, ofs;
1015 
1016 	reap = NULL;
1017 	IPFW_UH_WLOCK(chain);	/* arbitrate writers */
1018 
1019 	/*
1020 	 * Stage 1: Determine range to inspect.
1021 	 * Range is half-inclusive, e.g [start, end).
1022 	 */
1023 	start = 0;
1024 	end = chain->n_rules - 1;
1025 
1026 	if ((rt->flags & IPFW_RCFLAG_RANGE) != 0) {
1027 		start = ipfw_find_rule(chain, rt->start_rule, 0);
1028 
1029 		if (rt->end_rule >= IPFW_DEFAULT_RULE)
1030 			rt->end_rule = IPFW_DEFAULT_RULE - 1;
1031 		end = ipfw_find_rule(chain, rt->end_rule, UINT32_MAX);
1032 	}
1033 
1034 	if (rt->flags & IPFW_RCFLAG_DYNAMIC) {
1035 		/*
1036 		 * Requested deleting only for dynamic states.
1037 		 */
1038 		*ndel = 0;
1039 		ipfw_expire_dyn_states(chain, rt);
1040 		IPFW_UH_WUNLOCK(chain);
1041 		return (0);
1042 	}
1043 
1044 	/* Allocate new map of the same size */
1045 	map = get_map(chain, 0, 1 /* locked */);
1046 	if (map == NULL) {
1047 		IPFW_UH_WUNLOCK(chain);
1048 		return (ENOMEM);
1049 	}
1050 
1051 	n = 0;
1052 	ndyn = 0;
1053 	ofs = start;
1054 	/* 1. bcopy the initial part of the map */
1055 	if (start > 0)
1056 		bcopy(chain->map, map, start * sizeof(struct ip_fw *));
1057 	/* 2. copy active rules between start and end */
1058 	for (i = start; i < end; i++) {
1059 		rule = chain->map[i];
1060 		if (ipfw_match_range(rule, rt) == 0) {
1061 			map[ofs++] = rule;
1062 			continue;
1063 		}
1064 
1065 		n++;
1066 		if (ipfw_is_dyn_rule(rule) != 0)
1067 			ndyn++;
1068 	}
1069 	/* 3. copy the final part of the map */
1070 	bcopy(chain->map + end, map + ofs,
1071 		(chain->n_rules - end) * sizeof(struct ip_fw *));
1072 	/* 4. recalculate skipto cache */
1073 	update_skipto_cache(chain, map);
1074 	/* 5. swap the maps (under UH_WLOCK + WHLOCK) */
1075 	map = swap_map(chain, map, chain->n_rules - n);
1076 	/* 6. Remove all dynamic states originated by deleted rules */
1077 	if (ndyn > 0)
1078 		ipfw_expire_dyn_states(chain, rt);
1079 	/* 7. now remove the rules deleted from the old map */
1080 	for (i = start; i < end; i++) {
1081 		rule = map[i];
1082 		if (ipfw_match_range(rule, rt) == 0)
1083 			continue;
1084 		chain->static_len -= RULEUSIZE0(rule);
1085 		ipfw_reap_add(chain, &reap, rule);
1086 	}
1087 	IPFW_UH_WUNLOCK(chain);
1088 
1089 	ipfw_reap_rules(reap);
1090 	if (map != NULL)
1091 		free(map, M_IPFW);
1092 	*ndel = n;
1093 	return (0);
1094 }
1095 
1096 static int
move_objects(struct ip_fw_chain * ch,ipfw_range_tlv * rt)1097 move_objects(struct ip_fw_chain *ch, ipfw_range_tlv *rt)
1098 {
1099 	struct opcode_obj_rewrite *rw;
1100 	struct ip_fw *rule;
1101 	ipfw_insn *cmd;
1102 	int cmdlen, i, l, c;
1103 	uint16_t kidx;
1104 
1105 	IPFW_UH_WLOCK_ASSERT(ch);
1106 
1107 	/* Stage 1: count number of references by given rules */
1108 	for (c = 0, i = 0; i < ch->n_rules - 1; i++) {
1109 		rule = ch->map[i];
1110 		if (ipfw_match_range(rule, rt) == 0)
1111 			continue;
1112 		if (rule->set == rt->new_set) /* nothing to do */
1113 			continue;
1114 		/* Search opcodes with named objects */
1115 		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
1116 		    l > 0; l -= cmdlen, cmd += cmdlen) {
1117 			cmdlen = F_LEN(cmd);
1118 			rw = find_op_rw(cmd, &kidx, NULL);
1119 			if (rw == NULL || rw->manage_sets == NULL)
1120 				continue;
1121 			/*
1122 			 * When manage_sets() returns non-zero value to
1123 			 * COUNT_ONE command, consider this as an object
1124 			 * doesn't support sets (e.g. disabled with sysctl).
1125 			 * So, skip checks for this object.
1126 			 */
1127 			if (rw->manage_sets(ch, kidx, 1, COUNT_ONE) != 0)
1128 				continue;
1129 			c++;
1130 		}
1131 	}
1132 	if (c == 0) /* No objects found */
1133 		return (0);
1134 	/* Stage 2: verify "ownership" */
1135 	for (c = 0, i = 0; (i < ch->n_rules - 1) && c == 0; i++) {
1136 		rule = ch->map[i];
1137 		if (ipfw_match_range(rule, rt) == 0)
1138 			continue;
1139 		if (rule->set == rt->new_set) /* nothing to do */
1140 			continue;
1141 		/* Search opcodes with named objects */
1142 		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
1143 		    l > 0 && c == 0; l -= cmdlen, cmd += cmdlen) {
1144 			cmdlen = F_LEN(cmd);
1145 			rw = find_op_rw(cmd, &kidx, NULL);
1146 			if (rw == NULL || rw->manage_sets == NULL)
1147 				continue;
1148 			/* Test for ownership and conflicting names */
1149 			c = rw->manage_sets(ch, kidx,
1150 			    (uint8_t)rt->new_set, TEST_ONE);
1151 		}
1152 	}
1153 	/* Stage 3: change set and cleanup */
1154 	for (i = 0; i < ch->n_rules - 1; i++) {
1155 		rule = ch->map[i];
1156 		if (ipfw_match_range(rule, rt) == 0)
1157 			continue;
1158 		if (rule->set == rt->new_set) /* nothing to do */
1159 			continue;
1160 		/* Search opcodes with named objects */
1161 		for (l = rule->cmd_len, cmdlen = 0, cmd = rule->cmd;
1162 		    l > 0; l -= cmdlen, cmd += cmdlen) {
1163 			cmdlen = F_LEN(cmd);
1164 			rw = find_op_rw(cmd, &kidx, NULL);
1165 			if (rw == NULL || rw->manage_sets == NULL)
1166 				continue;
1167 			/* cleanup object counter */
1168 			rw->manage_sets(ch, kidx,
1169 			    0 /* reset counter */, COUNT_ONE);
1170 			if (c != 0)
1171 				continue;
1172 			/* change set */
1173 			rw->manage_sets(ch, kidx,
1174 			    (uint8_t)rt->new_set, MOVE_ONE);
1175 		}
1176 	}
1177 	return (c);
1178 }
1179 
1180 /*
1181  * Changes set of given rule rannge @rt
1182  * with each other.
1183  *
1184  * Returns 0 on success.
1185  */
1186 static int
move_range(struct ip_fw_chain * chain,ipfw_range_tlv * rt)1187 move_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
1188 {
1189 	struct ip_fw *rule;
1190 	int i;
1191 
1192 	IPFW_UH_WLOCK(chain);
1193 
1194 	/*
1195 	 * Move rules with matching paramenerts to a new set.
1196 	 * This one is much more complex. We have to ensure
1197 	 * that all referenced tables (if any) are referenced
1198 	 * by given rule subset only. Otherwise, we can't move
1199 	 * them to new set and have to return error.
1200 	 */
1201 	if ((i = move_objects(chain, rt)) != 0) {
1202 		IPFW_UH_WUNLOCK(chain);
1203 		return (i);
1204 	}
1205 
1206 	/* XXX: We have to do swap holding WLOCK */
1207 	for (i = 0; i < chain->n_rules; i++) {
1208 		rule = chain->map[i];
1209 		if (ipfw_match_range(rule, rt) == 0)
1210 			continue;
1211 		rule->set = rt->new_set;
1212 	}
1213 
1214 	IPFW_UH_WUNLOCK(chain);
1215 
1216 	return (0);
1217 }
1218 
1219 /*
1220  * Returns pointer to action instruction, skips all possible rule
1221  * modifiers like O_LOG, O_TAG, O_ALTQ.
1222  */
1223 ipfw_insn *
ipfw_get_action(struct ip_fw * rule)1224 ipfw_get_action(struct ip_fw *rule)
1225 {
1226 	ipfw_insn *cmd;
1227 	int l, cmdlen;
1228 
1229 	cmd = ACTION_PTR(rule);
1230 	l = rule->cmd_len - rule->act_ofs;
1231 	while (l > 0) {
1232 		switch (cmd->opcode) {
1233 		case O_ALTQ:
1234 		case O_LOG:
1235 		case O_TAG:
1236 			break;
1237 		default:
1238 			return (cmd);
1239 		}
1240 		cmdlen = F_LEN(cmd);
1241 		l -= cmdlen;
1242 		cmd += cmdlen;
1243 	}
1244 	panic("%s: rule (%p) has not action opcode", __func__, rule);
1245 	return (NULL);
1246 }
1247 
1248 /*
1249  * Clear counters for a specific rule.
1250  * Normally run under IPFW_UH_RLOCK, but these are idempotent ops
1251  * so we only care that rules do not disappear.
1252  */
1253 static void
clear_counters(struct ip_fw * rule,int log_only)1254 clear_counters(struct ip_fw *rule, int log_only)
1255 {
1256 	ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule);
1257 
1258 	if (log_only == 0)
1259 		IPFW_ZERO_RULE_COUNTER(rule);
1260 	if (l->o.opcode == O_LOG)
1261 		l->log_left = l->max_log;
1262 }
1263 
1264 /*
1265  * Flushes rules counters and/or log values on matching range.
1266  *
1267  * Returns number of items cleared.
1268  */
1269 static int
clear_range(struct ip_fw_chain * chain,ipfw_range_tlv * rt,int log_only)1270 clear_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int log_only)
1271 {
1272 	struct ip_fw *rule;
1273 	int num;
1274 	int i;
1275 
1276 	num = 0;
1277 	rt->flags |= IPFW_RCFLAG_DEFAULT;
1278 
1279 	IPFW_UH_WLOCK(chain);	/* arbitrate writers */
1280 	for (i = 0; i < chain->n_rules; i++) {
1281 		rule = chain->map[i];
1282 		if (ipfw_match_range(rule, rt) == 0)
1283 			continue;
1284 		clear_counters(rule, log_only);
1285 		num++;
1286 	}
1287 	IPFW_UH_WUNLOCK(chain);
1288 
1289 	return (num);
1290 }
1291 
1292 static int
check_range_tlv(ipfw_range_tlv * rt)1293 check_range_tlv(ipfw_range_tlv *rt)
1294 {
1295 
1296 	if (rt->head.length != sizeof(*rt))
1297 		return (1);
1298 	if (rt->start_rule > rt->end_rule)
1299 		return (1);
1300 	if (rt->set >= IPFW_MAX_SETS || rt->new_set >= IPFW_MAX_SETS)
1301 		return (1);
1302 
1303 	if ((rt->flags & IPFW_RCFLAG_USER) != rt->flags)
1304 		return (1);
1305 
1306 	return (0);
1307 }
1308 
1309 /*
1310  * Delete rules matching specified parameters
1311  * Data layout (v0)(current):
1312  * Request: [ ipfw_obj_header ipfw_range_tlv ]
1313  * Reply: [ ipfw_obj_header ipfw_range_tlv ]
1314  *
1315  * Saves number of deleted rules in ipfw_range_tlv->new_set.
1316  *
1317  * Returns 0 on success.
1318  */
1319 static int
del_rules(struct ip_fw_chain * chain,ip_fw3_opheader * op3,struct sockopt_data * sd)1320 del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
1321     struct sockopt_data *sd)
1322 {
1323 	ipfw_range_header *rh;
1324 	int error, ndel;
1325 
1326 	if (sd->valsize != sizeof(*rh))
1327 		return (EINVAL);
1328 
1329 	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
1330 
1331 	if (check_range_tlv(&rh->range) != 0)
1332 		return (EINVAL);
1333 
1334 	ndel = 0;
1335 	if ((error = delete_range(chain, &rh->range, &ndel)) != 0)
1336 		return (error);
1337 
1338 	/* Save number of rules deleted */
1339 	rh->range.new_set = ndel;
1340 	return (0);
1341 }
1342 
1343 /*
1344  * Move rules/sets matching specified parameters
1345  * Data layout (v0)(current):
1346  * Request: [ ipfw_obj_header ipfw_range_tlv ]
1347  *
1348  * Returns 0 on success.
1349  */
1350 static int
move_rules(struct ip_fw_chain * chain,ip_fw3_opheader * op3,struct sockopt_data * sd)1351 move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
1352     struct sockopt_data *sd)
1353 {
1354 	ipfw_range_header *rh;
1355 
1356 	if (sd->valsize != sizeof(*rh))
1357 		return (EINVAL);
1358 
1359 	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
1360 
1361 	if (check_range_tlv(&rh->range) != 0)
1362 		return (EINVAL);
1363 
1364 	return (move_range(chain, &rh->range));
1365 }
1366 
1367 /*
1368  * Clear rule accounting data matching specified parameters
1369  * Data layout (v0)(current):
1370  * Request: [ ipfw_obj_header ipfw_range_tlv ]
1371  * Reply: [ ipfw_obj_header ipfw_range_tlv ]
1372  *
1373  * Saves number of cleared rules in ipfw_range_tlv->new_set.
1374  *
1375  * Returns 0 on success.
1376  */
1377 static int
clear_rules(struct ip_fw_chain * chain,ip_fw3_opheader * op3,struct sockopt_data * sd)1378 clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
1379     struct sockopt_data *sd)
1380 {
1381 	ipfw_range_header *rh;
1382 	int log_only, num;
1383 	char *msg;
1384 
1385 	if (sd->valsize != sizeof(*rh))
1386 		return (EINVAL);
1387 
1388 	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
1389 
1390 	if (check_range_tlv(&rh->range) != 0)
1391 		return (EINVAL);
1392 
1393 	log_only = (op3->opcode == IP_FW_XRESETLOG);
1394 
1395 	num = clear_range(chain, &rh->range, log_only);
1396 
1397 	if (rh->range.flags & IPFW_RCFLAG_ALL)
1398 		msg = log_only ? "All logging counts reset" :
1399 		    "Accounting cleared";
1400 	else
1401 		msg = log_only ? "logging count reset" : "cleared";
1402 
1403 	if (V_fw_verbose) {
1404 		int lev = LOG_SECURITY | LOG_NOTICE;
1405 		log(lev, "ipfw: %s.\n", msg);
1406 	}
1407 
1408 	/* Save number of rules cleared */
1409 	rh->range.new_set = num;
1410 	return (0);
1411 }
1412 
1413 static void
enable_sets(struct ip_fw_chain * chain,ipfw_range_tlv * rt)1414 enable_sets(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
1415 {
1416 	uint32_t v_set;
1417 
1418 	IPFW_UH_WLOCK_ASSERT(chain);
1419 
1420 	/* Change enabled/disabled sets mask */
1421 	v_set = (V_set_disable | rt->set) & ~rt->new_set;
1422 	v_set &= ~(1 << RESVD_SET); /* set RESVD_SET always enabled */
1423 	IPFW_WLOCK(chain);
1424 	V_set_disable = v_set;
1425 	IPFW_WUNLOCK(chain);
1426 }
1427 
1428 static int
swap_sets(struct ip_fw_chain * chain,ipfw_range_tlv * rt,int mv)1429 swap_sets(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int mv)
1430 {
1431 	struct opcode_obj_rewrite *rw;
1432 	struct ip_fw *rule;
1433 	int i;
1434 
1435 	IPFW_UH_WLOCK_ASSERT(chain);
1436 
1437 	if (rt->set == rt->new_set) /* nothing to do */
1438 		return (0);
1439 
1440 	if (mv != 0) {
1441 		/*
1442 		 * Berfore moving the rules we need to check that
1443 		 * there aren't any conflicting named objects.
1444 		 */
1445 		for (rw = ctl3_rewriters;
1446 		    rw < ctl3_rewriters + ctl3_rsize; rw++) {
1447 			if (rw->manage_sets == NULL)
1448 				continue;
1449 			i = rw->manage_sets(chain, (uint8_t)rt->set,
1450 			    (uint8_t)rt->new_set, TEST_ALL);
1451 			if (i != 0)
1452 				return (EEXIST);
1453 		}
1454 	}
1455 	/* Swap or move two sets */
1456 	for (i = 0; i < chain->n_rules - 1; i++) {
1457 		rule = chain->map[i];
1458 		if (rule->set == (uint8_t)rt->set)
1459 			rule->set = (uint8_t)rt->new_set;
1460 		else if (rule->set == (uint8_t)rt->new_set && mv == 0)
1461 			rule->set = (uint8_t)rt->set;
1462 	}
1463 	for (rw = ctl3_rewriters; rw < ctl3_rewriters + ctl3_rsize; rw++) {
1464 		if (rw->manage_sets == NULL)
1465 			continue;
1466 		rw->manage_sets(chain, (uint8_t)rt->set,
1467 		    (uint8_t)rt->new_set, mv != 0 ? MOVE_ALL: SWAP_ALL);
1468 	}
1469 	return (0);
1470 }
1471 
1472 /*
1473  * Swaps or moves set
1474  * Data layout (v0)(current):
1475  * Request: [ ipfw_obj_header ipfw_range_tlv ]
1476  *
1477  * Returns 0 on success.
1478  */
1479 static int
manage_sets(struct ip_fw_chain * chain,ip_fw3_opheader * op3,struct sockopt_data * sd)1480 manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
1481     struct sockopt_data *sd)
1482 {
1483 	ipfw_range_header *rh;
1484 	int ret;
1485 
1486 	if (sd->valsize != sizeof(*rh))
1487 		return (EINVAL);
1488 
1489 	rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize);
1490 
1491 	if (rh->range.head.length != sizeof(ipfw_range_tlv))
1492 		return (1);
1493 	/* enable_sets() expects bitmasks. */
1494 	if (op3->opcode != IP_FW_SET_ENABLE &&
1495 	    (rh->range.set >= IPFW_MAX_SETS ||
1496 	    rh->range.new_set >= IPFW_MAX_SETS))
1497 		return (EINVAL);
1498 
1499 	ret = 0;
1500 	IPFW_UH_WLOCK(chain);
1501 	switch (op3->opcode) {
1502 	case IP_FW_SET_SWAP:
1503 	case IP_FW_SET_MOVE:
1504 		ret = swap_sets(chain, &rh->range,
1505 		    op3->opcode == IP_FW_SET_MOVE);
1506 		break;
1507 	case IP_FW_SET_ENABLE:
1508 		enable_sets(chain, &rh->range);
1509 		break;
1510 	}
1511 	IPFW_UH_WUNLOCK(chain);
1512 
1513 	return (ret);
1514 }
1515 
1516 /**
1517  * Remove all rules with given number, or do set manipulation.
1518  * Assumes chain != NULL && *chain != NULL.
1519  *
1520  * The argument is an uint32_t. The low 16 bit are the rule or set number;
1521  * the next 8 bits are the new set; the top 8 bits indicate the command:
1522  *
1523  *	0	delete rules numbered "rulenum"
1524  *	1	delete rules in set "rulenum"
1525  *	2	move rules "rulenum" to set "new_set"
1526  *	3	move rules from set "rulenum" to set "new_set"
1527  *	4	swap sets "rulenum" and "new_set"
1528  *	5	delete rules "rulenum" and set "new_set"
1529  */
1530 static int
del_entry(struct ip_fw_chain * chain,uint32_t arg)1531 del_entry(struct ip_fw_chain *chain, uint32_t arg)
1532 {
1533 	uint32_t num;	/* rule number or old_set */
1534 	uint8_t cmd, new_set;
1535 	int do_del, ndel;
1536 	int error = 0;
1537 	ipfw_range_tlv rt;
1538 
1539 	num = arg & 0xffff;
1540 	cmd = (arg >> 24) & 0xff;
1541 	new_set = (arg >> 16) & 0xff;
1542 
1543 	if (cmd > 5 || new_set > RESVD_SET)
1544 		return EINVAL;
1545 	if (cmd == 0 || cmd == 2 || cmd == 5) {
1546 		if (num >= IPFW_DEFAULT_RULE)
1547 			return EINVAL;
1548 	} else {
1549 		if (num > RESVD_SET)	/* old_set */
1550 			return EINVAL;
1551 	}
1552 
1553 	/* Convert old requests into new representation */
1554 	memset(&rt, 0, sizeof(rt));
1555 	rt.start_rule = num;
1556 	rt.end_rule = num;
1557 	rt.set = num;
1558 	rt.new_set = new_set;
1559 	do_del = 0;
1560 
1561 	switch (cmd) {
1562 	case 0: /* delete rules numbered "rulenum" */
1563 		if (num == 0)
1564 			rt.flags |= IPFW_RCFLAG_ALL;
1565 		else
1566 			rt.flags |= IPFW_RCFLAG_RANGE;
1567 		do_del = 1;
1568 		break;
1569 	case 1: /* delete rules in set "rulenum" */
1570 		rt.flags |= IPFW_RCFLAG_SET;
1571 		do_del = 1;
1572 		break;
1573 	case 5: /* delete rules "rulenum" and set "new_set" */
1574 		rt.flags |= IPFW_RCFLAG_RANGE | IPFW_RCFLAG_SET;
1575 		rt.set = new_set;
1576 		rt.new_set = 0;
1577 		do_del = 1;
1578 		break;
1579 	case 2: /* move rules "rulenum" to set "new_set" */
1580 		rt.flags |= IPFW_RCFLAG_RANGE;
1581 		break;
1582 	case 3: /* move rules from set "rulenum" to set "new_set" */
1583 		IPFW_UH_WLOCK(chain);
1584 		error = swap_sets(chain, &rt, 1);
1585 		IPFW_UH_WUNLOCK(chain);
1586 		return (error);
1587 	case 4: /* swap sets "rulenum" and "new_set" */
1588 		IPFW_UH_WLOCK(chain);
1589 		error = swap_sets(chain, &rt, 0);
1590 		IPFW_UH_WUNLOCK(chain);
1591 		return (error);
1592 	default:
1593 		return (ENOTSUP);
1594 	}
1595 
1596 	if (do_del != 0) {
1597 		if ((error = delete_range(chain, &rt, &ndel)) != 0)
1598 			return (error);
1599 
1600 		if (ndel == 0 && (cmd != 1 && num != 0))
1601 			return (EINVAL);
1602 
1603 		return (0);
1604 	}
1605 
1606 	return (move_range(chain, &rt));
1607 }
1608 
1609 /**
1610  * Reset some or all counters on firewall rules.
1611  * The argument `arg' is an u_int32_t. The low 16 bit are the rule number,
1612  * the next 8 bits are the set number, the top 8 bits are the command:
1613  *	0	work with rules from all set's;
1614  *	1	work with rules only from specified set.
1615  * Specified rule number is zero if we want to clear all entries.
1616  * log_only is 1 if we only want to reset logs, zero otherwise.
1617  */
1618 static int
zero_entry(struct ip_fw_chain * chain,u_int32_t arg,int log_only)1619 zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only)
1620 {
1621 	struct ip_fw *rule;
1622 	char *msg;
1623 	int i;
1624 
1625 	uint16_t rulenum = arg & 0xffff;
1626 	uint8_t set = (arg >> 16) & 0xff;
1627 	uint8_t cmd = (arg >> 24) & 0xff;
1628 
1629 	if (cmd > 1)
1630 		return (EINVAL);
1631 	if (cmd == 1 && set > RESVD_SET)
1632 		return (EINVAL);
1633 
1634 	IPFW_UH_RLOCK(chain);
1635 	if (rulenum == 0) {
1636 		V_norule_counter = 0;
1637 		for (i = 0; i < chain->n_rules; i++) {
1638 			rule = chain->map[i];
1639 			/* Skip rules not in our set. */
1640 			if (cmd == 1 && rule->set != set)
1641 				continue;
1642 			clear_counters(rule, log_only);
1643 		}
1644 		msg = log_only ? "All logging counts reset" :
1645 		    "Accounting cleared";
1646 	} else {
1647 		int cleared = 0;
1648 		for (i = 0; i < chain->n_rules; i++) {
1649 			rule = chain->map[i];
1650 			if (rule->rulenum == rulenum) {
1651 				if (cmd == 0 || rule->set == set)
1652 					clear_counters(rule, log_only);
1653 				cleared = 1;
1654 			}
1655 			if (rule->rulenum > rulenum)
1656 				break;
1657 		}
1658 		if (!cleared) {	/* we did not find any matching rules */
1659 			IPFW_UH_RUNLOCK(chain);
1660 			return (EINVAL);
1661 		}
1662 		msg = log_only ? "logging count reset" : "cleared";
1663 	}
1664 	IPFW_UH_RUNLOCK(chain);
1665 
1666 	if (V_fw_verbose) {
1667 		int lev = LOG_SECURITY | LOG_NOTICE;
1668 
1669 		if (rulenum)
1670 			log(lev, "ipfw: Entry %d %s.\n", rulenum, msg);
1671 		else
1672 			log(lev, "ipfw: %s.\n", msg);
1673 	}
1674 	return (0);
1675 }
1676 
1677 
1678 /*
1679  * Check rule head in FreeBSD11 format
1680  *
1681  */
1682 static int
check_ipfw_rule1(struct ip_fw_rule * rule,int size,struct rule_check_info * ci)1683 check_ipfw_rule1(struct ip_fw_rule *rule, int size,
1684     struct rule_check_info *ci)
1685 {
1686 	int l;
1687 
1688 	if (size < sizeof(*rule)) {
1689 		printf("ipfw: rule too short\n");
1690 		return (EINVAL);
1691 	}
1692 
1693 	/* Check for valid cmd_len */
1694 	l = roundup2(RULESIZE(rule), sizeof(uint64_t));
1695 	if (l != size) {
1696 		printf("ipfw: size mismatch (have %d want %d)\n", size, l);
1697 		return (EINVAL);
1698 	}
1699 	if (rule->act_ofs >= rule->cmd_len) {
1700 		printf("ipfw: bogus action offset (%u > %u)\n",
1701 		    rule->act_ofs, rule->cmd_len - 1);
1702 		return (EINVAL);
1703 	}
1704 
1705 	if (rule->rulenum > IPFW_DEFAULT_RULE - 1)
1706 		return (EINVAL);
1707 
1708 	return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci));
1709 }
1710 
1711 /*
1712  * Check rule head in FreeBSD8 format
1713  *
1714  */
1715 static int
check_ipfw_rule0(struct ip_fw_rule0 * rule,int size,struct rule_check_info * ci)1716 check_ipfw_rule0(struct ip_fw_rule0 *rule, int size,
1717     struct rule_check_info *ci)
1718 {
1719 	int l;
1720 
1721 	if (size < sizeof(*rule)) {
1722 		printf("ipfw: rule too short\n");
1723 		return (EINVAL);
1724 	}
1725 
1726 	/* Check for valid cmd_len */
1727 	l = sizeof(*rule) + rule->cmd_len * 4 - 4;
1728 	if (l != size) {
1729 		printf("ipfw: size mismatch (have %d want %d)\n", size, l);
1730 		return (EINVAL);
1731 	}
1732 	if (rule->act_ofs >= rule->cmd_len) {
1733 		printf("ipfw: bogus action offset (%u > %u)\n",
1734 		    rule->act_ofs, rule->cmd_len - 1);
1735 		return (EINVAL);
1736 	}
1737 
1738 	if (rule->rulenum > IPFW_DEFAULT_RULE - 1)
1739 		return (EINVAL);
1740 
1741 	return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci));
1742 }
1743 
1744 static int
check_ipfw_rule_body(ipfw_insn * cmd,int cmd_len,struct rule_check_info * ci)1745 check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci)
1746 {
1747 	int cmdlen, l;
1748 	int have_action;
1749 
1750 	have_action = 0;
1751 
1752 	/*
1753 	 * Now go for the individual checks. Very simple ones, basically only
1754 	 * instruction sizes.
1755 	 */
1756 	for (l = cmd_len; l > 0 ; l -= cmdlen, cmd += cmdlen) {
1757 		cmdlen = F_LEN(cmd);
1758 		if (cmdlen > l) {
1759 			printf("ipfw: opcode %d size truncated\n",
1760 			    cmd->opcode);
1761 			return EINVAL;
1762 		}
1763 		switch (cmd->opcode) {
1764 		case O_PROBE_STATE:
1765 		case O_KEEP_STATE:
1766 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1767 				goto bad_size;
1768 			ci->object_opcodes++;
1769 			break;
1770 		case O_PROTO:
1771 		case O_IP_SRC_ME:
1772 		case O_IP_DST_ME:
1773 		case O_LAYER2:
1774 		case O_IN:
1775 		case O_FRAG:
1776 		case O_DIVERTED:
1777 		case O_IPOPT:
1778 		case O_IPTOS:
1779 		case O_IPPRECEDENCE:
1780 		case O_IPVER:
1781 		case O_SOCKARG:
1782 		case O_TCPFLAGS:
1783 		case O_TCPOPTS:
1784 		case O_ESTAB:
1785 		case O_VERREVPATH:
1786 		case O_VERSRCREACH:
1787 		case O_ANTISPOOF:
1788 		case O_IPSEC:
1789 #ifdef INET6
1790 		case O_IP6_SRC_ME:
1791 		case O_IP6_DST_ME:
1792 		case O_EXT_HDR:
1793 		case O_IP6:
1794 #endif
1795 		case O_IP4:
1796 		case O_TAG:
1797 		case O_SKIP_ACTION:
1798 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1799 				goto bad_size;
1800 			break;
1801 
1802 		case O_EXTERNAL_ACTION:
1803 			if (cmd->arg1 == 0 ||
1804 			    cmdlen != F_INSN_SIZE(ipfw_insn)) {
1805 				printf("ipfw: invalid external "
1806 				    "action opcode\n");
1807 				return (EINVAL);
1808 			}
1809 			ci->object_opcodes++;
1810 			/*
1811 			 * Do we have O_EXTERNAL_INSTANCE or O_EXTERNAL_DATA
1812 			 * opcode?
1813 			 */
1814 			if (l != cmdlen) {
1815 				l -= cmdlen;
1816 				cmd += cmdlen;
1817 				cmdlen = F_LEN(cmd);
1818 				if (cmd->opcode == O_EXTERNAL_DATA)
1819 					goto check_action;
1820 				if (cmd->opcode != O_EXTERNAL_INSTANCE) {
1821 					printf("ipfw: invalid opcode "
1822 					    "next to external action %u\n",
1823 					    cmd->opcode);
1824 					return (EINVAL);
1825 				}
1826 				if (cmd->arg1 == 0 ||
1827 				    cmdlen != F_INSN_SIZE(ipfw_insn)) {
1828 					printf("ipfw: invalid external "
1829 					    "action instance opcode\n");
1830 					return (EINVAL);
1831 				}
1832 				ci->object_opcodes++;
1833 			}
1834 			goto check_action;
1835 
1836 		case O_FIB:
1837 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1838 				goto bad_size;
1839 			if (cmd->arg1 >= rt_numfibs) {
1840 				printf("ipfw: invalid fib number %d\n",
1841 					cmd->arg1);
1842 				return EINVAL;
1843 			}
1844 			break;
1845 
1846 		case O_SETFIB:
1847 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1848 				goto bad_size;
1849 			if ((cmd->arg1 != IP_FW_TARG) &&
1850 			    ((cmd->arg1 & 0x7FFF) >= rt_numfibs)) {
1851 				printf("ipfw: invalid fib number %d\n",
1852 					cmd->arg1 & 0x7FFF);
1853 				return EINVAL;
1854 			}
1855 			goto check_action;
1856 
1857 		case O_UID:
1858 		case O_GID:
1859 		case O_JAIL:
1860 		case O_IP_SRC:
1861 		case O_IP_DST:
1862 		case O_TCPSEQ:
1863 		case O_TCPACK:
1864 		case O_PROB:
1865 		case O_ICMPTYPE:
1866 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1867 				goto bad_size;
1868 			break;
1869 
1870 		case O_LIMIT:
1871 			if (cmdlen != F_INSN_SIZE(ipfw_insn_limit))
1872 				goto bad_size;
1873 			ci->object_opcodes++;
1874 			break;
1875 
1876 		case O_LOG:
1877 			if (cmdlen != F_INSN_SIZE(ipfw_insn_log))
1878 				goto bad_size;
1879 
1880 			((ipfw_insn_log *)cmd)->log_left =
1881 			    ((ipfw_insn_log *)cmd)->max_log;
1882 
1883 			break;
1884 
1885 		case O_IP_SRC_MASK:
1886 		case O_IP_DST_MASK:
1887 			/* only odd command lengths */
1888 			if ((cmdlen & 1) == 0)
1889 				goto bad_size;
1890 			break;
1891 
1892 		case O_IP_SRC_SET:
1893 		case O_IP_DST_SET:
1894 			if (cmd->arg1 == 0 || cmd->arg1 > 256) {
1895 				printf("ipfw: invalid set size %d\n",
1896 					cmd->arg1);
1897 				return EINVAL;
1898 			}
1899 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
1900 			    (cmd->arg1+31)/32 )
1901 				goto bad_size;
1902 			break;
1903 
1904 		case O_IP_SRC_LOOKUP:
1905 			if (cmdlen > F_INSN_SIZE(ipfw_insn_u32))
1906 				goto bad_size;
1907 		case O_IP_DST_LOOKUP:
1908 			if (cmd->arg1 >= V_fw_tables_max) {
1909 				printf("ipfw: invalid table number %d\n",
1910 				    cmd->arg1);
1911 				return (EINVAL);
1912 			}
1913 			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
1914 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
1915 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1916 				goto bad_size;
1917 			ci->object_opcodes++;
1918 			break;
1919 		case O_IP_FLOW_LOOKUP:
1920 			if (cmd->arg1 >= V_fw_tables_max) {
1921 				printf("ipfw: invalid table number %d\n",
1922 				    cmd->arg1);
1923 				return (EINVAL);
1924 			}
1925 			if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
1926 			    cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1927 				goto bad_size;
1928 			ci->object_opcodes++;
1929 			break;
1930 		case O_MACADDR2:
1931 			if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
1932 				goto bad_size;
1933 			break;
1934 
1935 		case O_NOP:
1936 		case O_IPID:
1937 		case O_IPTTL:
1938 		case O_IPLEN:
1939 		case O_TCPDATALEN:
1940 		case O_TCPMSS:
1941 		case O_TCPWIN:
1942 		case O_TAGGED:
1943 			if (cmdlen < 1 || cmdlen > 31)
1944 				goto bad_size;
1945 			break;
1946 
1947 		case O_DSCP:
1948 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1)
1949 				goto bad_size;
1950 			break;
1951 
1952 		case O_MAC_TYPE:
1953 		case O_IP_SRCPORT:
1954 		case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
1955 			if (cmdlen < 2 || cmdlen > 31)
1956 				goto bad_size;
1957 			break;
1958 
1959 		case O_RECV:
1960 		case O_XMIT:
1961 		case O_VIA:
1962 			if (cmdlen != F_INSN_SIZE(ipfw_insn_if))
1963 				goto bad_size;
1964 			ci->object_opcodes++;
1965 			break;
1966 
1967 		case O_ALTQ:
1968 			if (cmdlen != F_INSN_SIZE(ipfw_insn_altq))
1969 				goto bad_size;
1970 			break;
1971 
1972 		case O_PIPE:
1973 		case O_QUEUE:
1974 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
1975 				goto bad_size;
1976 			goto check_action;
1977 
1978 		case O_FORWARD_IP:
1979 			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa))
1980 				goto bad_size;
1981 			goto check_action;
1982 #ifdef INET6
1983 		case O_FORWARD_IP6:
1984 			if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6))
1985 				goto bad_size;
1986 			goto check_action;
1987 #endif /* INET6 */
1988 
1989 		case O_DIVERT:
1990 		case O_TEE:
1991 			if (ip_divert_ptr == NULL)
1992 				return EINVAL;
1993 			else
1994 				goto check_size;
1995 		case O_NETGRAPH:
1996 		case O_NGTEE:
1997 			if (ng_ipfw_input_p == NULL)
1998 				return EINVAL;
1999 			else
2000 				goto check_size;
2001 		case O_NAT:
2002 			if (!IPFW_NAT_LOADED)
2003 				return EINVAL;
2004 			if (cmdlen != F_INSN_SIZE(ipfw_insn_nat))
2005  				goto bad_size;
2006  			goto check_action;
2007 		case O_CHECK_STATE:
2008 			ci->object_opcodes++;
2009 			/* FALLTHROUGH */
2010 		case O_FORWARD_MAC: /* XXX not implemented yet */
2011 		case O_COUNT:
2012 		case O_ACCEPT:
2013 		case O_DENY:
2014 		case O_REJECT:
2015 		case O_SETDSCP:
2016 #ifdef INET6
2017 		case O_UNREACH6:
2018 #endif
2019 		case O_SKIPTO:
2020 		case O_REASS:
2021 		case O_CALLRETURN:
2022 check_size:
2023 			if (cmdlen != F_INSN_SIZE(ipfw_insn))
2024 				goto bad_size;
2025 check_action:
2026 			if (have_action) {
2027 				printf("ipfw: opcode %d, multiple actions"
2028 					" not allowed\n",
2029 					cmd->opcode);
2030 				return (EINVAL);
2031 			}
2032 			have_action = 1;
2033 			if (l != cmdlen) {
2034 				printf("ipfw: opcode %d, action must be"
2035 					" last opcode\n",
2036 					cmd->opcode);
2037 				return (EINVAL);
2038 			}
2039 			break;
2040 #ifdef INET6
2041 		case O_IP6_SRC:
2042 		case O_IP6_DST:
2043 			if (cmdlen != F_INSN_SIZE(struct in6_addr) +
2044 			    F_INSN_SIZE(ipfw_insn))
2045 				goto bad_size;
2046 			break;
2047 
2048 		case O_FLOW6ID:
2049 			if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
2050 			    ((ipfw_insn_u32 *)cmd)->o.arg1)
2051 				goto bad_size;
2052 			break;
2053 
2054 		case O_IP6_SRC_MASK:
2055 		case O_IP6_DST_MASK:
2056 			if ( !(cmdlen & 1) || cmdlen > 127)
2057 				goto bad_size;
2058 			break;
2059 		case O_ICMP6TYPE:
2060 			if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
2061 				goto bad_size;
2062 			break;
2063 #endif
2064 
2065 		default:
2066 			switch (cmd->opcode) {
2067 #ifndef INET6
2068 			case O_IP6_SRC_ME:
2069 			case O_IP6_DST_ME:
2070 			case O_EXT_HDR:
2071 			case O_IP6:
2072 			case O_UNREACH6:
2073 			case O_IP6_SRC:
2074 			case O_IP6_DST:
2075 			case O_FLOW6ID:
2076 			case O_IP6_SRC_MASK:
2077 			case O_IP6_DST_MASK:
2078 			case O_ICMP6TYPE:
2079 				printf("ipfw: no IPv6 support in kernel\n");
2080 				return (EPROTONOSUPPORT);
2081 #endif
2082 			default:
2083 				printf("ipfw: opcode %d, unknown opcode\n",
2084 					cmd->opcode);
2085 				return (EINVAL);
2086 			}
2087 		}
2088 	}
2089 	if (have_action == 0) {
2090 		printf("ipfw: missing action\n");
2091 		return (EINVAL);
2092 	}
2093 	return 0;
2094 
2095 bad_size:
2096 	printf("ipfw: opcode %d size %d wrong\n",
2097 		cmd->opcode, cmdlen);
2098 	return (EINVAL);
2099 }
2100 
2101 
2102 /*
2103  * Translation of requests for compatibility with FreeBSD 7.2/8.
2104  * a static variable tells us if we have an old client from userland,
2105  * and if necessary we translate requests and responses between the
2106  * two formats.
2107  */
2108 static int is7 = 0;
2109 
2110 struct ip_fw7 {
2111 	struct ip_fw7	*next;		/* linked list of rules     */
2112 	struct ip_fw7	*next_rule;	/* ptr to next [skipto] rule    */
2113 	/* 'next_rule' is used to pass up 'set_disable' status      */
2114 
2115 	uint16_t	act_ofs;	/* offset of action in 32-bit units */
2116 	uint16_t	cmd_len;	/* # of 32-bit words in cmd */
2117 	uint16_t	rulenum;	/* rule number          */
2118 	uint8_t		set;		/* rule set (0..31)     */
2119 	// #define RESVD_SET   31  /* set for default and persistent rules */
2120 	uint8_t		_pad;		/* padding          */
2121 	// uint32_t        id;             /* rule id, only in v.8 */
2122 	/* These fields are present in all rules.           */
2123 	uint64_t	pcnt;		/* Packet counter       */
2124 	uint64_t	bcnt;		/* Byte counter         */
2125 	uint32_t	timestamp;	/* tv_sec of last match     */
2126 
2127 	ipfw_insn	cmd[1];		/* storage for commands     */
2128 };
2129 
2130 static int convert_rule_to_7(struct ip_fw_rule0 *rule);
2131 static int convert_rule_to_8(struct ip_fw_rule0 *rule);
2132 
2133 #ifndef RULESIZE7
2134 #define RULESIZE7(rule)  (sizeof(struct ip_fw7) + \
2135 	((struct ip_fw7 *)(rule))->cmd_len * 4 - 4)
2136 #endif
2137 
2138 
2139 /*
2140  * Copy the static and dynamic rules to the supplied buffer
2141  * and return the amount of space actually used.
2142  * Must be run under IPFW_UH_RLOCK
2143  */
2144 static size_t
ipfw_getrules(struct ip_fw_chain * chain,void * buf,size_t space)2145 ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
2146 {
2147 	char *bp = buf;
2148 	char *ep = bp + space;
2149 	struct ip_fw *rule;
2150 	struct ip_fw_rule0 *dst;
2151 	struct timeval boottime;
2152 	int error, i, l, warnflag;
2153 	time_t	boot_seconds;
2154 
2155 	warnflag = 0;
2156 
2157 	getboottime(&boottime);
2158         boot_seconds = boottime.tv_sec;
2159 	for (i = 0; i < chain->n_rules; i++) {
2160 		rule = chain->map[i];
2161 
2162 		if (is7) {
2163 		    /* Convert rule to FreeBSd 7.2 format */
2164 		    l = RULESIZE7(rule);
2165 		    if (bp + l + sizeof(uint32_t) <= ep) {
2166 			bcopy(rule, bp, l + sizeof(uint32_t));
2167 			error = set_legacy_obj_kidx(chain,
2168 			    (struct ip_fw_rule0 *)bp);
2169 			if (error != 0)
2170 				return (0);
2171 			error = convert_rule_to_7((struct ip_fw_rule0 *) bp);
2172 			if (error)
2173 				return 0; /*XXX correct? */
2174 			/*
2175 			 * XXX HACK. Store the disable mask in the "next"
2176 			 * pointer in a wild attempt to keep the ABI the same.
2177 			 * Why do we do this on EVERY rule?
2178 			 */
2179 			bcopy(&V_set_disable,
2180 				&(((struct ip_fw7 *)bp)->next_rule),
2181 				sizeof(V_set_disable));
2182 			if (((struct ip_fw7 *)bp)->timestamp)
2183 			    ((struct ip_fw7 *)bp)->timestamp += boot_seconds;
2184 			bp += l;
2185 		    }
2186 		    continue; /* go to next rule */
2187 		}
2188 
2189 		l = RULEUSIZE0(rule);
2190 		if (bp + l > ep) { /* should not happen */
2191 			printf("overflow dumping static rules\n");
2192 			break;
2193 		}
2194 		dst = (struct ip_fw_rule0 *)bp;
2195 		export_rule0(rule, dst, l);
2196 		error = set_legacy_obj_kidx(chain, dst);
2197 
2198 		/*
2199 		 * XXX HACK. Store the disable mask in the "next"
2200 		 * pointer in a wild attempt to keep the ABI the same.
2201 		 * Why do we do this on EVERY rule?
2202 		 *
2203 		 * XXX: "ipfw set show" (ab)uses IP_FW_GET to read disabled mask
2204 		 * so we need to fail _after_ saving at least one mask.
2205 		 */
2206 		bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable));
2207 		if (dst->timestamp)
2208 			dst->timestamp += boot_seconds;
2209 		bp += l;
2210 
2211 		if (error != 0) {
2212 			if (error == 2) {
2213 				/* Non-fatal table rewrite error. */
2214 				warnflag = 1;
2215 				continue;
2216 			}
2217 			printf("Stop on rule %d. Fail to convert table\n",
2218 			    rule->rulenum);
2219 			break;
2220 		}
2221 	}
2222 	if (warnflag != 0)
2223 		printf("ipfw: process %s is using legacy interfaces,"
2224 		    " consider rebuilding\n", "");
2225 	ipfw_get_dynamic(chain, &bp, ep); /* protected by the dynamic lock */
2226 	return (bp - (char *)buf);
2227 }
2228 
2229 
2230 struct dump_args {
2231 	uint32_t	b;	/* start rule */
2232 	uint32_t	e;	/* end rule */
2233 	uint32_t	rcount;	/* number of rules */
2234 	uint32_t	rsize;	/* rules size */
2235 	uint32_t	tcount;	/* number of tables */
2236 	int		rcounters;	/* counters */
2237 	uint32_t	*bmask;	/* index bitmask of used named objects */
2238 };
2239 
2240 void
ipfw_export_obj_ntlv(struct named_object * no,ipfw_obj_ntlv * ntlv)2241 ipfw_export_obj_ntlv(struct named_object *no, ipfw_obj_ntlv *ntlv)
2242 {
2243 
2244 	ntlv->head.type = no->etlv;
2245 	ntlv->head.length = sizeof(*ntlv);
2246 	ntlv->idx = no->kidx;
2247 	strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
2248 }
2249 
2250 /*
2251  * Export named object info in instance @ni, identified by @kidx
2252  * to ipfw_obj_ntlv. TLV is allocated from @sd space.
2253  *
2254  * Returns 0 on success.
2255  */
2256 static int
export_objhash_ntlv(struct namedobj_instance * ni,uint16_t kidx,struct sockopt_data * sd)2257 export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
2258     struct sockopt_data *sd)
2259 {
2260 	struct named_object *no;
2261 	ipfw_obj_ntlv *ntlv;
2262 
2263 	no = ipfw_objhash_lookup_kidx(ni, kidx);
2264 	KASSERT(no != NULL, ("invalid object kernel index passed"));
2265 
2266 	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
2267 	if (ntlv == NULL)
2268 		return (ENOMEM);
2269 
2270 	ipfw_export_obj_ntlv(no, ntlv);
2271 	return (0);
2272 }
2273 
2274 static int
export_named_objects(struct namedobj_instance * ni,struct dump_args * da,struct sockopt_data * sd)2275 export_named_objects(struct namedobj_instance *ni, struct dump_args *da,
2276     struct sockopt_data *sd)
2277 {
2278 	int error, i;
2279 
2280 	for (i = 0; i < IPFW_TABLES_MAX && da->tcount > 0; i++) {
2281 		if ((da->bmask[i / 32] & (1 << (i % 32))) == 0)
2282 			continue;
2283 		if ((error = export_objhash_ntlv(ni, i, sd)) != 0)
2284 			return (error);
2285 		da->tcount--;
2286 	}
2287 	return (0);
2288 }
2289 
2290 static int
dump_named_objects(struct ip_fw_chain * ch,struct dump_args * da,struct sockopt_data * sd)2291 dump_named_objects(struct ip_fw_chain *ch, struct dump_args *da,
2292     struct sockopt_data *sd)
2293 {
2294 	ipfw_obj_ctlv *ctlv;
2295 	int error;
2296 
2297 	MPASS(da->tcount > 0);
2298 	/* Header first */
2299 	ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
2300 	if (ctlv == NULL)
2301 		return (ENOMEM);
2302 	ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
2303 	ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) +
2304 	    sizeof(*ctlv);
2305 	ctlv->count = da->tcount;
2306 	ctlv->objsize = sizeof(ipfw_obj_ntlv);
2307 
2308 	/* Dump table names first (if any) */
2309 	error = export_named_objects(ipfw_get_table_objhash(ch), da, sd);
2310 	if (error != 0)
2311 		return (error);
2312 	/* Then dump another named objects */
2313 	da->bmask += IPFW_TABLES_MAX / 32;
2314 	return (export_named_objects(CHAIN_TO_SRV(ch), da, sd));
2315 }
2316 
2317 /*
2318  * Dumps static rules with table TLVs in buffer @sd.
2319  *
2320  * Returns 0 on success.
2321  */
2322 static int
dump_static_rules(struct ip_fw_chain * chain,struct dump_args * da,struct sockopt_data * sd)2323 dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
2324     struct sockopt_data *sd)
2325 {
2326 	ipfw_obj_ctlv *ctlv;
2327 	struct ip_fw *krule;
2328 	caddr_t dst;
2329 	int i, l;
2330 
2331 	/* Dump rules */
2332 	ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
2333 	if (ctlv == NULL)
2334 		return (ENOMEM);
2335 	ctlv->head.type = IPFW_TLV_RULE_LIST;
2336 	ctlv->head.length = da->rsize + sizeof(*ctlv);
2337 	ctlv->count = da->rcount;
2338 
2339 	for (i = da->b; i < da->e; i++) {
2340 		krule = chain->map[i];
2341 
2342 		l = RULEUSIZE1(krule) + sizeof(ipfw_obj_tlv);
2343 		if (da->rcounters != 0)
2344 			l += sizeof(struct ip_fw_bcounter);
2345 		dst = (caddr_t)ipfw_get_sopt_space(sd, l);
2346 		if (dst == NULL)
2347 			return (ENOMEM);
2348 
2349 		export_rule1(krule, dst, l, da->rcounters);
2350 	}
2351 
2352 	return (0);
2353 }
2354 
2355 int
ipfw_mark_object_kidx(uint32_t * bmask,uint16_t etlv,uint16_t kidx)2356 ipfw_mark_object_kidx(uint32_t *bmask, uint16_t etlv, uint16_t kidx)
2357 {
2358 	uint32_t bidx;
2359 
2360 	/*
2361 	 * Maintain separate bitmasks for table and non-table objects.
2362 	 */
2363 	bidx = (etlv == IPFW_TLV_TBL_NAME) ? 0: IPFW_TABLES_MAX / 32;
2364 	bidx += kidx / 32;
2365 	if ((bmask[bidx] & (1 << (kidx % 32))) != 0)
2366 		return (0);
2367 
2368 	bmask[bidx] |= 1 << (kidx % 32);
2369 	return (1);
2370 }
2371 
2372 /*
2373  * Marks every object index used in @rule with bit in @bmask.
2374  * Used to generate bitmask of referenced tables/objects for given ruleset
2375  * or its part.
2376  */
2377 static void
mark_rule_objects(struct ip_fw_chain * ch,struct ip_fw * rule,struct dump_args * da)2378 mark_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
2379     struct dump_args *da)
2380 {
2381 	struct opcode_obj_rewrite *rw;
2382 	ipfw_insn *cmd;
2383 	int cmdlen, l;
2384 	uint16_t kidx;
2385 	uint8_t subtype;
2386 
2387 	l = rule->cmd_len;
2388 	cmd = rule->cmd;
2389 	cmdlen = 0;
2390 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2391 		cmdlen = F_LEN(cmd);
2392 
2393 		rw = find_op_rw(cmd, &kidx, &subtype);
2394 		if (rw == NULL)
2395 			continue;
2396 
2397 		if (ipfw_mark_object_kidx(da->bmask, rw->etlv, kidx))
2398 			da->tcount++;
2399 	}
2400 }
2401 
2402 /*
2403  * Dumps requested objects data
2404  * Data layout (version 0)(current):
2405  * Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags
2406  *   size = ipfw_cfg_lheader.size
2407  * Reply: [ ipfw_cfg_lheader
2408  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
2409  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST)
2410  *     ipfw_obj_tlv(IPFW_TLV_RULE_ENT) [ ip_fw_bcounter (optional) ip_fw_rule ]
2411  *   ] (optional)
2412  *   [ ipfw_obj_ctlv(IPFW_TLV_STATE_LIST) ipfw_obj_dyntlv x N ] (optional)
2413  * ]
2414  * * NOTE IPFW_TLV_STATE_LIST has the single valid field: objsize.
2415  * The rest (size, count) are set to zero and needs to be ignored.
2416  *
2417  * Returns 0 on success.
2418  */
2419 static int
dump_config(struct ip_fw_chain * chain,ip_fw3_opheader * op3,struct sockopt_data * sd)2420 dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2421     struct sockopt_data *sd)
2422 {
2423 	struct dump_args da;
2424 	ipfw_cfg_lheader *hdr;
2425 	struct ip_fw *rule;
2426 	size_t sz, rnum;
2427 	uint32_t hdr_flags, *bmask;
2428 	int error, i;
2429 
2430 	hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
2431 	if (hdr == NULL)
2432 		return (EINVAL);
2433 
2434 	error = 0;
2435 	bmask = NULL;
2436 	memset(&da, 0, sizeof(da));
2437 	/*
2438 	 * Allocate needed state.
2439 	 * Note we allocate 2xspace mask, for table & srv
2440 	 */
2441 	if (hdr->flags & (IPFW_CFG_GET_STATIC | IPFW_CFG_GET_STATES))
2442 		da.bmask = bmask = malloc(
2443 		    sizeof(uint32_t) * IPFW_TABLES_MAX * 2 / 32, M_TEMP,
2444 		    M_WAITOK | M_ZERO);
2445 	IPFW_UH_RLOCK(chain);
2446 
2447 	/*
2448 	 * STAGE 1: Determine size/count for objects in range.
2449 	 * Prepare used tables bitmask.
2450 	 */
2451 	sz = sizeof(ipfw_cfg_lheader);
2452 	da.e = chain->n_rules;
2453 
2454 	if (hdr->end_rule != 0) {
2455 		/* Handle custom range */
2456 		if ((rnum = hdr->start_rule) > IPFW_DEFAULT_RULE)
2457 			rnum = IPFW_DEFAULT_RULE;
2458 		da.b = ipfw_find_rule(chain, rnum, 0);
2459 		rnum = (hdr->end_rule < IPFW_DEFAULT_RULE) ?
2460 		    hdr->end_rule + 1: IPFW_DEFAULT_RULE;
2461 		da.e = ipfw_find_rule(chain, rnum, UINT32_MAX) + 1;
2462 	}
2463 
2464 	if (hdr->flags & IPFW_CFG_GET_STATIC) {
2465 		for (i = da.b; i < da.e; i++) {
2466 			rule = chain->map[i];
2467 			da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv);
2468 			da.rcount++;
2469 			/* Update bitmask of used objects for given range */
2470 			mark_rule_objects(chain, rule, &da);
2471 		}
2472 		/* Add counters if requested */
2473 		if (hdr->flags & IPFW_CFG_GET_COUNTERS) {
2474 			da.rsize += sizeof(struct ip_fw_bcounter) * da.rcount;
2475 			da.rcounters = 1;
2476 		}
2477 		sz += da.rsize + sizeof(ipfw_obj_ctlv);
2478 	}
2479 
2480 	if (hdr->flags & IPFW_CFG_GET_STATES) {
2481 		sz += sizeof(ipfw_obj_ctlv) +
2482 		    ipfw_dyn_get_count(bmask, &i) * sizeof(ipfw_obj_dyntlv);
2483 		da.tcount += i;
2484 	}
2485 
2486 	if (da.tcount > 0)
2487 		sz += da.tcount * sizeof(ipfw_obj_ntlv) +
2488 		    sizeof(ipfw_obj_ctlv);
2489 
2490 	/*
2491 	 * Fill header anyway.
2492 	 * Note we have to save header fields to stable storage
2493 	 * buffer inside @sd can be flushed after dumping rules
2494 	 */
2495 	hdr->size = sz;
2496 	hdr->set_mask = ~V_set_disable;
2497 	hdr_flags = hdr->flags;
2498 	hdr = NULL;
2499 
2500 	if (sd->valsize < sz) {
2501 		error = ENOMEM;
2502 		goto cleanup;
2503 	}
2504 
2505 	/* STAGE2: Store actual data */
2506 	if (da.tcount > 0) {
2507 		error = dump_named_objects(chain, &da, sd);
2508 		if (error != 0)
2509 			goto cleanup;
2510 	}
2511 
2512 	if (hdr_flags & IPFW_CFG_GET_STATIC) {
2513 		error = dump_static_rules(chain, &da, sd);
2514 		if (error != 0)
2515 			goto cleanup;
2516 	}
2517 
2518 	if (hdr_flags & IPFW_CFG_GET_STATES)
2519 		error = ipfw_dump_states(chain, sd);
2520 
2521 cleanup:
2522 	IPFW_UH_RUNLOCK(chain);
2523 
2524 	if (bmask != NULL)
2525 		free(bmask, M_TEMP);
2526 
2527 	return (error);
2528 }
2529 
2530 int
ipfw_check_object_name_generic(const char * name)2531 ipfw_check_object_name_generic(const char *name)
2532 {
2533 	int nsize;
2534 
2535 	nsize = sizeof(((ipfw_obj_ntlv *)0)->name);
2536 	if (strnlen(name, nsize) == nsize)
2537 		return (EINVAL);
2538 	if (name[0] == '\0')
2539 		return (EINVAL);
2540 	return (0);
2541 }
2542 
2543 /*
2544  * Creates non-existent objects referenced by rule.
2545  *
2546  * Return 0 on success.
2547  */
2548 int
create_objects_compat(struct ip_fw_chain * ch,ipfw_insn * cmd,struct obj_idx * oib,struct obj_idx * pidx,struct tid_info * ti)2549 create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd,
2550     struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti)
2551 {
2552 	struct opcode_obj_rewrite *rw;
2553 	struct obj_idx *p;
2554 	uint16_t kidx;
2555 	int error;
2556 
2557 	/*
2558 	 * Compatibility stuff: do actual creation for non-existing,
2559 	 * but referenced objects.
2560 	 */
2561 	for (p = oib; p < pidx; p++) {
2562 		if (p->kidx != 0)
2563 			continue;
2564 
2565 		ti->uidx = p->uidx;
2566 		ti->type = p->type;
2567 		ti->atype = 0;
2568 
2569 		rw = find_op_rw(cmd + p->off, NULL, NULL);
2570 		KASSERT(rw != NULL, ("Unable to find handler for op %d",
2571 		    (cmd + p->off)->opcode));
2572 
2573 		if (rw->create_object == NULL)
2574 			error = EOPNOTSUPP;
2575 		else
2576 			error = rw->create_object(ch, ti, &kidx);
2577 		if (error == 0) {
2578 			p->kidx = kidx;
2579 			continue;
2580 		}
2581 
2582 		/*
2583 		 * Error happened. We have to rollback everything.
2584 		 * Drop all already acquired references.
2585 		 */
2586 		IPFW_UH_WLOCK(ch);
2587 		unref_oib_objects(ch, cmd, oib, pidx);
2588 		IPFW_UH_WUNLOCK(ch);
2589 
2590 		return (error);
2591 	}
2592 
2593 	return (0);
2594 }
2595 
2596 /*
2597  * Compatibility function for old ipfw(8) binaries.
2598  * Rewrites table/nat kernel indices with userland ones.
2599  * Convert tables matching '/^\d+$/' to their atoi() value.
2600  * Use number 65535 for other tables.
2601  *
2602  * Returns 0 on success.
2603  */
2604 static int
set_legacy_obj_kidx(struct ip_fw_chain * ch,struct ip_fw_rule0 * rule)2605 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule)
2606 {
2607 	struct opcode_obj_rewrite *rw;
2608 	struct named_object *no;
2609 	ipfw_insn *cmd;
2610 	char *end;
2611 	long val;
2612 	int cmdlen, error, l;
2613 	uint16_t kidx, uidx;
2614 	uint8_t subtype;
2615 
2616 	error = 0;
2617 
2618 	l = rule->cmd_len;
2619 	cmd = rule->cmd;
2620 	cmdlen = 0;
2621 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2622 		cmdlen = F_LEN(cmd);
2623 
2624 		/* Check if is index in given opcode */
2625 		rw = find_op_rw(cmd, &kidx, &subtype);
2626 		if (rw == NULL)
2627 			continue;
2628 
2629 		/* Try to find referenced kernel object */
2630 		no = rw->find_bykidx(ch, kidx);
2631 		if (no == NULL)
2632 			continue;
2633 
2634 		val = strtol(no->name, &end, 10);
2635 		if (*end == '\0' && val < 65535) {
2636 			uidx = val;
2637 		} else {
2638 
2639 			/*
2640 			 * We are called via legacy opcode.
2641 			 * Save error and show table as fake number
2642 			 * not to make ipfw(8) hang.
2643 			 */
2644 			uidx = 65535;
2645 			error = 2;
2646 		}
2647 
2648 		rw->update(cmd, uidx);
2649 	}
2650 
2651 	return (error);
2652 }
2653 
2654 
2655 /*
2656  * Unreferences all already-referenced objects in given @cmd rule,
2657  * using information in @oib.
2658  *
2659  * Used to rollback partially converted rule on error.
2660  */
2661 static void
unref_oib_objects(struct ip_fw_chain * ch,ipfw_insn * cmd,struct obj_idx * oib,struct obj_idx * end)2662 unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib,
2663     struct obj_idx *end)
2664 {
2665 	struct opcode_obj_rewrite *rw;
2666 	struct named_object *no;
2667 	struct obj_idx *p;
2668 
2669 	IPFW_UH_WLOCK_ASSERT(ch);
2670 
2671 	for (p = oib; p < end; p++) {
2672 		if (p->kidx == 0)
2673 			continue;
2674 
2675 		rw = find_op_rw(cmd + p->off, NULL, NULL);
2676 		KASSERT(rw != NULL, ("Unable to find handler for op %d",
2677 		    (cmd + p->off)->opcode));
2678 
2679 		/* Find & unref by existing idx */
2680 		no = rw->find_bykidx(ch, p->kidx);
2681 		KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx));
2682 		no->refcnt--;
2683 	}
2684 }
2685 
2686 /*
2687  * Remove references from every object used in @rule.
2688  * Used at rule removal code.
2689  */
2690 static void
unref_rule_objects(struct ip_fw_chain * ch,struct ip_fw * rule)2691 unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule)
2692 {
2693 	struct opcode_obj_rewrite *rw;
2694 	struct named_object *no;
2695 	ipfw_insn *cmd;
2696 	int cmdlen, l;
2697 	uint16_t kidx;
2698 	uint8_t subtype;
2699 
2700 	IPFW_UH_WLOCK_ASSERT(ch);
2701 
2702 	l = rule->cmd_len;
2703 	cmd = rule->cmd;
2704 	cmdlen = 0;
2705 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2706 		cmdlen = F_LEN(cmd);
2707 
2708 		rw = find_op_rw(cmd, &kidx, &subtype);
2709 		if (rw == NULL)
2710 			continue;
2711 		no = rw->find_bykidx(ch, kidx);
2712 
2713 		KASSERT(no != NULL, ("object id %d not found", kidx));
2714 		KASSERT(no->subtype == subtype,
2715 		    ("wrong type %d (%d) for object id %d",
2716 		    no->subtype, subtype, kidx));
2717 		KASSERT(no->refcnt > 0, ("refcount for object %d is %d",
2718 		    kidx, no->refcnt));
2719 
2720 		if (no->refcnt == 1 && rw->destroy_object != NULL)
2721 			rw->destroy_object(ch, no);
2722 		else
2723 			no->refcnt--;
2724 	}
2725 }
2726 
2727 
2728 /*
2729  * Find and reference object (if any) stored in instruction @cmd.
2730  *
2731  * Saves object info in @pidx, sets
2732  *  - @unresolved to 1 if object should exists but not found
2733  *
2734  * Returns non-zero value in case of error.
2735  */
2736 static int
ref_opcode_object(struct ip_fw_chain * ch,ipfw_insn * cmd,struct tid_info * ti,struct obj_idx * pidx,int * unresolved)2737 ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti,
2738     struct obj_idx *pidx, int *unresolved)
2739 {
2740 	struct named_object *no;
2741 	struct opcode_obj_rewrite *rw;
2742 	int error;
2743 
2744 	/* Check if this opcode is candidate for rewrite */
2745 	rw = find_op_rw(cmd, &ti->uidx, &ti->type);
2746 	if (rw == NULL)
2747 		return (0);
2748 
2749 	/* Need to rewrite. Save necessary fields */
2750 	pidx->uidx = ti->uidx;
2751 	pidx->type = ti->type;
2752 
2753 	/* Try to find referenced kernel object */
2754 	error = rw->find_byname(ch, ti, &no);
2755 	if (error != 0)
2756 		return (error);
2757 	if (no == NULL) {
2758 		/*
2759 		 * Report about unresolved object for automaic
2760 		 * creation.
2761 		 */
2762 		*unresolved = 1;
2763 		return (0);
2764 	}
2765 
2766 	/*
2767 	 * Object is already exist.
2768 	 * Its subtype should match with expected value.
2769 	 */
2770 	if (ti->type != no->subtype)
2771 		return (EINVAL);
2772 
2773 	/* Bump refcount and update kidx. */
2774 	no->refcnt++;
2775 	rw->update(cmd, no->kidx);
2776 	return (0);
2777 }
2778 
2779 /*
2780  * Finds and bumps refcount for objects referenced by given @rule.
2781  * Auto-creates non-existing tables.
2782  * Fills in @oib array with userland/kernel indexes.
2783  *
2784  * Returns 0 on success.
2785  */
2786 static int
ref_rule_objects(struct ip_fw_chain * ch,struct ip_fw * rule,struct rule_check_info * ci,struct obj_idx * oib,struct tid_info * ti)2787 ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
2788     struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti)
2789 {
2790 	struct obj_idx *pidx;
2791 	ipfw_insn *cmd;
2792 	int cmdlen, error, l, unresolved;
2793 
2794 	pidx = oib;
2795 	l = rule->cmd_len;
2796 	cmd = rule->cmd;
2797 	cmdlen = 0;
2798 	error = 0;
2799 
2800 	IPFW_UH_WLOCK(ch);
2801 
2802 	/* Increase refcount on each existing referenced table. */
2803 	for ( ;	l > 0 ; l -= cmdlen, cmd += cmdlen) {
2804 		cmdlen = F_LEN(cmd);
2805 		unresolved = 0;
2806 
2807 		error = ref_opcode_object(ch, cmd, ti, pidx, &unresolved);
2808 		if (error != 0)
2809 			break;
2810 		/*
2811 		 * Compatibility stuff for old clients:
2812 		 * prepare to automaitcally create non-existing objects.
2813 		 */
2814 		if (unresolved != 0) {
2815 			pidx->off = rule->cmd_len - l;
2816 			pidx++;
2817 		}
2818 	}
2819 
2820 	if (error != 0) {
2821 		/* Unref everything we have already done */
2822 		unref_oib_objects(ch, rule->cmd, oib, pidx);
2823 		IPFW_UH_WUNLOCK(ch);
2824 		return (error);
2825 	}
2826 	IPFW_UH_WUNLOCK(ch);
2827 
2828 	/* Perform auto-creation for non-existing objects */
2829 	if (pidx != oib)
2830 		error = create_objects_compat(ch, rule->cmd, oib, pidx, ti);
2831 
2832 	/* Calculate real number of dynamic objects */
2833 	ci->object_opcodes = (uint16_t)(pidx - oib);
2834 
2835 	return (error);
2836 }
2837 
2838 /*
2839  * Checks is opcode is referencing table of appropriate type.
2840  * Adds reference count for found table if true.
2841  * Rewrites user-supplied opcode values with kernel ones.
2842  *
2843  * Returns 0 on success and appropriate error code otherwise.
2844  */
2845 static int
rewrite_rule_uidx(struct ip_fw_chain * chain,struct rule_check_info * ci)2846 rewrite_rule_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci)
2847 {
2848 	int error;
2849 	ipfw_insn *cmd;
2850 	uint8_t type;
2851 	struct obj_idx *p, *pidx_first, *pidx_last;
2852 	struct tid_info ti;
2853 
2854 	/*
2855 	 * Prepare an array for storing opcode indices.
2856 	 * Use stack allocation by default.
2857 	 */
2858 	if (ci->object_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
2859 		/* Stack */
2860 		pidx_first = ci->obuf;
2861 	} else
2862 		pidx_first = malloc(
2863 		    ci->object_opcodes * sizeof(struct obj_idx),
2864 		    M_IPFW, M_WAITOK | M_ZERO);
2865 
2866 	error = 0;
2867 	type = 0;
2868 	memset(&ti, 0, sizeof(ti));
2869 
2870 	/* Use set rule is assigned to. */
2871 	ti.set = ci->krule->set;
2872 	if (ci->ctlv != NULL) {
2873 		ti.tlvs = (void *)(ci->ctlv + 1);
2874 		ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
2875 	}
2876 
2877 	/* Reference all used tables and other objects */
2878 	error = ref_rule_objects(chain, ci->krule, ci, pidx_first, &ti);
2879 	if (error != 0)
2880 		goto free;
2881 	/*
2882 	 * Note that ref_rule_objects() might have updated ci->object_opcodes
2883 	 * to reflect actual number of object opcodes.
2884 	 */
2885 
2886 	/* Perform rewrite of remaining opcodes */
2887 	p = pidx_first;
2888 	pidx_last = pidx_first + ci->object_opcodes;
2889 	for (p = pidx_first; p < pidx_last; p++) {
2890 		cmd = ci->krule->cmd + p->off;
2891 		update_opcode_kidx(cmd, p->kidx);
2892 	}
2893 
2894 free:
2895 	if (pidx_first != ci->obuf)
2896 		free(pidx_first, M_IPFW);
2897 
2898 	return (error);
2899 }
2900 
2901 /*
2902  * Adds one or more rules to ipfw @chain.
2903  * Data layout (version 0)(current):
2904  * Request:
2905  * [
2906  *   ip_fw3_opheader
2907  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1)
2908  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3)
2909  * ]
2910  * Reply:
2911  * [
2912  *   ip_fw3_opheader
2913  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
2914  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ]
2915  * ]
2916  *
2917  * Rules in reply are modified to store their actual ruleset number.
2918  *
2919  * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending
2920  * according to their idx field and there has to be no duplicates.
2921  * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending.
2922  * (*3) Each ip_fw structure needs to be aligned to u64 boundary.
2923  *
2924  * Returns 0 on success.
2925  */
2926 static int
add_rules(struct ip_fw_chain * chain,ip_fw3_opheader * op3,struct sockopt_data * sd)2927 add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2928     struct sockopt_data *sd)
2929 {
2930 	ipfw_obj_ctlv *ctlv, *rtlv, *tstate;
2931 	ipfw_obj_ntlv *ntlv;
2932 	int clen, error, idx;
2933 	uint32_t count, read;
2934 	struct ip_fw_rule *r;
2935 	struct rule_check_info rci, *ci, *cbuf;
2936 	int i, rsize;
2937 
2938 	op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize);
2939 	ctlv = (ipfw_obj_ctlv *)(op3 + 1);
2940 
2941 	read = sizeof(ip_fw3_opheader);
2942 	rtlv = NULL;
2943 	tstate = NULL;
2944 	cbuf = NULL;
2945 	memset(&rci, 0, sizeof(struct rule_check_info));
2946 
2947 	if (read + sizeof(*ctlv) > sd->valsize)
2948 		return (EINVAL);
2949 
2950 	if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
2951 		clen = ctlv->head.length;
2952 		/* Check size and alignment */
2953 		if (clen > sd->valsize || clen < sizeof(*ctlv))
2954 			return (EINVAL);
2955 		if ((clen % sizeof(uint64_t)) != 0)
2956 			return (EINVAL);
2957 
2958 		/*
2959 		 * Some table names or other named objects.
2960 		 * Check for validness.
2961 		 */
2962 		count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv);
2963 		if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv))
2964 			return (EINVAL);
2965 
2966 		/*
2967 		 * Check each TLV.
2968 		 * Ensure TLVs are sorted ascending and
2969 		 * there are no duplicates.
2970 		 */
2971 		idx = -1;
2972 		ntlv = (ipfw_obj_ntlv *)(ctlv + 1);
2973 		while (count > 0) {
2974 			if (ntlv->head.length != sizeof(ipfw_obj_ntlv))
2975 				return (EINVAL);
2976 
2977 			error = ipfw_check_object_name_generic(ntlv->name);
2978 			if (error != 0)
2979 				return (error);
2980 
2981 			if (ntlv->idx <= idx)
2982 				return (EINVAL);
2983 
2984 			idx = ntlv->idx;
2985 			count--;
2986 			ntlv++;
2987 		}
2988 
2989 		tstate = ctlv;
2990 		read += ctlv->head.length;
2991 		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
2992 	}
2993 
2994 	if (read + sizeof(*ctlv) > sd->valsize)
2995 		return (EINVAL);
2996 
2997 	if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
2998 		clen = ctlv->head.length;
2999 		if (clen + read > sd->valsize || clen < sizeof(*ctlv))
3000 			return (EINVAL);
3001 		if ((clen % sizeof(uint64_t)) != 0)
3002 			return (EINVAL);
3003 
3004 		/*
3005 		 * TODO: Permit adding multiple rules at once
3006 		 */
3007 		if (ctlv->count != 1)
3008 			return (ENOTSUP);
3009 
3010 		clen -= sizeof(*ctlv);
3011 
3012 		if (ctlv->count > clen / sizeof(struct ip_fw_rule))
3013 			return (EINVAL);
3014 
3015 		/* Allocate state for each rule or use stack */
3016 		if (ctlv->count == 1) {
3017 			memset(&rci, 0, sizeof(struct rule_check_info));
3018 			cbuf = &rci;
3019 		} else
3020 			cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP,
3021 			    M_WAITOK | M_ZERO);
3022 		ci = cbuf;
3023 
3024 		/*
3025 		 * Check each rule for validness.
3026 		 * Ensure numbered rules are sorted ascending
3027 		 * and properly aligned
3028 		 */
3029 		idx = 0;
3030 		r = (struct ip_fw_rule *)(ctlv + 1);
3031 		count = 0;
3032 		error = 0;
3033 		while (clen > 0) {
3034 			rsize = roundup2(RULESIZE(r), sizeof(uint64_t));
3035 			if (rsize > clen || ctlv->count <= count) {
3036 				error = EINVAL;
3037 				break;
3038 			}
3039 
3040 			ci->ctlv = tstate;
3041 			error = check_ipfw_rule1(r, rsize, ci);
3042 			if (error != 0)
3043 				break;
3044 
3045 			/* Check sorting */
3046 			if (r->rulenum != 0 && r->rulenum < idx) {
3047 				printf("rulenum %d idx %d\n", r->rulenum, idx);
3048 				error = EINVAL;
3049 				break;
3050 			}
3051 			idx = r->rulenum;
3052 
3053 			ci->urule = (caddr_t)r;
3054 
3055 			rsize = roundup2(rsize, sizeof(uint64_t));
3056 			clen -= rsize;
3057 			r = (struct ip_fw_rule *)((caddr_t)r + rsize);
3058 			count++;
3059 			ci++;
3060 		}
3061 
3062 		if (ctlv->count != count || error != 0) {
3063 			if (cbuf != &rci)
3064 				free(cbuf, M_TEMP);
3065 			return (EINVAL);
3066 		}
3067 
3068 		rtlv = ctlv;
3069 		read += ctlv->head.length;
3070 		ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
3071 	}
3072 
3073 	if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) {
3074 		if (cbuf != NULL && cbuf != &rci)
3075 			free(cbuf, M_TEMP);
3076 		return (EINVAL);
3077 	}
3078 
3079 	/*
3080 	 * Passed rules seems to be valid.
3081 	 * Allocate storage and try to add them to chain.
3082 	 */
3083 	for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) {
3084 		clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule);
3085 		ci->krule = ipfw_alloc_rule(chain, clen);
3086 		import_rule1(ci);
3087 	}
3088 
3089 	if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) {
3090 		/* Free allocate krules */
3091 		for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++)
3092 			ipfw_free_rule(ci->krule);
3093 	}
3094 
3095 	if (cbuf != NULL && cbuf != &rci)
3096 		free(cbuf, M_TEMP);
3097 
3098 	return (error);
3099 }
3100 
3101 /*
3102  * Lists all sopts currently registered.
3103  * Data layout (v0)(current):
3104  * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
3105  * Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ]
3106  *
3107  * Returns 0 on success
3108  */
3109 static int
dump_soptcodes(struct ip_fw_chain * chain,ip_fw3_opheader * op3,struct sockopt_data * sd)3110 dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
3111     struct sockopt_data *sd)
3112 {
3113 	struct _ipfw_obj_lheader *olh;
3114 	ipfw_sopt_info *i;
3115 	struct ipfw_sopt_handler *sh;
3116 	uint32_t count, n, size;
3117 
3118 	olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
3119 	if (olh == NULL)
3120 		return (EINVAL);
3121 	if (sd->valsize < olh->size)
3122 		return (EINVAL);
3123 
3124 	CTL3_LOCK();
3125 	count = ctl3_hsize;
3126 	size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader);
3127 
3128 	/* Fill in header regadless of buffer size */
3129 	olh->count = count;
3130 	olh->objsize = sizeof(ipfw_sopt_info);
3131 
3132 	if (size > olh->size) {
3133 		olh->size = size;
3134 		CTL3_UNLOCK();
3135 		return (ENOMEM);
3136 	}
3137 	olh->size = size;
3138 
3139 	for (n = 1; n <= count; n++) {
3140 		i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i));
3141 		KASSERT(i != NULL, ("previously checked buffer is not enough"));
3142 		sh = &ctl3_handlers[n];
3143 		i->opcode = sh->opcode;
3144 		i->version = sh->version;
3145 		i->refcnt = sh->refcnt;
3146 	}
3147 	CTL3_UNLOCK();
3148 
3149 	return (0);
3150 }
3151 
3152 /*
3153  * Compares two opcodes.
3154  * Used both in qsort() and bsearch().
3155  *
3156  * Returns 0 if match is found.
3157  */
3158 static int
compare_opcodes(const void * _a,const void * _b)3159 compare_opcodes(const void *_a, const void *_b)
3160 {
3161 	const struct opcode_obj_rewrite *a, *b;
3162 
3163 	a = (const struct opcode_obj_rewrite *)_a;
3164 	b = (const struct opcode_obj_rewrite *)_b;
3165 
3166 	if (a->opcode < b->opcode)
3167 		return (-1);
3168 	else if (a->opcode > b->opcode)
3169 		return (1);
3170 
3171 	return (0);
3172 }
3173 
3174 /*
3175  * XXX: Rewrite bsearch()
3176  */
3177 static int
find_op_rw_range(uint16_t op,struct opcode_obj_rewrite ** plo,struct opcode_obj_rewrite ** phi)3178 find_op_rw_range(uint16_t op, struct opcode_obj_rewrite **plo,
3179     struct opcode_obj_rewrite **phi)
3180 {
3181 	struct opcode_obj_rewrite *ctl3_max, *lo, *hi, h, *rw;
3182 
3183 	memset(&h, 0, sizeof(h));
3184 	h.opcode = op;
3185 
3186 	rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters,
3187 	    ctl3_rsize, sizeof(h), compare_opcodes);
3188 	if (rw == NULL)
3189 		return (1);
3190 
3191 	/* Find the first element matching the same opcode */
3192 	lo = rw;
3193 	for ( ; lo > ctl3_rewriters && (lo - 1)->opcode == op; lo--)
3194 		;
3195 
3196 	/* Find the last element matching the same opcode */
3197 	hi = rw;
3198 	ctl3_max = ctl3_rewriters + ctl3_rsize;
3199 	for ( ; (hi + 1) < ctl3_max && (hi + 1)->opcode == op; hi++)
3200 		;
3201 
3202 	*plo = lo;
3203 	*phi = hi;
3204 
3205 	return (0);
3206 }
3207 
3208 /*
3209  * Finds opcode object rewriter based on @code.
3210  *
3211  * Returns pointer to handler or NULL.
3212  */
3213 static struct opcode_obj_rewrite *
find_op_rw(ipfw_insn * cmd,uint16_t * puidx,uint8_t * ptype)3214 find_op_rw(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
3215 {
3216 	struct opcode_obj_rewrite *rw, *lo, *hi;
3217 	uint16_t uidx;
3218 	uint8_t subtype;
3219 
3220 	if (find_op_rw_range(cmd->opcode, &lo, &hi) != 0)
3221 		return (NULL);
3222 
3223 	for (rw = lo; rw <= hi; rw++) {
3224 		if (rw->classifier(cmd, &uidx, &subtype) == 0) {
3225 			if (puidx != NULL)
3226 				*puidx = uidx;
3227 			if (ptype != NULL)
3228 				*ptype = subtype;
3229 			return (rw);
3230 		}
3231 	}
3232 
3233 	return (NULL);
3234 }
3235 int
classify_opcode_kidx(ipfw_insn * cmd,uint16_t * puidx)3236 classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx)
3237 {
3238 
3239 	if (find_op_rw(cmd, puidx, NULL) == NULL)
3240 		return (1);
3241 	return (0);
3242 }
3243 
3244 void
update_opcode_kidx(ipfw_insn * cmd,uint16_t idx)3245 update_opcode_kidx(ipfw_insn *cmd, uint16_t idx)
3246 {
3247 	struct opcode_obj_rewrite *rw;
3248 
3249 	rw = find_op_rw(cmd, NULL, NULL);
3250 	KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode));
3251 	rw->update(cmd, idx);
3252 }
3253 
3254 void
ipfw_init_obj_rewriter()3255 ipfw_init_obj_rewriter()
3256 {
3257 
3258 	ctl3_rewriters = NULL;
3259 	ctl3_rsize = 0;
3260 }
3261 
3262 void
ipfw_destroy_obj_rewriter()3263 ipfw_destroy_obj_rewriter()
3264 {
3265 
3266 	if (ctl3_rewriters != NULL)
3267 		free(ctl3_rewriters, M_IPFW);
3268 	ctl3_rewriters = NULL;
3269 	ctl3_rsize = 0;
3270 }
3271 
3272 /*
3273  * Adds one or more opcode object rewrite handlers to the global array.
3274  * Function may sleep.
3275  */
3276 void
ipfw_add_obj_rewriter(struct opcode_obj_rewrite * rw,size_t count)3277 ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
3278 {
3279 	size_t sz;
3280 	struct opcode_obj_rewrite *tmp;
3281 
3282 	CTL3_LOCK();
3283 
3284 	for (;;) {
3285 		sz = ctl3_rsize + count;
3286 		CTL3_UNLOCK();
3287 		tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO);
3288 		CTL3_LOCK();
3289 		if (ctl3_rsize + count <= sz)
3290 			break;
3291 
3292 		/* Retry */
3293 		free(tmp, M_IPFW);
3294 	}
3295 
3296 	/* Merge old & new arrays */
3297 	sz = ctl3_rsize + count;
3298 	memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw));
3299 	memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw));
3300 	qsort(tmp, sz, sizeof(*rw), compare_opcodes);
3301 	/* Switch new and free old */
3302 	if (ctl3_rewriters != NULL)
3303 		free(ctl3_rewriters, M_IPFW);
3304 	ctl3_rewriters = tmp;
3305 	ctl3_rsize = sz;
3306 
3307 	CTL3_UNLOCK();
3308 }
3309 
3310 /*
3311  * Removes one or more object rewrite handlers from the global array.
3312  */
3313 int
ipfw_del_obj_rewriter(struct opcode_obj_rewrite * rw,size_t count)3314 ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
3315 {
3316 	size_t sz;
3317 	struct opcode_obj_rewrite *ctl3_max, *ktmp, *lo, *hi;
3318 	int i;
3319 
3320 	CTL3_LOCK();
3321 
3322 	for (i = 0; i < count; i++) {
3323 		if (find_op_rw_range(rw[i].opcode, &lo, &hi) != 0)
3324 			continue;
3325 
3326 		for (ktmp = lo; ktmp <= hi; ktmp++) {
3327 			if (ktmp->classifier != rw[i].classifier)
3328 				continue;
3329 
3330 			ctl3_max = ctl3_rewriters + ctl3_rsize;
3331 			sz = (ctl3_max - (ktmp + 1)) * sizeof(*ktmp);
3332 			memmove(ktmp, ktmp + 1, sz);
3333 			ctl3_rsize--;
3334 			break;
3335 		}
3336 
3337 	}
3338 
3339 	if (ctl3_rsize == 0) {
3340 		if (ctl3_rewriters != NULL)
3341 			free(ctl3_rewriters, M_IPFW);
3342 		ctl3_rewriters = NULL;
3343 	}
3344 
3345 	CTL3_UNLOCK();
3346 
3347 	return (0);
3348 }
3349 
3350 static int
export_objhash_ntlv_internal(struct namedobj_instance * ni,struct named_object * no,void * arg)3351 export_objhash_ntlv_internal(struct namedobj_instance *ni,
3352     struct named_object *no, void *arg)
3353 {
3354 	struct sockopt_data *sd;
3355 	ipfw_obj_ntlv *ntlv;
3356 
3357 	sd = (struct sockopt_data *)arg;
3358 	ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
3359 	if (ntlv == NULL)
3360 		return (ENOMEM);
3361 	ipfw_export_obj_ntlv(no, ntlv);
3362 	return (0);
3363 }
3364 
3365 /*
3366  * Lists all service objects.
3367  * Data layout (v0)(current):
3368  * Request: [ ipfw_obj_lheader ] size = ipfw_obj_lheader.size
3369  * Reply: [ ipfw_obj_lheader [ ipfw_obj_ntlv x N ] (optional) ]
3370  * Returns 0 on success
3371  */
3372 static int
dump_srvobjects(struct ip_fw_chain * chain,ip_fw3_opheader * op3,struct sockopt_data * sd)3373 dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
3374     struct sockopt_data *sd)
3375 {
3376 	ipfw_obj_lheader *hdr;
3377 	int count;
3378 
3379 	hdr = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
3380 	if (hdr == NULL)
3381 		return (EINVAL);
3382 
3383 	IPFW_UH_RLOCK(chain);
3384 	count = ipfw_objhash_count(CHAIN_TO_SRV(chain));
3385 	hdr->size = sizeof(ipfw_obj_lheader) + count * sizeof(ipfw_obj_ntlv);
3386 	if (sd->valsize < hdr->size) {
3387 		IPFW_UH_RUNLOCK(chain);
3388 		return (ENOMEM);
3389 	}
3390 	hdr->count = count;
3391 	hdr->objsize = sizeof(ipfw_obj_ntlv);
3392 	if (count > 0)
3393 		ipfw_objhash_foreach(CHAIN_TO_SRV(chain),
3394 		    export_objhash_ntlv_internal, sd);
3395 	IPFW_UH_RUNLOCK(chain);
3396 	return (0);
3397 }
3398 
3399 /*
3400  * Compares two sopt handlers (code, version and handler ptr).
3401  * Used both as qsort() and bsearch().
3402  * Does not compare handler for latter case.
3403  *
3404  * Returns 0 if match is found.
3405  */
3406 static int
compare_sh(const void * _a,const void * _b)3407 compare_sh(const void *_a, const void *_b)
3408 {
3409 	const struct ipfw_sopt_handler *a, *b;
3410 
3411 	a = (const struct ipfw_sopt_handler *)_a;
3412 	b = (const struct ipfw_sopt_handler *)_b;
3413 
3414 	if (a->opcode < b->opcode)
3415 		return (-1);
3416 	else if (a->opcode > b->opcode)
3417 		return (1);
3418 
3419 	if (a->version < b->version)
3420 		return (-1);
3421 	else if (a->version > b->version)
3422 		return (1);
3423 
3424 	/* bsearch helper */
3425 	if (a->handler == NULL)
3426 		return (0);
3427 
3428 	if ((uintptr_t)a->handler < (uintptr_t)b->handler)
3429 		return (-1);
3430 	else if ((uintptr_t)a->handler > (uintptr_t)b->handler)
3431 		return (1);
3432 
3433 	return (0);
3434 }
3435 
3436 /*
3437  * Finds sopt handler based on @code and @version.
3438  *
3439  * Returns pointer to handler or NULL.
3440  */
3441 static struct ipfw_sopt_handler *
find_sh(uint16_t code,uint8_t version,sopt_handler_f * handler)3442 find_sh(uint16_t code, uint8_t version, sopt_handler_f *handler)
3443 {
3444 	struct ipfw_sopt_handler *sh, h;
3445 
3446 	memset(&h, 0, sizeof(h));
3447 	h.opcode = code;
3448 	h.version = version;
3449 	h.handler = handler;
3450 
3451 	sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers,
3452 	    ctl3_hsize, sizeof(h), compare_sh);
3453 
3454 	return (sh);
3455 }
3456 
3457 static int
find_ref_sh(uint16_t opcode,uint8_t version,struct ipfw_sopt_handler * psh)3458 find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh)
3459 {
3460 	struct ipfw_sopt_handler *sh;
3461 
3462 	CTL3_LOCK();
3463 	if ((sh = find_sh(opcode, version, NULL)) == NULL) {
3464 		CTL3_UNLOCK();
3465 		printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n",
3466 		    opcode, version);
3467 		return (EINVAL);
3468 	}
3469 	sh->refcnt++;
3470 	ctl3_refct++;
3471 	/* Copy handler data to requested buffer */
3472 	*psh = *sh;
3473 	CTL3_UNLOCK();
3474 
3475 	return (0);
3476 }
3477 
3478 static void
find_unref_sh(struct ipfw_sopt_handler * psh)3479 find_unref_sh(struct ipfw_sopt_handler *psh)
3480 {
3481 	struct ipfw_sopt_handler *sh;
3482 
3483 	CTL3_LOCK();
3484 	sh = find_sh(psh->opcode, psh->version, NULL);
3485 	KASSERT(sh != NULL, ("ctl3 handler disappeared"));
3486 	sh->refcnt--;
3487 	ctl3_refct--;
3488 	CTL3_UNLOCK();
3489 }
3490 
3491 void
ipfw_init_sopt_handler()3492 ipfw_init_sopt_handler()
3493 {
3494 
3495 	CTL3_LOCK_INIT();
3496 	IPFW_ADD_SOPT_HANDLER(1, scodes);
3497 }
3498 
3499 void
ipfw_destroy_sopt_handler()3500 ipfw_destroy_sopt_handler()
3501 {
3502 
3503 	IPFW_DEL_SOPT_HANDLER(1, scodes);
3504 	CTL3_LOCK_DESTROY();
3505 }
3506 
3507 /*
3508  * Adds one or more sockopt handlers to the global array.
3509  * Function may sleep.
3510  */
3511 void
ipfw_add_sopt_handler(struct ipfw_sopt_handler * sh,size_t count)3512 ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
3513 {
3514 	size_t sz;
3515 	struct ipfw_sopt_handler *tmp;
3516 
3517 	CTL3_LOCK();
3518 
3519 	for (;;) {
3520 		sz = ctl3_hsize + count;
3521 		CTL3_UNLOCK();
3522 		tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO);
3523 		CTL3_LOCK();
3524 		if (ctl3_hsize + count <= sz)
3525 			break;
3526 
3527 		/* Retry */
3528 		free(tmp, M_IPFW);
3529 	}
3530 
3531 	/* Merge old & new arrays */
3532 	sz = ctl3_hsize + count;
3533 	memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh));
3534 	memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh));
3535 	qsort(tmp, sz, sizeof(*sh), compare_sh);
3536 	/* Switch new and free old */
3537 	if (ctl3_handlers != NULL)
3538 		free(ctl3_handlers, M_IPFW);
3539 	ctl3_handlers = tmp;
3540 	ctl3_hsize = sz;
3541 	ctl3_gencnt++;
3542 
3543 	CTL3_UNLOCK();
3544 }
3545 
3546 /*
3547  * Removes one or more sockopt handlers from the global array.
3548  */
3549 int
ipfw_del_sopt_handler(struct ipfw_sopt_handler * sh,size_t count)3550 ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
3551 {
3552 	size_t sz;
3553 	struct ipfw_sopt_handler *tmp, *h;
3554 	int i;
3555 
3556 	CTL3_LOCK();
3557 
3558 	for (i = 0; i < count; i++) {
3559 		tmp = &sh[i];
3560 		h = find_sh(tmp->opcode, tmp->version, tmp->handler);
3561 		if (h == NULL)
3562 			continue;
3563 
3564 		sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h);
3565 		memmove(h, h + 1, sz);
3566 		ctl3_hsize--;
3567 	}
3568 
3569 	if (ctl3_hsize == 0) {
3570 		if (ctl3_handlers != NULL)
3571 			free(ctl3_handlers, M_IPFW);
3572 		ctl3_handlers = NULL;
3573 	}
3574 
3575 	ctl3_gencnt++;
3576 
3577 	CTL3_UNLOCK();
3578 
3579 	return (0);
3580 }
3581 
3582 /*
3583  * Writes data accumulated in @sd to sockopt buffer.
3584  * Zeroes internal @sd buffer.
3585  */
3586 static int
ipfw_flush_sopt_data(struct sockopt_data * sd)3587 ipfw_flush_sopt_data(struct sockopt_data *sd)
3588 {
3589 	struct sockopt *sopt;
3590 	int error;
3591 	size_t sz;
3592 
3593 	sz = sd->koff;
3594 	if (sz == 0)
3595 		return (0);
3596 
3597 	sopt = sd->sopt;
3598 
3599 	if (sopt->sopt_dir == SOPT_GET) {
3600 		error = copyout(sd->kbuf, sopt->sopt_val, sz);
3601 		if (error != 0)
3602 			return (error);
3603 	}
3604 
3605 	memset(sd->kbuf, 0, sd->ksize);
3606 	sd->ktotal += sz;
3607 	sd->koff = 0;
3608 	if (sd->ktotal + sd->ksize < sd->valsize)
3609 		sd->kavail = sd->ksize;
3610 	else
3611 		sd->kavail = sd->valsize - sd->ktotal;
3612 
3613 	/* Update sopt buffer data */
3614 	sopt->sopt_valsize = sd->ktotal;
3615 	sopt->sopt_val = sd->sopt_val + sd->ktotal;
3616 
3617 	return (0);
3618 }
3619 
3620 /*
3621  * Ensures that @sd buffer has contiguous @neeeded number of
3622  * bytes.
3623  *
3624  * Returns pointer to requested space or NULL.
3625  */
3626 caddr_t
ipfw_get_sopt_space(struct sockopt_data * sd,size_t needed)3627 ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed)
3628 {
3629 	int error;
3630 	caddr_t addr;
3631 
3632 	if (sd->kavail < needed) {
3633 		/*
3634 		 * Flush data and try another time.
3635 		 */
3636 		error = ipfw_flush_sopt_data(sd);
3637 
3638 		if (sd->kavail < needed || error != 0)
3639 			return (NULL);
3640 	}
3641 
3642 	addr = sd->kbuf + sd->koff;
3643 	sd->koff += needed;
3644 	sd->kavail -= needed;
3645 	return (addr);
3646 }
3647 
3648 /*
3649  * Requests @needed contiguous bytes from @sd buffer.
3650  * Function is used to notify subsystem that we are
3651  * interesed in first @needed bytes (request header)
3652  * and the rest buffer can be safely zeroed.
3653  *
3654  * Returns pointer to requested space or NULL.
3655  */
3656 caddr_t
ipfw_get_sopt_header(struct sockopt_data * sd,size_t needed)3657 ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed)
3658 {
3659 	caddr_t addr;
3660 
3661 	if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL)
3662 		return (NULL);
3663 
3664 	if (sd->kavail > 0)
3665 		memset(sd->kbuf + sd->koff, 0, sd->kavail);
3666 
3667 	return (addr);
3668 }
3669 
3670 /*
3671  * New sockopt handler.
3672  */
3673 int
ipfw_ctl3(struct sockopt * sopt)3674 ipfw_ctl3(struct sockopt *sopt)
3675 {
3676 	int error, locked;
3677 	size_t size, valsize;
3678 	struct ip_fw_chain *chain;
3679 	char xbuf[256];
3680 	struct sockopt_data sdata;
3681 	struct ipfw_sopt_handler h;
3682 	ip_fw3_opheader *op3 = NULL;
3683 
3684 	error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
3685 	if (error != 0)
3686 		return (error);
3687 
3688 	if (sopt->sopt_name != IP_FW3)
3689 		return (ipfw_ctl(sopt));
3690 
3691 	chain = &V_layer3_chain;
3692 	error = 0;
3693 
3694 	/* Save original valsize before it is altered via sooptcopyin() */
3695 	valsize = sopt->sopt_valsize;
3696 	memset(&sdata, 0, sizeof(sdata));
3697 	/* Read op3 header first to determine actual operation */
3698 	op3 = (ip_fw3_opheader *)xbuf;
3699 	error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3));
3700 	if (error != 0)
3701 		return (error);
3702 	sopt->sopt_valsize = valsize;
3703 
3704 	/*
3705 	 * Find and reference command.
3706 	 */
3707 	error = find_ref_sh(op3->opcode, op3->version, &h);
3708 	if (error != 0)
3709 		return (error);
3710 
3711 	/*
3712 	 * Disallow modifications in really-really secure mode, but still allow
3713 	 * the logging counters to be reset.
3714 	 */
3715 	if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) {
3716 		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
3717 		if (error != 0) {
3718 			find_unref_sh(&h);
3719 			return (error);
3720 		}
3721 	}
3722 
3723 	/*
3724 	 * Fill in sockopt_data structure that may be useful for
3725 	 * IP_FW3 get requests.
3726 	 */
3727 	locked = 0;
3728 	if (valsize <= sizeof(xbuf)) {
3729 		/* use on-stack buffer */
3730 		sdata.kbuf = xbuf;
3731 		sdata.ksize = sizeof(xbuf);
3732 		sdata.kavail = valsize;
3733 	} else {
3734 
3735 		/*
3736 		 * Determine opcode type/buffer size:
3737 		 * allocate sliding-window buf for data export or
3738 		 * contiguous buffer for special ops.
3739 		 */
3740 		if ((h.dir & HDIR_SET) != 0) {
3741 			/* Set request. Allocate contigous buffer. */
3742 			if (valsize > CTL3_LARGEBUF) {
3743 				find_unref_sh(&h);
3744 				return (EFBIG);
3745 			}
3746 
3747 			size = valsize;
3748 		} else {
3749 			/* Get request. Allocate sliding window buffer */
3750 			size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF;
3751 
3752 			if (size < valsize) {
3753 				/* We have to wire user buffer */
3754 				error = vslock(sopt->sopt_val, valsize);
3755 				if (error != 0)
3756 					return (error);
3757 				locked = 1;
3758 			}
3759 		}
3760 
3761 		sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
3762 		sdata.ksize = size;
3763 		sdata.kavail = size;
3764 	}
3765 
3766 	sdata.sopt = sopt;
3767 	sdata.sopt_val = sopt->sopt_val;
3768 	sdata.valsize = valsize;
3769 
3770 	/*
3771 	 * Copy either all request (if valsize < bsize_max)
3772 	 * or first bsize_max bytes to guarantee most consumers
3773 	 * that all necessary data has been copied).
3774 	 * Anyway, copy not less than sizeof(ip_fw3_opheader).
3775 	 */
3776 	if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize,
3777 	    sizeof(ip_fw3_opheader))) != 0)
3778 		return (error);
3779 	op3 = (ip_fw3_opheader *)sdata.kbuf;
3780 
3781 	/* Finally, run handler */
3782 	error = h.handler(chain, op3, &sdata);
3783 	find_unref_sh(&h);
3784 
3785 	/* Flush state and free buffers */
3786 	if (error == 0)
3787 		error = ipfw_flush_sopt_data(&sdata);
3788 	else
3789 		ipfw_flush_sopt_data(&sdata);
3790 
3791 	if (locked != 0)
3792 		vsunlock(sdata.sopt_val, valsize);
3793 
3794 	/* Restore original pointer and set number of bytes written */
3795 	sopt->sopt_val = sdata.sopt_val;
3796 	sopt->sopt_valsize = sdata.ktotal;
3797 	if (sdata.kbuf != xbuf)
3798 		free(sdata.kbuf, M_TEMP);
3799 
3800 	return (error);
3801 }
3802 
3803 /**
3804  * {set|get}sockopt parser.
3805  */
3806 int
ipfw_ctl(struct sockopt * sopt)3807 ipfw_ctl(struct sockopt *sopt)
3808 {
3809 #define	RULE_MAXSIZE	(512*sizeof(u_int32_t))
3810 	int error;
3811 	size_t size, valsize;
3812 	struct ip_fw *buf;
3813 	struct ip_fw_rule0 *rule;
3814 	struct ip_fw_chain *chain;
3815 	u_int32_t rulenum[2];
3816 	uint32_t opt;
3817 	struct rule_check_info ci;
3818 	IPFW_RLOCK_TRACKER;
3819 
3820 	chain = &V_layer3_chain;
3821 	error = 0;
3822 
3823 	/* Save original valsize before it is altered via sooptcopyin() */
3824 	valsize = sopt->sopt_valsize;
3825 	opt = sopt->sopt_name;
3826 
3827 	/*
3828 	 * Disallow modifications in really-really secure mode, but still allow
3829 	 * the logging counters to be reset.
3830 	 */
3831 	if (opt == IP_FW_ADD ||
3832 	    (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) {
3833 		error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
3834 		if (error != 0)
3835 			return (error);
3836 	}
3837 
3838 	switch (opt) {
3839 	case IP_FW_GET:
3840 		/*
3841 		 * pass up a copy of the current rules. Static rules
3842 		 * come first (the last of which has number IPFW_DEFAULT_RULE),
3843 		 * followed by a possibly empty list of dynamic rule.
3844 		 * The last dynamic rule has NULL in the "next" field.
3845 		 *
3846 		 * Note that the calculated size is used to bound the
3847 		 * amount of data returned to the user.  The rule set may
3848 		 * change between calculating the size and returning the
3849 		 * data in which case we'll just return what fits.
3850 		 */
3851 		for (;;) {
3852 			int len = 0, want;
3853 
3854 			size = chain->static_len;
3855 			size += ipfw_dyn_len();
3856 			if (size >= sopt->sopt_valsize)
3857 				break;
3858 			buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
3859 			IPFW_UH_RLOCK(chain);
3860 			/* check again how much space we need */
3861 			want = chain->static_len + ipfw_dyn_len();
3862 			if (size >= want)
3863 				len = ipfw_getrules(chain, buf, size);
3864 			IPFW_UH_RUNLOCK(chain);
3865 			if (size >= want)
3866 				error = sooptcopyout(sopt, buf, len);
3867 			free(buf, M_TEMP);
3868 			if (size >= want)
3869 				break;
3870 		}
3871 		break;
3872 
3873 	case IP_FW_FLUSH:
3874 		/* locking is done within del_entry() */
3875 		error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
3876 		break;
3877 
3878 	case IP_FW_ADD:
3879 		rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);
3880 		error = sooptcopyin(sopt, rule, RULE_MAXSIZE,
3881 			sizeof(struct ip_fw7) );
3882 
3883 		memset(&ci, 0, sizeof(struct rule_check_info));
3884 
3885 		/*
3886 		 * If the size of commands equals RULESIZE7 then we assume
3887 		 * a FreeBSD7.2 binary is talking to us (set is7=1).
3888 		 * is7 is persistent so the next 'ipfw list' command
3889 		 * will use this format.
3890 		 * NOTE: If wrong version is guessed (this can happen if
3891 		 *       the first ipfw command is 'ipfw [pipe] list')
3892 		 *       the ipfw binary may crash or loop infinitly...
3893 		 */
3894 		size = sopt->sopt_valsize;
3895 		if (size == RULESIZE7(rule)) {
3896 		    is7 = 1;
3897 		    error = convert_rule_to_8(rule);
3898 		    if (error) {
3899 			free(rule, M_TEMP);
3900 			return error;
3901 		    }
3902 		    size = RULESIZE(rule);
3903 		} else
3904 		    is7 = 0;
3905 		if (error == 0)
3906 			error = check_ipfw_rule0(rule, size, &ci);
3907 		if (error == 0) {
3908 			/* locking is done within add_rule() */
3909 			struct ip_fw *krule;
3910 			krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule));
3911 			ci.urule = (caddr_t)rule;
3912 			ci.krule = krule;
3913 			import_rule0(&ci);
3914 			error = commit_rules(chain, &ci, 1);
3915 			if (error != 0)
3916 				ipfw_free_rule(ci.krule);
3917 			else if (sopt->sopt_dir == SOPT_GET) {
3918 				if (is7) {
3919 					error = convert_rule_to_7(rule);
3920 					size = RULESIZE7(rule);
3921 					if (error) {
3922 						free(rule, M_TEMP);
3923 						return error;
3924 					}
3925 				}
3926 				error = sooptcopyout(sopt, rule, size);
3927 			}
3928 		}
3929 		free(rule, M_TEMP);
3930 		break;
3931 
3932 	case IP_FW_DEL:
3933 		/*
3934 		 * IP_FW_DEL is used for deleting single rules or sets,
3935 		 * and (ab)used to atomically manipulate sets. Argument size
3936 		 * is used to distinguish between the two:
3937 		 *    sizeof(u_int32_t)
3938 		 *	delete single rule or set of rules,
3939 		 *	or reassign rules (or sets) to a different set.
3940 		 *    2*sizeof(u_int32_t)
3941 		 *	atomic disable/enable sets.
3942 		 *	first u_int32_t contains sets to be disabled,
3943 		 *	second u_int32_t contains sets to be enabled.
3944 		 */
3945 		error = sooptcopyin(sopt, rulenum,
3946 			2*sizeof(u_int32_t), sizeof(u_int32_t));
3947 		if (error)
3948 			break;
3949 		size = sopt->sopt_valsize;
3950 		if (size == sizeof(u_int32_t) && rulenum[0] != 0) {
3951 			/* delete or reassign, locking done in del_entry() */
3952 			error = del_entry(chain, rulenum[0]);
3953 		} else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */
3954 			IPFW_UH_WLOCK(chain);
3955 			V_set_disable =
3956 			    (V_set_disable | rulenum[0]) & ~rulenum[1] &
3957 			    ~(1<<RESVD_SET); /* set RESVD_SET always enabled */
3958 			IPFW_UH_WUNLOCK(chain);
3959 		} else
3960 			error = EINVAL;
3961 		break;
3962 
3963 	case IP_FW_ZERO:
3964 	case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */
3965 		rulenum[0] = 0;
3966 		if (sopt->sopt_val != 0) {
3967 		    error = sooptcopyin(sopt, rulenum,
3968 			    sizeof(u_int32_t), sizeof(u_int32_t));
3969 		    if (error)
3970 			break;
3971 		}
3972 		error = zero_entry(chain, rulenum[0],
3973 			sopt->sopt_name == IP_FW_RESETLOG);
3974 		break;
3975 
3976 	/*--- TABLE opcodes ---*/
3977 	case IP_FW_TABLE_ADD:
3978 	case IP_FW_TABLE_DEL:
3979 		{
3980 			ipfw_table_entry ent;
3981 			struct tentry_info tei;
3982 			struct tid_info ti;
3983 			struct table_value v;
3984 
3985 			error = sooptcopyin(sopt, &ent,
3986 			    sizeof(ent), sizeof(ent));
3987 			if (error)
3988 				break;
3989 
3990 			memset(&tei, 0, sizeof(tei));
3991 			tei.paddr = &ent.addr;
3992 			tei.subtype = AF_INET;
3993 			tei.masklen = ent.masklen;
3994 			ipfw_import_table_value_legacy(ent.value, &v);
3995 			tei.pvalue = &v;
3996 			memset(&ti, 0, sizeof(ti));
3997 			ti.uidx = ent.tbl;
3998 			ti.type = IPFW_TABLE_CIDR;
3999 
4000 			error = (opt == IP_FW_TABLE_ADD) ?
4001 			    add_table_entry(chain, &ti, &tei, 0, 1) :
4002 			    del_table_entry(chain, &ti, &tei, 0, 1);
4003 		}
4004 		break;
4005 
4006 
4007 	case IP_FW_TABLE_FLUSH:
4008 		{
4009 			u_int16_t tbl;
4010 			struct tid_info ti;
4011 
4012 			error = sooptcopyin(sopt, &tbl,
4013 			    sizeof(tbl), sizeof(tbl));
4014 			if (error)
4015 				break;
4016 			memset(&ti, 0, sizeof(ti));
4017 			ti.uidx = tbl;
4018 			error = flush_table(chain, &ti);
4019 		}
4020 		break;
4021 
4022 	case IP_FW_TABLE_GETSIZE:
4023 		{
4024 			u_int32_t tbl, cnt;
4025 			struct tid_info ti;
4026 
4027 			if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
4028 			    sizeof(tbl))))
4029 				break;
4030 			memset(&ti, 0, sizeof(ti));
4031 			ti.uidx = tbl;
4032 			IPFW_RLOCK(chain);
4033 			error = ipfw_count_table(chain, &ti, &cnt);
4034 			IPFW_RUNLOCK(chain);
4035 			if (error)
4036 				break;
4037 			error = sooptcopyout(sopt, &cnt, sizeof(cnt));
4038 		}
4039 		break;
4040 
4041 	case IP_FW_TABLE_LIST:
4042 		{
4043 			ipfw_table *tbl;
4044 			struct tid_info ti;
4045 
4046 			if (sopt->sopt_valsize < sizeof(*tbl)) {
4047 				error = EINVAL;
4048 				break;
4049 			}
4050 			size = sopt->sopt_valsize;
4051 			tbl = malloc(size, M_TEMP, M_WAITOK);
4052 			error = sooptcopyin(sopt, tbl, size, sizeof(*tbl));
4053 			if (error) {
4054 				free(tbl, M_TEMP);
4055 				break;
4056 			}
4057 			tbl->size = (size - sizeof(*tbl)) /
4058 			    sizeof(ipfw_table_entry);
4059 			memset(&ti, 0, sizeof(ti));
4060 			ti.uidx = tbl->tbl;
4061 			IPFW_RLOCK(chain);
4062 			error = ipfw_dump_table_legacy(chain, &ti, tbl);
4063 			IPFW_RUNLOCK(chain);
4064 			if (error) {
4065 				free(tbl, M_TEMP);
4066 				break;
4067 			}
4068 			error = sooptcopyout(sopt, tbl, size);
4069 			free(tbl, M_TEMP);
4070 		}
4071 		break;
4072 
4073 	/*--- NAT operations are protected by the IPFW_LOCK ---*/
4074 	case IP_FW_NAT_CFG:
4075 		if (IPFW_NAT_LOADED)
4076 			error = ipfw_nat_cfg_ptr(sopt);
4077 		else {
4078 			printf("IP_FW_NAT_CFG: %s\n",
4079 			    "ipfw_nat not present, please load it");
4080 			error = EINVAL;
4081 		}
4082 		break;
4083 
4084 	case IP_FW_NAT_DEL:
4085 		if (IPFW_NAT_LOADED)
4086 			error = ipfw_nat_del_ptr(sopt);
4087 		else {
4088 			printf("IP_FW_NAT_DEL: %s\n",
4089 			    "ipfw_nat not present, please load it");
4090 			error = EINVAL;
4091 		}
4092 		break;
4093 
4094 	case IP_FW_NAT_GET_CONFIG:
4095 		if (IPFW_NAT_LOADED)
4096 			error = ipfw_nat_get_cfg_ptr(sopt);
4097 		else {
4098 			printf("IP_FW_NAT_GET_CFG: %s\n",
4099 			    "ipfw_nat not present, please load it");
4100 			error = EINVAL;
4101 		}
4102 		break;
4103 
4104 	case IP_FW_NAT_GET_LOG:
4105 		if (IPFW_NAT_LOADED)
4106 			error = ipfw_nat_get_log_ptr(sopt);
4107 		else {
4108 			printf("IP_FW_NAT_GET_LOG: %s\n",
4109 			    "ipfw_nat not present, please load it");
4110 			error = EINVAL;
4111 		}
4112 		break;
4113 
4114 	default:
4115 		printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);
4116 		error = EINVAL;
4117 	}
4118 
4119 	return (error);
4120 #undef RULE_MAXSIZE
4121 }
4122 #define	RULE_MAXSIZE	(256*sizeof(u_int32_t))
4123 
4124 /* Functions to convert rules 7.2 <==> 8.0 */
4125 static int
convert_rule_to_7(struct ip_fw_rule0 * rule)4126 convert_rule_to_7(struct ip_fw_rule0 *rule)
4127 {
4128 	/* Used to modify original rule */
4129 	struct ip_fw7 *rule7 = (struct ip_fw7 *)rule;
4130 	/* copy of original rule, version 8 */
4131 	struct ip_fw_rule0 *tmp;
4132 
4133 	/* Used to copy commands */
4134 	ipfw_insn *ccmd, *dst;
4135 	int ll = 0, ccmdlen = 0;
4136 
4137 	tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
4138 	if (tmp == NULL) {
4139 		return 1; //XXX error
4140 	}
4141 	bcopy(rule, tmp, RULE_MAXSIZE);
4142 
4143 	/* Copy fields */
4144 	//rule7->_pad = tmp->_pad;
4145 	rule7->set = tmp->set;
4146 	rule7->rulenum = tmp->rulenum;
4147 	rule7->cmd_len = tmp->cmd_len;
4148 	rule7->act_ofs = tmp->act_ofs;
4149 	rule7->next_rule = (struct ip_fw7 *)tmp->next_rule;
4150 	rule7->cmd_len = tmp->cmd_len;
4151 	rule7->pcnt = tmp->pcnt;
4152 	rule7->bcnt = tmp->bcnt;
4153 	rule7->timestamp = tmp->timestamp;
4154 
4155 	/* Copy commands */
4156 	for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ;
4157 			ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
4158 		ccmdlen = F_LEN(ccmd);
4159 
4160 		bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
4161 
4162 		if (dst->opcode > O_NAT)
4163 			/* O_REASS doesn't exists in 7.2 version, so
4164 			 * decrement opcode if it is after O_REASS
4165 			 */
4166 			dst->opcode--;
4167 
4168 		if (ccmdlen > ll) {
4169 			printf("ipfw: opcode %d size truncated\n",
4170 				ccmd->opcode);
4171 			return EINVAL;
4172 		}
4173 	}
4174 	free(tmp, M_TEMP);
4175 
4176 	return 0;
4177 }
4178 
4179 static int
convert_rule_to_8(struct ip_fw_rule0 * rule)4180 convert_rule_to_8(struct ip_fw_rule0 *rule)
4181 {
4182 	/* Used to modify original rule */
4183 	struct ip_fw7 *rule7 = (struct ip_fw7 *) rule;
4184 
4185 	/* Used to copy commands */
4186 	ipfw_insn *ccmd, *dst;
4187 	int ll = 0, ccmdlen = 0;
4188 
4189 	/* Copy of original rule */
4190 	struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
4191 	if (tmp == NULL) {
4192 		return 1; //XXX error
4193 	}
4194 
4195 	bcopy(rule7, tmp, RULE_MAXSIZE);
4196 
4197 	for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ;
4198 			ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
4199 		ccmdlen = F_LEN(ccmd);
4200 
4201 		bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
4202 
4203 		if (dst->opcode > O_NAT)
4204 			/* O_REASS doesn't exists in 7.2 version, so
4205 			 * increment opcode if it is after O_REASS
4206 			 */
4207 			dst->opcode++;
4208 
4209 		if (ccmdlen > ll) {
4210 			printf("ipfw: opcode %d size truncated\n",
4211 			    ccmd->opcode);
4212 			return EINVAL;
4213 		}
4214 	}
4215 
4216 	rule->_pad = tmp->_pad;
4217 	rule->set = tmp->set;
4218 	rule->rulenum = tmp->rulenum;
4219 	rule->cmd_len = tmp->cmd_len;
4220 	rule->act_ofs = tmp->act_ofs;
4221 	rule->next_rule = (struct ip_fw *)tmp->next_rule;
4222 	rule->cmd_len = tmp->cmd_len;
4223 	rule->id = 0; /* XXX see if is ok = 0 */
4224 	rule->pcnt = tmp->pcnt;
4225 	rule->bcnt = tmp->bcnt;
4226 	rule->timestamp = tmp->timestamp;
4227 
4228 	free (tmp, M_TEMP);
4229 	return 0;
4230 }
4231 
4232 /*
4233  * Named object api
4234  *
4235  */
4236 
4237 void
ipfw_init_srv(struct ip_fw_chain * ch)4238 ipfw_init_srv(struct ip_fw_chain *ch)
4239 {
4240 
4241 	ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT);
4242 	ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT,
4243 	    M_IPFW, M_WAITOK | M_ZERO);
4244 }
4245 
4246 void
ipfw_destroy_srv(struct ip_fw_chain * ch)4247 ipfw_destroy_srv(struct ip_fw_chain *ch)
4248 {
4249 
4250 	free(ch->srvstate, M_IPFW);
4251 	ipfw_objhash_destroy(ch->srvmap);
4252 }
4253 
4254 /*
4255  * Allocate new bitmask which can be used to enlarge/shrink
4256  * named instance index.
4257  */
4258 void
ipfw_objhash_bitmap_alloc(uint32_t items,void ** idx,int * pblocks)4259 ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks)
4260 {
4261 	size_t size;
4262 	int max_blocks;
4263 	u_long *idx_mask;
4264 
4265 	KASSERT((items % BLOCK_ITEMS) == 0,
4266 	   ("bitmask size needs to power of 2 and greater or equal to %zu",
4267 	    BLOCK_ITEMS));
4268 
4269 	max_blocks = items / BLOCK_ITEMS;
4270 	size = items / 8;
4271 	idx_mask = malloc(size * IPFW_MAX_SETS, M_IPFW, M_WAITOK);
4272 	/* Mark all as free */
4273 	memset(idx_mask, 0xFF, size * IPFW_MAX_SETS);
4274 	*idx_mask &= ~(u_long)1; /* Skip index 0 */
4275 
4276 	*idx = idx_mask;
4277 	*pblocks = max_blocks;
4278 }
4279 
4280 /*
4281  * Copy current bitmask index to new one.
4282  */
4283 void
ipfw_objhash_bitmap_merge(struct namedobj_instance * ni,void ** idx,int * blocks)4284 ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks)
4285 {
4286 	int old_blocks, new_blocks;
4287 	u_long *old_idx, *new_idx;
4288 	int i;
4289 
4290 	old_idx = ni->idx_mask;
4291 	old_blocks = ni->max_blocks;
4292 	new_idx = *idx;
4293 	new_blocks = *blocks;
4294 
4295 	for (i = 0; i < IPFW_MAX_SETS; i++) {
4296 		memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i],
4297 		    old_blocks * sizeof(u_long));
4298 	}
4299 }
4300 
4301 /*
4302  * Swaps current @ni index with new one.
4303  */
4304 void
ipfw_objhash_bitmap_swap(struct namedobj_instance * ni,void ** idx,int * blocks)4305 ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks)
4306 {
4307 	int old_blocks;
4308 	u_long *old_idx;
4309 
4310 	old_idx = ni->idx_mask;
4311 	old_blocks = ni->max_blocks;
4312 
4313 	ni->idx_mask = *idx;
4314 	ni->max_blocks = *blocks;
4315 
4316 	/* Save old values */
4317 	*idx = old_idx;
4318 	*blocks = old_blocks;
4319 }
4320 
4321 void
ipfw_objhash_bitmap_free(void * idx,int blocks)4322 ipfw_objhash_bitmap_free(void *idx, int blocks)
4323 {
4324 
4325 	free(idx, M_IPFW);
4326 }
4327 
4328 /*
4329  * Creates named hash instance.
4330  * Must be called without holding any locks.
4331  * Return pointer to new instance.
4332  */
4333 struct namedobj_instance *
ipfw_objhash_create(uint32_t items)4334 ipfw_objhash_create(uint32_t items)
4335 {
4336 	struct namedobj_instance *ni;
4337 	int i;
4338 	size_t size;
4339 
4340 	size = sizeof(struct namedobj_instance) +
4341 	    sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE +
4342 	    sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE;
4343 
4344 	ni = malloc(size, M_IPFW, M_WAITOK | M_ZERO);
4345 	ni->nn_size = NAMEDOBJ_HASH_SIZE;
4346 	ni->nv_size = NAMEDOBJ_HASH_SIZE;
4347 
4348 	ni->names = (struct namedobjects_head *)(ni +1);
4349 	ni->values = &ni->names[ni->nn_size];
4350 
4351 	for (i = 0; i < ni->nn_size; i++)
4352 		TAILQ_INIT(&ni->names[i]);
4353 
4354 	for (i = 0; i < ni->nv_size; i++)
4355 		TAILQ_INIT(&ni->values[i]);
4356 
4357 	/* Set default hashing/comparison functions */
4358 	ni->hash_f = objhash_hash_name;
4359 	ni->cmp_f = objhash_cmp_name;
4360 
4361 	/* Allocate bitmask separately due to possible resize */
4362 	ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks);
4363 
4364 	return (ni);
4365 }
4366 
4367 void
ipfw_objhash_destroy(struct namedobj_instance * ni)4368 ipfw_objhash_destroy(struct namedobj_instance *ni)
4369 {
4370 
4371 	free(ni->idx_mask, M_IPFW);
4372 	free(ni, M_IPFW);
4373 }
4374 
4375 void
ipfw_objhash_set_funcs(struct namedobj_instance * ni,objhash_hash_f * hash_f,objhash_cmp_f * cmp_f)4376 ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f,
4377     objhash_cmp_f *cmp_f)
4378 {
4379 
4380 	ni->hash_f = hash_f;
4381 	ni->cmp_f = cmp_f;
4382 }
4383 
4384 static uint32_t
objhash_hash_name(struct namedobj_instance * ni,const void * name,uint32_t set)4385 objhash_hash_name(struct namedobj_instance *ni, const void *name, uint32_t set)
4386 {
4387 
4388 	return (fnv_32_str((const char *)name, FNV1_32_INIT));
4389 }
4390 
4391 static int
objhash_cmp_name(struct named_object * no,const void * name,uint32_t set)4392 objhash_cmp_name(struct named_object *no, const void *name, uint32_t set)
4393 {
4394 
4395 	if ((strcmp(no->name, (const char *)name) == 0) && (no->set == set))
4396 		return (0);
4397 
4398 	return (1);
4399 }
4400 
4401 static uint32_t
objhash_hash_idx(struct namedobj_instance * ni,uint32_t val)4402 objhash_hash_idx(struct namedobj_instance *ni, uint32_t val)
4403 {
4404 	uint32_t v;
4405 
4406 	v = val % (ni->nv_size - 1);
4407 
4408 	return (v);
4409 }
4410 
4411 struct named_object *
ipfw_objhash_lookup_name(struct namedobj_instance * ni,uint32_t set,char * name)4412 ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name)
4413 {
4414 	struct named_object *no;
4415 	uint32_t hash;
4416 
4417 	hash = ni->hash_f(ni, name, set) % ni->nn_size;
4418 
4419 	TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
4420 		if (ni->cmp_f(no, name, set) == 0)
4421 			return (no);
4422 	}
4423 
4424 	return (NULL);
4425 }
4426 
4427 /*
4428  * Find named object by @uid.
4429  * Check @tlvs for valid data inside.
4430  *
4431  * Returns pointer to found TLV or NULL.
4432  */
4433 ipfw_obj_ntlv *
ipfw_find_name_tlv_type(void * tlvs,int len,uint16_t uidx,uint32_t etlv)4434 ipfw_find_name_tlv_type(void *tlvs, int len, uint16_t uidx, uint32_t etlv)
4435 {
4436 	ipfw_obj_ntlv *ntlv;
4437 	uintptr_t pa, pe;
4438 	int l;
4439 
4440 	pa = (uintptr_t)tlvs;
4441 	pe = pa + len;
4442 	l = 0;
4443 	for (; pa < pe; pa += l) {
4444 		ntlv = (ipfw_obj_ntlv *)pa;
4445 		l = ntlv->head.length;
4446 
4447 		if (l != sizeof(*ntlv))
4448 			return (NULL);
4449 
4450 		if (ntlv->idx != uidx)
4451 			continue;
4452 		/*
4453 		 * When userland has specified zero TLV type, do
4454 		 * not compare it with eltv. In some cases userland
4455 		 * doesn't know what type should it have. Use only
4456 		 * uidx and name for search named_object.
4457 		 */
4458 		if (ntlv->head.type != 0 &&
4459 		    ntlv->head.type != (uint16_t)etlv)
4460 			continue;
4461 
4462 		if (ipfw_check_object_name_generic(ntlv->name) != 0)
4463 			return (NULL);
4464 
4465 		return (ntlv);
4466 	}
4467 
4468 	return (NULL);
4469 }
4470 
4471 /*
4472  * Finds object config based on either legacy index
4473  * or name in ntlv.
4474  * Note @ti structure contains unchecked data from userland.
4475  *
4476  * Returns 0 in success and fills in @pno with found config
4477  */
4478 int
ipfw_objhash_find_type(struct namedobj_instance * ni,struct tid_info * ti,uint32_t etlv,struct named_object ** pno)4479 ipfw_objhash_find_type(struct namedobj_instance *ni, struct tid_info *ti,
4480     uint32_t etlv, struct named_object **pno)
4481 {
4482 	char *name;
4483 	ipfw_obj_ntlv *ntlv;
4484 	uint32_t set;
4485 
4486 	if (ti->tlvs == NULL)
4487 		return (EINVAL);
4488 
4489 	ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx, etlv);
4490 	if (ntlv == NULL)
4491 		return (EINVAL);
4492 	name = ntlv->name;
4493 
4494 	/*
4495 	 * Use set provided by @ti instead of @ntlv one.
4496 	 * This is needed due to different sets behavior
4497 	 * controlled by V_fw_tables_sets.
4498 	 */
4499 	set = ti->set;
4500 	*pno = ipfw_objhash_lookup_name(ni, set, name);
4501 	if (*pno == NULL)
4502 		return (ESRCH);
4503 	return (0);
4504 }
4505 
4506 /*
4507  * Find named object by name, considering also its TLV type.
4508  */
4509 struct named_object *
ipfw_objhash_lookup_name_type(struct namedobj_instance * ni,uint32_t set,uint32_t type,const char * name)4510 ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set,
4511     uint32_t type, const char *name)
4512 {
4513 	struct named_object *no;
4514 	uint32_t hash;
4515 
4516 	hash = ni->hash_f(ni, name, set) % ni->nn_size;
4517 
4518 	TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
4519 		if (ni->cmp_f(no, name, set) == 0 &&
4520 		    no->etlv == (uint16_t)type)
4521 			return (no);
4522 	}
4523 
4524 	return (NULL);
4525 }
4526 
4527 struct named_object *
ipfw_objhash_lookup_kidx(struct namedobj_instance * ni,uint16_t kidx)4528 ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx)
4529 {
4530 	struct named_object *no;
4531 	uint32_t hash;
4532 
4533 	hash = objhash_hash_idx(ni, kidx);
4534 
4535 	TAILQ_FOREACH(no, &ni->values[hash], nv_next) {
4536 		if (no->kidx == kidx)
4537 			return (no);
4538 	}
4539 
4540 	return (NULL);
4541 }
4542 
4543 int
ipfw_objhash_same_name(struct namedobj_instance * ni,struct named_object * a,struct named_object * b)4544 ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a,
4545     struct named_object *b)
4546 {
4547 
4548 	if ((strcmp(a->name, b->name) == 0) && a->set == b->set)
4549 		return (1);
4550 
4551 	return (0);
4552 }
4553 
4554 void
ipfw_objhash_add(struct namedobj_instance * ni,struct named_object * no)4555 ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no)
4556 {
4557 	uint32_t hash;
4558 
4559 	hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
4560 	TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next);
4561 
4562 	hash = objhash_hash_idx(ni, no->kidx);
4563 	TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next);
4564 
4565 	ni->count++;
4566 }
4567 
4568 void
ipfw_objhash_del(struct namedobj_instance * ni,struct named_object * no)4569 ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no)
4570 {
4571 	uint32_t hash;
4572 
4573 	hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
4574 	TAILQ_REMOVE(&ni->names[hash], no, nn_next);
4575 
4576 	hash = objhash_hash_idx(ni, no->kidx);
4577 	TAILQ_REMOVE(&ni->values[hash], no, nv_next);
4578 
4579 	ni->count--;
4580 }
4581 
4582 uint32_t
ipfw_objhash_count(struct namedobj_instance * ni)4583 ipfw_objhash_count(struct namedobj_instance *ni)
4584 {
4585 
4586 	return (ni->count);
4587 }
4588 
4589 uint32_t
ipfw_objhash_count_type(struct namedobj_instance * ni,uint16_t type)4590 ipfw_objhash_count_type(struct namedobj_instance *ni, uint16_t type)
4591 {
4592 	struct named_object *no;
4593 	uint32_t count;
4594 	int i;
4595 
4596 	count = 0;
4597 	for (i = 0; i < ni->nn_size; i++) {
4598 		TAILQ_FOREACH(no, &ni->names[i], nn_next) {
4599 			if (no->etlv == type)
4600 				count++;
4601 		}
4602 	}
4603 	return (count);
4604 }
4605 
4606 /*
4607  * Runs @func for each found named object.
4608  * It is safe to delete objects from callback
4609  */
4610 int
ipfw_objhash_foreach(struct namedobj_instance * ni,objhash_cb_t * f,void * arg)4611 ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg)
4612 {
4613 	struct named_object *no, *no_tmp;
4614 	int i, ret;
4615 
4616 	for (i = 0; i < ni->nn_size; i++) {
4617 		TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
4618 			ret = f(ni, no, arg);
4619 			if (ret != 0)
4620 				return (ret);
4621 		}
4622 	}
4623 	return (0);
4624 }
4625 
4626 /*
4627  * Runs @f for each found named object with type @type.
4628  * It is safe to delete objects from callback
4629  */
4630 int
ipfw_objhash_foreach_type(struct namedobj_instance * ni,objhash_cb_t * f,void * arg,uint16_t type)4631 ipfw_objhash_foreach_type(struct namedobj_instance *ni, objhash_cb_t *f,
4632     void *arg, uint16_t type)
4633 {
4634 	struct named_object *no, *no_tmp;
4635 	int i, ret;
4636 
4637 	for (i = 0; i < ni->nn_size; i++) {
4638 		TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
4639 			if (no->etlv != type)
4640 				continue;
4641 			ret = f(ni, no, arg);
4642 			if (ret != 0)
4643 				return (ret);
4644 		}
4645 	}
4646 	return (0);
4647 }
4648 
4649 /*
4650  * Removes index from given set.
4651  * Returns 0 on success.
4652  */
4653 int
ipfw_objhash_free_idx(struct namedobj_instance * ni,uint16_t idx)4654 ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx)
4655 {
4656 	u_long *mask;
4657 	int i, v;
4658 
4659 	i = idx / BLOCK_ITEMS;
4660 	v = idx % BLOCK_ITEMS;
4661 
4662 	if (i >= ni->max_blocks)
4663 		return (1);
4664 
4665 	mask = &ni->idx_mask[i];
4666 
4667 	if ((*mask & ((u_long)1 << v)) != 0)
4668 		return (1);
4669 
4670 	/* Mark as free */
4671 	*mask |= (u_long)1 << v;
4672 
4673 	/* Update free offset */
4674 	if (ni->free_off[0] > i)
4675 		ni->free_off[0] = i;
4676 
4677 	return (0);
4678 }
4679 
4680 /*
4681  * Allocate new index in given instance and stores in in @pidx.
4682  * Returns 0 on success.
4683  */
4684 int
ipfw_objhash_alloc_idx(void * n,uint16_t * pidx)4685 ipfw_objhash_alloc_idx(void *n, uint16_t *pidx)
4686 {
4687 	struct namedobj_instance *ni;
4688 	u_long *mask;
4689 	int i, off, v;
4690 
4691 	ni = (struct namedobj_instance *)n;
4692 
4693 	off = ni->free_off[0];
4694 	mask = &ni->idx_mask[off];
4695 
4696 	for (i = off; i < ni->max_blocks; i++, mask++) {
4697 		if ((v = ffsl(*mask)) == 0)
4698 			continue;
4699 
4700 		/* Mark as busy */
4701 		*mask &= ~ ((u_long)1 << (v - 1));
4702 
4703 		ni->free_off[0] = i;
4704 
4705 		v = BLOCK_ITEMS * i + v - 1;
4706 
4707 		*pidx = v;
4708 		return (0);
4709 	}
4710 
4711 	return (1);
4712 }
4713 
4714 /* end of file */
4715