#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <netinet/in.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <arpa/inet.h> #include <net/if.h> #include <stdbool.h> #include <errno.h> static void usage (void) { fprintf(stderr, "Usage: health_check" " -d debug" " -I interface" "\n"); exit(2); } int main (int argc, char **argv) { int sd, ch; uint8_t *opt, *pkt; struct ifreq ifr; char *interface = NULL; bool debug = false; while ((ch = getopt(argc, argv, "h?" "I:" "d")) != EOF) { switch(ch) { case 'I': interface = optarg; break; case 'd': debug = true; break; default: usage(); break; } } argc -= optind; argv += optind; if (!interface) usage(); /* Request a socket descriptor sd. */ if ((sd = socket (AF_INET6, SOCK_RAW, IPPROTO_IPIP)) < 0) { perror ("Failed to get socket descriptor "); exit (EXIT_FAILURE); } memset(&ifr, 0, sizeof(ifr)); snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface); /* Bind socket to interface of this node. */ if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, (void *) &ifr, sizeof (ifr)) < 0) { perror ("SO_BINDTODEVICE failed"); exit (EXIT_FAILURE); } if (debug) printf("Binding to interface %s\n", interface); while (1) { struct sockaddr_in6 src_addr; socklen_t addrlen = sizeof(src_addr); char source[INET6_ADDRSTRLEN+1]; int len; uint8_t inpack[IP_MAXPACKET]; if ((len = recvfrom(sd, inpack, sizeof(inpack), 0, (struct sockaddr *)&src_addr, &addrlen)) < 0) { perror("recvfrom failed "); } if (inet_ntop(AF_INET6, &src_addr.sin6_addr, source, INET6_ADDRSTRLEN) == NULL) { perror("inet_ntop() failed."); exit(EXIT_FAILURE); } /* Reply */ struct iphdr *ip = (struct iphdr *)inpack; uint32_t saddr; struct icmphdr *icmp; saddr = ip->saddr; ip->saddr = ip->daddr; ip->daddr = saddr; switch (ip->protocol) { case 1: if (debug) printf ("ICMP Echo request from %s\n", source); icmp = (struct icmphdr *)&ip[1]; icmp->type = ICMP_ECHOREPLY; break; default: fprintf(stderr, "Unsupported protocol %d", ip->protocol); } if (len = sendto(sd, inpack, len, 0, (struct sockaddr *)&src_addr, addrlen) < 0) { perror("sendto failed "); } } close (sd); return (EXIT_SUCCESS); }