libxt_udp.c revision 8b7c64d6ba156a99008fcd810cba874c73294333
1/* Shared library add-on to iptables to add UDP support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <xtables.h>
8#include <linux/netfilter/xt_tcpudp.h>
9
10/* Function which prints out usage message. */
11static void udp_help(void)
12{
13	printf(
14"udp match options:\n"
15" --source-port [!] port[:port]\n"
16" --sport ...\n"
17"				match source port(s)\n"
18" --destination-port [!] port[:port]\n"
19" --dport ...\n"
20"				match destination port(s)\n");
21}
22
23static const struct option udp_opts[] = {
24	{ "source-port", 1, NULL, '1' },
25	{ "sport", 1, NULL, '1' }, /* synonym */
26	{ "destination-port", 1, NULL, '2' },
27	{ "dport", 1, NULL, '2' }, /* synonym */
28	{ .name = NULL }
29};
30
31static void
32parse_udp_ports(const char *portstring, u_int16_t *ports)
33{
34	char *buffer;
35	char *cp;
36
37	buffer = strdup(portstring);
38	if ((cp = strchr(buffer, ':')) == NULL)
39		ports[0] = ports[1] = parse_port(buffer, "udp");
40	else {
41		*cp = '\0';
42		cp++;
43
44		ports[0] = buffer[0] ? parse_port(buffer, "udp") : 0;
45		ports[1] = cp[0] ? parse_port(cp, "udp") : 0xFFFF;
46
47		if (ports[0] > ports[1])
48			exit_error(PARAMETER_PROBLEM,
49				   "invalid portrange (min > max)");
50	}
51	free(buffer);
52}
53
54/* Initialize the match. */
55static void udp_init(struct xt_entry_match *m)
56{
57	struct xt_udp *udpinfo = (struct xt_udp *)m->data;
58
59	udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
60}
61
62#define UDP_SRC_PORTS 0x01
63#define UDP_DST_PORTS 0x02
64
65/* Function which parses command options; returns true if it
66   ate an option */
67static int
68udp_parse(int c, char **argv, int invert, unsigned int *flags,
69          const void *entry, struct xt_entry_match **match)
70{
71	struct xt_udp *udpinfo = (struct xt_udp *)(*match)->data;
72
73	switch (c) {
74	case '1':
75		if (*flags & UDP_SRC_PORTS)
76			exit_error(PARAMETER_PROBLEM,
77				   "Only one `--source-port' allowed");
78		check_inverse(optarg, &invert, &optind, 0);
79		parse_udp_ports(argv[optind-1], udpinfo->spts);
80		if (invert)
81			udpinfo->invflags |= XT_UDP_INV_SRCPT;
82		*flags |= UDP_SRC_PORTS;
83		break;
84
85	case '2':
86		if (*flags & UDP_DST_PORTS)
87			exit_error(PARAMETER_PROBLEM,
88				   "Only one `--destination-port' allowed");
89		check_inverse(optarg, &invert, &optind, 0);
90		parse_udp_ports(argv[optind-1], udpinfo->dpts);
91		if (invert)
92			udpinfo->invflags |= XT_UDP_INV_DSTPT;
93		*flags |= UDP_DST_PORTS;
94		break;
95
96	default:
97		return 0;
98	}
99
100	return 1;
101}
102
103static char *
104port_to_service(int port)
105{
106	struct servent *service;
107
108	if ((service = getservbyport(htons(port), "udp")))
109		return service->s_name;
110
111	return NULL;
112}
113
114static void
115print_port(u_int16_t port, int numeric)
116{
117	char *service;
118
119	if (numeric || (service = port_to_service(port)) == NULL)
120		printf("%u", port);
121	else
122		printf("%s", service);
123}
124
125static void
126print_ports(const char *name, u_int16_t min, u_int16_t max,
127	    int invert, int numeric)
128{
129	const char *inv = invert ? "!" : "";
130
131	if (min != 0 || max != 0xFFFF || invert) {
132		printf("%s", name);
133		if (min == max) {
134			printf(":%s", inv);
135			print_port(min, numeric);
136		} else {
137			printf("s:%s", inv);
138			print_port(min, numeric);
139			printf(":");
140			print_port(max, numeric);
141		}
142		printf(" ");
143	}
144}
145
146/* Prints out the union ipt_matchinfo. */
147static void
148udp_print(const void *ip, const struct xt_entry_match *match, int numeric)
149{
150	const struct xt_udp *udp = (struct xt_udp *)match->data;
151
152	printf("udp ");
153	print_ports("spt", udp->spts[0], udp->spts[1],
154		    udp->invflags & XT_UDP_INV_SRCPT,
155		    numeric);
156	print_ports("dpt", udp->dpts[0], udp->dpts[1],
157		    udp->invflags & XT_UDP_INV_DSTPT,
158		    numeric);
159	if (udp->invflags & ~XT_UDP_INV_MASK)
160		printf("Unknown invflags: 0x%X ",
161		       udp->invflags & ~XT_UDP_INV_MASK);
162}
163
164/* Saves the union ipt_matchinfo in parsable form to stdout. */
165static void udp_save(const void *ip, const struct xt_entry_match *match)
166{
167	const struct xt_udp *udpinfo = (struct xt_udp *)match->data;
168
169	if (udpinfo->spts[0] != 0
170	    || udpinfo->spts[1] != 0xFFFF) {
171		if (udpinfo->invflags & XT_UDP_INV_SRCPT)
172			printf("! ");
173		if (udpinfo->spts[0]
174		    != udpinfo->spts[1])
175			printf("--sport %u:%u ",
176			       udpinfo->spts[0],
177			       udpinfo->spts[1]);
178		else
179			printf("--sport %u ",
180			       udpinfo->spts[0]);
181	}
182
183	if (udpinfo->dpts[0] != 0
184	    || udpinfo->dpts[1] != 0xFFFF) {
185		if (udpinfo->invflags & XT_UDP_INV_DSTPT)
186			printf("! ");
187		if (udpinfo->dpts[0]
188		    != udpinfo->dpts[1])
189			printf("--dport %u:%u ",
190			       udpinfo->dpts[0],
191			       udpinfo->dpts[1]);
192		else
193			printf("--dport %u ",
194			       udpinfo->dpts[0]);
195	}
196}
197
198static struct xtables_match udp_match = {
199	.family		= AF_INET,
200	.name		= "udp",
201	.version	= XTABLES_VERSION,
202	.size		= XT_ALIGN(sizeof(struct xt_udp)),
203	.userspacesize	= XT_ALIGN(sizeof(struct xt_udp)),
204	.help		= udp_help,
205	.init		= udp_init,
206	.parse		= udp_parse,
207	.print		= udp_print,
208	.save		= udp_save,
209	.extra_opts	= udp_opts,
210};
211
212static struct xtables_match udp_match6 = {
213	.family		= AF_INET6,
214	.name		= "udp",
215	.version	= XTABLES_VERSION,
216	.size		= XT_ALIGN(sizeof(struct xt_udp)),
217	.userspacesize	= XT_ALIGN(sizeof(struct xt_udp)),
218	.help		= udp_help,
219	.init		= udp_init,
220	.parse		= udp_parse,
221	.print		= udp_print,
222	.save		= udp_save,
223	.extra_opts	= udp_opts,
224};
225
226void
227_init(void)
228{
229	xtables_register_match(&udp_match);
230	xtables_register_match(&udp_match6);
231}
232