iptables-1.2.9-2.3.1.src.rpm
[iptables.git] / extensions / libipt_length.c
1 /* Shared library add-on to iptables to add packet length matching support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7
8 #include <iptables.h>
9 #include <linux/netfilter_ipv4/ipt_length.h>
10
11 /* Function which prints out usage message. */
12 static void
13 help(void)
14 {
15         printf(
16 "length v%s options:\n"
17 "[!] --length length[:length]    Match packet length against value or range\n"
18 "                                of values (inclusive)\n",
19 IPTABLES_VERSION);
20
21 }
22   
23 static struct option opts[] = {
24         { "length", 1, 0, '1' },
25         {0}
26 };
27
28 /* Initialize the match. */
29 static void
30 init(struct ipt_entry_match *m, unsigned int *nfcache)
31 {
32         *nfcache |= NFC_UNKNOWN;
33 }
34
35 static u_int16_t
36 parse_length(const char *s)
37 {
38         unsigned int len;
39         
40         if (string_to_number(s, 0, 0xFFFF, &len) == -1)
41                 exit_error(PARAMETER_PROBLEM, "length invalid: `%s'\n", s);
42         else
43                 return (u_int16_t )len;
44 }
45
46 /* If a single value is provided, min and max are both set to the value */
47 static void
48 parse_lengths(const char *s, struct ipt_length_info *info)
49 {
50         char *buffer;
51         char *cp;
52
53         buffer = strdup(s);
54         if ((cp = strchr(buffer, ':')) == NULL)
55                 info->min = info->max = parse_length(buffer);
56         else {
57                 *cp = '\0';
58                 cp++;
59
60                 info->min = buffer[0] ? parse_length(buffer) : 0;
61                 info->max = cp[0] ? parse_length(cp) : 0xFFFF;
62         }
63         free(buffer);
64         
65         if (info->min > info->max)
66                 exit_error(PARAMETER_PROBLEM,
67                            "length min. range value `%u' greater than max. "
68                            "range value `%u'", info->min, info->max);
69         
70 }
71
72 /* Function which parses command options; returns true if it
73    ate an option */
74 static int
75 parse(int c, char **argv, int invert, unsigned int *flags,
76       const struct ipt_entry *entry,
77       unsigned int *nfcache,
78       struct ipt_entry_match **match)
79 {
80         struct ipt_length_info *info = (struct ipt_length_info *)(*match)->data;
81
82         switch (c) {
83                 case '1':
84                         if (*flags)
85                                 exit_error(PARAMETER_PROBLEM,
86                                            "length: `--length' may only be "
87                                            "specified once");
88                         check_inverse(optarg, &invert, &optind, 0);
89                         parse_lengths(argv[optind-1], info);
90                         if (invert)
91                                 info->invert = 1;
92                         *flags = 1;
93                         break;
94                         
95                 default:
96                         return 0;
97         }
98         return 1;
99 }
100
101 /* Final check; must have specified --length. */
102 static void
103 final_check(unsigned int flags)
104 {
105         if (!flags)
106                 exit_error(PARAMETER_PROBLEM,
107                            "length: You must specify `--length'");
108 }
109
110 /* Common match printing code. */
111 static void
112 print_length(struct ipt_length_info *info)
113 {
114         if (info->invert)
115                 printf("! ");
116         
117         if (info->max == info->min)
118                 printf("%u ", info->min);
119         else
120                 printf("%u:%u ", info->min, info->max);
121 }
122
123 /* Prints out the matchinfo. */
124 static void
125 print(const struct ipt_ip *ip,
126       const struct ipt_entry_match *match,
127       int numeric)
128 {
129         printf("length ");
130         print_length((struct ipt_length_info *)match->data);
131 }
132
133 /* Saves the union ipt_matchinfo in parsable form to stdout. */
134 static void
135 save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
136 {
137         printf("--length ");
138         print_length((struct ipt_length_info *)match->data);
139 }
140
141 static
142 struct iptables_match length
143 = { NULL,
144     "length",
145     IPTABLES_VERSION,
146     IPT_ALIGN(sizeof(struct ipt_length_info)),
147     IPT_ALIGN(sizeof(struct ipt_length_info)),
148     &help,
149     &init,
150     &parse,
151     &final_check,
152     &print,
153     &save,
154     opts
155 };
156
157 void _init(void)
158 {
159         register_match(&length);
160 }