Merge commit 'crater/master'
[dragonfly.git] / contrib / ipfilter / common.c
blobfa21fc97b5746d2e6c63c70504ef672bee301dc8
1 /*
2 * Copyright (C) 1993-2001 by Darren Reed.
4 * See the IPFILTER.LICENCE file for details on licencing.
5 */
6 #if defined(__sgi) && (IRIX > 602)
7 # include <sys/ptimers.h>
8 #endif
9 #include <sys/types.h>
10 #if !defined(__SVR4) && !defined(__svr4__)
11 #include <strings.h>
12 #else
13 #include <sys/byteorder.h>
14 #endif
15 #include <sys/param.h>
16 #include <sys/time.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <netinet/in_systm.h>
20 #include <netinet/ip.h>
21 #include <netinet/tcp.h>
22 #include <net/if.h>
23 #if __FreeBSD_version >= 300000
24 # include <net/if_var.h>
25 #endif
26 #include <stdio.h>
27 #include <string.h>
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <stddef.h>
32 #include <netdb.h>
33 #include <arpa/nameser.h>
34 #include <arpa/inet.h>
35 #include <resolv.h>
36 #include <ctype.h>
37 #include <syslog.h>
38 #include "ip_compat.h"
39 #include "ip_fil.h"
40 #include "ipf.h"
41 #include "facpri.h"
43 #if !defined(lint)
44 static const char sccsid[] = "@(#)parse.c 1.44 6/5/96 (C) 1993-2000 Darren Reed";
45 static const char rcsid[] = "@(#)$IPFilter: parse.c,v 2.8 1999/12/28 10:49:46 darrenr Exp $";
46 #endif
48 extern struct ipopt_names ionames[], secclass[];
49 extern int opts;
50 extern int use_inet6;
53 char *proto = NULL;
54 char flagset[] = "FSRPAUEC";
55 u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG,
56 TH_ECN, TH_CWR };
58 void fill6bits __P((int, u_32_t *));
59 int count6bits __P((u_32_t *));
61 static char thishost[MAXHOSTNAMELEN];
64 void initparse()
66 gethostname(thishost, sizeof(thishost));
67 thishost[sizeof(thishost) - 1] = '\0';
71 int genmask(msk, mskp)
72 char *msk;
73 u_32_t *mskp;
75 char *endptr = NULL;
76 #ifdef USE_INET6
77 u_32_t addr;
78 #endif
79 int bits;
81 if (index(msk, '.') || index(msk, 'x') || index(msk, ':')) {
82 /* possibly of the form xxx.xxx.xxx.xxx
83 * or 0xYYYYYYYY */
84 #ifdef USE_INET6
85 if (use_inet6) {
86 if (inet_pton(AF_INET6, msk, &addr) != 1)
87 return -1;
88 } else
89 #endif
90 if (inet_aton(msk, (struct in_addr *)mskp) == 0)
91 return -1;
92 } else {
94 * set x most significant bits
96 bits = (int)strtol(msk, &endptr, 0);
97 if ((*endptr != '\0') ||
98 ((bits > 32) && !use_inet6) || (bits < 0) ||
99 ((bits > 128) && use_inet6))
100 return -1;
101 if (use_inet6)
102 fill6bits(bits, mskp);
103 else {
104 if (bits == 0)
105 *mskp = 0;
106 else
107 *mskp = htonl(0xffffffff << (32 - bits));
110 return 0;
115 void fill6bits(bits, msk)
116 int bits;
117 u_32_t *msk;
119 int i;
121 for (i = 0; bits >= 32 && i < 4 ; ++i, bits -= 32)
122 msk[i] = 0xffffffff;
124 if (bits > 0 && i < 4)
125 msk[i++] = htonl(0xffffffff << (32 - bits));
127 while (i < 4)
128 msk[i++] = 0;
133 * returns -1 if neither "hostmask/num" or "hostmask mask addr" are
134 * found in the line segments, there is an error processing this information,
135 * or there is an error processing ports information.
137 int hostmask(seg, sa, msk, pp, cp, tp, linenum)
138 char ***seg;
139 u_32_t *sa, *msk;
140 u_short *pp, *tp;
141 int *cp;
142 int linenum;
144 struct in_addr maskaddr;
145 char *s;
148 * is it possibly hostname/num ?
150 if ((s = index(**seg, '/')) ||
151 ((s = index(**seg, ':')) && !index(s + 1, ':'))) {
152 *s++ = '\0';
153 if (genmask(s, msk) == -1) {
154 fprintf(stderr, "%d: bad mask (%s)\n", linenum, s);
155 return -1;
157 if (hostnum(sa, **seg, linenum) == -1) {
158 fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
159 return -1;
161 *sa &= *msk;
162 (*seg)++;
163 return ports(seg, pp, cp, tp, linenum);
167 * look for extra segments if "mask" found in right spot
169 if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) {
170 if (hostnum(sa, **seg, linenum) == -1) {
171 fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
172 return -1;
174 (*seg)++;
175 (*seg)++;
176 if (inet_aton(**seg, &maskaddr) == 0) {
177 fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg);
178 return -1;
180 *msk = maskaddr.s_addr;
181 (*seg)++;
182 *sa &= *msk;
183 return ports(seg, pp, cp, tp, linenum);
186 if (**seg) {
187 if (hostnum(sa, **seg, linenum) == -1) {
188 fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
189 return -1;
191 (*seg)++;
192 if (use_inet6) {
193 u_32_t k = 0;
194 if (sa[0] || sa[1] || sa[2] || sa[3])
195 k = 0xffffffff;
196 msk[0] = msk[1] = msk[2] = msk[3] = k;
198 else
199 *msk = *sa ? 0xffffffff : 0;
200 return ports(seg, pp, cp, tp, linenum);
202 fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
203 return -1;
207 * returns an ip address as a long var as a result of either a DNS lookup or
208 * straight inet_addr() call
210 int hostnum(ipa, host, linenum)
211 u_32_t *ipa;
212 char *host;
213 int linenum;
215 struct hostent *hp;
216 struct netent *np;
217 struct in_addr ip;
219 if (!strcasecmp("any", host))
220 return 0;
221 #ifdef USE_INET6
222 if (use_inet6) {
223 if (inet_pton(AF_INET6, host, ipa) == 1)
224 return 0;
225 else
226 return -1;
228 #endif
229 if (isdigit(*host) && inet_aton(host, &ip)) {
230 *ipa = ip.s_addr;
231 return 0;
234 if (!strcasecmp("<thishost>", host))
235 host = thishost;
237 if (!(hp = gethostbyname(host))) {
238 if (!(np = getnetbyname(host))) {
239 fprintf(stderr, "%d: can't resolve hostname: %s\n",
240 linenum, host);
241 return -1;
243 *ipa = htonl(np->n_net);
244 return 0;
246 *ipa = *(u_32_t *)hp->h_addr;
247 return 0;
252 * check for possible presence of the port fields in the line
254 int ports(seg, pp, cp, tp, linenum)
255 char ***seg;
256 u_short *pp, *tp;
257 int *cp;
258 int linenum;
260 int comp = -1;
262 if (!*seg || !**seg || !***seg)
263 return 0;
264 if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) {
265 (*seg)++;
266 if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq"))
267 comp = FR_EQUAL;
268 else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne"))
269 comp = FR_NEQUAL;
270 else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt"))
271 comp = FR_LESST;
272 else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt"))
273 comp = FR_GREATERT;
274 else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le"))
275 comp = FR_LESSTE;
276 else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge"))
277 comp = FR_GREATERTE;
278 else if (isalnum(***seg) && *(*seg + 2)) {
279 if (portnum(**seg, pp, linenum) == 0)
280 return -1;
281 (*seg)++;
282 if (!strcmp(**seg, "<>"))
283 comp = FR_OUTRANGE;
284 else if (!strcmp(**seg, "><"))
285 comp = FR_INRANGE;
286 else {
287 fprintf(stderr,
288 "%d: unknown range operator (%s)\n",
289 linenum, **seg);
290 return -1;
292 (*seg)++;
293 if (**seg == NULL) {
294 fprintf(stderr, "%d: missing 2nd port value\n",
295 linenum);
296 return -1;
298 if (portnum(**seg, tp, linenum) == 0)
299 return -1;
300 } else {
301 fprintf(stderr, "%d: unknown comparator (%s)\n",
302 linenum, **seg);
303 return -1;
305 if (comp != FR_OUTRANGE && comp != FR_INRANGE) {
306 (*seg)++;
307 if (portnum(**seg, pp, linenum) == 0)
308 return -1;
310 *cp = comp;
311 (*seg)++;
313 return 0;
318 * find the port number given by the name, either from getservbyname() or
319 * straight atoi(). Return 1 on success, 0 on failure
321 int portnum(name, port, linenum)
322 char *name;
323 u_short *port;
324 int linenum;
326 struct servent *sp, *sp2;
327 u_short p1 = 0;
328 int i;
330 if (isdigit(*name)) {
331 if (ratoi(name, &i, 0, USHRT_MAX)) {
332 *port = (u_short)i;
333 return 1;
335 fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name);
336 return 0;
338 if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) {
339 sp = getservbyname(name, proto);
340 if (sp) {
341 *port = ntohs(sp->s_port);
342 return 1;
344 fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name);
345 return 0;
347 sp = getservbyname(name, "tcp");
348 if (sp)
349 p1 = sp->s_port;
350 sp2 = getservbyname(name, "udp");
351 if (!sp || !sp2) {
352 fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n",
353 linenum, name);
354 return 0;
356 if (p1 != sp2->s_port) {
357 fprintf(stderr, "%d: %s %d/tcp is a different port to ",
358 linenum, name, p1);
359 fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port);
360 return 0;
362 *port = ntohs(p1);
363 return 1;
367 u_char tcp_flags(flgs, mask, linenum)
368 char *flgs;
369 u_char *mask;
370 int linenum;
372 u_char tcpf = 0, tcpfm = 0, *fp = &tcpf;
373 char *s, *t;
375 if (*flgs == '0') {
376 s = strchr(flgs, '/');
377 if (s)
378 *s++ = '\0';
379 tcpf = strtol(flgs, NULL, 0);
380 fp = &tcpfm;
381 } else
382 s = flgs;
384 for (; *s; s++) {
385 if (*s == '/' && fp == &tcpf) {
386 fp = &tcpfm;
387 if (*(s + 1) == '0')
388 break;
389 continue;
391 if (!(t = index(flagset, *s))) {
392 fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s);
393 return 0;
395 *fp |= flags[t - flagset];
398 if (s && *s == '0')
399 tcpfm = strtol(s, NULL, 0);
401 if (!tcpfm) {
402 if (tcpf == TH_SYN)
403 tcpfm = 0xff & ~(TH_ECN|TH_CWR);
404 else
405 tcpfm = 0xff & ~(TH_ECN);
407 *mask = tcpfm;
408 return tcpf;
413 * count consecutive 1's in bit mask. If the mask generated by counting
414 * consecutive 1's is different to that passed, return -1, else return #
415 * of bits.
417 int countbits(ip)
418 u_32_t ip;
420 u_32_t ipn;
421 int cnt = 0, i, j;
423 ip = ipn = ntohl(ip);
424 for (i = 32; i; i--, ipn *= 2)
425 if (ipn & 0x80000000)
426 cnt++;
427 else
428 break;
429 ipn = 0;
430 for (i = 32, j = cnt; i; i--, j--) {
431 ipn *= 2;
432 if (j > 0)
433 ipn++;
435 if (ipn == ip)
436 return cnt;
437 return -1;
441 int count6bits(msk)
442 u_32_t *msk;
444 int i = 0, k;
445 u_32_t j;
447 for (k = 3; k >= 0; k--)
448 if (msk[k] == 0xffffffff)
449 i += 32;
450 else {
451 for (j = msk[k]; j; j <<= 1)
452 if (j & 0x80000000)
453 i++;
455 return i;
459 char *portname(pr, port)
460 int pr, port;
462 static char buf[32];
463 struct protoent *p = NULL;
464 struct servent *sv = NULL, *sv1 = NULL;
466 if (pr == -1) {
467 if ((sv = getservbyport(htons(port), "tcp"))) {
468 strncpy(buf, sv->s_name, sizeof(buf)-1);
469 buf[sizeof(buf)-1] = '\0';
470 sv1 = getservbyport(htons(port), "udp");
471 sv = strncasecmp(buf, sv->s_name, strlen(buf)) ?
472 NULL : sv1;
474 if (sv)
475 return buf;
476 } else if (pr && (p = getprotobynumber(pr))) {
477 if ((sv = getservbyport(htons(port), p->p_name))) {
478 strncpy(buf, sv->s_name, sizeof(buf)-1);
479 buf[sizeof(buf)-1] = '\0';
480 return buf;
484 (void) sprintf(buf, "%d", port);
485 return buf;
489 int ratoi(ps, pi, min, max)
490 char *ps;
491 int *pi, min, max;
493 int i;
494 char *pe;
496 i = (int)strtol(ps, &pe, 0);
497 if (*pe != '\0' || i < min || i > max)
498 return 0;
499 *pi = i;
500 return 1;
504 int ratoui(ps, pi, min, max)
505 char *ps;
506 u_int *pi, min, max;
508 u_int i;
509 char *pe;
511 i = (u_int)strtol(ps, &pe, 0);
512 if (*pe != '\0' || i < min || i > max)
513 return 0;
514 *pi = i;
515 return 1;
519 void printhostmask(v, addr, mask)
520 int v;
521 u_32_t *addr, *mask;
523 struct in_addr ipa;
524 int ones;
526 #ifdef USE_INET6
527 if (v == 6) {
528 ones = count6bits(mask);
529 if (ones == 0 && !addr[0] && !addr[1] && !addr[2] && !addr[3])
530 printf("any");
531 else {
532 char ipbuf[64];
533 printf("%s/%d",
534 inet_ntop(AF_INET6, addr, ipbuf, sizeof(ipbuf)),
535 ones);
538 else
539 #endif
540 if (!*addr && !*mask)
541 printf("any");
542 else {
543 ipa.s_addr = *addr;
544 printf("%s", inet_ntoa(ipa));
545 if ((ones = countbits(*mask)) == -1) {
546 ipa.s_addr = *mask;
547 printf("/%s", inet_ntoa(ipa));
548 } else
549 printf("/%d", ones);
554 void printportcmp(pr, frp)
555 int pr;
556 frpcmp_t *frp;
558 static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=",
559 "<>", "><"};
561 if (frp->frp_cmp == FR_INRANGE || frp->frp_cmp == FR_OUTRANGE)
562 printf(" port %d %s %d", frp->frp_port,
563 pcmp1[frp->frp_cmp], frp->frp_top);
564 else
565 printf(" port %s %s", pcmp1[frp->frp_cmp],
566 portname(pr, frp->frp_port));
570 void printbuf(buf, len, zend)
571 char *buf;
572 int len, zend;
574 char *s, c;
575 int i;
577 for (s = buf, i = len; i; i--) {
578 c = *s++;
579 if (isprint(c))
580 putchar(c);
581 else
582 printf("\\%03o", c);
583 if ((c == '\0') && zend)
584 break;
590 char *hostname(v, ip)
591 int v;
592 void *ip;
594 #ifdef USE_INET6
595 static char hostbuf[MAXHOSTNAMELEN+1];
596 #endif
597 struct in_addr ipa;
599 if (v == 4) {
600 ipa.s_addr = *(u_32_t *)ip;
601 return inet_ntoa(ipa);
603 #ifdef USE_INET6
604 (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1);
605 hostbuf[MAXHOSTNAMELEN] = '\0';
606 return hostbuf;
607 #else
608 return "IPv6";
609 #endif