blob: 131851aa77cad057358edca6156df8d7ead2beda [file] [log] [blame]
Bart De Schuymer80c82bb2004-01-14 20:06:44 +00001/*
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
33const unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
34const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
35const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
36const unsigned char msk_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
37const unsigned char mac_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
38const unsigned char msk_type_broadcast[ETH_ALEN] = {255,255,255,255,255,255};
39const unsigned char mac_type_bridge_group[ETH_ALEN] = {0x01,0x80,0xc2,0,0,0};
40const unsigned char msk_type_bridge_group[ETH_ALEN] = {255,255,255,255,255,255};
41
Bart De Schuymerff587202005-02-08 20:02:28 +000042/* 0: default, print only 2 digits if necessary
Bart De Schuymer55d44132004-02-23 20:55:24 +000043 * 2: always print 2 digits, a printed mac address
Bart De Schuymerff587202005-02-08 20:02:28 +000044 * then always has the same length */
Bart De Schuymer55d44132004-02-23 20:55:24 +000045int ebt_printstyle_mac;
46
Bart De Schuymer510c9ce2006-01-23 18:50:54 +000047void ebt_print_mac(const unsigned char *mac)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000048{
49 if (ebt_printstyle_mac == 2) {
50 int j;
51 for (j = 0; j < ETH_ALEN; j++)
Bart De Schuymer510c9ce2006-01-23 18:50:54 +000052 printf("%02x%s", mac[j],
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000053 (j==ETH_ALEN-1) ? "" : ":");
54 } else
55 printf("%s", ether_ntoa((struct ether_addr *) mac));
56}
57
Bart De Schuymer510c9ce2006-01-23 18:50:54 +000058void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000059{
60 char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
61
62 if (!memcmp(mac, mac_type_unicast, 6) &&
63 !memcmp(mask, msk_type_unicast, 6))
64 printf("Unicast");
65 else if (!memcmp(mac, mac_type_multicast, 6) &&
66 !memcmp(mask, msk_type_multicast, 6))
67 printf("Multicast");
68 else if (!memcmp(mac, mac_type_broadcast, 6) &&
69 !memcmp(mask, msk_type_broadcast, 6))
70 printf("Broadcast");
71 else if (!memcmp(mac, mac_type_bridge_group, 6) &&
72 !memcmp(mask, msk_type_bridge_group, 6))
73 printf("BGA");
74 else {
75 ebt_print_mac(mac);
76 if (memcmp(mask, hlpmsk, 6)) {
77 printf("/");
78 ebt_print_mac(mask);
79 }
80 }
81}
82
Bart De Schuymerff587202005-02-08 20:02:28 +000083/* Checks the type for validity and calls getethertypebynumber(). */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000084struct ethertypeent *parseethertypebynumber(int type)
85{
86 if (type < 1536)
Bart De Schuymer64182a32004-01-21 20:39:54 +000087 ebt_print_error("Ethernet protocols have values >= 0x0600");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000088 if (type > 0xffff)
Bart De Schuymer64182a32004-01-21 20:39:54 +000089 ebt_print_error("Ethernet protocols have values <= 0xffff");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000090 return getethertypebynumber(type);
91}
92
Bart De Schuymerff587202005-02-08 20:02:28 +000093/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
Bart De Schuymer510c9ce2006-01-23 18:50:54 +000094int ebt_get_mac_and_mask(const char *from, unsigned char *to,
95 unsigned char *mask)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000096{
97 char *p;
98 int i;
99 struct ether_addr *addr;
100
101 if (strcasecmp(from, "Unicast") == 0) {
102 memcpy(to, mac_type_unicast, ETH_ALEN);
103 memcpy(mask, msk_type_unicast, ETH_ALEN);
104 return 0;
105 }
106 if (strcasecmp(from, "Multicast") == 0) {
107 memcpy(to, mac_type_multicast, ETH_ALEN);
108 memcpy(mask, msk_type_multicast, ETH_ALEN);
109 return 0;
110 }
111 if (strcasecmp(from, "Broadcast") == 0) {
112 memcpy(to, mac_type_broadcast, ETH_ALEN);
113 memcpy(mask, msk_type_broadcast, ETH_ALEN);
114 return 0;
115 }
116 if (strcasecmp(from, "BGA") == 0) {
117 memcpy(to, mac_type_bridge_group, ETH_ALEN);
118 memcpy(mask, msk_type_bridge_group, ETH_ALEN);
119 return 0;
120 }
121 if ( (p = strrchr(from, '/')) != NULL) {
122 *p = '\0';
123 if (!(addr = ether_aton(p + 1)))
124 return -1;
125 memcpy(mask, addr, ETH_ALEN);
126 } else
127 memset(mask, 0xff, ETH_ALEN);
128 if (!(addr = ether_aton(from)))
129 return -1;
130 memcpy(to, addr, ETH_ALEN);
131 for (i = 0; i < ETH_ALEN; i++)
132 to[i] &= mask[i];
133 return 0;
134}
135
Bart De Schuymerff587202005-02-08 20:02:28 +0000136/* 0: default
137 * 1: the inverse '!' of the option has already been specified */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000138int ebt_invert = 0;
Bart De Schuymer55d44132004-02-23 20:55:24 +0000139
140/*
141 * Check if the inverse of the option is specified. This is used
Bart De Schuymerff587202005-02-08 20:02:28 +0000142 * in the parse functions of the extensions and ebtables.c
Bart De Schuymer55d44132004-02-23 20:55:24 +0000143 */
Bart De Schuymerff587202005-02-08 20:02:28 +0000144int _ebt_check_inverse(const char option[], int argc, char **argv)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000145{
Bart De Schuymer620443a2004-11-14 13:22:29 +0000146 if (!option)
147 return ebt_invert;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000148 if (strcmp(option, "!") == 0) {
149 if (ebt_invert == 1)
Bart De Schuymerff587202005-02-08 20:02:28 +0000150 ebt_print_error("Double use of '!' not allowed");
151 if (optind >= argc)
152 optarg = NULL;
153 else
154 optarg = argv[optind];
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000155 optind++;
156 ebt_invert = 1;
157 return 1;
158 }
159 return ebt_invert;
160}
161
Bart De Schuymerff587202005-02-08 20:02:28 +0000162/* Make sure the same option wasn't specified twice. This is used
163 * in the parse functions of the extensions and ebtables.c */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000164void ebt_check_option(unsigned int *flags, unsigned int mask)
165{
166 if (*flags & mask)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000167 ebt_print_error("Multiple use of same option not allowed");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000168 *flags |= mask;
169}
170
Bart De Schuymerff587202005-02-08 20:02:28 +0000171/* Put the ip string into 4 bytes. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000172static int undot_ip(char *ip, unsigned char *ip2)
173{
174 char *p, *q, *end;
175 long int onebyte;
176 int i;
177 char buf[20];
178
179 strncpy(buf, ip, sizeof(buf) - 1);
180
181 p = buf;
182 for (i = 0; i < 3; i++) {
183 if ((q = strchr(p, '.')) == NULL)
184 return -1;
185 *q = '\0';
186 onebyte = strtol(p, &end, 10);
187 if (*end != '\0' || onebyte > 255 || onebyte < 0)
188 return -1;
189 ip2[i] = (unsigned char)onebyte;
190 p = q + 1;
191 }
192
193 onebyte = strtol(p, &end, 10);
194 if (*end != '\0' || onebyte > 255 || onebyte < 0)
195 return -1;
196 ip2[3] = (unsigned char)onebyte;
197
198 return 0;
199}
200
Bart De Schuymerff587202005-02-08 20:02:28 +0000201/* Put the mask into 4 bytes. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000202static int ip_mask(char *mask, unsigned char *mask2)
203{
204 char *end;
205 long int bits;
206 uint32_t mask22;
207
208 if (undot_ip(mask, mask2)) {
209 /* not the /a.b.c.e format, maybe the /x format */
210 bits = strtol(mask, &end, 10);
211 if (*end != '\0' || bits > 32 || bits < 0)
212 return -1;
213 if (bits != 0) {
214 mask22 = htonl(0xFFFFFFFF << (32 - bits));
215 memcpy(mask2, &mask22, 4);
216 } else {
217 mask22 = 0xFFFFFFFF;
218 memcpy(mask2, &mask22, 4);
219 }
220 }
221 return 0;
222}
223
Bart De Schuymerff587202005-02-08 20:02:28 +0000224/* Set the ip mask and ip address. Callers should check ebt_errormsg[0].
225 * The string pointed to by address can be altered. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000226void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
227{
228 char *p;
229
230 /* first the mask */
231 if ((p = strrchr(address, '/')) != NULL) {
232 *p = '\0';
Bart De Schuymerff587202005-02-08 20:02:28 +0000233 if (ip_mask(p + 1, (unsigned char *)msk)) {
234 ebt_print_error("Problem with the IP mask '%s'", p + 1);
235 return;
236 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000237 } else
238 *msk = 0xFFFFFFFF;
239
Bart De Schuymerff587202005-02-08 20:02:28 +0000240 if (undot_ip(address, (unsigned char *)addr)) {
241 ebt_print_error("Problem with the IP address '%s'", address);
242 return;
243 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000244 *addr = *addr & *msk;
245}
246
Bart De Schuymerff587202005-02-08 20:02:28 +0000247/* Transform the ip mask into a string ready for output. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000248char *ebt_mask_to_dotted(uint32_t mask)
249{
250 int i;
251 static char buf[20];
252 uint32_t maskaddr, bits;
253
254 maskaddr = ntohl(mask);
255
256 /* don't print /32 */
257 if (mask == 0xFFFFFFFFL) {
258 *buf = '\0';
259 return buf;
260 }
261
262 i = 32;
Bart De Schuymerff587202005-02-08 20:02:28 +0000263 bits = 0xFFFFFFFEL; /* Case 0xFFFFFFFF has just been dealt with */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000264 while (--i >= 0 && maskaddr != bits)
265 bits <<= 1;
266
267 if (i > 0)
268 sprintf(buf, "/%d", i);
269 else if (!i)
270 *buf = '\0';
271 else
Bart De Schuymerff587202005-02-08 20:02:28 +0000272 /* Mask was not a decent combination of 1's and 0's */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000273 sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0],
274 ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2],
275 ((unsigned char *)&mask)[3]);
276
277 return buf;
278}