int	icmpcode __P((char *)), addkeep __P((char ***, struct frentry *, int)); int	to_interface __P((frdest_t *, char *, int)); void	print_toif __P((char *, frdest_t *)); void	optprint __P((u_short *, u_long, u_long)); int	loglevel __P((char **, u_int *, int)); void	printlog __P((frentry_t *));  extern	char	*proto; extern	char	flagset[]; extern	u_char	flags[];    struct	frentry	*parse(line, linenum) char	*line; int     linenum; { static	struct	frentry	fil; struct	protoent	*p = NULL; char	*cps[31], **cpp, *endptr; int	i, cnt = 1, j, ch; u_int	k;  while (*line && isspace(*line)) line++; if (!*line) return NULL;  bzero((char *)&fil, sizeof(fil)); fil.fr_mip.fi_v = 0xf; #ifdef	USE_INET6 fil.fr_ip.fi_v = use_inet6 ? 6 : 4; #else fil.fr_ip.fi_v = 4; #endif fil.fr_loglevel = 0xffff;   if (opts & OPT_DEBUG) fprintf(stderr, "parse [%s]\n", line); for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++) cps[++i] = strtok(NULL, " \b\t\r\n"); cps[i] = NULL;  if (cnt < 3) { fprintf(stderr, "%d: not enough segments in line\n", linenum); return NULL; }  cpp = cps; if (**cpp == '@') fil.fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1;   if (!strcasecmp("block", *cpp)) { fil.fr_flags |= FR_BLOCK; if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) && (i = 19)) fil.fr_flags |= FR_FAKEICMP; else if (!strncasecmp(*(cpp+1), "return-icmp", 11) && (i = 11)) fil.fr_flags |= FR_RETICMP; if (fil.fr_flags & FR_RETICMP) { cpp++; if (strlen(*cpp) == i) { if (*(cpp + 1) && **(cpp +1) == '(') { cpp++; i = 0; } else i = -1; }   if ((i >= 0) && (*(*cpp + i) == '(')) { i++; j = icmpcode(*cpp + i); if (j == -1) { fprintf(stderr, "%d: unrecognised icmp code %s\n", linenum, *cpp + 20); return NULL; } fil.fr_icode = j; } } else if (!strncasecmp(*(cpp+1), "return-rst", 10)) { fil.fr_flags |= FR_RETRST; cpp++; } } else if (!strcasecmp("count", *cpp)) { fil.fr_flags |= FR_ACCOUNT; } else if (!strcasecmp("pass", *cpp)) { fil.fr_flags |= FR_PASS; } else if (!strcasecmp("auth", *cpp)) { fil.fr_flags |= FR_AUTH; } else if (!strcasecmp("preauth", *cpp)) { fil.fr_flags |= FR_PREAUTH; } else if (!strcasecmp("skip", *cpp)) { cpp++; if (ratoui(*cpp, &k, 0, UINT_MAX)) fil.fr_skip = k; else { fprintf(stderr, "%d: integer must follow skip\n", linenum); return NULL; } } else if (!strcasecmp("log", *cpp)) { fil.fr_flags |= FR_LOG; if (!strcasecmp(*(cpp+1), "body")) { fil.fr_flags |= FR_LOGBODY; cpp++; } if (!strcasecmp(*(cpp+1), "first")) { fil.fr_flags |= FR_LOGFIRST; cpp++; } if (*cpp && !strcasecmp(*(cpp+1), "or-block")) { fil.fr_flags |= FR_LOGORBLOCK; cpp++; } if (!strcasecmp(*(cpp+1), "level")) { cpp++; if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) return NULL; cpp++; } } else {  fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp); return NULL; } if (!*++cpp) { fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum); return NULL; }  if (!strcasecmp("in", *cpp)) fil.fr_flags |= FR_INQUE; else if (!strcasecmp("out", *cpp)) { fil.fr_flags |= FR_OUTQUE; if (fil.fr_flags & FR_RETICMP) { fprintf(stderr, "%d: Can only use return-icmp with 'in'\n", linenum); return NULL; } else if (fil.fr_flags & FR_RETRST) { fprintf(stderr, "%d: Can only use return-rst with 'in'\n", linenum); return NULL; } } if (!*++cpp) { fprintf(stderr, "%d: missing source specification\n", linenum); return NULL; }  if (!strcasecmp("log", *cpp)) { if (!*++cpp) { fprintf(stderr, "%d: missing source specification\n", linenum); return NULL; } if (fil.fr_flags & FR_PASS) fil.fr_flags |= FR_LOGP; else if (fil.fr_flags & FR_BLOCK) fil.fr_flags |= FR_LOGB; if (*cpp && !strcasecmp(*cpp, "body")) { fil.fr_flags |= FR_LOGBODY; cpp++; } if (*cpp && !strcasecmp(*cpp, "first")) { fil.fr_flags |= FR_LOGFIRST; cpp++; } if (*cpp && !strcasecmp(*cpp, "or-block")) { if (!(fil.fr_flags & FR_PASS)) { fprintf(stderr, "%d: or-block must be used with pass\n", linenum); return NULL; } fil.fr_flags |= FR_LOGORBLOCK; cpp++; } if (*cpp && !strcasecmp(*cpp, "level")) { if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1) return NULL; cpp++; cpp++; } }  if (*cpp && !strcasecmp("quick", *cpp)) { cpp++; fil.fr_flags |= FR_QUICK; }  *fil.fr_ifname = '\0'; if (*cpp && !strcasecmp(*cpp, "on")) { if (!*++cpp) { fprintf(stderr, "%d: interface name missing\n", linenum); return NULL; } (void)strncpy(fil.fr_ifname, *cpp, IFNAMSIZ-1); fil.fr_ifname[IFNAMSIZ-1] = '\0'; cpp++; if (!*cpp) { if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) { fprintf(stderr, "%d: %s can only be used with TCP\n", linenum, "return-rst"); return NULL; } return &fil; }  if (*cpp) { if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) { cpp++; if (to_interface(&fil.fr_dif, *cpp, linenum)) return NULL; cpp++; } if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) { cpp++; if (to_interface(&fil.fr_tif, *cpp, linenum)) return NULL; cpp++; } else if (*cpp && !strcasecmp(*cpp, "fastroute")) { if (!(fil.fr_flags & FR_INQUE)) { fprintf(stderr, "can only use %s with 'in'\n", "fastroute"); return NULL; } fil.fr_flags |= FR_FASTROUTE; cpp++; } } } if (*cpp && !strcasecmp(*cpp, "tos")) { if (!*++cpp) { fprintf(stderr, "%d: tos missing value\n", linenum); return NULL; } fil.fr_tos = strtol(*cpp, NULL, 0); fil.fr_mip.fi_tos = 0xff; cpp++; }  if (*cpp && !strcasecmp(*cpp, "ttl")) { if (!*++cpp) { fprintf(stderr, "%d: ttl missing hopcount value\n", linenum); return NULL; } if (ratoi(*cpp, &i, 0, 255)) fil.fr_ttl = i; else { fprintf(stderr, "%d: invalid ttl (%s)\n", linenum, *cpp); return NULL; } fil.fr_mip.fi_ttl = 0xff; cpp++; }   proto = NULL; if (*cpp && !strcasecmp(*cpp, "proto")) { if (!*++cpp) { fprintf(stderr, "%d: protocol name missing\n", linenum); return NULL; } proto = *cpp++; if (!strcasecmp(proto, "tcp/udp")) { fil.fr_ip.fi_fl |= FI_TCPUDP; fil.fr_mip.fi_fl |= FI_TCPUDP; } else { if (!(p = getprotobyname(proto)) && !isdigit(*proto)) { fprintf(stderr, "%d: unknown protocol (%s)\n", linenum, proto); return NULL; } if (p) fil.fr_proto = p->p_proto; else if (isdigit(*proto)) { i = (int)strtol(proto, &endptr, 0); if (*endptr != '\0' || i < 0 || i > 255) { fprintf(stderr, "%d: unknown protocol (%s)\n", linenum, proto); return NULL; } fil.fr_proto = i; } fil.fr_mip.fi_p = 0xff; } } if ((fil.fr_proto != IPPROTO_TCP) && ((fil.fr_flags & FR_RETMASK) == FR_RETRST)) { fprintf(stderr, "%d: %s can only be used with TCP\n", linenum, "return-rst"); return NULL; }    if (!*cpp) { fprintf(stderr, "%d: missing source specification\n", linenum); return NULL; } if (!strcasecmp(*cpp, "all")) { cpp++; if (!*cpp) return &fil; } else { if (strcasecmp(*cpp, "from")) { fprintf(stderr, "%d: unexpected keyword (%s) - from\n", linenum, *cpp); return NULL; } if (!*++cpp) { fprintf(stderr, "%d: missing host after from\n", linenum); return NULL; } if (**cpp == '!') { fil.fr_flags |= FR_NOTSRCIP; (*cpp)++; } ch = 0; if (hostmask(&cpp, (u_32_t *)&fil.fr_src, (u_32_t *)&fil.fr_smsk, &fil.fr_sport, &ch, &fil.fr_stop, linenum)) { return NULL; }  fil.fr_scmp = ch; if (!*cpp) { fprintf(stderr, "%d: missing to fields\n", linenum); return NULL; }   if (strcasecmp(*cpp, "to")) { fprintf(stderr, "%d: unexpected keyword (%s) - to\n", linenum, *cpp); return NULL; } if (!*++cpp) { fprintf(stderr, "%d: missing host after to\n", linenum); return NULL; } ch = 0; if (**cpp == '!') { fil.fr_flags |= FR_NOTDSTIP; (*cpp)++; } if (hostmask(&cpp, (u_32_t *)&fil.fr_dst, (u_32_t *)&fil.fr_dmsk, &fil.fr_dport, &ch, &fil.fr_dtop, linenum)) { return NULL; } fil.fr_dcmp = ch; }   if (fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp) && fil.fr_proto != IPPROTO_TCP && fil.fr_proto != IPPROTO_UDP) { fprintf(stderr, "%d: port operation on non tcp/udp\n", linenum); return NULL; } if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) { fprintf(stderr, "%d: icmp comparisons on wrong protocol\n", linenum); return NULL; }  if (!*cpp) return &fil;  if (*cpp && !strcasecmp(*cpp, "flags")) { if (!*++cpp) { fprintf(stderr, "%d: no flags present\n", linenum); return NULL; } fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm, linenum); cpp++; }   if ((fil.fr_v == 4) && *cpp && (!strcasecmp(*cpp, "with") || !strcasecmp(*cpp, "and"))) if (extras(&cpp, &fil, linenum)) return NULL;   if (*cpp && !strcasecmp(*cpp, "icmp-type")) { if (fil.fr_proto != IPPROTO_ICMP) { fprintf(stderr, "%d: icmp with wrong protocol (%d)\n", linenum, fil.fr_proto); return NULL; } if (addicmp(&cpp, &fil, linenum)) return NULL; fil.fr_icmp = htons(fil.fr_icmp); fil.fr_icmpm = htons(fil.fr_icmpm); }   while (*cpp && !strcasecmp(*cpp, "keep")) if (addkeep(&cpp, &fil, linenum)) return NULL;   if (*cpp && !strcasecmp(*cpp, "head")) { if (!*++cpp) { fprintf(stderr, "%d: head without group #\n", linenum); return NULL; } if (ratoui(*cpp, &k, 0, UINT_MAX)) fil.fr_grhead = (u_32_t)k; else { fprintf(stderr, "%d: invalid group (%s)\n", linenum, *cpp); return NULL; } cpp++; }   if (*cpp && !strcasecmp(*cpp, "group")) { if (!*++cpp) { fprintf(stderr, "%d: group without group #\n", linenum); return NULL; } if (ratoui(*cpp, &k, 0, UINT_MAX)) fil.fr_group = k; else { fprintf(stderr, "%d: invalid group (%s)\n", linenum, *cpp); return NULL; } cpp++; }   if (*cpp && **cpp) { fprintf(stderr, "%d: unknown words at end: [", linenum); for (; *cpp; cpp++) fprintf(stderr, "%s ", *cpp); fprintf(stderr, "]\n"); return NULL; }   if ((fil.fr_tcpf || fil.fr_tcpfm) && fil.fr_proto != IPPROTO_TCP) { fprintf(stderr, "%d: TCP protocol not specified\n", linenum); return NULL; } if (!(fil.fr_ip.fi_fl & FI_TCPUDP) && (fil.fr_proto != IPPROTO_TCP) && (fil.fr_proto != IPPROTO_UDP) && (fil.fr_dcmp || fil.fr_scmp)) { if (!fil.fr_proto) { fil.fr_ip.fi_fl |= FI_TCPUDP; fil.fr_mip.fi_fl |= FI_TCPUDP; } else { fprintf(stderr, "%d: port comparisons for non-TCP/UDP\n", linenum); return NULL; } }  return &fil; }   int loglevel(cpp, facpri, linenum) char **cpp; u_int *facpri; int linenum; { int fac, pri; char *s;  fac = 0; pri = 0; if (!*++cpp) { fprintf(stderr, "%d: %s\n", linenum, "missing identifier after level"); return -1; }  s = index(*cpp, '.'); if (s) { *s++ = '\0'; fac = fac_findname(*cpp); if (fac == -1) { fprintf(stderr, "%d: %s %s\n", linenum, "Unknown facility", *cpp); return -1; } pri = pri_findname(s); if (pri == -1) { fprintf(stderr, "%d: %s %s\n", linenum, "Unknown priority", s); return -1; } } else { pri = pri_findname(*cpp); if (pri == -1) { fprintf(stderr, "%d: %s %s\n", linenum, "Unknown priority", *cpp); return -1; } } *facpri = fac|pri; return 0; }   int to_interface(fdp, to, linenum) frdest_t *fdp; char *to; int linenum; { char *s;  s = index(to, ':'); fdp->fd_ifp = NULL; if (s) { *s++ = '\0'; if (hostnum((u_32_t *)&fdp->fd_ip, s, linenum) == -1) return -1; } (void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1); fdp->fd_ifname[sizeof(fdp->fd_ifname) - 1] = '\0'; return 0; }   void print_toif(tag, fdp) char *tag; frdest_t *fdp; { printf("%s %s%s", tag, fdp->fd_ifname, (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)"); if (fdp->fd_ip.s_addr) printf(":%s", inet_ntoa(fdp->fd_ip)); putchar(' '); }    int	extras(cp, fr, linenum) char	***cp; struct	frentry	*fr; int     linenum; { u_short	secmsk; u_long	opts; int	notopt; char	oflags;  opts = 0; secmsk = 0; notopt = 0; (*cp)++; if (!**cp) return -1;  while (**cp && (!strncasecmp(**cp, "ipopt", 5) || !strncasecmp(**cp, "not", 3) || !strncasecmp(**cp, "opt", 3) || !strncasecmp(**cp, "frag", 4) || !strncasecmp(**cp, "no", 2) || !strncasecmp(**cp, "short", 5))) { if (***cp == 'n' || ***cp == 'N') { notopt = 1; (*cp)++; continue; } else if (***cp == 'i' || ***cp == 'I') { if (!notopt) fr->fr_ip.fi_fl |= FI_OPTIONS; fr->fr_mip.fi_fl |= FI_OPTIONS; goto nextopt; } else if (***cp == 'f' || ***cp == 'F') { if (!notopt) fr->fr_ip.fi_fl |= FI_FRAG; fr->fr_mip.fi_fl |= FI_FRAG; goto nextopt; } else if (***cp == 'o' || ***cp == 'O') { if (!*(*cp + 1)) { fprintf(stderr, "%d: opt missing arguements\n", linenum); return -1; } (*cp)++; if (!(opts = optname(cp, &secmsk, linenum))) return -1; oflags = FI_OPTIONS; } else if (***cp == 's' || ***cp == 'S') { if (fr->fr_tcpf) { fprintf(stderr, "%d: short cannot be used with TCP flags\n", linenum); return -1; }  if (!notopt) fr->fr_ip.fi_fl |= FI_SHORT; fr->fr_mip.fi_fl |= FI_SHORT; goto nextopt; } else return -1;  if (!notopt || !opts) fr->fr_mip.fi_fl |= oflags; if (notopt) { if (!secmsk) { fr->fr_mip.fi_optmsk |= opts; } else { fr->fr_mip.fi_optmsk |= (opts & ~0x0100); } } else { fr->fr_mip.fi_optmsk |= opts; } fr->fr_mip.fi_secmsk |= secmsk;  if (notopt) { fr->fr_ip.fi_fl &= (~oflags & 0xf); fr->fr_ip.fi_optmsk &= ~opts; fr->fr_ip.fi_secmsk &= ~secmsk; } else { fr->fr_ip.fi_fl |= oflags; fr->fr_ip.fi_optmsk |= opts; fr->fr_ip.fi_secmsk |= secmsk; } nextopt: notopt = 0; opts = 0; oflags = 0; secmsk = 0; (*cp)++; } return 0; }   u_32_t optname(cp, sp, linenum) char ***cp; u_short *sp; int linenum; { struct ipopt_names *io, *so; u_long msk = 0; u_short smsk = 0; char *s; int sec = 0;  for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) { for (io = ionames; io->on_name; io++) if (!strcasecmp(s, io->on_name)) { msk |= io->on_bit; break; } if (!io->on_name) { fprintf(stderr, "%d: unknown IP option name %s\n", linenum, s); return 0; } if (!strcasecmp(s, "sec-class")) sec = 1; }  if (sec && !*(*cp + 1)) { fprintf(stderr, "%d: missing security level after sec-class\n", linenum); return 0; }  if (sec) { (*cp)++; for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) { for (so = secclass; so->on_name; so++) if (!strcasecmp(s, so->on_name)) { smsk |= so->on_bit; break; } if (!so->on_name) { fprintf(stderr, "%d: no such security level: %s\n", linenum, s); return 0; } } if (smsk) *sp = smsk; } return msk; }   #ifdef __STDC__ void optprint(u_short *sec, u_long optmsk, u_long optbits) #else void optprint(sec, optmsk, optbits) u_short *sec; u_long optmsk, optbits; #endif { u_short secmsk = sec[0], secbits = sec[1]; struct ipopt_names *io, *so; char *s; int secflag = 0;  s = " opt "; for (io = ionames; io->on_name; io++) if ((io->on_bit & optmsk) && ((io->on_bit & optmsk) == (io->on_bit & optbits))) { if ((io->on_value != IPOPT_SECURITY) || (!secmsk && !secbits)) { printf("%s%s", s, io->on_name); if (io->on_value == IPOPT_SECURITY) io++; s = ","; } else secflag = 1; }   if (secmsk & secbits) { printf("%ssec-class", s); s = " "; for (so = secclass; so->on_name; so++) if ((secmsk & so->on_bit) && ((so->on_bit & secmsk) == (so->on_bit & secbits))) { printf("%s%s", s, so->on_name); s = ","; } }  if ((optmsk && (optmsk != optbits)) || (secmsk && (secmsk != secbits))) { s = " "; printf(" not opt"); if (optmsk != optbits) { for (io = ionames; io->on_name; io++) if ((io->on_bit & optmsk) && ((io->on_bit & optmsk) != (io->on_bit & optbits))) { if ((io->on_value != IPOPT_SECURITY) || (!secmsk && !secbits)) { printf("%s%s", s, io->on_name); s = ","; if (io->on_value == IPOPT_SECURITY) io++; } else io++; } }  if (secmsk != secbits) { printf("%ssec-class", s); s = " "; for (so = secclass; so->on_name; so++) if ((so->on_bit & secmsk) && ((so->on_bit & secmsk) != (so->on_bit & secbits))) { printf("%s%s", s, so->on_name); s = ","; } } } }  char	*icmptypes[] = { "echorep", (char *)NULL, (char *)NULL, "unreach", "squench", "redir", (char *)NULL, (char *)NULL, "echo", "routerad", "routersol", "timex", "paramprob", "timest", "timestrep", "inforeq", "inforep", "maskreq", "maskrep", "END" };   int	addicmp(cp, fp, linenum) char	***cp; struct	frentry	*fp; int     linenum; { char	**t; int	i;  (*cp)++; if (!**cp) return -1; if (!fp->fr_proto)	 fp->fr_proto = IPPROTO_ICMP; if (isdigit(***cp)) { if (!ratoi(**cp, &i, 0, 255)) { fprintf(stderr, "%d: Invalid icmp-type (%s) specified\n", linenum, **cp); return -1; } } else { for (t = icmptypes, i = 0; ; t++, i++) { if (!*t) continue; if (!strcasecmp("END", *t)) { i = -1; break; } if (!strcasecmp(*t, **cp)) break; } if (i == -1) { fprintf(stderr, "%d: Invalid icmp-type (%s) specified\n", linenum, **cp); return -1; } } fp->fr_icmp = (u_short)(i << 8); fp->fr_icmpm = (u_short)0xff00; (*cp)++; if (!**cp) return 0;  if (**cp && strcasecmp("code", **cp)) return 0; (*cp)++; if (isdigit(***cp)) { if (!ratoi(**cp, &i, 0, 255)) { fprintf(stderr, "%d: Invalid icmp code (%s) specified\n", linenum, **cp); return -1; } } else { i = icmpcode(**cp); if (i == -1) { fprintf(stderr, "%d: Invalid icmp code (%s) specified\n", linenum, **cp); return -1; } } i &= 0xff; fp->fr_icmp |= (u_short)i; fp->fr_icmpm = (u_short)0xffff; (*cp)++; return 0; }   #define	MAX_ICMPCODE	15  char	*icmpcodes[] = { "net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail", "net-unk", "host-unk", "isolate", "net-prohib", "host-prohib", "net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff", NULL };  int icmpcode(str) char *str; { char	*s; int	i, len;  if ((s = strrchr(str, ')'))) *s = '\0'; if (isdigit(*str)) { if (!ratoi(str, &i, 0, 255)) return -1; else return i; } len = strlen(str); for (i = 0; icmpcodes[i]; i++) if (!strncasecmp(str, icmpcodes[i], MIN(len, strlen(icmpcodes[i])) )) return i; return -1; }
int	icmpcode __P((char *)), addkeep __P((char ***, struct frentry *, int));int	to_interface __P((frdest_t *, char *, int));void	print_toif __P((char *, frdest_t *));void	optprint __P((u_short *, u_long, u_long));int	loglevel __P((char **, u_int *, int));void	printlog __P((frentry_t *));extern	char	*proto;extern	char	flagset[];extern	u_char	flags[];/* parse() * * parse a line read from the input filter rule file */struct	frentry	*parse(line, linenum)char	*line;int     linenum;{	static	struct	frentry	fil;	struct	protoent	*p = NULL;	char	*cps[31], **cpp, *endptr;	int	i, cnt = 1, j, ch;	u_int	k;	while (*line && isspace(*line))		line++;	if (!*line)		return NULL;	bzero((char *)&fil, sizeof(fil));	fil.fr_mip.fi_v = 0xf;#ifdef	USE_INET6	fil.fr_ip.fi_v = use_inet6 ? 6 : 4;#else	fil.fr_ip.fi_v = 4;#endif	fil.fr_loglevel = 0xffff;	/*	 * break line up into max of 20 segments	 */	if (opts & OPT_DEBUG)		fprintf(stderr, "parse [%s]\n", line);	for (i = 0, *cps = strtok(line, " \b\t\r\n"); cps[i] && i < 30; cnt++)		cps[++i] = strtok(NULL, " \b\t\r\n");	cps[i] = NULL;	if (cnt < 3) {		fprintf(stderr, "%d: not enough segments in line\n", linenum);		return NULL;	}	cpp = cps;	if (**cpp == '@')		fil.fr_hits = (U_QUAD_T)atoi(*cpp++ + 1) + 1;	if (!strcasecmp("block", *cpp)) {		fil.fr_flags |= FR_BLOCK;		if (!strncasecmp(*(cpp+1), "return-icmp-as-dest", 19) &&		    (i = 19))			fil.fr_flags |= FR_FAKEICMP;		else if (!strncasecmp(*(cpp+1), "return-icmp", 11) && (i = 11))			fil.fr_flags |= FR_RETICMP;		if (fil.fr_flags & FR_RETICMP) {			cpp++;			if (strlen(*cpp) == i) {				if (*(cpp + 1) && **(cpp +1) == '(') {					cpp++;					i = 0;				} else					i = -1;			}			/*			 * The ICMP code is not required to follow in ()'s			 */			if ((i >= 0) && (*(*cpp + i) == '(')) {				i++;				j = icmpcode(*cpp + i);				if (j == -1) {					fprintf(stderr,					"%d: unrecognised icmp code %s\n",						linenum, *cpp + 20);					return NULL;				}				fil.fr_icode = j;			}		} else if (!strncasecmp(*(cpp+1), "return-rst", 10)) {			fil.fr_flags |= FR_RETRST;			cpp++;		}	} else if (!strcasecmp("count", *cpp)) {		fil.fr_flags |= FR_ACCOUNT;	} else if (!strcasecmp("pass", *cpp)) {		fil.fr_flags |= FR_PASS;	} else if (!strcasecmp("auth", *cpp)) {		 fil.fr_flags |= FR_AUTH;	} else if (!strcasecmp("preauth", *cpp)) {		 fil.fr_flags |= FR_PREAUTH;	} else if (!strcasecmp("skip", *cpp)) {		cpp++;		if (ratoui(*cpp, &k, 0, UINT_MAX))			fil.fr_skip = k;		else {			fprintf(stderr, "%d: integer must follow skip\n",				linenum);			return NULL;		}	} else if (!strcasecmp("log", *cpp)) {		fil.fr_flags |= FR_LOG;		if (!strcasecmp(*(cpp+1), "body")) {			fil.fr_flags |= FR_LOGBODY;			cpp++;		}		if (!strcasecmp(*(cpp+1), "first")) {			fil.fr_flags |= FR_LOGFIRST;			cpp++;		}		if (*cpp && !strcasecmp(*(cpp+1), "or-block")) {			fil.fr_flags |= FR_LOGORBLOCK;			cpp++;		}		if (!strcasecmp(*(cpp+1), "level")) {			cpp++;			if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1)				return NULL;			cpp++;		}	} else {		/*		 * Doesn't start with one of the action words		 */		fprintf(stderr, "%d: unknown keyword (%s)\n", linenum, *cpp);		return NULL;	}	if (!*++cpp) {		fprintf(stderr, "%d: missing 'in'/'out' keyword\n", linenum);		return NULL;	}	if (!strcasecmp("in", *cpp))		fil.fr_flags |= FR_INQUE;	else if (!strcasecmp("out", *cpp)) {		fil.fr_flags |= FR_OUTQUE;		if (fil.fr_flags & FR_RETICMP) {			fprintf(stderr,				"%d: Can only use return-icmp with 'in'\n",				linenum);			return NULL;		} else if (fil.fr_flags & FR_RETRST) {			fprintf(stderr,				"%d: Can only use return-rst with 'in'\n", 				linenum);			return NULL;		}	}	if (!*++cpp) {		fprintf(stderr, "%d: missing source specification\n", linenum);		return NULL;	}	if (!strcasecmp("log", *cpp)) {		if (!*++cpp) {			fprintf(stderr, "%d: missing source specification\n",				linenum);			return NULL;		}		if (fil.fr_flags & FR_PASS)			fil.fr_flags |= FR_LOGP;		else if (fil.fr_flags & FR_BLOCK)			fil.fr_flags |= FR_LOGB;		if (*cpp && !strcasecmp(*cpp, "body")) {			fil.fr_flags |= FR_LOGBODY;			cpp++;		}		if (*cpp && !strcasecmp(*cpp, "first")) {			fil.fr_flags |= FR_LOGFIRST;			cpp++;		}		if (*cpp && !strcasecmp(*cpp, "or-block")) {			if (!(fil.fr_flags & FR_PASS)) {				fprintf(stderr,					"%d: or-block must be used with pass\n",					linenum);				return NULL;			}			fil.fr_flags |= FR_LOGORBLOCK;			cpp++;		}		if (*cpp && !strcasecmp(*cpp, "level")) {			if (loglevel(cpp, &fil.fr_loglevel, linenum) == -1)				return NULL;			cpp++;			cpp++;		}	}	if (*cpp && !strcasecmp("quick", *cpp)) {		cpp++;		fil.fr_flags |= FR_QUICK;	}	*fil.fr_ifname = '\0';	if (*cpp && !strcasecmp(*cpp, "on")) {		if (!*++cpp) {			fprintf(stderr, "%d: interface name missing\n",				linenum);			return NULL;		}		(void)strncpy(fil.fr_ifname, *cpp, IFNAMSIZ-1);		fil.fr_ifname[IFNAMSIZ-1] = '\0';		cpp++;		if (!*cpp) {			if ((fil.fr_flags & FR_RETMASK) == FR_RETRST) {				fprintf(stderr,					"%d: %s can only be used with TCP\n",					linenum, "return-rst");				return NULL;			}			return &fil;		}		if (*cpp) {			if (!strcasecmp(*cpp, "dup-to") && *(cpp + 1)) {				cpp++;				if (to_interface(&fil.fr_dif, *cpp, linenum))					return NULL;				cpp++;			}			if (*cpp && !strcasecmp(*cpp, "to") && *(cpp + 1)) {				cpp++;				if (to_interface(&fil.fr_tif, *cpp, linenum))					return NULL;				cpp++;			} else if (*cpp && !strcasecmp(*cpp, "fastroute")) {				if (!(fil.fr_flags & FR_INQUE)) {					fprintf(stderr,						"can only use %s with 'in'\n",						"fastroute");					return NULL;				}				fil.fr_flags |= FR_FASTROUTE;				cpp++;			}		}	}	if (*cpp && !strcasecmp(*cpp, "tos")) {		if (!*++cpp) {			fprintf(stderr, "%d: tos missing value\n", linenum);			return NULL;		}		fil.fr_tos = strtol(*cpp, NULL, 0);		fil.fr_mip.fi_tos = 0xff;		cpp++;	}	if (*cpp && !strcasecmp(*cpp, "ttl")) {		if (!*++cpp) {			fprintf(stderr, "%d: ttl missing hopcount value\n",				linenum);			return NULL;		}		if (ratoi(*cpp, &i, 0, 255))			fil.fr_ttl = i;		else {			fprintf(stderr, "%d: invalid ttl (%s)\n",				linenum, *cpp);			return NULL;		}		fil.fr_mip.fi_ttl = 0xff;		cpp++;	}	/*	 * check for "proto <protoname>" only decode udp/tcp/icmp as protoname	 */	proto = NULL;	if (*cpp && !strcasecmp(*cpp, "proto")) {		if (!*++cpp) {			fprintf(stderr, "%d: protocol name missing\n", linenum);			return NULL;		}		proto = *cpp++;		if (!strcasecmp(proto, "tcp/udp")) {			fil.fr_ip.fi_fl |= FI_TCPUDP;			fil.fr_mip.fi_fl |= FI_TCPUDP;		} else {			if (!(p = getprotobyname(proto)) && !isdigit(*proto)) {				fprintf(stderr,					"%d: unknown protocol (%s)\n",					linenum, proto);				return NULL;			}			if (p)				fil.fr_proto = p->p_proto;			else if (isdigit(*proto)) {				i = (int)strtol(proto, &endptr, 0);				if (*endptr != '\0' || i < 0 || i > 255) {					fprintf(stderr,						"%d: unknown protocol (%s)\n",						linenum, proto);					return NULL;						}				fil.fr_proto = i;			}			fil.fr_mip.fi_p = 0xff;		}	}	if ((fil.fr_proto != IPPROTO_TCP) &&	    ((fil.fr_flags & FR_RETMASK) == FR_RETRST)) {		fprintf(stderr, "%d: %s can only be used with TCP\n",			linenum, "return-rst");		return NULL;	}	/*	 * get the from host and bit mask to use against packets	 */	if (!*cpp) {		fprintf(stderr, "%d: missing source specification\n", linenum);		return NULL;	}	if (!strcasecmp(*cpp, "all")) {		cpp++;		if (!*cpp)			return &fil;	} else {		if (strcasecmp(*cpp, "from")) {			fprintf(stderr, "%d: unexpected keyword (%s) - from\n",				linenum, *cpp);			return NULL;		}		if (!*++cpp) {			fprintf(stderr, "%d: missing host after from\n",				linenum);			return NULL;		}		if (**cpp == '!') {			fil.fr_flags |= FR_NOTSRCIP;			(*cpp)++;		}		ch = 0;		if (hostmask(&cpp, (u_32_t *)&fil.fr_src,			     (u_32_t *)&fil.fr_smsk, &fil.fr_sport, &ch,			     &fil.fr_stop, linenum)) {			return NULL;		}		fil.fr_scmp = ch;		if (!*cpp) {			fprintf(stderr, "%d: missing to fields\n", linenum);			return NULL;		}		/*		 * do the same for the to field (destination host)		 */		if (strcasecmp(*cpp, "to")) {			fprintf(stderr, "%d: unexpected keyword (%s) - to\n",				linenum, *cpp);			return NULL;		}		if (!*++cpp) {			fprintf(stderr, "%d: missing host after to\n", linenum);			return NULL;		}		ch = 0;		if (**cpp == '!') {			fil.fr_flags |= FR_NOTDSTIP;			(*cpp)++;		}		if (hostmask(&cpp, (u_32_t *)&fil.fr_dst,			     (u_32_t *)&fil.fr_dmsk, &fil.fr_dport, &ch,			     &fil.fr_dtop, linenum)) {			return NULL;		}		fil.fr_dcmp = ch;	}	/*	 * check some sanity, make sure we don't have icmp checks with tcp	 * or udp or visa versa.	 */	if (fil.fr_proto && (fil.fr_dcmp || fil.fr_scmp) &&	    fil.fr_proto != IPPROTO_TCP && fil.fr_proto != IPPROTO_UDP) {		fprintf(stderr, "%d: port operation on non tcp/udp\n", linenum);		return NULL;	}	if (fil.fr_icmp && fil.fr_proto != IPPROTO_ICMP) {		fprintf(stderr, "%d: icmp comparisons on wrong protocol\n",			linenum);		return NULL;	}	if (!*cpp)		return &fil;	if (*cpp && !strcasecmp(*cpp, "flags")) {		if (!*++cpp) {			fprintf(stderr, "%d: no flags present\n", linenum);			return NULL;		}		fil.fr_tcpf = tcp_flags(*cpp, &fil.fr_tcpfm, linenum);		cpp++;	}	/*	 * extras...	 */	if ((fil.fr_v == 4) && *cpp && (!strcasecmp(*cpp, "with") ||	     !strcasecmp(*cpp, "and")))		if (extras(&cpp, &fil, linenum))			return NULL;	/*	 * icmp types for use with the icmp protocol	 */	if (*cpp && !strcasecmp(*cpp, "icmp-type")) {		if (fil.fr_proto != IPPROTO_ICMP) {			fprintf(stderr,				"%d: icmp with wrong protocol (%d)\n",				linenum, fil.fr_proto);			return NULL;		}		if (addicmp(&cpp, &fil, linenum))			return NULL;		fil.fr_icmp = htons(fil.fr_icmp);		fil.fr_icmpm = htons(fil.fr_icmpm);	}	/*	 * Keep something...	 */	while (*cpp && !strcasecmp(*cpp, "keep"))		if (addkeep(&cpp, &fil, linenum))			return NULL;	/*	 * head of a new group ?	 */	if (*cpp && !strcasecmp(*cpp, "head")) {		if (!*++cpp) {			fprintf(stderr, "%d: head without group #\n", linenum);			return NULL;		}		if (ratoui(*cpp, &k, 0, UINT_MAX))			fil.fr_grhead = (u_32_t)k;		else {			fprintf(stderr, "%d: invalid group (%s)\n",				linenum, *cpp);			return NULL;		}		cpp++;	}	/*	 * head of a new group ?	 */	if (*cpp && !strcasecmp(*cpp, "group")) {		if (!*++cpp) {			fprintf(stderr, "%d: group without group #\n",				linenum);			return NULL;		}		if (ratoui(*cpp, &k, 0, UINT_MAX))			fil.fr_group = k;		else {			fprintf(stderr, "%d: invalid group (%s)\n",				linenum, *cpp);			return NULL;		}		cpp++;	}	/*	 * leftovers...yuck	 */	if (*cpp && **cpp) {		fprintf(stderr, "%d: unknown words at end: [", linenum);		for (; *cpp; cpp++)			fprintf(stderr, "%s ", *cpp);		fprintf(stderr, "]\n");		return NULL;	}	/*	 * lazy users...	 */	if ((fil.fr_tcpf || fil.fr_tcpfm) && fil.fr_proto != IPPROTO_TCP) {		fprintf(stderr, "%d: TCP protocol not specified\n", linenum);		return NULL;	}	if (!(fil.fr_ip.fi_fl & FI_TCPUDP) && (fil.fr_proto != IPPROTO_TCP) &&	    (fil.fr_proto != IPPROTO_UDP) && (fil.fr_dcmp || fil.fr_scmp)) {		if (!fil.fr_proto) {			fil.fr_ip.fi_fl |= FI_TCPUDP;			fil.fr_mip.fi_fl |= FI_TCPUDP;		} else {			fprintf(stderr,				"%d: port comparisons for non-TCP/UDP\n",				linenum);			return NULL;		}	}/*	if ((fil.fr_flags & FR_KEEPFRAG) &&	    (!(fil.fr_ip.fi_fl & FI_FRAG) || !(fil.fr_ip.fi_fl & FI_FRAG))) {		fprintf(stderr,			"%d: must use 'with frags' with 'keep frags'\n",			linenum);		return NULL;	}*/	return &fil;}int loglevel(cpp, facpri, linenum)char **cpp;u_int *facpri;int linenum;{	int fac, pri;	char *s;	fac = 0;	pri = 0;	if (!*++cpp) {		fprintf(stderr, "%d: %s\n", linenum,			"missing identifier after level");		return -1;	}	s = index(*cpp, '.');	if (s) {		*s++ = '\0';		fac = fac_findname(*cpp);		if (fac == -1) {			fprintf(stderr, "%d: %s %s\n", linenum,				"Unknown facility", *cpp);			return -1;		}		pri = pri_findname(s);		if (pri == -1) {			fprintf(stderr, "%d: %s %s\n", linenum,				"Unknown priority", s);			return -1;		}	} else {		pri = pri_findname(*cpp);		if (pri == -1) {			fprintf(stderr, "%d: %s %s\n", linenum,				"Unknown priority", *cpp);			return -1;		}	}	*facpri = fac|pri;	return 0;}int to_interface(fdp, to, linenum)frdest_t *fdp;char *to;int linenum;{	char *s;	s = index(to, ':');	fdp->fd_ifp = NULL;	if (s) {		*s++ = '\0';		if (hostnum((u_32_t *)&fdp->fd_ip, s, linenum) == -1)			return -1;	}	(void) strncpy(fdp->fd_ifname, to, sizeof(fdp->fd_ifname) - 1);	fdp->fd_ifname[sizeof(fdp->fd_ifname) - 1] = '\0';	return 0;}void print_toif(tag, fdp)char *tag;frdest_t *fdp;{	printf("%s %s%s", tag, fdp->fd_ifname,		     (fdp->fd_ifp || (long)fdp->fd_ifp == -1) ? "" : "(!)");	if (fdp->fd_ip.s_addr)		printf(":%s", inet_ntoa(fdp->fd_ip));	putchar(' ');}/* * deal with extra bits on end of the line */int	extras(cp, fr, linenum)char	***cp;struct	frentry	*fr;int     linenum;{	u_short	secmsk;	u_long	opts;	int	notopt;	char	oflags;	opts = 0;	secmsk = 0;	notopt = 0;	(*cp)++;	if (!**cp)		return -1;	while (**cp && (!strncasecmp(**cp, "ipopt", 5) ||	       !strncasecmp(**cp, "not", 3) || !strncasecmp(**cp, "opt", 3) ||	       !strncasecmp(**cp, "frag", 4) || !strncasecmp(**cp, "no", 2) ||	       !strncasecmp(**cp, "short", 5))) {		if (***cp == 'n' || ***cp == 'N') {			notopt = 1;			(*cp)++;			continue;		} else if (***cp == 'i' || ***cp == 'I') {			if (!notopt)				fr->fr_ip.fi_fl |= FI_OPTIONS;			fr->fr_mip.fi_fl |= FI_OPTIONS;			goto nextopt;		} else if (***cp == 'f' || ***cp == 'F') {			if (!notopt)				fr->fr_ip.fi_fl |= FI_FRAG;			fr->fr_mip.fi_fl |= FI_FRAG;			goto nextopt;		} else if (***cp == 'o' || ***cp == 'O') {			if (!*(*cp + 1)) {				fprintf(stderr,					"%d: opt missing arguements\n",					linenum);				return -1;			}			(*cp)++;			if (!(opts = optname(cp, &secmsk, linenum)))				return -1;			oflags = FI_OPTIONS;		} else if (***cp == 's' || ***cp == 'S') {			if (fr->fr_tcpf) {				fprintf(stderr,				"%d: short cannot be used with TCP flags\n",					linenum);				return -1;			}			if (!notopt)				fr->fr_ip.fi_fl |= FI_SHORT;			fr->fr_mip.fi_fl |= FI_SHORT;			goto nextopt;		} else			return -1;		if (!notopt || !opts)			fr->fr_mip.fi_fl |= oflags;		if (notopt) {		  if (!secmsk) {				fr->fr_mip.fi_optmsk |= opts;		  } else {				fr->fr_mip.fi_optmsk |= (opts & ~0x0100);		  }		} else {				fr->fr_mip.fi_optmsk |= opts;		}		fr->fr_mip.fi_secmsk |= secmsk;		if (notopt) {			fr->fr_ip.fi_fl &= (~oflags & 0xf);			fr->fr_ip.fi_optmsk &= ~opts;			fr->fr_ip.fi_secmsk &= ~secmsk;		} else {			fr->fr_ip.fi_fl |= oflags;			fr->fr_ip.fi_optmsk |= opts;			fr->fr_ip.fi_secmsk |= secmsk;		}nextopt:		notopt = 0;		opts = 0;		oflags = 0;		secmsk = 0;		(*cp)++;	}	return 0;}u_32_t optname(cp, sp, linenum)char ***cp;u_short *sp;int linenum;{	struct ipopt_names *io, *so;	u_long msk = 0;	u_short smsk = 0;	char *s;	int sec = 0;	for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {		for (io = ionames; io->on_name; io++)			if (!strcasecmp(s, io->on_name)) {				msk |= io->on_bit;				break;			}		if (!io->on_name) {			fprintf(stderr, "%d: unknown IP option name %s\n",				linenum, s);			return 0;		}		if (!strcasecmp(s, "sec-class"))			sec = 1;	}	if (sec && !*(*cp + 1)) {		fprintf(stderr, "%d: missing security level after sec-class\n",			linenum);		return 0;	}	if (sec) {		(*cp)++;		for (s = strtok(**cp, ","); s; s = strtok(NULL, ",")) {			for (so = secclass; so->on_name; so++)				if (!strcasecmp(s, so->on_name)) {					smsk |= so->on_bit;					break;				}			if (!so->on_name) {				fprintf(stderr,					"%d: no such security level: %s\n",					linenum, s);				return 0;			}		}		if (smsk)			*sp = smsk;	}	return msk;}#ifdef __STDC__void optprint(u_short *sec, u_long optmsk, u_long optbits)#elsevoid optprint(sec, optmsk, optbits)u_short *sec;u_long optmsk, optbits;#endif{	u_short secmsk = sec[0], secbits = sec[1];	struct ipopt_names *io, *so;	char *s;	int secflag = 0;	s = " opt ";	for (io = ionames; io->on_name; io++)		if ((io->on_bit & optmsk) &&		    ((io->on_bit & optmsk) == (io->on_bit & optbits))) {			if ((io->on_value != IPOPT_SECURITY) ||			    (!secmsk && !secbits)) {				printf("%s%s", s, io->on_name);				if (io->on_value == IPOPT_SECURITY)					io++;				s = ",";			} else				secflag = 1;		}	if (secmsk & secbits) {		printf("%ssec-class", s);		s = " ";		for (so = secclass; so->on_name; so++)			if ((secmsk & so->on_bit) &&			    ((so->on_bit & secmsk) == (so->on_bit & secbits))) {				printf("%s%s", s, so->on_name);				s = ",";			}	}	if ((optmsk && (optmsk != optbits)) ||	    (secmsk && (secmsk != secbits))) {		s = " ";		printf(" not opt");		if (optmsk != optbits) {			for (io = ionames; io->on_name; io++)				if ((io->on_bit & optmsk) &&				    ((io->on_bit & optmsk) !=				     (io->on_bit & optbits))) {					if ((io->on_value != IPOPT_SECURITY) ||					    (!secmsk && !secbits)) {						printf("%s%s", s, io->on_name);						s = ",";						if (io->on_value ==						    IPOPT_SECURITY)							io++;					} else						io++;				}		}		if (secmsk != secbits) {			printf("%ssec-class", s);			s = " ";			for (so = secclass; so->on_name; so++)				if ((so->on_bit & secmsk) &&				    ((so->on_bit & secmsk) !=				     (so->on_bit & secbits))) {					printf("%s%s", s, so->on_name);					s = ",";				}		}	}}char	*icmptypes[] = {	"echorep", (char *)NULL, (char *)NULL, "unreach", "squench",	"redir", (char *)NULL, (char *)NULL, "echo", "routerad",	"routersol", "timex", "paramprob", "timest", "timestrep",	"inforeq", "inforep", "maskreq", "maskrep", "END"};/* * set the icmp field to the correct type if "icmp" word is found */int	addicmp(cp, fp, linenum)char	***cp;struct	frentry	*fp;int     linenum;{	char	**t;	int	i;	(*cp)++;	if (!**cp)		return -1;	if (!fp->fr_proto)	/* to catch lusers */		fp->fr_proto = IPPROTO_ICMP;	if (isdigit(***cp)) {		if (!ratoi(**cp, &i, 0, 255)) {			fprintf(stderr,				"%d: Invalid icmp-type (%s) specified\n",				linenum, **cp);			return -1;		}	} else {		for (t = icmptypes, i = 0; ; t++, i++) {			if (!*t)				continue;			if (!strcasecmp("END", *t)) {				i = -1;				break;			}			if (!strcasecmp(*t, **cp))				break;		}		if (i == -1) {			fprintf(stderr,				"%d: Invalid icmp-type (%s) specified\n",				linenum, **cp);			return -1;		}	}	fp->fr_icmp = (u_short)(i << 8);	fp->fr_icmpm = (u_short)0xff00;	(*cp)++;	if (!**cp)		return 0;	if (**cp && strcasecmp("code", **cp))		return 0;	(*cp)++;	if (isdigit(***cp)) {		if (!ratoi(**cp, &i, 0, 255)) {			fprintf(stderr, 				"%d: Invalid icmp code (%s) specified\n",				linenum, **cp);			return -1;		}	} else {		i = icmpcode(**cp);		if (i == -1) {			fprintf(stderr, 				"%d: Invalid icmp code (%s) specified\n",				linenum, **cp);			return -1;		}	}	i &= 0xff;	fp->fr_icmp |= (u_short)i;	fp->fr_icmpm = (u_short)0xffff;	(*cp)++;	return 0;}#define	MAX_ICMPCODE	15char	*icmpcodes[] = {	"net-unr", "host-unr", "proto-unr", "port-unr", "needfrag", "srcfail",	"net-unk", "host-unk", "isolate", "net-prohib", "host-prohib",	"net-tos", "host-tos", "filter-prohib", "host-preced", "preced-cutoff", 	NULL };/* * Return the number for the associated ICMP unreachable code. */int icmpcode(str)char *str;{	char	*s;	int	i, len;	if ((s = strrchr(str, ')')))		*s = '\0';	if (isdigit(*str)) {		if (!ratoi(str, &i, 0, 255))			return -1;		else			return i;	}	len = strlen(str);	for (i = 0; icmpcodes[i]; i++)		if (!strncasecmp(str, icmpcodes[i], MIN(len,				 strlen(icmpcodes[i])) ))			return i;	return -1;}/* * set the icmp field to the correct type if "icmp" word is found */int	addkeep(cp, fp, linenum)char	***cp;struct	frentry	*fp;int     linenum; {	if (fp->fr_proto != IPPROTO_TCP && fp->fr_proto != IPPROTO_UDP &&#ifdef	USE_INET6	    fp->fr_proto != IPPROTO_ICMPV6 &&#endif	    fp->fr_proto != IPPROTO_ICMP && !(fp->fr_ip.fi_fl & FI_TCPUDP)) {		fprintf(stderr, "%d: Can only use keep with UDP/ICMP/TCP\n",			linenum);		return -1;	}	(*cp)++;	if (!**cp) {		fprintf(stderr, "%d: Missing state/frag after keep\n",			linenum);		return -1;	}	if (strcasecmp(**cp, "state") && strcasecmp(**cp, "frags")) {		fprintf(stderr, "%d: Unrecognised state keyword \"%s\"\n",			linenum, **cp);		return -1;	}	if (***cp == 's' || ***cp == 'S')		fp->fr_flags |= FR_KEEPSTATE;	else if (***cp == 'f' || ***cp == 'F')		fp->fr_flags |= FR_KEEPFRAG;	(*cp)++;	return 0;}