/* * useful_functions.c, January 2004 * * Random collection of functions that can be used by extensions. * * Author: Bart De Schuymer * * This code is stongly inspired on the iptables code which is * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "include/ebtables_u.h" #include "include/ethernetdb.h" #include #include #include #include #include const unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0}; const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0}; const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; const unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0}; const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; const unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255}; const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0}; const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255}; /* * 0: default, print only 2 digits if necessary * 2: always print 2 digits, a printed mac address * then always has the same length */ int ebt_printstyle_mac; void ebt_print_mac(const char *mac) { if (ebt_printstyle_mac == 2) { int j; for (j = 0; j < ETH_ALEN; j++) printf("%02x%s", (unsigned char)mac[j], (j==ETH_ALEN-1) ? "" : ":"); } else printf("%s", ether_ntoa((struct ether_addr *) mac)); } void ebt_print_mac_and_mask(const char *mac, const char *mask) { char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; if (!memcmp(mac, mac_type_unicast, 6) && !memcmp(mask, msk_type_unicast, 6)) printf("Unicast"); else if (!memcmp(mac, mac_type_multicast, 6) && !memcmp(mask, msk_type_multicast, 6)) printf("Multicast"); else if (!memcmp(mac, mac_type_broadcast, 6) && !memcmp(mask, msk_type_broadcast, 6)) printf("Broadcast"); else if (!memcmp(mac, mac_type_bridge_group, 6) && !memcmp(mask, msk_type_bridge_group, 6)) printf("BGA"); else { ebt_print_mac(mac); if (memcmp(mask, hlpmsk, 6)) { printf("/"); ebt_print_mac(mask); } } } /* * Checks the type for validity and calls getethertypebynumber() */ struct ethertypeent *parseethertypebynumber(int type) { if (type < 1536) ebt_print_error("Ethernet protocols have values >= 0x0600"); if (type > 0xffff) ebt_print_error("Ethernet protocols have values <= 0xffff"); return getethertypebynumber(type); } /* * put the mac address into 6 (ETH_ALEN) bytes * returns 0 on success */ int ebt_get_mac_and_mask(char *from, char *to, char *mask) { char *p; int i; struct ether_addr *addr; if (strcasecmp(from, "Unicast") == 0) { memcpy(to, mac_type_unicast, ETH_ALEN); memcpy(mask, msk_type_unicast, ETH_ALEN); return 0; } if (strcasecmp(from, "Multicast") == 0) { memcpy(to, mac_type_multicast, ETH_ALEN); memcpy(mask, msk_type_multicast, ETH_ALEN); return 0; } if (strcasecmp(from, "Broadcast") == 0) { memcpy(to, mac_type_broadcast, ETH_ALEN); memcpy(mask, msk_type_broadcast, ETH_ALEN); return 0; } if (strcasecmp(from, "BGA") == 0) { memcpy(to, mac_type_bridge_group, ETH_ALEN); memcpy(mask, msk_type_bridge_group, ETH_ALEN); return 0; } if ( (p = strrchr(from, '/')) != NULL) { *p = '\0'; if (!(addr = ether_aton(p + 1))) return -1; memcpy(mask, addr, ETH_ALEN); } else memset(mask, 0xff, ETH_ALEN); if (!(addr = ether_aton(from))) return -1; memcpy(to, addr, ETH_ALEN); for (i = 0; i < ETH_ALEN; i++) to[i] &= mask[i]; return 0; } /* * 0: default * 1: the inverse '!' of the option has already been specified */ int ebt_invert = 0; /* * Check if the inverse of the option is specified. This is used * in the parse functions of the extensions and ebtables.c. */ int ebt_check_inverse(const char option[]) { if (!option) return ebt_invert; if (strcmp(option, "!") == 0) { if (ebt_invert == 1) ebt_print_error("double use of '!' not allowed"); optind++; ebt_invert = 1; return 1; } return ebt_invert; } /* * Make sure the same option wasn't specified twice. This is used * in the parse functions of the extensions and ebtables.c. */ void ebt_check_option(unsigned int *flags, unsigned int mask) { if (*flags & mask) ebt_print_error("Multiple use of same option not allowed"); *flags |= mask; } /* * put the ip string into 4 bytes */ static int undot_ip(char *ip, unsigned char *ip2) { char *p, *q, *end; long int onebyte; int i; char buf[20]; strncpy(buf, ip, sizeof(buf) - 1); p = buf; for (i = 0; i < 3; i++) { if ((q = strchr(p, '.')) == NULL) return -1; *q = '\0'; onebyte = strtol(p, &end, 10); if (*end != '\0' || onebyte > 255 || onebyte < 0) return -1; ip2[i] = (unsigned char)onebyte; p = q + 1; } onebyte = strtol(p, &end, 10); if (*end != '\0' || onebyte > 255 || onebyte < 0) return -1; ip2[3] = (unsigned char)onebyte; return 0; } /* * put the mask into 4 bytes */ static int ip_mask(char *mask, unsigned char *mask2) { char *end; long int bits; uint32_t mask22; if (undot_ip(mask, mask2)) { /* not the /a.b.c.e format, maybe the /x format */ bits = strtol(mask, &end, 10); if (*end != '\0' || bits > 32 || bits < 0) return -1; if (bits != 0) { mask22 = htonl(0xFFFFFFFF << (32 - bits)); memcpy(mask2, &mask22, 4); } else { mask22 = 0xFFFFFFFF; memcpy(mask2, &mask22, 4); } } return 0; } /* * set the ip mask and ip address */ void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk) { char *p; /* first the mask */ if ((p = strrchr(address, '/')) != NULL) { *p = '\0'; if (ip_mask(p + 1, (unsigned char *)msk)) ebt_print_error("Problem with the IP mask"); } else *msk = 0xFFFFFFFF; if (undot_ip(address, (unsigned char *)addr)) ebt_print_error("Problem with the IP address"); *addr = *addr & *msk; } /* * transform the ip mask into a string ready for output */ char *ebt_mask_to_dotted(uint32_t mask) { int i; static char buf[20]; uint32_t maskaddr, bits; maskaddr = ntohl(mask); /* don't print /32 */ if (mask == 0xFFFFFFFFL) { *buf = '\0'; return buf; } i = 32; bits = 0xFFFFFFFEL; /* case 0xFFFFFFFF has just been dealt with */ while (--i >= 0 && maskaddr != bits) bits <<= 1; if (i > 0) sprintf(buf, "/%d", i); else if (!i) *buf = '\0'; else /* mask was not a decent combination of 1's and 0's */ sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0], ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2], ((unsigned char *)&mask)[3]); return buf; }