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