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