2 * useful_functions.c, January 2004
4 * Random collection of functions that can be used by extensions.
6 * Author: Bart De Schuymer
8 * This code is stongly inspired on the iptables code which is
9 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
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.
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.
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.
25 #include "include/ebtables_u.h"
26 #include "include/ethernetdb.h"
28 #include <netinet/ether.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <arpa/inet.h>
37 const unsigned char mac_type_unicast
[ETH_ALEN
] = {0,0,0,0,0,0};
38 const unsigned char msk_type_unicast
[ETH_ALEN
] = {1,0,0,0,0,0};
39 const unsigned char mac_type_multicast
[ETH_ALEN
] = {1,0,0,0,0,0};
40 const unsigned char msk_type_multicast
[ETH_ALEN
] = {1,0,0,0,0,0};
41 const unsigned char mac_type_broadcast
[ETH_ALEN
] = {255,255,255,255,255,255};
42 const unsigned char msk_type_broadcast
[ETH_ALEN
] = {255,255,255,255,255,255};
43 const unsigned char mac_type_bridge_group
[ETH_ALEN
] = {0x01,0x80,0xc2,0,0,0};
44 const unsigned char msk_type_bridge_group
[ETH_ALEN
] = {255,255,255,255,255,255};
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 */
49 int ebt_printstyle_mac
;
51 void ebt_print_mac(const unsigned char *mac
)
53 if (ebt_printstyle_mac
== 2) {
55 for (j
= 0; j
< ETH_ALEN
; j
++)
56 printf("%02x%s", mac
[j
],
57 (j
==ETH_ALEN
-1) ? "" : ":");
59 printf("%s", ether_ntoa((struct ether_addr
*) mac
));
62 void ebt_print_mac_and_mask(const unsigned char *mac
, const unsigned char *mask
)
64 char hlpmsk
[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
66 if (!memcmp(mac
, mac_type_unicast
, 6) &&
67 !memcmp(mask
, msk_type_unicast
, 6))
69 else if (!memcmp(mac
, mac_type_multicast
, 6) &&
70 !memcmp(mask
, msk_type_multicast
, 6))
72 else if (!memcmp(mac
, mac_type_broadcast
, 6) &&
73 !memcmp(mask
, msk_type_broadcast
, 6))
75 else if (!memcmp(mac
, mac_type_bridge_group
, 6) &&
76 !memcmp(mask
, msk_type_bridge_group
, 6))
80 if (memcmp(mask
, hlpmsk
, 6)) {
87 /* Checks the type for validity and calls getethertypebynumber(). */
88 struct ethertypeent
*parseethertypebynumber(int type
)
91 ebt_print_error("Ethernet protocols have values >= 0x0600");
93 ebt_print_error("Ethernet protocols have values <= 0xffff");
94 return getethertypebynumber(type
);
97 /* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
98 int ebt_get_mac_and_mask(const char *from
, unsigned char *to
,
103 struct ether_addr
*addr
;
105 if (strcasecmp(from
, "Unicast") == 0) {
106 memcpy(to
, mac_type_unicast
, ETH_ALEN
);
107 memcpy(mask
, msk_type_unicast
, ETH_ALEN
);
110 if (strcasecmp(from
, "Multicast") == 0) {
111 memcpy(to
, mac_type_multicast
, ETH_ALEN
);
112 memcpy(mask
, msk_type_multicast
, ETH_ALEN
);
115 if (strcasecmp(from
, "Broadcast") == 0) {
116 memcpy(to
, mac_type_broadcast
, ETH_ALEN
);
117 memcpy(mask
, msk_type_broadcast
, ETH_ALEN
);
120 if (strcasecmp(from
, "BGA") == 0) {
121 memcpy(to
, mac_type_bridge_group
, ETH_ALEN
);
122 memcpy(mask
, msk_type_bridge_group
, ETH_ALEN
);
125 if ( (p
= strrchr(from
, '/')) != NULL
) {
127 if (!(addr
= ether_aton(p
+ 1)))
129 memcpy(mask
, addr
, ETH_ALEN
);
131 memset(mask
, 0xff, ETH_ALEN
);
132 if (!(addr
= ether_aton(from
)))
134 memcpy(to
, addr
, ETH_ALEN
);
135 for (i
= 0; i
< ETH_ALEN
; i
++)
141 * 1: the inverse '!' of the option has already been specified */
145 * Check if the inverse of the option is specified. This is used
146 * in the parse functions of the extensions and ebtables.c
148 int _ebt_check_inverse(const char option
[], int argc
, char **argv
)
152 if (strcmp(option
, "!") == 0) {
154 ebt_print_error("Double use of '!' not allowed");
158 optarg
= argv
[optind
];
166 /* Make sure the same option wasn't specified twice. This is used
167 * in the parse functions of the extensions and ebtables.c */
168 void ebt_check_option(unsigned int *flags
, unsigned int mask
)
171 ebt_print_error("Multiple use of same option not allowed");
175 /* Put the ip string into 4 bytes. */
176 static int undot_ip(char *ip
, unsigned char *ip2
)
183 strncpy(buf
, ip
, sizeof(buf
) - 1);
186 for (i
= 0; i
< 3; i
++) {
187 if ((q
= strchr(p
, '.')) == NULL
)
190 onebyte
= strtol(p
, &end
, 10);
191 if (*end
!= '\0' || onebyte
> 255 || onebyte
< 0)
193 ip2
[i
] = (unsigned char)onebyte
;
197 onebyte
= strtol(p
, &end
, 10);
198 if (*end
!= '\0' || onebyte
> 255 || onebyte
< 0)
200 ip2
[3] = (unsigned char)onebyte
;
205 /* Put the mask into 4 bytes. */
206 static int ip_mask(char *mask
, unsigned char *mask2
)
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)
218 mask22
= htonl(0xFFFFFFFF << (32 - bits
));
219 memcpy(mask2
, &mask22
, 4);
222 memcpy(mask2
, &mask22
, 4);
228 /* Set the ip mask and ip address. Callers should check ebt_errormsg[0].
229 * The string pointed to by address can be altered. */
230 void ebt_parse_ip_address(char *address
, uint32_t *addr
, uint32_t *msk
)
235 if ((p
= strrchr(address
, '/')) != NULL
) {
237 if (ip_mask(p
+ 1, (unsigned char *)msk
)) {
238 ebt_print_error("Problem with the IP mask '%s'", p
+ 1);
244 if (undot_ip(address
, (unsigned char *)addr
)) {
245 ebt_print_error("Problem with the IP address '%s'", address
);
248 *addr
= *addr
& *msk
;
252 /* Transform the ip mask into a string ready for output. */
253 char *ebt_mask_to_dotted(uint32_t mask
)
257 uint32_t maskaddr
, bits
;
259 maskaddr
= ntohl(mask
);
261 /* don't print /32 */
262 if (mask
== 0xFFFFFFFFL
) {
268 bits
= 0xFFFFFFFEL
; /* Case 0xFFFFFFFF has just been dealt with */
269 while (--i
>= 0 && maskaddr
!= bits
)
273 sprintf(buf
, "/%d", i
);
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]);
285 /* Most of the following code is derived from iptables */
287 in6addrcpy(struct in6_addr
*dst
, struct in6_addr
*src
)
289 memcpy(dst
, src
, sizeof(struct in6_addr
));
292 int string_to_number_ll(const char *s
, unsigned long long min
,
293 unsigned long long max
, unsigned long long *ret
)
295 unsigned long long number
;
298 /* Handle hex, octal, etc. */
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
)) {
311 int string_to_number_l(const char *s
, unsigned long min
, unsigned long max
,
315 unsigned long long number
;
317 result
= string_to_number_ll(s
, min
, max
, &number
);
318 *ret
= (unsigned long)number
;
323 int string_to_number(const char *s
, unsigned int min
, unsigned int max
,
327 unsigned long number
;
329 result
= string_to_number_l(s
, min
, max
, &number
);
330 *ret
= (unsigned int)number
;
335 static struct in6_addr
*numeric_to_addr(const char *num
)
337 static struct in6_addr ap
;
340 if ((err
=inet_pton(AF_INET6
, num
, &ap
)) == 1)
342 return (struct in6_addr
*)NULL
;
345 static struct in6_addr
*parse_ip6_mask(char *mask
)
347 static struct in6_addr maskaddr
;
348 struct in6_addr
*addrp
;
352 /* no mask at all defaults to 128 bits */
353 memset(&maskaddr
, 0xff, sizeof maskaddr
);
356 if ((addrp
= numeric_to_addr(mask
)) != NULL
)
358 if (string_to_number(mask
, 0, 128, &bits
) == -1)
359 ebt_print_error("Invalid IPv6 Mask '%s' specified", mask
);
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));
368 memset(&maskaddr
, 0, sizeof maskaddr
);
372 /* Set the ipv6 mask and address. Callers should check ebt_errormsg[0].
373 * The string pointed to by address can be altered. */
374 void ebt_parse_ip6_address(char *address
, struct in6_addr
*addr
,
375 struct in6_addr
*msk
)
377 struct in6_addr
*tmp_addr
;
383 strncpy(buf
, address
, sizeof(buf
) - 1);
385 buf
[sizeof(buf
) - 1] = '\0';
386 if ((p
= strrchr(buf
, '/')) != NULL
) {
388 tmp_addr
= parse_ip6_mask(p
+ 1);
390 tmp_addr
= parse_ip6_mask(NULL
);
391 in6addrcpy(msk
, tmp_addr
);
393 /* if a null mask is given, the name is ignored, like in "any/0" */
394 if (!memcmp(msk
, &in6addr_any
, sizeof(in6addr_any
)))
397 if ((err
=inet_pton(AF_INET6
, buf
, addr
)) < 1) {
398 ebt_print_error("Invalid IPv6 Address '%s' specified", buf
);
402 for (i
= 0; i
< 4; i
++)
403 addr
->s6_addr32
[i
] &= msk
->s6_addr32
[i
];
406 /* Transform the ip6 addr into a string ready for output. */
407 char *ebt_ip6_to_numeric(const struct in6_addr
*addrp
)
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
));