--- dhcp_probe-1.1.0/src/configfile.c 2004-11-02 19:10:47.000000000 +0100 +++ dhcp_probe-1.1.0-patch/src/configfile.c 2006-09-06 14:49:28.000000000 +0200 @@ -51,6 +51,7 @@ /* optional name of external alert program to call */ char *alert_program_name = NULL; +char *ok_program_name = NULL; int @@ -275,6 +276,33 @@ if (debug > 2) report(LOG_DEBUG, "read_configfile: alert_program_name %s", alert_program_name); + } else if (! strcasecmp(str1, "ok_program_name")) { + + if (ok_program_name) { + report(LOG_ERR, "read_configfile: line %d, ok_program_name may be specified only once, ignoring", line); + continue; + } + + /* token2: required program name */ + if (tokens < 2) { + report(LOG_ERR, "read_configfile: line %d, not enough values: %s", line, buf); + continue; + } + + if (str2[0] != '/') { + report(LOG_ERR, "read_configfile: line %d, invalid ok_program_name '%s', must be an absolute pathname, ignoring", line, str2); + continue; + } + + ok_program_name = strdup(str2); + if (! ok_program_name) { + report(LOG_ERR, "read_configfile: line %d, can't save ok_program_name because strdup() could not malloc() space, ignoring", line); + continue; + } + + if (debug > 2) + report(LOG_DEBUG, "read_configfile: ok_program_name %s", ok_program_name); + } else { report(LOG_ERR, "read_configfile: line %d, unrecognized token: %s", line, str1); } @@ -440,3 +468,34 @@ return alert_program_name_copy; } +char * +GetOk_program_name(void) +{ + static char *ok_program_name_copy = NULL; + + if (ok_program_name_copy) { + /* Space was allocated from a previous call. + We must not re-use that space, since it's possible that the ok_program_name has + gotten longer due to a re-read of the configfile. + */ + free(ok_program_name_copy); + ok_program_name_copy = NULL; + } + + if (!ok_program_name) { + return (char *) NULL; + } + + /* we re-init the static copy on each call, since we don't know if the caller has + written into it. */ + ok_program_name_copy = strdup(ok_program_name); + + if (!ok_program_name_copy) { + report(LOG_ERR, "GetOk_program_name: strdup() failed (presumably a malloc error)-- exiting"); + cleanup(); + exit(1); + } + + return ok_program_name_copy; +} + --- dhcp_probe-1.1.0/src/dhcp_probe.c 2004-11-10 22:35:43.000000000 +0100 +++ dhcp_probe-1.1.0-patch/src/dhcp_probe.c 2006-09-06 15:09:26.000000000 +0200 @@ -35,6 +35,7 @@ /* initialize options to defaults */ int debug = 0; int dont_fork = 0; +int ilegalservers = 0; char *config_file = CONFIG_FILE; char *pid_file = PID_FILE; char *capture_file = NULL; @@ -51,6 +52,7 @@ char *prog = NULL; char *logfile_name = NULL; +char *program_name; int sockfd; @@ -246,11 +248,9 @@ cleanup(); exit(1); } - reread_config_file = 0; /* set by signal handler */ reopen_log_file = 0; /* set by signal handler */ reopen_capture_file = 0; /* set by signal handler */ - ifname = strdup(argv[optind]); /* interface name is a required final argument */ /* general purpose dgram socket for various uses */ @@ -278,7 +278,13 @@ cleanup(); exit(1); } - +#ifdef linux + if(arp_getdevhw(ifname, &my_eaddr, sockfd) < 0) { + report(LOG_ERR, "couldn't determine my ethernet addr for my IP address %s", inet_ntoa(my_ipaddr)); + cleanup(); + exit(1); + } +#else /* lookup ethernet address for specified IP address */ /* note that my_eaddr must be init'd before calling GetChaddr() */ if (get_myeaddr(sockfd, &my_ipaddr, &my_eaddr, ifname) < 0) { @@ -286,6 +292,7 @@ cleanup(); exit(1); } +#endif if (debug > 0) report(LOG_INFO, "using interface %s (IP address %s, hardware address %s)", @@ -389,6 +396,9 @@ cleanup(); exit(1); } +#ifdef linux + set_timeout(pd_template); +#endif /* linux */ if (pcap_errbuf[0] != '\0') /* even on success, a warning may be produced */ report(LOG_WARNING, "pcap_open_live %s: %s", ifname, pcap_errbuf); @@ -407,6 +417,7 @@ } while (1) { /* MAIN EVENT LOOP */ + ilegalservers = 0; int promiscuous; libnet_t *l; /* to iterate through libnet context queue */ /* struct pcap_stat ps; */ /* to hold pcap stats */ @@ -433,11 +444,11 @@ close_and_reopen_capture_file(); reopen_capture_file = 0; } - if (reread_config_file) { /* set by signal handler */ - reconfigure(write_packet_len); - reread_config_file = 0; - } +// if (reread_config_file) { /* set by signal handler */ +// reconfigure(write_packet_len); +// reread_config_file = 0; +// } /* We open (and later close) the packet capture descriptor on each packet sent (rather than just once for the entire program) because a change in the configfile (specifically, 'chaddr') @@ -462,7 +473,6 @@ else promiscuous = 0; - for (l = libnet_cq_head(); libnet_cq_last(); l = libnet_cq_next()) { /* write one flavor packet and listen for answers */ int pcap_rc; @@ -640,14 +650,14 @@ close_and_reopen_log_file(logfile_name); reopen_log_file = 0; } - if (reopen_capture_file) { /* set by signal handler */ - close_and_reopen_capture_file(); - reopen_capture_file = 0; - } - if (reread_config_file) { /* set by signal handler */ - reconfigure(write_packet_len); - reread_config_file = 0; - } +// if (reopen_capture_file) { /* set by signal handler */ +// close_and_reopen_capture_file(); +// reopen_capture_file = 0; +// } +// if (reread_config_file) { /* set by signal handler */ +// reconfigure(write_packet_len); +// reread_config_file = 0; +// } /* We allow must signals that come in during our sleep() to interrupt us. E.g. we want to cut short our sleep when we're signalled to exit. But we must block SIGCHLD during our sleep. That's because @@ -655,14 +665,21 @@ we'll end up being interrupted by the SIGCHLD almost immediately, cutting short our sleep and forcing us to proceed to the next probe cycle far too soon. */ - alarm(0); /* cancel any alarm left over, just in-case something's left by libpcap */ - time_to_sleep = GetCycle_time(); + if (ilegalservers == 1) + program_name = GetAlert_program_name(); + else + program_name = GetOk_program_name(); + + if (program_name) { + system(program_name); + } + + time_to_sleep = GetCycle_time(); sigemptyset(&new_sigset); sigaddset(&new_sigset, SIGCHLD); sigprocmask(SIG_BLOCK, &new_sigset, &old_sigset); /* block SIGCHLD */ - sleep(time_to_sleep); sigprocmask(SIG_SETMASK, &old_sigset, NULL); /* unblock SIGCHLD */ @@ -709,7 +726,7 @@ int udp_len; /* XXX why does udp.h declare this as signed? */ int udp_payload_len; - char *alert_program_name; + char *program_name; if (debug > 10) report(LOG_DEBUG, " captured a packet"); @@ -771,7 +788,7 @@ return; } - udp_len = udp_header->uh_ulen; + udp_len = udp_header->len; if (udp_len < sizeof(struct udphdr)) { report(LOG_WARNING, "interface %s, invalid UDP packet (UDP length %d, smaller than minimum value %d)", ifname, udp_len, sizeof(struct udphdr)); return; @@ -842,32 +859,7 @@ pcap_dump((u_char *) pcap_dump_d, pkthdr, packet); } - /* Also call the alert_program_name if the user has specified one */ - /* We must fetch it anew as it may have changed due to configfile change */ - alert_program_name = GetAlert_program_name(); - if (alert_program_name) { - /* We run it in a child, so we don't block waiting for it to return. */ - pid_t pid; - if ((pid = fork()) < 0) { - report(LOG_ERR, "can't fork to run %s: %s", alert_program_name, get_errmsg()); - /* just skip running alert_program_name, but keep running since we're still fine */ - } else if (pid == 0) { /* child */ - /* We do allow child to inherit fd 0,1,2. If we're logging to stderr, we want child to have it too. */ - if (sockfd) /* We don't want child to inherit the general purpose dgram socket */ - close(sockfd); - libnet_cq_destroy(); /* We don't want child to inherit to inherit libnet context queue */ - if (pd) /* We don't want child to inherit packet capture descriptor, nor packet dumpfile descriptor. */ - pcap_close(pd); - if (pcap_dump_d) - pcap_dump_close(pcap_dump_d); - if (execl(alert_program_name, alert_program_name, prog, ifname, ip_src_str, ether_shost_str, (char *) 0 ) < 0) { - report(LOG_ERR, "can't execute alert_program_name '%s': %s", alert_program_name, get_errmsg()); - exit(0); /* child exits */ - } - } - - } - + ilegalservers = 1; return; } @@ -878,7 +870,6 @@ /* Perform all necessary functions to handle a request to reconfigure. Must not be called until after initial configuration is complete. */ - int i; if (! read_configfile(config_file)) { @@ -886,14 +877,13 @@ cleanup(); exit(1); } - /* Contents of the packets we send may need to change as a result of change to the configuration. Free the packets we've already constructed, and build new ones. */ if (! init_libnet_context_queue()) { cleanup(); + exit(1); } - return; } @@ -985,7 +975,7 @@ cleanup(void) { /* Cleanup tasks at exit. */ - +report(LOG_INFO, "cleanup"); /* Destroy all the libnet contexts (if any), and the context queue (if any). */ libnet_cq_destroy(); @@ -1020,3 +1010,23 @@ return; } +void +set_timeout(pcap_t *pc) +{ + struct timeval timeout; + int time_wait; + + time_wait = GetResponse_wait_time(); + timeout.tv_sec = time_wait / 1000; + timeout.tv_usec = (time_wait % 1000) * 1000; + if(setsockopt(pcap_fileno(pc), SOL_SOCKET, SO_RCVTIMEO, + &timeout, sizeof(timeout)) < 0) { + report(LOG_ERR, + "set_timeout: Unable to set receive timeout: %s", + strerror(errno)); + cleanup(); + exit(1); + } + +} +