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