dhcp4o6_ipc.cc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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/dhcp4o6.h>
  16. #include <dhcp/iface_mgr.h>
  17. #include <dhcpsrv/dhcp4o6_ipc.h>
  18. #include <netinet/in.h>
  19. #include <string>
  20. using namespace isc::asiolink;
  21. using namespace isc::util;
  22. using namespace std;
  23. namespace isc {
  24. namespace dhcp {
  25. Dhcp4o6IpcBase::Dhcp4o6IpcBase() : port_(0), socket_fd_(-1) {}
  26. Dhcp4o6IpcBase::~Dhcp4o6IpcBase() {
  27. close();
  28. }
  29. int Dhcp4o6IpcBase::open(uint16_t port, int side) {
  30. if (port == port_) {
  31. // No change: nothing to do
  32. return (socket_fd_);
  33. }
  34. // Port 0: closing
  35. if (port == 0) {
  36. port_ = 0;
  37. if (socket_fd_ != -1) {
  38. IfaceMgr::instance().deleteExternalSocket(socket_fd_);
  39. ::close(socket_fd_);
  40. socket_fd_ = -1;
  41. }
  42. return (socket_fd_);
  43. }
  44. // Open socket
  45. int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
  46. if (sock < 0) {
  47. isc_throw(Unexpected, "Failed to create DHCP4o6 socket.");
  48. }
  49. // Set reuse address
  50. int flag = 1;
  51. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
  52. (char *)&flag, sizeof(flag)) < 0) {
  53. ::close(sock);
  54. isc_throw(Unexpected, "Failed to set SO_REUSEADDR on DHCP4o6 socket.");
  55. }
  56. // Set no blocking
  57. if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
  58. ::close(sock);
  59. isc_throw(Unexpected, "Failed to set O_NONBLOCK on DHCP4o6 socket.");
  60. }
  61. // Bind to the local address
  62. struct sockaddr_in6 local6;
  63. memset(&local6, 0, sizeof(local6));
  64. local6.sin6_family = AF_INET6;
  65. #ifdef HAVE_SA_LEN
  66. local6.sin6_len = sizeof(local6);
  67. #endif
  68. if (side == 6) {
  69. local6.sin6_port = htons(port);
  70. } else {
  71. local6.sin6_port = htons(port + 1);
  72. }
  73. if (bind(sock, (struct sockaddr *)&local6, sizeof(local6)) < 0) {
  74. ::close(sock);
  75. isc_throw(Unexpected, "Failed to bind DHCP4o6 socket.");
  76. }
  77. // Connect to the remote address
  78. struct sockaddr_in6 remote6;
  79. memset(&remote6, 0, sizeof(remote6));
  80. remote6.sin6_family = AF_INET6;
  81. #ifdef HAVE_SA_LEN
  82. remote6.sin6_len = sizeof(remote6);
  83. #endif
  84. if (side == 6) {
  85. remote6.sin6_port = htons(port + 1);
  86. } else {
  87. remote6.sin6_port = htons(port);
  88. }
  89. if (connect(sock, (struct sockaddr *)&remote6, sizeof(remote6)) < 0) {
  90. ::close(sock);
  91. isc_throw(Unexpected, "Failed to connect DHCP4o6 socket.");
  92. }
  93. if (socket_fd_ != -1) {
  94. if (dup2(sock, socket_fd_) == -1) {
  95. ::close(sock);
  96. isc_throw(Unexpected, "Failed to duplicate DHCP4o6 socket.");
  97. }
  98. if (sock != socket_fd_) {
  99. ::close(sock);
  100. sock = socket_fd_;
  101. }
  102. }
  103. // Success
  104. port_ = port;
  105. socket_fd_ = sock;
  106. return (socket_fd_);
  107. }
  108. void Dhcp4o6IpcBase::close() {
  109. static_cast<void>(open(0, 0));
  110. }
  111. Pkt6Ptr Dhcp4o6IpcBase::receive() {
  112. uint8_t buf[65536];
  113. ssize_t cc = recv(socket_fd_, buf, sizeof(buf), 0);
  114. if (cc < 0) {
  115. isc_throw(Unexpected, "Failed to receive on DHCP4o6 socket.");
  116. }
  117. if (cc < DHCP4O6_DHCP6_OFFSET + Pkt6::DHCPV6_PKT_HDR_LEN) {
  118. // Ignore too short messages
  119. return (Pkt6Ptr());
  120. }
  121. char name[DHCP4O6_IFNAME_SIZE + 1];
  122. memcpy(name, buf, DHCP4O6_IFNAME_SIZE);
  123. IfacePtr iface = IfaceMgr::instance().getIface(string(name));
  124. if (!iface) {
  125. // Can't get the interface: ignore
  126. return (Pkt6Ptr());
  127. }
  128. uint8_t raddr[DHCP4O6_RADDR_SIZE];
  129. memcpy(raddr, buf + DHCP4O6_RADDR_OFFSET, DHCP4O6_RADDR_SIZE);
  130. IOAddress from = IOAddress::fromBytes(AF_INET6, raddr);
  131. Pkt6Ptr pkt;
  132. pkt = Pkt6Ptr(new Pkt6(buf + DHCP4O6_DHCP6_OFFSET,
  133. cc - DHCP4O6_DHCP6_OFFSET));
  134. pkt->updateTimestamp();
  135. pkt->setRemoteAddr(from);
  136. pkt->setIface(iface->getName());
  137. pkt->setIndex(iface->getIndex());
  138. return (pkt);
  139. }
  140. void Dhcp4o6IpcBase::send(Pkt6Ptr pkt) {
  141. // No packet: nothing to send
  142. if (!pkt) {
  143. return;
  144. }
  145. // Disabled: nowhere to send
  146. if (socket_fd_ == -1) {
  147. return;
  148. }
  149. // Get interface name
  150. string name = pkt->getIface();
  151. if (name.empty() || name.size() > DHCP4O6_IFNAME_SIZE) {
  152. // Bad interface name: ignore
  153. return;
  154. }
  155. name.resize(DHCP4O6_IFNAME_SIZE);
  156. // Get remote address
  157. IOAddress from = pkt->getRemoteAddr();
  158. vector<uint8_t> raddr = from.toBytes();
  159. if (raddr.size() != DHCP4O6_RADDR_SIZE) {
  160. // Bad remote address: ignore
  161. return;
  162. }
  163. // Get packet content
  164. OutputBuffer& pbuf = pkt->getBuffer();
  165. if (!pbuf.getLength()) {
  166. // Empty buffer: content is not (yet) here, get it
  167. pkt->repack();
  168. }
  169. // Fill buffer
  170. vector<uint8_t> buf(DHCP4O6_DHCP6_OFFSET + pbuf.getLength());
  171. memcpy(&buf[0], name.c_str(), DHCP4O6_IFNAME_SIZE);
  172. memcpy(&buf[0] + DHCP4O6_RADDR_OFFSET, &raddr[0], DHCP4O6_RADDR_SIZE);
  173. memcpy(&buf[0] + DHCP4O6_DHCP6_OFFSET, pbuf.getData(), pbuf.getLength());
  174. // Send
  175. static_cast<void>(::send(socket_fd_, &buf[0], buf.size(), 0));
  176. return;
  177. }
  178. }; // namespace dhcp
  179. }; // namespace isc