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