/* * Copyright (c) 2014 - 2018 The DragonFly Project. All rights reserved. * * This code is derived from software contributed to The DragonFly Project * by Bill Yuan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name of The DragonFly Project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific, prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "opt_ipfw.h" #include "opt_inet.h" #ifndef INET #error IPFIREWALL3 requires INET. #endif /* INET */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ip_fw3.h" #include "ip_fw3_set.h" extern struct ipfw3_context *fw3_ctx[MAXCPU]; void move_set_dispatch(netmsg_t smsg) { struct netmsg_sets *msg = (struct netmsg_sets *)smsg; struct ipfw3_context *ctx = fw3_ctx[mycpuid]; struct ip_fw *rule; for (rule = ctx->rules; rule; rule = rule->next) { if (rule->set == msg->set_from) rule->set = msg->set_to; } netisr_forwardmsg_all(&smsg->base, mycpuid + 1); } int ip_fw3_ctl_set_move_set(struct sockopt *sopt) { struct ipfw3_context *ctx; struct netmsg_sets msg; int *set1, *set2; ctx = fw3_ctx[mycpuid]; set1 =(int *)sopt->sopt_val; set2 = set1 + 1; if (*set1 > 0 && *set1 < 32 && *set2 > 0 && *set2 < 32) { bzero(&msg, sizeof(msg)); netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0, move_set_dispatch); msg.set_from = *set1; msg.set_to = *set2; netisr_domsg(&msg.base, 0); } return 0; } void move_rule_dispatch(netmsg_t smsg) { struct netmsg_sets *msg = (struct netmsg_sets *)smsg; struct ipfw3_context *ctx = fw3_ctx[mycpuid]; struct ip_fw *rule; for (rule = ctx->rules; rule; rule = rule->next) { if (rule->rulenum == msg->rule_num) rule->set = msg->set_to; } netisr_forwardmsg_all(&smsg->base, mycpuid + 1); } int ip_fw3_ctl_set_move_rule(struct sockopt *sopt) { struct ipfw3_context *ctx; struct netmsg_sets msg; int *rule_num, *set; ctx = fw3_ctx[mycpuid]; rule_num =(int *)sopt->sopt_val; set = rule_num + 1; if (*rule_num > 0 && *rule_num < 65535 && *set >= 0 && *set < 32) { bzero(&msg, sizeof(msg)); netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0, move_rule_dispatch); msg.rule_num = *rule_num; msg.set_to = *set; netisr_domsg(&msg.base, 0); } return 0; } void set_swap_dispatch(netmsg_t smsg) { struct netmsg_sets *msg = (struct netmsg_sets *)smsg; struct ipfw3_context *ctx = fw3_ctx[mycpuid]; struct ip_fw *rule; for (rule = ctx->rules; rule; rule = rule->next) { if (rule->set == msg->set_from) rule->set = msg->set_to; else if (rule->set == msg->set_to) rule->set = msg->set_from; } netisr_forwardmsg_all(&smsg->base, mycpuid + 1); } int ip_fw3_ctl_set_swap(struct sockopt *sopt) { struct ipfw3_context *ctx; struct netmsg_sets msg; int *set1, *set2; ctx = fw3_ctx[mycpuid]; set1 =(int *)sopt->sopt_val; set2 = set1 + 1; if (*set1 > 0 && *set1 < 32 && *set2 > 0 && *set2 < 32) { bzero(&msg, sizeof(msg)); netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0, set_swap_dispatch); msg.set_from = *set1; msg.set_to = *set2; netisr_domsg(&msg.base, 0); } return 0; } int ip_fw3_ctl_set_toggle(struct sockopt *sopt) { struct ipfw3_context *ctx; int *num; ctx = fw3_ctx[mycpuid]; num =(int *)sopt->sopt_val; if (*num > 0 && *num < 32) { ctx->sets = ctx->sets ^ (1 << *num); } return 0; } int ip_fw3_ctl_set_get(struct sockopt *sopt) { struct ipfw3_context *ctx; ctx = fw3_ctx[mycpuid]; bcopy(&ctx->sets, sopt->sopt_val, sopt->sopt_valsize); return 0; } void set_flush_dispatch(netmsg_t smsg) { struct netmsg_sets *msg = (struct netmsg_sets *)smsg; struct ipfw3_context *ctx = fw3_ctx[mycpuid]; struct ip_fw *prev, *rule; prev = NULL; rule = ctx->rules; while (rule != NULL) { if (rule->set == msg->set_to) { rule = ip_fw3_delete_rule(ctx, prev, rule); } else { prev = rule; rule = rule->next; } } netisr_forwardmsg_all(&smsg->base, mycpuid + 1); } int ip_fw3_ctl_set_flush(struct sockopt *sopt) { struct netmsg_sets msg; int *num; num =(int *)sopt->sopt_val; if (*num > 0 && *num < 32) { bzero(&msg, sizeof(msg)); netmsg_init(&msg.base, NULL, &curthread->td_msgport, 0, set_flush_dispatch); msg.set_to = *num; netisr_domsg(&msg.base, 0); } return 0; } int ip_fw3_ctl_set_sockopt(struct sockopt *sopt) { int error = 0; switch (sopt->sopt_name) { case IP_FW_SET_GET: error = ip_fw3_ctl_set_get(sopt); break; case IP_FW_SET_TOGGLE: error = ip_fw3_ctl_set_toggle(sopt); break; case IP_FW_SET_SWAP: error = ip_fw3_ctl_set_swap(sopt); break; case IP_FW_SET_MOVE_RULE: error = ip_fw3_ctl_set_move_rule(sopt); break; case IP_FW_SET_MOVE_SET: error = ip_fw3_ctl_set_move_set(sopt); break; case IP_FW_SET_FLUSH: error = ip_fw3_ctl_set_flush(sopt); break; default: kprintf("ipfw3 set invalid socket option %d\n", sopt->sopt_name); } return error; }