2 net_socket.c -- Handle various kinds of sockets.
3 Copyright (C) 1998-2003 Ivo Timmermans <ivo@o2w.nl>,
4 2000-2003 Guus Sliepen <guus@sliepen.eu.org>
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.
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.
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.
20 $Id: net_socket.c,v 1.1.2.38 2003/12/22 11:04:16 guus Exp $
25 #include <gnutls/gnutls.h>
29 #include "connection.h"
40 #define EINPROGRESS WSAEINPROGRESS
43 int addressfamily = AF_UNSPEC;
45 int seconds_till_retry = 5;
47 listen_socket_t listen_socket[MAXSOCKETS];
50 int certselfunc(gnutls_session session, const gnutls_datum *client_cert, int ncerts, const gnutls_datum* req_ca_cert, int nreqs) {
51 logger(LOG_DEBUG, "Client certificate select function called with %d certs, %d requests\n", ncerts, nreqs);
55 int scertselfunc(gnutls_session session, const gnutls_datum *server_cert, int ncerts) {
56 logger(LOG_DEBUG, "Server certificate select function called with %d certs\n", ncerts);
62 int setup_listen_socket(const sockaddr_t *sa)
71 nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
74 ifdebug(STATUS) logger(LOG_ERR, _("Creating metasocket failed: %s"), strerror(errno));
80 int flags = fcntl(nfd, F_GETFL);
82 if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
84 logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl",
91 /* Optimize TCP settings */
94 setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
96 #if defined(SOL_TCP) && defined(TCP_NODELAY)
97 setsockopt(nfd, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
100 #if defined(SOL_IP) && defined(IP_TOS) && defined(IPTOS_LOWDELAY)
101 option = IPTOS_LOWDELAY;
102 setsockopt(nfd, SOL_IP, IP_TOS, &option, sizeof(option));
106 (lookup_config(config_tree, "BindToInterface"), &iface)) {
107 #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
110 memset(&ifr, 0, sizeof(ifr));
111 strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
113 if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) {
115 logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
120 logger(LOG_WARNING, _("BindToInterface not supported on this platform"));
124 if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
126 addrstr = sockaddr2hostname(sa);
127 logger(LOG_ERR, _("Can't bind to %s/tcp: %s"), addrstr,
135 logger(LOG_ERR, _("System call `%s' failed: %s"), "listen",
143 int setup_vpn_in_socket(const sockaddr_t *sa)
151 nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
154 logger(LOG_ERR, _("Creating UDP socket failed: %s"), strerror(errno));
160 int flags = fcntl(nfd, F_GETFL);
162 if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
164 logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl",
172 setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
174 #if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
178 if(get_config_bool(lookup_config(myself->connection->config_tree, "PMTUDiscovery"), &choice) && choice) {
179 option = IP_PMTUDISC_DO;
180 setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, &option, sizeof(option));
185 #if defined(SOL_IPV6) && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
189 if(get_config_bool(lookup_config(myself->connection->config_tree, "PMTUDiscovery"), &choice) && choice) {
190 option = IPV6_PMTUDISC_DO;
191 setsockopt(nfd, SOL_IPV6, IPV6_MTU_DISCOVER, &option, sizeof(option));
196 #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
201 if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) {
202 memset(&ifr, 0, sizeof(ifr));
203 strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
205 if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) {
207 logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
215 if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
217 addrstr = sockaddr2hostname(sa);
218 logger(LOG_ERR, _("Can't bind to %s/udp: %s"), addrstr,
227 void retry_outgoing(outgoing_t *outgoing)
233 outgoing->timeout += 5;
235 if(outgoing->timeout > maxtimeout)
236 outgoing->timeout = maxtimeout;
239 event->handler = (event_handler_t) setup_outgoing_connection;
240 event->time = now + outgoing->timeout;
241 event->data = outgoing;
244 ifdebug(CONNECTIONS) logger(LOG_NOTICE,
245 _("Trying to re-establish outgoing connection in %d seconds"),
249 void finish_connecting(connection_t *c)
255 ifdebug(CONNECTIONS) logger(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname);
257 c->last_ping_time = now;
259 gnutls_init(&c->session, GNUTLS_SERVER);
260 gnutls_set_default_priority(c->session);
261 gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, myself->connection->credentials);
262 gnutls_certificate_server_set_request(c->session, GNUTLS_CERT_REQUEST);
263 // gnutls_certificate_client_set_select_function(c->session, certselfunc);
264 // gnutls_certificate_server_set_select_function(c->session, scertselfunc);
265 gnutls_transport_set_ptr(c->session, c->socket);
268 void do_outgoing_connection(connection_t *c)
270 char *address, *port;
271 int option, result, flags;
276 if(!c->outgoing->ai) {
277 if(!c->outgoing->cfg) {
278 ifdebug(CONNECTIONS) logger(LOG_ERR, _("Could not set up a meta connection to %s"),
280 c->status.remove = true;
281 retry_outgoing(c->outgoing);
285 get_config_string(c->outgoing->cfg, &address);
287 if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
288 asprintf(&port, "655");
290 c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
294 c->outgoing->aip = c->outgoing->ai;
295 c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg);
298 if(!c->outgoing->aip) {
299 freeaddrinfo(c->outgoing->ai);
300 c->outgoing->ai = NULL;
304 memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen);
305 c->outgoing->aip = c->outgoing->aip->ai_next;
310 c->hostname = sockaddr2hostname(&c->address);
312 ifdebug(CONNECTIONS) logger(LOG_INFO, _("Trying to connect to %s (%s)"), c->name,
315 c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
317 if(c->socket == -1) {
318 ifdebug(CONNECTIONS) logger(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname,
324 /* Optimize TCP settings */
326 #if defined(SOL_TCP) && defined(TCP_NODELAY)
328 setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
331 #if defined(SOL_IP) && defined(IP_TOS)
332 option = IPTOS_LOWDELAY;
333 setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option));
339 flags = fcntl(c->socket, F_GETFL);
341 if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0) {
342 logger(LOG_ERR, _("fcntl for %s: %s"), c->hostname, strerror(errno));
348 result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
351 if(errno == EINPROGRESS) {
352 c->status.connecting = true;
356 closesocket(c->socket);
358 ifdebug(CONNECTIONS) logger(LOG_ERR, _("%s: %s"), c->hostname, strerror(errno));
363 logger(LOG_DEBUG, _("finishing connection"));
364 finish_connecting(c);
369 void setup_outgoing_connection(outgoing_t *outgoing)
376 n = lookup_node(outgoing->name);
380 ifdebug(CONNECTIONS) logger(LOG_INFO, _("Already connected to %s"), outgoing->name);
382 n->connection->outgoing = outgoing;
386 c = new_connection();
387 c->name = xstrdup(outgoing->name);
389 init_configuration(&c->config_tree);
390 read_connection_config(c);
392 outgoing->cfg = lookup_config(c->config_tree, "Address");
395 logger(LOG_ERR, _("No address specified for %s"), c->name);
397 free(outgoing->name);
402 c->outgoing = outgoing;
403 c->last_ping_time = now;
407 do_outgoing_connection(c);
411 accept a new tcp connect and create a
414 bool handle_new_meta_connection(int sock)
418 int fd, len = sizeof(sa);
423 fd = accept(sock, &sa.sa, &len);
426 logger(LOG_ERR, _("Accepting a new connection failed: %s"),
433 int flags = fcntl(fd, F_GETFL);
435 if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
437 logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl",
446 c = new_connection();
449 c->hostname = sockaddr2hostname(&sa);
451 c->last_ping_time = now;
453 ifdebug(CONNECTIONS) logger(LOG_NOTICE, _("Connection from %s"), c->hostname);
457 c->allow_request = ID;
458 gnutls_init(&c->session, GNUTLS_CLIENT);
459 gnutls_set_default_priority(c->session);
460 gnutls_credentials_set(c->session, GNUTLS_CRD_CERTIFICATE, myself->connection->credentials);
461 gnutls_certificate_server_set_request(c->session, GNUTLS_CERT_REQUEST);
462 // gnutls_certificate_client_set_select_function(c->session, certselfunc);
463 // gnutls_certificate_server_set_select_function(c->session, scertselfunc);
464 gnutls_transport_set_ptr(c->session, c->socket);
465 gnutls_handshake(c->session);
470 void try_outgoing_connections(void)
472 static config_t *cfg = NULL;
474 outgoing_t *outgoing;
478 for(cfg = lookup_config(config_tree, "ConnectTo"); cfg;
479 cfg = lookup_config_next(config_tree, cfg)) {
480 get_config_string(cfg, &name);
482 if(!check_id(name)) {
484 _("Invalid name for outgoing connection in %s line %d"),
485 cfg->file, cfg->line);
490 outgoing = xmalloc_and_zero(sizeof(*outgoing));
491 outgoing->name = name;
492 setup_outgoing_connection(outgoing);