1 /*
2  * Copyright (c) 2014 - 2018 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Bill Yuan <bycn82@dragonflybsd.org>
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  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "opt_ipfw.h"
36 #include "opt_inet.h"
37 #ifndef INET
38 #error IPFIREWALL3 requires INET.
39 #endif /* INET */
40 
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/mbuf.h>
45 #include <sys/socketvar.h>
46 #include <sys/sysctl.h>
47 #include <sys/systimer.h>
48 #include <sys/in_cksum.h>
49 #include <sys/systm.h>
50 #include <sys/proc.h>
51 #include <sys/socket.h>
52 #include <sys/syslog.h>
53 #include <sys/ucred.h>
54 #include <sys/lock.h>
55 #include <sys/tree.h>
56 
57 #include <net/if.h>
58 #include <net/ethernet.h>
59 #include <net/netmsg2.h>
60 #include <net/netisr2.h>
61 #include <net/route.h>
62 
63 #include <netinet/ip.h>
64 #include <netinet/in.h>
65 #include <netinet/in_systm.h>
66 #include <netinet/in_var.h>
67 #include <netinet/in_pcb.h>
68 #include <netinet/ip_var.h>
69 #include <netinet/ip_icmp.h>
70 #include <netinet/tcp.h>
71 #include <netinet/tcp_timer.h>
72 #include <netinet/tcp_var.h>
73 #include <netinet/tcpip.h>
74 #include <netinet/udp.h>
75 #include <netinet/udp_var.h>
76 #include <netinet/ip_divert.h>
77 #include <netinet/if_ether.h>
78 
79 #include <net/ipfw3/ip_fw.h>
80 #include <net/ipfw3_basic/ip_fw3_table.h>
81 #include <net/ipfw3_basic/ip_fw3_sync.h>
82 #include <net/ipfw3_basic/ip_fw3_basic.h>
83 #include <net/ipfw3_basic/ip_fw3_state.h>
84 
85 extern struct ipfw3_context		*fw3_ctx[MAXCPU];
86 extern struct ipfw3_sync_context 	fw3_sync_ctx;
87 extern struct ipfw3_state_context 	*fw3_state_ctx[MAXCPU];
88 extern ip_fw_ctl_t 			*ipfw_ctl_basic_ptr;
89 
90 extern int 				sysctl_var_fw3_verbose;
91 
92 extern int 			sysctl_var_state_max_tcp_in;
93 extern int 			sysctl_var_state_max_udp_in;
94 extern int 			sysctl_var_state_max_icmp_in;
95 
96 extern int 			sysctl_var_state_max_tcp_out;
97 extern int 			sysctl_var_state_max_udp_out;
98 extern int 			sysctl_var_state_max_icmp_out;
99 
100 extern int 			sysctl_var_icmp_timeout;
101 extern int 			sysctl_var_tcp_timeout;
102 extern int 			sysctl_var_udp_timeout;
103 
104 static struct ip_fw *
105 lookup_next_rule(struct ip_fw *me)
106 {
107 	struct ip_fw *rule = NULL;
108 	ipfw_insn *cmd;
109 
110 	/* look for action, in case it is a skipto */
111 	cmd = ACTION_PTR(me);
112 	if ((int)cmd->module == MODULE_BASIC_ID &&
113 		(int)cmd->opcode == O_BASIC_SKIPTO) {
114 		for (rule = me->next; rule; rule = rule->next) {
115 			if (rule->rulenum >= cmd->arg1)
116 				break;
117 		}
118 	}
119 	if (rule == NULL) /* failure or not a skipto */
120 		rule = me->next;
121 
122 	me->next_rule = rule;
123 	return rule;
124 }
125 
126 
127 static int
128 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
129 {
130 	if (ifp == NULL)	/* no iface with this packet, match fails */
131 		return 0;
132 
133 	/* Check by name or by IP address */
134 	if (cmd->name[0] != '\0') { /* match by name */
135 		/* Check name */
136 		if (cmd->p.glob) {
137 			if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
138 				return(1);
139 		} else {
140 			if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
141 				return(1);
142 		}
143 	} else {
144 		struct ifaddr_container *ifac;
145 
146 		TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
147 			struct ifaddr *ia = ifac->ifa;
148 
149 			if (ia->ifa_addr == NULL)
150 				continue;
151 			if (ia->ifa_addr->sa_family != AF_INET)
152 				continue;
153 			if (cmd->p.ip.s_addr ==
154 				((struct sockaddr_in *)
155 				(ia->ifa_addr))->sin_addr.s_addr)
156 					return(1);	/* match */
157 
158 		}
159 	}
160 	return 0;	/* no match, fail ... */
161 }
162 
163 /* implimentation of the checker functions */
164 void
165 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
166 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
167 {
168 	(*f)->pcnt++;
169 	(*f)->bcnt += ip_len;
170 	(*f)->timestamp = time_second;
171 	*cmd_ctl = IP_FW_CTL_NEXT;
172 }
173 
174 void
175 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
176 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
177 {
178 	(*f)->pcnt++;
179 	(*f)->bcnt += ip_len;
180 	(*f)->timestamp = time_second;
181 	if ((*f)->next_rule == NULL)
182 		lookup_next_rule(*f);
183 	*f = (*f)->next_rule;
184 	*cmd_ctl = IP_FW_CTL_AGAIN;
185 }
186 
187 void
188 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
189 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
190 {
191 	struct sockaddr_in *sin, *sa;
192 	struct m_tag *mtag;
193 
194 	if ((*args)->eh) {	/* not valid on layer2 pkts */
195 		*cmd_ctl=IP_FW_CTL_NEXT;
196 		return;
197 	}
198 
199 	(*f)->pcnt++;
200 	(*f)->bcnt += ip_len;
201 	(*f)->timestamp = time_second;
202 	if ((*f)->next_rule == NULL)
203 		lookup_next_rule(*f);
204 
205 	mtag = m_tag_get(PACKET_TAG_IPFORWARD,
206 			sizeof(*sin), M_INTWAIT | M_NULLOK);
207 	if (mtag == NULL) {
208 		*cmd_val = IP_FW_DENY;
209 		*cmd_ctl = IP_FW_CTL_DONE;
210 		return;
211 	}
212 	sin = m_tag_data(mtag);
213 	sa = &((ipfw_insn_sa *)cmd)->sa;
214 	/* arg3: count of the dest, arg1: type of fwd */
215 	int i = 0;
216 	if(cmd->arg3 > 1) {
217 		if (cmd->arg1 == 0) {		/* type: random */
218 			i = krandom() % cmd->arg3;
219 		} else if (cmd->arg1 == 1) {	/* type: round-robin */
220 			i = cmd->arg2++ % cmd->arg3;
221 		} else if (cmd->arg1 == 2) {	/* type: sticky */
222 			struct ip *ip = mtod((*args)->m, struct ip *);
223 			i = ip->ip_src.s_addr & (cmd->arg3 - 1);
224 		}
225 		sa += i;
226 	}
227 	*sin = *sa;	/* apply the destination */
228 	m_tag_prepend((*args)->m, mtag);
229 	(*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
230 	(*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
231 	*cmd_ctl = IP_FW_CTL_DONE;
232 	*cmd_val = IP_FW_PASS;
233 }
234 
235 void
236 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
237 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
238 {
239 	*cmd_ctl = IP_FW_CTL_NO;
240 	*cmd_val = ((*args)->oif == NULL);
241 }
242 
243 void
244 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
245 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
246 {
247 	*cmd_ctl = IP_FW_CTL_NO;
248 	*cmd_val = ((*args)->oif != NULL);
249 }
250 
251 void
252 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
253 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
254 {
255 	*cmd_ctl = IP_FW_CTL_NO;
256 	*cmd_val = iface_match((*args)->oif ?
257 			(*args)->oif : (*args)->m->m_pkthdr.rcvif,
258 			(ipfw_insn_if *)cmd);
259 }
260 
261 void
262 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
263 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
264 {
265 	*cmd_ctl = IP_FW_CTL_NO;
266 	*cmd_val = ((*args)->f_id.proto == cmd->arg1);
267 }
268 
269 void
270 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
271 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
272 {
273 	*cmd_ctl = IP_FW_CTL_NO;
274 	*cmd_val = (krandom() % 100) < cmd->arg1;
275 }
276 
277 void
278 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
279 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
280 {
281 	u_int hlen = 0;
282 	struct mbuf *m = (*args)->m;
283 	struct ip *ip = mtod(m, struct ip *);
284 	struct in_addr src_ip = ip->ip_src;
285 
286 	if ((*args)->eh == NULL ||
287 		(m->m_pkthdr.len >= sizeof(struct ip) &&
288 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
289 		hlen = ip->ip_hl << 2;
290 	}
291 	*cmd_val = (hlen > 0 &&
292 			((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
293 	*cmd_ctl = IP_FW_CTL_NO;
294 }
295 
296 void
297 check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
298 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
299 {
300 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
301 	struct ipfw3_table_context *table_ctx;
302 	struct radix_node_head *rnh;
303 	struct sockaddr_in sa;
304 
305 	struct mbuf *m = (*args)->m;
306 	struct ip *ip = mtod(m, struct ip *);
307 	struct in_addr src_ip = ip->ip_src;
308 
309 	*cmd_val = IP_FW_NOT_MATCH;
310 
311 	table_ctx = ctx->table_ctx;
312 	table_ctx += cmd->arg1;
313 
314         if (table_ctx->type != 0) {
315                 rnh = table_ctx->node;
316                 sa.sin_len = 8;
317                 sa.sin_addr.s_addr = src_ip.s_addr;
318                 if (rnh->rnh_lookup(&sa, NULL, rnh) != NULL)
319                         *cmd_val = IP_FW_MATCH;
320         }
321 	*cmd_ctl = IP_FW_CTL_NO;
322 }
323 
324 void
325 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
326 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
327 {
328 	u_int hlen = 0;
329 	struct mbuf *m = (*args)->m;
330 	struct ip *ip = mtod(m, struct ip *);
331 	struct in_addr src_ip = ip->ip_src;
332 
333 	if ((*args)->eh == NULL ||
334 		(m->m_pkthdr.len >= sizeof(struct ip) &&
335 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
336 		hlen = ip->ip_hl << 2;
337 	}
338 	*cmd_ctl = IP_FW_CTL_NO;
339 	if (hlen > 0) {
340 		struct ifnet *tif;
341 		tif = INADDR_TO_IFP(&src_ip);
342 		*cmd_val = (tif != NULL);
343 	} else {
344 		*cmd_val = IP_FW_NOT_MATCH;
345 	}
346 }
347 
348 void
349 check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
350 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
351 {
352 	u_int hlen = 0;
353 	struct mbuf *m = (*args)->m;
354 	struct ip *ip = mtod(m, struct ip *);
355 	struct in_addr src_ip = ip->ip_src;
356 
357 	if ((*args)->eh == NULL ||
358 		(m->m_pkthdr.len >= sizeof(struct ip) &&
359 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
360 		hlen = ip->ip_hl << 2;
361 	}
362 
363 	*cmd_ctl = IP_FW_CTL_NO;
364 	*cmd_val = (hlen > 0 &&
365 			((ipfw_insn_ip *)cmd)->addr.s_addr ==
366 			(src_ip.s_addr &
367 			((ipfw_insn_ip *)cmd)->mask.s_addr));
368 }
369 
370 void
371 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
372 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
373 {
374 	u_int hlen = 0;
375 	struct mbuf *m = (*args)->m;
376 	struct ip *ip = mtod(m, struct ip *);
377 	struct in_addr dst_ip = ip->ip_dst;
378 
379 	if ((*args)->eh == NULL ||
380 		(m->m_pkthdr.len >= sizeof(struct ip) &&
381 		 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
382 		hlen = ip->ip_hl << 2;
383 	}
384 	*cmd_val = (hlen > 0 &&
385 			((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
386 	*cmd_ctl = IP_FW_CTL_NO;
387 }
388 
389 void
390 check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
391 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
392 {
393 	struct ipfw3_context *ctx = fw3_ctx[mycpuid];
394 	struct ipfw3_table_context *table_ctx;
395 	struct radix_node_head *rnh;
396 	struct sockaddr_in sa;
397 
398 	struct mbuf *m = (*args)->m;
399 	struct ip *ip = mtod(m, struct ip *);
400 	struct in_addr dst_ip = ip->ip_dst;
401 
402 	*cmd_val = IP_FW_NOT_MATCH;
403 
404 	table_ctx = ctx->table_ctx;
405 	table_ctx += cmd->arg1;
406 
407         if (table_ctx->type != 0) {
408                 rnh = table_ctx->node;
409                 sa.sin_len = 8;
410                 sa.sin_addr.s_addr = dst_ip.s_addr;
411                 if (rnh->rnh_lookup(&sa, NULL, rnh) != NULL)
412                         *cmd_val = IP_FW_MATCH;
413         }
414 	*cmd_ctl = IP_FW_CTL_NO;
415 }
416 
417 void
418 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
419 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
420 {
421 	u_int hlen = 0;
422 	struct mbuf *m = (*args)->m;
423 	struct ip *ip = mtod(m, struct ip *);
424 	struct in_addr dst_ip = ip->ip_dst;
425 
426 	if ((*args)->eh == NULL ||
427 		(m->m_pkthdr.len >= sizeof(struct ip) &&
428 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
429 		hlen = ip->ip_hl << 2;
430 	}
431 	*cmd_ctl = IP_FW_CTL_NO;
432 	if (hlen > 0) {
433 		struct ifnet *tif;
434 		tif = INADDR_TO_IFP(&dst_ip);
435 		*cmd_val = (tif != NULL);
436 	} else {
437 		*cmd_val = IP_FW_NOT_MATCH;
438 	}
439 }
440 
441 void
442 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
443 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
444 {
445 	u_int hlen = 0;
446 	struct mbuf *m = (*args)->m;
447 	struct ip *ip = mtod(m, struct ip *);
448 	struct in_addr dst_ip = ip->ip_dst;
449 
450 	if ((*args)->eh == NULL ||
451 		(m->m_pkthdr.len >= sizeof(struct ip) &&
452 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
453 		hlen = ip->ip_hl << 2;
454 	}
455 
456 	*cmd_ctl = IP_FW_CTL_NO;
457 	*cmd_val = (hlen > 0 &&
458 			((ipfw_insn_ip *)cmd)->addr.s_addr ==
459 			(dst_ip.s_addr &
460 			((ipfw_insn_ip *)cmd)->mask.s_addr));
461 }
462 
463 void
464 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
465 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
466 {
467 	struct m_tag *mtag = m_tag_locate((*args)->m,
468 			MTAG_IPFW, cmd->arg1, NULL);
469 	if (mtag == NULL) {
470 		mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
471 		if (mtag != NULL)
472 			m_tag_prepend((*args)->m, mtag);
473 
474 	}
475 	(*f)->pcnt++;
476 	(*f)->bcnt += ip_len;
477 	(*f)->timestamp = time_second;
478 	*cmd_ctl = IP_FW_CTL_NEXT;
479 }
480 
481 void
482 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
483 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
484 {
485 	struct m_tag *mtag = m_tag_locate((*args)->m,
486 			MTAG_IPFW, cmd->arg1, NULL);
487 	if (mtag != NULL)
488 		m_tag_delete((*args)->m, mtag);
489 
490 	(*f)->pcnt++;
491 	(*f)->bcnt += ip_len;
492 	(*f)->timestamp = time_second;
493 	*cmd_ctl = IP_FW_CTL_NEXT;
494 }
495 
496 void
497 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
498 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
499 {
500 	*cmd_ctl = IP_FW_CTL_NO;
501 	if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL )
502 		*cmd_val = IP_FW_MATCH;
503 	else
504 		*cmd_val = IP_FW_NOT_MATCH;
505 }
506 
507 void
508 check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
509         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
510 {
511         *cmd_ctl = IP_FW_CTL_NO;
512         if ((*args)->f_id.src_port == cmd->arg1)
513                 *cmd_val = IP_FW_MATCH;
514         else
515                 *cmd_val = IP_FW_NOT_MATCH;
516 }
517 
518 void
519 check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
520         struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
521 {
522         *cmd_ctl = IP_FW_CTL_NO;
523         if ((*args)->f_id.dst_port == cmd->arg1)
524                 *cmd_val = IP_FW_MATCH;
525         else
526                 *cmd_val = IP_FW_NOT_MATCH;
527 }
528 
529 void
530 check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
531 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
532 {
533 	struct in_addr src_ip;
534 	u_int hlen = 0;
535 	struct mbuf *m = (*args)->m;
536 	struct ip *ip = mtod(m, struct ip *);
537 	src_ip = ip->ip_src;
538 	if ((*args)->eh == NULL ||
539 		(m->m_pkthdr.len >= sizeof(struct ip) &&
540 		ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
541 		hlen = ip->ip_hl << 2;
542 	}
543 	*cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
544 	*cmd_ctl = IP_FW_CTL_NO;
545 	if (*cmd_val && (*args)->f_id.src_port == cmd->arg1)
546 		*cmd_val = IP_FW_MATCH;
547 	else
548 		*cmd_val = IP_FW_NOT_MATCH;
549 }
550 
551 void
552 check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
553 	struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
554 {
555 	struct in_addr dst_ip;
556 	u_int hlen = 0;
557 	struct mbuf *m = (*args)->m;
558 	struct ip *ip = mtod(m, struct ip *);
559 	dst_ip = ip->ip_dst;
560 	if ((*args)->eh == NULL ||
561 		(m->m_pkthdr.len >= sizeof(struct ip) &&
562 		 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
563 		hlen = ip->ip_hl << 2;
564 	}
565 	*cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
566 	*cmd_ctl = IP_FW_CTL_NO;
567 	if (*cmd_val && (*args)->f_id.dst_port == cmd->arg1)
568 		*cmd_val = IP_FW_MATCH;
569 	else
570 		*cmd_val = IP_FW_NOT_MATCH;
571 }
572 
573 int
574 ip_fw3_basic_init(void)
575 {
576 	ip_fw3_register_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
577 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
578 			(filter_func)check_count);
579 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
580 			(filter_func)check_skipto);
581 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
582 			(filter_func)check_forward);
583 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
584 			(filter_func)check_keep_state);
585 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
586 			(filter_func)check_check_state);
587 
588 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
589 			O_BASIC_IN, (filter_func)check_in);
590 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
591 			O_BASIC_OUT, (filter_func)check_out);
592 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
593 			O_BASIC_VIA, (filter_func)check_via);
594 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
595 			O_BASIC_XMIT, (filter_func)check_via);
596 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
597 			O_BASIC_RECV, (filter_func)check_via);
598 
599 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
600 			O_BASIC_PROTO, (filter_func)check_proto);
601 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
602 			O_BASIC_PROB, (filter_func)check_prob);
603 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
604 			O_BASIC_IP_SRC, (filter_func)check_from);
605 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
606 			O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup);
607 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
608 			O_BASIC_IP_SRC_ME, (filter_func)check_from_me);
609 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
610 			O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask);
611 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
612 			O_BASIC_IP_DST, (filter_func)check_to);
613 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
614 			O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup);
615 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
616 			O_BASIC_IP_DST_ME, (filter_func)check_to_me);
617 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
618 			O_BASIC_IP_DST_MASK, (filter_func)check_to_mask);
619 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
620 			O_BASIC_TAG, (filter_func)check_tag);
621 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
622 			O_BASIC_UNTAG, (filter_func)check_untag);
623 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
624 			O_BASIC_TAGGED, (filter_func)check_tagged);
625 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
626 			O_BASIC_IP_SRCPORT, (filter_func)check_src_port);
627 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
628 			O_BASIC_IP_DSTPORT, (filter_func)check_dst_port);
629 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
630 			O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port);
631 	ip_fw3_register_filter_funcs(MODULE_BASIC_ID,
632 			O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port);
633 
634 	return 0;
635 }
636 
637 int
638 ip_fw3_basic_fini(void)
639 {
640 	return ip_fw3_unregister_module(MODULE_BASIC_ID);
641 }
642 
643 static int
644 ipfw3_basic_modevent(module_t mod, int type, void *data)
645 {
646 	int err;
647 	switch (type) {
648 		case MOD_LOAD:
649 			err = ip_fw3_basic_init();
650 			break;
651 		case MOD_UNLOAD:
652 			err = ip_fw3_basic_fini();
653 			break;
654 		default:
655 			err = 1;
656 	}
657 	ip_fw3_state_modevent(type);
658 	ip_fw3_table_modevent(type);
659 	return err;
660 }
661 
662 static moduledata_t ipfw3_basic_mod = {
663 	"ipfw3_basic",
664 	ipfw3_basic_modevent,
665 	NULL
666 };
667 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
668 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
669 MODULE_VERSION(ipfw3_basic, 1);
670