~csurbhi/ubuntu/maverick/iptables/iptable-fix.600195

« back to all changes in this revision

Viewing changes to iptables/extensions/libipt_tcp.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2008-06-24 15:06:04 UTC
  • mfrom: (5.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080624150604-5t7r1o1kxq0ycz81
Tags: 1.4.0-4ubuntu1
* Merge from debian unstable, remaining changes:
  - Took references to 2.4 kernel out of doc-base control files (Jordan
    Mantha, Malone #25972) (patches/all/091-fix-2.4-references.patch)
  - Use linux-libc-dev instead of local copy of kernel-headers.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Shared library add-on to iptables to add TCP support. */
2
 
#include <stdio.h>
3
 
#include <netdb.h>
4
 
#include <string.h>
5
 
#include <stdlib.h>
6
 
#include <getopt.h>
7
 
#include <iptables.h>
8
 
#include <linux/netfilter_ipv4/ip_tables.h>
9
 
 
10
 
/* Function which prints out usage message. */
11
 
static void
12
 
help(void)
13
 
{
14
 
        printf(
15
 
"TCP v%s options:\n"
16
 
" --tcp-flags [!] mask comp     match when TCP flags & mask == comp\n"
17
 
"                               (Flags: SYN ACK FIN RST URG PSH ALL NONE)\n"
18
 
"[!] --syn                      match when only SYN flag set\n"
19
 
"                               (equivalent to --tcp-flags SYN,RST,ACK SYN)\n"
20
 
" --source-port [!] port[:port]\n"
21
 
" --sport ...\n"
22
 
"                               match source port(s)\n"
23
 
" --destination-port [!] port[:port]\n"
24
 
" --dport ...\n"
25
 
"                               match destination port(s)\n"
26
 
" --tcp-option [!] number       match if TCP option set\n\n",
27
 
IPTABLES_VERSION);
28
 
}
29
 
 
30
 
static struct option opts[] = {
31
 
        { "source-port", 1, 0, '1' },
32
 
        { "sport", 1, 0, '1' }, /* synonym */
33
 
        { "destination-port", 1, 0, '2' },
34
 
        { "dport", 1, 0, '2' }, /* synonym */
35
 
        { "syn", 0, 0, '3' },
36
 
        { "tcp-flags", 1, 0, '4' },
37
 
        { "tcp-option", 1, 0, '5' },
38
 
        {0}
39
 
};
40
 
 
41
 
static void
42
 
parse_tcp_ports(const char *portstring, u_int16_t *ports)
43
 
{
44
 
        char *buffer;
45
 
        char *cp;
46
 
 
47
 
        buffer = strdup(portstring);
48
 
        if ((cp = strchr(buffer, ':')) == NULL)
49
 
                ports[0] = ports[1] = parse_port(buffer, "tcp");
50
 
        else {
51
 
                *cp = '\0';
52
 
                cp++;
53
 
 
54
 
                ports[0] = buffer[0] ? parse_port(buffer, "tcp") : 0;
55
 
                ports[1] = cp[0] ? parse_port(cp, "tcp") : 0xFFFF;
56
 
 
57
 
                if (ports[0] > ports[1])
58
 
                        exit_error(PARAMETER_PROBLEM,
59
 
                                   "invalid portrange (min > max)");
60
 
        }
61
 
        free(buffer);
62
 
}
63
 
 
64
 
struct tcp_flag_names {
65
 
        const char *name;
66
 
        unsigned int flag;
67
 
};
68
 
 
69
 
static struct tcp_flag_names tcp_flag_names[]
70
 
= { { "FIN", 0x01 },
71
 
    { "SYN", 0x02 },
72
 
    { "RST", 0x04 },
73
 
    { "PSH", 0x08 },
74
 
    { "ACK", 0x10 },
75
 
    { "URG", 0x20 },
76
 
    { "ALL", 0x3F },
77
 
    { "NONE", 0 },
78
 
};
79
 
 
80
 
static unsigned int
81
 
parse_tcp_flag(const char *flags)
82
 
{
83
 
        unsigned int ret = 0;
84
 
        char *ptr;
85
 
        char *buffer;
86
 
 
87
 
        buffer = strdup(flags);
88
 
 
89
 
        for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
90
 
                unsigned int i;
91
 
                for (i = 0;
92
 
                     i < sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names);
93
 
                     i++) {
94
 
                        if (strcasecmp(tcp_flag_names[i].name, ptr) == 0) {
95
 
                                ret |= tcp_flag_names[i].flag;
96
 
                                break;
97
 
                        }
98
 
                }
99
 
                if (i == sizeof(tcp_flag_names)/sizeof(struct tcp_flag_names))
100
 
                        exit_error(PARAMETER_PROBLEM,
101
 
                                   "Unknown TCP flag `%s'", ptr);
102
 
                }
103
 
 
104
 
        free(buffer);
105
 
        return ret;
106
 
}
107
 
 
108
 
static void
109
 
parse_tcp_flags(struct ipt_tcp *tcpinfo,
110
 
                const char *mask,
111
 
                const char *cmp,
112
 
                int invert)
113
 
{
114
 
        tcpinfo->flg_mask = parse_tcp_flag(mask);
115
 
        tcpinfo->flg_cmp = parse_tcp_flag(cmp);
116
 
 
117
 
        if (invert)
118
 
                tcpinfo->invflags |= IPT_TCP_INV_FLAGS;
119
 
}
120
 
 
121
 
static void
122
 
parse_tcp_option(const char *option, u_int8_t *result)
123
 
{
124
 
        unsigned int ret;
125
 
 
126
 
        if (string_to_number(option, 1, 255, &ret) == -1)
127
 
                exit_error(PARAMETER_PROBLEM, "Bad TCP option `%s'", option);
128
 
 
129
 
        *result = (u_int8_t)ret;
130
 
}
131
 
 
132
 
/* Initialize the match. */
133
 
static void
134
 
init(struct ipt_entry_match *m, unsigned int *nfcache)
135
 
{
136
 
        struct ipt_tcp *tcpinfo = (struct ipt_tcp *)m->data;
137
 
 
138
 
        tcpinfo->spts[1] = tcpinfo->dpts[1] = 0xFFFF;
139
 
}
140
 
 
141
 
#define TCP_SRC_PORTS 0x01
142
 
#define TCP_DST_PORTS 0x02
143
 
#define TCP_FLAGS 0x04
144
 
#define TCP_OPTION      0x08
145
 
 
146
 
/* Function which parses command options; returns true if it
147
 
   ate an option. */
148
 
static int
149
 
parse(int c, char **argv, int invert, unsigned int *flags,
150
 
      const struct ipt_entry *entry,
151
 
      unsigned int *nfcache,
152
 
      struct ipt_entry_match **match)
153
 
{
154
 
        struct ipt_tcp *tcpinfo = (struct ipt_tcp *)(*match)->data;
155
 
 
156
 
        switch (c) {
157
 
        case '1':
158
 
                if (*flags & TCP_SRC_PORTS)
159
 
                        exit_error(PARAMETER_PROBLEM,
160
 
                                   "Only one `--source-port' allowed");
161
 
                check_inverse(optarg, &invert, &optind, 0);
162
 
                parse_tcp_ports(argv[optind-1], tcpinfo->spts);
163
 
                if (invert)
164
 
                        tcpinfo->invflags |= IPT_TCP_INV_SRCPT;
165
 
                *flags |= TCP_SRC_PORTS;
166
 
                break;
167
 
 
168
 
        case '2':
169
 
                if (*flags & TCP_DST_PORTS)
170
 
                        exit_error(PARAMETER_PROBLEM,
171
 
                                   "Only one `--destination-port' allowed");
172
 
                check_inverse(optarg, &invert, &optind, 0);
173
 
                parse_tcp_ports(argv[optind-1], tcpinfo->dpts);
174
 
                if (invert)
175
 
                        tcpinfo->invflags |= IPT_TCP_INV_DSTPT;
176
 
                *flags |= TCP_DST_PORTS;
177
 
                break;
178
 
 
179
 
        case '3':
180
 
                if (*flags & TCP_FLAGS)
181
 
                        exit_error(PARAMETER_PROBLEM,
182
 
                                   "Only one of `--syn' or `--tcp-flags' "
183
 
                                   " allowed");
184
 
                parse_tcp_flags(tcpinfo, "SYN,RST,ACK,FIN", "SYN", invert);
185
 
                *flags |= TCP_FLAGS;
186
 
                break;
187
 
 
188
 
        case '4':
189
 
                if (*flags & TCP_FLAGS)
190
 
                        exit_error(PARAMETER_PROBLEM,
191
 
                                   "Only one of `--syn' or `--tcp-flags' "
192
 
                                   " allowed");
193
 
                check_inverse(optarg, &invert, &optind, 0);
194
 
 
195
 
                if (!argv[optind]
196
 
                    || argv[optind][0] == '-' || argv[optind][0] == '!')
197
 
                        exit_error(PARAMETER_PROBLEM,
198
 
                                   "--tcp-flags requires two args.");
199
 
 
200
 
                parse_tcp_flags(tcpinfo, argv[optind-1], argv[optind],
201
 
                                invert);
202
 
                optind++;
203
 
                *flags |= TCP_FLAGS;
204
 
                break;
205
 
 
206
 
        case '5':
207
 
                if (*flags & TCP_OPTION)
208
 
                        exit_error(PARAMETER_PROBLEM,
209
 
                                   "Only one `--tcp-option' allowed");
210
 
                check_inverse(optarg, &invert, &optind, 0);
211
 
                parse_tcp_option(argv[optind-1], &tcpinfo->option);
212
 
                if (invert)
213
 
                        tcpinfo->invflags |= IPT_TCP_INV_OPTION;
214
 
                *flags |= TCP_OPTION;
215
 
                break;
216
 
 
217
 
        default:
218
 
                return 0;
219
 
        }
220
 
 
221
 
        return 1;
222
 
}
223
 
 
224
 
/* Final check; we don't care. */
225
 
static void
226
 
final_check(unsigned int flags)
227
 
{
228
 
}
229
 
 
230
 
static char *
231
 
port_to_service(int port)
232
 
{
233
 
        struct servent *service;
234
 
 
235
 
        if ((service = getservbyport(htons(port), "tcp")))
236
 
                return service->s_name;
237
 
 
238
 
        return NULL;
239
 
}
240
 
 
241
 
static void
242
 
print_port(u_int16_t port, int numeric)
243
 
{
244
 
        char *service;
245
 
 
246
 
        if (numeric || (service = port_to_service(port)) == NULL)
247
 
                printf("%u", port);
248
 
        else
249
 
                printf("%s", service);
250
 
}
251
 
 
252
 
static void
253
 
print_ports(const char *name, u_int16_t min, u_int16_t max,
254
 
            int invert, int numeric)
255
 
{
256
 
        const char *inv = invert ? "!" : "";
257
 
 
258
 
        if (min != 0 || max != 0xFFFF || invert) {
259
 
                printf("%s", name);
260
 
                if (min == max) {
261
 
                        printf(":%s", inv);
262
 
                        print_port(min, numeric);
263
 
                } else {
264
 
                        printf("s:%s", inv);
265
 
                        print_port(min, numeric);
266
 
                        printf(":");
267
 
                        print_port(max, numeric);
268
 
                }
269
 
                printf(" ");
270
 
        }
271
 
}
272
 
 
273
 
static void
274
 
print_option(u_int8_t option, int invert, int numeric)
275
 
{
276
 
        if (option || invert)
277
 
                printf("option=%s%u ", invert ? "!" : "", option);
278
 
}
279
 
 
280
 
static void
281
 
print_tcpf(u_int8_t flags)
282
 
{
283
 
        int have_flag = 0;
284
 
 
285
 
        while (flags) {
286
 
                unsigned int i;
287
 
 
288
 
                for (i = 0; (flags & tcp_flag_names[i].flag) == 0; i++);
289
 
 
290
 
                if (have_flag)
291
 
                        printf(",");
292
 
                printf("%s", tcp_flag_names[i].name);
293
 
                have_flag = 1;
294
 
 
295
 
                flags &= ~tcp_flag_names[i].flag;
296
 
        }
297
 
 
298
 
        if (!have_flag)
299
 
                printf("NONE");
300
 
}
301
 
 
302
 
static void
303
 
print_flags(u_int8_t mask, u_int8_t cmp, int invert, int numeric)
304
 
{
305
 
        if (mask || invert) {
306
 
                printf("flags:%s", invert ? "!" : "");
307
 
                if (numeric)
308
 
                        printf("0x%02X/0x%02X ", mask, cmp);
309
 
                else {
310
 
                        print_tcpf(mask);
311
 
                        printf("/");
312
 
                        print_tcpf(cmp);
313
 
                        printf(" ");
314
 
                }
315
 
        }
316
 
}
317
 
 
318
 
/* Prints out the union ipt_matchinfo. */
319
 
static void
320
 
print(const struct ipt_ip *ip,
321
 
      const struct ipt_entry_match *match, int numeric)
322
 
{
323
 
        const struct ipt_tcp *tcp = (struct ipt_tcp *)match->data;
324
 
 
325
 
        printf("tcp ");
326
 
        print_ports("spt", tcp->spts[0], tcp->spts[1],
327
 
                    tcp->invflags & IPT_TCP_INV_SRCPT,
328
 
                    numeric);
329
 
        print_ports("dpt", tcp->dpts[0], tcp->dpts[1],
330
 
                    tcp->invflags & IPT_TCP_INV_DSTPT,
331
 
                    numeric);
332
 
        print_option(tcp->option,
333
 
                     tcp->invflags & IPT_TCP_INV_OPTION,
334
 
                     numeric);
335
 
        print_flags(tcp->flg_mask, tcp->flg_cmp,
336
 
                    tcp->invflags & IPT_TCP_INV_FLAGS,
337
 
                    numeric);
338
 
        if (tcp->invflags & ~IPT_TCP_INV_MASK)
339
 
                printf("Unknown invflags: 0x%X ",
340
 
                       tcp->invflags & ~IPT_TCP_INV_MASK);
341
 
}
342
 
 
343
 
/* Saves the union ipt_matchinfo in parsable form to stdout. */
344
 
static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
345
 
{
346
 
        const struct ipt_tcp *tcpinfo = (struct ipt_tcp *)match->data;
347
 
 
348
 
        if (tcpinfo->spts[0] != 0
349
 
            || tcpinfo->spts[1] != 0xFFFF) {
350
 
                if (tcpinfo->invflags & IPT_TCP_INV_SRCPT)
351
 
                        printf("! ");
352
 
                if (tcpinfo->spts[0]
353
 
                    != tcpinfo->spts[1])
354
 
                        printf("--sport %u:%u ",
355
 
                               tcpinfo->spts[0],
356
 
                               tcpinfo->spts[1]);
357
 
                else
358
 
                        printf("--sport %u ",
359
 
                               tcpinfo->spts[0]);
360
 
        }
361
 
 
362
 
        if (tcpinfo->dpts[0] != 0
363
 
            || tcpinfo->dpts[1] != 0xFFFF) {
364
 
                if (tcpinfo->invflags & IPT_TCP_INV_DSTPT)
365
 
                        printf("! ");
366
 
                if (tcpinfo->dpts[0]
367
 
                    != tcpinfo->dpts[1])
368
 
                        printf("--dport %u:%u ",
369
 
                               tcpinfo->dpts[0],
370
 
                               tcpinfo->dpts[1]);
371
 
                else
372
 
                        printf("--dport %u ",
373
 
                               tcpinfo->dpts[0]);
374
 
        }
375
 
 
376
 
        if (tcpinfo->option
377
 
            || (tcpinfo->invflags & IPT_TCP_INV_OPTION)) {
378
 
                if (tcpinfo->invflags & IPT_TCP_INV_OPTION)
379
 
                        printf("! ");
380
 
                printf("--tcp-option %u ", tcpinfo->option);
381
 
        }
382
 
 
383
 
        if (tcpinfo->flg_mask
384
 
            || (tcpinfo->invflags & IPT_TCP_INV_FLAGS)) {
385
 
                if (tcpinfo->invflags & IPT_TCP_INV_FLAGS)
386
 
                        printf("! ");
387
 
                printf("--tcp-flags ");
388
 
                if (tcpinfo->flg_mask != 0xFF) {
389
 
                        print_tcpf(tcpinfo->flg_mask);
390
 
                }
391
 
                printf(" ");
392
 
                print_tcpf(tcpinfo->flg_cmp);
393
 
                printf(" ");
394
 
        }
395
 
}
396
 
 
397
 
static struct iptables_match tcp = { 
398
 
        .next           = NULL,
399
 
        .name           = "tcp",
400
 
        .version        = IPTABLES_VERSION,
401
 
        .size           = IPT_ALIGN(sizeof(struct ipt_tcp)),
402
 
        .userspacesize  = IPT_ALIGN(sizeof(struct ipt_tcp)),
403
 
        .help           = &help,
404
 
        .init           = &init,
405
 
        .parse          = &parse,
406
 
        .final_check    = &final_check,
407
 
        .print          = &print,
408
 
        .save           = &save,
409
 
        .extra_opts     = opts
410
 
};
411
 
 
412
 
void
413
 
_init(void)
414
 
{
415
 
        register_match(&tcp);
416
 
}