filter.c revision 43313
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.26 1998/10/22 02:32:48 brian Exp $
21 *
22 *	TODO: Shoud send ICMP error message when we discard packets.
23 */
24
25#include <sys/param.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#include <netdb.h>
29#include <netinet/in_systm.h>
30#include <netinet/ip.h>
31#include <sys/un.h>
32
33#include <stdio.h>
34#include <stdlib.h>
35#include <strings.h>
36#include <termios.h>
37
38#include "defs.h"
39#include "command.h"
40#include "mbuf.h"
41#include "log.h"
42#include "iplist.h"
43#include "timer.h"
44#include "throughput.h"
45#include "lqr.h"
46#include "hdlc.h"
47#include "fsm.h"
48#include "lcp.h"
49#include "ccp.h"
50#include "link.h"
51#include "slcompress.h"
52#include "ipcp.h"
53#include "filter.h"
54#include "descriptor.h"
55#include "prompt.h"
56#include "mp.h"
57#ifndef NORADIUS
58#include "radius.h"
59#endif
60#include "bundle.h"
61
62static int filter_Nam2Proto(int, char const *const *);
63static int filter_Nam2Op(const char *);
64
65static const u_int32_t netmasks[33] = {
66  0x00000000,
67  0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
68  0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
69  0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
70  0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
71  0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
72  0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
73  0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
74  0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
75};
76
77struct in_addr
78bits2mask(int bits)
79{
80  struct in_addr result;
81
82  result.s_addr = htonl(netmasks[bits]);
83  return result;
84}
85
86int
87ParseAddr(struct ipcp *ipcp, const char *data,
88	  struct in_addr *paddr, struct in_addr *pmask, int *pwidth)
89{
90  int bits, len;
91  char *wp;
92  const char *cp;
93
94  if (pmask)
95    pmask->s_addr = INADDR_BROADCAST;	/* Assume 255.255.255.255 as default */
96
97  cp = pmask || pwidth ? strchr(data, '/') : NULL;
98  len = cp ? cp - data : strlen(data);
99
100  if (ipcp && strncasecmp(data, "HISADDR", len) == 0)
101    *paddr = ipcp->peer_ip;
102  else if (ipcp && strncasecmp(data, "MYADDR", len) == 0)
103    *paddr = ipcp->my_ip;
104  else if (len > 15)
105    log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", data);
106  else {
107    char s[16];
108    strncpy(s, data, len);
109    s[len] = '\0';
110    if (inet_aton(s, paddr) == 0) {
111      log_Printf(LogWARN, "ParseAddr: %s: Bad address\n", s);
112      return (0);
113    }
114  }
115  if (cp && *++cp) {
116    bits = strtol(cp, &wp, 0);
117    if (cp == wp || bits < 0 || bits > 32) {
118      log_Printf(LogWARN, "ParseAddr: bad mask width.\n");
119      return (0);
120    }
121  } else if (paddr->s_addr == INADDR_ANY)
122    /* An IP of 0.0.0.0 without a width is anything */
123    bits = 0;
124  else
125    /* If a valid IP is given without a width, assume 32 bits */
126    bits = 32;
127
128  if (pwidth)
129    *pwidth = bits;
130
131  if (pmask) {
132    if (paddr->s_addr == INADDR_ANY)
133      pmask->s_addr = INADDR_ANY;
134    else
135      *pmask = bits2mask(bits);
136  }
137
138  return (1);
139}
140
141static int
142ParsePort(const char *service, int proto)
143{
144  const char *protocol_name;
145  char *cp;
146  struct servent *servent;
147  int port;
148
149  switch (proto) {
150  case P_UDP:
151    protocol_name = "udp";
152    break;
153  case P_TCP:
154    protocol_name = "tcp";
155    break;
156  default:
157    protocol_name = 0;
158  }
159
160  servent = getservbyname(service, protocol_name);
161  if (servent != 0)
162    return (ntohs(servent->s_port));
163
164  port = strtol(service, &cp, 0);
165  if (cp == service) {
166    log_Printf(LogWARN, "ParsePort: %s is not a port name or number.\n",
167	      service);
168    return (0);
169  }
170  return (port);
171}
172
173/*
174 *	ICMP Syntax:	src eq icmp_message_type
175 */
176static int
177ParseIcmp(int argc, char const *const *argv, struct filterent *tgt)
178{
179  int type;
180  char *cp;
181
182  switch (argc) {
183  case 0:
184    /* permit/deny all ICMP types */
185    tgt->opt.srcop = OP_NONE;
186    break;
187
188  case 3:
189    if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) {
190      type = strtol(argv[2], &cp, 0);
191      if (cp == argv[2]) {
192	log_Printf(LogWARN, "ParseIcmp: type is expected.\n");
193	return (0);
194      }
195      tgt->opt.srcop = OP_EQ;
196      tgt->opt.srcport = type;
197    }
198    break;
199
200  default:
201    log_Printf(LogWARN, "ParseIcmp: bad icmp syntax.\n");
202    return (0);
203  }
204  return (1);
205}
206
207/*
208 *	UDP Syntax: [src op port] [dst op port]
209 */
210static int
211ParseUdpOrTcp(int argc, char const *const *argv, int proto,
212              struct filterent *tgt)
213{
214  tgt->opt.srcop = tgt->opt.dstop = OP_NONE;
215  tgt->opt.estab = tgt->opt.syn = tgt->opt.finrst = 0;
216
217  if (argc >= 3 && !strcmp(*argv, "src")) {
218    tgt->opt.srcop = filter_Nam2Op(argv[1]);
219    if (tgt->opt.srcop == OP_NONE) {
220      log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n");
221      return (0);
222    }
223    tgt->opt.srcport = ParsePort(argv[2], proto);
224    if (tgt->opt.srcport == 0)
225      return (0);
226    argc -= 3;
227    argv += 3;
228  }
229
230  if (argc >= 3 && !strcmp(argv[0], "dst")) {
231    tgt->opt.dstop = filter_Nam2Op(argv[1]);
232    if (tgt->opt.dstop == OP_NONE) {
233      log_Printf(LogWARN, "ParseUdpOrTcp: bad operation\n");
234      return (0);
235    }
236    tgt->opt.dstport = ParsePort(argv[2], proto);
237    if (tgt->opt.dstport == 0)
238      return (0);
239    argc -= 3;
240    argv += 3;
241  }
242
243  if (proto == P_TCP) {
244    for (; argc > 0; argc--, argv++)
245      if (!strcmp(*argv, "estab"))
246        tgt->opt.estab = 1;
247      else if (!strcmp(*argv, "syn"))
248        tgt->opt.syn = 1;
249      else if (!strcmp(*argv, "finrst"))
250        tgt->opt.finrst = 1;
251      else
252        break;
253  }
254
255  if (argc > 0) {
256    log_Printf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv);
257    return 0;
258  }
259
260  return 1;
261}
262
263static int
264Parse(struct ipcp *ipcp, int argc, char const *const *argv,
265      struct filterent *ofp)
266{
267  int action, proto;
268  int val;
269  char *wp;
270  struct filterent filterdata;
271
272  val = strtol(*argv, &wp, 0);
273  if (*argv == wp || val > MAXFILTERS) {
274    log_Printf(LogWARN, "Parse: invalid filter number.\n");
275    return (0);
276  }
277  if (val < 0) {
278    for (val = 0; val < MAXFILTERS; val++) {
279      ofp->action = A_NONE;
280      ofp++;
281    }
282    log_Printf(LogWARN, "Parse: filter cleared.\n");
283    return (1);
284  }
285  ofp += val;
286
287  if (--argc == 0) {
288    log_Printf(LogWARN, "Parse: missing action.\n");
289    return (0);
290  }
291  argv++;
292
293  proto = P_NONE;
294  memset(&filterdata, '\0', sizeof filterdata);
295
296  if (!strcmp(*argv, "permit")) {
297    action = A_PERMIT;
298  } else if (!strcmp(*argv, "deny")) {
299    action = A_DENY;
300  } else if (!strcmp(*argv, "clear")) {
301    ofp->action = A_NONE;
302    return (1);
303  } else {
304    log_Printf(LogWARN, "Parse: bad action: %s\n", *argv);
305    return (0);
306  }
307  filterdata.action = action;
308
309  argc--;
310  argv++;
311
312  if (argc && filterdata.action == A_DENY) {
313    if (!strcmp(*argv, "host")) {
314      filterdata.action |= A_UHOST;
315      argc--;
316      argv++;
317    } else if (!strcmp(*argv, "port")) {
318      filterdata.action |= A_UPORT;
319      argc--;
320      argv++;
321    }
322  }
323
324  proto = filter_Nam2Proto(argc, argv);
325  if (proto == P_NONE) {
326    if (!argc)
327      log_Printf(LogWARN, "Parse: address/mask is expected.\n");
328    else if (ParseAddr(ipcp, *argv, &filterdata.saddr, &filterdata.smask,
329                       &filterdata.swidth)) {
330      argc--;
331      argv++;
332      proto = filter_Nam2Proto(argc, argv);
333      if (!argc)
334        log_Printf(LogWARN, "Parse: address/mask is expected.\n");
335      else if (proto == P_NONE) {
336	if (ParseAddr(ipcp, *argv, &filterdata.daddr, &filterdata.dmask,
337                      &filterdata.dwidth)) {
338	  argc--;
339	  argv++;
340	}
341	proto = filter_Nam2Proto(argc, argv);
342	if (argc && proto != P_NONE) {
343	  argc--;
344	  argv++;
345	}
346      } else {
347	argc--;
348	argv++;
349      }
350    } else {
351      log_Printf(LogWARN, "Parse: Address/protocol expected.\n");
352      return (0);
353    }
354  } else {
355    argc--;
356    argv++;
357  }
358
359  val = 1;
360  filterdata.proto = proto;
361
362  switch (proto) {
363  case P_TCP:
364    val = ParseUdpOrTcp(argc, argv, P_TCP, &filterdata);
365    break;
366  case P_UDP:
367    val = ParseUdpOrTcp(argc, argv, P_UDP, &filterdata);
368    break;
369  case P_ICMP:
370    val = ParseIcmp(argc, argv, &filterdata);
371    break;
372  }
373
374  log_Printf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(filterdata.saddr));
375  log_Printf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(filterdata.smask));
376  log_Printf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(filterdata.daddr));
377  log_Printf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(filterdata.dmask));
378  log_Printf(LogDEBUG, "Parse: Proto = %d\n", proto);
379
380  log_Printf(LogDEBUG, "Parse: src:  %s (%d)\n",
381            filter_Op2Nam(filterdata.opt.srcop), filterdata.opt.srcport);
382  log_Printf(LogDEBUG, "Parse: dst:  %s (%d)\n",
383            filter_Op2Nam(filterdata.opt.dstop), filterdata.opt.dstport);
384  log_Printf(LogDEBUG, "Parse: estab: %u\n", filterdata.opt.estab);
385  log_Printf(LogDEBUG, "Parse: syn: %u\n", filterdata.opt.syn);
386  log_Printf(LogDEBUG, "Parse: finrst: %u\n", filterdata.opt.finrst);
387
388  if (val)
389    *ofp = filterdata;
390  return (val);
391}
392
393int
394filter_Set(struct cmdargs const *arg)
395{
396  struct filter *filter;
397
398  if (arg->argc < arg->argn+2)
399    return -1;
400
401  if (!strcmp(arg->argv[arg->argn], "in"))
402    filter = &arg->bundle->filter.in;
403  else if (!strcmp(arg->argv[arg->argn], "out"))
404    filter = &arg->bundle->filter.out;
405  else if (!strcmp(arg->argv[arg->argn], "dial"))
406    filter = &arg->bundle->filter.dial;
407  else if (!strcmp(arg->argv[arg->argn], "alive"))
408    filter = &arg->bundle->filter.alive;
409  else {
410    log_Printf(LogWARN, "filter_Set: %s: Invalid filter name.\n",
411              arg->argv[arg->argn]);
412    return -1;
413  }
414
415  Parse(&arg->bundle->ncp.ipcp, arg->argc - arg->argn - 1,
416        arg->argv + arg->argn + 1, filter->rule);
417  return 0;
418}
419
420const char *
421filter_Action2Nam(int act)
422{
423  static const char *actname[] = { "none   ", "permit ", "deny   " };
424  return actname[act & (A_PERMIT|A_DENY)];
425}
426
427static void
428doShowFilter(struct filterent *fp, struct prompt *prompt)
429{
430  int n;
431
432  for (n = 0; n < MAXFILTERS; n++, fp++) {
433    if (fp->action != A_NONE) {
434      prompt_Printf(prompt, "  %2d %s", n, filter_Action2Nam(fp->action));
435      if (fp->action & A_UHOST)
436        prompt_Printf(prompt, "host ");
437      else if (fp->action & A_UPORT)
438        prompt_Printf(prompt, "port ");
439      else
440        prompt_Printf(prompt, "     ");
441      prompt_Printf(prompt, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
442      prompt_Printf(prompt, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
443      if (fp->proto) {
444	prompt_Printf(prompt, "%s", filter_Proto2Nam(fp->proto));
445
446	if (fp->opt.srcop)
447	  prompt_Printf(prompt, " src %s %d", filter_Op2Nam(fp->opt.srcop),
448		  fp->opt.srcport);
449	if (fp->opt.dstop)
450	  prompt_Printf(prompt, " dst %s %d", filter_Op2Nam(fp->opt.dstop),
451		  fp->opt.dstport);
452	if (fp->opt.estab)
453	  prompt_Printf(prompt, " estab");
454	if (fp->opt.syn)
455	  prompt_Printf(prompt, " syn");
456	if (fp->opt.finrst)
457	  prompt_Printf(prompt, " finrst");
458      }
459      prompt_Printf(prompt, "\n");
460    }
461  }
462}
463
464int
465filter_Show(struct cmdargs const *arg)
466{
467  if (arg->argc > arg->argn+1)
468    return -1;
469
470  if (arg->argc == arg->argn+1) {
471    struct filter *filter;
472
473    if (!strcmp(arg->argv[arg->argn], "in"))
474      filter = &arg->bundle->filter.in;
475    else if (!strcmp(arg->argv[arg->argn], "out"))
476      filter = &arg->bundle->filter.out;
477    else if (!strcmp(arg->argv[arg->argn], "dial"))
478      filter = &arg->bundle->filter.dial;
479    else if (!strcmp(arg->argv[arg->argn], "alive"))
480      filter = &arg->bundle->filter.alive;
481    else
482      return -1;
483    doShowFilter(filter->rule, arg->prompt);
484  } else {
485    struct filter *filter[4];
486    int f;
487
488    filter[0] = &arg->bundle->filter.in;
489    filter[1] = &arg->bundle->filter.out;
490    filter[2] = &arg->bundle->filter.dial;
491    filter[3] = &arg->bundle->filter.alive;
492    for (f = 0; f < 4; f++) {
493      if (f)
494        prompt_Printf(arg->prompt, "\n");
495      prompt_Printf(arg->prompt, "%s:\n", filter[f]->name);
496      doShowFilter(filter[f]->rule, arg->prompt);
497    }
498  }
499
500  return 0;
501}
502
503static const char *protoname[] = { "none", "tcp", "udp", "icmp" };
504
505const char *
506filter_Proto2Nam(int proto)
507{
508  if (proto >= sizeof protoname / sizeof protoname[0])
509    return "unknown";
510  return protoname[proto];
511}
512
513static int
514filter_Nam2Proto(int argc, char const *const *argv)
515{
516  int proto;
517
518  if (argc == 0)
519    proto = 0;
520  else
521    for (proto = sizeof protoname / sizeof protoname[0] - 1; proto; proto--)
522      if (!strcasecmp(*argv, protoname[proto]))
523        break;
524
525  return proto;
526}
527
528static const char *opname[] = {"none", "eq", "gt", "unknown", "lt"};
529
530const char *
531filter_Op2Nam(int op)
532{
533  if (op >= sizeof opname / sizeof opname[0])
534    return "unknown";
535  return opname[op];
536
537}
538
539static int
540filter_Nam2Op(const char *cp)
541{
542  int op;
543
544  for (op = sizeof opname / sizeof opname[0] - 1; op; op--)
545    if (!strcasecmp(cp, opname[op]))
546      break;
547
548  return op;
549}
550