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 <err.h> 36 #include <errno.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <sysexits.h> 41 42 #include <net/if.h> 43 #include <net/route.h> 44 #include <net/pfil.h> 45 #include <netinet/in.h> 46 47 #include <net/ipfw3/ip_fw3.h> 48 #include "../../../sbin/ipfw3/ipfw3.h" 49 #include "ipfw3_layer2.h" 50 51 /* 52 * Returns the number of bits set (from left) in a contiguous bitmask, 53 * or -1 if the mask is not contiguous. 54 * XXX this needs a proper fix. 55 * This effectively works on masks in big-endian (network) format. 56 * when compiled on little endian architectures. 57 * 58 * First bit is bit 7 of the first byte -- note, for MAC addresses, 59 * the first bit on the wire is bit 0 of the first byte. 60 * len is the max length in bits. 61 */ 62 static int 63 contigmask(u_char *p, int len) 64 { 65 int i, n; 66 for (i = 0; i < len ; i++) { 67 if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 68 break; 69 } 70 for (n = i + 1; n < len; n++) { 71 if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 72 return -1; /* mask not contiguous */ 73 } 74 return i; 75 } 76 77 /* 78 * prints a MAC address/mask pair 79 */ 80 static void 81 print_mac(u_char *addr, u_char *mask) 82 { 83 int l = contigmask(mask, 48); 84 85 if (l == 0) { 86 printf(" any"); 87 } else { 88 printf(" %02x:%02x:%02x:%02x:%02x:%02x", 89 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 90 if (l == -1) { 91 printf("&%02x:%02x:%02x:%02x:%02x:%02x", 92 mask[0], mask[1], mask[2], 93 mask[3], mask[4], mask[5]); 94 } else if (l < 48) { 95 printf("/%d", l); 96 } 97 } 98 } 99 100 static void 101 get_mac_addr_mask(char *p, u_char *addr, u_char *mask) 102 { 103 int i, l; 104 105 for (i = 0; i < 6; i++) 106 addr[i] = mask[i] = 0; 107 if (!strcmp(p, "any")) 108 return; 109 110 for (i = 0; *p && i < 6; i++, p++) { 111 addr[i] = strtol(p, &p, 16); 112 if (*p != ':') /* we start with the mask */ 113 break; 114 } 115 if (*p == '/') { /* mask len */ 116 l = strtol(p + 1, &p, 0); 117 for (i = 0; l > 0; l -= 8, i++) 118 mask[i] = (l >=8) ? 0xff : (~0) << (8-l); 119 } else if (*p == '&') { /* mask */ 120 for (i = 0, p++; *p && i < 6; i++, p++) { 121 mask[i] = strtol(p, &p, 16); 122 if (*p != ':') 123 break; 124 } 125 } else if (*p == '\0') { 126 for (i = 0; i < 6; i++) 127 mask[i] = 0xff; 128 } 129 for (i = 0; i < 6; i++) 130 addr[i] &= mask[i]; 131 } 132 133 void 134 parse_layer2(ipfw_insn **cmd, int *ac, char **av[]) 135 { 136 (*cmd)->opcode = O_LAYER2_LAYER2; 137 (*cmd)->module = MODULE_LAYER2_ID; 138 (*cmd)->len |= LEN_OF_IPFWINSN; 139 NEXT_ARG1; 140 } 141 142 void 143 parse_mac_from(ipfw_insn **cmd, int *ac, char **av[]) 144 { 145 NEED(*ac, 2, "mac-from src"); 146 NEXT_ARG1; 147 if (strcmp(**av, "table") == 0) { 148 NEED(*ac, 2, "mac-from table N"); 149 NEXT_ARG1; 150 (*cmd)->opcode = O_LAYER2_MAC_SRC_LOOKUP; 151 (*cmd)->module = MODULE_LAYER2_ID; 152 (*cmd)->len |= F_INSN_SIZE(ipfw_insn); 153 (*cmd)->arg1 = strtoul(**av, NULL, 10); 154 NEXT_ARG1; 155 } else { 156 (*cmd)->opcode = O_LAYER2_MAC_SRC; 157 (*cmd)->module = MODULE_LAYER2_ID; 158 (*cmd)->len |= F_INSN_SIZE(ipfw_insn_mac); 159 ipfw_insn_mac *mac = (ipfw_insn_mac *)(*cmd); 160 /* src */ 161 get_mac_addr_mask(**av, &(mac->addr[6]), &(mac->mask[6])); 162 NEXT_ARG1; 163 } 164 } 165 166 void 167 parse_mac_to(ipfw_insn **cmd, int *ac, char **av[]) 168 { 169 NEED(*ac, 2, "mac-to dst"); 170 NEXT_ARG1; 171 if (strcmp(**av, "table") == 0) { 172 NEED(*ac, 2, "mac-to table N"); 173 NEXT_ARG1; 174 (*cmd)->opcode = O_LAYER2_MAC_DST_LOOKUP; 175 (*cmd)->module = MODULE_LAYER2_ID; 176 (*cmd)->len |= F_INSN_SIZE(ipfw_insn); 177 (*cmd)->arg1 = strtoul(**av, NULL, 10); 178 NEXT_ARG1; 179 } else { 180 (*cmd)->opcode = O_LAYER2_MAC_DST; 181 (*cmd)->module = MODULE_LAYER2_ID; 182 (*cmd)->len |= F_INSN_SIZE(ipfw_insn_mac); 183 ipfw_insn_mac *mac = (ipfw_insn_mac *)(*cmd); 184 /* dst */ 185 get_mac_addr_mask(**av, mac->addr, mac->mask); 186 NEXT_ARG1; 187 } 188 } 189 190 191 void 192 parse_mac(ipfw_insn **cmd, int *ac, char **av[]) 193 { 194 NEED(*ac, 3, "mac dst src"); 195 NEXT_ARG1; 196 (*cmd)->opcode = O_LAYER2_MAC; 197 (*cmd)->module = MODULE_LAYER2_ID; 198 (*cmd)->len |= F_INSN_SIZE(ipfw_insn_mac); 199 ipfw_insn_mac *mac = (ipfw_insn_mac *)(*cmd); 200 get_mac_addr_mask(**av, mac->addr, mac->mask); /* dst */ 201 NEXT_ARG1; 202 get_mac_addr_mask(**av, &(mac->addr[6]), &(mac->mask[6])); /* src */ 203 NEXT_ARG1; 204 } 205 206 void 207 show_layer2(ipfw_insn *cmd, int show_or) 208 { 209 printf(" layer2"); 210 } 211 212 void 213 show_mac(ipfw_insn *cmd, int show_or) 214 { 215 ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 216 if (show_or) 217 printf(" or"); 218 else 219 printf(" mac"); 220 print_mac( m->addr, m->mask); 221 print_mac( m->addr + 6, m->mask + 6); 222 } 223 224 void 225 show_mac_from(ipfw_insn *cmd, int show_or) 226 { 227 ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 228 if (show_or) 229 printf(" or"); 230 else 231 printf(" mac-from"); 232 print_mac( m->addr + 6, m->mask + 6); 233 } 234 235 void 236 show_mac_from_lookup(ipfw_insn *cmd, int show_or) 237 { 238 printf(" mac-from table %d", cmd->arg1); 239 } 240 241 void 242 show_mac_to(ipfw_insn *cmd, int show_or) 243 { 244 ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 245 if (show_or) 246 printf(" or"); 247 else 248 printf(" mac-to"); 249 print_mac( m->addr, m->mask); 250 } 251 252 void 253 show_mac_to_lookup(ipfw_insn *cmd, int show_or) 254 { 255 printf(" mac-to table %d", cmd->arg1); 256 } 257 258 void 259 load_module(register_func function, register_keyword keyword) 260 { 261 keyword(MODULE_LAYER2_ID, O_LAYER2_LAYER2, "layer2", FILTER); 262 function(MODULE_LAYER2_ID, O_LAYER2_LAYER2, 263 (parser_func)parse_layer2, (shower_func)show_layer2); 264 265 keyword(MODULE_LAYER2_ID, O_LAYER2_MAC, "mac", FILTER); 266 function(MODULE_LAYER2_ID, O_LAYER2_MAC, 267 (parser_func)parse_mac,(shower_func)show_mac); 268 keyword(MODULE_LAYER2_ID, O_LAYER2_MAC_SRC, "mac-from", FROM); 269 function(MODULE_LAYER2_ID, O_LAYER2_MAC_SRC, 270 (parser_func)parse_mac_from,(shower_func)show_mac_from); 271 keyword(MODULE_LAYER2_ID, O_LAYER2_MAC_SRC_LOOKUP, 272 "mac-from-[table]", FROM); 273 function(MODULE_LAYER2_ID, O_LAYER2_MAC_SRC_LOOKUP, 274 (parser_func)parse_mac_from, 275 (shower_func)show_mac_from_lookup); 276 277 keyword(MODULE_LAYER2_ID, O_LAYER2_MAC_DST, "mac-to", TO); 278 function(MODULE_LAYER2_ID, O_LAYER2_MAC_DST, 279 (parser_func)parse_mac_to,(shower_func)show_mac_to); 280 keyword(MODULE_LAYER2_ID, O_LAYER2_MAC_DST_LOOKUP, 281 "mac-to-[table]", TO); 282 function(MODULE_LAYER2_ID, O_LAYER2_MAC_DST_LOOKUP, 283 (parser_func)parse_mac_to, 284 (shower_func)show_mac_to_lookup); 285 } 286