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