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