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