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