Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netpfil/ipfw/ip_fw_compat.c
39482 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2025 Yandex LLC
5
* Copyright (c) 2025 Andrey V. Elsukov <[email protected]>
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/cdefs.h>
30
/*
31
* Example of compatibility layer for ipfw's rule management routines.
32
*/
33
34
#include "opt_inet.h"
35
#include "opt_inet6.h"
36
#include "opt_ipfw.h"
37
38
#include <sys/param.h>
39
#include <sys/systm.h>
40
#include <sys/malloc.h>
41
#include <sys/mbuf.h>
42
#include <sys/module.h>
43
#include <sys/kernel.h>
44
#include <sys/lock.h>
45
#include <sys/priv.h>
46
#include <sys/proc.h>
47
#include <sys/rwlock.h>
48
#include <sys/rmlock.h>
49
#include <sys/socket.h>
50
#include <sys/socketvar.h>
51
#include <sys/sysctl.h>
52
#include <sys/syslog.h>
53
#include <sys/fnv_hash.h>
54
#include <net/if.h>
55
#include <net/pfil.h>
56
#include <net/route.h>
57
#include <net/vnet.h>
58
#include <vm/vm.h>
59
#include <vm/vm_extern.h>
60
61
#include <netinet/in.h>
62
#include <netinet/ip_var.h> /* hooks */
63
#include <netinet/ip_fw.h>
64
65
#include <netpfil/ipfw/ip_fw_private.h>
66
#include <netpfil/ipfw/ip_fw_table.h>
67
68
#ifdef MAC
69
#include <security/mac/mac_framework.h>
70
#endif
71
72
/*
73
* These structures were used by IP_FW3 socket option with version 0.
74
*/
75
typedef struct _ipfw_dyn_rule_v0 {
76
ipfw_dyn_rule *next; /* linked list of rules. */
77
struct ip_fw *rule; /* pointer to rule */
78
/* 'rule' is used to pass up the rule number (from the parent) */
79
80
ipfw_dyn_rule *parent; /* pointer to parent rule */
81
u_int64_t pcnt; /* packet match counter */
82
u_int64_t bcnt; /* byte match counter */
83
struct ipfw_flow_id id; /* (masked) flow id */
84
u_int32_t expire; /* expire time */
85
u_int32_t bucket; /* which bucket in hash table */
86
u_int32_t state; /* state of this rule (typically a
87
* combination of TCP flags)
88
*/
89
u_int32_t ack_fwd; /* most recent ACKs in forward */
90
u_int32_t ack_rev; /* and reverse directions (used */
91
/* to generate keepalives) */
92
u_int16_t dyn_type; /* rule type */
93
u_int16_t count; /* refcount */
94
u_int16_t kidx; /* index of named object */
95
} __packed __aligned(8) ipfw_dyn_rule_v0;
96
97
typedef struct _ipfw_obj_dyntlv_v0 {
98
ipfw_obj_tlv head;
99
ipfw_dyn_rule_v0 state;
100
} ipfw_obj_dyntlv_v0;
101
102
typedef struct _ipfw_obj_ntlv_v0 {
103
ipfw_obj_tlv head; /* TLV header */
104
uint16_t idx; /* Name index */
105
uint8_t set; /* set, if applicable */
106
uint8_t type; /* object type, if applicable */
107
uint32_t spare; /* unused */
108
char name[64]; /* Null-terminated name */
109
} ipfw_obj_ntlv_v0;
110
111
typedef struct _ipfw_range_tlv_v0 {
112
ipfw_obj_tlv head; /* TLV header */
113
uint32_t flags; /* Range flags */
114
uint16_t start_rule; /* Range start */
115
uint16_t end_rule; /* Range end */
116
uint32_t set; /* Range set to match */
117
uint32_t new_set; /* New set to move/swap to */
118
} ipfw_range_tlv_v0;
119
120
typedef struct _ipfw_range_header_v0 {
121
ip_fw3_opheader opheader; /* IP_FW3 opcode */
122
ipfw_range_tlv_v0 range;
123
} ipfw_range_header_v0;
124
125
typedef struct _ipfw_insn_limit_v0 {
126
ipfw_insn o;
127
uint8_t _pad;
128
uint8_t limit_mask;
129
uint16_t conn_limit;
130
} ipfw_insn_limit_v0;
131
132
typedef struct _ipfw_obj_tentry_v0 {
133
ipfw_obj_tlv head; /* TLV header */
134
uint8_t subtype; /* subtype (IPv4,IPv6) */
135
uint8_t masklen; /* mask length */
136
uint8_t result; /* request result */
137
uint8_t spare0;
138
uint16_t idx; /* Table name index */
139
uint16_t spare1;
140
union {
141
/* Longest field needs to be aligned by 8-byte boundary */
142
struct in_addr addr; /* IPv4 address */
143
uint32_t key; /* uid/gid/port */
144
struct in6_addr addr6; /* IPv6 address */
145
char iface[IF_NAMESIZE]; /* interface name */
146
struct tflow_entry flow;
147
} k;
148
union {
149
ipfw_table_value value; /* value data */
150
uint32_t kidx; /* value kernel index */
151
} v;
152
} ipfw_obj_tentry_v0;
153
154
static sopt_handler_f dump_config_v0, add_rules_v0, del_rules_v0,
155
clear_rules_v0, move_rules_v0, manage_sets_v0, dump_soptcodes_v0,
156
dump_srvobjects_v0;
157
158
static struct ipfw_sopt_handler scodes[] = {
159
{ IP_FW_XGET, IP_FW3_OPVER_0, HDIR_GET, dump_config_v0 },
160
{ IP_FW_XADD, IP_FW3_OPVER_0, HDIR_BOTH, add_rules_v0 },
161
{ IP_FW_XDEL, IP_FW3_OPVER_0, HDIR_BOTH, del_rules_v0 },
162
{ IP_FW_XZERO, IP_FW3_OPVER_0, HDIR_SET, clear_rules_v0 },
163
{ IP_FW_XRESETLOG, IP_FW3_OPVER_0, HDIR_SET, clear_rules_v0 },
164
{ IP_FW_XMOVE, IP_FW3_OPVER_0, HDIR_SET, move_rules_v0 },
165
{ IP_FW_SET_SWAP, IP_FW3_OPVER_0, HDIR_SET, manage_sets_v0 },
166
{ IP_FW_SET_MOVE, IP_FW3_OPVER_0, HDIR_SET, manage_sets_v0 },
167
{ IP_FW_SET_ENABLE, IP_FW3_OPVER_0, HDIR_SET, manage_sets_v0 },
168
{ IP_FW_DUMP_SOPTCODES, IP_FW3_OPVER_0, HDIR_GET, dump_soptcodes_v0 },
169
{ IP_FW_DUMP_SRVOBJECTS, IP_FW3_OPVER_0, HDIR_GET, dump_srvobjects_v0 },
170
};
171
172
static int
173
dump_config_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
174
struct sockopt_data *sd)
175
{
176
return (EOPNOTSUPP);
177
}
178
179
/*
180
* Calculate the size adjust needed to store opcodes converted from v0
181
* to v1.
182
*/
183
static int
184
adjust_size_v0(ipfw_insn *cmd)
185
{
186
int cmdlen, adjust;
187
188
cmdlen = F_LEN(cmd);
189
switch (cmd->opcode) {
190
case O_CHECK_STATE:
191
case O_KEEP_STATE:
192
case O_PROBE_STATE:
193
case O_EXTERNAL_ACTION:
194
case O_EXTERNAL_INSTANCE:
195
adjust = F_INSN_SIZE(ipfw_insn_kidx) - cmdlen;
196
break;
197
case O_LIMIT:
198
adjust = F_INSN_SIZE(ipfw_insn_limit) - cmdlen;
199
break;
200
case O_IP_SRC_LOOKUP:
201
case O_IP_DST_LOOKUP:
202
case O_IP_FLOW_LOOKUP:
203
case O_MAC_SRC_LOOKUP:
204
case O_MAC_DST_LOOKUP:
205
if (cmdlen == F_INSN_SIZE(ipfw_insn))
206
adjust = F_INSN_SIZE(ipfw_insn_kidx) - cmdlen;
207
else
208
adjust = F_INSN_SIZE(ipfw_insn_table) - cmdlen;
209
break;
210
case O_SKIPTO:
211
case O_CALLRETURN:
212
adjust = F_INSN_SIZE(ipfw_insn_u32) - cmdlen;
213
break;
214
default:
215
adjust = 0;
216
}
217
return (adjust);
218
}
219
220
static int
221
parse_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
222
struct sockopt_data *sd, ipfw_obj_ctlv **prtlv,
223
struct rule_check_info **pci)
224
{
225
ipfw_obj_ctlv *ctlv, *rtlv, *tstate;
226
ipfw_obj_ntlv_v0 *ntlv;
227
struct rule_check_info *ci, *cbuf;
228
struct ip_fw_rule *r;
229
size_t count, clen, read, rsize;
230
uint32_t rulenum;
231
int idx, error;
232
233
op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize);
234
ctlv = (ipfw_obj_ctlv *)(op3 + 1);
235
read = sizeof(ip_fw3_opheader);
236
if (read + sizeof(*ctlv) > sd->valsize)
237
return (EINVAL);
238
239
rtlv = NULL;
240
tstate = NULL;
241
cbuf = NULL;
242
/* Table names or other named objects. */
243
if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) {
244
/* Check size and alignment. */
245
clen = ctlv->head.length;
246
if (read + clen > sd->valsize || clen < sizeof(*ctlv) ||
247
(clen % sizeof(uint64_t)) != 0)
248
return (EINVAL);
249
/* Check for validness. */
250
count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv);
251
if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv))
252
return (EINVAL);
253
/*
254
* Check each TLV.
255
* Ensure TLVs are sorted ascending and
256
* there are no duplicates.
257
*/
258
idx = -1;
259
ntlv = (ipfw_obj_ntlv_v0 *)(ctlv + 1);
260
while (count > 0) {
261
if (ntlv->head.length != sizeof(ipfw_obj_ntlv_v0))
262
return (EINVAL);
263
264
error = ipfw_check_object_name_generic(ntlv->name);
265
if (error != 0)
266
return (error);
267
268
if (ntlv->idx <= idx)
269
return (EINVAL);
270
271
idx = ntlv->idx;
272
count--;
273
ntlv++;
274
}
275
276
tstate = ctlv;
277
read += ctlv->head.length;
278
ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
279
280
if (read + sizeof(*ctlv) > sd->valsize)
281
return (EINVAL);
282
}
283
284
/* List of rules. */
285
if (ctlv->head.type == IPFW_TLV_RULE_LIST) {
286
clen = ctlv->head.length;
287
if (read + clen > sd->valsize || clen < sizeof(*ctlv) ||
288
(clen % sizeof(uint64_t)) != 0)
289
return (EINVAL);
290
291
clen -= sizeof(*ctlv);
292
if (ctlv->count == 0 ||
293
ctlv->count > clen / sizeof(struct ip_fw_rule))
294
return (EINVAL);
295
296
/* Allocate state for each rule */
297
cbuf = malloc(ctlv->count * sizeof(struct rule_check_info),
298
M_TEMP, M_WAITOK | M_ZERO);
299
300
/*
301
* Check each rule for validness.
302
* Ensure numbered rules are sorted ascending
303
* and properly aligned
304
*/
305
rulenum = 0;
306
count = 0;
307
error = 0;
308
ci = cbuf;
309
r = (struct ip_fw_rule *)(ctlv + 1);
310
while (clen > 0) {
311
rsize = RULEUSIZE1(r);
312
if (rsize > clen || count > ctlv->count) {
313
error = EINVAL;
314
break;
315
}
316
ci->ctlv = tstate;
317
ci->version = IP_FW3_OPVER_0;
318
error = ipfw_check_rule(r, rsize, ci);
319
if (error != 0)
320
break;
321
322
/* Check sorting */
323
if (r->rulenum != 0 && r->rulenum < rulenum) {
324
printf("ipfw: wrong order: rulenum %u"
325
" vs %u\n", r->rulenum, rulenum);
326
error = EINVAL;
327
break;
328
}
329
rulenum = r->rulenum;
330
ci->urule = (caddr_t)r;
331
clen -= rsize;
332
r = (struct ip_fw_rule *)((caddr_t)r + rsize);
333
count++;
334
ci++;
335
}
336
337
if (ctlv->count != count || error != 0) {
338
free(cbuf, M_TEMP);
339
return (EINVAL);
340
}
341
342
rtlv = ctlv;
343
read += ctlv->head.length;
344
ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length);
345
}
346
347
if (read != sd->valsize || rtlv == NULL) {
348
free(cbuf, M_TEMP);
349
return (EINVAL);
350
}
351
352
*prtlv = rtlv;
353
*pci = cbuf;
354
return (0);
355
}
356
357
static void
358
convert_v0_to_v1(struct rule_check_info *ci, int rule_len)
359
{
360
struct ip_fw_rule *urule;
361
struct ip_fw *krule;
362
ipfw_insn *src, *dst;
363
int l, cmdlen, newlen;
364
365
urule = (struct ip_fw_rule *)ci->urule;
366
krule = ci->krule;
367
for (l = urule->cmd_len, src = urule->cmd, dst = krule->cmd;
368
l > 0 && rule_len > 0;
369
l -= cmdlen, src += cmdlen,
370
rule_len -= newlen, dst += newlen) {
371
cmdlen = F_LEN(src);
372
switch (src->opcode) {
373
case O_CHECK_STATE:
374
case O_KEEP_STATE:
375
case O_PROBE_STATE:
376
case O_EXTERNAL_ACTION:
377
case O_EXTERNAL_INSTANCE:
378
newlen = F_INSN_SIZE(ipfw_insn_kidx);
379
insntod(dst, kidx)->kidx = src->arg1;
380
break;
381
case O_LIMIT:
382
newlen = F_INSN_SIZE(ipfw_insn_limit);
383
insntod(dst, limit)->kidx = src->arg1;
384
insntod(dst, limit)->limit_mask =
385
insntoc(src, limit)->limit_mask;
386
insntod(dst, limit)->conn_limit =
387
insntoc(src, limit)->conn_limit;
388
break;
389
case O_IP_DST_LOOKUP:
390
if (cmdlen == F_INSN_SIZE(ipfw_insn) + 2) {
391
/* lookup type stored in d[1] */
392
dst->arg1 = insntoc(src, table)->value;
393
}
394
case O_IP_SRC_LOOKUP:
395
case O_IP_FLOW_LOOKUP:
396
case O_MAC_SRC_LOOKUP:
397
case O_MAC_DST_LOOKUP:
398
if (cmdlen == F_INSN_SIZE(ipfw_insn)) {
399
newlen = F_INSN_SIZE(ipfw_insn_kidx);
400
insntod(dst, kidx)->kidx = src->arg1;
401
} else {
402
newlen = F_INSN_SIZE(ipfw_insn_table);
403
insntod(dst, table)->kidx = src->arg1;
404
insntod(dst, table)->value =
405
insntoc(src, u32)->d[0];
406
}
407
break;
408
case O_CALLRETURN:
409
case O_SKIPTO:
410
newlen = F_INSN_SIZE(ipfw_insn_u32);
411
insntod(dst, u32)->d[0] = src->arg1;
412
break;
413
default:
414
newlen = cmdlen;
415
memcpy(dst, src, sizeof(uint32_t) * newlen);
416
continue;
417
}
418
dst->opcode = src->opcode;
419
dst->len = (src->len & (F_NOT | F_OR)) | newlen;
420
}
421
}
422
423
/*
424
* Copy rule @urule from v0 userland format to kernel @krule.
425
*/
426
static void
427
import_rule_v0(struct ip_fw_chain *chain, struct rule_check_info *ci)
428
{
429
struct ip_fw_rule *urule;
430
struct ip_fw *krule;
431
ipfw_insn *cmd;
432
int l, cmdlen, adjust, aadjust;
433
434
urule = (struct ip_fw_rule *)ci->urule;
435
l = urule->cmd_len;
436
cmd = urule->cmd;
437
adjust = aadjust = 0;
438
439
/* Scan all opcodes and determine the needed size */
440
while (l > 0) {
441
adjust += adjust_size_v0(cmd);
442
if (ACTION_PTR(urule) < cmd)
443
aadjust = adjust;
444
cmdlen = F_LEN(cmd);
445
l -= cmdlen;
446
cmd += cmdlen;
447
}
448
449
cmdlen = urule->cmd_len + adjust;
450
krule = ci->krule = ipfw_alloc_rule(chain, /* RULEKSIZE1(cmdlen) */
451
roundup2(sizeof(struct ip_fw) + cmdlen * 4 - 4, 8));
452
453
krule->act_ofs = urule->act_ofs + aadjust;
454
krule->cmd_len = urule->cmd_len + adjust;
455
456
if (adjust != 0)
457
printf("%s: converted rule %u: cmd_len %u -> %u, "
458
"act_ofs %u -> %u\n", __func__, urule->rulenum,
459
urule->cmd_len, krule->cmd_len, urule->act_ofs,
460
krule->act_ofs);
461
462
krule->rulenum = urule->rulenum;
463
krule->set = urule->set;
464
krule->flags = urule->flags;
465
466
/* Save rulenum offset */
467
ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum);
468
convert_v0_to_v1(ci, cmdlen);
469
}
470
471
static int
472
add_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
473
struct sockopt_data *sd)
474
{
475
ipfw_obj_ctlv *rtlv;
476
struct rule_check_info *ci, *nci;
477
int i, ret;
478
479
/*
480
* Check rules buffer for validness.
481
*/
482
ret = parse_rules_v0(chain, op3, sd, &rtlv, &nci);
483
if (ret != 0)
484
return (ret);
485
/*
486
* Allocate storage for the kernel representation of rules.
487
*/
488
for (i = 0, ci = nci; i < rtlv->count; i++, ci++)
489
import_rule_v0(chain, ci);
490
/*
491
* Try to add new rules to the chain.
492
*/
493
if ((ret = ipfw_commit_rules(chain, nci, rtlv->count)) != 0) {
494
for (i = 0, ci = nci; i < rtlv->count; i++, ci++)
495
ipfw_free_rule(ci->krule);
496
}
497
/* Cleanup after ipfw_parse_rules() */
498
free(nci, M_TEMP);
499
return (ret);
500
}
501
502
static int
503
check_range_tlv_v0(const ipfw_range_tlv_v0 *rt, ipfw_range_tlv *crt)
504
{
505
if (rt->head.length != sizeof(*rt))
506
return (1);
507
if (rt->start_rule > rt->end_rule)
508
return (1);
509
if (rt->set >= IPFW_MAX_SETS || rt->new_set >= IPFW_MAX_SETS)
510
return (1);
511
if ((rt->flags & IPFW_RCFLAG_USER) != rt->flags)
512
return (1);
513
514
crt->head = rt->head;
515
crt->head.length = sizeof(*crt);
516
crt->flags = rt->flags;
517
crt->start_rule = rt->start_rule;
518
crt->end_rule = rt->end_rule;
519
crt->set = rt->set;
520
crt->new_set = rt->new_set;
521
return (0);
522
}
523
524
static int
525
del_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
526
struct sockopt_data *sd)
527
{
528
ipfw_range_tlv rv;
529
ipfw_range_header_v0 *rh;
530
int error, ndel;
531
532
if (sd->valsize != sizeof(*rh))
533
return (EINVAL);
534
535
rh = (ipfw_range_header_v0 *)ipfw_get_sopt_space(sd, sd->valsize);
536
if (check_range_tlv_v0(&rh->range, &rv) != 0)
537
return (EINVAL);
538
539
ndel = 0;
540
if ((error = delete_range(chain, &rv, &ndel)) != 0)
541
return (error);
542
543
/* Save number of rules deleted */
544
rh->range.new_set = ndel;
545
return (0);
546
}
547
548
static int
549
clear_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
550
struct sockopt_data *sd)
551
{
552
return (EOPNOTSUPP);
553
}
554
555
static int
556
move_rules_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
557
struct sockopt_data *sd)
558
{
559
return (EOPNOTSUPP);
560
}
561
562
static int
563
manage_sets_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
564
struct sockopt_data *sd)
565
{
566
return (EOPNOTSUPP);
567
}
568
569
static int
570
dump_soptcodes_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
571
struct sockopt_data *sd)
572
{
573
return (EOPNOTSUPP);
574
}
575
576
static int
577
dump_srvobjects_v0(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
578
struct sockopt_data *sd)
579
{
580
return (EOPNOTSUPP);
581
}
582
583
static enum ipfw_opcheck_result
584
check_opcode_compat(ipfw_insn **pcmd, int *plen, struct rule_check_info *ci)
585
{
586
ipfw_insn *cmd;
587
size_t cmdlen;
588
589
if (ci->version != IP_FW3_OPVER_0)
590
return (FAILED);
591
592
cmd = *pcmd;
593
cmdlen = F_LEN(cmd);
594
switch (cmd->opcode) {
595
case O_PROBE_STATE:
596
case O_KEEP_STATE:
597
if (cmdlen != F_INSN_SIZE(ipfw_insn))
598
return (BAD_SIZE);
599
ci->object_opcodes++;
600
break;
601
case O_LIMIT:
602
if (cmdlen != F_INSN_SIZE(ipfw_insn_limit_v0))
603
return (BAD_SIZE);
604
ci->object_opcodes++;
605
break;
606
case O_IP_SRC_LOOKUP:
607
if (cmdlen > F_INSN_SIZE(ipfw_insn_u32))
608
return (BAD_SIZE);
609
/* FALLTHROUGH */
610
case O_IP_DST_LOOKUP:
611
if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
612
cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 &&
613
cmdlen != F_INSN_SIZE(ipfw_insn_u32))
614
return (BAD_SIZE);
615
if (cmd->arg1 >= V_fw_tables_max) {
616
printf("ipfw: invalid table number %u\n",
617
cmd->arg1);
618
return (FAILED);
619
}
620
ci->object_opcodes++;
621
break;
622
case O_IP_FLOW_LOOKUP:
623
if (cmdlen != F_INSN_SIZE(ipfw_insn) &&
624
cmdlen != F_INSN_SIZE(ipfw_insn_u32))
625
return (BAD_SIZE);
626
if (cmd->arg1 >= V_fw_tables_max) {
627
printf("ipfw: invalid table number %u\n",
628
cmd->arg1);
629
return (FAILED);
630
}
631
ci->object_opcodes++;
632
break;
633
case O_CHECK_STATE:
634
ci->object_opcodes++;
635
/* FALLTHROUGH */
636
case O_SKIPTO:
637
case O_CALLRETURN:
638
if (cmdlen != F_INSN_SIZE(ipfw_insn))
639
return (BAD_SIZE);
640
return (CHECK_ACTION);
641
642
case O_EXTERNAL_ACTION:
643
if (cmd->arg1 == 0 ||
644
cmdlen != F_INSN_SIZE(ipfw_insn)) {
645
printf("ipfw: invalid external "
646
"action opcode\n");
647
return (FAILED);
648
}
649
ci->object_opcodes++;
650
/*
651
* Do we have O_EXTERNAL_INSTANCE or O_EXTERNAL_DATA
652
* opcode?
653
*/
654
if (*plen != cmdlen) {
655
*plen -= cmdlen;
656
*pcmd = cmd += cmdlen;
657
cmdlen = F_LEN(cmd);
658
if (cmd->opcode == O_EXTERNAL_DATA)
659
return (CHECK_ACTION);
660
if (cmd->opcode != O_EXTERNAL_INSTANCE) {
661
printf("ipfw: invalid opcode "
662
"next to external action %u\n",
663
cmd->opcode);
664
return (FAILED);
665
}
666
if (cmd->arg1 == 0 ||
667
cmdlen != F_INSN_SIZE(ipfw_insn)) {
668
printf("ipfw: invalid external "
669
"action instance opcode\n");
670
return (FAILED);
671
}
672
ci->object_opcodes++;
673
}
674
return (CHECK_ACTION);
675
676
default:
677
return (ipfw_check_opcode(pcmd, plen, ci));
678
}
679
return (SUCCESS);
680
}
681
682
static int
683
ipfw_compat_modevent(module_t mod, int type, void *unused)
684
{
685
switch (type) {
686
case MOD_LOAD:
687
IPFW_ADD_SOPT_HANDLER(1, scodes);
688
ipfw_register_compat(check_opcode_compat);
689
break;
690
case MOD_UNLOAD:
691
ipfw_unregister_compat();
692
IPFW_DEL_SOPT_HANDLER(1, scodes);
693
break;
694
default:
695
return (EOPNOTSUPP);
696
}
697
return (0);
698
}
699
700
static moduledata_t ipfw_compat_mod = {
701
"ipfw_compat",
702
ipfw_compat_modevent,
703
0
704
};
705
706
/* Define startup order. */
707
#define IPFW_COMPAT_SI_SUB_FIREWALL SI_SUB_PROTO_FIREWALL
708
#define IPFW_COMPAT_MODEVENT_ORDER (SI_ORDER_ANY - 128) /* after ipfw */
709
#define IPFW_COMPAT_MODULE_ORDER (IPFW_COMPAT_MODEVENT_ORDER + 1)
710
711
DECLARE_MODULE(ipfw_compat, ipfw_compat_mod, IPFW_COMPAT_SI_SUB_FIREWALL,
712
IPFW_COMPAT_MODULE_ORDER);
713
MODULE_DEPEND(ipfw_compat, ipfw, 3, 3, 3);
714
MODULE_VERSION(ipfw_compat, 1);
715
716