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 &ap;
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