• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/ebtables/extensions/
1/* ebt_ip
2 *
3 * Authors:
4 * Bart De Schuymer <bdschuym@pandora.be>
5 *
6 * Changes:
7 *    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
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <getopt.h>
17#include <netdb.h>
18#include "../include/ebtables_u.h"
19#include <linux/netfilter_bridge/ebt_ip.h>
20
21#define IP_SOURCE '1'
22#define IP_DEST   '2'
23#define IP_myTOS  '3' /* include/bits/in.h seems to already define IP_TOS */
24#define IP_PROTO  '4'
25#define IP_SPORT  '5'
26#define IP_DPORT  '6'
27
28static struct option opts[] =
29{
30	{ "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  },
41	{ 0 }
42};
43
44/* put the mask into 4 bytes */
45/* transform a protocol and service name into a port number */
46static 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	}
61	ebt_print_error("Problem with specified %s port '%s'",
62			protocol?protocol:"", name);
63	return 0;
64}
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;
79		if (ebt_errormsg[0] != '\0')
80			return;
81		ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF;
82		if (ebt_errormsg[0] != '\0')
83			return;
84
85		if (ports[0] > ports[1])
86			ebt_print_error("Invalid portrange (min > max)");
87	}
88	free(buffer);
89}
90
91static void print_port_range(uint16_t *ports)
92{
93	if (ports[0] == ports[1])
94		printf("%d ", ports[0]);
95	else
96		printf("%d:%d ", ports[0], ports[1]);
97}
98
99static 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"
106"--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");
109}
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
123#define OPT_SPORT  0x10
124#define OPT_DPORT  0x20
125static 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;
129	char *end;
130	long int i;
131
132	switch (c) {
133	case IP_SOURCE:
134		ebt_check_option2(flags, OPT_SOURCE);
135		ipinfo->bitmask |= EBT_IP_SOURCE;
136
137	case IP_DEST:
138		if (c == IP_DEST) {
139			ebt_check_option2(flags, OPT_DEST);
140			ipinfo->bitmask |= EBT_IP_DEST;
141		}
142		if (ebt_check_inverse2(optarg)) {
143			if (c == IP_SOURCE)
144				ipinfo->invflags |= EBT_IP_SOURCE;
145			else
146				ipinfo->invflags |= EBT_IP_DEST;
147		}
148		if (c == IP_SOURCE)
149			ebt_parse_ip_address(optarg, &ipinfo->saddr, &ipinfo->smsk);
150		else
151			ebt_parse_ip_address(optarg, &ipinfo->daddr, &ipinfo->dmsk);
152		break;
153
154	case IP_SPORT:
155	case IP_DPORT:
156		if (c == IP_SPORT) {
157			ebt_check_option2(flags, OPT_SPORT);
158			ipinfo->bitmask |= EBT_IP_SPORT;
159			if (ebt_check_inverse2(optarg))
160				ipinfo->invflags |= EBT_IP_SPORT;
161		} else {
162			ebt_check_option2(flags, OPT_DPORT);
163			ipinfo->bitmask |= EBT_IP_DPORT;
164			if (ebt_check_inverse2(optarg))
165				ipinfo->invflags |= EBT_IP_DPORT;
166		}
167		if (c == IP_SPORT)
168			parse_port_range(NULL, optarg, ipinfo->sport);
169		else
170			parse_port_range(NULL, optarg, ipinfo->dport);
171		break;
172
173	case IP_myTOS:
174		ebt_check_option2(flags, OPT_TOS);
175		if (ebt_check_inverse2(optarg))
176			ipinfo->invflags |= EBT_IP_TOS;
177		i = strtol(optarg, &end, 16);
178		if (i < 0 || i > 255 || *end != '\0')
179			ebt_print_error2("Problem with specified IP tos");
180		ipinfo->tos = i;
181		ipinfo->bitmask |= EBT_IP_TOS;
182		break;
183
184	case IP_PROTO:
185		ebt_check_option2(flags, OPT_PROTO);
186		if (ebt_check_inverse2(optarg))
187			ipinfo->invflags |= EBT_IP_PROTO;
188		i = strtoul(optarg, &end, 10);
189		if (*end != '\0') {
190			struct protoent *pe;
191
192			pe = getprotobyname(optarg);
193			if (pe == NULL)
194				ebt_print_error("Unknown specified IP protocol - %s", argv[optind - 1]);
195			ipinfo->protocol = pe->p_proto;
196		} else {
197			ipinfo->protocol = (unsigned char) i;
198		}
199		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,
208   const struct ebt_entry_match *match, const char *name,
209   unsigned int hookmask, unsigned int time)
210{
211	struct ebt_ip_info *ipinfo = (struct ebt_ip_info *)match->data;
212
213	if (entry->ethproto != ETH_P_IP || entry->invflags & EBT_IPROTO) {
214		ebt_print_error("For IP filtering the protocol must be "
215		            "specified as IPv4");
216	} else if (ipinfo->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT) &&
217		(!(ipinfo->bitmask & EBT_IP_PROTO) ||
218		ipinfo->invflags & EBT_IP_PROTO ||
219		(ipinfo->protocol!=IPPROTO_TCP &&
220		 ipinfo->protocol!=IPPROTO_UDP &&
221		 ipinfo->protocol!=IPPROTO_SCTP &&
222		 ipinfo->protocol!=IPPROTO_DCCP)))
223		ebt_print_error("For port filtering the IP protocol must be "
224				"either 6 (tcp), 17 (udp), 33 (dccp) or "
225				"132 (sctp)");
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) {
235		printf("--ip-src ");
236		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) ? "" : ".");
241		printf("%s ", ebt_mask_to_dotted(ipinfo->smsk));
242	}
243	if (ipinfo->bitmask & EBT_IP_DEST) {
244		printf("--ip-dst ");
245		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) ? "" : ".");
250		printf("%s ", ebt_mask_to_dotted(ipinfo->dmsk));
251	}
252	if (ipinfo->bitmask & EBT_IP_TOS) {
253		printf("--ip-tos ");
254		if (ipinfo->invflags & EBT_IP_TOS)
255			printf("! ");
256		printf("0x%02X ", ipinfo->tos);
257	}
258	if (ipinfo->bitmask & EBT_IP_PROTO) {
259		struct protoent *pe;
260
261		printf("--ip-proto ");
262		if (ipinfo->invflags & EBT_IP_PROTO)
263			printf("! ");
264		pe = getprotobynumber(ipinfo->protocol);
265		if (pe == NULL) {
266			printf("%d ", ipinfo->protocol);
267		} else {
268			printf("%s ", pe->p_name);
269		}
270	}
271	if (ipinfo->bitmask & EBT_IP_SPORT) {
272		printf("--ip-sport ");
273		if (ipinfo->invflags & EBT_IP_SPORT)
274			printf("! ");
275		print_port_range(ipinfo->sport);
276	}
277	if (ipinfo->bitmask & EBT_IP_DPORT) {
278		printf("--ip-dport ");
279		if (ipinfo->invflags & EBT_IP_DPORT)
280			printf("! ");
281		print_port_range(ipinfo->dport);
282	}
283}
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	}
315	if (ipinfo1->bitmask & EBT_IP_SPORT) {
316		if (ipinfo1->sport[0] != ipinfo2->sport[0] ||
317		   ipinfo1->sport[1] != ipinfo2->sport[1])
318			return 0;
319	}
320	if (ipinfo1->bitmask & EBT_IP_DPORT) {
321		if (ipinfo1->dport[0] != ipinfo2->dport[0] ||
322		   ipinfo1->dport[1] != ipinfo2->dport[1])
323			return 0;
324	}
325	return 1;
326}
327
328static struct ebt_u_match ip_match =
329{
330	.name		= "ip",
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,
339};
340
341void _init(void)
342{
343	ebt_register_match(&ip_match);
344}
345