]> git.meshlink.io Git - meshlink/blob - src/net_socket.c
fdeac79ae945ea1611284a9e6872a87bc20840a3
[meshlink] / src / net_socket.c
1 /*
2     net_socket.c -- Handle various kinds of sockets.
3     Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
4                   2000-2002 Guus Sliepen <guus@sliepen.warande.net>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: net_socket.c,v 1.1.2.5 2002/03/01 11:18:34 guus Exp $
21 */
22
23 #include "config.h"
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <netdb.h>
28 #include <netinet/in.h>
29 #ifdef HAVE_LINUX
30  #include <netinet/ip.h>
31  #include <netinet/tcp.h>
32 #endif
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <syslog.h>
40 #include <unistd.h>
41 #include <sys/ioctl.h>
42 /* SunOS really wants sys/socket.h BEFORE net/if.h,
43    and FreeBSD wants these lines below the rest. */
44 #include <arpa/inet.h>
45 #include <sys/socket.h>
46 #include <net/if.h>
47
48 #include <utils.h>
49 #include <xalloc.h>
50 #include <avl_tree.h>
51 #include <list.h>
52
53 #include "conf.h"
54 #include "connection.h"
55 #include "meta.h"
56 #include "net.h"
57 #include "netutl.h"
58 #include "process.h"
59 #include "protocol.h"
60 #include "subnet.h"
61 #include "graph.h"
62 #include "process.h"
63 #include "route.h"
64 #include "device.h"
65 #include "event.h"
66
67 #include "system.h"
68
69 int addressfamily = AF_INET;
70 int maxtimeout = 900;
71 int seconds_till_retry = 5;
72
73 int tcp_socket[MAXSOCKETS];
74 int udp_socket[MAXSOCKETS];
75 int tcp_sockets = 0;
76 int udp_sockets = 0;
77
78 /* Setup sockets */
79
80 int setup_listen_socket(sockaddr_t *sa)
81 {
82   int nfd, flags;
83   char *addrstr;
84   int option;
85 #ifdef HAVE_LINUX
86   char *interface;
87   struct ifreq ifr;
88 #endif
89 cp
90   if((nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP)) < 0)
91     {
92       syslog(LOG_ERR, _("Creating metasocket failed: %s"), strerror(errno));
93       return -1;
94     }
95
96   flags = fcntl(nfd, F_GETFL);
97   if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
98     {
99       close(nfd);
100       syslog(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
101       return -1;
102     }
103
104   /* Optimize TCP settings */
105
106   option = 1;
107   setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
108 #ifdef HAVE_LINUX
109   setsockopt(nfd, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
110
111   option = IPTOS_LOWDELAY;
112   setsockopt(nfd, SOL_IP, IP_TOS, &option, sizeof(option));
113
114   if(get_config_string(lookup_config(config_tree, "BindToInterface"), &interface))
115     {
116       memset(&ifr, 0, sizeof(ifr));
117       strncpy(ifr.ifr_ifrn.ifrn_name, interface, IFNAMSIZ);
118       if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)))
119         {
120           close(nfd);
121           syslog(LOG_ERR, _("Can't bind to interface %s: %s"), interface, strerror(errno));
122           return -1;
123         }
124     }
125 #endif
126
127   if(bind(nfd, &sa->sa, SALEN(sa->sa)))
128     {
129       close(nfd);
130       addrstr = sockaddr2hostname(sa);
131       syslog(LOG_ERR, _("Can't bind to %s/tcp: %s"), addrstr, strerror(errno));
132       free(addrstr);
133       return -1;
134     }
135
136   if(listen(nfd, 3))
137     {
138       close(nfd);
139       syslog(LOG_ERR, _("System call `%s' failed: %s"), "listen", strerror(errno));
140       return -1;
141     }
142 cp
143   return nfd;
144 }
145
146 int setup_vpn_in_socket(sockaddr_t *sa)
147 {
148   int nfd, flags;
149   char *addrstr;
150   int option;
151 #ifdef HAVE_LINUX
152   char *interface;
153   struct ifreq ifr;
154 #endif
155 cp
156   if((nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
157     {
158       syslog(LOG_ERR, _("Creating UDP socket failed: %s"), strerror(errno));
159       return -1;
160     }
161
162   flags = fcntl(nfd, F_GETFL);
163   if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
164     {
165       close(nfd);
166       syslog(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
167       return -1;
168     }
169
170   option = 1;
171   setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
172 #ifdef HAVE_LINUX
173   if(get_config_string(lookup_config(config_tree, "BindToInterface"), &interface))
174     {
175       memset(&ifr, 0, sizeof(ifr));
176       strncpy(ifr.ifr_ifrn.ifrn_name, interface, IFNAMSIZ);
177       if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)))
178         {
179           close(nfd);
180           syslog(LOG_ERR, _("Can't bind to interface %s: %s"), interface, strerror(errno));
181           return -1;
182         }
183     }
184 #endif
185
186   if(bind(nfd, &sa->sa, SALEN(sa->sa)))
187     {
188       close(nfd);
189       addrstr = sockaddr2hostname(sa);
190       syslog(LOG_ERR, _("Can't bind to %s/udp: %s"), addrstr, strerror(errno));
191       free(addrstr);
192       return -1;
193     }
194 cp
195   return nfd;
196 }
197
198 void retry_outgoing(outgoing_t *outgoing)
199 {
200   event_t *event;
201 cp
202   outgoing->timeout += 5;
203   if(outgoing->timeout > maxtimeout)
204     outgoing->timeout = maxtimeout;
205
206   event = new_event();
207   event->handler = (event_handler_t)setup_outgoing_connection;
208   event->time = time(NULL) + outgoing->timeout;
209   event->data = outgoing;
210   event_add(event);
211
212   if(debug_lvl >= DEBUG_CONNECTIONS)
213     syslog(LOG_NOTICE, _("Trying to re-establish outgoing connection in %d seconds"), outgoing->timeout);
214 cp
215 }
216
217 int setup_outgoing_socket(connection_t *c)
218 {
219   int option;
220 cp
221   if(debug_lvl >= DEBUG_CONNECTIONS)
222     syslog(LOG_INFO, _("Trying to connect to %s (%s)"), c->name, c->hostname);
223
224   c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
225
226   if(c->socket == -1)
227     {
228       syslog(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname, strerror(errno));
229       return -1;
230     }
231
232   /* Optimize TCP settings */
233
234 #ifdef HAVE_LINUX
235   option = 1;
236   setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
237
238   option = IPTOS_LOWDELAY;
239   setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option));
240 #endif
241
242   /* Connect */
243
244   if(connect(c->socket, &c->address.sa, SALEN(c->address.sa)) == -1)
245     {
246       close(c->socket);
247       syslog(LOG_ERR, _("Error while connecting to %s (%s): %s"), c->name, c->hostname, strerror(errno));
248       return -1;
249     }
250
251   if(debug_lvl >= DEBUG_CONNECTIONS)
252     syslog(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname);
253 cp
254   return 0;
255 }
256
257
258 void finish_connecting(connection_t *c)
259 {
260 cp
261   if(debug_lvl >= DEBUG_CONNECTIONS)
262     syslog(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname);
263
264   c->last_ping_time = time(NULL);
265
266   send_id(c);
267 cp
268 }
269
270 void do_outgoing_connection(connection_t *c)
271 {
272   char *address, *port;
273   int option, result, flags;
274 cp
275 begin:
276   if(!c->outgoing->ai)
277     {
278       if(!c->outgoing->cfg)
279         {
280           if(debug_lvl >= DEBUG_CONNECTIONS)
281             syslog(LOG_ERR, _("Could not set up a meta connection to %s"), c->name);
282           c->status.remove = 1;
283           do_prune = 1;
284           retry_outgoing(c->outgoing);
285           return;
286         }
287
288       get_config_string(c->outgoing->cfg, &address);
289
290       if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
291         asprintf(&port, "655");
292
293       c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
294       free(address);
295       free(port);
296
297       c->outgoing->aip = c->outgoing->ai;
298       c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg);
299     }
300
301   if(!c->outgoing->aip)
302     {
303       freeaddrinfo(c->outgoing->ai);
304       c->outgoing->ai = NULL;
305       goto begin;
306     }
307
308   memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen);
309   c->outgoing->aip = c->outgoing->aip->ai_next;
310
311   if(c->hostname)
312     free(c->hostname);
313
314   c->hostname = sockaddr2hostname(&c->address);
315
316   if(debug_lvl >= DEBUG_CONNECTIONS)
317     syslog(LOG_INFO, _("Trying to connect to %s (%s)"), c->name, c->hostname);
318
319   c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
320
321   if(c->socket == -1)
322     {
323       if(debug_lvl >= DEBUG_CONNECTIONS)
324         syslog(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname, strerror(errno));
325
326       goto begin;
327     }
328
329   /* Optimize TCP settings */
330
331 #ifdef HAVE_LINUX
332   option = 1;
333   setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
334
335   option = IPTOS_LOWDELAY;
336   setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option));
337 #endif
338
339   /* Non-blocking */
340
341   flags = fcntl(c->socket, F_GETFL);
342
343   if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0)
344     {
345       syslog(LOG_ERR, _("fcntl for %s: %s"), c->hostname, strerror(errno));
346     }
347
348   /* Connect */
349
350   result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
351
352   if(result == -1)
353     {
354       if(errno == EINPROGRESS)
355         {
356           c->status.connecting = 1;
357           return;
358         }
359
360       close(c->socket);
361
362       if(debug_lvl >= DEBUG_CONNECTIONS)
363         syslog(LOG_ERR, _("%s: %s"), c->hostname, strerror(errno));
364
365       goto begin;
366     }
367
368   finish_connecting(c);
369   return;
370 cp
371 }
372
373 void setup_outgoing_connection(outgoing_t *outgoing)
374 {
375   connection_t *c;
376   node_t *n;
377 cp
378   n = lookup_node(outgoing->name);
379   
380   if(n)
381     if(n->connection)
382       {
383         if(debug_lvl >= DEBUG_CONNECTIONS)       
384           syslog(LOG_INFO, _("Already connected to %s"), outgoing->name);
385         n->connection->outgoing = outgoing;
386         return;
387       }
388
389   c = new_connection();
390   c->name = xstrdup(outgoing->name);
391   c->outcipher = myself->connection->outcipher;
392   c->outdigest = myself->connection->outdigest;
393   c->outmaclength = myself->connection->outmaclength;
394   c->outcompression = myself->connection->outcompression;
395
396   init_configuration(&c->config_tree);
397   read_connection_config(c);
398   
399   outgoing->cfg = lookup_config(c->config_tree, "Address");
400   
401   if(!outgoing->cfg)
402     {
403       syslog(LOG_ERR, _("No address specified for %s"), c->name);
404       free_connection(c);
405       free(outgoing->name);
406       free(outgoing);
407       return;
408     }
409   
410   c->outgoing = outgoing;
411   c->last_ping_time = time(NULL);
412
413   connection_add(c);
414
415   do_outgoing_connection(c);
416 }
417
418 /*
419   accept a new tcp connect and create a
420   new connection
421 */
422 int handle_new_meta_connection(int sock)
423 {
424   connection_t *c;
425   sockaddr_t sa;
426   int fd, len = sizeof(sa);
427 cp
428   if((fd = accept(sock, &sa.sa, &len)) < 0)
429     {
430       syslog(LOG_ERR, _("Accepting a new connection failed: %s"), strerror(errno));
431       return -1;
432     }
433
434   c = new_connection();
435   c->outcipher = myself->connection->outcipher;
436   c->outdigest = myself->connection->outdigest;
437   c->outmaclength = myself->connection->outmaclength;
438   c->outcompression = myself->connection->outcompression;
439
440   c->address = sa;
441   c->hostname = sockaddr2hostname(&sa);
442   c->socket = fd;
443   c->last_ping_time = time(NULL);
444
445   if(debug_lvl >= DEBUG_CONNECTIONS)
446     syslog(LOG_NOTICE, _("Connection from %s"), c->hostname);
447
448   connection_add(c);
449
450   c->allow_request = ID;
451   send_id(c);
452 cp
453   return 0;
454 }
455
456 void try_outgoing_connections(void)
457 {
458   static config_t *cfg = NULL;
459   char *name;
460   outgoing_t *outgoing;
461 cp
462   for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg))
463     {
464       get_config_string(cfg, &name);
465
466       if(check_id(name))
467         {
468           syslog(LOG_ERR, _("Invalid name for outgoing connection in %s line %d"), cfg->file, cfg->line);
469           free(name);
470           continue;
471         }
472
473       outgoing = xmalloc_and_zero(sizeof(*outgoing));
474       outgoing->name = name;
475       setup_outgoing_connection(outgoing);
476     }
477 }