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