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