blob: 4fac896c4dc631672ac40f97cb1e00f6e60bfd8d [file] [log] [blame]
Bart De Schuymerff587202005-02-08 20:02:28 +00001/* ebt_ip
Bart De Schuymer4883ba52002-09-19 21:10:45 +00002 *
Bart De Schuymerff587202005-02-08 20:02:28 +00003 * Authors:
4 * Bart De Schuymer <bdschuym@pandora.be>
Bart De Schuymer4883ba52002-09-19 21:10:45 +00005 *
Bart De Schuymerff587202005-02-08 20:02:28 +00006 * Changes:
Bart De Schuymer4883ba52002-09-19 21:10:45 +00007 * added ip-sport and ip-dport; parsing of port arguments is
8 * based on code from iptables-1.2.7a
9 * Innominate Security Technologies AG <mhopf@innominate.com>
10 * September, 2002
Bart De Schuymer4883ba52002-09-19 21:10:45 +000011 */
12
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000013#include <stdio.h>
14#include <stdlib.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000015#include <string.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000016#include <getopt.h>
Bart De Schuymer4883ba52002-09-19 21:10:45 +000017#include <netdb.h>
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000018#include "../include/ebtables_u.h"
19#include <linux/netfilter_bridge/ebt_ip.h>
20
21#define IP_SOURCE '1'
22#define IP_DEST '2'
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000023#define IP_myTOS '3' /* include/bits/in.h seems to already define IP_TOS */
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000024#define IP_PROTO '4'
Bart De Schuymer4883ba52002-09-19 21:10:45 +000025#define IP_SPORT '5'
26#define IP_DPORT '6'
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000027
28static struct option opts[] =
29{
Bart De Schuymer4883ba52002-09-19 21:10:45 +000030 { "ip-source" , required_argument, 0, IP_SOURCE },
31 { "ip-src" , required_argument, 0, IP_SOURCE },
32 { "ip-destination" , required_argument, 0, IP_DEST },
33 { "ip-dst" , required_argument, 0, IP_DEST },
34 { "ip-tos" , required_argument, 0, IP_myTOS },
35 { "ip-protocol" , required_argument, 0, IP_PROTO },
36 { "ip-proto" , required_argument, 0, IP_PROTO },
37 { "ip-source-port" , required_argument, 0, IP_SPORT },
38 { "ip-sport" , required_argument, 0, IP_SPORT },
39 { "ip-destination-port" , required_argument, 0, IP_DPORT },
40 { "ip-dport" , required_argument, 0, IP_DPORT },
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000041 { 0 }
42};
43
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000044/* put the mask into 4 bytes */
Bart De Schuymer9895a8e2003-01-11 10:14:24 +000045/* transform a protocol and service name into a port number */
Bart De Schuymer4883ba52002-09-19 21:10:45 +000046static uint16_t parse_port(const char *protocol, const char *name)
47{
48 struct servent *service;
49 char *end;
50 int port;
51
52 port = strtol(name, &end, 10);
53 if (*end != '\0') {
54 if (protocol &&
55 (service = getservbyname(name, protocol)) != NULL)
56 return ntohs(service->s_port);
57 }
58 else if (port >= 0 || port <= 0xFFFF) {
59 return port;
60 }
Bart De Schuymer64182a32004-01-21 20:39:54 +000061 ebt_print_error("Problem with specified %s port '%s'",
62 protocol?protocol:"", name);
Bart De Schuymerff587202005-02-08 20:02:28 +000063 return 0;
Bart De Schuymer4883ba52002-09-19 21:10:45 +000064}
65
66static void
67parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
68{
69 char *buffer;
70 char *cp;
71
72 buffer = strdup(portstring);
73 if ((cp = strchr(buffer, ':')) == NULL)
74 ports[0] = ports[1] = parse_port(protocol, buffer);
75 else {
76 *cp = '\0';
77 cp++;
78 ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0;
Bart De Schuymerff587202005-02-08 20:02:28 +000079 if (ebt_errormsg[0] != '\0')
80 return;
Bart De Schuymer4883ba52002-09-19 21:10:45 +000081 ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF;
Bart De Schuymerff587202005-02-08 20:02:28 +000082 if (ebt_errormsg[0] != '\0')
83 return;
Bart De Schuymer4883ba52002-09-19 21:10:45 +000084
85 if (ports[0] > ports[1])
Bart De Schuymer64182a32004-01-21 20:39:54 +000086 ebt_print_error("Invalid portrange (min > max)");
Bart De Schuymer4883ba52002-09-19 21:10:45 +000087 }
88 free(buffer);
89}
90
91static void print_port_range(uint16_t *ports)
92{
93 if (ports[0] == ports[1])
Bart De Schuymer2a9b5882002-10-11 18:29:00 +000094 printf("%d ", ports[0]);
Bart De Schuymer4883ba52002-09-19 21:10:45 +000095 else
Bart De Schuymer2a9b5882002-10-11 18:29:00 +000096 printf("%d:%d ", ports[0], ports[1]);
Bart De Schuymer4883ba52002-09-19 21:10:45 +000097}
98
Bart De Schuymer1abc55d2002-06-01 19:23:47 +000099static void print_help()
100{
101 printf(
102"ip options:\n"
103"--ip-src [!] address[/mask]: ip source specification\n"
104"--ip-dst [!] address[/mask]: ip destination specification\n"
105"--ip-tos [!] tos : ip tos specification\n"
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000106"--ip-proto [!] protocol : ip protocol specification\n"
107"--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
108"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000109}
110
111static void init(struct ebt_entry_match *match)
112{
113 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
114
115 ipinfo->invflags = 0;
116 ipinfo->bitmask = 0;
117}
118
119#define OPT_SOURCE 0x01
120#define OPT_DEST 0x02
121#define OPT_TOS 0x04
122#define OPT_PROTO 0x08
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000123#define OPT_SPORT 0x10
124#define OPT_DPORT 0x20
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000125static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
126 unsigned int *flags, struct ebt_entry_match **match)
127{
128 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)(*match)->data;
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000129 char *end;
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000130 long int i;
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000131
132 switch (c) {
133 case IP_SOURCE:
Bart De Schuymerff587202005-02-08 20:02:28 +0000134 ebt_check_option2(flags, OPT_SOURCE);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000135 ipinfo->bitmask |= EBT_IP_SOURCE;
136
137 case IP_DEST:
138 if (c == IP_DEST) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000139 ebt_check_option2(flags, OPT_DEST);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000140 ipinfo->bitmask |= EBT_IP_DEST;
141 }
Bart De Schuymerff587202005-02-08 20:02:28 +0000142 if (ebt_check_inverse2(optarg)) {
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000143 if (c == IP_SOURCE)
144 ipinfo->invflags |= EBT_IP_SOURCE;
145 else
146 ipinfo->invflags |= EBT_IP_DEST;
147 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000148 if (c == IP_SOURCE)
Bart De Schuymerff587202005-02-08 20:02:28 +0000149 ebt_parse_ip_address(optarg, &ipinfo->saddr, &ipinfo->smsk);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000150 else
Bart De Schuymerff587202005-02-08 20:02:28 +0000151 ebt_parse_ip_address(optarg, &ipinfo->daddr, &ipinfo->dmsk);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000152 break;
153
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000154 case IP_SPORT:
155 case IP_DPORT:
156 if (c == IP_SPORT) {
Bart De Schuymerff587202005-02-08 20:02:28 +0000157 ebt_check_option2(flags, OPT_SPORT);
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000158 ipinfo->bitmask |= EBT_IP_SPORT;
Bart De Schuymerff587202005-02-08 20:02:28 +0000159 if (ebt_check_inverse2(optarg))
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000160 ipinfo->invflags |= EBT_IP_SPORT;
161 } else {
Bart De Schuymerff587202005-02-08 20:02:28 +0000162 ebt_check_option2(flags, OPT_DPORT);
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000163 ipinfo->bitmask |= EBT_IP_DPORT;
Bart De Schuymerff587202005-02-08 20:02:28 +0000164 if (ebt_check_inverse2(optarg))
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000165 ipinfo->invflags |= EBT_IP_DPORT;
166 }
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000167 if (c == IP_SPORT)
Bart De Schuymerff587202005-02-08 20:02:28 +0000168 parse_port_range(NULL, optarg, ipinfo->sport);
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000169 else
Bart De Schuymerff587202005-02-08 20:02:28 +0000170 parse_port_range(NULL, optarg, ipinfo->dport);
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000171 break;
172
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000173 case IP_myTOS:
Bart De Schuymerff587202005-02-08 20:02:28 +0000174 ebt_check_option2(flags, OPT_TOS);
175 if (ebt_check_inverse2(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000176 ipinfo->invflags |= EBT_IP_TOS;
Bart De Schuymerff587202005-02-08 20:02:28 +0000177 i = strtol(optarg, &end, 16);
Bart De Schuymerf8f8f292002-06-25 15:43:57 +0000178 if (i < 0 || i > 255 || *end != '\0')
Bart De Schuymerff587202005-02-08 20:02:28 +0000179 ebt_print_error2("Problem with specified IP tos");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000180 ipinfo->tos = i;
181 ipinfo->bitmask |= EBT_IP_TOS;
182 break;
183
184 case IP_PROTO:
Bart De Schuymerff587202005-02-08 20:02:28 +0000185 ebt_check_option2(flags, OPT_PROTO);
186 if (ebt_check_inverse2(optarg))
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000187 ipinfo->invflags |= EBT_IP_PROTO;
Bart De Schuymerff587202005-02-08 20:02:28 +0000188 i = strtoul(optarg, &end, 10);
fnm3e1b09c32002-12-11 10:52:18 +0000189 if (*end != '\0') {
Bart De Schuymer9895a8e2003-01-11 10:14:24 +0000190 struct protoent *pe;
191
Bart De Schuymerff587202005-02-08 20:02:28 +0000192 pe = getprotobyname(optarg);
fnm3e1b09c32002-12-11 10:52:18 +0000193 if (pe == NULL)
Bart De Schuymerff587202005-02-08 20:02:28 +0000194 ebt_print_error("Unknown specified IP protocol - %s", argv[optind - 1]);
fnm3e1b09c32002-12-11 10:52:18 +0000195 ipinfo->protocol = pe->p_proto;
196 } else {
197 ipinfo->protocol = (unsigned char) i;
198 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000199 ipinfo->bitmask |= EBT_IP_PROTO;
200 break;
201 default:
202 return 0;
203 }
204 return 1;
205}
206
207static void final_check(const struct ebt_u_entry *entry,
Bart De Schuymer7b9aaeb2002-06-23 20:38:34 +0000208 const struct ebt_entry_match *match, const char *name,
Bart De Schuymerc9b52932002-08-24 13:26:34 +0000209 unsigned int hookmask, unsigned int time)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000210{
Bart De Schuymer639bbe92006-01-23 18:08:07 +0000211 struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000212
Bart De Schuymerff587202005-02-08 20:02:28 +0000213 if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO) {
Bart De Schuymer64182a32004-01-21 20:39:54 +0000214 ebt_print_error("For IP filtering the protocol must be "
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000215 "specified as IPv4");
Bart De Schuymerff587202005-02-08 20:02:28 +0000216 } else if (ipinfo->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) &&
Bart De Schuymer639bbe92006-01-23 18:08:07 +0000217 (!(ipinfo->bitmask & EBT_IP_PROTO) ||
Bart De Schuymer82f7f072003-03-01 12:20:49 +0000218 ipinfo->invflags & EBT_IP_PROTO ||
Bart De Schuymer639bbe92006-01-23 18:08:07 +0000219 (ipinfo->protocol!=IPPROTO_TCP &&
220 ipinfo->protocol!=IPPROTO_UDP &&
221 ipinfo->protocol!=IPPROTO_SCTP &&
222 ipinfo->protocol!=IPPROTO_DCCP)))
Bart De Schuymer64182a32004-01-21 20:39:54 +0000223 ebt_print_error("For port filtering the IP protocol must be "
Bart De Schuymer639bbe92006-01-23 18:08:07 +0000224 "either 6 (tcp), 17 (udp), 33 (dccp) or "
225 "132 (sctp)");
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000226}
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 Schuymer8339ff12004-01-14 20:05:27 +0000241 printf("%s ", ebt_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 Schuymer8339ff12004-01-14 20:05:27 +0000250 printf("%s ", ebt_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 Schuymer9895a8e2003-01-11 10:14:24 +0000259 struct protoent *pe;
260
Bart De Schuymer41e8a192002-06-23 08:03:12 +0000261 printf("--ip-proto ");
Bart De Schuymer9cfd6542002-08-13 16:08:08 +0000262 if (ipinfo->invflags & EBT_IP_PROTO)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000263 printf("! ");
fnm3e1b09c32002-12-11 10:52:18 +0000264 pe = getprotobynumber(ipinfo->protocol);
265 if (pe == NULL) {
266 printf("%d ", ipinfo->protocol);
267 } else {
268 printf("%s ", pe->p_name);
269 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000270 }
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000271 if (ipinfo->bitmask & EBT_IP_SPORT) {
272 printf("--ip-sport ");
Bart De Schuymerff587202005-02-08 20:02:28 +0000273 if (ipinfo->invflags & EBT_IP_SPORT)
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000274 printf("! ");
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000275 print_port_range(ipinfo->sport);
276 }
277 if (ipinfo->bitmask & EBT_IP_DPORT) {
278 printf("--ip-dport ");
Bart De Schuymerff587202005-02-08 20:02:28 +0000279 if (ipinfo->invflags & EBT_IP_DPORT)
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000280 printf("! ");
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000281 print_port_range(ipinfo->dport);
282 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000283}
284
285static int compare(const struct ebt_entry_match *m1,
286 const struct ebt_entry_match *m2)
287{
288 struct ebt_ip_info *ipinfo1 = (struct ebt_ip_info *)m1->data;
289 struct ebt_ip_info *ipinfo2 = (struct ebt_ip_info *)m2->data;
290
291 if (ipinfo1->bitmask != ipinfo2->bitmask)
292 return 0;
293 if (ipinfo1->invflags != ipinfo2->invflags)
294 return 0;
295 if (ipinfo1->bitmask & EBT_IP_SOURCE) {
296 if (ipinfo1->saddr != ipinfo2->saddr)
297 return 0;
298 if (ipinfo1->smsk != ipinfo2->smsk)
299 return 0;
300 }
301 if (ipinfo1->bitmask & EBT_IP_DEST) {
302 if (ipinfo1->daddr != ipinfo2->daddr)
303 return 0;
304 if (ipinfo1->dmsk != ipinfo2->dmsk)
305 return 0;
306 }
307 if (ipinfo1->bitmask & EBT_IP_TOS) {
308 if (ipinfo1->tos != ipinfo2->tos)
309 return 0;
310 }
311 if (ipinfo1->bitmask & EBT_IP_PROTO) {
312 if (ipinfo1->protocol != ipinfo2->protocol)
313 return 0;
314 }
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000315 if (ipinfo1->bitmask & EBT_IP_SPORT) {
Bart De Schuymerfd529b72003-04-01 06:31:46 +0000316 if (ipinfo1->sport[0] != ipinfo2->sport[0] ||
317 ipinfo1->sport[1] != ipinfo2->sport[1])
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000318 return 0;
319 }
320 if (ipinfo1->bitmask & EBT_IP_DPORT) {
Bart De Schuymerfd529b72003-04-01 06:31:46 +0000321 if (ipinfo1->dport[0] != ipinfo2->dport[0] ||
322 ipinfo1->dport[1] != ipinfo2->dport[1])
Bart De Schuymer4883ba52002-09-19 21:10:45 +0000323 return 0;
324 }
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000325 return 1;
326}
327
328static struct ebt_u_match ip_match =
329{
Bart De Schuymer7cf1cca2003-08-30 16:20:19 +0000330 .name = EBT_IP_MATCH,
331 .size = sizeof(struct ebt_ip_info),
332 .help = print_help,
333 .init = init,
334 .parse = parse,
335 .final_check = final_check,
336 .print = print,
337 .compare = compare,
338 .extra_ops = opts,
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000339};
340
Bart De Schuymer64182a32004-01-21 20:39:54 +0000341void _init(void)
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000342{
Bart De Schuymer8339ff12004-01-14 20:05:27 +0000343 ebt_register_match(&ip_match);
Bart De Schuymer1abc55d2002-06-01 19:23:47 +0000344}