filter.c revision 32663
1238603Sjoerg/* 2238603Sjoerg * PPP Filter command Interface 3238603Sjoerg * 4238603Sjoerg * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5238603Sjoerg * 6238603Sjoerg * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7238603Sjoerg * 8238603Sjoerg * Redistribution and use in source and binary forms are permitted 9238603Sjoerg * provided that the above copyright notice and this paragraph are 10238603Sjoerg * duplicated in all such forms and that any documentation, 11238603Sjoerg * advertising materials, and other materials related to such 12238603Sjoerg * distribution and use acknowledge that the software was developed 13238603Sjoerg * by the Internet Initiative Japan. The name of the 14238603Sjoerg * IIJ may not be used to endorse or promote products derived 15238603Sjoerg * from this software without specific prior written permission. 16238603Sjoerg * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17238603Sjoerg * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18238603Sjoerg * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19238603Sjoerg * 20238603Sjoerg * $Id: filter.c,v 1.21 1997/12/24 09:28:57 brian Exp $ 21238603Sjoerg * 22238603Sjoerg * TODO: Shoud send ICMP error message when we discard packets. 23238603Sjoerg */ 24238603Sjoerg 25238603Sjoerg#include <sys/param.h> 26238603Sjoerg#include <netinet/in.h> 27238603Sjoerg#include <arpa/inet.h> 28238603Sjoerg#include <netdb.h> 29238603Sjoerg 30238603Sjoerg#include <stdio.h> 31238603Sjoerg#include <stdlib.h> 32238603Sjoerg#include <strings.h> 33238603Sjoerg 34238603Sjoerg#include "command.h" 35238603Sjoerg#include "mbuf.h" 36238603Sjoerg#include "log.h" 37238603Sjoerg#include "loadalias.h" 38238603Sjoerg#include "defs.h" 39238603Sjoerg#include "vars.h" 40238603Sjoerg#include "ipcp.h" 41238603Sjoerg#include "filter.h" 42238603Sjoerg 43238603Sjoergstruct filterent ifilters[MAXFILTERS]; /* incoming packet filter */ 44269879Semastestruct filterent ofilters[MAXFILTERS]; /* outgoing packet filter */ 45238603Sjoergstruct filterent dfilters[MAXFILTERS]; /* dial-out packet filter */ 46238603Sjoergstruct filterent afilters[MAXFILTERS]; /* keep-alive packet filter */ 47238603Sjoerg 48238603Sjoergstatic struct filterent filterdata; 49238603Sjoerg 50238603Sjoergstatic u_long netmasks[33] = { 51238603Sjoerg 0x00000000, 52238603Sjoerg 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 53238603Sjoerg 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000, 54238603Sjoerg 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000, 55238603Sjoerg 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, 56238603Sjoerg 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 57238603Sjoerg 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00, 58238603Sjoerg 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, 59238603Sjoerg 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF, 60238603Sjoerg}; 61238603Sjoerg 62238603Sjoergint 63238603SjoergParseAddr(int argc, 64238603Sjoerg char const *const *argv, 65238603Sjoerg struct in_addr * paddr, 66238603Sjoerg struct in_addr * pmask, 67238603Sjoerg int *pwidth) 68238603Sjoerg{ 69238603Sjoerg int bits, len; 70238603Sjoerg char *wp; 71238603Sjoerg const char *cp; 72238603Sjoerg 73238603Sjoerg if (argc < 1) { 74238603Sjoerg LogPrintf(LogWARN, "ParseAddr: address/mask is expected.\n"); 75238603Sjoerg return (0); 76238603Sjoerg } 77269879Semaste 78238603Sjoerg if (pmask) 79238603Sjoerg pmask->s_addr = 0xffffffff; /* Assume 255.255.255.255 as default */ 80238603Sjoerg 81238603Sjoerg cp = pmask || pwidth ? strchr(*argv, '/') : NULL; 82238603Sjoerg len = cp ? cp - *argv : strlen(*argv); 83238603Sjoerg 84238603Sjoerg if (strncasecmp(*argv, "HISADDR", len) == 0) 85238603Sjoerg *paddr = IpcpInfo.his_ipaddr; 86238603Sjoerg else if (strncasecmp(*argv, "MYADDR", len) == 0) 87269879Semaste *paddr = IpcpInfo.want_ipaddr; 88238603Sjoerg else if (len > 15) 89238603Sjoerg LogPrintf(LogWARN, "ParseAddr: %s: Bad address\n", *argv); 90238603Sjoerg else { 91238603Sjoerg char s[16]; 92238603Sjoerg strncpy(s, *argv, len); 93238603Sjoerg s[len] = '\0'; 94238603Sjoerg if (inet_aton(s, paddr) == 0) { 95238603Sjoerg LogPrintf(LogWARN, "ParseAddr: %s: Bad address\n", s); 96238603Sjoerg return (0); 97238603Sjoerg } 98238603Sjoerg } 99238603Sjoerg if (cp && *++cp) { 100269879Semaste bits = strtol(cp, &wp, 0); 101238603Sjoerg if (cp == wp || bits < 0 || bits > 32) { 102238603Sjoerg LogPrintf(LogWARN, "ParseAddr: bad mask width.\n"); 103238603Sjoerg return (0); 104238603Sjoerg } 105238603Sjoerg } else { 106238603Sjoerg /* if width is not given, assume whole 32 bits are meaningfull */ 107238603Sjoerg bits = 32; 108238603Sjoerg } 109238603Sjoerg 110269879Semaste if (pwidth) 111238603Sjoerg *pwidth = bits; 112238603Sjoerg 113238603Sjoerg if (pmask) 114238603Sjoerg pmask->s_addr = htonl(netmasks[bits]); 115269879Semaste 116238603Sjoerg return (1); 117238603Sjoerg} 118238603Sjoerg 119238603Sjoergstatic int 120238603SjoergParseProto(int argc, char const *const *argv) 121238603Sjoerg{ 122238603Sjoerg int proto; 123238603Sjoerg 124238603Sjoerg if (argc < 1) 125238603Sjoerg return (P_NONE); 126238603Sjoerg 127269879Semaste if (!strcmp(*argv, "tcp")) 128238603Sjoerg proto = P_TCP; 129238603Sjoerg else if (!strcmp(*argv, "udp")) 130238603Sjoerg proto = P_UDP; 131238603Sjoerg else if (!strcmp(*argv, "icmp")) 132238603Sjoerg proto = P_ICMP; 133238603Sjoerg else 134238603Sjoerg proto = P_NONE; 135269879Semaste return (proto); 136238603Sjoerg} 137238603Sjoerg 138238603Sjoergstatic int 139238603SjoergParsePort(const char *service, int proto) 140238603Sjoerg{ 141238603Sjoerg const char *protocol_name; 142238603Sjoerg char *cp; 143238603Sjoerg struct servent *servent; 144238603Sjoerg int port; 145238603Sjoerg 146238603Sjoerg switch (proto) { 147238603Sjoerg case P_UDP: 148238603Sjoerg protocol_name = "udp"; 149238603Sjoerg break; 150238603Sjoerg case P_TCP: 151238603Sjoerg protocol_name = "tcp"; 152238603Sjoerg break; 153238603Sjoerg default: 154238603Sjoerg protocol_name = 0; 155238603Sjoerg } 156238603Sjoerg 157238603Sjoerg servent = getservbyname(service, protocol_name); 158238603Sjoerg if (servent != 0) 159238603Sjoerg return (ntohs(servent->s_port)); 160238603Sjoerg 161238603Sjoerg port = strtol(service, &cp, 0); 162238603Sjoerg if (cp == service) { 163238603Sjoerg LogPrintf(LogWARN, "ParsePort: %s is not a port name or number.\n", 164238603Sjoerg service); 165238603Sjoerg return (0); 166238603Sjoerg } 167238603Sjoerg return (port); 168238603Sjoerg} 169238603Sjoerg 170238603Sjoerg/* 171238603Sjoerg * ICMP Syntax: src eq icmp_message_type 172238603Sjoerg */ 173238603Sjoergstatic int 174238603SjoergParseIcmp(int argc, char const *const *argv) 175238603Sjoerg{ 176238603Sjoerg int type; 177238603Sjoerg char *cp; 178238603Sjoerg 179238603Sjoerg switch (argc) { 180238603Sjoerg case 0: 181238603Sjoerg /* permit/deny all ICMP types */ 182238603Sjoerg filterdata.opt.srcop = OP_NONE; 183238603Sjoerg break; 184238603Sjoerg default: 185238603Sjoerg LogPrintf(LogWARN, "ParseIcmp: bad icmp syntax.\n"); 186238603Sjoerg return (0); 187238603Sjoerg case 3: 188238603Sjoerg if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) { 189238603Sjoerg type = strtol(argv[2], &cp, 0); 190238603Sjoerg if (cp == argv[2]) { 191238603Sjoerg LogPrintf(LogWARN, "ParseIcmp: type is expected.\n"); 192238603Sjoerg return (0); 193238603Sjoerg } 194238603Sjoerg filterdata.opt.srcop = OP_EQ; 195238603Sjoerg filterdata.opt.srcport = type; 196238603Sjoerg } 197238603Sjoerg break; 198238603Sjoerg } 199238603Sjoerg return (1); 200238603Sjoerg} 201238603Sjoerg 202238603Sjoergstatic int 203238603SjoergParseOp(const char *cp) 204238603Sjoerg{ 205238603Sjoerg int op = OP_NONE; 206238603Sjoerg 207238603Sjoerg if (!strcmp(cp, "eq")) 208238603Sjoerg op = OP_EQ; 209238603Sjoerg else if (!strcmp(cp, "gt")) 210238603Sjoerg op = OP_GT; 211238603Sjoerg else if (!strcmp(cp, "lt")) 212238603Sjoerg op = OP_LT; 213238603Sjoerg return (op); 214238603Sjoerg} 215238603Sjoerg 216238603Sjoerg/* 217238603Sjoerg * UDP Syntax: [src op port] [dst op port] 218238603Sjoerg */ 219238603Sjoergstatic int 220238603SjoergParseUdpOrTcp(int argc, char const *const *argv, int proto) 221238603Sjoerg{ 222238603Sjoerg filterdata.opt.srcop = filterdata.opt.dstop = OP_NONE; 223238603Sjoerg filterdata.opt.estab = 0; 224238603Sjoerg 225238603Sjoerg if (argc == 0) { 226238603Sjoerg /* permit/deny all tcp traffic */ 227238603Sjoerg return (1); 228238603Sjoerg } 229238603Sjoerg 230238603Sjoerg if (argc >= 3 && !strcmp(*argv, "src")) { 231238603Sjoerg filterdata.opt.srcop = ParseOp(argv[1]); 232238603Sjoerg if (filterdata.opt.srcop == OP_NONE) { 233238603Sjoerg LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 234238603Sjoerg return (0); 235238603Sjoerg } 236238603Sjoerg filterdata.opt.srcport = ParsePort(argv[2], proto); 237238603Sjoerg if (filterdata.opt.srcport == 0) 238238603Sjoerg return (0); 239238603Sjoerg argc -= 3; 240238603Sjoerg argv += 3; 241238603Sjoerg if (argc == 0) 242238603Sjoerg return (1); 243238603Sjoerg } 244 if (argc >= 3 && !strcmp(argv[0], "dst")) { 245 filterdata.opt.dstop = ParseOp(argv[1]); 246 if (filterdata.opt.dstop == OP_NONE) { 247 LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n"); 248 return (0); 249 } 250 filterdata.opt.dstport = ParsePort(argv[2], proto); 251 if (filterdata.opt.dstport == 0) 252 return (0); 253 argc -= 3; 254 argv += 3; 255 if (argc == 0) 256 return (1); 257 } 258 if (argc == 1 && proto == P_TCP) { 259 if (!strcmp(*argv, "estab")) { 260 filterdata.opt.estab = 1; 261 return (1); 262 } 263 LogPrintf(LogWARN, "ParseUdpOrTcp: estab is expected: %s\n", *argv); 264 return (0); 265 } 266 if (argc > 0) 267 LogPrintf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv); 268 return (0); 269} 270 271static const char *opname[] = {"none", "eq", "gt", NULL, "lt"}; 272 273static int 274Parse(int argc, char const *const *argv, struct filterent * ofp) 275{ 276 int action, proto; 277 int val; 278 char *wp; 279 struct filterent *fp = &filterdata; 280 281 val = strtol(*argv, &wp, 0); 282 if (*argv == wp || val > MAXFILTERS) { 283 LogPrintf(LogWARN, "Parse: invalid filter number.\n"); 284 return (0); 285 } 286 if (val < 0) { 287 for (val = 0; val < MAXFILTERS; val++) { 288 ofp->action = A_NONE; 289 ofp++; 290 } 291 LogPrintf(LogWARN, "Parse: filter cleared.\n"); 292 return (1); 293 } 294 ofp += val; 295 296 if (--argc == 0) { 297 LogPrintf(LogWARN, "Parse: missing action.\n"); 298 return (0); 299 } 300 argv++; 301 302 proto = P_NONE; 303 memset(&filterdata, '\0', sizeof filterdata); 304 305 if (!strcmp(*argv, "permit")) { 306 action = A_PERMIT; 307 } else if (!strcmp(*argv, "deny")) { 308 action = A_DENY; 309 } else if (!strcmp(*argv, "clear")) { 310 ofp->action = A_NONE; 311 return (1); 312 } else { 313 LogPrintf(LogWARN, "Parse: bad action: %s\n", *argv); 314 return (0); 315 } 316 fp->action = action; 317 318 argc--; 319 argv++; 320 321 if (fp->action == A_DENY) { 322 if (!strcmp(*argv, "host")) { 323 fp->action |= A_UHOST; 324 argc--; 325 argv++; 326 } else if (!strcmp(*argv, "port")) { 327 fp->action |= A_UPORT; 328 argc--; 329 argv++; 330 } 331 } 332 proto = ParseProto(argc, argv); 333 if (proto == P_NONE) { 334 if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) { 335 argc--; 336 argv++; 337 proto = ParseProto(argc, argv); 338 if (proto == P_NONE) { 339 if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) { 340 argc--; 341 argv++; 342 } 343 proto = ParseProto(argc, argv); 344 if (proto != P_NONE) { 345 argc--; 346 argv++; 347 } 348 } else { 349 argc--; 350 argv++; 351 } 352 } else { 353 LogPrintf(LogWARN, "Parse: Address/protocol expected.\n"); 354 return (0); 355 } 356 } else { 357 argc--; 358 argv++; 359 } 360 361 val = 1; 362 fp->proto = proto; 363 364 switch (proto) { 365 case P_TCP: 366 val = ParseUdpOrTcp(argc, argv, P_TCP); 367 break; 368 case P_UDP: 369 val = ParseUdpOrTcp(argc, argv, P_UDP); 370 break; 371 case P_ICMP: 372 val = ParseIcmp(argc, argv); 373 break; 374 } 375 376 LogPrintf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(fp->saddr)); 377 LogPrintf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(fp->smask)); 378 LogPrintf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(fp->daddr)); 379 LogPrintf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(fp->dmask)); 380 LogPrintf(LogDEBUG, "Parse: Proto = %d\n", proto); 381 382 LogPrintf(LogDEBUG, "Parse: src: %s (%d)\n", opname[fp->opt.srcop], 383 fp->opt.srcport); 384 LogPrintf(LogDEBUG, "Parse: dst: %s (%d)\n", opname[fp->opt.dstop], 385 fp->opt.dstport); 386 LogPrintf(LogDEBUG, "Parse: estab: %d\n", fp->opt.estab); 387 388 if (val) 389 *ofp = *fp; 390 return (val); 391} 392 393int 394SetIfilter(struct cmdargs const *arg) 395{ 396 if (arg->argc > 0) { 397 Parse(arg->argc, arg->argv, ifilters); 398 return 0; 399 } 400 return -1; 401} 402 403int 404SetOfilter(struct cmdargs const *arg) 405{ 406 if (arg->argc > 0) { 407 (void) Parse(arg->argc, arg->argv, ofilters); 408 return 0; 409 } 410 return -1; 411} 412 413int 414SetDfilter(struct cmdargs const *arg) 415{ 416 if (arg->argc > 0) { 417 (void) Parse(arg->argc, arg->argv, dfilters); 418 return 0; 419 } 420 return -1; 421} 422 423int 424SetAfilter(struct cmdargs const *arg) 425{ 426 if (arg->argc > 0) { 427 (void) Parse(arg->argc, arg->argv, afilters); 428 return 0; 429 } 430 return -1; 431} 432 433static const char *protoname[] = { "none", "tcp", "udp", "icmp" }; 434static const char *actname[] = { "none ", "permit ", "deny " }; 435 436static void 437ShowFilter(struct filterent * fp) 438{ 439 int n; 440 441 if (!VarTerm) 442 return; 443 444 for (n = 0; n < MAXFILTERS; n++, fp++) { 445 if (fp->action != A_NONE) { 446 fprintf(VarTerm, "%2d %s", n, actname[fp->action & (A_PERMIT|A_DENY)]); 447 if (fp->action & A_UHOST) 448 fprintf(VarTerm, "host "); 449 else if (fp->action & A_UPORT) 450 fprintf(VarTerm, "port "); 451 else 452 fprintf(VarTerm, " "); 453 fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth); 454 fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth); 455 if (fp->proto) { 456 fprintf(VarTerm, "%s", protoname[fp->proto]); 457 458 if (fp->opt.srcop) 459 fprintf(VarTerm, " src %s %d", opname[fp->opt.srcop], 460 fp->opt.srcport); 461 if (fp->opt.dstop) 462 fprintf(VarTerm, " dst %s %d", opname[fp->opt.dstop], 463 fp->opt.dstport); 464 if (fp->opt.estab) 465 fprintf(VarTerm, " estab"); 466 467 } 468 fprintf(VarTerm, "\n"); 469 } 470 } 471} 472 473int 474ShowIfilter(struct cmdargs const *arg) 475{ 476 ShowFilter(ifilters); 477 return 0; 478} 479 480int 481ShowOfilter(struct cmdargs const *arg) 482{ 483 ShowFilter(ofilters); 484 return 0; 485} 486 487int 488ShowDfilter(struct cmdargs const *arg) 489{ 490 ShowFilter(dfilters); 491 return 0; 492} 493 494int 495ShowAfilter(struct cmdargs const *arg) 496{ 497 ShowFilter(afilters); 498 return 0; 499} 500