|
|
@@ -0,0 +1,170 @@
|
|
|
+#include <netinet/in.h>
|
|
|
+#include <net/if.h>
|
|
|
+#include <net/ethernet.h>
|
|
|
+#include <net/bpf.h>
|
|
|
+#include <sys/ioctl.h>
|
|
|
+#include <string.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <getopt.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <err.h>
|
|
|
+
|
|
|
+#define DEVICE_BPF "/dev/bpf"
|
|
|
+static int verbose;
|
|
|
+static const char *out_net = "tap0";
|
|
|
+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 net][--mac mac][--packets samples][--verbose]\n", stderr);
|
|
|
+ fputs(" --if : interface\n", stderr);
|
|
|
+ fputs(" --mac : destination MAC address\n", stderr);
|
|
|
+ fputs(" --packets: packets samples to sent\n", stderr);
|
|
|
+ fputs(" --verbose: verbose\n", stderr);
|
|
|
+ exit(EXIT_SUCCESS);
|
|
|
+}
|
|
|
+
|
|
|
+/* open BPF interface */
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
+static void sender(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, daddr, 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");
|
|
|
+}
|
|
|
+
|
|
|
+int main(int argc, char *argv[])
|
|
|
+{
|
|
|
+ size_t packets = 10;
|
|
|
+ struct ifreq out_if = {0};
|
|
|
+ const char *mac_address = fake_dest;
|
|
|
+
|
|
|
+ /* options */
|
|
|
+ int ch;
|
|
|
+ static struct option longopts[] = {
|
|
|
+ { "if" , required_argument, NULL, 'i' },
|
|
|
+ { "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:o:p:m:", longopts, NULL)) != -1) {
|
|
|
+ switch (ch) {
|
|
|
+ case 'v':
|
|
|
+ verbose = 1;
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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(packets);
|
|
|
+
|
|
|
+last:
|
|
|
+ close(bpf);
|
|
|
+
|
|
|
+ return EXIT_SUCCESS;
|
|
|
+}
|
|
|
+
|