1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 3145510Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5145510Sdarrenr * 6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145510Sdarrenr */ 8255332Scy#include "ipf.h" 9255332Scy#include "ipmon.h" 10255332Scy#include <sys/ioctl.h> 11145510Sdarrenr#include <sys/stat.h> 12255332Scy#include <syslog.h> 13255332Scy#include <ctype.h> 14145510Sdarrenr#include <fcntl.h> 15145510Sdarrenr#include <signal.h> 16145510Sdarrenr 17145510Sdarrenr#if !defined(lint) 18145510Sdarrenrstatic const char sccsid[] = "@(#)ipmon.c 1.21 6/5/96 (C)1993-2000 Darren Reed"; 19255332Scystatic const char rcsid[] = "@(#)$Id$"; 20145510Sdarrenr#endif 21145510Sdarrenr 22145510Sdarrenr 23145510Sdarrenr#if defined(sun) && !defined(SOLARIS2) 24145510Sdarrenr#define STRERROR(x) sys_errlist[x] 25145510Sdarrenrextern char *sys_errlist[]; 26145510Sdarrenr#else 27145510Sdarrenr#define STRERROR(x) strerror(x) 28145510Sdarrenr#endif 29145510Sdarrenr 30255332Scyextern int optind; 31255332Scyextern char *optarg; 32145510Sdarrenr 33255332Scyextern ipmon_saver_t executesaver; 34255332Scyextern ipmon_saver_t filesaver; 35255332Scyextern ipmon_saver_t nothingsaver; 36255332Scyextern ipmon_saver_t snmpv1saver; 37255332Scyextern ipmon_saver_t snmpv2saver; 38255332Scyextern ipmon_saver_t syslogsaver; 39255332Scy 40255332Scy 41145510Sdarrenrstruct flags { 42145510Sdarrenr int value; 43145510Sdarrenr char flag; 44145510Sdarrenr}; 45145510Sdarrenr 46255332Scytypedef struct logsource { 47255332Scy int fd; 48255332Scy int logtype; 49255332Scy char *file; 50255332Scy int regular; 51255332Scy size_t size; 52255332Scy} logsource_t; 53145510Sdarrenr 54255332Scytypedef struct config { 55255332Scy int opts; 56255332Scy int maxfd; 57255332Scy logsource_t logsrc[3]; 58255332Scy fd_set fdmr; 59255332Scy FILE *blog; 60255332Scy char *bfile; 61255332Scy FILE *log; 62255332Scy char *file; 63255332Scy char *cfile; 64255332Scy} config_t; 65255332Scy 66145510Sdarrenrtypedef struct icmp_subtype { 67145510Sdarrenr int ist_val; 68145510Sdarrenr char *ist_name; 69145510Sdarrenr} icmp_subtype_t; 70145510Sdarrenr 71145510Sdarrenrtypedef struct icmp_type { 72145510Sdarrenr int it_val; 73145510Sdarrenr struct icmp_subtype *it_subtable; 74145510Sdarrenr size_t it_stsize; 75145510Sdarrenr char *it_name; 76145510Sdarrenr} icmp_type_t; 77145510Sdarrenr 78145510Sdarrenr 79145510Sdarrenr#define IST_SZ(x) (sizeof(x)/sizeof(icmp_subtype_t)) 80145510Sdarrenr 81145510Sdarrenr 82145510Sdarrenrstruct flags tcpfl[] = { 83145510Sdarrenr { TH_ACK, 'A' }, 84145510Sdarrenr { TH_RST, 'R' }, 85145510Sdarrenr { TH_SYN, 'S' }, 86145510Sdarrenr { TH_FIN, 'F' }, 87145510Sdarrenr { TH_URG, 'U' }, 88145510Sdarrenr { TH_PUSH,'P' }, 89145510Sdarrenr { TH_ECN, 'E' }, 90145510Sdarrenr { TH_CWR, 'C' }, 91145510Sdarrenr { 0, '\0' } 92145510Sdarrenr}; 93145510Sdarrenr 94255332Scychar *reasons[] = { 95255332Scy "filter-rule", 96255332Scy "log-or-block_1", 97255332Scy "pps-rate", 98255332Scy "jumbogram", 99255332Scy "makefrip-fail", 100255332Scy "state_add-fail", 101255332Scy "updateipid-fail", 102255332Scy "log-or-block_2", 103255332Scy "decap-fail", 104255332Scy "auth_new-fail", 105255332Scy "auth_captured", 106255332Scy "coalesce-fail", 107255332Scy "pullup-fail", 108255332Scy "auth-feedback", 109255332Scy "bad-frag", 110255332Scy "natv4_out-fail", 111255332Scy "natv4_in-fail", 112255332Scy "natv6_out-fail", 113255332Scy "natv6_in-fail", 114255332Scy}; 115255332Scy 116145510Sdarrenr#ifdef MENTAT 117145510Sdarrenrstatic char *pidfile = "/etc/opt/ipf/ipmon.pid"; 118145510Sdarrenr#else 119145510Sdarrenr# if BSD >= 199306 120145510Sdarrenrstatic char *pidfile = "/var/run/ipmon.pid"; 121145510Sdarrenr# else 122145510Sdarrenrstatic char *pidfile = "/etc/ipmon.pid"; 123145510Sdarrenr# endif 124145510Sdarrenr#endif 125145510Sdarrenr 126145510Sdarrenrstatic char line[2048]; 127145510Sdarrenrstatic int donehup = 0; 128145510Sdarrenrstatic void usage __P((char *)); 129145510Sdarrenrstatic void handlehup __P((int)); 130145510Sdarrenrstatic void flushlogs __P((char *, FILE *)); 131255332Scystatic void print_log __P((config_t *, logsource_t *, char *, int)); 132255332Scystatic void print_ipflog __P((config_t *, char *, int)); 133255332Scystatic void print_natlog __P((config_t *, char *, int)); 134255332Scystatic void print_statelog __P((config_t *, char *, int)); 135145510Sdarrenrstatic int read_log __P((int, int *, char *, int)); 136145510Sdarrenrstatic void write_pid __P((char *)); 137145510Sdarrenrstatic char *icmpname __P((u_int, u_int)); 138145510Sdarrenrstatic char *icmpname6 __P((u_int, u_int)); 139145510Sdarrenrstatic icmp_type_t *find_icmptype __P((int, icmp_type_t *, size_t)); 140145510Sdarrenrstatic icmp_subtype_t *find_icmpsubtype __P((int, icmp_subtype_t *, size_t)); 141145510Sdarrenr#ifdef __hpux 142145510Sdarrenrstatic struct tm *get_tm __P((u_32_t)); 143145510Sdarrenr#else 144145510Sdarrenrstatic struct tm *get_tm __P((time_t)); 145145510Sdarrenr#endif 146145510Sdarrenr 147255332Scychar *portlocalname __P((int, char *, u_int)); 148145510Sdarrenrint main __P((int, char *[])); 149145510Sdarrenr 150145510Sdarrenrstatic void logopts __P((int, char *)); 151145510Sdarrenrstatic void init_tabs __P((void)); 152255332Scystatic char *getlocalproto __P((u_int)); 153255332Scystatic void openlogs __P((config_t *conf)); 154255332Scystatic int read_loginfo __P((config_t *conf)); 155255332Scystatic void initconfig __P((config_t *conf)); 156145510Sdarrenr 157145510Sdarrenrstatic char **protocols = NULL; 158145510Sdarrenrstatic char **udp_ports = NULL; 159145510Sdarrenrstatic char **tcp_ports = NULL; 160145510Sdarrenr 161145510Sdarrenr 162255332Scy#define HOSTNAMEV4(b) hostname(AF_INET, (u_32_t *)&(b)) 163145510Sdarrenr 164145510Sdarrenr#ifndef LOGFAC 165145510Sdarrenr#define LOGFAC LOG_LOCAL0 166145510Sdarrenr#endif 167161357Sguidoint logfac = LOGFAC; 168255332Scyint ipmonopts = 0; 169255332Scyint opts = OPT_NORESOLVE; 170255332Scyint use_inet6 = 0; 171145510Sdarrenr 172145510Sdarrenr 173145510Sdarrenrstatic icmp_subtype_t icmpunreachnames[] = { 174145510Sdarrenr { ICMP_UNREACH_NET, "net" }, 175145510Sdarrenr { ICMP_UNREACH_HOST, "host" }, 176145510Sdarrenr { ICMP_UNREACH_PROTOCOL, "protocol" }, 177145510Sdarrenr { ICMP_UNREACH_PORT, "port" }, 178145510Sdarrenr { ICMP_UNREACH_NEEDFRAG, "needfrag" }, 179145510Sdarrenr { ICMP_UNREACH_SRCFAIL, "srcfail" }, 180145510Sdarrenr { ICMP_UNREACH_NET_UNKNOWN, "net_unknown" }, 181145510Sdarrenr { ICMP_UNREACH_HOST_UNKNOWN, "host_unknown" }, 182145510Sdarrenr { ICMP_UNREACH_NET, "isolated" }, 183145510Sdarrenr { ICMP_UNREACH_NET_PROHIB, "net_prohib" }, 184145510Sdarrenr { ICMP_UNREACH_NET_PROHIB, "host_prohib" }, 185145510Sdarrenr { ICMP_UNREACH_TOSNET, "tosnet" }, 186145510Sdarrenr { ICMP_UNREACH_TOSHOST, "toshost" }, 187145510Sdarrenr { ICMP_UNREACH_ADMIN_PROHIBIT, "admin_prohibit" }, 188145510Sdarrenr { -2, NULL } 189145510Sdarrenr}; 190145510Sdarrenr 191145510Sdarrenrstatic icmp_subtype_t redirectnames[] = { 192145510Sdarrenr { ICMP_REDIRECT_NET, "net" }, 193145510Sdarrenr { ICMP_REDIRECT_HOST, "host" }, 194145510Sdarrenr { ICMP_REDIRECT_TOSNET, "tosnet" }, 195145510Sdarrenr { ICMP_REDIRECT_TOSHOST, "toshost" }, 196145510Sdarrenr { -2, NULL } 197145510Sdarrenr}; 198145510Sdarrenr 199145510Sdarrenrstatic icmp_subtype_t timxceednames[] = { 200145510Sdarrenr { ICMP_TIMXCEED_INTRANS, "transit" }, 201145510Sdarrenr { ICMP_TIMXCEED_REASS, "reassem" }, 202145510Sdarrenr { -2, NULL } 203145510Sdarrenr}; 204145510Sdarrenr 205145510Sdarrenrstatic icmp_subtype_t paramnames[] = { 206145510Sdarrenr { ICMP_PARAMPROB_ERRATPTR, "errata_pointer" }, 207145510Sdarrenr { ICMP_PARAMPROB_OPTABSENT, "optmissing" }, 208145510Sdarrenr { ICMP_PARAMPROB_LENGTH, "length" }, 209145510Sdarrenr { -2, NULL } 210145510Sdarrenr}; 211145510Sdarrenr 212255332Scystatic icmp_type_t icmptypes4[] = { 213145510Sdarrenr { ICMP_ECHOREPLY, NULL, 0, "echoreply" }, 214145510Sdarrenr { -1, NULL, 0, NULL }, 215145510Sdarrenr { -1, NULL, 0, NULL }, 216145510Sdarrenr { ICMP_UNREACH, icmpunreachnames, 217145510Sdarrenr IST_SZ(icmpunreachnames),"unreach" }, 218145510Sdarrenr { ICMP_SOURCEQUENCH, NULL, 0, "sourcequench" }, 219145510Sdarrenr { ICMP_REDIRECT, redirectnames, 220145510Sdarrenr IST_SZ(redirectnames), "redirect" }, 221145510Sdarrenr { -1, NULL, 0, NULL }, 222145510Sdarrenr { -1, NULL, 0, NULL }, 223145510Sdarrenr { ICMP_ECHO, NULL, 0, "echo" }, 224145510Sdarrenr { ICMP_ROUTERADVERT, NULL, 0, "routeradvert" }, 225145510Sdarrenr { ICMP_ROUTERSOLICIT, NULL, 0, "routersolicit" }, 226145510Sdarrenr { ICMP_TIMXCEED, timxceednames, 227145510Sdarrenr IST_SZ(timxceednames), "timxceed" }, 228145510Sdarrenr { ICMP_PARAMPROB, paramnames, 229145510Sdarrenr IST_SZ(paramnames), "paramprob" }, 230145510Sdarrenr { ICMP_TSTAMP, NULL, 0, "timestamp" }, 231145510Sdarrenr { ICMP_TSTAMPREPLY, NULL, 0, "timestampreply" }, 232145510Sdarrenr { ICMP_IREQ, NULL, 0, "inforeq" }, 233145510Sdarrenr { ICMP_IREQREPLY, NULL, 0, "inforeply" }, 234145510Sdarrenr { ICMP_MASKREQ, NULL, 0, "maskreq" }, 235145510Sdarrenr { ICMP_MASKREPLY, NULL, 0, "maskreply" }, 236145510Sdarrenr { -2, NULL, 0, NULL } 237145510Sdarrenr}; 238145510Sdarrenr 239145510Sdarrenrstatic icmp_subtype_t icmpredirect6[] = { 240145510Sdarrenr { ICMP6_DST_UNREACH_NOROUTE, "noroute" }, 241145510Sdarrenr { ICMP6_DST_UNREACH_ADMIN, "admin" }, 242145510Sdarrenr { ICMP6_DST_UNREACH_NOTNEIGHBOR, "neighbour" }, 243145510Sdarrenr { ICMP6_DST_UNREACH_ADDR, "address" }, 244145510Sdarrenr { ICMP6_DST_UNREACH_NOPORT, "noport" }, 245145510Sdarrenr { -2, NULL } 246145510Sdarrenr}; 247145510Sdarrenr 248145510Sdarrenrstatic icmp_subtype_t icmptimexceed6[] = { 249145510Sdarrenr { ICMP6_TIME_EXCEED_TRANSIT, "intransit" }, 250145510Sdarrenr { ICMP6_TIME_EXCEED_REASSEMBLY, "reassem" }, 251145510Sdarrenr { -2, NULL } 252145510Sdarrenr}; 253145510Sdarrenr 254145510Sdarrenrstatic icmp_subtype_t icmpparamprob6[] = { 255145510Sdarrenr { ICMP6_PARAMPROB_HEADER, "header" }, 256145510Sdarrenr { ICMP6_PARAMPROB_NEXTHEADER, "nextheader" }, 257145510Sdarrenr { ICMP6_PARAMPROB_OPTION, "option" }, 258145510Sdarrenr { -2, NULL } 259145510Sdarrenr}; 260145510Sdarrenr 261145510Sdarrenrstatic icmp_subtype_t icmpquerysubject6[] = { 262145510Sdarrenr { ICMP6_NI_SUBJ_IPV6, "ipv6" }, 263145510Sdarrenr { ICMP6_NI_SUBJ_FQDN, "fqdn" }, 264145510Sdarrenr { ICMP6_NI_SUBJ_IPV4, "ipv4" }, 265145510Sdarrenr { -2, NULL }, 266145510Sdarrenr}; 267145510Sdarrenr 268145510Sdarrenrstatic icmp_subtype_t icmpnodeinfo6[] = { 269145510Sdarrenr { ICMP6_NI_SUCCESS, "success" }, 270145510Sdarrenr { ICMP6_NI_REFUSED, "refused" }, 271145510Sdarrenr { ICMP6_NI_UNKNOWN, "unknown" }, 272145510Sdarrenr { -2, NULL } 273145510Sdarrenr}; 274145510Sdarrenr 275145510Sdarrenrstatic icmp_subtype_t icmprenumber6[] = { 276145510Sdarrenr { ICMP6_ROUTER_RENUMBERING_COMMAND, "command" }, 277145510Sdarrenr { ICMP6_ROUTER_RENUMBERING_RESULT, "result" }, 278145510Sdarrenr { ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET, "seqnum_reset" }, 279145510Sdarrenr { -2, NULL } 280145510Sdarrenr}; 281145510Sdarrenr 282145510Sdarrenrstatic icmp_type_t icmptypes6[] = { 283145510Sdarrenr { 0, NULL, 0, NULL }, 284145510Sdarrenr { ICMP6_DST_UNREACH, icmpredirect6, 285145510Sdarrenr IST_SZ(icmpredirect6), "unreach" }, 286145510Sdarrenr { ICMP6_PACKET_TOO_BIG, NULL, 0, "toobig" }, 287145510Sdarrenr { ICMP6_TIME_EXCEEDED, icmptimexceed6, 288145510Sdarrenr IST_SZ(icmptimexceed6), "timxceed" }, 289145510Sdarrenr { ICMP6_PARAM_PROB, icmpparamprob6, 290145510Sdarrenr IST_SZ(icmpparamprob6), "paramprob" }, 291145510Sdarrenr { ICMP6_ECHO_REQUEST, NULL, 0, "echo" }, 292145510Sdarrenr { ICMP6_ECHO_REPLY, NULL, 0, "echoreply" }, 293145510Sdarrenr { ICMP6_MEMBERSHIP_QUERY, icmpquerysubject6, 294145510Sdarrenr IST_SZ(icmpquerysubject6), "groupmemberquery" }, 295145510Sdarrenr { ICMP6_MEMBERSHIP_REPORT,NULL, 0, "groupmemberreport" }, 296145510Sdarrenr { ICMP6_MEMBERSHIP_REDUCTION,NULL, 0, "groupmemberterm" }, 297145510Sdarrenr { ND_ROUTER_SOLICIT, NULL, 0, "routersolicit" }, 298145510Sdarrenr { ND_ROUTER_ADVERT, NULL, 0, "routeradvert" }, 299145510Sdarrenr { ND_NEIGHBOR_SOLICIT, NULL, 0, "neighborsolicit" }, 300145510Sdarrenr { ND_NEIGHBOR_ADVERT, NULL, 0, "neighboradvert" }, 301145510Sdarrenr { ND_REDIRECT, NULL, 0, "redirect" }, 302145510Sdarrenr { ICMP6_ROUTER_RENUMBERING, icmprenumber6, 303145510Sdarrenr IST_SZ(icmprenumber6), "routerrenumber" }, 304145510Sdarrenr { ICMP6_WRUREQUEST, NULL, 0, "whoareyourequest" }, 305145510Sdarrenr { ICMP6_WRUREPLY, NULL, 0, "whoareyoureply" }, 306145510Sdarrenr { ICMP6_FQDN_QUERY, NULL, 0, "fqdnquery" }, 307145510Sdarrenr { ICMP6_FQDN_REPLY, NULL, 0, "fqdnreply" }, 308145510Sdarrenr { ICMP6_NI_QUERY, icmpnodeinfo6, 309145510Sdarrenr IST_SZ(icmpnodeinfo6), "nodeinforequest" }, 310145510Sdarrenr { ICMP6_NI_REPLY, NULL, 0, "nodeinforeply" }, 311145510Sdarrenr { MLD6_MTRACE_RESP, NULL, 0, "mtraceresponse" }, 312145510Sdarrenr { MLD6_MTRACE, NULL, 0, "mtracerequest" }, 313145510Sdarrenr { -2, NULL, 0, NULL } 314145510Sdarrenr}; 315145510Sdarrenr 316145510Sdarrenrstatic icmp_subtype_t *find_icmpsubtype(type, table, tablesz) 317255332Scy int type; 318255332Scy icmp_subtype_t *table; 319255332Scy size_t tablesz; 320145510Sdarrenr{ 321145510Sdarrenr icmp_subtype_t *ist; 322145510Sdarrenr int i; 323145510Sdarrenr 324145510Sdarrenr if (tablesz < 2) 325145510Sdarrenr return NULL; 326145510Sdarrenr 327145510Sdarrenr if ((type < 0) || (type > table[tablesz - 2].ist_val)) 328145510Sdarrenr return NULL; 329145510Sdarrenr 330145510Sdarrenr i = type; 331145510Sdarrenr if (table[type].ist_val == type) 332145510Sdarrenr return table + type; 333145510Sdarrenr 334145510Sdarrenr for (i = 0, ist = table; ist->ist_val != -2; i++, ist++) 335145510Sdarrenr if (ist->ist_val == type) 336145510Sdarrenr return ist; 337145510Sdarrenr return NULL; 338145510Sdarrenr} 339145510Sdarrenr 340145510Sdarrenr 341145510Sdarrenrstatic icmp_type_t *find_icmptype(type, table, tablesz) 342255332Scy int type; 343255332Scy icmp_type_t *table; 344255332Scy size_t tablesz; 345145510Sdarrenr{ 346145510Sdarrenr icmp_type_t *it; 347145510Sdarrenr int i; 348145510Sdarrenr 349145510Sdarrenr if (tablesz < 2) 350145510Sdarrenr return NULL; 351145510Sdarrenr 352145510Sdarrenr if ((type < 0) || (type > table[tablesz - 2].it_val)) 353145510Sdarrenr return NULL; 354145510Sdarrenr 355145510Sdarrenr i = type; 356145510Sdarrenr if (table[type].it_val == type) 357145510Sdarrenr return table + type; 358145510Sdarrenr 359145510Sdarrenr for (i = 0, it = table; it->it_val != -2; i++, it++) 360145510Sdarrenr if (it->it_val == type) 361145510Sdarrenr return it; 362145510Sdarrenr return NULL; 363145510Sdarrenr} 364145510Sdarrenr 365145510Sdarrenr 366145510Sdarrenrstatic void handlehup(sig) 367255332Scy int sig; 368145510Sdarrenr{ 369145510Sdarrenr signal(SIGHUP, handlehup); 370145510Sdarrenr donehup = 1; 371145510Sdarrenr} 372145510Sdarrenr 373145510Sdarrenr 374145510Sdarrenrstatic void init_tabs() 375145510Sdarrenr{ 376145510Sdarrenr struct protoent *p; 377145510Sdarrenr struct servent *s; 378145510Sdarrenr char *name, **tab; 379145510Sdarrenr int port, i; 380145510Sdarrenr 381145510Sdarrenr if (protocols != NULL) { 382145510Sdarrenr for (i = 0; i < 256; i++) 383145510Sdarrenr if (protocols[i] != NULL) { 384145510Sdarrenr free(protocols[i]); 385145510Sdarrenr protocols[i] = NULL; 386145510Sdarrenr } 387145510Sdarrenr free(protocols); 388145510Sdarrenr protocols = NULL; 389145510Sdarrenr } 390145510Sdarrenr protocols = (char **)malloc(256 * sizeof(*protocols)); 391145510Sdarrenr if (protocols != NULL) { 392145510Sdarrenr bzero((char *)protocols, 256 * sizeof(*protocols)); 393145510Sdarrenr 394145510Sdarrenr setprotoent(1); 395145510Sdarrenr while ((p = getprotoent()) != NULL) 396145510Sdarrenr if (p->p_proto >= 0 && p->p_proto <= 255 && 397145510Sdarrenr p->p_name != NULL && protocols[p->p_proto] == NULL) 398145510Sdarrenr protocols[p->p_proto] = strdup(p->p_name); 399145510Sdarrenr endprotoent(); 400153881Sguido if (protocols[0]) 401153881Sguido free(protocols[0]); 402255332Scy protocols[0] = strdup("ip"); 403255332Scy#if defined(_AIX51) 404153881Sguido if (protocols[252]) 405153881Sguido free(protocols[252]); 406153881Sguido protocols[252] = NULL; 407153881Sguido#endif 408145510Sdarrenr } 409145510Sdarrenr 410145510Sdarrenr if (udp_ports != NULL) { 411145510Sdarrenr for (i = 0; i < 65536; i++) 412145510Sdarrenr if (udp_ports[i] != NULL) { 413145510Sdarrenr free(udp_ports[i]); 414145510Sdarrenr udp_ports[i] = NULL; 415145510Sdarrenr } 416145510Sdarrenr free(udp_ports); 417145510Sdarrenr udp_ports = NULL; 418145510Sdarrenr } 419145510Sdarrenr udp_ports = (char **)malloc(65536 * sizeof(*udp_ports)); 420145510Sdarrenr if (udp_ports != NULL) 421145510Sdarrenr bzero((char *)udp_ports, 65536 * sizeof(*udp_ports)); 422145510Sdarrenr 423145510Sdarrenr if (tcp_ports != NULL) { 424145510Sdarrenr for (i = 0; i < 65536; i++) 425145510Sdarrenr if (tcp_ports[i] != NULL) { 426145510Sdarrenr free(tcp_ports[i]); 427145510Sdarrenr tcp_ports[i] = NULL; 428145510Sdarrenr } 429145510Sdarrenr free(tcp_ports); 430145510Sdarrenr tcp_ports = NULL; 431145510Sdarrenr } 432145510Sdarrenr tcp_ports = (char **)malloc(65536 * sizeof(*tcp_ports)); 433145510Sdarrenr if (tcp_ports != NULL) 434145510Sdarrenr bzero((char *)tcp_ports, 65536 * sizeof(*tcp_ports)); 435145510Sdarrenr 436145510Sdarrenr setservent(1); 437145510Sdarrenr while ((s = getservent()) != NULL) { 438145510Sdarrenr if (s->s_proto == NULL) 439145510Sdarrenr continue; 440145510Sdarrenr else if (!strcmp(s->s_proto, "tcp")) { 441145510Sdarrenr port = ntohs(s->s_port); 442145510Sdarrenr name = s->s_name; 443145510Sdarrenr tab = tcp_ports; 444145510Sdarrenr } else if (!strcmp(s->s_proto, "udp")) { 445145510Sdarrenr port = ntohs(s->s_port); 446145510Sdarrenr name = s->s_name; 447145510Sdarrenr tab = udp_ports; 448145510Sdarrenr } else 449145510Sdarrenr continue; 450145510Sdarrenr if ((port < 0 || port > 65535) || (name == NULL)) 451145510Sdarrenr continue; 452145510Sdarrenr if (tab != NULL) 453145510Sdarrenr tab[port] = strdup(name); 454145510Sdarrenr } 455145510Sdarrenr endservent(); 456145510Sdarrenr} 457145510Sdarrenr 458145510Sdarrenr 459255332Scystatic char *getlocalproto(p) 460255332Scy u_int p; 461145510Sdarrenr{ 462145510Sdarrenr static char pnum[4]; 463145510Sdarrenr char *s; 464145510Sdarrenr 465145510Sdarrenr p &= 0xff; 466145510Sdarrenr s = protocols ? protocols[p] : NULL; 467145510Sdarrenr if (s == NULL) { 468145510Sdarrenr sprintf(pnum, "%u", p); 469145510Sdarrenr s = pnum; 470145510Sdarrenr } 471145510Sdarrenr return s; 472145510Sdarrenr} 473145510Sdarrenr 474145510Sdarrenr 475145510Sdarrenrstatic int read_log(fd, lenp, buf, bufsize) 476255332Scy int fd, bufsize, *lenp; 477255332Scy char *buf; 478145510Sdarrenr{ 479145510Sdarrenr int nr; 480145510Sdarrenr 481255332Scy if (bufsize > IPFILTER_LOGSIZE) 482255332Scy bufsize = IPFILTER_LOGSIZE; 483255332Scy 484145510Sdarrenr nr = read(fd, buf, bufsize); 485145510Sdarrenr if (!nr) 486145510Sdarrenr return 2; 487145510Sdarrenr if ((nr < 0) && (errno != EINTR)) 488145510Sdarrenr return -1; 489145510Sdarrenr *lenp = nr; 490145510Sdarrenr return 0; 491145510Sdarrenr} 492145510Sdarrenr 493145510Sdarrenr 494255332Scychar *portlocalname(res, proto, port) 495255332Scy int res; 496255332Scy char *proto; 497255332Scy u_int port; 498145510Sdarrenr{ 499255332Scy static char pname[8]; 500255332Scy char *s; 501145510Sdarrenr 502145510Sdarrenr port = ntohs(port); 503145510Sdarrenr port &= 0xffff; 504255332Scy sprintf(pname, "%u", port); 505255332Scy if (!res || (ipmonopts & IPMON_PORTNUM)) 506145510Sdarrenr return pname; 507145510Sdarrenr s = NULL; 508145510Sdarrenr if (!strcmp(proto, "tcp")) 509145510Sdarrenr s = tcp_ports[port]; 510145510Sdarrenr else if (!strcmp(proto, "udp")) 511145510Sdarrenr s = udp_ports[port]; 512145510Sdarrenr if (s == NULL) 513145510Sdarrenr s = pname; 514145510Sdarrenr return s; 515145510Sdarrenr} 516145510Sdarrenr 517145510Sdarrenr 518255332Scystatic char *icmpname(type, code) 519255332Scy u_int type; 520255332Scy u_int code; 521145510Sdarrenr{ 522145510Sdarrenr static char name[80]; 523145510Sdarrenr icmp_subtype_t *ist; 524145510Sdarrenr icmp_type_t *it; 525145510Sdarrenr char *s; 526145510Sdarrenr 527145510Sdarrenr s = NULL; 528255332Scy it = find_icmptype(type, icmptypes4, sizeof(icmptypes4) / sizeof(*it)); 529145510Sdarrenr if (it != NULL) 530145510Sdarrenr s = it->it_name; 531145510Sdarrenr 532145510Sdarrenr if (s == NULL) 533145510Sdarrenr sprintf(name, "icmptype(%d)/", type); 534145510Sdarrenr else 535145510Sdarrenr sprintf(name, "%s/", s); 536145510Sdarrenr 537145510Sdarrenr ist = NULL; 538145510Sdarrenr if (it != NULL && it->it_subtable != NULL) 539145510Sdarrenr ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); 540145510Sdarrenr 541145510Sdarrenr if (ist != NULL && ist->ist_name != NULL) 542145510Sdarrenr strcat(name, ist->ist_name); 543145510Sdarrenr else 544145510Sdarrenr sprintf(name + strlen(name), "%d", code); 545145510Sdarrenr 546145510Sdarrenr return name; 547145510Sdarrenr} 548145510Sdarrenr 549255332Scystatic char *icmpname6(type, code) 550255332Scy u_int type; 551255332Scy u_int code; 552145510Sdarrenr{ 553145510Sdarrenr static char name[80]; 554145510Sdarrenr icmp_subtype_t *ist; 555145510Sdarrenr icmp_type_t *it; 556145510Sdarrenr char *s; 557145510Sdarrenr 558145510Sdarrenr s = NULL; 559145510Sdarrenr it = find_icmptype(type, icmptypes6, sizeof(icmptypes6) / sizeof(*it)); 560145510Sdarrenr if (it != NULL) 561145510Sdarrenr s = it->it_name; 562145510Sdarrenr 563145510Sdarrenr if (s == NULL) 564145510Sdarrenr sprintf(name, "icmpv6type(%d)/", type); 565145510Sdarrenr else 566145510Sdarrenr sprintf(name, "%s/", s); 567145510Sdarrenr 568145510Sdarrenr ist = NULL; 569145510Sdarrenr if (it != NULL && it->it_subtable != NULL) 570145510Sdarrenr ist = find_icmpsubtype(code, it->it_subtable, it->it_stsize); 571145510Sdarrenr 572145510Sdarrenr if (ist != NULL && ist->ist_name != NULL) 573145510Sdarrenr strcat(name, ist->ist_name); 574145510Sdarrenr else 575145510Sdarrenr sprintf(name + strlen(name), "%d", code); 576145510Sdarrenr 577145510Sdarrenr return name; 578145510Sdarrenr} 579145510Sdarrenr 580145510Sdarrenr 581255332Scyvoid dumphex(log, dopts, buf, len) 582255332Scy FILE *log; 583255332Scy int dopts; 584255332Scy char *buf; 585255332Scy int len; 586145510Sdarrenr{ 587145510Sdarrenr char hline[80]; 588145510Sdarrenr int i, j, k; 589145510Sdarrenr u_char *s = (u_char *)buf, *t = (u_char *)hline; 590145510Sdarrenr 591145510Sdarrenr if (buf == NULL || len == 0) 592145510Sdarrenr return; 593145510Sdarrenr 594145510Sdarrenr *hline = '\0'; 595145510Sdarrenr 596145510Sdarrenr for (i = len, j = 0; i; i--, j++, s++) { 597145510Sdarrenr if (j && !(j & 0xf)) { 598145510Sdarrenr *t++ = '\n'; 599145510Sdarrenr *t = '\0'; 600255332Scy if ((dopts & IPMON_SYSLOG)) 601161357Sguido syslog(LOG_INFO, "%s", hline); 602161357Sguido else if (log != NULL) 603145510Sdarrenr fputs(hline, log); 604145510Sdarrenr t = (u_char *)hline; 605145510Sdarrenr *t = '\0'; 606145510Sdarrenr } 607145510Sdarrenr sprintf((char *)t, "%02x", *s & 0xff); 608145510Sdarrenr t += 2; 609145510Sdarrenr if (!((j + 1) & 0xf)) { 610145510Sdarrenr s -= 15; 611145510Sdarrenr sprintf((char *)t, " "); 612145510Sdarrenr t += 8; 613145510Sdarrenr for (k = 16; k; k--, s++) 614255332Scy *t++ = (isprint(*s) ? *s : '.'); 615145510Sdarrenr s--; 616145510Sdarrenr } 617255332Scy 618145510Sdarrenr if ((j + 1) & 0xf) 619145510Sdarrenr *t++ = ' ';; 620145510Sdarrenr } 621145510Sdarrenr 622145510Sdarrenr if (j & 0xf) { 623145510Sdarrenr for (k = 16 - (j & 0xf); k; k--) { 624145510Sdarrenr *t++ = ' '; 625145510Sdarrenr *t++ = ' '; 626145510Sdarrenr *t++ = ' '; 627145510Sdarrenr } 628145510Sdarrenr sprintf((char *)t, " "); 629145510Sdarrenr t += 7; 630145510Sdarrenr s -= j & 0xf; 631145510Sdarrenr for (k = j & 0xf; k; k--, s++) 632255332Scy *t++ = (isprint(*s) ? *s : '.'); 633145510Sdarrenr *t++ = '\n'; 634145510Sdarrenr *t = '\0'; 635145510Sdarrenr } 636255332Scy if ((dopts & IPMON_SYSLOG) != 0) 637161357Sguido syslog(LOG_INFO, "%s", hline); 638161357Sguido else if (log != NULL) { 639145510Sdarrenr fputs(hline, log); 640145510Sdarrenr fflush(log); 641161357Sguido } 642145510Sdarrenr} 643145510Sdarrenr 644145510Sdarrenr 645255332Scystatic struct tm *get_tm(sec) 646145510Sdarrenr#ifdef __hpux 647255332Scy u_32_t sec; 648145510Sdarrenr#else 649255332Scy time_t sec; 650145510Sdarrenr#endif 651145510Sdarrenr{ 652145510Sdarrenr struct tm *tm; 653145510Sdarrenr time_t t; 654145510Sdarrenr 655145510Sdarrenr t = sec; 656145510Sdarrenr tm = localtime(&t); 657145510Sdarrenr return tm; 658145510Sdarrenr} 659145510Sdarrenr 660255332Scystatic void print_natlog(conf, buf, blen) 661255332Scy config_t *conf; 662255332Scy char *buf; 663255332Scy int blen; 664145510Sdarrenr{ 665255332Scy static u_32_t seqnum = 0; 666255332Scy int res, i, len, family; 667255332Scy struct natlog *nl; 668255332Scy struct tm *tm; 669255332Scy iplog_t *ipl; 670255332Scy char *proto; 671255332Scy int simple; 672255332Scy char *t; 673145510Sdarrenr 674255332Scy t = line; 675255332Scy simple = 0; 676255332Scy ipl = (iplog_t *)buf; 677255332Scy if (ipl->ipl_seqnum != seqnum) { 678255332Scy if ((ipmonopts & IPMON_SYSLOG) != 0) { 679255332Scy syslog(LOG_WARNING, 680255332Scy "missed %u NAT log entries: %u %u", 681255332Scy ipl->ipl_seqnum - seqnum, seqnum, 682255332Scy ipl->ipl_seqnum); 683255332Scy } else { 684255332Scy (void) fprintf(conf->log, 685255332Scy "missed %u NAT log entries: %u %u\n", 686255332Scy ipl->ipl_seqnum - seqnum, seqnum, 687255332Scy ipl->ipl_seqnum); 688255332Scy } 689255332Scy } 690255332Scy seqnum = ipl->ipl_seqnum + ipl->ipl_count; 691255332Scy 692145510Sdarrenr nl = (struct natlog *)((char *)ipl + sizeof(*ipl)); 693255332Scy res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; 694145510Sdarrenr tm = get_tm(ipl->ipl_sec); 695145510Sdarrenr len = sizeof(line); 696255332Scy 697255332Scy if (!(ipmonopts & IPMON_SYSLOG)) { 698145510Sdarrenr (void) strftime(t, len, "%d/%m/%Y ", tm); 699145510Sdarrenr i = strlen(t); 700145510Sdarrenr len -= i; 701145510Sdarrenr t += i; 702145510Sdarrenr } 703145510Sdarrenr (void) strftime(t, len, "%T", tm); 704145510Sdarrenr t += strlen(t); 705255332Scy sprintf(t, ".%-.6ld @%hd ", (long)ipl->ipl_usec, nl->nl_rule + 1); 706145510Sdarrenr t += strlen(t); 707145510Sdarrenr 708255332Scy switch (nl->nl_action) 709255332Scy { 710255332Scy case NL_NEW : 711255332Scy strcpy(t, "NAT:NEW"); 712255332Scy break; 713255332Scy 714255332Scy case NL_FLUSH : 715255332Scy strcpy(t, "NAT:FLUSH"); 716255332Scy break; 717255332Scy 718255332Scy case NL_CLONE : 719255332Scy strcpy(t, "NAT:CLONE"); 720255332Scy break; 721255332Scy 722255332Scy case NL_EXPIRE : 723255332Scy strcpy(t, "NAT:EXPIRE"); 724255332Scy break; 725255332Scy 726255332Scy case NL_DESTROY : 727255332Scy strcpy(t, "NAT:DESTROY"); 728255332Scy break; 729255332Scy 730255332Scy case NL_PURGE : 731255332Scy strcpy(t, "NAT:PURGE"); 732255332Scy break; 733255332Scy 734255332Scy default : 735255332Scy sprintf(t, "NAT:Action(%d)", nl->nl_action); 736255332Scy break; 737255332Scy } 738145510Sdarrenr t += strlen(t); 739145510Sdarrenr 740145510Sdarrenr 741255332Scy switch (nl->nl_type) 742255332Scy { 743255332Scy case NAT_MAP : 744255332Scy strcpy(t, "-MAP "); 745255332Scy simple = 1; 746255332Scy break; 747255332Scy 748255332Scy case NAT_REDIRECT : 749255332Scy strcpy(t, "-RDR "); 750255332Scy simple = 1; 751255332Scy break; 752255332Scy 753255332Scy case NAT_BIMAP : 754255332Scy strcpy(t, "-BIMAP "); 755255332Scy simple = 1; 756255332Scy break; 757255332Scy 758255332Scy case NAT_MAPBLK : 759255332Scy strcpy(t, "-MAPBLOCK "); 760255332Scy simple = 1; 761255332Scy break; 762255332Scy 763255332Scy case NAT_REWRITE|NAT_MAP : 764255332Scy strcpy(t, "-RWR_MAP "); 765255332Scy break; 766255332Scy 767255332Scy case NAT_REWRITE|NAT_REDIRECT : 768255332Scy strcpy(t, "-RWR_RDR "); 769255332Scy break; 770255332Scy 771255332Scy case NAT_ENCAP|NAT_MAP : 772255332Scy strcpy(t, "-ENC_MAP "); 773255332Scy break; 774255332Scy 775255332Scy case NAT_ENCAP|NAT_REDIRECT : 776255332Scy strcpy(t, "-ENC_RDR "); 777255332Scy break; 778255332Scy 779255332Scy case NAT_DIVERTUDP|NAT_MAP : 780255332Scy strcpy(t, "-DIV_MAP "); 781255332Scy break; 782255332Scy 783255332Scy case NAT_DIVERTUDP|NAT_REDIRECT : 784255332Scy strcpy(t, "-DIV_RDR "); 785255332Scy break; 786255332Scy 787255332Scy default : 788255332Scy sprintf(t, "-Type(%d) ", nl->nl_type); 789255332Scy break; 790255332Scy } 791145510Sdarrenr t += strlen(t); 792255332Scy 793255332Scy proto = getlocalproto(nl->nl_p[0]); 794255332Scy 795255332Scy family = vtof(nl->nl_v[0]); 796255332Scy 797255332Scy if (simple == 1) { 798255332Scy sprintf(t, "%s,%s <- -> ", hostname(family, nl->nl_osrcip.i6), 799255332Scy portlocalname(res, proto, (u_int)nl->nl_osrcport)); 800255332Scy t += strlen(t); 801255332Scy sprintf(t, "%s,%s ", hostname(family, nl->nl_nsrcip.i6), 802255332Scy portlocalname(res, proto, (u_int)nl->nl_nsrcport)); 803255332Scy t += strlen(t); 804255332Scy sprintf(t, "[%s,%s] ", hostname(family, nl->nl_odstip.i6), 805255332Scy portlocalname(res, proto, (u_int)nl->nl_odstport)); 806255332Scy } else { 807255332Scy sprintf(t, "%s,%s ", hostname(family, nl->nl_osrcip.i6), 808255332Scy portlocalname(res, proto, (u_int)nl->nl_osrcport)); 809255332Scy t += strlen(t); 810255332Scy sprintf(t, "%s,%s <- -> ", hostname(family, nl->nl_odstip.i6), 811255332Scy portlocalname(res, proto, (u_int)nl->nl_odstport)); 812255332Scy t += strlen(t); 813255332Scy sprintf(t, "%s,%s ", hostname(family, nl->nl_nsrcip.i6), 814255332Scy portlocalname(res, proto, (u_int)nl->nl_nsrcport)); 815255332Scy t += strlen(t); 816255332Scy sprintf(t, "%s,%s ", hostname(family, nl->nl_ndstip.i6), 817255332Scy portlocalname(res, proto, (u_int)nl->nl_ndstport)); 818255332Scy } 819145510Sdarrenr t += strlen(t); 820255332Scy 821255332Scy strcpy(t, getlocalproto(nl->nl_p[0])); 822145510Sdarrenr t += strlen(t); 823255332Scy 824255332Scy if (nl->nl_action == NL_EXPIRE || nl->nl_action == NL_FLUSH) { 825145510Sdarrenr#ifdef USE_QUAD_T 826255332Scy# ifdef PRId64 827255332Scy sprintf(t, " Pkts %" PRId64 "/%" PRId64 " Bytes %" PRId64 "/%" 828255332Scy PRId64, 829255332Scy# else 830255332Scy sprintf(t, " Pkts %qd/%qd Bytes %qd/%qd", 831255332Scy# endif 832145510Sdarrenr#else 833255332Scy sprintf(t, " Pkts %ld/%ld Bytes %ld/%ld", 834255332Scy#endif 835145510Sdarrenr nl->nl_pkts[0], nl->nl_pkts[1], 836145510Sdarrenr nl->nl_bytes[0], nl->nl_bytes[1]); 837145510Sdarrenr t += strlen(t); 838145510Sdarrenr } 839145510Sdarrenr 840145510Sdarrenr *t++ = '\n'; 841145510Sdarrenr *t++ = '\0'; 842255332Scy if (ipmonopts & IPMON_SYSLOG) 843145510Sdarrenr syslog(LOG_INFO, "%s", line); 844255332Scy else if (conf->log != NULL) 845255332Scy (void) fprintf(conf->log, "%s", line); 846145510Sdarrenr} 847145510Sdarrenr 848145510Sdarrenr 849255332Scystatic void print_statelog(conf, buf, blen) 850255332Scy config_t *conf; 851255332Scy char *buf; 852255332Scy int blen; 853145510Sdarrenr{ 854255332Scy static u_32_t seqnum = 0; 855255332Scy int res, i, len, family; 856255332Scy struct ipslog *sl; 857255332Scy char *t, *proto; 858255332Scy struct tm *tm; 859255332Scy iplog_t *ipl; 860145510Sdarrenr 861255332Scy t = line; 862255332Scy ipl = (iplog_t *)buf; 863255332Scy if (ipl->ipl_seqnum != seqnum) { 864255332Scy if ((ipmonopts & IPMON_SYSLOG) != 0) { 865255332Scy syslog(LOG_WARNING, 866255332Scy "missed %u state log entries: %u %u", 867255332Scy ipl->ipl_seqnum - seqnum, seqnum, 868255332Scy ipl->ipl_seqnum); 869255332Scy } else { 870255332Scy (void) fprintf(conf->log, 871255332Scy "missed %u state log entries: %u %u\n", 872255332Scy ipl->ipl_seqnum - seqnum, seqnum, 873255332Scy ipl->ipl_seqnum); 874255332Scy } 875255332Scy } 876255332Scy seqnum = ipl->ipl_seqnum + ipl->ipl_count; 877255332Scy 878145510Sdarrenr sl = (struct ipslog *)((char *)ipl + sizeof(*ipl)); 879255332Scy res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; 880145510Sdarrenr tm = get_tm(ipl->ipl_sec); 881145510Sdarrenr len = sizeof(line); 882255332Scy if (!(ipmonopts & IPMON_SYSLOG)) { 883145510Sdarrenr (void) strftime(t, len, "%d/%m/%Y ", tm); 884145510Sdarrenr i = strlen(t); 885145510Sdarrenr len -= i; 886145510Sdarrenr t += i; 887145510Sdarrenr } 888145510Sdarrenr (void) strftime(t, len, "%T", tm); 889145510Sdarrenr t += strlen(t); 890255332Scy sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec); 891145510Sdarrenr t += strlen(t); 892145510Sdarrenr 893255332Scy family = vtof(sl->isl_v); 894255332Scy 895170268Sdarrenr switch (sl->isl_type) 896170268Sdarrenr { 897170268Sdarrenr case ISL_NEW : 898145510Sdarrenr strcpy(t, "STATE:NEW "); 899170268Sdarrenr break; 900170268Sdarrenr 901170268Sdarrenr case ISL_CLONE : 902145510Sdarrenr strcpy(t, "STATE:CLONED "); 903170268Sdarrenr break; 904170268Sdarrenr 905170268Sdarrenr case ISL_EXPIRE : 906145510Sdarrenr if ((sl->isl_p == IPPROTO_TCP) && 907145510Sdarrenr (sl->isl_state[0] > IPF_TCPS_ESTABLISHED || 908145510Sdarrenr sl->isl_state[1] > IPF_TCPS_ESTABLISHED)) 909145510Sdarrenr strcpy(t, "STATE:CLOSE "); 910145510Sdarrenr else 911145510Sdarrenr strcpy(t, "STATE:EXPIRE "); 912170268Sdarrenr break; 913170268Sdarrenr 914170268Sdarrenr case ISL_FLUSH : 915145510Sdarrenr strcpy(t, "STATE:FLUSH "); 916170268Sdarrenr break; 917170268Sdarrenr 918170268Sdarrenr case ISL_INTERMEDIATE : 919145510Sdarrenr strcpy(t, "STATE:INTERMEDIATE "); 920170268Sdarrenr break; 921170268Sdarrenr 922170268Sdarrenr case ISL_REMOVE : 923145510Sdarrenr strcpy(t, "STATE:REMOVE "); 924170268Sdarrenr break; 925170268Sdarrenr 926170268Sdarrenr case ISL_KILLED : 927145510Sdarrenr strcpy(t, "STATE:KILLED "); 928170268Sdarrenr break; 929170268Sdarrenr 930170268Sdarrenr case ISL_UNLOAD : 931170268Sdarrenr strcpy(t, "STATE:UNLOAD "); 932170268Sdarrenr break; 933170268Sdarrenr 934170268Sdarrenr default : 935145510Sdarrenr sprintf(t, "Type: %d ", sl->isl_type); 936170268Sdarrenr break; 937170268Sdarrenr } 938145510Sdarrenr t += strlen(t); 939145510Sdarrenr 940255332Scy proto = getlocalproto(sl->isl_p); 941145510Sdarrenr 942145510Sdarrenr if (sl->isl_p == IPPROTO_TCP || sl->isl_p == IPPROTO_UDP) { 943255332Scy sprintf(t, "%s,%s -> ", 944255332Scy hostname(family, (u_32_t *)&sl->isl_src), 945255332Scy portlocalname(res, proto, (u_int)sl->isl_sport)); 946145510Sdarrenr t += strlen(t); 947255332Scy sprintf(t, "%s,%s PR %s", 948255332Scy hostname(family, (u_32_t *)&sl->isl_dst), 949255332Scy portlocalname(res, proto, (u_int)sl->isl_dport), proto); 950145510Sdarrenr } else if (sl->isl_p == IPPROTO_ICMP) { 951255332Scy sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); 952145510Sdarrenr t += strlen(t); 953255332Scy sprintf(t, "%s PR icmp %d", 954255332Scy hostname(family, (u_32_t *)&sl->isl_dst), 955145510Sdarrenr sl->isl_itype); 956145510Sdarrenr } else if (sl->isl_p == IPPROTO_ICMPV6) { 957255332Scy sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); 958145510Sdarrenr t += strlen(t); 959255332Scy sprintf(t, "%s PR icmpv6 %d", 960255332Scy hostname(family, (u_32_t *)&sl->isl_dst), 961145510Sdarrenr sl->isl_itype); 962145510Sdarrenr } else { 963255332Scy sprintf(t, "%s -> ", hostname(family, (u_32_t *)&sl->isl_src)); 964145510Sdarrenr t += strlen(t); 965255332Scy sprintf(t, "%s PR %s", 966255332Scy hostname(family, (u_32_t *)&sl->isl_dst), proto); 967145510Sdarrenr } 968145510Sdarrenr t += strlen(t); 969145510Sdarrenr if (sl->isl_tag != FR_NOLOGTAG) { 970255332Scy sprintf(t, " tag %u", sl->isl_tag); 971145510Sdarrenr t += strlen(t); 972145510Sdarrenr } 973145510Sdarrenr if (sl->isl_type != ISL_NEW) { 974145510Sdarrenr sprintf(t, 975145510Sdarrenr#ifdef USE_QUAD_T 976145510Sdarrenr#ifdef PRId64 977145510Sdarrenr " Forward: Pkts in %" PRId64 " Bytes in %" PRId64 978145510Sdarrenr " Pkts out %" PRId64 " Bytes out %" PRId64 979145510Sdarrenr " Backward: Pkts in %" PRId64 " Bytes in %" PRId64 980145510Sdarrenr " Pkts out %" PRId64 " Bytes out %" PRId64, 981145510Sdarrenr#else 982145510Sdarrenr " 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", 983145510Sdarrenr#endif /* PRId64 */ 984145510Sdarrenr#else 985145510Sdarrenr " 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", 986145510Sdarrenr#endif 987145510Sdarrenr sl->isl_pkts[0], sl->isl_bytes[0], 988145510Sdarrenr sl->isl_pkts[1], sl->isl_bytes[1], 989145510Sdarrenr sl->isl_pkts[2], sl->isl_bytes[2], 990145510Sdarrenr sl->isl_pkts[3], sl->isl_bytes[3]); 991145510Sdarrenr 992145510Sdarrenr t += strlen(t); 993145510Sdarrenr } 994145510Sdarrenr 995145510Sdarrenr *t++ = '\n'; 996145510Sdarrenr *t++ = '\0'; 997255332Scy if (ipmonopts & IPMON_SYSLOG) 998145510Sdarrenr syslog(LOG_INFO, "%s", line); 999255332Scy else if (conf->log != NULL) 1000255332Scy (void) fprintf(conf->log, "%s", line); 1001145510Sdarrenr} 1002145510Sdarrenr 1003145510Sdarrenr 1004255332Scystatic void print_log(conf, log, buf, blen) 1005255332Scy config_t *conf; 1006255332Scy logsource_t *log; 1007255332Scy char *buf; 1008255332Scy int blen; 1009145510Sdarrenr{ 1010255332Scy char *bp, *bpo; 1011145510Sdarrenr iplog_t *ipl; 1012145510Sdarrenr int psize; 1013145510Sdarrenr 1014255332Scy bp = NULL; 1015255332Scy bpo = NULL; 1016255332Scy 1017145510Sdarrenr while (blen > 0) { 1018145510Sdarrenr ipl = (iplog_t *)buf; 1019145510Sdarrenr if ((u_long)ipl & (sizeof(long)-1)) { 1020145510Sdarrenr if (bp) 1021145510Sdarrenr bpo = bp; 1022145510Sdarrenr bp = (char *)malloc(blen); 1023145510Sdarrenr bcopy((char *)ipl, bp, blen); 1024145510Sdarrenr if (bpo) { 1025145510Sdarrenr free(bpo); 1026145510Sdarrenr bpo = NULL; 1027145510Sdarrenr } 1028145510Sdarrenr buf = bp; 1029145510Sdarrenr continue; 1030145510Sdarrenr } 1031145510Sdarrenr 1032145510Sdarrenr psize = ipl->ipl_dsize; 1033145510Sdarrenr if (psize > blen) 1034145510Sdarrenr break; 1035145510Sdarrenr 1036255332Scy if (conf->blog != NULL) { 1037255332Scy fwrite(buf, psize, 1, conf->blog); 1038255332Scy fflush(conf->blog); 1039145510Sdarrenr } 1040145510Sdarrenr 1041255332Scy if (log->logtype == IPL_LOGIPF) { 1042145510Sdarrenr if (ipl->ipl_magic == IPL_MAGIC) 1043255332Scy print_ipflog(conf, buf, psize); 1044145510Sdarrenr 1045255332Scy } else if (log->logtype == IPL_LOGNAT) { 1046145510Sdarrenr if (ipl->ipl_magic == IPL_MAGIC_NAT) 1047255332Scy print_natlog(conf, buf, psize); 1048145510Sdarrenr 1049255332Scy } else if (log->logtype == IPL_LOGSTATE) { 1050145510Sdarrenr if (ipl->ipl_magic == IPL_MAGIC_STATE) 1051255332Scy print_statelog(conf, buf, psize); 1052145510Sdarrenr } 1053145510Sdarrenr 1054145510Sdarrenr blen -= psize; 1055145510Sdarrenr buf += psize; 1056145510Sdarrenr } 1057145510Sdarrenr if (bp) 1058145510Sdarrenr free(bp); 1059145510Sdarrenr return; 1060145510Sdarrenr} 1061145510Sdarrenr 1062145510Sdarrenr 1063255332Scystatic void print_ipflog(conf, buf, blen) 1064255332Scy config_t *conf; 1065255332Scy char *buf; 1066255332Scy int blen; 1067145510Sdarrenr{ 1068255332Scy static u_32_t seqnum = 0; 1069255332Scy int i, f, lvl, res, len, off, plen, ipoff, defaction; 1070255332Scy struct icmp *icmp; 1071255332Scy struct icmp *ic; 1072255332Scy char *t, *proto; 1073255332Scy ip_t *ipc, *ip; 1074255332Scy struct tm *tm; 1075255332Scy u_32_t *s, *d; 1076255332Scy u_short hl, p; 1077145510Sdarrenr ipflog_t *ipf; 1078255332Scy iplog_t *ipl; 1079255332Scy tcphdr_t *tp; 1080145510Sdarrenr#ifdef USE_INET6 1081172776Sdarrenr struct ip6_ext *ehp; 1082172776Sdarrenr u_short ehl; 1083145510Sdarrenr ip6_t *ip6; 1084172776Sdarrenr int go; 1085145510Sdarrenr#endif 1086145510Sdarrenr 1087145510Sdarrenr ipl = (iplog_t *)buf; 1088255332Scy if (ipl->ipl_seqnum != seqnum) { 1089255332Scy if ((ipmonopts & IPMON_SYSLOG) != 0) { 1090255332Scy syslog(LOG_WARNING, 1091255332Scy "missed %u ipf log entries: %u %u", 1092255332Scy ipl->ipl_seqnum - seqnum, seqnum, 1093255332Scy ipl->ipl_seqnum); 1094255332Scy } else { 1095255332Scy (void) fprintf(conf->log, 1096255332Scy "missed %u ipf log entries: %u %u\n", 1097255332Scy ipl->ipl_seqnum - seqnum, seqnum, 1098255332Scy ipl->ipl_seqnum); 1099255332Scy } 1100255332Scy } 1101255332Scy seqnum = ipl->ipl_seqnum + ipl->ipl_count; 1102255332Scy 1103145510Sdarrenr ipf = (ipflog_t *)((char *)buf + sizeof(*ipl)); 1104145510Sdarrenr ip = (ip_t *)((char *)ipf + sizeof(*ipf)); 1105255332Scy f = ipf->fl_family; 1106255332Scy res = (ipmonopts & IPMON_RESOLVE) ? 1 : 0; 1107145510Sdarrenr t = line; 1108145510Sdarrenr *t = '\0'; 1109145510Sdarrenr tm = get_tm(ipl->ipl_sec); 1110145510Sdarrenr 1111145510Sdarrenr len = sizeof(line); 1112255332Scy if (!(ipmonopts & IPMON_SYSLOG)) { 1113145510Sdarrenr (void) strftime(t, len, "%d/%m/%Y ", tm); 1114145510Sdarrenr i = strlen(t); 1115145510Sdarrenr len -= i; 1116145510Sdarrenr t += i; 1117145510Sdarrenr } 1118145510Sdarrenr (void) strftime(t, len, "%T", tm); 1119145510Sdarrenr t += strlen(t); 1120255332Scy sprintf(t, ".%-.6ld ", (long)ipl->ipl_usec); 1121145510Sdarrenr t += strlen(t); 1122145510Sdarrenr if (ipl->ipl_count > 1) { 1123255332Scy sprintf(t, "%dx ", ipl->ipl_count); 1124145510Sdarrenr t += strlen(t); 1125145510Sdarrenr } 1126145510Sdarrenr#if (defined(MENTAT) || \ 1127145510Sdarrenr (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ 1128145510Sdarrenr (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \ 1129145510Sdarrenr (defined(OpenBSD) && (OpenBSD >= 199603))) || defined(linux) 1130145510Sdarrenr { 1131145510Sdarrenr char ifname[sizeof(ipf->fl_ifname) + 1]; 1132145510Sdarrenr 1133145510Sdarrenr strncpy(ifname, ipf->fl_ifname, sizeof(ipf->fl_ifname)); 1134145510Sdarrenr ifname[sizeof(ipf->fl_ifname)] = '\0'; 1135255332Scy sprintf(t, "%s", ifname); 1136145510Sdarrenr t += strlen(t); 1137145510Sdarrenr# if defined(MENTAT) || defined(linux) 1138255332Scy# if defined(linux) 1139255332Scy /* 1140255332Scy * On Linux, the loopback interface is just "lo", not "lo0". 1141255332Scy */ 1142255332Scy if (strcmp(ifname, "lo") != 0) 1143255332Scy# endif 1144255332Scy if (ISALPHA(*(t - 1))) { 1145255332Scy sprintf(t, "%d", ipf->fl_unit); 1146255332Scy t += strlen(t); 1147255332Scy } 1148145510Sdarrenr# endif 1149145510Sdarrenr } 1150145510Sdarrenr#else 1151145510Sdarrenr for (len = 0; len < 3; len++) 1152145510Sdarrenr if (ipf->fl_ifname[len] == '\0') 1153145510Sdarrenr break; 1154145510Sdarrenr if (ipf->fl_ifname[len]) 1155145510Sdarrenr len++; 1156255332Scy sprintf(t, "%*.*s%u", len, len, ipf->fl_ifname, ipf->fl_unit); 1157145510Sdarrenr t += strlen(t); 1158145510Sdarrenr#endif 1159161357Sguido if ((ipf->fl_group[0] == (char)~0) && (ipf->fl_group[1] == '\0')) 1160145510Sdarrenr strcat(t, " @-1:"); 1161145510Sdarrenr else if (ipf->fl_group[0] == '\0') 1162145510Sdarrenr (void) strcpy(t, " @0:"); 1163145510Sdarrenr else 1164255332Scy sprintf(t, " @%s:", ipf->fl_group); 1165145510Sdarrenr t += strlen(t); 1166145510Sdarrenr if (ipf->fl_rule == 0xffffffff) 1167145510Sdarrenr strcat(t, "-1 "); 1168145510Sdarrenr else 1169255332Scy sprintf(t, "%u ", ipf->fl_rule + 1); 1170145510Sdarrenr t += strlen(t); 1171145510Sdarrenr 1172145510Sdarrenr lvl = LOG_NOTICE; 1173145510Sdarrenr 1174145510Sdarrenr if (ipf->fl_lflags & FI_SHORT) { 1175145510Sdarrenr *t++ = 'S'; 1176145510Sdarrenr lvl = LOG_ERR; 1177145510Sdarrenr } 1178145510Sdarrenr 1179145510Sdarrenr if (FR_ISPASS(ipf->fl_flags)) { 1180145510Sdarrenr if (ipf->fl_flags & FR_LOGP) 1181145510Sdarrenr *t++ = 'p'; 1182145510Sdarrenr else 1183145510Sdarrenr *t++ = 'P'; 1184145510Sdarrenr } else if (FR_ISBLOCK(ipf->fl_flags)) { 1185145510Sdarrenr if (ipf->fl_flags & FR_LOGB) 1186145510Sdarrenr *t++ = 'b'; 1187145510Sdarrenr else 1188145510Sdarrenr *t++ = 'B'; 1189145510Sdarrenr lvl = LOG_WARNING; 1190145510Sdarrenr } else if ((ipf->fl_flags & FR_LOGMASK) == FR_LOG) { 1191145510Sdarrenr *t++ = 'L'; 1192145510Sdarrenr lvl = LOG_INFO; 1193145510Sdarrenr } else if (ipf->fl_flags & FF_LOGNOMATCH) { 1194145510Sdarrenr *t++ = 'n'; 1195145510Sdarrenr } else { 1196145510Sdarrenr *t++ = '?'; 1197145510Sdarrenr lvl = LOG_EMERG; 1198145510Sdarrenr } 1199145510Sdarrenr if (ipf->fl_loglevel != 0xffff) 1200145510Sdarrenr lvl = ipf->fl_loglevel; 1201145510Sdarrenr *t++ = ' '; 1202145510Sdarrenr *t = '\0'; 1203145510Sdarrenr 1204255332Scy if (f == AF_INET) { 1205255332Scy hl = IP_HL(ip) << 2; 1206255332Scy ipoff = ntohs(ip->ip_off); 1207255332Scy off = ipoff & IP_OFFMASK; 1208255332Scy p = (u_short)ip->ip_p; 1209255332Scy s = (u_32_t *)&ip->ip_src; 1210255332Scy d = (u_32_t *)&ip->ip_dst; 1211255332Scy plen = ntohs(ip->ip_len); 1212255332Scy } else 1213145510Sdarrenr#ifdef USE_INET6 1214255332Scy if (f == AF_INET6) { 1215145510Sdarrenr off = 0; 1216145510Sdarrenr ipoff = 0; 1217145510Sdarrenr hl = sizeof(ip6_t); 1218145510Sdarrenr ip6 = (ip6_t *)ip; 1219145510Sdarrenr p = (u_short)ip6->ip6_nxt; 1220145510Sdarrenr s = (u_32_t *)&ip6->ip6_src; 1221145510Sdarrenr d = (u_32_t *)&ip6->ip6_dst; 1222145510Sdarrenr plen = hl + ntohs(ip6->ip6_plen); 1223172776Sdarrenr go = 1; 1224172776Sdarrenr ehp = (struct ip6_ext *)((char *)ip6 + hl); 1225172776Sdarrenr while (go == 1) { 1226172776Sdarrenr switch (p) 1227172776Sdarrenr { 1228172776Sdarrenr case IPPROTO_HOPOPTS : 1229172776Sdarrenr case IPPROTO_MOBILITY : 1230172776Sdarrenr case IPPROTO_DSTOPTS : 1231172776Sdarrenr case IPPROTO_ROUTING : 1232172776Sdarrenr case IPPROTO_AH : 1233172776Sdarrenr p = ehp->ip6e_nxt; 1234172776Sdarrenr ehl = 8 + (ehp->ip6e_len << 3); 1235172776Sdarrenr hl += ehl; 1236172776Sdarrenr ehp = (struct ip6_ext *)((char *)ehp + ehl); 1237172776Sdarrenr break; 1238172776Sdarrenr case IPPROTO_FRAGMENT : 1239172776Sdarrenr hl += sizeof(struct ip6_frag); 1240172776Sdarrenr /* FALLTHROUGH */ 1241172776Sdarrenr default : 1242172776Sdarrenr go = 0; 1243172776Sdarrenr break; 1244172776Sdarrenr } 1245172776Sdarrenr } 1246255332Scy } else 1247145510Sdarrenr#endif 1248255332Scy { 1249145510Sdarrenr goto printipflog; 1250145510Sdarrenr } 1251255332Scy proto = getlocalproto(p); 1252145510Sdarrenr 1253145510Sdarrenr if ((p == IPPROTO_TCP || p == IPPROTO_UDP) && !off) { 1254145510Sdarrenr tp = (tcphdr_t *)((char *)ip + hl); 1255145510Sdarrenr if (!(ipf->fl_lflags & FI_SHORT)) { 1256255332Scy sprintf(t, "%s,%s -> ", hostname(f, s), 1257255332Scy portlocalname(res, proto, (u_int)tp->th_sport)); 1258145510Sdarrenr t += strlen(t); 1259255332Scy sprintf(t, "%s,%s PR %s len %hu %hu", 1260255332Scy hostname(f, d), 1261255332Scy portlocalname(res, proto, (u_int)tp->th_dport), 1262145510Sdarrenr proto, hl, plen); 1263145510Sdarrenr t += strlen(t); 1264145510Sdarrenr 1265145510Sdarrenr if (p == IPPROTO_TCP) { 1266145510Sdarrenr *t++ = ' '; 1267145510Sdarrenr *t++ = '-'; 1268145510Sdarrenr for (i = 0; tcpfl[i].value; i++) 1269145510Sdarrenr if (tp->th_flags & tcpfl[i].value) 1270145510Sdarrenr *t++ = tcpfl[i].flag; 1271255332Scy if (ipmonopts & IPMON_VERBOSE) { 1272255332Scy sprintf(t, " %lu %lu %hu", 1273145510Sdarrenr (u_long)(ntohl(tp->th_seq)), 1274145510Sdarrenr (u_long)(ntohl(tp->th_ack)), 1275145510Sdarrenr ntohs(tp->th_win)); 1276145510Sdarrenr t += strlen(t); 1277145510Sdarrenr } 1278145510Sdarrenr } 1279145510Sdarrenr *t = '\0'; 1280145510Sdarrenr } else { 1281255332Scy sprintf(t, "%s -> ", hostname(f, s)); 1282145510Sdarrenr t += strlen(t); 1283255332Scy sprintf(t, "%s PR %s len %hu %hu", 1284255332Scy hostname(f, d), proto, hl, plen); 1285145510Sdarrenr } 1286255332Scy#if defined(AF_INET6) && defined(IPPROTO_ICMPV6) 1287255332Scy } else if ((p == IPPROTO_ICMPV6) && !off && (f == AF_INET6)) { 1288145510Sdarrenr ic = (struct icmp *)((char *)ip + hl); 1289255332Scy sprintf(t, "%s -> ", hostname(f, s)); 1290145510Sdarrenr t += strlen(t); 1291255332Scy sprintf(t, "%s PR icmpv6 len %hu %hu icmpv6 %s", 1292255332Scy hostname(f, d), hl, plen, 1293145510Sdarrenr icmpname6(ic->icmp_type, ic->icmp_code)); 1294255332Scy#endif 1295255332Scy } else if ((p == IPPROTO_ICMP) && !off && (f == AF_INET)) { 1296145510Sdarrenr ic = (struct icmp *)((char *)ip + hl); 1297255332Scy sprintf(t, "%s -> ", hostname(f, s)); 1298145510Sdarrenr t += strlen(t); 1299255332Scy sprintf(t, "%s PR icmp len %hu %hu icmp %s", 1300255332Scy hostname(f, d), hl, plen, 1301145510Sdarrenr icmpname(ic->icmp_type, ic->icmp_code)); 1302145510Sdarrenr if (ic->icmp_type == ICMP_UNREACH || 1303145510Sdarrenr ic->icmp_type == ICMP_SOURCEQUENCH || 1304145510Sdarrenr ic->icmp_type == ICMP_PARAMPROB || 1305145510Sdarrenr ic->icmp_type == ICMP_REDIRECT || 1306145510Sdarrenr ic->icmp_type == ICMP_TIMXCEED) { 1307145510Sdarrenr ipc = &ic->icmp_ip; 1308145510Sdarrenr i = ntohs(ipc->ip_len); 1309145510Sdarrenr /* 1310145510Sdarrenr * XXX - try to guess endian of ip_len in ICMP 1311145510Sdarrenr * returned data. 1312145510Sdarrenr */ 1313145510Sdarrenr if (i > 1500) 1314145510Sdarrenr i = ipc->ip_len; 1315145510Sdarrenr ipoff = ntohs(ipc->ip_off); 1316255332Scy proto = getlocalproto(ipc->ip_p); 1317145510Sdarrenr 1318145510Sdarrenr if (!(ipoff & IP_OFFMASK) && 1319145510Sdarrenr ((ipc->ip_p == IPPROTO_TCP) || 1320145510Sdarrenr (ipc->ip_p == IPPROTO_UDP))) { 1321145510Sdarrenr tp = (tcphdr_t *)((char *)ipc + hl); 1322145510Sdarrenr t += strlen(t); 1323255332Scy sprintf(t, " for %s,%s -", 1324255332Scy HOSTNAMEV4(ipc->ip_src), 1325255332Scy portlocalname(res, proto, 1326145510Sdarrenr (u_int)tp->th_sport)); 1327145510Sdarrenr t += strlen(t); 1328255332Scy sprintf(t, " %s,%s PR %s len %hu %hu", 1329255332Scy HOSTNAMEV4(ipc->ip_dst), 1330255332Scy portlocalname(res, proto, 1331145510Sdarrenr (u_int)tp->th_dport), 1332145510Sdarrenr proto, IP_HL(ipc) << 2, i); 1333145510Sdarrenr } else if (!(ipoff & IP_OFFMASK) && 1334145510Sdarrenr (ipc->ip_p == IPPROTO_ICMP)) { 1335145510Sdarrenr icmp = (icmphdr_t *)((char *)ipc + hl); 1336145510Sdarrenr 1337145510Sdarrenr t += strlen(t); 1338255332Scy sprintf(t, " for %s -", 1339255332Scy HOSTNAMEV4(ipc->ip_src)); 1340145510Sdarrenr t += strlen(t); 1341255332Scy sprintf(t, 1342145510Sdarrenr " %s PR icmp len %hu %hu icmp %d/%d", 1343255332Scy HOSTNAMEV4(ipc->ip_dst), 1344145510Sdarrenr IP_HL(ipc) << 2, i, 1345145510Sdarrenr icmp->icmp_type, icmp->icmp_code); 1346145510Sdarrenr } else { 1347145510Sdarrenr t += strlen(t); 1348255332Scy sprintf(t, " for %s -", 1349255332Scy HOSTNAMEV4(ipc->ip_src)); 1350145510Sdarrenr t += strlen(t); 1351255332Scy sprintf(t, " %s PR %s len %hu (%hu)", 1352255332Scy HOSTNAMEV4(ipc->ip_dst), proto, 1353145510Sdarrenr IP_HL(ipc) << 2, i); 1354145510Sdarrenr t += strlen(t); 1355145510Sdarrenr if (ipoff & IP_OFFMASK) { 1356255332Scy sprintf(t, "(frag %d:%hu@%hu%s%s)", 1357145510Sdarrenr ntohs(ipc->ip_id), 1358145510Sdarrenr i - (IP_HL(ipc) << 2), 1359145510Sdarrenr (ipoff & IP_OFFMASK) << 3, 1360145510Sdarrenr ipoff & IP_MF ? "+" : "", 1361145510Sdarrenr ipoff & IP_DF ? "-" : ""); 1362145510Sdarrenr } 1363145510Sdarrenr } 1364145510Sdarrenr 1365145510Sdarrenr } 1366145510Sdarrenr } else { 1367255332Scy sprintf(t, "%s -> ", hostname(f, s)); 1368145510Sdarrenr t += strlen(t); 1369255332Scy sprintf(t, "%s PR %s len %hu (%hu)", 1370255332Scy hostname(f, d), proto, hl, plen); 1371145510Sdarrenr t += strlen(t); 1372145510Sdarrenr if (off & IP_OFFMASK) 1373255332Scy sprintf(t, " (frag %d:%hu@%hu%s%s)", 1374145510Sdarrenr ntohs(ip->ip_id), 1375145510Sdarrenr plen - hl, (off & IP_OFFMASK) << 3, 1376145510Sdarrenr ipoff & IP_MF ? "+" : "", 1377145510Sdarrenr ipoff & IP_DF ? "-" : ""); 1378145510Sdarrenr } 1379145510Sdarrenr t += strlen(t); 1380145510Sdarrenr 1381145510Sdarrenrprintipflog: 1382145510Sdarrenr if (ipf->fl_flags & FR_KEEPSTATE) { 1383145510Sdarrenr (void) strcpy(t, " K-S"); 1384145510Sdarrenr t += strlen(t); 1385145510Sdarrenr } 1386145510Sdarrenr 1387145510Sdarrenr if (ipf->fl_flags & FR_KEEPFRAG) { 1388145510Sdarrenr (void) strcpy(t, " K-F"); 1389145510Sdarrenr t += strlen(t); 1390145510Sdarrenr } 1391145510Sdarrenr 1392145510Sdarrenr if (ipf->fl_dir == 0) 1393145510Sdarrenr strcpy(t, " IN"); 1394145510Sdarrenr else if (ipf->fl_dir == 1) 1395145510Sdarrenr strcpy(t, " OUT"); 1396145510Sdarrenr t += strlen(t); 1397145510Sdarrenr if (ipf->fl_logtag != 0) { 1398145510Sdarrenr sprintf(t, " log-tag %d", ipf->fl_logtag); 1399145510Sdarrenr t += strlen(t); 1400145510Sdarrenr } 1401145510Sdarrenr if (ipf->fl_nattag.ipt_num[0] != 0) { 1402145510Sdarrenr strcpy(t, " nat-tag "); 1403145510Sdarrenr t += strlen(t); 1404145510Sdarrenr strncpy(t, ipf->fl_nattag.ipt_tag, sizeof(ipf->fl_nattag)); 1405145510Sdarrenr t += strlen(t); 1406145510Sdarrenr } 1407145510Sdarrenr if ((ipf->fl_lflags & FI_LOWTTL) != 0) { 1408145510Sdarrenr strcpy(t, " low-ttl"); 1409145510Sdarrenr t += 8; 1410145510Sdarrenr } 1411145510Sdarrenr if ((ipf->fl_lflags & FI_OOW) != 0) { 1412145510Sdarrenr strcpy(t, " OOW"); 1413145510Sdarrenr t += 4; 1414145510Sdarrenr } 1415145510Sdarrenr if ((ipf->fl_lflags & FI_BAD) != 0) { 1416145510Sdarrenr strcpy(t, " bad"); 1417145510Sdarrenr t += 4; 1418145510Sdarrenr } 1419145510Sdarrenr if ((ipf->fl_lflags & FI_NATED) != 0) { 1420145510Sdarrenr strcpy(t, " NAT"); 1421145510Sdarrenr t += 4; 1422145510Sdarrenr } 1423145510Sdarrenr if ((ipf->fl_lflags & FI_BADNAT) != 0) { 1424145510Sdarrenr strcpy(t, " bad-NAT"); 1425145510Sdarrenr t += 8; 1426145510Sdarrenr } 1427145510Sdarrenr if ((ipf->fl_lflags & FI_BADSRC) != 0) { 1428145510Sdarrenr strcpy(t, " bad-src"); 1429145510Sdarrenr t += 8; 1430145510Sdarrenr } 1431145510Sdarrenr if ((ipf->fl_lflags & FI_MULTICAST) != 0) { 1432145510Sdarrenr strcpy(t, " multicast"); 1433145510Sdarrenr t += 10; 1434145510Sdarrenr } 1435145510Sdarrenr if ((ipf->fl_lflags & FI_BROADCAST) != 0) { 1436145510Sdarrenr strcpy(t, " broadcast"); 1437145510Sdarrenr t += 10; 1438145510Sdarrenr } 1439145510Sdarrenr if ((ipf->fl_lflags & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST)) == 1440145510Sdarrenr FI_MBCAST) { 1441145510Sdarrenr strcpy(t, " mbcast"); 1442145510Sdarrenr t += 7; 1443145510Sdarrenr } 1444255332Scy if (ipf->fl_breason != 0) { 1445255332Scy strcpy(t, " reason:"); 1446255332Scy t += 8; 1447255332Scy strcpy(t, reasons[ipf->fl_breason]); 1448255332Scy t += strlen(reasons[ipf->fl_breason]); 1449255332Scy } 1450145510Sdarrenr *t++ = '\n'; 1451145510Sdarrenr *t++ = '\0'; 1452145510Sdarrenr defaction = 0; 1453255332Scy if (conf->cfile != NULL) 1454255332Scy defaction = check_action(buf, line, ipmonopts, lvl); 1455255332Scy 1456145510Sdarrenr if (defaction == 0) { 1457255332Scy if (ipmonopts & IPMON_SYSLOG) { 1458145510Sdarrenr syslog(lvl, "%s", line); 1459255332Scy } else if (conf->log != NULL) { 1460255332Scy (void) fprintf(conf->log, "%s", line); 1461255332Scy } 1462161357Sguido 1463255332Scy if (ipmonopts & IPMON_HEXHDR) { 1464255332Scy dumphex(conf->log, ipmonopts, buf, 1465145510Sdarrenr sizeof(iplog_t) + sizeof(*ipf)); 1466255332Scy } 1467255332Scy if (ipmonopts & IPMON_HEXBODY) { 1468255332Scy dumphex(conf->log, ipmonopts, (char *)ip, 1469145510Sdarrenr ipf->fl_plen + ipf->fl_hlen); 1470255332Scy } else if ((ipmonopts & IPMON_LOGBODY) && 1471255332Scy (ipf->fl_flags & FR_LOGBODY)) { 1472255332Scy dumphex(conf->log, ipmonopts, (char *)ip + ipf->fl_hlen, 1473145510Sdarrenr ipf->fl_plen); 1474255332Scy } 1475145510Sdarrenr } 1476145510Sdarrenr} 1477145510Sdarrenr 1478145510Sdarrenr 1479145510Sdarrenrstatic void usage(prog) 1480255332Scy char *prog; 1481145510Sdarrenr{ 1482145510Sdarrenr fprintf(stderr, "%s: [-NFhstvxX] [-f <logfile>]\n", prog); 1483145510Sdarrenr exit(1); 1484145510Sdarrenr} 1485145510Sdarrenr 1486145510Sdarrenr 1487145510Sdarrenrstatic void write_pid(file) 1488255332Scy char *file; 1489145510Sdarrenr{ 1490145510Sdarrenr FILE *fp = NULL; 1491145510Sdarrenr int fd; 1492145510Sdarrenr 1493145510Sdarrenr if ((fd = open(file, O_CREAT|O_TRUNC|O_WRONLY, 0644)) >= 0) { 1494145510Sdarrenr fp = fdopen(fd, "w"); 1495145510Sdarrenr if (fp == NULL) { 1496145510Sdarrenr close(fd); 1497145510Sdarrenr fprintf(stderr, 1498145510Sdarrenr "unable to open/create pid file: %s\n", file); 1499145510Sdarrenr return; 1500145510Sdarrenr } 1501145510Sdarrenr fprintf(fp, "%d", getpid()); 1502145510Sdarrenr fclose(fp); 1503145510Sdarrenr } 1504145510Sdarrenr} 1505145510Sdarrenr 1506145510Sdarrenr 1507145510Sdarrenrstatic void flushlogs(file, log) 1508255332Scy char *file; 1509255332Scy FILE *log; 1510145510Sdarrenr{ 1511145510Sdarrenr int fd, flushed = 0; 1512145510Sdarrenr 1513145510Sdarrenr if ((fd = open(file, O_RDWR)) == -1) { 1514145510Sdarrenr (void) fprintf(stderr, "%s: open: %s\n", 1515145510Sdarrenr file, STRERROR(errno)); 1516145510Sdarrenr exit(1); 1517145510Sdarrenr } 1518145510Sdarrenr 1519145510Sdarrenr if (ioctl(fd, SIOCIPFFB, &flushed) == 0) { 1520145510Sdarrenr printf("%d bytes flushed from log buffer\n", 1521145510Sdarrenr flushed); 1522145510Sdarrenr fflush(stdout); 1523145510Sdarrenr } else 1524255332Scy ipferror(fd, "SIOCIPFFB"); 1525145510Sdarrenr (void) close(fd); 1526145510Sdarrenr 1527145510Sdarrenr if (flushed) { 1528255332Scy if (ipmonopts & IPMON_SYSLOG) { 1529145510Sdarrenr syslog(LOG_INFO, "%d bytes flushed from log\n", 1530145510Sdarrenr flushed); 1531161357Sguido } else if ((log != stdout) && (log != NULL)) { 1532145510Sdarrenr fprintf(log, "%d bytes flushed from log\n", flushed); 1533161357Sguido } 1534145510Sdarrenr } 1535145510Sdarrenr} 1536145510Sdarrenr 1537145510Sdarrenr 1538145510Sdarrenrstatic void logopts(turnon, options) 1539255332Scy int turnon; 1540255332Scy char *options; 1541145510Sdarrenr{ 1542145510Sdarrenr int flags = 0; 1543145510Sdarrenr char *s; 1544145510Sdarrenr 1545145510Sdarrenr for (s = options; *s; s++) 1546145510Sdarrenr { 1547145510Sdarrenr switch (*s) 1548145510Sdarrenr { 1549145510Sdarrenr case 'N' : 1550255332Scy flags |= IPMON_NAT; 1551145510Sdarrenr break; 1552145510Sdarrenr case 'S' : 1553255332Scy flags |= IPMON_STATE; 1554145510Sdarrenr break; 1555145510Sdarrenr case 'I' : 1556255332Scy flags |= IPMON_FILTER; 1557145510Sdarrenr break; 1558145510Sdarrenr default : 1559145510Sdarrenr fprintf(stderr, "Unknown log option %c\n", *s); 1560145510Sdarrenr exit(1); 1561145510Sdarrenr } 1562145510Sdarrenr } 1563145510Sdarrenr 1564145510Sdarrenr if (turnon) 1565255332Scy ipmonopts |= flags; 1566145510Sdarrenr else 1567255332Scy ipmonopts &= ~(flags); 1568145510Sdarrenr} 1569145510Sdarrenr 1570255332Scystatic void initconfig(config_t *conf) 1571255332Scy{ 1572255332Scy int i; 1573145510Sdarrenr 1574255332Scy memset(conf, 0, sizeof(*conf)); 1575255332Scy 1576255332Scy conf->log = stdout; 1577255332Scy conf->maxfd = -1; 1578255332Scy 1579255332Scy for (i = 0; i < 3; i++) { 1580255332Scy conf->logsrc[i].fd = -1; 1581255332Scy conf->logsrc[i].logtype = -1; 1582255332Scy conf->logsrc[i].regular = -1; 1583255332Scy } 1584255332Scy 1585255332Scy conf->logsrc[0].file = IPL_NAME; 1586255332Scy conf->logsrc[1].file = IPNAT_NAME; 1587255332Scy conf->logsrc[2].file = IPSTATE_NAME; 1588255332Scy 1589255332Scy add_doing(&executesaver); 1590255332Scy add_doing(&snmpv1saver); 1591255332Scy add_doing(&snmpv2saver); 1592255332Scy add_doing(&syslogsaver); 1593255332Scy add_doing(&filesaver); 1594255332Scy add_doing(¬hingsaver); 1595255332Scy} 1596255332Scy 1597255332Scy 1598145510Sdarrenrint main(argc, argv) 1599255332Scy int argc; 1600255332Scy char *argv[]; 1601145510Sdarrenr{ 1602255332Scy int doread, c, make_daemon = 0; 1603255332Scy char *prog; 1604255332Scy config_t config; 1605145510Sdarrenr 1606255332Scy prog = strrchr(argv[0], '/'); 1607255332Scy if (prog == NULL) 1608255332Scy prog = argv[0]; 1609255332Scy else 1610255332Scy prog++; 1611145510Sdarrenr 1612255332Scy initconfig(&config); 1613255332Scy 1614161357Sguido while ((c = getopt(argc, argv, 1615161357Sguido "?abB:C:Df:FhL:nN:o:O:pP:sS:tvxX")) != -1) 1616145510Sdarrenr switch (c) 1617145510Sdarrenr { 1618145510Sdarrenr case 'a' : 1619255332Scy ipmonopts |= IPMON_LOGALL; 1620255332Scy config.logsrc[0].logtype = IPL_LOGIPF; 1621255332Scy config.logsrc[1].logtype = IPL_LOGNAT; 1622255332Scy config.logsrc[2].logtype = IPL_LOGSTATE; 1623145510Sdarrenr break; 1624145510Sdarrenr case 'b' : 1625255332Scy ipmonopts |= IPMON_LOGBODY; 1626145510Sdarrenr break; 1627145510Sdarrenr case 'B' : 1628255332Scy config.bfile = optarg; 1629255332Scy config.blog = fopen(optarg, "a"); 1630145510Sdarrenr break; 1631145510Sdarrenr case 'C' : 1632255332Scy config.cfile = optarg; 1633145510Sdarrenr break; 1634145510Sdarrenr case 'D' : 1635145510Sdarrenr make_daemon = 1; 1636145510Sdarrenr break; 1637145510Sdarrenr case 'f' : case 'I' : 1638255332Scy ipmonopts |= IPMON_FILTER; 1639255332Scy config.logsrc[0].logtype = IPL_LOGIPF; 1640255332Scy config.logsrc[0].file = optarg; 1641145510Sdarrenr break; 1642145510Sdarrenr case 'F' : 1643255332Scy flushlogs(config.logsrc[0].file, config.log); 1644255332Scy flushlogs(config.logsrc[1].file, config.log); 1645255332Scy flushlogs(config.logsrc[2].file, config.log); 1646145510Sdarrenr break; 1647161357Sguido case 'L' : 1648161357Sguido logfac = fac_findname(optarg); 1649161357Sguido if (logfac == -1) { 1650161357Sguido fprintf(stderr, 1651161357Sguido "Unknown syslog facility '%s'\n", 1652161357Sguido optarg); 1653161357Sguido exit(1); 1654161357Sguido } 1655161357Sguido break; 1656145510Sdarrenr case 'n' : 1657255332Scy ipmonopts |= IPMON_RESOLVE; 1658255332Scy opts &= ~OPT_NORESOLVE; 1659145510Sdarrenr break; 1660145510Sdarrenr case 'N' : 1661255332Scy ipmonopts |= IPMON_NAT; 1662255332Scy config.logsrc[1].logtype = IPL_LOGNAT; 1663255332Scy config.logsrc[1].file = optarg; 1664145510Sdarrenr break; 1665145510Sdarrenr case 'o' : case 'O' : 1666145510Sdarrenr logopts(c == 'o', optarg); 1667255332Scy if (ipmonopts & IPMON_FILTER) 1668255332Scy config.logsrc[0].logtype = IPL_LOGIPF; 1669255332Scy if (ipmonopts & IPMON_NAT) 1670255332Scy config.logsrc[1].logtype = IPL_LOGNAT; 1671255332Scy if (ipmonopts & IPMON_STATE) 1672255332Scy config.logsrc[2].logtype = IPL_LOGSTATE; 1673145510Sdarrenr break; 1674145510Sdarrenr case 'p' : 1675255332Scy ipmonopts |= IPMON_PORTNUM; 1676145510Sdarrenr break; 1677145510Sdarrenr case 'P' : 1678145510Sdarrenr pidfile = optarg; 1679145510Sdarrenr break; 1680145510Sdarrenr case 's' : 1681255332Scy ipmonopts |= IPMON_SYSLOG; 1682255332Scy config.log = NULL; 1683145510Sdarrenr break; 1684145510Sdarrenr case 'S' : 1685255332Scy ipmonopts |= IPMON_STATE; 1686255332Scy config.logsrc[2].logtype = IPL_LOGSTATE; 1687255332Scy config.logsrc[2].file = optarg; 1688145510Sdarrenr break; 1689145510Sdarrenr case 't' : 1690255332Scy ipmonopts |= IPMON_TAIL; 1691145510Sdarrenr break; 1692145510Sdarrenr case 'v' : 1693255332Scy ipmonopts |= IPMON_VERBOSE; 1694145510Sdarrenr break; 1695145510Sdarrenr case 'x' : 1696255332Scy ipmonopts |= IPMON_HEXBODY; 1697145510Sdarrenr break; 1698145510Sdarrenr case 'X' : 1699255332Scy ipmonopts |= IPMON_HEXHDR; 1700145510Sdarrenr break; 1701145510Sdarrenr default : 1702145510Sdarrenr case 'h' : 1703145510Sdarrenr case '?' : 1704145510Sdarrenr usage(argv[0]); 1705145510Sdarrenr } 1706145510Sdarrenr 1707255332Scy if (ipmonopts & IPMON_SYSLOG) 1708255332Scy openlog(prog, LOG_NDELAY|LOG_PID, logfac); 1709255332Scy 1710145510Sdarrenr init_tabs(); 1711255332Scy if (config.cfile) 1712255332Scy if (load_config(config.cfile) == -1) { 1713255332Scy unload_config(); 1714145510Sdarrenr exit(1); 1715255332Scy } 1716145510Sdarrenr 1717145510Sdarrenr /* 1718145510Sdarrenr * Default action is to only open the filter log file. 1719145510Sdarrenr */ 1720255332Scy if ((config.logsrc[0].logtype == -1) && 1721255332Scy (config.logsrc[0].logtype == -1) && 1722255332Scy (config.logsrc[0].logtype == -1)) 1723255332Scy config.logsrc[0].logtype = IPL_LOGIPF; 1724145510Sdarrenr 1725255332Scy openlogs(&config); 1726145510Sdarrenr 1727255332Scy if (!(ipmonopts & IPMON_SYSLOG)) { 1728255332Scy config.file = argv[optind]; 1729255332Scy config.log = config.file ? fopen(config.file, "a") : stdout; 1730255332Scy if (config.log == NULL) { 1731145510Sdarrenr (void) fprintf(stderr, "%s: fopen: %s\n", 1732145510Sdarrenr argv[optind], STRERROR(errno)); 1733145510Sdarrenr exit(1); 1734145510Sdarrenr /* NOTREACHED */ 1735145510Sdarrenr } 1736255332Scy setvbuf(config.log, NULL, _IONBF, 0); 1737255332Scy } else { 1738255332Scy config.log = NULL; 1739255332Scy } 1740145510Sdarrenr 1741255332Scy if (make_daemon && 1742255332Scy ((config.log != stdout) || (ipmonopts & IPMON_SYSLOG))) { 1743145510Sdarrenr#if BSD >= 199306 1744255332Scy daemon(0, !(ipmonopts & IPMON_SYSLOG)); 1745145510Sdarrenr#else 1746145510Sdarrenr int pid; 1747255332Scy 1748255332Scy switch (fork()) 1749255332Scy { 1750255332Scy case -1 : 1751145510Sdarrenr (void) fprintf(stderr, "%s: fork() failed: %s\n", 1752145510Sdarrenr argv[0], STRERROR(errno)); 1753145510Sdarrenr exit(1); 1754145510Sdarrenr /* NOTREACHED */ 1755255332Scy case 0 : 1756255332Scy break; 1757255332Scy default : 1758255332Scy exit(0); 1759145510Sdarrenr } 1760255332Scy 1761145510Sdarrenr setsid(); 1762255332Scy if ((ipmonopts & IPMON_SYSLOG)) 1763145510Sdarrenr close(2); 1764145510Sdarrenr#endif /* !BSD */ 1765145510Sdarrenr close(0); 1766145510Sdarrenr close(1); 1767161357Sguido write_pid(pidfile); 1768145510Sdarrenr } 1769145510Sdarrenr 1770145510Sdarrenr signal(SIGHUP, handlehup); 1771145510Sdarrenr 1772255332Scy for (doread = 1; doread; ) 1773255332Scy doread = read_loginfo(&config); 1774145510Sdarrenr 1775255332Scy unload_config(); 1776255332Scy 1777255332Scy return(0); 1778255332Scy /* NOTREACHED */ 1779255332Scy} 1780255332Scy 1781255332Scy 1782255332Scystatic void openlogs(config_t *conf) 1783255332Scy{ 1784255332Scy logsource_t *l; 1785255332Scy struct stat sb; 1786255332Scy int i; 1787255332Scy 1788255332Scy for (i = 0; i < 3; i++) { 1789255332Scy l = &conf->logsrc[i]; 1790255332Scy if (l->logtype == -1) 1791255332Scy continue; 1792255332Scy if (!strcmp(l->file, "-")) 1793255332Scy l->fd = 0; 1794255332Scy else { 1795255332Scy if ((l->fd= open(l->file, O_RDONLY)) == -1) { 1796255332Scy (void) fprintf(stderr, 1797255332Scy "%s: open: %s\n", l->file, 1798255332Scy STRERROR(errno)); 1799255332Scy exit(1); 1800255332Scy /* NOTREACHED */ 1801145510Sdarrenr } 1802145510Sdarrenr 1803255332Scy if (fstat(l->fd, &sb) == -1) { 1804255332Scy (void) fprintf(stderr, "%d: fstat: %s\n", 1805255332Scy l->fd, STRERROR(errno)); 1806255332Scy exit(1); 1807255332Scy /* NOTREACHED */ 1808255332Scy } 1809255332Scy 1810255332Scy l->regular = !S_ISCHR(sb.st_mode); 1811255332Scy if (l->regular) 1812255332Scy l->size = sb.st_size; 1813255332Scy 1814255332Scy FD_SET(l->fd, &conf->fdmr); 1815255332Scy if (l->fd > conf->maxfd) 1816255332Scy conf->maxfd = l->fd; 1817255332Scy } 1818255332Scy } 1819255332Scy} 1820255332Scy 1821255332Scy 1822255332Scystatic int read_loginfo(config_t *conf) 1823255332Scy{ 1824255332Scy iplog_t buf[DEFAULT_IPFLOGSIZE/sizeof(iplog_t)+1]; 1825255332Scy int n, tr, nr, i; 1826255332Scy logsource_t *l; 1827255332Scy fd_set fdr; 1828255332Scy 1829255332Scy fdr = conf->fdmr; 1830255332Scy 1831255332Scy n = select(conf->maxfd + 1, &fdr, NULL, NULL, NULL); 1832255332Scy if (n == 0) 1833255332Scy return 1; 1834255332Scy if (n == -1) { 1835255332Scy if (errno == EINTR) 1836255332Scy return 1; 1837255332Scy return -1; 1838255332Scy } 1839255332Scy 1840255332Scy for (i = 0, nr = 0; i < 3; i++) { 1841255332Scy l = &conf->logsrc[i]; 1842255332Scy 1843255332Scy if ((l->logtype == -1) || !FD_ISSET(l->fd, &fdr)) 1844255332Scy continue; 1845255332Scy 1846255332Scy tr = 0; 1847255332Scy if (l->regular) { 1848255332Scy tr = (lseek(l->fd, 0, SEEK_CUR) < l->size); 1849255332Scy if (!tr && !(ipmonopts & IPMON_TAIL)) 1850255332Scy return 0; 1851255332Scy } 1852255332Scy 1853255332Scy n = 0; 1854255332Scy tr = read_log(l->fd, &n, (char *)buf, sizeof(buf)); 1855255332Scy if (donehup) { 1856255332Scy if (conf->file != NULL) { 1857255332Scy if (conf->log != NULL) { 1858255332Scy fclose(conf->log); 1859255332Scy conf->log = NULL; 1860145510Sdarrenr } 1861255332Scy conf->log = fopen(conf->file, "a"); 1862145510Sdarrenr } 1863145510Sdarrenr 1864255332Scy if (conf->bfile != NULL) { 1865255332Scy if (conf->blog != NULL) { 1866255332Scy fclose(conf->blog); 1867255332Scy conf->blog = NULL; 1868145510Sdarrenr } 1869255332Scy conf->blog = fopen(conf->bfile, "a"); 1870145510Sdarrenr } 1871255332Scy 1872255332Scy init_tabs(); 1873255332Scy if (conf->cfile != NULL) 1874255332Scy load_config(conf->cfile); 1875255332Scy donehup = 0; 1876145510Sdarrenr } 1877255332Scy 1878255332Scy switch (tr) 1879255332Scy { 1880255332Scy case -1 : 1881255332Scy if (ipmonopts & IPMON_SYSLOG) 1882255332Scy syslog(LOG_CRIT, "read: %m\n"); 1883255332Scy else { 1884255332Scy ipferror(l->fd, "read"); 1885255332Scy } 1886255332Scy return 0; 1887255332Scy case 1 : 1888255332Scy if (ipmonopts & IPMON_SYSLOG) 1889255332Scy syslog(LOG_CRIT, "aborting logging\n"); 1890255332Scy else if (conf->log != NULL) 1891255332Scy fprintf(conf->log, "aborting logging\n"); 1892255332Scy return 0; 1893255332Scy case 2 : 1894255332Scy break; 1895255332Scy case 0 : 1896255332Scy nr += tr; 1897255332Scy if (n > 0) { 1898255332Scy print_log(conf, l, (char *)buf, n); 1899255332Scy if (!(ipmonopts & IPMON_SYSLOG)) 1900255332Scy fflush(conf->log); 1901255332Scy } 1902255332Scy break; 1903255332Scy } 1904145510Sdarrenr } 1905255332Scy 1906255332Scy if (!nr && (ipmonopts & IPMON_TAIL)) 1907255332Scy sleep(1); 1908255332Scy 1909255332Scy return 1; 1910145510Sdarrenr} 1911