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