socketsession.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. // Copyright (C) 2011 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 <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <sys/uio.h>
  18. #include <sys/un.h>
  19. #include <netinet/in.h>
  20. #include <fcntl.h>
  21. #include <stdint.h>
  22. #include <cerrno>
  23. #include <csignal>
  24. #include <cstddef>
  25. #include <cstring>
  26. #include <cassert>
  27. #include <string>
  28. #include <vector>
  29. #include <boost/noncopyable.hpp>
  30. #include <exceptions/exceptions.h>
  31. #include <util/buffer.h>
  32. #include "fd_share.h"
  33. #include "socketsession.h"
  34. #include "sockaddr_util.h"
  35. using namespace std;
  36. namespace isc {
  37. namespace util {
  38. namespace io {
  39. using namespace internal;
  40. // The expected max size of the session header: 2-byte header length,
  41. // 6 32-bit fields, and 2 sockaddr structure. (see the SocketSessionUtility
  42. // overview description in the header file). sizeof sockaddr_storage
  43. // should be the possible max of any sockaddr structure
  44. const size_t DEFAULT_HEADER_BUFLEN = sizeof(uint16_t) + sizeof(uint32_t) * 6 +
  45. sizeof(struct sockaddr_storage) * 2;
  46. // The allowable maximum size of data passed with the socket FD. For now
  47. // we use a fixed value of 65535, the largest possible size of valid DNS
  48. // messages. We may enlarge it or make it configurable as we see the need
  49. // for more flexibility.
  50. const int MAX_DATASIZE = 65535;
  51. // The initial buffer size for receiving socket session data in the receiver.
  52. // This value is the maximum message size of DNS messages carried over UDP
  53. // (without EDNS). In our expected usage (at the moment) this should be
  54. // sufficiently large (the expected data is AXFR/IXFR query or an UPDATE
  55. // requests. The former should be generally quite small. While the latter
  56. // could be large, it would often be small enough for a single UDP message).
  57. // If it turns out that there are many exceptions, we may want to extend
  58. // the class so that this value can be customized. Note that the buffer
  59. // will be automatically extended for longer data and this is only about
  60. // efficiency.
  61. const size_t INITIAL_BUFSIZE = 512;
  62. // The (default) socket buffer size for the forwarder and receiver. This is
  63. // chosen to be sufficiently large to store two full-size DNS messages. We
  64. // may want to customize this value in future.
  65. const int SOCKSESSION_BUFSIZE = (DEFAULT_HEADER_BUFLEN + MAX_DATASIZE) * 2;
  66. struct SocketSessionForwarder::ForwarderImpl {
  67. ForwarderImpl() : fd_(-1), buf_(DEFAULT_HEADER_BUFLEN) {}
  68. struct sockaddr_un sock_un_;
  69. socklen_t sock_un_len_;
  70. int fd_;
  71. OutputBuffer buf_;
  72. };
  73. SocketSessionForwarder::SocketSessionForwarder(const std::string& unix_file) :
  74. impl_(NULL)
  75. {
  76. // We need to filter SIGPIPE for subsequent push(). See the class
  77. // description.
  78. if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
  79. isc_throw(Unexpected, "Failed to filter SIGPIPE: " << strerror(errno));
  80. }
  81. ForwarderImpl impl;
  82. if (sizeof(impl.sock_un_.sun_path) - 1 < unix_file.length()) {
  83. isc_throw(SocketSessionError,
  84. "File name for a UNIX domain socket is too long: " <<
  85. unix_file);
  86. }
  87. impl.sock_un_.sun_family = AF_UNIX;
  88. // the copy should be safe due to the above check, but we'd be rather
  89. // paranoid about making it 100% sure even if the check has a bug (with
  90. // triggering the assertion in the worse case)
  91. strncpy(impl.sock_un_.sun_path, unix_file.c_str(),
  92. sizeof(impl.sock_un_.sun_path));
  93. assert(impl.sock_un_.sun_path[sizeof(impl.sock_un_.sun_path) - 1] == '\0');
  94. impl.sock_un_len_ = offsetof(struct sockaddr_un, sun_path) +
  95. unix_file.length();
  96. #ifdef HAVE_SA_LEN
  97. impl.sock_un_.sun_len = impl.sock_un_len_;
  98. #endif
  99. impl.fd_ = -1;
  100. impl_ = new ForwarderImpl;
  101. *impl_ = impl;
  102. }
  103. SocketSessionForwarder::~SocketSessionForwarder() {
  104. if (impl_->fd_ != -1) {
  105. close();
  106. }
  107. delete impl_;
  108. }
  109. void
  110. SocketSessionForwarder::connectToReceiver() {
  111. if (impl_->fd_ != -1) {
  112. isc_throw(BadValue, "Duplicate connect to UNIX domain "
  113. "endpoint " << impl_->sock_un_.sun_path);
  114. }
  115. impl_->fd_ = socket(AF_UNIX, SOCK_STREAM, 0);
  116. if (impl_->fd_ == -1) {
  117. isc_throw(SocketSessionError, "Failed to create a UNIX domain socket: "
  118. << strerror(errno));
  119. }
  120. // Make the socket non blocking
  121. int fcntl_flags = fcntl(impl_->fd_, F_GETFL, 0);
  122. if (fcntl_flags != -1) {
  123. fcntl_flags |= O_NONBLOCK;
  124. fcntl_flags = fcntl(impl_->fd_, F_SETFL, fcntl_flags);
  125. }
  126. if (fcntl_flags == -1) {
  127. close(); // note: this is the internal method, not ::close()
  128. isc_throw(SocketSessionError,
  129. "Failed to make UNIX domain socket non blocking: " <<
  130. strerror(errno));
  131. }
  132. // Ensure the socket send buffer is large enough. If we can't get the
  133. // current size, simply set the sufficient size.
  134. int sndbuf_size;
  135. socklen_t sndbuf_size_len = sizeof(sndbuf_size);
  136. if (getsockopt(impl_->fd_, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
  137. &sndbuf_size_len) == -1 ||
  138. sndbuf_size < SOCKSESSION_BUFSIZE) {
  139. if (setsockopt(impl_->fd_, SOL_SOCKET, SO_SNDBUF, &SOCKSESSION_BUFSIZE,
  140. sizeof(SOCKSESSION_BUFSIZE)) == -1) {
  141. close();
  142. isc_throw(SocketSessionError,
  143. "Failed to set send buffer size to " <<
  144. SOCKSESSION_BUFSIZE);
  145. }
  146. }
  147. if (connect(impl_->fd_, convertSockAddr(&impl_->sock_un_),
  148. impl_->sock_un_len_) == -1) {
  149. close();
  150. isc_throw(SocketSessionError, "Failed to connect to UNIX domain "
  151. "endpoint " << impl_->sock_un_.sun_path << ": " <<
  152. strerror(errno));
  153. }
  154. }
  155. void
  156. SocketSessionForwarder::close() {
  157. if (impl_->fd_ == -1) {
  158. isc_throw(BadValue, "Attempt of close before connect");
  159. }
  160. ::close(impl_->fd_);
  161. impl_->fd_ = -1;
  162. }
  163. void
  164. SocketSessionForwarder::push(int sock, int family, int type, int protocol,
  165. const struct sockaddr& local_end,
  166. const struct sockaddr& remote_end,
  167. const void* data, size_t data_len)
  168. {
  169. if (impl_->fd_ == -1) {
  170. isc_throw(BadValue, "Attempt of push before connect");
  171. }
  172. if ((local_end.sa_family != AF_INET && local_end.sa_family != AF_INET6) ||
  173. (remote_end.sa_family != AF_INET && remote_end.sa_family != AF_INET6))
  174. {
  175. isc_throw(BadValue, "Invalid address family: must be "
  176. "AF_INET or AF_INET6; " <<
  177. static_cast<int>(local_end.sa_family) << ", " <<
  178. static_cast<int>(remote_end.sa_family) << " given");
  179. }
  180. if (family != local_end.sa_family || family != remote_end.sa_family) {
  181. isc_throw(BadValue, "Inconsistent address family: must be "
  182. << static_cast<int>(family) << "; "
  183. << static_cast<int>(local_end.sa_family) << ", "
  184. << static_cast<int>(remote_end.sa_family) << " given");
  185. }
  186. if (data_len == 0 || data == NULL) {
  187. isc_throw(BadValue, "Data for a socket session must not be empty");
  188. }
  189. if (data_len > MAX_DATASIZE) {
  190. isc_throw(BadValue, "Invalid socket session data size: " <<
  191. data_len << ", must not exceed " << MAX_DATASIZE);
  192. }
  193. if (send_fd(impl_->fd_, sock) != 0) {
  194. isc_throw(SocketSessionError, "FD passing failed: " <<
  195. strerror(errno));
  196. }
  197. impl_->buf_.clear();
  198. // Leave the space for the header length
  199. impl_->buf_.skip(sizeof(uint16_t));
  200. // Socket properties: family, type, protocol
  201. impl_->buf_.writeUint32(static_cast<uint32_t>(family));
  202. impl_->buf_.writeUint32(static_cast<uint32_t>(type));
  203. impl_->buf_.writeUint32(static_cast<uint32_t>(protocol));
  204. // Local endpoint
  205. impl_->buf_.writeUint32(static_cast<uint32_t>(getSALength(local_end)));
  206. impl_->buf_.writeData(&local_end, getSALength(local_end));
  207. // Remote endpoint
  208. impl_->buf_.writeUint32(static_cast<uint32_t>(getSALength(remote_end)));
  209. impl_->buf_.writeData(&remote_end, getSALength(remote_end));
  210. // Data length. Must be fit uint32 due to the range check above.
  211. const uint32_t data_len32 = static_cast<uint32_t>(data_len);
  212. assert(data_len == data_len32); // shouldn't cause overflow.
  213. impl_->buf_.writeUint32(data_len32);
  214. // Write the resulting header length at the beginning of the buffer
  215. impl_->buf_.writeUint16At(impl_->buf_.getLength() - sizeof(uint16_t), 0);
  216. const struct iovec iov[2] = {
  217. { const_cast<void*>(impl_->buf_.getData()), impl_->buf_.getLength() },
  218. { const_cast<void*>(data), data_len }
  219. };
  220. const int cc = writev(impl_->fd_, iov, 2);
  221. if (cc != impl_->buf_.getLength() + data_len) {
  222. if (cc < 0) {
  223. isc_throw(SocketSessionError,
  224. "Write failed in forwarding a socket session: " <<
  225. strerror(errno));
  226. }
  227. isc_throw(SocketSessionError,
  228. "Incomplete write in forwarding a socket session: " << cc <<
  229. "/" << (impl_->buf_.getLength() + data_len));
  230. }
  231. }
  232. SocketSession::SocketSession(int sock, int family, int type, int protocol,
  233. const sockaddr* local_end,
  234. const sockaddr* remote_end,
  235. const void* data, size_t data_len) :
  236. sock_(sock), family_(family), type_(type), protocol_(protocol),
  237. local_end_(local_end), remote_end_(remote_end),
  238. data_(data), data_len_(data_len)
  239. {
  240. if (local_end == NULL || remote_end == NULL) {
  241. isc_throw(BadValue, "sockaddr must be non NULL for SocketSession");
  242. }
  243. if (data_len == 0) {
  244. isc_throw(BadValue, "data_len must be non 0 for SocketSession");
  245. }
  246. if (data == NULL) {
  247. isc_throw(BadValue, "data must be non NULL for SocketSession");
  248. }
  249. }
  250. struct SocketSessionReceiver::ReceiverImpl {
  251. ReceiverImpl(int fd) : fd_(fd),
  252. sa_local_(convertSockAddr(&ss_local_)),
  253. sa_remote_(convertSockAddr(&ss_remote_)),
  254. header_buf_(DEFAULT_HEADER_BUFLEN),
  255. data_buf_(INITIAL_BUFSIZE)
  256. {
  257. if (setsockopt(fd_, SOL_SOCKET, SO_RCVBUF, &SOCKSESSION_BUFSIZE,
  258. sizeof(SOCKSESSION_BUFSIZE)) == -1) {
  259. isc_throw(SocketSessionError,
  260. "Failed to set receive buffer size to " <<
  261. SOCKSESSION_BUFSIZE);
  262. }
  263. }
  264. const int fd_;
  265. struct sockaddr_storage ss_local_; // placeholder for local endpoint
  266. struct sockaddr* const sa_local_;
  267. struct sockaddr_storage ss_remote_; // placeholder for remote endpoint
  268. struct sockaddr* const sa_remote_;
  269. // placeholder for session header and data
  270. vector<uint8_t> header_buf_;
  271. vector<uint8_t> data_buf_;
  272. };
  273. SocketSessionReceiver::SocketSessionReceiver(int fd) :
  274. impl_(new ReceiverImpl(fd))
  275. {
  276. }
  277. SocketSessionReceiver::~SocketSessionReceiver() {
  278. delete impl_;
  279. }
  280. namespace {
  281. // A shortcut to throw common exception on failure of recv(2)
  282. void
  283. readFail(int actual_len, int expected_len) {
  284. if (expected_len < 0) {
  285. isc_throw(SocketSessionError, "Failed to receive data from "
  286. "SocketSessionForwarder: " << strerror(errno));
  287. }
  288. isc_throw(SocketSessionError, "Incomplete data from "
  289. "SocketSessionForwarder: " << actual_len << "/" <<
  290. expected_len);
  291. }
  292. // A helper container for a (socket) file descriptor used in
  293. // SocketSessionReceiver::pop that ensures the socket is closed unless it
  294. // can be safely passed to the caller via release().
  295. struct ScopedSocket : boost::noncopyable {
  296. ScopedSocket(int fd) : fd_(fd) {}
  297. ~ScopedSocket() {
  298. if (fd_ >= 0) {
  299. close(fd_);
  300. }
  301. }
  302. int release() {
  303. const int fd = fd_;
  304. fd_ = -1;
  305. return (fd);
  306. }
  307. int fd_;
  308. };
  309. }
  310. SocketSession
  311. SocketSessionReceiver::pop() {
  312. ScopedSocket passed_sock(recv_fd(impl_->fd_));
  313. if (passed_sock.fd_ == FD_SYSTEM_ERROR) {
  314. isc_throw(SocketSessionError, "Receiving a forwarded FD failed: " <<
  315. strerror(errno));
  316. } else if (passed_sock.fd_ < 0) {
  317. isc_throw(SocketSessionError, "No FD forwarded");
  318. }
  319. uint16_t header_len;
  320. const int cc_hlen = recv(impl_->fd_, &header_len, sizeof(header_len),
  321. MSG_WAITALL);
  322. if (cc_hlen < sizeof(header_len)) {
  323. readFail(cc_hlen, sizeof(header_len));
  324. }
  325. header_len = InputBuffer(&header_len, sizeof(header_len)).readUint16();
  326. if (header_len > DEFAULT_HEADER_BUFLEN) {
  327. isc_throw(SocketSessionError, "Too large header length: " <<
  328. header_len);
  329. }
  330. impl_->header_buf_.clear();
  331. impl_->header_buf_.resize(header_len);
  332. const int cc_hdr = recv(impl_->fd_, &impl_->header_buf_[0], header_len,
  333. MSG_WAITALL);
  334. if (cc_hdr < header_len) {
  335. readFail(cc_hdr, header_len);
  336. }
  337. InputBuffer ibuffer(&impl_->header_buf_[0], header_len);
  338. try {
  339. const int family = static_cast<int>(ibuffer.readUint32());
  340. if (family != AF_INET && family != AF_INET6) {
  341. isc_throw(SocketSessionError,
  342. "Unsupported address family is passed: " << family);
  343. }
  344. const int type = static_cast<int>(ibuffer.readUint32());
  345. const int protocol = static_cast<int>(ibuffer.readUint32());
  346. const socklen_t local_end_len = ibuffer.readUint32();
  347. const socklen_t endpoint_minlen = (family == AF_INET) ?
  348. sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
  349. if (local_end_len < endpoint_minlen ||
  350. local_end_len > sizeof(impl_->ss_local_)) {
  351. isc_throw(SocketSessionError, "Invalid local SA length: " <<
  352. local_end_len);
  353. }
  354. ibuffer.readData(&impl_->ss_local_, local_end_len);
  355. const socklen_t remote_end_len = ibuffer.readUint32();
  356. if (remote_end_len < endpoint_minlen ||
  357. remote_end_len > sizeof(impl_->ss_remote_)) {
  358. isc_throw(SocketSessionError, "Invalid remote SA length: " <<
  359. remote_end_len);
  360. }
  361. ibuffer.readData(&impl_->ss_remote_, remote_end_len);
  362. if (family != impl_->sa_local_->sa_family ||
  363. family != impl_->sa_remote_->sa_family) {
  364. isc_throw(SocketSessionError, "SA family inconsistent: " <<
  365. static_cast<int>(impl_->sa_local_->sa_family) << ", " <<
  366. static_cast<int>(impl_->sa_remote_->sa_family) <<
  367. " given, must be " << family);
  368. }
  369. const size_t data_len = ibuffer.readUint32();
  370. if (data_len == 0 || data_len > MAX_DATASIZE) {
  371. isc_throw(SocketSessionError,
  372. "Invalid socket session data size: " << data_len <<
  373. ", must be > 0 and <= " << MAX_DATASIZE);
  374. }
  375. impl_->data_buf_.clear();
  376. impl_->data_buf_.resize(data_len);
  377. const int cc_data = recv(impl_->fd_, &impl_->data_buf_[0], data_len,
  378. MSG_WAITALL);
  379. if (cc_data < data_len) {
  380. readFail(cc_data, data_len);
  381. }
  382. return (SocketSession(passed_sock.release(), family, type, protocol,
  383. impl_->sa_local_, impl_->sa_remote_,
  384. &impl_->data_buf_[0], data_len));
  385. } catch (const InvalidBufferPosition& ex) {
  386. // We catch the case where the given header is too short and convert
  387. // the exception to SocketSessionError.
  388. isc_throw(SocketSessionError, "bogus socket session header: " <<
  389. ex.what());
  390. }
  391. }
  392. }
  393. }
  394. }