blob: 1634f22452a7b53af47d650e4c9268530f7bbad2 [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>
Bart De Schuymer005837e2008-02-21 21:32:25 +000032#include <errno.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <arpa/inet.h>
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000036
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
Bart De Schuymerff587202005-02-08 20:02:28 +000046/* 0: default, print only 2 digits if necessary
Bart De Schuymer55d44132004-02-23 20:55:24 +000047 * 2: always print 2 digits, a printed mac address
Bart De Schuymerff587202005-02-08 20:02:28 +000048 * then always has the same length */
Bart De Schuymer55d44132004-02-23 20:55:24 +000049int ebt_printstyle_mac;
50
Bart De Schuymer510c9ce2006-01-23 18:50:54 +000051void ebt_print_mac(const unsigned char *mac)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000052{
53 if (ebt_printstyle_mac == 2) {
54 int j;
55 for (j = 0; j < ETH_ALEN; j++)
Bart De Schuymer510c9ce2006-01-23 18:50:54 +000056 printf("%02x%s", mac[j],
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000057 (j==ETH_ALEN-1) ? "" : ":");
58 } else
59 printf("%s", ether_ntoa((struct ether_addr *) mac));
60}
61
Bart De Schuymer510c9ce2006-01-23 18:50:54 +000062void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000063{
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
Bart De Schuymerff587202005-02-08 20:02:28 +000087/* Checks the type for validity and calls getethertypebynumber(). */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000088struct ethertypeent *parseethertypebynumber(int type)
89{
90 if (type < 1536)
Bart De Schuymer64182a32004-01-21 20:39:54 +000091 ebt_print_error("Ethernet protocols have values >= 0x0600");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000092 if (type > 0xffff)
Bart De Schuymer64182a32004-01-21 20:39:54 +000093 ebt_print_error("Ethernet protocols have values <= 0xffff");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +000094 return getethertypebynumber(type);
95}
96
Bart De Schuymerff587202005-02-08 20:02:28 +000097/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
Bart De Schuymer510c9ce2006-01-23 18:50:54 +000098int ebt_get_mac_and_mask(const char *from, unsigned char *to,
99 unsigned char *mask)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000100{
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
Bart De Schuymerff587202005-02-08 20:02:28 +0000140/* 0: default
141 * 1: the inverse '!' of the option has already been specified */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000142int ebt_invert = 0;
Bart De Schuymer55d44132004-02-23 20:55:24 +0000143
144/*
145 * Check if the inverse of the option is specified. This is used
Bart De Schuymerff587202005-02-08 20:02:28 +0000146 * in the parse functions of the extensions and ebtables.c
Bart De Schuymer55d44132004-02-23 20:55:24 +0000147 */
Bart De Schuymerff587202005-02-08 20:02:28 +0000148int _ebt_check_inverse(const char option[], int argc, char **argv)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000149{
Bart De Schuymer620443a2004-11-14 13:22:29 +0000150 if (!option)
151 return ebt_invert;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000152 if (strcmp(option, "!") == 0) {
153 if (ebt_invert == 1)
Bart De Schuymerff587202005-02-08 20:02:28 +0000154 ebt_print_error("Double use of '!' not allowed");
155 if (optind >= argc)
156 optarg = NULL;
157 else
158 optarg = argv[optind];
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000159 optind++;
160 ebt_invert = 1;
161 return 1;
162 }
163 return ebt_invert;
164}
165
Bart De Schuymerff587202005-02-08 20:02:28 +0000166/* Make sure the same option wasn't specified twice. This is used
167 * in the parse functions of the extensions and ebtables.c */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000168void ebt_check_option(unsigned int *flags, unsigned int mask)
169{
170 if (*flags & mask)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000171 ebt_print_error("Multiple use of same option not allowed");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000172 *flags |= mask;
173}
174
Bart De Schuymerff587202005-02-08 20:02:28 +0000175/* Put the ip string into 4 bytes. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000176static 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
Bart De Schuymerff587202005-02-08 20:02:28 +0000205/* Put the mask into 4 bytes. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000206static 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
Bart De Schuymerff587202005-02-08 20:02:28 +0000228/* Set the ip mask and ip address. Callers should check ebt_errormsg[0].
229 * The string pointed to by address can be altered. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000230void 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';
Bart De Schuymerff587202005-02-08 20:02:28 +0000237 if (ip_mask(p + 1, (unsigned char *)msk)) {
238 ebt_print_error("Problem with the IP mask '%s'", p + 1);
239 return;
240 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000241 } else
242 *msk = 0xFFFFFFFF;
243
Bart De Schuymerff587202005-02-08 20:02:28 +0000244 if (undot_ip(address, (unsigned char *)addr)) {
245 ebt_print_error("Problem with the IP address '%s'", address);
246 return;
247 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000248 *addr = *addr & *msk;
249}
250
Bart De Schuymer005837e2008-02-21 21:32:25 +0000251
Bart De Schuymerff587202005-02-08 20:02:28 +0000252/* Transform the ip mask into a string ready for output. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000253char *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;
Bart De Schuymerff587202005-02-08 20:02:28 +0000268 bits = 0xFFFFFFFEL; /* Case 0xFFFFFFFF has just been dealt with */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000269 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
Bart De Schuymerff587202005-02-08 20:02:28 +0000277 /* Mask was not a decent combination of 1's and 0's */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000278 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}
Bart De Schuymer005837e2008-02-21 21:32:25 +0000284
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 *
336numeric_to_addr(const char *num)
337{
338 static struct in6_addr ap;
339 int err;
340 if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
341 return &ap;
342 return (struct in6_addr *)NULL;
343}
344
345static struct in6_addr *
346parse_ip6_mask(char *mask)
347{
348 static struct in6_addr maskaddr;
349 struct in6_addr *addrp;
350 unsigned int bits;
351
352 if (mask == NULL) {
353 /* no mask at all defaults to 128 bits */
354 memset(&maskaddr, 0xff, sizeof maskaddr);
355 return &maskaddr;
356 }
357 if ((addrp = numeric_to_addr(mask)) != NULL)
358 return addrp;
359 if (string_to_number(mask, 0, 128, &bits) == -1)
360 ebt_print_error("Invalid IPv6 Mask '%s' specified", mask);
361 if (bits != 0) {
362 char *p = (char *)&maskaddr;
363 memset(p, 0xff, bits / 8);
364 memset(p + (bits / 8) + 1, 0, (128 - bits) / 8);
365 p[bits / 8] = 0xff << (8 - (bits & 7));
366 return &maskaddr;
367 }
368
369 memset(&maskaddr, 0, sizeof maskaddr);
370 return &maskaddr;
371}
372
373/* Set the ipv6 mask and address. Callers should check ebt_errormsg[0].
374 * The string pointed to by address can be altered. */
375void ebt_parse_ip6_address(char *address, struct in6_addr *addr,
376 struct in6_addr *msk)
377{
378 struct in6_addr *tmp_addr;
379 char buf[256];
380 char *p;
381 int i;
382 int err;
383
384 strncpy(buf, address, sizeof(buf) - 1);
385 /* first the mask */
386 buf[sizeof(buf) - 1] = '\0';
387 if ((p = strrchr(buf, '/')) != NULL) {
388 *p = '\0';
389 tmp_addr = parse_ip6_mask(p + 1);
390 } else
391 tmp_addr = parse_ip6_mask(NULL);
392 in6addrcpy(msk, tmp_addr);
393
394 /* if a null mask is given, the name is ignored, like in "any/0" */
395 if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any)))
396 strcpy(buf, "::");
397
398 if ((err=inet_pton(AF_INET6, buf, addr)) < 1) {
399 ebt_print_error("Invalid IPv6 Address '%s' specified", buf);
400 return;
401 }
402
403 for (i = 0; i < 4; i++)
404 addr->in6_u.u6_addr32[i] &= msk->in6_u.u6_addr32[i];
405}
406
407/* Transform the ip6 addr into a string ready for output. */
408char *ebt_ip6_to_numeric(const struct in6_addr *addrp)
409{
410 /* 0000:0000:0000:0000:0000:000.000.000.000
411 * 0000:0000:0000:0000:0000:0000:0000:0000 */
412 static char buf[50+1];
413 return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
414}