| /* |
| * Copyright (C) 1993-2002 by Darren Reed. |
| * |
| * See the IPFILTER.LICENCE file for details on licencing. |
| */ |
| #ifndef SOLARIS |
| #define SOLARIS (defined(__SVR4) || defined(__svr4__)) && defined(sun) |
| #endif |
| |
| #if defined(__sgi) && (IRIX > 602) |
| # include <sys/ptimers.h> |
| #endif |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/param.h> |
| #include <sys/file.h> |
| #include <sys/time.h> |
| #include <sys/socket.h> |
| #include <sys/ioctl.h> |
| |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #if !defined(__SVR4) && !defined(__svr4__) |
| # if (__FreeBSD_version >= 300000) |
| # include <sys/dirent.h> |
| # else |
| # include <sys/dir.h> |
| # endif |
| #else |
| # include <sys/filio.h> |
| # include <sys/byteorder.h> |
| #endif |
| #if !defined(__SVR4) && !defined(__GNUC__) |
| # include <strings.h> |
| #endif |
| #include <signal.h> |
| #include <stdlib.h> |
| #include <stddef.h> |
| #include <netinet/in.h> |
| #include <netinet/in_systm.h> |
| #include <net/if.h> |
| #include <netinet/ip.h> |
| #include <netinet/tcp_fsm.h> |
| #include <netdb.h> |
| #include <arpa/inet.h> |
| #include <arpa/nameser.h> |
| #include <resolv.h> |
| |
| #ifndef linux |
| # include <sys/protosw.h> |
| # include <netinet/ip_var.h> |
| #endif |
| |
| #include <netinet/tcp.h> |
| #include <netinet/ip_icmp.h> |
| |
| #include <ctype.h> |
| #include <syslog.h> |
| |
| #include "netinet/ip_compat.h" |
| #include <netinet/tcpip.h> |
| #include "netinet/ip_fil.h" |
| #include "netinet/ip_nat.h" |
| #include "netinet/ip_state.h" |
| |
| #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 |
| |
| |
| #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; |
| }; |
| |
| |
| 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' } |
| }; |
| |
| #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 *)); |
| static char *icmpname __P((u_int, u_int)); |
| static char *icmpname6 __P((u_int, u_int)); |
| static icmp_type_t *find_icmptype __P((int, icmp_type_t *, size_t)); |
| static icmp_subtype_t *find_icmpsubtype __P((int, icmp_subtype_t *, size_t)); |
| |
| 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 OPT_LOGBODY 0x800 |
| |
| #define HOSTNAME_V4(a,b) hostname((a), 4, (u_32_t *)&(b)) |
| |
| #ifndef LOGFAC |
| #define LOGFAC LOG_LOCAL0 |
| #endif |
| |
| |
| 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 icmptypes[] = { |
| { 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(type, table, tablesz) |
| 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(type, table, tablesz) |
| 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(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; |
| 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] == 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 = 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; |
| 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, v, ip) |
| int res, v; |
| u_32_t *ip; |
| { |
| # define MAX_INETA 16 |
| static char hname[MAXHOSTNAMELEN + MAX_INETA + 3]; |
| #ifdef USE_INET6 |
| static char hostbuf[MAXHOSTNAMELEN+1]; |
| #endif |
| struct hostent *hp; |
| struct in_addr ipa; |
| |
| 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); |
| sprintf(hname, "%.*s[%s]", MAXHOSTNAMELEN, hp->h_name, |
| inet_ntoa(ipa)); |
| return hname; |
| } |
| #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 char *icmpname(type, code) |
| 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, icmptypes, sizeof(icmptypes) / 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(type, code) |
| 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; |
| } |
| |
| |
| 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; |
| |
| if (len == 0 || buf == 0) |
| return; |
| *line = '\0'; |
| |
| 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 + IPLOG_SIZE); |
| 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 if (nl->nl_type == NL_FLUSH) |
| strcpy(t, "NAT:FLUSH "); |
| else if (nl->nl_type == NL_NEWBIMAP) |
| strcpy(t, "NAT:BIMAP "); |
| else if (nl->nl_type == NL_NEWBLOCK) |
| strcpy(t, "NAT:MAPBLOCK "); |
| else |
| sprintf(t, "Type: %d ", nl->nl_type); |
| t += strlen(t); |
| |
| proto = getproto(nl->nl_p); |
| |
| (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_V4(res, nl->nl_outip), |
| portname(res, proto, (u_int)nl->nl_outport)); |
| t += strlen(t); |
| (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", |
| 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 + IPLOG_SIZE); |
| 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_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_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_v, |
| (u_32_t *)&sl->isl_src)); |
| t += strlen(t); |
| (void) sprintf(t, "%s PR icmp %d", |
| hostname(res, sl->isl_v, (u_32_t *)&sl->isl_dst), |
| sl->isl_itype); |
| } else if (sl->isl_p == IPPROTO_ICMPV6) { |
| (void) sprintf(t, "%s -> ", hostname(res, sl->isl_v, |
| (u_32_t *)&sl->isl_src)); |
| t += strlen(t); |
| (void) sprintf(t, "%s PR icmpv6 %d", |
| 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", |
| 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 icmp *icmp; |
| struct tm *tm; |
| char *t, *proto; |
| int i, v, lvl, res, len, off, plen, ipoff; |
| ip_t *ipc, *ip; |
| 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 + IPLOG_SIZE); |
| ip = (ip_t *)((char *)ipf + sizeof(*ipf)); |
| v = ip->ip_v; |
| res = (opts & OPT_RESOLVE) ? 1 : 0; |
| t = line; |
| *t = '\0'; |
| tm = localtime((time_t *)&ipl->ipl_sec); |
| #ifdef linux |
| 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(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \ |
| (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux) |
| { |
| char ifname[sizeof(ipf->fl_ifname) + 1]; |
| |
| strncpy(ifname, (char *)ipf->fl_ifname, sizeof(ipf->fl_ifname)); |
| ifname[sizeof(ipf->fl_ifname)] = '\0'; |
| (void) sprintf(t, "%s", ifname); |
| t += strlen(t); |
| # if SOLARIS |
| if (isalpha(*(t - 1))) { |
| sprintf(t, "%d", ipf->fl_unit); |
| t += strlen(t); |
| } |
| # 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 |
| if (ipf->fl_group == 0xffffffff) |
| strcat(t, " @-1:"); |
| else |
| (void) sprintf(t, " @%u:", ipf->fl_group); |
| t += strlen(t); |
| if (ipf->fl_rule == 0xffffffff) |
| strcat(t, "-1 "); |
| else |
| (void) sprintf(t, "%u ", ipf->fl_rule + 1); |
| t += strlen(t); |
| |
| if (ipf->fl_flags & FF_SHORT) { |
| *t++ = 'S'; |
| lvl = LOG_ERR; |
| } else if (ipf->fl_flags & FR_PASS) { |
| if (ipf->fl_flags & FR_LOG) |
| *t++ = 'p'; |
| else |
| *t++ = 'P'; |
| lvl = LOG_NOTICE; |
| } else if (ipf->fl_flags & FR_BLOCK) { |
| if (ipf->fl_flags & FR_LOG) |
| *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 (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 = hl + 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 = 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 & FF_SHORT)) { |
| (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, v, d), |
| portname(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 (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, v, s)); |
| t += strlen(t); |
| (void) sprintf(t, "%s PR %s len %hu %hu", |
| hostname(res, v, d), proto, hl, plen); |
| } |
| } else if ((p == IPPROTO_ICMPV6) && !off && (v == 6)) { |
| ic = (struct icmp *)((char *)ip + hl); |
| (void) sprintf(t, "%s -> ", hostname(res, v, s)); |
| t += strlen(t); |
| (void) sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s", |
| hostname(res, v, d), hl, plen, |
| icmpname6(ic->icmp_type, ic->icmp_code)); |
| } else if ((p == IPPROTO_ICMP) && !off && (v == 4)) { |
| ic = (struct icmp *)((char *)ip + hl); |
| (void) sprintf(t, "%s -> ", hostname(res, v, s)); |
| t += strlen(t); |
| (void) sprintf(t, "%s PR icmp len %hu %hu icmp %s", |
| hostname(res, v, 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); |
| ipoff = ntohs(ipc->ip_off); |
| proto = getproto(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); |
| (void) sprintf(t, " for %s,%s -", |
| 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_V4(res, ipc->ip_dst), |
| portname(res, proto, |
| (u_int)tp->th_dport), |
| proto, ipc->ip_hl << 2, i); |
| } else if (!(ipoff & IP_OFFMASK) && |
| (ipc->ip_p == IPPROTO_ICMP)) { |
| icmp = (icmphdr_t *)((char *)ipc + hl); |
| |
| t += strlen(t); |
| (void) sprintf(t, " for %s -", |
| HOSTNAME_V4(res, ipc->ip_src)); |
| t += strlen(t); |
| (void) sprintf(t, |
| " %s PR icmp len %hu %hu icmp %d/%d", |
| HOSTNAME_V4(res, ipc->ip_dst), |
| ipc->ip_hl << 2, i, |
| icmp->icmp_type, icmp->icmp_code); |
| |
| } else { |
| t += strlen(t); |
| (void) sprintf(t, " for %s -", |
| HOSTNAME_V4(res, ipc->ip_src)); |
| t += strlen(t); |
| (void) sprintf(t, " %s PR %s len %hu (%hu)", |
| HOSTNAME_V4(res, ipc->ip_dst), proto, |
| ipc->ip_hl << 2, i); |
| t += strlen(t); |
| if (ipoff & IP_OFFMASK) { |
| (void) sprintf(t, " (frag %d:%hu@%hu%s%s)", |
| ntohs(ipc->ip_id), |
| i - (ipc->ip_hl<<2), |
| (ipoff & IP_OFFMASK) << 3, |
| ipoff & IP_MF ? "+" : "", |
| ipoff & IP_DF ? "-" : ""); |
| } |
| } |
| } |
| } else { |
| (void) sprintf(t, "%s -> ", hostname(res, v, s)); |
| t += strlen(t); |
| (void) sprintf(t, "%s PR %s len %hu (%hu)", |
| hostname(res, v, d), proto, hl, plen); |
| t += strlen(t); |
| if (off & IP_OFFMASK) |
| (void) 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); |
| |
| 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); |
| 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); |
| else if ((opts & OPT_LOGBODY) && (ipf->fl_flags & FR_LOGBODY)) |
| dumphex(log, (u_char *)ip + ipf->fl_hlen, ipf->fl_plen); |
| } |
| |
| |
| static void usage(prog) |
| char *prog; |
| { |
| fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\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[]; |
| { |
| int fdt[3], devices = 0, make_daemon = 0; |
| char buf[IPLLOGSIZE], *iplfile[3], *s; |
| int fd[3], doread, n, i; |
| extern char *optarg; |
| extern int optind; |
| int regular[3], c; |
| FILE *log = stdout; |
| struct stat sb; |
| size_t nr, tr; |
| |
| 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, "?abDf: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 'b' : |
| opts |= OPT_LOGBODY; |
| 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); |
| opts |= OPT_SYSLOG; |
| log = NULL; |
| 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); |
| /* NOTREACHED */ |
| } |
| if (fstat(fd[i], &sb) == -1) { |
| (void) fprintf(stderr, "%d: fstat: %s\n", |
| fd[i], STRERROR(errno)); |
| exit(1); |
| /* NOTREACHED */ |
| } |
| 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); |
| /* NOTREACHED */ |
| } |
| setvbuf(log, NULL, _IONBF, 0); |
| } else |
| log = NULL; |
| |
| if (make_daemon && ((log != stdout) || (opts & OPT_SYSLOG))) { |
| #if BSD |
| daemon(0, !(opts & OPT_SYSLOG)); |
| #else |
| int pid; |
| if ((pid = fork()) > 0) |
| exit(0); |
| if (pid < 0) { |
| (void) fprintf(stderr, "%s: fork() failed: %s\n", |
| argv[0], STRERROR(errno)); |
| exit(1); |
| /* NOTREACHED */ |
| } |
| setsid(); |
| if ((opts & OPT_SYSLOG)) |
| close(2); |
| #endif /* !BSD */ |
| close(0); |
| close(1); |
| } |
| 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) { |
| if (opts & OPT_SYSLOG) |
| syslog(LOG_CRIT, |
| "ioctl(FIONREAD): %m"); |
| else |
| perror("ioctl(FIONREAD)"); |
| exit(1); |
| /* NOTREACHED */ |
| } |
| } 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_CRIT, "read: %m\n"); |
| else |
| perror("read"); |
| doread = 0; |
| break; |
| case 1 : |
| if (opts & OPT_SYSLOG) |
| syslog(LOG_CRIT, "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 */ |
| } |