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 50 #include <net/ethernet.h> 51 #include <net/netmsg2.h> 52 #include <net/netisr2.h> 53 #include <net/route.h> 54 #include <net/if.h> 55 56 #include <netinet/in_var.h> 57 #include <netinet/ip_var.h> 58 59 #include <net/ipfw3/ip_fw.h> 60 #include <net/ipfw3_basic/ip_fw3_table.h> 61 62 #include "ip_fw3_layer2.h" 63 64 extern struct ipfw3_context *fw3_ctx[MAXCPU]; 65 66 void 67 check_layer2(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 68 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 69 { 70 *cmd_val = ((*args)->eh != NULL); 71 *cmd_ctl = IP_FW_CTL_NO; 72 } 73 74 void 75 check_mac(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 76 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 77 { 78 *cmd_ctl = IP_FW_CTL_NO; 79 if ((*args)->eh != NULL) { 80 uint32_t *want = (uint32_t *)((ipfw_insn_mac *)cmd)->addr; 81 uint32_t *mask = (uint32_t *)((ipfw_insn_mac *)cmd)->mask; 82 uint32_t *hdr = (uint32_t *)(*args)->eh; 83 *cmd_val = 84 (want[0] == (hdr[0] & mask[0]) && 85 want[1] == (hdr[1] & mask[1]) && 86 want[2] == (hdr[2] & mask[2])); 87 } else { 88 *cmd_val = IP_FW_NOT_MATCH; 89 } 90 } 91 92 void 93 check_mac_from(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 94 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 95 { 96 *cmd_ctl = IP_FW_CTL_NO; 97 if ((*args)->eh != NULL) { 98 uint16_t *want = (uint16_t *)((ipfw_insn_mac *)cmd)->addr; 99 uint16_t *mask = (uint16_t *)((ipfw_insn_mac *)cmd)->mask; 100 uint16_t *hdr = (uint16_t *)(*args)->eh; 101 *cmd_val = 102 (want[3] == (hdr[3] & mask[3]) && 103 want[4] == (hdr[4] & mask[4]) && 104 want[5] == (hdr[5] & mask[5])); 105 } else { 106 *cmd_val = IP_FW_NOT_MATCH; 107 } 108 } 109 110 void 111 check_mac_from_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 112 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 113 { 114 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 115 struct ipfw3_table_context *table_ctx; 116 struct radix_node_head *rnh; 117 struct table_mac_entry *ent = NULL; 118 119 table_ctx = ctx->table_ctx; 120 table_ctx += cmd->arg1; 121 rnh = table_ctx->node; 122 123 *cmd_ctl = IP_FW_CTL_NO; 124 *cmd_val = IP_FW_NOT_MATCH; 125 if ((*args)->eh != NULL) { 126 struct sockaddr sa; 127 sa.sa_len = 8; 128 strncpy(sa.sa_data, (*args)->eh->ether_shost, 6); 129 ent = (struct table_mac_entry *)rnh->rnh_lookup((char *)&sa, 130 NULL, rnh); 131 if(ent != NULL) 132 *cmd_val = IP_FW_MATCH; 133 } 134 } 135 136 void 137 check_mac_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 138 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 139 { 140 *cmd_ctl = IP_FW_CTL_NO; 141 if ((*args)->eh != NULL) { 142 uint16_t *want = (uint16_t *)((ipfw_insn_mac *)cmd)->addr; 143 uint16_t *mask = (uint16_t *)((ipfw_insn_mac *)cmd)->mask; 144 uint16_t *hdr = (uint16_t *)(*args)->eh; 145 *cmd_val = 146 (want[0] == (hdr[0] & mask[0]) && 147 want[1] == (hdr[1] & mask[1]) && 148 want[2] == (hdr[2] & mask[2])); 149 } else { 150 *cmd_val = IP_FW_NOT_MATCH; 151 } 152 } 153 154 void 155 check_mac_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 156 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 157 { 158 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 159 struct ipfw3_table_context *table_ctx; 160 struct radix_node_head *rnh; 161 struct table_mac_entry *ent = NULL; 162 163 table_ctx = ctx->table_ctx; 164 table_ctx += cmd->arg1; 165 rnh = table_ctx->node; 166 167 *cmd_ctl = IP_FW_CTL_NO; 168 *cmd_val = IP_FW_NOT_MATCH; 169 if ((*args)->eh != NULL) { 170 struct sockaddr sa; 171 sa.sa_len = 8; 172 strncpy(sa.sa_data, (*args)->eh->ether_dhost, 6); 173 ent = (struct table_mac_entry *)rnh->rnh_lookup((char *)&sa, 174 NULL, rnh); 175 if(ent != NULL) 176 *cmd_val = IP_FW_MATCH; 177 } 178 } 179 180 static int 181 ip_fw3_layer2_init(void) 182 { 183 ip_fw3_register_module(MODULE_LAYER2_ID, MODULE_LAYER2_NAME); 184 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 185 O_LAYER2_LAYER2, (filter_func)check_layer2); 186 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 187 O_LAYER2_MAC, (filter_func)check_mac); 188 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 189 O_LAYER2_MAC_SRC, (filter_func)check_mac_from); 190 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 191 O_LAYER2_MAC_DST, (filter_func)check_mac_to); 192 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 193 O_LAYER2_MAC_SRC_LOOKUP, 194 (filter_func)check_mac_from_lookup); 195 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 196 O_LAYER2_MAC_DST_LOOKUP, 197 (filter_func)check_mac_to_lookup); 198 return 0; 199 } 200 201 static int 202 ip_fw3_layer2_stop(void) 203 { 204 return ip_fw3_unregister_module(MODULE_LAYER2_ID); 205 } 206 207 static int 208 ipfw3_layer2_modevent(module_t mod, int type, void *data) 209 { 210 switch (type) { 211 case MOD_LOAD: 212 return ip_fw3_layer2_init(); 213 case MOD_UNLOAD: 214 return ip_fw3_layer2_stop(); 215 default: 216 break; 217 } 218 return 0; 219 } 220 221 static moduledata_t ipfw3_layer2_mod = { 222 "ipfw3_layer2", 223 ipfw3_layer2_modevent, 224 NULL 225 }; 226 DECLARE_MODULE(ipfw3_layer2, ipfw3_layer2_mod, SI_SUB_PROTO_END, SI_ORDER_ANY); 227 MODULE_DEPEND(ipfw3_layer2, ipfw3_basic, 1, 1, 1); 228 MODULE_VERSION(ipfw3_layer2, 1); 229