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
57const int IPT_RPC_RPCS = 1;
58const int IPT_RPC_STRC = 2;
59
60const int IPT_RPC_INT_LBL = 1;
61const int IPT_RPC_INT_NUM = 2;
62const int IPT_RPC_INT_BTH = 3;
63
64const int IPT_RPC_CHAR_LEN = 11;
65const int IPT_RPC_MAX_ENTS = 128;
66
67const char preerr[11] = "RPC match:";
68
69
70static 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
92static 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
113static 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
156static 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
171static struct option opts[] = {
172	{ "rpcs", 1, 0, '1'},
173	{ "strict", 0, 0, '2'},
174	{0}
175};
176
177
178static 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
191static 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
261static 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
303static 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
312static 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
336static 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
353static 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
369void _init(void)
370{
371	register_match(&rpcstruct);
372}
373
374