blob: 4b4e84fbcd7f3c3788f1e32f3577166f453ca66e [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* 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 <netinet/in.h>
8#include <xtables.h>
9#include <linux/netfilter/xt_tcpudp.h>
10
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] = xtables_parse_port(buffer, "udp");
40 else {
41 *cp = '\0';
42 cp++;
43
44 ports[0] = buffer[0] ? xtables_parse_port(buffer, "udp") : 0;
45 ports[1] = cp[0] ? xtables_parse_port(cp, "udp") : 0xFFFF;
46
47 if (ports[0] > ports[1])
48 xtables_error(PARAMETER_PROBLEM,
49 "invalid portrange (min > max)");
50 }
51 free(buffer);
52}
53
54static void udp_init(struct xt_entry_match *m)
55{
56 struct xt_udp *udpinfo = (struct xt_udp *)m->data;
57
58 udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF;
59}
60
61#define UDP_SRC_PORTS 0x01
62#define UDP_DST_PORTS 0x02
63
64static int
65udp_parse(int c, char **argv, int invert, unsigned int *flags,
66 const void *entry, struct xt_entry_match **match)
67{
68 struct xt_udp *udpinfo = (struct xt_udp *)(*match)->data;
69
70 switch (c) {
71 case '1':
72 if (*flags & UDP_SRC_PORTS)
73 xtables_error(PARAMETER_PROBLEM,
74 "Only one `--source-port' allowed");
75 xtables_check_inverse(optarg, &invert, &optind, 0);
76 parse_udp_ports(argv[optind-1], udpinfo->spts);
77 if (invert)
78 udpinfo->invflags |= XT_UDP_INV_SRCPT;
79 *flags |= UDP_SRC_PORTS;
80 break;
81
82 case '2':
83 if (*flags & UDP_DST_PORTS)
84 xtables_error(PARAMETER_PROBLEM,
85 "Only one `--destination-port' allowed");
86 xtables_check_inverse(optarg, &invert, &optind, 0);
87 parse_udp_ports(argv[optind-1], udpinfo->dpts);
88 if (invert)
89 udpinfo->invflags |= XT_UDP_INV_DSTPT;
90 *flags |= UDP_DST_PORTS;
91 break;
92
93 default:
94 return 0;
95 }
96
97 return 1;
98}
99
100static char *
101port_to_service(int port)
102{
103 struct servent *service;
104
105 if ((service = getservbyport(htons(port), "udp")))
106 return service->s_name;
107
108 return NULL;
109}
110
111static void
112print_port(u_int16_t port, int numeric)
113{
114 char *service;
115
116 if (numeric || (service = port_to_service(port)) == NULL)
117 printf("%u", port);
118 else
119 printf("%s", service);
120}
121
122static void
123print_ports(const char *name, u_int16_t min, u_int16_t max,
124 int invert, int numeric)
125{
126 const char *inv = invert ? "!" : "";
127
128 if (min != 0 || max != 0xFFFF || invert) {
129 printf("%s", name);
130 if (min == max) {
131 printf(":%s", inv);
132 print_port(min, numeric);
133 } else {
134 printf("s:%s", inv);
135 print_port(min, numeric);
136 printf(":");
137 print_port(max, numeric);
138 }
139 printf(" ");
140 }
141}
142
143static void
144udp_print(const void *ip, const struct xt_entry_match *match, int numeric)
145{
146 const struct xt_udp *udp = (struct xt_udp *)match->data;
147
148 printf("udp ");
149 print_ports("spt", udp->spts[0], udp->spts[1],
150 udp->invflags & XT_UDP_INV_SRCPT,
151 numeric);
152 print_ports("dpt", udp->dpts[0], udp->dpts[1],
153 udp->invflags & XT_UDP_INV_DSTPT,
154 numeric);
155 if (udp->invflags & ~XT_UDP_INV_MASK)
156 printf("Unknown invflags: 0x%X ",
157 udp->invflags & ~XT_UDP_INV_MASK);
158}
159
160static void udp_save(const void *ip, const struct xt_entry_match *match)
161{
162 const struct xt_udp *udpinfo = (struct xt_udp *)match->data;
163
164 if (udpinfo->spts[0] != 0
165 || udpinfo->spts[1] != 0xFFFF) {
166 if (udpinfo->invflags & XT_UDP_INV_SRCPT)
167 printf("! ");
168 if (udpinfo->spts[0]
169 != udpinfo->spts[1])
170 printf("--sport %u:%u ",
171 udpinfo->spts[0],
172 udpinfo->spts[1]);
173 else
174 printf("--sport %u ",
175 udpinfo->spts[0]);
176 }
177
178 if (udpinfo->dpts[0] != 0
179 || udpinfo->dpts[1] != 0xFFFF) {
180 if (udpinfo->invflags & XT_UDP_INV_DSTPT)
181 printf("! ");
182 if (udpinfo->dpts[0]
183 != udpinfo->dpts[1])
184 printf("--dport %u:%u ",
185 udpinfo->dpts[0],
186 udpinfo->dpts[1]);
187 else
188 printf("--dport %u ",
189 udpinfo->dpts[0]);
190 }
191}
192
193static struct xtables_match udp_match = {
194 .family = NFPROTO_IPV4,
195 .name = "udp",
196 .version = XTABLES_VERSION,
197 .size = XT_ALIGN(sizeof(struct xt_udp)),
198 .userspacesize = XT_ALIGN(sizeof(struct xt_udp)),
199 .help = udp_help,
200 .init = udp_init,
201 .parse = udp_parse,
202 .print = udp_print,
203 .save = udp_save,
204 .extra_opts = udp_opts,
205};
206
207static struct xtables_match udp_match6 = {
208 .family = NFPROTO_IPV6,
209 .name = "udp",
210 .version = XTABLES_VERSION,
211 .size = XT_ALIGN(sizeof(struct xt_udp)),
212 .userspacesize = XT_ALIGN(sizeof(struct xt_udp)),
213 .help = udp_help,
214 .init = udp_init,
215 .parse = udp_parse,
216 .print = udp_print,
217 .save = udp_save,
218 .extra_opts = udp_opts,
219};
220
221void
222_init(void)
223{
224 xtables_register_match(&udp_match);
225 xtables_register_match(&udp_match6);
226}