X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=pl-poddoit.c;fp=pl-poddoit.c;h=20e72c26e5336f067e75aea5d8761778eeaca6ca;hb=93f0412887322c8f7f38ec71d6a57d5b3ddd9260;hp=0000000000000000000000000000000000000000;hpb=2df2fbe518d5a221ce6e3ee88a3fb23fb1b94b27;p=pingofdeath.git diff --git a/pl-poddoit.c b/pl-poddoit.c new file mode 100644 index 0000000..20e72c2 --- /dev/null +++ b/pl-poddoit.c @@ -0,0 +1,336 @@ +/* + * EMULAB-COPYRIGHT + * Copyright (c) 2000-2002 University of Utah and the Flux Group. + * All rights reserved. + */ + +/* + * Send the magical ping of death ICMP type + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPOD_ICMPTYPE 6 +#define IPOD_ICMPCODE 6 +#define IPOD_IPLEN 666 +#define IPOD_IDLEN 32 + +int icmpid = 0; +static char myid[IPOD_IDLEN]; +static int myidlen = 0; + +u_short in_cksum(u_short *addr, int len); +void icmpmap_init(); /* For getting information */ +void icmp_info(struct icmp *icmp, char *outbuf, int maxlen); + +/* + * We perform lookups on the hosts, and then store them in a chain + * here. + */ + +struct hostdesc { + char *hostname; + struct in_addr hostaddr; + struct hostdesc *next; +}; + +struct hostdesc *hostnames; +struct hostdesc *hosttail; + +/* + * Set up the list of hosts. Return the count. + */ + +int makehosts(char **hostlist) +{ + int i; + struct hostent *hp; + struct in_addr tmpaddr; + int hostcount = 0; + + for (i = 0; hostlist[i]; i++) { +#ifdef DEBUG + printf("Resolving %s\n", hostlist[i]); +#endif + if (!hostlist[i] || + !hostlist[i][0] || + strlen(hostlist[i]) > MAXHOSTNAMELEN) { + fprintf(stderr, "bad host entry, exiting\n"); + exit(-1); + } + if (!inet_aton(hostlist[i], &tmpaddr)) { + if ((hp = gethostbyname(hostlist[i])) == NULL) { + /* Could not resolve it. Skip it. */ + fprintf(stderr, "%s: unknown host\n", + hostlist[i]); + continue; + } + else { + memcpy(&tmpaddr.s_addr, + hp->h_addr_list[0], + hp->h_length); + } + } + + /* The host has been resolved. Put it in the chain */ + /* We want to stick it on the end. */ + if (hostnames == NULL) { + hostnames = (struct hostdesc *) + malloc(sizeof(*hostnames)); + if (hostnames == NULL) { + perror("hostnames malloc failed"); + exit(-1); + } + hosttail = hostnames; + } else { + hosttail->next = (struct hostdesc *) + malloc(sizeof(*hostnames)); + if (hosttail->next == NULL) { + perror("hosttail->next malloc failed"); + exit(-1); + } + hosttail = hosttail->next; + } + hosttail->hostname = strdup(hostlist[i]); + if (hosttail->hostname == NULL) { + perror("strdup failed"); + exit(-1); + } + hosttail->hostaddr = tmpaddr; + hosttail->next = NULL; + hostcount++; + } + return hostcount; +} + +void usage(char *prog) +{ + fprintf(stderr, "%s [ -i identityfile ] target [ target ... ]\n", prog); +} + +/* + * Set up a packet. Returns the length of the ICMP portion. + */ + +void initpacket(char *buf, int querytype, struct in_addr fromaddr) +{ + struct ip *ip = (struct ip *)buf; + struct icmp *icmp = (struct icmp *)(ip + 1); + + /* things we customize */ + int icmplen = 0; + + ip->ip_src = fromaddr; /* if 0, have kernel fill in */ + ip->ip_v = 4; /* Always use ipv4 for now */ + ip->ip_hl = sizeof *ip >> 2; + ip->ip_tos = 0; + ip->ip_id = htons(4321); + ip->ip_ttl = 255; + ip->ip_p = 1; + ip->ip_sum = 0; /* kernel fills in */ + + icmp->icmp_seq = 1; + icmp->icmp_cksum = 0; /* We'll compute it later. */ + icmp->icmp_type = querytype; + icmp->icmp_code = IPOD_ICMPCODE; + if (myidlen) + memcpy(icmp->icmp_data, myid, myidlen); + + ip->ip_len = IPOD_IPLEN; + icmplen = IPOD_IPLEN - sizeof(struct ip); + icmp->icmp_cksum = in_cksum((u_short *)icmp, icmplen); +} + +/* + * Send all of the ICMP queries. + */ + +void sendpings(int s, int querytype, struct hostdesc *head, int delay, + struct in_addr fromaddr) + +{ + char buf[1500]; + struct ip *ip = (struct ip *)buf; + struct sockaddr_in dst; + + bzero(buf, 1500); + initpacket(buf, querytype, fromaddr); + dst.sin_family = AF_INET; +#ifdef DA_HAS_SIN_LEN + dst.sin_len = sizeof(dst); +#endif + + while (head != NULL) { + int rc; +#ifdef DEBUG + printf("pinging %s\n", head->hostname); +#endif + ip->ip_dst.s_addr = head->hostaddr.s_addr; + dst.sin_addr = head->hostaddr; + rc = sendto(s, buf, ip->ip_len, 0, + (struct sockaddr *)&dst, + sizeof(dst)); + if (rc != ip->ip_len) { + perror("sendto"); + } + /* Don't flood small pipes. */ + if (delay) + usleep(delay); + head = head->next; + } +} + +/* + * Handles our timeout for us. Called by the signal handler + * when we get a SIGARLM. + */ + +void myexit(int whatsig) +{ + exit(0); +} + +/* + * Open a raw socket for receiving ICMP. Tell the kernel we want + * to supply the IP headers. + */ + +int get_icmp_socket() +{ + int s; + int on = 1; + if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) { + perror("socket"); + exit(1); + } + if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, + (const char *)&on, sizeof(on)) < 0) { + perror("IP_HDRINCL"); + exit(1); + } + return s; +} + +int +main(int argc, char **argv) +{ + int s; + + char *progname; + extern char *optarg; /* getopt variable declarations */ + extern int optind; + char ch; /* Holds the getopt result */ + int hostcount; + int delay = 0; + int querytype = ICMP_TSTAMP; + struct in_addr fromaddr; + int timeout = 5; /* Default to 5 seconds */ + int identityfile; + + fromaddr.s_addr = 0; + + progname = argv[0]; + + querytype = IPOD_ICMPTYPE; /* the magical death packet number */ + + while ((ch = getopt(argc, argv, "i:")) != -1) + switch(ch) + { + case 'i': + if (optarg[0] == '-') + identityfile = 0; + else if ((identityfile = open(optarg, 0)) < 0) + { + perror(optarg); + exit(1); + } + myidlen = read(identityfile, myid, IPOD_IDLEN); + if (optarg[0] != '-') + close(identityfile); + if (myidlen != IPOD_IDLEN) + { + fprintf(stderr, "%s: cannot read %d-byte identity\n", + optarg[0] != '-' ? optarg : "", IPOD_IDLEN); + exit(2); + } + break; + default: + usage(progname); + exit(-1); + } + + argc -= optind; + argv += optind; + if (!argv[0] || !strlen(argv[0])) + { + usage(progname); + exit(-1); + } + + hostcount = makehosts(argv); + + s = get_icmp_socket(); + + signal(SIGALRM, myexit); + alarm(timeout); + sendpings(s, querytype, hostnames, delay, fromaddr); + exit(0); +} + +/* + * in_cksum -- + * Checksum routine for Internet Protocol family headers (C Version) + * From FreeBSD's ping.c + */ + +u_short +in_cksum(addr, len) + u_short *addr; + int len; +{ + register int nleft = len; + register u_short *w = addr; + register int sum = 0; + u_short answer = 0; + + /* + * Our algorithm is simple, using a 32 bit accumulator (sum), we add + * sequential 16 bit words to it, and at the end, fold back all the + * carry bits from the top 16 bits into the lower 16 bits. + */ + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + + /* mop up an odd byte, if necessary */ + if (nleft == 1) { + *(u_char *)(&answer) = *(u_char *)w ; + sum += answer; + } + + /* add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return(answer); +} +