2 netmon - a simple network connectivity monitor
3 Copyright © 2008 Mikko Rasa, Mikkosoft Productions
4 Distributed under the GPL
13 #include <netinet/ip_icmp.h>
18 unsigned checksum(const char *, unsigned);
19 void send_ping(in_addr_t, uint16_t);
20 pid_t run_command(const char *);
25 int main(int argc, char **argv)
27 const char *target_name = "google.com";
28 struct hostent *target_host;
35 unsigned max_streak = 0;
36 unsigned next_stats = 0;
40 unsigned stats_interval = 1800;
41 unsigned trigger_count = 900;
42 const char *trigger_cmd = NULL;
43 unsigned next_trigger;
47 while((o = getopt(argc, argv, "fvi:t:c:"))!=-1)
57 stats_interval = strtoul(optarg, NULL, 10);
60 trigger_count = strtoul(optarg, NULL, 10);
67 /* Take target hostname from commandline if specified */
69 target_name = argv[optind];
71 target_host = gethostbyname(target_name);
74 herror("gethostbyname");
78 if(target_host->h_addrtype!=AF_INET)
80 fprintf(stderr, "Got a hostent, but it doesn't have an IPv4 address");
83 target = ntohl(*(in_addr_t *)*target_host->h_addr_list);
86 printf("Target is %s\n", inet_ntoa(htonl(target)));
88 /* Miscellaneous initialization */
90 sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
100 if(!no_daemon && daemon(1, 0)==-1)
103 openlog("netmon", 0, LOG_LOCAL7);
105 next_trigger = trigger_count;
111 gettimeofday(&tv, NULL);
113 /* Send stats to syslog every stats_interval seconds */
114 if(tv.tv_sec>next_stats)
119 printf("Lost %d, max streak %d\n", lost, max_streak);
121 syslog(LOG_INFO, "Lost %d, max streak %d", lost, max_streak);
125 next_stats = tv.tv_sec+stats_interval;
130 if(waitpid(child_pid, NULL, WNOHANG)==child_pid)
134 res = poll(&pfd, 1, 1000);
137 struct sockaddr_in addr;
138 socklen_t alen = sizeof(addr);
142 struct icmphdr *icmp;
144 /* Receive a packet */
145 len = recvfrom(sock, data, sizeof(data), 0, (struct sockaddr *)&addr, &alen);
147 fprintf(stderr, "recvfrom error: %s\n", strerror(errno));
150 ip = (struct iphdr *)data;
151 if(ip->protocol==IPPROTO_ICMP)
153 icmp = (struct icmphdr *)(ip+1);
154 if(icmp->type==ICMP_ECHOREPLY && icmp->un.echo.id==pid)
156 /* It's an ICMP echo reply and ours, process it */
158 printf("Ping reply from %s\n", inet_ntoa(addr.sin_addr.s_addr));
159 if(icmp->un.echo.sequence==pending)
163 next_trigger = trigger_count;
166 printf("Sequence %d, expected %d\n", icmp->un.echo.sequence, pending);
173 /* Poll timed out, check for lost ping and send more */
177 printf("Lost ping\n");
180 if(streak>max_streak)
182 if(streak>=next_trigger && trigger_cmd && !child_pid)
185 printf("Running %s\n", trigger_cmd);
187 syslog(LOG_INFO, "Running %s\n", trigger_cmd);
188 child_pid = run_command(trigger_cmd);
189 next_trigger += trigger_count;
192 send_ping(target, seq);
204 unsigned checksum(const char *data, unsigned len)
209 for(i=0; i<len; i+=2)
210 sum += *(const unsigned short *)(data+i);
212 sum = (sum>>16)+(sum&0xFFFF);
217 void send_ping(in_addr_t target, uint16_t seq)
222 struct sockaddr_in addr;
224 for(i=0; i<sizeof(data); ++i)
227 hdr = (struct icmphdr *)data;
228 hdr->type = ICMP_ECHO;
231 hdr->un.echo.id = pid;
232 hdr->un.echo.sequence = seq;
233 hdr->checksum = checksum(data, sizeof(data));
235 addr.sin_family = AF_INET;
236 addr.sin_addr.s_addr = htonl(target);
239 if(sendto(sock, data, sizeof(data), 0, (struct sockaddr *)&addr, sizeof(addr))==-1)
240 fprintf(stderr, "sendto error: %s\n", strerror(errno));
243 pid_t run_command(const char *cmd)