Merge to iptables-1.3.5
[iptables.git] / extensions / libipt_rpc.c
1 /* RPC extension for IP connection matching, Version 2.2
2  * (C) 2000 by Marcelo Barbosa Lima <marcelo.lima@dcc.unicamp.br>
3  *      - original rpc tracking module
4  *      - "recent" connection handling for kernel 2.3+ netfilter
5  *
6  * (C) 2001 by Rusty Russell <rusty@rustcorp.com.au>
7  *      - upgraded conntrack modules to oldnat api - kernel 2.4.0+
8  *
9  * (C) 2002,2003 by Ian (Larry) Latter <Ian.Latter@mq.edu.au>
10  *      - upgraded conntrack modules to newnat api - kernel 2.4.20+
11  *      - extended matching to support filtering on procedures
12  *
13  * libipt_rpc.c,v 2.2 2003/01/12 18:30:00
14  *
15  *      This program is free software; you can redistribute it and/or
16  *      modify it under the terms of the GNU General Public License
17  *      as published by the Free Software Foundation; either version
18  *      2 of the License, or (at your option) any later version.
19  **
20  *      Userspace library syntax:
21  *      --rpc [--rpcs procedure1,procedure2,...procedure128] [--static]
22  *
23  *      Procedures can be supplied in either numeric or named formats.
24  *      Without --rpcs, this module will behave as the old record-rpc.
25  **
26  *      Note to all:
27  *
28  *      RPCs should not be exposed to the internet - ask the Pentagon;
29  *
30  *        "The unidentified crackers pleaded guilty in July to charges
31  *         of juvenile delinquency stemming from a string of Pentagon
32  *         network intrusions in February.
33  *
34  *         The youths, going by the names TooShort and Makaveli, used
35  *         a common server security hole to break in, according to
36  *         Dane Jasper, owner of the California Internet service
37  *         provider, Sonic. They used the hole, known as the 'statd'
38  *         exploit, to attempt more than 800 break-ins, Jasper said."
39  *
40  *      From: Wired News; "Pentagon Kids Kicked Off Grid" - Nov 6, 1998
41  *      URL:  http://www.wired.com/news/politics/0,1283,16098,00.html
42  **
43  */
44
45 #include <stdio.h>
46 #include <netdb.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <getopt.h>
50 #include <rpc/rpc.h>
51
52 #include <iptables.h>
53 #include <linux/netfilter_ipv4/ipt_rpc.h>
54 #include <time.h>
55
56
57 const int IPT_RPC_RPCS = 1;
58 const int IPT_RPC_STRC = 2;
59
60 const int IPT_RPC_INT_LBL = 1;
61 const int IPT_RPC_INT_NUM = 2;
62 const int IPT_RPC_INT_BTH = 3;
63
64 const int IPT_RPC_CHAR_LEN = 11;
65 const int IPT_RPC_MAX_ENTS = 128;
66
67 const char preerr[11] = "RPC match:";
68
69
70 static int k_itoa(char *string, int number)
71 {
72         int maxoctet = IPT_RPC_CHAR_LEN - 1;
73         int store[IPT_RPC_CHAR_LEN];
74         int counter;
75
76
77         for (counter=0 ; maxoctet != 0 && number != 0; counter++, maxoctet--) {
78                 store[counter] = number / 10;
79                 store[counter] = number - ( store[counter] * 10 );
80                 number = number / 10;
81         }
82
83         for ( ; counter != 0; counter--, string++)
84                 *string = store[counter - 1] + 48;
85
86         *string = 0;
87
88         return(0);
89 }
90
91
92 static int k_atoi(char *string)
93 {
94         unsigned int result = 0;
95         int maxoctet = IPT_RPC_CHAR_LEN;
96
97
98         for ( ; *string != 0 && maxoctet != 0; maxoctet--, string++) {
99                 if (*string < 0)
100                         return(0);
101                 if (*string == 0)
102                         break;
103                 if (*string < 48 || *string > 57) {
104                         return(0);
105                 }
106                 result = result * 10 + ( *string - 48 );
107         }
108
109         return(result);
110 }
111
112
113 static void print_rpcs(char *c_procs, int i_procs, int labels)
114 {
115         int   proc_ctr;
116         char *proc_ptr;
117         unsigned int proc_num;
118         struct rpcent *rpcent;
119
120
121         for (proc_ctr=0; proc_ctr <= i_procs; proc_ctr++) {
122
123                 if ( proc_ctr != 0 )
124                         printf(",");
125
126                 proc_ptr = c_procs;
127                 proc_ptr += proc_ctr * IPT_RPC_CHAR_LEN;
128                 proc_num = k_atoi(proc_ptr);
129
130                 /* labels(1) == no labels, only numbers
131                  * labels(2) == no numbers, only labels
132                  * labels(3) == both labels and numbers
133                  */
134
135                 if (labels == IPT_RPC_INT_LBL || labels == IPT_RPC_INT_BTH ) {
136                         if ( (rpcent = getrpcbynumber(proc_num)) == NULL )
137                                 printf("unknown");
138                         else
139                                 printf("%s", rpcent->r_name);
140                 }
141
142                 if (labels == IPT_RPC_INT_BTH )
143                         printf("(");
144
145                 if (labels == IPT_RPC_INT_NUM || labels == IPT_RPC_INT_BTH )
146                         printf("%i", proc_num);
147
148                 if (labels == IPT_RPC_INT_BTH )
149                         printf(")");
150
151         }
152
153 }
154
155
156 static void help(void) 
157 {
158         printf(
159                 "RPC v%s options:\n"
160                 "  --rpcs list,of,procedures"
161                 "\ta list of rpc program numbers to apply\n"
162                 "\t\t\t\tie. 100003,mountd,rquotad (numeric or\n"
163                 "\t\t\t\tname form; see /etc/rpc).\n"
164                 "  --strict"
165                 "\t\t\ta flag to force the drop of packets\n"
166                 "\t\t\t\tnot containing \"get\" portmapper requests.\n",
167                 IPTABLES_VERSION);
168 }
169
170
171 static struct option opts[] = {
172         { "rpcs", 1, 0, '1'},
173         { "strict", 0, 0, '2'},
174         {0}
175 };
176
177
178 static void init(struct ipt_entry_match *match, unsigned int *nfcache)
179 {
180         struct ipt_rpc_info *rpcinfo = ((struct ipt_rpc_info *)match->data);
181
182
183
184         /* initialise those funky user vars */
185         rpcinfo->i_procs = -1;
186         rpcinfo->strict  =  0;
187         memset((char *)rpcinfo->c_procs, 0, sizeof(rpcinfo->c_procs));
188 }
189
190
191 static void parse_rpcs_string(char *string, struct ipt_entry_match **match)
192 {
193         char err1[64] = "%s invalid --rpcs option-set: `%s' (at character %i)";
194         char err2[64] = "%s unable to resolve rpc name entry: `%s'";
195         char err3[64] = "%s maximum number of --rpc options (%i) exceeded";
196         char buf[256];
197         char *dup = buf;
198         int idup = 0;
199         int term = 0;
200         char *src, *dst;
201         char *c_procs;
202         struct rpcent *rpcent_ptr;
203         struct ipt_rpc_info *rpcinfo = (struct ipt_rpc_info *)(*match)->data;
204
205
206         memset(buf, 0, sizeof(buf));
207
208         for (src=string, dst=buf; term != 1 ; src++, dst++) {
209
210                 if ( *src != ',' && *src != '\0' ) {
211                         if ( ( *src >= 65 && *src <= 90 ) || ( *src >= 97 && *src <= 122) ) {
212                                 *dst = *src;
213                                 idup = 1;
214
215                         } else if ( *src >= 48 && *src <= 57 ) {
216                                 *dst = *src;
217
218                         } else {
219                                 exit_error(PARAMETER_PROBLEM, err1, preerr,
220                                            string, src - string + 1);
221
222                         }
223
224                 } else {
225                         *dst = '\0';
226                         if ( idup == 1 ) {
227                                 if ( (rpcent_ptr = getrpcbyname(dup)) == NULL )
228                                         exit_error(PARAMETER_PROBLEM, err2,
229                                                    preerr, dup);
230                                 idup = rpcent_ptr->r_number;
231                         } else {
232                                 idup = k_atoi(dup);
233                         }
234
235                         rpcinfo->i_procs++;
236                         if ( rpcinfo->i_procs > IPT_RPC_MAX_ENTS )
237                                 exit_error(PARAMETER_PROBLEM, err3, preerr,
238                                            IPT_RPC_MAX_ENTS);
239                                 
240                         c_procs  = (char *)rpcinfo->c_procs;
241                         c_procs += rpcinfo->i_procs * IPT_RPC_CHAR_LEN;
242                         
243                         memset(buf, 0, sizeof(buf));
244                         k_itoa((char *)dup, idup);
245
246                         strcpy(c_procs, dup);
247         
248                         if ( *src == '\0')
249                                 term = 1;
250
251                         idup = 0;
252                         memset(buf, 0, sizeof(buf));
253                         dst = (char *)buf - 1;
254                 }
255         }
256
257         return;
258 }
259
260
261 static int parse(int c, char **argv, int invert, unsigned int *flags,
262                 const struct ipt_entry *entry,
263                 unsigned int *nfcache,
264                 struct ipt_entry_match **match)
265 {
266         struct ipt_rpc_info *rpcinfo = (struct ipt_rpc_info *)(*match)->data;
267
268
269         switch (c)
270         {
271         case '1':
272                 if (invert)
273                         exit_error(PARAMETER_PROBLEM,
274                                    "%s unexpected '!' with --rpcs\n", preerr);
275                 if (*flags & IPT_RPC_RPCS)
276                         exit_error(PARAMETER_PROBLEM,
277                                    "%s repeated use of --rpcs\n", preerr);
278                 parse_rpcs_string(optarg, match);
279
280                 *flags |= IPT_RPC_RPCS;
281                 break;
282
283         case '2':
284                 if (invert)
285                         exit_error(PARAMETER_PROBLEM,
286                                    "%s unexpected '!' with --strict\n", preerr);
287                 if (*flags & IPT_RPC_STRC)
288                         exit_error(PARAMETER_PROBLEM,
289                                    "%s repeated use of --strict\n", preerr);
290                 rpcinfo->strict = 1;
291                 *flags |= IPT_RPC_STRC;
292                 break;
293
294         default:
295                 return 0;
296         }
297
298         return 1;
299
300 }
301
302
303 static void final_check(unsigned int flags)
304 {
305         if (flags != (flags | IPT_RPC_RPCS)) {
306                 printf("%s option \"--rpcs\" was not used ... reverting ", preerr);
307                 printf("to old \"record-rpc\" functionality ..\n");
308         }
309 }
310
311
312 static void print(const struct ipt_ip *ip,
313                 const struct ipt_entry_match *match,
314                 int numeric)
315 {
316         struct ipt_rpc_info *rpcinfo = ((struct ipt_rpc_info *)match->data);
317
318
319         printf("RPCs");
320         if(rpcinfo->strict == 1)
321                 printf("[strict]");
322
323         printf(": ");
324
325         if(rpcinfo->i_procs == -1) {
326                 printf("any(*)");
327
328         } else {
329                 print_rpcs((char *)&rpcinfo->c_procs, rpcinfo->i_procs, IPT_RPC_INT_BTH);
330         }
331         printf(" ");
332
333 }
334
335
336 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
337 {
338         struct ipt_rpc_info *rpcinfo = ((struct ipt_rpc_info *)match->data);
339
340
341         if(rpcinfo->i_procs > -1) {
342                 printf("--rpcs ");
343                 print_rpcs((char *)&rpcinfo->c_procs, rpcinfo->i_procs, IPT_RPC_INT_NUM);
344                 printf(" ");
345         }
346
347         if(rpcinfo->strict == 1)
348                 printf("--strict ");
349
350 }
351
352
353 static struct iptables_match rpcstruct = { 
354         .next           = NULL,
355         .name           = "rpc",
356         .version        = IPTABLES_VERSION,
357         .size           = IPT_ALIGN(sizeof(struct ipt_rpc_info)),
358         .userspacesize  = IPT_ALIGN(sizeof(struct ipt_rpc_info)),
359         .help           = &help,
360         .init           = &init,
361         .parse          = &parse,
362         .final_check    = &final_check,
363         .print          = &print,
364         .save           = &save,
365         .extra_opts     = opts
366 };
367
368
369 void _init(void)
370 {
371         register_match(&rpcstruct);
372 }
373