2 * Copyright (c) 2014 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
39 #include <sys/socketvar.h>
40 #include <sys/sysctl.h>
41 #include <sys/syslog.h>
42 #include <sys/systimer.h>
43 #include <sys/thread2.h>
44 #include <sys/in_cksum.h>
47 #include <net/ethernet.h>
48 #include <net/netmsg2.h>
49 #include <net/netisr2.h>
50 #include <net/route.h>
52 #include <netinet/ip.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/in_var.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/ip_icmp.h>
59 #include <netinet/tcp.h>
60 #include <netinet/tcp_timer.h>
61 #include <netinet/tcp_var.h>
62 #include <netinet/tcpip.h>
63 #include <netinet/udp.h>
64 #include <netinet/udp_var.h>
65 #include <netinet/ip_divert.h>
66 #include <netinet/if_ether.h>
68 #include <net/ipfw3/ip_fw.h>
70 #include "ip_fw3_basic.h"
72 #define TIME_LEQ(a, b) ((int)((a) - (b)) <= 0)
74 extern struct ipfw_context *ipfw_ctx[MAXCPU];
75 extern int fw_verbose;
76 extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt;
77 extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt;
79 static int ip_fw_basic_loaded;
80 static struct netmsg_base ipfw_timeout_netmsg; /* schedule ipfw timeout */
81 static struct callout ipfw_tick_callout;
82 static int state_lifetime = 20;
83 static int state_expiry_check_interval = 10;
84 static int state_count_max = 4096;
85 static int state_hash_size_old = 0;
86 static int state_hash_size = 4096;
89 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
90 void adjust_hash_size_dispatch(netmsg_t nmsg);
92 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic,
93 CTLFLAG_RW, 0, "Firewall Basic");
94 SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size,
95 CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0,
96 ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size");
98 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW,
99 &state_lifetime, 0, "default life time");
100 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO,
101 state_expiry_check_interval, CTLFLAG_RW,
102 &state_expiry_check_interval, 0,
103 "default state expiry check interval");
104 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW,
105 &state_count_max, 0, "maximum of state");
108 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
110 int error, value = 0;
112 state_hash_size_old = state_hash_size;
113 value = state_hash_size;
114 error = sysctl_handle_int(oidp, &value, 0, req);
115 if (error || !req->newptr) {
119 * Make sure we have a power of 2 and
120 * do not allow more than 64k entries.
123 if (value <= 1 || value > 65536) {
126 if ((value & (value - 1)) != 0) {
131 if (state_hash_size != value) {
132 state_hash_size = value;
134 struct netmsg_base *msg, the_msg;
136 bzero(msg,sizeof(struct netmsg_base));
138 netmsg_init(msg, NULL, &curthread->td_msgport,
139 0, adjust_hash_size_dispatch);
140 ifnet_domsg(&msg->lmsg, 0);
147 adjust_hash_size_dispatch(netmsg_t nmsg)
149 struct ipfw_state_context *state_ctx;
150 struct ip_fw_state *the_state, *state;
151 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
154 for (i = 0; i < state_hash_size_old; i++) {
155 state_ctx = &ctx->state_ctx[i];
156 if (state_ctx != NULL) {
157 state = state_ctx->state;
158 while (state != NULL) {
161 kfree(the_state, M_IPFW3_BASIC);
166 kfree(ctx->state_ctx,M_IPFW3_BASIC);
167 ctx->state_ctx = kmalloc(state_hash_size *
168 sizeof(struct ipfw_state_context),
169 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
170 ctx->state_hash_size = state_hash_size;
171 ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
175 /* prototype of the checker functions */
176 void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
177 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
178 void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
179 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
180 void check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
181 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
182 void check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
183 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
185 void check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
186 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
187 void check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
188 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
189 void check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
190 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
191 void check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
192 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
193 void check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
194 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
195 void check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
196 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
197 void check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
198 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
199 void check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
200 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
201 void check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
202 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
203 void check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
204 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
205 void check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
206 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
207 void check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
208 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
209 void check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
210 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
211 void check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
212 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
213 void check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
214 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
216 /* prototype of the utility functions */
217 static struct ip_fw *lookup_next_rule(struct ip_fw *me);
218 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd);
219 static __inline int hash_packet(struct ipfw_flow_id *id);
222 hash_packet(struct ipfw_flow_id *id)
225 i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
226 (id->dst_port) ^ (id->src_port);
227 i &= state_hash_size - 1;
231 static struct ip_fw *
232 lookup_next_rule(struct ip_fw *me)
234 struct ip_fw *rule = NULL;
237 /* look for action, in case it is a skipto */
238 cmd = ACTION_PTR(me);
239 if ((int)cmd->module == MODULE_BASIC_ID &&
240 (int)cmd->opcode == O_BASIC_SKIPTO) {
241 for (rule = me->next; rule; rule = rule->next) {
242 if (rule->rulenum >= cmd->arg1)
246 if (rule == NULL) /* failure or not a skipto */
249 me->next_rule = rule;
254 * when all = 1, it will check all the state_ctx
256 static struct ip_fw_state *
257 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
259 struct ip_fw_state *state = NULL;
260 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
261 struct ipfw_state_context *state_ctx;
262 int start, end, i, count = 0;
264 if (all && cmd->arg1) {
266 end = state_hash_size - 1;
268 start = hash_packet(&args->f_id);
269 end = hash_packet(&args->f_id);
271 for (i = start; i <= end; i++) {
272 state_ctx = &ctx->state_ctx[i];
273 if (state_ctx != NULL) {
274 state = state_ctx->state;
275 struct ipfw_flow_id *fid = &args->f_id;
276 while (state != NULL) {
278 if ((cmd->arg3 == 1 &&
280 state->flow_id.src_ip) ||
283 state->flow_id.src_port) ||
286 state->flow_id.dst_ip) ||
289 state->flow_id.dst_port)) {
292 if (count >= cmd->arg1) {
299 if (fid->proto == state->flow_id.proto) {
301 state->flow_id.src_ip &&
303 state->flow_id.dst_ip &&
305 state->flow_id.src_port ||
306 state->flow_id.src_port == 0) &&
308 state->flow_id.dst_port ||
309 state->flow_id.dst_port == 0)) {
313 state->flow_id.dst_ip &&
315 state->flow_id.src_ip &&
317 state->flow_id.dst_port ||
318 state->flow_id.dst_port == 0) &&
320 state->flow_id.src_port ||
321 state->flow_id.src_port == 0)) {
333 static struct ip_fw_state *
334 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
336 struct ip_fw_state *state;
337 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
338 struct ipfw_state_context *state_ctx;
339 state_ctx = &ctx->state_ctx[hash_packet(&args->f_id)];
340 state = kmalloc(sizeof(struct ip_fw_state),
341 M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
346 state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
347 state->timestamp = time_second;
349 bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id));
350 //append the state into the state chian
351 if (state_ctx->last != NULL)
352 state_ctx->last->next = state;
354 state_ctx->state = state;
355 state_ctx->last = state;
362 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
364 if (ifp == NULL) /* no iface with this packet, match fails */
367 /* Check by name or by IP address */
368 if (cmd->name[0] != '\0') { /* match by name */
371 if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
374 if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
378 struct ifaddr_container *ifac;
380 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
381 struct ifaddr *ia = ifac->ifa;
383 if (ia->ifa_addr == NULL)
385 if (ia->ifa_addr->sa_family != AF_INET)
387 if (cmd->p.ip.s_addr ==
388 ((struct sockaddr_in *)
389 (ia->ifa_addr))->sin_addr.s_addr)
390 return(1); /* match */
394 return 0; /* no match, fail ... */
397 /* implimentation of the checker functions */
399 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
400 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
403 (*f)->bcnt += ip_len;
404 (*f)->timestamp = time_second;
405 *cmd_ctl = IP_FW_CTL_NEXT;
409 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
410 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
413 (*f)->bcnt += ip_len;
414 (*f)->timestamp = time_second;
415 if ((*f)->next_rule == NULL)
416 lookup_next_rule(*f);
418 *cmd_ctl = IP_FW_CTL_AGAIN;
422 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
423 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
425 struct sockaddr_in *sin, *sa;
428 if ((*args)->eh) { /* not valid on layer2 pkts */
429 *cmd_ctl=IP_FW_CTL_NEXT;
434 (*f)->bcnt += ip_len;
435 (*f)->timestamp = time_second;
436 if ((*f)->next_rule == NULL)
437 lookup_next_rule(*f);
439 mtag = m_tag_get(PACKET_TAG_IPFORWARD,
440 sizeof(*sin), M_NOWAIT);
442 *cmd_val = IP_FW_DENY;
443 *cmd_ctl = IP_FW_CTL_DONE;
446 sin = m_tag_data(mtag);
447 sa = &((ipfw_insn_sa *)cmd)->sa;
448 /* arg3: count of the dest, arg1: type of fwd */
451 if (cmd->arg1 == 0) { /* type: random */
452 i = krandom() % cmd->arg3;
453 } else if (cmd->arg1 == 1) { /* type: round-robin */
454 i = cmd->arg2++ % cmd->arg3;
455 } else if (cmd->arg1 == 2) { /* type: sticky */
456 struct ip *ip = mtod((*args)->m, struct ip *);
457 i = ip->ip_src.s_addr & (cmd->arg3 - 1);
461 *sin = *sa; /* apply the destination */
462 m_tag_prepend((*args)->m, mtag);
463 (*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
464 (*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
465 *cmd_ctl = IP_FW_CTL_DONE;
466 *cmd_val = IP_FW_PASS;
470 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
471 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
473 struct ip_fw_state *state=NULL;
475 state = lookup_state(*args, cmd, &limited, 0);
478 state->bcnt += ip_len;
479 state->timestamp = time_second;
481 (*f)->bcnt += ip_len;
482 (*f)->timestamp = time_second;
484 *cmd_ctl = IP_FW_CTL_CHK_STATE;
486 *cmd_ctl = IP_FW_CTL_NEXT;
491 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
492 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
494 *cmd_ctl = IP_FW_CTL_NO;
495 *cmd_val = ((*args)->oif == NULL);
499 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
500 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
502 *cmd_ctl = IP_FW_CTL_NO;
503 *cmd_val = ((*args)->oif != NULL);
507 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
508 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
510 *cmd_ctl = IP_FW_CTL_NO;
511 *cmd_val = iface_match((*args)->oif ?
512 (*args)->oif : (*args)->m->m_pkthdr.rcvif,
513 (ipfw_insn_if *)cmd);
517 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
518 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
520 *cmd_ctl = IP_FW_CTL_NO;
521 *cmd_val = ((*args)->f_id.proto == cmd->arg1);
525 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
526 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
528 *cmd_ctl = IP_FW_CTL_NO;
529 *cmd_val = (krandom() % 100) < cmd->arg1;
533 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
534 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
536 struct in_addr src_ip;
538 struct mbuf *m = (*args)->m;
539 struct ip *ip = mtod(m, struct ip *);
541 if ((*args)->eh == NULL ||
542 (m->m_pkthdr.len >= sizeof(struct ip) &&
543 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
544 hlen = ip->ip_hl << 2;
546 *cmd_val = (hlen > 0 &&
547 ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
548 *cmd_ctl = IP_FW_CTL_NO;
552 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
553 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
555 struct in_addr src_ip;
557 struct mbuf *m = (*args)->m;
558 struct ip *ip = mtod(m, struct ip *);
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;
565 *cmd_ctl = IP_FW_CTL_NO;
568 tif = INADDR_TO_IFP(&src_ip);
569 *cmd_val = (tif != NULL);
571 *cmd_val = IP_FW_NOT_MATCH;
576 check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
577 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
579 struct in_addr src_ip;
581 struct mbuf *m = (*args)->m;
582 struct ip *ip = mtod(m, struct ip *);
584 if ((*args)->eh == NULL ||
585 (m->m_pkthdr.len >= sizeof(struct ip) &&
586 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
587 hlen = ip->ip_hl << 2;
590 *cmd_ctl = IP_FW_CTL_NO;
591 *cmd_val = (hlen > 0 &&
592 ((ipfw_insn_ip *)cmd)->addr.s_addr ==
594 ((ipfw_insn_ip *)cmd)->mask.s_addr));
598 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
599 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
601 struct in_addr dst_ip;
603 struct mbuf *m = (*args)->m;
604 struct ip *ip = mtod(m, struct ip *);
606 if ((*args)->eh == NULL ||
607 (m->m_pkthdr.len >= sizeof(struct ip) &&
608 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
609 hlen = ip->ip_hl << 2;
611 *cmd_val = (hlen > 0 &&
612 ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
613 *cmd_ctl = IP_FW_CTL_NO;
617 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
618 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
620 struct in_addr dst_ip;
622 struct mbuf *m = (*args)->m;
623 struct ip *ip = mtod(m, struct ip *);
625 if ((*args)->eh == NULL ||
626 (m->m_pkthdr.len >= sizeof(struct ip) &&
627 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
628 hlen = ip->ip_hl << 2;
630 *cmd_ctl = IP_FW_CTL_NO;
633 tif = INADDR_TO_IFP(&dst_ip);
634 *cmd_val = (tif != NULL);
636 *cmd_val = IP_FW_NOT_MATCH;
641 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
642 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
644 struct in_addr dst_ip;
646 struct mbuf *m = (*args)->m;
647 struct ip *ip = mtod(m, struct ip *);
649 if ((*args)->eh == NULL ||
650 (m->m_pkthdr.len >= sizeof(struct ip) &&
651 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
652 hlen = ip->ip_hl << 2;
655 *cmd_ctl = IP_FW_CTL_NO;
656 *cmd_val = (hlen > 0 &&
657 ((ipfw_insn_ip *)cmd)->addr.s_addr ==
659 ((ipfw_insn_ip *)cmd)->mask.s_addr));
663 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
664 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
666 struct ip_fw_state *state;
669 *cmd_ctl = IP_FW_CTL_NO;
670 state = lookup_state(*args, cmd, &limited, 1);
672 *cmd_val = IP_FW_NOT_MATCH;
675 state = install_state(*f, cmd, *args);
679 state->bcnt += ip_len;
680 state->timestamp = time_second;
681 *cmd_val = IP_FW_MATCH;
683 *cmd_val = IP_FW_NOT_MATCH;
689 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
690 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
692 struct m_tag *mtag = m_tag_locate((*args)->m,
693 MTAG_IPFW, cmd->arg1, NULL);
695 mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
697 m_tag_prepend((*args)->m, mtag);
701 (*f)->bcnt += ip_len;
702 (*f)->timestamp = time_second;
703 *cmd_ctl = IP_FW_CTL_NEXT;
707 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
708 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
710 struct m_tag *mtag = m_tag_locate((*args)->m,
711 MTAG_IPFW, cmd->arg1, NULL);
713 m_tag_delete((*args)->m, mtag);
716 (*f)->bcnt += ip_len;
717 (*f)->timestamp = time_second;
718 *cmd_ctl = IP_FW_CTL_NEXT;
722 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
723 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
725 *cmd_ctl = IP_FW_CTL_NO;
726 if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL )
727 *cmd_val = IP_FW_MATCH;
729 *cmd_val = IP_FW_NOT_MATCH;
733 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state)
735 struct ip_fw_state *state;
736 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
737 struct ipfw_state_context *state_ctx;
738 state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))];
739 state = kmalloc(sizeof(struct ip_fw_state),
740 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
741 struct ip_fw *rule = ctx->ipfw_rule_chain;
742 while (rule != NULL) {
743 if (rule->rulenum == ioc_state->rulenum) {
753 state->lifetime = ioc_state->lifetime == 0 ?
754 state_lifetime : ioc_state->lifetime ;
755 state->timestamp = time_second;
756 state->expiry = ioc_state->expiry;
757 bcopy(&ioc_state->flow_id, &state->flow_id,
758 sizeof(struct ipfw_flow_id));
759 //append the state into the state chian
760 if (state_ctx->last != NULL)
761 state_ctx->last->next = state;
763 state_ctx->state = state;
765 state_ctx->last = state;
773 * flush states which stub is the rule
776 ipfw_basic_flush_state(struct ip_fw *rule)
778 struct ipfw_state_context *state_ctx;
779 struct ip_fw_state *state,*the_state, *prev_state;
780 struct ipfw_context *ctx;
783 ctx = ipfw_ctx[mycpuid];
784 for (i = 0; i < state_hash_size; i++) {
785 state_ctx = &ctx->state_ctx[i];
786 if (state_ctx != NULL) {
787 state = state_ctx->state;
789 while (state != NULL) {
790 if (rule != NULL && state->stub != rule) {
794 if (prev_state == NULL)
795 state_ctx->state = state->next;
797 prev_state->next = state->next;
801 kfree(the_state, M_IPFW3_BASIC);
804 state_ctx->last = prev_state;
813 * clean up expired state in every tick
816 ipfw_cleanup_expired_state(netmsg_t nmsg)
818 struct ip_fw_state *state,*the_state,*prev_state;
819 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
820 struct ipfw_state_context *state_ctx;
823 for (i = 0; i < state_hash_size; i++) {
825 state_ctx = &(ctx->state_ctx[i]);
826 if (ctx->state_ctx != NULL) {
827 state = state_ctx->state;
828 while (state != NULL) {
829 if (IS_EXPIRED(state)) {
830 if (prev_state == NULL)
831 state_ctx->state = state->next;
833 prev_state->next = state->next;
838 if (the_state == state_ctx->last)
839 state_ctx->last = NULL;
842 kfree(the_state, M_IPFW3_BASIC);
851 ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
855 ipfw_tick(void *dummy __unused)
857 struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg;
858 KKASSERT(mycpuid == IPFW_CFGCPUID);
861 KKASSERT(lmsg->ms_flags & MSGF_DONE);
862 if (IPFW_BASIC_LOADED) {
863 lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg);
864 /* ipfw_timeout_netmsg's handler reset this callout */
868 struct netmsg_base *msg;
869 struct netmsg_base the_msg;
871 bzero(msg,sizeof(struct netmsg_base));
873 netmsg_init(msg, NULL, &curthread->td_msgport, 0,
874 ipfw_cleanup_expired_state);
875 ifnet_domsg(&msg->lmsg, 0);
879 ipfw_tick_dispatch(netmsg_t nmsg)
881 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
882 KKASSERT(IPFW_BASIC_LOADED);
886 lwkt_replymsg(&nmsg->lmsg, 0);
889 callout_reset(&ipfw_tick_callout,
890 state_expiry_check_interval * hz, ipfw_tick, NULL);
894 ipfw_basic_init_dispatch(netmsg_t nmsg)
896 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
897 KKASSERT(IPFW3_LOADED);
900 callout_init_mp(&ipfw_tick_callout);
901 netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport,
902 MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch);
903 callout_reset(&ipfw_tick_callout,
904 state_expiry_check_interval * hz, ipfw_tick, NULL);
905 lwkt_replymsg(&nmsg->lmsg, error);
906 ip_fw_basic_loaded=1;
910 ipfw_basic_init(void)
912 ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
913 ipfw_basic_append_state_prt = ipfw_basic_add_state;
915 register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
916 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
917 (filter_func)check_count);
918 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
919 (filter_func)check_skipto);
920 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
921 (filter_func)check_forward);
922 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
923 (filter_func)check_keep_state);
924 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
925 (filter_func)check_check_state);
927 register_ipfw_filter_funcs(MODULE_BASIC_ID,
928 O_BASIC_IN, (filter_func)check_in);
929 register_ipfw_filter_funcs(MODULE_BASIC_ID,
930 O_BASIC_OUT, (filter_func)check_out);
931 register_ipfw_filter_funcs(MODULE_BASIC_ID,
932 O_BASIC_VIA, (filter_func)check_via);
933 register_ipfw_filter_funcs(MODULE_BASIC_ID,
934 O_BASIC_XMIT, (filter_func)check_via);
935 register_ipfw_filter_funcs(MODULE_BASIC_ID,
936 O_BASIC_RECV, (filter_func)check_via);
938 register_ipfw_filter_funcs(MODULE_BASIC_ID,
939 O_BASIC_PROTO, (filter_func)check_proto);
940 register_ipfw_filter_funcs(MODULE_BASIC_ID,
941 O_BASIC_PROB, (filter_func)check_prob);
942 register_ipfw_filter_funcs(MODULE_BASIC_ID,
943 O_BASIC_IP_SRC, (filter_func)check_from);
944 register_ipfw_filter_funcs(MODULE_BASIC_ID,
945 O_BASIC_IP_SRC_ME, (filter_func)check_from_me);
946 register_ipfw_filter_funcs(MODULE_BASIC_ID,
947 O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask);
948 register_ipfw_filter_funcs(MODULE_BASIC_ID,
949 O_BASIC_IP_DST, (filter_func)check_to);
950 register_ipfw_filter_funcs(MODULE_BASIC_ID,
951 O_BASIC_IP_DST_ME, (filter_func)check_to_me);
952 register_ipfw_filter_funcs(MODULE_BASIC_ID,
953 O_BASIC_IP_DST_MASK, (filter_func)check_to_mask);
954 register_ipfw_filter_funcs(MODULE_BASIC_ID,
955 O_BASIC_TAG, (filter_func)check_tag);
956 register_ipfw_filter_funcs(MODULE_BASIC_ID,
957 O_BASIC_UNTAG, (filter_func)check_untag);
958 register_ipfw_filter_funcs(MODULE_BASIC_ID,
959 O_BASIC_TAGGED, (filter_func)check_tagged);
962 struct ipfw_context *ctx;
964 for (cpu = 0; cpu < ncpus; cpu++) {
967 ctx->state_ctx = kmalloc(state_hash_size *
968 sizeof(struct ipfw_state_context),
969 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
970 ctx->state_hash_size = state_hash_size;
974 struct netmsg_base smsg;
975 netmsg_init(&smsg, NULL, &curthread->td_msgport,
976 0, ipfw_basic_init_dispatch);
977 lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
982 ipfw_basic_stop_dispatch(netmsg_t nmsg)
984 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
985 KKASSERT(IPFW3_LOADED);
987 callout_stop(&ipfw_tick_callout);
988 netmsg_service_sync();
990 lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
992 lwkt_replymsg(&nmsg->lmsg, error);
993 ip_fw_basic_loaded=0;
997 ipfw_basic_stop(void)
1000 struct ipfw_state_context *state_ctx;
1001 struct ip_fw_state *state,*the_state;
1002 struct ipfw_context *ctx;
1003 if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) {
1004 ipfw_basic_flush_state_prt = NULL;
1005 ipfw_basic_append_state_prt = NULL;
1007 for (cpu = 0; cpu < ncpus; cpu++) {
1008 ctx = ipfw_ctx[cpu];
1010 for (i = 0; i < state_hash_size; i++) {
1011 state_ctx = &ctx->state_ctx[i];
1012 if (state_ctx != NULL) {
1013 state = state_ctx->state;
1014 while (state != NULL) {
1016 state = state->next;
1019 state_ctx->last = NULL;
1026 ctx->state_hash_size = 0;
1027 kfree(ctx->state_ctx, M_IPFW3_BASIC);
1028 ctx->state_ctx = NULL;
1031 struct netmsg_base smsg;
1032 netmsg_init(&smsg, NULL, &curthread->td_msgport,
1033 0, ipfw_basic_stop_dispatch);
1034 return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1041 ipfw3_basic_modevent(module_t mod, int type, void *data)
1046 err = ipfw_basic_init();
1049 err = ipfw_basic_stop();
1057 static moduledata_t ipfw3_basic_mod = {
1059 ipfw3_basic_modevent,
1062 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
1063 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
1064 MODULE_VERSION(ipfw3_basic, 1);