]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/ipfw/ip_fw_sockopt.c
MFV r315633, 315635:
[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                         if (cmdlen > F_INSN_SIZE(ipfw_insn_u32))
1830                                 goto bad_size;
1831                 case O_IP_DST_LOOKUP:
1832                         if (cmd->arg1 >= V_fw_tables_max) {
1833                                 printf("ipfw: invalid table number %d\n",
1834                                     cmd->arg1);
1835                                 return (EINVAL);
1836                         }
1837                         if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
1838                             cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
1839                             cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1840                                 goto bad_size;
1841                         ci->object_opcodes++;
1842                         break;
1843                 case O_IP_FLOW_LOOKUP:
1844                         if (cmd->arg1 >= V_fw_tables_max) {
1845                                 printf("ipfw: invalid table number %d\n",
1846                                     cmd->arg1);
1847                                 return (EINVAL);
1848                         }
1849                         if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
1850                             cmdlen != F_INSN_SIZE(ipfw_insn_u32))
1851                                 goto bad_size;
1852                         ci->object_opcodes++;
1853                         break;
1854                 case O_MACADDR2:
1855                         if (cmdlen != F_INSN_SIZE(ipfw_insn_mac))
1856                                 goto bad_size;
1857                         break;
1858
1859                 case O_NOP:
1860                 case O_IPID:
1861                 case O_IPTTL:
1862                 case O_IPLEN:
1863                 case O_TCPDATALEN:
1864                 case O_TCPWIN:
1865                 case O_TAGGED:
1866                         if (cmdlen < 1 || cmdlen > 31)
1867                                 goto bad_size;
1868                         break;
1869
1870                 case O_DSCP:
1871                         if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1)
1872                                 goto bad_size;
1873                         break;
1874
1875                 case O_MAC_TYPE:
1876                 case O_IP_SRCPORT:
1877                 case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */
1878                         if (cmdlen < 2 || cmdlen > 31)
1879                                 goto bad_size;
1880                         break;
1881
1882                 case O_RECV:
1883                 case O_XMIT:
1884                 case O_VIA:
1885                         if (cmdlen != F_INSN_SIZE(ipfw_insn_if))
1886                                 goto bad_size;
1887                         ci->object_opcodes++;
1888                         break;
1889
1890                 case O_ALTQ:
1891                         if (cmdlen != F_INSN_SIZE(ipfw_insn_altq))
1892                                 goto bad_size;
1893                         break;
1894
1895                 case O_PIPE:
1896                 case O_QUEUE:
1897                         if (cmdlen != F_INSN_SIZE(ipfw_insn))
1898                                 goto bad_size;
1899                         goto check_action;
1900
1901                 case O_FORWARD_IP:
1902                         if (cmdlen != F_INSN_SIZE(ipfw_insn_sa))
1903                                 goto bad_size;
1904                         goto check_action;
1905 #ifdef INET6
1906                 case O_FORWARD_IP6:
1907                         if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6))
1908                                 goto bad_size;
1909                         goto check_action;
1910 #endif /* INET6 */
1911
1912                 case O_DIVERT:
1913                 case O_TEE:
1914                         if (ip_divert_ptr == NULL)
1915                                 return EINVAL;
1916                         else
1917                                 goto check_size;
1918                 case O_NETGRAPH:
1919                 case O_NGTEE:
1920                         if (ng_ipfw_input_p == NULL)
1921                                 return EINVAL;
1922                         else
1923                                 goto check_size;
1924                 case O_NAT:
1925                         if (!IPFW_NAT_LOADED)
1926                                 return EINVAL;
1927                         if (cmdlen != F_INSN_SIZE(ipfw_insn_nat))
1928                                 goto bad_size;          
1929                         goto check_action;
1930                 case O_CHECK_STATE:
1931                         ci->object_opcodes++;
1932                         /* FALLTHROUGH */
1933                 case O_FORWARD_MAC: /* XXX not implemented yet */
1934                 case O_COUNT:
1935                 case O_ACCEPT:
1936                 case O_DENY:
1937                 case O_REJECT:
1938                 case O_SETDSCP:
1939 #ifdef INET6
1940                 case O_UNREACH6:
1941 #endif
1942                 case O_SKIPTO:
1943                 case O_REASS:
1944                 case O_CALLRETURN:
1945 check_size:
1946                         if (cmdlen != F_INSN_SIZE(ipfw_insn))
1947                                 goto bad_size;
1948 check_action:
1949                         if (have_action) {
1950                                 printf("ipfw: opcode %d, multiple actions"
1951                                         " not allowed\n",
1952                                         cmd->opcode);
1953                                 return (EINVAL);
1954                         }
1955                         have_action = 1;
1956                         if (l != cmdlen) {
1957                                 printf("ipfw: opcode %d, action must be"
1958                                         " last opcode\n",
1959                                         cmd->opcode);
1960                                 return (EINVAL);
1961                         }
1962                         break;
1963 #ifdef INET6
1964                 case O_IP6_SRC:
1965                 case O_IP6_DST:
1966                         if (cmdlen != F_INSN_SIZE(struct in6_addr) +
1967                             F_INSN_SIZE(ipfw_insn))
1968                                 goto bad_size;
1969                         break;
1970
1971                 case O_FLOW6ID:
1972                         if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) +
1973                             ((ipfw_insn_u32 *)cmd)->o.arg1)
1974                                 goto bad_size;
1975                         break;
1976
1977                 case O_IP6_SRC_MASK:
1978                 case O_IP6_DST_MASK:
1979                         if ( !(cmdlen & 1) || cmdlen > 127)
1980                                 goto bad_size;
1981                         break;
1982                 case O_ICMP6TYPE:
1983                         if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) )
1984                                 goto bad_size;
1985                         break;
1986 #endif
1987
1988                 default:
1989                         switch (cmd->opcode) {
1990 #ifndef INET6
1991                         case O_IP6_SRC_ME:
1992                         case O_IP6_DST_ME:
1993                         case O_EXT_HDR:
1994                         case O_IP6:
1995                         case O_UNREACH6:
1996                         case O_IP6_SRC:
1997                         case O_IP6_DST:
1998                         case O_FLOW6ID:
1999                         case O_IP6_SRC_MASK:
2000                         case O_IP6_DST_MASK:
2001                         case O_ICMP6TYPE:
2002                                 printf("ipfw: no IPv6 support in kernel\n");
2003                                 return (EPROTONOSUPPORT);
2004 #endif
2005                         default:
2006                                 printf("ipfw: opcode %d, unknown opcode\n",
2007                                         cmd->opcode);
2008                                 return (EINVAL);
2009                         }
2010                 }
2011         }
2012         if (have_action == 0) {
2013                 printf("ipfw: missing action\n");
2014                 return (EINVAL);
2015         }
2016         return 0;
2017
2018 bad_size:
2019         printf("ipfw: opcode %d size %d wrong\n",
2020                 cmd->opcode, cmdlen);
2021         return (EINVAL);
2022 }
2023
2024
2025 /*
2026  * Translation of requests for compatibility with FreeBSD 7.2/8.
2027  * a static variable tells us if we have an old client from userland,
2028  * and if necessary we translate requests and responses between the
2029  * two formats.
2030  */
2031 static int is7 = 0;
2032
2033 struct ip_fw7 {
2034         struct ip_fw7   *next;          /* linked list of rules     */
2035         struct ip_fw7   *next_rule;     /* ptr to next [skipto] rule    */
2036         /* 'next_rule' is used to pass up 'set_disable' status      */
2037
2038         uint16_t        act_ofs;        /* offset of action in 32-bit units */
2039         uint16_t        cmd_len;        /* # of 32-bit words in cmd */
2040         uint16_t        rulenum;        /* rule number          */
2041         uint8_t         set;            /* rule set (0..31)     */
2042         // #define RESVD_SET   31  /* set for default and persistent rules */
2043         uint8_t         _pad;           /* padding          */
2044         // uint32_t        id;             /* rule id, only in v.8 */
2045         /* These fields are present in all rules.           */
2046         uint64_t        pcnt;           /* Packet counter       */
2047         uint64_t        bcnt;           /* Byte counter         */
2048         uint32_t        timestamp;      /* tv_sec of last match     */
2049
2050         ipfw_insn       cmd[1];         /* storage for commands     */
2051 };
2052
2053 static int convert_rule_to_7(struct ip_fw_rule0 *rule);
2054 static int convert_rule_to_8(struct ip_fw_rule0 *rule);
2055
2056 #ifndef RULESIZE7
2057 #define RULESIZE7(rule)  (sizeof(struct ip_fw7) + \
2058         ((struct ip_fw7 *)(rule))->cmd_len * 4 - 4)
2059 #endif
2060
2061
2062 /*
2063  * Copy the static and dynamic rules to the supplied buffer
2064  * and return the amount of space actually used.
2065  * Must be run under IPFW_UH_RLOCK
2066  */
2067 static size_t
2068 ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space)
2069 {
2070         char *bp = buf;
2071         char *ep = bp + space;
2072         struct ip_fw *rule;
2073         struct ip_fw_rule0 *dst;
2074         struct timeval boottime;
2075         int error, i, l, warnflag;
2076         time_t  boot_seconds;
2077
2078         warnflag = 0;
2079
2080         getboottime(&boottime);
2081         boot_seconds = boottime.tv_sec;
2082         for (i = 0; i < chain->n_rules; i++) {
2083                 rule = chain->map[i];
2084
2085                 if (is7) {
2086                     /* Convert rule to FreeBSd 7.2 format */
2087                     l = RULESIZE7(rule);
2088                     if (bp + l + sizeof(uint32_t) <= ep) {
2089                         bcopy(rule, bp, l + sizeof(uint32_t));
2090                         error = set_legacy_obj_kidx(chain,
2091                             (struct ip_fw_rule0 *)bp);
2092                         if (error != 0)
2093                                 return (0);
2094                         error = convert_rule_to_7((struct ip_fw_rule0 *) bp);
2095                         if (error)
2096                                 return 0; /*XXX correct? */
2097                         /*
2098                          * XXX HACK. Store the disable mask in the "next"
2099                          * pointer in a wild attempt to keep the ABI the same.
2100                          * Why do we do this on EVERY rule?
2101                          */
2102                         bcopy(&V_set_disable,
2103                                 &(((struct ip_fw7 *)bp)->next_rule),
2104                                 sizeof(V_set_disable));
2105                         if (((struct ip_fw7 *)bp)->timestamp)
2106                             ((struct ip_fw7 *)bp)->timestamp += boot_seconds;
2107                         bp += l;
2108                     }
2109                     continue; /* go to next rule */
2110                 }
2111
2112                 l = RULEUSIZE0(rule);
2113                 if (bp + l > ep) { /* should not happen */
2114                         printf("overflow dumping static rules\n");
2115                         break;
2116                 }
2117                 dst = (struct ip_fw_rule0 *)bp;
2118                 export_rule0(rule, dst, l);
2119                 error = set_legacy_obj_kidx(chain, dst);
2120
2121                 /*
2122                  * XXX HACK. Store the disable mask in the "next"
2123                  * pointer in a wild attempt to keep the ABI the same.
2124                  * Why do we do this on EVERY rule?
2125                  *
2126                  * XXX: "ipfw set show" (ab)uses IP_FW_GET to read disabled mask
2127                  * so we need to fail _after_ saving at least one mask.
2128                  */
2129                 bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable));
2130                 if (dst->timestamp)
2131                         dst->timestamp += boot_seconds;
2132                 bp += l;
2133
2134                 if (error != 0) {
2135                         if (error == 2) {
2136                                 /* Non-fatal table rewrite error. */
2137                                 warnflag = 1;
2138                                 continue;
2139                         }
2140                         printf("Stop on rule %d. Fail to convert table\n",
2141                             rule->rulenum);
2142                         break;
2143                 }
2144         }
2145         if (warnflag != 0)
2146                 printf("ipfw: process %s is using legacy interfaces,"
2147                     " consider rebuilding\n", "");
2148         ipfw_get_dynamic(chain, &bp, ep); /* protected by the dynamic lock */
2149         return (bp - (char *)buf);
2150 }
2151
2152
2153 struct dump_args {
2154         uint32_t        b;      /* start rule */
2155         uint32_t        e;      /* end rule */
2156         uint32_t        rcount; /* number of rules */
2157         uint32_t        rsize;  /* rules size */
2158         uint32_t        tcount; /* number of tables */
2159         int             rcounters;      /* counters */
2160 };
2161
2162 void
2163 ipfw_export_obj_ntlv(struct named_object *no, ipfw_obj_ntlv *ntlv)
2164 {
2165
2166         ntlv->head.type = no->etlv;
2167         ntlv->head.length = sizeof(*ntlv);
2168         ntlv->idx = no->kidx;
2169         strlcpy(ntlv->name, no->name, sizeof(ntlv->name));
2170 }
2171
2172 /*
2173  * Export named object info in instance @ni, identified by @kidx
2174  * to ipfw_obj_ntlv. TLV is allocated from @sd space.
2175  *
2176  * Returns 0 on success.
2177  */
2178 static int
2179 export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx,
2180     struct sockopt_data *sd)
2181 {
2182         struct named_object *no;
2183         ipfw_obj_ntlv *ntlv;
2184
2185         no = ipfw_objhash_lookup_kidx(ni, kidx);
2186         KASSERT(no != NULL, ("invalid object kernel index passed"));
2187
2188         ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
2189         if (ntlv == NULL)
2190                 return (ENOMEM);
2191
2192         ipfw_export_obj_ntlv(no, ntlv);
2193         return (0);
2194 }
2195
2196 /*
2197  * Dumps static rules with table TLVs in buffer @sd.
2198  *
2199  * Returns 0 on success.
2200  */
2201 static int
2202 dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da,
2203     uint32_t *bmask, struct sockopt_data *sd)
2204 {
2205         int error;
2206         int i, l;
2207         uint32_t tcount;
2208         ipfw_obj_ctlv *ctlv;
2209         struct ip_fw *krule;
2210         struct namedobj_instance *ni;
2211         caddr_t dst;
2212
2213         /* Dump table names first (if any) */
2214         if (da->tcount > 0) {
2215                 /* Header first */
2216                 ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
2217                 if (ctlv == NULL)
2218                         return (ENOMEM);
2219                 ctlv->head.type = IPFW_TLV_TBLNAME_LIST;
2220                 ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) + 
2221                     sizeof(*ctlv);
2222                 ctlv->count = da->tcount;
2223                 ctlv->objsize = sizeof(ipfw_obj_ntlv);
2224         }
2225
2226         i = 0;
2227         tcount = da->tcount;
2228         ni = ipfw_get_table_objhash(chain);
2229         while (tcount > 0) {
2230                 if ((bmask[i / 32] & (1 << (i % 32))) == 0) {
2231                         i++;
2232                         continue;
2233                 }
2234
2235                 /* Jump to shared named object bitmask */
2236                 if (i >= IPFW_TABLES_MAX) {
2237                         ni = CHAIN_TO_SRV(chain);
2238                         i -= IPFW_TABLES_MAX;
2239                         bmask += IPFW_TABLES_MAX / 32;
2240                 }
2241
2242                 if ((error = export_objhash_ntlv(ni, i, sd)) != 0)
2243                         return (error);
2244
2245                 i++;
2246                 tcount--;
2247         }
2248
2249         /* Dump rules */
2250         ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
2251         if (ctlv == NULL)
2252                 return (ENOMEM);
2253         ctlv->head.type = IPFW_TLV_RULE_LIST;
2254         ctlv->head.length = da->rsize + sizeof(*ctlv);
2255         ctlv->count = da->rcount;
2256
2257         for (i = da->b; i < da->e; i++) {
2258                 krule = chain->map[i];
2259
2260                 l = RULEUSIZE1(krule) + sizeof(ipfw_obj_tlv);
2261                 if (da->rcounters != 0)
2262                         l += sizeof(struct ip_fw_bcounter);
2263                 dst = (caddr_t)ipfw_get_sopt_space(sd, l);
2264                 if (dst == NULL)
2265                         return (ENOMEM);
2266
2267                 export_rule1(krule, dst, l, da->rcounters);
2268         }
2269
2270         return (0);
2271 }
2272
2273 /*
2274  * Marks every object index used in @rule with bit in @bmask.
2275  * Used to generate bitmask of referenced tables/objects for given ruleset
2276  * or its part.
2277  *
2278  * Returns number of newly-referenced objects.
2279  */
2280 static int
2281 mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule,
2282     uint32_t *bmask)
2283 {
2284         struct opcode_obj_rewrite *rw;
2285         ipfw_insn *cmd;
2286         int bidx, cmdlen, l, count;
2287         uint16_t kidx;
2288         uint8_t subtype;
2289
2290         l = rule->cmd_len;
2291         cmd = rule->cmd;
2292         cmdlen = 0;
2293         count = 0;
2294         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2295                 cmdlen = F_LEN(cmd);
2296
2297                 rw = find_op_rw(cmd, &kidx, &subtype);
2298                 if (rw == NULL)
2299                         continue;
2300
2301                 bidx = kidx / 32;
2302                 /*
2303                  * Maintain separate bitmasks for table and
2304                  * non-table objects.
2305                  */
2306                 if (rw->etlv != IPFW_TLV_TBL_NAME)
2307                         bidx += IPFW_TABLES_MAX / 32;
2308
2309                 if ((bmask[bidx] & (1 << (kidx % 32))) == 0)
2310                         count++;
2311
2312                 bmask[bidx] |= 1 << (kidx % 32);
2313         }
2314
2315         return (count);
2316 }
2317
2318 /*
2319  * Dumps requested objects data
2320  * Data layout (version 0)(current):
2321  * Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags
2322  *   size = ipfw_cfg_lheader.size
2323  * Reply: [ ipfw_cfg_lheader 
2324  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
2325  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST)
2326  *     ipfw_obj_tlv(IPFW_TLV_RULE_ENT) [ ip_fw_bcounter (optional) ip_fw_rule ]
2327  *   ] (optional)
2328  *   [ ipfw_obj_ctlv(IPFW_TLV_STATE_LIST) ipfw_obj_dyntlv x N ] (optional)
2329  * ]
2330  * * NOTE IPFW_TLV_STATE_LIST has the single valid field: objsize.
2331  * The rest (size, count) are set to zero and needs to be ignored.
2332  *
2333  * Returns 0 on success.
2334  */
2335 static int
2336 dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2337     struct sockopt_data *sd)
2338 {
2339         ipfw_cfg_lheader *hdr;
2340         struct ip_fw *rule;
2341         size_t sz, rnum;
2342         uint32_t hdr_flags;
2343         int error, i;
2344         struct dump_args da;
2345         uint32_t *bmask;
2346
2347         hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
2348         if (hdr == NULL)
2349                 return (EINVAL);
2350
2351         error = 0;
2352         bmask = NULL;
2353         /* Allocate needed state. Note we allocate 2xspace mask, for table&srv  */
2354         if (hdr->flags & IPFW_CFG_GET_STATIC)
2355                 bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO);
2356
2357         IPFW_UH_RLOCK(chain);
2358
2359         /*
2360          * STAGE 1: Determine size/count for objects in range.
2361          * Prepare used tables bitmask.
2362          */
2363         sz = sizeof(ipfw_cfg_lheader);
2364         memset(&da, 0, sizeof(da));
2365
2366         da.b = 0;
2367         da.e = chain->n_rules;
2368
2369         if (hdr->end_rule != 0) {
2370                 /* Handle custom range */
2371                 if ((rnum = hdr->start_rule) > IPFW_DEFAULT_RULE)
2372                         rnum = IPFW_DEFAULT_RULE;
2373                 da.b = ipfw_find_rule(chain, rnum, 0);
2374                 rnum = hdr->end_rule;
2375                 rnum = (rnum < IPFW_DEFAULT_RULE) ? rnum+1 : IPFW_DEFAULT_RULE;
2376                 da.e = ipfw_find_rule(chain, rnum, 0) + 1;
2377         }
2378
2379         if (hdr->flags & IPFW_CFG_GET_STATIC) {
2380                 for (i = da.b; i < da.e; i++) {
2381                         rule = chain->map[i];
2382                         da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv);
2383                         da.rcount++;
2384                         /* Update bitmask of used objects for given range */
2385                         da.tcount += mark_object_kidx(chain, rule, bmask);
2386                 }
2387                 /* Add counters if requested */
2388                 if (hdr->flags & IPFW_CFG_GET_COUNTERS) {
2389                         da.rsize += sizeof(struct ip_fw_bcounter) * da.rcount;
2390                         da.rcounters = 1;
2391                 }
2392
2393                 if (da.tcount > 0)
2394                         sz += da.tcount * sizeof(ipfw_obj_ntlv) +
2395                             sizeof(ipfw_obj_ctlv);
2396                 sz += da.rsize + sizeof(ipfw_obj_ctlv);
2397         }
2398
2399         if (hdr->flags & IPFW_CFG_GET_STATES)
2400                 sz += ipfw_dyn_get_count() * sizeof(ipfw_obj_dyntlv) +
2401                      sizeof(ipfw_obj_ctlv);
2402
2403
2404         /*
2405          * Fill header anyway.
2406          * Note we have to save header fields to stable storage
2407          * buffer inside @sd can be flushed after dumping rules
2408          */
2409         hdr->size = sz;
2410         hdr->set_mask = ~V_set_disable;
2411         hdr_flags = hdr->flags;
2412         hdr = NULL;
2413
2414         if (sd->valsize < sz) {
2415                 error = ENOMEM;
2416                 goto cleanup;
2417         }
2418
2419         /* STAGE2: Store actual data */
2420         if (hdr_flags & IPFW_CFG_GET_STATIC) {
2421                 error = dump_static_rules(chain, &da, bmask, sd);
2422                 if (error != 0)
2423                         goto cleanup;
2424         }
2425
2426         if (hdr_flags & IPFW_CFG_GET_STATES)
2427                 error = ipfw_dump_states(chain, sd);
2428
2429 cleanup:
2430         IPFW_UH_RUNLOCK(chain);
2431
2432         if (bmask != NULL)
2433                 free(bmask, M_TEMP);
2434
2435         return (error);
2436 }
2437
2438 int
2439 ipfw_check_object_name_generic(const char *name)
2440 {
2441         int nsize;
2442
2443         nsize = sizeof(((ipfw_obj_ntlv *)0)->name);
2444         if (strnlen(name, nsize) == nsize)
2445                 return (EINVAL);
2446         if (name[0] == '\0')
2447                 return (EINVAL);
2448         return (0);
2449 }
2450
2451 /*
2452  * Creates non-existent objects referenced by rule.
2453  *
2454  * Return 0 on success.
2455  */
2456 int
2457 create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd,
2458     struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti)
2459 {
2460         struct opcode_obj_rewrite *rw;
2461         struct obj_idx *p;
2462         uint16_t kidx;
2463         int error;
2464
2465         /*
2466          * Compatibility stuff: do actual creation for non-existing,
2467          * but referenced objects.
2468          */
2469         for (p = oib; p < pidx; p++) {
2470                 if (p->kidx != 0)
2471                         continue;
2472
2473                 ti->uidx = p->uidx;
2474                 ti->type = p->type;
2475                 ti->atype = 0;
2476
2477                 rw = find_op_rw(cmd + p->off, NULL, NULL);
2478                 KASSERT(rw != NULL, ("Unable to find handler for op %d",
2479                     (cmd + p->off)->opcode));
2480
2481                 if (rw->create_object == NULL)
2482                         error = EOPNOTSUPP;
2483                 else
2484                         error = rw->create_object(ch, ti, &kidx);
2485                 if (error == 0) {
2486                         p->kidx = kidx;
2487                         continue;
2488                 }
2489
2490                 /*
2491                  * Error happened. We have to rollback everything.
2492                  * Drop all already acquired references.
2493                  */
2494                 IPFW_UH_WLOCK(ch);
2495                 unref_oib_objects(ch, cmd, oib, pidx);
2496                 IPFW_UH_WUNLOCK(ch);
2497
2498                 return (error);
2499         }
2500
2501         return (0);
2502 }
2503
2504 /*
2505  * Compatibility function for old ipfw(8) binaries.
2506  * Rewrites table/nat kernel indices with userland ones.
2507  * Convert tables matching '/^\d+$/' to their atoi() value.
2508  * Use number 65535 for other tables.
2509  *
2510  * Returns 0 on success.
2511  */
2512 static int
2513 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule)
2514 {
2515         struct opcode_obj_rewrite *rw;
2516         struct named_object *no;
2517         ipfw_insn *cmd;
2518         char *end;
2519         long val;
2520         int cmdlen, error, l;
2521         uint16_t kidx, uidx;
2522         uint8_t subtype;
2523
2524         error = 0;
2525
2526         l = rule->cmd_len;
2527         cmd = rule->cmd;
2528         cmdlen = 0;
2529         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2530                 cmdlen = F_LEN(cmd);
2531
2532                 /* Check if is index in given opcode */
2533                 rw = find_op_rw(cmd, &kidx, &subtype);
2534                 if (rw == NULL)
2535                         continue;
2536
2537                 /* Try to find referenced kernel object */
2538                 no = rw->find_bykidx(ch, kidx);
2539                 if (no == NULL)
2540                         continue;
2541
2542                 val = strtol(no->name, &end, 10);
2543                 if (*end == '\0' && val < 65535) {
2544                         uidx = val;
2545                 } else {
2546
2547                         /*
2548                          * We are called via legacy opcode.
2549                          * Save error and show table as fake number
2550                          * not to make ipfw(8) hang.
2551                          */
2552                         uidx = 65535;
2553                         error = 2;
2554                 }
2555
2556                 rw->update(cmd, uidx);
2557         }
2558
2559         return (error);
2560 }
2561
2562
2563 /*
2564  * Unreferences all already-referenced objects in given @cmd rule,
2565  * using information in @oib.
2566  *
2567  * Used to rollback partially converted rule on error.
2568  */
2569 static void
2570 unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib,
2571     struct obj_idx *end)
2572 {
2573         struct opcode_obj_rewrite *rw;
2574         struct named_object *no;
2575         struct obj_idx *p;
2576
2577         IPFW_UH_WLOCK_ASSERT(ch);
2578
2579         for (p = oib; p < end; p++) {
2580                 if (p->kidx == 0)
2581                         continue;
2582
2583                 rw = find_op_rw(cmd + p->off, NULL, NULL);
2584                 KASSERT(rw != NULL, ("Unable to find handler for op %d",
2585                     (cmd + p->off)->opcode));
2586
2587                 /* Find & unref by existing idx */
2588                 no = rw->find_bykidx(ch, p->kidx);
2589                 KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx));
2590                 no->refcnt--;
2591         }
2592 }
2593
2594 /*
2595  * Remove references from every object used in @rule.
2596  * Used at rule removal code.
2597  */
2598 static void
2599 unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule)
2600 {
2601         struct opcode_obj_rewrite *rw;
2602         struct named_object *no;
2603         ipfw_insn *cmd;
2604         int cmdlen, l;
2605         uint16_t kidx;
2606         uint8_t subtype;
2607
2608         IPFW_UH_WLOCK_ASSERT(ch);
2609
2610         l = rule->cmd_len;
2611         cmd = rule->cmd;
2612         cmdlen = 0;
2613         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2614                 cmdlen = F_LEN(cmd);
2615
2616                 rw = find_op_rw(cmd, &kidx, &subtype);
2617                 if (rw == NULL)
2618                         continue;
2619                 no = rw->find_bykidx(ch, kidx);
2620
2621                 KASSERT(no != NULL, ("table id %d not found", kidx));
2622                 KASSERT(no->subtype == subtype,
2623                     ("wrong type %d (%d) for table id %d",
2624                     no->subtype, subtype, kidx));
2625                 KASSERT(no->refcnt > 0, ("refcount for table %d is %d",
2626                     kidx, no->refcnt));
2627
2628                 if (no->refcnt == 1 && rw->destroy_object != NULL)
2629                         rw->destroy_object(ch, no);
2630                 else
2631                         no->refcnt--;
2632         }
2633 }
2634
2635
2636 /*
2637  * Find and reference object (if any) stored in instruction @cmd.
2638  *
2639  * Saves object info in @pidx, sets
2640  *  - @unresolved to 1 if object should exists but not found
2641  *
2642  * Returns non-zero value in case of error.
2643  */
2644 static int
2645 ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti,
2646     struct obj_idx *pidx, int *unresolved)
2647 {
2648         struct named_object *no;
2649         struct opcode_obj_rewrite *rw;
2650         int error;
2651
2652         /* Check if this opcode is candidate for rewrite */
2653         rw = find_op_rw(cmd, &ti->uidx, &ti->type);
2654         if (rw == NULL)
2655                 return (0);
2656
2657         /* Need to rewrite. Save necessary fields */
2658         pidx->uidx = ti->uidx;
2659         pidx->type = ti->type;
2660
2661         /* Try to find referenced kernel object */
2662         error = rw->find_byname(ch, ti, &no);
2663         if (error != 0)
2664                 return (error);
2665         if (no == NULL) {
2666                 /*
2667                  * Report about unresolved object for automaic
2668                  * creation.
2669                  */
2670                 *unresolved = 1;
2671                 return (0);
2672         }
2673
2674         /*
2675          * Object is already exist.
2676          * Its subtype should match with expected value.
2677          */
2678         if (ti->type != no->subtype)
2679                 return (EINVAL);
2680
2681         /* Bump refcount and update kidx. */
2682         no->refcnt++;
2683         rw->update(cmd, no->kidx);
2684         return (0);
2685 }
2686
2687 /*
2688  * Finds and bumps refcount for objects referenced by given @rule.
2689  * Auto-creates non-existing tables.
2690  * Fills in @oib array with userland/kernel indexes.
2691  *
2692  * Returns 0 on success.
2693  */
2694 static int
2695 ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule,
2696     struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti)
2697 {
2698         struct obj_idx *pidx;
2699         ipfw_insn *cmd;
2700         int cmdlen, error, l, unresolved;
2701
2702         pidx = oib;
2703         l = rule->cmd_len;
2704         cmd = rule->cmd;
2705         cmdlen = 0;
2706         error = 0;
2707
2708         IPFW_UH_WLOCK(ch);
2709
2710         /* Increase refcount on each existing referenced table. */
2711         for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
2712                 cmdlen = F_LEN(cmd);
2713                 unresolved = 0;
2714
2715                 error = ref_opcode_object(ch, cmd, ti, pidx, &unresolved);
2716                 if (error != 0)
2717                         break;
2718                 /*
2719                  * Compatibility stuff for old clients:
2720                  * prepare to automaitcally create non-existing objects.
2721                  */
2722                 if (unresolved != 0) {
2723                         pidx->off = rule->cmd_len - l;
2724                         pidx++;
2725                 }
2726         }
2727
2728         if (error != 0) {
2729                 /* Unref everything we have already done */
2730                 unref_oib_objects(ch, rule->cmd, oib, pidx);
2731                 IPFW_UH_WUNLOCK(ch);
2732                 return (error);
2733         }
2734         IPFW_UH_WUNLOCK(ch);
2735
2736         /* Perform auto-creation for non-existing objects */
2737         if (pidx != oib)
2738                 error = create_objects_compat(ch, rule->cmd, oib, pidx, ti);
2739
2740         /* Calculate real number of dynamic objects */
2741         ci->object_opcodes = (uint16_t)(pidx - oib);
2742
2743         return (error);
2744 }
2745
2746 /*
2747  * Checks is opcode is referencing table of appropriate type.
2748  * Adds reference count for found table if true.
2749  * Rewrites user-supplied opcode values with kernel ones.
2750  *
2751  * Returns 0 on success and appropriate error code otherwise.
2752  */
2753 static int
2754 rewrite_rule_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci)
2755 {
2756         int error;
2757         ipfw_insn *cmd;
2758         uint8_t type;
2759         struct obj_idx *p, *pidx_first, *pidx_last;
2760         struct tid_info ti;
2761
2762         /*
2763          * Prepare an array for storing opcode indices.
2764          * Use stack allocation by default.
2765          */
2766         if (ci->object_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) {
2767                 /* Stack */
2768                 pidx_first = ci->obuf;
2769         } else
2770                 pidx_first = malloc(
2771                     ci->object_opcodes * sizeof(struct obj_idx),
2772                     M_IPFW, M_WAITOK | M_ZERO);
2773
2774         error = 0;
2775         type = 0;
2776         memset(&ti, 0, sizeof(ti));
2777
2778         /* Use set rule is assigned to. */
2779         ti.set = ci->krule->set;
2780         if (ci->ctlv != NULL) {
2781                 ti.tlvs = (void *)(ci->ctlv + 1);
2782                 ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv);
2783         }
2784
2785         /* Reference all used tables and other objects */
2786         error = ref_rule_objects(chain, ci->krule, ci, pidx_first, &ti);
2787         if (error != 0)
2788                 goto free;
2789         /*
2790          * Note that ref_rule_objects() might have updated ci->object_opcodes
2791          * to reflect actual number of object opcodes.
2792          */
2793
2794         /* Perform rewrite of remaining opcodes */
2795         p = pidx_first;
2796         pidx_last = pidx_first + ci->object_opcodes;
2797         for (p = pidx_first; p < pidx_last; p++) {
2798                 cmd = ci->krule->cmd + p->off;
2799                 update_opcode_kidx(cmd, p->kidx);
2800         }
2801
2802 free:
2803         if (pidx_first != ci->obuf)
2804                 free(pidx_first, M_IPFW);
2805
2806         return (error);
2807 }
2808
2809 /*
2810  * Adds one or more rules to ipfw @chain.
2811  * Data layout (version 0)(current):
2812  * Request:
2813  * [
2814  *   ip_fw3_opheader
2815  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1)
2816  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3)
2817  * ]
2818  * Reply:
2819  * [
2820  *   ip_fw3_opheader
2821  *   [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional)
2822  *   [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ]
2823  * ]
2824  *
2825  * Rules in reply are modified to store their actual ruleset number.
2826  *
2827  * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending
2828  * according to their idx field and there has to be no duplicates.
2829  * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending.
2830  * (*3) Each ip_fw structure needs to be aligned to u64 boundary.
2831  *
2832  * Returns 0 on success.
2833  */
2834 static int
2835 add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
2836     struct sockopt_data *sd)
2837 {
2838         ipfw_obj_ctlv *ctlv, *rtlv, *tstate;
2839         ipfw_obj_ntlv *ntlv;
2840         int clen, error, idx;
2841         uint32_t count, read;
2842         struct ip_fw_rule *r;
2843         struct rule_check_info rci, *ci, *cbuf;
2844         int i, rsize;
2845
2846         op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize);
2847         ctlv = (ipfw_obj_ctlv *)(op3 + 1);
2848
2849         read = sizeof(ip_fw3_opheader);
2850         rtlv = NULL;
2851         tstate = NULL;
2852         cbuf = NULL;
2853         memset(&rci, 0, sizeof(struct rule_check_info));
2854
2855         if (read + sizeof(*ctlv) > sd->valsize)
2856                 return (EINVAL);
2857
2858         if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
2859                 clen = ctlv->head.length;
2860                 /* Check size and alignment */
2861                 if (clen > sd->valsize || clen < sizeof(*ctlv))
2862                         return (EINVAL);
2863                 if ((clen % sizeof(uint64_t)) != 0)
2864                         return (EINVAL);
2865
2866                 /*
2867                  * Some table names or other named objects.
2868                  * Check for validness.
2869                  */
2870                 count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv);
2871                 if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv))
2872                         return (EINVAL);
2873
2874                 /*
2875                  * Check each TLV.
2876                  * Ensure TLVs are sorted ascending and
2877                  * there are no duplicates.
2878                  */
2879                 idx = -1;
2880                 ntlv = (ipfw_obj_ntlv *)(ctlv + 1);
2881                 while (count > 0) {
2882                         if (ntlv->head.length != sizeof(ipfw_obj_ntlv))
2883                                 return (EINVAL);
2884
2885                         error = ipfw_check_object_name_generic(ntlv->name);
2886                         if (error != 0)
2887                                 return (error);
2888
2889                         if (ntlv->idx <= idx)
2890                                 return (EINVAL);
2891
2892                         idx = ntlv->idx;
2893                         count--;
2894                         ntlv++;
2895                 }
2896
2897                 tstate = ctlv;
2898                 read += ctlv->head.length;
2899                 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
2900         }
2901
2902         if (read + sizeof(*ctlv) > sd->valsize)
2903                 return (EINVAL);
2904
2905         if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
2906                 clen = ctlv->head.length;
2907                 if (clen + read > sd->valsize || clen < sizeof(*ctlv))
2908                         return (EINVAL);
2909                 if ((clen % sizeof(uint64_t)) != 0)
2910                         return (EINVAL);
2911
2912                 /*
2913                  * TODO: Permit adding multiple rules at once
2914                  */
2915                 if (ctlv->count != 1)
2916                         return (ENOTSUP);
2917
2918                 clen -= sizeof(*ctlv);
2919
2920                 if (ctlv->count > clen / sizeof(struct ip_fw_rule))
2921                         return (EINVAL);
2922
2923                 /* Allocate state for each rule or use stack */
2924                 if (ctlv->count == 1) {
2925                         memset(&rci, 0, sizeof(struct rule_check_info));
2926                         cbuf = &rci;
2927                 } else
2928                         cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP,
2929                             M_WAITOK | M_ZERO);
2930                 ci = cbuf;
2931
2932                 /*
2933                  * Check each rule for validness.
2934                  * Ensure numbered rules are sorted ascending
2935                  * and properly aligned
2936                  */
2937                 idx = 0;
2938                 r = (struct ip_fw_rule *)(ctlv + 1);
2939                 count = 0;
2940                 error = 0;
2941                 while (clen > 0) {
2942                         rsize = roundup2(RULESIZE(r), sizeof(uint64_t));
2943                         if (rsize > clen || ctlv->count <= count) {
2944                                 error = EINVAL;
2945                                 break;
2946                         }
2947
2948                         ci->ctlv = tstate;
2949                         error = check_ipfw_rule1(r, rsize, ci);
2950                         if (error != 0)
2951                                 break;
2952
2953                         /* Check sorting */
2954                         if (r->rulenum != 0 && r->rulenum < idx) {
2955                                 printf("rulenum %d idx %d\n", r->rulenum, idx);
2956                                 error = EINVAL;
2957                                 break;
2958                         }
2959                         idx = r->rulenum;
2960
2961                         ci->urule = (caddr_t)r;
2962
2963                         rsize = roundup2(rsize, sizeof(uint64_t));
2964                         clen -= rsize;
2965                         r = (struct ip_fw_rule *)((caddr_t)r + rsize);
2966                         count++;
2967                         ci++;
2968                 }
2969
2970                 if (ctlv->count != count || error != 0) {
2971                         if (cbuf != &rci)
2972                                 free(cbuf, M_TEMP);
2973                         return (EINVAL);
2974                 }
2975
2976                 rtlv = ctlv;
2977                 read += ctlv->head.length;
2978                 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
2979         }
2980
2981         if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) {
2982                 if (cbuf != NULL && cbuf != &rci)
2983                         free(cbuf, M_TEMP);
2984                 return (EINVAL);
2985         }
2986
2987         /*
2988          * Passed rules seems to be valid.
2989          * Allocate storage and try to add them to chain.
2990          */
2991         for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) {
2992                 clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule);
2993                 ci->krule = ipfw_alloc_rule(chain, clen);
2994                 import_rule1(ci);
2995         }
2996
2997         if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) {
2998                 /* Free allocate krules */
2999                 for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++)
3000                         free_rule(ci->krule);
3001         }
3002
3003         if (cbuf != NULL && cbuf != &rci)
3004                 free(cbuf, M_TEMP);
3005
3006         return (error);
3007 }
3008
3009 /*
3010  * Lists all sopts currently registered.
3011  * Data layout (v0)(current):
3012  * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size
3013  * Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ]
3014  *
3015  * Returns 0 on success
3016  */
3017 static int
3018 dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
3019     struct sockopt_data *sd)
3020 {
3021         struct _ipfw_obj_lheader *olh;
3022         ipfw_sopt_info *i;
3023         struct ipfw_sopt_handler *sh;
3024         uint32_t count, n, size;
3025
3026         olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh));
3027         if (olh == NULL)
3028                 return (EINVAL);
3029         if (sd->valsize < olh->size)
3030                 return (EINVAL);
3031
3032         CTL3_LOCK();
3033         count = ctl3_hsize;
3034         size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader);
3035
3036         /* Fill in header regadless of buffer size */
3037         olh->count = count;
3038         olh->objsize = sizeof(ipfw_sopt_info);
3039
3040         if (size > olh->size) {
3041                 olh->size = size;
3042                 CTL3_UNLOCK();
3043                 return (ENOMEM);
3044         }
3045         olh->size = size;
3046
3047         for (n = 1; n <= count; n++) {
3048                 i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i));
3049                 KASSERT(i != NULL, ("previously checked buffer is not enough"));
3050                 sh = &ctl3_handlers[n];
3051                 i->opcode = sh->opcode;
3052                 i->version = sh->version;
3053                 i->refcnt = sh->refcnt;
3054         }
3055         CTL3_UNLOCK();
3056
3057         return (0);
3058 }
3059
3060 /*
3061  * Compares two opcodes.
3062  * Used both in qsort() and bsearch().
3063  *
3064  * Returns 0 if match is found.
3065  */
3066 static int
3067 compare_opcodes(const void *_a, const void *_b)
3068 {
3069         const struct opcode_obj_rewrite *a, *b;
3070
3071         a = (const struct opcode_obj_rewrite *)_a;
3072         b = (const struct opcode_obj_rewrite *)_b;
3073
3074         if (a->opcode < b->opcode)
3075                 return (-1);
3076         else if (a->opcode > b->opcode)
3077                 return (1);
3078
3079         return (0);
3080 }
3081
3082 /*
3083  * XXX: Rewrite bsearch()
3084  */
3085 static int
3086 find_op_rw_range(uint16_t op, struct opcode_obj_rewrite **plo,
3087     struct opcode_obj_rewrite **phi)
3088 {
3089         struct opcode_obj_rewrite *ctl3_max, *lo, *hi, h, *rw;
3090
3091         memset(&h, 0, sizeof(h));
3092         h.opcode = op;
3093
3094         rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters,
3095             ctl3_rsize, sizeof(h), compare_opcodes);
3096         if (rw == NULL)
3097                 return (1);
3098
3099         /* Find the first element matching the same opcode */
3100         lo = rw;
3101         for ( ; lo > ctl3_rewriters && (lo - 1)->opcode == op; lo--)
3102                 ;
3103
3104         /* Find the last element matching the same opcode */
3105         hi = rw;
3106         ctl3_max = ctl3_rewriters + ctl3_rsize;
3107         for ( ; (hi + 1) < ctl3_max && (hi + 1)->opcode == op; hi++)
3108                 ;
3109
3110         *plo = lo;
3111         *phi = hi;
3112
3113         return (0);
3114 }
3115
3116 /*
3117  * Finds opcode object rewriter based on @code.
3118  *
3119  * Returns pointer to handler or NULL.
3120  */
3121 static struct opcode_obj_rewrite *
3122 find_op_rw(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype)
3123 {
3124         struct opcode_obj_rewrite *rw, *lo, *hi;
3125         uint16_t uidx;
3126         uint8_t subtype;
3127
3128         if (find_op_rw_range(cmd->opcode, &lo, &hi) != 0)
3129                 return (NULL);
3130
3131         for (rw = lo; rw <= hi; rw++) {
3132                 if (rw->classifier(cmd, &uidx, &subtype) == 0) {
3133                         if (puidx != NULL)
3134                                 *puidx = uidx;
3135                         if (ptype != NULL)
3136                                 *ptype = subtype;
3137                         return (rw);
3138                 }
3139         }
3140
3141         return (NULL);
3142 }
3143 int
3144 classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx)
3145 {
3146
3147         if (find_op_rw(cmd, puidx, NULL) == NULL)
3148                 return (1);
3149         return (0);
3150 }
3151
3152 void
3153 update_opcode_kidx(ipfw_insn *cmd, uint16_t idx)
3154 {
3155         struct opcode_obj_rewrite *rw;
3156
3157         rw = find_op_rw(cmd, NULL, NULL);
3158         KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode));
3159         rw->update(cmd, idx);
3160 }
3161
3162 void
3163 ipfw_init_obj_rewriter()
3164 {
3165
3166         ctl3_rewriters = NULL;
3167         ctl3_rsize = 0;
3168 }
3169
3170 void
3171 ipfw_destroy_obj_rewriter()
3172 {
3173
3174         if (ctl3_rewriters != NULL)
3175                 free(ctl3_rewriters, M_IPFW);
3176         ctl3_rewriters = NULL;
3177         ctl3_rsize = 0;
3178 }
3179
3180 /*
3181  * Adds one or more opcode object rewrite handlers to the global array.
3182  * Function may sleep.
3183  */
3184 void
3185 ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
3186 {
3187         size_t sz;
3188         struct opcode_obj_rewrite *tmp;
3189
3190         CTL3_LOCK();
3191
3192         for (;;) {
3193                 sz = ctl3_rsize + count;
3194                 CTL3_UNLOCK();
3195                 tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO);
3196                 CTL3_LOCK();
3197                 if (ctl3_rsize + count <= sz)
3198                         break;
3199
3200                 /* Retry */
3201                 free(tmp, M_IPFW);
3202         }
3203
3204         /* Merge old & new arrays */
3205         sz = ctl3_rsize + count;
3206         memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw));
3207         memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw));
3208         qsort(tmp, sz, sizeof(*rw), compare_opcodes);
3209         /* Switch new and free old */
3210         if (ctl3_rewriters != NULL)
3211                 free(ctl3_rewriters, M_IPFW);
3212         ctl3_rewriters = tmp;
3213         ctl3_rsize = sz;
3214
3215         CTL3_UNLOCK();
3216 }
3217
3218 /*
3219  * Removes one or more object rewrite handlers from the global array.
3220  */
3221 int
3222 ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count)
3223 {
3224         size_t sz;
3225         struct opcode_obj_rewrite *ctl3_max, *ktmp, *lo, *hi;
3226         int i;
3227
3228         CTL3_LOCK();
3229
3230         for (i = 0; i < count; i++) {
3231                 if (find_op_rw_range(rw[i].opcode, &lo, &hi) != 0)
3232                         continue;
3233
3234                 for (ktmp = lo; ktmp <= hi; ktmp++) {
3235                         if (ktmp->classifier != rw[i].classifier)
3236                                 continue;
3237
3238                         ctl3_max = ctl3_rewriters + ctl3_rsize;
3239                         sz = (ctl3_max - (ktmp + 1)) * sizeof(*ktmp);
3240                         memmove(ktmp, ktmp + 1, sz);
3241                         ctl3_rsize--;
3242                         break;
3243                 }
3244
3245         }
3246
3247         if (ctl3_rsize == 0) {
3248                 if (ctl3_rewriters != NULL)
3249                         free(ctl3_rewriters, M_IPFW);
3250                 ctl3_rewriters = NULL;
3251         }
3252
3253         CTL3_UNLOCK();
3254
3255         return (0);
3256 }
3257
3258 static int
3259 export_objhash_ntlv_internal(struct namedobj_instance *ni,
3260     struct named_object *no, void *arg)
3261 {
3262         struct sockopt_data *sd;
3263         ipfw_obj_ntlv *ntlv;
3264
3265         sd = (struct sockopt_data *)arg;
3266         ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv));
3267         if (ntlv == NULL)
3268                 return (ENOMEM);
3269         ipfw_export_obj_ntlv(no, ntlv);
3270         return (0);
3271 }
3272
3273 /*
3274  * Lists all service objects.
3275  * Data layout (v0)(current):
3276  * Request: [ ipfw_obj_lheader ] size = ipfw_obj_lheader.size
3277  * Reply: [ ipfw_obj_lheader [ ipfw_obj_ntlv x N ] (optional) ]
3278  * Returns 0 on success
3279  */
3280 static int
3281 dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
3282     struct sockopt_data *sd)
3283 {
3284         ipfw_obj_lheader *hdr;
3285         int count;
3286
3287         hdr = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr));
3288         if (hdr == NULL)
3289                 return (EINVAL);
3290
3291         IPFW_UH_RLOCK(chain);
3292         count = ipfw_objhash_count(CHAIN_TO_SRV(chain));
3293         hdr->size = sizeof(ipfw_obj_lheader) + count * sizeof(ipfw_obj_ntlv);
3294         if (sd->valsize < hdr->size) {
3295                 IPFW_UH_RUNLOCK(chain);
3296                 return (ENOMEM);
3297         }
3298         hdr->count = count;
3299         hdr->objsize = sizeof(ipfw_obj_ntlv);
3300         if (count > 0)
3301                 ipfw_objhash_foreach(CHAIN_TO_SRV(chain),
3302                     export_objhash_ntlv_internal, sd);
3303         IPFW_UH_RUNLOCK(chain);
3304         return (0);
3305 }
3306
3307 /*
3308  * Compares two sopt handlers (code, version and handler ptr).
3309  * Used both as qsort() and bsearch().
3310  * Does not compare handler for latter case.
3311  *
3312  * Returns 0 if match is found.
3313  */
3314 static int
3315 compare_sh(const void *_a, const void *_b)
3316 {
3317         const struct ipfw_sopt_handler *a, *b;
3318
3319         a = (const struct ipfw_sopt_handler *)_a;
3320         b = (const struct ipfw_sopt_handler *)_b;
3321
3322         if (a->opcode < b->opcode)
3323                 return (-1);
3324         else if (a->opcode > b->opcode)
3325                 return (1);
3326
3327         if (a->version < b->version)
3328                 return (-1);
3329         else if (a->version > b->version)
3330                 return (1);
3331
3332         /* bsearch helper */
3333         if (a->handler == NULL)
3334                 return (0);
3335
3336         if ((uintptr_t)a->handler < (uintptr_t)b->handler)
3337                 return (-1);
3338         else if ((uintptr_t)a->handler > (uintptr_t)b->handler)
3339                 return (1);
3340
3341         return (0);
3342 }
3343
3344 /*
3345  * Finds sopt handler based on @code and @version.
3346  *
3347  * Returns pointer to handler or NULL.
3348  */
3349 static struct ipfw_sopt_handler *
3350 find_sh(uint16_t code, uint8_t version, sopt_handler_f *handler)
3351 {
3352         struct ipfw_sopt_handler *sh, h;
3353
3354         memset(&h, 0, sizeof(h));
3355         h.opcode = code;
3356         h.version = version;
3357         h.handler = handler;
3358
3359         sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers,
3360             ctl3_hsize, sizeof(h), compare_sh);
3361
3362         return (sh);
3363 }
3364
3365 static int
3366 find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh)
3367 {
3368         struct ipfw_sopt_handler *sh;
3369
3370         CTL3_LOCK();
3371         if ((sh = find_sh(opcode, version, NULL)) == NULL) {
3372                 CTL3_UNLOCK();
3373                 printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n",
3374                     opcode, version);
3375                 return (EINVAL);
3376         }
3377         sh->refcnt++;
3378         ctl3_refct++;
3379         /* Copy handler data to requested buffer */
3380         *psh = *sh; 
3381         CTL3_UNLOCK();
3382
3383         return (0);
3384 }
3385
3386 static void
3387 find_unref_sh(struct ipfw_sopt_handler *psh)
3388 {
3389         struct ipfw_sopt_handler *sh;
3390
3391         CTL3_LOCK();
3392         sh = find_sh(psh->opcode, psh->version, NULL);
3393         KASSERT(sh != NULL, ("ctl3 handler disappeared"));
3394         sh->refcnt--;
3395         ctl3_refct--;
3396         CTL3_UNLOCK();
3397 }
3398
3399 void
3400 ipfw_init_sopt_handler()
3401 {
3402
3403         CTL3_LOCK_INIT();
3404         IPFW_ADD_SOPT_HANDLER(1, scodes);
3405 }
3406
3407 void
3408 ipfw_destroy_sopt_handler()
3409 {
3410
3411         IPFW_DEL_SOPT_HANDLER(1, scodes);
3412         CTL3_LOCK_DESTROY();
3413 }
3414
3415 /*
3416  * Adds one or more sockopt handlers to the global array.
3417  * Function may sleep.
3418  */
3419 void
3420 ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
3421 {
3422         size_t sz;
3423         struct ipfw_sopt_handler *tmp;
3424
3425         CTL3_LOCK();
3426
3427         for (;;) {
3428                 sz = ctl3_hsize + count;
3429                 CTL3_UNLOCK();
3430                 tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO);
3431                 CTL3_LOCK();
3432                 if (ctl3_hsize + count <= sz)
3433                         break;
3434
3435                 /* Retry */
3436                 free(tmp, M_IPFW);
3437         }
3438
3439         /* Merge old & new arrays */
3440         sz = ctl3_hsize + count;
3441         memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh));
3442         memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh));
3443         qsort(tmp, sz, sizeof(*sh), compare_sh);
3444         /* Switch new and free old */
3445         if (ctl3_handlers != NULL)
3446                 free(ctl3_handlers, M_IPFW);
3447         ctl3_handlers = tmp;
3448         ctl3_hsize = sz;
3449         ctl3_gencnt++;
3450
3451         CTL3_UNLOCK();
3452 }
3453
3454 /*
3455  * Removes one or more sockopt handlers from the global array.
3456  */
3457 int
3458 ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count)
3459 {
3460         size_t sz;
3461         struct ipfw_sopt_handler *tmp, *h;
3462         int i;
3463
3464         CTL3_LOCK();
3465
3466         for (i = 0; i < count; i++) {
3467                 tmp = &sh[i];
3468                 h = find_sh(tmp->opcode, tmp->version, tmp->handler);
3469                 if (h == NULL)
3470                         continue;
3471
3472                 sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h);
3473                 memmove(h, h + 1, sz);
3474                 ctl3_hsize--;
3475         }
3476
3477         if (ctl3_hsize == 0) {
3478                 if (ctl3_handlers != NULL)
3479                         free(ctl3_handlers, M_IPFW);
3480                 ctl3_handlers = NULL;
3481         }
3482
3483         ctl3_gencnt++;
3484
3485         CTL3_UNLOCK();
3486
3487         return (0);
3488 }
3489
3490 /*
3491  * Writes data accumulated in @sd to sockopt buffer.
3492  * Zeroes internal @sd buffer.
3493  */
3494 static int
3495 ipfw_flush_sopt_data(struct sockopt_data *sd)
3496 {
3497         struct sockopt *sopt;
3498         int error;
3499         size_t sz;
3500
3501         sz = sd->koff;
3502         if (sz == 0)
3503                 return (0);
3504
3505         sopt = sd->sopt;
3506
3507         if (sopt->sopt_dir == SOPT_GET) {
3508                 error = copyout(sd->kbuf, sopt->sopt_val, sz);
3509                 if (error != 0)
3510                         return (error);
3511         }
3512
3513         memset(sd->kbuf, 0, sd->ksize);
3514         sd->ktotal += sz;
3515         sd->koff = 0;
3516         if (sd->ktotal + sd->ksize < sd->valsize)
3517                 sd->kavail = sd->ksize;
3518         else
3519                 sd->kavail = sd->valsize - sd->ktotal;
3520
3521         /* Update sopt buffer data */
3522         sopt->sopt_valsize = sd->ktotal;
3523         sopt->sopt_val = sd->sopt_val + sd->ktotal;
3524
3525         return (0);
3526 }
3527
3528 /*
3529  * Ensures that @sd buffer has contiguous @neeeded number of
3530  * bytes.
3531  *
3532  * Returns pointer to requested space or NULL.
3533  */
3534 caddr_t
3535 ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed)
3536 {
3537         int error;
3538         caddr_t addr;
3539
3540         if (sd->kavail < needed) {
3541                 /*
3542                  * Flush data and try another time.
3543                  */
3544                 error = ipfw_flush_sopt_data(sd);
3545
3546                 if (sd->kavail < needed || error != 0)
3547                         return (NULL);
3548         }
3549
3550         addr = sd->kbuf + sd->koff;
3551         sd->koff += needed;
3552         sd->kavail -= needed;
3553         return (addr);
3554 }
3555
3556 /*
3557  * Requests @needed contiguous bytes from @sd buffer.
3558  * Function is used to notify subsystem that we are
3559  * interesed in first @needed bytes (request header)
3560  * and the rest buffer can be safely zeroed.
3561  *
3562  * Returns pointer to requested space or NULL.
3563  */
3564 caddr_t
3565 ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed)
3566 {
3567         caddr_t addr;
3568
3569         if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL)
3570                 return (NULL);
3571
3572         if (sd->kavail > 0)
3573                 memset(sd->kbuf + sd->koff, 0, sd->kavail);
3574         
3575         return (addr);
3576 }
3577
3578 /*
3579  * New sockopt handler.
3580  */
3581 int
3582 ipfw_ctl3(struct sockopt *sopt)
3583 {
3584         int error, locked;
3585         size_t size, valsize;
3586         struct ip_fw_chain *chain;
3587         char xbuf[256];
3588         struct sockopt_data sdata;
3589         struct ipfw_sopt_handler h;
3590         ip_fw3_opheader *op3 = NULL;
3591
3592         error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW);
3593         if (error != 0)
3594                 return (error);
3595
3596         if (sopt->sopt_name != IP_FW3)
3597                 return (ipfw_ctl(sopt));
3598
3599         chain = &V_layer3_chain;
3600         error = 0;
3601
3602         /* Save original valsize before it is altered via sooptcopyin() */
3603         valsize = sopt->sopt_valsize;
3604         memset(&sdata, 0, sizeof(sdata));
3605         /* Read op3 header first to determine actual operation */
3606         op3 = (ip_fw3_opheader *)xbuf;
3607         error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3));
3608         if (error != 0)
3609                 return (error);
3610         sopt->sopt_valsize = valsize;
3611
3612         /*
3613          * Find and reference command.
3614          */
3615         error = find_ref_sh(op3->opcode, op3->version, &h);
3616         if (error != 0)
3617                 return (error);
3618
3619         /*
3620          * Disallow modifications in really-really secure mode, but still allow
3621          * the logging counters to be reset.
3622          */
3623         if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) {
3624                 error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
3625                 if (error != 0) {
3626                         find_unref_sh(&h);
3627                         return (error);
3628                 }
3629         }
3630
3631         /*
3632          * Fill in sockopt_data structure that may be useful for
3633          * IP_FW3 get requests.
3634          */
3635         locked = 0;
3636         if (valsize <= sizeof(xbuf)) {
3637                 /* use on-stack buffer */
3638                 sdata.kbuf = xbuf;
3639                 sdata.ksize = sizeof(xbuf);
3640                 sdata.kavail = valsize;
3641         } else {
3642
3643                 /*
3644                  * Determine opcode type/buffer size:
3645                  * allocate sliding-window buf for data export or
3646                  * contiguous buffer for special ops.
3647                  */
3648                 if ((h.dir & HDIR_SET) != 0) {
3649                         /* Set request. Allocate contigous buffer. */
3650                         if (valsize > CTL3_LARGEBUF) {
3651                                 find_unref_sh(&h);
3652                                 return (EFBIG);
3653                         }
3654
3655                         size = valsize;
3656                 } else {
3657                         /* Get request. Allocate sliding window buffer */
3658                         size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF;
3659
3660                         if (size < valsize) {
3661                                 /* We have to wire user buffer */
3662                                 error = vslock(sopt->sopt_val, valsize);
3663                                 if (error != 0)
3664                                         return (error);
3665                                 locked = 1;
3666                         }
3667                 }
3668
3669                 sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
3670                 sdata.ksize = size;
3671                 sdata.kavail = size;
3672         }
3673
3674         sdata.sopt = sopt;
3675         sdata.sopt_val = sopt->sopt_val;
3676         sdata.valsize = valsize;
3677
3678         /*
3679          * Copy either all request (if valsize < bsize_max)
3680          * or first bsize_max bytes to guarantee most consumers
3681          * that all necessary data has been copied).
3682          * Anyway, copy not less than sizeof(ip_fw3_opheader).
3683          */
3684         if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize,
3685             sizeof(ip_fw3_opheader))) != 0)
3686                 return (error);
3687         op3 = (ip_fw3_opheader *)sdata.kbuf;
3688
3689         /* Finally, run handler */
3690         error = h.handler(chain, op3, &sdata);
3691         find_unref_sh(&h);
3692
3693         /* Flush state and free buffers */
3694         if (error == 0)
3695                 error = ipfw_flush_sopt_data(&sdata);
3696         else
3697                 ipfw_flush_sopt_data(&sdata);
3698
3699         if (locked != 0)
3700                 vsunlock(sdata.sopt_val, valsize);
3701
3702         /* Restore original pointer and set number of bytes written */
3703         sopt->sopt_val = sdata.sopt_val;
3704         sopt->sopt_valsize = sdata.ktotal;
3705         if (sdata.kbuf != xbuf)
3706                 free(sdata.kbuf, M_TEMP);
3707
3708         return (error);
3709 }
3710
3711 /**
3712  * {set|get}sockopt parser.
3713  */
3714 int
3715 ipfw_ctl(struct sockopt *sopt)
3716 {
3717 #define RULE_MAXSIZE    (512*sizeof(u_int32_t))
3718         int error;
3719         size_t size, valsize;
3720         struct ip_fw *buf;
3721         struct ip_fw_rule0 *rule;
3722         struct ip_fw_chain *chain;
3723         u_int32_t rulenum[2];
3724         uint32_t opt;
3725         struct rule_check_info ci;
3726         IPFW_RLOCK_TRACKER;
3727
3728         chain = &V_layer3_chain;
3729         error = 0;
3730
3731         /* Save original valsize before it is altered via sooptcopyin() */
3732         valsize = sopt->sopt_valsize;
3733         opt = sopt->sopt_name;
3734
3735         /*
3736          * Disallow modifications in really-really secure mode, but still allow
3737          * the logging counters to be reset.
3738          */
3739         if (opt == IP_FW_ADD ||
3740             (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) {
3741                 error = securelevel_ge(sopt->sopt_td->td_ucred, 3);
3742                 if (error != 0)
3743                         return (error);
3744         }
3745
3746         switch (opt) {
3747         case IP_FW_GET:
3748                 /*
3749                  * pass up a copy of the current rules. Static rules
3750                  * come first (the last of which has number IPFW_DEFAULT_RULE),
3751                  * followed by a possibly empty list of dynamic rule.
3752                  * The last dynamic rule has NULL in the "next" field.
3753                  *
3754                  * Note that the calculated size is used to bound the
3755                  * amount of data returned to the user.  The rule set may
3756                  * change between calculating the size and returning the
3757                  * data in which case we'll just return what fits.
3758                  */
3759                 for (;;) {
3760                         int len = 0, want;
3761
3762                         size = chain->static_len;
3763                         size += ipfw_dyn_len();
3764                         if (size >= sopt->sopt_valsize)
3765                                 break;
3766                         buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
3767                         IPFW_UH_RLOCK(chain);
3768                         /* check again how much space we need */
3769                         want = chain->static_len + ipfw_dyn_len();
3770                         if (size >= want)
3771                                 len = ipfw_getrules(chain, buf, size);
3772                         IPFW_UH_RUNLOCK(chain);
3773                         if (size >= want)
3774                                 error = sooptcopyout(sopt, buf, len);
3775                         free(buf, M_TEMP);
3776                         if (size >= want)
3777                                 break;
3778                 }
3779                 break;
3780
3781         case IP_FW_FLUSH:
3782                 /* locking is done within del_entry() */
3783                 error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */
3784                 break;
3785
3786         case IP_FW_ADD:
3787                 rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK);
3788                 error = sooptcopyin(sopt, rule, RULE_MAXSIZE,
3789                         sizeof(struct ip_fw7) );
3790
3791                 memset(&ci, 0, sizeof(struct rule_check_info));
3792
3793                 /*
3794                  * If the size of commands equals RULESIZE7 then we assume
3795                  * a FreeBSD7.2 binary is talking to us (set is7=1).
3796                  * is7 is persistent so the next 'ipfw list' command
3797                  * will use this format.
3798                  * NOTE: If wrong version is guessed (this can happen if
3799                  *       the first ipfw command is 'ipfw [pipe] list')
3800                  *       the ipfw binary may crash or loop infinitly...
3801                  */
3802                 size = sopt->sopt_valsize;
3803                 if (size == RULESIZE7(rule)) {
3804                     is7 = 1;
3805                     error = convert_rule_to_8(rule);
3806                     if (error) {
3807                         free(rule, M_TEMP);
3808                         return error;
3809                     }
3810                     size = RULESIZE(rule);
3811                 } else
3812                     is7 = 0;
3813                 if (error == 0)
3814                         error = check_ipfw_rule0(rule, size, &ci);
3815                 if (error == 0) {
3816                         /* locking is done within add_rule() */
3817                         struct ip_fw *krule;
3818                         krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule));
3819                         ci.urule = (caddr_t)rule;
3820                         ci.krule = krule;
3821                         import_rule0(&ci);
3822                         error = commit_rules(chain, &ci, 1);
3823                         if (error != 0)
3824                                 free_rule(ci.krule);
3825                         else if (sopt->sopt_dir == SOPT_GET) {
3826                                 if (is7) {
3827                                         error = convert_rule_to_7(rule);
3828                                         size = RULESIZE7(rule);
3829                                         if (error) {
3830                                                 free(rule, M_TEMP);
3831                                                 return error;
3832                                         }
3833                                 }
3834                                 error = sooptcopyout(sopt, rule, size);
3835                         }
3836                 }
3837                 free(rule, M_TEMP);
3838                 break;
3839
3840         case IP_FW_DEL:
3841                 /*
3842                  * IP_FW_DEL is used for deleting single rules or sets,
3843                  * and (ab)used to atomically manipulate sets. Argument size
3844                  * is used to distinguish between the two:
3845                  *    sizeof(u_int32_t)
3846                  *      delete single rule or set of rules,
3847                  *      or reassign rules (or sets) to a different set.
3848                  *    2*sizeof(u_int32_t)
3849                  *      atomic disable/enable sets.
3850                  *      first u_int32_t contains sets to be disabled,
3851                  *      second u_int32_t contains sets to be enabled.
3852                  */
3853                 error = sooptcopyin(sopt, rulenum,
3854                         2*sizeof(u_int32_t), sizeof(u_int32_t));
3855                 if (error)
3856                         break;
3857                 size = sopt->sopt_valsize;
3858                 if (size == sizeof(u_int32_t) && rulenum[0] != 0) {
3859                         /* delete or reassign, locking done in del_entry() */
3860                         error = del_entry(chain, rulenum[0]);
3861                 } else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */
3862                         IPFW_UH_WLOCK(chain);
3863                         V_set_disable =
3864                             (V_set_disable | rulenum[0]) & ~rulenum[1] &
3865                             ~(1<<RESVD_SET); /* set RESVD_SET always enabled */
3866                         IPFW_UH_WUNLOCK(chain);
3867                 } else
3868                         error = EINVAL;
3869                 break;
3870
3871         case IP_FW_ZERO:
3872         case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */
3873                 rulenum[0] = 0;
3874                 if (sopt->sopt_val != 0) {
3875                     error = sooptcopyin(sopt, rulenum,
3876                             sizeof(u_int32_t), sizeof(u_int32_t));
3877                     if (error)
3878                         break;
3879                 }
3880                 error = zero_entry(chain, rulenum[0],
3881                         sopt->sopt_name == IP_FW_RESETLOG);
3882                 break;
3883
3884         /*--- TABLE opcodes ---*/
3885         case IP_FW_TABLE_ADD:
3886         case IP_FW_TABLE_DEL:
3887                 {
3888                         ipfw_table_entry ent;
3889                         struct tentry_info tei;
3890                         struct tid_info ti;
3891                         struct table_value v;
3892
3893                         error = sooptcopyin(sopt, &ent,
3894                             sizeof(ent), sizeof(ent));
3895                         if (error)
3896                                 break;
3897
3898                         memset(&tei, 0, sizeof(tei));
3899                         tei.paddr = &ent.addr;
3900                         tei.subtype = AF_INET;
3901                         tei.masklen = ent.masklen;
3902                         ipfw_import_table_value_legacy(ent.value, &v);
3903                         tei.pvalue = &v;
3904                         memset(&ti, 0, sizeof(ti));
3905                         ti.uidx = ent.tbl;
3906                         ti.type = IPFW_TABLE_CIDR;
3907
3908                         error = (opt == IP_FW_TABLE_ADD) ?
3909                             add_table_entry(chain, &ti, &tei, 0, 1) :
3910                             del_table_entry(chain, &ti, &tei, 0, 1);
3911                 }
3912                 break;
3913
3914
3915         case IP_FW_TABLE_FLUSH:
3916                 {
3917                         u_int16_t tbl;
3918                         struct tid_info ti;
3919
3920                         error = sooptcopyin(sopt, &tbl,
3921                             sizeof(tbl), sizeof(tbl));
3922                         if (error)
3923                                 break;
3924                         memset(&ti, 0, sizeof(ti));
3925                         ti.uidx = tbl;
3926                         error = flush_table(chain, &ti);
3927                 }
3928                 break;
3929
3930         case IP_FW_TABLE_GETSIZE:
3931                 {
3932                         u_int32_t tbl, cnt;
3933                         struct tid_info ti;
3934
3935                         if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl),
3936                             sizeof(tbl))))
3937                                 break;
3938                         memset(&ti, 0, sizeof(ti));
3939                         ti.uidx = tbl;
3940                         IPFW_RLOCK(chain);
3941                         error = ipfw_count_table(chain, &ti, &cnt);
3942                         IPFW_RUNLOCK(chain);
3943                         if (error)
3944                                 break;
3945                         error = sooptcopyout(sopt, &cnt, sizeof(cnt));
3946                 }
3947                 break;
3948
3949         case IP_FW_TABLE_LIST:
3950                 {
3951                         ipfw_table *tbl;
3952                         struct tid_info ti;
3953
3954                         if (sopt->sopt_valsize < sizeof(*tbl)) {
3955                                 error = EINVAL;
3956                                 break;
3957                         }
3958                         size = sopt->sopt_valsize;
3959                         tbl = malloc(size, M_TEMP, M_WAITOK);
3960                         error = sooptcopyin(sopt, tbl, size, sizeof(*tbl));
3961                         if (error) {
3962                                 free(tbl, M_TEMP);
3963                                 break;
3964                         }
3965                         tbl->size = (size - sizeof(*tbl)) /
3966                             sizeof(ipfw_table_entry);
3967                         memset(&ti, 0, sizeof(ti));
3968                         ti.uidx = tbl->tbl;
3969                         IPFW_RLOCK(chain);
3970                         error = ipfw_dump_table_legacy(chain, &ti, tbl);
3971                         IPFW_RUNLOCK(chain);
3972                         if (error) {
3973                                 free(tbl, M_TEMP);
3974                                 break;
3975                         }
3976                         error = sooptcopyout(sopt, tbl, size);
3977                         free(tbl, M_TEMP);
3978                 }
3979                 break;
3980
3981         /*--- NAT operations are protected by the IPFW_LOCK ---*/
3982         case IP_FW_NAT_CFG:
3983                 if (IPFW_NAT_LOADED)
3984                         error = ipfw_nat_cfg_ptr(sopt);
3985                 else {
3986                         printf("IP_FW_NAT_CFG: %s\n",
3987                             "ipfw_nat not present, please load it");
3988                         error = EINVAL;
3989                 }
3990                 break;
3991
3992         case IP_FW_NAT_DEL:
3993                 if (IPFW_NAT_LOADED)
3994                         error = ipfw_nat_del_ptr(sopt);
3995                 else {
3996                         printf("IP_FW_NAT_DEL: %s\n",
3997                             "ipfw_nat not present, please load it");
3998                         error = EINVAL;
3999                 }
4000                 break;
4001
4002         case IP_FW_NAT_GET_CONFIG:
4003                 if (IPFW_NAT_LOADED)
4004                         error = ipfw_nat_get_cfg_ptr(sopt);
4005                 else {
4006                         printf("IP_FW_NAT_GET_CFG: %s\n",
4007                             "ipfw_nat not present, please load it");
4008                         error = EINVAL;
4009                 }
4010                 break;
4011
4012         case IP_FW_NAT_GET_LOG:
4013                 if (IPFW_NAT_LOADED)
4014                         error = ipfw_nat_get_log_ptr(sopt);
4015                 else {
4016                         printf("IP_FW_NAT_GET_LOG: %s\n",
4017                             "ipfw_nat not present, please load it");
4018                         error = EINVAL;
4019                 }
4020                 break;
4021
4022         default:
4023                 printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name);
4024                 error = EINVAL;
4025         }
4026
4027         return (error);
4028 #undef RULE_MAXSIZE
4029 }
4030 #define RULE_MAXSIZE    (256*sizeof(u_int32_t))
4031
4032 /* Functions to convert rules 7.2 <==> 8.0 */
4033 static int
4034 convert_rule_to_7(struct ip_fw_rule0 *rule)
4035 {
4036         /* Used to modify original rule */
4037         struct ip_fw7 *rule7 = (struct ip_fw7 *)rule;
4038         /* copy of original rule, version 8 */
4039         struct ip_fw_rule0 *tmp;
4040
4041         /* Used to copy commands */
4042         ipfw_insn *ccmd, *dst;
4043         int ll = 0, ccmdlen = 0;
4044
4045         tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
4046         if (tmp == NULL) {
4047                 return 1; //XXX error
4048         }
4049         bcopy(rule, tmp, RULE_MAXSIZE);
4050
4051         /* Copy fields */
4052         //rule7->_pad = tmp->_pad;
4053         rule7->set = tmp->set;
4054         rule7->rulenum = tmp->rulenum;
4055         rule7->cmd_len = tmp->cmd_len;
4056         rule7->act_ofs = tmp->act_ofs;
4057         rule7->next_rule = (struct ip_fw7 *)tmp->next_rule;
4058         rule7->cmd_len = tmp->cmd_len;
4059         rule7->pcnt = tmp->pcnt;
4060         rule7->bcnt = tmp->bcnt;
4061         rule7->timestamp = tmp->timestamp;
4062
4063         /* Copy commands */
4064         for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ;
4065                         ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
4066                 ccmdlen = F_LEN(ccmd);
4067
4068                 bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
4069
4070                 if (dst->opcode > O_NAT)
4071                         /* O_REASS doesn't exists in 7.2 version, so
4072                          * decrement opcode if it is after O_REASS
4073                          */
4074                         dst->opcode--;
4075
4076                 if (ccmdlen > ll) {
4077                         printf("ipfw: opcode %d size truncated\n",
4078                                 ccmd->opcode);
4079                         return EINVAL;
4080                 }
4081         }
4082         free(tmp, M_TEMP);
4083
4084         return 0;
4085 }
4086
4087 static int
4088 convert_rule_to_8(struct ip_fw_rule0 *rule)
4089 {
4090         /* Used to modify original rule */
4091         struct ip_fw7 *rule7 = (struct ip_fw7 *) rule;
4092
4093         /* Used to copy commands */
4094         ipfw_insn *ccmd, *dst;
4095         int ll = 0, ccmdlen = 0;
4096
4097         /* Copy of original rule */
4098         struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO);
4099         if (tmp == NULL) {
4100                 return 1; //XXX error
4101         }
4102
4103         bcopy(rule7, tmp, RULE_MAXSIZE);
4104
4105         for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ;
4106                         ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) {
4107                 ccmdlen = F_LEN(ccmd);
4108                 
4109                 bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t));
4110
4111                 if (dst->opcode > O_NAT)
4112                         /* O_REASS doesn't exists in 7.2 version, so
4113                          * increment opcode if it is after O_REASS
4114                          */
4115                         dst->opcode++;
4116
4117                 if (ccmdlen > ll) {
4118                         printf("ipfw: opcode %d size truncated\n",
4119                             ccmd->opcode);
4120                         return EINVAL;
4121                 }
4122         }
4123
4124         rule->_pad = tmp->_pad;
4125         rule->set = tmp->set;
4126         rule->rulenum = tmp->rulenum;
4127         rule->cmd_len = tmp->cmd_len;
4128         rule->act_ofs = tmp->act_ofs;
4129         rule->next_rule = (struct ip_fw *)tmp->next_rule;
4130         rule->cmd_len = tmp->cmd_len;
4131         rule->id = 0; /* XXX see if is ok = 0 */
4132         rule->pcnt = tmp->pcnt;
4133         rule->bcnt = tmp->bcnt;
4134         rule->timestamp = tmp->timestamp;
4135
4136         free (tmp, M_TEMP);
4137         return 0;
4138 }
4139
4140 /*
4141  * Named object api
4142  *
4143  */
4144
4145 void
4146 ipfw_init_srv(struct ip_fw_chain *ch)
4147 {
4148
4149         ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT);
4150         ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT,
4151             M_IPFW, M_WAITOK | M_ZERO);
4152 }
4153
4154 void
4155 ipfw_destroy_srv(struct ip_fw_chain *ch)
4156 {
4157
4158         free(ch->srvstate, M_IPFW);
4159         ipfw_objhash_destroy(ch->srvmap);
4160 }
4161
4162 /*
4163  * Allocate new bitmask which can be used to enlarge/shrink
4164  * named instance index.
4165  */
4166 void
4167 ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks)
4168 {
4169         size_t size;
4170         int max_blocks;
4171         u_long *idx_mask;
4172
4173         KASSERT((items % BLOCK_ITEMS) == 0,
4174            ("bitmask size needs to power of 2 and greater or equal to %zu",
4175             BLOCK_ITEMS));
4176
4177         max_blocks = items / BLOCK_ITEMS;
4178         size = items / 8;
4179         idx_mask = malloc(size * IPFW_MAX_SETS, M_IPFW, M_WAITOK);
4180         /* Mark all as free */
4181         memset(idx_mask, 0xFF, size * IPFW_MAX_SETS);
4182         *idx_mask &= ~(u_long)1; /* Skip index 0 */
4183
4184         *idx = idx_mask;
4185         *pblocks = max_blocks;
4186 }
4187
4188 /*
4189  * Copy current bitmask index to new one.
4190  */
4191 void
4192 ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks)
4193 {
4194         int old_blocks, new_blocks;
4195         u_long *old_idx, *new_idx;
4196         int i;
4197
4198         old_idx = ni->idx_mask;
4199         old_blocks = ni->max_blocks;
4200         new_idx = *idx;
4201         new_blocks = *blocks;
4202
4203         for (i = 0; i < IPFW_MAX_SETS; i++) {
4204                 memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i],
4205                     old_blocks * sizeof(u_long));
4206         }
4207 }
4208
4209 /*
4210  * Swaps current @ni index with new one.
4211  */
4212 void
4213 ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks)
4214 {
4215         int old_blocks;
4216         u_long *old_idx;
4217
4218         old_idx = ni->idx_mask;
4219         old_blocks = ni->max_blocks;
4220
4221         ni->idx_mask = *idx;
4222         ni->max_blocks = *blocks;
4223
4224         /* Save old values */
4225         *idx = old_idx;
4226         *blocks = old_blocks;
4227 }
4228
4229 void
4230 ipfw_objhash_bitmap_free(void *idx, int blocks)
4231 {
4232
4233         free(idx, M_IPFW);
4234 }
4235
4236 /*
4237  * Creates named hash instance.
4238  * Must be called without holding any locks.
4239  * Return pointer to new instance.
4240  */
4241 struct namedobj_instance *
4242 ipfw_objhash_create(uint32_t items)
4243 {
4244         struct namedobj_instance *ni;
4245         int i;
4246         size_t size;
4247
4248         size = sizeof(struct namedobj_instance) +
4249             sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE +
4250             sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE;
4251
4252         ni = malloc(size, M_IPFW, M_WAITOK | M_ZERO);
4253         ni->nn_size = NAMEDOBJ_HASH_SIZE;
4254         ni->nv_size = NAMEDOBJ_HASH_SIZE;
4255
4256         ni->names = (struct namedobjects_head *)(ni +1);
4257         ni->values = &ni->names[ni->nn_size];
4258
4259         for (i = 0; i < ni->nn_size; i++)
4260                 TAILQ_INIT(&ni->names[i]);
4261
4262         for (i = 0; i < ni->nv_size; i++)
4263                 TAILQ_INIT(&ni->values[i]);
4264
4265         /* Set default hashing/comparison functions */
4266         ni->hash_f = objhash_hash_name;
4267         ni->cmp_f = objhash_cmp_name;
4268
4269         /* Allocate bitmask separately due to possible resize */
4270         ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks);
4271
4272         return (ni);
4273 }
4274
4275 void
4276 ipfw_objhash_destroy(struct namedobj_instance *ni)
4277 {
4278
4279         free(ni->idx_mask, M_IPFW);
4280         free(ni, M_IPFW);
4281 }
4282
4283 void
4284 ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f,
4285     objhash_cmp_f *cmp_f)
4286 {
4287
4288         ni->hash_f = hash_f;
4289         ni->cmp_f = cmp_f;
4290 }
4291
4292 static uint32_t
4293 objhash_hash_name(struct namedobj_instance *ni, const void *name, uint32_t set)
4294 {
4295
4296         return (fnv_32_str((const char *)name, FNV1_32_INIT));
4297 }
4298
4299 static int
4300 objhash_cmp_name(struct named_object *no, const void *name, uint32_t set)
4301 {
4302
4303         if ((strcmp(no->name, (const char *)name) == 0) && (no->set == set))
4304                 return (0);
4305
4306         return (1);
4307 }
4308
4309 static uint32_t
4310 objhash_hash_idx(struct namedobj_instance *ni, uint32_t val)
4311 {
4312         uint32_t v;
4313
4314         v = val % (ni->nv_size - 1);
4315
4316         return (v);
4317 }
4318
4319 struct named_object *
4320 ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name)
4321 {
4322         struct named_object *no;
4323         uint32_t hash;
4324
4325         hash = ni->hash_f(ni, name, set) % ni->nn_size;
4326         
4327         TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
4328                 if (ni->cmp_f(no, name, set) == 0)
4329                         return (no);
4330         }
4331
4332         return (NULL);
4333 }
4334
4335 /*
4336  * Find named object by @uid.
4337  * Check @tlvs for valid data inside.
4338  *
4339  * Returns pointer to found TLV or NULL.
4340  */
4341 ipfw_obj_ntlv *
4342 ipfw_find_name_tlv_type(void *tlvs, int len, uint16_t uidx, uint32_t etlv)
4343 {
4344         ipfw_obj_ntlv *ntlv;
4345         uintptr_t pa, pe;
4346         int l;
4347
4348         pa = (uintptr_t)tlvs;
4349         pe = pa + len;
4350         l = 0;
4351         for (; pa < pe; pa += l) {
4352                 ntlv = (ipfw_obj_ntlv *)pa;
4353                 l = ntlv->head.length;
4354
4355                 if (l != sizeof(*ntlv))
4356                         return (NULL);
4357
4358                 if (ntlv->idx != uidx)
4359                         continue;
4360                 /*
4361                  * When userland has specified zero TLV type, do
4362                  * not compare it with eltv. In some cases userland
4363                  * doesn't know what type should it have. Use only
4364                  * uidx and name for search named_object.
4365                  */
4366                 if (ntlv->head.type != 0 &&
4367                     ntlv->head.type != (uint16_t)etlv)
4368                         continue;
4369
4370                 if (ipfw_check_object_name_generic(ntlv->name) != 0)
4371                         return (NULL);
4372
4373                 return (ntlv);
4374         }
4375
4376         return (NULL);
4377 }
4378
4379 /*
4380  * Finds object config based on either legacy index
4381  * or name in ntlv.
4382  * Note @ti structure contains unchecked data from userland.
4383  *
4384  * Returns 0 in success and fills in @pno with found config
4385  */
4386 int
4387 ipfw_objhash_find_type(struct namedobj_instance *ni, struct tid_info *ti,
4388     uint32_t etlv, struct named_object **pno)
4389 {
4390         char *name;
4391         ipfw_obj_ntlv *ntlv;
4392         uint32_t set;
4393
4394         if (ti->tlvs == NULL)
4395                 return (EINVAL);
4396
4397         ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx, etlv);
4398         if (ntlv == NULL)
4399                 return (EINVAL);
4400         name = ntlv->name;
4401
4402         /*
4403          * Use set provided by @ti instead of @ntlv one.
4404          * This is needed due to different sets behavior
4405          * controlled by V_fw_tables_sets.
4406          */
4407         set = ti->set;
4408         *pno = ipfw_objhash_lookup_name(ni, set, name);
4409         if (*pno == NULL)
4410                 return (ESRCH);
4411         return (0);
4412 }
4413
4414 /*
4415  * Find named object by name, considering also its TLV type.
4416  */
4417 struct named_object *
4418 ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set,
4419     uint32_t type, const char *name)
4420 {
4421         struct named_object *no;
4422         uint32_t hash;
4423
4424         hash = ni->hash_f(ni, name, set) % ni->nn_size;
4425
4426         TAILQ_FOREACH(no, &ni->names[hash], nn_next) {
4427                 if (ni->cmp_f(no, name, set) == 0 &&
4428                     no->etlv == (uint16_t)type)
4429                         return (no);
4430         }
4431
4432         return (NULL);
4433 }
4434
4435 struct named_object *
4436 ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx)
4437 {
4438         struct named_object *no;
4439         uint32_t hash;
4440
4441         hash = objhash_hash_idx(ni, kidx);
4442         
4443         TAILQ_FOREACH(no, &ni->values[hash], nv_next) {
4444                 if (no->kidx == kidx)
4445                         return (no);
4446         }
4447
4448         return (NULL);
4449 }
4450
4451 int
4452 ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a,
4453     struct named_object *b)
4454 {
4455
4456         if ((strcmp(a->name, b->name) == 0) && a->set == b->set)
4457                 return (1);
4458
4459         return (0);
4460 }
4461
4462 void
4463 ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no)
4464 {
4465         uint32_t hash;
4466
4467         hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
4468         TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next);
4469
4470         hash = objhash_hash_idx(ni, no->kidx);
4471         TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next);
4472
4473         ni->count++;
4474 }
4475
4476 void
4477 ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no)
4478 {
4479         uint32_t hash;
4480
4481         hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size;
4482         TAILQ_REMOVE(&ni->names[hash], no, nn_next);
4483
4484         hash = objhash_hash_idx(ni, no->kidx);
4485         TAILQ_REMOVE(&ni->values[hash], no, nv_next);
4486
4487         ni->count--;
4488 }
4489
4490 uint32_t
4491 ipfw_objhash_count(struct namedobj_instance *ni)
4492 {
4493
4494         return (ni->count);
4495 }
4496
4497 uint32_t
4498 ipfw_objhash_count_type(struct namedobj_instance *ni, uint16_t type)
4499 {
4500         struct named_object *no;
4501         uint32_t count;
4502         int i;
4503
4504         count = 0;
4505         for (i = 0; i < ni->nn_size; i++) {
4506                 TAILQ_FOREACH(no, &ni->names[i], nn_next) {
4507                         if (no->etlv == type)
4508                                 count++;
4509                 }
4510         }
4511         return (count);
4512 }
4513
4514 /*
4515  * Runs @func for each found named object.
4516  * It is safe to delete objects from callback
4517  */
4518 int
4519 ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg)
4520 {
4521         struct named_object *no, *no_tmp;
4522         int i, ret;
4523
4524         for (i = 0; i < ni->nn_size; i++) {
4525                 TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
4526                         ret = f(ni, no, arg);
4527                         if (ret != 0)
4528                                 return (ret);
4529                 }
4530         }
4531         return (0);
4532 }
4533
4534 /*
4535  * Runs @f for each found named object with type @type.
4536  * It is safe to delete objects from callback
4537  */
4538 int
4539 ipfw_objhash_foreach_type(struct namedobj_instance *ni, objhash_cb_t *f,
4540     void *arg, uint16_t type)
4541 {
4542         struct named_object *no, *no_tmp;
4543         int i, ret;
4544
4545         for (i = 0; i < ni->nn_size; i++) {
4546                 TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) {
4547                         if (no->etlv != type)
4548                                 continue;
4549                         ret = f(ni, no, arg);
4550                         if (ret != 0)
4551                                 return (ret);
4552                 }
4553         }
4554         return (0);
4555 }
4556
4557 /*
4558  * Removes index from given set.
4559  * Returns 0 on success.
4560  */
4561 int
4562 ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx)
4563 {
4564         u_long *mask;
4565         int i, v;
4566
4567         i = idx / BLOCK_ITEMS;
4568         v = idx % BLOCK_ITEMS;
4569
4570         if (i >= ni->max_blocks)
4571                 return (1);
4572
4573         mask = &ni->idx_mask[i];
4574
4575         if ((*mask & ((u_long)1 << v)) != 0)
4576                 return (1);
4577
4578         /* Mark as free */
4579         *mask |= (u_long)1 << v;
4580
4581         /* Update free offset */
4582         if (ni->free_off[0] > i)
4583                 ni->free_off[0] = i;
4584         
4585         return (0);
4586 }
4587
4588 /*
4589  * Allocate new index in given instance and stores in in @pidx.
4590  * Returns 0 on success.
4591  */
4592 int
4593 ipfw_objhash_alloc_idx(void *n, uint16_t *pidx)
4594 {
4595         struct namedobj_instance *ni;
4596         u_long *mask;
4597         int i, off, v;
4598
4599         ni = (struct namedobj_instance *)n;
4600
4601         off = ni->free_off[0];
4602         mask = &ni->idx_mask[off];
4603
4604         for (i = off; i < ni->max_blocks; i++, mask++) {
4605                 if ((v = ffsl(*mask)) == 0)
4606                         continue;
4607
4608                 /* Mark as busy */
4609                 *mask &= ~ ((u_long)1 << (v - 1));
4610
4611                 ni->free_off[0] = i;
4612                 
4613                 v = BLOCK_ITEMS * i + v - 1;
4614
4615                 *pidx = v;
4616                 return (0);
4617         }
4618
4619         return (1);
4620 }
4621
4622 /* end of file */