symuxnet.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /* $Id: symuxnet.c,v 1.24 2007/11/29 13:13:18 dijkstra Exp $ */
  2. /*
  3. * Copyright (c) 2001-2007 Willem Dijkstra
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * - Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * - Redistributions in binary form must reproduce the above
  13. * copyright notice, this list of conditions and the following
  14. * disclaimer in the documentation and/or other materials provided
  15. * with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. * POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. #include <sys/types.h>
  32. #include <sys/socket.h>
  33. #include <errno.h>
  34. #include <fcntl.h>
  35. #include <netdb.h>
  36. #include <string.h>
  37. #include <unistd.h>
  38. #include "conf.h"
  39. #include "data.h"
  40. #include "error.h"
  41. #include "symux.h"
  42. #include "symuxnet.h"
  43. #include "net.h"
  44. #include "xmalloc.h"
  45. #include "share.h"
  46. __BEGIN_DECLS
  47. int check_crc_packet(struct symonpacket *);
  48. __END_DECLS
  49. /* Obtain sockets for incoming symon traffic */
  50. int
  51. get_symon_sockets(struct mux * mux)
  52. {
  53. struct source *source;
  54. struct sockaddr_storage sockaddr;
  55. int family, nsocks, one = 1;
  56. nsocks = 0;
  57. /* generate the udp listen socket specified in the mux statement */
  58. get_mux_sockaddr(mux, SOCK_DGRAM);
  59. /* iterate over our sources to determine what types of sockets we need */
  60. SLIST_FOREACH(source, &mux->sol, sources) {
  61. if (!get_source_sockaddr(source, AF_INET)) {
  62. if (!get_source_sockaddr(source, AF_INET6)) {
  63. warning("cannot determine socket family for source %.200s", source->addr);
  64. }
  65. }
  66. family = source->sockaddr.ss_family;
  67. /* do we have a socket for this type of family */
  68. if (mux->symonsocket[family] <= 0) {
  69. if ((mux->symonsocket[family] = socket(family, SOCK_DGRAM, 0)) != -1) {
  70. /* attempt to set reuse, ignore errors */
  71. if (setsockopt(mux->symonsocket[family], SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
  72. warning ("could set socket options: %.200s", strerror(errno));
  73. }
  74. /*
  75. * does the mux statement specify a specific destination
  76. * address
  77. */
  78. if (mux->sockaddr.ss_family == family) {
  79. cpysock((struct sockaddr *) & mux->sockaddr, &sockaddr);
  80. } else {
  81. get_sockaddr(&sockaddr, family, SOCK_DGRAM, AI_PASSIVE, NULL, mux->port);
  82. }
  83. if (bind(mux->symonsocket[family], (struct sockaddr *) & sockaddr,
  84. SS_LEN(&sockaddr)) == -1) {
  85. switch (errno) {
  86. case EADDRNOTAVAIL:
  87. warning("mux address %.200s is not a local address", mux->addr);
  88. break;
  89. case EADDRINUSE:
  90. warning("mux address %.200s %.200s already in use", mux->addr, mux->port);
  91. break;
  92. case EACCES:
  93. warning("mux port %.200s is restricted from current user", mux->port);
  94. break;
  95. default:
  96. warning("mux port %.200s bind failed", mux->port);
  97. break;
  98. }
  99. close(mux->symonsocket[family]);
  100. mux->symonsocket[family] = 0;
  101. } else {
  102. if (get_numeric_name(&sockaddr)) {
  103. info("getnameinfo error - cannot determine numeric hostname and service");
  104. info("listening for incoming symon traffic for family %d", family);
  105. } else
  106. info("listening for incoming symon traffic on udp %.200s %.200s",
  107. res_host, res_service);
  108. nsocks++;
  109. }
  110. }
  111. }
  112. }
  113. return nsocks;
  114. }
  115. /* Obtain a listen socket for new clients */
  116. int
  117. get_client_socket(struct mux * mux)
  118. {
  119. struct addrinfo hints, *res;
  120. int error, sock, one = 1;
  121. if ((sock = socket(mux->sockaddr.ss_family, SOCK_STREAM, 0)) == -1)
  122. fatal("could not obtain socket: %.200s", strerror(errno));
  123. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
  124. fatal ("could set socket options: %.200s", strerror(errno));
  125. }
  126. bzero((void *) &hints, sizeof(struct addrinfo));
  127. hints.ai_family = mux->sockaddr.ss_family;
  128. hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
  129. hints.ai_socktype = SOCK_STREAM;
  130. if ((error = getaddrinfo(mux->addr, mux->port, &hints, &res)) != 0)
  131. fatal("could not get address information for %.200s:%.200s - %.200s",
  132. mux->addr, mux->port, gai_strerror(error));
  133. if (bind(sock, (struct sockaddr *) res->ai_addr, res->ai_addrlen) == -1)
  134. fatal("could not bind socket: %.200s", strerror(errno));
  135. freeaddrinfo(res);
  136. if (listen(sock, SYMUX_TCPBACKLOG) == -1)
  137. fatal("could not listen to socket: %.200s", strerror(errno));
  138. fcntl(sock, O_NONBLOCK);
  139. mux->clientsocket = sock;
  140. info("listening for incoming connections on tcp %.200s %.200s",
  141. mux->addr, mux->port);
  142. return sock;
  143. }
  144. /*
  145. * Wait for traffic (symon reports from a source in sourclist | clients trying to connect
  146. * Returns the <source> and <packet>
  147. * Silently forks off clienthandlers
  148. */
  149. void
  150. wait_for_traffic(struct mux * mux, struct source ** source)
  151. {
  152. fd_set readset;
  153. int i;
  154. int socksactive;
  155. int maxsock;
  156. for (;;) { /* FOREVER - until a valid symon packet is
  157. * received */
  158. FD_ZERO(&readset);
  159. FD_SET(mux->clientsocket, &readset);
  160. maxsock = mux->clientsocket;
  161. for (i = 0; i < AF_MAX; i++) {
  162. if (mux->symonsocket[i] > 0) {
  163. FD_SET(mux->symonsocket[i], &readset);
  164. maxsock = ((maxsock < mux->symonsocket[i]) ? mux->symonsocket[i] :
  165. maxsock);
  166. }
  167. }
  168. maxsock++;
  169. socksactive = select(maxsock, &readset, NULL, NULL, NULL);
  170. if (socksactive != -1) {
  171. if (FD_ISSET(mux->clientsocket, &readset)) {
  172. spawn_client(mux->clientsocket);
  173. }
  174. for (i = 0; i < AF_MAX; i++)
  175. if (FD_ISSET(mux->symonsocket[i], &readset)) {
  176. if (recv_symon_packet(mux, i, source))
  177. return;
  178. }
  179. } else {
  180. if (errno == EINTR)
  181. return; /* signal received while waiting, bail out */
  182. }
  183. }
  184. }
  185. /* Receive a symon packet for mux. Checks if the source is allowed and returns the source found.
  186. * return 0 if no valid packet found
  187. */
  188. int
  189. recv_symon_packet(struct mux * mux, int socknr, struct source ** source)
  190. {
  191. struct sockaddr_storage sind;
  192. socklen_t sl;
  193. int size, tries;
  194. unsigned int received;
  195. u_int32_t crc;
  196. received = 0;
  197. tries = 0;
  198. do {
  199. sl = sizeof(sind);
  200. size = recvfrom(mux->symonsocket[socknr],
  201. (mux->packet.data + received),
  202. (mux->packet.size - received),
  203. 0, (struct sockaddr *) &sind, &sl);
  204. if (size > 0)
  205. received += size;
  206. tries++;
  207. } while ((size == -1) &&
  208. (errno == EAGAIN || errno == EINTR) &&
  209. (tries < SYMUX_MAXREADTRIES) &&
  210. (received < mux->packet.size));
  211. if ((size == -1) &&
  212. errno)
  213. warning("recvfrom failed: %.200s", strerror(errno));
  214. *source = find_source_sockaddr(&mux->sol, (struct sockaddr *) &sind);
  215. get_numeric_name(&sind);
  216. if (*source == NULL) {
  217. debug("ignored data from %.200s:%.200s", res_host, res_service);
  218. return 0;
  219. } else {
  220. /* get header stream */
  221. mux->packet.offset = getheader(mux->packet.data, &mux->packet.header);
  222. /* check crc */
  223. crc = mux->packet.header.crc;
  224. mux->packet.header.crc = 0;
  225. setheader(mux->packet.data, &mux->packet.header);
  226. crc ^= crc32(mux->packet.data, received);
  227. if (crc != 0) {
  228. if (mux->packet.header.length > mux->packet.size)
  229. warning("ignored oversized packet from %.200s:%.200s; client and server have different stream configurations",
  230. res_host, res_service);
  231. else
  232. warning("ignored packet with bad crc from %.200s:%.200s",
  233. res_host, res_service);
  234. return 0;
  235. }
  236. /* check packet version */
  237. if (mux->packet.header.symon_version > SYMON_PACKET_VER) {
  238. warning("ignored packet with unsupported version %d from %.200s:%.200s",
  239. mux->packet.header.symon_version, res_host, res_service);
  240. return 0;
  241. } else {
  242. if (flag_debug) {
  243. debug("good data received from %.200s:%.200s", res_host, res_service);
  244. }
  245. return 1; /* good packet received */
  246. }
  247. }
  248. }
  249. int
  250. accept_connection(int sock)
  251. {
  252. struct sockaddr_storage sind;
  253. socklen_t len;
  254. int clientsock;
  255. bzero(&sind, sizeof(struct sockaddr_storage));
  256. len = 0;
  257. if ((clientsock = accept(sock, (struct sockaddr *) &sind, &len)) < 0)
  258. fatal("failed to accept an incoming connection. (%.200s)",
  259. strerror(errno));
  260. get_numeric_name(&sind);
  261. return clientsock;
  262. }