int ether_wake_main(int argc UNUSED_PARAM, char **argv) { const char *ifname = "eth0"; char *pass; unsigned flags; unsigned char wol_passwd[6]; int wol_passwd_sz = 0; int s; /* Raw socket */ int pktsize; unsigned char outpack[1000]; struct ether_addr eaddr; struct whereto_t whereto; /* who to wake up */ /* handle misc user options */ opt_complementary = "=1"; flags = getopt32(argv, "bi:p:", &ifname, &pass); if (flags & 4) /* -p */ wol_passwd_sz = get_wol_pw(pass, wol_passwd); flags &= 1; /* we further interested only in -b [bcast] flag */ /* create the raw socket */ s = make_socket(); /* now that we have a raw socket we can drop root */ /* xsetuid(getuid()); - but save on code size... */ /* look up the dest mac address */ get_dest_addr(argv[optind], &eaddr); /* fill out the header of the packet */ pktsize = get_fill(outpack, &eaddr, flags /* & 1 OPT_BROADCAST */); bb_debug_dump_packet(outpack, pktsize); /* Fill in the source address, if possible. */ #ifdef __linux__ { struct ifreq if_hwaddr; strncpy_IFNAMSIZ(if_hwaddr.ifr_name, ifname); ioctl_or_perror_and_die(s, SIOCGIFHWADDR, &if_hwaddr, "SIOCGIFHWADDR on %s failed", ifname); memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6); # ifdef DEBUG { unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; printf("The hardware address (SIOCGIFHWADDR) of %s is type %d " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n", ifname, if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); } # endif } #endif /* __linux__ */ bb_debug_dump_packet(outpack, pktsize); /* append the password if specified */ if (wol_passwd_sz > 0) { memcpy(outpack+pktsize, wol_passwd, wol_passwd_sz); pktsize += wol_passwd_sz; } bb_debug_dump_packet(outpack, pktsize); /* This is necessary for broadcasts to work */ if (flags /* & 1 OPT_BROADCAST */) { if (setsockopt_broadcast(s) != 0) bb_perror_msg("SO_BROADCAST"); } #if defined(PF_PACKET) { struct ifreq ifr; strncpy_IFNAMSIZ(ifr.ifr_name, ifname); xioctl(s, SIOCGIFINDEX, &ifr); memset(&whereto, 0, sizeof(whereto)); whereto.sll_family = AF_PACKET; whereto.sll_ifindex = ifr.ifr_ifindex; /* The manual page incorrectly claims the address must be filled. We do so because the code may change to match the docs. */ whereto.sll_halen = ETH_ALEN; memcpy(whereto.sll_addr, outpack, ETH_ALEN); } #else whereto.sa_family = 0; strcpy(whereto.sa_data, ifname); #endif xsendto(s, outpack, pktsize, (struct sockaddr *)&whereto, sizeof(whereto)); if (ENABLE_FEATURE_CLEAN_UP) close(s); return EXIT_SUCCESS; }
int ether_wake_main(int argc, char *argv[]) { const char *ifname = "eth0"; char *pass = NULL; unsigned long flags; unsigned char wol_passwd[6]; int wol_passwd_sz = 0; int s; /* Raw socket */ int pktsize; unsigned char outpack[1000]; struct ether_addr eaddr; struct whereto_t whereto; /* who to wake up */ /* handle misc user options */ flags = getopt32(argc, argv, "bi:p:", &ifname, &pass); if (optind == argc) bb_show_usage(); if (pass) wol_passwd_sz = get_wol_pw(pass, wol_passwd); /* create the raw socket */ s = make_socket(); /* now that we have a raw socket we can drop root */ xsetuid(getuid()); /* look up the dest mac address */ get_dest_addr(argv[optind], &eaddr); /* fill out the header of the packet */ pktsize = get_fill(outpack, &eaddr, flags /*& 1 [OPT_BROADCAST]*/); bb_debug_dump_packet(outpack, pktsize); /* Fill in the source address, if possible. */ #ifdef __linux__ { struct ifreq if_hwaddr; strncpy(if_hwaddr.ifr_name, ifname, sizeof(if_hwaddr.ifr_name)); if (ioctl(s, SIOCGIFHWADDR, &if_hwaddr) < 0) bb_perror_msg_and_die("SIOCGIFHWADDR on %s failed", ifname); memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6); # ifdef DEBUG { unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; printf("The hardware address (SIOCGIFHWADDR) of %s is type %d " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n", ifname, if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); } # endif } #endif /* __linux__ */ bb_debug_dump_packet(outpack, pktsize); /* append the password if specified */ if (wol_passwd_sz > 0) { memcpy(outpack+pktsize, wol_passwd, wol_passwd_sz); pktsize += wol_passwd_sz; } bb_debug_dump_packet(outpack, pktsize); /* This is necessary for broadcasts to work */ if (flags /*& 1 [OPT_BROADCAST]*/) { if (setsockopt_broadcast(s) < 0) bb_perror_msg("SO_BROADCAST"); } #if defined(PF_PACKET) { struct ifreq ifr; strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) bb_perror_msg_and_die("SIOCGIFINDEX"); memset(&whereto, 0, sizeof(whereto)); whereto.sll_family = AF_PACKET; whereto.sll_ifindex = ifr.ifr_ifindex; /* The manual page incorrectly claims the address must be filled. We do so because the code may change to match the docs. */ whereto.sll_halen = ETH_ALEN; memcpy(whereto.sll_addr, outpack, ETH_ALEN); } #else whereto.sa_family = 0; strcpy(whereto.sa_data, ifname); #endif if (sendto(s, outpack, pktsize, 0, (struct sockaddr *)&whereto, sizeof(whereto)) < 0) bb_perror_msg(bb_msg_write_error); close(s); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { char *ifname = "eth0"; int one = 1; /* True, for socket options. */ int s; /* Raw socket */ int errflag = 0, verbose = 0, do_version = 0; int perm_failure = 0; int i, c, pktsize; #if defined(PF_PACKET) struct sockaddr_ll whereto; #else struct sockaddr whereto; /* who to wake up */ #endif struct ether_addr eaddr; while ((c = getopt(argc, argv, "bDi:p:uvV")) != -1) switch (c) { case 'b': opt_broadcast++; break; case 'D': debug++; break; case 'i': ifname = optarg; break; case 'p': get_wol_pw(optarg); break; case 'u': printf(usage_msg); return 0; case 'v': verbose++; break; case 'V': do_version++; break; case '?': errflag++; } if (verbose || do_version) printf("%s\n", version_msg); if (errflag) { fprintf(stderr, brief_usage_msg); return 3; } if (optind == argc) { fprintf(stderr, "Specify the Ethernet address as 00:11:22:33:44:55.\n"); return 3; } /* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to work as non-root, but we need SOCK_PACKET to specify the Ethernet destination address. */ #if defined(PF_PACKET) s = socket(PF_PACKET, SOCK_RAW, 0); #else s = socket(AF_INET, SOCK_PACKET, SOCK_PACKET); #endif if (s < 0) { if (errno == EPERM) fprintf(stderr, "ether-wake: This program must be run as root.\n"); else perror("ether-wake: socket"); perm_failure++; } /* Don't revert if debugging allows a normal user to get the raw socket. */ setuid(getuid()); /* We look up the station address before reporting failure so that errors may be reported even when run as a normal user. */ if (get_dest_addr(argv[optind], &eaddr) != 0) return 3; if (perm_failure && ! debug) return 2; pktsize = get_fill(outpack, &eaddr); /* Fill in the source address, if possible. The code to retrieve the local station address is Linux specific. */ if (! opt_no_src_addr) { struct ifreq if_hwaddr; char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; strcpy(if_hwaddr.ifr_name, ifname); if (ioctl(s, SIOCGIFHWADDR, &if_hwaddr) < 0) { fprintf(stderr, "SIOCGIFHWADDR on %s failed: %s\n", ifname, strerror(errno)); /* Magic packets still work if our source address is bogus, but we fail just to be anal. */ return 1; } memcpy(outpack+6, if_hwaddr.ifr_hwaddr.sa_data, 6); if (verbose) { printf("The hardware address (SIOCGIFHWADDR) of %s is type %d " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", ifname, if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); } } if (wol_passwd_sz > 0) { memcpy(outpack+pktsize, wol_passwd, wol_passwd_sz); pktsize += wol_passwd_sz; } if (verbose > 1) { printf("The final packet is: "); for (i = 0; i < pktsize; i++) printf(" %2.2x", outpack[i]); printf(".\n"); } /* This is necessary for broadcasts to work */ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof(one)) < 0) perror("setsockopt: SO_BROADCAST"); #if defined(PF_PACKET) { struct ifreq ifr; strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) { fprintf(stderr, "SIOCGIFINDEX on %s failed: %s\n", ifname, strerror(errno)); return 1; } memset(&whereto, 0, sizeof(whereto)); whereto.sll_family = AF_PACKET; whereto.sll_ifindex = ifr.ifr_ifindex; /* The manual page incorrectly claims the address must be filled. We do so because the code may change to match the docs. */ whereto.sll_halen = ETH_ALEN; memcpy(whereto.sll_addr, outpack, ETH_ALEN); } #else whereto.sa_family = 0; strcpy(whereto.sa_data, ifname); #endif if ((i = sendto(s, outpack, pktsize, 0, (struct sockaddr *)&whereto, sizeof(whereto))) < 0) perror("sendto"); else if (debug) printf("Sendto worked ! %d.\n", i); #ifdef USE_SEND if (bind(s, (struct sockaddr *)&whereto, sizeof(whereto)) < 0) perror("bind"); else if (send(s, outpack, 100, 0) < 0) perror("send"); #endif #ifdef USE_SENDMSG { struct msghdr msghdr = { 0,}; struct iovec iovector[1]; msghdr.msg_name = &whereto; msghdr.msg_namelen = sizeof(whereto); msghdr.msg_iov = iovector; msghdr.msg_iovlen = 1; iovector[0].iov_base = outpack; iovector[0].iov_len = pktsize; if ((i = sendmsg(s, &msghdr, 0)) < 0) perror("sendmsg"); else if (debug) printf("sendmsg worked, %d (%d).\n", i, errno); } #endif return 0; }