/*
 * $Id: udp-tracerouted.c,v 1.2 2003/04/25 21:58:30 wessels Exp $
 * 
 * udp-tracerouted.c
 * 
 * to be executed from inetd as udp service
 * 
 * reads UDP socket for a hostname or IP address, then executes 'traceroute' to
 * that address.  Sends the traceroute output back to the source in a UDP
 * message.
 * 
 * used in conjunction with traceroute-query.pl CGI script
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <sys/wait.h>
#include <errno.h>

#define MAX_PKT_SZ 8192

int
main(int argc, char *argv[])
{
    int x;
    int p[2];
    int l;
    int n;
    time_t start;
    time_t now;
    char pkt[MAX_PKT_SZ];
    struct sockaddr_in F;
    open("/dev/null", 0);
    openlog(argv[0], LOG_NDELAY, LOG_DAEMON);
    for (;;) {
	l = sizeof(F);
	memset(&F, '\0', l);
	memset(pkt, '\0', MAX_PKT_SZ);
	x = recvfrom(0, pkt, MAX_PKT_SZ, 0, (struct sockaddr *) & F, &l);
	if (x < 0) {
	    syslog(LOG_ERR, "recvfrom: %s", strerror(errno));
	    return 1;
	}
	strtok(pkt, "\r\n");
	syslog(LOG_ERR, "%s: traceroute to %s\n", inet_ntoa(F.sin_addr), pkt);
	x = pipe(p);
	if (x < 0) {
	    syslog(LOG_ERR, "pipe: %s", strerror(errno));
	    return 1;
	}
	x = fork();
	if (x < 0) {
	    syslog(LOG_ERR, "fork: %s", strerror(errno));
	    return 1;
	} else if (x == 0) {
	    dup2(p[1], 1);
	    close(0);
	    close(p[0]);
	    close(p[1]);
	    execl("/usr/local/sbin/traceroute", "traceroute", pkt, NULL);
	    execl("/usr/local/bin/traceroute", "traceroute", pkt, NULL);
	    execl("/usr/sbin/traceroute", "traceroute", pkt, NULL);
	    execl("/usr/bin/traceroute", "traceroute", pkt, NULL);
	    execl("/sbin/traceroute", "traceroute", pkt, NULL);
	    execl("/bin/traceroute", "traceroute", pkt, NULL);
	    execl("/usr/etc/traceroute", "traceroute", pkt, NULL);
	    perror("traceroute");
	    _exit(1);
	}
	time(&start);
	close(p[1]);
	l = 0;
	memset(pkt, '\0', MAX_PKT_SZ);
	while (l < MAX_PKT_SZ) {
	    n = read(p[0], pkt + l, MAX_PKT_SZ - l);
	    if (n <= 0)
		break;
	    l += n;
	    time(&now);
	    if (now - start > 50)
		break;
	}
	close(p[0]);
	waitpid(-1, NULL, 0);
	x = sendto(1, pkt, l, 0, (struct sockaddr *) & F, sizeof(F));
	if (x < 0) {
	    syslog(LOG_ERR, "sendto: %s", strerror(errno));
	    return 1;
	}
    }
}

