#include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE_BPF "/dev/bpf" static int verbose; static const char *out_net = "epair0a"; static const char *dest_net = NULL; struct ether_addr *daddr; #define PAYLOAD_LEN 64 union __attribute__((packed)) frame { struct { struct ether_header header; unsigned char payload[PAYLOAD_LEN]; } frame; unsigned char buffer[ETHER_MAX_LEN]; } out_buffer ; /* bpf */ int bpf = -1; static const char *fake_dest = "6:66:6:66:6:66"; #define VPRINTF(...) if(verbose) {printf(__VA_ARGS__);}; #define EPRINTF(...) do {fprintf(stderr, __VA_ARGS__); } while(0); static void __attribute__((__noreturn__)) usage(void) { fputs("\nUsage:\n", stderr); fputs("sockraw [--if iface][--mac maca[-to iface]][--packets samples][--verbose]\n", stderr); fputs(" --if : interface\n", stderr); fputs(" --mac : destination MAC address\n", stderr); fputs(" --to : destination MAC address from interface name\n", stderr); fputs(" --packets: packets samples to sent\n", stderr); fputs(" --verbose: verbose\n", stderr); exit(EXIT_SUCCESS); } /* open BPF interface * * Setup global variable bpf * * return pbf value on success, -1 on error */ static int get_first_bpf(void) { size_t i = 0; char buf[16] = {0}; for(; i < 99; ) { sprintf(buf, "%s%zu", DEVICE_BPF, i++); bpf = open(buf, O_RDWR); if (bpf != -1) break; /* must have root access*/ if (errno == EACCES) break; } return bpf; } /* * send packets * * @ifr: destination interface * @nb: packets number * */ static void sender(const struct ifreq *ifr, size_t nb) { static unsigned char dummy; size_t total = nb + 1; printf("Prepare to send %zu packets to %s.\n", nb, out_net); out_buffer.frame.header.ether_type = htons(PAYLOAD_LEN); memcpy(out_buffer.frame.header.ether_dhost, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN); while (nb) { memset(out_buffer.frame.payload, ++dummy, sizeof out_buffer.frame.payload); ssize_t r = write(bpf, out_buffer.buffer, sizeof out_buffer.frame.payload + sizeof(struct ether_header)); if (r == -1) warn("Unable to send packet #%zu.\n", nb); else VPRINTF("Packet #%zu sent.\n", total - nb); --nb; } printf("Done.\n"); } /* * Return MAC address * * @iface: Interface name * * @return -1 on error, 0 on success */ static int get_hwaddr(const char * restrict iface, struct ifreq * restrict dest_ifr) { int shw; int rc; strncpy(dest_ifr->ifr_name, iface, sizeof dest_ifr->ifr_name); dest_ifr->ifr_addr.sa_family = AF_LINK; if ((shw = socket(AF_INET, SOCK_RAW, 0)) < 0) { return -1; } rc = ioctl(shw, SIOCGHWADDR, dest_ifr); close(shw); if (rc) return -1; VPRINTF("Destination %s, HW address: %s.\n", iface, ether_ntoa((const struct ether_addr *)dest_ifr->ifr_addr.sa_data)); return 0; } int main(int argc, char *argv[]) { size_t packets = 10; struct ifreq out_if = {0}; const char *mac_address = fake_dest; struct ifreq dest_ifr = {0}; int rc; /* options */ int ch; static struct option longopts[] = { { "if" , required_argument, NULL, 'i' }, { "to" , required_argument, NULL, 't' }, { "verbose", no_argument , NULL, 'v' }, { "mac" , required_argument, NULL, 'm' }, { "packets", required_argument, NULL, 'p' }, { NULL, 0, NULL, 0 } }; while ((ch = getopt_long(argc, argv, "vi:t:p:m:", longopts, NULL)) != -1) { switch (ch) { case 'v': verbose = 1; break; case 't': dest_net = optarg; break; case 'i': out_net = optarg; break; case 'p': packets = strtoul(optarg, NULL, 10); break; case 'm': mac_address = optarg; break; case 0: /* long option */ break; default: usage(); } } if (argc - optind != 0) usage(); /* sanity checks */ daddr = ether_aton(mac_address); if (daddr == NULL) err(EXIT_FAILURE, "Cannot get mac destination"); if (strlcpy(out_if.ifr_name, out_net, sizeof(out_if.ifr_name)) >= sizeof(out_if.ifr_name)) errx(EXIT_FAILURE, "%s is not a valid interface name.\n", out_net); /* man 4 BPF */ if (get_first_bpf() < 0) err(EXIT_FAILURE, "Cannot open bpf interface"); /* Get net device index */ if (ioctl(bpf, BIOCSETIF, &out_if) == -1) { warn("Cannot open %s interface.\n", out_net); goto last; } rc = dest_net == NULL; if (!rc) rc = get_hwaddr(dest_net, &dest_ifr); if (rc) memcpy(dest_ifr.ifr_addr.sa_data, daddr, ETHER_ADDR_LEN); /* * pointless until we do not read _from_ interface * static int dummy_true = 1; * if( ioctl( bpf, BIOCIMMEDIATE, &dummy_true ) == -1 ) { * warn("Can not activate immediate mode.\n"); * } * if( ioctl( bpf, BIOCGBLEN, &buf_len ) == -1 ) { * warn("Can not request buffer length\n"); * exit(1); * } */ sender(&dest_ifr, packets); last: close(bpf); return EXIT_SUCCESS; }