Index: head/contrib/ipfilter/ipmon.c =================================================================== --- head/contrib/ipfilter/ipmon.c (revision 60844) +++ head/contrib/ipfilter/ipmon.c (revision 60845) @@ -1,1054 +1,1105 @@ -/* $FreeBSD$ */ /* - * Copyright (C) 1993-1998 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-1998 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipmon.c,v 2.3.2.4 2000/01/24 12:45:25 darrenr Exp $"; +static const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$FreeBSD$"; #endif #ifndef SOLARIS #define SOLARIS (defined(__SVR4) || defined(__svr4__)) && defined(sun) #endif #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(__SVR4) && !defined(__svr4__) # if (__FreeBSD_version >= 300000) # include # else # include # endif #else # include # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef linux # include # include #endif #include #include #include #include #include "netinet/ip_compat.h" #include #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" #include "netinet/ip_state.h" #if defined(sun) && !defined(SOLARIS2) #define STRERROR(x) sys_errlist[x] extern char *sys_errlist[]; #else #define STRERROR(x) strerror(x) #endif struct flags { int value; char flag; }; struct flags tcpfl[] = { { TH_ACK, 'A' }, { TH_RST, 'R' }, { TH_SYN, 'S' }, { TH_FIN, 'F' }, { TH_URG, 'U' }, { TH_PUSH,'P' }, { 0, '\0' } }; #if SOLARIS static char *pidfile = "/etc/opt/ipf/ipmon.pid"; #else # if BSD >= 199306 static char *pidfile = "/var/run/ipmon.pid"; # else static char *pidfile = "/etc/ipmon.pid"; # endif #endif static char line[2048]; static int opts = 0; static FILE *newlog = NULL; static char *logfile = NULL; static int donehup = 0; static void usage __P((char *)); static void handlehup __P((int)); static void flushlogs __P((char *, FILE *)); static void print_log __P((int, FILE *, char *, int)); static void print_ipflog __P((FILE *, char *, int)); static void print_natlog __P((FILE *, char *, int)); static void print_statelog __P((FILE *, char *, int)); static void dumphex __P((FILE *, u_char *, int)); static int read_log __P((int, int *, char *, int)); static void write_pid __P((char *)); -char *hostname __P((int, struct in_addr)); +char *hostname __P((int, int, u_32_t *)); char *portname __P((int, char *, u_int)); int main __P((int, char *[])); static void logopts __P((int, char *)); static void init_tabs __P((void)); static char *getproto __P((u_int)); static char **protocols = NULL; static char **udp_ports = NULL; static char **tcp_ports = NULL; #define OPT_SYSLOG 0x001 #define OPT_RESOLVE 0x002 #define OPT_HEXBODY 0x004 #define OPT_VERBOSE 0x008 #define OPT_HEXHDR 0x010 #define OPT_TAIL 0x020 #define OPT_NAT 0x080 #define OPT_STATE 0x100 #define OPT_FILTER 0x200 #define OPT_PORTNUM 0x400 #define OPT_LOGALL (OPT_NAT|OPT_STATE|OPT_FILTER) +#define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) + #ifndef LOGFAC #define LOGFAC LOG_LOCAL0 #endif void handlehup(sig) int sig; { FILE *fp; signal(SIGHUP, handlehup); if (logfile && (fp = fopen(logfile, "a"))) newlog = fp; init_tabs(); donehup = 1; } static void init_tabs() { struct protoent *p; struct servent *s; char *name, **tab; - u_int port; + int port; if (protocols != 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] = strdup(p->p_name); endprotoent(); } if (udp_ports != 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) { 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 = (u_int)s->s_port; + port = s->s_port; name = s->s_name; tab = tcp_ports; } else if (!strcmp(s->s_proto, "udp")) { - port = (u_int)s->s_port; + port = s->s_port; name = s->s_name; tab = udp_ports; } else continue; if ((port < 0 || port > 65535) || (name == NULL)) continue; tab[port] = strdup(name); } endservent(); } static char *getproto(p) 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(fd, lenp, buf, bufsize) int fd, bufsize, *lenp; char *buf; { int nr; nr = read(fd, buf, bufsize); if (!nr) return 2; if ((nr < 0) && (errno != EINTR)) return -1; *lenp = nr; return 0; } -char *hostname(res, ip) -int res; -struct in_addr ip; +char *hostname(res, v, ip) +int res, v; +u_32_t *ip; { +#ifdef USE_INET6 + static char hostbuf[MAXHOSTNAMELEN+1]; +#endif struct hostent *hp; + struct in_addr ipa; - if (!res) - return inet_ntoa(ip); - hp = gethostbyaddr((char *)&ip, sizeof(ip), AF_INET); - if (!hp) - return inet_ntoa(ip); - return hp->h_name; + if (v == 4) { + ipa.s_addr = *ip; + if (!res) + return inet_ntoa(ipa); + hp = gethostbyaddr((char *)ip, sizeof(ip), AF_INET); + if (!hp) + return inet_ntoa(ipa); + return hp->h_name; + + } +#ifdef USE_INET6 + (void) inet_ntop(AF_INET6, ip, hostbuf, sizeof(hostbuf) - 1); + hostbuf[MAXHOSTNAMELEN] = '\0'; + return hostbuf; +#else + return "IPv6"; +#endif } char *portname(res, proto, port) int res; char *proto; u_int port; { static char pname[8]; char *s; port = ntohs(port); port &= 0xffff; (void) sprintf(pname, "%u", port); if (!res || (opts & OPT_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 void dumphex(log, buf, len) FILE *log; u_char *buf; int len; { char line[80]; int i, j, k; u_char *s = buf, *t = (u_char *)line; for (i = len, j = 0; i; i--, j++, s++) { if (j && !(j & 0xf)) { *t++ = '\n'; *t = '\0'; if (!(opts & OPT_SYSLOG)) fputs(line, log); else syslog(LOG_INFO, "%s", line); t = (u_char *)line; *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 (!(opts & OPT_SYSLOG)) { fputs(line, log); fflush(log); } else syslog(LOG_INFO, "%s", line); } static void print_natlog(log, buf, blen) FILE *log; char *buf; int blen; { struct natlog *nl; iplog_t *ipl = (iplog_t *)buf; char *t = line; struct tm *tm; int res, i, len; char *proto; nl = (struct natlog *)((char *)ipl + sizeof(*ipl)); res = (opts & OPT_RESOLVE) ? 1 : 0; tm = localtime((time_t *)&ipl->ipl_sec); len = sizeof(line); if (!(opts & OPT_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); (void) sprintf(t, ".%-.6ld @%hd ", ipl->ipl_usec, nl->nl_rule + 1); t += strlen(t); if (nl->nl_type == NL_NEWMAP) strcpy(t, "NAT:MAP "); else if (nl->nl_type == NL_NEWRDR) strcpy(t, "NAT:RDR "); else if (nl->nl_type == NL_EXPIRE) strcpy(t, "NAT:EXPIRE "); else sprintf(t, "Type: %d ", nl->nl_type); t += strlen(t); proto = getproto(nl->nl_p); - (void) sprintf(t, "%s,%s <- -> ", hostname(res, nl->nl_inip), + (void) sprintf(t, "%s,%s <- -> ", HOSTNAME_V4(res, nl->nl_inip), portname(res, proto, (u_int)nl->nl_inport)); t += strlen(t); - (void) sprintf(t, "%s,%s ", hostname(res, nl->nl_outip), + (void) sprintf(t, "%s,%s ", HOSTNAME_V4(res, nl->nl_outip), portname(res, proto, (u_int)nl->nl_outport)); t += strlen(t); - (void) sprintf(t, "[%s,%s]", hostname(res, nl->nl_origip), + (void) sprintf(t, "[%s,%s]", HOSTNAME_V4(res, nl->nl_origip), portname(res, proto, (u_int)nl->nl_origport)); t += strlen(t); if (nl->nl_type == NL_EXPIRE) { #ifdef USE_QUAD_T (void) sprintf(t, " Pkts %qd Bytes %qd", + (long long)nl->nl_pkts, + (long long)nl->nl_bytes); #else (void) sprintf(t, " Pkts %ld Bytes %ld", -#endif nl->nl_pkts, nl->nl_bytes); +#endif t += strlen(t); } *t++ = '\n'; *t++ = '\0'; if (opts & OPT_SYSLOG) syslog(LOG_INFO, "%s", line); else (void) fprintf(log, "%s", line); } static void print_statelog(log, buf, blen) FILE *log; char *buf; int blen; { struct ipslog *sl; iplog_t *ipl = (iplog_t *)buf; char *t = line, *proto; struct tm *tm; int res, i, len; sl = (struct ipslog *)((char *)ipl + sizeof(*ipl)); res = (opts & OPT_RESOLVE) ? 1 : 0; tm = localtime((time_t *)&ipl->ipl_sec); len = sizeof(line); if (!(opts & OPT_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); (void) sprintf(t, ".%-.6ld ", ipl->ipl_usec); t += strlen(t); if (sl->isl_type == ISL_NEW) strcpy(t, "STATE:NEW "); else if (sl->isl_type == ISL_EXPIRE) { if ((sl->isl_p == IPPROTO_TCP) && (sl->isl_state[0] > TCPS_ESTABLISHED || sl->isl_state[1] > TCPS_ESTABLISHED)) strcpy(t, "STATE:CLOSE "); else strcpy(t, "STATE:EXPIRE "); } else if (sl->isl_type == ISL_FLUSH) strcpy(t, "STATE:FLUSH "); + else if (sl->isl_type == ISL_REMOVE) + strcpy(t, "STATE:REMOVE "); else sprintf(t, "Type: %d ", sl->isl_type); t += strlen(t); proto = getproto(sl->isl_p); if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { (void) sprintf(t, "%s,%s -> ", - hostname(res, sl->isl_src), + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_src), portname(res, proto, (u_int)sl->isl_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s", - hostname(res, sl->isl_dst), + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), portname(res, proto, (u_int)sl->isl_dport), proto); } else if (sl->isl_p == IPPROTO_ICMP) { - (void) sprintf(t, "%s -> ", hostname(res, sl->isl_src)); + (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, + (u_32_t *)&sl->isl_src)); t += strlen(t); (void) sprintf(t, "%s PR icmp %d", - hostname(res, sl->isl_dst), sl->isl_itype); + hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), + sl->isl_itype); } t += strlen(t); if (sl->isl_type != ISL_NEW) { #ifdef USE_QUAD_T (void) sprintf(t, " Pkts %qd Bytes %qd", + (long long)sl->isl_pkts, + (long long)sl->isl_bytes); #else (void) sprintf(t, " Pkts %ld Bytes %ld", -#endif sl->isl_pkts, sl->isl_bytes); +#endif t += strlen(t); } *t++ = '\n'; *t++ = '\0'; if (opts & OPT_SYSLOG) syslog(LOG_INFO, "%s", line); else (void) fprintf(log, "%s", line); } static void print_log(logtype, log, buf, blen) FILE *log; char *buf; int logtype, blen; { iplog_t *ipl; char *bp = NULL, *bpo = NULL; int psize; 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; } if (ipl->ipl_magic != IPL_MAGIC) { /* invalid data or out of sync */ break; } psize = ipl->ipl_dsize; switch (logtype) { case IPL_LOGIPF : print_ipflog(log, buf, psize); break; case IPL_LOGNAT : print_natlog(log, buf, psize); break; case IPL_LOGSTATE : print_statelog(log, buf, psize); break; } blen -= psize; buf += psize; } if (bp) free(bp); return; } static void print_ipflog(log, buf, blen) FILE *log; char *buf; int blen; { tcphdr_t *tp; struct icmp *ic; struct tm *tm; char *t, *proto; - u_short hl, p; - int i, lvl, res, len; + int i, v, lvl, res, len, off, plen, ipoff; ip_t *ipc, *ip; - iplog_t *ipl; + u_short hl, p; ipflog_t *ipf; + iplog_t *ipl; + u_32_t *s, *d; +#ifdef USE_INET6 + ip6_t *ip6; +#endif ipl = (iplog_t *)buf; ipf = (ipflog_t *)((char *)buf + sizeof(*ipl)); ip = (ip_t *)((char *)ipf + sizeof(*ipf)); + v = ip->ip_v; res = (opts & OPT_RESOLVE) ? 1 : 0; t = line; *t = '\0'; - hl = (ip->ip_hl << 2); - p = (u_short)ip->ip_p; tm = localtime((time_t *)&ipl->ipl_sec); #ifdef linux - ip->ip_len = ntohs(ip->ip_len); + if (v == 4) + ip->ip_len = ntohs(ip->ip_len); #endif len = sizeof(line); if (!(opts & OPT_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); (void) sprintf(t, ".%-.6ld ", ipl->ipl_usec); t += strlen(t); if (ipl->ipl_count > 1) { (void) sprintf(t, "%dx ", ipl->ipl_count); t += strlen(t); } #if (SOLARIS || \ (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux) len = (int)sizeof(ipf->fl_ifname); (void) sprintf(t, "%*.*s", len, len, ipf->fl_ifname); t += strlen(t); # if SOLARIS if (isalpha(*(t - 1))) *t++ = '0' + ipf->fl_unit; # endif #else for (len = 0; len < 3; len++) if (ipf->fl_ifname[len] == '\0') break; if (ipf->fl_ifname[len]) len++; (void) sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit); t += strlen(t); #endif (void) sprintf(t, " @%hu:%hu ", ipf->fl_group, ipf->fl_rule + 1); t += strlen(t); - proto = getproto(p); if (ipf->fl_flags & FF_SHORT) { *t++ = 'S'; lvl = LOG_ERR; } else if (ipf->fl_flags & FR_PASS) { if (ipf->fl_flags & FR_LOGP) *t++ = 'p'; else *t++ = 'P'; lvl = LOG_NOTICE; } else if (ipf->fl_flags & FR_BLOCK) { if (ipf->fl_flags & FR_LOGB) *t++ = 'b'; else *t++ = 'B'; lvl = LOG_WARNING; } else if (ipf->fl_flags & FF_LOGNOMATCH) { *t++ = 'n'; lvl = LOG_NOTICE; } else { *t++ = 'L'; lvl = LOG_INFO; } if (ipf->fl_loglevel != 0xffff) lvl = ipf->fl_loglevel; *t++ = ' '; *t = '\0'; - if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && - !(ip->ip_off & IP_OFFMASK)) { + if (v == 6) { +#ifdef USE_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 = ntohs(ip6->ip6_plen); +#else + sprintf(t, "ipv6"); + goto printipflog; +#endif + } else if (v == 4) { + hl = (ip->ip_hl << 2); + ipoff = 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 { + goto printipflog; + } + proto = getproto(p); + + if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { tp = (tcphdr_t *)((char *)ip + hl); if (!(ipf->fl_flags & (FI_SHORT << 16))) { - (void) sprintf(t, "%s,%s -> ", - hostname(res, ip->ip_src), + (void) sprintf(t, "%s,%s -> ", hostname(res, v, s), portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, "%s,%s PR %s len %hu %hu ", - hostname(res, ip->ip_dst), + hostname(res, v, d), portname(res, proto, (u_int)tp->th_dport), - proto, hl, ip->ip_len); + proto, hl, plen); t += strlen(t); if (p == IPPROTO_TCP) { *t++ = '-'; for (i = 0; tcpfl[i].value; i++) if (tp->th_flags & tcpfl[i].value) *t++ = tcpfl[i].flag; if (opts & OPT_VERBOSE) { (void) 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 { - (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src)); + (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR %s len %hu %hu", - hostname(res, ip->ip_dst), proto, - hl, ip->ip_len); + hostname(res, v, d), proto, hl, plen); } - } else if ((p == IPPROTO_ICMP) && !(ip->ip_off & IP_OFFMASK)) { + } else if ((p == IPPROTO_ICMP) && !off && (v == 4)) { ic = (struct icmp *)((char *)ip + hl); - (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src)); + (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR icmp len %hu %hu icmp %d/%d", - hostname(res, ip->ip_dst), hl, ip->ip_len, + hostname(res, v, d), hl, plen, 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; tp = (tcphdr_t *)((char *)ipc + hl); proto = getproto(ipc->ip_p); t += strlen(t); (void) sprintf(t, " for %s,%s -", - hostname(res, ipc->ip_src), + HOSTNAME_V4(res, ipc->ip_src), portname(res, proto, (u_int)tp->th_sport)); t += strlen(t); (void) sprintf(t, " %s,%s PR %s len %hu %hu", - hostname(res, ipc->ip_dst), + HOSTNAME_V4(res, ipc->ip_dst), portname(res, proto, (u_int)tp->th_dport), proto, ipc->ip_hl << 2, ipc->ip_len); } } else { - (void) sprintf(t, "%s -> ", hostname(res, ip->ip_src)); + (void) sprintf(t, "%s -> ", hostname(res, v, s)); t += strlen(t); (void) sprintf(t, "%s PR %s len %hu (%hu)", - hostname(res, ip->ip_dst), proto, hl, ip->ip_len); + hostname(res, v, d), proto, hl, plen); t += strlen(t); - if (ip->ip_off & IP_OFFMASK) + if (off & IP_OFFMASK) (void) sprintf(t, " frag %s%s%hu@%hu", - ip->ip_off & IP_MF ? "+" : "", - ip->ip_off & IP_DF ? "-" : "", - ip->ip_len - hl, - (ip->ip_off & IP_OFFMASK) << 3); + ipoff & IP_MF ? "+" : "", + ipoff & IP_DF ? "-" : "", + plen - hl, (off & IP_OFFMASK) << 3); } t += strlen(t); 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_flags & FR_INQUE) strcpy(t, " IN"); else if (ipf->fl_flags & FR_OUTQUE) strcpy(t, " OUT"); t += strlen(t); +printipflog: *t++ = '\n'; *t++ = '\0'; if (opts & OPT_SYSLOG) syslog(lvl, "%s", line); else (void) fprintf(log, "%s", line); if (opts & OPT_HEXHDR) dumphex(log, (u_char *)buf, sizeof(iplog_t) + sizeof(*ipf)); if (opts & OPT_HEXBODY) dumphex(log, (u_char *)ip, ipf->fl_plen + ipf->fl_hlen); } static void usage(prog) char *prog; { fprintf(stderr, "%s: [-NFhstvxX] [-f ]\n", prog); exit(1); } static void write_pid(file) 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) { close(fd); fprintf(stderr, "unable to open/create pid file: %s\n", file); return; } fprintf(fp, "%d", getpid()); fclose(fp); close(fd); } static void flushlogs(file, log) 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 perror("SIOCIPFFB"); (void) close(fd); if (flushed) { if (opts & OPT_SYSLOG) syslog(LOG_INFO, "%d bytes flushed from log\n", flushed); else if (log != stdout) fprintf(log, "%d bytes flushed from log\n", flushed); } } static void logopts(turnon, options) int turnon; char *options; { int flags = 0; char *s; for (s = options; *s; s++) { switch (*s) { case 'N' : flags |= OPT_NAT; break; case 'S' : flags |= OPT_STATE; break; case 'I' : flags |= OPT_FILTER; break; default : fprintf(stderr, "Unknown log option %c\n", *s); exit(1); } } if (turnon) opts |= flags; else opts &= ~(flags); } int main(argc, argv) int argc; char *argv[]; { struct stat sb; FILE *log = stdout; int fd[3], doread, n, i; int tr, nr, regular[3], c; int fdt[3], devices = 0, make_daemon = 0; char buf[512], *iplfile[3], *s; extern int optind; extern char *optarg; fd[0] = fd[1] = fd[2] = -1; fdt[0] = fdt[1] = fdt[2] = -1; iplfile[0] = IPL_NAME; iplfile[1] = IPNAT_NAME; iplfile[2] = IPSTATE_NAME; while ((c = getopt(argc, argv, "?aDf:FhnN:o:O:pP:sS:tvxX")) != -1) switch (c) { case 'a' : opts |= OPT_LOGALL; fdt[0] = IPL_LOGIPF; fdt[1] = IPL_LOGNAT; fdt[2] = IPL_LOGSTATE; break; case 'D' : make_daemon = 1; break; case 'f' : case 'I' : opts |= OPT_FILTER; fdt[0] = IPL_LOGIPF; iplfile[0] = optarg; break; case 'F' : flushlogs(iplfile[0], log); flushlogs(iplfile[1], log); flushlogs(iplfile[2], log); break; case 'n' : opts |= OPT_RESOLVE; break; case 'N' : opts |= OPT_NAT; fdt[1] = IPL_LOGNAT; iplfile[1] = optarg; break; case 'o' : case 'O' : logopts(c == 'o', optarg); fdt[0] = fdt[1] = fdt[2] = -1; if (opts & OPT_FILTER) fdt[0] = IPL_LOGIPF; if (opts & OPT_NAT) fdt[1] = IPL_LOGNAT; if (opts & OPT_STATE) fdt[2] = IPL_LOGSTATE; break; case 'p' : opts |= OPT_PORTNUM; break; case 'P' : pidfile = optarg; break; case 's' : s = strrchr(argv[0], '/'); if (s == NULL) s = argv[0]; else s++; openlog(s, LOG_NDELAY|LOG_PID, LOGFAC); s = NULL; opts |= OPT_SYSLOG; break; case 'S' : opts |= OPT_STATE; fdt[2] = IPL_LOGSTATE; iplfile[2] = optarg; break; case 't' : opts |= OPT_TAIL; break; case 'v' : opts |= OPT_VERBOSE; break; case 'x' : opts |= OPT_HEXBODY; break; case 'X' : opts |= OPT_HEXHDR; break; default : case 'h' : case '?' : usage(argv[0]); } init_tabs(); /* * Default action is to only open the filter log file. */ if ((fdt[0] == -1) && (fdt[1] == -1) && (fdt[2] == -1)) fdt[0] = IPL_LOGIPF; for (i = 0; i < 3; i++) { if (fdt[i] == -1) continue; if (!strcmp(iplfile[i], "-")) fd[i] = 0; else { if ((fd[i] = open(iplfile[i], O_RDONLY)) == -1) { (void) fprintf(stderr, "%s: open: %s\n", iplfile[i], STRERROR(errno)); exit(-1); } if (fstat(fd[i], &sb) == -1) { (void) fprintf(stderr, "%d: fstat: %s\n",fd[i], STRERROR(errno)); exit(-1); } if (!(regular[i] = !S_ISCHR(sb.st_mode))) devices++; } } if (!(opts & OPT_SYSLOG)) { logfile = argv[optind]; log = logfile ? fopen(logfile, "a") : stdout; if (log == NULL) { (void) fprintf(stderr, "%s: fopen: %s\n", argv[optind], STRERROR(errno)); exit(-1); } setvbuf(log, NULL, _IONBF, 0); } else log = NULL; if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) { if (fork() > 0) exit(0); write_pid(pidfile); close(0); close(1); close(2); setsid(); } else write_pid(pidfile); signal(SIGHUP, handlehup); for (doread = 1; doread; ) { nr = 0; for (i = 0; i < 3; i++) { tr = 0; if (fdt[i] == -1) continue; if (!regular[i]) { if (ioctl(fd[i], FIONREAD, &tr) == -1) { perror("ioctl(FIONREAD)"); exit(-1); } } else { tr = (lseek(fd[i], 0, SEEK_CUR) < sb.st_size); if (!tr && !(opts & OPT_TAIL)) doread = 0; } if (!tr) continue; nr += tr; tr = read_log(fd[i], &n, buf, sizeof(buf)); if (donehup) { donehup = 0; if (newlog) { fclose(log); log = newlog; newlog = NULL; } } switch (tr) { case -1 : if (opts & OPT_SYSLOG) syslog(LOG_ERR, "read: %m\n"); else perror("read"); doread = 0; break; case 1 : if (opts & OPT_SYSLOG) syslog(LOG_ERR, "aborting logging\n"); else fprintf(log, "aborting logging\n"); doread = 0; break; case 2 : break; case 0 : if (n > 0) { print_log(fdt[i], log, buf, n); if (!(opts & OPT_SYSLOG)) fflush(log); } break; } } if (!nr && ((opts & OPT_TAIL) || devices)) sleep(1); } exit(0); /* NOTREACHED */ } Index: head/contrib/ipfilter/ipsend/ipsend.c =================================================================== --- head/contrib/ipfilter/ipsend/ipsend.c (revision 60844) +++ head/contrib/ipfilter/ipsend/ipsend.c (revision 60845) @@ -1,401 +1,401 @@ /* $FreeBSD$ */ /* * ipsend.c (C) 1995-1998 Darren Reed * * This was written to test what size TCP fragments would get through * various TCP/IP packet filters, as used in IP firewalls. In certain * conditions, enough of the TCP header is missing for unpredictable * results unless the filter is aware that this can happen. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) static const char sccsid[] = "@(#)ipsend.c 1.5 12/10/95 (C)1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ipsend.c,v 2.1.2.2 1999/11/28 03:43:44 darrenr Exp $"; +static const char rcsid[] = "@(#)$FreeBSD$"; #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef linux #include #endif #include "ipsend.h" #include "ipf.h" extern char *optarg; extern int optind; extern void iplang __P((FILE *)); char options[68]; int opts; #ifdef linux char default_device[] = "eth0"; #else # ifdef sun char default_device[] = "le0"; # else # ifdef ultrix char default_device[] = "ln0"; # else # ifdef __bsdi__ char default_device[] = "ef0"; # else # ifdef __sgi char default_device[] = "ec0"; # else char default_device[] = "lan0"; # endif # endif # endif # endif #endif static void usage __P((char *)); static void do_icmp __P((ip_t *, char *)); int main __P((int, char **)); static void usage(prog) char *prog; { fprintf(stderr, "Usage: %s [options] dest [flags]\n\ \toptions:\n\ \t\t-d\tdebug mode\n\ \t\t-i device\tSend out on this device\n\ \t\t-f fragflags\tcan set IP_MF or IP_DF\n\ \t\t-g gateway\tIP gateway to use if non-local dest.\n\ \t\t-I code,type[,gw[,dst[,src]]]\tSet ICMP protocol\n\ \t\t-m mtu\t\tfake MTU to use when sending out\n\ \t\t-P protocol\tSet protocol by name\n\ \t\t-s src\t\tsource address for IP packet\n\ \t\t-T\t\tSet TCP protocol\n\ \t\t-t port\t\tdestination port\n\ \t\t-U\t\tSet UDP protocol\n\ \t\t-v\tverbose mode\n\ \t\t-w \tSet the TCP window size\n\ ", prog); fprintf(stderr, "Usage: %s [-dv] -L \n\ \toptions:\n\ \t\t-d\tdebug mode\n\ \t\t-L filename\tUse IP language for sending packets\n\ \t\t-v\tverbose mode\n\ ", prog); exit(1); } static void do_icmp(ip, args) ip_t *ip; char *args; { struct icmp *ic; char *s; ip->ip_p = IPPROTO_ICMP; ip->ip_len += sizeof(*ic); ic = (struct icmp *)(ip + 1); bzero((char *)ic, sizeof(*ic)); if (!(s = strchr(args, ','))) { fprintf(stderr, "ICMP args missing: ,\n"); return; } *s++ = '\0'; ic->icmp_type = atoi(args); ic->icmp_code = atoi(s); if (ic->icmp_type == ICMP_REDIRECT && strchr(s, ',')) { char *t; t = strtok(s, ","); t = strtok(NULL, ","); if (resolve(t, (char *)&ic->icmp_gwaddr) == -1) { fprintf(stderr,"Cant resolve %s\n", t); exit(2); } if ((t = strtok(NULL, ","))) { if (resolve(t, (char *)&ic->icmp_ip.ip_dst) == -1) { fprintf(stderr,"Cant resolve %s\n", t); exit(2); } if ((t = strtok(NULL, ","))) { if (resolve(t, (char *)&ic->icmp_ip.ip_src) == -1) { fprintf(stderr,"Cant resolve %s\n", t); exit(2); } } } } } int send_packets(dev, mtu, ip, gwip) char *dev; int mtu; ip_t *ip; struct in_addr gwip; { u_short sport = 0; int wfd; if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) sport = ((struct tcpiphdr *)ip)->ti_sport; wfd = initdevice(dev, sport, 5); return send_packet(wfd, mtu, ip, gwip); } int main(argc, argv) int argc; char **argv; { FILE *langfile = NULL; struct tcpiphdr *ti; struct in_addr gwip; tcphdr_t *tcp; ip_t *ip; char *name = argv[0], host[MAXHOSTNAMELEN + 1]; char *gateway = NULL, *dev = NULL; char *src = NULL, *dst, *s; int mtu = 1500, olen = 0, c, nonl = 0; /* * 65535 is maximum packet size...you never know... */ ip = (ip_t *)calloc(1, 65536); ti = (struct tcpiphdr *)ip; tcp = (tcphdr_t *)&ti->ti_sport; ip->ip_len = sizeof(*ip); ip->ip_hl = sizeof(*ip) >> 2; while ((c = getopt(argc, argv, "I:L:P:TUdf:i:g:m:o:s:t:vw:")) != -1) switch (c) { case 'I' : nonl++; if (ip->ip_p) { fprintf(stderr, "Protocol already set: %d\n", ip->ip_p); break; } do_icmp(ip, optarg); break; case 'L' : if (nonl) { fprintf(stderr, "Incorrect usage of -L option.\n"); usage(name); } if (!strcmp(optarg, "-")) langfile = stdin; else if (!(langfile = fopen(optarg, "r"))) { fprintf(stderr, "can't open file %s\n", optarg); exit(1); } iplang(langfile); return 0; case 'P' : { struct protoent *p; nonl++; if (ip->ip_p) { fprintf(stderr, "Protocol already set: %d\n", ip->ip_p); break; } if ((p = getprotobyname(optarg))) ip->ip_p = p->p_proto; else fprintf(stderr, "Unknown protocol: %s\n", optarg); break; } case 'T' : nonl++; if (ip->ip_p) { fprintf(stderr, "Protocol already set: %d\n", ip->ip_p); break; } ip->ip_p = IPPROTO_TCP; ip->ip_len += sizeof(tcphdr_t); break; case 'U' : nonl++; if (ip->ip_p) { fprintf(stderr, "Protocol already set: %d\n", ip->ip_p); break; } ip->ip_p = IPPROTO_UDP; ip->ip_len += sizeof(udphdr_t); break; case 'd' : opts |= OPT_DEBUG; break; case 'f' : nonl++; ip->ip_off = strtol(optarg, NULL, 0); break; case 'g' : nonl++; gateway = optarg; break; case 'i' : nonl++; dev = optarg; break; case 'm' : nonl++; mtu = atoi(optarg); if (mtu < 28) { fprintf(stderr, "mtu must be > 28\n"); exit(1); } break; case 'o' : nonl++; olen = buildopts(optarg, options, (ip->ip_hl - 5) << 2); break; case 's' : nonl++; src = optarg; break; case 't' : nonl++; if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) tcp->th_dport = htons(atoi(optarg)); break; case 'v' : opts |= OPT_VERBOSE; break; case 'w' : nonl++; if (ip->ip_p == IPPROTO_TCP) tcp->th_win = atoi(optarg); else fprintf(stderr, "set protocol to TCP first\n"); break; default : fprintf(stderr, "Unknown option \"%c\"\n", c); usage(name); } if (argc - optind < 1) usage(name); dst = argv[optind++]; if (!src) { gethostname(host, sizeof(host)); src = host; } if (resolve(src, (char *)&ip->ip_src) == -1) { fprintf(stderr,"Cant resolve %s\n", src); exit(2); } if (resolve(dst, (char *)&ip->ip_dst) == -1) { fprintf(stderr,"Cant resolve %s\n", dst); exit(2); } if (!gateway) gwip = ip->ip_dst; else if (resolve(gateway, (char *)&gwip) == -1) { fprintf(stderr,"Cant resolve %s\n", gateway); exit(2); } if (olen) { caddr_t ipo = (caddr_t)ip; printf("Options: %d\n", olen); ti = (struct tcpiphdr *)malloc(olen + ip->ip_len); bcopy((char *)ip, (char *)ti, sizeof(*ip)); ip = (ip_t *)ti; ip->ip_hl = (olen >> 2); bcopy(options, (char *)(ip + 1), olen); bcopy((char *)tcp, (char *)(ip + 1) + olen, sizeof(*tcp)); ip->ip_len += olen; bcopy((char *)ip, (char *)ipo, ip->ip_len); ip = (ip_t *)ipo; tcp = (tcphdr_t *)((char *)(ip + 1) + olen); } if (ip->ip_p == IPPROTO_TCP) for (s = argv[optind]; s && (c = *s); s++) switch(c) { case 'S' : case 's' : tcp->th_flags |= TH_SYN; break; case 'A' : case 'a' : tcp->th_flags |= TH_ACK; break; case 'F' : case 'f' : tcp->th_flags |= TH_FIN; break; case 'R' : case 'r' : tcp->th_flags |= TH_RST; break; case 'P' : case 'p' : tcp->th_flags |= TH_PUSH; break; case 'U' : case 'u' : tcp->th_flags |= TH_URG; break; } if (!dev) dev = default_device; printf("Device: %s\n", dev); printf("Source: %s\n", inet_ntoa(ip->ip_src)); printf("Dest: %s\n", inet_ntoa(ip->ip_dst)); printf("Gateway: %s\n", inet_ntoa(gwip)); if (ip->ip_p == IPPROTO_TCP && tcp->th_flags) printf("Flags: %#x\n", tcp->th_flags); printf("mtu: %d\n", mtu); #ifdef DOSOCKET if (tcp->th_dport) return do_socket(dev, mtu, ti, gwip); #endif return send_packets(dev, mtu, (ip_t *)ti, gwip); } Index: head/contrib/ipfilter/man/ipf.8 =================================================================== --- head/contrib/ipfilter/man/ipf.8 (revision 60844) +++ head/contrib/ipfilter/man/ipf.8 (revision 60845) @@ -1,133 +1,136 @@ .\" $FreeBSD$ .TH IPF 8 .SH NAME ipf \- alters packet filtering lists for IP packet input and output .SH SYNOPSIS .B ipf [ -.B \-AdDEInoPrsUvVyzZ +.B \-6AdDEInoPrsUvVyzZ ] [ .B \-l ] [ .B \-F ] .B \-f <\fIfilename\fP> [ .B \-f <\fIfilename\fP> [...]] .SH DESCRIPTION .PP \fBipf\fP opens the filenames listed (treating "\-" as stdin) and parses the file for a set of rules which are to be added or removed from the packet filter rule set. .PP Each rule processed by \fBipf\fP is added to the kernel's internal lists if there are no parsing problems. Rules are added to the end of the internal lists, matching the order in which they appear when given to \fBipf\fP. .SH OPTIONS +.TP +.B \-6 +This option is required to parse IPv6 rules and to have them loaded. .TP .B \-A Set the list to make changes to the active list (default). .TP .B \-d Turn debug mode on. Causes a hexdump of filter rules to be generated as it processes each one. .TP .B \-D Disable the filter (if enabled). Not effective for loadable kernel versions. .TP .B \-E Enable the filter (if disabled). Not effective for loadable kernel versions. .TP .BR \-F \0 This option specifies which filter list to flush. The parameter should either be "i" (input), "o" (output) or "a" (remove all filter rules). Either a single letter or an entire word starting with the appropriate letter maybe used. This option maybe before, or after, any other with the order on the command line being that used to execute options. .TP .BR \-F \0 To flush entries from the state table, the \fB-F\fP option is used in conjuction with either "s" (removes state information about any non-fully established connections) or "S" (deletes the entire state table). Only one of the two options may be given. A fully established connection will show up in \fBipfstat -s\fP output as 4/4, with deviations either way indicating it is not fully established any more. .TP .BR \-f \0 This option specifies which files \fBipf\fP should use to get input from for modifying the packet filter rule lists. .TP .B \-I Set the list to make changes to the inactive list. .TP .B \-l \0 Use of the \fB-l\fP flag toggles default logging of packets. Valid arguments to this option are \fBpass\fP, \fBblock\fP and \fBnomatch\fP. When an option is set, any packet which exits filtering and matches the set category is logged. This is most useful for causing all packets which don't match any of the loaded rules to be logged. .TP .B \-n This flag (no-change) prevents \fBipf\fP from actually making any ioctl calls or doing anything which would alter the currently running kernel. .TP .B \-o Force rules by default to be added/deleted to/from the output list, rather than the (default) input list. .TP .B \-P Add rules as temporary entries in the authentication rule table. .TP .B \-r Remove matching filter rules rather than add them to the internal lists .TP .B \-s Swap the active filter list in use to be the "other" one. .TP .B \-U (SOLARIS 2 ONLY) Block packets travelling along the data stream which aren't recognised as IP packets. They will be printed out on the console. .TP .B \-v Turn verbose mode on. Displays information relating to rule processing. .TP .B \-V Show version information. This will display the version information compiled into the ipf binary and retrieve it from the kernel code (if running/present). If it is present in the kernel, information about its current state will be displayed (whether logging is active, default filtering, etc). .TP .B \-y Manually resync the in-kernel interface list maintained by IP Filter with the current interface status list. .TP .B \-z For each rule in the input file, reset the statistics for it to zero and display the statistics prior to them being zero'd. .TP .B \-Z Zero global statistics held in the kernel for filtering only (this doesn't affect fragment or state statistics). .DT .SH FILES /dev/ipauth .br /dev/ipl .br /dev/ipstate .SH SEE ALSO ipftest(1), mkfilters(1), ipf(4), ipl(4), ipf(5), ipfstat(8), ipmon(8), ipnat(8) .SH DIAGNOSTICS .PP Needs to be run as root for the packet filtering lists to actually be affected inside the kernel. .SH BUGS .PP If you find any, please send email to me at darrenr@pobox.com Index: head/contrib/ipfilter/man/ipfstat.8 =================================================================== --- head/contrib/ipfilter/man/ipfstat.8 (revision 60844) +++ head/contrib/ipfilter/man/ipfstat.8 (revision 60845) @@ -1,84 +1,178 @@ .\" $FreeBSD$ .TH ipfstat 8 .SH NAME ipfstat \- reports on packet filter statistics and filter list .SH SYNOPSIS .B ipfstat [ -.B \-aAfghIinosv +.B \-6aAfghIinosv ] [ .B \-d ] + +.B ipfstat -t +[ +.B \-C +] [ +.B \-D + +] [ +.B \-P + +] [ +.B \-S + +] [ +.B \-T + +] [ +.B \-d + +] .SH DESCRIPTION .PP \fBipfstat\fP examines /dev/kmem using the symbols \fB_fr_flags\fP, \fB_frstats\fP, \fB_filterin\fP, and \fB_filterout\fP. To run and work, it needs to be able to read both /dev/kmem and the kernel itself. The kernel name defaults to \fB/kernel\fP. .PP The default behaviour of \fBipfstat\fP is to retrieve and display the accumulated statistics which have been accumulated over time as the kernel has put packets through the filter. .SH OPTIONS .TP +.B \-6 +Display filter lists for IPv6, if available. +.TP .B \-a Display the accounting filter list and show bytes counted against each rule. .TP .B \-A Display packet authentication statistics. +.TP +.B \-C +This option is only valid in combination with \fB\-t\fP. +Display "closed" states as well in the top. Normally, a TCP connection is +not displayed when it reaches the CLOSE_WAIT protocol state. With this +option enabled, all state entries are displayed. .TP .BR \-d \0 Use a device other than \fB/dev/ipl\fP for interfacing with the kernel. .TP +.BR \-D \0 +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries whose destination IP address and port +match the addport argument. The addrport specification is of the form +ipaddress[,port]. The ipaddress and port should be either numerical or the +string "any" (specifying any ip address resp. any port). If the \fB\-D\fP +option is not specified, it defaults to "\fB\-D\fP any,any". +.TP .B \-f Show fragment state information (statistics) and held state information (in the kernel) if any is present. .TP .B \-g Show groups currently configured (both active and inactive). .TP .B \-h Show per-rule the number of times each one scores a "hit". For use in combination with \fB\-i\fP. .TP .B \-i Display the filter list used for the input side of the kernel IP processing. .TP .B \-I Swap between retrieving "inactive"/"active" filter list details. For use in combination with \fB\-i\fP. .TP .B \-n Show the "rule number" for each rule as it is printed. .TP .B \-o Display the filter list used for the output side of the kernel IP processing. .TP +.BR \-P \0 +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries that match a specific protocol. The +argument can be a protocol name (as defined in \fB/etc/protocols\fP) or a +protocol number. If this option is not specified, state entries for any +protocol are specified. +.TP .B \-s Show packet/flow state information (statistics) and held state information (in the kernel) if any is present. .TP +.BR \-S \0 +This option is only valid in combination with \fB\-t\fP. Limit the state top +display to show only state entries whose source IP address and port match +the addport argument. The addrport specification is of the form +ipaddress[,port]. The ipaddress and port should be either numerical or the +string "any" (specifying any ip address resp. any port). If the \fB\-S\fP +option is not specified, it defaults to "\fB\-S\fP any,any". +.TP +.B \-t +Show the state table in a way similar to they way \fBtop(1)\fP shows the process +table. States can be sorted using a number of different ways. This options +requires \fBncurses(3)\fP and needs to be compiled in. It may not be available on +all operating systems. See below, for more information on the keys that can +be used while ipfstat is in top mode. +.TP +.BR \-T \0 +This option is only valid in combination with \fB\-t\fP. Specifies how often +the state top display should be updated. The refresh time is the number of +seconds between an update. Any postive integer can be used. The default (and +minimal update time) is 1. +.TP .B \-v Turn verbose mode on. Displays more debugging information. .SH SYNOPSIS The role of \fBipfstat\fP is to display current kernel statistics gathered as a result of applying the filters in place (if any) to packets going in and out of the kernel. This is the default operation when no command line parameters are present. .PP When supplied with either \fB\-i\fP or \fB\-o\fP, it will retrieve and display the appropriate list of filter rules currently installed and in use by the kernel. +.SH STATE TOP +Using the \fB\-t\fP option \fBipfstat\fP will enter the state top mode. In +this mode the state table is displayed similar to the way \fBtop\fP displays +the process table. The \fB\-C\fP, \fB\-D\fP, \fB\-P\fP, \fB\-S\fP and\fB\-T\fP +commandline options can be used to restrict the state entries that will be +shown and to specify the frequency of display updates. +.PP +In state top mode, the following keys can be used to influence the displayed +information. \fBl\fP can be used to redraw the screen. \fBq\fP is used to +quit the program. \fBs\fP can be used to change the sorting criterion and +\fBr\fP can be used to reverse the sorting criterion. +.PP +States can be sorted by protocol number, by number of IP packets, by number +of bytes and by time-to-live of the state entry. The default is to sort by +the number of bytes. States are sorted in descending order, but you can use +the \fBr\fP key to sort them in ascending order. +.SH STATE TOP LIMITATIONS +It is currently not possible to interactively change the source, destination +and protocol filters or the refreh frequency. This must be done from the +command line. +.PP +The screen must have at least 80 columns. This is however not checked. +.PP +Only the first X-5 entries that match the sort and filter criteria are +displayed (where X is the number of rows on the display. There is no way to +see more entries. +.PP +No support for IPv6 +.PP .SH FILES /dev/kmem .br /dev/ipl .br /dev/ipstate .br /kernel .SH SEE ALSO ipf(8) .SH BUGS none known. Index: head/contrib/ipfilter/man/ipmon.8 =================================================================== --- head/contrib/ipfilter/man/ipmon.8 (revision 60844) +++ head/contrib/ipfilter/man/ipmon.8 (revision 60845) @@ -1,149 +1,165 @@ .\" $FreeBSD$ .TH ipmon 8 .SH NAME ipmon \- monitors /dev/ipl for logged packets .SH SYNOPSIS .B ipmon [ -.B \-aFhnstvxX +.B \-aDFhnpstvxX ] [ +.B "\-N " +] [ .B "\-o [NSI]" ] [ .B "\-O [NSI]" ] [ -.B "\-N " +.B "\-P " ] [ .B "\-S " ] [ .B "\-f " ] [ .B ] .SH DESCRIPTION .LP \fBipmon\fP opens \fB/dev/ipl\fP for reading and awaits data to be saved from the packet filter. The binary data read from the device is reprinted in human readable for, however, IP#'s are not mapped back to hostnames, nor are ports mapped back to service names. The output goes to standard output by default or a filename, if given on the command line. Should the \fB\-s\fP option be used, output is instead sent to \fBsyslogd(8)\fP. Messages sent via syslog have the day, month and year removed from the message, but the time (including microseconds), as recorded in the log, is still included. .LP Messages generated by ipmon consist of whitespace separated fields. Fields common to all messages are: .LP 1. The date of packet receipt. This is suppressed when the message is sent to syslog. .LP 2. The time of packet receipt. This is in the form HH:MM:SS.F, for hours, minutes seconds, and fractions of a second (which can be several digits long). .LP 3. The name of the interface the packet was processed on, e.g., \fBwe1\fP. .LP 4. The group and rule number of the rule, e.g., \fB@0:17\fP. These can be viewed with \fBipfstat -n\fP. .LP 5. The action: \fBp\fP for passed or \fBb\fP for blocked. .LP 6. The addresses. This is actually three fields: the source address and port (separted by a comma), the \fB->\fP symbol, and the destination address and port. E.g.: \fB209.53.17.22,80 -> 198.73.220.17,1722\fP. .LP 7. \fBPR\fP followed by the protocol name or number, e.g., \fBPR tcp\fP. .LP 8. \fBlen\fP followed by the header length and total length of the packet, e.g., \fBlen 20 40\fP. .LP If the packet is a TCP packet, there will be an additional field starting with a hyphen followed by letters corresponding to any flags that were set. See the ipf.conf manual page for a list of letters and their flags. .LP If the packet is an ICMP packet, there will be two fields at the end, the first always being `icmp', and the next being the ICMP message and submessage type, separated by a slash, e.g., \fBicmp 3/3\fP for a port unreachable message. .LP In order for \fBipmon\fP to properly work, the kernel option \fBIPFILTER_LOG\fP must be turned on in your kernel. Please see \fBoptions(4)\fP for more details. .SH OPTIONS .TP .B \-a Open all of the device logfiles for reading log entries from. All entries are displayed to the same output 'device' (stderr or syslog). .TP +.B \-D +Cause ipmon to turn itself into a daemon. Using subshells or backgrounding +of ipmon is not required to turn it into an orphan so it can run indefinately. +.TP .B "\-f " specify an alternative device/file from which to read the log information for normal IP Filter log records. .TP .B \-F Flush the current packet log buffer. The number of bytes flushed is displayed, even should the result be zero. .TP .B \-n IP addresses and port numbers will be mapped, where possible, back into hostnames and service names. .TP .B "\-N " Set the logfile to be opened for reading NAT log records from to . .TP .B \-o Specify which log files to actually read data from. N - NAT logfile, S - State logfile, I - normal IP Filter logfile. The \fB-a\fP option is equivalent to using \fB-o NSI\fP. .TP .B \-O Specify which log files you do not wish to read from. This is most sensibly used with the \fB-a\fP. Letters available as parameters to this are the same as for \fB-o\fP. .TP +.B \-p +Cause the port number in log messages to always be printed as a number and +never attempt to look it up as from \fI/etc/services\fP, etc. +.TP +.B \-P +Write the pid of the ipmon process to a file. By default this is +\fI//etc/opt/ipf/ipmon.pid\fP (Solaris), \fI/var/run/ipmon.pid\fP (44BSD +or later) or \fI/etc/ipmon.pid\fP for all others. +.TP .B \-s Packet information read in will be sent through syslogd rather than saved to a file. The default facility when compiled and installed is \fBlocal0\fP. The following levels are used: -.TP -.B "\-S " -Set the logfile to be opened for reading state log records from to . -.TP .IP .B LOG_INFO \- packets logged using the "log" keyword as the action rather than pass or block. .IP .B LOG_NOTICE \- packets logged which are also passed .IP .B LOG_WARNING \- packets logged which are also blocked .IP .B LOG_ERR \- packets which have been logged and which can be considered "short". .TP +.B "\-S " +Set the logfile to be opened for reading state log records from to . +.TP .B \-t read the input file/device in a manner akin to tail(1). .TP .B \-v show tcp window, ack and sequence fields. .TP .B \-x show the packet data in hex. .TP .B \-X show the log header record data in hex. .SH DIAGNOSTICS \fBipmon\fP expects data that it reads to be consistent with how it should be saved and will abort if it fails an assertion which detects an anomoly in the recorded data. .SH FILES /dev/ipl .br /dev/ipnat .br /dev/ipstate +.br +/etc/services .SH SEE ALSO ipl(4), ipf(8), ipfstat(8), ipnat(8) .\".SH BUGS