2 * Copyright (C) 1993-1998 by Darren Reed.
4 * Redistribution and use in source and binary forms are permitted
5 * provided that this notice is preserved and due credit is given
6 * to the original author and the contributors.
9 #if !defined(__SVR4) && !defined(__svr4__)
12 #include <sys/byteorder.h>
14 #include <sys/param.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <netinet/in_systm.h>
19 #include <netinet/ip.h>
20 #include <netinet/tcp.h>
22 #if __FreeBSD_version >= 300000
23 # include <net/if_var.h>
32 #include <arpa/nameser.h>
33 #include <arpa/inet.h>
37 #include "ip_compat.h"
43 static const char sccsid[] = "@(#)parse.c 1.44 6/5/96 (C) 1993-1996 Darren Reed";
44 static const char rcsid[] = "@(#)$Id: parse.c,v 2.1.2.8 2000/01/27 08:49:42 darrenr Exp $";
47 extern struct ipopt_names ionames[], secclass[];
50 int portnum __P((char *, u_short *, int));
51 u_char tcp_flags __P((char *, u_char *, int));
52 int addicmp __P((char ***, struct frentry *, int));
53 int extras __P((char ***, struct frentry *, int));
59 int hostmask __P((char ***, u_32_t *, u_32_t *, u_short *, u_char *,
61 int ports __P((char ***, u_short *, u_char *, u_short *, int));
62 int icmpcode __P((char *)), addkeep __P((char ***, struct frentry *, int));
63 int to_interface __P((frdest_t *, char *, int));
64 void print_toif __P((char *, frdest_t *));
65 void optprint __P((u_short *, u_long, u_long));
66 int countbits __P((u_32_t));
67 char *portname __P((int, int));
68 int ratoi __P((char *, int *, int, int));
72 char flagset[] = "FSRPAU";
73 u_char flags[] = { TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG };
75 static char thishost[MAXHOSTNAMELEN];
80 gethostname(thishost, sizeof(thishost));
81 thishost[sizeof(thishost) - 1] = '\0';
87 * parse a line read from the input filter rule file
89 struct frentry *parse(line, linenum)
93 static struct frentry fil;
94 struct protoent *p = NULL;
95 char *cps[31], **cpp, *endptr;
99 while (*line && isspace(*line))
104 bzero((char *)&fil, sizeof(fil));
105 fil.fr_mip.fi_v = 0xf;
107 fil.fr_loglevel = 0xffff;
110 * break line up into max of 20 segments
112 if (opts & OPT_DEBUG)
113 fprintf(stderr, "parse [%s]\n", line);
114 for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++)
115 cps[++i] = strtok(NULL, " \b\t\r\n");
119 fprintf(stderr, "%d: not enough segments in line\n", linenum);
125 fil.fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1;
128 if (!strcasecmp("block", *cpp)) {
129 fil.fr_flags |= FR_BLOCK;
130 if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) &&
132 fil.fr_flags |= FR_FAKEICMP;
133 else if (!strncasecmp(*(cpp+1), "return-icmp", 11) && (i = 11))
134 fil.fr_flags |= FR_RETICMP;
135 if (fil.fr_flags & FR_RETICMP) {
137 if (strlen(*cpp) == i) {
138 if (*(cpp + 1) && **(cpp +1) == '(') {
146 * The ICMP code is not required to follow in ()'s
148 if ((i >= 0) && (*(*cpp + i) == '(')) {
150 j = icmpcode(*cpp + i);
153 "%d: unrecognised icmp code %s\n",
159 } else if (!strncasecmp(*(cpp+1), "return-rst", 10)) {
160 fil.fr_flags |= FR_RETRST;
163 } else if (!strcasecmp("count", *cpp)) {
164 fil.fr_flags |= FR_ACCOUNT;
165 } else if (!strcasecmp("pass", *cpp)) {
166 fil.fr_flags |= FR_PASS;
167 } else if (!strcasecmp("auth", *cpp)) {
168 fil.fr_flags |= FR_AUTH;
169 } else if (!strcasecmp("preauth", *cpp)) {
170 fil.fr_flags |= FR_PREAUTH;
171 } else if (!strcasecmp("skip", *cpp)) {
173 if (ratoi(*cpp, &i, 0, USHRT_MAX))
176 fprintf(stderr, "%d: integer must follow skip\n",
180 } else if (!strcasecmp("log", *cpp)) {
181 fil.fr_flags |= FR_LOG;
182 if (!strcasecmp(*(cpp+1), "body")) {
183 fil.fr_flags |= FR_LOGBODY;
186 if (!strcasecmp(*(cpp+1), "first")) {
187 fil.fr_flags |= FR_LOGFIRST;
189 if (!strcasecmp(*(cpp+1), "level")) {
196 fprintf(stderr, "%d: %s\n", linenum,
197 "missing identifier after level");
200 s = index(*cpp, '.');
203 fac = fac_findname(*cpp);
205 fprintf(stderr, "%d: %s %s\n", linenum,
206 "Unknown facility", *cpp);
209 pri = pri_findname(s);
211 fprintf(stderr, "%d: %s %s\n", linenum,
212 "Unknown priority", s);
216 pri = pri_findname(*cpp);
218 fprintf(stderr, "%d: %s %s\n", linenum,
219 "Unknown priority", *cpp);
223 fil.fr_loglevel = fac|pri;
228 * Doesn't start with one of the action words
230 fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp);
234 fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum);
238 if (!strcasecmp("in", *cpp))
239 fil.fr_flags |= FR_INQUE;
240 else if (!strcasecmp("out", *cpp)) {
241 fil.fr_flags |= FR_OUTQUE;
242 if (fil.fr_flags & FR_RETICMP) {
244 "%d: Can only use return-icmp with 'in'\n",
247 } else if (fil.fr_flags & FR_RETRST) {
249 "%d: Can only use return-rst with 'in'\n",
255 fprintf(stderr, "%d: missing source specification\n", linenum);
259 if (!strcasecmp("log", *cpp)) {
261 fprintf(stderr, "%d: missing source specification\n",
265 if (fil.fr_flags & FR_PASS)
266 fil.fr_flags |= FR_LOGP;
267 else if (fil.fr_flags & FR_BLOCK)
268 fil.fr_flags |= FR_LOGB;
269 if (*cpp && !strcasecmp(*cpp, "body")) {
270 fil.fr_flags |= FR_LOGBODY;
273 if (*cpp && !strcasecmp(*cpp, "first")) {
274 fil.fr_flags |= FR_LOGFIRST;
277 if (*cpp && !strcasecmp(*cpp, "or-block")) {
278 if (!(fil.fr_flags & FR_PASS)) {
280 "%d: or-block must be used with pass\n",
284 fil.fr_flags |= FR_LOGORBLOCK;
287 if (*cpp && !strcasecmp(*cpp, "level")) {
294 fprintf(stderr, "%d: %s\n", linenum,
295 "missing identifier after level");
298 s = index(*cpp, '.');
301 fac = fac_findname(*cpp);
303 fprintf(stderr, "%d: %s %s\n", linenum,
304 "Unknown facility", *cpp);
307 pri = pri_findname(s);
309 fprintf(stderr, "%d: %s %s\n", linenum,
310 "Unknown priority", s);
314 pri = pri_findname(*cpp);
316 fprintf(stderr, "%d: %s %s\n", linenum,
317 "Unknown priority", *cpp);
321 fil.fr_loglevel = fac|pri;
326 if (*cpp && !strcasecmp("quick", *cpp)) {
328 fil.fr_flags |= FR_QUICK;
331 *fil.fr_ifname = '\0';
332 if (*cpp && !strcasecmp(*cpp, "on")) {
334 fprintf(stderr, "%d: interface name missing\n",
338 (void)strncpy(fil.fr_ifname, *cpp, IFNAMSIZ-1);
339 fil.fr_ifname[IFNAMSIZ-1] = '\0';
342 if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) {
344 "%d: %s can only be used with TCP\n",
345 linenum, "return-rst");
352 if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) {
354 if (to_interface(&fil.fr_dif, *cpp, linenum))
358 if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) {
360 if (to_interface(&fil.fr_tif, *cpp, linenum))
363 } else if (*cpp && !strcasecmp(*cpp, "fastroute")) {
364 if (!(fil.fr_flags & FR_INQUE)) {
366 "can only use %s with 'in'\n",
370 fil.fr_flags |= FR_FASTROUTE;
375 if (*cpp && !strcasecmp(*cpp, "tos")) {
377 fprintf(stderr, "%d: tos missing value\n", linenum);
380 fil.fr_tos = strtol(*cpp, NULL, 0);
381 fil.fr_mip.fi_tos = 0xff;
385 if (*cpp && !strcasecmp(*cpp, "ttl")) {
387 fprintf(stderr, "%d: ttl missing hopcount value\n",
391 if (ratoi(*cpp, &i, 0, 255))
394 fprintf(stderr, "%d: invalid ttl (%s)\n",
398 fil.fr_mip.fi_ttl = 0xff;
403 * check for "proto <protoname>" only decode udp/tcp/icmp as protoname
406 if (*cpp && !strcasecmp(*cpp, "proto")) {
408 fprintf(stderr, "%d: protocol name missing\n", linenum);
412 if (!strcasecmp(proto, "tcp/udp")) {
413 fil.fr_ip.fi_fl |= FI_TCPUDP;
414 fil.fr_mip.fi_fl |= FI_TCPUDP;
416 if (!(p = getprotobyname(proto)) && !isdigit(*proto)) {
418 "%d: unknown protocol (%s)\n",
423 fil.fr_proto = p->p_proto;
424 else if (isdigit(*proto)) {
425 i = (int)strtol(proto, &endptr, 0);
426 if (*endptr != '\0' || i < 0 || i > 255) {
428 "%d: unknown protocol (%s)\n",
434 fil.fr_mip.fi_p = 0xff;
437 if ((fil.fr_proto != IPPROTO_TCP) &&
438 ((fil.fr_flags & FR_RETMASK) == FR_RETRST)) {
439 fprintf(stderr, "%d: %s can only be used with TCP\n",
440 linenum, "return-rst");
445 * get the from host and bit mask to use against packets
449 fprintf(stderr, "%d: missing source specification\n", linenum);
452 if (!strcasecmp(*cpp, "all")) {
457 if (strcasecmp(*cpp, "from")) {
458 fprintf(stderr, "%d: unexpected keyword (%s) - from\n",
463 fprintf(stderr, "%d: missing host after from\n",
469 fil.fr_flags |= FR_NOTSRCIP;
472 if (hostmask(&cpp, (u_32_t *)&fil.fr_src,
473 (u_32_t *)&fil.fr_smsk, &fil.fr_sport, &ch,
474 &fil.fr_stop, linenum)) {
479 fprintf(stderr, "%d: missing to fields\n", linenum);
484 * do the same for the to field (destination host)
486 if (strcasecmp(*cpp, "to")) {
487 fprintf(stderr, "%d: unexpected keyword (%s) - to\n",
492 fprintf(stderr, "%d: missing host after to\n", linenum);
497 fil.fr_flags |= FR_NOTDSTIP;
500 if (hostmask(&cpp, (u_32_t *)&fil.fr_dst,
501 (u_32_t *)&fil.fr_dmsk, &fil.fr_dport, &ch,
502 &fil.fr_dtop, linenum)) {
509 * check some sanity, make sure we don't have icmp checks with tcp
510 * or udp or visa versa.
512 if (fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp) &&
513 fil.fr_proto != IPPROTO_TCP && fil.fr_proto != IPPROTO_UDP) {
514 fprintf(stderr, "%d: port operation on non tcp/udp\n", linenum);
517 if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) {
518 fprintf(stderr, "%d: icmp comparisons on wrong protocol\n",
526 if (*cpp && !strcasecmp(*cpp, "flags")) {
528 fprintf(stderr, "%d: no flags present\n", linenum);
531 fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm, linenum);
538 if (*cpp && (!strcasecmp(*cpp, "with") || !strcasecmp(*cpp, "and")))
539 if (extras(&cpp, &fil, linenum))
543 * icmp types for use with the icmp protocol
545 if (*cpp && !strcasecmp(*cpp, "icmp-type")) {
546 if (fil.fr_proto != IPPROTO_ICMP) {
548 "%d: icmp with wrong protocol (%d)\n",
549 linenum, fil.fr_proto);
552 if (addicmp(&cpp, &fil, linenum))
554 fil.fr_icmp = htons(fil.fr_icmp);
555 fil.fr_icmpm = htons(fil.fr_icmpm);
561 while (*cpp && !strcasecmp(*cpp, "keep"))
562 if (addkeep(&cpp, &fil, linenum))
566 * head of a new group ?
568 if (*cpp && !strcasecmp(*cpp, "head")) {
570 fprintf(stderr, "%d: head without group #\n", linenum);
573 if (ratoi(*cpp, &i, 0, USHRT_MAX))
576 fprintf(stderr, "%d: invalid group (%s)\n",
584 * head of a new group ?
586 if (*cpp && !strcasecmp(*cpp, "group")) {
588 fprintf(stderr, "%d: group without group #\n",
592 if (ratoi(*cpp, &i, 0, USHRT_MAX))
595 fprintf(stderr, "%d: invalid group (%s)\n",
606 fprintf(stderr, "%d: unknown words at end: [", linenum);
608 fprintf(stderr, "%s ", *cpp);
609 fprintf(stderr, "]\n");
616 if ((fil.fr_tcpf || fil.fr_tcpfm) && fil.fr_proto != IPPROTO_TCP) {
617 fprintf(stderr, "%d: TCP protocol not specified\n", linenum);
620 if (!(fil.fr_ip.fi_fl & FI_TCPUDP) && (fil.fr_proto != IPPROTO_TCP) &&
621 (fil.fr_proto != IPPROTO_UDP) && (fil.fr_dcmp || fil.fr_scmp)) {
623 fil.fr_ip.fi_fl |= FI_TCPUDP;
624 fil.fr_mip.fi_fl |= FI_TCPUDP;
627 "%d: port comparisons for non-TCP/UDP\n",
633 if ((fil.fr_flags & FR_KEEPFRAG) &&
634 (!(fil.fr_ip.fi_fl & FI_FRAG) || !(fil.fr_ip.fi_fl & FI_FRAG))) {
636 "%d: must use 'with frags' with 'keep frags'\n",
645 int to_interface(fdp, to, linenum)
657 fdp->fd_ip.s_addr = hostnum(s, &r, linenum);
661 (void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1);
662 fdp->fd_ifname[sizeof(fdp->fd_ifname) - 1] = '\0';
667 void print_toif(tag, fdp)
671 printf("%s %s%s", tag, fdp->fd_ifname,
672 (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)");
673 if (fdp->fd_ip.s_addr)
674 printf(":%s", inet_ntoa(fdp->fd_ip));
680 * returns -1 if neither "hostmask/num" or "hostmask mask addr" are
681 * found in the line segments, there is an error processing this information,
682 * or there is an error processing ports information.
684 int hostmask(seg, sa, msk, pp, cp, tp, linenum)
692 int bits = -1, resolved;
693 struct in_addr maskaddr;
696 * is it possibly hostname/num ?
698 if ((s = index(**seg, '/')) || (s = index(**seg, ':'))) {
700 if (index(s, '.') || index(s, 'x')) {
701 /* possibly of the form xxx.xxx.xxx.xxx
703 if (inet_aton(s, &maskaddr) == 0) {
704 fprintf(stderr, "%d: bad mask (%s)\n",
708 *msk = maskaddr.s_addr;
711 * set x most significant bits
713 bits = (int)strtol(s, &endptr, 0);
714 if (*endptr != '\0' || bits > 32 || bits < 0) {
715 fprintf(stderr, "%d: bad mask (/%s)\n",
722 *msk = htonl(0xffffffff << (32 - bits));
724 *sa = hostnum(**seg, &resolved, linenum) & *msk;
725 if (resolved == -1) {
726 fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
730 return ports(seg, pp, cp, tp, linenum);
734 * look for extra segments if "mask" found in right spot
736 if (*(*seg+1) && *(*seg+2) && !strcasecmp(*(*seg+1), "mask")) {
737 *sa = hostnum(**seg, &resolved, linenum);
738 if (resolved == -1) {
739 fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
744 if (inet_aton(**seg, &maskaddr) == 0) {
745 fprintf(stderr, "%d: bad mask (%s)\n", linenum, **seg);
748 *msk = maskaddr.s_addr;
751 return ports(seg, pp, cp, tp, linenum);
755 *sa = hostnum(**seg, &resolved, linenum);
756 if (resolved == -1) {
757 fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
761 *msk = (*sa ? inet_addr("255.255.255.255") : 0L);
763 return ports(seg, pp, cp, tp, linenum);
765 fprintf(stderr, "%d: bad host (%s)\n", linenum, **seg);
770 * returns an ip address as a long var as a result of either a DNS lookup or
771 * straight inet_addr() call
773 u_32_t hostnum(host, resolved, linenum)
783 if (!strcasecmp("any", host))
785 if (isdigit(*host) && inet_aton(host, &ip))
788 if (!strcasecmp("<thishost>", host))
791 if (!(hp = gethostbyname(host))) {
792 if (!(np = getnetbyname(host))) {
794 fprintf(stderr, "%d: can't resolve hostname: %s\n",
798 return htonl(np->n_net);
800 return *(u_32_t *)hp->h_addr;
804 * check for possible presence of the port fields in the line
806 int ports(seg, pp, cp, tp, linenum)
814 if (!*seg || !**seg || !***seg)
816 if (!strcasecmp(**seg, "port") && *(*seg + 1) && *(*seg + 2)) {
818 if (isdigit(***seg) && *(*seg + 2)) {
819 if (portnum(**seg, pp, linenum) == 0)
822 if (!strcmp(**seg, "<>"))
824 else if (!strcmp(**seg, "><"))
828 "%d: unknown range operator (%s)\n",
834 fprintf(stderr, "%d: missing 2nd port value\n",
838 if (portnum(**seg, tp, linenum) == 0)
840 } else if (!strcmp(**seg, "=") || !strcasecmp(**seg, "eq"))
842 else if (!strcmp(**seg, "!=") || !strcasecmp(**seg, "ne"))
844 else if (!strcmp(**seg, "<") || !strcasecmp(**seg, "lt"))
846 else if (!strcmp(**seg, ">") || !strcasecmp(**seg, "gt"))
848 else if (!strcmp(**seg, "<=") || !strcasecmp(**seg, "le"))
850 else if (!strcmp(**seg, ">=") || !strcasecmp(**seg, "ge"))
853 fprintf(stderr, "%d: unknown comparator (%s)\n",
857 if (comp != FR_OUTRANGE && comp != FR_INRANGE) {
859 if (portnum(**seg, pp, linenum) == 0)
869 * find the port number given by the name, either from getservbyname() or
870 * straight atoi(). Return 1 on success, 0 on failure
872 int portnum(name, port, linenum)
877 struct servent *sp, *sp2;
880 if (isdigit(*name)) {
881 if (ratoi(name, &i, 0, USHRT_MAX)) {
885 fprintf(stderr, "%d: unknown port \"%s\"\n", linenum, name);
888 if (proto != NULL && strcasecmp(proto, "tcp/udp") != 0) {
889 sp = getservbyname(name, proto);
891 *port = ntohs(sp->s_port);
894 fprintf(stderr, "%d: unknown service \"%s\".\n", linenum, name);
897 sp = getservbyname(name, "tcp");
900 sp2 = getservbyname(name, "udp");
902 fprintf(stderr, "%d: unknown tcp/udp service \"%s\".\n",
906 if (p1 != sp2->s_port) {
907 fprintf(stderr, "%d: %s %d/tcp is a different port to ",
909 fprintf(stderr, "%d: %s %d/udp\n", linenum, name, sp->s_port);
917 u_char tcp_flags(flgs, mask, linenum)
922 u_char tcpf = 0, tcpfm = 0, *fp = &tcpf;
925 for (s = flgs; *s; s++) {
926 if (*s == '/' && fp == &tcpf) {
930 if (!(t = index(flagset, *s))) {
931 fprintf(stderr, "%d: unknown flag (%c)\n", linenum, *s);
934 *fp |= flags[t - flagset];
944 * deal with extra bits on end of the line
946 int extras(cp, fr, linenum)
963 while (**cp && (!strncasecmp(**cp, "ipopt", 5) ||
964 !strncasecmp(**cp, "not", 3) || !strncasecmp(**cp, "opt", 4) ||
965 !strncasecmp(**cp, "frag", 3) || !strncasecmp(**cp, "no", 2) ||
966 !strncasecmp(**cp, "short", 5))) {
967 if (***cp == 'n' || ***cp == 'N') {
971 } else if (***cp == 'i' || ***cp == 'I') {
973 fr->fr_ip.fi_fl |= FI_OPTIONS;
974 fr->fr_mip.fi_fl |= FI_OPTIONS;
976 } else if (***cp == 'f' || ***cp == 'F') {
978 fr->fr_ip.fi_fl |= FI_FRAG;
979 fr->fr_mip.fi_fl |= FI_FRAG;
981 } else if (***cp == 'o' || ***cp == 'O') {
984 "%d: opt missing arguements\n",
989 if (!(opts = optname(cp, &secmsk, linenum)))
992 } else if (***cp == 's' || ***cp == 'S') {
995 "%d: short cannot be used with TCP flags\n",
1001 fr->fr_ip.fi_fl |= FI_SHORT;
1002 fr->fr_mip.fi_fl |= FI_SHORT;
1007 if (!notopt || !opts)
1008 fr->fr_mip.fi_fl |= oflags;
1011 fr->fr_mip.fi_optmsk |= opts;
1013 fr->fr_mip.fi_optmsk |= (opts & ~0x0100);
1016 fr->fr_mip.fi_optmsk |= opts;
1018 fr->fr_mip.fi_secmsk |= secmsk;
1021 fr->fr_ip.fi_fl &= (~oflags & 0xf);
1022 fr->fr_ip.fi_optmsk &= ~opts;
1023 fr->fr_ip.fi_secmsk &= ~secmsk;
1025 fr->fr_ip.fi_fl |= oflags;
1026 fr->fr_ip.fi_optmsk |= opts;
1027 fr->fr_ip.fi_secmsk |= secmsk;
1040 u_32_t optname(cp, sp, linenum)
1045 struct ipopt_names *io, *so;
1051 for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
1052 for (io = ionames; io->on_name; io++)
1053 if (!strcasecmp(s, io->on_name)) {
1058 fprintf(stderr, "%d: unknown IP option name %s\n",
1062 if (!strcasecmp(s, "sec-class"))
1066 if (sec && !*(*cp + 1)) {
1067 fprintf(stderr, "%d: missing security level after sec-class\n",
1074 for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {
1075 for (so = secclass; so->on_name; so++)
1076 if (!strcasecmp(s, so->on_name)) {
1082 "%d: no such security level: %s\n",
1095 void optprint(u_short *sec, u_long optmsk, u_long optbits)
1097 void optprint(sec, optmsk, optbits)
1099 u_long optmsk, optbits;
1102 u_short secmsk = sec[0], secbits = sec[1];
1103 struct ipopt_names *io, *so;
1108 for (io = ionames; io->on_name; io++)
1109 if ((io->on_bit & optmsk) &&
1110 ((io->on_bit & optmsk) == (io->on_bit & optbits))) {
1111 if ((io->on_value != IPOPT_SECURITY) ||
1112 (!secmsk && !secbits)) {
1113 printf("%s%s", s, io->on_name);
1114 if (io->on_value == IPOPT_SECURITY)
1122 if (secmsk & secbits) {
1123 printf("%ssec-class", s);
1125 for (so = secclass; so->on_name; so++)
1126 if ((secmsk & so->on_bit) &&
1127 ((so->on_bit & secmsk) == (so->on_bit & secbits))) {
1128 printf("%s%s", s, so->on_name);
1133 if ((optmsk && (optmsk != optbits)) ||
1134 (secmsk && (secmsk != secbits))) {
1137 if (optmsk != optbits) {
1138 for (io = ionames; io->on_name; io++)
1139 if ((io->on_bit & optmsk) &&
1140 ((io->on_bit & optmsk) !=
1141 (io->on_bit & optbits))) {
1142 if ((io->on_value != IPOPT_SECURITY) ||
1143 (!secmsk && !secbits)) {
1144 printf("%s%s", s, io->on_name);
1154 if (secmsk != secbits) {
1155 printf("%ssec-class", s);
1157 for (so = secclass; so->on_name; so++)
1158 if ((so->on_bit & secmsk) &&
1159 ((so->on_bit & secmsk) !=
1160 (so->on_bit & secbits))) {
1161 printf("%s%s", s, so->on_name);
1168 char *icmptypes[] = {
1169 "echorep", (char *)NULL, (char *)NULL, "unreach", "squench",
1170 "redir", (char *)NULL, (char *)NULL, "echo", "routerad",
1171 "routersol", "timex", "paramprob", "timest", "timestrep",
1172 "inforeq", "inforep", "maskreq", "maskrep", "END"
1176 * set the icmp field to the correct type if "icmp" word is found
1178 int addicmp(cp, fp, linenum)
1189 if (!fp->fr_proto) /* to catch lusers */
1190 fp->fr_proto = IPPROTO_ICMP;
1191 if (isdigit(***cp)) {
1192 if (!ratoi(**cp, &i, 0, 255)) {
1194 "%d: Invalid icmp-type (%s) specified\n",
1199 for (t = icmptypes, i = 0; ; t++, i++) {
1202 if (!strcasecmp("END", *t)) {
1206 if (!strcasecmp(*t, **cp))
1211 "%d: Invalid icmp-type (%s) specified\n",
1216 fp->fr_icmp = (u_short)(i << 8);
1217 fp->fr_icmpm = (u_short)0xff00;
1222 if (**cp && strcasecmp("code", **cp))
1225 if (isdigit(***cp)) {
1226 if (!ratoi(**cp, &i, 0, 255)) {
1228 "%d: Invalid icmp code (%s) specified\n",
1232 fp->fr_icmp |= (u_short)i;
1233 fp->fr_icmpm = (u_short)0xffff;
1237 fprintf(stderr, "%d: Invalid icmp code (%s) specified\n",
1243 #define MAX_ICMPCODE 15
1245 char *icmpcodes[] = {
1246 "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail",
1247 "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib",
1248 "net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff",
1251 * Return the number for the associated ICMP unreachable code.
1259 if (!(s = strrchr(str, ')')))
1262 if (isdigit(*str)) {
1263 if (!ratoi(str, &i, 0, 255))
1269 for (i = 0; icmpcodes[i]; i++)
1270 if (!strncasecmp(str, icmpcodes[i], MIN(len,
1271 strlen(icmpcodes[i])) ))
1278 * set the icmp field to the correct type if "icmp" word is found
1280 int addkeep(cp, fp, linenum)
1285 if (fp->fr_proto != IPPROTO_TCP && fp->fr_proto != IPPROTO_UDP &&
1286 fp->fr_proto != IPPROTO_ICMP && !(fp->fr_ip.fi_fl & FI_TCPUDP)) {
1287 fprintf(stderr, "%d: Can only use keep with UDP/ICMP/TCP\n",
1293 if (**cp && strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) {
1294 fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n",
1299 if (***cp == 's' || ***cp == 'S')
1300 fp->fr_flags |= FR_KEEPSTATE;
1301 else if (***cp == 'f' || ***cp == 'F')
1302 fp->fr_flags |= FR_KEEPFRAG;
1309 * count consecutive 1's in bit mask. If the mask generated by counting
1310 * consecutive 1's is different to that passed, return -1, else return #
1319 ip = ipn = ntohl(ip);
1320 for (i = 32; i; i--, ipn *= 2)
1321 if (ipn & 0x80000000)
1326 for (i = 32, j = cnt; i; i--, j--) {
1337 char *portname(pr, port)
1340 static char buf[32];
1341 struct protoent *p = NULL;
1342 struct servent *sv = NULL, *sv1 = NULL;
1345 if ((sv = getservbyport(htons(port), "tcp"))) {
1346 strncpy(buf, sv->s_name, sizeof(buf)-1);
1347 buf[sizeof(buf)-1] = '\0';
1348 sv1 = getservbyport(htons(port), "udp");
1349 sv = strncasecmp(buf, sv->s_name, strlen(buf)) ?
1354 } else if (pr && (p = getprotobynumber(pr))) {
1355 if ((sv = getservbyport(htons(port), p->p_name))) {
1356 strncpy(buf, sv->s_name, sizeof(buf)-1);
1357 buf[sizeof(buf)-1] = '\0';
1362 (void) sprintf(buf, "%d", port);
1368 * print the filter structure in a useful way
1373 static char *pcmp1[] = { "*", "=", "!=", "<", ">", "<=", ">=",
1381 if (fp->fr_flags & FR_PASS)
1383 else if (fp->fr_flags & FR_BLOCK) {
1385 if (fp->fr_flags & FR_RETICMP) {
1386 if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP)
1387 printf(" return-icmp-as-dest");
1388 else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP)
1389 printf(" return-icmp");
1391 if (fp->fr_icode <= MAX_ICMPCODE)
1393 icmpcodes[(int)fp->fr_icode]);
1395 printf("(%d)", fp->fr_icode);
1397 } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST)
1398 printf(" return-rst");
1399 } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) {
1401 if (fp->fr_flags & FR_LOGBODY)
1403 if (fp->fr_flags & FR_LOGFIRST)
1405 } else if (fp->fr_flags & FR_ACCOUNT)
1407 else if (fp->fr_flags & FR_AUTH)
1409 else if (fp->fr_flags & FR_PREAUTH)
1411 else if (fp->fr_skip)
1412 printf("skip %hu", fp->fr_skip);
1414 if (fp->fr_flags & FR_OUTQUE)
1419 if (((fp->fr_flags & FR_LOGB) == FR_LOGB) ||
1420 ((fp->fr_flags & FR_LOGP) == FR_LOGP)) {
1422 if (fp->fr_flags & FR_LOGBODY)
1424 if (fp->fr_flags & FR_LOGFIRST)
1426 if (fp->fr_flags & FR_LOGORBLOCK)
1427 printf("or-block ");
1428 if (fp->fr_loglevel != 0xffff) {
1429 if (fp->fr_loglevel & LOG_FACMASK) {
1430 s = fac_toname(fp->fr_loglevel);
1435 u = pri_toname(fp->fr_loglevel);
1439 printf("level %s.%s ", s, u);
1441 printf("level %s ", u);
1445 if (fp->fr_flags & FR_QUICK)
1448 if (*fp->fr_ifname) {
1449 printf("on %s%s ", fp->fr_ifname,
1450 (fp->fr_ifa || (long)fp->fr_ifa == -1) ? "" : "(!)");
1451 if (*fp->fr_dif.fd_ifname)
1452 print_toif("dup-to", &fp->fr_dif);
1453 if (*fp->fr_tif.fd_ifname)
1454 print_toif("to", &fp->fr_tif);
1455 if (fp->fr_flags & FR_FASTROUTE)
1456 printf("fastroute ");
1459 if (fp->fr_mip.fi_tos)
1460 printf("tos %#x ", fp->fr_tos);
1461 if (fp->fr_mip.fi_ttl)
1462 printf("ttl %d ", fp->fr_ttl);
1463 if (fp->fr_ip.fi_fl & FI_TCPUDP) {
1464 printf("proto tcp/udp ");
1466 } else if ((pr = fp->fr_mip.fi_p)) {
1467 if ((p = getprotobynumber(fp->fr_proto)))
1468 printf("proto %s ", p->p_name);
1470 printf("proto %d ", fp->fr_proto);
1473 printf("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : "");
1474 if (!fp->fr_src.s_addr && !fp->fr_smsk.s_addr)
1477 printf("%s", inet_ntoa(fp->fr_src));
1478 if ((ones = countbits(fp->fr_smsk.s_addr)) == -1)
1479 printf("/%s ", inet_ntoa(fp->fr_smsk));
1481 printf("/%d ", ones);
1484 if (fp->fr_scmp == FR_INRANGE || fp->fr_scmp == FR_OUTRANGE)
1485 printf("port %d %s %d ", fp->fr_sport,
1486 pcmp1[fp->fr_scmp], fp->fr_stop);
1488 printf("port %s %s ", pcmp1[fp->fr_scmp],
1489 portname(pr, fp->fr_sport));
1492 printf("to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : "");
1493 if (!fp->fr_dst.s_addr && !fp->fr_dmsk.s_addr)
1496 printf("%s", inet_ntoa(fp->fr_dst));
1497 if ((ones = countbits(fp->fr_dmsk.s_addr)) == -1)
1498 printf("/%s", inet_ntoa(fp->fr_dmsk));
1500 printf("/%d", ones);
1503 if (fp->fr_dcmp == FR_INRANGE || fp->fr_dcmp == FR_OUTRANGE)
1504 printf(" port %d %s %d", fp->fr_dport,
1505 pcmp1[fp->fr_dcmp], fp->fr_dtop);
1507 printf(" port %s %s", pcmp1[fp->fr_dcmp],
1508 portname(pr, fp->fr_dport));
1510 if ((fp->fr_ip.fi_fl & ~FI_TCPUDP) ||
1511 (fp->fr_mip.fi_fl & ~FI_TCPUDP) ||
1512 fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk ||
1513 fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) {
1515 if (fp->fr_ip.fi_optmsk || fp->fr_mip.fi_optmsk ||
1516 fp->fr_ip.fi_secmsk || fp->fr_mip.fi_secmsk) {
1517 sec[0] = fp->fr_mip.fi_secmsk;
1518 sec[1] = fp->fr_ip.fi_secmsk;
1520 fp->fr_mip.fi_optmsk, fp->fr_ip.fi_optmsk);
1521 } else if (fp->fr_mip.fi_fl & FI_OPTIONS) {
1522 if (!(fp->fr_ip.fi_fl & FI_OPTIONS))
1526 if (fp->fr_mip.fi_fl & FI_SHORT) {
1527 if (!(fp->fr_ip.fi_fl & FI_SHORT))
1531 if (fp->fr_mip.fi_fl & FI_FRAG) {
1532 if (!(fp->fr_ip.fi_fl & FI_FRAG))
1537 if (fp->fr_proto == IPPROTO_ICMP && fp->fr_icmpm) {
1538 int type = fp->fr_icmp, code;
1540 type = ntohs(fp->fr_icmp);
1543 if (type < (sizeof(icmptypes) / sizeof(char *)) &&
1545 printf(" icmp-type %s", icmptypes[type]);
1547 printf(" icmp-type %d", type);
1549 printf(" code %d", code);
1551 if (fp->fr_proto == IPPROTO_TCP && (fp->fr_tcpf || fp->fr_tcpfm)) {
1553 for (s = flagset, t = flags; *s; s++, t++)
1554 if (fp->fr_tcpf & *t)
1558 for (s = flagset, t = flags; *s; s++, t++)
1559 if (fp->fr_tcpfm & *t)
1564 if (fp->fr_flags & FR_KEEPSTATE)
1565 printf(" keep state");
1566 if (fp->fr_flags & FR_KEEPFRAG)
1567 printf(" keep frags");
1569 printf(" head %d", fp->fr_grhead);
1571 printf(" group %d", fp->fr_group);
1572 (void)putchar('\n');
1578 int i = sizeof(*fp), j = 0;
1581 for (s = (u_char *)fp; i; i--, s++) {
1583 printf("%02x ", *s);
1590 (void)fflush(stdout);
1594 int ratoi(ps, pi, min, max)
1601 i = (int)strtol(ps, &pe, 0);
1602 if (*pe != '\0' || i < min || i > max)