12e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt#include <stdint.h>
2e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <stdio.h>
3e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher#include <netdb.h>
42e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt#include <arpa/inet.h>
517908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI#include <xtables.h>
617908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI#include <linux/netfilter/xt_tcpudp.h>
7e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
82e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardtenum {
92e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	O_SOURCE_PORT = 0,
102e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	O_DEST_PORT,
112e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt};
122e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt
13181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void udp_help(void)
14e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
15e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	printf(
168b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"udp match options:\n"
17967279231a9ecfa99f26694a954afc535c63db1dJan Engelhardt"[!] --source-port port[:port]\n"
18e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher" --sport ...\n"
19e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher"				match source port(s)\n"
20967279231a9ecfa99f26694a954afc535c63db1dJan Engelhardt"[!] --destination-port port[:port]\n"
21e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher" --dport ...\n"
228b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt"				match destination port(s)\n");
23e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
24e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
252e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt#define s struct xt_udp
262e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardtstatic const struct xt_option_entry udp_opts[] = {
272e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	{.name = "source-port", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC,
282e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)},
292e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	{.name = "sport", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC,
302e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)},
312e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	{.name = "destination-port", .id = O_DEST_PORT, .type = XTTYPE_PORTRC,
322e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)},
332e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	{.name = "dport", .id = O_DEST_PORT, .type = XTTYPE_PORTRC,
342e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)},
352e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	XTOPT_TABLEEND,
36e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
372e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt#undef s
38e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
39181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void udp_init(struct xt_entry_match *m)
40e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
4117908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI	struct xt_udp *udpinfo = (struct xt_udp *)m->data;
42e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
43e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
44e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
45e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
462e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardtstatic void udp_parse(struct xt_option_call *cb)
47e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
482e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	struct xt_udp *udpinfo = cb->data;
492e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt
502e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	xtables_option_parse(cb);
512e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	switch (cb->entry->id) {
522e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	case O_SOURCE_PORT:
532e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt		if (cb->invert)
5417908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI			udpinfo->invflags |= XT_UDP_INV_SRCPT;
55e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
562e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	case O_DEST_PORT:
572e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt		if (cb->invert)
5817908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI			udpinfo->invflags |= XT_UDP_INV_DSTPT;
59e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		break;
60e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
61e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
62e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
63dd6e4b90b5b2dbc2bbaac5008e26949a18478197Jan Engelhardtstatic const char *
64e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherport_to_service(int port)
65e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
66dd6e4b90b5b2dbc2bbaac5008e26949a18478197Jan Engelhardt	const struct servent *service;
67e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
68e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if ((service = getservbyport(htons(port), "udp")))
69e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		return service->s_name;
70e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
71e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	return NULL;
72e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
73e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
74e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
757ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtprint_port(uint16_t port, int numeric)
76e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
77dd6e4b90b5b2dbc2bbaac5008e26949a18478197Jan Engelhardt	const char *service;
78e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
79e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (numeric || (service = port_to_service(port)) == NULL)
80e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("%u", port);
81e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	else
82e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		printf("%s", service);
83e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
84e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
85e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
867ac405297ec38449b30e3b05fd6bf2082fd3d803Jan Engelhardtprint_ports(const char *name, uint16_t min, uint16_t max,
87e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	    int invert, int numeric)
88e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
89e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	const char *inv = invert ? "!" : "";
90e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
91e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (min != 0 || max != 0xFFFF || invert) {
9273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" %s", name);
93e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (min == max) {
94e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(":%s", inv);
95e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			print_port(min, numeric);
96e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		} else {
97e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf("s:%s", inv);
98e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			print_port(min, numeric);
99e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			printf(":");
100e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher			print_port(max, numeric);
101e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		}
102e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
103e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
104e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
105e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucherstatic void
106181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtudp_print(const void *ip, const struct xt_entry_match *match, int numeric)
107e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
10817908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI	const struct xt_udp *udp = (struct xt_udp *)match->data;
109e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
11073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt	printf(" udp");
111e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_ports("spt", udp->spts[0], udp->spts[1],
11217908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI		    udp->invflags & XT_UDP_INV_SRCPT,
113e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    numeric);
114e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	print_ports("dpt", udp->dpts[0], udp->dpts[1],
11517908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI		    udp->invflags & XT_UDP_INV_DSTPT,
116e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    numeric);
11717908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI	if (udp->invflags & ~XT_UDP_INV_MASK)
11873866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt		printf(" Unknown invflags: 0x%X",
11917908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI		       udp->invflags & ~XT_UDP_INV_MASK);
120e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
121e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
122181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic void udp_save(const void *ip, const struct xt_entry_match *match)
123e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
12417908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI	const struct xt_udp *udpinfo = (struct xt_udp *)match->data;
125e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
126e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (udpinfo->spts[0] != 0
12773f72f541ac4dab538d4d418b9bbf1707b31342bRusty Russell	    || udpinfo->spts[1] != 0xFFFF) {
12817908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI		if (udpinfo->invflags & XT_UDP_INV_SRCPT)
12973866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" !");
130e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (udpinfo->spts[0]
131e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    != udpinfo->spts[1])
13273866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" --sport %u:%u",
1339f2009cbfda7a4e341258322a7c8b462605990afMarc Boucher			       udpinfo->spts[0],
1342382c8c3a126ba82e6da03f79a88f44e7f3caa54Marc Boucher			       udpinfo->spts[1]);
135e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
13673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" --sport %u",
1379f2009cbfda7a4e341258322a7c8b462605990afMarc Boucher			       udpinfo->spts[0]);
138e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
139e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
140e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	if (udpinfo->dpts[0] != 0
14173f72f541ac4dab538d4d418b9bbf1707b31342bRusty Russell	    || udpinfo->dpts[1] != 0xFFFF) {
14217908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI		if (udpinfo->invflags & XT_UDP_INV_DSTPT)
14373866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" !");
144e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		if (udpinfo->dpts[0]
145e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		    != udpinfo->dpts[1])
14673866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" --dport %u:%u",
1479f2009cbfda7a4e341258322a7c8b462605990afMarc Boucher			       udpinfo->dpts[0],
1489f2009cbfda7a4e341258322a7c8b462605990afMarc Boucher			       udpinfo->dpts[1]);
149e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher		else
15073866357e4a7a0fdc1b293bf8863fee2bd56da9eJan Engelhardt			printf(" --dport %u",
1519f2009cbfda7a4e341258322a7c8b462605990afMarc Boucher			       udpinfo->dpts[0]);
152e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher	}
153e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
154e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
155181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardtstatic struct xtables_match udp_match = {
156c5e85736c207f211d82d2878a5781f512327dfceJan Engelhardt	.family		= NFPROTO_UNSPEC,
15717908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI	.name		= "udp",
1588b7c64d6ba156a99008fcd810cba874c73294333Jan Engelhardt	.version	= XTABLES_VERSION,
15917908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI	.size		= XT_ALIGN(sizeof(struct xt_udp)),
16017908e4bd0bc8ddb7a85bda316864ad8e1e56a29Yasuyuki KOZAKAI	.userspacesize	= XT_ALIGN(sizeof(struct xt_udp)),
161181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt	.help		= udp_help,
162181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt	.init		= udp_init,
163181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt	.print		= udp_print,
164181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt	.save		= udp_save,
1652e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	.x6_parse	= udp_parse,
1662e73af96178f0ed7ebbd99478f1bc05ec5c86dc7Jan Engelhardt	.x6_options	= udp_opts,
167e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher};
168e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher
169e6869a8f59d779ff4d5a0984c86d80db7078496Marc Bouchervoid
170e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher_init(void)
171e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher{
172181dead3f13befe02769ef479bcbb51801b7fc4eJan Engelhardt	xtables_register_match(&udp_match);
173e6869a8f59d779ff4d5a0984c86d80db7078496Marc Boucher}
174