blob: ddd9944c29d295411f106c327716fab20e235bc2 [file] [log] [blame]
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00001#include <stdio.h>
2#include <stdlib.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00003#include <string.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +00004#include <getopt.h>
5#include "../include/ebtables_u.h"
6#include <linux/netfilter_bridge/ebt_ip.h>
7
8#define IP_SOURCE '1'
9#define IP_DEST '2'
10#define IP_myTOS '3' // include/bits/in.h seems to already define IP_TOS
11#define IP_PROTO '4'
12
13static struct option opts[] =
14{
15 { "ip-source" , required_argument, 0, IP_SOURCE },
16 { "ip-src" , required_argument, 0, IP_SOURCE },
17 { "ip-destination", required_argument, 0, IP_DEST },
18 { "ip-dst" , required_argument, 0, IP_DEST },
19 { "ip-tos" , required_argument, 0, IP_myTOS },
20 { "ip-protocol" , required_argument, 0, IP_PROTO },
21 { "ip-proto" , required_argument, 0, IP_PROTO },
22 { 0 }
23};
24
25// put the ip string into 4 bytes
26static int undot_ip(char *ip, unsigned char *ip2)
27{
28 char *p, *q, *end;
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000029 long int onebyte;
30 int i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000031 char buf[20];
32
33 strncpy(buf, ip, sizeof(buf) - 1);
34
35 p = buf;
36 for (i = 0; i < 3; i++) {
37 if ((q = strchr(p, '.')) == NULL)
38 return -1;
39 *q = '\0';
40 onebyte = strtol(p, &end, 10);
41 if (*end != '\0' || onebyte > 255 || onebyte < 0)
42 return -1;
43 ip2[i] = (unsigned char)onebyte;
44 p = q + 1;
45 }
46
47 onebyte = strtol(p, &end, 10);
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000048 if (*end != '\0' || onebyte > 255 || onebyte < 0)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000049 return -1;
50 ip2[3] = (unsigned char)onebyte;
51
52 return 0;
53}
54
55// put the mask into 4 bytes
56static int ip_mask(char *mask, unsigned char *mask2)
57{
58 char *end;
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000059 long int bits;
60 uint32_t mask22;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000061
62 if (undot_ip(mask, mask2)) {
63 // not the /a.b.c.e format, maybe the /x format
64 bits = strtol(mask, &end, 10);
65 if (*end != '\0' || bits > 32 || bits < 0)
66 return -1;
67 if (bits != 0) {
68 mask22 = htonl(0xFFFFFFFF << (32 - bits));
69 memcpy(mask2, &mask22, 4);
70 } else {
71 mask22 = 0xFFFFFFFF;
72 memcpy(mask2, &mask22, 4);
73 }
74 }
75 return 0;
76}
77
78// set the ip mask and ip address
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000079void parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000080{
81 char *p;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000082
83 // first the mask
84 if ((p = strrchr(address, '/')) != NULL) {
85 *p = '\0';
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000086 if (ip_mask(p + 1, (unsigned char *)msk))
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +000087 print_error("Problem with the IP mask");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000088 }
89 else
90 *msk = 0xFFFFFFFF;
91
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000092 if (undot_ip(address, (unsigned char *)addr))
Bart De Schuymer23f6dcf2002-08-17 09:14:07 +000093 print_error("Problem with the IP address");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000094 *addr = *addr & *msk;
95}
96
97// transform the ip mask into a string ready for output
Bart De Schuymer9cfd6542002-08-13 16:08:08 +000098char *mask_to_dotted(uint32_t mask)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000099{
100 int i;
101 static char buf[20];
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000102 uint32_t maskaddr, bits;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000103
104 maskaddr = ntohl(mask);
105
106 // don't print /32
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000107 if (mask == 0xFFFFFFFFL) {
108 *buf = '\0';
109 return buf;
110 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000111
112 i = 32;
113 bits = 0xFFFFFFFEL; // case 0xFFFFFFFF has just been dealt with
114 while (--i >= 0 && maskaddr != bits)
115 bits <<= 1;
116
117 if (i > 0)
118 sprintf(buf, "/%d", i);
119 else if (!i)
120 *buf = '\0';
121 else
122 // mask was not a decent combination of 1's and 0's
123 sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0],
124 ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2],
125 ((unsigned char *)&mask)[3]);
126
127 return buf;
128}
129
130static void print_help()
131{
132 printf(
133"ip options:\n"
134"--ip-src [!] address[/mask]: ip source specification\n"
135"--ip-dst [!] address[/mask]: ip destination specification\n"
136"--ip-tos [!] tos : ip tos specification\n"
137"--ip-proto [!] protocol : ip protocol specification\n");
138}
139
140static void init(struct ebt_entry_match *match)
141{
142 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
143
144 ipinfo->invflags = 0;
145 ipinfo->bitmask = 0;
146}
147
148#define OPT_SOURCE 0x01
149#define OPT_DEST 0x02
150#define OPT_TOS 0x04
151#define OPT_PROTO 0x08
152static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
153 unsigned int *flags, struct ebt_entry_match **match)
154{
155 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)(*match)->data;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000156 char *end;
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000157 long int i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000158
159 switch (c) {
160 case IP_SOURCE:
161 check_option(flags, OPT_SOURCE);
162 ipinfo->bitmask |= EBT_IP_SOURCE;
163
164 case IP_DEST:
165 if (c == IP_DEST) {
166 check_option(flags, OPT_DEST);
167 ipinfo->bitmask |= EBT_IP_DEST;
168 }
169 if (check_inverse(optarg)) {
170 if (c == IP_SOURCE)
171 ipinfo->invflags |= EBT_IP_SOURCE;
172 else
173 ipinfo->invflags |= EBT_IP_DEST;
174 }
175
176 if (optind > argc)
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000177 print_error("Missing IP address argument");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000178 if (c == IP_SOURCE)
179 parse_ip_address(argv[optind - 1], &ipinfo->saddr,
180 &ipinfo->smsk);
181 else
182 parse_ip_address(argv[optind - 1], &ipinfo->daddr,
183 &ipinfo->dmsk);
184 break;
185
186 case IP_myTOS:
187 check_option(flags, OPT_TOS);
188 if (check_inverse(optarg))
189 ipinfo->invflags |= EBT_IP_TOS;
190
191 if (optind > argc)
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000192 print_error("Missing IP tos argument");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000193 i = strtol(argv[optind - 1], &end, 16);
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000194 if (i < 0 || i > 255 || *end != '\0')
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000195 print_error("Problem with specified IP tos");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000196 ipinfo->tos = i;
197 ipinfo->bitmask |= EBT_IP_TOS;
198 break;
199
200 case IP_PROTO:
201 check_option(flags, OPT_PROTO);
202 if (check_inverse(optarg))
203 ipinfo->invflags |= EBT_IP_PROTO;
204 if (optind > argc)
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000205 print_error("Missing IP protocol argument");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000206 i = strtol(argv[optind - 1], &end, 10);
207 if (i < 0 || i > 255 || *end != '\0')
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000208 print_error("Problem with specified IP protocol");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000209 ipinfo->protocol = i;
210 ipinfo->bitmask |= EBT_IP_PROTO;
211 break;
212 default:
213 return 0;
214 }
215 return 1;
216}
217
218static void final_check(const struct ebt_u_entry *entry,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +0000219 const struct ebt_entry_match *match, const char *name,
220 unsigned int hook_mask, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000221{
222 if (entry->bitmask & EBT_NOPROTO || entry->bitmask & EBT_802_3 ||
Bart De Schuymerb2632c52002-08-09 18:57:05 +0000223 entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000224 print_error("For IP filtering the protocol must be "
225 "specified as IPv4");
226}
227
228static void print(const struct ebt_u_entry *entry,
229 const struct ebt_entry_match *match)
230{
231 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
232 int j;
233
234 if (ipinfo->bitmask & EBT_IP_SOURCE) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000235 printf("--ip-src ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000236 if (ipinfo->invflags & EBT_IP_SOURCE)
237 printf("! ");
238 for (j = 0; j < 4; j++)
239 printf("%d%s",((unsigned char *)&ipinfo->saddr)[j],
240 (j == 3) ? "" : ".");
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000241 printf("%s ", mask_to_dotted(ipinfo->smsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000242 }
243 if (ipinfo->bitmask & EBT_IP_DEST) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000244 printf("--ip-dst ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000245 if (ipinfo->invflags & EBT_IP_DEST)
246 printf("! ");
247 for (j = 0; j < 4; j++)
248 printf("%d%s", ((unsigned char *)&ipinfo->daddr)[j],
249 (j == 3) ? "" : ".");
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000250 printf("%s ", mask_to_dotted(ipinfo->dmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000251 }
252 if (ipinfo->bitmask & EBT_IP_TOS) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000253 printf("--ip-tos ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000254 if (ipinfo->invflags & EBT_IP_TOS)
255 printf("! ");
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000256 printf("0x%02X ", ipinfo->tos);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000257 }
258 if (ipinfo->bitmask & EBT_IP_PROTO) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000259 printf("--ip-proto ");
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000260 if (ipinfo->invflags & EBT_IP_PROTO)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000261 printf("! ");
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000262 printf("%d ", ipinfo->protocol);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000263 }
264}
265
266static int compare(const struct ebt_entry_match *m1,
267 const struct ebt_entry_match *m2)
268{
269 struct ebt_ip_info *ipinfo1 = (struct ebt_ip_info *)m1->data;
270 struct ebt_ip_info *ipinfo2 = (struct ebt_ip_info *)m2->data;
271
272 if (ipinfo1->bitmask != ipinfo2->bitmask)
273 return 0;
274 if (ipinfo1->invflags != ipinfo2->invflags)
275 return 0;
276 if (ipinfo1->bitmask & EBT_IP_SOURCE) {
277 if (ipinfo1->saddr != ipinfo2->saddr)
278 return 0;
279 if (ipinfo1->smsk != ipinfo2->smsk)
280 return 0;
281 }
282 if (ipinfo1->bitmask & EBT_IP_DEST) {
283 if (ipinfo1->daddr != ipinfo2->daddr)
284 return 0;
285 if (ipinfo1->dmsk != ipinfo2->dmsk)
286 return 0;
287 }
288 if (ipinfo1->bitmask & EBT_IP_TOS) {
289 if (ipinfo1->tos != ipinfo2->tos)
290 return 0;
291 }
292 if (ipinfo1->bitmask & EBT_IP_PROTO) {
293 if (ipinfo1->protocol != ipinfo2->protocol)
294 return 0;
295 }
296 return 1;
297}
298
299static struct ebt_u_match ip_match =
300{
301 EBT_IP_MATCH,
302 sizeof(struct ebt_ip_info),
303 print_help,
304 init,
305 parse,
306 final_check,
307 print,
308 compare,
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000309 opts
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000310};
311
312static void _init(void) __attribute((constructor));
313static void _init(void)
314{
315 register_match(&ip_match);
316}