3 * Copyright (c) 2000-2002 University of Utah and the Flux Group.
8 * Send the magical ping of death ICMP type
17 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/in_systm.h>
24 #include <netinet/ip.h>
25 #include <netinet/ip_icmp.h>
29 #include <arpa/inet.h>
31 #define IPOD_ICMPTYPE 6
32 #define IPOD_ICMPCODE 6
33 #define IPOD_IPLEN 666
37 static char myid[IPOD_IDLEN];
38 static int myidlen = 0;
40 u_short in_cksum(u_short *addr, int len);
41 void icmpmap_init(); /* For getting information */
42 void icmp_info(struct icmp *icmp, char *outbuf, int maxlen);
45 * We perform lookups on the hosts, and then store them in a chain
51 struct in_addr hostaddr;
52 struct hostdesc *next;
55 struct hostdesc *hostnames;
56 struct hostdesc *hosttail;
59 * Set up the list of hosts. Return the count.
62 int makehosts(char **hostlist)
66 struct in_addr tmpaddr;
69 for (i = 0; hostlist[i]; i++) {
71 printf("Resolving %s\n", hostlist[i]);
75 strlen(hostlist[i]) > MAXHOSTNAMELEN) {
76 fprintf(stderr, "bad host entry, exiting\n");
79 if (!inet_aton(hostlist[i], &tmpaddr)) {
80 if ((hp = gethostbyname(hostlist[i])) == NULL) {
81 /* Could not resolve it. Skip it. */
82 fprintf(stderr, "%s: unknown host\n",
87 memcpy(&tmpaddr.s_addr,
93 /* The host has been resolved. Put it in the chain */
94 /* We want to stick it on the end. */
95 if (hostnames == NULL) {
96 hostnames = (struct hostdesc *)
97 malloc(sizeof(*hostnames));
98 if (hostnames == NULL) {
99 perror("hostnames malloc failed");
102 hosttail = hostnames;
104 hosttail->next = (struct hostdesc *)
105 malloc(sizeof(*hostnames));
106 if (hosttail->next == NULL) {
107 perror("hosttail->next malloc failed");
110 hosttail = hosttail->next;
112 hosttail->hostname = strdup(hostlist[i]);
113 if (hosttail->hostname == NULL) {
114 perror("strdup failed");
117 hosttail->hostaddr = tmpaddr;
118 hosttail->next = NULL;
124 void usage(char *prog)
126 fprintf(stderr, "%s [ -i identityfile ] target [ target ... ]\n", prog);
130 * Set up a packet. Returns the length of the ICMP portion.
133 void initpacket(char *buf, int querytype, struct in_addr fromaddr)
135 struct ip *ip = (struct ip *)buf;
136 struct icmp *icmp = (struct icmp *)(ip + 1);
138 /* things we customize */
141 ip->ip_src = fromaddr; /* if 0, have kernel fill in */
142 ip->ip_v = 4; /* Always use ipv4 for now */
143 ip->ip_hl = sizeof *ip >> 2;
145 ip->ip_id = htons(4321);
148 ip->ip_sum = 0; /* kernel fills in */
151 icmp->icmp_cksum = 0; /* We'll compute it later. */
152 icmp->icmp_type = querytype;
153 icmp->icmp_code = IPOD_ICMPCODE;
155 memcpy(icmp->icmp_data, myid, myidlen);
157 ip->ip_len = IPOD_IPLEN;
158 icmplen = IPOD_IPLEN - sizeof(struct ip);
159 icmp->icmp_cksum = in_cksum((u_short *)icmp, icmplen);
163 * Send all of the ICMP queries.
166 void sendpings(int s, int querytype, struct hostdesc *head, int delay,
167 struct in_addr fromaddr)
171 struct ip *ip = (struct ip *)buf;
172 struct sockaddr_in dst;
175 initpacket(buf, querytype, fromaddr);
176 dst.sin_family = AF_INET;
177 #ifdef DA_HAS_SIN_LEN
178 dst.sin_len = sizeof(dst);
181 while (head != NULL) {
184 printf("pinging %s\n", head->hostname);
186 ip->ip_dst.s_addr = head->hostaddr.s_addr;
187 dst.sin_addr = head->hostaddr;
188 rc = sendto(s, buf, ip->ip_len, 0,
189 (struct sockaddr *)&dst,
191 if (rc != ip->ip_len) {
194 /* Don't flood small pipes. */
202 * Handles our timeout for us. Called by the signal handler
203 * when we get a SIGARLM.
206 void myexit(int whatsig)
212 * Open a raw socket for receiving ICMP. Tell the kernel we want
213 * to supply the IP headers.
216 int get_icmp_socket()
220 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
224 if (setsockopt(s, IPPROTO_IP, IP_HDRINCL,
225 (const char *)&on, sizeof(on)) < 0) {
226 perror("IP_HDRINCL");
233 main(int argc, char **argv)
238 extern char *optarg; /* getopt variable declarations */
240 char ch; /* Holds the getopt result */
243 int querytype = ICMP_TSTAMP;
244 struct in_addr fromaddr;
245 int timeout = 5; /* Default to 5 seconds */
252 querytype = IPOD_ICMPTYPE; /* the magical death packet number */
254 while ((ch = getopt(argc, argv, "i:")) != -1)
258 if (optarg[0] == '-')
260 else if ((identityfile = open(optarg, 0)) < 0)
265 myidlen = read(identityfile, myid, IPOD_IDLEN);
266 if (optarg[0] != '-')
268 if (myidlen != IPOD_IDLEN)
270 fprintf(stderr, "%s: cannot read %d-byte identity\n",
271 optarg[0] != '-' ? optarg : "<stdin>", IPOD_IDLEN);
282 if (!argv[0] || !strlen(argv[0]))
288 hostcount = makehosts(argv);
290 s = get_icmp_socket();
292 signal(SIGALRM, myexit);
294 sendpings(s, querytype, hostnames, delay, fromaddr);
300 * Checksum routine for Internet Protocol family headers (C Version)
301 * From FreeBSD's ping.c
309 register int nleft = len;
310 register u_short *w = addr;
311 register int sum = 0;
315 * Our algorithm is simple, using a 32 bit accumulator (sum), we add
316 * sequential 16 bit words to it, and at the end, fold back all the
317 * carry bits from the top 16 bits into the lower 16 bits.
324 /* mop up an odd byte, if necessary */
326 *(u_char *)(&answer) = *(u_char *)w ;
330 /* add back carry outs from top 16 bits to low 16 bits */
331 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
332 sum += (sum >> 16); /* add carry */
333 answer = ~sum; /* truncate to 16 bits */