xref: /freebsd/usr.sbin/ppp/filter.c (revision 02f2e93b60c2b91feac8f45c4c889a5a8e40d8a2)
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.15 1997/10/23 10:09:35 brian Exp $
21  *
22  *	TODO: Shoud send ICMP error message when we discard packets.
23  */
24 
25 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <netdb.h>
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 
35 #include "command.h"
36 #include "mbuf.h"
37 #include "log.h"
38 #include "loadalias.h"
39 #include "vars.h"
40 #include "ipcp.h"
41 #include "filter.h"
42 
43 struct filterent ifilters[MAXFILTERS];	/* incoming packet filter */
44 struct filterent ofilters[MAXFILTERS];	/* outgoing packet filter */
45 struct filterent dfilters[MAXFILTERS];	/* dial-out packet filter */
46 struct filterent afilters[MAXFILTERS];	/* keep-alive packet filter */
47 
48 static struct filterent filterdata;
49 
50 static u_long netmasks[33] = {
51   0x00000000,
52   0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,
53   0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,
54   0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,
55   0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,
56   0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,
57   0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,
58   0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,
59   0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
60 };
61 
62 int
63 ParseAddr(int argc,
64 	  char **argv,
65 	  struct in_addr * paddr,
66 	  struct in_addr * pmask,
67 	  int *pwidth)
68 {
69   int bits;
70   char *cp, *wp;
71 
72   if (argc < 1) {
73     LogPrintf(LogWARN, "ParseAddr: address/mask is expected.\n");
74     return (0);
75   }
76   pmask->s_addr = 0xffffffff;	/* Assume 255.255.255.255 as default */
77   cp = strchr(*argv, '/');
78   if (cp)
79     *cp++ = '\0';
80   if (strcasecmp(*argv, "HISADDR") == 0)
81     *paddr = IpcpInfo.his_ipaddr;
82   else if (strcasecmp(*argv, "MYADDR") == 0)
83     *paddr = IpcpInfo.want_ipaddr;
84   else if (inet_aton(*argv, paddr) == 0) {
85     LogPrintf(LogWARN, "ParseAddr: %s: Bad address\n", *argv);
86     return (0);
87   }
88   if (cp && *cp) {
89     bits = strtol(cp, &wp, 0);
90     if (cp == wp || bits < 0 || bits > 32) {
91       LogPrintf(LogWARN, "ParseAddr: bad mask width.\n");
92       return (0);
93     }
94   } else {
95     /* if width is not given, assume whole 32 bits are meaningfull */
96     bits = 32;
97   }
98 
99   *pwidth = bits;
100   pmask->s_addr = htonl(netmasks[bits]);
101 
102   return (1);
103 }
104 
105 static int
106 ParseProto(int argc, char **argv)
107 {
108   int proto;
109 
110   if (argc < 1)
111     return (P_NONE);
112 
113   if (!strcmp(*argv, "tcp"))
114     proto = P_TCP;
115   else if (!strcmp(*argv, "udp"))
116     proto = P_UDP;
117   else if (!strcmp(*argv, "icmp"))
118     proto = P_ICMP;
119   else
120     proto = P_NONE;
121   return (proto);
122 }
123 
124 static int
125 ParsePort(char *service, int proto)
126 {
127   char *protocol_name, *cp;
128   struct servent *servent;
129   int port;
130 
131   switch (proto) {
132   case P_UDP:
133     protocol_name = "udp";
134     break;
135   case P_TCP:
136     protocol_name = "tcp";
137     break;
138   default:
139     protocol_name = 0;
140   }
141 
142   servent = getservbyname(service, protocol_name);
143   if (servent != 0)
144     return (ntohs(servent->s_port));
145 
146   port = strtol(service, &cp, 0);
147   if (cp == service) {
148     LogPrintf(LogWARN, "ParsePort: %s is not a port name or number.\n",
149 	      service);
150     return (0);
151   }
152   return (port);
153 }
154 
155 /*
156  *	ICMP Syntax:	src eq icmp_message_type
157  */
158 static int
159 ParseIcmp(int argc, char **argv)
160 {
161   int type;
162   char *cp;
163 
164   switch (argc) {
165   case 0:
166     /* permit/deny all ICMP types */
167     filterdata.opt.srcop = OP_NONE;
168     break;
169   default:
170     LogPrintf(LogWARN, "ParseIcmp: bad icmp syntax.\n");
171     return (0);
172   case 3:
173     if (!strcmp(*argv, "src") && !strcmp(argv[1], "eq")) {
174       type = strtol(argv[2], &cp, 0);
175       if (cp == argv[2]) {
176 	LogPrintf(LogWARN, "ParseIcmp: type is expected.\n");
177 	return (0);
178       }
179       filterdata.opt.srcop = OP_EQ;
180       filterdata.opt.srcport = type;
181     }
182     break;
183   }
184   return (1);
185 }
186 
187 static int
188 ParseOp(char *cp)
189 {
190   int op = OP_NONE;
191 
192   if (!strcmp(cp, "eq"))
193     op = OP_EQ;
194   else if (!strcmp(cp, "gt"))
195     op = OP_GT;
196   else if (!strcmp(cp, "lt"))
197     op = OP_LT;
198   return (op);
199 }
200 
201 /*
202  *	UDP Syntax: [src op port] [dst op port]
203  */
204 static int
205 ParseUdpOrTcp(int argc, char **argv, int proto)
206 {
207   filterdata.opt.srcop = filterdata.opt.dstop = OP_NONE;
208   filterdata.opt.estab = 0;
209 
210   if (argc == 0) {
211     /* permit/deny all tcp traffic */
212     return (1);
213   }
214 
215   if (argc >= 3 && !strcmp(*argv, "src")) {
216     filterdata.opt.srcop = ParseOp(argv[1]);
217     if (filterdata.opt.srcop == OP_NONE) {
218       LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
219       return (0);
220     }
221     filterdata.opt.srcport = ParsePort(argv[2], proto);
222     if (filterdata.opt.srcport == 0)
223       return (0);
224     argc -= 3;
225     argv += 3;
226     if (argc == 0)
227       return (1);
228   }
229   if (argc >= 3 && !strcmp(argv[0], "dst")) {
230     filterdata.opt.dstop = ParseOp(argv[1]);
231     if (filterdata.opt.dstop == OP_NONE) {
232       LogPrintf(LogWARN, "ParseUdpOrTcp: bad operation\n");
233       return (0);
234     }
235     filterdata.opt.dstport = ParsePort(argv[2], proto);
236     if (filterdata.opt.dstport == 0)
237       return (0);
238     argc -= 3;
239     argv += 3;
240     if (argc == 0)
241       return (1);
242   }
243   if (argc == 1 && proto == P_TCP) {
244     if (!strcmp(*argv, "estab")) {
245       filterdata.opt.estab = 1;
246       return (1);
247     }
248     LogPrintf(LogWARN, "ParseUdpOrTcp: estab is expected: %s\n", *argv);
249     return (0);
250   }
251   if (argc > 0)
252     LogPrintf(LogWARN, "ParseUdpOrTcp: bad src/dst port syntax: %s\n", *argv);
253   return (0);
254 }
255 
256 char *opname[] = {"none", "eq", "gt", NULL, "lt"};
257 
258 static int
259 Parse(int argc, char **argv, struct filterent * ofp)
260 {
261   int action, proto;
262   int val;
263   char *wp;
264   struct filterent *fp = &filterdata;
265 
266   val = strtol(*argv, &wp, 0);
267   if (*argv == wp || val > MAXFILTERS) {
268     LogPrintf(LogWARN, "Parse: invalid filter number.\n");
269     return (0);
270   }
271   if (val < 0) {
272     for (val = 0; val < MAXFILTERS; val++) {
273       ofp->action = A_NONE;
274       ofp++;
275     }
276     LogPrintf(LogWARN, "Parse: filter cleared.\n");
277     return (1);
278   }
279   ofp += val;
280 
281   if (--argc == 0) {
282     LogPrintf(LogWARN, "Parse: missing action.\n");
283     return (0);
284   }
285   argv++;
286 
287   proto = P_NONE;
288   memset(&filterdata, '\0', sizeof(filterdata));
289 
290   if (!strcmp(*argv, "permit")) {
291     action = A_PERMIT;
292   } else if (!strcmp(*argv, "deny")) {
293     action = A_DENY;
294   } else if (!strcmp(*argv, "clear")) {
295     ofp->action = A_NONE;
296     return (1);
297   } else {
298     LogPrintf(LogWARN, "Parse: bad action: %s\n", *argv);
299     return (0);
300   }
301   fp->action = action;
302 
303   argc--;
304   argv++;
305 
306   if (fp->action == A_DENY) {
307     if (!strcmp(*argv, "host")) {
308       fp->action |= A_UHOST;
309       argc--;
310       argv++;
311     } else if (!strcmp(*argv, "port")) {
312       fp->action |= A_UPORT;
313       argc--;
314       argv++;
315     }
316   }
317   proto = ParseProto(argc, argv);
318   if (proto == P_NONE) {
319     if (ParseAddr(argc, argv, &fp->saddr, &fp->smask, &fp->swidth)) {
320       argc--;
321       argv++;
322       proto = ParseProto(argc, argv);
323       if (proto == P_NONE) {
324 	if (ParseAddr(argc, argv, &fp->daddr, &fp->dmask, &fp->dwidth)) {
325 	  argc--;
326 	  argv++;
327 	}
328 	proto = ParseProto(argc, argv);
329 	if (proto != P_NONE) {
330 	  argc--;
331 	  argv++;
332 	}
333       } else {
334 	argc--;
335 	argv++;
336       }
337     } else {
338       LogPrintf(LogWARN, "Parse: Address/protocol expected.\n");
339       return (0);
340     }
341   } else {
342     argc--;
343     argv++;
344   }
345 
346   val = 1;
347   fp->proto = proto;
348 
349   switch (proto) {
350   case P_TCP:
351     val = ParseUdpOrTcp(argc, argv, P_TCP);
352     break;
353   case P_UDP:
354     val = ParseUdpOrTcp(argc, argv, P_UDP);
355     break;
356   case P_ICMP:
357     val = ParseIcmp(argc, argv);
358     break;
359   }
360 
361   LogPrintf(LogDEBUG, "Parse: Src: %s\n", inet_ntoa(fp->saddr));
362   LogPrintf(LogDEBUG, "Parse: Src mask: %s\n", inet_ntoa(fp->smask));
363   LogPrintf(LogDEBUG, "Parse: Dst: %s\n", inet_ntoa(fp->daddr));
364   LogPrintf(LogDEBUG, "Parse: Dst mask: %s\n", inet_ntoa(fp->dmask));
365   LogPrintf(LogDEBUG, "Parse: Proto = %d\n", proto);
366 
367   LogPrintf(LogDEBUG, "Parse: src:  %s (%d)\n", opname[fp->opt.srcop],
368 	    fp->opt.srcport);
369   LogPrintf(LogDEBUG, "Parse: dst:  %s (%d)\n", opname[fp->opt.dstop],
370 	    fp->opt.dstport);
371   LogPrintf(LogDEBUG, "Parse: estab: %d\n", fp->opt.estab);
372 
373   if (val)
374     *ofp = *fp;
375   return (val);
376 }
377 
378 int
379 SetIfilter(struct cmdtab *list, int argc, char **argv)
380 {
381   if (argc > 0) {
382     (void) Parse(argc, argv, ifilters);
383     return 0;
384   }
385   return -1;
386 }
387 
388 int
389 SetOfilter(struct cmdtab *list, int argc, char **argv)
390 {
391   if (argc > 0) {
392     (void) Parse(argc, argv, ofilters);
393     return 0;
394   }
395   return -1;
396 }
397 
398 int
399 SetDfilter(struct cmdtab *list, int argc, char **argv)
400 {
401   if (argc > 0) {
402     (void) Parse(argc, argv, dfilters);
403     return 0;
404   }
405   return -1;
406 }
407 
408 int
409 SetAfilter(struct cmdtab *list, int argc, char **argv)
410 {
411   if (argc > 0) {
412     (void) Parse(argc, argv, afilters);
413     return 0;
414   }
415   return -1;
416 }
417 
418 static char *protoname[] = {
419   "none", "tcp", "udp", "icmp",
420 };
421 
422 static char *actname[] = {
423   "none   ", "permit ", "deny   ",
424 };
425 
426 static void
427 ShowFilter(struct filterent * fp)
428 {
429   int n;
430 
431   if (!VarTerm)
432     return;
433 
434   for (n = 0; n < MAXFILTERS; n++, fp++) {
435     if (fp->action != A_NONE) {
436       fprintf(VarTerm, "%2d %s", n, actname[fp->action]);
437       fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->saddr), fp->swidth);
438       fprintf(VarTerm, "%s/%d ", inet_ntoa(fp->daddr), fp->dwidth);
439       if (fp->proto) {
440 	fprintf(VarTerm, "%s", protoname[fp->proto]);
441 
442 	if (fp->opt.srcop)
443 	  fprintf(VarTerm, " src %s %d", opname[fp->opt.srcop],
444 		  fp->opt.srcport);
445 	if (fp->opt.dstop)
446 	  fprintf(VarTerm, " dst %s %d", opname[fp->opt.dstop],
447 		  fp->opt.dstport);
448 	if (fp->opt.estab)
449 	  fprintf(VarTerm, " estab");
450 
451       }
452       fprintf(VarTerm, "\n");
453     }
454   }
455 }
456 
457 int
458 ShowIfilter(struct cmdtab * list, int argc, char **argv)
459 {
460   ShowFilter(ifilters);
461   return 0;
462 }
463 
464 int
465 ShowOfilter(struct cmdtab * list, int argc, char **argv)
466 {
467   ShowFilter(ofilters);
468   return 0;
469 }
470 
471 int
472 ShowDfilter(struct cmdtab * list, int argc, char **argv)
473 {
474   ShowFilter(dfilters);
475   return 0;
476 }
477 
478 int
479 ShowAfilter(struct cmdtab * list, int argc, char **argv)
480 {
481   ShowFilter(afilters);
482   return 0;
483 }
484