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