filter.c revision 28974
1284990Scy/*
2294569Sdelphij *		PPP Filter command Interface
3284990Scy *
4284990Scy *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5284990Scy *
6284990Scy *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7284990Scy *
8330141Sdelphij * Redistribution and use in source and binary forms are permitted
9330141Sdelphij * provided that the above copyright notice and this paragraph are
10289997Sglebius * duplicated in all such forms and that any documentation,
11330141Sdelphij * advertising materials, and other materials related to such
12284990Scy * distribution and use acknowledge that the software was developed
13284990Scy * by the Internet Initiative Japan.  The name of the
14309008Sdelphij * IIJ may not be used to endorse or promote products derived
15284990Scy * from this software without specific prior written permission.
16284990Scy * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17284990Scy * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18284990Scy * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19289997Sglebius *
20289997Sglebius * $Id: filter.c,v 1.13 1997/08/25 00:29:11 brian Exp $
21289997Sglebius *
22289997Sglebius *	TODO: Shoud send ICMP error message when we discard packets.
23289997Sglebius */
24289997Sglebius
25289997Sglebius#include <sys/types.h>
26289997Sglebius#include <sys/socket.h>
27289997Sglebius#include <sys/param.h>
28289997Sglebius#include <netinet/in.h>
29289997Sglebius#include <arpa/inet.h>
30289997Sglebius#include <netdb.h>
31289997Sglebius#include <stdio.h>
32289997Sglebius#include <stdlib.h>
33289997Sglebius#include <strings.h>
34289997Sglebius#include "command.h"
35289997Sglebius#include "mbuf.h"
36289997Sglebius#include "log.h"
37289997Sglebius#include "filter.h"
38289997Sglebius#include "loadalias.h"
39289997Sglebius#include "vars.h"
40289997Sglebius#include "ipcp.h"
41330141Sdelphij
42289997Sglebiusstatic struct filterent filterdata;
43309008Sdelphij
44309008Sdelphijstatic u_long netmasks[33] = {
45309008Sdelphij  0x00000000,
46309008Sdelphij  0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
47309008Sdelphij  0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
48309008Sdelphij  0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
49309008Sdelphij  0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
50309008Sdelphij  0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
51309008Sdelphij  0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
52309008Sdelphij  0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
53309008Sdelphij  0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
54289997Sglebius};
55309008Sdelphij
56309008Sdelphijint
57309008SdelphijParseAddr(int argc,
58309008Sdelphij	  char **argv,
59309008Sdelphij	  struct in_addr * paddr,
60309008Sdelphij	  struct in_addr * pmask,
61309008Sdelphij	  int *pwidth)
62284990Scy{
63284990Scy  int bits;
64284990Scy  char *cp, *wp;
65289997Sglebius
66289997Sglebius  if (argc < 1) {
67294569Sdelphij    LogPrintf(LogWARN, "ParseAddr: address/mask is expected.\n");
68294569Sdelphij    return (0);
69294569Sdelphij  }
70294569Sdelphij  pmask->s_addr = 0xffffffff;	/* Assume 255.255.255.255 as default */
71294569Sdelphij  cp = index(*argv, '/');
72294569Sdelphij  if (cp)
73294569Sdelphij    *cp++ = '\0';
74284990Scy  if (strcasecmp(*argv, "HISADDR") == 0)
75289997Sglebius    *paddr = IpcpInfo.his_ipaddr;
76284990Scy  else if (strcasecmp(*argv, "MYADDR") == 0)
77284990Scy    *paddr = IpcpInfo.want_ipaddr;
78284990Scy  else
79289997Sglebius    paddr->s_addr = inet_addr(*argv);
80284990Scy  if (cp && *cp) {
81284990Scy    bits = strtol(cp, &wp, 0);
82284990Scy    if (cp == wp || bits < 0 || bits > 32) {
83330141Sdelphij      LogPrintf(LogWARN, "ParseAddr: bad mask width.\n");
84284990Scy      return (0);
85284990Scy    }
86284990Scy  } else {
87284990Scy    /* if width is not given, assume whole 32 bits are meaningfull */
88284990Scy    bits = 32;
89284990Scy  }
90284990Scy
91289997Sglebius  *pwidth = bits;
92289997Sglebius  pmask->s_addr = htonl(netmasks[bits]);
93294569Sdelphij
94294569Sdelphij  return (1);
95294569Sdelphij}
96294569Sdelphij
97294569Sdelphijstatic int
98294569SdelphijParseProto(int argc, char **argv)
99284990Scy{
100284990Scy  int proto;
101284990Scy
102284990Scy  if (argc < 1)
103289997Sglebius    return (P_NONE);
104294569Sdelphij
105294569Sdelphij  if (STREQ(*argv, "tcp"))
106289997Sglebius    proto = P_TCP;
107284990Scy  else if (STREQ(*argv, "udp"))
108284990Scy    proto = P_UDP;
109284990Scy  else if (STREQ(*argv, "icmp"))
110284990Scy    proto = P_ICMP;
111294569Sdelphij  else
112294569Sdelphij    proto = P_NONE;
113309008Sdelphij  return (proto);
114284990Scy}
115309008Sdelphij
116309008Sdelphijstatic int
117284990ScyParsePort(char *service, int proto)
118284990Scy{
119294569Sdelphij  char *protocol_name, *cp;
120294569Sdelphij  struct servent *servent;
121284990Scy  int port;
122284990Scy
123284990Scy  switch (proto) {
124284990Scy  case P_UDP:
125309008Sdelphij    protocol_name = "udp";
126309008Sdelphij    break;
127284990Scy  case P_TCP:
128284990Scy    protocol_name = "tcp";
129289997Sglebius    break;
130289997Sglebius  default:
131294569Sdelphij    protocol_name = 0;
132294569Sdelphij  }
133284990Scy
134284990Scy  servent = getservbyname(service, protocol_name);
135284990Scy  if (servent != 0)
136284990Scy    return (ntohs(servent->s_port));
137284990Scy
138284990Scy  port = strtol(service, &cp, 0);
139294569Sdelphij  if (cp == service) {
140284990Scy    LogPrintf(LogWARN, "ParsePort: %s is not a port name or number.\n",
141284990Scy	      service);
142284990Scy    return (0);
143289997Sglebius  }
144294569Sdelphij  return (port);
145294569Sdelphij}
146284990Scy
147309008Sdelphij/*
148309008Sdelphij *	ICMP Syntax:	src eq icmp_message_type
149284990Scy */
150309008Sdelphijstatic int
151309008SdelphijParseIcmp(int argc, char **argv)
152284990Scy{
153284990Scy  int type;
154289997Sglebius  char *cp;
155289997Sglebius
156294569Sdelphij  switch (argc) {
157294569Sdelphij  case 0:
158284990Scy    /* permit/deny all ICMP types */
159309008Sdelphij    filterdata.opt.srcop = OP_NONE;
160309008Sdelphij    break;
161284990Scy  default:
162309008Sdelphij    LogPrintf(LogWARN, "ParseIcmp: bad icmp syntax.\n");
163309008Sdelphij    return (0);
164284990Scy  case 3:
165284990Scy    if (STREQ(*argv, "src") && STREQ(argv[1], "eq")) {
166289997Sglebius      type = strtol(argv[2], &cp, 0);
167289997Sglebius      if (cp == argv[2]) {
168294569Sdelphij	LogPrintf(LogWARN, "ParseIcmp: type is expected.\n");
169294569Sdelphij	return (0);
170309008Sdelphij      }
171309008Sdelphij      filterdata.opt.srcop = OP_EQ;
172309008Sdelphij      filterdata.opt.srcport = type;
173309008Sdelphij    }
174309008Sdelphij    break;
175309008Sdelphij  }
176309008Sdelphij  return (1);
177284990Scy}
178284990Scy
179294569Sdelphijstatic int
180294569SdelphijParseOp(char *cp)
181309008Sdelphij{
182284990Scy  int op = OP_NONE;
183284990Scy
184284990Scy  if (STREQ(cp, "eq"))
185294569Sdelphij    op = OP_EQ;
186294569Sdelphij  else if (STREQ(cp, "gt"))
187284990Scy    op = OP_GT;
188284990Scy  else if (STREQ(cp, "lt"))
189284990Scy    op = OP_LT;
190309008Sdelphij  return (op);
191309008Sdelphij}
192284990Scy
193284990Scy/*
194289997Sglebius *	UDP Syntax: [src op port] [dst op port]
195289997Sglebius */
196294569Sdelphijstatic int
197294569SdelphijParseUdpOrTcp(int argc, char **argv, int proto)
198294569Sdelphij{
199284990Scy  if (argc == 0) {
200284990Scy    /* permit/deny all tcp traffic */
201284990Scy    filterdata.opt.srcop = filterdata.opt.dstop = A_NONE;
202284990Scy    return (1);
203284990Scy  }
204294569Sdelphij  if (argc < 3) {
205284990Scy    LogPrintf(LogWARN, "ParseUdpOrTcp: bad udp/tcp syntax.\n");
206309008Sdelphij    return (0);
207309008Sdelphij  }
208284990Scy  if (argc >= 3 && STREQ(*argv, "src")) {
209284990Scy    filterdata.opt.srcop = ParseOp(argv[1]);
210289997Sglebius    if (filterdata.opt.srcop == OP_NONE) {
211289997Sglebius      LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
212294569Sdelphij      return (0);
213294569Sdelphij    }
214294569Sdelphij    filterdata.opt.srcport = ParsePort(argv[2], proto);
215284990Scy    if (filterdata.opt.srcport == 0)
216284990Scy      return (0);
217284990Scy    argc -= 3;
218294569Sdelphij    argv += 3;
219284990Scy    if (argc == 0)
220284990Scy      return (1);
221309008Sdelphij  }
222309008Sdelphij  if (argc >= 3 && STREQ(argv[0], "dst")) {
223284990Scy    filterdata.opt.dstop = ParseOp(argv[1]);
224284990Scy    if (filterdata.opt.dstop == OP_NONE) {
225289997Sglebius      LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
226289997Sglebius      return (0);
227294569Sdelphij    }
228294569Sdelphij    filterdata.opt.dstport = ParsePort(argv[2], proto);
229294569Sdelphij    if (filterdata.opt.dstport == 0)
230284990Scy      return (0);
231284990Scy    argc -= 3;
232284990Scy    argv += 3;
233294569Sdelphij    if (argc == 0)
234284990Scy      return (1);
235284990Scy  }
236309008Sdelphij  if (argc == 1) {
237309008Sdelphij    if (STREQ(*argv, "estab")) {
238330141Sdelphij      filterdata.opt.estab = 1;
239309008Sdelphij      return (1);
240284990Scy    }
241284990Scy    LogPrintf(LogWARN, "ParseUdpOrTcp: estab is expected: %s\n", *argv);
242284990Scy    return (0);
243294569Sdelphij  }
244309008Sdelphij  if (argc > 0)
245284990Scy    LogPrintf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv);
246284990Scy  return (0);
247309008Sdelphij}
248309008Sdelphij
249284990Scychar *opname[] = {"none", "eq", "gt", "lt"};
250284990Scy
251289997Sglebiusstatic int
252289997SglebiusParse(int argc, char **argv, struct filterent * ofp)
253294569Sdelphij{
254294569Sdelphij  int action, proto;
255294569Sdelphij  int val;
256284990Scy  char *wp;
257284990Scy  struct filterent *fp = &filterdata;
258284990Scy
259294569Sdelphij  val = strtol(*argv, &wp, 0);
260294569Sdelphij  if (*argv == wp || val > MAXFILTERS) {
261294569Sdelphij    LogPrintf(LogWARN, "Parse: invalid filter number.\n");
262284990Scy    return (0);
263284990Scy  }
264309008Sdelphij  if (val < 0) {
265309008Sdelphij    for (val = 0; val < MAXFILTERS; val++) {
266330141Sdelphij      ofp->action = A_NONE;
267309008Sdelphij      ofp++;
268330141Sdelphij    }
269284990Scy    LogPrintf(LogWARN, "Parse: filter cleared.\n");
270284990Scy    return (1);
271309008Sdelphij  }
272309008Sdelphij  ofp += val;
273284990Scy
274284990Scy  if (--argc == 0) {
275289997Sglebius    LogPrintf(LogWARN, "Parse: missing action.\n");
276289997Sglebius    return (0);
277294569Sdelphij  }
278294569Sdelphij  argv++;
279284990Scy
280284990Scy  proto = P_NONE;
281309008Sdelphij  bzero(&filterdata, sizeof(filterdata));
282309008Sdelphij
283309008Sdelphij  if (STREQ(*argv, "permit")) {
284309008Sdelphij    action = A_PERMIT;
285284990Scy  } else if (STREQ(*argv, "deny")) {
286284990Scy    action = A_DENY;
287284990Scy  } else if (STREQ(*argv, "clear")) {
288284990Scy    ofp->action = A_NONE;
289309008Sdelphij    return (1);
290309008Sdelphij  } else {
291284990Scy    LogPrintf(LogWARN, "Parse: bad action: %s\n", *argv);
292284990Scy    return (0);
293289997Sglebius  }
294289997Sglebius  fp->action = action;
295294569Sdelphij
296294569Sdelphij  argc--;
297284990Scy  argv++;
298284990Scy
299309008Sdelphij  if (fp->action == A_DENY) {
300309008Sdelphij    if (STREQ(*argv, "host")) {
301309008Sdelphij      fp->action |= A_UHOST;
302309008Sdelphij      argc--;
303284990Scy      argv++;
304284990Scy    } else if (STREQ(*argv, "port")) {
305284990Scy      fp->action |= A_UPORT;
306284990Scy      argc--;
307309008Sdelphij      argv++;
308309008Sdelphij    }
309284990Scy  }
310284990Scy  proto = ParseProto(argc, argv);
311289997Sglebius  if (proto == P_NONE) {
312289997Sglebius    if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) {
313294569Sdelphij      argc--;
314294569Sdelphij      argv++;
315284990Scy      proto = ParseProto(argc, argv);
316284990Scy      if (proto == P_NONE) {
317309008Sdelphij	if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) {
318309008Sdelphij	  argc--;
319309008Sdelphij	  argv++;
320284990Scy	}
321294569Sdelphij	proto = ParseProto(argc, argv);
322294569Sdelphij	if (proto) {
323294569Sdelphij	  argc--;
324284990Scy	  argv++;
325309008Sdelphij	}
326309008Sdelphij      } else {
327284990Scy	argc--;
328284990Scy	argv++;
329289997Sglebius      }
330284990Scy    } else {
331289997Sglebius      LogPrintf(LogWARN, "Parse: Address/protocol expected.\n");
332294569Sdelphij      return (0);
333294569Sdelphij    }
334284990Scy  } else {
335284990Scy    argc--;
336309008Sdelphij    argv++;
337309008Sdelphij  }
338284990Scy
339284990Scy  val = 1;
340309008Sdelphij  fp->proto = proto;
341309008Sdelphij
342284990Scy  switch (proto) {
343284990Scy  case P_TCP:
344289997Sglebius    val = ParseUdpOrTcp(argc, argv, P_TCP);
345289997Sglebius    break;
346294569Sdelphij  case P_UDP:
347294569Sdelphij    val = ParseUdpOrTcp(argc, argv, P_UDP);
348284990Scy    break;
349284990Scy  case P_ICMP:
350309008Sdelphij    val = ParseIcmp(argc, argv);
351309008Sdelphij    break;
352284990Scy  }
353284990Scy
354309008Sdelphij  LogPrintf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(fp->saddr));
355309008Sdelphij  LogPrintf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(fp->smask));
356284990Scy  LogPrintf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(fp->daddr));
357284990Scy  LogPrintf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(fp->dmask));
358289997Sglebius  LogPrintf(LogDEBUG, "Parse: Proto = %d\n", proto);
359289997Sglebius
360294569Sdelphij  LogPrintf(LogDEBUG, "Parse: src:  %s (%d)\n", opname[fp->opt.srcop],
361294569Sdelphij	    fp->opt.srcport);
362284990Scy  LogPrintf(LogDEBUG, "Parse: dst:  %s (%d)\n", opname[fp->opt.dstop],
363284990Scy	    fp->opt.dstport);
364309008Sdelphij  LogPrintf(LogDEBUG, "Parse: estab: %d\n", fp->opt.estab);
365309008Sdelphij
366309008Sdelphij  if (val)
367284990Scy    *ofp = *fp;
368284990Scy  return (val);
369309008Sdelphij}
370309008Sdelphij
371284990Scyint
372284990ScySetIfilter(struct cmdtab * list, int argc, char **argv)
373289997Sglebius{
374289997Sglebius  if (argc > 0) {
375294569Sdelphij    (void) Parse(argc, argv, ifilters);
376294569Sdelphij    return 0;
377284990Scy  }
378284990Scy  return -1;
379284990Scy}
380284990Scy
381284990Scyint
382309008SdelphijSetOfilter(struct cmdtab * list, int argc, char **argv)
383284990Scy{
384284990Scy  if (argc > 0) {
385284990Scy    (void) Parse(argc, argv, ofilters);
386309008Sdelphij    return 0;
387284990Scy  }
388284990Scy  return -1;
389309008Sdelphij}
390309008Sdelphij
391284990Scyint
392284990ScySetDfilter(struct cmdtab * list, int argc, char **argv)
393289997Sglebius{
394289997Sglebius  if (argc > 0) {
395294569Sdelphij    (void) Parse(argc, argv, dfilters);
396294569Sdelphij    return 0;
397284990Scy  }
398284990Scy  return -1;
399309008Sdelphij}
400309008Sdelphij
401309008Sdelphijint
402284990ScySetAfilter(struct cmdtab * list, int argc, char **argv)
403284990Scy{
404309008Sdelphij  if (argc > 0) {
405284990Scy    (void) Parse(argc, argv, afilters);
406284990Scy    return 0;
407284990Scy  }
408289997Sglebius  return -1;
409289997Sglebius}
410294569Sdelphij
411294569Sdelphijstatic char *protoname[] = {
412284990Scy  "none", "tcp", "udp", "icmp",
413284990Scy};
414284990Scy
415309008Sdelphijstatic char *actname[] = {
416309008Sdelphij  "none   ", "permit ", "deny   ",
417284990Scy};
418284990Scy
419289997Sglebiusstatic void
420289997SglebiusShowFilter(struct filterent * fp)
421294569Sdelphij{
422294569Sdelphij  int n;
423284990Scy
424284990Scy  if (!VarTerm)
425284990Scy    return;
426284990Scy
427284990Scy  for (n = 0; n < MAXFILTERS; n++, fp++) {
428294569Sdelphij    if (fp->action != A_NONE) {
429309008Sdelphij      fprintf(VarTerm, "%2d %s", n, actname[fp->action]);
430309008Sdelphij      fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
431330141Sdelphij      fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
432309008Sdelphij      if (fp->proto) {
433284990Scy	fprintf(VarTerm, "%s", protoname[fp->proto]);
434330141Sdelphij
435284990Scy	if (fp->opt.srcop)
436284990Scy	  fprintf(VarTerm, " src %s %d", opname[fp->opt.srcop],
437309008Sdelphij		  fp->opt.srcport);
438309008Sdelphij	if (fp->opt.dstop)
439284990Scy	  fprintf(VarTerm, " dst %s %d", opname[fp->opt.dstop],
440284990Scy		  fp->opt.dstport);
441289997Sglebius	if (fp->opt.estab)
442289997Sglebius	  fprintf(VarTerm, " estab");
443294569Sdelphij
444294569Sdelphij      }
445284990Scy      fprintf(VarTerm, "\n");
446284990Scy    }
447284990Scy  }
448284990Scy}
449284990Scy
450294569Sdelphijint
451309008SdelphijShowIfilter(struct cmdtab * list, int argc, char **argv)
452309008Sdelphij{
453330141Sdelphij  ShowFilter(ifilters);
454330141Sdelphij  return 0;
455330141Sdelphij}
456330141Sdelphij
457330141Sdelphijint
458330141SdelphijShowOfilter(struct cmdtab * list, int argc, char **argv)
459330141Sdelphij{
460330141Sdelphij  ShowFilter(ofilters);
461330141Sdelphij  return 0;
462330141Sdelphij}
463330141Sdelphij
464330141Sdelphijint
465330141SdelphijShowDfilter(struct cmdtab * list, int argc, char **argv)
466330141Sdelphij{
467338531Sdelphij  ShowFilter(dfilters);
468338531Sdelphij  return 0;
469330141Sdelphij}
470330141Sdelphij
471330141Sdelphijint
472330141SdelphijShowAfilter(struct cmdtab * list, int argc, char **argv)
473330141Sdelphij{
474330141Sdelphij  ShowFilter(afilters);
475330141Sdelphij  return 0;
476330141Sdelphij}
477294569Sdelphij