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