pong.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. pong.c -- ICMP echo reply generator
  3. Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "../src/system.h"
  17. uint8_t mymac[6] = {6, 5, 5, 6, 5, 5};
  18. static ssize_t do_arp(uint8_t *buf, ssize_t len, struct sockaddr_in *in) {
  19. struct ether_arp arp;
  20. memcpy(&arp, buf + 14, sizeof arp);
  21. // Is it a valid ARP request?
  22. if(ntohs(arp.arp_hrd) != ARPHRD_ETHER || ntohs(arp.arp_pro) != ETH_P_IP || arp.arp_hln != ETH_ALEN || arp.arp_pln != sizeof in->sin_addr.s_addr || ntohs(arp.arp_op) != ARPOP_REQUEST)
  23. return 0;
  24. // Does it match our address?
  25. if(memcmp(&in->sin_addr.s_addr, arp.arp_tpa, 4))
  26. return 0;
  27. // Swap addresses
  28. memcpy(buf, buf + 6, 6);
  29. memcpy(buf + 6, mymac, 6);
  30. arp.arp_op = htons(ARPOP_REPLY);
  31. memcpy(arp.arp_tpa, arp.arp_spa, sizeof arp.arp_tpa);
  32. memcpy(arp.arp_tha, arp.arp_sha, sizeof arp.arp_tha);
  33. memcpy(arp.arp_spa, &in->sin_addr.s_addr, sizeof in->sin_addr.s_addr);
  34. memcpy(arp.arp_sha, mymac, 6);
  35. memcpy(buf + 14, &arp, sizeof arp);
  36. return len;
  37. }
  38. static ssize_t do_ipv4(uint8_t *buf, ssize_t len, struct sockaddr_in *in) {
  39. struct ip ip;
  40. struct icmp icmp;
  41. // Does it match our address?
  42. if(memcmp(buf, mymac, 6))
  43. return 0;
  44. memcpy(&ip, buf + 14, sizeof ip);
  45. if(memcmp(&ip.ip_dst, &in->sin_addr.s_addr, 4))
  46. return 0;
  47. // Is it an ICMP echo request?
  48. if(ip.ip_p != IPPROTO_ICMP)
  49. return 0;
  50. memcpy(&icmp, buf + 14 + sizeof ip, sizeof icmp);
  51. if(icmp.icmp_type != ICMP_ECHO)
  52. return 0;
  53. // Return an echo reply
  54. memcpy(buf, buf + 6, 6);
  55. memcpy(buf + 6, mymac, 6);
  56. ip.ip_dst = ip.ip_src;
  57. memcpy(&ip.ip_src, &in->sin_addr.s_addr, 4);
  58. icmp.icmp_type = ICMP_ECHOREPLY;
  59. memcpy(buf + 14, &ip, sizeof ip);
  60. memcpy(buf + 14 + sizeof ip, &icmp, sizeof icmp);
  61. return len;
  62. }
  63. static ssize_t do_ipv6(uint8_t *buf, ssize_t len, struct sockaddr_in6 *in) {
  64. return 0;
  65. }
  66. int main(int argc, char *argv[]) {
  67. if(argc != 4) {
  68. fprintf(stderr, "Usage: %s <multicast address> <port> <ping address>\n", argv[0]);
  69. return 1;
  70. }
  71. struct addrinfo hints = {}, *ai = NULL;
  72. hints.ai_socktype = SOCK_DGRAM;
  73. hints.ai_flags = AI_ADDRCONFIG;
  74. errno = ENOENT;
  75. if(getaddrinfo(argv[1], argv[2], &hints, &ai) || !ai) {
  76. fprintf(stderr, "Could not resolve %s port %s: %s\n", argv[1], argv[2], strerror(errno));
  77. return 1;
  78. }
  79. int fd;
  80. fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  81. if(!fd) {
  82. fprintf(stderr, "Could not create socket: %s\n", strerror(errno));
  83. return 1;
  84. }
  85. static const int one = 1;
  86. setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof one);
  87. if(bind(fd, ai->ai_addr, ai->ai_addrlen)) {
  88. fprintf(stderr, "Could not bind socket: %s\n", strerror(errno));
  89. return 1;
  90. }
  91. switch(ai->ai_family) {
  92. case AF_INET: {
  93. struct ip_mreq mreq;
  94. struct sockaddr_in in;
  95. memcpy(&in, ai->ai_addr, sizeof in);
  96. mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr;
  97. mreq.imr_interface.s_addr = htonl(INADDR_ANY);
  98. if(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof mreq)) {
  99. fprintf(stderr, "Cannot join multicast group: %s\n", strerror(errno));
  100. return 1;
  101. }
  102. #ifdef IP_MULTICAST_LOOP
  103. setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof one);
  104. #endif
  105. } break;
  106. #ifdef IPV6_JOIN_GROUP
  107. case AF_INET6: {
  108. struct ipv6_mreq mreq;
  109. struct sockaddr_in6 in6;
  110. memcpy(&in6, ai->ai_addr, sizeof in6);
  111. memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof mreq.ipv6mr_multiaddr);
  112. mreq.ipv6mr_interface = in6.sin6_scope_id;
  113. if(setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof mreq)) {
  114. fprintf(stderr, "Cannot join multicast group: %s\n", strerror(errno));
  115. return 1;
  116. }
  117. #ifdef IPV6_MULTICAST_LOOP
  118. setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof one);
  119. #endif
  120. } break;
  121. #endif
  122. default:
  123. fprintf(stderr, "Multicast for address family %hx unsupported\n", ai->ai_family);
  124. return 1;
  125. }
  126. errno = ENOENT;
  127. struct addrinfo *ai2 = NULL;
  128. if(getaddrinfo(argv[3], NULL, &hints, &ai2) || !ai2) {
  129. fprintf(stderr, "Could not resolve %s: %s\n", argv[3], strerror(errno));
  130. return 1;
  131. }
  132. while(true) {
  133. uint8_t buf[10000];
  134. struct sockaddr src;
  135. socklen_t srclen;
  136. ssize_t len = recvfrom(fd, buf, sizeof buf, 0, &src, &srclen);
  137. if(len <= 0)
  138. break;
  139. // Ignore short packets.
  140. if(len < 14)
  141. continue;
  142. uint16_t type = buf[12] << 8 | buf[13];
  143. if(ai2->ai_family == AF_INET && type == ETH_P_IP)
  144. len = do_ipv4(buf, len, (struct sockaddr_in *)ai2->ai_addr);
  145. else if(ai2->ai_family == AF_INET && type == ETH_P_ARP)
  146. len = do_arp(buf, len, (struct sockaddr_in *)ai2->ai_addr);
  147. else if(ai2->ai_family == AF_INET6 && type == ETH_P_IPV6)
  148. len = do_ipv6(buf, len, (struct sockaddr_in6 *)ai2->ai_addr);
  149. else
  150. continue;
  151. if(len > 0)
  152. sendto(fd, buf, len, 0, ai->ai_addr, ai->ai_addrlen);
  153. }
  154. return 0;
  155. }