blob: 0cd3d518e38b0368dd653aa9a5f9673ccf382888 [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 Schuymer80c82bb2004-01-14 20:06:44 +000047void ebt_print_mac(const char *mac)
48{
49 if (ebt_printstyle_mac == 2) {
50 int j;
51 for (j = 0; j < ETH_ALEN; j++)
52 printf("%02x%s", (unsigned char)mac[j],
53 (j==ETH_ALEN-1) ? "" : ":");
54 } else
55 printf("%s", ether_ntoa((struct ether_addr *) mac));
56}
57
58void ebt_print_mac_and_mask(const char *mac, const char *mask)
59{
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 Schuymer80c82bb2004-01-14 20:06:44 +000094int ebt_get_mac_and_mask(char *from, char *to, char *mask)
95{
96 char *p;
97 int i;
98 struct ether_addr *addr;
99
100 if (strcasecmp(from, "Unicast") == 0) {
101 memcpy(to, mac_type_unicast, ETH_ALEN);
102 memcpy(mask, msk_type_unicast, ETH_ALEN);
103 return 0;
104 }
105 if (strcasecmp(from, "Multicast") == 0) {
106 memcpy(to, mac_type_multicast, ETH_ALEN);
107 memcpy(mask, msk_type_multicast, ETH_ALEN);
108 return 0;
109 }
110 if (strcasecmp(from, "Broadcast") == 0) {
111 memcpy(to, mac_type_broadcast, ETH_ALEN);
112 memcpy(mask, msk_type_broadcast, ETH_ALEN);
113 return 0;
114 }
115 if (strcasecmp(from, "BGA") == 0) {
116 memcpy(to, mac_type_bridge_group, ETH_ALEN);
117 memcpy(mask, msk_type_bridge_group, ETH_ALEN);
118 return 0;
119 }
120 if ( (p = strrchr(from, '/')) != NULL) {
121 *p = '\0';
122 if (!(addr = ether_aton(p + 1)))
123 return -1;
124 memcpy(mask, addr, ETH_ALEN);
125 } else
126 memset(mask, 0xff, ETH_ALEN);
127 if (!(addr = ether_aton(from)))
128 return -1;
129 memcpy(to, addr, ETH_ALEN);
130 for (i = 0; i < ETH_ALEN; i++)
131 to[i] &= mask[i];
132 return 0;
133}
134
Bart De Schuymerff587202005-02-08 20:02:28 +0000135/* 0: default
136 * 1: the inverse '!' of the option has already been specified */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000137int ebt_invert = 0;
Bart De Schuymer55d44132004-02-23 20:55:24 +0000138
139/*
140 * Check if the inverse of the option is specified. This is used
Bart De Schuymerff587202005-02-08 20:02:28 +0000141 * in the parse functions of the extensions and ebtables.c
Bart De Schuymer55d44132004-02-23 20:55:24 +0000142 */
Bart De Schuymerff587202005-02-08 20:02:28 +0000143int _ebt_check_inverse(const char option[], int argc, char **argv)
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000144{
Bart De Schuymer620443a2004-11-14 13:22:29 +0000145 if (!option)
146 return ebt_invert;
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000147 if (strcmp(option, "!") == 0) {
148 if (ebt_invert == 1)
Bart De Schuymerff587202005-02-08 20:02:28 +0000149 ebt_print_error("Double use of '!' not allowed");
150 if (optind >= argc)
151 optarg = NULL;
152 else
153 optarg = argv[optind];
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000154 optind++;
155 ebt_invert = 1;
156 return 1;
157 }
158 return ebt_invert;
159}
160
Bart De Schuymerff587202005-02-08 20:02:28 +0000161/* Make sure the same option wasn't specified twice. This is used
162 * in the parse functions of the extensions and ebtables.c */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000163void ebt_check_option(unsigned int *flags, unsigned int mask)
164{
165 if (*flags & mask)
Bart De Schuymer64182a32004-01-21 20:39:54 +0000166 ebt_print_error("Multiple use of same option not allowed");
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000167 *flags |= mask;
168}
169
Bart De Schuymerff587202005-02-08 20:02:28 +0000170/* Put the ip string into 4 bytes. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000171static int undot_ip(char *ip, unsigned char *ip2)
172{
173 char *p, *q, *end;
174 long int onebyte;
175 int i;
176 char buf[20];
177
178 strncpy(buf, ip, sizeof(buf) - 1);
179
180 p = buf;
181 for (i = 0; i < 3; i++) {
182 if ((q = strchr(p, '.')) == NULL)
183 return -1;
184 *q = '\0';
185 onebyte = strtol(p, &end, 10);
186 if (*end != '\0' || onebyte > 255 || onebyte < 0)
187 return -1;
188 ip2[i] = (unsigned char)onebyte;
189 p = q + 1;
190 }
191
192 onebyte = strtol(p, &end, 10);
193 if (*end != '\0' || onebyte > 255 || onebyte < 0)
194 return -1;
195 ip2[3] = (unsigned char)onebyte;
196
197 return 0;
198}
199
Bart De Schuymerff587202005-02-08 20:02:28 +0000200/* Put the mask into 4 bytes. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000201static int ip_mask(char *mask, unsigned char *mask2)
202{
203 char *end;
204 long int bits;
205 uint32_t mask22;
206
207 if (undot_ip(mask, mask2)) {
208 /* not the /a.b.c.e format, maybe the /x format */
209 bits = strtol(mask, &end, 10);
210 if (*end != '\0' || bits > 32 || bits < 0)
211 return -1;
212 if (bits != 0) {
213 mask22 = htonl(0xFFFFFFFF << (32 - bits));
214 memcpy(mask2, &mask22, 4);
215 } else {
216 mask22 = 0xFFFFFFFF;
217 memcpy(mask2, &mask22, 4);
218 }
219 }
220 return 0;
221}
222
Bart De Schuymerff587202005-02-08 20:02:28 +0000223/* Set the ip mask and ip address. Callers should check ebt_errormsg[0].
224 * The string pointed to by address can be altered. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000225void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
226{
227 char *p;
228
229 /* first the mask */
230 if ((p = strrchr(address, '/')) != NULL) {
231 *p = '\0';
Bart De Schuymerff587202005-02-08 20:02:28 +0000232 if (ip_mask(p + 1, (unsigned char *)msk)) {
233 ebt_print_error("Problem with the IP mask '%s'", p + 1);
234 return;
235 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000236 } else
237 *msk = 0xFFFFFFFF;
238
Bart De Schuymerff587202005-02-08 20:02:28 +0000239 if (undot_ip(address, (unsigned char *)addr)) {
240 ebt_print_error("Problem with the IP address '%s'", address);
241 return;
242 }
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000243 *addr = *addr & *msk;
244}
245
Bart De Schuymerff587202005-02-08 20:02:28 +0000246/* Transform the ip mask into a string ready for output. */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000247char *ebt_mask_to_dotted(uint32_t mask)
248{
249 int i;
250 static char buf[20];
251 uint32_t maskaddr, bits;
252
253 maskaddr = ntohl(mask);
254
255 /* don't print /32 */
256 if (mask == 0xFFFFFFFFL) {
257 *buf = '\0';
258 return buf;
259 }
260
261 i = 32;
Bart De Schuymerff587202005-02-08 20:02:28 +0000262 bits = 0xFFFFFFFEL; /* Case 0xFFFFFFFF has just been dealt with */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000263 while (--i >= 0 && maskaddr != bits)
264 bits <<= 1;
265
266 if (i > 0)
267 sprintf(buf, "/%d", i);
268 else if (!i)
269 *buf = '\0';
270 else
Bart De Schuymerff587202005-02-08 20:02:28 +0000271 /* Mask was not a decent combination of 1's and 0's */
Bart De Schuymer80c82bb2004-01-14 20:06:44 +0000272 sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0],
273 ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2],
274 ((unsigned char *)&mask)[3]);
275
276 return buf;
277}