diff --git a/GNUmakefile.in b/GNUmakefile.in index 763d74fb590840e52373acdcf5ae360f6ad3d981..a4f1944278cbffb0b19c27ea8d75a60346c4b59b 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -23,7 +23,7 @@ include Makeconf # SUBDIRS = lib db assign www @optional_subdirs@ ipod security sensors \ pxe tbsetup account tmcd utils tip capture ipod vis \ - sensors os xmlrpc install/newnode_sshkeys mote + sensors os xmlrpc install/newnode_sshkeys mote tools/whol all: all-subdirs diff --git a/configure b/configure index 56dad3eff6ea39b30f47651e8f0361f852c0f502..5e0714abe4bf0818d008dfa037e782caacc2db91 100755 --- a/configure +++ b/configure @@ -2239,7 +2239,7 @@ outfiles="$outfiles Makeconf GNUmakefile \ rc.d/2.elvind.sh rc.d/3.plab.sh rc.d/2.dhcpd.sh \ tools/GNUmakefile \ tools/pcapper/GNUmakefile tools/teachswitch/GNUmakefile \ - tools/webcamapplet/GNUmakefile \ + tools/webcamapplet/GNUmakefile tools/whol/GNUmakefile \ $eventfiles \ $winfiles \ apache/GNUmakefile apache/httpd.conf \ diff --git a/configure.in b/configure.in index bd692a8bf8e5560732d876bee6ff3952ceb88600..07f06306322e35a5d1618459405026e3c8174d42 100755 --- a/configure.in +++ b/configure.in @@ -734,7 +734,7 @@ outfiles="$outfiles Makeconf GNUmakefile \ rc.d/2.elvind.sh rc.d/3.plab.sh rc.d/2.dhcpd.sh \ tools/GNUmakefile \ tools/pcapper/GNUmakefile tools/teachswitch/GNUmakefile \ - tools/webcamapplet/GNUmakefile \ + tools/webcamapplet/GNUmakefile tools/whol/GNUmakefile \ $eventfiles \ $winfiles \ apache/GNUmakefile apache/httpd.conf \ diff --git a/tools/GNUmakefile.in b/tools/GNUmakefile.in index c18ebe5c2d4c1c652491c642b663d3fdce02319e..dc27801df8781b0ba13b1a93d7314fa06d4e1bcc 100644 --- a/tools/GNUmakefile.in +++ b/tools/GNUmakefile.in @@ -11,7 +11,7 @@ SUBDIR = tools include $(OBJDIR)/Makeconf -SUBDIRS = pcapper teachswitch webcamapplet +SUBDIRS = pcapper teachswitch webcamapplet whol all: all-subdirs diff --git a/tools/whol/GNUmakefile.in b/tools/whol/GNUmakefile.in new file mode 100644 index 0000000000000000000000000000000000000000..dd964f9b35a3998f29915f8c7933f5d42b0d9485 --- /dev/null +++ b/tools/whol/GNUmakefile.in @@ -0,0 +1,29 @@ +# +# EMULAB-COPYRIGHT +# Copyright (c) 2005 University of Utah and the Flux Group. +# All rights reserved. +# + +SRCDIR = @srcdir@ +TESTBED_SRCDIR = @top_srcdir@ +OBJDIR = ../.. +SUBDIR = tools/whol + +include $(OBJDIR)/Makeconf + +all: whol + +include $(TESTBED_SRCDIR)/GNUmakerules + +whol: GNUmakefile whol.o + $(CC) $(CFLAGS) $(LDFLAGS) whol.o -o whol + cp whol whol.debug + strip whol + +whol.o: whol.c + $(CC) -c -o whol.o $(CFLAGS) $< + +install: $(INSTALL_SBINDIR)/whol + +clean: + rm -f *.o core whol whol.debug diff --git a/tools/whol/whol.c b/tools/whol/whol.c new file mode 100644 index 0000000000000000000000000000000000000000..8b075f0e40a6b2e593e7962e902c8953f27741b2 --- /dev/null +++ b/tools/whol/whol.c @@ -0,0 +1,214 @@ +/* + * EMULAB-COPYRIGHT + * Copyright (c) 2005 University of Utah and the Flux Group. + * + * whol.c - Send a 'whack on LAN' packet to node + */ + +#include <stdio.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <net/bpf.h> + +#include <sys/socket.h> +#include <net/if.h> +#include <net/ethernet.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/udp.h> + +u_short in_cksum(u_short *addr, int len); + +const int MAX_BPFNUM = 16; + +const int packet_len = 666; + +int main(int argc, char **argv) { + int bpfnum; + int bpffd; + struct ifreq req; + void *buf; + ssize_t written; + int i,j,length; + struct ether_header *eheader; + struct ip *ip; + struct udphdr *udp; + char *pbody; + char *victim; + char *iface; + u_char dst_mac[6]; + + /* + * Handle command line args + */ + if (argc != 3) { + fprintf(stderr,"Usage: whol <dst_address> <interface>\n"); + fprintf(stderr,"dst_addr: A MAC address in hex, without puncuation\n"); + fprintf(stderr,"interface: Name of the interface to send packet on\n"); + exit(1); + } + + victim = argv[1]; + iface = argv[2]; + + /* + * Convert the victim MAC address from ASCII into bytes + */ + if (strlen(victim) != 12) { + fprintf(stderr,"Bad format for MAC address\n"); + exit(1); + } + for (i = 0; i < 6; i++) { + char digits[3]; + unsigned int tmp; + strncpy(digits, victim + (i*2),3); /* Copy in two digits */ + digits[2] = '\0'; /* Null-terminate */ + if (sscanf(digits,"%x",&tmp) != 1) { + printf("Bad hex value in dst_addr: %s\n",digits); + exit(1); + } + dst_mac[i] = tmp; + } + + /* + * Find and open a BPF device to send the packet on + */ + for (bpfnum = 0; bpfnum < MAX_BPFNUM; bpfnum++) { + char bpfpath[1024]; + sprintf(bpfpath,"/dev/bpf%i",bpfnum); + bpffd = open(bpfpath,O_WRONLY); + if (bpffd >= 0) { + break; + } + } + + if (bpffd < 0) { + fprintf(stderr,"Failed to find an open-able BPF device\n"); + exit(1); + } + + /* + * Attach it to the correct interface + */ + strcpy(req.ifr_name,iface); + + if (ioctl(bpffd,BIOCSETIF,&req) < 0) { + perror("BIOSETIF failed"); + exit(1); + } + + /* + * Build up a packet ourselves + */ + buf = (void*)malloc(packet_len); + bzero(buf,packet_len); + + eheader = buf; + ip = buf + ETHER_HDR_LEN; + udp = buf + ETHER_HDR_LEN + sizeof(*ip); + pbody = buf + ETHER_HDR_LEN + sizeof(*ip) + sizeof(*udp); + + /* + * Fill in the destination MAC, and make it look like an IP packet so that + * the switch will deliver it. + */ + for (i = 0; i < ETHER_ADDR_LEN; i++) { + eheader->ether_dhost[i] = dst_mac[i]; + } + eheader->ether_type = htons(ETHERTYPE_IP); + + /* Note: The NIC will fill in the src MAC automagically */ + + /* + * Make an IP header + */ + ip->ip_hl = (sizeof *ip >> 2); + ip->ip_v = 4; + ip->ip_tos = 0; + ip->ip_len = htons(packet_len - ETHER_HDR_LEN); + ip->ip_id = 0; + ip->ip_off = 0; + ip->ip_ttl = 1; + ip->ip_p = 17; /* UDP, really oughta use getprotobyname */ + ip->ip_src.s_addr = 0xffffffff; + ip->ip_dst.s_addr = 0xffffffff; + ip->ip_sum = in_cksum((u_short *)ip,sizeof(*ip)); + + /* + * Make a UDP header + */ + udp->uh_sport = 0; + udp->uh_dport = 0; + udp->uh_ulen = htons(packet_len - ETHER_HDR_LEN - sizeof(*ip) - sizeof(*udp)); + udp->uh_sum = 0; + + /* + * Put in the magic juice that maekes the victim reboot - 6 bytes of 1s, + * then 16 repititions of the victim's MAC address + */ + length = 0; + for (i = 0; i < 6; i++) { + pbody[length++] = (char)0xff; + } + + for (i = 0; i < 16; i++) { + for (j = 0; j < 6; j++) { + pbody[length++] = dst_mac[j]; + } + } + + /* + * Whack away! + */ + printf("Whack!\n"); + written = write(bpffd,buf,packet_len); + if (written < 0) { + perror("Write failed"); + } + + 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); +}