filter.c revision 27723
1250003Sadrian/*
2250003Sadrian *		PPP Filter command Interface
3250003Sadrian *
4250003Sadrian *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5250003Sadrian *
6250003Sadrian *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7250003Sadrian *
8250003Sadrian * Redistribution and use in source and binary forms are permitted
9250003Sadrian * provided that the above copyright notice and this paragraph are
10250003Sadrian * duplicated in all such forms and that any documentation,
11250003Sadrian * advertising materials, and other materials related to such
12250003Sadrian * distribution and use acknowledge that the software was developed
13250003Sadrian * by the Internet Initiative Japan.  The name of the
14250003Sadrian * IIJ may not be used to endorse or promote products derived
15250003Sadrian * from this software without specific prior written permission.
16250003Sadrian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17250003Sadrian * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18250003Sadrian * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19250003Sadrian *
20250003Sadrian * $Id: filter.c,v 1.11 1997/06/28 01:34:03 brian Exp $
21250003Sadrian *
22250003Sadrian *	TODO: Shoud send ICMP error message when we discard packets.
23250003Sadrian */
24250003Sadrian
25250003Sadrian#include <sys/types.h>
26250003Sadrian#include <sys/socket.h>
27250003Sadrian#include <sys/param.h>
28250003Sadrian#include <netinet/in.h>
29250003Sadrian#include <arpa/inet.h>
30250003Sadrian#include <netdb.h>
31250003Sadrian#include <stdio.h>
32250003Sadrian#include <stdlib.h>
33250003Sadrian#include <strings.h>
34250003Sadrian#include "command.h"
35250003Sadrian#include "mbuf.h"
36250003Sadrian#include "log.h"
37250003Sadrian#include "filter.h"
38250003Sadrian#include "loadalias.h"
39250003Sadrian#include "vars.h"
40250003Sadrian#include "ipcp.h"
41250003Sadrian
42250003Sadrianstatic struct filterent filterdata;
43250003Sadrian
44250003Sadrianstatic u_long netmasks[33] = {
45250003Sadrian 0x00000000,
46250003Sadrian 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
47250003Sadrian 0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
48250003Sadrian 0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
49250003Sadrian 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
50250003Sadrian 0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
51250008Sadrian 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
52250003Sadrian 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
53250008Sadrian 0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
54250008Sadrian};
55250003Sadrian
56250003Sadrianint
57250003SadrianParseAddr(argc, argv, paddr, pmask, pwidth)
58250003Sadrianint argc;
59250003Sadrianchar **argv;
60250003Sadrianstruct in_addr *paddr;
61250003Sadrianstruct in_addr *pmask;
62250003Sadrianint *pwidth;
63250003Sadrian{
64250003Sadrian  int bits;
65250003Sadrian  char *cp, *wp;
66250003Sadrian
67250003Sadrian  if (argc < 1) {
68250003Sadrian    LogPrintf(LogWARN, "ParseAddr: address/mask is expected.\n");
69250003Sadrian    return(0);
70250003Sadrian  }
71250003Sadrian
72250003Sadrian  pmask->s_addr = 0xffffffff;	/* Assume 255.255.255.255 as default */
73250003Sadrian  cp = index(*argv, '/');
74250003Sadrian  if (cp) *cp++ = '\0';
75250003Sadrian  if (strcasecmp(*argv, "HISADDR") == 0)
76250003Sadrian    *paddr = IpcpInfo.his_ipaddr;
77250003Sadrian  else if (strcasecmp(*argv, "MYADDR") == 0)
78250008Sadrian    *paddr = IpcpInfo.want_ipaddr;
79250003Sadrian  else
80250003Sadrian    paddr->s_addr = inet_addr(*argv);
81250003Sadrian  if (cp && *cp) {
82250003Sadrian    bits = strtol(cp, &wp, 0);
83250003Sadrian    if (cp == wp || bits < 0 || bits > 32) {
84250003Sadrian      LogPrintf(LogWARN, "ParseAddr: bad mask width.\n");
85250003Sadrian      return(0);
86250003Sadrian    }
87250003Sadrian  } else {
88250003Sadrian    /* if width is not given, assume whole 32 bits are meaningfull */
89250003Sadrian    bits = 32;
90250003Sadrian  }
91250003Sadrian
92250003Sadrian  *pwidth = bits;
93250003Sadrian  pmask->s_addr = htonl(netmasks[bits]);
94250003Sadrian
95250003Sadrian  return(1);
96250008Sadrian}
97250003Sadrian
98250003Sadrianstatic int
99250003SadrianParseProto(argc, argv)
100250003Sadrianint argc;
101250003Sadrianchar **argv;
102250003Sadrian{
103250003Sadrian  int proto;
104250003Sadrian
105250003Sadrian  if (argc < 1)
106250003Sadrian    return(P_NONE);
107250003Sadrian
108250003Sadrian  if (STREQ(*argv, "tcp"))
109250003Sadrian    proto = P_TCP;
110250003Sadrian  else if (STREQ(*argv, "udp"))
111250003Sadrian    proto = P_UDP;
112250003Sadrian  else if (STREQ(*argv, "icmp"))
113250003Sadrian    proto = P_ICMP;
114250003Sadrian  else
115250003Sadrian    proto = P_NONE;
116250003Sadrian  return(proto);
117250003Sadrian}
118250003Sadrian
119250003Sadrianstatic int
120250003SadrianParsePort(service, proto)
121250003Sadrianchar *service;
122250003Sadrianint proto;
123250003Sadrian{
124250008Sadrian  char *protocol_name, *cp;
125250003Sadrian  struct servent *servent;
126250003Sadrian  int port;
127250003Sadrian
128250003Sadrian  switch (proto) {
129250003Sadrian  case P_UDP:
130250003Sadrian    protocol_name = "udp";
131250003Sadrian    break;
132250003Sadrian  case P_TCP:
133250003Sadrian    protocol_name = "tcp";
134250003Sadrian    break;
135250003Sadrian  default:
136250003Sadrian    protocol_name = 0;
137250003Sadrian  }
138250003Sadrian
139250003Sadrian  servent = getservbyname (service, protocol_name);
140250003Sadrian  if (servent != 0)
141250003Sadrian    return(ntohs(servent->s_port));
142250003Sadrian
143250003Sadrian  port = strtol(service, &cp, 0);
144250003Sadrian  if (cp == service) {
145250003Sadrian    LogPrintf(LogWARN, "ParsePort: %s is not a port name or number.\n",
146250003Sadrian              service);
147250003Sadrian    return(0);
148250003Sadrian  }
149250003Sadrian  return(port);
150250003Sadrian}
151250003Sadrian
152250003Sadrian/*
153250003Sadrian *	ICMP Syntax:	src eq icmp_message_type
154250003Sadrian */
155250003Sadrianstatic int
156250003SadrianParseIcmp(argc, argv)
157250003Sadrianint argc;
158250003Sadrianchar **argv;
159250003Sadrian{
160250003Sadrian  int type;
161250003Sadrian  char *cp;
162250003Sadrian
163250003Sadrian  switch (argc) {
164250003Sadrian  case 0:
165250003Sadrian    /* permit/deny all ICMP types */
166250003Sadrian    filterdata.opt.srcop = OP_NONE;
167250003Sadrian    break;
168250003Sadrian  default:
169250003Sadrian    LogPrintf(LogWARN, "ParseIcmp: bad icmp syntax.\n");
170250003Sadrian    return(0);
171250003Sadrian  case 3:
172250003Sadrian    if (STREQ(*argv, "src") && STREQ(argv[1], "eq")) {
173250003Sadrian      type = strtol(argv[2], &cp, 0);
174250003Sadrian      if (cp == argv[2]) {
175250003Sadrian	LogPrintf(LogWARN, "ParseIcmp: type is expected.\n");
176250003Sadrian	return(0);
177250003Sadrian      }
178250003Sadrian      filterdata.opt.srcop = OP_EQ;
179250003Sadrian      filterdata.opt.srcport = type;
180250003Sadrian    }
181250003Sadrian    break;
182250003Sadrian  }
183250003Sadrian  return(1);
184250003Sadrian}
185250003Sadrian
186250003Sadrianstatic int
187250003SadrianParseOp(cp)
188250003Sadrianchar *cp;
189250003Sadrian{
190250003Sadrian  int op = OP_NONE;
191250003Sadrian
192250003Sadrian  if (STREQ(cp, "eq"))
193250003Sadrian    op = OP_EQ;
194250003Sadrian  else if (STREQ(cp, "gt"))
195250008Sadrian    op = OP_GT;
196250003Sadrian  else if (STREQ(cp, "lt"))
197250003Sadrian    op = OP_LT;
198250003Sadrian  return(op);
199250003Sadrian}
200250003Sadrian
201250003Sadrian/*
202250003Sadrian *	UDP Syntax: [src op port] [dst op port]
203250003Sadrian */
204250003Sadrianstatic int
205250003SadrianParseUdpOrTcp(argc, argv, proto)
206250003Sadrianint argc;
207250003Sadrianchar **argv;
208250003Sadrianint proto;
209250003Sadrian{
210250003Sadrian
211250003Sadrian  if (argc == 0) {
212250003Sadrian    /* permit/deny all tcp traffic */
213250003Sadrian    filterdata.opt.srcop = filterdata.opt.dstop = A_NONE;
214250003Sadrian    return(1);
215250003Sadrian  }
216250003Sadrian  if (argc < 3) {
217250003Sadrian    LogPrintf(LogWARN, "ParseUdpOrTcp: bad udp/tcp syntax.\n");
218250003Sadrian    return(0);
219250003Sadrian  }
220250003Sadrian  if (argc >= 3 && STREQ(*argv, "src")) {
221250003Sadrian    filterdata.opt.srcop = ParseOp(argv[1]);
222250003Sadrian    if (filterdata.opt.srcop == OP_NONE) {
223250003Sadrian      LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
224250003Sadrian      return(0);
225250003Sadrian    }
226250003Sadrian    filterdata.opt.srcport = ParsePort(argv[2], proto);
227250003Sadrian    if (filterdata.opt.srcport == 0)
228250003Sadrian      return(0);
229250003Sadrian    argc -= 3; argv += 3;
230250003Sadrian    if (argc == 0)
231250003Sadrian      return(1);
232250003Sadrian  }
233250003Sadrian  if (argc >= 3 && STREQ(argv[0], "dst")) {
234250003Sadrian    filterdata.opt.dstop = ParseOp(argv[1]);
235250003Sadrian    if (filterdata.opt.dstop == OP_NONE) {
236250003Sadrian      LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
237250003Sadrian      return(0);
238250003Sadrian    }
239250003Sadrian    filterdata.opt.dstport = ParsePort(argv[2], proto);
240250003Sadrian    if (filterdata.opt.dstport == 0)
241250003Sadrian      return(0);
242250003Sadrian    argc -= 3; argv += 3;
243250003Sadrian    if (argc == 0)
244250003Sadrian      return(1);
245250003Sadrian  }
246250003Sadrian  if (argc == 1) {
247250003Sadrian    if (STREQ(*argv, "estab")) {
248250003Sadrian      filterdata.opt.estab = 1;
249250003Sadrian      return(1);
250250003Sadrian    }
251250003Sadrian    LogPrintf(LogWARN, "ParseUdpOrTcp: estab is expected: %s\n", *argv);
252250003Sadrian    return(0);
253250003Sadrian  }
254250003Sadrian  if (argc > 0)
255250003Sadrian    LogPrintf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv);
256250003Sadrian  return(0);
257250003Sadrian}
258250003Sadrian
259250003Sadrianchar *opname[] = { "none", "eq", "gt", "lt" };
260250003Sadrian
261250003Sadrianstatic int
262250003SadrianParse(argc, argv, ofp)
263250003Sadrianint argc;
264250003Sadrianchar **argv;
265250003Sadrianstruct filterent *ofp;
266250003Sadrian{
267250003Sadrian  int action, proto;
268250003Sadrian  int val;
269250003Sadrian  char *wp;
270250003Sadrian  struct filterent *fp = &filterdata;
271250003Sadrian
272250003Sadrian  val = strtol(*argv, &wp, 0);
273250003Sadrian  if (*argv == wp || val > MAXFILTERS) {
274250003Sadrian    LogPrintf(LogWARN, "Parse: invalid filter number.\n");
275250003Sadrian    return(0);
276250003Sadrian  }
277250003Sadrian  if (val < 0) {
278250003Sadrian    for (val = 0; val < MAXFILTERS; val++) {
279250003Sadrian      ofp->action = A_NONE;
280250003Sadrian      ofp++;
281250003Sadrian    }
282250003Sadrian    LogPrintf(LogWARN, "Parse: filter cleared.\n");
283250003Sadrian    return(1);
284250003Sadrian  }
285250003Sadrian  ofp += val;
286250003Sadrian
287250003Sadrian  if (--argc == 0) {
288250003Sadrian    LogPrintf(LogWARN, "Parse: missing action.\n");
289250003Sadrian    return(0);
290250003Sadrian  }
291250003Sadrian  argv++;
292250003Sadrian
293250003Sadrian  proto = P_NONE;
294250003Sadrian  bzero(&filterdata, sizeof(filterdata));
295250003Sadrian
296250003Sadrian  if (STREQ(*argv, "permit")) {
297250003Sadrian    action = A_PERMIT;
298250003Sadrian  } else if (STREQ(*argv, "deny")) {
299250003Sadrian    action = A_DENY;
300250003Sadrian  } else if (STREQ(*argv, "clear")) {
301250003Sadrian    ofp->action = A_NONE;
302250003Sadrian    return(1);
303250003Sadrian  } else {
304250003Sadrian    LogPrintf(LogWARN, "Parse: bad action: %s\n", *argv);
305250003Sadrian    return(0);
306250003Sadrian  }
307250003Sadrian  fp->action = action;
308250003Sadrian
309250003Sadrian  argc--; argv++;
310250003Sadrian
311250003Sadrian  if (fp->action == A_DENY) {
312250003Sadrian    if (STREQ(*argv, "host")) {
313250003Sadrian      fp->action |= A_UHOST;
314250003Sadrian      argc--; argv++;
315250003Sadrian    } else if (STREQ(*argv, "port")) {
316250003Sadrian      fp->action |= A_UPORT;
317250003Sadrian      argc--; argv++;
318250003Sadrian    }
319250003Sadrian  }
320250003Sadrian
321250003Sadrian  proto = ParseProto(argc, argv);
322250003Sadrian  if (proto == P_NONE) {
323250003Sadrian    if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) {
324250003Sadrian      argc--; argv++;
325250003Sadrian      proto = ParseProto(argc, argv);
326250003Sadrian      if (proto == P_NONE) {
327250003Sadrian	if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) {
328250003Sadrian	  argc--; argv++;
329250003Sadrian	}
330250003Sadrian	proto = ParseProto(argc, argv);
331250003Sadrian	if (proto) {
332250003Sadrian	  argc--; argv++;
333250003Sadrian	}
334250003Sadrian      } else {
335250003Sadrian	argc--; argv++;
336250003Sadrian      }
337250003Sadrian    } else {
338250003Sadrian      LogPrintf(LogWARN, "Parse: Address/protocol expected.\n");
339250003Sadrian      return(0);
340250003Sadrian    }
341250003Sadrian  } else {
342250003Sadrian    argc--; argv++;
343250003Sadrian  }
344250003Sadrian
345250003Sadrian  val = 1;
346250003Sadrian  fp->proto = proto;
347250003Sadrian
348250003Sadrian  switch (proto) {
349250003Sadrian  case P_TCP:
350250003Sadrian    val = ParseUdpOrTcp(argc, argv, P_TCP);
351250003Sadrian    break;
352250003Sadrian  case P_UDP:
353250003Sadrian    val = ParseUdpOrTcp(argc, argv, P_UDP);
354250003Sadrian    break;
355250003Sadrian  case P_ICMP:
356250003Sadrian    val = ParseIcmp(argc, argv);
357250003Sadrian    break;
358250003Sadrian  }
359250003Sadrian
360250003Sadrian  LogPrintf(LogDEBUG, "Parse: Src: %s", inet_ntoa(fp->saddr));
361250003Sadrian  LogPrintf(LogDEBUG, "Parse: Src mask: %s ", inet_ntoa(fp->smask));
362250003Sadrian  LogPrintf(LogDEBUG, "Parse: Dst: %s", inet_ntoa(fp->daddr));
363250003Sadrian  LogPrintf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(fp->dmask));
364250003Sadrian  LogPrintf(LogDEBUG, "Parse: Proto = %d\n", proto);
365250003Sadrian
366250003Sadrian  LogPrintf(LogDEBUG, "Parse: src:  %s (%d)\n", opname[fp->opt.srcop],
367250003Sadrian	    fp->opt.srcport);
368250003Sadrian  LogPrintf(LogDEBUG, "Parse: dst:  %s (%d)\n", opname[fp->opt.dstop],
369250003Sadrian	    fp->opt.dstport);
370250003Sadrian  LogPrintf(LogDEBUG, "Parse: estab: %d\n", fp->opt.estab);
371250003Sadrian
372250003Sadrian  if (val)
373250003Sadrian    *ofp = *fp;
374250003Sadrian  return(val);
375250003Sadrian}
376250003Sadrian
377250003Sadrianint
378250003SadrianSetIfilter(list, argc, argv)
379250003Sadrianstruct cmdtab *list;
380250003Sadrianint argc;
381250003Sadrianchar **argv;
382250003Sadrian{
383250003Sadrian  if (argc > 0) {
384250003Sadrian    (void) Parse(argc, argv, ifilters);
385250003Sadrian    return 0;
386250003Sadrian  }
387250003Sadrian
388250003Sadrian  return -1;
389250003Sadrian}
390250003Sadrian
391250003Sadrianint
392250003SadrianSetOfilter(list, argc, argv)
393250003Sadrianstruct cmdtab *list;
394250003Sadrianint argc;
395250003Sadrianchar **argv;
396250003Sadrian{
397250003Sadrian  if (argc > 0) {
398250003Sadrian    (void) Parse(argc, argv, ofilters);
399250003Sadrian    return 0;
400250003Sadrian  }
401250003Sadrian
402250003Sadrian  return -1;
403250003Sadrian}
404250003Sadrian
405250003Sadrianint
406250003SadrianSetDfilter(list, argc, argv)
407250008Sadrianstruct cmdtab *list;
408250008Sadrianint argc;
409250008Sadrianchar **argv;
410250008Sadrian{
411250003Sadrian  if (argc > 0) {
412250003Sadrian    (void) Parse(argc, argv, dfilters);
413250003Sadrian    return 0;
414250003Sadrian  }
415250003Sadrian
416250003Sadrian  return -1;
417250003Sadrian}
418250003Sadrian
419250003Sadrianint
420250003SadrianSetAfilter(list, argc, argv)
421250003Sadrianstruct cmdtab *list;
422250003Sadrianint argc;
423250003Sadrianchar **argv;
424250003Sadrian{
425250003Sadrian  if (argc > 0) {
426250003Sadrian    (void) Parse(argc, argv, afilters);
427250003Sadrian    return 0;
428250003Sadrian  }
429250003Sadrian
430250003Sadrian  return -1;
431250003Sadrian}
432250003Sadrian
433250003Sadrianstatic char *protoname[] = {
434250003Sadrian  "none", "tcp", "udp", "icmp",
435250003Sadrian};
436250003Sadrian
437250003Sadrianstatic char *actname[] = {
438250008Sadrian  "none   ", "permit ", "deny   ",
439250003Sadrian};
440250003Sadrian
441250008Sadrianstatic void
442250003SadrianShowFilter(fp)
443250003Sadrianstruct filterent *fp;
444250003Sadrian{
445250003Sadrian  int n;
446250008Sadrian
447250008Sadrian  if (!VarTerm)
448250003Sadrian    return;
449250003Sadrian
450250003Sadrian  for (n = 0; n < MAXFILTERS; n++, fp++) {
451250003Sadrian    if (fp->action != A_NONE) {
452250003Sadrian      fprintf(VarTerm, "%2d %s", n, actname[fp->action]);
453250003Sadrian      fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
454250003Sadrian      fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
455250003Sadrian      if (fp->proto) {
456250003Sadrian	fprintf(VarTerm, "%s", protoname[fp->proto]);
457250003Sadrian
458250003Sadrian	if (fp->opt.srcop)
459250003Sadrian	  fprintf(VarTerm, " src %s %d", opname[fp->opt.srcop],
460250003Sadrian                  fp->opt.srcport);
461250003Sadrian	if (fp->opt.dstop)
462250003Sadrian	  fprintf(VarTerm, " dst %s %d", opname[fp->opt.dstop],
463250003Sadrian                  fp->opt.dstport);
464250003Sadrian	if (fp->opt.estab)
465250003Sadrian	  fprintf(VarTerm, " estab");
466250003Sadrian
467250003Sadrian      }
468250003Sadrian      fprintf(VarTerm, "\n");
469250003Sadrian    }
470250008Sadrian  }
471250003Sadrian}
472250003Sadrian
473250003Sadrianint
474250008SadrianShowIfilter(list, argc, argv)
475250003Sadrianstruct cmdtab *list;
476250003Sadrianint argc;
477250003Sadrianchar **argv;
478250003Sadrian{
479250003Sadrian  ShowFilter(ifilters);
480250003Sadrian  return 0;
481250003Sadrian}
482250003Sadrian
483250003Sadrianint
484250003SadrianShowOfilter(list, argc, argv)
485250003Sadrianstruct cmdtab *list;
486250003Sadrianint argc;
487250003Sadrianchar **argv;
488250003Sadrian{
489250003Sadrian  ShowFilter(ofilters);
490250003Sadrian  return 0;
491250003Sadrian}
492250003Sadrian
493250003Sadrianint
494250003SadrianShowDfilter(list, argc, argv)
495250003Sadrianstruct cmdtab *list;
496250003Sadrianint argc;
497250003Sadrianchar **argv;
498250003Sadrian{
499250003Sadrian  ShowFilter(dfilters);
500250003Sadrian  return 0;
501250003Sadrian}
502250003Sadrian
503250003Sadrianint
504250003SadrianShowAfilter(list, argc, argv)
505250003Sadrianstruct cmdtab *list;
506250003Sadrianint argc;
507250003Sadrianchar **argv;
508250003Sadrian{
509250003Sadrian  ShowFilter(afilters);
510250003Sadrian  return 0;
511250003Sadrian}
512250003Sadrian