/*- * Copyright (c) 2001-2005 Christian S.J. Peron * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header: /usr/cvs/ipex/util.c,v 1.21 2005/04/24 22:13:43 modulus Exp $"; #endif #include "ipex_includes.h" /* * time_stamp() returns a pointer to * a null terminated string. This * string contains a timestamp of * arbitary precision. (nice precision too ;)) */ char * time_stamp(const struct timeval *tvp, int32_t zone) { static char buf[32]; struct tm *tm; char date[12]; int s; tm = localtime((time_t *)&tvp->tv_sec); strftime(date, sizeof(date), "%Y-%m-%d", tm); s = (tvp->tv_sec + zone) % 86400; snprintf(buf, sizeof(buf), "%s %02d:%02d:%02d.%06u", date, (s / 3600), ((s % 3600) / 60), (s % 60), ((u_int32_t)tvp->tv_usec)); return (buf); } /* * this gmt2local() was taken from the * tcpdump(1) source code. thanks. */ int32_t gmt2local(time_t t) { struct tm *gmt, *loc, sgmt; int dt, dir; if (t == 0) t = time(0); gmt = &sgmt; *gmt = *gmtime(&t); loc = localtime(&t); dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 + (loc->tm_min - gmt->tm_min) *60; dir = loc->tm_year - gmt->tm_year; if (dir == 0) dir = loc->tm_yday - gmt->tm_yday; dt += dir * 24 * 60 * 60; return (dt); } /* * text_dump() is the function wich is responsible * for dumping the packet's contents in * human readable form (where available). * it was borrowed from ngrep(1). again. thanks. */ void text_dump(char *data, int len, struct offset *off) { int pos; if (len > 0) { unsigned width = 70; char c, *str = data; int j, i = 0; while (i < len) { putchar(' '); for(j = 0; j < width; j++) { pos = i + j; if (pos == off->base && opts.Eflag) printf("\033[7m"); if (pos == (off->base + off->len) && opts.Eflag) printf("\033[m"); if (pos < len) { c = isprint(str[j]) ? str[j] : ' '; putchar(c); } else putchar(' '); } str += width; i += j; putchar('\n'); } } } /* * this function returns a pointer to a null terminated string. * for the use of grep()'ing & dumping matched packets. */ void rettext(char *buffer, int len) { int i; for(i = 0; i < len; i++) if (!isprint(buffer[i])) buffer[i] = ' '; } int grep(char *pattern, char *buf, struct offset *off) { static regex_t *rp, rd; int match, flags, err; const int nmatch = 1; regmatch_t pmatch[1]; if (rp == NULL) { flags = REG_EXTENDED | REG_ICASE; if ((err = regcomp(&rd, pattern, flags)) != 0) errx(1, "regular expression error"); rp = &rd; } match = regexec(rp, buf, nmatch, &pmatch[0], 0); if (match == REG_NOMATCH) return (0); if (match != 0) { warnx("regexec failed"); return (0); } off->base = (u_long)pmatch[0].rm_so; off->len = (u_long)pmatch[0].rm_eo - (u_long)pmatch[0].rm_so; return (1); } int strtolower(string) char *string; { char *c; for (c = string; *c; c++) if (!(*c = tolower (*c))) return (0); return (1); } int strisdigit(string) char *string; { while (*string) { if (!isdigit(*string)) return (1); string++; } return (0); } #define IGNORE 0x1 #define SPACE ' ' #if (!defined(IS_IGNORING)) #define IS_IGNORING(a) ((a & IGNORE) ? (1) : (0)) #endif /* * this function will return a null terminated * string to the contents located in the file * suppied by -f on the command line. * we will however parse out any comments that * may have been used in the file. Example * of legal comments: * * this is a body of text ; this is ignored. * this is also a body of text # this is ignored. * standard C and C++ comments are also supported. */ void logic_load(char *p, FILE *fp) { int flag = 0; char nwchar, nwchar_temp, *op; op = p; while ((nwchar = getc(fp)) != EOF) { switch(nwchar) { case '#': case ';': flag |= IGNORE; break; case '/': nwchar_temp = getc(fp); if (nwchar_temp == '*') { while ((nwchar = getc(fp)) != EOF && nwchar_temp == '*') { if (nwchar == '*') { nwchar = getc(fp); if (nwchar == '/') nwchar_temp = '0'; } } } else if (nwchar_temp != '/') { *p = nwchar; p++; ungetc(nwchar_temp, fp); } else if (nwchar_temp == '/') flag |= IGNORE; break; case '\r': break; case '\n': if (IS_IGNORING(flag)) { flag &= ~IGNORE; break; } *p = SPACE; p++; break; default: if (IS_IGNORING(flag)) break; *p = nwchar; p++; break; } } *p = 0; } void prescan_pcap_expr(char *expr) { const char charset[]= "1234567890abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; while (*expr) { if (strchr(charset, *expr)) return; expr++; } fprintf(stderr,"\n>> WARNING: NULL expr compiled: capturing ALL packets. <<\n\n"); } char * retrive_pcap_expr(char **argv) { char *p; static char pcap_expr[1000]; if (*argv == NULL) return (*argv); while ((p = *argv++)) { /* XXX size bug here */ strncat(pcap_expr, p, sizeof(pcap_expr)); strncat(pcap_expr, " ", 0x1); } return (pcap_expr); } /* XXX change out ns cache mechanism to use a radix tree * instead of a home rolled tail queue. */ /* * return a pointer to a null terminated string. * this string will be in xxx.xxx.xxx.xxx or * hostname form depending on the value of ``res'' */ char * hostname(int v, u_32_t *ip) { #define MAX_INETA 16 struct in_addr ipa; char *ptr; if (v == 4) { ipa.s_addr = *ip; if (opts.nflag) ptr = inet_ntoa(ipa); else ptr = cache_ns_entry(ip); return (ptr); } return ("ip6"); } /* * specify soft limit for cache */ #if (!defined(MAX_NS_CACHE)) #define MAX_NS_CACHE 524288 /* 1/2 Mb */ #endif struct ns_entry { char alpha_host[MAXHOSTNAMELEN + MAX_INETA + 3]; u_long ip_addr; struct ns_entry *next; struct ns_entry *prev; }; static struct ns_entry *NsHead; static struct ns_entry *NsTail; static unsigned long cached_nodes; char * cache_ns_entry(u_32_t *ip) { struct ns_entry *new = NULL; struct hostent *hp; struct in_addr ipa; if (cached_nodes * sizeof(struct ns_entry) > MAX_NS_CACHE) return (inet_ntoa(ipa)); ipa.s_addr = *ip; for(new = NsHead; new != NULL; new = new->next) if (ipa.s_addr == new->ip_addr) return (new->alpha_host); new = NULL; new = memalloc(sizeof(struct ns_entry)); if (new == NULL) { fprintf(stderr,"fatal: exhausted memory.\n"); exit(1); } hp = gethostbyaddr((char *)ip, sizeof(ip), AF_INET); if (!hp) { new->ip_addr = ipa.s_addr; strcpy(new->alpha_host, inet_ntoa(ipa)); goto arrange; } new->ip_addr = ipa.s_addr; strcpy(new->alpha_host, hp->h_name); arrange: if (NsHead == NULL) { NsHead = new; new->prev = NULL; } else { NsTail->next = new; new->prev = NsTail; } NsTail = new; new->next = NULL; cached_nodes++; return (hp ? hp->h_name : new->alpha_host); } void flush_ns_cache(void) { struct ns_entry *node; struct ns_entry *next_node; for (node = NsHead; node != NULL; node = next_node) { next_node = node->next; if (node->prev == NULL) NsHead = node->next; else node->prev->next = node->next; if (node->next == NULL) NsTail = node->prev; else node->next->prev = node->prev; free(node); } } void * memalloc(unsigned int n) { void *ret; if (!(ret = malloc(n))) errx(EX_UNAVAILABLE, "memory exhausted (failed to allocate" \ " %u bytes).", n); else return (ret); } void * memrealloc(void *ptr, unsigned int n) { void *ret; if (!(ret = realloc(ptr, n))) errx(EX_UNAVAILABLE, "memory exhausted (failed to reallocate" \ " %u bytes).", n); else return (ret); }