changing trunk/trunk to trunk
[iptables.git] / extensions / libip6t_ah.c
1 /* Shared library add-on to ip6tables to add AH support. */
2 #include <stdio.h>
3 #include <netdb.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7 #include <errno.h>
8 #include <ip6tables.h>
9 #include <linux/netfilter_ipv6/ip6t_ah.h>
10                                         
11 /* Function which prints out usage message. */
12 static void ah_help(void)
13 {
14         printf(
15 "ah match options:\n"
16 " --ahspi [!] spi[:spi]         match spi (range)\n"
17 " --ahlen [!] length            total length of this header\n"
18 " --ahres                       check the reserved filed, too\n");
19 }
20
21 static const struct option ah_opts[] = {
22         { .name = "ahspi", .has_arg = 1, .val = '1' },
23         { .name = "ahlen", .has_arg = 1, .val = '2' },
24         { .name = "ahres", .has_arg = 0, .val = '3' },
25         { .name = NULL }
26 };
27
28 static u_int32_t
29 parse_ah_spi(const char *spistr, const char *typestr)
30 {
31         unsigned long int spi;
32         char* ep;
33
34         spi = strtoul(spistr, &ep, 0);
35
36         if ( spistr == ep )
37                 exit_error(PARAMETER_PROBLEM,
38                            "AH no valid digits in %s `%s'", typestr, spistr);
39
40         if ( spi == ULONG_MAX  && errno == ERANGE )
41                 exit_error(PARAMETER_PROBLEM,
42                            "%s `%s' specified too big: would overflow",
43                            typestr, spistr);
44
45         if ( *spistr != '\0'  && *ep != '\0' )
46                 exit_error(PARAMETER_PROBLEM,
47                            "AH error parsing %s `%s'", typestr, spistr);
48
49         return (u_int32_t) spi;
50 }
51
52 static void
53 parse_ah_spis(const char *spistring, u_int32_t *spis)
54 {
55         char *buffer;
56         char *cp;
57
58         buffer = strdup(spistring);
59         if ((cp = strchr(buffer, ':')) == NULL)
60                 spis[0] = spis[1] = parse_ah_spi(buffer, "spi");
61         else {
62                 *cp = '\0';
63                 cp++;
64
65                 spis[0] = buffer[0] ? parse_ah_spi(buffer, "spi") : 0;
66                 spis[1] = cp[0] ? parse_ah_spi(cp, "spi") : 0xFFFFFFFF;
67         }
68         free(buffer);
69 }
70
71 /* Initialize the match. */
72 static void ah_init(struct xt_entry_match *m)
73 {
74         struct ip6t_ah *ahinfo = (struct ip6t_ah *)m->data;
75
76         ahinfo->spis[1] = 0xFFFFFFFF;
77         ahinfo->hdrlen = 0;
78         ahinfo->hdrres = 0;
79 }
80
81 /* Function which parses command options; returns true if it
82    ate an option */
83 static int ah_parse(int c, char **argv, int invert, unsigned int *flags,
84                     const void *entry, struct xt_entry_match **match)
85 {
86         struct ip6t_ah *ahinfo = (struct ip6t_ah *)(*match)->data;
87
88         switch (c) {
89         case '1':
90                 if (*flags & IP6T_AH_SPI)
91                         exit_error(PARAMETER_PROBLEM,
92                                    "Only one `--ahspi' allowed");
93                 check_inverse(optarg, &invert, &optind, 0);
94                 parse_ah_spis(argv[optind-1], ahinfo->spis);
95                 if (invert)
96                         ahinfo->invflags |= IP6T_AH_INV_SPI;
97                 *flags |= IP6T_AH_SPI;
98                 break;
99         case '2':
100                 if (*flags & IP6T_AH_LEN)
101                         exit_error(PARAMETER_PROBLEM,
102                                    "Only one `--ahlen' allowed");
103                 check_inverse(optarg, &invert, &optind, 0);
104                 ahinfo->hdrlen = parse_ah_spi(argv[optind-1], "length");
105                 if (invert)
106                         ahinfo->invflags |= IP6T_AH_INV_LEN;
107                 *flags |= IP6T_AH_LEN;
108                 break;
109         case '3':
110                 if (*flags & IP6T_AH_RES)
111                         exit_error(PARAMETER_PROBLEM,
112                                    "Only one `--ahres' allowed");
113                 ahinfo->hdrres = 1;
114                 *flags |= IP6T_AH_RES;
115                 break;
116         default:
117                 return 0;
118         }
119
120         return 1;
121 }
122
123 static void
124 print_spis(const char *name, u_int32_t min, u_int32_t max,
125             int invert)
126 {
127         const char *inv = invert ? "!" : "";
128
129         if (min != 0 || max != 0xFFFFFFFF || invert) {
130                 if (min == max)
131                         printf("%s:%s%u ", name, inv, min);
132                 else
133                         printf("%ss:%s%u:%u ", name, inv, min, max);
134         }
135 }
136
137 static void
138 print_len(const char *name, u_int32_t len, int invert)
139 {
140         const char *inv = invert ? "!" : "";
141
142         if (len != 0 || invert)
143                 printf("%s:%s%u ", name, inv, len);
144 }
145
146 /* Prints out the union ip6t_matchinfo. */
147 static void ah_print(const void *ip, const struct xt_entry_match *match,
148                      int numeric)
149 {
150         const struct ip6t_ah *ah = (struct ip6t_ah *)match->data;
151
152         printf("ah ");
153         print_spis("spi", ah->spis[0], ah->spis[1],
154                     ah->invflags & IP6T_AH_INV_SPI);
155         print_len("length", ah->hdrlen, 
156                     ah->invflags & IP6T_AH_INV_LEN);
157
158         if (ah->hdrres)
159                 printf("reserved ");
160
161         if (ah->invflags & ~IP6T_AH_INV_MASK)
162                 printf("Unknown invflags: 0x%X ",
163                        ah->invflags & ~IP6T_AH_INV_MASK);
164 }
165
166 /* Saves the union ip6t_matchinfo in parsable form to stdout. */
167 static void ah_save(const void *ip, const struct xt_entry_match *match)
168 {
169         const struct ip6t_ah *ahinfo = (struct ip6t_ah *)match->data;
170
171         if (!(ahinfo->spis[0] == 0
172             && ahinfo->spis[1] == 0xFFFFFFFF)) {
173                 printf("--ahspi %s", 
174                         (ahinfo->invflags & IP6T_AH_INV_SPI) ? "! " : "");
175                 if (ahinfo->spis[0]
176                     != ahinfo->spis[1])
177                         printf("%u:%u ",
178                                ahinfo->spis[0],
179                                ahinfo->spis[1]);
180                 else
181                         printf("%u ",
182                                ahinfo->spis[0]);
183         }
184
185         if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) {
186                 printf("--ahlen %s%u ", 
187                         (ahinfo->invflags & IP6T_AH_INV_LEN) ? "! " : "", 
188                         ahinfo->hdrlen);
189         }
190
191         if (ahinfo->hdrres != 0 )
192                 printf("--ahres ");
193 }
194
195 static struct xtables_match ah_mt6_reg = {
196         .name          = "ah",
197         .version       = XTABLES_VERSION,
198         .family        = PF_INET6,
199         .size          = XT_ALIGN(sizeof(struct ip6t_ah)),
200         .userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)),
201         .help          = ah_help,
202         .init          = ah_init,
203         .parse         = ah_parse,
204         .print         = ah_print,
205         .save          = ah_save,
206         .extra_opts    = ah_opts,
207 };
208
209 void
210 _init(void)
211 {
212         xtables_register_match(&ah_mt6_reg);
213 }