"Fossies" - the Fresh Open Source Software Archive

Member "arpwatch-NG1.7/arpwatch.c" (9 Nov 2006, 21776 Bytes) of archive /linux/misc/old/arpwatch-NG1.7.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "arpwatch.c": 2.1a15_vs_1.7.

    1 /*
    2  * Copyright (c) 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000
    3  *  The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that: (1) source code distributions
    7  * retain the above copyright notice and this paragraph in its entirety, (2)
    8  * distributions including binary code include the above copyright notice and
    9  * this paragraph in its entirety in the documentation or other materials
   10  * provided with the distribution, and (3) all advertising materials mentioning
   11  * features or use of this software display the following acknowledgement:
   12  * ``This product includes software developed by the University of California,
   13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
   14  * the University nor the names of its contributors may be used to endorse
   15  * or promote products derived from this software without specific prior
   16  * written permission.
   17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
   18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   20  */
   21 
   22 /*
   23  arpwatch NG has been forked by and is copyrighted by freek
   24  numerous changes have been made - please consult the CHANGES file in
   25  this distribution
   26 
   27  arpwatch NG is distributed under the GPL
   28  */
   29 
   30 #include <sys/param.h>
   31 #include <sys/types.h>      /* concession to AIX */
   32 #include <sys/file.h>
   33 #include <sys/ioctl.h>
   34 #include <sys/socket.h>
   35 #include <sys/time.h>
   36 
   37 #if __STDC__
   38 struct mbuf;
   39 struct rtentry;
   40 #endif
   41 #include <net/if.h>
   42 
   43 #include <netinet/in.h>
   44 #include <netinet/if_ether.h>
   45 
   46 #include <arpa/inet.h>
   47 
   48 #include <ctype.h>
   49 #include <errno.h>
   50 #ifdef HAVE_MEMORY_H
   51 #include <memory.h>
   52 #endif
   53 #ifdef HAVE_FCNTL_H
   54 #include <fcntl.h>
   55 #endif
   56 #include <signal.h>
   57 #include <stdio.h>
   58 #include <stdlib.h>
   59 #include <string.h>
   60 #include <syslog.h>
   61 #include <unistd.h>
   62 
   63 #include <pwd.h>
   64 #include <grp.h>
   65 
   66 #include <pcap.h>
   67 
   68 #include "gnuc.h"
   69 #ifdef HAVE_OS_PROTO_H
   70 #include "os-proto.h"
   71 #endif
   72 
   73 #include "arpwatch.h"
   74 #include "db.h"
   75 #include "ec.h"
   76 #include "fddi.h"
   77 #include "file.h"
   78 #include "machdep.h"
   79 #include "setsignal.h"
   80 #include "util.h"
   81 #include "report.h"
   82 
   83 /* Some systems don't define these */
   84 #ifndef ETHERTYPE_REVARP
   85 #define ETHERTYPE_REVARP    0x8035
   86 #endif
   87 
   88 #ifndef REVARP_REQUEST
   89 #define REVARP_REQUEST      3
   90 #define REVARP_REPLY        4
   91 #endif
   92 
   93 #ifndef ETHERTYPE_TRAIL
   94 #define ETHERTYPE_TRAIL     0x1000
   95 #endif
   96 
   97 #ifndef ETHERTYPE_APOLLO
   98 #define ETHERTYPE_APOLLO    0x8019
   99 #endif
  100 
  101 #ifndef IN_CLASSD_NET
  102 #define IN_CLASSD_NET       0xf0000000
  103 #endif
  104 
  105 #ifndef max
  106 #define max(a,b) ((b)>(a)?(b):(a))
  107 #endif
  108 
  109 char *prog;
  110 
  111 int can_checkpoint;
  112 int swapped;
  113 int nobogons;
  114 
  115 static u_int32_t net;
  116 static u_int32_t netmask;
  117 
  118 struct nets {
  119     u_int32_t net;
  120     u_int32_t netmask;
  121 };
  122 
  123 static struct nets *nets;
  124 static int nets_ind;
  125 static int nets_size;
  126 
  127 extern int optind;
  128 extern int opterr;
  129 extern char *optarg;
  130 
  131 /* Forwards */
  132 static void process_ether(u_char *, const struct pcap_pkthdr *, const u_char *);
  133 static void process_fddi(u_char *, const struct pcap_pkthdr *, const u_char *);
  134 static int sanity_ether(struct ether_header *, struct ether_arp *, int, time_t *);
  135 static int sanity_fddi(struct fddi_header *, struct ether_arp *, int, time_t *);
  136 static int isbogon(u_int32_t);
  137 static int addnet(const char *);
  138 
  139 __dead void usage(void) __attribute__ ((volatile));
  140 static void drop_privileges(const char* user);
  141 static void go_daemon(void);
  142 RETSIGTYPE checkpoint(int);
  143 RETSIGTYPE die(int);
  144 
  145 
  146 int main(int argc, char **argv)
  147 {
  148     char *cp;
  149     int op, snaplen, timeout, linktype, status;
  150     int ret;
  151 
  152     pcap_t *pd;
  153     char *interface, *rfilename;
  154     struct bpf_program code;
  155     
  156     char errbuf[PCAP_ERRBUF_SIZE];
  157     /* this is the default filter: only arp or rarp traffic */
  158     char pcap_filter[512]={"(arp or rarp)"};
  159     
  160     /* default report mode is 0 == old style */
  161     int report_mode=0;
  162         char *drop_username=NULL;
  163 
  164     if(argv[0] == NULL)
  165         prog = "arpwatch";
  166     else if((cp = strrchr(argv[0], '/')) != NULL)
  167         prog = cp + 1;
  168     else
  169         prog = argv[0];
  170 
  171     if(abort_on_misalignment(errbuf) < 0) {
  172         fprintf(stderr, "%s: %s\n", prog, errbuf);
  173         exit(1);
  174     }
  175 
  176     interface = NULL;
  177     rfilename = NULL;
  178     pd = NULL;
  179     while((op = getopt(argc, argv, "df:i:n:Nr:m:ps:t:F:u:P:h")) != EOF) {
  180         switch (op) {
  181 
  182         case 'd':
  183             ++debug;
  184             break;
  185 
  186         case 'f':
  187             arpfile = optarg;
  188             break;
  189 
  190         case 'i':
  191             interface = optarg;
  192             break;
  193 
  194         case 'n':
  195             if(!addnet(optarg))
  196                 usage();
  197             break;
  198 
  199         case 'N':
  200             ++nobogons;
  201             break;
  202 
  203         case 'r':
  204             rfilename = optarg;
  205                         break;
  206 
  207                 case 'm':
  208             /*
  209              set the report function pointer to whatever is requested
  210              the original mode remains default
  211              */
  212             report_mode=atoi(optarg);
  213             if(setup_reportmode(report_mode)) {
  214                                 fprintf(stderr, "%s: Unknown report mode %d, exiting\n", prog, report_mode);
  215                                 exit(1);
  216                         }
  217             break;
  218 
  219                 case 't':
  220                         mailto=optarg;
  221                         break;
  222             
  223         case 'F':
  224             mailfrom=optarg;
  225             break;
  226 
  227                 case 'p':
  228             ++nopromisc;
  229                         break;
  230 
  231                 case 's':
  232             sendmail=optarg;
  233             break;
  234 
  235                 case 'u':
  236             drop_username=optarg;
  237             break;
  238             
  239         case 'P':
  240             sprintf(pcap_filter, "%s and %s", "(arp or rarp)", optarg);
  241             //printf("arpwatch: using pcap filter: %s\n", pcap_filter);
  242             break;
  243 
  244         case 'h':
  245         default:
  246             usage();
  247         }
  248     }
  249 
  250     if(optind != argc) {
  251         usage();
  252     }
  253 
  254     openlog(prog, 0, LOG_DAEMON);
  255 
  256     if(chdir(arpdir) < 0) {
  257         fprintf(stderr, "%s: chdir(%s) failed, using cwd for data.\n", prog, arpdir);
  258     }
  259 
  260     /* run in offline mode, no fork, analyze file */
  261     if(rfilename != NULL) {
  262         pd = pcap_open_offline(rfilename, errbuf);
  263         if(pd == NULL) {
  264             fprintf(stderr, "pcap open %s (%s)", rfilename, errbuf);
  265             exit(1);
  266         }
  267         swapped = pcap_is_swapped(pd);
  268 
  269     } else {
  270 
  271         /* Determine interface if not specified */
  272         if(interface == NULL && (interface = pcap_lookupdev(errbuf)) == NULL) {
  273             fprintf(stderr, "%s: lookup_device (%s)\n", prog, errbuf);
  274             exit(1);
  275         }
  276 
  277         /* Determine network and netmask */
  278         if(pcap_lookupnet(interface, &net, &netmask, errbuf) < 0) {
  279             fprintf(stderr, "%s: assuming unconfigured interface \"%s\" (%s), continuing\n", prog, interface, errbuf);
  280                         net=0;
  281                         netmask=0;
  282         }
  283 
  284         snaplen = max(sizeof(struct ether_header), sizeof(struct fddi_header)) + sizeof(struct ether_arp);
  285         timeout = 1000;
  286 
  287         pd = pcap_open_live(interface, snaplen, !nopromisc, timeout, errbuf);
  288         if(pd == NULL) {
  289             fprintf(stderr, "%s: pcap_open for interface \"%s\" failed (%s)\n", prog, interface, errbuf);
  290             exit(1);
  291         }
  292 #ifdef WORDS_BIGENDIAN
  293         swapped = 1;
  294 #endif
  295     }
  296 
  297         /*
  298          Revert to non-privileged user after opening sockets
  299          Just to be safe
  300          */
  301     if(drop_username) {
  302         drop_privileges(drop_username);
  303     } else {
  304         setgid(getgid());
  305         setuid(getuid());
  306     }
  307 
  308     /* Must be ethernet or fddi */
  309     linktype = pcap_datalink(pd);
  310     if(linktype != DLT_EN10MB && linktype != DLT_FDDI) {
  311         fprintf(stderr, "%s: Link layer type %d not ethernet or fddi", prog, linktype);
  312         exit(1);
  313     }
  314 
  315     /* Compile and install filter */
  316     if(pcap_compile(pd, &code, pcap_filter, 1, netmask) < 0) {
  317         fprintf(stderr, "%s: pcap_compile %s for: %s\n", prog, pcap_geterr(pd), pcap_filter);
  318         exit(1);
  319     }
  320     if(pcap_setfilter(pd, &code) < 0) {
  321         fprintf(stderr, "%s: pcap_setfilter: %s\n", prog, pcap_geterr(pd));
  322         exit(1);
  323     }
  324     if(rfilename == NULL)
  325         syslog(LOG_INFO, "listening on %s", interface);
  326 
  327     /*
  328      read in the arp.dat and ethercodes.dat databases
  329      o exit on no arp.dat
  330      o don't exit on no ethercodes.dat
  331      o try to report meaningful errors if something fails
  332 
  333      sort arp db
  334      if debuglevel is high enough: dump() it
  335      */
  336     initializing = 1;
  337     ret=readdata();
  338     if(ret == 1) {
  339         fprintf(stderr, "%s: could not read arp db \"%s\": %s\n" \
  340             "\tPlease create an arpwatch-writeable empty file \"%s\" first.\n",
  341             prog, arpfile, strerror(errno), arpfile
  342                );
  343         exit(1);
  344     } else if(ret == 2) {
  345         fprintf(stderr, "%s: could not read ethercodes.dat \"%s\": %s, continuing\n" \
  346             "\tThere will be no MAC -> vendor translation.\n",
  347             prog, ethercodes, strerror(errno)
  348                );
  349     }
  350     sorteinfo();
  351 
  352         if(debug > 2) {
  353         debugdump();
  354         exit(0);
  355     }
  356 
  357         initializing = 0;
  358 
  359         /* Drop into daemon mode the latest time possible */
  360     if(!debug && report_mode==REPORT_NORMAL) {
  361         go_daemon();
  362     }
  363 
  364     /*
  365      setup signals after we dropped into daemon mode
  366      else they're out of effect, dumb me
  367      Fixes bug with arp.dat not being updated
  368      */
  369     setsignal(SIGINT, die);
  370     setsignal(SIGTERM, die);
  371     setsignal(SIGHUP, die);
  372     if(rfilename == NULL) {
  373         setsignal(SIGQUIT, checkpoint);
  374         setsignal(SIGALRM, checkpoint);
  375         alarm(CHECKPOINT_INTERVAL);
  376     }
  377 
  378     switch (linktype) {
  379 
  380     case DLT_EN10MB:
  381         status = pcap_loop(pd, 0, process_ether, NULL);
  382         break;
  383 
  384     case DLT_FDDI:
  385         status = pcap_loop(pd, 0, process_fddi, NULL);
  386         break;
  387 
  388     default:
  389         fprintf(stderr, "%s: bad linktype %d (can't happen)\n", prog, linktype);
  390                 syslog(LOG_ERR, "bad linktype %d (can't happen)", linktype);
  391         exit(1);
  392     }
  393 
  394         if(status < 0) {
  395         fprintf(stderr, "%s: pcap_loop: %s\n", prog, pcap_geterr(pd));
  396         syslog(LOG_ERR, "pcap_loop: %s", pcap_geterr(pd));
  397         exit(1);
  398     }
  399 
  400         pcap_close(pd);
  401     if(!dump())
  402         exit(1);
  403     exit(0);
  404 }
  405 
  406 
  407 /* Process an ethernet arp/rarp packet */
  408 static void process_ether(u_char *u, const struct pcap_pkthdr *h, const u_char *p)
  409 {
  410     struct ether_header *eh;
  411     struct ether_arp *ea;
  412     u_char *sea, *sha;
  413     time_t t;
  414     u_int32_t sia;
  415 
  416     eh = (struct ether_header *)p;
  417     ea = (struct ether_arp *)(eh + 1);
  418 
  419         /* extract time of observation */
  420         t=h->ts.tv_sec;
  421 
  422     if(!sanity_ether(eh, ea, h->caplen, &t))
  423         return;
  424 
  425     /* Source hardware ethernet address */
  426     sea = (u_char *) ESRC(eh);
  427 
  428     /* Source ethernet address */
  429     sha = (u_char *) SHA(ea);
  430 
  431     /* Source ip address */
  432     BCOPY(SPA(ea), &sia, 4);
  433 
  434 
  435     /* Watch for bogons */
  436     if(isbogon(sia)) {
  437                 report(ACTION_BOGON, sia, sea, sha, &t, NULL);
  438         return;
  439     }
  440 
  441     /* Watch for ethernet broadcast */
  442         if(MEMCMP(sea, zero, 6) == 0 || MEMCMP(sea, allones, 6) == 0
  443            || MEMCMP(sha, zero, 6) == 0 || MEMCMP(sha, allones, 6) == 0) {
  444                 report(ACTION_ETHER_BROADCAST, sia, sea, sha, &t, NULL);
  445         return;
  446     }
  447 
  448     /* Double check ethernet addresses */
  449     if(MEMCMP(sea, sha, 6) != 0) {
  450                 report(ACTION_ETHER_MISMATCH, sia, sea, sha, &t, NULL);
  451         return;
  452     }
  453 
  454     /* when all checks have been passed add(check) the entry into the arp db */
  455     can_checkpoint = 0;
  456     if(!ent_add(sia, sea, t, NULL))
  457         syslog(LOG_ERR, "ent_add(%s, %s, %ld) failed", intoa(sia), e2str(sea), t);
  458     can_checkpoint = 1;
  459 }
  460 
  461 /* Perform sanity checks on an ethernet arp/rarp packet, return true if ok */
  462 static int sanity_ether(struct ether_header *eh, struct ether_arp *ea, int len, time_t *t)
  463 {
  464     /* XXX use bsd style ether_header to avoid messy ifdef's */
  465     struct bsd_ether_header {
  466         u_char ether_dhost[6];
  467         u_char ether_shost[6];
  468         u_short ether_type;
  469     };
  470     u_char *shost = ((struct bsd_ether_header *)eh)->ether_shost;
  471 
  472     eh->ether_type = ntohs(eh->ether_type);
  473     ea->arp_hrd = ntohs(ea->arp_hrd);
  474     ea->arp_pro = ntohs(ea->arp_pro);
  475     ea->arp_op = ntohs(ea->arp_op);
  476 
  477         /* these are cheap, but maybe don't do them twice */
  478     u_char *sea, *sha;
  479     u_int32_t sia;
  480     /* Source addresses */
  481     sea = (u_char *) ESRC(eh);
  482     sha = (u_char *) SHA(ea);
  483     /* Source ip address */
  484     BCOPY(SPA(ea), &sia, 4);
  485 
  486     if(len < sizeof(*eh) + sizeof(*ea)) {
  487         //syslog(LOG_ERR, "short (want %d)\n", sizeof(*eh) + sizeof(*ea));
  488                 report(ACTION_ETHER_TOOSHORT, sia, sea, sha, t, NULL);
  489         return (0);
  490     }
  491 
  492     /* XXX sysv r4 seems to use hardware format 6 */
  493     if(ea->arp_hrd != ARPHRD_ETHER && ea->arp_hrd != 6) {
  494         //syslog(LOG_ERR, "%s sent bad hardware format 0x%x\n", e2str(shost), ea->arp_hrd);
  495                 report(ACTION_ETHER_BADFORMAT, sia, sea, sha, t, NULL);
  496         return (0);
  497     }
  498 
  499     /* XXX hds X terminals sometimes send trailer arp replies */
  500     if(ea->arp_pro != ETHERTYPE_IP && ea->arp_pro != ETHERTYPE_TRAIL) {
  501         //syslog(LOG_ERR, "%s sent packet not ETHERTYPE_IP (0x%x)\n", e2str(shost), ea->arp_pro);
  502         report(ACTION_ETHER_WRONGTYPE_IP, sia, sea, sha, t, NULL);
  503         return (0);
  504     }
  505 
  506     if(ea->arp_hln != 6 || ea->arp_pln != 4) {
  507         //syslog(LOG_ERR, "%s sent bad addr len (hard %d, prot %d)\n", e2str(shost), ea->arp_hln, ea->arp_pln);
  508         report(ACTION_ETHER_BADLENGTH, sia, sea, sha, t, NULL);
  509         return (0);
  510     }
  511 
  512     /*
  513      * We're only interested in arp requests, arp replies
  514      * and reverse arp replies
  515      */
  516     if(eh->ether_type == ETHERTYPE_ARP) {
  517         if(ea->arp_op != ARPOP_REQUEST && ea->arp_op != ARPOP_REPLY) {
  518             //syslog(LOG_ERR, "%s sent wrong arp op %d\n", e2str(shost), ea->arp_op);
  519             report(ACTION_ETHER_WRONGOP, sia, sea, sha, t, NULL);
  520             return (0);
  521         }
  522     } else if(eh->ether_type == ETHERTYPE_REVARP) {
  523         if(ea->arp_op == REVARP_REQUEST) {
  524             /* no useful information here */
  525             return (0);
  526         } else if(ea->arp_op != REVARP_REPLY) {
  527             report(ACTION_ETHER_WRONGRARP, sia, sea, sha, t, NULL);
  528             if(debug)
  529                 syslog(LOG_ERR, "%s sent wrong revarp op %d\n", e2str(shost), ea->arp_op);
  530             return (0);
  531         }
  532     } else {
  533         //syslog(LOG_ERR, "%s sent bad type 0x%x\n", e2str(shost), eh->ether_type);
  534         report(ACTION_ETHER_WRONGTYPE, sia, sea, sha, t, NULL);
  535         return (0);
  536     }
  537 
  538     return (1);
  539 }
  540 
  541 static void bit_reverse(u_char *p, unsigned len)
  542 {
  543     unsigned i;
  544     u_char b;
  545 
  546     for(i = len; i; i--, p++) {
  547         b = (*p & 0x01 ? 0x80 : 0)
  548             | (*p & 0x02 ? 0x40 : 0)
  549             | (*p & 0x04 ? 0x20 : 0)
  550             | (*p & 0x08 ? 0x10 : 0)
  551             | (*p & 0x10 ? 0x08 : 0)
  552             | (*p & 0x20 ? 0x04 : 0)
  553             | (*p & 0x40 ? 0x02 : 0)
  554             | (*p & 0x80 ? 0x01 : 0);
  555         *p = b;
  556     }
  557 }
  558 
  559 static void process_fddi(u_char *u, const struct pcap_pkthdr *h, const u_char *p)
  560 {
  561     struct fddi_header *fh;
  562     struct ether_arp *ea;
  563     u_char *sea, *sha;
  564     time_t t;
  565     u_int32_t sia;
  566 
  567     fh = (struct fddi_header *)p;
  568     ea = (struct ether_arp *)(fh + 1);
  569 
  570     if(!swapped) {
  571         bit_reverse(fh->src, 6);
  572         bit_reverse(fh->dst, 6);
  573     }
  574         /* extract time of observation */
  575     t = h->ts.tv_sec;
  576 
  577     if(!sanity_fddi(fh, ea, h->caplen, &t))
  578         return;
  579 
  580     /* Source MAC hardware ethernet address */
  581     sea = (u_char *) fh->src;
  582 
  583     /* Source ARP ethernet address */
  584     sha = (u_char *) SHA(ea);
  585 
  586     /* Source ARP ip address */
  587     BCOPY(SPA(ea), &sia, 4);
  588 
  589     /* Watch for bogons */
  590     if(isbogon(sia)) {
  591                 report(ACTION_BOGON, sia, sea, sha, &t, NULL);
  592         return;
  593     }
  594 
  595     /* Watch for ethernet broadcast */
  596     if(MEMCMP(sea, zero, 6) == 0 || MEMCMP(sea, allones, 6) == 0 || MEMCMP(sha, zero, 6) == 0 || MEMCMP(sha, allones, 6) == 0) {
  597                 report(ACTION_ETHER_BROADCAST, sia, sea, sha, &t, NULL);
  598         return;
  599     }
  600 
  601     /* Double check ethernet addresses */
  602     if(MEMCMP(sea, sha, 6) != 0) {
  603                 report(ACTION_ETHER_MISMATCH, sia, sea, sha, &t, NULL);
  604         return;
  605     }
  606 
  607     /* Got a live one */
  608     can_checkpoint = 0;
  609     if(!ent_add(sia, sea, t, NULL))
  610         syslog(LOG_ERR, "ent_add(%s, %s, %ld) failed", intoa(sia), e2str(sea), t);
  611     can_checkpoint = 1;
  612 }
  613 
  614 /* Perform sanity checks on arp/rarp packet, return true if ok */
  615 static int sanity_fddi(struct fddi_header *fh, struct ether_arp *ea, int len, time_t *t)
  616 {
  617     u_char *shost = fh->src;
  618     u_short type, hrd, pro, op;
  619 
  620         /* these are cheap, but maybe don't do them twice */
  621     u_char *sea, *sha;
  622     u_int32_t sia;
  623     /* Source MAC hardware ethernet address */
  624     sea = (u_char *) fh->src;
  625     /* Source ARP ethernet address */
  626     sha = (u_char *) SHA(ea);
  627     /* Source ARP ip address */
  628     BCOPY(SPA(ea), &sia, 4);
  629 
  630     /* This rather clunky copy stuff is needed because the fddi header
  631      * has an odd (i.e. not even) length, causing memory alignment
  632      * errors when attempts are made to access the arp header fields
  633      * as shorts */
  634     BCOPY(fh->snap.snap_type, &type, sizeof(u_short));
  635     BCOPY(&(ea->arp_hrd), &hrd, sizeof(hrd));
  636     BCOPY(&(ea->arp_pro), &pro, sizeof(pro));
  637     BCOPY(&(ea->arp_op), &op, sizeof(op));
  638     type = ntohs(type);
  639     hrd = ntohs(hrd);
  640     pro = ntohs(pro);
  641     op = ntohs(op);
  642 
  643     if(len < sizeof(*fh) + sizeof(*ea)) {
  644         //syslog(LOG_ERR, "short (want %d)\n", sizeof(*fh) + sizeof(*ea));
  645         report(ACTION_ETHER_TOOSHORT, sia, sea, sha, t, NULL);
  646         return (0);
  647     }
  648 
  649     /* XXX sysv r4 seems to use hardware format 6 */
  650     if(hrd != ARPHRD_ETHER && hrd != 6) {
  651         //syslog(LOG_ERR, "%s sent bad hardware format 0x%x\n", e2str(shost), hrd);
  652         report(ACTION_ETHER_BADFORMAT, sia, sea, sha, t, NULL);
  653         return (0);
  654     }
  655 
  656 
  657     /* XXX hds X terminals sometimes send trailer arp replies */
  658     if(pro != ETHERTYPE_IP && pro != ETHERTYPE_TRAIL && pro != ETHERTYPE_APOLLO) {
  659         //syslog(LOG_ERR, "%s sent packet not ETHERTYPE_IP (0x%x)\n", e2str(shost), pro);
  660         report(ACTION_ETHER_WRONGTYPE_IP, sia, sea, sha, t, NULL);
  661         return (0);
  662     }
  663 
  664     if(ea->arp_hln != 6 || ea->arp_pln != 4) {
  665         //syslog(LOG_ERR, "%s sent bad addr len (hard %d, prot %d)\n", e2str(shost), ea->arp_hln, ea->arp_pln);
  666         report(ACTION_ETHER_BADLENGTH, sia, sea, sha, t, NULL);
  667         return (0);
  668     }
  669 
  670     /*
  671      * We're only interested in arp requests, arp replies
  672      * and reverse arp replies
  673      */
  674     if(type == ETHERTYPE_ARP) {
  675         if(op != ARPOP_REQUEST && op != ARPOP_REPLY) {
  676             //syslog(LOG_ERR, "%s sent wrong arp op %d\n", e2str(shost), op);
  677             report(ACTION_ETHER_WRONGOP, sia, sea, sha, t, NULL);
  678             return (0);
  679         }
  680     } else if(type == ETHERTYPE_REVARP) {
  681         if(op == REVARP_REQUEST) {
  682             /* no useful information here */
  683             return (0);
  684         } else if(op != REVARP_REPLY) {
  685             report(ACTION_ETHER_WRONGRARP, sia, sea, sha, t, NULL);
  686             if(debug)
  687                 syslog(LOG_ERR, "%s sent wrong revarp op %d\n", e2str(shost), op);
  688             return (0);
  689         }
  690     } else {
  691         //syslog(LOG_ERR, "%s sent bad type 0x%x\n", e2str(shost), type);
  692         report(ACTION_ETHER_WRONGTYPE, sia, sea, sha, t, NULL);
  693         return (0);
  694     }
  695     return (1);
  696 }
  697 
  698 static int addnet(const char *str)
  699 {
  700     char *cp;
  701     int width;
  702     u_int32_t n, m;
  703     struct nets *np;
  704     char *cp2;
  705     char tstr[64];
  706 
  707     if(strlen(str) > sizeof(tstr) - 1)
  708         return (0);
  709 
  710     if(nets_size <= 0) {
  711         nets_size = 8;
  712         nets = malloc(nets_size * sizeof(*nets));
  713     } else if(nets_size <= nets_ind) {
  714         /* XXX debugging */
  715         nets_size <<= 1;
  716         nets = realloc(nets, nets_size * sizeof(*nets));
  717     }
  718     if(nets == NULL) {
  719         fprintf(stderr, "%s: addnet: malloc/realloc: %s\n", prog, strerror(errno));
  720         exit(1);
  721     }
  722     np = nets + nets_ind;
  723 
  724     width = 0;
  725     strcpy(tstr, str);
  726     cp = strchr(tstr, '/');
  727     if(cp != NULL) {
  728         *cp++ = '\0';
  729         width = strtol(cp, &cp2, 10);
  730         /* Trailing garbage */
  731         if(*cp2 != '\0')
  732             return (0);
  733         if(width > 32)
  734             return (0);
  735     }
  736 
  737     /* XXX hack */
  738     n = ntohl(inet_addr(tstr));
  739     while((n & 0xff000000) == 0) {
  740         n <<= 8;
  741         if(n == 0)
  742             return (0);
  743     }
  744     n = htonl(n);
  745 
  746     if(width != 0) {
  747         m = ~0;
  748         m <<= 32 - width;
  749     } else if(IN_CLASSA(n))
  750         m = IN_CLASSA_NET;
  751     else if(IN_CLASSB(n))
  752         m = IN_CLASSB_NET;
  753     else if(IN_CLASSC(n))
  754         m = IN_CLASSC_NET;
  755     else if(IN_CLASSD(n))
  756         m = IN_CLASSD_NET;
  757     else
  758         return (0);
  759     m = htonl(m);
  760 
  761     np->net = n;
  762     np->netmask = m;
  763     ++nets_ind;
  764 
  765     return (1);
  766 }
  767 
  768 static int isbogon(u_int32_t sia)
  769 {
  770     int i;
  771     struct nets *np;
  772 
  773     if(nobogons)
  774         return (0);
  775     if((sia & netmask) == net)
  776         return (0);
  777     for(i = 0, np = nets; i < nets_ind; ++i, ++np)
  778         if((sia & np->netmask) == np->net)
  779             return (0);
  780     return (1);
  781 }
  782 
  783 RETSIGTYPE die(int signo)
  784 {
  785 
  786     syslog(LOG_DEBUG, "exiting");
  787     checkpoint(0);
  788     exit(1);
  789 }
  790 
  791 RETSIGTYPE checkpoint(int signo)
  792 {
  793 
  794     if(!can_checkpoint)
  795         alarm(1);
  796     else {
  797         alarm(0);
  798         dump();
  799         alarm(CHECKPOINT_INTERVAL);
  800     }
  801     return RETSIGVAL;
  802 }
  803 
  804 __dead void usage(void)
  805 {
  806     int n, i;
  807         const struct report_mode *modes;
  808     extern const char *version;
  809 
  810         n=get_reportmodes(&modes);
  811 
  812     printf("%s version %s - released under GPL\n", prog, version);
  813     printf("    -d                increase debugging level\n" \
  814            "    -i if             only listen on interface if\n" \
  815            "    -m report_mode    run in mode:\n"
  816           );
  817     for(i=0; i < n; i++) {
  818         printf("\t\t\t%d - %s\n", i, modes[i].name);
  819     }
  820     printf("    -u username       drop privileges to username after opening interface\n"
  821            "    -p                do NOT put interface into promisc mode\n" \
  822            "    -P \"pcap_filter\"  attach pcap filter; see tcpdump(8) for expressions\n" \
  823            "    -n net[/width]    add networks to watch\n" \
  824                "    -N                do NOT report bogons\n" \
  825            "    -f data_file      write arp DB to file instead of default arp.dat\n" \
  826            "    -r pcap_dump      read in data from captured pcap file instead of network\n" \
  827            "    -t mail_to        send mail reports To:\n" \
  828            "    -F mail_from      set mail From: header\n" \
  829            "    -s prog           use prog instead of sendmail to send mail\n" \
  830           );
  831     exit(1);
  832 }
  833 
  834 
  835 static void drop_privileges(const char *user)
  836 {
  837     struct passwd* pw;
  838     pw=getpwnam(user);
  839     if(pw) {
  840         if( initgroups(pw->pw_name, 0) != 0 ||
  841             setgid(pw->pw_gid) != 0 ||
  842             setuid(pw->pw_uid) != 0
  843           ){
  844             fprintf(stderr, "%s: could not change to %.32s uid=%d gid=%d; exiting", prog, user,pw->pw_uid, pw->pw_gid);
  845             exit(1);
  846         }
  847 
  848     } else {
  849         fprintf(stderr, "%s: could not find user '%.32s'; exiting\n", prog, user);
  850         exit(1);
  851     }
  852 
  853     //syslog(LOG_INFO, "Running as uid=%d gid=%d", getuid(), getgid());
  854 }
  855 
  856 
  857 static void go_daemon()
  858 {
  859     pid_t pid;
  860         int fd;
  861 
  862     pid = fork();
  863     if(pid < 0) {
  864         syslog(LOG_ERR, "main fork(): %m");
  865         exit(1);
  866     } else if(pid != 0) {
  867         exit(0);
  868     }
  869 
  870     close(fileno(stdin));
  871     close(fileno(stdout));
  872     close(fileno(stderr));
  873 #ifdef TIOCNOTTY
  874     fd = open("/dev/tty", O_RDWR);
  875     if(fd >= 0) {
  876         ioctl(fd, TIOCNOTTY, 0);
  877         close(fd);
  878     }
  879 #else
  880     setsid();
  881 #endif
  882 
  883 }