dhcp4o6_ipc.cc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <config.h>
  15. #include <dhcp/dhcp6.h>
  16. #include <dhcp/iface_mgr.h>
  17. #include <dhcp/option6_addrlst.h>
  18. #include <dhcp/option_custom.h>
  19. #include <dhcp/option_string.h>
  20. #include <dhcp/option_vendor.h>
  21. #include <dhcpsrv/dhcp4o6_ipc.h>
  22. #include <netinet/in.h>
  23. #include <string>
  24. using namespace isc::asiolink;
  25. using namespace isc::util;
  26. using namespace std;
  27. namespace isc {
  28. namespace dhcp {
  29. Dhcp4o6IpcBase::Dhcp4o6IpcBase() : port_(0), socket_fd_(-1) {}
  30. Dhcp4o6IpcBase::~Dhcp4o6IpcBase() {
  31. close();
  32. }
  33. int Dhcp4o6IpcBase::open(uint16_t port, int side) {
  34. if (port == port_) {
  35. // No change: nothing to do
  36. return (socket_fd_);
  37. }
  38. // Port 0: closing
  39. if (port == 0) {
  40. port_ = 0;
  41. if (socket_fd_ != -1) {
  42. IfaceMgr::instance().deleteExternalSocket(socket_fd_);
  43. ::close(socket_fd_);
  44. socket_fd_ = -1;
  45. }
  46. return (socket_fd_);
  47. }
  48. // Open socket
  49. int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  50. if (sock < 0) {
  51. isc_throw(Unexpected, "Failed to create DHCP4o6 socket.");
  52. }
  53. // Set reuse address
  54. int flag = 1;
  55. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
  56. (char *)&flag, sizeof(flag)) < 0) {
  57. ::close(sock);
  58. isc_throw(Unexpected, "Failed to set SO_REUSEADDR on DHCP4o6 socket.");
  59. }
  60. // Set no blocking
  61. if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
  62. ::close(sock);
  63. isc_throw(Unexpected, "Failed to set O_NONBLOCK on DHCP4o6 socket.");
  64. }
  65. // Bind to the local address
  66. struct sockaddr_in6 local6;
  67. memset(&local6, 0, sizeof(local6));
  68. local6.sin6_family = AF_INET6;
  69. #ifdef HAVE_SA_LEN
  70. local6.sin6_len = sizeof(local6);
  71. #endif
  72. if (side == 6) {
  73. local6.sin6_port = htons(port);
  74. } else {
  75. local6.sin6_port = htons(port + 1);
  76. }
  77. if (bind(sock, (struct sockaddr *)&local6, sizeof(local6)) < 0) {
  78. ::close(sock);
  79. isc_throw(Unexpected, "Failed to bind DHCP4o6 socket.");
  80. }
  81. // Connect to the remote address
  82. struct sockaddr_in6 remote6;
  83. memset(&remote6, 0, sizeof(remote6));
  84. remote6.sin6_family = AF_INET6;
  85. #ifdef HAVE_SA_LEN
  86. remote6.sin6_len = sizeof(remote6);
  87. #endif
  88. if (side == 6) {
  89. remote6.sin6_port = htons(port + 1);
  90. } else {
  91. remote6.sin6_port = htons(port);
  92. }
  93. if (connect(sock, (struct sockaddr *)&remote6, sizeof(remote6)) < 0) {
  94. ::close(sock);
  95. isc_throw(Unexpected, "Failed to connect DHCP4o6 socket.");
  96. }
  97. if (socket_fd_ != -1) {
  98. if (dup2(sock, socket_fd_) == -1) {
  99. ::close(sock);
  100. isc_throw(Unexpected, "Failed to duplicate DHCP4o6 socket.");
  101. }
  102. if (sock != socket_fd_) {
  103. ::close(sock);
  104. sock = socket_fd_;
  105. }
  106. }
  107. // Success
  108. port_ = port;
  109. socket_fd_ = sock;
  110. return (socket_fd_);
  111. }
  112. void Dhcp4o6IpcBase::close() {
  113. static_cast<void>(open(0, 0));
  114. }
  115. Pkt6Ptr Dhcp4o6IpcBase::receive() {
  116. uint8_t buf[65536];
  117. ssize_t cc = recv(socket_fd_, buf, sizeof(buf), 0);
  118. if (cc < 0) {
  119. isc_throw(Unexpected, "Failed to receive on DHCP4o6 socket.");
  120. }
  121. Pkt6Ptr pkt = Pkt6Ptr(new Pkt6(buf, cc));
  122. pkt->updateTimestamp();
  123. // Get interface name and remote address
  124. pkt->unpack();
  125. OptionVendorPtr vendor =
  126. boost::dynamic_pointer_cast<OptionVendor>(pkt->getOption(D6O_VENDOR_OPTS));
  127. if (!vendor || vendor->getVendorId() != ENTERPRISE_ID_ISC) {
  128. return (Pkt6Ptr());
  129. }
  130. OptionStringPtr ifname =
  131. boost::dynamic_pointer_cast<OptionString>(vendor->getOption(ISC_V6_4O6_INTERFACE));
  132. if (!ifname) {
  133. return (Pkt6Ptr());
  134. }
  135. IfacePtr iface = IfaceMgr::instance().getIface(ifname->getValue());
  136. if (!iface) {
  137. return (Pkt6Ptr());
  138. }
  139. OptionCustomPtr srcs =
  140. boost::dynamic_pointer_cast<OptionCustom>(vendor->getOption(ISC_V6_4O6_SRC_ADDRESS));
  141. if (!srcs) {
  142. return (Pkt6Ptr());
  143. }
  144. // Update the packet and return it
  145. static_cast<void>(pkt->delOption(D6O_VENDOR_OPTS));
  146. pkt->setRemoteAddr(srcs->readAddress());
  147. pkt->setIface(iface->getName());
  148. pkt->setIndex(iface->getIndex());
  149. return (pkt);
  150. }
  151. void Dhcp4o6IpcBase::send(Pkt6Ptr pkt) {
  152. // No packet: nothing to send
  153. if (!pkt) {
  154. return;
  155. }
  156. // Disabled: nowhere to send
  157. if (socket_fd_ == -1) {
  158. return;
  159. }
  160. // Get a vendor option
  161. OptionVendorPtr vendor(new OptionVendor(Option::V6, ENTERPRISE_ID_ISC));
  162. // Push interface name and source address in it
  163. vendor->addOption(OptionPtr(new OptionString(Option::V6,
  164. ISC_V6_4O6_INTERFACE,
  165. pkt->getIface())));
  166. vendor->addOption(OptionPtr(new Option6AddrLst(ISC_V6_4O6_SRC_ADDRESS,
  167. pkt->getRemoteAddr())));
  168. pkt->addOption(vendor);
  169. // Get packet content
  170. OutputBuffer& buf = pkt->getBuffer();
  171. buf.clear();
  172. pkt->pack();
  173. // Send
  174. static_cast<void>(::send(socket_fd_, buf.getData(), buf.getLength(), 0));
  175. return;
  176. }
  177. }; // namespace dhcp
  178. }; // namespace isc