/*-
 * 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);
}


syntax highlighted by Code2HTML, v. 0.9.1