/* * by Jakub Wartak 2006 * Licensed under GPLv2. * * most mogacy polaczyc tcpdump -w na routerze * z jakims analizatorem czytajacym z FIFO */ // TODO: syslog #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* MTU ? */ #define BUFLEN 1200 #define VERSION "0.0.1" static int mode, run, fifook, debuglvl; static time_t startup; static unsigned long packets, bytes; enum { M_SENDER = 0x1, M_RECIVER = 0x2 }; static void usage(char *progname) { fprintf(stderr, "Remote PCAP Daemon version %s by vnull 2006\n", VERSION); fprintf(stderr, "Usage: %s <-r|-s -d [ip]> [-p ]\n\n", progname); fprintf(stderr, "\t-r\t\t\t- reciver mode\n"); fprintf(stderr, "\t-s\t\t\t- sender mode\n"); fprintf(stderr, "\t-d \t\t\t- destination IP (sender mode only)\n"); fprintf(stderr, "\t-p \t\t- UDP port to use (default: 32001)\n"); fprintf(stderr, "\t-f \t\t- FIFO file name (default: /tmp/rpcapd.fifo)\n"); fprintf(stderr, "\t-u \t\t- switch to UID after initialization\n"); fprintf(stderr, "\t-g \t\t- switch to GID after initialization\n"); fprintf(stderr, "\t-x\t\t\t- don't detach ( run foreground )\n"); fprintf(stderr, "\t-D \t\t- enable debug messagess, enforces -x\n"); fprintf(stderr, "\n"); exit(-1); } void die(char *s) { perror(s); exit(1); } int create_udpsock(void) { int s; if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) { die("socket"); } return s; } void init_si(struct sockaddr_in *si, int port) { memset(si, 0, sizeof(struct sockaddr_in)); si->sin_family = AF_INET; si->sin_port = htons(port); } int init_socket(struct sockaddr_in *si, int port, char *ip) { int s = create_udpsock(); init_si(si, port); if(debuglvl) { printf("Created socket with fd %d\n", s); } if(mode == M_SENDER) { if (inet_aton(ip, &(si->sin_addr))==0) { fprintf(stderr, "inet_aton() failed: bad IP given, unable to convert\n"); exit(1); } } else if(mode == M_RECIVER) { si->sin_addr.s_addr = htonl(INADDR_ANY); if (bind(s, (struct sockaddr *)si, sizeof(struct sockaddr_in))==-1) { die("bind"); } } return s; } /* * SEKCJA OBSLUGI SYGNALOW */ void handle_sigend(int no) { int diff = time(NULL) - startup; printf("Terminating. Uptime = %d seconds\n", diff); exit(1); } void float2strbytes(unsigned long b, char buf[], int bufmax) { char *app = "B/s"; if(b > 1024) { b %= 1024; if(b > 1024*1024) { b %= 1024*1024; if(b > 1024*1024*1024) { b %= 1024*1024*1024; app = "GB/s"; } else { app = "MB/s"; } } else { app = "KB/s"; } } snprintf(buf, bufmax, "%ld%s", b, app); return; } void handle_sigusr1(int no) { /* stats */ int diff = time(NULL) - startup; int avgp = packets / diff; unsigned long avgb = bytes / diff; char buf[32]; float2strbytes(avgb, buf, sizeof(buf)-1); printf("AveragePPS=%d AverageRate=%s Uptime=%d\n", avgp, buf, diff); } void handle_sigpipe(int no) { /* co 2s bedziemy sprawdzac potok ( probowac znow pisac do niego ) */ if(fifook) { alarm(2); printf("SIGALARM! fifook was 1 will be 0, sched alarm\n"); } /* ustawiamy znacznik ze cos jest nie tak z FIFO */ fifook = 0; printf("SIGPIPE! fifook=0\n"); } void handle_sigalrm(int no) { fifook = 1; printf("SIGALARM! fifook=1\n"); } void init_signals(void) { signal(SIGINT, handle_sigend); signal(SIGTERM, handle_sigend); signal(SIGUSR1, handle_sigusr1); signal(SIGPIPE, handle_sigpipe); signal(SIGALRM, handle_sigalrm); signal(SIGCHLD,SIG_IGN); signal(SIGTSTP,SIG_IGN); /* tty */ } static int init_fifo(char *name) { int f, flags, err = remove(name); if(err == -1 && errno != ENOENT) die("remove()"); if(mkfifo(name, 0600) == -1) die("mkfifo()"); if(mode == M_SENDER) { flags = O_RDONLY|O_SYNC; } else { flags = O_WRONLY|O_SYNC; } if((f = open(name, flags)) == -1) die("open()"); return f; } int main(int argc, char **argv) { int ret, s, i, f, optch, port = 32001, uid=-1, gid=-1, dontfork=0; struct sockaddr_in si; /* defaulty */ char buf[BUFLEN], *fifoname = "/tmp/rpcapd.fifo", *ip = "127.0.0.1"; static char optstring[] = "xrsd:p:f:Vu:g:D:"; /* defaulty #2 */ mode = 0; debuglvl = 0; packets = bytes = 0; while((optch = getopt(argc, argv, optstring)) != -1) { switch(optch) { case 'r': mode = M_RECIVER; break; case 's': mode = M_SENDER; break; case 'd': ip = strdup(optarg); break; case 'p': port = atoi(optarg); break; case 'f': fifoname = strdup(optarg); break; case 'V': usage(argv[0]); break; case 'u': uid = atoi(optarg); break; case 'g': gid = atoi(optarg); break; case 'D': debuglvl = atoi(optarg); dontfork = 1; printf("Enabling debug mode, level=%d\n", debuglvl); break; case 'x': dontfork = 1; break; default: usage(argv[0]); /* i tak nigdy do tego nie dojdzie */ break; } } if(!mode) { fprintf(stderr, "You must specify sender/reciver mode!\n\n"); usage(argv[0]); } /* sekcja inicjalizacyjna */ // TODO: syslog if(dontfork==0) { ret = fork(); if(ret == -1) { die("fork()"); } if(ret != 0 ) { printf("parent: daemon mode enabled - forking\n"); exit(-1); } /* child */ if (setsid() < 0) { die("setsid()"); } } startup = time(NULL); /* fifook == 1 => mozna pisac do FIFO i jest ok */ run = fifook = 1; init_signals(); s = init_socket(&si, port, ip); f = init_fifo(fifoname); if(gid != -1) { if(setgid(gid) < 0) { die("setgid()"); } } if(uid != -1) { if(setuid(uid) < 0) { die("setuid()"); } } while(run) { ssize_t len; if(mode == M_RECIVER) { struct sockaddr_in other; socklen_t slen = sizeof(other); if ((len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *)&other, &slen))==-1) { die("recvfrom()"); } if(debuglvl==2) { printf("Received packet from %s:%d, len=%ld\n", inet_ntoa(other.sin_addr), ntohs(other.sin_port), len); } if(fifook) { /* jezeli jest wszystko jest OK z fifo to piszemy * moze sie tez zdarzyc ze dostaniemy po tym writcie SIGPIPE * jezeli nikt nie bedzie czytal FIFO, wtedy to co 2s * bedziemy probowac znow pisac i moze sie okazac ze bedzie OK * albo ze znow jest zle i wtedy znow za 2s .... */ write(f, buf, len); packets++; bytes += len; } } else if(mode == M_SENDER) { socklen_t slen2 = sizeof(si); len = read(f, buf, BUFLEN); packets++; bytes += len; struct in_addr *ia = &(si.sin_addr); if(debuglvl==2) { printf("sending %ld bytes data=%d\n", len, ia->s_addr); } if (sendto(s, buf, len, 0, (struct sockaddr *)&si, slen2)==-1) { die("send()"); } } } close(f); close(s); return 0; }