blob: f93b8b97d325e59f1c7df416669277bcf1ed529c [file] [log] [blame]
Bart De Schuymer4883ba52002-09-19 21:10:45 +00001/*
2 * ebtables ebt_ip: IP extension module for userspace
3 *
4 * Authors:
Bart De Schuymer9895a8e2003-01-11 10:14:24 +00005 * Bart De Schuymer <bdschuym@pandora.be>
Bart De Schuymer4883ba52002-09-19 21:10:45 +00006 *
7 * Changes:
8 * added ip-sport and ip-dport; parsing of port arguments is
9 * based on code from iptables-1.2.7a
10 * Innominate Security Technologies AG <mhopf@innominate.com>
11 * September, 2002
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 *
27 */
28
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000029#include <stdio.h>
30#include <stdlib.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000031#include <string.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000032#include <getopt.h>
Bart De Schuymer4883ba52002-09-19 21:10:45 +000033#include <netdb.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000034#include "../include/ebtables_u.h"
35#include <linux/netfilter_bridge/ebt_ip.h>
36
37#define IP_SOURCE '1'
38#define IP_DEST '2'
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000039#define IP_myTOS '3' /* include/bits/in.h seems to already define IP_TOS */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000040#define IP_PROTO '4'
Bart De Schuymer4883ba52002-09-19 21:10:45 +000041#define IP_SPORT '5'
42#define IP_DPORT '6'
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000043
44static struct option opts[] =
45{
Bart De Schuymer4883ba52002-09-19 21:10:45 +000046 { "ip-source" , required_argument, 0, IP_SOURCE },
47 { "ip-src" , required_argument, 0, IP_SOURCE },
48 { "ip-destination" , required_argument, 0, IP_DEST },
49 { "ip-dst" , required_argument, 0, IP_DEST },
50 { "ip-tos" , required_argument, 0, IP_myTOS },
51 { "ip-protocol" , required_argument, 0, IP_PROTO },
52 { "ip-proto" , required_argument, 0, IP_PROTO },
53 { "ip-source-port" , required_argument, 0, IP_SPORT },
54 { "ip-sport" , required_argument, 0, IP_SPORT },
55 { "ip-destination-port" , required_argument, 0, IP_DPORT },
56 { "ip-dport" , required_argument, 0, IP_DPORT },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000057 { 0 }
58};
59
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000060/* put the mask into 4 bytes */
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000061/* transform a protocol and service name into a port number */
Bart De Schuymer4883ba52002-09-19 21:10:45 +000062static uint16_t parse_port(const char *protocol, const char *name)
63{
64 struct servent *service;
65 char *end;
66 int port;
67
68 port = strtol(name, &end, 10);
69 if (*end != '\0') {
70 if (protocol &&
71 (service = getservbyname(name, protocol)) != NULL)
72 return ntohs(service->s_port);
73 }
74 else if (port >= 0 || port <= 0xFFFF) {
75 return port;
76 }
77 print_error("Problem with specified %s port '%s'",
78 protocol?protocol:"", name);
79 return 0; /* never reached */
80}
81
82static void
83parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
84{
85 char *buffer;
86 char *cp;
87
88 buffer = strdup(portstring);
89 if ((cp = strchr(buffer, ':')) == NULL)
90 ports[0] = ports[1] = parse_port(protocol, buffer);
91 else {
92 *cp = '\0';
93 cp++;
94 ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0;
95 ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF;
96
97 if (ports[0] > ports[1])
98 print_error("Invalid portrange (min > max)");
99 }
100 free(buffer);
101}
102
103static void print_port_range(uint16_t *ports)
104{
105 if (ports[0] == ports[1])
Bart De Schuymer2a9b5882002-10-11 18:29:00 +0000106 printf("%d ", ports[0]);
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000107 else
Bart De Schuymer2a9b5882002-10-11 18:29:00 +0000108 printf("%d:%d ", ports[0], ports[1]);
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000109}
110
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000111static void print_help()
112{
113 printf(
114"ip options:\n"
115"--ip-src [!] address[/mask]: ip source specification\n"
116"--ip-dst [!] address[/mask]: ip destination specification\n"
117"--ip-tos [!] tos : ip tos specification\n"
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000118"--ip-proto [!] protocol : ip protocol specification\n"
119"--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
120"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000121}
122
123static void init(struct ebt_entry_match *match)
124{
125 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
126
127 ipinfo->invflags = 0;
128 ipinfo->bitmask = 0;
129}
130
131#define OPT_SOURCE 0x01
132#define OPT_DEST 0x02
133#define OPT_TOS 0x04
134#define OPT_PROTO 0x08
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000135#define OPT_SPORT 0x10
136#define OPT_DPORT 0x20
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000137static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
138 unsigned int *flags, struct ebt_entry_match **match)
139{
140 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)(*match)->data;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000141 char *end;
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000142 long int i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000143
144 switch (c) {
145 case IP_SOURCE:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000146 ebt_check_option(flags, OPT_SOURCE);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000147 ipinfo->bitmask |= EBT_IP_SOURCE;
148
149 case IP_DEST:
150 if (c == IP_DEST) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000151 ebt_check_option(flags, OPT_DEST);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000152 ipinfo->bitmask |= EBT_IP_DEST;
153 }
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000154 if (ebt_check_inverse(optarg)) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000155 if (c == IP_SOURCE)
156 ipinfo->invflags |= EBT_IP_SOURCE;
157 else
158 ipinfo->invflags |= EBT_IP_DEST;
159 }
160
161 if (optind > argc)
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000162 print_error("Missing IP address argument");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000163 if (c == IP_SOURCE)
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000164 ebt_parse_ip_address(argv[optind - 1], &ipinfo->saddr,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000165 &ipinfo->smsk);
166 else
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000167 ebt_parse_ip_address(argv[optind - 1], &ipinfo->daddr,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000168 &ipinfo->dmsk);
169 break;
170
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000171 case IP_SPORT:
172 case IP_DPORT:
173 if (c == IP_SPORT) {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000174 ebt_check_option(flags, OPT_SPORT);
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000175 ipinfo->bitmask |= EBT_IP_SPORT;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000176 if (ebt_check_inverse(optarg))
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000177 ipinfo->invflags |= EBT_IP_SPORT;
178 } else {
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000179 ebt_check_option(flags, OPT_DPORT);
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000180 ipinfo->bitmask |= EBT_IP_DPORT;
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000181 if (ebt_check_inverse(optarg))
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000182 ipinfo->invflags |= EBT_IP_DPORT;
183 }
184 if (optind > argc)
185 print_error("Missing port argument");
186 if (c == IP_SPORT)
187 parse_port_range(NULL, argv[optind - 1], ipinfo->sport);
188 else
189 parse_port_range(NULL, argv[optind - 1], ipinfo->dport);
190 break;
191
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000192 case IP_myTOS:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000193 ebt_check_option(flags, OPT_TOS);
194 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000195 ipinfo->invflags |= EBT_IP_TOS;
196
197 if (optind > argc)
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000198 print_error("Missing IP tos argument");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000199 i = strtol(argv[optind - 1], &end, 16);
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000200 if (i < 0 || i > 255 || *end != '\0')
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000201 print_error("Problem with specified IP tos");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000202 ipinfo->tos = i;
203 ipinfo->bitmask |= EBT_IP_TOS;
204 break;
205
206 case IP_PROTO:
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000207 ebt_check_option(flags, OPT_PROTO);
208 if (ebt_check_inverse(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000209 ipinfo->invflags |= EBT_IP_PROTO;
210 if (optind > argc)
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000211 print_error("Missing IP protocol argument");
fnm3e1b09c32002-12-11 10:52:18 +0000212 (unsigned char) i = strtoul(argv[optind - 1], &end, 10);
213 if (*end != '\0') {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000214 struct protoent *pe;
215
fnm3e1b09c32002-12-11 10:52:18 +0000216 pe = getprotobyname(argv[optind - 1]);
217 if (pe == NULL)
218 print_error
219 ("Unknown specified IP protocol - %s",
220 argv[optind - 1]);
221 ipinfo->protocol = pe->p_proto;
222 } else {
223 ipinfo->protocol = (unsigned char) i;
224 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000225 ipinfo->bitmask |= EBT_IP_PROTO;
226 break;
227 default:
228 return 0;
229 }
230 return 1;
231}
232
233static void final_check(const struct ebt_u_entry *entry,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +0000234 const struct ebt_entry_match *match, const char *name,
Bart De Schuymerc9b52932002-08-24 13:26:34 +0000235 unsigned int hookmask, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000236{
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000237 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
238
Bart De Schuymer40573192002-08-29 16:48:36 +0000239 if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000240 print_error("For IP filtering the protocol must be "
241 "specified as IPv4");
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000242
Bart De Schuymer82f7f072003-03-01 12:20:49 +0000243 if (ipinfo->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) &&
244 (!(ipinfo->bitmask & EBT_IP_PROTO) ||
245 ipinfo->invflags & EBT_IP_PROTO ||
246 (ipinfo->protocol!=IPPROTO_TCP &&
247 ipinfo->protocol!=IPPROTO_UDP)))
248 print_error("For port filtering the IP protocol must be "
249 "either 6 (tcp) or 17 (udp)");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000250}
251
252static void print(const struct ebt_u_entry *entry,
253 const struct ebt_entry_match *match)
254{
255 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
256 int j;
257
258 if (ipinfo->bitmask & EBT_IP_SOURCE) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000259 printf("--ip-src ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000260 if (ipinfo->invflags & EBT_IP_SOURCE)
261 printf("! ");
262 for (j = 0; j < 4; j++)
263 printf("%d%s",((unsigned char *)&ipinfo->saddr)[j],
264 (j == 3) ? "" : ".");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000265 printf("%s ", ebt_mask_to_dotted(ipinfo->smsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000266 }
267 if (ipinfo->bitmask & EBT_IP_DEST) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000268 printf("--ip-dst ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000269 if (ipinfo->invflags & EBT_IP_DEST)
270 printf("! ");
271 for (j = 0; j < 4; j++)
272 printf("%d%s", ((unsigned char *)&ipinfo->daddr)[j],
273 (j == 3) ? "" : ".");
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000274 printf("%s ", ebt_mask_to_dotted(ipinfo->dmsk));
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000275 }
276 if (ipinfo->bitmask & EBT_IP_TOS) {
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000277 printf("--ip-tos ");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000278 if (ipinfo->invflags & EBT_IP_TOS)
279 printf("! ");
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000280 printf("0x%02X ", ipinfo->tos);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000281 }
282 if (ipinfo->bitmask & EBT_IP_PROTO) {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000283 struct protoent *pe;
284
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000285 printf("--ip-proto ");
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000286 if (ipinfo->invflags & EBT_IP_PROTO)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000287 printf("! ");
fnm3e1b09c32002-12-11 10:52:18 +0000288 pe = getprotobynumber(ipinfo->protocol);
289 if (pe == NULL) {
290 printf("%d ", ipinfo->protocol);
291 } else {
292 printf("%s ", pe->p_name);
293 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000294 }
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000295 if (ipinfo->bitmask & EBT_IP_SPORT) {
296 printf("--ip-sport ");
297 if (ipinfo->invflags & EBT_IP_SPORT) {
298 printf("! ");
299 }
300 print_port_range(ipinfo->sport);
301 }
302 if (ipinfo->bitmask & EBT_IP_DPORT) {
303 printf("--ip-dport ");
304 if (ipinfo->invflags & EBT_IP_DPORT) {
305 printf("! ");
306 }
307 print_port_range(ipinfo->dport);
308 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000309}
310
311static int compare(const struct ebt_entry_match *m1,
312 const struct ebt_entry_match *m2)
313{
314 struct ebt_ip_info *ipinfo1 = (struct ebt_ip_info *)m1->data;
315 struct ebt_ip_info *ipinfo2 = (struct ebt_ip_info *)m2->data;
316
317 if (ipinfo1->bitmask != ipinfo2->bitmask)
318 return 0;
319 if (ipinfo1->invflags != ipinfo2->invflags)
320 return 0;
321 if (ipinfo1->bitmask & EBT_IP_SOURCE) {
322 if (ipinfo1->saddr != ipinfo2->saddr)
323 return 0;
324 if (ipinfo1->smsk != ipinfo2->smsk)
325 return 0;
326 }
327 if (ipinfo1->bitmask & EBT_IP_DEST) {
328 if (ipinfo1->daddr != ipinfo2->daddr)
329 return 0;
330 if (ipinfo1->dmsk != ipinfo2->dmsk)
331 return 0;
332 }
333 if (ipinfo1->bitmask & EBT_IP_TOS) {
334 if (ipinfo1->tos != ipinfo2->tos)
335 return 0;
336 }
337 if (ipinfo1->bitmask & EBT_IP_PROTO) {
338 if (ipinfo1->protocol != ipinfo2->protocol)
339 return 0;
340 }
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000341 if (ipinfo1->bitmask & EBT_IP_SPORT) {
Bart De Schuymerfd529b72003-04-01 06:31:46 +0000342 if (ipinfo1->sport[0] != ipinfo2->sport[0] ||
343 ipinfo1->sport[1] != ipinfo2->sport[1])
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000344 return 0;
345 }
346 if (ipinfo1->bitmask & EBT_IP_DPORT) {
Bart De Schuymerfd529b72003-04-01 06:31:46 +0000347 if (ipinfo1->dport[0] != ipinfo2->dport[0] ||
348 ipinfo1->dport[1] != ipinfo2->dport[1])
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000349 return 0;
350 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000351 return 1;
352}
353
354static struct ebt_u_match ip_match =
355{
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000356 .name = EBT_IP_MATCH,
357 .size = sizeof(struct ebt_ip_info),
358 .help = print_help,
359 .init = init,
360 .parse = parse,
361 .final_check = final_check,
362 .print = print,
363 .compare = compare,
364 .extra_ops = opts,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000365};
366
367static void _init(void) __attribute((constructor));
368static void _init(void)
369{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000370 ebt_register_match(&ip_match);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000371}