Distributed under the GPL
*/
+#define _DEFAULT_SOURCE
#include <stdint.h>
#include <stdio.h>
-#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
+#include <netinet/ip6.h>
#include <netdb.h>
-#include <sys/wait.h>
-#include <stdlib.h>
#include <arpa/inet.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <string.h>
#include <pcap/pcap.h>
-#include <netinet/ether.h>
-#include <netinet/ip6.h>
typedef unsigned long long Time;
Time connection_down_time;
} Monitor;
+typedef struct
+{
+ Monitor *monitor;
+ Time delay;
+ Time interval;
+ const char *command;
+ Time next;
+ pid_t child_pid;
+} Trigger;
+
typedef struct
{
const char *target_name;
int monitor_init(Monitor *);
void monitor_check(Monitor *, Time);
void capture_handler(uint8_t *, const struct pcap_pkthdr *, const uint8_t *);
+int trigger_init(Trigger *);
+void trigger_check(Trigger *, Time);
int get_inet_scope(uint32_t, const Address *);
int get_inet6_scope(const struct in6_addr *, const Address *);
int pinger_init(Pinger *);
int main(int argc, char **argv)
{
Monitor monitor;
+ Trigger trigger;
Pinger pinger;
int o;
char *endp;
Time stats_interval = 1800000000ULL;
- Time trigger_delay = 60000000ULL;
- Time trigger_interval = 600000000ULL;
- const char *trigger_cmd = NULL;
no_daemon = 0;
verbose = 0;
monitor.interface_name = NULL;
+ trigger.monitor = &monitor;
+ trigger.delay = 60000000ULL;
+ trigger.interval = 600000000ULL;
pinger.target_name = NULL;
/* Parse options */
stats_interval = strtoul(optarg, NULL, 10)*1000000;
break;
case 't':
- trigger_delay = strtoul(optarg, &endp, 10)*1000000;
+ trigger.delay = strtoul(optarg, &endp, 10)*1000000;
if(*endp==',')
- trigger_interval = strtoul(endp+1, NULL, 10)*1000000;
+ trigger.interval = strtoul(endp+1, NULL, 10)*1000000;
else
- trigger_interval = trigger_delay;
+ trigger.interval = trigger.delay;
break;
case 'c':
- trigger_cmd = optarg;
+ trigger.command = optarg;
break;
case 'i':
monitor.interface_name = strdup(optarg);
}
if(monitor.interface_name)
- monitor_init(&monitor);
+ {
+ if(monitor_init(&monitor))
+ return 1;
+
+ if(trigger.command)
+ if(trigger_init(&trigger))
+ return 1;
+ }
if(pinger.target_name)
- pinger_init(&pinger);
+ if(pinger_init(&pinger))
+ return 1;
if(!no_daemon && daemon(1, 0)==-1)
+ {
perror("daemon");
+ return 1;
+ }
openlog("netmon", 0, LOG_LOCAL7);
Time next_stats = current_time()+stats_interval;
- Time next_trigger = trigger_delay;
- pid_t child_pid = 0;
while(1)
{
Time time = current_time();
{
monitor_check(&monitor, time);
- if(monitor.connection_status)
- next_trigger = trigger_delay;
- else if(time>=monitor.last_receive+next_trigger)
- {
- if(no_daemon)
- printf("Running %s\n", trigger_cmd);
- else
- syslog(LOG_INFO, "Running %s", trigger_cmd);
- child_pid = run_command(trigger_cmd);
- next_trigger += trigger_interval;
- }
+ if(trigger.command)
+ trigger_check(&trigger, time);
}
if(pinger.target_name)
next_stats += stats_interval;
}
}
-
- /* Reap any finished child process */
- if(child_pid)
- {
- if(waitpid(child_pid, NULL, WNOHANG)==child_pid)
- child_pid = 0;
- }
}
closelog();
void capture_handler(uint8_t *user, const struct pcap_pkthdr *header, const uint8_t *data)
{
Monitor *monitor = (Monitor *)user;
- const struct ethhdr *eth = (const struct ethhdr *)(data);
+ const struct ether_header *eth = (const struct ether_header *)(data);
int src_scope = 0;
int dst_scope = 0;
- int proto = ntohs(eth->h_proto);
- if(proto==ETH_P_IP)
+ int proto = ntohs(eth->ether_type);
+ if(proto==ETHERTYPE_IP)
{
- const struct iphdr *ip = (const struct iphdr *)(eth+1);
- if(ntohl(ip->daddr)>>28==14)
+ const struct ip *ip = (const struct ip *)(eth+1);
+ if(ntohl(ip->ip_dst.s_addr)>>28==14)
dst_scope = 3;
for(unsigned i=0; i<monitor->n_addresses; ++i)
if(monitor->addresses[i].address.ss_family==AF_INET)
{
- int s = get_inet_scope(ip->saddr, &monitor->addresses[i]);
+ int s = get_inet_scope(ip->ip_src.s_addr, &monitor->addresses[i]);
if(s>src_scope)
src_scope = s;
- s = get_inet_scope(ip->daddr, &monitor->addresses[i]);
+ s = get_inet_scope(ip->ip_dst.s_addr, &monitor->addresses[i]);
if(s>dst_scope)
dst_scope = s;
}
}
- else if(proto==ETH_P_IPV6)
+ else if(proto==ETHERTYPE_IPV6)
{
const struct ip6_hdr *ip6 = (const struct ip6_hdr *)(eth+1);
for(unsigned i=0; i<monitor->n_addresses; ++i)
monitor->last_transmit = timestamp;
}
+int trigger_init(Trigger *trigger)
+{
+ trigger->next = trigger->delay;
+ trigger->child_pid = 0;
+
+ return 0;
+}
+
+void trigger_check(Trigger *trigger, Time time)
+{
+ Monitor *monitor = trigger->monitor;
+
+ if(monitor->connection_status)
+ trigger->next = trigger->delay;
+ else if(time>=monitor->last_receive+trigger->next)
+ {
+ if(no_daemon)
+ printf("Running %s\n", trigger->command);
+ else
+ syslog(LOG_INFO, "Running %s", trigger->command);
+ trigger->child_pid = run_command(trigger->command);
+ trigger->next += trigger->interval;
+ }
+
+ /* Reap any finished child process */
+ if(trigger->child_pid)
+ {
+ if(waitpid(trigger->child_pid, NULL, WNOHANG)==trigger->child_pid)
+ trigger->child_pid = 0;
+ }
+}
+
int get_inet_scope(uint32_t addr, const Address *local_addr)
{
uint32_t diff = addr^((struct sockaddr_in *)&local_addr->address)->sin_addr.s_addr;
pinger->socket = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
if(pinger->socket==-1)
{
- perror("socket");
+ perror("socket(SOCK_RAW)");
return -1;
}
fprintf(stderr, "recvfrom error: %s\n", strerror(errno));
else
{
- struct iphdr *ip = (struct iphdr *)data;
- if(ip->protocol==IPPROTO_ICMP)
+ struct ip *ip = (struct ip *)data;
+ if(ip->ip_p==IPPROTO_ICMP)
{
- struct icmphdr *icmp = (struct icmphdr *)(ip+1);
- if(icmp->type==ICMP_ECHOREPLY && icmp->un.echo.id==pinger->id)
+ struct icmp *icmp = (struct icmp *)(ip+1);
+ if(icmp->icmp_type==ICMP_ECHOREPLY && icmp->icmp_id==pinger->id)
{
/* It's an ICMP echo reply and ours, process it */
if(verbose)
printf("Ping reply from %s\n", buf);
}
- if(icmp->un.echo.sequence==pinger->pending)
+ if(icmp->icmp_seq==pinger->pending)
pinger->pending = 0;
else if(verbose)
- printf("Sequence %d, expected %d\n", icmp->un.echo.sequence, pinger->pending);
+ printf("Sequence %d, expected %d\n", icmp->icmp_seq, pinger->pending);
}
}
}
for(unsigned i=0; i<sizeof(data); ++i)
data[i] = i;
- struct icmphdr *hdr = (struct icmphdr *)data;
- hdr->type = ICMP_ECHO;
- hdr->code = 0;
- hdr->checksum = 0;
- hdr->un.echo.id = pinger->id;
- hdr->un.echo.sequence = pinger->seq;
- hdr->checksum = checksum(data, sizeof(data));
+ struct icmp *hdr = (struct icmp *)data;
+ hdr->icmp_type = ICMP_ECHO;
+ hdr->icmp_code = 0;
+ hdr->icmp_cksum = 0;
+ hdr->icmp_id = pinger->id;
+ hdr->icmp_seq = pinger->seq;
+ hdr->icmp_cksum = checksum(data, sizeof(data));
if(sendto(pinger->socket, data, sizeof(data), 0, (struct sockaddr *)&pinger->target_addr, sizeof(struct sockaddr_in))==-1)
fprintf(stderr, "sendto error: %s\n", strerror(errno));