symuxnet.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /* $Id: symuxnet.c,v 1.19 2005/02/16 20:24:51 dijkstra Exp $ */
  2. /*
  3. * Copyright (c) 2001-2004 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;
  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. /*
  71. * does the mux statement specify a specific destination
  72. * address
  73. */
  74. if (mux->sockaddr.ss_family == family) {
  75. cpysock((struct sockaddr *) & mux->sockaddr, &sockaddr);
  76. } else {
  77. get_inaddrany_sockaddr(&sockaddr, family, SOCK_DGRAM, mux->port);
  78. }
  79. if (bind(mux->symonsocket[family], (struct sockaddr *) & sockaddr,
  80. SS_LEN(&sockaddr)) == -1) {
  81. switch (errno) {
  82. case EADDRNOTAVAIL:
  83. warning("mux address %.200s is not a local address", mux->addr);
  84. break;
  85. case EADDRINUSE:
  86. warning("mux address %.200s %.200s already in use", mux->addr, mux->port);
  87. break;
  88. case EACCES:
  89. warning("mux port %.200s is restricted from current user", mux->port);
  90. break;
  91. default:
  92. warning("mux port %.200s bind failed", mux->port);
  93. break;
  94. }
  95. close(mux->symonsocket[family]);
  96. mux->symonsocket[family] = 0;
  97. } else {
  98. if (get_numeric_name(&sockaddr)) {
  99. info("getnameinfo error - cannot determine numeric hostname and service");
  100. info("listening for incoming symon traffic for family %d", family);
  101. } else
  102. info("listening for incoming symon traffic on udp %.200s %.200s",
  103. res_host, res_service);
  104. nsocks++;
  105. }
  106. }
  107. }
  108. }
  109. return nsocks;
  110. }
  111. /* Obtain a listen socket for new clients */
  112. int
  113. get_client_socket(struct mux * mux)
  114. {
  115. struct addrinfo hints, *res;
  116. int error, sock, one = 1;
  117. if ((sock = socket(mux->sockaddr.ss_family, SOCK_STREAM, 0)) == -1)
  118. fatal("could not obtain socket: %.200s", strerror(errno));
  119. if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
  120. fatal ("could set socket options: %.200s", strerror (errno));
  121. }
  122. bzero((void *) &hints, sizeof(struct addrinfo));
  123. hints.ai_family = mux->sockaddr.ss_family;
  124. hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
  125. hints.ai_socktype = SOCK_STREAM;
  126. if ((error = getaddrinfo(mux->addr, mux->port, &hints, &res)) != 0)
  127. fatal("could not get address information for %.200s:%.200s - %.200s",
  128. mux->addr, mux->port, gai_strerror(error));
  129. if (bind(sock, (struct sockaddr *) res->ai_addr, res->ai_addrlen) == -1)
  130. fatal("could not bind socket: %.200s", strerror(errno));
  131. freeaddrinfo(res);
  132. if (listen(sock, SYMUX_TCPBACKLOG) == -1)
  133. fatal("could not listen to socket: %.200s", strerror(errno));
  134. fcntl(sock, O_NONBLOCK);
  135. mux->clientsocket = sock;
  136. info("listening for incoming connections on tcp %.200s %.200s",
  137. mux->addr, mux->port);
  138. return sock;
  139. }
  140. /*
  141. * Wait for traffic (symon reports from a source in sourclist | clients trying to connect
  142. * Returns the <source> and <packet>
  143. * Silently forks off clienthandlers
  144. */
  145. void
  146. wait_for_traffic(struct mux * mux, struct source ** source,
  147. struct symonpacket * packet)
  148. {
  149. fd_set readset;
  150. int i;
  151. int socksactive;
  152. int maxsock;
  153. for (;;) { /* FOREVER - until a valid symon packet is
  154. * received */
  155. FD_ZERO(&readset);
  156. FD_SET(mux->clientsocket, &readset);
  157. maxsock = mux->clientsocket;
  158. for (i = 0; i < AF_MAX; i++) {
  159. if (mux->symonsocket[i] > 0) {
  160. FD_SET(mux->symonsocket[i], &readset);
  161. maxsock = ((maxsock < mux->symonsocket[i]) ? mux->symonsocket[i] :
  162. maxsock);
  163. }
  164. }
  165. maxsock++;
  166. socksactive = select(maxsock, &readset, NULL, NULL, NULL);
  167. if (socksactive != -1) {
  168. if (FD_ISSET(mux->clientsocket, &readset)) {
  169. spawn_client(mux->clientsocket);
  170. }
  171. for (i = 0; i < AF_MAX; i++)
  172. if (FD_ISSET(mux->symonsocket[i], &readset)) {
  173. if (recv_symon_packet(mux, i, source, packet))
  174. return;
  175. }
  176. } else {
  177. if (errno == EINTR)
  178. return; /* signal received while waiting, bail out */
  179. }
  180. }
  181. }
  182. /* Receive a symon packet for mux. Checks if the source is allowed and returns the source found.
  183. * return 0 if no valid packet found
  184. */
  185. int
  186. recv_symon_packet(struct mux * mux, int socknr, struct source ** source,
  187. struct symonpacket * packet)
  188. {
  189. struct sockaddr_storage sind;
  190. socklen_t sl;
  191. int size, tries;
  192. unsigned int received;
  193. u_int32_t crc;
  194. received = 0;
  195. tries = 0;
  196. do {
  197. sl = sizeof(sind);
  198. size = recvfrom(mux->symonsocket[socknr],
  199. (void *) (packet->data + received),
  200. sizeof(struct symonpacket) - received,
  201. 0, (struct sockaddr *) &sind, &sl);
  202. if (size > 0)
  203. received += size;
  204. tries++;
  205. } while ((size == -1) &&
  206. (errno == EAGAIN || errno == EINTR) &&
  207. (tries < SYMUX_MAXREADTRIES) &&
  208. (received < sizeof(packet->data)));
  209. if ((size == -1) &&
  210. errno)
  211. warning("recvfrom failed: %.200s", strerror(errno));
  212. *source = find_source_sockaddr(&mux->sol, (struct sockaddr *) &sind);
  213. get_numeric_name(&sind);
  214. if (*source == NULL) {
  215. debug("ignored data from %.200s:%.200s", res_host, res_service);
  216. return 0;
  217. } else {
  218. /* get header stream */
  219. mux->offset = getheader(packet->data, &packet->header);
  220. /* check crc */
  221. crc = packet->header.crc;
  222. packet->header.crc = 0;
  223. setheader(packet->data, &packet->header);
  224. crc ^= crc32(packet->data, received);
  225. if (crc != 0) {
  226. warning("ignored packet with bad crc from %.200s:%.200s",
  227. res_host, res_service);
  228. return 0;
  229. }
  230. /* check packet version */
  231. if (packet->header.symon_version != SYMON_PACKET_VER) {
  232. warning("ignored packet with wrong version %d from %.200s:%.200s",
  233. packet->header.symon_version, res_host, res_service);
  234. return 0;
  235. } else {
  236. if (flag_debug) {
  237. debug("good data received from %.200s:%.200s", res_host, res_service);
  238. }
  239. return 1; /* good packet received */
  240. }
  241. }
  242. }
  243. int
  244. accept_connection(int sock)
  245. {
  246. struct sockaddr_storage sind;
  247. socklen_t len;
  248. int clientsock;
  249. if ((clientsock = accept(sock, (struct sockaddr *) &sind, &len)) < 0)
  250. fatal("failed to accept an incoming connection. (%.200s)",
  251. strerror(errno));
  252. get_numeric_name(&sind);
  253. return clientsock;
  254. }