123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- /*
- * Copyright (c) 2001-2007 Willem Dijkstra
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <string.h>
- #include <unistd.h>
- #include "conf.h"
- #include "data.h"
- #include "error.h"
- #include "symux.h"
- #include "symuxnet.h"
- #include "net.h"
- #include "xmalloc.h"
- #include "share.h"
- __BEGIN_DECLS
- int check_crc_packet(struct symonpacket *);
- __END_DECLS
- /* Obtain sockets for incoming symon traffic */
- int
- get_symon_sockets(struct mux * mux)
- {
- struct source *source;
- struct sockaddr_storage sockaddr;
- int family, nsocks, one = 1;
- nsocks = 0;
- /* generate the udp listen socket specified in the mux statement */
- get_mux_sockaddr(mux, SOCK_DGRAM);
- /* iterate over our sources to determine what types of sockets we need */
- SLIST_FOREACH(source, &mux->sol, sources) {
- if (!get_source_sockaddr(source, AF_INET)) {
- if (!get_source_sockaddr(source, AF_INET6)) {
- warning("cannot determine socket family for source %.200s", source->addr);
- }
- }
- family = source->sockaddr.ss_family;
- /* do we have a socket for this type of family */
- if (mux->symonsocket[family] <= 0) {
- if ((mux->symonsocket[family] = socket(family, SOCK_DGRAM, 0)) != -1) {
- /* attempt to set reuse, ignore errors */
- if (setsockopt(mux->symonsocket[family], SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
- warning ("could set socket options: %.200s", strerror(errno));
- }
- /*
- * does the mux statement specify a specific destination
- * address
- */
- if (mux->sockaddr.ss_family == family) {
- cpysock((struct sockaddr *) & mux->sockaddr, &sockaddr);
- } else {
- get_sockaddr(&sockaddr, family, SOCK_DGRAM, AI_PASSIVE, NULL, mux->port);
- }
- if (bind(mux->symonsocket[family], (struct sockaddr *) & sockaddr,
- SS_LEN(&sockaddr)) == -1) {
- switch (errno) {
- case EADDRNOTAVAIL:
- warning("mux address %.200s is not a local address", mux->addr);
- break;
- case EADDRINUSE:
- warning("mux address %.200s %.200s already in use", mux->addr, mux->port);
- break;
- case EACCES:
- warning("mux port %.200s is restricted from current user", mux->port);
- break;
- default:
- warning("mux port %.200s bind failed", mux->port);
- break;
- }
- close(mux->symonsocket[family]);
- mux->symonsocket[family] = 0;
- } else {
- if (get_numeric_name(&sockaddr)) {
- info("getnameinfo error - cannot determine numeric hostname and service");
- info("listening for incoming symon traffic for family %d", family);
- } else
- info("listening for incoming symon traffic on udp %.200s %.200s",
- res_host, res_service);
- nsocks++;
- }
- }
- }
- }
- return nsocks;
- }
- /* Obtain a listen socket for new clients */
- int
- get_client_socket(struct mux * mux)
- {
- struct addrinfo hints, *res;
- int error, sock, one = 1;
- if ((sock = socket(mux->sockaddr.ss_family, SOCK_STREAM, 0)) == -1)
- fatal("could not obtain socket: %.200s", strerror(errno));
- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
- fatal ("could set socket options: %.200s", strerror(errno));
- }
- bzero((void *) &hints, sizeof(struct addrinfo));
- hints.ai_family = mux->sockaddr.ss_family;
- hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
- hints.ai_socktype = SOCK_STREAM;
- if ((error = getaddrinfo(mux->addr, mux->port, &hints, &res)) != 0)
- fatal("could not get address information for %.200s:%.200s - %.200s",
- mux->addr, mux->port, gai_strerror(error));
- if (bind(sock, (struct sockaddr *) res->ai_addr, res->ai_addrlen) == -1)
- fatal("could not bind socket: %.200s", strerror(errno));
- freeaddrinfo(res);
- if (listen(sock, SYMUX_TCPBACKLOG) == -1)
- fatal("could not listen to socket: %.200s", strerror(errno));
- fcntl(sock, O_NONBLOCK);
- mux->clientsocket = sock;
- info("listening for incoming connections on tcp %.200s %.200s",
- mux->addr, mux->port);
- return sock;
- }
- /*
- * Wait for traffic (symon reports from a source in sourclist | clients trying to connect
- * Returns the <source> and <packet>
- * Silently forks off clienthandlers
- */
- void
- wait_for_traffic(struct mux * mux, struct source ** source)
- {
- fd_set readset;
- int i;
- int socksactive;
- int maxsock;
- for (;;) { /* FOREVER - until a valid symon packet is
- * received */
- FD_ZERO(&readset);
- FD_SET(mux->clientsocket, &readset);
- maxsock = mux->clientsocket;
- for (i = 0; i < AF_MAX; i++) {
- if (mux->symonsocket[i] > 0) {
- FD_SET(mux->symonsocket[i], &readset);
- maxsock = ((maxsock < mux->symonsocket[i]) ? mux->symonsocket[i] :
- maxsock);
- }
- }
- maxsock++;
- socksactive = select(maxsock, &readset, NULL, NULL, NULL);
- if (socksactive != -1) {
- if (FD_ISSET(mux->clientsocket, &readset)) {
- spawn_client(mux->clientsocket);
- }
- for (i = 0; i < AF_MAX; i++)
- if (FD_ISSET(mux->symonsocket[i], &readset)) {
- if (recv_symon_packet(mux, i, source))
- return;
- }
- } else {
- if (errno == EINTR)
- return; /* signal received while waiting, bail out */
- }
- }
- }
- /* Receive a symon packet for mux. Checks if the source is allowed and returns the source found.
- * return 0 if no valid packet found
- */
- int
- recv_symon_packet(struct mux * mux, int socknr, struct source ** source)
- {
- struct sockaddr_storage sind;
- socklen_t sl;
- int size, tries;
- unsigned int received;
- u_int32_t crc;
- received = 0;
- tries = 0;
- do {
- sl = sizeof(sind);
- size = recvfrom(mux->symonsocket[socknr],
- (mux->packet.data + received),
- (mux->packet.size - received),
- 0, (struct sockaddr *) &sind, &sl);
- if (size > 0)
- received += size;
- tries++;
- } while ((size == -1) &&
- (errno == EAGAIN || errno == EINTR) &&
- (tries < SYMUX_MAXREADTRIES) &&
- (received < mux->packet.size));
- if ((size == -1) &&
- errno)
- warning("recvfrom failed: %.200s", strerror(errno));
- *source = find_source_sockaddr(&mux->sol, (struct sockaddr *) &sind);
- get_numeric_name(&sind);
- if (*source == NULL) {
- debug("ignored data from %.200s:%.200s", res_host, res_service);
- return 0;
- } else {
- /* get header stream */
- mux->packet.offset = getheader(mux->packet.data, &mux->packet.header);
- /* check crc */
- crc = mux->packet.header.crc;
- mux->packet.header.crc = 0;
- setheader(mux->packet.data, &mux->packet.header);
- crc ^= crc32(mux->packet.data, received);
- if (crc != 0) {
- if (mux->packet.header.length > mux->packet.size)
- warning("ignored oversized packet from %.200s:%.200s; client and server have different stream configurations",
- res_host, res_service);
- else
- warning("ignored packet with bad crc from %.200s:%.200s",
- res_host, res_service);
- return 0;
- }
- /* check packet version */
- if (mux->packet.header.symon_version > SYMON_PACKET_VER) {
- warning("ignored packet with unsupported version %d from %.200s:%.200s",
- mux->packet.header.symon_version, res_host, res_service);
- return 0;
- } else {
- if (flag_debug) {
- debug("good data received from %.200s:%.200s", res_host, res_service);
- }
- return 1; /* good packet received */
- }
- }
- }
- int
- accept_connection(int sock)
- {
- struct sockaddr_storage sind;
- socklen_t len;
- int clientsock;
- bzero(&sind, sizeof(struct sockaddr_storage));
- len = 0;
- if ((clientsock = accept(sock, (struct sockaddr *) &sind, &len)) < 0)
- fatal("failed to accept an incoming connection. (%.200s)",
- strerror(errno));
- get_numeric_name(&sind);
- return clientsock;
- }
|