sockbpf.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include <netinet/in.h>
  2. #include <net/if.h>
  3. #include <net/ethernet.h>
  4. #include <net/bpf.h>
  5. #include <sys/ioctl.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <getopt.h>
  11. #include <fcntl.h>
  12. #include <errno.h>
  13. #include <err.h>
  14. #define DEVICE_BPF "/dev/bpf"
  15. static int verbose;
  16. static const char *out_net = "epair0a";
  17. static const char *dest_net = NULL;
  18. struct ether_addr *daddr;
  19. #define PAYLOAD_LEN 64
  20. union __attribute__((packed)) frame {
  21. struct {
  22. struct ether_header header;
  23. unsigned char payload[PAYLOAD_LEN];
  24. } frame;
  25. unsigned char buffer[ETHER_MAX_LEN];
  26. } out_buffer ;
  27. /* bpf */
  28. int bpf = -1;
  29. static const char *fake_dest = "6:66:6:66:6:66";
  30. #define VPRINTF(...) if(verbose) {printf(__VA_ARGS__);};
  31. #define EPRINTF(...) do {fprintf(stderr, __VA_ARGS__); } while(0);
  32. static void __attribute__((__noreturn__)) usage(void)
  33. {
  34. fputs("\nUsage:\n", stderr);
  35. fputs("sockraw [--if iface][--mac maca[-to iface]][--packets samples][--verbose]\n", stderr);
  36. fputs(" --if : interface\n", stderr);
  37. fputs(" --mac : destination MAC address\n", stderr);
  38. fputs(" --to : destination MAC address from interface name\n", stderr);
  39. fputs(" --packets: packets samples to sent\n", stderr);
  40. fputs(" --verbose: verbose\n", stderr);
  41. exit(EXIT_SUCCESS);
  42. }
  43. /* open BPF interface
  44. *
  45. * Setup global variable bpf
  46. *
  47. * return pbf value on success, -1 on error
  48. */
  49. static int get_first_bpf(void)
  50. {
  51. size_t i = 0;
  52. char buf[16] = {0};
  53. for(; i < 99; ) {
  54. sprintf(buf, "%s%zu", DEVICE_BPF, i++);
  55. bpf = open(buf, O_RDWR);
  56. if (bpf != -1)
  57. break;
  58. /* must have root access*/
  59. if (errno == EACCES)
  60. break;
  61. }
  62. return bpf;
  63. }
  64. /*
  65. * send packets
  66. *
  67. * @ifr: destination interface
  68. * @nb: packets number
  69. *
  70. */
  71. static void sender(const struct ifreq *ifr, size_t nb)
  72. {
  73. static unsigned char dummy;
  74. size_t total = nb + 1;
  75. printf("Prepare to send %zu packets to %s.\n", nb, out_net);
  76. out_buffer.frame.header.ether_type = htons(PAYLOAD_LEN);
  77. memcpy(out_buffer.frame.header.ether_dhost, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN);
  78. while (nb) {
  79. memset(out_buffer.frame.payload, ++dummy, sizeof out_buffer.frame.payload);
  80. ssize_t r = write(bpf, out_buffer.buffer,
  81. sizeof out_buffer.frame.payload + sizeof(struct ether_header));
  82. if (r == -1)
  83. warn("Unable to send packet #%zu.\n", nb);
  84. else
  85. VPRINTF("Packet #%zu sent.\n", total - nb);
  86. --nb;
  87. }
  88. printf("Done.\n");
  89. }
  90. /*
  91. * Return MAC address
  92. *
  93. * @iface: Interface name
  94. *
  95. * @return -1 on error, 0 on success
  96. */
  97. static int get_hwaddr(const char * restrict iface, struct ifreq * restrict dest_ifr)
  98. {
  99. int shw;
  100. int rc;
  101. strncpy(dest_ifr->ifr_name, iface, sizeof dest_ifr->ifr_name);
  102. dest_ifr->ifr_addr.sa_family = AF_LINK;
  103. if ((shw = socket(AF_INET, SOCK_RAW, 0)) < 0) {
  104. return -1;
  105. }
  106. rc = ioctl(shw, SIOCGHWADDR, dest_ifr);
  107. close(shw);
  108. if (rc)
  109. return -1;
  110. VPRINTF("Destination %s, HW address: %s.\n", iface, ether_ntoa((const struct ether_addr *)dest_ifr->ifr_addr.sa_data));
  111. return 0;
  112. }
  113. int main(int argc, char *argv[])
  114. {
  115. size_t packets = 10;
  116. struct ifreq out_if = {0};
  117. const char *mac_address = fake_dest;
  118. struct ifreq dest_ifr = {0};
  119. int rc;
  120. /* options */
  121. int ch;
  122. static struct option longopts[] = {
  123. { "if" , required_argument, NULL, 'i' },
  124. { "to" , required_argument, NULL, 't' },
  125. { "verbose", no_argument , NULL, 'v' },
  126. { "mac" , required_argument, NULL, 'm' },
  127. { "packets", required_argument, NULL, 'p' },
  128. { NULL, 0, NULL, 0 }
  129. };
  130. while ((ch = getopt_long(argc, argv, "vi:t:p:m:", longopts, NULL)) != -1) {
  131. switch (ch) {
  132. case 'v':
  133. verbose = 1;
  134. break;
  135. case 't':
  136. dest_net = optarg;
  137. break;
  138. case 'i':
  139. out_net = optarg;
  140. break;
  141. case 'p':
  142. packets = strtoul(optarg, NULL, 10);
  143. break;
  144. case 'm':
  145. mac_address = optarg;
  146. break;
  147. case 0:
  148. /* long option */
  149. break;
  150. default:
  151. usage();
  152. }
  153. }
  154. if (argc - optind != 0)
  155. usage();
  156. /* sanity checks */
  157. daddr = ether_aton(mac_address);
  158. if (daddr == NULL)
  159. err(EXIT_FAILURE, "Cannot get mac destination");
  160. if (strlcpy(out_if.ifr_name, out_net, sizeof(out_if.ifr_name)) >= sizeof(out_if.ifr_name))
  161. errx(EXIT_FAILURE, "%s is not a valid interface name.\n", out_net);
  162. /* man 4 BPF */
  163. if (get_first_bpf() < 0)
  164. err(EXIT_FAILURE, "Cannot open bpf interface");
  165. /* Get net device index */
  166. if (ioctl(bpf, BIOCSETIF, &out_if) == -1) {
  167. warn("Cannot open %s interface.\n", out_net);
  168. goto last;
  169. }
  170. rc = dest_net == NULL;
  171. if (!rc)
  172. rc = get_hwaddr(dest_net, &dest_ifr);
  173. if (rc)
  174. memcpy(dest_ifr.ifr_addr.sa_data, daddr, ETHER_ADDR_LEN);
  175. /*
  176. * pointless until we do not read _from_ interface
  177. * static int dummy_true = 1;
  178. * if( ioctl( bpf, BIOCIMMEDIATE, &dummy_true ) == -1 ) {
  179. * warn("Can not activate immediate mode.\n");
  180. * }
  181. * if( ioctl( bpf, BIOCGBLEN, &buf_len ) == -1 ) {
  182. * warn("Can not request buffer length\n");
  183. * exit(1);
  184. * }
  185. */
  186. sender(&dest_ifr, packets);
  187. last:
  188. close(bpf);
  189. return EXIT_SUCCESS;
  190. }