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>
69 #include <net/ipfw3/ip_fw3_table.h>
71 #include "ip_fw3_basic.h"
73 #define TIME_LEQ(a, b) ((int)((a) - (b)) <= 0)
75 extern struct ipfw_context *ipfw_ctx[MAXCPU];
76 extern int fw_verbose;
77 extern ipfw_basic_delete_state_t *ipfw_basic_flush_state_prt;
78 extern ipfw_basic_append_state_t *ipfw_basic_append_state_prt;
80 static int ip_fw_basic_loaded;
81 static struct netmsg_base ipfw_timeout_netmsg; /* schedule ipfw timeout */
82 static struct callout ipfw_tick_callout;
83 static int state_lifetime = 20;
84 static int state_expiry_check_interval = 10;
85 static int state_count_max = 4096;
86 static int state_hash_size_old = 0;
87 static int state_hash_size = 4096;
90 static int ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS);
91 void adjust_hash_size_dispatch(netmsg_t nmsg);
93 SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw_basic,
94 CTLFLAG_RW, 0, "Firewall Basic");
95 SYSCTL_PROC(_net_inet_ip_fw_basic, OID_AUTO, state_hash_size,
96 CTLTYPE_INT | CTLFLAG_RW, &state_hash_size, 0,
97 ipfw_sysctl_adjust_hash_size, "I", "Adjust hash size");
99 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_lifetime, CTLFLAG_RW,
100 &state_lifetime, 0, "default life time");
101 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO,
102 state_expiry_check_interval, CTLFLAG_RW,
103 &state_expiry_check_interval, 0,
104 "default state expiry check interval");
105 SYSCTL_INT(_net_inet_ip_fw_basic, OID_AUTO, state_count_max, CTLFLAG_RW,
106 &state_count_max, 0, "maximum of state");
109 ipfw_sysctl_adjust_hash_size(SYSCTL_HANDLER_ARGS)
111 int error, value = 0;
113 state_hash_size_old = state_hash_size;
114 value = state_hash_size;
115 error = sysctl_handle_int(oidp, &value, 0, req);
116 if (error || !req->newptr) {
120 * Make sure we have a power of 2 and
121 * do not allow more than 64k entries.
124 if (value <= 1 || value > 65536) {
127 if ((value & (value - 1)) != 0) {
132 if (state_hash_size != value) {
133 state_hash_size = value;
135 struct netmsg_base *msg, the_msg;
137 bzero(msg,sizeof(struct netmsg_base));
139 netmsg_init(msg, NULL, &curthread->td_msgport,
140 0, adjust_hash_size_dispatch);
141 ifnet_domsg(&msg->lmsg, 0);
148 adjust_hash_size_dispatch(netmsg_t nmsg)
150 struct ipfw_state_context *state_ctx;
151 struct ip_fw_state *the_state, *state;
152 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
155 for (i = 0; i < state_hash_size_old; i++) {
156 state_ctx = &ctx->state_ctx[i];
157 if (state_ctx != NULL) {
158 state = state_ctx->state;
159 while (state != NULL) {
162 kfree(the_state, M_IPFW3_BASIC);
167 kfree(ctx->state_ctx,M_IPFW3_BASIC);
168 ctx->state_ctx = kmalloc(state_hash_size *
169 sizeof(struct ipfw_state_context),
170 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
171 ctx->state_hash_size = state_hash_size;
172 ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
176 /* prototype of the checker functions */
177 void check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
178 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
179 void check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
180 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
181 void check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
182 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
183 void check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
184 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
186 void check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
187 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
188 void check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
189 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
190 void check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
191 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
192 void check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
193 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
194 void check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
195 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
196 void check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
197 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
198 void check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
199 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
200 void check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
201 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
202 void check_from_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
203 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
204 void check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
205 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
206 void check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
207 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
208 void check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
209 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
210 void check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
211 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
212 void check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
213 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
214 void check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
215 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
216 void check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
217 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
218 void check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
219 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
220 void check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
221 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
222 void check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
223 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
224 void check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
225 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
226 void check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
227 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len);
229 /* prototype of the utility functions */
230 static struct ip_fw *lookup_next_rule(struct ip_fw *me);
231 static int iface_match(struct ifnet *ifp, ipfw_insn_if *cmd);
232 static __inline int hash_packet(struct ipfw_flow_id *id);
235 hash_packet(struct ipfw_flow_id *id)
238 i = (id->proto) ^ (id->dst_ip) ^ (id->src_ip) ^
239 (id->dst_port) ^ (id->src_port);
240 i &= state_hash_size - 1;
244 static struct ip_fw *
245 lookup_next_rule(struct ip_fw *me)
247 struct ip_fw *rule = NULL;
250 /* look for action, in case it is a skipto */
251 cmd = ACTION_PTR(me);
252 if ((int)cmd->module == MODULE_BASIC_ID &&
253 (int)cmd->opcode == O_BASIC_SKIPTO) {
254 for (rule = me->next; rule; rule = rule->next) {
255 if (rule->rulenum >= cmd->arg1)
259 if (rule == NULL) /* failure or not a skipto */
262 me->next_rule = rule;
267 * when all = 1, it will check all the state_ctx
269 static struct ip_fw_state *
270 lookup_state(struct ip_fw_args *args, ipfw_insn *cmd, int *limited, int all)
272 struct ip_fw_state *state = NULL;
273 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
274 struct ipfw_state_context *state_ctx;
275 int start, end, i, count = 0;
277 if (all && cmd->arg1) {
279 end = state_hash_size - 1;
281 start = hash_packet(&args->f_id);
282 end = hash_packet(&args->f_id);
284 for (i = start; i <= end; i++) {
285 state_ctx = &ctx->state_ctx[i];
286 if (state_ctx != NULL) {
287 state = state_ctx->state;
288 struct ipfw_flow_id *fid = &args->f_id;
289 while (state != NULL) {
291 if ((cmd->arg3 == 1 &&
293 state->flow_id.src_ip) ||
296 state->flow_id.src_port) ||
299 state->flow_id.dst_ip) ||
302 state->flow_id.dst_port)) {
305 if (count >= cmd->arg1) {
312 if (fid->proto == state->flow_id.proto) {
314 state->flow_id.src_ip &&
316 state->flow_id.dst_ip &&
318 state->flow_id.src_port ||
319 state->flow_id.src_port == 0) &&
321 state->flow_id.dst_port ||
322 state->flow_id.dst_port == 0)) {
326 state->flow_id.dst_ip &&
328 state->flow_id.src_ip &&
330 state->flow_id.dst_port ||
331 state->flow_id.dst_port == 0) &&
333 state->flow_id.src_port ||
334 state->flow_id.src_port == 0)) {
346 static struct ip_fw_state *
347 install_state(struct ip_fw *rule, ipfw_insn *cmd, struct ip_fw_args *args)
349 struct ip_fw_state *state;
350 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
351 struct ipfw_state_context *state_ctx;
352 state_ctx = &ctx->state_ctx[hash_packet(&args->f_id)];
353 state = kmalloc(sizeof(struct ip_fw_state),
354 M_IPFW3_BASIC, M_NOWAIT | M_ZERO);
359 state->lifetime = cmd->arg2 == 0 ? state_lifetime : cmd->arg2 ;
360 state->timestamp = time_second;
362 bcopy(&args->f_id,&state->flow_id,sizeof(struct ipfw_flow_id));
363 //append the state into the state chian
364 if (state_ctx->last != NULL)
365 state_ctx->last->next = state;
367 state_ctx->state = state;
368 state_ctx->last = state;
375 iface_match(struct ifnet *ifp, ipfw_insn_if *cmd)
377 if (ifp == NULL) /* no iface with this packet, match fails */
380 /* Check by name or by IP address */
381 if (cmd->name[0] != '\0') { /* match by name */
384 if (kfnmatch(cmd->name, ifp->if_xname, 0) == 0)
387 if (strncmp(ifp->if_xname, cmd->name, IFNAMSIZ) == 0)
391 struct ifaddr_container *ifac;
393 TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
394 struct ifaddr *ia = ifac->ifa;
396 if (ia->ifa_addr == NULL)
398 if (ia->ifa_addr->sa_family != AF_INET)
400 if (cmd->p.ip.s_addr ==
401 ((struct sockaddr_in *)
402 (ia->ifa_addr))->sin_addr.s_addr)
403 return(1); /* match */
407 return 0; /* no match, fail ... */
410 /* implimentation of the checker functions */
412 check_count(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
413 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
416 (*f)->bcnt += ip_len;
417 (*f)->timestamp = time_second;
418 *cmd_ctl = IP_FW_CTL_NEXT;
422 check_skipto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
423 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
426 (*f)->bcnt += ip_len;
427 (*f)->timestamp = time_second;
428 if ((*f)->next_rule == NULL)
429 lookup_next_rule(*f);
431 *cmd_ctl = IP_FW_CTL_AGAIN;
435 check_forward(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
436 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
438 struct sockaddr_in *sin, *sa;
441 if ((*args)->eh) { /* not valid on layer2 pkts */
442 *cmd_ctl=IP_FW_CTL_NEXT;
447 (*f)->bcnt += ip_len;
448 (*f)->timestamp = time_second;
449 if ((*f)->next_rule == NULL)
450 lookup_next_rule(*f);
452 mtag = m_tag_get(PACKET_TAG_IPFORWARD,
453 sizeof(*sin), M_NOWAIT);
455 *cmd_val = IP_FW_DENY;
456 *cmd_ctl = IP_FW_CTL_DONE;
459 sin = m_tag_data(mtag);
460 sa = &((ipfw_insn_sa *)cmd)->sa;
461 /* arg3: count of the dest, arg1: type of fwd */
464 if (cmd->arg1 == 0) { /* type: random */
465 i = krandom() % cmd->arg3;
466 } else if (cmd->arg1 == 1) { /* type: round-robin */
467 i = cmd->arg2++ % cmd->arg3;
468 } else if (cmd->arg1 == 2) { /* type: sticky */
469 struct ip *ip = mtod((*args)->m, struct ip *);
470 i = ip->ip_src.s_addr & (cmd->arg3 - 1);
474 *sin = *sa; /* apply the destination */
475 m_tag_prepend((*args)->m, mtag);
476 (*args)->m->m_pkthdr.fw_flags |= IPFORWARD_MBUF_TAGGED;
477 (*args)->m->m_pkthdr.fw_flags &= ~BRIDGE_MBUF_TAGGED;
478 *cmd_ctl = IP_FW_CTL_DONE;
479 *cmd_val = IP_FW_PASS;
483 check_check_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
484 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
486 struct ip_fw_state *state=NULL;
488 state = lookup_state(*args, cmd, &limited, 0);
491 state->bcnt += ip_len;
492 state->timestamp = time_second;
494 (*f)->bcnt += ip_len;
495 (*f)->timestamp = time_second;
497 *cmd_ctl = IP_FW_CTL_CHK_STATE;
499 *cmd_ctl = IP_FW_CTL_NEXT;
504 check_in(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
505 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
507 *cmd_ctl = IP_FW_CTL_NO;
508 *cmd_val = ((*args)->oif == NULL);
512 check_out(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
513 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
515 *cmd_ctl = IP_FW_CTL_NO;
516 *cmd_val = ((*args)->oif != NULL);
520 check_via(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
521 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
523 *cmd_ctl = IP_FW_CTL_NO;
524 *cmd_val = iface_match((*args)->oif ?
525 (*args)->oif : (*args)->m->m_pkthdr.rcvif,
526 (ipfw_insn_if *)cmd);
530 check_proto(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
531 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
533 *cmd_ctl = IP_FW_CTL_NO;
534 *cmd_val = ((*args)->f_id.proto == cmd->arg1);
538 check_prob(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
539 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
541 *cmd_ctl = IP_FW_CTL_NO;
542 *cmd_val = (krandom() % 100) < cmd->arg1;
546 check_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
547 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
549 struct in_addr src_ip;
551 struct mbuf *m = (*args)->m;
552 struct ip *ip = mtod(m, struct ip *);
554 if ((*args)->eh == NULL ||
555 (m->m_pkthdr.len >= sizeof(struct ip) &&
556 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
557 hlen = ip->ip_hl << 2;
559 *cmd_val = (hlen > 0 &&
560 ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
561 *cmd_ctl = IP_FW_CTL_NO;
565 check_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
566 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
568 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
569 struct ipfw_table_context *table_ctx;
570 struct radix_node_head *rnh;
571 struct sockaddr_in sa;
573 struct mbuf *m = (*args)->m;
574 struct ip *ip = mtod(m, struct ip *);
575 struct in_addr src_ip = ip->ip_src;
577 *cmd_val = IP_FW_NOT_MATCH;
579 table_ctx = ctx->table_ctx;
580 table_ctx += cmd->arg1;
582 if (table_ctx->type != 0) {
583 rnh = table_ctx->node;
585 sa.sin_addr.s_addr = src_ip.s_addr;
586 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
587 *cmd_val = IP_FW_MATCH;
589 *cmd_ctl = IP_FW_CTL_NO;
593 check_from_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
594 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
596 struct in_addr src_ip;
598 struct mbuf *m = (*args)->m;
599 struct ip *ip = mtod(m, struct ip *);
601 if ((*args)->eh == NULL ||
602 (m->m_pkthdr.len >= sizeof(struct ip) &&
603 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
604 hlen = ip->ip_hl << 2;
606 *cmd_ctl = IP_FW_CTL_NO;
609 tif = INADDR_TO_IFP(&src_ip);
610 *cmd_val = (tif != NULL);
612 *cmd_val = IP_FW_NOT_MATCH;
617 check_from_mask(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 src_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;
631 *cmd_ctl = IP_FW_CTL_NO;
632 *cmd_val = (hlen > 0 &&
633 ((ipfw_insn_ip *)cmd)->addr.s_addr ==
635 ((ipfw_insn_ip *)cmd)->mask.s_addr));
639 check_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
640 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
642 struct in_addr dst_ip;
644 struct mbuf *m = (*args)->m;
645 struct ip *ip = mtod(m, struct ip *);
647 if ((*args)->eh == NULL ||
648 (m->m_pkthdr.len >= sizeof(struct ip) &&
649 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
650 hlen = ip->ip_hl << 2;
652 *cmd_val = (hlen > 0 &&
653 ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
654 *cmd_ctl = IP_FW_CTL_NO;
658 check_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
659 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
661 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
662 struct ipfw_table_context *table_ctx;
663 struct radix_node_head *rnh;
664 struct sockaddr_in sa;
666 struct mbuf *m = (*args)->m;
667 struct ip *ip = mtod(m, struct ip *);
668 struct in_addr dst_ip = ip->ip_dst;
670 *cmd_val = IP_FW_NOT_MATCH;
672 table_ctx = ctx->table_ctx;
673 table_ctx += cmd->arg1;
675 if (table_ctx->type != 0) {
676 rnh = table_ctx->node;
678 sa.sin_addr.s_addr = dst_ip.s_addr;
679 if(rnh->rnh_lookup((char *)&sa, NULL, rnh) != NULL)
680 *cmd_val = IP_FW_MATCH;
682 *cmd_ctl = IP_FW_CTL_NO;
686 check_to_me(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
687 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
689 struct in_addr dst_ip;
691 struct mbuf *m = (*args)->m;
692 struct ip *ip = mtod(m, struct ip *);
694 if ((*args)->eh == NULL ||
695 (m->m_pkthdr.len >= sizeof(struct ip) &&
696 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
697 hlen = ip->ip_hl << 2;
699 *cmd_ctl = IP_FW_CTL_NO;
702 tif = INADDR_TO_IFP(&dst_ip);
703 *cmd_val = (tif != NULL);
705 *cmd_val = IP_FW_NOT_MATCH;
710 check_to_mask(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
711 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
713 struct in_addr dst_ip;
715 struct mbuf *m = (*args)->m;
716 struct ip *ip = mtod(m, struct ip *);
718 if ((*args)->eh == NULL ||
719 (m->m_pkthdr.len >= sizeof(struct ip) &&
720 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
721 hlen = ip->ip_hl << 2;
724 *cmd_ctl = IP_FW_CTL_NO;
725 *cmd_val = (hlen > 0 &&
726 ((ipfw_insn_ip *)cmd)->addr.s_addr ==
728 ((ipfw_insn_ip *)cmd)->mask.s_addr));
732 check_keep_state(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
733 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
735 struct ip_fw_state *state;
738 *cmd_ctl = IP_FW_CTL_NO;
739 state = lookup_state(*args, cmd, &limited, 1);
741 *cmd_val = IP_FW_NOT_MATCH;
744 state = install_state(*f, cmd, *args);
748 state->bcnt += ip_len;
749 state->timestamp = time_second;
750 *cmd_val = IP_FW_MATCH;
752 *cmd_val = IP_FW_NOT_MATCH;
758 check_tag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
759 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
761 struct m_tag *mtag = m_tag_locate((*args)->m,
762 MTAG_IPFW, cmd->arg1, NULL);
764 mtag = m_tag_alloc(MTAG_IPFW,cmd->arg1, 0, M_NOWAIT);
766 m_tag_prepend((*args)->m, mtag);
770 (*f)->bcnt += ip_len;
771 (*f)->timestamp = time_second;
772 *cmd_ctl = IP_FW_CTL_NEXT;
776 check_untag(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
777 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
779 struct m_tag *mtag = m_tag_locate((*args)->m,
780 MTAG_IPFW, cmd->arg1, NULL);
782 m_tag_delete((*args)->m, mtag);
785 (*f)->bcnt += ip_len;
786 (*f)->timestamp = time_second;
787 *cmd_ctl = IP_FW_CTL_NEXT;
791 check_tagged(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
792 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
794 *cmd_ctl = IP_FW_CTL_NO;
795 if (m_tag_locate( (*args)->m, MTAG_IPFW,cmd->arg1, NULL) != NULL )
796 *cmd_val = IP_FW_MATCH;
798 *cmd_val = IP_FW_NOT_MATCH;
802 check_src_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
803 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
805 *cmd_ctl = IP_FW_CTL_NO;
806 if ((*args)->f_id.src_port == cmd->arg1)
807 *cmd_val = IP_FW_MATCH;
809 *cmd_val = IP_FW_NOT_MATCH;
813 check_dst_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
814 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
816 *cmd_ctl = IP_FW_CTL_NO;
817 if ((*args)->f_id.dst_port == cmd->arg1)
818 *cmd_val = IP_FW_MATCH;
820 *cmd_val = IP_FW_NOT_MATCH;
824 check_src_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
825 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
827 struct in_addr src_ip;
829 struct mbuf *m = (*args)->m;
830 struct ip *ip = mtod(m, struct ip *);
832 if ((*args)->eh == NULL ||
833 (m->m_pkthdr.len >= sizeof(struct ip) &&
834 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
835 hlen = ip->ip_hl << 2;
837 *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == src_ip.s_addr);
838 *cmd_ctl = IP_FW_CTL_NO;
839 if (*cmd_val && (*args)->f_id.src_port == cmd->arg1)
840 *cmd_val = IP_FW_MATCH;
842 *cmd_val = IP_FW_NOT_MATCH;
846 check_dst_n_port(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args,
847 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len)
849 struct in_addr dst_ip;
851 struct mbuf *m = (*args)->m;
852 struct ip *ip = mtod(m, struct ip *);
854 if ((*args)->eh == NULL ||
855 (m->m_pkthdr.len >= sizeof(struct ip) &&
856 ntohs((*args)->eh->ether_type) == ETHERTYPE_IP)) {
857 hlen = ip->ip_hl << 2;
859 *cmd_val = (hlen > 0 && ((ipfw_insn_ip *)cmd)->addr.s_addr == dst_ip.s_addr);
860 *cmd_ctl = IP_FW_CTL_NO;
861 if (*cmd_val && (*args)->f_id.dst_port == cmd->arg1)
862 *cmd_val = IP_FW_MATCH;
864 *cmd_val = IP_FW_NOT_MATCH;
870 ipfw_basic_add_state(struct ipfw_ioc_state *ioc_state)
872 struct ip_fw_state *state;
873 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
874 struct ipfw_state_context *state_ctx;
875 state_ctx = &ctx->state_ctx[hash_packet(&(ioc_state->flow_id))];
876 state = kmalloc(sizeof(struct ip_fw_state),
877 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
878 struct ip_fw *rule = ctx->ipfw_rule_chain;
879 while (rule != NULL) {
880 if (rule->rulenum == ioc_state->rulenum) {
890 state->lifetime = ioc_state->lifetime == 0 ?
891 state_lifetime : ioc_state->lifetime ;
892 state->timestamp = time_second;
893 state->expiry = ioc_state->expiry;
894 bcopy(&ioc_state->flow_id, &state->flow_id,
895 sizeof(struct ipfw_flow_id));
896 //append the state into the state chian
897 if (state_ctx->last != NULL)
898 state_ctx->last->next = state;
900 state_ctx->state = state;
902 state_ctx->last = state;
910 * flush states which stub is the rule
913 ipfw_basic_flush_state(struct ip_fw *rule)
915 struct ipfw_state_context *state_ctx;
916 struct ip_fw_state *state,*the_state, *prev_state;
917 struct ipfw_context *ctx;
920 ctx = ipfw_ctx[mycpuid];
921 for (i = 0; i < state_hash_size; i++) {
922 state_ctx = &ctx->state_ctx[i];
923 if (state_ctx != NULL) {
924 state = state_ctx->state;
926 while (state != NULL) {
927 if (rule != NULL && state->stub != rule) {
931 if (prev_state == NULL)
932 state_ctx->state = state->next;
934 prev_state->next = state->next;
938 kfree(the_state, M_IPFW3_BASIC);
941 state_ctx->last = prev_state;
950 * clean up expired state in every tick
953 ipfw_cleanup_expired_state(netmsg_t nmsg)
955 struct ip_fw_state *state,*the_state,*prev_state;
956 struct ipfw_context *ctx = ipfw_ctx[mycpuid];
957 struct ipfw_state_context *state_ctx;
960 for (i = 0; i < state_hash_size; i++) {
962 state_ctx = &(ctx->state_ctx[i]);
963 if (ctx->state_ctx != NULL) {
964 state = state_ctx->state;
965 while (state != NULL) {
966 if (IS_EXPIRED(state)) {
967 if (prev_state == NULL)
968 state_ctx->state = state->next;
970 prev_state->next = state->next;
975 if (the_state == state_ctx->last)
976 state_ctx->last = NULL;
979 kfree(the_state, M_IPFW3_BASIC);
988 ifnet_forwardmsg(&nmsg->lmsg, mycpuid + 1);
992 ipfw_tick(void *dummy __unused)
994 struct lwkt_msg *lmsg = &ipfw_timeout_netmsg.lmsg;
995 KKASSERT(mycpuid == IPFW_CFGCPUID);
998 KKASSERT(lmsg->ms_flags & MSGF_DONE);
999 if (IPFW_BASIC_LOADED) {
1000 lwkt_sendmsg_oncpu(IPFW_CFGPORT, lmsg);
1001 /* ipfw_timeout_netmsg's handler reset this callout */
1005 struct netmsg_base *msg;
1006 struct netmsg_base the_msg;
1008 bzero(msg,sizeof(struct netmsg_base));
1010 netmsg_init(msg, NULL, &curthread->td_msgport, 0,
1011 ipfw_cleanup_expired_state);
1012 ifnet_domsg(&msg->lmsg, 0);
1016 ipfw_tick_dispatch(netmsg_t nmsg)
1018 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1019 KKASSERT(IPFW_BASIC_LOADED);
1023 lwkt_replymsg(&nmsg->lmsg, 0);
1026 callout_reset(&ipfw_tick_callout,
1027 state_expiry_check_interval * hz, ipfw_tick, NULL);
1031 ipfw_basic_init_dispatch(netmsg_t nmsg)
1033 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1034 KKASSERT(IPFW3_LOADED);
1037 callout_init_mp(&ipfw_tick_callout);
1038 netmsg_init(&ipfw_timeout_netmsg, NULL, &netisr_adone_rport,
1039 MSGF_DROPABLE | MSGF_PRIORITY, ipfw_tick_dispatch);
1040 callout_reset(&ipfw_tick_callout,
1041 state_expiry_check_interval * hz, ipfw_tick, NULL);
1042 lwkt_replymsg(&nmsg->lmsg, error);
1043 ip_fw_basic_loaded=1;
1047 ipfw_basic_init(void)
1049 ipfw_basic_flush_state_prt = ipfw_basic_flush_state;
1050 ipfw_basic_append_state_prt = ipfw_basic_add_state;
1052 register_ipfw_module(MODULE_BASIC_ID, MODULE_BASIC_NAME);
1053 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_COUNT,
1054 (filter_func)check_count);
1055 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_SKIPTO,
1056 (filter_func)check_skipto);
1057 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_FORWARD,
1058 (filter_func)check_forward);
1059 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_KEEP_STATE,
1060 (filter_func)check_keep_state);
1061 register_ipfw_filter_funcs(MODULE_BASIC_ID, O_BASIC_CHECK_STATE,
1062 (filter_func)check_check_state);
1064 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1065 O_BASIC_IN, (filter_func)check_in);
1066 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1067 O_BASIC_OUT, (filter_func)check_out);
1068 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1069 O_BASIC_VIA, (filter_func)check_via);
1070 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1071 O_BASIC_XMIT, (filter_func)check_via);
1072 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1073 O_BASIC_RECV, (filter_func)check_via);
1075 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1076 O_BASIC_PROTO, (filter_func)check_proto);
1077 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1078 O_BASIC_PROB, (filter_func)check_prob);
1079 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1080 O_BASIC_IP_SRC, (filter_func)check_from);
1081 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1082 O_BASIC_IP_SRC_LOOKUP, (filter_func)check_from_lookup);
1083 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1084 O_BASIC_IP_SRC_ME, (filter_func)check_from_me);
1085 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1086 O_BASIC_IP_SRC_MASK, (filter_func)check_from_mask);
1087 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1088 O_BASIC_IP_DST, (filter_func)check_to);
1089 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1090 O_BASIC_IP_DST_LOOKUP, (filter_func)check_to_lookup);
1091 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1092 O_BASIC_IP_DST_ME, (filter_func)check_to_me);
1093 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1094 O_BASIC_IP_DST_MASK, (filter_func)check_to_mask);
1095 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1096 O_BASIC_TAG, (filter_func)check_tag);
1097 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1098 O_BASIC_UNTAG, (filter_func)check_untag);
1099 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1100 O_BASIC_TAGGED, (filter_func)check_tagged);
1101 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1102 O_BASIC_IP_SRCPORT, (filter_func)check_src_port);
1103 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1104 O_BASIC_IP_DSTPORT, (filter_func)check_dst_port);
1105 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1106 O_BASIC_IP_SRC_N_PORT, (filter_func)check_src_n_port);
1107 register_ipfw_filter_funcs(MODULE_BASIC_ID,
1108 O_BASIC_IP_DST_N_PORT, (filter_func)check_dst_n_port);
1111 struct ipfw_context *ctx;
1113 for (cpu = 0; cpu < ncpus; cpu++) {
1114 ctx = ipfw_ctx[cpu];
1116 ctx->state_ctx = kmalloc(state_hash_size *
1117 sizeof(struct ipfw_state_context),
1118 M_IPFW3_BASIC, M_WAITOK | M_ZERO);
1119 ctx->state_hash_size = state_hash_size;
1123 struct netmsg_base smsg;
1124 netmsg_init(&smsg, NULL, &curthread->td_msgport,
1125 0, ipfw_basic_init_dispatch);
1126 lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1131 ipfw_basic_stop_dispatch(netmsg_t nmsg)
1133 IPFW_ASSERT_CFGPORT(&curthread->td_msgport);
1134 KKASSERT(IPFW3_LOADED);
1136 callout_stop(&ipfw_tick_callout);
1137 netmsg_service_sync();
1139 lwkt_dropmsg(&ipfw_timeout_netmsg.lmsg);
1141 lwkt_replymsg(&nmsg->lmsg, error);
1142 ip_fw_basic_loaded=0;
1146 ipfw_basic_stop(void)
1149 struct ipfw_state_context *state_ctx;
1150 struct ip_fw_state *state,*the_state;
1151 struct ipfw_context *ctx;
1152 if (unregister_ipfw_module(MODULE_BASIC_ID) ==0 ) {
1153 ipfw_basic_flush_state_prt = NULL;
1154 ipfw_basic_append_state_prt = NULL;
1156 for (cpu = 0; cpu < ncpus; cpu++) {
1157 ctx = ipfw_ctx[cpu];
1159 for (i = 0; i < state_hash_size; i++) {
1160 state_ctx = &ctx->state_ctx[i];
1161 if (state_ctx != NULL) {
1162 state = state_ctx->state;
1163 while (state != NULL) {
1165 state = state->next;
1168 state_ctx->last = NULL;
1175 ctx->state_hash_size = 0;
1176 kfree(ctx->state_ctx, M_IPFW3_BASIC);
1177 ctx->state_ctx = NULL;
1180 struct netmsg_base smsg;
1181 netmsg_init(&smsg, NULL, &curthread->td_msgport,
1182 0, ipfw_basic_stop_dispatch);
1183 return lwkt_domsg(IPFW_CFGPORT, &smsg.lmsg, 0);
1190 ipfw3_basic_modevent(module_t mod, int type, void *data)
1195 err = ipfw_basic_init();
1198 err = ipfw_basic_stop();
1206 static moduledata_t ipfw3_basic_mod = {
1208 ipfw3_basic_modevent,
1211 DECLARE_MODULE(ipfw3_basic, ipfw3_basic_mod, SI_SUB_PROTO_END, SI_ORDER_ANY);
1212 MODULE_DEPEND(ipfw3_basic, ipfw3, 1, 1, 1);
1213 MODULE_VERSION(ipfw3_basic, 1);