1 /* 2 * PPP Filter command Interface 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: filter.c,v 1.1.1.1 1995/01/31 06:29:57 amurai Exp $ 21 * 22 * TODO: Shoud send ICMP error message when we discard packets. 23 */ 24 25 #include <sys/types.h> 26 #include <sys/socket.h> 27 #include <netinet/in.h> 28 #include <arpa/inet.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <strings.h> 32 #include "command.h" 33 #include "filter.h" 34 35 static struct filterent filterdata; 36 37 static u_long netmasks[33] = { 38 0x00000000, 39 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 40 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, 41 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, 42 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, 43 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 44 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 45 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, 46 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, 47 }; 48 49 int 50 ParseAddr(argc, argv, paddr, pmask, pwidth) 51 int argc; 52 char **argv; 53 struct in_addr *paddr; 54 struct in_addr *pmask; 55 int *pwidth; 56 { 57 u_long addr; 58 int bits; 59 char *cp, *wp; 60 61 if (argc < 1) { 62 #ifdef notdef 63 printf("address/mask is expected.\n"); 64 #endif 65 return(0); 66 } 67 68 pmask->s_addr = -1; /* Assume 255.255.255.255 as default */ 69 cp = index(*argv, '/'); 70 if (cp) *cp++ = '\0'; 71 addr = inet_addr(*argv); 72 paddr->s_addr = addr; 73 if (cp && *cp) { 74 bits = strtol(cp, &wp, 0); 75 if (cp == wp || bits < 0 || bits > 32) { 76 printf("bad mask width.\n"); 77 return(0); 78 } 79 } else { 80 /* if width is not given, assume whole 32 bits are meaningfull */ 81 bits = 32; 82 } 83 84 *pwidth = bits; 85 pmask->s_addr = htonl(netmasks[bits]); 86 87 return(1); 88 } 89 90 static int 91 ParseProto(argc, argv) 92 int argc; 93 char **argv; 94 { 95 int proto; 96 97 if (argc < 1) 98 return(P_NONE); 99 100 if (STREQ(*argv, "tcp")) 101 proto = P_TCP; 102 else if (STREQ(*argv, "udp")) 103 proto = P_UDP; 104 else if (STREQ(*argv, "icmp")) 105 proto = P_ICMP; 106 else 107 proto = P_NONE; 108 return(proto); 109 } 110 111 /* 112 * ICMP Syntax: src eq icmp_message_type 113 */ 114 static int 115 ParseIcmp(argc, argv) 116 int argc; 117 char **argv; 118 { 119 int type; 120 char *cp; 121 122 switch (argc) { 123 case 0: 124 /* permit/deny all ICMP types */ 125 filterdata.opt.srcop = OP_NONE; 126 break; 127 default: 128 printf("bad icmp syntax.\n"); 129 return(0); 130 case 3: 131 if (STREQ(*argv, "src") && STREQ(argv[1], "eq")) { 132 type = strtol(argv[2], &cp, 0); 133 if (cp == argv[2]) { 134 printf("type is expected.\n"); 135 return(0); 136 } 137 filterdata.opt.srcop = OP_EQ; 138 filterdata.opt.srcport = type; 139 } 140 break; 141 } 142 return(1); 143 } 144 145 static int 146 ParseOp(cp) 147 char *cp; 148 { 149 int op = OP_NONE; 150 151 if (STREQ(cp, "eq")) 152 op = OP_EQ; 153 else if (STREQ(cp, "gt")) 154 op = OP_GT; 155 else if (STREQ(cp, "lt")) 156 op = OP_LT; 157 return(op); 158 } 159 160 /* 161 * UDP Syntax: [src op port] [dst op port] 162 */ 163 static int 164 ParseUdp(argc, argv) 165 int argc; 166 char **argv; 167 { 168 int port; 169 char *cp; 170 171 if (argc == 0) { 172 /* permit/deny all tcp traffic */ 173 filterdata.opt.srcop = filterdata.opt.dstop = A_NONE; 174 return(1); 175 } 176 if (argc < 3) { 177 #ifdef notdef 178 printf("bad udp syntax.\n"); 179 #endif 180 return(0); 181 } 182 if (STREQ(*argv, "src")) { 183 filterdata.opt.srcop = ParseOp(argv[1]); 184 if (filterdata.opt.srcop == OP_NONE) { 185 printf("bad operation\n"); 186 return(0); 187 } 188 port = strtol(argv[2], &cp, 0); 189 if (cp == argv[2]) { 190 printf("expect port number.\n"); 191 return(0); 192 } 193 filterdata.opt.srcport = port; 194 argc -= 3; argv += 3; 195 if (argc == 0) 196 return(1); 197 } 198 199 if (argc >= 3 && STREQ(argv[0], "dst")) { 200 filterdata.opt.dstop = ParseOp(argv[1]); 201 if (filterdata.opt.dstop == OP_NONE) { 202 printf("bad operation\n"); 203 return(0); 204 } 205 port = strtol(argv[2], &cp, 0); 206 if (cp == argv[2]) { 207 printf("port number is expected.\n"); 208 return(0); 209 } 210 filterdata.opt.dstport = port; 211 return(1); 212 } 213 if (argc == 1 && STREQ(argv[0], "estab")) 214 return(1); 215 printf("no src/dst port.\n"); 216 return(0); 217 } 218 219 /* 220 * TCP Syntax: [src op port] [dst op port] [estab] 221 */ 222 static int 223 ParseTcp(argc, argv) 224 int argc; 225 char **argv; 226 { 227 int val; 228 229 val = ParseUdp(argc, argv); 230 if (val) { 231 if (argc == 0) return(1); /* Will permit/deny all tcp traffic */ 232 argc -= 3; argv += 3; 233 if (argc > 1) { 234 argc -= 3; argv += 3; 235 } 236 if (argc < 0 || argc > 1) { 237 printf("bad tcp syntax.\n"); 238 return(0); 239 } 240 if (argc == 1) { 241 checkestab: 242 if (STREQ(*argv, "estab")) { 243 filterdata.opt.estab = 1; 244 return(1); 245 } 246 printf("estab is expected.\n"); 247 return(0); 248 } 249 250 return(1); 251 } else if (argc == 1) 252 goto checkestab; 253 printf("bad port syntax (val = %d, argc = %d.\n", val, argc); 254 return(0); 255 } 256 257 char *opname[] = { "none", "eq", "gt", "lt" }; 258 259 static int 260 Parse(argc, argv, ofp) 261 int argc; 262 char **argv; 263 struct filterent *ofp; 264 { 265 int action, proto; 266 int val; 267 char *wp; 268 struct filterent *fp = &filterdata; 269 270 val = strtol(*argv, &wp, 0); 271 if (*argv == wp || val > MAXFILTERS) { 272 printf("invalid filter number.\n"); 273 return(0); 274 } 275 if (val < 0) { 276 for (val = 0; val < MAXFILTERS; val++) { 277 ofp->action = A_NONE; 278 ofp++; 279 } 280 printf("filter cleard.\n"); 281 return(1); 282 } 283 ofp += val; 284 285 if (--argc == 0) { 286 printf("missing action.\n"); 287 return(0); 288 } 289 argv++; 290 291 proto = P_NONE; 292 bzero(&filterdata, sizeof(filterdata)); 293 294 if (STREQ(*argv, "permit")) { 295 action = A_PERMIT; 296 } else if (STREQ(*argv, "deny")) { 297 action = A_DENY; 298 } else if (STREQ(*argv, "clear")) { 299 ofp->action = A_NONE; 300 return(1); 301 } else { 302 printf("bad action: %s\n", *argv); 303 return(0); 304 } 305 fp->action = action; 306 307 argc--; argv++; 308 309 if (ofp->action == A_DENY) { 310 if (STREQ(*argv, "host")) { 311 fp->action |= A_UHOST; 312 argc--; argv++; 313 } else if (STREQ(*argv, "port")) { 314 fp->action |= A_UPORT; 315 argc--; argv++; 316 } 317 } 318 319 proto = ParseProto(argc, argv); 320 if (proto == P_NONE) { 321 if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) { 322 argc--; argv++; 323 proto = ParseProto(argc, argv); 324 if (proto == P_NONE) { 325 if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) { 326 argc--; argv++; 327 } 328 proto = ParseProto(argc, argv); 329 } 330 if (proto) { 331 argc--; argv++; 332 } 333 } else { 334 printf("Address/protocol expected.\n"); 335 return(0); 336 } 337 } else { 338 argc--; argv++; 339 } 340 341 val = 1; 342 fp->proto = proto; 343 344 switch (proto) { 345 case P_TCP: 346 val = ParseTcp(argc, argv); 347 break; 348 case P_UDP: 349 val = ParseUdp(argc, argv); 350 break; 351 case P_ICMP: 352 val = ParseIcmp(argc, argv); 353 break; 354 } 355 356 #ifdef DEBUG 357 printf("src: %s/", inet_ntoa(fp->saddr)); 358 printf("%s ", inet_ntoa(fp->smask)); 359 printf("dst: %s/", inet_ntoa(fp->daddr)); 360 printf("%s proto = %d\n", inet_ntoa(fp->dmask), proto); 361 362 printf("src: %s (%d)\n", opname[fp->opt.srcop], fp->opt.srcport); 363 printf("dst: %s (%d)\n", opname[fp->opt.dstop], fp->opt.dstport); 364 printf("estab: %d\n", fp->opt.estab); 365 #endif 366 367 if (val) 368 *ofp = *fp; 369 return(val); 370 } 371 372 int 373 SetIfilter(list, argc, argv) 374 struct cmdtab *list; 375 int argc; 376 char **argv; 377 { 378 if (argc > 0) 379 (void) Parse(argc, argv, ifilters); 380 else 381 printf("syntax error.\n"); 382 383 return(1); 384 } 385 386 int 387 SetOfilter(list, argc, argv) 388 struct cmdtab *list; 389 int argc; 390 char **argv; 391 { 392 if (argc > 0) 393 (void) Parse(argc, argv, ofilters); 394 else 395 printf("syntax error.\n"); 396 return(1); 397 } 398 399 int 400 SetDfilter(list, argc, argv) 401 struct cmdtab *list; 402 int argc; 403 char **argv; 404 { 405 if (argc > 0) 406 (void) Parse(argc, argv, dfilters); 407 else 408 printf("syntax error.\n"); 409 return(1); 410 } 411 412 static char *protoname[] = { 413 "none", "tcp", "udp", "icmp", 414 }; 415 416 static char *actname[] = { 417 "none ", "permit ", "deny ", 418 }; 419 420 static void 421 ShowFilter(fp) 422 struct filterent *fp; 423 { 424 int n; 425 426 for (n = 0; n < MAXFILTERS; n++, fp++) { 427 if (fp->action != A_NONE) { 428 printf("%2d %s", n, actname[fp->action]); 429 430 printf("%s/%d ", inet_ntoa(fp->saddr), fp->swidth); 431 printf("%s/%d ", inet_ntoa(fp->daddr), fp->dwidth); 432 if (fp->proto) { 433 printf("%s", protoname[fp->proto]); 434 435 if (fp->opt.srcop) 436 printf(" src %s %d", opname[fp->opt.srcop], fp->opt.srcport); 437 if (fp->opt.dstop) 438 printf(" dst %s %d", opname[fp->opt.dstop], fp->opt.dstport); 439 if (fp->opt.estab) 440 printf(" estab"); 441 442 } 443 printf("\n"); 444 } 445 } 446 } 447 448 int 449 ShowIfilter(list, argc, argv) 450 struct cmdtab *list; 451 int argc; 452 char **argv; 453 { 454 ShowFilter(ifilters); 455 return(1); 456 } 457 458 int 459 ShowOfilter(list, argc, argv) 460 struct cmdtab *list; 461 int argc; 462 char **argv; 463 { 464 ShowFilter(ofilters); 465 return(1); 466 } 467 468 int 469 ShowDfilter(list, argc, argv) 470 struct cmdtab *list; 471 int argc; 472 char **argv; 473 { 474 ShowFilter(dfilters); 475 return(1); 476 } 477