1/* 2 * useful_functions.c, January 2004 3 * 4 * Random collection of functions that can be used by extensions. 5 * 6 * Author: Bart De Schuymer 7 * 8 * This code is stongly inspired on the iptables code which is 9 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation; either version 2 of the 14 * License, or (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, but 17 * WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 * General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 */ 25#include "include/ebtables_u.h" 26#include "include/ethernetdb.h" 27#include <stdio.h> 28#include <netinet/ether.h> 29#include <string.h> 30#include <stdlib.h> 31#include <getopt.h> 32#include <errno.h> 33#include <sys/types.h> 34#include <sys/socket.h> 35#include <arpa/inet.h> 36 37const unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0}; 38const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0}; 39const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; 40const unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; 41const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; 42const unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; 43const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0}; 44const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255}; 45 46/* 0: default, print only 2 digits if necessary 47 * 2: always print 2 digits, a printed mac address 48 * then always has the same length */ 49int ebt_printstyle_mac; 50 51void ebt_print_mac(const unsigned char *mac) 52{ 53 if (ebt_printstyle_mac == 2) { 54 int j; 55 for (j = 0; j < ETH_ALEN; j++) 56 printf("%02x%s", mac[j], 57 (j==ETH_ALEN-1) ? "" : ":"); 58 } else 59 printf("%s", ether_ntoa((struct ether_addr *) mac)); 60} 61 62void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask) 63{ 64 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 65 66 if (!memcmp(mac, mac_type_unicast, 6) && 67 !memcmp(mask, msk_type_unicast, 6)) 68 printf("Unicast"); 69 else if (!memcmp(mac, mac_type_multicast, 6) && 70 !memcmp(mask, msk_type_multicast, 6)) 71 printf("Multicast"); 72 else if (!memcmp(mac, mac_type_broadcast, 6) && 73 !memcmp(mask, msk_type_broadcast, 6)) 74 printf("Broadcast"); 75 else if (!memcmp(mac, mac_type_bridge_group, 6) && 76 !memcmp(mask, msk_type_bridge_group, 6)) 77 printf("BGA"); 78 else { 79 ebt_print_mac(mac); 80 if (memcmp(mask, hlpmsk, 6)) { 81 printf("/"); 82 ebt_print_mac(mask); 83 } 84 } 85} 86 87/* Checks the type for validity and calls getethertypebynumber(). */ 88struct ethertypeent *parseethertypebynumber(int type) 89{ 90 if (type < 1536) 91 ebt_print_error("Ethernet protocols have values >= 0x0600"); 92 if (type > 0xffff) 93 ebt_print_error("Ethernet protocols have values <= 0xffff"); 94 return getethertypebynumber(type); 95} 96 97/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */ 98int ebt_get_mac_and_mask(const char *from, unsigned char *to, 99 unsigned char *mask) 100{ 101 char *p; 102 int i; 103 struct ether_addr *addr; 104 105 if (strcasecmp(from, "Unicast") == 0) { 106 memcpy(to, mac_type_unicast, ETH_ALEN); 107 memcpy(mask, msk_type_unicast, ETH_ALEN); 108 return 0; 109 } 110 if (strcasecmp(from, "Multicast") == 0) { 111 memcpy(to, mac_type_multicast, ETH_ALEN); 112 memcpy(mask, msk_type_multicast, ETH_ALEN); 113 return 0; 114 } 115 if (strcasecmp(from, "Broadcast") == 0) { 116 memcpy(to, mac_type_broadcast, ETH_ALEN); 117 memcpy(mask, msk_type_broadcast, ETH_ALEN); 118 return 0; 119 } 120 if (strcasecmp(from, "BGA") == 0) { 121 memcpy(to, mac_type_bridge_group, ETH_ALEN); 122 memcpy(mask, msk_type_bridge_group, ETH_ALEN); 123 return 0; 124 } 125 if ( (p = strrchr(from, '/')) != NULL) { 126 *p = '\0'; 127 if (!(addr = ether_aton(p + 1))) 128 return -1; 129 memcpy(mask, addr, ETH_ALEN); 130 } else 131 memset(mask, 0xff, ETH_ALEN); 132 if (!(addr = ether_aton(from))) 133 return -1; 134 memcpy(to, addr, ETH_ALEN); 135 for (i = 0; i < ETH_ALEN; i++) 136 to[i] &= mask[i]; 137 return 0; 138} 139 140/* 0: default 141 * 1: the inverse '!' of the option has already been specified */ 142int ebt_invert = 0; 143 144/* 145 * Check if the inverse of the option is specified. This is used 146 * in the parse functions of the extensions and ebtables.c 147 */ 148int _ebt_check_inverse(const char option[], int argc, char **argv) 149{ 150 if (!option) 151 return ebt_invert; 152 if (strcmp(option, "!") == 0) { 153 if (ebt_invert == 1) 154 ebt_print_error("Double use of '!' not allowed"); 155 if (optind >= argc) 156 optarg = NULL; 157 else 158 optarg = argv[optind]; 159 optind++; 160 ebt_invert = 1; 161 return 1; 162 } 163 return ebt_invert; 164} 165 166/* Make sure the same option wasn't specified twice. This is used 167 * in the parse functions of the extensions and ebtables.c */ 168void ebt_check_option(unsigned int *flags, unsigned int mask) 169{ 170 if (*flags & mask) 171 ebt_print_error("Multiple use of same option not allowed"); 172 *flags |= mask; 173} 174 175/* Put the ip string into 4 bytes. */ 176static int undot_ip(char *ip, unsigned char *ip2) 177{ 178 char *p, *q, *end; 179 long int onebyte; 180 int i; 181 char buf[20]; 182 183 strncpy(buf, ip, sizeof(buf) - 1); 184 185 p = buf; 186 for (i = 0; i < 3; i++) { 187 if ((q = strchr(p, '.')) == NULL) 188 return -1; 189 *q = '\0'; 190 onebyte = strtol(p, &end, 10); 191 if (*end != '\0' || onebyte > 255 || onebyte < 0) 192 return -1; 193 ip2[i] = (unsigned char)onebyte; 194 p = q + 1; 195 } 196 197 onebyte = strtol(p, &end, 10); 198 if (*end != '\0' || onebyte > 255 || onebyte < 0) 199 return -1; 200 ip2[3] = (unsigned char)onebyte; 201 202 return 0; 203} 204 205/* Put the mask into 4 bytes. */ 206static int ip_mask(char *mask, unsigned char *mask2) 207{ 208 char *end; 209 long int bits; 210 uint32_t mask22; 211 212 if (undot_ip(mask, mask2)) { 213 /* not the /a.b.c.e format, maybe the /x format */ 214 bits = strtol(mask, &end, 10); 215 if (*end != '\0' || bits > 32 || bits < 0) 216 return -1; 217 if (bits != 0) { 218 mask22 = htonl(0xFFFFFFFF << (32 - bits)); 219 memcpy(mask2, &mask22, 4); 220 } else { 221 mask22 = 0xFFFFFFFF; 222 memcpy(mask2, &mask22, 4); 223 } 224 } 225 return 0; 226} 227 228/* Set the ip mask and ip address. Callers should check ebt_errormsg[0]. 229 * The string pointed to by address can be altered. */ 230void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk) 231{ 232 char *p; 233 234 /* first the mask */ 235 if ((p = strrchr(address, '/')) != NULL) { 236 *p = '\0'; 237 if (ip_mask(p + 1, (unsigned char *)msk)) { 238 ebt_print_error("Problem with the IP mask '%s'", p + 1); 239 return; 240 } 241 } else 242 *msk = 0xFFFFFFFF; 243 244 if (undot_ip(address, (unsigned char *)addr)) { 245 ebt_print_error("Problem with the IP address '%s'", address); 246 return; 247 } 248 *addr = *addr & *msk; 249} 250 251 252/* Transform the ip mask into a string ready for output. */ 253char *ebt_mask_to_dotted(uint32_t mask) 254{ 255 int i; 256 static char buf[20]; 257 uint32_t maskaddr, bits; 258 259 maskaddr = ntohl(mask); 260 261 /* don't print /32 */ 262 if (mask == 0xFFFFFFFFL) { 263 *buf = '\0'; 264 return buf; 265 } 266 267 i = 32; 268 bits = 0xFFFFFFFEL; /* Case 0xFFFFFFFF has just been dealt with */ 269 while (--i >= 0 && maskaddr != bits) 270 bits <<= 1; 271 272 if (i > 0) 273 sprintf(buf, "/%d", i); 274 else if (!i) 275 *buf = '\0'; 276 else 277 /* Mask was not a decent combination of 1's and 0's */ 278 sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0], 279 ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2], 280 ((unsigned char *)&mask)[3]); 281 282 return buf; 283} 284 285/* Most of the following code is derived from iptables */ 286static void 287in6addrcpy(struct in6_addr *dst, struct in6_addr *src) 288{ 289 memcpy(dst, src, sizeof(struct in6_addr)); 290} 291 292int string_to_number_ll(const char *s, unsigned long long min, 293 unsigned long long max, unsigned long long *ret) 294{ 295 unsigned long long number; 296 char *end; 297 298 /* Handle hex, octal, etc. */ 299 errno = 0; 300 number = strtoull(s, &end, 0); 301 if (*end == '\0' && end != s) { 302 /* we parsed a number, let's see if we want this */ 303 if (errno != ERANGE && min <= number && (!max || number <= max)) { 304 *ret = number; 305 return 0; 306 } 307 } 308 return -1; 309} 310 311int string_to_number_l(const char *s, unsigned long min, unsigned long max, 312 unsigned long *ret) 313{ 314 int result; 315 unsigned long long number; 316 317 result = string_to_number_ll(s, min, max, &number); 318 *ret = (unsigned long)number; 319 320 return result; 321} 322 323int string_to_number(const char *s, unsigned int min, unsigned int max, 324 unsigned int *ret) 325{ 326 int result; 327 unsigned long number; 328 329 result = string_to_number_l(s, min, max, &number); 330 *ret = (unsigned int)number; 331 332 return result; 333} 334 335static struct in6_addr *numeric_to_addr(const char *num) 336{ 337 static struct in6_addr ap; 338 int err; 339 340 if ((err=inet_pton(AF_INET6, num, &ap)) == 1) 341 return ≈ 342 return (struct in6_addr *)NULL; 343} 344 345static struct in6_addr *parse_ip6_mask(char *mask) 346{ 347 static struct in6_addr maskaddr; 348 struct in6_addr *addrp; 349 unsigned int bits; 350 351 if (mask == NULL) { 352 /* no mask at all defaults to 128 bits */ 353 memset(&maskaddr, 0xff, sizeof maskaddr); 354 return &maskaddr; 355 } 356 if ((addrp = numeric_to_addr(mask)) != NULL) 357 return addrp; 358 if (string_to_number(mask, 0, 128, &bits) == -1) 359 ebt_print_error("Invalid IPv6 Mask '%s' specified", mask); 360 if (bits != 0) { 361 char *p = (char *)&maskaddr; 362 memset(p, 0xff, bits / 8); 363 memset(p + (bits / 8) + 1, 0, (128 - bits) / 8); 364 p[bits / 8] = 0xff << (8 - (bits & 7)); 365 return &maskaddr; 366 } 367 368 memset(&maskaddr, 0, sizeof maskaddr); 369 return &maskaddr; 370} 371 372/* Set the ipv6 mask and address. Callers should check ebt_errormsg[0]. 373 * The string pointed to by address can be altered. */ 374void ebt_parse_ip6_address(char *address, struct in6_addr *addr, 375 struct in6_addr *msk) 376{ 377 struct in6_addr *tmp_addr; 378 char buf[256]; 379 char *p; 380 int i; 381 int err; 382 383 strncpy(buf, address, sizeof(buf) - 1); 384 /* first the mask */ 385 buf[sizeof(buf) - 1] = '\0'; 386 if ((p = strrchr(buf, '/')) != NULL) { 387 *p = '\0'; 388 tmp_addr = parse_ip6_mask(p + 1); 389 } else 390 tmp_addr = parse_ip6_mask(NULL); 391 in6addrcpy(msk, tmp_addr); 392 393 /* if a null mask is given, the name is ignored, like in "any/0" */ 394 if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any))) 395 strcpy(buf, "::"); 396 397 if ((err=inet_pton(AF_INET6, buf, addr)) < 1) { 398 ebt_print_error("Invalid IPv6 Address '%s' specified", buf); 399 return; 400 } 401 402 for (i = 0; i < 4; i++) 403 addr->s6_addr32[i] &= msk->s6_addr32[i]; 404} 405 406/* Transform the ip6 addr into a string ready for output. */ 407char *ebt_ip6_to_numeric(const struct in6_addr *addrp) 408{ 409 /* 0000:0000:0000:0000:0000:000.000.000.000 410 * 0000:0000:0000:0000:0000:0000:0000:0000 */ 411 static char buf[50+1]; 412 return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); 413} 414