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