/* Copyright 1998 by Vadim Kolontsov			
 * All rights reserved
 *
 * Distribute freely, except: don't remove my name from the source or
 * documentation (don't take credit for my work), mark your changes (don't
 * get me blamed for your possible bugs), don't alter or remove this
 * notice.  May be sold if buildable source is provided to buyer.  No
 * warrantee of any kind, express or implied, is included with this
 * software; use at your own risk, responsibility for damages (if any) to
 * anyone resulting from the use of this software rests entirely with the
 * user.
 *
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
 * I'll try to keep a version up to date.  I can be reached as follows:
 *
 * Vadim Kolontsov <sb@123.org>
 *
 * ---------------------------------------------------------------------------
 * Traceroute Detector, version 0.2
 * Dedicated to beloved Gala. 
 *
 * Version 0.2
 *
 * The main idea is detecting UDP (unix traceroute) and ICMP (windows tracert)
 * packets with TTL == 1. Easy, isn't it..
 *
 * Tested under FreeBSD 2.2.2/Linux 2.1.113, should work with other systems 
 * with BPF library. Can use ethernet or loopback interface.
 * Based on some my very old code.
 *
 * http://sb.123.org/tdetect.html
 *
 *-----------------------------------------------------------------------
 * Made usefull by Mike Eddington
 *
 * Now fork()'s at runtime to deamon.
 * Logs messages to syslog(3).
 *
 * Note: log floods should be "ok" with built in syslog stuff
 *  (that "last message repeated N times" stuff).
 *
 */  

#include <stdio.h>
#include <pcap.h>
#include <unistd.h>
#include <fcntl.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "config.h"

#define _PATH_DEVNULL "/dev/null"	

void log( char* str )
{
	syslog(SYSLOG_LEVEL, str);
}

void error(char *errstr)
{
	printf("error: %s\n", errstr);
	exit(-1);
}

/* Make daemon */
void daemonize(void)
{
        int fd;

        /* Now daemonize.. */
        switch (fork()) 
        {
            case -1:
                error("Can't daemonize");
            case 0:
                break;
            default:
                _exit(0);
        }

        if (setsid() == -1)
            error("Can't set session leader");

        if (chdir("/") == -1)
            error("Can't chdir to /");

        if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) 
        {
            dup2(fd, STDIN_FILENO);
            dup2(fd, STDOUT_FILENO);
            dup2(fd, STDERR_FILENO);
            if (fd > 2)
                close(fd);
        }
}

/* Analyzers */
extern void ether_analyzer(u_char *,const struct pcap_pkthdr *, const u_char *);
extern void null_analyzer(u_char *, const struct pcap_pkthdr *, const u_char *);

/* (not implemented yet)
extern void slip_analyzer(u_char *, const struct pcap_pkthdr *, const u_char *);
extern void ppp_analyzer(u_char *, const struct pcap_pkthdr *, const u_char *);
extern void fddi_analyzer(u_char *, const struct pcap_pkthdr *, const u_char *);
*/

struct analyzer {
	pcap_handler handler;
	int type;
};

static struct analyzer analyzers[] = {
/*	{ slip_analyzer, DLT_SLIP },
	{ ppp_analyzer, DLT_PPP },
	{ fddi_analyzer, DLT_FDDI },
*/	{ ether_analyzer, DLT_EN10MB },
	{ null_analyzer, DLT_NULL },
	{ NULL, 0 }
};

/* Select analyzer function for data link */
static pcap_handler select_analyzer(int type)
{
	struct analyzer *an;
	
	for (an = analyzers; an->handler; ++an)
	  if (an->type == type)
	    return(an->handler);

	error("unknown data link");
	exit(0);	/* NOTREACHED */
}

/* Keeps broadcast address for my network */
struct in_addr broadcast;
char tmsg[100];

int main(int argc, char *argv[])
{
	register char *cmdbuf = NULL;
	pcap_t *pd;
	bpf_u_int32 localnet, netmask;
	char errbuf[PCAP_ERRBUF_SIZE];
	u_char *userdata = NULL;
	pcap_handler handler;
	struct bpf_program bpfprog;

	if (argc != 2)
	{
	  printf("Usage: %s interface\n", argv[0]);
	  exit(-1);
	}
	
	if (!(pd = pcap_open_live(argv[1], 4096, 1, 1000, errbuf)))
	  error(errbuf);

	if (pcap_lookupnet(argv[1], &localnet, &netmask, errbuf) < 0)
	  error(errbuf);

	broadcast.s_addr = localnet | ~netmask;

	openlog(SYSLOG_APP_NAME, LOG_NDELAY, SYSLOG_LOG );

	sprintf(tmsg, "Traceroute Detector active on %s\n", argv[1]);
	log(tmsg);
	
	if (pcap_compile(pd, &bpfprog, cmdbuf, 1, netmask) < 0)
	  error(pcap_geterr(pd));

	if (pcap_setfilter(pd, &bpfprog) < 0)
	  error(pcap_geterr(pd));

	handler = select_analyzer(pcap_datalink(pd));

	daemonize();
	pcap_loop(pd, -1, handler, userdata);
	pcap_close(pd);
	closelog();
	exit(0);
}



syntax highlighted by Code2HTML, v. 0.9.1