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(&sa, NULL, rnh); 129 if (ent != NULL) 130 *cmd_val = IP_FW_MATCH; 131 } 132 } 133 134 void 135 check_mac_to(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 136 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 137 { 138 *cmd_ctl = IP_FW_CTL_NO; 139 if ((*args)->eh != NULL) { 140 uint16_t *want = (uint16_t *)((ipfw_insn_mac *)cmd)->addr; 141 uint16_t *mask = (uint16_t *)((ipfw_insn_mac *)cmd)->mask; 142 uint16_t *hdr = (uint16_t *)(*args)->eh; 143 *cmd_val = 144 (want[0] == (hdr[0] & mask[0]) && 145 want[1] == (hdr[1] & mask[1]) && 146 want[2] == (hdr[2] & mask[2])); 147 } else { 148 *cmd_val = IP_FW_NOT_MATCH; 149 } 150 } 151 152 void 153 check_mac_to_lookup(int *cmd_ctl, int *cmd_val, struct ip_fw_args **args, 154 struct ip_fw **f, ipfw_insn *cmd, uint16_t ip_len) 155 { 156 struct ipfw3_context *ctx = fw3_ctx[mycpuid]; 157 struct ipfw3_table_context *table_ctx; 158 struct radix_node_head *rnh; 159 struct table_mac_entry *ent = NULL; 160 161 table_ctx = ctx->table_ctx; 162 table_ctx += cmd->arg1; 163 rnh = table_ctx->node; 164 165 *cmd_ctl = IP_FW_CTL_NO; 166 *cmd_val = IP_FW_NOT_MATCH; 167 if ((*args)->eh != NULL) { 168 struct sockaddr sa; 169 sa.sa_len = 8; 170 strncpy(sa.sa_data, (*args)->eh->ether_dhost, 6); 171 ent = (struct table_mac_entry *)rnh->rnh_lookup(&sa, NULL, rnh); 172 if (ent != NULL) 173 *cmd_val = IP_FW_MATCH; 174 } 175 } 176 177 static int 178 ip_fw3_layer2_init(void) 179 { 180 ip_fw3_register_module(MODULE_LAYER2_ID, MODULE_LAYER2_NAME); 181 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 182 O_LAYER2_LAYER2, (filter_func)check_layer2); 183 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 184 O_LAYER2_MAC, (filter_func)check_mac); 185 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 186 O_LAYER2_MAC_SRC, (filter_func)check_mac_from); 187 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 188 O_LAYER2_MAC_DST, (filter_func)check_mac_to); 189 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 190 O_LAYER2_MAC_SRC_LOOKUP, 191 (filter_func)check_mac_from_lookup); 192 ip_fw3_register_filter_funcs(MODULE_LAYER2_ID, 193 O_LAYER2_MAC_DST_LOOKUP, 194 (filter_func)check_mac_to_lookup); 195 return 0; 196 } 197 198 static int 199 ip_fw3_layer2_stop(void) 200 { 201 return ip_fw3_unregister_module(MODULE_LAYER2_ID); 202 } 203 204 static int 205 ipfw3_layer2_modevent(module_t mod, int type, void *data) 206 { 207 switch (type) { 208 case MOD_LOAD: 209 return ip_fw3_layer2_init(); 210 case MOD_UNLOAD: 211 return ip_fw3_layer2_stop(); 212 default: 213 break; 214 } 215 return 0; 216 } 217 218 static moduledata_t ipfw3_layer2_mod = { 219 "ipfw3_layer2", 220 ipfw3_layer2_modevent, 221 NULL 222 }; 223 DECLARE_MODULE(ipfw3_layer2, ipfw3_layer2_mod, SI_SUB_PROTO_END, SI_ORDER_ANY); 224 MODULE_DEPEND(ipfw3_layer2, ipfw3_basic, 1, 1, 1); 225 MODULE_VERSION(ipfw3_layer2, 1); 226