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