486518fcaa
threaded in order to better deal with the requirements of multi-interface routers. Information regarding MAC addresses and interfaces is maintained by the program, and an alert is issued should a device move between interfaces. In addition, event processing has been refactored, and some bugs have been fixed. PR: 59180 Submitted by: Matthew George <mdg@secureworks.net> Approved by: portmgr
316 lines
7 KiB
Text
316 lines
7 KiB
Text
--- arpwatch.c.orig Sat Oct 14 04:07:35 2000
|
|
+++ arpwatch.c Tue Jan 20 00:22:23 2004
|
|
@@ -36,6 +36,7 @@
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/time.h>
|
|
+#include <pthread.h>
|
|
|
|
#if __STDC__
|
|
struct mbuf;
|
|
@@ -107,6 +108,8 @@
|
|
|
|
char *prog;
|
|
|
|
+char *Watcher = NULL;
|
|
+
|
|
int can_checkpoint;
|
|
int swapped;
|
|
int nobogons;
|
|
@@ -123,6 +126,14 @@
|
|
static int nets_ind;
|
|
static int nets_size;
|
|
|
|
+struct aw_threads {
|
|
+ char *interface;
|
|
+ pthread_t thread;
|
|
+};
|
|
+
|
|
+struct aw_threads *threads = NULL;
|
|
+extern pthread_mutex_t mtx_einfo, mtx_ainfo;
|
|
+
|
|
extern int optind;
|
|
extern int opterr;
|
|
extern char *optarg;
|
|
@@ -145,14 +156,14 @@
|
|
main(int argc, char **argv)
|
|
{
|
|
register char *cp;
|
|
- register int op, pid, snaplen, timeout, linktype, status;
|
|
+ register int op, pid, if_cnt, i;
|
|
#ifdef TIOCNOTTY
|
|
register int fd;
|
|
#endif
|
|
- register pcap_t *pd;
|
|
- register char *interface, *rfilename;
|
|
- struct bpf_program code;
|
|
+ register char *rfilename;
|
|
char errbuf[PCAP_ERRBUF_SIZE];
|
|
+ pcap_if_t *adp, *alldevsp = NULL;
|
|
+ char *interface = NULL;
|
|
|
|
if (argv[0] == NULL)
|
|
prog = "arpwatch";
|
|
@@ -167,10 +178,8 @@
|
|
}
|
|
|
|
opterr = 0;
|
|
- interface = NULL;
|
|
rfilename = NULL;
|
|
- pd = NULL;
|
|
- while ((op = getopt(argc, argv, "df:i:n:Nr:")) != EOF)
|
|
+ while ((op = getopt(argc, argv, "de:f:i:m:n:Nr:")) != EOF)
|
|
switch (op) {
|
|
|
|
case 'd':
|
|
@@ -181,6 +190,10 @@
|
|
#endif
|
|
break;
|
|
|
|
+ case 'e':
|
|
+ etherfile = optarg;
|
|
+ break;
|
|
+
|
|
case 'f':
|
|
arpfile = optarg;
|
|
break;
|
|
@@ -202,6 +215,10 @@
|
|
rfilename = optarg;
|
|
break;
|
|
|
|
+ case 'm':
|
|
+ Watcher = optarg;
|
|
+ break;
|
|
+
|
|
default:
|
|
usage();
|
|
}
|
|
@@ -213,19 +230,23 @@
|
|
net = 0;
|
|
netmask = 0;
|
|
} else {
|
|
- /* Determine interface if not specified */
|
|
- if (interface == NULL &&
|
|
- (interface = pcap_lookupdev(errbuf)) == NULL) {
|
|
- (void)fprintf(stderr, "%s: lookup_device: %s\n",
|
|
- prog, errbuf);
|
|
- exit(1);
|
|
- }
|
|
+ /* if not specified, do all non loopback interfaces */
|
|
+ if (interface == NULL) {
|
|
|
|
- /* Determine network and netmask */
|
|
- if (pcap_lookupnet(interface, &net, &netmask, errbuf) < 0) {
|
|
- (void)fprintf(stderr, "%s: bad interface %s: %s\n",
|
|
- prog, interface, errbuf);
|
|
- exit(1);
|
|
+ pcap_findalldevs(&alldevsp, errbuf);
|
|
+ if (alldevsp == NULL) {
|
|
+ (void)fprintf(stderr, "no suitable interfaces\n");
|
|
+ exit(1);
|
|
+ }
|
|
+
|
|
+ if_cnt = 0;
|
|
+ for(adp = alldevsp; adp != NULL; adp = adp->next) {
|
|
+ if (adp->flags != PCAP_IF_LOOPBACK)
|
|
+ ++if_cnt;
|
|
+ }
|
|
+
|
|
+ } else {
|
|
+ if_cnt = 1;
|
|
}
|
|
|
|
/* Drop into the background if not debugging */
|
|
@@ -238,7 +259,7 @@
|
|
exit(0);
|
|
(void)close(fileno(stdin));
|
|
(void)close(fileno(stdout));
|
|
- (void)close(fileno(stderr));
|
|
+
|
|
#ifdef TIOCNOTTY
|
|
fd = open("/dev/tty", O_RDWR);
|
|
if (fd >= 0) {
|
|
@@ -251,12 +272,82 @@
|
|
}
|
|
}
|
|
|
|
- openlog(prog, 0, LOG_DAEMON);
|
|
+ if (debug)
|
|
+ openlog(prog, LOG_PERROR, LOG_DAEMON);
|
|
+ else
|
|
+ openlog(prog, 0, LOG_DAEMON);
|
|
|
|
if (chdir(arpdir) < 0) {
|
|
syslog(LOG_ERR, "chdir(%s): %m", arpdir);
|
|
syslog(LOG_ERR, "(using current working directory)");
|
|
}
|
|
+ /* Read in database */
|
|
+ initializing = 1;
|
|
+ if (!readdata())
|
|
+ exit(1);
|
|
+ sorteinfo();
|
|
+#ifdef DEBUG
|
|
+ if (debug > 2) {
|
|
+ debugdump();
|
|
+ exit(0);
|
|
+ }
|
|
+#endif
|
|
+ initializing = 0;
|
|
+
|
|
+ (void)setsignal(SIGINT, die);
|
|
+ (void)setsignal(SIGTERM, die);
|
|
+ (void)setsignal(SIGHUP, die);
|
|
+ if (rfilename == NULL) {
|
|
+ (void)setsignal(SIGQUIT, checkpoint);
|
|
+ (void)setsignal(SIGALRM, checkpoint);
|
|
+ (void)alarm(CHECKPOINT);
|
|
+ }
|
|
+
|
|
+ threads = (struct aw_threads *) malloc(sizeof(struct aw_threads) * (if_cnt + 1));
|
|
+ memset((char *)threads, 0, sizeof(*threads) * (if_cnt + 1));
|
|
+ pthread_mutex_init(&mtx_einfo, NULL);
|
|
+ pthread_mutex_init(&mtx_ainfo, NULL);
|
|
+
|
|
+ if (interface != NULL)
|
|
+ {
|
|
+ threads[0].interface = interface;
|
|
+ pthread_create(&threads[0].thread, NULL, (void *)pcap_thread, interface);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ i = 0;
|
|
+
|
|
+ for (adp = alldevsp; adp != NULL; adp = adp->next)
|
|
+ if (adp->flags != PCAP_IF_LOOPBACK)
|
|
+ {
|
|
+ threads[i].interface = adp->name;
|
|
+ pthread_create(&threads[i++].thread, NULL, (void *)pcap_thread, adp->name);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i=0; i < if_cnt; i++)
|
|
+ pthread_join(threads[i].thread, NULL);
|
|
+
|
|
+ if (!dump())
|
|
+ exit(1);
|
|
+ exit(0);
|
|
+}
|
|
+
|
|
+int
|
|
+pcap_thread(char *interface)
|
|
+{
|
|
+ register char *rfilename = NULL;
|
|
+ char errbuf[PCAP_ERRBUF_SIZE];
|
|
+ register pcap_t *pd = NULL;
|
|
+ register int snaplen, timeout, linktype, status;
|
|
+ struct bpf_program code;
|
|
+
|
|
+ /* Determine network and netmask */
|
|
+ if (pcap_lookupnet(interface, &net, &netmask, errbuf) < 0) {
|
|
+ (void)fprintf(stderr, "%s: bad interface %s: %s\n",
|
|
+ prog, interface, errbuf);
|
|
+ return(1);
|
|
+ }
|
|
|
|
if (rfilename != NULL) {
|
|
pd = pcap_open_offline(rfilename, errbuf);
|
|
@@ -306,27 +397,7 @@
|
|
if (rfilename == NULL)
|
|
syslog(LOG_INFO, "listening on %s", interface);
|
|
|
|
- /* Read in database */
|
|
- initializing = 1;
|
|
- if (!readdata())
|
|
- exit(1);
|
|
- sorteinfo();
|
|
-#ifdef DEBUG
|
|
- if (debug > 2) {
|
|
- debugdump();
|
|
- exit(0);
|
|
- }
|
|
-#endif
|
|
- initializing = 0;
|
|
|
|
- (void)setsignal(SIGINT, die);
|
|
- (void)setsignal(SIGTERM, die);
|
|
- (void)setsignal(SIGHUP, die);
|
|
- if (rfilename == NULL) {
|
|
- (void)setsignal(SIGQUIT, checkpoint);
|
|
- (void)setsignal(SIGALRM, checkpoint);
|
|
- (void)alarm(CHECKPOINT);
|
|
- }
|
|
|
|
switch (linktype) {
|
|
|
|
@@ -347,9 +418,7 @@
|
|
exit(1);
|
|
}
|
|
pcap_close(pd);
|
|
- if (!dump())
|
|
- exit(1);
|
|
- exit(0);
|
|
+ return(0);
|
|
}
|
|
|
|
/* Process an ethernet arp/rarp packet */
|
|
@@ -362,6 +431,8 @@
|
|
register u_char *sea, *sha;
|
|
register time_t t;
|
|
u_int32_t sia;
|
|
+ register pthread_t thread_self = NULL;
|
|
+ register struct aw_threads *atp = threads;
|
|
|
|
eh = (struct ether_header *)p;
|
|
ea = (struct ether_arp *)(eh + 1);
|
|
@@ -400,9 +471,16 @@
|
|
/* Got a live one */
|
|
t = h->ts.tv_sec;
|
|
can_checkpoint = 0;
|
|
- if (!ent_add(sia, sea, t, NULL))
|
|
+ thread_self = pthread_self();
|
|
+
|
|
+ for (atp = threads; atp != NULL; atp++)
|
|
+ if (pthread_equal(atp->thread, thread_self))
|
|
+ break;
|
|
+
|
|
+ if (!ent_add(sia, sea, t, NULL, atp->interface))
|
|
syslog(LOG_ERR, "ent_add(%s, %s, %ld) failed",
|
|
intoa(sia), e2str(sea), t);
|
|
+
|
|
can_checkpoint = 1;
|
|
}
|
|
|
|
@@ -507,6 +585,8 @@
|
|
register u_char *sea, *sha;
|
|
register time_t t;
|
|
u_int32_t sia;
|
|
+ register pthread_t thread_self = NULL;
|
|
+ register struct aw_threads *atp = threads;
|
|
|
|
fh = (struct fddi_header *)p;
|
|
ea = (struct ether_arp *)(fh + 1);
|
|
@@ -549,7 +629,13 @@
|
|
/* Got a live one */
|
|
t = h->ts.tv_sec;
|
|
can_checkpoint = 0;
|
|
- if (!ent_add(sia, sea, t, NULL))
|
|
+ thread_self = pthread_self();
|
|
+
|
|
+ for (atp = threads; atp != NULL; atp++)
|
|
+ if (atp->thread == thread_self)
|
|
+ break;
|
|
+
|
|
+ if (!ent_add(sia, sea, t, NULL, atp->interface))
|
|
syslog(LOG_ERR, "ent_add(%s, %s, %ld) failed",
|
|
intoa(sia), e2str(sea), t);
|
|
can_checkpoint = 1;
|
|
@@ -750,7 +836,7 @@
|
|
extern char version[];
|
|
|
|
(void)fprintf(stderr, "Version %s\n", version);
|
|
- (void)fprintf(stderr, "usage: %s [-dN] [-f datafile] [-i interface]"
|
|
- " [-n net[/width]] [-r file]\n", prog);
|
|
+ (void)fprintf(stderr, "usage: %s [-dN] [-f arpfile] [-e etherfile] [-i interface]"
|
|
+ " [-m email] [-n net[/width]] [-r file]\n", prog);
|
|
exit(1);
|
|
}
|