NDPServer.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "interface/tuntap/TUNMessageType.h"
  16. #include "interface/tuntap/NDPServer.h"
  17. #include "util/Bits.h"
  18. #include "util/Checksum.h"
  19. #include "util/Identity.h"
  20. #include "wire/Message.h"
  21. #include "wire/Ethernet.h"
  22. #include "wire/Headers.h"
  23. #include "wire/NDPHeader.h"
  24. #include <stdbool.h>
  25. struct NDPServer_pvt
  26. {
  27. struct NDPServer pub;
  28. struct Iface external;
  29. struct Log* log;
  30. uint8_t localMac[Ethernet_ADDRLEN];
  31. Identity
  32. };
  33. #define MULTICAST_ADDR "\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x00\x00\x08"
  34. // ff 02 00 00 00 00 00 00 00 00 00 01 ff 00 00 02 870099
  35. #define UNICAST_ADDR "\xfe\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\x08"
  36. //#define UNICAST_ADDR "\xfd\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\x08"
  37. #define ALL_ROUTERS "\xff\x02\0\0\0\0\0\0\0\0\0\0\0\0\0\x02"
  38. static bool isNeighborSolicitation(struct Message* msg, struct NDPServer_pvt* ns)
  39. {
  40. if (msg->length < Headers_IP6Header_SIZE + NDPHeader_NeighborSolicitation_SIZE) {
  41. return false;
  42. }
  43. struct Headers_IP6Header* ip6 = (struct Headers_IP6Header*) msg->bytes;
  44. struct NDPHeader_NeighborSolicitation* sol = (struct NDPHeader_NeighborSolicitation*) &ip6[1];
  45. if (sol->oneThirtyFive != 135 || sol->zero != 0) {
  46. Log_debug(ns->log, "wrong type/code for neighbor solicitation");
  47. return false;
  48. }
  49. if (//Bits_memcmp(ip6->destinationAddr, UNICAST_ADDR, 16) ||
  50. Bits_memcmp(ip6->destinationAddr, MULTICAST_ADDR, 13))
  51. {
  52. Log_debug(ns->log, "wrong address for neighbor solicitation");
  53. return false;
  54. }
  55. /*if (Bits_memcmp(sol->targetAddr, UNICAST_ADDR, 16)) {
  56. Log_debug(ns->log, "Soliciting the wrong neighbor");
  57. return false;
  58. }*/
  59. return true;
  60. }
  61. static Iface_DEFUN answerNeighborSolicitation(struct Message* msg, struct NDPServer_pvt* ns)
  62. {
  63. struct Headers_IP6Header ip6;
  64. Message_pop(msg, &ip6, Headers_IP6Header_SIZE, NULL);
  65. struct NDPHeader_NeighborSolicitation sol;
  66. Message_pop(msg, &sol, NDPHeader_NeighborSolicitation_SIZE, NULL);
  67. if (msg->length) {
  68. /* Right now we ignore any ICMP options. Windows will send them. */
  69. Log_debug(ns->log, "%d extra bytes (ICMP options?) in neighbor solicitation",
  70. msg->length);
  71. }
  72. struct NDPHeader_MacOpt macOpt = {
  73. .type = NDPHeader_MacOpt_type_TARGET,
  74. .one = 1
  75. };
  76. Bits_memcpy(macOpt.mac, ns->localMac, Ethernet_ADDRLEN);
  77. Message_push(msg, &macOpt, sizeof(struct NDPHeader_MacOpt), NULL);
  78. struct NDPHeader_NeighborAdvert na = {
  79. .oneThirtySix = 136,
  80. .zero = 0,
  81. .checksum = 0,
  82. .bits = NDPHeader_NeighborAdvert_bits_ROUTER
  83. | NDPHeader_NeighborAdvert_bits_SOLICITED
  84. | NDPHeader_NeighborAdvert_bits_OVERRIDE
  85. };
  86. Bits_memcpy(na.targetAddr, sol.targetAddr, 16);
  87. Message_push(msg, &na, sizeof(struct NDPHeader_NeighborAdvert), NULL);
  88. Bits_memcpy(ip6.destinationAddr, ip6.sourceAddr, 16);
  89. Bits_memcpy(ip6.sourceAddr, sol.targetAddr, 16);
  90. ip6.hopLimit = 255;
  91. ip6.payloadLength_be = Endian_hostToBigEndian16(msg->length);
  92. struct NDPHeader_RouterAdvert* adv = (struct NDPHeader_RouterAdvert*) msg->bytes;
  93. adv->checksum = Checksum_icmp6(ip6.sourceAddr, msg->bytes, msg->length);
  94. Message_push(msg, &ip6, sizeof(struct Headers_IP6Header), NULL);
  95. TUNMessageType_push(msg, Ethernet_TYPE_IP6, NULL);
  96. Log_debug(ns->log, "Sending neighbor advert");
  97. return Iface_next(&ns->external, msg);
  98. }
  99. static Iface_DEFUN receiveMessage(struct Message* msg, struct Iface* external)
  100. {
  101. struct NDPServer_pvt* ns = Identity_containerOf(external, struct NDPServer_pvt, external);
  102. if (msg->length > Headers_IP6Header_SIZE + 4) {
  103. uint16_t ethertype = TUNMessageType_pop(msg, NULL);
  104. if (ethertype != Ethernet_TYPE_IP6) {
  105. } else if (isNeighborSolicitation(msg, ns)) {
  106. //TODO(cjdns, Kubuxu): Filtering basing on cjdns network and tunnels.
  107. return answerNeighborSolicitation(msg, ns);
  108. }
  109. TUNMessageType_push(msg, ethertype, NULL);
  110. }
  111. return Iface_next(&ns->pub.internal, msg);
  112. }
  113. static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* internal)
  114. {
  115. struct NDPServer_pvt* ns = Identity_containerOf(internal, struct NDPServer_pvt, pub.internal);
  116. return Iface_next(&ns->external, msg);
  117. }
  118. struct NDPServer* NDPServer_new(struct Iface* external,
  119. struct Log* log,
  120. uint8_t localMac[Ethernet_ADDRLEN],
  121. struct Allocator* alloc)
  122. {
  123. struct NDPServer_pvt* out = Allocator_calloc(alloc, sizeof(struct NDPServer_pvt), 1);
  124. Identity_set(out);
  125. out->external.send = receiveMessage;
  126. Iface_plumb(&out->external, external);
  127. out->pub.internal.send = sendMessage;
  128. out->log = log;
  129. Bits_memcpy(out->localMac, localMac, Ethernet_ADDRLEN);
  130. return &out->pub;
  131. }