1*a71a9546SAutomerger Merge Worker /* Shared library add-on to iptables to add TCP support. */
2*a71a9546SAutomerger Merge Worker #include <stdbool.h>
3*a71a9546SAutomerger Merge Worker #include <stdio.h>
4*a71a9546SAutomerger Merge Worker #include <netdb.h>
5*a71a9546SAutomerger Merge Worker #include <string.h>
6*a71a9546SAutomerger Merge Worker #include <stdlib.h>
7*a71a9546SAutomerger Merge Worker #include <getopt.h>
8*a71a9546SAutomerger Merge Worker #include <netinet/in.h>
9*a71a9546SAutomerger Merge Worker #include <xtables.h>
10*a71a9546SAutomerger Merge Worker #include <linux/netfilter/xt_tcpudp.h>
11*a71a9546SAutomerger Merge Worker
tcp_help(void)12*a71a9546SAutomerger Merge Worker static void tcp_help(void)
13*a71a9546SAutomerger Merge Worker {
14*a71a9546SAutomerger Merge Worker printf(
15*a71a9546SAutomerger Merge Worker "tcp match options:\n"
16*a71a9546SAutomerger Merge Worker "[!] --tcp-flags mask comp match when TCP flags & mask == comp\n"
17*a71a9546SAutomerger Merge Worker " (Flags: SYN ACK FIN RST URG PSH ALL NONE)\n"
18*a71a9546SAutomerger Merge Worker "[!] --syn match when only SYN flag set\n"
19*a71a9546SAutomerger Merge Worker " (equivalent to --tcp-flags SYN,RST,ACK,FIN SYN)\n"
20*a71a9546SAutomerger Merge Worker "[!] --source-port port[:port]\n"
21*a71a9546SAutomerger Merge Worker " --sport ...\n"
22*a71a9546SAutomerger Merge Worker " match source port(s)\n"
23*a71a9546SAutomerger Merge Worker "[!] --destination-port port[:port]\n"
24*a71a9546SAutomerger Merge Worker " --dport ...\n"
25*a71a9546SAutomerger Merge Worker " match destination port(s)\n"
26*a71a9546SAutomerger Merge Worker "[!] --tcp-option number match if TCP option set\n");
27*a71a9546SAutomerger Merge Worker }
28*a71a9546SAutomerger Merge Worker
29*a71a9546SAutomerger Merge Worker static const struct option tcp_opts[] = {
30*a71a9546SAutomerger Merge Worker {.name = "source-port", .has_arg = true, .val = '1'},
31*a71a9546SAutomerger Merge Worker {.name = "sport", .has_arg = true, .val = '1'}, /* synonym */
32*a71a9546SAutomerger Merge Worker {.name = "destination-port", .has_arg = true, .val = '2'},
33*a71a9546SAutomerger Merge Worker {.name = "dport", .has_arg = true, .val = '2'}, /* synonym */
34*a71a9546SAutomerger Merge Worker {.name = "syn", .has_arg = false, .val = '3'},
35*a71a9546SAutomerger Merge Worker {.name = "tcp-flags", .has_arg = true, .val = '4'},
36*a71a9546SAutomerger Merge Worker {.name = "tcp-option", .has_arg = true, .val = '5'},
37*a71a9546SAutomerger Merge Worker XT_GETOPT_TABLEEND,
38*a71a9546SAutomerger Merge Worker };
39*a71a9546SAutomerger Merge Worker
40*a71a9546SAutomerger Merge Worker static void
parse_tcp_ports(const char * portstring,uint16_t * ports)41*a71a9546SAutomerger Merge Worker parse_tcp_ports(const char *portstring, uint16_t *ports)
42*a71a9546SAutomerger Merge Worker {
43*a71a9546SAutomerger Merge Worker char *buffer;
44*a71a9546SAutomerger Merge Worker char *cp;
45*a71a9546SAutomerger Merge Worker
46*a71a9546SAutomerger Merge Worker buffer = xtables_strdup(portstring);
47*a71a9546SAutomerger Merge Worker if ((cp = strchr(buffer, ':')) == NULL)
48*a71a9546SAutomerger Merge Worker ports[0] = ports[1] = xtables_parse_port(buffer, "tcp");
49*a71a9546SAutomerger Merge Worker else {
50*a71a9546SAutomerger Merge Worker *cp = '\0';
51*a71a9546SAutomerger Merge Worker cp++;
52*a71a9546SAutomerger Merge Worker
53*a71a9546SAutomerger Merge Worker ports[0] = buffer[0] ? xtables_parse_port(buffer, "tcp") : 0;
54*a71a9546SAutomerger Merge Worker ports[1] = cp[0] ? xtables_parse_port(cp, "tcp") : 0xFFFF;
55*a71a9546SAutomerger Merge Worker
56*a71a9546SAutomerger Merge Worker if (ports[0] > ports[1])
57*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
58*a71a9546SAutomerger Merge Worker "invalid portrange (min > max)");
59*a71a9546SAutomerger Merge Worker }
60*a71a9546SAutomerger Merge Worker free(buffer);
61*a71a9546SAutomerger Merge Worker }
62*a71a9546SAutomerger Merge Worker
63*a71a9546SAutomerger Merge Worker struct tcp_flag_names {
64*a71a9546SAutomerger Merge Worker const char *name;
65*a71a9546SAutomerger Merge Worker unsigned int flag;
66*a71a9546SAutomerger Merge Worker };
67*a71a9546SAutomerger Merge Worker
68*a71a9546SAutomerger Merge Worker static const struct tcp_flag_names tcp_flag_names[]
69*a71a9546SAutomerger Merge Worker = { { "FIN", 0x01 },
70*a71a9546SAutomerger Merge Worker { "SYN", 0x02 },
71*a71a9546SAutomerger Merge Worker { "RST", 0x04 },
72*a71a9546SAutomerger Merge Worker { "PSH", 0x08 },
73*a71a9546SAutomerger Merge Worker { "ACK", 0x10 },
74*a71a9546SAutomerger Merge Worker { "URG", 0x20 },
75*a71a9546SAutomerger Merge Worker { "ALL", 0x3F },
76*a71a9546SAutomerger Merge Worker { "NONE", 0 },
77*a71a9546SAutomerger Merge Worker };
78*a71a9546SAutomerger Merge Worker
79*a71a9546SAutomerger Merge Worker static unsigned int
parse_tcp_flag(const char * flags)80*a71a9546SAutomerger Merge Worker parse_tcp_flag(const char *flags)
81*a71a9546SAutomerger Merge Worker {
82*a71a9546SAutomerger Merge Worker unsigned int ret = 0;
83*a71a9546SAutomerger Merge Worker char *ptr;
84*a71a9546SAutomerger Merge Worker char *buffer;
85*a71a9546SAutomerger Merge Worker
86*a71a9546SAutomerger Merge Worker buffer = xtables_strdup(flags);
87*a71a9546SAutomerger Merge Worker
88*a71a9546SAutomerger Merge Worker for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
89*a71a9546SAutomerger Merge Worker unsigned int i;
90*a71a9546SAutomerger Merge Worker for (i = 0; i < ARRAY_SIZE(tcp_flag_names); ++i)
91*a71a9546SAutomerger Merge Worker if (strcasecmp(tcp_flag_names[i].name, ptr) == 0) {
92*a71a9546SAutomerger Merge Worker ret |= tcp_flag_names[i].flag;
93*a71a9546SAutomerger Merge Worker break;
94*a71a9546SAutomerger Merge Worker }
95*a71a9546SAutomerger Merge Worker if (i == ARRAY_SIZE(tcp_flag_names))
96*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
97*a71a9546SAutomerger Merge Worker "Unknown TCP flag `%s'", ptr);
98*a71a9546SAutomerger Merge Worker }
99*a71a9546SAutomerger Merge Worker
100*a71a9546SAutomerger Merge Worker free(buffer);
101*a71a9546SAutomerger Merge Worker return ret;
102*a71a9546SAutomerger Merge Worker }
103*a71a9546SAutomerger Merge Worker
104*a71a9546SAutomerger Merge Worker static void
parse_tcp_flags(struct xt_tcp * tcpinfo,const char * mask,const char * cmp,int invert)105*a71a9546SAutomerger Merge Worker parse_tcp_flags(struct xt_tcp *tcpinfo,
106*a71a9546SAutomerger Merge Worker const char *mask,
107*a71a9546SAutomerger Merge Worker const char *cmp,
108*a71a9546SAutomerger Merge Worker int invert)
109*a71a9546SAutomerger Merge Worker {
110*a71a9546SAutomerger Merge Worker tcpinfo->flg_mask = parse_tcp_flag(mask);
111*a71a9546SAutomerger Merge Worker tcpinfo->flg_cmp = parse_tcp_flag(cmp);
112*a71a9546SAutomerger Merge Worker
113*a71a9546SAutomerger Merge Worker if (invert)
114*a71a9546SAutomerger Merge Worker tcpinfo->invflags |= XT_TCP_INV_FLAGS;
115*a71a9546SAutomerger Merge Worker }
116*a71a9546SAutomerger Merge Worker
117*a71a9546SAutomerger Merge Worker static void
parse_tcp_option(const char * option,uint8_t * result)118*a71a9546SAutomerger Merge Worker parse_tcp_option(const char *option, uint8_t *result)
119*a71a9546SAutomerger Merge Worker {
120*a71a9546SAutomerger Merge Worker unsigned int ret;
121*a71a9546SAutomerger Merge Worker
122*a71a9546SAutomerger Merge Worker if (!xtables_strtoui(option, NULL, &ret, 1, UINT8_MAX))
123*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM, "Bad TCP option \"%s\"", option);
124*a71a9546SAutomerger Merge Worker
125*a71a9546SAutomerger Merge Worker *result = ret;
126*a71a9546SAutomerger Merge Worker }
127*a71a9546SAutomerger Merge Worker
tcp_init(struct xt_entry_match * m)128*a71a9546SAutomerger Merge Worker static void tcp_init(struct xt_entry_match *m)
129*a71a9546SAutomerger Merge Worker {
130*a71a9546SAutomerger Merge Worker struct xt_tcp *tcpinfo = (struct xt_tcp *)m->data;
131*a71a9546SAutomerger Merge Worker
132*a71a9546SAutomerger Merge Worker tcpinfo->spts[1] = tcpinfo->dpts[1] = 0xFFFF;
133*a71a9546SAutomerger Merge Worker }
134*a71a9546SAutomerger Merge Worker
135*a71a9546SAutomerger Merge Worker #define TCP_SRC_PORTS 0x01
136*a71a9546SAutomerger Merge Worker #define TCP_DST_PORTS 0x02
137*a71a9546SAutomerger Merge Worker #define TCP_FLAGS 0x04
138*a71a9546SAutomerger Merge Worker #define TCP_OPTION 0x08
139*a71a9546SAutomerger Merge Worker
140*a71a9546SAutomerger Merge Worker static int
tcp_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_match ** match)141*a71a9546SAutomerger Merge Worker tcp_parse(int c, char **argv, int invert, unsigned int *flags,
142*a71a9546SAutomerger Merge Worker const void *entry, struct xt_entry_match **match)
143*a71a9546SAutomerger Merge Worker {
144*a71a9546SAutomerger Merge Worker struct xt_tcp *tcpinfo = (struct xt_tcp *)(*match)->data;
145*a71a9546SAutomerger Merge Worker
146*a71a9546SAutomerger Merge Worker switch (c) {
147*a71a9546SAutomerger Merge Worker case '1':
148*a71a9546SAutomerger Merge Worker if (*flags & TCP_SRC_PORTS)
149*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
150*a71a9546SAutomerger Merge Worker "Only one `--source-port' allowed");
151*a71a9546SAutomerger Merge Worker parse_tcp_ports(optarg, tcpinfo->spts);
152*a71a9546SAutomerger Merge Worker if (invert)
153*a71a9546SAutomerger Merge Worker tcpinfo->invflags |= XT_TCP_INV_SRCPT;
154*a71a9546SAutomerger Merge Worker *flags |= TCP_SRC_PORTS;
155*a71a9546SAutomerger Merge Worker break;
156*a71a9546SAutomerger Merge Worker
157*a71a9546SAutomerger Merge Worker case '2':
158*a71a9546SAutomerger Merge Worker if (*flags & TCP_DST_PORTS)
159*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
160*a71a9546SAutomerger Merge Worker "Only one `--destination-port' allowed");
161*a71a9546SAutomerger Merge Worker parse_tcp_ports(optarg, tcpinfo->dpts);
162*a71a9546SAutomerger Merge Worker if (invert)
163*a71a9546SAutomerger Merge Worker tcpinfo->invflags |= XT_TCP_INV_DSTPT;
164*a71a9546SAutomerger Merge Worker *flags |= TCP_DST_PORTS;
165*a71a9546SAutomerger Merge Worker break;
166*a71a9546SAutomerger Merge Worker
167*a71a9546SAutomerger Merge Worker case '3':
168*a71a9546SAutomerger Merge Worker if (*flags & TCP_FLAGS)
169*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
170*a71a9546SAutomerger Merge Worker "Only one of `--syn' or `--tcp-flags' "
171*a71a9546SAutomerger Merge Worker " allowed");
172*a71a9546SAutomerger Merge Worker parse_tcp_flags(tcpinfo, "SYN,RST,ACK,FIN", "SYN", invert);
173*a71a9546SAutomerger Merge Worker *flags |= TCP_FLAGS;
174*a71a9546SAutomerger Merge Worker break;
175*a71a9546SAutomerger Merge Worker
176*a71a9546SAutomerger Merge Worker case '4':
177*a71a9546SAutomerger Merge Worker if (*flags & TCP_FLAGS)
178*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
179*a71a9546SAutomerger Merge Worker "Only one of `--syn' or `--tcp-flags' "
180*a71a9546SAutomerger Merge Worker " allowed");
181*a71a9546SAutomerger Merge Worker if (!argv[optind]
182*a71a9546SAutomerger Merge Worker || argv[optind][0] == '-' || argv[optind][0] == '!')
183*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
184*a71a9546SAutomerger Merge Worker "--tcp-flags requires two args.");
185*a71a9546SAutomerger Merge Worker
186*a71a9546SAutomerger Merge Worker parse_tcp_flags(tcpinfo, optarg, argv[optind],
187*a71a9546SAutomerger Merge Worker invert);
188*a71a9546SAutomerger Merge Worker optind++;
189*a71a9546SAutomerger Merge Worker *flags |= TCP_FLAGS;
190*a71a9546SAutomerger Merge Worker break;
191*a71a9546SAutomerger Merge Worker
192*a71a9546SAutomerger Merge Worker case '5':
193*a71a9546SAutomerger Merge Worker if (*flags & TCP_OPTION)
194*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
195*a71a9546SAutomerger Merge Worker "Only one `--tcp-option' allowed");
196*a71a9546SAutomerger Merge Worker parse_tcp_option(optarg, &tcpinfo->option);
197*a71a9546SAutomerger Merge Worker if (invert)
198*a71a9546SAutomerger Merge Worker tcpinfo->invflags |= XT_TCP_INV_OPTION;
199*a71a9546SAutomerger Merge Worker *flags |= TCP_OPTION;
200*a71a9546SAutomerger Merge Worker break;
201*a71a9546SAutomerger Merge Worker }
202*a71a9546SAutomerger Merge Worker
203*a71a9546SAutomerger Merge Worker return 1;
204*a71a9546SAutomerger Merge Worker }
205*a71a9546SAutomerger Merge Worker
206*a71a9546SAutomerger Merge Worker static const char *
port_to_service(int port)207*a71a9546SAutomerger Merge Worker port_to_service(int port)
208*a71a9546SAutomerger Merge Worker {
209*a71a9546SAutomerger Merge Worker const struct servent *service;
210*a71a9546SAutomerger Merge Worker
211*a71a9546SAutomerger Merge Worker if ((service = getservbyport(htons(port), "tcp")))
212*a71a9546SAutomerger Merge Worker return service->s_name;
213*a71a9546SAutomerger Merge Worker
214*a71a9546SAutomerger Merge Worker return NULL;
215*a71a9546SAutomerger Merge Worker }
216*a71a9546SAutomerger Merge Worker
217*a71a9546SAutomerger Merge Worker static void
print_port(uint16_t port,int numeric)218*a71a9546SAutomerger Merge Worker print_port(uint16_t port, int numeric)
219*a71a9546SAutomerger Merge Worker {
220*a71a9546SAutomerger Merge Worker const char *service;
221*a71a9546SAutomerger Merge Worker
222*a71a9546SAutomerger Merge Worker if (numeric || (service = port_to_service(port)) == NULL)
223*a71a9546SAutomerger Merge Worker printf("%u", port);
224*a71a9546SAutomerger Merge Worker else
225*a71a9546SAutomerger Merge Worker printf("%s", service);
226*a71a9546SAutomerger Merge Worker }
227*a71a9546SAutomerger Merge Worker
228*a71a9546SAutomerger Merge Worker static void
print_ports(const char * name,uint16_t min,uint16_t max,int invert,int numeric)229*a71a9546SAutomerger Merge Worker print_ports(const char *name, uint16_t min, uint16_t max,
230*a71a9546SAutomerger Merge Worker int invert, int numeric)
231*a71a9546SAutomerger Merge Worker {
232*a71a9546SAutomerger Merge Worker const char *inv = invert ? "!" : "";
233*a71a9546SAutomerger Merge Worker
234*a71a9546SAutomerger Merge Worker if (min != 0 || max != 0xFFFF || invert) {
235*a71a9546SAutomerger Merge Worker printf(" %s", name);
236*a71a9546SAutomerger Merge Worker if (min == max) {
237*a71a9546SAutomerger Merge Worker printf(":%s", inv);
238*a71a9546SAutomerger Merge Worker print_port(min, numeric);
239*a71a9546SAutomerger Merge Worker } else {
240*a71a9546SAutomerger Merge Worker printf("s:%s", inv);
241*a71a9546SAutomerger Merge Worker print_port(min, numeric);
242*a71a9546SAutomerger Merge Worker printf(":");
243*a71a9546SAutomerger Merge Worker print_port(max, numeric);
244*a71a9546SAutomerger Merge Worker }
245*a71a9546SAutomerger Merge Worker }
246*a71a9546SAutomerger Merge Worker }
247*a71a9546SAutomerger Merge Worker
248*a71a9546SAutomerger Merge Worker static void
print_option(uint8_t option,int invert,int numeric)249*a71a9546SAutomerger Merge Worker print_option(uint8_t option, int invert, int numeric)
250*a71a9546SAutomerger Merge Worker {
251*a71a9546SAutomerger Merge Worker if (option || invert)
252*a71a9546SAutomerger Merge Worker printf(" option=%s%u", invert ? "!" : "", option);
253*a71a9546SAutomerger Merge Worker }
254*a71a9546SAutomerger Merge Worker
255*a71a9546SAutomerger Merge Worker static void
print_tcpf(uint8_t flags)256*a71a9546SAutomerger Merge Worker print_tcpf(uint8_t flags)
257*a71a9546SAutomerger Merge Worker {
258*a71a9546SAutomerger Merge Worker int have_flag = 0;
259*a71a9546SAutomerger Merge Worker
260*a71a9546SAutomerger Merge Worker while (flags) {
261*a71a9546SAutomerger Merge Worker unsigned int i;
262*a71a9546SAutomerger Merge Worker
263*a71a9546SAutomerger Merge Worker for (i = 0; (flags & tcp_flag_names[i].flag) == 0; i++);
264*a71a9546SAutomerger Merge Worker
265*a71a9546SAutomerger Merge Worker if (have_flag)
266*a71a9546SAutomerger Merge Worker printf(",");
267*a71a9546SAutomerger Merge Worker printf("%s", tcp_flag_names[i].name);
268*a71a9546SAutomerger Merge Worker have_flag = 1;
269*a71a9546SAutomerger Merge Worker
270*a71a9546SAutomerger Merge Worker flags &= ~tcp_flag_names[i].flag;
271*a71a9546SAutomerger Merge Worker }
272*a71a9546SAutomerger Merge Worker
273*a71a9546SAutomerger Merge Worker if (!have_flag)
274*a71a9546SAutomerger Merge Worker printf("NONE");
275*a71a9546SAutomerger Merge Worker }
276*a71a9546SAutomerger Merge Worker
277*a71a9546SAutomerger Merge Worker static void
print_flags(uint8_t mask,uint8_t cmp,int invert,int numeric)278*a71a9546SAutomerger Merge Worker print_flags(uint8_t mask, uint8_t cmp, int invert, int numeric)
279*a71a9546SAutomerger Merge Worker {
280*a71a9546SAutomerger Merge Worker if (mask || invert) {
281*a71a9546SAutomerger Merge Worker printf(" flags:%s", invert ? "!" : "");
282*a71a9546SAutomerger Merge Worker if (numeric)
283*a71a9546SAutomerger Merge Worker printf("0x%02X/0x%02X", mask, cmp);
284*a71a9546SAutomerger Merge Worker else {
285*a71a9546SAutomerger Merge Worker print_tcpf(mask);
286*a71a9546SAutomerger Merge Worker printf("/");
287*a71a9546SAutomerger Merge Worker print_tcpf(cmp);
288*a71a9546SAutomerger Merge Worker }
289*a71a9546SAutomerger Merge Worker }
290*a71a9546SAutomerger Merge Worker }
291*a71a9546SAutomerger Merge Worker
292*a71a9546SAutomerger Merge Worker static void
tcp_print(const void * ip,const struct xt_entry_match * match,int numeric)293*a71a9546SAutomerger Merge Worker tcp_print(const void *ip, const struct xt_entry_match *match, int numeric)
294*a71a9546SAutomerger Merge Worker {
295*a71a9546SAutomerger Merge Worker const struct xt_tcp *tcp = (struct xt_tcp *)match->data;
296*a71a9546SAutomerger Merge Worker
297*a71a9546SAutomerger Merge Worker printf(" tcp");
298*a71a9546SAutomerger Merge Worker print_ports("spt", tcp->spts[0], tcp->spts[1],
299*a71a9546SAutomerger Merge Worker tcp->invflags & XT_TCP_INV_SRCPT,
300*a71a9546SAutomerger Merge Worker numeric);
301*a71a9546SAutomerger Merge Worker print_ports("dpt", tcp->dpts[0], tcp->dpts[1],
302*a71a9546SAutomerger Merge Worker tcp->invflags & XT_TCP_INV_DSTPT,
303*a71a9546SAutomerger Merge Worker numeric);
304*a71a9546SAutomerger Merge Worker print_option(tcp->option,
305*a71a9546SAutomerger Merge Worker tcp->invflags & XT_TCP_INV_OPTION,
306*a71a9546SAutomerger Merge Worker numeric);
307*a71a9546SAutomerger Merge Worker print_flags(tcp->flg_mask, tcp->flg_cmp,
308*a71a9546SAutomerger Merge Worker tcp->invflags & XT_TCP_INV_FLAGS,
309*a71a9546SAutomerger Merge Worker numeric);
310*a71a9546SAutomerger Merge Worker if (tcp->invflags & ~XT_TCP_INV_MASK)
311*a71a9546SAutomerger Merge Worker printf(" Unknown invflags: 0x%X",
312*a71a9546SAutomerger Merge Worker tcp->invflags & ~XT_TCP_INV_MASK);
313*a71a9546SAutomerger Merge Worker }
314*a71a9546SAutomerger Merge Worker
tcp_save(const void * ip,const struct xt_entry_match * match)315*a71a9546SAutomerger Merge Worker static void tcp_save(const void *ip, const struct xt_entry_match *match)
316*a71a9546SAutomerger Merge Worker {
317*a71a9546SAutomerger Merge Worker const struct xt_tcp *tcpinfo = (struct xt_tcp *)match->data;
318*a71a9546SAutomerger Merge Worker
319*a71a9546SAutomerger Merge Worker if (tcpinfo->spts[0] != 0
320*a71a9546SAutomerger Merge Worker || tcpinfo->spts[1] != 0xFFFF) {
321*a71a9546SAutomerger Merge Worker if (tcpinfo->invflags & XT_TCP_INV_SRCPT)
322*a71a9546SAutomerger Merge Worker printf(" !");
323*a71a9546SAutomerger Merge Worker if (tcpinfo->spts[0]
324*a71a9546SAutomerger Merge Worker != tcpinfo->spts[1])
325*a71a9546SAutomerger Merge Worker printf(" --sport %u:%u",
326*a71a9546SAutomerger Merge Worker tcpinfo->spts[0],
327*a71a9546SAutomerger Merge Worker tcpinfo->spts[1]);
328*a71a9546SAutomerger Merge Worker else
329*a71a9546SAutomerger Merge Worker printf(" --sport %u",
330*a71a9546SAutomerger Merge Worker tcpinfo->spts[0]);
331*a71a9546SAutomerger Merge Worker }
332*a71a9546SAutomerger Merge Worker
333*a71a9546SAutomerger Merge Worker if (tcpinfo->dpts[0] != 0
334*a71a9546SAutomerger Merge Worker || tcpinfo->dpts[1] != 0xFFFF) {
335*a71a9546SAutomerger Merge Worker if (tcpinfo->invflags & XT_TCP_INV_DSTPT)
336*a71a9546SAutomerger Merge Worker printf(" !");
337*a71a9546SAutomerger Merge Worker if (tcpinfo->dpts[0]
338*a71a9546SAutomerger Merge Worker != tcpinfo->dpts[1])
339*a71a9546SAutomerger Merge Worker printf(" --dport %u:%u",
340*a71a9546SAutomerger Merge Worker tcpinfo->dpts[0],
341*a71a9546SAutomerger Merge Worker tcpinfo->dpts[1]);
342*a71a9546SAutomerger Merge Worker else
343*a71a9546SAutomerger Merge Worker printf(" --dport %u",
344*a71a9546SAutomerger Merge Worker tcpinfo->dpts[0]);
345*a71a9546SAutomerger Merge Worker }
346*a71a9546SAutomerger Merge Worker
347*a71a9546SAutomerger Merge Worker if (tcpinfo->option
348*a71a9546SAutomerger Merge Worker || (tcpinfo->invflags & XT_TCP_INV_OPTION)) {
349*a71a9546SAutomerger Merge Worker if (tcpinfo->invflags & XT_TCP_INV_OPTION)
350*a71a9546SAutomerger Merge Worker printf(" !");
351*a71a9546SAutomerger Merge Worker printf(" --tcp-option %u", tcpinfo->option);
352*a71a9546SAutomerger Merge Worker }
353*a71a9546SAutomerger Merge Worker
354*a71a9546SAutomerger Merge Worker if (tcpinfo->flg_mask
355*a71a9546SAutomerger Merge Worker || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) {
356*a71a9546SAutomerger Merge Worker if (tcpinfo->invflags & XT_TCP_INV_FLAGS)
357*a71a9546SAutomerger Merge Worker printf(" !");
358*a71a9546SAutomerger Merge Worker printf(" --tcp-flags ");
359*a71a9546SAutomerger Merge Worker print_tcpf(tcpinfo->flg_mask);
360*a71a9546SAutomerger Merge Worker printf(" ");
361*a71a9546SAutomerger Merge Worker print_tcpf(tcpinfo->flg_cmp);
362*a71a9546SAutomerger Merge Worker }
363*a71a9546SAutomerger Merge Worker }
364*a71a9546SAutomerger Merge Worker
365*a71a9546SAutomerger Merge Worker static const struct tcp_flag_names tcp_flag_names_xlate[] = {
366*a71a9546SAutomerger Merge Worker { "fin", 0x01 },
367*a71a9546SAutomerger Merge Worker { "syn", 0x02 },
368*a71a9546SAutomerger Merge Worker { "rst", 0x04 },
369*a71a9546SAutomerger Merge Worker { "psh", 0x08 },
370*a71a9546SAutomerger Merge Worker { "ack", 0x10 },
371*a71a9546SAutomerger Merge Worker { "urg", 0x20 },
372*a71a9546SAutomerger Merge Worker };
373*a71a9546SAutomerger Merge Worker
print_tcp_xlate(struct xt_xlate * xl,uint8_t flags)374*a71a9546SAutomerger Merge Worker static void print_tcp_xlate(struct xt_xlate *xl, uint8_t flags)
375*a71a9546SAutomerger Merge Worker {
376*a71a9546SAutomerger Merge Worker int have_flag = 0;
377*a71a9546SAutomerger Merge Worker
378*a71a9546SAutomerger Merge Worker while (flags) {
379*a71a9546SAutomerger Merge Worker unsigned int i;
380*a71a9546SAutomerger Merge Worker
381*a71a9546SAutomerger Merge Worker for (i = 0; (flags & tcp_flag_names_xlate[i].flag) == 0; i++);
382*a71a9546SAutomerger Merge Worker
383*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "%s%s",
384*a71a9546SAutomerger Merge Worker have_flag ? "," : "",
385*a71a9546SAutomerger Merge Worker tcp_flag_names_xlate[i].name);
386*a71a9546SAutomerger Merge Worker have_flag = 1;
387*a71a9546SAutomerger Merge Worker
388*a71a9546SAutomerger Merge Worker flags &= ~tcp_flag_names_xlate[i].flag;
389*a71a9546SAutomerger Merge Worker }
390*a71a9546SAutomerger Merge Worker
391*a71a9546SAutomerger Merge Worker if (!have_flag)
392*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "0x0");
393*a71a9546SAutomerger Merge Worker }
394*a71a9546SAutomerger Merge Worker
tcp_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)395*a71a9546SAutomerger Merge Worker static int tcp_xlate(struct xt_xlate *xl,
396*a71a9546SAutomerger Merge Worker const struct xt_xlate_mt_params *params)
397*a71a9546SAutomerger Merge Worker {
398*a71a9546SAutomerger Merge Worker const struct xt_tcp *tcpinfo =
399*a71a9546SAutomerger Merge Worker (const struct xt_tcp *)params->match->data;
400*a71a9546SAutomerger Merge Worker
401*a71a9546SAutomerger Merge Worker if (tcpinfo->spts[0] != 0 || tcpinfo->spts[1] != 0xffff) {
402*a71a9546SAutomerger Merge Worker if (tcpinfo->spts[0] != tcpinfo->spts[1]) {
403*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "tcp sport %s%u-%u",
404*a71a9546SAutomerger Merge Worker tcpinfo->invflags & XT_TCP_INV_SRCPT ?
405*a71a9546SAutomerger Merge Worker "!= " : "",
406*a71a9546SAutomerger Merge Worker tcpinfo->spts[0], tcpinfo->spts[1]);
407*a71a9546SAutomerger Merge Worker } else {
408*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "tcp sport %s%u",
409*a71a9546SAutomerger Merge Worker tcpinfo->invflags & XT_TCP_INV_SRCPT ?
410*a71a9546SAutomerger Merge Worker "!= " : "",
411*a71a9546SAutomerger Merge Worker tcpinfo->spts[0]);
412*a71a9546SAutomerger Merge Worker }
413*a71a9546SAutomerger Merge Worker }
414*a71a9546SAutomerger Merge Worker
415*a71a9546SAutomerger Merge Worker if (tcpinfo->dpts[0] != 0 || tcpinfo->dpts[1] != 0xffff) {
416*a71a9546SAutomerger Merge Worker if (tcpinfo->dpts[0] != tcpinfo->dpts[1]) {
417*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "tcp dport %s%u-%u",
418*a71a9546SAutomerger Merge Worker tcpinfo->invflags & XT_TCP_INV_DSTPT ?
419*a71a9546SAutomerger Merge Worker "!= " : "",
420*a71a9546SAutomerger Merge Worker tcpinfo->dpts[0], tcpinfo->dpts[1]);
421*a71a9546SAutomerger Merge Worker } else {
422*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "tcp dport %s%u",
423*a71a9546SAutomerger Merge Worker tcpinfo->invflags & XT_TCP_INV_DSTPT ?
424*a71a9546SAutomerger Merge Worker "!= " : "",
425*a71a9546SAutomerger Merge Worker tcpinfo->dpts[0]);
426*a71a9546SAutomerger Merge Worker }
427*a71a9546SAutomerger Merge Worker }
428*a71a9546SAutomerger Merge Worker
429*a71a9546SAutomerger Merge Worker if (tcpinfo->option)
430*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "tcp option %u %s", tcpinfo->option,
431*a71a9546SAutomerger Merge Worker tcpinfo->invflags & XT_TCP_INV_OPTION ?
432*a71a9546SAutomerger Merge Worker "missing" : "exists");
433*a71a9546SAutomerger Merge Worker
434*a71a9546SAutomerger Merge Worker if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) {
435*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "tcp flags %s",
436*a71a9546SAutomerger Merge Worker tcpinfo->invflags & XT_TCP_INV_FLAGS ? "!= ": "");
437*a71a9546SAutomerger Merge Worker print_tcp_xlate(xl, tcpinfo->flg_cmp);
438*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, " / ");
439*a71a9546SAutomerger Merge Worker print_tcp_xlate(xl, tcpinfo->flg_mask);
440*a71a9546SAutomerger Merge Worker }
441*a71a9546SAutomerger Merge Worker
442*a71a9546SAutomerger Merge Worker return 1;
443*a71a9546SAutomerger Merge Worker }
444*a71a9546SAutomerger Merge Worker
445*a71a9546SAutomerger Merge Worker static struct xtables_match tcp_match = {
446*a71a9546SAutomerger Merge Worker .family = NFPROTO_UNSPEC,
447*a71a9546SAutomerger Merge Worker .name = "tcp",
448*a71a9546SAutomerger Merge Worker .version = XTABLES_VERSION,
449*a71a9546SAutomerger Merge Worker .size = XT_ALIGN(sizeof(struct xt_tcp)),
450*a71a9546SAutomerger Merge Worker .userspacesize = XT_ALIGN(sizeof(struct xt_tcp)),
451*a71a9546SAutomerger Merge Worker .help = tcp_help,
452*a71a9546SAutomerger Merge Worker .init = tcp_init,
453*a71a9546SAutomerger Merge Worker .parse = tcp_parse,
454*a71a9546SAutomerger Merge Worker .print = tcp_print,
455*a71a9546SAutomerger Merge Worker .save = tcp_save,
456*a71a9546SAutomerger Merge Worker .extra_opts = tcp_opts,
457*a71a9546SAutomerger Merge Worker .xlate = tcp_xlate,
458*a71a9546SAutomerger Merge Worker };
459*a71a9546SAutomerger Merge Worker
460*a71a9546SAutomerger Merge Worker void
_init(void)461*a71a9546SAutomerger Merge Worker _init(void)
462*a71a9546SAutomerger Merge Worker {
463*a71a9546SAutomerger Merge Worker xtables_register_match(&tcp_match);
464*a71a9546SAutomerger Merge Worker }
465