filter.c revision 47648
174465Srwatson/*
274465Srwatson *		PPP Filter command Interface
374465Srwatson *
474465Srwatson *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
574465Srwatson *
674465Srwatson *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
774465Srwatson *
874465Srwatson * Redistribution and use in source and binary forms are permitted
974465Srwatson * provided that the above copyright notice and this paragraph are
1074465Srwatson * duplicated in all such forms and that any documentation,
1174465Srwatson * advertising materials, and other materials related to such
1274465Srwatson * distribution and use acknowledge that the software was developed
1374465Srwatson * by the Internet Initiative Japan.  The name of the
1474465Srwatson * IIJ may not be used to endorse or promote products derived
1574465Srwatson * from this software without specific prior written permission.
1674465Srwatson * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1774465Srwatson * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1874465Srwatson * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1974465Srwatson *
2074465Srwatson * $Id: filter.c,v 1.28 1999/05/08 11:06:33 brian Exp $
2174465Srwatson *
2274465Srwatson *	TODO: Shoud send ICMP error message when we discard packets.
2374465Srwatson */
2474465Srwatson
2574465Srwatson#include <sys/param.h>
2674465Srwatson#include <netinet/in.h>
2774465Srwatson#include <arpa/inet.h>
2874465Srwatson#include <netdb.h>
2974465Srwatson#include <netinet/in_systm.h>
3074465Srwatson#include <netinet/ip.h>
3174465Srwatson#include <sys/un.h>
3274465Srwatson
3374465Srwatson#include <stdio.h>
3474465Srwatson#include <stdlib.h>
3574465Srwatson#include <strings.h>
3674465Srwatson#include <termios.h>
3774465Srwatson
3874465Srwatson#include "layer.h"
3974465Srwatson#include "defs.h"
4074465Srwatson#include "command.h"
4174465Srwatson#include "mbuf.h"
4274465Srwatson#include "log.h"
4374465Srwatson#include "iplist.h"
4474465Srwatson#include "timer.h"
4574465Srwatson#include "throughput.h"
4674465Srwatson#include "lqr.h"
4774465Srwatson#include "hdlc.h"
4874465Srwatson#include "fsm.h"
4974465Srwatson#include "lcp.h"
5074465Srwatson#include "ccp.h"
5174465Srwatson#include "link.h"
5274465Srwatson#include "slcompress.h"
5374465Srwatson#include "ipcp.h"
5474465Srwatson#include "filter.h"
5574465Srwatson#include "descriptor.h"
5674465Srwatson#include "prompt.h"
5774465Srwatson#include "mp.h"
5874465Srwatson#ifndef NORADIUS
5974465Srwatson#include "radius.h"
6074465Srwatson#endif
6174465Srwatson#include "bundle.h"
6274465Srwatson
6374465Srwatsonstatic int filter_Nam2Proto(int, char const *const *);
6474465Srwatsonstatic int filter_Nam2Op(const char *);
6574465Srwatson
6674465Srwatsonstatic const u_int32_t netmasks[33] = {
6774465Srwatson  0x00000000,
6874465Srwatson  0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
6974465Srwatson  0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
7074465Srwatson  0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
7174465Srwatson  0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
7274465Srwatson  0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
7374465Srwatson  0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
7474465Srwatson  0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
7574465Srwatson  0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
7674465Srwatson};
7774465Srwatson
7874465Srwatsonstruct in_addr
7974465Srwatsonbits2mask(int bits)
8074465Srwatson{
8174465Srwatson  struct in_addr result;
8274465Srwatson
8374465Srwatson  result.s_addr = htonl(netmasks[bits]);
8474465Srwatson  return result;
8574465Srwatson}
8674465Srwatson
8774465Srwatsonint
8874465SrwatsonParseAddr(struct ipcp *ipcp, const char *data,
8974465Srwatson	  struct in_addr *paddr, struct in_addr *pmask, int *pwidth)
9074465Srwatson{
9174465Srwatson  int bits, len;
9274465Srwatson  char *wp;
9374465Srwatson  const char *cp;
9474465Srwatson
9574465Srwatson  if (pmask)
9674465Srwatson    pmask->s_addr = INADDR_BROADCAST;	/* Assume 255.255.255.255 as default */
9774465Srwatson
9874465Srwatson  cp = pmask || pwidth ? strchr(data, '/') : NULL;
9974465Srwatson  len = cp ? cp - data : strlen(data);
10074465Srwatson
10174465Srwatson  if (ipcp && strncasecmp(data, "HISADDR", len) == 0)
10274465Srwatson    *paddr = ipcp->peer_ip;
10374465Srwatson  else if (ipcp && strncasecmp(data, "MYADDR", len) == 0)
10474465Srwatson    *paddr = ipcp->my_ip;
10574465Srwatson  else if (len > 15)
10674465Srwatson    log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", data);
10774465Srwatson  else {
10874465Srwatson    char s[16];
10974465Srwatson    strncpy(s, data, len);
11074465Srwatson    s[len] = '\0';
11174465Srwatson    if (inet_aton(s, paddr) == 0) {
11274465Srwatson      log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", s);
11374465Srwatson      return (0);
11474465Srwatson    }
11574465Srwatson  }
11674465Srwatson  if (cp && *++cp) {
11774465Srwatson    bits = strtol(cp, &wp, 0);
11874465Srwatson    if (cp == wp || bits < 0 || bits > 32) {
11974465Srwatson      log_Printf(LogWARN, "ParseAddr: bad mask width.\n");
12074465Srwatson      return (0);
12174465Srwatson    }
12274465Srwatson  } else if (paddr->s_addr == INADDR_ANY)
12374465Srwatson    /* An IP of 0.0.0.0 without a width is anything */
12474465Srwatson    bits = 0;
12574465Srwatson  else
12674465Srwatson    /* If a valid IP is given without a width, assume 32 bits */
12774465Srwatson    bits = 32;
12874465Srwatson
12974465Srwatson  if (pwidth)
13074465Srwatson    *pwidth = bits;
13174465Srwatson
13274465Srwatson  if (pmask) {
13374465Srwatson    if (paddr->s_addr == INADDR_ANY)
13474465Srwatson      pmask->s_addr = INADDR_ANY;
13574465Srwatson    else
13674465Srwatson      *pmask = bits2mask(bits);
13774465Srwatson  }
13874465Srwatson
13974465Srwatson  return (1);
14074465Srwatson}
14174465Srwatson
14274465Srwatsonstatic int
14374465SrwatsonParsePort(const char *service, int proto)
14474465Srwatson{
14574465Srwatson  const char *protocol_name;
14674465Srwatson  char *cp;
14774465Srwatson  struct servent *servent;
14874465Srwatson  int port;
14974465Srwatson
15074465Srwatson  switch (proto) {
15174465Srwatson  case P_UDP:
15274465Srwatson    protocol_name = "udp";
15374465Srwatson    break;
15474465Srwatson  case P_TCP:
15574465Srwatson    protocol_name = "tcp";
15674465Srwatson    break;
15774465Srwatson  default:
15874465Srwatson    protocol_name = 0;
15974465Srwatson  }
16074465Srwatson
16174465Srwatson  servent = getservbyname(service, protocol_name);
16274465Srwatson  if (servent != 0)
16374465Srwatson    return (ntohs(servent->s_port));
16474465Srwatson
16574465Srwatson  port = strtol(service, &cp, 0);
16674465Srwatson  if (cp == service) {
16774465Srwatson    log_Printf(LogWARN, "ParsePort: %s is not a port name or number.\n",
16874465Srwatson	      service);
16974465Srwatson    return (0);
17074465Srwatson  }
17174465Srwatson  return (port);
17274465Srwatson}
17374465Srwatson
17474465Srwatson/*
17574465Srwatson *	ICMP Syntax:	src eq icmp_message_type
17674465Srwatson */
17774465Srwatsonstatic int
17874465SrwatsonParseIcmp(int argc, char const *const *argv, struct filterent *tgt)
17974465Srwatson{
18074465Srwatson  int type;
18174465Srwatson  char *cp;
18274465Srwatson
18374465Srwatson  switch (argc) {
18474465Srwatson  case 0:
18574465Srwatson    /* permit/deny all ICMP types */
18674465Srwatson    tgt->opt.srcop = OP_NONE;
18774465Srwatson    break;
18874465Srwatson
18974465Srwatson  case 3:
19074465Srwatson    if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) {
19174465Srwatson      type = strtol(argv[2], &cp, 0);
19274465Srwatson      if (cp == argv[2]) {
19374465Srwatson	log_Printf(LogWARN, "ParseIcmp: type is expected.\n");
19474465Srwatson	return (0);
19574465Srwatson      }
19674465Srwatson      tgt->opt.srcop = OP_EQ;
19774465Srwatson      tgt->opt.srcport = type;
19874465Srwatson    }
19974465Srwatson    break;
20074465Srwatson
20174465Srwatson  default:
20274465Srwatson    log_Printf(LogWARN, "ParseIcmp: bad icmp syntax.\n");
20374465Srwatson    return (0);
20474465Srwatson  }
20574465Srwatson  return (1);
20674465Srwatson}
20774465Srwatson
20874465Srwatson/*
20974465Srwatson *	UDP Syntax: [src op port] [dst op port]
21074465Srwatson */
21174465Srwatsonstatic int
21274465SrwatsonParseUdpOrTcp(int argc, char const *const *argv, int proto,
21374465Srwatson              struct filterent *tgt)
21474465Srwatson{
21574465Srwatson  tgt->opt.srcop = tgt->opt.dstop = OP_NONE;
21674465Srwatson  tgt->opt.estab = tgt->opt.syn = tgt->opt.finrst = 0;
21774465Srwatson
21874465Srwatson  if (argc >= 3 && !strcmp(*argv, "src")) {
21974465Srwatson    tgt->opt.srcop = filter_Nam2Op(argv[1]);
22074465Srwatson    if (tgt->opt.srcop == OP_NONE) {
22174465Srwatson      log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n");
22274465Srwatson      return (0);
22374465Srwatson    }
22474465Srwatson    tgt->opt.srcport = ParsePort(argv[2], proto);
22574465Srwatson    if (tgt->opt.srcport == 0)
22674465Srwatson      return (0);
22774465Srwatson    argc -= 3;
22874465Srwatson    argv += 3;
22974465Srwatson  }
23074465Srwatson
23174465Srwatson  if (argc >= 3 && !strcmp(argv[0], "dst")) {
23274465Srwatson    tgt->opt.dstop = filter_Nam2Op(argv[1]);
23374465Srwatson    if (tgt->opt.dstop == OP_NONE) {
23474465Srwatson      log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n");
23574465Srwatson      return (0);
23674465Srwatson    }
23774465Srwatson    tgt->opt.dstport = ParsePort(argv[2], proto);
23874465Srwatson    if (tgt->opt.dstport == 0)
23974465Srwatson      return (0);
24074465Srwatson    argc -= 3;
24174465Srwatson    argv += 3;
24274465Srwatson  }
24374465Srwatson
24474465Srwatson  if (proto == P_TCP) {
24574465Srwatson    for (; argc > 0; argc--, argv++)
24674465Srwatson      if (!strcmp(*argv, "estab"))
24774465Srwatson        tgt->opt.estab = 1;
24874465Srwatson      else if (!strcmp(*argv, "syn"))
24974465Srwatson        tgt->opt.syn = 1;
25074465Srwatson      else if (!strcmp(*argv, "finrst"))
25174465Srwatson        tgt->opt.finrst = 1;
25274465Srwatson      else
25374465Srwatson        break;
25474465Srwatson  }
255
256  if (argc > 0) {
257    log_Printf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv);
258    return 0;
259  }
260
261  return 1;
262}
263
264static unsigned
265addrtype(const char *addr)
266{
267  if (!strncasecmp(addr, "MYADDR", 6) && (addr[6] == '\0' || addr[6] == '/'))
268    return T_MYADDR;
269  if (!strncasecmp(addr, "HISADDR", 7) && (addr[7] == '\0' || addr[7] == '/'))
270    return T_HISADDR;
271
272  return T_ADDR;
273}
274
275static const char *
276addrstr(struct in_addr addr, unsigned type)
277{
278  switch (type) {
279    case T_MYADDR:
280      return "MYADDR";
281    case T_HISADDR:
282      return "HISADDR";
283  }
284  return inet_ntoa(addr);
285}
286
287static int
288Parse(struct ipcp *ipcp, int argc, char const *const *argv,
289      struct filterent *ofp)
290{
291  int action, proto;
292  int val;
293  char *wp;
294  struct filterent filterdata;
295
296  val = strtol(*argv, &wp, 0);
297  if (*argv == wp || val > MAXFILTERS) {
298    log_Printf(LogWARN, "Parse: invalid filter number.\n");
299    return (0);
300  }
301  if (val < 0) {
302    for (val = 0; val < MAXFILTERS; val++) {
303      ofp->action = A_NONE;
304      ofp++;
305    }
306    log_Printf(LogWARN, "Parse: filter cleared.\n");
307    return (1);
308  }
309  ofp += val;
310
311  if (--argc == 0) {
312    log_Printf(LogWARN, "Parse: missing action.\n");
313    return (0);
314  }
315  argv++;
316
317  proto = P_NONE;
318  memset(&filterdata, '\0', sizeof filterdata);
319
320  if (!strcmp(*argv, "permit")) {
321    action = A_PERMIT;
322  } else if (!strcmp(*argv, "deny")) {
323    action = A_DENY;
324  } else if (!strcmp(*argv, "clear")) {
325    ofp->action = A_NONE;
326    return (1);
327  } else {
328    log_Printf(LogWARN, "Parse: bad action: %s\n", *argv);
329    return (0);
330  }
331  filterdata.action = action;
332
333  argc--;
334  argv++;
335
336  if (argc && filterdata.action == A_DENY) {
337    if (!strcmp(*argv, "host")) {
338      filterdata.action |= A_UHOST;
339      argc--;
340      argv++;
341    } else if (!strcmp(*argv, "port")) {
342      filterdata.action |= A_UPORT;
343      argc--;
344      argv++;
345    }
346  }
347
348  proto = filter_Nam2Proto(argc, argv);
349  if (proto == P_NONE) {
350    if (!argc)
351      log_Printf(LogWARN, "Parse: address/mask is expected.\n");
352    else if (ParseAddr(ipcp, *argv, &filterdata.src.ipaddr,
353                       &filterdata.src.mask, &filterdata.src.width)) {
354      filterdata.srctype = addrtype(*argv);
355      argc--;
356      argv++;
357      proto = filter_Nam2Proto(argc, argv);
358      if (!argc)
359        log_Printf(LogWARN, "Parse: address/mask is expected.\n");
360      else if (proto == P_NONE) {
361	if (ParseAddr(ipcp, *argv, &filterdata.dst.ipaddr, &filterdata.dst.mask,
362                      &filterdata.dst.width)) {
363          filterdata.dsttype = addrtype(*argv);
364	  argc--;
365	  argv++;
366	} else
367          filterdata.dsttype = T_ADDR;
368	proto = filter_Nam2Proto(argc, argv);
369	if (argc && proto != P_NONE) {
370	  argc--;
371	  argv++;
372	}
373      } else {
374	argc--;
375	argv++;
376      }
377    } else {
378      log_Printf(LogWARN, "Parse: Address/protocol expected.\n");
379      return (0);
380    }
381  } else {
382    argc--;
383    argv++;
384  }
385
386  val = 1;
387  filterdata.proto = proto;
388
389  switch (proto) {
390  case P_TCP:
391    val = ParseUdpOrTcp(argc, argv, P_TCP, &filterdata);
392    break;
393  case P_UDP:
394    val = ParseUdpOrTcp(argc, argv, P_UDP, &filterdata);
395    break;
396  case P_ICMP:
397    val = ParseIcmp(argc, argv, &filterdata);
398    break;
399  }
400
401  log_Printf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(filterdata.src.ipaddr));
402  log_Printf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(filterdata.src.mask));
403  log_Printf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(filterdata.dst.ipaddr));
404  log_Printf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(filterdata.dst.mask));
405  log_Printf(LogDEBUG, "Parse: Proto = %d\n", proto);
406
407  log_Printf(LogDEBUG, "Parse: src:  %s (%d)\n",
408            filter_Op2Nam(filterdata.opt.srcop), filterdata.opt.srcport);
409  log_Printf(LogDEBUG, "Parse: dst:  %s (%d)\n",
410            filter_Op2Nam(filterdata.opt.dstop), filterdata.opt.dstport);
411  log_Printf(LogDEBUG, "Parse: estab: %u\n", filterdata.opt.estab);
412  log_Printf(LogDEBUG, "Parse: syn: %u\n", filterdata.opt.syn);
413  log_Printf(LogDEBUG, "Parse: finrst: %u\n", filterdata.opt.finrst);
414
415  if (val)
416    *ofp = filterdata;
417  return (val);
418}
419
420int
421filter_Set(struct cmdargs const *arg)
422{
423  struct filter *filter;
424
425  if (arg->argc < arg->argn+2)
426    return -1;
427
428  if (!strcmp(arg->argv[arg->argn], "in"))
429    filter = &arg->bundle->filter.in;
430  else if (!strcmp(arg->argv[arg->argn], "out"))
431    filter = &arg->bundle->filter.out;
432  else if (!strcmp(arg->argv[arg->argn], "dial"))
433    filter = &arg->bundle->filter.dial;
434  else if (!strcmp(arg->argv[arg->argn], "alive"))
435    filter = &arg->bundle->filter.alive;
436  else {
437    log_Printf(LogWARN, "filter_Set: %s: Invalid filter name.\n",
438              arg->argv[arg->argn]);
439    return -1;
440  }
441
442  Parse(&arg->bundle->ncp.ipcp, arg->argc - arg->argn - 1,
443        arg->argv + arg->argn + 1, filter->rule);
444  return 0;
445}
446
447const char *
448filter_Action2Nam(int act)
449{
450  static const char *actname[] = { "none   ", "permit ", "deny   " };
451  return actname[act & (A_PERMIT|A_DENY)];
452}
453
454static void
455doShowFilter(struct filterent *fp, struct prompt *prompt)
456{
457  int n;
458
459  for (n = 0; n < MAXFILTERS; n++, fp++) {
460    if (fp->action != A_NONE) {
461      prompt_Printf(prompt, "  %2d %s", n, filter_Action2Nam(fp->action));
462      if (fp->action & A_UHOST)
463        prompt_Printf(prompt, "host ");
464      else if (fp->action & A_UPORT)
465        prompt_Printf(prompt, "port ");
466      else
467        prompt_Printf(prompt, "     ");
468      prompt_Printf(prompt, "%s/%d ", addrstr(fp->src.ipaddr, fp->srctype),
469                    fp->src.width);
470      prompt_Printf(prompt, "%s/%d ", addrstr(fp->dst.ipaddr, fp->dsttype),
471                    fp->dst.width);
472      if (fp->proto) {
473	prompt_Printf(prompt, "%s", filter_Proto2Nam(fp->proto));
474
475	if (fp->opt.srcop)
476	  prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->opt.srcop),
477		  fp->opt.srcport);
478	if (fp->opt.dstop)
479	  prompt_Printf(prompt, " dst %s %d", filter_Op2Nam(fp->opt.dstop),
480		  fp->opt.dstport);
481	if (fp->opt.estab)
482	  prompt_Printf(prompt, " estab");
483	if (fp->opt.syn)
484	  prompt_Printf(prompt, " syn");
485	if (fp->opt.finrst)
486	  prompt_Printf(prompt, " finrst");
487      }
488      prompt_Printf(prompt, "\n");
489    }
490  }
491}
492
493int
494filter_Show(struct cmdargs const *arg)
495{
496  if (arg->argc > arg->argn+1)
497    return -1;
498
499  if (arg->argc == arg->argn+1) {
500    struct filter *filter;
501
502    if (!strcmp(arg->argv[arg->argn], "in"))
503      filter = &arg->bundle->filter.in;
504    else if (!strcmp(arg->argv[arg->argn], "out"))
505      filter = &arg->bundle->filter.out;
506    else if (!strcmp(arg->argv[arg->argn], "dial"))
507      filter = &arg->bundle->filter.dial;
508    else if (!strcmp(arg->argv[arg->argn], "alive"))
509      filter = &arg->bundle->filter.alive;
510    else
511      return -1;
512    doShowFilter(filter->rule, arg->prompt);
513  } else {
514    struct filter *filter[4];
515    int f;
516
517    filter[0] = &arg->bundle->filter.in;
518    filter[1] = &arg->bundle->filter.out;
519    filter[2] = &arg->bundle->filter.dial;
520    filter[3] = &arg->bundle->filter.alive;
521    for (f = 0; f < 4; f++) {
522      if (f)
523        prompt_Printf(arg->prompt, "\n");
524      prompt_Printf(arg->prompt, "%s:\n", filter[f]->name);
525      doShowFilter(filter[f]->rule, arg->prompt);
526    }
527  }
528
529  return 0;
530}
531
532static const char *protoname[] = { "none", "tcp", "udp", "icmp" };
533
534const char *
535filter_Proto2Nam(int proto)
536{
537  if (proto >= sizeof protoname / sizeof protoname[0])
538    return "unknown";
539  return protoname[proto];
540}
541
542static int
543filter_Nam2Proto(int argc, char const *const *argv)
544{
545  int proto;
546
547  if (argc == 0)
548    proto = 0;
549  else
550    for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--)
551      if (!strcasecmp(*argv, protoname[proto]))
552        break;
553
554  return proto;
555}
556
557static const char *opname[] = {"none", "eq", "gt", "unknown", "lt"};
558
559const char *
560filter_Op2Nam(int op)
561{
562  if (op >= sizeof opname / sizeof opname[0])
563    return "unknown";
564  return opname[op];
565
566}
567
568static int
569filter_Nam2Op(const char *cp)
570{
571  int op;
572
573  for (op = sizeof opname / sizeof opname[0] - 1; op; op--)
574    if (!strcasecmp(cp, opname[op]))
575      break;
576
577  return op;
578}
579
580void
581filter_AdjustAddr(struct filter *filter, struct in_addr *my_ip,
582                  struct in_addr *peer_ip)
583{
584  struct filterent *fp;
585  int n;
586
587  for (fp = filter->rule, n = 0; n < MAXFILTERS; fp++, n++)
588    if (fp->action != A_NONE) {
589      if (my_ip) {
590        if (fp->srctype == T_MYADDR)
591          fp->src.ipaddr = *my_ip;
592        if (fp->dsttype == T_MYADDR)
593          fp->dst.ipaddr = *my_ip;
594      }
595      if (peer_ip) {
596        if (fp->srctype == T_HISADDR)
597          fp->src.ipaddr = *peer_ip;
598        if (fp->dsttype == T_HISADDR)
599          fp->dst.ipaddr = *peer_ip;
600      }
601    }
602}
603