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