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