diff --git a/sbin/ipf/common/genmask.c b/sbin/ipf/common/genmask.c index 5b715cf4c901..a3b912b67ef3 100644 --- a/sbin/ipf/common/genmask.c +++ b/sbin/ipf/common/genmask.c @@ -1,68 +1,66 @@ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id$ */ #include "ipf.h" -int genmask(family, msk, mskp) - int family; - char *msk; - i6addr_t *mskp; +int +genmask(int family, char *msk, i6addr_t *mskp) { char *endptr = 0L; u_32_t addr; int bits; if (strchr(msk, '.') || strchr(msk, 'x') || strchr(msk, ':')) { /* possibly of the form xxx.xxx.xxx.xxx * or 0xYYYYYYYY */ switch (family) { #ifdef USE_INET6 case AF_INET6 : if (inet_pton(AF_INET6, msk, &mskp->in4) != 1) return (-1); break; #endif case AF_INET : if (inet_aton(msk, &mskp->in4) == 0) return (-1); break; default : return (-1); /*NOTREACHED*/ } } else { /* * set x most significant bits */ bits = (int)strtol(msk, &endptr, 0); switch (family) { case AF_INET6 : if ((*endptr != '\0') || (bits < 0) || (bits > 128)) return (-1); fill6bits(bits, mskp->i6); break; case AF_INET : if (*endptr != '\0' || bits > 32 || bits < 0) return (-1); if (bits == 0) addr = 0; else addr = htonl(0xffffffff << (32 - bits)); mskp->in4.s_addr = addr; break; default : return (-1); /*NOTREACHED*/ } } return (0); } diff --git a/sbin/ipf/common/lexer.c b/sbin/ipf/common/lexer.c index 16fbb2272034..12ec3c825dd4 100644 --- a/sbin/ipf/common/lexer.c +++ b/sbin/ipf/common/lexer.c @@ -1,737 +1,736 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ #include #include "ipf.h" #ifdef IPFILTER_SCAN # include "netinet/ip_scan.h" #endif #include #include #ifdef TEST_LEXER # define NO_YACC union { int num; char *str; struct in_addr ipa; i6addr_t ip6; } yylval; #endif #include "lexer.h" #include "y.tab.h" FILE *yyin; #define ishex(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || \ ((c) >= 'A' && (c) <= 'F')) #define TOOLONG -3 extern int string_start; extern int string_end; extern char *string_val; extern int pos; extern int yydebug; char *yystr = NULL; int yytext[YYBUFSIZ+1]; char yychars[YYBUFSIZ+1]; int yylineNum = 1; int yypos = 0; int yylast = -1; int yydictfixed = 0; int yyexpectaddr = 0; int yybreakondot = 0; int yyvarnext = 0; int yytokentype = 0; wordtab_t *yywordtab = NULL; int yysavedepth = 0; wordtab_t *yysavewords[30]; static wordtab_t *yyfindkey(char *); static int yygetc(int); static void yyunputc(int); static int yyswallow(int); static char *yytexttostr(int, int); static void yystrtotext(char *); static char *yytexttochar(void); static int yygetc(int docont) { int c; if (yypos < yylast) { c = yytext[yypos++]; if (c == '\n') yylineNum++; return (c); } if (yypos == YYBUFSIZ) return (TOOLONG); if (pos >= string_start && pos <= string_end) { c = string_val[pos - string_start]; yypos++; } else { c = fgetc(yyin); if (docont && (c == '\\')) { c = fgetc(yyin); if (c == '\n') { yylineNum++; c = fgetc(yyin); } } } if (c == '\n') yylineNum++; yytext[yypos++] = c; yylast = yypos; yytext[yypos] = '\0'; return (c); } static void yyunputc(int c) { if (c == '\n') yylineNum--; yytext[--yypos] = c; } static int yyswallow(int last) { int c; while (((c = yygetc(0)) > '\0') && (c != last)) ; if (c != EOF) yyunputc(c); if (c == last) return (0); return (-1); } static char * yytexttochar(void) { int i; for (i = 0; i < yypos; i++) yychars[i] = (char)(yytext[i] & 0xff); yychars[i] = '\0'; return (yychars); } static void yystrtotext(char *str) { int len; char *s; len = strlen(str); if (len > YYBUFSIZ) len = YYBUFSIZ; for (s = str; *s != '\0' && len > 0; s++, len--) yytext[yylast++] = *s; yytext[yylast] = '\0'; } static char * yytexttostr(int offset, int max) { char *str; int i; if ((yytext[offset] == '\'' || yytext[offset] == '"') && (yytext[offset] == yytext[offset + max - 1])) { offset++; max--; } if (max > yylast) max = yylast; str = malloc(max + 1); if (str != NULL) { for (i = offset; i < max; i++) str[i - offset] = (char)(yytext[i] & 0xff); str[i - offset] = '\0'; } return (str); } int yylex(void) { static int prior = 0; static int priornum = 0; int c, n, isbuilding, rval, lnext, nokey = 0; char *name; int triedv6 = 0; isbuilding = 0; lnext = 0; rval = 0; if (yystr != NULL) { free(yystr); yystr = NULL; } nextchar: c = yygetc(0); if (yydebug > 1) printf("yygetc = (%x) %c [%*.*s]\n", c, c, yypos, yypos, yytexttochar()); switch (c) { case '\n' : lnext = 0; nokey = 0; case '\t' : case '\r' : case ' ' : if (isbuilding == 1) { yyunputc(c); goto done; } if (yylast > yypos) { bcopy(yytext + yypos, yytext, sizeof(yytext[0]) * (yylast - yypos + 1)); } yylast -= yypos; if (yyexpectaddr == 2) yyexpectaddr = 0; yypos = 0; lnext = 0; nokey = 0; goto nextchar; case '\\' : if (lnext == 0) { lnext = 1; if (yylast == yypos) { yylast--; yypos--; } else yypos--; if (yypos == 0) nokey = 1; goto nextchar; } break; } if (lnext == 1) { lnext = 0; if ((isbuilding == 0) && !ISALNUM(c)) { prior = c; return (c); } goto nextchar; } switch (c) { case '#' : if (isbuilding == 1) { yyunputc(c); goto done; } yyswallow('\n'); rval = YY_COMMENT; goto done; case '$' : if (isbuilding == 1) { yyunputc(c); goto done; } n = yygetc(0); if (n == '{') { if (yyswallow('}') == -1) { rval = -2; goto done; } (void) yygetc(0); } else { if (!ISALPHA(n)) { yyunputc(n); break; } do { n = yygetc(1); } while (ISALPHA(n) || ISDIGIT(n) || n == '_'); yyunputc(n); } name = yytexttostr(1, yypos); /* skip $ */ if (name != NULL) { string_val = get_variable(name, NULL, yylineNum); free(name); if (string_val != NULL) { name = yytexttostr(yypos, yylast); if (name != NULL) { yypos = 0; yylast = 0; yystrtotext(string_val); yystrtotext(name); free(string_val); free(name); goto nextchar; } free(string_val); } } break; case '\'': case '"' : if (isbuilding == 1) { goto done; } do { n = yygetc(1); if (n == EOF || n == TOOLONG) { rval = -2; goto done; } if (n == '\n') { yyunputc(' '); yypos++; } } while (n != c); rval = YY_STR; goto done; /* NOTREACHED */ case EOF : yylineNum = 1; yypos = 0; yylast = -1; yyexpectaddr = 0; yybreakondot = 0; yyvarnext = 0; yytokentype = 0; if (yydebug) fprintf(stderr, "reset at EOF\n"); prior = 0; return (0); } if (strchr("=,/;{}()@", c) != NULL) { if (isbuilding == 1) { yyunputc(c); goto done; } rval = c; goto done; } else if (c == '.') { if (isbuilding == 0) { rval = c; goto done; } if (yybreakondot != 0) { yyunputc(c); goto done; } } switch (c) { case '-' : n = yygetc(0); if (n == '>') { isbuilding = 1; goto done; } yyunputc(n); if (yyexpectaddr) { if (isbuilding == 1) yyunputc(c); else rval = '-'; goto done; } if (isbuilding == 1) break; rval = '-'; goto done; case '!' : if (isbuilding == 1) { yyunputc(c); goto done; } n = yygetc(0); if (n == '=') { rval = YY_CMP_NE; goto done; } yyunputc(n); rval = '!'; goto done; case '<' : if (yyexpectaddr) break; if (isbuilding == 1) { yyunputc(c); goto done; } n = yygetc(0); if (n == '=') { rval = YY_CMP_LE; goto done; } if (n == '>') { rval = YY_RANGE_OUT; goto done; } yyunputc(n); rval = YY_CMP_LT; goto done; case '>' : if (yyexpectaddr) break; if (isbuilding == 1) { yyunputc(c); goto done; } n = yygetc(0); if (n == '=') { rval = YY_CMP_GE; goto done; } if (n == '<') { rval = YY_RANGE_IN; goto done; } yyunputc(n); rval = YY_CMP_GT; goto done; } /* * Now for the reason this is here...IPv6 address parsing. * The longest string we can expect is of this form: * 0000:0000:0000:0000:0000:0000:000.000.000.000 * not: * 0000:0000:0000:0000:0000:0000:0000:0000 */ #ifdef USE_INET6 if (yyexpectaddr != 0 && isbuilding == 0 && (ishex(c) || isdigit(c) || c == ':')) { char ipv6buf[45 + 1], *s, oc; int start; buildipv6: start = yypos; s = ipv6buf; oc = c; if (prior == YY_NUMBER && c == ':') { snprintf(s, sizeof(s), "%d", priornum); s += strlen(s); } /* * Perhaps we should implement stricter controls on what we * swallow up here, but surely it would just be duplicating * the code in inet_pton() anyway. */ do { *s++ = c; c = yygetc(1); } while ((ishex(c) || c == ':' || c == '.') && (s - ipv6buf < 46)); yyunputc(c); *s = '\0'; if (inet_pton(AF_INET6, ipv6buf, &yylval.ip6) == 1) { rval = YY_IPV6; yyexpectaddr = 0; goto done; } yypos = start; c = oc; } #endif if ((c == ':') && (rval != YY_IPV6) && (triedv6 == 0)) { #ifdef USE_INET6 yystr = yytexttostr(0, yypos - 1); if (yystr != NULL) { char *s; for (s = yystr; *s && ishex(*s); s++) ; if (!*s && *yystr) { isbuilding = 0; c = *yystr; free(yystr); triedv6 = 1; yypos = 1; goto buildipv6; } free(yystr); } #endif if (isbuilding == 1) { yyunputc(c); goto done; } rval = ':'; goto done; } if (isbuilding == 0 && c == '0') { n = yygetc(0); if (n == 'x') { do { n = yygetc(1); } while (ishex(n)); yyunputc(n); rval = YY_HEX; goto done; } yyunputc(n); } /* * No negative numbers with leading - sign.. */ if (isbuilding == 0 && ISDIGIT(c)) { do { n = yygetc(1); } while (ISDIGIT(n)); yyunputc(n); rval = YY_NUMBER; goto done; } isbuilding = 1; goto nextchar; done: yystr = yytexttostr(0, yypos); if (yydebug) printf("isbuilding %d yyvarnext %d nokey %d fixed %d addr %d\n", isbuilding, yyvarnext, nokey, yydictfixed, yyexpectaddr); if (isbuilding == 1) { wordtab_t *w; w = NULL; isbuilding = 0; if ((yyvarnext == 0) && (nokey == 0)) { w = yyfindkey(yystr); if (w == NULL && yywordtab != NULL && !yydictfixed) { yyresetdict(); w = yyfindkey(yystr); } } else yyvarnext = 0; if (w != NULL) rval = w->w_value; else rval = YY_STR; } if (rval == YY_STR) { if (yysavedepth > 0 && !yydictfixed) yyresetdict(); if (yyexpectaddr != 0) yyexpectaddr = 0; } yytokentype = rval; if (yydebug) printf("lexed(%s) %d,%d,%d [%d,%d,%d] => %d @%d\n", yystr, isbuilding, yyexpectaddr, yysavedepth, string_start, string_end, pos, rval, yysavedepth); switch (rval) { case YY_NUMBER : sscanf(yystr, "%u", &yylval.num); break; case YY_HEX : sscanf(yystr, "0x%x", (u_int *)&yylval.num); break; case YY_STR : yylval.str = strdup(yystr); break; default : break; } if (yylast > 0) { bcopy(yytext + yypos, yytext, sizeof(yytext[0]) * (yylast - yypos + 1)); yylast -= yypos; yypos = 0; } if (rval == YY_NUMBER) priornum = yylval.num; prior = rval; return (rval); } -static wordtab_t *yyfindkey(key) - char *key; +static wordtab_t *yyfindkey(char *key) { wordtab_t *w; if (yywordtab == NULL) return (NULL); for (w = yywordtab; w->w_word != 0; w++) if (strcasecmp(key, w->w_word) == 0) return (w); return (NULL); } char * yykeytostr(int num) { wordtab_t *w; if (yywordtab == NULL) return (""); for (w = yywordtab; w->w_word; w++) if (w->w_value == num) return (w->w_word); return (""); } wordtab_t * yysettab(wordtab_t *words) { wordtab_t *save; save = yywordtab; yywordtab = words; return (save); } void yyerror(char *msg) { char *txt, letter[2]; int freetxt = 0; if (yytokentype < 256) { letter[0] = yytokentype; letter[1] = '\0'; txt = letter; } else if (yytokentype == YY_STR || yytokentype == YY_HEX || yytokentype == YY_NUMBER) { if (yystr == NULL) { txt = yytexttostr(yypos, YYBUFSIZ); freetxt = 1; } else txt = yystr; } else { txt = yykeytostr(yytokentype); } fprintf(stderr, "%s error at \"%s\", line %d\n", msg, txt, yylineNum); if (freetxt == 1) free(txt); exit(1); } void yysetfixeddict(wordtab_t *newdict) { if (yydebug) printf("yysetfixeddict(%lx)\n", (u_long)newdict); if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { fprintf(stderr, "%d: at maximum dictionary depth\n", yylineNum); return; } yysavewords[yysavedepth++] = yysettab(newdict); if (yydebug) printf("yysavedepth++ => %d\n", yysavedepth); yydictfixed = 1; } void yysetdict(wordtab_t *newdict) { if (yydebug) printf("yysetdict(%lx)\n", (u_long)newdict); if (yysavedepth == sizeof(yysavewords)/sizeof(yysavewords[0])) { fprintf(stderr, "%d: at maximum dictionary depth\n", yylineNum); return; } yysavewords[yysavedepth++] = yysettab(newdict); if (yydebug) printf("yysavedepth++ => %d\n", yysavedepth); } void yyresetdict(void) { if (yydebug) printf("yyresetdict(%d)\n", yysavedepth); if (yysavedepth > 0) { yysettab(yysavewords[--yysavedepth]); if (yydebug) printf("yysavedepth-- => %d\n", yysavedepth); } yydictfixed = 0; } #ifdef TEST_LEXER int main(int argc, char *argv[]) { int n; yyin = stdin; while ((n = yylex()) != 0) printf("%d.n = %d [%s] %d %d\n", yylineNum, n, yystr, yypos, yylast); } #endif diff --git a/sbin/ipf/ipf/bpf_filter.c b/sbin/ipf/ipf/bpf_filter.c index fbb0138f51d8..64d416feaf36 100644 --- a/sbin/ipf/ipf/bpf_filter.c +++ b/sbin/ipf/ipf/bpf_filter.c @@ -1,595 +1,585 @@ /* $FreeBSD$ */ /*- * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * This code is derived from the Stanford/CMU enet packet filter, * (net/enet.c) distributed as part of 4.3BSD, and code contributed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence * Berkeley Laboratory. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)bpf.c 7.5 (Berkeley) 7/15/91 */ #if !(defined(lint) || defined(KERNEL) || defined(_KERNEL)) static const char rcsid[] = "@(#) $Header: /devel/CVS/IP-Filter/bpf_filter.c,v 2.2.2.3 2006/10/03 11:25:56 darrenr Exp $ (LBL)"; #endif #include #include #include #include #include #include #include "netinet/ip_compat.h" #include "bpf-ipf.h" #if (defined(__hpux) || SOLARIS) && (defined(_KERNEL) || defined(KERNEL)) # include # include #endif #include "pcap-ipf.h" #if !defined(KERNEL) && !defined(_KERNEL) #include #endif #define int32 bpf_int32 #define u_int32 bpf_u_int32 static int m_xword(mb_t *, int, int *); static int m_xhalf(mb_t *, int, int *); #ifndef LBL_ALIGN /* * XXX - IA-64? If not, this probably won't work on Win64 IA-64 * systems, unless LBL_ALIGN is defined elsewhere for them. * XXX - SuperH? If not, this probably won't work on WinCE SuperH * systems, unless LBL_ALIGN is defined elsewhere for them. */ #if defined(sparc) || defined(__sparc__) || defined(mips) || \ defined(ibm032) || defined(__alpha) || defined(__hpux) || \ defined(__arm__) #define LBL_ALIGN #endif #endif #ifndef LBL_ALIGN #define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p)) #define EXTRACT_LONG(p) (ntohl(*(u_int32 *)p)) #else #define EXTRACT_SHORT(p)\ ((u_short)\ ((u_short)*((u_char *)p+0)<<8|\ (u_short)*((u_char *)p+1)<<0)) #define EXTRACT_LONG(p)\ ((u_int32)*((u_char *)p+0)<<24|\ (u_int32)*((u_char *)p+1)<<16|\ (u_int32)*((u_char *)p+2)<<8|\ (u_int32)*((u_char *)p+3)<<0) #endif #define MINDEX(len, _m, _k) \ { \ len = M_LEN(m); \ while ((_k) >= len) { \ (_k) -= len; \ (_m) = (_m)->m_next; \ if ((_m) == 0) \ return (0); \ len = M_LEN(m); \ } \ } static int -m_xword(m, k, err) - register mb_t *m; - register int k, *err; +m_xword(mb_t *m, int k, int *err) { register int len; register u_char *cp, *np; register mb_t *m0; MINDEX(len, m, k); cp = MTOD(m, u_char *) + k; if (len - k >= 4) { *err = 0; return (EXTRACT_LONG(cp)); } m0 = m->m_next; if (m0 == NULL || M_LEN(m0) + len - k < 4) goto bad; *err = 0; np = MTOD(m0, u_char *); switch (len - k) { case 1: return (cp[0] << 24) | (np[0] << 16) | (np[1] << 8) | np[2]; case 2: return (cp[0] << 24) | (cp[1] << 16) | (np[0] << 8) | np[1]; default: return (cp[0] << 24) | (cp[1] << 16) | (cp[2] << 8) | np[0]; } bad: *err = 1; return (0); } static int -m_xhalf(m, k, err) - register mb_t *m; - register int k, *err; +m_xhalf(mb_t *m, int k, int *err) { register int len; register u_char *cp; register mb_t *m0; MINDEX(len, m, k); cp = MTOD(m, u_char *) + k; if (len - k >= 2) { *err = 0; return (EXTRACT_SHORT(cp)); } m0 = m->m_next; if (m0 == NULL) goto bad; *err = 0; return (cp[0] << 8) | MTOD(m0, u_char *)[0]; bad: *err = 1; return (0); } /* * Execute the filter program starting at pc on the packet p * wirelen is the length of the original packet * buflen is the amount of data present * For the kernel, p is assumed to be a pointer to an mbuf if buflen is 0, * in all other cases, p is a pointer to a buffer and buflen is its size. */ u_int -bpf_filter(pc, p, wirelen, buflen) - register struct bpf_insn *pc; - register u_char *p; - u_int wirelen; - register u_int buflen; +bpf_filter(struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) { register u_int32 A, X; register int k; int32 mem[BPF_MEMWORDS]; mb_t *m, *n; int merr = 0; /* XXX: GCC */ int len; if (buflen == 0) { m = (mb_t *)p; p = MTOD(m, u_char *); buflen = M_LEN(m); } else m = NULL; if (pc == NULL) /* * No filter means accept all. */ return (u_int)-1; A = 0; X = 0; --pc; while (1) { ++pc; switch (pc->code) { default: return (0); case BPF_RET|BPF_K: return (u_int)pc->k; case BPF_RET|BPF_A: return (u_int)A; case BPF_LD|BPF_W|BPF_ABS: k = pc->k; if (k + sizeof(int32) > buflen) { if (m == NULL) return (0); A = m_xword(m, k, &merr); if (merr != 0) return (0); continue; } A = EXTRACT_LONG(&p[k]); continue; case BPF_LD|BPF_H|BPF_ABS: k = pc->k; if (k + sizeof(short) > buflen) { if (m == NULL) return (0); A = m_xhalf(m, k, &merr); if (merr != 0) return (0); continue; } A = EXTRACT_SHORT(&p[k]); continue; case BPF_LD|BPF_B|BPF_ABS: k = pc->k; if (k >= buflen) { if (m == NULL) return (0); n = m; MINDEX(len, n, k); A = MTOD(n, u_char *)[k]; continue; } A = p[k]; continue; case BPF_LD|BPF_W|BPF_LEN: A = wirelen; continue; case BPF_LDX|BPF_W|BPF_LEN: X = wirelen; continue; case BPF_LD|BPF_W|BPF_IND: k = X + pc->k; if (k + sizeof(int32) > buflen) { if (m == NULL) return (0); A = m_xword(m, k, &merr); if (merr != 0) return (0); continue; } A = EXTRACT_LONG(&p[k]); continue; case BPF_LD|BPF_H|BPF_IND: k = X + pc->k; if (k + sizeof(short) > buflen) { if (m == NULL) return (0); A = m_xhalf(m, k, &merr); if (merr != 0) return (0); continue; } A = EXTRACT_SHORT(&p[k]); continue; case BPF_LD|BPF_B|BPF_IND: k = X + pc->k; if (k >= buflen) { if (m == NULL) return (0); n = m; MINDEX(len, n, k); A = MTOD(n, u_char *)[k]; continue; } A = p[k]; continue; case BPF_LDX|BPF_MSH|BPF_B: k = pc->k; if (k >= buflen) { if (m == NULL) return (0); n = m; MINDEX(len, n, k); X = (MTOD(n, char *)[k] & 0xf) << 2; continue; } X = (p[pc->k] & 0xf) << 2; continue; case BPF_LD|BPF_IMM: A = pc->k; continue; case BPF_LDX|BPF_IMM: X = pc->k; continue; case BPF_LD|BPF_MEM: A = mem[pc->k]; continue; case BPF_LDX|BPF_MEM: X = mem[pc->k]; continue; case BPF_ST: mem[pc->k] = A; continue; case BPF_STX: mem[pc->k] = X; continue; case BPF_JMP|BPF_JA: pc += pc->k; continue; case BPF_JMP|BPF_JGT|BPF_K: pc += (A > pc->k) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JGE|BPF_K: pc += (A >= pc->k) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JEQ|BPF_K: pc += (A == pc->k) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JSET|BPF_K: pc += (A & pc->k) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JGT|BPF_X: pc += (A > X) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JGE|BPF_X: pc += (A >= X) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JEQ|BPF_X: pc += (A == X) ? pc->jt : pc->jf; continue; case BPF_JMP|BPF_JSET|BPF_X: pc += (A & X) ? pc->jt : pc->jf; continue; case BPF_ALU|BPF_ADD|BPF_X: A += X; continue; case BPF_ALU|BPF_SUB|BPF_X: A -= X; continue; case BPF_ALU|BPF_MUL|BPF_X: A *= X; continue; case BPF_ALU|BPF_DIV|BPF_X: if (X == 0) return (0); A /= X; continue; case BPF_ALU|BPF_AND|BPF_X: A &= X; continue; case BPF_ALU|BPF_OR|BPF_X: A |= X; continue; case BPF_ALU|BPF_LSH|BPF_X: A <<= X; continue; case BPF_ALU|BPF_RSH|BPF_X: A >>= X; continue; case BPF_ALU|BPF_ADD|BPF_K: A += pc->k; continue; case BPF_ALU|BPF_SUB|BPF_K: A -= pc->k; continue; case BPF_ALU|BPF_MUL|BPF_K: A *= pc->k; continue; case BPF_ALU|BPF_DIV|BPF_K: A /= pc->k; continue; case BPF_ALU|BPF_AND|BPF_K: A &= pc->k; continue; case BPF_ALU|BPF_OR|BPF_K: A |= pc->k; continue; case BPF_ALU|BPF_LSH|BPF_K: A <<= pc->k; continue; case BPF_ALU|BPF_RSH|BPF_K: A >>= pc->k; continue; case BPF_ALU|BPF_NEG: A = -A; continue; case BPF_MISC|BPF_TAX: X = A; continue; case BPF_MISC|BPF_TXA: A = X; continue; } } } /* * Return true if the 'fcode' is a valid filter program. * The constraints are that each jump be forward and to a valid * code, that memory accesses are within valid ranges (to the * extent that this can be checked statically; loads of packet * data have to be, and are, also checked at run time), and that * the code terminates with either an accept or reject. * * The kernel needs to be able to verify an application's filter code. * Otherwise, a bogus program could easily crash the system. */ int -bpf_validate(f, len) - struct bpf_insn *f; - int len; +bpf_validate(struct bpf_insn *f, int len) { u_int i, from; const struct bpf_insn *p; if (len == 0) return (1); if (len < 1 || len > BPF_MAXINSNS) return (0); for (i = 0; i < len; ++i) { p = &f[i]; switch (BPF_CLASS(p->code)) { /* * Check that memory operations use valid addresses. */ case BPF_LD: case BPF_LDX: switch (BPF_MODE(p->code)) { case BPF_IMM: break; case BPF_ABS: case BPF_IND: case BPF_MSH: /* * More strict check with actual packet length * is done runtime. */ #if 0 if (p->k >= bpf_maxbufsize) return (0); #endif break; case BPF_MEM: if (p->k >= BPF_MEMWORDS) return (0); break; case BPF_LEN: break; default: return (0); } break; case BPF_ST: case BPF_STX: if (p->k >= BPF_MEMWORDS) return (0); break; case BPF_ALU: switch (BPF_OP(p->code)) { case BPF_ADD: case BPF_SUB: case BPF_OR: case BPF_AND: case BPF_LSH: case BPF_RSH: case BPF_NEG: break; case BPF_DIV: /* * Check for constant division by 0. */ if (BPF_RVAL(p->code) == BPF_K && p->k == 0) return (0); default: return (0); } break; case BPF_JMP: /* * Check that jumps are within the code block, * and that unconditional branches don't go * backwards as a result of an overflow. * Unconditional branches have a 32-bit offset, * so they could overflow; we check to make * sure they don't. Conditional branches have * an 8-bit offset, and the from address is <= * BPF_MAXINSNS, and we assume that BPF_MAXINSNS * is sufficiently small that adding 255 to it * won't overflow. * * We know that len is <= BPF_MAXINSNS, and we * assume that BPF_MAXINSNS is < the maximum size * of a u_int, so that i + 1 doesn't overflow. */ from = i + 1; switch (BPF_OP(p->code)) { case BPF_JA: if (from + p->k < from || from + p->k >= len) return (0); break; case BPF_JEQ: case BPF_JGT: case BPF_JGE: case BPF_JSET: if (from + p->jt >= len || from + p->jf >= len) return (0); break; default: return (0); } break; case BPF_RET: break; case BPF_MISC: break; default: return (0); } } return (BPF_CLASS(f[len - 1].code) == BPF_RET); } diff --git a/sbin/ipf/ipfstat/ipfstat.c b/sbin/ipf/ipfstat/ipfstat.c index 11b3043f919c..55c876724d4a 100644 --- a/sbin/ipf/ipfstat/ipfstat.c +++ b/sbin/ipf/ipfstat/ipfstat.c @@ -1,2316 +1,2315 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ #include #include #include # include #include #if defined(sun) && defined(__SVR4) # include #endif #include "ipf.h" #include "netinet/ipl.h" #if defined(STATETOP) # if defined(sun) && defined(__SVR4) # include # endif # include # include # include # include # include # if SOLARIS || defined(__NetBSD__) # ifdef ERR # undef ERR # endif # include # else /* SOLARIS */ # include # endif /* SOLARIS */ #endif /* STATETOP */ #include "kmem.h" #if defined(__NetBSD__) # include #endif #if !defined(lint) static const char sccsid[] = "@(#)fils.c 1.21 4/20/96 (C) 1993-2000 Darren Reed"; static const char rcsid[] = "@(#)$Id$"; #endif extern char *optarg; extern int optind; extern int opterr; #define PRINTF (void)printf #define FPRINTF (void)fprintf static char *filters[4] = { "ipfilter(in)", "ipfilter(out)", "ipacct(in)", "ipacct(out)" }; static int state_logging = -1; static wordtab_t *state_fields = NULL; int nohdrfields = 0; int opts = 0; #ifdef USE_INET6 int use_inet4 = 0; int use_inet6 = 0; #endif int live_kernel = 1; int state_fd = -1; int ipf_fd = -1; int auth_fd = -1; int nat_fd = -1; frgroup_t *grtop = NULL; frgroup_t *grtail = NULL; char *blockreasons[FRB_MAX_VALUE + 1] = { "packet blocked", "log rule failure", "pps rate exceeded", "jumbogram", "makefrip failed", "cannot add state", "IP ID update failed", "log-or-block failed", "decapsulate failure", "cannot create new auth entry", "packet queued for auth", "buffer coalesce failure", "buffer pullup failure", "auth feedback", "bad fragment", "IPv4 NAT failure", "IPv6 NAT failure" }; #ifdef STATETOP #define STSTRSIZE 80 #define STGROWSIZE 16 #define HOSTNMLEN 40 #define STSORT_PR 0 #define STSORT_PKTS 1 #define STSORT_BYTES 2 #define STSORT_TTL 3 #define STSORT_SRCIP 4 #define STSORT_SRCPT 5 #define STSORT_DSTIP 6 #define STSORT_DSTPT 7 #define STSORT_MAX STSORT_DSTPT #define STSORT_DEFAULT STSORT_BYTES typedef struct statetop { i6addr_t st_src; i6addr_t st_dst; u_short st_sport; u_short st_dport; u_char st_p; u_char st_v; u_char st_state[2]; U_QUAD_T st_pkts; U_QUAD_T st_bytes; u_long st_age; } statetop_t; #endif int main(int, char *[]); static int fetchfrag(int, int, ipfr_t *); static void showstats(friostat_t *, u_32_t); static void showfrstates(ipfrstat_t *, u_long); static void showlist(friostat_t *); static void showstatestats(ips_stat_t *); static void showipstates(ips_stat_t *, int *); static void showauthstates(ipf_authstat_t *); static void showtqtable_live(int); static void showgroups(friostat_t *); static void usage(char *); static int state_matcharray(ipstate_t *, int *); static int printlivelist(friostat_t *, int, int, frentry_t *, char *, char *); static void printdeadlist(friostat_t *, int, int, frentry_t *, char *, char *); static void printside(char *, ipf_statistics_t *); static void parse_ipportstr(const char *, i6addr_t *, int *); static void ipfstate_live(char *, friostat_t **, ips_stat_t **, ipfrstat_t **, ipf_authstat_t **, u_32_t *); static void ipfstate_dead(char *, friostat_t **, ips_stat_t **, ipfrstat_t **, ipf_authstat_t **, u_32_t *); static ipstate_t *fetchstate(ipstate_t *, ipstate_t *); #ifdef STATETOP static void topipstates(i6addr_t, i6addr_t, int, int, int, int, int, int, int *); static void sig_break(int); static void sig_resize(int); static char *getip(int, i6addr_t *); static char *ttl_to_string(long); static int sort_p(const void *, const void *); static int sort_pkts(const void *, const void *); static int sort_bytes(const void *, const void *); static int sort_ttl(const void *, const void *); static int sort_srcip(const void *, const void *); static int sort_srcpt(const void *, const void *); static int sort_dstip(const void *, const void *); static int sort_dstpt(const void *, const void *); #endif -static void usage(name) - char *name; +static void usage(char *name) { #ifdef USE_INET6 fprintf(stderr, "Usage: %s [-46aAdfghIilnoRsv]\n", name); #else fprintf(stderr, "Usage: %s [-4aAdfghIilnoRsv]\n", name); #endif fprintf(stderr, " %s [-M corefile] [-N symbol-list]\n", name); #ifdef STATETOP #ifdef USE_INET6 fprintf(stderr, " %s -t [-46C] ", name); #else fprintf(stderr, " %s -t [-4C] ", name); #endif #endif fprintf(stderr, "[-D destination address] [-P protocol] [-S source address] [-T refresh time]\n"); exit(1); } int main(int argc, char *argv[]) { ipf_authstat_t frauthst; ipf_authstat_t *frauthstp = &frauthst; friostat_t fio; friostat_t *fiop = &fio; ips_stat_t ipsst; ips_stat_t *ipsstp = &ipsst; ipfrstat_t ifrst; ipfrstat_t *ifrstp = &ifrst; char *options; char *kern = NULL; char *memf = NULL; int c; int myoptind; int *filter = NULL; int protocol = -1; /* -1 = wild card for any protocol */ int refreshtime = 1; /* default update time */ int sport = -1; /* -1 = wild card for any source port */ int dport = -1; /* -1 = wild card for any dest port */ int topclosed = 0; /* do not show closed tcp sessions */ i6addr_t saddr, daddr; u_32_t frf; #ifdef USE_INET6 options = "46aACdfghIilnostvD:m:M:N:O:P:RS:T:"; #else options = "4aACdfghIilnostvD:m:M:N:O:P:RS:T:"; #endif saddr.in4.s_addr = INADDR_ANY; /* default any v4 source addr */ daddr.in4.s_addr = INADDR_ANY; /* default any v4 dest addr */ #ifdef USE_INET6 saddr.in6 = in6addr_any; /* default any v6 source addr */ daddr.in6 = in6addr_any; /* default any v6 dest addr */ #endif /* Don't warn about invalid flags when we run getopt for the 1st time */ opterr = 0; /* * Parse these two arguments now lest there be any buffer overflows * in the parsing of the rest. */ myoptind = optind; while ((c = getopt(argc, argv, options)) != -1) { switch (c) { case 'M' : memf = optarg; live_kernel = 0; break; case 'N' : kern = optarg; live_kernel = 0; break; } } optind = myoptind; if (live_kernel == 1) { if ((state_fd = open(IPSTATE_NAME, O_RDONLY)) == -1) { perror("open(IPSTATE_NAME)"); exit(-1); } if ((auth_fd = open(IPAUTH_NAME, O_RDONLY)) == -1) { perror("open(IPAUTH_NAME)"); exit(-1); } if ((nat_fd = open(IPNAT_NAME, O_RDONLY)) == -1) { perror("open(IPAUTH_NAME)"); exit(-1); } if ((ipf_fd = open(IPL_NAME, O_RDONLY)) == -1) { fprintf(stderr, "open(%s)", IPL_NAME); perror(""); exit(-1); } } if (kern != NULL || memf != NULL) { (void)setgid(getgid()); (void)setuid(getuid()); } if (live_kernel == 1) { (void) checkrev(IPL_NAME); } else { if (openkmem(kern, memf) == -1) exit(-1); } (void)setgid(getgid()); (void)setuid(getuid()); opterr = 1; while ((c = getopt(argc, argv, options)) != -1) { switch (c) { #ifdef USE_INET6 case '4' : use_inet4 = 1; break; case '6' : use_inet6 = 1; break; #endif case 'a' : opts |= OPT_ACCNT|OPT_SHOWLIST; break; case 'A' : opts |= OPT_AUTHSTATS; break; case 'C' : topclosed = 1; break; case 'd' : opts |= OPT_DEBUG; break; case 'D' : parse_ipportstr(optarg, &daddr, &dport); break; case 'f' : opts |= OPT_FRSTATES; break; case 'g' : opts |= OPT_GROUPS; break; case 'h' : opts |= OPT_HITS; break; case 'i' : opts |= OPT_INQUE|OPT_SHOWLIST; break; case 'I' : opts |= OPT_INACTIVE; break; case 'l' : opts |= OPT_SHOWLIST; break; case 'm' : filter = parseipfexpr(optarg, NULL); if (filter == NULL) { fprintf(stderr, "Error parseing '%s'\n", optarg); exit(1); } break; case 'M' : break; case 'N' : break; case 'n' : opts |= OPT_SHOWLINENO; break; case 'o' : opts |= OPT_OUTQUE|OPT_SHOWLIST; break; case 'O' : state_fields = parsefields(statefields, optarg); break; case 'P' : protocol = getproto(optarg); if (protocol == -1) { fprintf(stderr, "%s: Invalid protocol: %s\n", argv[0], optarg); exit(-2); } break; case 'R' : opts |= OPT_NORESOLVE; break; case 's' : opts |= OPT_IPSTATES; break; case 'S' : parse_ipportstr(optarg, &saddr, &sport); break; case 't' : #ifdef STATETOP opts |= OPT_STATETOP; break; #else fprintf(stderr, "%s: state top facility not compiled in\n", argv[0]); exit(-2); #endif case 'T' : if (!sscanf(optarg, "%d", &refreshtime) || (refreshtime <= 0)) { fprintf(stderr, "%s: Invalid refreshtime < 1 : %s\n", argv[0], optarg); exit(-2); } break; case 'v' : opts |= OPT_VERBOSE; break; default : usage(argv[0]); break; } } #ifdef USE_INET6 if ((use_inet4 || use_inet6) && !(opts & (OPT_INQUE | OPT_OUTQUE | OPT_STATETOP))) { #ifdef STATETOP FPRINTF(stderr, "No -i, -o, or -t given with -4 or -6\n"); #else FPRINTF(stderr, "No -i or -o given with -4 or -6\n"); #endif exit(-2); } if (use_inet4 == 0 && use_inet6 == 0) use_inet4 = use_inet6 = 1; #endif if (live_kernel == 1) { bzero((char *)&fio, sizeof(fio)); bzero((char *)&ipsst, sizeof(ipsst)); bzero((char *)&ifrst, sizeof(ifrst)); ipfstate_live(IPL_NAME, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); } else { ipfstate_dead(kern, &fiop, &ipsstp, &ifrstp, &frauthstp, &frf); } if (opts & OPT_IPSTATES) { showipstates(ipsstp, filter); } else if (opts & OPT_SHOWLIST) { showlist(fiop); if ((opts & OPT_OUTQUE) && (opts & OPT_INQUE)){ opts &= ~OPT_OUTQUE; showlist(fiop); } } else if (opts & OPT_FRSTATES) showfrstates(ifrstp, fiop->f_ticks); #ifdef STATETOP else if (opts & OPT_STATETOP) topipstates(saddr, daddr, sport, dport, protocol, #ifdef USE_INET6 use_inet6 && use_inet4 ? 0 : use_inet6 && !use_inet4 ? 6 : 4, #else 4, #endif #endif refreshtime, topclosed, filter); else if (opts & OPT_AUTHSTATS) showauthstates(frauthstp); else if (opts & OPT_GROUPS) showgroups(fiop); else showstats(fiop, frf); return (0); } /* * Fill in the stats structures from the live kernel, using a combination * of ioctl's and copying directly from kernel memory. */ static void ipfstate_live(char *device, friostat_t **fiopp, ips_stat_t **ipsstpp, ipfrstat_t **ifrstpp, ipf_authstat_t **frauthstpp, u_32_t *frfp) { ipfobj_t ipfo; if (checkrev(device) == -1) { fprintf(stderr, "User/kernel version check failed\n"); exit(1); } if ((opts & OPT_AUTHSTATS) == 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_type = IPFOBJ_IPFSTAT; ipfo.ipfo_size = sizeof(friostat_t); ipfo.ipfo_ptr = (void *)*fiopp; if (ioctl(ipf_fd, SIOCGETFS, &ipfo) == -1) { ipferror(ipf_fd, "ioctl(ipf:SIOCGETFS)"); exit(-1); } if (ioctl(ipf_fd, SIOCGETFF, frfp) == -1) ipferror(ipf_fd, "ioctl(SIOCGETFF)"); } if ((opts & OPT_IPSTATES) != 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_type = IPFOBJ_STATESTAT; ipfo.ipfo_size = sizeof(ips_stat_t); ipfo.ipfo_ptr = (void *)*ipsstpp; if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { ipferror(state_fd, "ioctl(state:SIOCGETFS)"); exit(-1); } if (ioctl(state_fd, SIOCGETLG, &state_logging) == -1) { ipferror(state_fd, "ioctl(state:SIOCGETLG)"); exit(-1); } } if ((opts & OPT_FRSTATES) != 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_type = IPFOBJ_FRAGSTAT; ipfo.ipfo_size = sizeof(ipfrstat_t); ipfo.ipfo_ptr = (void *)*ifrstpp; if (ioctl(ipf_fd, SIOCGFRST, &ipfo) == -1) { ipferror(ipf_fd, "ioctl(SIOCGFRST)"); exit(-1); } } if (opts & OPT_DEBUG) PRINTF("opts %#x name %s\n", opts, device); if ((opts & OPT_AUTHSTATS) != 0) { bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_type = IPFOBJ_AUTHSTAT; ipfo.ipfo_size = sizeof(ipf_authstat_t); ipfo.ipfo_ptr = (void *)*frauthstpp; if (ioctl(auth_fd, SIOCATHST, &ipfo) == -1) { ipferror(auth_fd, "ioctl(SIOCATHST)"); exit(-1); } } } /* * Build up the stats structures from data held in the "core" memory. * This is mainly useful when looking at data in crash dumps and ioctl's * just won't work any more. */ static void ipfstate_dead( char *kernel, friostat_t **fiopp, ips_stat_t **ipsstpp, ipfrstat_t **ifrstpp, ipf_authstat_t **frauthstpp, u_32_t *frfp) { static ipf_authstat_t frauthst, *frauthstp; static ipftq_t ipstcptab[IPF_TCP_NSTATES]; static ips_stat_t ipsst, *ipsstp; static ipfrstat_t ifrst, *ifrstp; static friostat_t fio, *fiop; int temp; void *rules[2][2]; struct nlist deadlist[44] = { { "ipf_auth_stats", 0, 0, 0, 0 }, /* 0 */ { "fae_list", 0, 0, 0, 0 }, { "ipauth", 0, 0, 0, 0 }, { "ipf_auth_list", 0, 0, 0, 0 }, { "ipf_auth_start", 0, 0, 0, 0 }, { "ipf_auth_end", 0, 0, 0, 0 }, /* 5 */ { "ipf_auth_next", 0, 0, 0, 0 }, { "ipf_auth", 0, 0, 0, 0 }, { "ipf_auth_used", 0, 0, 0, 0 }, { "ipf_auth_size", 0, 0, 0, 0 }, { "ipf_auth_defaultage", 0, 0, 0, 0 }, /* 10 */ { "ipf_auth_pkts", 0, 0, 0, 0 }, { "ipf_auth_lock", 0, 0, 0, 0 }, { "frstats", 0, 0, 0, 0 }, { "ips_stats", 0, 0, 0, 0 }, { "ips_num", 0, 0, 0, 0 }, /* 15 */ { "ips_wild", 0, 0, 0, 0 }, { "ips_list", 0, 0, 0, 0 }, { "ips_table", 0, 0, 0, 0 }, { "ipf_state_max", 0, 0, 0, 0 }, { "ipf_state_size", 0, 0, 0, 0 }, /* 20 */ { "ipf_state_doflush", 0, 0, 0, 0 }, { "ipf_state_lock", 0, 0, 0, 0 }, { "ipfr_heads", 0, 0, 0, 0 }, { "ipfr_nattab", 0, 0, 0, 0 }, { "ipfr_stats", 0, 0, 0, 0 }, /* 25 */ { "ipfr_inuse", 0, 0, 0, 0 }, { "ipf_ipfrttl", 0, 0, 0, 0 }, { "ipf_frag_lock", 0, 0, 0, 0 }, { "ipfr_timer_id", 0, 0, 0, 0 }, { "ipf_nat_lock", 0, 0, 0, 0 }, /* 30 */ { "ipf_rules", 0, 0, 0, 0 }, { "ipf_acct", 0, 0, 0, 0 }, { "ipl_frouteok", 0, 0, 0, 0 }, { "ipf_running", 0, 0, 0, 0 }, { "ipf_groups", 0, 0, 0, 0 }, /* 35 */ { "ipf_active", 0, 0, 0, 0 }, { "ipf_pass", 0, 0, 0, 0 }, { "ipf_flags", 0, 0, 0, 0 }, { "ipf_state_logging", 0, 0, 0, 0 }, { "ips_tqtqb", 0, 0, 0, 0 }, /* 40 */ { NULL, 0, 0, 0, 0 } }; frauthstp = &frauthst; ipsstp = &ipsst; ifrstp = &ifrst; fiop = &fio; *frfp = 0; *fiopp = fiop; *ipsstpp = ipsstp; *ifrstpp = ifrstp; *frauthstpp = frauthstp; bzero((char *)fiop, sizeof(*fiop)); bzero((char *)ipsstp, sizeof(*ipsstp)); bzero((char *)ifrstp, sizeof(*ifrstp)); bzero((char *)frauthstp, sizeof(*frauthstp)); if (nlist(kernel, deadlist) == -1) { fprintf(stderr, "nlist error\n"); return; } /* * This is for SIOCGETFF. */ kmemcpy((char *)frfp, (u_long)deadlist[40].n_value, sizeof(*frfp)); /* * f_locks is a combination of the lock variable from each part of * ipfilter (state, auth, nat, fragments). */ kmemcpy((char *)fiop, (u_long)deadlist[13].n_value, sizeof(*fiop)); kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[22].n_value, sizeof(fiop->f_locks[0])); kmemcpy((char *)&fiop->f_locks[0], (u_long)deadlist[30].n_value, sizeof(fiop->f_locks[1])); kmemcpy((char *)&fiop->f_locks[2], (u_long)deadlist[28].n_value, sizeof(fiop->f_locks[2])); kmemcpy((char *)&fiop->f_locks[3], (u_long)deadlist[12].n_value, sizeof(fiop->f_locks[3])); /* * Get pointers to each list of rules (active, inactive, in, out) */ kmemcpy((char *)&rules, (u_long)deadlist[31].n_value, sizeof(rules)); fiop->f_fin[0] = rules[0][0]; fiop->f_fin[1] = rules[0][1]; fiop->f_fout[0] = rules[1][0]; fiop->f_fout[1] = rules[1][1]; /* * Now get accounting rules pointers. */ kmemcpy((char *)&rules, (u_long)deadlist[33].n_value, sizeof(rules)); fiop->f_acctin[0] = rules[0][0]; fiop->f_acctin[1] = rules[0][1]; fiop->f_acctout[0] = rules[1][0]; fiop->f_acctout[1] = rules[1][1]; /* * A collection of "global" variables used inside the kernel which * are all collected in friostat_t via ioctl. */ kmemcpy((char *)&fiop->f_froute, (u_long)deadlist[33].n_value, sizeof(fiop->f_froute)); kmemcpy((char *)&fiop->f_running, (u_long)deadlist[34].n_value, sizeof(fiop->f_running)); kmemcpy((char *)&fiop->f_groups, (u_long)deadlist[35].n_value, sizeof(fiop->f_groups)); kmemcpy((char *)&fiop->f_active, (u_long)deadlist[36].n_value, sizeof(fiop->f_active)); kmemcpy((char *)&fiop->f_defpass, (u_long)deadlist[37].n_value, sizeof(fiop->f_defpass)); /* * Build up the state information stats structure. */ kmemcpy((char *)ipsstp, (u_long)deadlist[14].n_value, sizeof(*ipsstp)); kmemcpy((char *)&temp, (u_long)deadlist[15].n_value, sizeof(temp)); kmemcpy((char *)ipstcptab, (u_long)deadlist[40].n_value, sizeof(ipstcptab)); ipsstp->iss_active = temp; ipsstp->iss_table = (void *)deadlist[18].n_value; ipsstp->iss_list = (void *)deadlist[17].n_value; ipsstp->iss_tcptab = ipstcptab; /* * Build up the authentiation information stats structure. */ kmemcpy((char *)frauthstp, (u_long)deadlist[0].n_value, sizeof(*frauthstp)); frauthstp->fas_faelist = (void *)deadlist[1].n_value; /* * Build up the fragment information stats structure. */ kmemcpy((char *)ifrstp, (u_long)deadlist[25].n_value, sizeof(*ifrstp)); ifrstp->ifs_table = (void *)deadlist[23].n_value; ifrstp->ifs_nattab = (void *)deadlist[24].n_value; kmemcpy((char *)&ifrstp->ifs_inuse, (u_long)deadlist[26].n_value, sizeof(ifrstp->ifs_inuse)); /* * Get logging on/off switches */ kmemcpy((char *)&state_logging, (u_long)deadlist[41].n_value, sizeof(state_logging)); } static void printside(char *side, ipf_statistics_t *frs) { int i; PRINTF("%lu\t%s bad packets\n", frs->fr_bad, side); #ifdef USE_INET6 PRINTF("%lu\t%s IPv6 packets\n", frs->fr_ipv6, side); #endif PRINTF("%lu\t%s packets blocked\n", frs->fr_block, side); PRINTF("%lu\t%s packets passed\n", frs->fr_pass, side); PRINTF("%lu\t%s packets not matched\n", frs->fr_nom, side); PRINTF("%lu\t%s packets counted\n", frs->fr_acct, side); PRINTF("%lu\t%s packets short\n", frs->fr_short, side); PRINTF("%lu\t%s packets logged and blocked\n", frs->fr_bpkl, side); PRINTF("%lu\t%s packets logged and passed\n", frs->fr_ppkl, side); PRINTF("%lu\t%s fragment state kept\n", frs->fr_nfr, side); PRINTF("%lu\t%s fragment state lost\n", frs->fr_bnfr, side); PRINTF("%lu\t%s packet state kept\n", frs->fr_ads, side); PRINTF("%lu\t%s packet state lost\n", frs->fr_bads, side); PRINTF("%lu\t%s invalid source\n", frs->fr_v4_badsrc, side); PRINTF("%lu\t%s cache hits\n", frs->fr_chit, side); PRINTF("%lu\t%s cache misses\n", frs->fr_cmiss, side); PRINTF("%lu\t%s bad coalesces\n", frs->fr_badcoalesces, side); PRINTF("%lu\t%s pullups succeeded\n", frs->fr_pull[0], side); PRINTF("%lu\t%s pullups failed\n", frs->fr_pull[1], side); PRINTF("%lu\t%s TCP checksum failures\n", frs->fr_tcpbad, side); for (i = 0; i <= FRB_MAX_VALUE; i++) PRINTF("%lu\t%s block reason %s\n", frs->fr_blocked[i], side, blockreasons[i]); } /* * Display the kernel stats for packets blocked and passed and other * associated running totals which are kept. */ static void showstats( struct friostat *fp, u_32_t frf) { printside("input", &fp->f_st[0]); printside("output", &fp->f_st[1]); PRINTF("%lu\tpackets logged\n", fp->f_log_ok); PRINTF("%lu\tlog failures\n", fp->f_log_fail); PRINTF("%lu\tred-black no memory\n", fp->f_rb_no_mem); PRINTF("%lu\tred-black node maximum\n", fp->f_rb_node_max); PRINTF("%lu\tICMP replies sent\n", fp->f_st[0].fr_ret); PRINTF("%lu\tTCP RSTs sent\n", fp->f_st[1].fr_ret); PRINTF("%lu\tfastroute successes\n", fp->f_froute[0]); PRINTF("%lu\tfastroute failures\n", fp->f_froute[1]); PRINTF("%u\tIPF Ticks\n", fp->f_ticks); PRINTF("%x\tPacket log flags set:\n", frf); if (frf & FF_LOGPASS) PRINTF("\tpackets passed through filter\n"); if (frf & FF_LOGBLOCK) PRINTF("\tpackets blocked by filter\n"); if (frf & FF_LOGNOMATCH) PRINTF("\tpackets not matched by filter\n"); if (!frf) PRINTF("\tnone\n"); } /* * Print out a list of rules from the kernel, starting at the one passed. */ static int printlivelist( struct friostat *fiop, int out, int set, frentry_t *fp, char *group, char *comment) { struct frentry fb; ipfruleiter_t rule; frentry_t zero; frgroup_t *g; ipfobj_t obj; int rules; int num; rules = 0; rule.iri_inout = out; rule.iri_active = set; rule.iri_rule = &fb; rule.iri_nrules = 1; if (group != NULL) strncpy(rule.iri_group, group, FR_GROUPLEN); else rule.iri_group[0] = '\0'; bzero((char *)&zero, sizeof(zero)); bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_IPFITER; obj.ipfo_size = sizeof(rule); obj.ipfo_ptr = &rule; while (rule.iri_rule != NULL) { u_long array[1000]; memset(array, 0xff, sizeof(array)); fp = (frentry_t *)array; rule.iri_rule = fp; if (ioctl(ipf_fd, SIOCIPFITER, &obj) == -1) { ipferror(ipf_fd, "ioctl(SIOCIPFITER)"); num = IPFGENITER_IPF; (void) ioctl(ipf_fd,SIOCIPFDELTOK, &num); return (rules); } if (bcmp(fp, &zero, sizeof(zero)) == 0) break; if (rule.iri_rule == NULL) break; #ifdef USE_INET6 if (use_inet6 != 0 && use_inet4 == 0) { if (fp->fr_family != 0 && fp->fr_family != AF_INET6) continue; } else if (use_inet4 != 0 && use_inet6 == 0) { #endif if (fp->fr_family != 0 && fp->fr_family != AF_INET) continue; #ifdef USE_INET6 } else { if (fp->fr_family != 0 && fp->fr_family != AF_INET && fp->fr_family != AF_INET6) continue; } #endif if (fp->fr_data != NULL) fp->fr_data = (char *)fp + fp->fr_size; rules++; if (opts & (OPT_HITS|OPT_DEBUG)) #ifdef USE_QUAD_T PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_hits); #else PRINTF("%lu ", fp->fr_hits); #endif if (opts & (OPT_ACCNT|OPT_DEBUG)) #ifdef USE_QUAD_T PRINTF("%"PRIu64" ", (unsigned long long) fp->fr_bytes); #else PRINTF("%lu ", fp->fr_bytes); #endif if (opts & OPT_SHOWLINENO) PRINTF("@%d ", rules); if (fp->fr_die != 0) fp->fr_die -= fiop->f_ticks; printfr(fp, ioctl); if (opts & OPT_DEBUG) { binprint(fp, fp->fr_size); if (fp->fr_data != NULL && fp->fr_dsize > 0) binprint(fp->fr_data, fp->fr_dsize); } if (fp->fr_grhead != -1) { for (g = grtop; g != NULL; g = g->fg_next) { if (!strncmp(fp->fr_names + fp->fr_grhead, g->fg_name, FR_GROUPLEN)) break; } if (g == NULL) { g = calloc(1, sizeof(*g)); if (g != NULL) { strncpy(g->fg_name, fp->fr_names + fp->fr_grhead, FR_GROUPLEN); if (grtop == NULL) { grtop = g; grtail = g; } else { grtail->fg_next = g; grtail = g; } } } } if (fp->fr_type == FR_T_CALLFUNC) { rules += printlivelist(fiop, out, set, fp->fr_data, group, "# callfunc: "); } } num = IPFGENITER_IPF; (void) ioctl(ipf_fd,SIOCIPFDELTOK, &num); return (rules); } static void printdeadlist(friostat_t *fiop, int out, int set, frentry_t *fp, char *group, char *comment) { frgroup_t *grtop, *grtail, *g; struct frentry fb; char *data; u_32_t type; int n; fb.fr_next = fp; n = 0; grtop = NULL; grtail = NULL; for (n = 1; fp; fp = fb.fr_next, n++) { if (kmemcpy((char *)&fb, (u_long)fb.fr_next, fb.fr_size) == -1) { perror("kmemcpy"); return; } fp = &fb; #ifdef USE_INET6 if (use_inet6 != 0 && use_inet4 == 0) { if (fp->fr_family != 0 && fp->fr_family != AF_INET6) continue; } else if (use_inet4 != 0 && use_inet6 == 0) { #endif if (fp->fr_family != 0 && fp->fr_family != AF_INET) continue; #ifdef USE_INET6 } else { if (fp->fr_family != 0 && fp->fr_family != AF_INET && fp->fr_family != AF_INET6) continue; } #endif data = NULL; type = fb.fr_type & ~FR_T_BUILTIN; if (type == FR_T_IPF || type == FR_T_BPFOPC) { if (fb.fr_dsize) { data = malloc(fb.fr_dsize); if (kmemcpy(data, (u_long)fb.fr_data, fb.fr_dsize) == -1) { perror("kmemcpy"); return; } fb.fr_data = data; } } if (opts & OPT_HITS) #ifdef USE_QUAD_T PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_hits); #else PRINTF("%lu ", fb.fr_hits); #endif if (opts & OPT_ACCNT) #ifdef USE_QUAD_T PRINTF("%"PRIu64" ", (unsigned long long) fb.fr_bytes); #else PRINTF("%lu ", fb.fr_bytes); #endif if (opts & OPT_SHOWLINENO) PRINTF("@%d ", n); printfr(fp, ioctl); if (opts & OPT_DEBUG) { binprint(fp, fp->fr_size); if (fb.fr_data != NULL && fb.fr_dsize > 0) binprint(fb.fr_data, fb.fr_dsize); } if (data != NULL) free(data); if (fb.fr_grhead != -1) { g = calloc(1, sizeof(*g)); if (g != NULL) { strncpy(g->fg_name, fb.fr_names + fb.fr_grhead, FR_GROUPLEN); if (grtop == NULL) { grtop = g; grtail = g; } else { grtail->fg_next = g; grtail = g; } } } if (type == FR_T_CALLFUNC) { printdeadlist(fiop, out, set, fb.fr_data, group, "# callfunc: "); } } while ((g = grtop) != NULL) { printdeadlist(fiop, out, set, NULL, g->fg_name, comment); grtop = g->fg_next; free(g); } } /* * print out all of the asked for rule sets, using the stats struct as * the base from which to get the pointers. */ static void showlist(struct friostat *fiop) { struct frentry *fp = NULL; int i, set; set = fiop->f_active; if (opts & OPT_INACTIVE) set = 1 - set; if (opts & OPT_ACCNT) { if (opts & OPT_OUTQUE) { i = F_ACOUT; fp = (struct frentry *)fiop->f_acctout[set]; } else if (opts & OPT_INQUE) { i = F_ACIN; fp = (struct frentry *)fiop->f_acctin[set]; } else { FPRINTF(stderr, "No -i or -o given with -a\n"); return; } } else { if (opts & OPT_OUTQUE) { i = F_OUT; fp = (struct frentry *)fiop->f_fout[set]; } else if (opts & OPT_INQUE) { i = F_IN; fp = (struct frentry *)fiop->f_fin[set]; } else return; } if (opts & OPT_DEBUG) FPRINTF(stderr, "showlist:opts %#x i %d\n", opts, i); if (opts & OPT_DEBUG) PRINTF("fp %p set %d\n", fp, set); if (live_kernel == 1) { int printed; printed = printlivelist(fiop, i, set, fp, NULL, NULL); if (printed == 0) { FPRINTF(stderr, "# empty list for %s%s\n", (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); } } else { if (!fp) { FPRINTF(stderr, "# empty list for %s%s\n", (opts & OPT_INACTIVE) ? "inactive " : "", filters[i]); } else { printdeadlist(fiop, i, set, fp, NULL, NULL); } } } /* * Display ipfilter stateful filtering information */ static void showipstates(ips_stat_t *ipsp, int *filter) { ipstate_t *is; int i; /* * If a list of states hasn't been asked for, only print out stats */ if (!(opts & OPT_SHOWLIST)) { showstatestats(ipsp); return; } if ((state_fields != NULL) && (nohdrfields == 0)) { for (i = 0; state_fields[i].w_value != 0; i++) { printfieldhdr(statefields, state_fields + i); if (state_fields[i + 1].w_value != 0) printf("\t"); } printf("\n"); } /* * Print out all the state information currently held in the kernel. */ for (is = ipsp->iss_list; is != NULL; ) { ipstate_t ips; is = fetchstate(is, &ips); if (is == NULL) break; is = ips.is_next; if ((filter != NULL) && (state_matcharray(&ips, filter) == 0)) { continue; } if (state_fields != NULL) { for (i = 0; state_fields[i].w_value != 0; i++) { printstatefield(&ips, state_fields[i].w_value); if (state_fields[i + 1].w_value != 0) printf("\t"); } printf("\n"); } else { printstate(&ips, opts, ipsp->iss_ticks); } } } static void showstatestats(ips_stat_t *ipsp) { int minlen, maxlen, totallen; ipftable_t table; u_int *buckets; ipfobj_t obj; int i, sz; /* * If a list of states hasn't been asked for, only print out stats */ sz = sizeof(*buckets) * ipsp->iss_state_size; buckets = (u_int *)malloc(sz); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GTABLE; obj.ipfo_size = sizeof(table); obj.ipfo_ptr = &table; table.ita_type = IPFTABLE_BUCKETS; table.ita_table = buckets; if (live_kernel == 1) { if (ioctl(state_fd, SIOCGTABL, &obj) != 0) { free(buckets); return; } } else { if (kmemcpy((char *)buckets, (u_long)ipsp->iss_bucketlen, sz)) { free(buckets); return; } } PRINTF("%u\tactive state table entries\n",ipsp->iss_active); PRINTF("%lu\tadd bad\n", ipsp->iss_add_bad); PRINTF("%lu\tadd duplicate\n", ipsp->iss_add_dup); PRINTF("%lu\tadd locked\n", ipsp->iss_add_locked); PRINTF("%lu\tadd oow\n", ipsp->iss_add_oow); PRINTF("%lu\tbucket full\n", ipsp->iss_bucket_full); PRINTF("%lu\tcheck bad\n", ipsp->iss_check_bad); PRINTF("%lu\tcheck miss\n", ipsp->iss_check_miss); PRINTF("%lu\tcheck nattag\n", ipsp->iss_check_nattag); PRINTF("%lu\tclone nomem\n", ipsp->iss_clone_nomem); PRINTF("%lu\tcheck notag\n", ipsp->iss_check_notag); PRINTF("%lu\tcheck success\n", ipsp->iss_hits); PRINTF("%lu\tcloned\n", ipsp->iss_cloned); PRINTF("%lu\texpired\n", ipsp->iss_expire); PRINTF("%lu\tflush all\n", ipsp->iss_flush_all); PRINTF("%lu\tflush closing\n", ipsp->iss_flush_closing); PRINTF("%lu\tflush queue\n", ipsp->iss_flush_queue); PRINTF("%lu\tflush state\n", ipsp->iss_flush_state); PRINTF("%lu\tflush timeout\n", ipsp->iss_flush_timeout); PRINTF("%u\thash buckets in use\n", ipsp->iss_inuse); PRINTF("%lu\tICMP bad\n", ipsp->iss_icmp_bad); PRINTF("%lu\tICMP banned\n", ipsp->iss_icmp_banned); PRINTF("%lu\tICMP errors\n", ipsp->iss_icmp_icmperr); PRINTF("%lu\tICMP head block\n", ipsp->iss_icmp_headblock); PRINTF("%lu\tICMP hits\n", ipsp->iss_icmp_hits); PRINTF("%lu\tICMP not query\n", ipsp->iss_icmp_notquery); PRINTF("%lu\tICMP short\n", ipsp->iss_icmp_short); PRINTF("%lu\tICMP too many\n", ipsp->iss_icmp_toomany); PRINTF("%lu\tICMPv6 errors\n", ipsp->iss_icmp6_icmperr); PRINTF("%lu\tICMPv6 miss\n", ipsp->iss_icmp6_miss); PRINTF("%lu\tICMPv6 not info\n", ipsp->iss_icmp6_notinfo); PRINTF("%lu\tICMPv6 not query\n", ipsp->iss_icmp6_notquery); PRINTF("%lu\tlog fail\n", ipsp->iss_log_fail); PRINTF("%lu\tlog ok\n", ipsp->iss_log_ok); PRINTF("%lu\tlookup interface mismatch\n", ipsp->iss_lookup_badifp); PRINTF("%lu\tlookup mask mismatch\n", ipsp->iss_miss_mask); PRINTF("%lu\tlookup port mismatch\n", ipsp->iss_lookup_badport); PRINTF("%lu\tlookup miss\n", ipsp->iss_lookup_miss); PRINTF("%lu\tmaximum rule references\n", ipsp->iss_max_ref); PRINTF("%lu\tmaximum hosts per rule\n", ipsp->iss_max_track); PRINTF("%lu\tno memory\n", ipsp->iss_nomem); PRINTF("%lu\tout of window\n", ipsp->iss_oow); PRINTF("%lu\torphans\n", ipsp->iss_orphan); PRINTF("%lu\tscan block\n", ipsp->iss_scan_block); PRINTF("%lu\tstate table maximum reached\n", ipsp->iss_max); PRINTF("%lu\tTCP closing\n", ipsp->iss_tcp_closing); PRINTF("%lu\tTCP OOW\n", ipsp->iss_tcp_oow); PRINTF("%lu\tTCP RST add\n", ipsp->iss_tcp_rstadd); PRINTF("%lu\tTCP too small\n", ipsp->iss_tcp_toosmall); PRINTF("%lu\tTCP bad options\n", ipsp->iss_tcp_badopt); PRINTF("%lu\tTCP removed\n", ipsp->iss_fin); PRINTF("%lu\tTCP FSM\n", ipsp->iss_tcp_fsm); PRINTF("%lu\tTCP strict\n", ipsp->iss_tcp_strict); PRINTF("%lu\tTCP wild\n", ipsp->iss_wild); PRINTF("%lu\tMicrosoft Windows SACK\n", ipsp->iss_winsack); PRINTF("State logging %sabled\n", state_logging ? "en" : "dis"); PRINTF("IP states added:\n"); for (i = 0; i < 256; i++) { if (ipsp->iss_proto[i] != 0) { struct protoent *proto; proto = getprotobynumber(i); PRINTF("%lu", ipsp->iss_proto[i]); if (proto != NULL) PRINTF("\t%s\n", proto->p_name); else PRINTF("\t%d\n", i); } } PRINTF("\nState table bucket statistics:\n"); PRINTF("%u\tin use\n", ipsp->iss_inuse); minlen = ipsp->iss_max; totallen = 0; maxlen = 0; for (i = 0; i < ipsp->iss_state_size; i++) { if (buckets[i] > maxlen) maxlen = buckets[i]; if (buckets[i] < minlen) minlen = buckets[i]; totallen += buckets[i]; } PRINTF("%d\thash efficiency\n", totallen ? ipsp->iss_inuse * 100 / totallen : 0); PRINTF("%2.2f%%\tbucket usage\n%u\tminimal length\n", ((float)ipsp->iss_inuse / ipsp->iss_state_size) * 100.0, minlen); PRINTF("%u\tmaximal length\n%.3f\taverage length\n", maxlen, ipsp->iss_inuse ? (float) totallen/ ipsp->iss_inuse : 0.0); #define ENTRIES_PER_LINE 5 if (opts & OPT_VERBOSE) { PRINTF("\nCurrent bucket sizes :\n"); for (i = 0; i < ipsp->iss_state_size; i++) { if ((i % ENTRIES_PER_LINE) == 0) PRINTF("\t"); PRINTF("%4d -> %4u", i, buckets[i]); if ((i % ENTRIES_PER_LINE) == (ENTRIES_PER_LINE - 1)) PRINTF("\n"); else PRINTF(" "); } PRINTF("\n"); } PRINTF("\n"); free(buckets); if (live_kernel == 1) { showtqtable_live(state_fd); } else { printtqtable(ipsp->iss_tcptab); } } #ifdef STATETOP static int handle_resize = 0, handle_break = 0; static void topipstates(i6addr_t saddr, i6addr_t daddr, int sport, int dport, int protocol, int ver, int refreshtime, int topclosed, int *filter) { char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE]; int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT; int i, j, winy, tsentry, maxx, maxy, redraw = 0, ret = 0; int len, srclen, dstlen, forward = 1, c = 0; ips_stat_t ipsst, *ipsstp = &ipsst; int token_type = IPFGENITER_STATE; statetop_t *tstable = NULL, *tp; const char *errstr = ""; ipstate_t ips; ipfobj_t ipfo; struct timeval selecttimeout; char hostnm[HOSTNMLEN]; struct protoent *proto; fd_set readfd; time_t t; /* install signal handlers */ signal(SIGINT, sig_break); signal(SIGQUIT, sig_break); signal(SIGTERM, sig_break); signal(SIGWINCH, sig_resize); /* init ncurses stuff */ initscr(); cbreak(); noecho(); curs_set(0); timeout(0); getmaxyx(stdscr, maxy, maxx); /* init hostname */ gethostname(hostnm, sizeof(hostnm) - 1); hostnm[sizeof(hostnm) - 1] = '\0'; /* init ipfobj_t stuff */ bzero((caddr_t)&ipfo, sizeof(ipfo)); ipfo.ipfo_rev = IPFILTER_VERSION; ipfo.ipfo_type = IPFOBJ_STATESTAT; ipfo.ipfo_size = sizeof(*ipsstp); ipfo.ipfo_ptr = (void *)ipsstp; /* repeat until user aborts */ while ( 1 ) { /* get state table */ bzero((char *)&ipsst, sizeof(ipsst)); if ((ioctl(state_fd, SIOCGETFS, &ipfo) == -1)) { errstr = "ioctl(SIOCGETFS)"; ret = -1; goto out; } /* clear the history */ tsentry = -1; /* reset max str len */ srclen = dstlen = 0; /* read the state table and store in tstable */ for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) { ipsstp->iss_list = fetchstate(ipsstp->iss_list, &ips); if (ipsstp->iss_list == NULL) break; if (ver != 0 && ips.is_v != ver) continue; if ((filter != NULL) && (state_matcharray(&ips, filter) == 0)) continue; /* check v4 src/dest addresses */ if (ips.is_v == 4) { if ((saddr.in4.s_addr != INADDR_ANY && saddr.in4.s_addr != ips.is_saddr) || (daddr.in4.s_addr != INADDR_ANY && daddr.in4.s_addr != ips.is_daddr)) continue; } #ifdef USE_INET6 /* check v6 src/dest addresses */ if (ips.is_v == 6) { if ((IP6_NEQ(&saddr, &in6addr_any) && IP6_NEQ(&saddr, &ips.is_src)) || (IP6_NEQ(&daddr, &in6addr_any) && IP6_NEQ(&daddr, &ips.is_dst))) continue; } #endif /* check protocol */ if (protocol > 0 && protocol != ips.is_p) continue; /* check ports if protocol is TCP or UDP */ if (((ips.is_p == IPPROTO_TCP) || (ips.is_p == IPPROTO_UDP)) && (((sport > 0) && (htons(sport) != ips.is_sport)) || ((dport > 0) && (htons(dport) != ips.is_dport)))) continue; /* show closed TCP sessions ? */ if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) && (ips.is_state[0] >= IPF_TCPS_LAST_ACK) && (ips.is_state[1] >= IPF_TCPS_LAST_ACK)) continue; /* * if necessary make room for this state * entry */ tsentry++; if (!maxtsentries || tsentry == maxtsentries) { maxtsentries += STGROWSIZE; tstable = reallocarray(tstable, maxtsentries, sizeof(statetop_t)); if (tstable == NULL) { perror("realloc"); exit(-1); } } /* get max src/dest address string length */ len = strlen(getip(ips.is_v, &ips.is_src)); if (srclen < len) srclen = len; len = strlen(getip(ips.is_v, &ips.is_dst)); if (dstlen < len) dstlen = len; /* fill structure */ tp = tstable + tsentry; tp->st_src = ips.is_src; tp->st_dst = ips.is_dst; tp->st_p = ips.is_p; tp->st_v = ips.is_v; tp->st_state[0] = ips.is_state[0]; tp->st_state[1] = ips.is_state[1]; if (forward) { tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1]; tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1]; } else { tp->st_pkts = ips.is_pkts[2]+ips.is_pkts[3]; tp->st_bytes = ips.is_bytes[2]+ips.is_bytes[3]; } tp->st_age = ips.is_die - ipsstp->iss_ticks; if ((ips.is_p == IPPROTO_TCP) || (ips.is_p == IPPROTO_UDP)) { tp->st_sport = ips.is_sport; tp->st_dport = ips.is_dport; } } (void) ioctl(state_fd, SIOCIPFDELTOK, &token_type); /* sort the array */ if (tsentry != -1) { switch (sorting) { case STSORT_PR: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_p); break; case STSORT_PKTS: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_pkts); break; case STSORT_BYTES: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_bytes); break; case STSORT_TTL: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_ttl); break; case STSORT_SRCIP: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_srcip); break; case STSORT_SRCPT: qsort(tstable, tsentry +1, sizeof(statetop_t), sort_srcpt); break; case STSORT_DSTIP: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_dstip); break; case STSORT_DSTPT: qsort(tstable, tsentry + 1, sizeof(statetop_t), sort_dstpt); break; default: break; } } /* handle window resizes */ if (handle_resize) { endwin(); initscr(); cbreak(); noecho(); curs_set(0); timeout(0); getmaxyx(stdscr, maxy, maxx); redraw = 1; handle_resize = 0; } /* stop program? */ if (handle_break) break; /* print title */ erase(); attron(A_BOLD); winy = 0; move(winy,0); snprintf(str1, sizeof(str1), "%s - %s - state top", hostnm, IPL_VERSION); for (j = 0 ; j < (maxx - 8 - strlen(str1)) / 2; j++) printw(" "); printw("%s", str1); attroff(A_BOLD); /* just for fun add a clock */ move(winy, maxx - 8); t = time(NULL); strftime(str1, 80, "%T", localtime(&t)); printw("%s\n", str1); /* * print the display filters, this is placed in the loop, * because someday I might add code for changing these * while the programming is running :-) */ if (sport >= 0) snprintf(str1, sizeof(str1), "%s,%d", getip(ver, &saddr), sport); else snprintf(str1, sizeof(str1), "%s", getip(ver, &saddr)); if (dport >= 0) snprintf(str2, sizeof(str2), "%s,%d", getip(ver, &daddr), dport); else snprintf(str2, sizeof(str2), "%s", getip(ver, &daddr)); if (protocol < 0) strcpy(str3, "any"); else if ((proto = getprotobynumber(protocol)) != NULL) snprintf(str3, sizeof(str3), "%s", proto->p_name); else snprintf(str3, sizeof(str3), "%d", protocol); switch (sorting) { case STSORT_PR: snprintf(str4, sizeof(str4), "proto"); break; case STSORT_PKTS: snprintf(str4, sizeof(str4), "# pkts"); break; case STSORT_BYTES: snprintf(str4, sizeof(str4), "# bytes"); break; case STSORT_TTL: snprintf(str4, sizeof(str4), "ttl"); break; case STSORT_SRCIP: snprintf(str4, sizeof(str4), "src ip"); break; case STSORT_SRCPT: snprintf(str4, sizeof(str4), "src port"); break; case STSORT_DSTIP: snprintf(str4, sizeof(str4), "dest ip"); break; case STSORT_DSTPT: snprintf(str4, sizeof(str4), "dest port"); break; default: snprintf(str4, sizeof(str4), "unknown"); break; } if (reverse) strcat(str4, " (reverse)"); winy += 2; move(winy,0); printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n", str1, str2, str3, str4); /* * For an IPv4 IP address we need at most 15 characters, * 4 tuples of 3 digits, separated by 3 dots. Enforce this * length, so the colums do not change positions based * on the size of the IP address. This length makes the * output fit in a 80 column terminal. * We are lacking a good solution for IPv6 addresses (that * can be longer that 15 characters), so we do not enforce * a maximum on the IP field size. */ if (srclen < 15) srclen = 15; if (dstlen < 15) dstlen = 15; /* print column description */ winy += 2; move(winy,0); attron(A_BOLD); printw("%-*s %-*s %3s %4s %7s %9s %9s\n", srclen + 6, "Source IP", dstlen + 6, "Destination IP", "ST", "PR", "#pkts", "#bytes", "ttl"); attroff(A_BOLD); /* print all the entries */ tp = tstable; if (reverse) tp += tsentry; if (tsentry > maxy - 6) tsentry = maxy - 6; for (i = 0; i <= tsentry; i++) { /* print src/dest and port */ if ((tp->st_p == IPPROTO_TCP) || (tp->st_p == IPPROTO_UDP)) { snprintf(str1, sizeof(str1), "%s,%hu", getip(tp->st_v, &tp->st_src), ntohs(tp->st_sport)); snprintf(str2, sizeof(str2), "%s,%hu", getip(tp->st_v, &tp->st_dst), ntohs(tp->st_dport)); } else { snprintf(str1, sizeof(str1), "%s", getip(tp->st_v, &tp->st_src)); snprintf(str2, sizeof(str2), "%s", getip(tp->st_v, &tp->st_dst)); } winy++; move(winy, 0); printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2); /* print state */ snprintf(str1, sizeof(str1), "%X/%X", tp->st_state[0], tp->st_state[1]); printw(" %3s", str1); /* print protocol */ proto = getprotobynumber(tp->st_p); if (proto) { strncpy(str1, proto->p_name, 4); str1[4] = '\0'; } else { snprintf(str1, sizeof(str1), "%d", tp->st_p); } /* just print icmp for IPv6-ICMP */ if (tp->st_p == IPPROTO_ICMPV6) strcpy(str1, "icmp"); printw(" %4s", str1); /* print #pkt/#bytes */ #ifdef USE_QUAD_T printw(" %7qu %9qu", (unsigned long long) tp->st_pkts, (unsigned long long) tp->st_bytes); #else printw(" %7lu %9lu", tp->st_pkts, tp->st_bytes); #endif printw(" %9s", ttl_to_string(tp->st_age)); if (reverse) tp--; else tp++; } /* screen data structure is filled, now update the screen */ if (redraw) clearok(stdscr,1); if (refresh() == ERR) break; if (redraw) { clearok(stdscr,0); redraw = 0; } /* wait for key press or a 1 second time out period */ selecttimeout.tv_sec = refreshtime; selecttimeout.tv_usec = 0; FD_ZERO(&readfd); FD_SET(0, &readfd); select(1, &readfd, NULL, NULL, &selecttimeout); /* if key pressed, read all waiting keys */ if (FD_ISSET(0, &readfd)) { c = wgetch(stdscr); if (c == ERR) continue; if (ISALPHA(c) && ISUPPER(c)) c = TOLOWER(c); if (c == 'l') { redraw = 1; } else if (c == 'q') { break; } else if (c == 'r') { reverse = !reverse; } else if (c == 'b') { forward = 0; } else if (c == 'f') { forward = 1; } else if (c == 's') { if (++sorting > STSORT_MAX) sorting = 0; } } } /* while */ out: printw("\n"); curs_set(1); /* nocbreak(); XXX - endwin() should make this redundant */ endwin(); free(tstable); if (ret != 0) perror(errstr); } #endif /* * Show fragment cache information that's held in the kernel. */ static void showfrstates(ipfrstat_t *ifsp, u_long ticks) { struct ipfr *ipfrtab[IPFT_SIZE], ifr; int i; /* * print out the numeric statistics */ PRINTF("IP fragment states:\n%lu\tnew\n%lu\texpired\n%lu\thits\n", ifsp->ifs_new, ifsp->ifs_expire, ifsp->ifs_hits); PRINTF("%lu\tretrans\n%lu\ttoo short\n", ifsp->ifs_retrans0, ifsp->ifs_short); PRINTF("%lu\tno memory\n%lu\talready exist\n", ifsp->ifs_nomem, ifsp->ifs_exists); PRINTF("%lu\tinuse\n", ifsp->ifs_inuse); PRINTF("\n"); if (live_kernel == 0) { if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_table, sizeof(ipfrtab))) return; } /* * Print out the contents (if any) of the fragment cache table. */ if (live_kernel == 1) { do { if (fetchfrag(ipf_fd, IPFGENITER_FRAG, &ifr) != 0) break; if (ifr.ipfr_ifp == NULL) break; ifr.ipfr_ttl -= ticks; printfraginfo("", &ifr); } while (ifr.ipfr_next != NULL); } else { for (i = 0; i < IPFT_SIZE; i++) while (ipfrtab[i] != NULL) { if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], sizeof(ifr)) == -1) break; printfraginfo("", &ifr); ipfrtab[i] = ifr.ipfr_next; } } /* * Print out the contents (if any) of the NAT fragment cache table. */ if (live_kernel == 0) { if (kmemcpy((char *)ipfrtab, (u_long)ifsp->ifs_nattab, sizeof(ipfrtab))) return; } if (live_kernel == 1) { do { if (fetchfrag(nat_fd, IPFGENITER_NATFRAG, &ifr) != 0) break; if (ifr.ipfr_ifp == NULL) break; ifr.ipfr_ttl -= ticks; printfraginfo("NAT: ", &ifr); } while (ifr.ipfr_next != NULL); } else { for (i = 0; i < IPFT_SIZE; i++) while (ipfrtab[i] != NULL) { if (kmemcpy((char *)&ifr, (u_long)ipfrtab[i], sizeof(ifr)) == -1) break; printfraginfo("NAT: ", &ifr); ipfrtab[i] = ifr.ipfr_next; } } } /* * Show stats on how auth within IPFilter has been used */ static void showauthstates(ipf_authstat_t *asp) { frauthent_t *frap, fra; ipfgeniter_t auth; ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GENITER; obj.ipfo_size = sizeof(auth); obj.ipfo_ptr = &auth; auth.igi_type = IPFGENITER_AUTH; auth.igi_nitems = 1; auth.igi_data = &fra; #ifdef USE_QUAD_T printf("Authorisation hits: %"PRIu64"\tmisses %"PRIu64"\n", (unsigned long long) asp->fas_hits, (unsigned long long) asp->fas_miss); #else printf("Authorisation hits: %ld\tmisses %ld\n", asp->fas_hits, asp->fas_miss); #endif printf("nospace %ld\nadded %ld\nsendfail %ld\nsendok %ld\n", asp->fas_nospace, asp->fas_added, asp->fas_sendfail, asp->fas_sendok); printf("queok %ld\nquefail %ld\nexpire %ld\n", asp->fas_queok, asp->fas_quefail, asp->fas_expire); frap = asp->fas_faelist; while (frap) { if (live_kernel == 1) { if (ioctl(auth_fd, SIOCGENITER, &obj)) break; } else { if (kmemcpy((char *)&fra, (u_long)frap, sizeof(fra)) == -1) break; } printf("age %ld\t", fra.fae_age); printfr(&fra.fae_fr, ioctl); frap = fra.fae_next; } } /* * Display groups used for each of filter rules, accounting rules and * authentication, separately. */ static void showgroups(struct friostat *fiop) { static char *gnames[3] = { "Filter", "Accounting", "Authentication" }; static int gnums[3] = { IPL_LOGIPF, IPL_LOGCOUNT, IPL_LOGAUTH }; frgroup_t *fp, grp; int on, off, i; on = fiop->f_active; off = 1 - on; for (i = 0; i < 3; i++) { printf("%s groups (active):\n", gnames[i]); for (fp = fiop->f_groups[gnums[i]][on]; fp != NULL; fp = grp.fg_next) if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) break; else printf("%s\n", grp.fg_name); printf("%s groups (inactive):\n", gnames[i]); for (fp = fiop->f_groups[gnums[i]][off]; fp != NULL; fp = grp.fg_next) if (kmemcpy((char *)&grp, (u_long)fp, sizeof(grp))) break; else printf("%s\n", grp.fg_name); } } static void parse_ipportstr(const char *argument, i6addr_t *ip, int *port) { char *s, *comma; int ok = 0; /* make working copy of argument, Theoretically you must be able * to write to optarg, but that seems very ugly to me.... */ s = strdup(argument); if (s == NULL) return; /* get port */ if ((comma = strchr(s, ',')) != NULL) { if (!strcasecmp(comma + 1, "any")) { *port = -1; } else if (!sscanf(comma + 1, "%d", port) || (*port < 0) || (*port > 65535)) { fprintf(stderr, "Invalid port specification in %s\n", argument); free(s); exit(-2); } *comma = '\0'; } /* get ip address */ if (!strcasecmp(s, "any")) { ip->in4.s_addr = INADDR_ANY; ok = 1; #ifdef USE_INET6 ip->in6 = in6addr_any; } else if (use_inet6 && !use_inet4 && inet_pton(AF_INET6, s, &ip->in6)) { ok = 1; #endif } else if (inet_aton(s, &ip->in4)) ok = 1; if (ok == 0) { fprintf(stderr, "Invalid IP address: %s\n", s); free(s); exit(-2); } /* free allocated memory */ free(s); } #ifdef STATETOP static void sig_resize(int s) { handle_resize = 1; } static void sig_break(int s) { handle_break = 1; } static char *getip(int v, i6addr_t *addr) { #ifdef USE_INET6 static char hostbuf[MAXHOSTNAMELEN+1]; #endif if (v == 0) return ("any"); if (v == 4) return (inet_ntoa(addr->in4)); #ifdef USE_INET6 (void) inet_ntop(AF_INET6, &addr->in6, hostbuf, sizeof(hostbuf) - 1); hostbuf[MAXHOSTNAMELEN] = '\0'; return (hostbuf); #else return ("IPv6"); #endif } static char *ttl_to_string(long int ttl) { static char ttlbuf[STSTRSIZE]; int hours, minutes, seconds; /* ttl is in half seconds */ ttl /= 2; hours = ttl / 3600; ttl = ttl % 3600; minutes = ttl / 60; seconds = ttl % 60; if (hours > 0) snprintf(ttlbuf, sizeof(ttlbuf), "%2d:%02d:%02d", hours, minutes, seconds); else snprintf(ttlbuf, sizeof(ttlbuf), "%2d:%02d", minutes, seconds); return (ttlbuf); } static int sort_pkts(const void *a, const void *b) { register const statetop_t *ap = a; register const statetop_t *bp = b; if (ap->st_pkts == bp->st_pkts) return (0); else if (ap->st_pkts < bp->st_pkts) return (1); return (-1); } static int sort_bytes(const void *a, const void *b) { register const statetop_t *ap = a; register const statetop_t *bp = b; if (ap->st_bytes == bp->st_bytes) return (0); else if (ap->st_bytes < bp->st_bytes) return (1); return (-1); } static int sort_p(const void *a, const void *b) { register const statetop_t *ap = a; register const statetop_t *bp = b; if (ap->st_p == bp->st_p) return (0); else if (ap->st_p < bp->st_p) return (1); return (-1); } static int sort_ttl(const void *a, const void *b) { register const statetop_t *ap = a; register const statetop_t *bp = b; if (ap->st_age == bp->st_age) return (0); else if (ap->st_age < bp->st_age) return (1); return (-1); } static int sort_srcip(const void *a, const void *b) { register const statetop_t *ap = a; register const statetop_t *bp = b; #ifdef USE_INET6 if (use_inet6 && !use_inet4) { if (IP6_EQ(&ap->st_src, &bp->st_src)) return (0); else if (IP6_GT(&ap->st_src, &bp->st_src)) return (1); } else #endif { if (ntohl(ap->st_src.in4.s_addr) == ntohl(bp->st_src.in4.s_addr)) return (0); else if (ntohl(ap->st_src.in4.s_addr) > ntohl(bp->st_src.in4.s_addr)) return (1); } return (-1); } static int sort_srcpt(const void *a, const void *b) { register const statetop_t *ap = a; register const statetop_t *bp = b; if (htons(ap->st_sport) == htons(bp->st_sport)) return (0); else if (htons(ap->st_sport) > htons(bp->st_sport)) return (1); return (-1); } static int sort_dstip(const void *a, const void *b) { register const statetop_t *ap = a; register const statetop_t *bp = b; #ifdef USE_INET6 if (use_inet6 && !use_inet4) { if (IP6_EQ(&ap->st_dst, &bp->st_dst)) return (0); else if (IP6_GT(&ap->st_dst, &bp->st_dst)) return (1); } else #endif { if (ntohl(ap->st_dst.in4.s_addr) == ntohl(bp->st_dst.in4.s_addr)) return (0); else if (ntohl(ap->st_dst.in4.s_addr) > ntohl(bp->st_dst.in4.s_addr)) return (1); } return (-1); } static int sort_dstpt(const void *a, const void *b) { register const statetop_t *ap = a; register const statetop_t *bp = b; if (htons(ap->st_dport) == htons(bp->st_dport)) return (0); else if (htons(ap->st_dport) > htons(bp->st_dport)) return (1); return (-1); } #endif ipstate_t *fetchstate(ipstate_t *src, ipstate_t *dst) { if (live_kernel == 1) { ipfgeniter_t state; ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GENITER; obj.ipfo_size = sizeof(state); obj.ipfo_ptr = &state; state.igi_type = IPFGENITER_STATE; state.igi_nitems = 1; state.igi_data = dst; if (ioctl(state_fd, SIOCGENITER, &obj) != 0) return (NULL); if (dst->is_next == NULL) { int n = IPFGENITER_STATE; (void) ioctl(ipf_fd,SIOCIPFDELTOK, &n); } } else { if (kmemcpy((char *)dst, (u_long)src, sizeof(*dst))) return (NULL); } return (dst); } static int fetchfrag( int fd, int type, ipfr_t *frp) { ipfgeniter_t frag; ipfobj_t obj; obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_type = IPFOBJ_GENITER; obj.ipfo_size = sizeof(frag); obj.ipfo_ptr = &frag; frag.igi_type = type; frag.igi_nitems = 1; frag.igi_data = frp; if (ioctl(fd, SIOCGENITER, &obj)) return (EFAULT); return (0); } static int state_matcharray(ipstate_t *stp, int *array) { int i, n, *x, rv, p; ipfexp_t *e; rv = 0; for (n = array[0], x = array + 1; n > 0; x += e->ipfe_size) { e = (ipfexp_t *)x; if (e->ipfe_cmd == IPF_EXP_END) break; n -= e->ipfe_size; rv = 0; /* * The upper 16 bits currently store the protocol value. * This is currently used with TCP and UDP port compares and * allows "tcp.port = 80" without requiring an explicit " "ip.pr = tcp" first. */ p = e->ipfe_cmd >> 16; if ((p != 0) && (p != stp->is_p)) break; switch (e->ipfe_cmd) { case IPF_EXP_IP_PR : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (stp->is_p == e->ipfe_arg0[i]); } break; case IPF_EXP_IP_SRCADDR : if (stp->is_v != 4) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= ((stp->is_saddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]); } break; case IPF_EXP_IP_DSTADDR : if (stp->is_v != 4) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= ((stp->is_daddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]); } break; case IPF_EXP_IP_ADDR : if (stp->is_v != 4) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= ((stp->is_saddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]) || ((stp->is_daddr & e->ipfe_arg0[i * 2 + 1]) == e->ipfe_arg0[i * 2]); } break; #ifdef USE_INET6 case IPF_EXP_IP6_SRCADDR : if (stp->is_v != 6) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= IP6_MASKEQ(&stp->is_src, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]); } break; case IPF_EXP_IP6_DSTADDR : if (stp->is_v != 6) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= IP6_MASKEQ(&stp->is_dst, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]); } break; case IPF_EXP_IP6_ADDR : if (stp->is_v != 6) break; for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= IP6_MASKEQ(&stp->is_src, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]) || IP6_MASKEQ(&stp->is_dst, &e->ipfe_arg0[i * 8 + 4], &e->ipfe_arg0[i * 8]); } break; #endif case IPF_EXP_UDP_PORT : case IPF_EXP_TCP_PORT : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (stp->is_sport == e->ipfe_arg0[i]) || (stp->is_dport == e->ipfe_arg0[i]); } break; case IPF_EXP_UDP_SPORT : case IPF_EXP_TCP_SPORT : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (stp->is_sport == e->ipfe_arg0[i]); } break; case IPF_EXP_UDP_DPORT : case IPF_EXP_TCP_DPORT : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (stp->is_dport == e->ipfe_arg0[i]); } break; case IPF_EXP_IDLE_GT : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (stp->is_die < e->ipfe_arg0[i]); } break; case IPF_EXP_TCP_STATE : for (i = 0; !rv && i < e->ipfe_narg; i++) { rv |= (stp->is_state[0] == e->ipfe_arg0[i]) || (stp->is_state[1] == e->ipfe_arg0[i]); } break; } rv ^= e->ipfe_not; if (rv == 0) break; } return (rv); } static void showtqtable_live(int fd) { ipftq_t table[IPF_TCP_NSTATES]; ipfobj_t obj; bzero((char *)&obj, sizeof(obj)); obj.ipfo_rev = IPFILTER_VERSION; obj.ipfo_size = sizeof(table); obj.ipfo_ptr = (void *)table; obj.ipfo_type = IPFOBJ_STATETQTAB; if (ioctl(fd, SIOCGTQTAB, &obj) == 0) { printtqtable(table); } } diff --git a/sbin/ipf/ipmon/ipmon.c b/sbin/ipf/ipmon/ipmon.c index f71a33b1034e..4f07dda27e62 100644 --- a/sbin/ipf/ipmon/ipmon.c +++ b/sbin/ipf/ipmon/ipmon.c @@ -1,1855 +1,1852 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. */ #include "ipf.h" #include "ipmon.h" #include #include #include #include #include #include #if !defined(lint) static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed"; static const char rcsid[] = "@(#)$Id$"; #endif #define STRERROR(x) strerror(x) extern int optind; extern char *optarg; extern ipmon_saver_t executesaver; extern ipmon_saver_t filesaver; extern ipmon_saver_t nothingsaver; extern ipmon_saver_t snmpv1saver; extern ipmon_saver_t snmpv2saver; extern ipmon_saver_t syslogsaver; struct flags { int value; char flag; }; typedef struct logsource { int fd; int logtype; char *file; int regular; size_t size; } logsource_t; typedef struct config { int opts; int maxfd; logsource_t logsrc[3]; fd_set fdmr; FILE *blog; char *bfile; FILE *log; char *file; char *cfile; } config_t; typedef struct icmp_subtype { int ist_val; char *ist_name; } icmp_subtype_t; typedef struct icmp_type { int it_val; struct icmp_subtype *it_subtable; size_t it_stsize; char *it_name; } icmp_type_t; #define IST_SZ(x) (sizeof(x)/sizeof(icmp_subtype_t)) struct flags tcpfl[] = { { TH_ACK, 'A' }, { TH_RST, 'R' }, { TH_SYN, 'S' }, { TH_FIN, 'F' }, { TH_URG, 'U' }, { TH_PUSH,'P' }, { TH_ECN, 'E' }, { TH_CWR, 'C' }, { 0, '\0' } }; char *reasons[] = { "filter-rule", "log-or-block_1", "pps-rate", "jumbogram", "makefrip-fail", "state_add-fail", "updateipid-fail", "log-or-block_2", "decap-fail", "auth_new-fail", "auth_captured", "coalesce-fail", "pullup-fail", "auth-feedback", "bad-frag", "natv4_out-fail", "natv4_in-fail", "natv6_out-fail", "natv6_in-fail", }; #if SOLARIS static char *pidfile = "/etc/opt/ipf/ipmon.pid"; #else static char *pidfile = "/var/run/ipmon.pid"; #endif static char line[2048]; static int donehup = 0; static void usage(char *); static void handlehup(int); static void flushlogs(char *, FILE *); static void print_log(config_t *, logsource_t *, char *, int); static void print_ipflog(config_t *, char *, int); static void print_natlog(config_t *, char *, int); static void print_statelog(config_t *, char *, int); static int read_log(int, int *, char *, int); static void write_pid(char *); static char *icmpname(u_int, u_int); static char *icmpname6(u_int, u_int); static icmp_type_t *find_icmptype(int, icmp_type_t *, size_t); static icmp_subtype_t *find_icmpsubtype(int, icmp_subtype_t *, size_t); static struct tm *get_tm(time_t); char *portlocalname(int, char *, u_int); int main(int, char *[]); static void logopts(int, char *); static void init_tabs(void); static char *getlocalproto(u_int); static void openlogs(config_t *conf); static int read_loginfo(config_t *conf); static void initconfig(config_t *conf); static char **protocols = NULL; static char **udp_ports = NULL; static char **tcp_ports = NULL; #define HOSTNAMEV4(b) hostname(AF_INET, (u_32_t *)&(b)) #ifndef LOGFAC #define LOGFAC LOG_LOCAL0 #endif int logfac = LOGFAC; int ipmonopts = 0; int opts = OPT_NORESOLVE; int use_inet6 = 0; static icmp_subtype_t icmpunreachnames[] = { { ICMP_UNREACH_NET, "net" }, { ICMP_UNREACH_HOST, "host" }, { ICMP_UNREACH_PROTOCOL, "protocol" }, { ICMP_UNREACH_PORT, "port" }, { ICMP_UNREACH_NEEDFRAG, "needfrag" }, { ICMP_UNREACH_SRCFAIL, "srcfail" }, { ICMP_UNREACH_NET_UNKNOWN, "net_unknown" }, { ICMP_UNREACH_HOST_UNKNOWN, "host_unknown" }, { ICMP_UNREACH_NET, "isolated" }, { ICMP_UNREACH_NET_PROHIB, "net_prohib" }, { ICMP_UNREACH_NET_PROHIB, "host_prohib" }, { ICMP_UNREACH_TOSNET, "tosnet" }, { ICMP_UNREACH_TOSHOST, "toshost" }, { ICMP_UNREACH_ADMIN_PROHIBIT, "admin_prohibit" }, { -2, NULL } }; static icmp_subtype_t redirectnames[] = { { ICMP_REDIRECT_NET, "net" }, { ICMP_REDIRECT_HOST, "host" }, { ICMP_REDIRECT_TOSNET, "tosnet" }, { ICMP_REDIRECT_TOSHOST, "toshost" }, { -2, NULL } }; static icmp_subtype_t timxceednames[] = { { ICMP_TIMXCEED_INTRANS, "transit" }, { ICMP_TIMXCEED_REASS, "reassem" }, { -2, NULL } }; static icmp_subtype_t paramnames[] = { { ICMP_PARAMPROB_ERRATPTR, "errata_pointer" }, { ICMP_PARAMPROB_OPTABSENT, "optmissing" }, { ICMP_PARAMPROB_LENGTH, "length" }, { -2, NULL } }; static icmp_type_t icmptypes4[] = { { ICMP_ECHOREPLY, NULL, 0, "echoreply" }, { -1, NULL, 0, NULL }, { -1, NULL, 0, NULL }, { ICMP_UNREACH, icmpunreachnames, IST_SZ(icmpunreachnames),"unreach" }, { ICMP_SOURCEQUENCH, NULL, 0, "sourcequench" }, { ICMP_REDIRECT, redirectnames, IST_SZ(redirectnames), "redirect" }, { -1, NULL, 0, NULL }, { -1, NULL, 0, NULL }, { ICMP_ECHO, NULL, 0, "echo" }, { ICMP_ROUTERADVERT, NULL, 0, "routeradvert" }, { ICMP_ROUTERSOLICIT, NULL, 0, "routersolicit" }, { ICMP_TIMXCEED, timxceednames, IST_SZ(timxceednames), "timxceed" }, { ICMP_PARAMPROB, paramnames, IST_SZ(paramnames), "paramprob" }, { ICMP_TSTAMP, NULL, 0, "timestamp" }, { ICMP_TSTAMPREPLY, NULL, 0, "timestampreply" }, { ICMP_IREQ, NULL, 0, "inforeq" }, { ICMP_IREQREPLY, NULL, 0, "inforeply" }, { ICMP_MASKREQ, NULL, 0, "maskreq" }, { ICMP_MASKREPLY, NULL, 0, "maskreply" }, { -2, NULL, 0, NULL } }; static icmp_subtype_t icmpredirect6[] = { { ICMP6_DST_UNREACH_NOROUTE, "noroute" }, { ICMP6_DST_UNREACH_ADMIN, "admin" }, { ICMP6_DST_UNREACH_NOTNEIGHBOR, "neighbour" }, { ICMP6_DST_UNREACH_ADDR, "address" }, { ICMP6_DST_UNREACH_NOPORT, "noport" }, { -2, NULL } }; static icmp_subtype_t icmptimexceed6[] = { { ICMP6_TIME_EXCEED_TRANSIT, "intransit" }, { ICMP6_TIME_EXCEED_REASSEMBLY, "reassem" }, { -2, NULL } }; static icmp_subtype_t icmpparamprob6[] = { { ICMP6_PARAMPROB_HEADER, "header" }, { ICMP6_PARAMPROB_NEXTHEADER, "nextheader" }, { ICMP6_PARAMPROB_OPTION, "option" }, { -2, NULL } }; static icmp_subtype_t icmpquerysubject6[] = { { ICMP6_NI_SUBJ_IPV6, "ipv6" }, { ICMP6_NI_SUBJ_FQDN, "fqdn" }, { ICMP6_NI_SUBJ_IPV4, "ipv4" }, { -2, NULL }, }; static icmp_subtype_t icmpnodeinfo6[] = { { ICMP6_NI_SUCCESS, "success" }, { ICMP6_NI_REFUSED, "refused" }, { ICMP6_NI_UNKNOWN, "unknown" }, { -2, NULL } }; static icmp_subtype_t icmprenumber6[] = { { ICMP6_ROUTER_RENUMBERING_COMMAND, "command" }, { ICMP6_ROUTER_RENUMBERING_RESULT, "result" }, { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "seqnum_reset" }, { -2, NULL } }; static icmp_type_t icmptypes6[] = { { 0, NULL, 0, NULL }, { ICMP6_DST_UNREACH, icmpredirect6, IST_SZ(icmpredirect6), "unreach" }, { ICMP6_PACKET_TOO_BIG, NULL, 0, "toobig" }, { ICMP6_TIME_EXCEEDED, icmptimexceed6, IST_SZ(icmptimexceed6), "timxceed" }, { ICMP6_PARAM_PROB, icmpparamprob6, IST_SZ(icmpparamprob6), "paramprob" }, { ICMP6_ECHO_REQUEST, NULL, 0, "echo" }, { ICMP6_ECHO_REPLY, NULL, 0, "echoreply" }, { ICMP6_MEMBERSHIP_QUERY, icmpquerysubject6, IST_SZ(icmpquerysubject6), "groupmemberquery" }, { ICMP6_MEMBERSHIP_REPORT,NULL, 0, "groupmemberreport" }, { ICMP6_MEMBERSHIP_REDUCTION,NULL, 0, "groupmemberterm" }, { ND_ROUTER_SOLICIT, NULL, 0, "routersolicit" }, { ND_ROUTER_ADVERT, NULL, 0, "routeradvert" }, { ND_NEIGHBOR_SOLICIT, NULL, 0, "neighborsolicit" }, { ND_NEIGHBOR_ADVERT, NULL, 0, "neighboradvert" }, { ND_REDIRECT, NULL, 0, "redirect" }, { ICMP6_ROUTER_RENUMBERING, icmprenumber6, IST_SZ(icmprenumber6), "routerrenumber" }, { ICMP6_WRUREQUEST, NULL, 0, "whoareyourequest" }, { ICMP6_WRUREPLY, NULL, 0, "whoareyoureply" }, { ICMP6_FQDN_QUERY, NULL, 0, "fqdnquery" }, { ICMP6_FQDN_REPLY, NULL, 0, "fqdnreply" }, { ICMP6_NI_QUERY, icmpnodeinfo6, IST_SZ(icmpnodeinfo6), "nodeinforequest" }, { ICMP6_NI_REPLY, NULL, 0, "nodeinforeply" }, { MLD6_MTRACE_RESP, NULL, 0, "mtraceresponse" }, { MLD6_MTRACE, NULL, 0, "mtracerequest" }, { -2, NULL, 0, NULL } }; static icmp_subtype_t * find_icmpsubtype(int type, icmp_subtype_t *table, size_t tablesz) { icmp_subtype_t *ist; int i; if (tablesz < 2) return (NULL); if ((type < 0) || (type > table[tablesz - 2].ist_val)) return (NULL); i = type; if (table[type].ist_val == type) return (table + type); for (i = 0, ist = table; ist->ist_val != -2; i++, ist++) if (ist->ist_val == type) return (ist); return (NULL); } static icmp_type_t * find_icmptype(int type, icmp_type_t *table, size_t tablesz) { icmp_type_t *it; int i; if (tablesz < 2) return (NULL); if ((type < 0) || (type > table[tablesz - 2].it_val)) return (NULL); i = type; if (table[type].it_val == type) return (table + type); for (i = 0, it = table; it->it_val != -2; i++, it++) if (it->it_val == type) return (it); return (NULL); } static void handlehup(int sig) { signal(SIGHUP, handlehup); donehup = 1; } static void init_tabs(void) { struct protoent *p; struct servent *s; char *name, **tab; int port, i; if (protocols != NULL) { for (i = 0; i < 256; i++) if (protocols[i] != NULL) { free(protocols[i]); protocols[i] = NULL; } free(protocols); protocols = NULL; } protocols = (char **)malloc(256 * sizeof(*protocols)); if (protocols != NULL) { bzero((char *)protocols, 256 * sizeof(*protocols)); setprotoent(1); while ((p = getprotoent()) != NULL) if (p->p_proto >= 0 && p->p_proto <= 255 && p->p_name != NULL && protocols[p->p_proto] == NULL) protocols[p->p_proto] = strdup(p->p_name); endprotoent(); if (protocols[0]) free(protocols[0]); protocols[0] = strdup("ip"); } if (udp_ports != NULL) { for (i = 0; i < 65536; i++) if (udp_ports[i] != NULL) { free(udp_ports[i]); udp_ports[i] = NULL; } free(udp_ports); udp_ports = NULL; } udp_ports = (char **)malloc(65536 * sizeof(*udp_ports)); if (udp_ports != NULL) bzero((char *)udp_ports, 65536 * sizeof(*udp_ports)); if (tcp_ports != NULL) { for (i = 0; i < 65536; i++) if (tcp_ports[i] != NULL) { free(tcp_ports[i]); tcp_ports[i] = NULL; } free(tcp_ports); tcp_ports = NULL; } tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports)); if (tcp_ports != NULL) bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports)); setservent(1); while ((s = getservent()) != NULL) { if (s->s_proto == NULL) continue; else if (!strcmp(s->s_proto, "tcp")) { port = ntohs(s->s_port); name = s->s_name; tab = tcp_ports; } else if (!strcmp(s->s_proto, "udp")) { port = ntohs(s->s_port); name = s->s_name; tab = udp_ports; } else continue; if ((port < 0 || port > 65535) || (name == NULL)) continue; if (tab != NULL) tab[port] = strdup(name); } endservent(); } static char * getlocalproto(u_int p) { static char pnum[4]; char *s; p &= 0xff; s = protocols ? protocols[p] : NULL; if (s == NULL) { sprintf(pnum, "%u", p); s = pnum; } return (s); } static int read_log(int fd, int *lenp, char *buf, int bufsize) { int nr; if (bufsize > IPFILTER_LOGSIZE) bufsize = IPFILTER_LOGSIZE; nr = read(fd, buf, bufsize); if (!nr) return (2); if ((nr < 0) && (errno != EINTR)) return (-1); *lenp = nr; return (0); } char * -portlocalname(res, proto, port) - int res; - char *proto; - u_int port; +portlocalname(int res, char *proto, u_int port) { static char pname[8]; char *s; port = ntohs(port); port &= 0xffff; sprintf(pname, "%u", port); if (!res || (ipmonopts & IPMON_PORTNUM)) return (pname); s = NULL; if (!strcmp(proto, "tcp")) s = tcp_ports[port]; else if (!strcmp(proto, "udp")) s = udp_ports[port]; if (s == NULL) s = pname; return (s); } static char * icmpname(u_int type, u_int code) { static char name[80]; icmp_subtype_t *ist; icmp_type_t *it; char *s; s = NULL; it = find_icmptype(type, icmptypes4, sizeof(icmptypes4) / sizeof(*it)); if (it != NULL) s = it->it_name; if (s == NULL) sprintf(name, "icmptype(%d)/", type); else sprintf(name, "%s/", s); ist = NULL; if (it != NULL && it->it_subtable != NULL) ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); if (ist != NULL && ist->ist_name != NULL) strcat(name, ist->ist_name); else sprintf(name + strlen(name), "%d", code); return (name); } static char * icmpname6(u_int type, u_int code) { static char name[80]; icmp_subtype_t *ist; icmp_type_t *it; char *s; s = NULL; it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it)); if (it != NULL) s = it->it_name; if (s == NULL) sprintf(name, "icmpv6type(%d)/", type); else sprintf(name, "%s/", s); ist = NULL; if (it != NULL && it->it_subtable != NULL) ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); if (ist != NULL && ist->ist_name != NULL) strcat(name, ist->ist_name); else sprintf(name + strlen(name), "%d", code); return (name); } void dumphex(FILE *log, int dopts, char *buf, int len) { char hline[80]; int i, j, k; u_char *s = (u_char *)buf, *t = (u_char *)hline; if (buf == NULL || len == 0) return; *hline = '\0'; for (i = len, j = 0; i; i--, j++, s++) { if (j && !(j & 0xf)) { *t++ = '\n'; *t = '\0'; if ((dopts & IPMON_SYSLOG)) syslog(LOG_INFO, "%s", hline); else if (log != NULL) fputs(hline, log); t = (u_char *)hline; *t = '\0'; } sprintf((char *)t, "%02x", *s & 0xff); t += 2; if (!((j + 1) & 0xf)) { s -= 15; sprintf((char *)t, " "); t += 8; for (k = 16; k; k--, s++) *t++ = (isprint(*s) ? *s : '.'); s--; } if ((j + 1) & 0xf) *t++ = ' ';; } if (j & 0xf) { for (k = 16 - (j & 0xf); k; k--) { *t++ = ' '; *t++ = ' '; *t++ = ' '; } sprintf((char *)t, " "); t += 7; s -= j & 0xf; for (k = j & 0xf; k; k--, s++) *t++ = (isprint(*s) ? *s : '.'); *t++ = '\n'; *t = '\0'; } if ((dopts & IPMON_SYSLOG) != 0) syslog(LOG_INFO, "%s", hline); else if (log != NULL) { fputs(hline, log); fflush(log); } } static struct tm * get_tm(time_t sec) { struct tm *tm; time_t t; t = sec; tm = localtime(&t); return (tm); } static void print_natlog(config_t *conf, char *buf, int blen) { static u_32_t seqnum = 0; int res, i, len, family; struct natlog *nl; struct tm *tm; iplog_t *ipl; char *proto; int simple; char *t; t = line; simple = 0; ipl = (iplog_t *)buf; if (ipl->ipl_seqnum != seqnum) { if ((ipmonopts & IPMON_SYSLOG) != 0) { syslog(LOG_WARNING, "missed %u NAT log entries: %u %u", ipl->ipl_seqnum - seqnum, seqnum, ipl->ipl_seqnum); } else { (void) fprintf(conf->log, "missed %u NAT log entries: %u %u\n", ipl->ipl_seqnum - seqnum, seqnum, ipl->ipl_seqnum); } } seqnum = ipl->ipl_seqnum + ipl->ipl_count; nl = (struct natlog *)((char *)ipl + sizeof(*ipl)); res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(ipmonopts & IPMON_SYSLOG)) { (void) strftime(t, len, "%d/%m/%Y ", tm); i = strlen(t); len -= i; t += i; } (void) strftime(t, len, "%T", tm); t += strlen(t); sprintf(t, ".%-.6ld @%hd ", (long)ipl->ipl_usec, nl->nl_rule + 1); t += strlen(t); switch (nl->nl_action) { case NL_NEW : strcpy(t, "NAT:NEW"); break; case NL_FLUSH : strcpy(t, "NAT:FLUSH"); break; case NL_CLONE : strcpy(t, "NAT:CLONE"); break; case NL_EXPIRE : strcpy(t, "NAT:EXPIRE"); break; case NL_DESTROY : strcpy(t, "NAT:DESTROY"); break; case NL_PURGE : strcpy(t, "NAT:PURGE"); break; default : sprintf(t, "NAT:Action(%d)", nl->nl_action); break; } t += strlen(t); switch (nl->nl_type) { case NAT_MAP : strcpy(t, "-MAP "); simple = 1; break; case NAT_REDIRECT : strcpy(t, "-RDR "); simple = 1; break; case NAT_BIMAP : strcpy(t, "-BIMAP "); simple = 1; break; case NAT_MAPBLK : strcpy(t, "-MAPBLOCK "); simple = 1; break; case NAT_REWRITE|NAT_MAP : strcpy(t, "-RWR_MAP "); break; case NAT_REWRITE|NAT_REDIRECT : strcpy(t, "-RWR_RDR "); break; case NAT_ENCAP|NAT_MAP : strcpy(t, "-ENC_MAP "); break; case NAT_ENCAP|NAT_REDIRECT : strcpy(t, "-ENC_RDR "); break; case NAT_DIVERTUDP|NAT_MAP : strcpy(t, "-DIV_MAP "); break; case NAT_DIVERTUDP|NAT_REDIRECT : strcpy(t, "-DIV_RDR "); break; default : sprintf(t, "-Type(%d) ", nl->nl_type); break; } t += strlen(t); proto = getlocalproto(nl->nl_p[0]); family = vtof(nl->nl_v[0]); if (simple == 1) { sprintf(t, "%s,%s <- -> ", hostname(family, nl->nl_osrcip.i6), portlocalname(res, proto, (u_int)nl->nl_osrcport)); t += strlen(t); sprintf(t, "%s,%s ", hostname(family, nl->nl_nsrcip.i6), portlocalname(res, proto, (u_int)nl->nl_nsrcport)); t += strlen(t); sprintf(t, "[%s,%s] ", hostname(family, nl->nl_odstip.i6), portlocalname(res, proto, (u_int)nl->nl_odstport)); } else { sprintf(t, "%s,%s ", hostname(family, nl->nl_osrcip.i6), portlocalname(res, proto, (u_int)nl->nl_osrcport)); t += strlen(t); sprintf(t, "%s,%s <- -> ", hostname(family, nl->nl_odstip.i6), portlocalname(res, proto, (u_int)nl->nl_odstport)); t += strlen(t); sprintf(t, "%s,%s ", hostname(family, nl->nl_nsrcip.i6), portlocalname(res, proto, (u_int)nl->nl_nsrcport)); t += strlen(t); sprintf(t, "%s,%s ", hostname(family, nl->nl_ndstip.i6), portlocalname(res, proto, (u_int)nl->nl_ndstport)); } t += strlen(t); strcpy(t, getlocalproto(nl->nl_p[0])); t += strlen(t); if (nl->nl_action == NL_EXPIRE || nl->nl_action == NL_FLUSH) { #ifdef USE_QUAD_T # ifdef PRId64 sprintf(t, " Pkts %" PRId64 "/%" PRId64 " Bytes %" PRId64 "/%" PRId64, # else sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd", # endif #else sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld", #endif nl->nl_pkts[0], nl->nl_pkts[1], nl->nl_bytes[0], nl->nl_bytes[1]); t += strlen(t); } *t++ = '\n'; *t++ = '\0'; if (ipmonopts & IPMON_SYSLOG) syslog(LOG_INFO, "%s", line); else if (conf->log != NULL) (void) fprintf(conf->log, "%s", line); } static void print_statelog(config_t *conf, char *buf, int blen) { static u_32_t seqnum = 0; int res, i, len, family; struct ipslog *sl; char *t, *proto; struct tm *tm; iplog_t *ipl; t = line; ipl = (iplog_t *)buf; if (ipl->ipl_seqnum != seqnum) { if ((ipmonopts & IPMON_SYSLOG) != 0) { syslog(LOG_WARNING, "missed %u state log entries: %u %u", ipl->ipl_seqnum - seqnum, seqnum, ipl->ipl_seqnum); } else { (void) fprintf(conf->log, "missed %u state log entries: %u %u\n", ipl->ipl_seqnum - seqnum, seqnum, ipl->ipl_seqnum); } } seqnum = ipl->ipl_seqnum + ipl->ipl_count; sl = (struct ipslog *)((char *)ipl + sizeof(*ipl)); res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(ipmonopts & IPMON_SYSLOG)) { (void) strftime(t, len, "%d/%m/%Y ", tm); i = strlen(t); len -= i; t += i; } (void) strftime(t, len, "%T", tm); t += strlen(t); sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec); t += strlen(t); family = vtof(sl->isl_v); switch (sl->isl_type) { case ISL_NEW : strcpy(t, "STATE:NEW "); break; case ISL_CLONE : strcpy(t, "STATE:CLONED "); break; case ISL_EXPIRE : if ((sl->isl_p == IPPROTO_TCP) && (sl->isl_state[0] > IPF_TCPS_ESTABLISHED || sl->isl_state[1] > IPF_TCPS_ESTABLISHED)) strcpy(t, "STATE:CLOSE "); else strcpy(t, "STATE:EXPIRE "); break; case ISL_FLUSH : strcpy(t, "STATE:FLUSH "); break; case ISL_INTERMEDIATE : strcpy(t, "STATE:INTERMEDIATE "); break; case ISL_REMOVE : strcpy(t, "STATE:REMOVE "); break; case ISL_KILLED : strcpy(t, "STATE:KILLED "); break; case ISL_UNLOAD : strcpy(t, "STATE:UNLOAD "); break; default : sprintf(t, "Type: %d ", sl->isl_type); break; } t += strlen(t); proto = getlocalproto(sl->isl_p); if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { sprintf(t, "%s,%s -> ", hostname(family, (u_32_t *)&sl->isl_src), portlocalname(res, proto, (u_int)sl->isl_sport)); t += strlen(t); sprintf(t, "%s,%s PR %s", hostname(family, (u_32_t *)&sl->isl_dst), portlocalname(res, proto, (u_int)sl->isl_dport), proto); } else if (sl->isl_p == IPPROTO_ICMP) { sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); t += strlen(t); sprintf(t, "%s PR icmp %d", hostname(family, (u_32_t *)&sl->isl_dst), sl->isl_itype); } else if (sl->isl_p == IPPROTO_ICMPV6) { sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); t += strlen(t); sprintf(t, "%s PR icmpv6 %d", hostname(family, (u_32_t *)&sl->isl_dst), sl->isl_itype); } else { sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); t += strlen(t); sprintf(t, "%s PR %s", hostname(family, (u_32_t *)&sl->isl_dst), proto); } t += strlen(t); if (sl->isl_tag != FR_NOLOGTAG) { sprintf(t, " tag %u", sl->isl_tag); t += strlen(t); } if (sl->isl_type != ISL_NEW) { sprintf(t, #ifdef USE_QUAD_T #ifdef PRId64 " Forward: Pkts in %" PRId64 " Bytes in %" PRId64 " Pkts out %" PRId64 " Bytes out %" PRId64 " Backward: Pkts in %" PRId64 " Bytes in %" PRId64 " Pkts out %" PRId64 " Bytes out %" PRId64, #else " Forward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd Backward: Pkts in %qd Bytes in %qd Pkts out %qd Bytes out %qd", #endif /* PRId64 */ #else " Forward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld Backward: Pkts in %ld Bytes in %ld Pkts out %ld Bytes out %ld", #endif sl->isl_pkts[0], sl->isl_bytes[0], sl->isl_pkts[1], sl->isl_bytes[1], sl->isl_pkts[2], sl->isl_bytes[2], sl->isl_pkts[3], sl->isl_bytes[3]); t += strlen(t); } *t++ = '\n'; *t++ = '\0'; if (ipmonopts & IPMON_SYSLOG) syslog(LOG_INFO, "%s", line); else if (conf->log != NULL) (void) fprintf(conf->log, "%s", line); } static void print_log(config_t *conf, logsource_t *log, char *buf, int blen) { char *bp, *bpo; iplog_t *ipl; int psize; bp = NULL; bpo = NULL; while (blen > 0) { ipl = (iplog_t *)buf; if ((u_long)ipl & (sizeof(long)-1)) { if (bp) bpo = bp; bp = (char *)malloc(blen); bcopy((char *)ipl, bp, blen); if (bpo) { free(bpo); bpo = NULL; } buf = bp; continue; } psize = ipl->ipl_dsize; if (psize > blen) break; if (conf->blog != NULL) { fwrite(buf, psize, 1, conf->blog); fflush(conf->blog); } if (log->logtype == IPL_LOGIPF) { if (ipl->ipl_magic == IPL_MAGIC) print_ipflog(conf, buf, psize); } else if (log->logtype == IPL_LOGNAT) { if (ipl->ipl_magic == IPL_MAGIC_NAT) print_natlog(conf, buf, psize); } else if (log->logtype == IPL_LOGSTATE) { if (ipl->ipl_magic == IPL_MAGIC_STATE) print_statelog(conf, buf, psize); } blen -= psize; buf += psize; } if (bp) free(bp); return; } static void print_ipflog(config_t *conf, char *buf, int blen) { static u_32_t seqnum = 0; int i, f, lvl, res, len, off, plen, ipoff, defaction; struct icmp *icmp; struct icmp *ic; char *t, *proto; ip_t *ipc, *ip; struct tm *tm; u_32_t *s, *d; u_short hl, p; ipflog_t *ipf; iplog_t *ipl; tcphdr_t *tp; #ifdef USE_INET6 struct ip6_ext *ehp; u_short ehl; ip6_t *ip6; int go; #endif ipl = (iplog_t *)buf; if (ipl->ipl_seqnum != seqnum) { if ((ipmonopts & IPMON_SYSLOG) != 0) { syslog(LOG_WARNING, "missed %u ipf log entries: %u %u", ipl->ipl_seqnum - seqnum, seqnum, ipl->ipl_seqnum); } else { (void) fprintf(conf->log, "missed %u ipf log entries: %u %u\n", ipl->ipl_seqnum - seqnum, seqnum, ipl->ipl_seqnum); } } seqnum = ipl->ipl_seqnum + ipl->ipl_count; ipf = (ipflog_t *)((char *)buf + sizeof(*ipl)); ip = (ip_t *)((char *)ipf + sizeof(*ipf)); f = ipf->fl_family; res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; t = line; *t = '\0'; tm = get_tm(ipl->ipl_sec); len = sizeof(line); if (!(ipmonopts & IPMON_SYSLOG)) { (void) strftime(t, len, "%d/%m/%Y ", tm); i = strlen(t); len -= i; t += i; } (void) strftime(t, len, "%T", tm); t += strlen(t); sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec); t += strlen(t); if (ipl->ipl_count > 1) { sprintf(t, "%dx ", ipl->ipl_count); t += strlen(t); } { char ifname[sizeof(ipf->fl_ifname) + 1]; strncpy(ifname, ipf->fl_ifname, sizeof(ipf->fl_ifname)); ifname[sizeof(ipf->fl_ifname)] = '\0'; sprintf(t, "%s", ifname); t += strlen(t); # if SOLARIS if (ISALPHA(*(t - 1))) { sprintf(t, "%d", ipf->fl_unit); t += strlen(t); } # endif } if ((ipf->fl_group[0] == (char)~0) && (ipf->fl_group[1] == '\0')) strcat(t, " @-1:"); else if (ipf->fl_group[0] == '\0') (void) strcpy(t, " @0:"); else sprintf(t, " @%s:", ipf->fl_group); t += strlen(t); if (ipf->fl_rule == 0xffffffff) strcat(t, "-1 "); else sprintf(t, "%u ", ipf->fl_rule + 1); t += strlen(t); lvl = LOG_NOTICE; if (ipf->fl_lflags & FI_SHORT) { *t++ = 'S'; lvl = LOG_ERR; } if (FR_ISPASS(ipf->fl_flags)) { if (ipf->fl_flags & FR_LOGP) *t++ = 'p'; else *t++ = 'P'; } else if (FR_ISBLOCK(ipf->fl_flags)) { if (ipf->fl_flags & FR_LOGB) *t++ = 'b'; else *t++ = 'B'; lvl = LOG_WARNING; } else if ((ipf->fl_flags & FR_LOGMASK) == FR_LOG) { *t++ = 'L'; lvl = LOG_INFO; } else if (ipf->fl_flags & FF_LOGNOMATCH) { *t++ = 'n'; } else { *t++ = '?'; lvl = LOG_EMERG; } if (ipf->fl_loglevel != 0xffff) lvl = ipf->fl_loglevel; *t++ = ' '; *t = '\0'; if (f == AF_INET) { hl = IP_HL(ip) << 2; ipoff = ntohs(ip->ip_off); off = ipoff & IP_OFFMASK; p = (u_short)ip->ip_p; s = (u_32_t *)&ip->ip_src; d = (u_32_t *)&ip->ip_dst; plen = ntohs(ip->ip_len); } else #ifdef USE_INET6 if (f == AF_INET6) { off = 0; ipoff = 0; hl = sizeof(ip6_t); ip6 = (ip6_t *)ip; p = (u_short)ip6->ip6_nxt; s = (u_32_t *)&ip6->ip6_src; d = (u_32_t *)&ip6->ip6_dst; plen = hl + ntohs(ip6->ip6_plen); go = 1; ehp = (struct ip6_ext *)((char *)ip6 + hl); while (go == 1) { switch (p) { case IPPROTO_HOPOPTS : case IPPROTO_MOBILITY : case IPPROTO_DSTOPTS : case IPPROTO_ROUTING : case IPPROTO_AH : p = ehp->ip6e_nxt; ehl = 8 + (ehp->ip6e_len << 3); hl += ehl; ehp = (struct ip6_ext *)((char *)ehp + ehl); break; case IPPROTO_FRAGMENT : hl += sizeof(struct ip6_frag); /* FALLTHROUGH */ default : go = 0; break; } } } else #endif { goto printipflog; } proto = getlocalproto(p); if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { tp = (tcphdr_t *)((char *)ip + hl); if (!(ipf->fl_lflags & FI_SHORT)) { sprintf(t, "%s,%s -> ", hostname(f, s), portlocalname(res, proto, (u_int)tp->th_sport)); t += strlen(t); sprintf(t, "%s,%s PR %s len %hu %hu", hostname(f, d), portlocalname(res, proto, (u_int)tp->th_dport), proto, hl, plen); t += strlen(t); if (p == IPPROTO_TCP) { *t++ = ' '; *t++ = '-'; for (i = 0; tcpfl[i].value; i++) if (tp->th_flags & tcpfl[i].value) *t++ = tcpfl[i].flag; if (ipmonopts & IPMON_VERBOSE) { sprintf(t, " %lu %lu %hu", (u_long)(ntohl(tp->th_seq)), (u_long)(ntohl(tp->th_ack)), ntohs(tp->th_win)); t += strlen(t); } } *t = '\0'; } else { sprintf(t, "%s -> ", hostname(f, s)); t += strlen(t); sprintf(t, "%s PR %s len %hu %hu", hostname(f, d), proto, hl, plen); } #if defined(AF_INET6) && defined(IPPROTO_ICMPV6) } else if ((p == IPPROTO_ICMPV6) && !off && (f == AF_INET6)) { ic = (struct icmp *)((char *)ip + hl); sprintf(t, "%s -> ", hostname(f, s)); t += strlen(t); sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s", hostname(f, d), hl, plen, icmpname6(ic->icmp_type, ic->icmp_code)); #endif } else if ((p == IPPROTO_ICMP) && !off && (f == AF_INET)) { ic = (struct icmp *)((char *)ip + hl); sprintf(t, "%s -> ", hostname(f, s)); t += strlen(t); sprintf(t, "%s PR icmp len %hu %hu icmp %s", hostname(f, d), hl, plen, icmpname(ic->icmp_type, ic->icmp_code)); if (ic->icmp_type == ICMP_UNREACH || ic->icmp_type == ICMP_SOURCEQUENCH || ic->icmp_type == ICMP_PARAMPROB || ic->icmp_type == ICMP_REDIRECT || ic->icmp_type == ICMP_TIMXCEED) { ipc = &ic->icmp_ip; i = ntohs(ipc->ip_len); /* * XXX - try to guess endian of ip_len in ICMP * returned data. */ if (i > 1500) i = ipc->ip_len; ipoff = ntohs(ipc->ip_off); proto = getlocalproto(ipc->ip_p); if (!(ipoff & IP_OFFMASK) && ((ipc->ip_p == IPPROTO_TCP) || (ipc->ip_p == IPPROTO_UDP))) { tp = (tcphdr_t *)((char *)ipc + hl); t += strlen(t); sprintf(t, " for %s,%s -", HOSTNAMEV4(ipc->ip_src), portlocalname(res, proto, (u_int)tp->th_sport)); t += strlen(t); sprintf(t, " %s,%s PR %s len %hu %hu", HOSTNAMEV4(ipc->ip_dst), portlocalname(res, proto, (u_int)tp->th_dport), proto, IP_HL(ipc) << 2, i); } else if (!(ipoff & IP_OFFMASK) && (ipc->ip_p == IPPROTO_ICMP)) { icmp = (icmphdr_t *)((char *)ipc + hl); t += strlen(t); sprintf(t, " for %s -", HOSTNAMEV4(ipc->ip_src)); t += strlen(t); sprintf(t, " %s PR icmp len %hu %hu icmp %d/%d", HOSTNAMEV4(ipc->ip_dst), IP_HL(ipc) << 2, i, icmp->icmp_type, icmp->icmp_code); } else { t += strlen(t); sprintf(t, " for %s -", HOSTNAMEV4(ipc->ip_src)); t += strlen(t); sprintf(t, " %s PR %s len %hu (%hu)", HOSTNAMEV4(ipc->ip_dst), proto, IP_HL(ipc) << 2, i); t += strlen(t); if (ipoff & IP_OFFMASK) { sprintf(t, "(frag %d:%hu@%hu%s%s)", ntohs(ipc->ip_id), i - (IP_HL(ipc) << 2), (ipoff & IP_OFFMASK) << 3, ipoff & IP_MF ? "+" : "", ipoff & IP_DF ? "-" : ""); } } } } else { sprintf(t, "%s -> ", hostname(f, s)); t += strlen(t); sprintf(t, "%s PR %s len %hu (%hu)", hostname(f, d), proto, hl, plen); t += strlen(t); if (off & IP_OFFMASK) sprintf(t, " (frag %d:%hu@%hu%s%s)", ntohs(ip->ip_id), plen - hl, (off & IP_OFFMASK) << 3, ipoff & IP_MF ? "+" : "", ipoff & IP_DF ? "-" : ""); } t += strlen(t); printipflog: if (ipf->fl_flags & FR_KEEPSTATE) { (void) strcpy(t, " K-S"); t += strlen(t); } if (ipf->fl_flags & FR_KEEPFRAG) { (void) strcpy(t, " K-F"); t += strlen(t); } if (ipf->fl_dir == 0) strcpy(t, " IN"); else if (ipf->fl_dir == 1) strcpy(t, " OUT"); t += strlen(t); if (ipf->fl_logtag != 0) { sprintf(t, " log-tag %d", ipf->fl_logtag); t += strlen(t); } if (ipf->fl_nattag.ipt_num[0] != 0) { strcpy(t, " nat-tag "); t += strlen(t); strncpy(t, ipf->fl_nattag.ipt_tag, sizeof(ipf->fl_nattag)); t += strlen(t); } if ((ipf->fl_lflags & FI_LOWTTL) != 0) { strcpy(t, " low-ttl"); t += 8; } if ((ipf->fl_lflags & FI_OOW) != 0) { strcpy(t, " OOW"); t += 4; } if ((ipf->fl_lflags & FI_BAD) != 0) { strcpy(t, " bad"); t += 4; } if ((ipf->fl_lflags & FI_NATED) != 0) { strcpy(t, " NAT"); t += 4; } if ((ipf->fl_lflags & FI_BADNAT) != 0) { strcpy(t, " bad-NAT"); t += 8; } if ((ipf->fl_lflags & FI_BADSRC) != 0) { strcpy(t, " bad-src"); t += 8; } if ((ipf->fl_lflags & FI_MULTICAST) != 0) { strcpy(t, " multicast"); t += 10; } if ((ipf->fl_lflags & FI_BROADCAST) != 0) { strcpy(t, " broadcast"); t += 10; } if ((ipf->fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) == FI_MBCAST) { strcpy(t, " mbcast"); t += 7; } if (ipf->fl_breason != 0) { strcpy(t, " reason:"); t += 8; strcpy(t, reasons[ipf->fl_breason]); t += strlen(reasons[ipf->fl_breason]); } *t++ = '\n'; *t++ = '\0'; defaction = 0; if (conf->cfile != NULL) defaction = check_action(buf, line, ipmonopts, lvl); if (defaction == 0) { if (ipmonopts & IPMON_SYSLOG) { syslog(lvl, "%s", line); } else if (conf->log != NULL) { (void) fprintf(conf->log, "%s", line); } if (ipmonopts & IPMON_HEXHDR) { dumphex(conf->log, ipmonopts, buf, sizeof(iplog_t) + sizeof(*ipf)); } if (ipmonopts & IPMON_HEXBODY) { dumphex(conf->log, ipmonopts, (char *)ip, ipf->fl_plen + ipf->fl_hlen); } else if ((ipmonopts & IPMON_LOGBODY) && (ipf->fl_flags & FR_LOGBODY)) { dumphex(conf->log, ipmonopts, (char *)ip + ipf->fl_hlen, ipf->fl_plen); } } } static void usage(char *prog) { fprintf(stderr, "Usage: %s [ -abDFhnpstvxX ] [ -B ] [ -C ]\n" "\t[ -f ] [ -L ] [ -N ]\n" "\t[ -o [NSI] ] [ -O [NSI] ] [ -P ] [ -S ]\n" "\t[ ]\n", prog); exit(1); } static void write_pid(char *file) { FILE *fp = NULL; int fd; if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) { fp = fdopen(fd, "w"); if (fp == NULL) { close(fd); fprintf(stderr, "unable to open/create pid file: %s\n", file); return; } fprintf(fp, "%d", getpid()); fclose(fp); } } static void flushlogs(char *file, FILE *log) { int fd, flushed = 0; if ((fd = open(file, O_RDWR)) == -1) { (void) fprintf(stderr, "%s: open: %s\n", file, STRERROR(errno)); exit(1); } if (ioctl(fd, SIOCIPFFB, &flushed) == 0) { printf("%d bytes flushed from log buffer\n", flushed); fflush(stdout); } else ipferror(fd, "SIOCIPFFB"); (void) close(fd); if (flushed) { if (ipmonopts & IPMON_SYSLOG) { syslog(LOG_INFO, "%d bytes flushed from log\n", flushed); } else if ((log != stdout) && (log != NULL)) { fprintf(log, "%d bytes flushed from log\n", flushed); } } } static void logopts(int turnon, char *options) { int flags = 0; char *s; for (s = options; *s; s++) { switch (*s) { case 'N' : flags |= IPMON_NAT; break; case 'S' : flags |= IPMON_STATE; break; case 'I' : flags |= IPMON_FILTER; break; default : fprintf(stderr, "Unknown log option %c\n", *s); exit(1); } } if (turnon) ipmonopts |= flags; else ipmonopts &= ~(flags); } static void initconfig(config_t *conf) { int i; memset(conf, 0, sizeof(*conf)); conf->log = stdout; conf->maxfd = -1; for (i = 0; i < 3; i++) { conf->logsrc[i].fd = -1; conf->logsrc[i].logtype = -1; conf->logsrc[i].regular = -1; } conf->logsrc[0].file = IPL_NAME; conf->logsrc[1].file = IPNAT_NAME; conf->logsrc[2].file = IPSTATE_NAME; add_doing(&executesaver); add_doing(&snmpv1saver); add_doing(&snmpv2saver); add_doing(&syslogsaver); add_doing(&filesaver); add_doing(¬hingsaver); } int main(int argc, char *argv[]) { int doread, c, make_daemon = 0; char *prog; config_t config; prog = strrchr(argv[0], '/'); if (prog == NULL) prog = argv[0]; else prog++; initconfig(&config); while ((c = getopt(argc, argv, "?abB:C:Df:FhL:nN:o:O:pP:sS:tvxX")) != -1) switch (c) { case 'a' : ipmonopts |= IPMON_LOGALL; config.logsrc[0].logtype = IPL_LOGIPF; config.logsrc[1].logtype = IPL_LOGNAT; config.logsrc[2].logtype = IPL_LOGSTATE; break; case 'b' : ipmonopts |= IPMON_LOGBODY; break; case 'B' : config.bfile = optarg; config.blog = fopen(optarg, "a"); break; case 'C' : config.cfile = optarg; break; case 'D' : make_daemon = 1; break; case 'f' : case 'I' : ipmonopts |= IPMON_FILTER; config.logsrc[0].logtype = IPL_LOGIPF; config.logsrc[0].file = optarg; break; case 'F' : flushlogs(config.logsrc[0].file, config.log); flushlogs(config.logsrc[1].file, config.log); flushlogs(config.logsrc[2].file, config.log); break; case 'L' : logfac = fac_findname(optarg); if (logfac == -1) { fprintf(stderr, "Unknown syslog facility '%s'\n", optarg); exit(1); } break; case 'n' : ipmonopts |= IPMON_RESOLVE; opts &= ~OPT_NORESOLVE; break; case 'N' : ipmonopts |= IPMON_NAT; config.logsrc[1].logtype = IPL_LOGNAT; config.logsrc[1].file = optarg; break; case 'o' : case 'O' : logopts(c == 'o', optarg); if (ipmonopts & IPMON_FILTER) config.logsrc[0].logtype = IPL_LOGIPF; if (ipmonopts & IPMON_NAT) config.logsrc[1].logtype = IPL_LOGNAT; if (ipmonopts & IPMON_STATE) config.logsrc[2].logtype = IPL_LOGSTATE; break; case 'p' : ipmonopts |= IPMON_PORTNUM; break; case 'P' : pidfile = optarg; break; case 's' : ipmonopts |= IPMON_SYSLOG; config.log = NULL; break; case 'S' : ipmonopts |= IPMON_STATE; config.logsrc[2].logtype = IPL_LOGSTATE; config.logsrc[2].file = optarg; break; case 't' : ipmonopts |= IPMON_TAIL; break; case 'v' : ipmonopts |= IPMON_VERBOSE; break; case 'x' : ipmonopts |= IPMON_HEXBODY; break; case 'X' : ipmonopts |= IPMON_HEXHDR; break; default : case 'h' : case '?' : usage(argv[0]); } if (ipmonopts & IPMON_SYSLOG) openlog(prog, LOG_NDELAY|LOG_PID, logfac); init_tabs(); if (config.cfile) if (load_config(config.cfile) == -1) { unload_config(); exit(1); } /* * Default action is to only open the filter log file. */ if ((config.logsrc[0].logtype == -1) && (config.logsrc[0].logtype == -1) && (config.logsrc[0].logtype == -1)) config.logsrc[0].logtype = IPL_LOGIPF; openlogs(&config); if (!(ipmonopts & IPMON_SYSLOG)) { config.file = argv[optind]; config.log = config.file ? fopen(config.file, "a") : stdout; if (config.log == NULL) { (void) fprintf(stderr, "%s: fopen: %s\n", argv[optind], STRERROR(errno)); exit(1); /* NOTREACHED */ } setvbuf(config.log, NULL, _IONBF, 0); } else { config.log = NULL; } if (make_daemon && ((config.log != stdout) || (ipmonopts & IPMON_SYSLOG))) { #ifdef BSD daemon(0, !(ipmonopts & IPMON_SYSLOG)); #else int pid; switch (fork()) { case -1 : (void) fprintf(stderr, "%s: fork() failed: %s\n", argv[0], STRERROR(errno)); exit(1); /* NOTREACHED */ case 0 : break; default : exit(0); } setsid(); if ((ipmonopts & IPMON_SYSLOG)) close(2); #endif /* !BSD */ close(0); close(1); write_pid(pidfile); } signal(SIGHUP, handlehup); for (doread = 1; doread; ) doread = read_loginfo(&config); unload_config(); return (0); /* NOTREACHED */ } static void openlogs(config_t *conf) { logsource_t *l; struct stat sb; int i; for (i = 0; i < 3; i++) { l = &conf->logsrc[i]; if (l->logtype == -1) continue; if (!strcmp(l->file, "-")) l->fd = 0; else { if ((l->fd= open(l->file, O_RDONLY)) == -1) { (void) fprintf(stderr, "%s: open: %s\n", l->file, STRERROR(errno)); exit(1); /* NOTREACHED */ } if (fstat(l->fd, &sb) == -1) { (void) fprintf(stderr, "%d: fstat: %s\n", l->fd, STRERROR(errno)); exit(1); /* NOTREACHED */ } l->regular = !S_ISCHR(sb.st_mode); if (l->regular) l->size = sb.st_size; FD_SET(l->fd, &conf->fdmr); if (l->fd > conf->maxfd) conf->maxfd = l->fd; } } } static int read_loginfo(config_t *conf) { iplog_t buf[DEFAULT_IPFLOGSIZE/sizeof(iplog_t)+1]; int n, tr, nr, i; logsource_t *l; fd_set fdr; fdr = conf->fdmr; n = select(conf->maxfd + 1, &fdr, NULL, NULL, NULL); if (n == 0) return (1); if (n == -1) { if (errno == EINTR) return (1); return (-1); } for (i = 0, nr = 0; i < 3; i++) { l = &conf->logsrc[i]; if ((l->logtype == -1) || !FD_ISSET(l->fd, &fdr)) continue; tr = 0; if (l->regular) { tr = (lseek(l->fd, 0, SEEK_CUR) < l->size); if (!tr && !(ipmonopts & IPMON_TAIL)) return (0); } n = 0; tr = read_log(l->fd, &n, (char *)buf, sizeof(buf)); if (donehup) { if (conf->file != NULL) { if (conf->log != NULL) { fclose(conf->log); conf->log = NULL; } conf->log = fopen(conf->file, "a"); } if (conf->bfile != NULL) { if (conf->blog != NULL) { fclose(conf->blog); conf->blog = NULL; } conf->blog = fopen(conf->bfile, "a"); } init_tabs(); if (conf->cfile != NULL) load_config(conf->cfile); donehup = 0; } switch (tr) { case -1 : if (ipmonopts & IPMON_SYSLOG) syslog(LOG_CRIT, "read: %m\n"); else { ipferror(l->fd, "read"); } return (0); case 1 : if (ipmonopts & IPMON_SYSLOG) syslog(LOG_CRIT, "aborting logging\n"); else if (conf->log != NULL) fprintf(conf->log, "aborting logging\n"); return (0); case 2 : break; case 0 : nr += tr; if (n > 0) { print_log(conf, l, (char *)buf, n); if (!(ipmonopts & IPMON_SYSLOG)) fflush(conf->log); } break; } } if (!nr && (ipmonopts & IPMON_TAIL)) sleep(1); return (1); } diff --git a/sbin/ipf/libipf/mutex_emul.c b/sbin/ipf/libipf/mutex_emul.c index 3152d2e47013..a7e1c1389901 100644 --- a/sbin/ipf/libipf/mutex_emul.c +++ b/sbin/ipf/libipf/mutex_emul.c @@ -1,123 +1,120 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id$ */ #include "ipf.h" #define EMM_MAGIC 0x9d7adba3 static int mutex_debug = 0; static FILE *mutex_file = NULL; static int initcount = 0; void eMmutex_enter(eMmutex_t *mtx, char *file, int line) { if (mutex_debug & 2) fprintf(mutex_file, "%s:%d:eMmutex_enter(%s)\n", file, line, mtx->eMm_owner); if (mtx->eMm_magic != EMM_MAGIC) { fprintf(stderr, "%s:eMmutex_enter(%p): bad magic: %#x\n", mtx->eMm_owner, mtx, mtx->eMm_magic); abort(); } if (mtx->eMm_held != 0) { fprintf(stderr, "%s:eMmutex_enter(%p): already locked: %d\n", mtx->eMm_owner, mtx, mtx->eMm_held); abort(); } mtx->eMm_held++; mtx->eMm_heldin = file; mtx->eMm_heldat = line; } void eMmutex_exit(eMmutex_t *mtx, char *file, int line) { if (mutex_debug & 2) fprintf(mutex_file, "%s:%d:eMmutex_exit(%s)\n", file, line, mtx->eMm_owner); if (mtx->eMm_magic != EMM_MAGIC) { fprintf(stderr, "%s:eMmutex_exit(%p): bad magic: %#x\n", mtx->eMm_owner, mtx, mtx->eMm_magic); abort(); } if (mtx->eMm_held != 1) { fprintf(stderr, "%s:eMmutex_exit(%p): not locked: %d\n", mtx->eMm_owner, mtx, mtx->eMm_held); abort(); } mtx->eMm_held--; mtx->eMm_heldin = NULL; mtx->eMm_heldat = 0; } void eMmutex_init(eMmutex_t *mtx, char *who, char *file, int line) { if (mutex_file == NULL && mutex_debug) mutex_file = fopen("ipf_mutex_log", "w"); if (mutex_debug & 1) fprintf(mutex_file, "%s:%d:eMmutex_init(%p,%s)\n", file, line, mtx, who); if (mtx->eMm_magic == EMM_MAGIC) { /* safe bet ? */ fprintf(stderr, "%s:eMmutex_init(%p): already initialised?: %#x\n", mtx->eMm_owner, mtx, mtx->eMm_magic); abort(); } mtx->eMm_magic = EMM_MAGIC; mtx->eMm_held = 0; if (who != NULL) mtx->eMm_owner = strdup(who); else mtx->eMm_owner = NULL; initcount++; } void -eMmutex_destroy(mtx, file, line) - eMmutex_t *mtx; - char *file; - int line; +eMmutex_destroy(eMmutex_t *mtx, char *file, int line) { if (mutex_debug & 1) fprintf(mutex_file, "%s:%d:eMmutex_destroy(%p,%s)\n", file, line, mtx, mtx->eMm_owner); if (mtx->eMm_magic != EMM_MAGIC) { fprintf(stderr, "%s:eMmutex_destroy(%p): bad magic: %#x\n", mtx->eMm_owner, mtx, mtx->eMm_magic); abort(); } if (mtx->eMm_held != 0) { fprintf(stderr, "%s:eMmutex_enter(%p): still locked: %d\n", mtx->eMm_owner, mtx, mtx->eMm_held); abort(); } if (mtx->eMm_owner != NULL) free(mtx->eMm_owner); memset(mtx, 0xa5, sizeof(*mtx)); initcount--; } void ipf_mutex_clean(void) { if (initcount != 0) { if (mutex_file) fprintf(mutex_file, "initcount %d\n", initcount); abort(); } } diff --git a/sbin/ipf/libipf/poolio.c b/sbin/ipf/libipf/poolio.c index 765d37fae350..f12120fd5467 100644 --- a/sbin/ipf/libipf/poolio.c +++ b/sbin/ipf/libipf/poolio.c @@ -1,53 +1,50 @@ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id: poolio.c,v 1.1.2.3 2012/07/22 08:04:24 darren_r Exp $ */ #include #include #include "ipf.h" #include "netinet/ip_lookup.h" #include "netinet/ip_pool.h" static int poolfd = -1; int pool_open(void) { if ((opts & OPT_DONTOPEN) != 0) return (0); if (poolfd == -1) poolfd = open(IPLOOKUP_NAME, O_RDWR); return (poolfd); } int -pool_ioctl(iocfunc, cmd, ptr) - ioctlfunc_t iocfunc; - ioctlcmd_t cmd; - void *ptr; +pool_ioctl(ioctlfunc_t iocfunc, ioctlcmd_t cmd, void *ptr) { return (*iocfunc)(poolfd, cmd, ptr); } void pool_close(void) { if (poolfd != -1) { close(poolfd); poolfd = -1; } } int pool_fd(void) { return (poolfd); } diff --git a/sbin/ipf/libipf/var.c b/sbin/ipf/libipf/var.c index d3a03b6e46d7..47eb5d1595df 100644 --- a/sbin/ipf/libipf/var.c +++ b/sbin/ipf/libipf/var.c @@ -1,173 +1,172 @@ /* $FreeBSD$ */ /* * Copyright (C) 2012 by Darren Reed. * * See the IPFILTER.LICENCE file for details on licencing. * * $Id$ */ #include #include "ipf.h" typedef struct variable { struct variable *v_next; char *v_name; char *v_value; } variable_t; static variable_t *vtop = NULL; static variable_t *find_var(char *); static char *expand_string(char *, int); -static variable_t *find_var(name) - char *name; +static variable_t *find_var(char *name) { variable_t *v; for (v = vtop; v != NULL; v = v->v_next) if (!strcmp(name, v->v_name)) return (v); return (NULL); } char *get_variable(char *string, char **after, int line) { char c, *s, *t, *value; variable_t *v; s = string; if (*s == '{') { s++; for (t = s; *t != '\0'; t++) if (*t == '}') break; if (*t == '\0') { fprintf(stderr, "%d: { without }\n", line); return (NULL); } } else if (ISALPHA(*s)) { for (t = s + 1; *t != '\0'; t++) if (!ISALPHA(*t) && !ISDIGIT(*t) && (*t != '_')) break; } else { fprintf(stderr, "%d: variables cannot start with '%c'\n", line, *s); return (NULL); } if (after != NULL) *after = t; c = *t; *t = '\0'; v = find_var(s); *t = c; if (v == NULL) { fprintf(stderr, "%d: unknown variable '%s'\n", line, s); return (NULL); } s = strdup(v->v_value); value = expand_string(s, line); if (value != s) free(s); return (value); } static char *expand_string(char *oldstring, int line) { char c, *s, *p1, *p2, *p3, *newstring, *value; int len; p3 = NULL; newstring = oldstring; for (s = oldstring; *s != '\0'; s++) if (*s == '$') { *s = '\0'; s++; switch (*s) { case '$' : bcopy(s, s - 1, strlen(s)); break; default : c = *s; if (c == '\0') return (newstring); value = get_variable(s, &p3, line); if (value == NULL) return (NULL); p2 = expand_string(value, line); if (p2 == NULL) return (NULL); len = strlen(newstring) + strlen(p2); if (p3 != NULL) { if (c == '{' && *p3 == '}') p3++; len += strlen(p3); } p1 = malloc(len + 1); if (p1 == NULL) return (NULL); *(s - 1) = '\0'; strcpy(p1, newstring); strcat(p1, p2); if (p3 != NULL) strcat(p1, p3); s = p1 + len - strlen(p3) - 1; if (newstring != oldstring) free(newstring); newstring = p1; break; } } return (newstring); } void set_variable(char *name, char *value) { variable_t *v; int len; if (name == NULL || value == NULL || *name == '\0') return; v = find_var(name); if (v != NULL) { free(v->v_value); v->v_value = strdup(value); return; } len = strlen(value); if ((*value == '"' && value[len - 1] == '"') || (*value == '\'' && value[len - 1] == '\'')) { value[len - 1] = '\0'; value++; len -=2; } v = (variable_t *)malloc(sizeof(*v)); if (v == NULL) return; v->v_name = strdup(name); v->v_value = strdup(value); v->v_next = vtop; vtop = v; }