X-Git-Url: https://git.librecmc.org/?p=oweals%2Ftinc.git;a=blobdiff_plain;f=src%2Fnet.c;h=8d92cc10088c305ded504ce6246648a9ba2f163e;hp=016b86ad6207e19603f3f2d64972a63a521bf14a;hb=485f7a5043a4b3345bd02e5063502603550b4c76;hpb=15246df85d6171c92478541a835effb96d6085c4 diff --git a/src/net.c b/src/net.c index 016b86a..8d92cc1 100644 --- a/src/net.c +++ b/src/net.c @@ -17,31 +17,47 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: net.c,v 1.35.4.64 2000/11/04 15:32:05 zarq Exp $ + $Id: net.c,v 1.35.4.76 2000/11/16 22:11:40 zarq Exp $ */ #include "config.h" -#include #include #include -#include -#include #include #include #include #include #include #include -#include #include #include #include #include #include -#include -#include -#include +/* SunOS really wants sys/socket.h BEFORE net/if.h, + and FreeBSD wants these lines below the rest. */ +#include +#include +#include + +#ifdef HAVE_OPENSSL_RAND_H +# include +#else +# include +#endif + +#ifdef HAVE_OPENSSL_EVP_H +# include +#else +# include +#endif + +#ifdef HAVE_OPENSSL_ERR_H +# include +#else +# include +#endif #ifdef HAVE_TUNTAP #include LINUX_IF_TUN_H @@ -52,9 +68,11 @@ #include "conf.h" #include "connlist.h" +#include "list.h" #include "meta.h" #include "net.h" #include "netutl.h" +#include "process.h" #include "protocol.h" #include "subnet.h" @@ -74,66 +92,9 @@ int keylifetime = 0; int keyexpires = 0; char *unknown = NULL; -char *interface_name = NULL; /* Contains the name of the interface */ subnet_t mymac; -/* - Execute the given script. - This function doesn't really belong here. -*/ -int execute_script(const char* name) -{ - char *scriptname; - pid_t pid; - char *s; - - if((pid = fork()) < 0) - { - syslog(LOG_ERR, _("System call `%s' failed: %m"), - "fork"); - return -1; - } - - if(pid) - { - return 0; - } - - /* Child here */ - - asprintf(&scriptname, "%s/%s", confbase, name); - asprintf(&s, "IFNAME=%s", interface_name); - putenv(s); - free(s); - - if(netname) - { - asprintf(&s, "NETNAME=%s", netname); - putenv(s); - free(s); - } - else - { - unsetenv("NETNAME"); - } - - if(chdir(confbase) < 0) - { - syslog(LOG_ERR, _("Couldn't chdir to `%s': %m"), - confbase); - } - - execl(scriptname, NULL); - /* No return on success */ - - if(errno != ENOENT) /* Ignore if the file does not exist */ - syslog(LOG_WARNING, _("Error executing `%s': %m"), scriptname); - - /* No need to free things */ - exit(0); -} - int xsend(conn_list_t *cl, vpn_packet_t *inpkt) { vpn_packet_t outpkt; @@ -160,8 +121,6 @@ cp total_socket_out += outlen; - cl->want_ping = 1; - if((send(cl->socket, (char *) &(outpkt.len), outlen, 0)) < 0) { syslog(LOG_ERR, _("Error sending packet to %s (%s): %m"), @@ -172,7 +131,7 @@ cp return 0; } -int xrecv(vpn_packet_t *inpkt) +int xrecv(conn_list_t *cl, vpn_packet_t *inpkt) { vpn_packet_t outpkt; int outlen, outpad; @@ -296,7 +255,7 @@ cp returned a zero exit code */ void flush_queue(conn_list_t *cl, packet_queue_t **pq, - int (*function)(conn_list_t*,void*)) + int (*function)(conn_list_t*,vpn_packet_t*)) { queue_element_t *p, *next = NULL; cp @@ -358,14 +317,27 @@ cp } return -1; - } + } cl = subnet->owner; + if(cl == myself) + { + if(debug_lvl >= DEBUG_TRAFFIC) + { + syslog(LOG_NOTICE, _("Packet with destination %d.%d.%d.%d is looping back to us!"), + IP_ADDR_V(to)); + } + + return -1; + } + /* If we ourselves have indirectdata flag set, we should send only to our uplink! */ /* FIXME - check for indirection and reprogram it The Right Way(tm) this time. */ + /* Connections are now opened beforehand... + if(!cl->status.dataopen) if(setup_vpn_connection(cl) < 0) { @@ -373,6 +345,7 @@ cp cl->name, cl->hostname); return -1; } + */ if(!cl->status.validkey) { @@ -411,10 +384,9 @@ int setup_tap_fd(void) int nfd; const char *tapfname; config_t const *cfg; - struct ifreq ifr; cp - if((cfg = get_config_val(config, tapdevice))) + if((cfg = get_config_val(config, config_tapdevice))) tapfname = cfg->data.ptr; else #ifdef HAVE_TUNTAP @@ -451,18 +423,11 @@ cp strncpy(ifr.ifr_name, netname, IFNAMSIZ); cp if (!ioctl(tap_fd, TUNSETIFF, (void *) &ifr)) - { + { syslog(LOG_INFO, _("%s is a new style tun/tap device"), tapfname); taptype = TAP_TYPE_TUNTAP; } #endif - - /* Add name of network interface to environment (for scripts) */ - - ioctl(tap_fd, SIOCGIFNAME, (void *) &ifr); - interface_name = xmalloc(strlen(ifr.ifr_name)); - strcpy(interface_name, ifr.ifr_name); - cp return 0; } @@ -486,6 +451,7 @@ cp if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + close(nfd); syslog(LOG_ERR, _("System call `%s' failed: %m"), "setsockopt"); return -1; @@ -493,6 +459,7 @@ cp if(setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one))) { + close(nfd); syslog(LOG_ERR, _("System call `%s' failed: %m"), "setsockopt"); return -1; @@ -501,15 +468,17 @@ cp flags = fcntl(nfd, F_GETFL); if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(nfd); syslog(LOG_ERR, _("System call `%s' failed: %m"), "fcntl"); return -1; } - if((cfg = get_config_val(config, interface))) + if((cfg = get_config_val(config, config_interface))) { if(setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, cfg->data.ptr, strlen(cfg->data.ptr))) { + close(nfd); syslog(LOG_ERR, _("Unable to bind listen socket to interface %s: %m"), cfg->data.ptr); return -1; } @@ -519,19 +488,21 @@ cp a.sin_family = AF_INET; a.sin_port = htons(port); - if((cfg = get_config_val(config, interfaceip))) + if((cfg = get_config_val(config, config_interfaceip))) a.sin_addr.s_addr = htonl(cfg->data.ip->address); else a.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(nfd, (struct sockaddr *)&a, sizeof(struct sockaddr))) { + close(nfd); syslog(LOG_ERR, _("Can't bind to port %hd/tcp: %m"), port); return -1; } if(listen(nfd, 3)) { + close(nfd); syslog(LOG_ERR, _("System call `%s' failed: %m"), "listen"); return -1; @@ -552,12 +523,14 @@ int setup_vpn_in_socket(int port) cp if((nfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + close(nfd); syslog(LOG_ERR, _("Creating socket failed: %m")); return -1; } if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + close(nfd); syslog(LOG_ERR, _("System call `%s' failed: %m"), "setsockopt"); return -1; @@ -566,6 +539,7 @@ cp flags = fcntl(nfd, F_GETFL); if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(nfd); syslog(LOG_ERR, _("System call `%s' failed: %m"), "fcntl"); return -1; @@ -578,6 +552,7 @@ cp if(bind(nfd, (struct sockaddr *)&a, sizeof(struct sockaddr))) { + close(nfd); syslog(LOG_ERR, _("Can't bind to port %hd/udp: %m"), port); return -1; } @@ -597,7 +572,7 @@ cp if(debug_lvl >= DEBUG_CONNECTIONS) syslog(LOG_INFO, _("Trying to connect to %s"), cl->hostname); - if((cfg = get_config_val(cl->config, port)) == NULL) + if((cfg = get_config_val(cl->config, config_port)) == NULL) cl->port = 655; else cl->port = cfg->data.val; @@ -616,6 +591,7 @@ cp if(connect(cl->meta_socket, (struct sockaddr *)&a, sizeof(a)) == -1) { + close(cl->meta_socket); syslog(LOG_ERR, _("%s port %hd: %m"), cl->hostname, cl->port); return -1; } @@ -623,6 +599,7 @@ cp flags = fcntl(cl->meta_socket, F_GETFL); if(fcntl(cl->meta_socket, F_SETFL, flags | O_NONBLOCK) < 0) { + close(cl->meta_socket); syslog(LOG_ERR, _("fcntl for %s port %d: %m"), cl->hostname, cl->port); return -1; @@ -666,7 +643,7 @@ cp return -1; } - if(!(cfg = get_config_val(ncn->config, address))) + if(!(cfg = get_config_val(ncn->config, config_address))) { syslog(LOG_ERR, _("No address specified for %s")); free_conn_list(ncn); @@ -695,7 +672,6 @@ cp ncn->buffer = xmalloc(MAXBUFSIZE); ncn->buflen = 0; ncn->last_ping_time = time(NULL); - ncn->want_ping = 0; conn_list_add(ncn); @@ -710,6 +686,7 @@ cp int setup_myself(void) { config_t const *cfg; + config_t *next; subnet_t *net; cp myself = new_conn_list(); @@ -718,7 +695,7 @@ cp myself->flags = 0; myself->protocol_version = PROT_CURRENT; - if(!(cfg = get_config_val(config, tincname))) /* Not acceptable */ + if(!(cfg = get_config_val(config, config_name))) /* Not acceptable */ { syslog(LOG_ERR, _("Name for tinc daemon required!")); return -1; @@ -732,7 +709,7 @@ cp return -1; } cp - if(!(cfg = get_config_val(config, privatekey))) + if(!(cfg = get_config_val(config, config_privatekey))) { syslog(LOG_ERR, _("Private key for tinc daemon required!")); return -1; @@ -750,7 +727,7 @@ cp return -1; } cp - if(!(cfg = get_config_val(myself->config, publickey))) + if(!(cfg = get_config_val(myself->config, config_publickey))) { syslog(LOG_ERR, _("Public key for tinc daemon required!")); return -1; @@ -766,22 +743,22 @@ cp return -1; } */ - if(!(cfg = get_config_val(myself->config, port))) + if(!(cfg = get_config_val(myself->config, config_port))) myself->port = 655; else myself->port = cfg->data.val; - if((cfg = get_config_val(myself->config, indirectdata))) + if((cfg = get_config_val(myself->config, config_indirectdata))) if(cfg->data.val == stupid_true) myself->flags |= EXPORTINDIRECTDATA; - if((cfg = get_config_val(myself->config, tcponly))) + if((cfg = get_config_val(myself->config, config_tcponly))) if(cfg->data.val == stupid_true) myself->flags |= TCPONLY; /* Read in all the subnets specified in the host configuration file */ - for(cfg = myself->config; (cfg = get_config_val(cfg, subnet)); cfg = cfg->next) + for(next = myself->config; (cfg = get_config_val(next, config_subnet)); next = cfg->next) { net = new_subnet(); net->type = SUBNET_IPV4; @@ -805,13 +782,6 @@ cp return -1; } - if((myself->socket = setup_vpn_in_socket(myself->port)) < 0) - { - syslog(LOG_ERR, _("Unable to set up an incoming vpn data socket!")); - close(myself->meta_socket); - return -1; - } - /* Generate packet encryption key */ myself->cipher_pkttype = EVP_bf_cfb(); @@ -821,7 +791,7 @@ cp myself->cipher_pktkey = (char *)xmalloc(myself->cipher_pktkeylength); RAND_bytes(myself->cipher_pktkey, myself->cipher_pktkeylength); - if(!(cfg = get_config_val(config, keyexpire))) + if(!(cfg = get_config_val(config, config_keyexpire))) keylifetime = 3600; else keylifetime = cfg->data.val; @@ -833,6 +803,8 @@ cp myself->status.active = 1; syslog(LOG_NOTICE, _("Ready: listening on port %hd"), myself->port); + + child_pids = list_new(); cp return 0; } @@ -842,7 +814,7 @@ sigalrm_handler(int a) { config_t const *cfg; cp - cfg = get_config_val(upstreamcfg, connectto); + cfg = get_config_val(upstreamcfg, config_connectto); if(!cfg && upstreamcfg == config) /* No upstream IP given, we're listen only. */ @@ -856,7 +828,7 @@ cp signal(SIGALRM, SIG_IGN); return; } - cfg = get_config_val(upstreamcfg, connectto); /* Or else we try the next ConnectTo line */ + cfg = get_config_val(upstreamcfg, config_connectto); /* Or else we try the next ConnectTo line */ } signal(SIGALRM, sigalrm_handler); @@ -877,10 +849,16 @@ int setup_network_connections(void) { config_t const *cfg; cp - if((cfg = get_config_val(config, pingtimeout)) == NULL) - timeout = 5; + if((cfg = get_config_val(config, config_pingtimeout)) == NULL) + timeout = 60; else - timeout = cfg->data.val; + { + timeout = cfg->data.val; + if(timeout < 1) + { + timeout = 86400; + } + } if(setup_tap_fd() < 0) return -1; @@ -891,7 +869,7 @@ cp /* Run tinc-up script to further initialize the tap interface */ execute_script("tinc-up"); - if(!(cfg = get_config_val(config, connectto))) + if(!(cfg = get_config_val(config, config_connectto))) /* No upstream IP given, we're listen only. */ return 0; @@ -900,7 +878,7 @@ cp upstreamcfg = cfg->next; if(!setup_outgoing_connection(cfg->data.ptr)) /* function returns 0 when there are no problems */ return 0; - cfg = get_config_val(upstreamcfg, connectto); /* Or else we try the next ConnectTo line */ + cfg = get_config_val(upstreamcfg, config_connectto); /* Or else we try the next ConnectTo line */ } signal(SIGALRM, sigalrm_handler); @@ -929,7 +907,6 @@ cp if(myself->status.active) { close(myself->meta_socket); - close(myself->socket); free_conn_list(myself); myself = NULL; } @@ -953,6 +930,7 @@ int setup_vpn_connection(conn_list_t *cl) { int nfd, flags; struct sockaddr_in a; + const int one = 1; cp if(debug_lvl >= DEBUG_TRAFFIC) syslog(LOG_DEBUG, _("Opening UDP socket to %s"), cl->hostname); @@ -964,12 +942,42 @@ cp return -1; } + if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) + { + close(nfd); + syslog(LOG_ERR, _("System call `%s' failed: %m"), + "setsockopt"); + return -1; + } + + flags = fcntl(nfd, F_GETFL); + if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) + { + close(nfd); + syslog(LOG_ERR, _("System call `%s' failed: %m"), + "fcntl"); + return -1; + } + + memset(&a, 0, sizeof(a)); + a.sin_family = AF_INET; + a.sin_port = htons(myself->port); + a.sin_addr.s_addr = htonl(INADDR_ANY); + + if(bind(nfd, (struct sockaddr *)&a, sizeof(struct sockaddr))) + { + close(nfd); + syslog(LOG_ERR, _("Can't bind to port %hd/udp: %m"), myself->port); + return -1; + } + a.sin_family = AF_INET; a.sin_port = htons(cl->port); a.sin_addr.s_addr = htonl(cl->address); if(connect(nfd, (struct sockaddr *)&a, sizeof(a)) == -1) { + close(nfd); syslog(LOG_ERR, _("Connecting to %s port %d failed: %m"), cl->hostname, cl->port); return -1; @@ -978,6 +986,7 @@ cp flags = fcntl(nfd, F_GETFL); if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { + close(nfd); syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m %s (%s)"), __FILE__, __LINE__, nfd, cl->name, cl->hostname); return -1; @@ -1001,7 +1010,7 @@ conn_list_t *create_new_connection(int sfd) cp p = new_conn_list(); - if(getpeername(sfd, &ci, &len) < 0) + if(getpeername(sfd, (struct sockaddr *) &ci, (socklen_t *) &len) < 0) { syslog(LOG_ERR, _("System call `%s' failed: %m"), "getpeername"); @@ -1016,7 +1025,6 @@ cp p->buffer = xmalloc(MAXBUFSIZE); p->buflen = 0; p->last_ping_time = time(NULL); - p->want_ping = 0; if(debug_lvl >= DEBUG_CONNECTIONS) syslog(LOG_NOTICE, _("Connection from %s port %d"), @@ -1045,7 +1053,6 @@ cp } FD_SET(myself->meta_socket, fs); - FD_SET(myself->socket, fs); FD_SET(tap_fd, fs); cp } @@ -1055,18 +1062,16 @@ cp udp socket and write it to the ethertap device after being decrypted */ -int handle_incoming_vpn_data() +int handle_incoming_vpn_data(conn_list_t *cl) { vpn_packet_t pkt; int x, l = sizeof(x); - struct sockaddr from; int lenin; - socklen_t fromlen = sizeof(from); cp - if(getsockopt(myself->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0) + if(getsockopt(cl->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0) { syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m"), - __FILE__, __LINE__, myself->socket); + __FILE__, __LINE__, cl->socket); return -1; } if(x) @@ -1075,7 +1080,7 @@ cp return -1; } - if((lenin = recvfrom(myself->socket, (char *) &(pkt.len), MTU, 0, &from, &fromlen)) <= 0) + if((lenin = recv(cl->socket, (char *) &(pkt.len), MTU, 0)) <= 0) { syslog(LOG_ERR, _("Receiving packet failed: %m")); return -1; @@ -1083,11 +1088,12 @@ cp if(debug_lvl >= DEBUG_TRAFFIC) { - syslog(LOG_DEBUG, _("Received packet of %d bytes"), lenin); - } + syslog(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"), lenin, + cl->name, cl->hostname); + } cp - return xrecv(&pkt); + return xrecv(cl, &pkt); } /* @@ -1170,7 +1176,7 @@ cp { if(p->last_ping_time + timeout < now) { - if(p->status.pinged && !p->status.got_pong) + if(p->status.pinged) { if(debug_lvl >= DEBUG_PROTOCOL) syslog(LOG_INFO, _("%s (%s) didn't respond to PING"), @@ -1178,12 +1184,9 @@ cp p->status.timeout = 1; terminate_connection(p); } - else if(p->want_ping) + else { send_ping(p); - p->last_ping_time = now; - p->status.pinged = 1; - p->status.got_pong = 0; } } } @@ -1228,7 +1231,6 @@ cp void check_network_activity(fd_set *f) { conn_list_t *p; - int x, l = sizeof(x); cp for(p = conn_list; p != NULL; p = p->next) { @@ -1238,16 +1240,15 @@ cp if(p->status.dataopen) if(FD_ISSET(p->socket, f)) { - /* - The only thing that can happen to get us here is apparently an - error on this outgoing(!) UDP socket that isn't immediate (i.e. - something that will not trigger an error directly on send()). - I've once got here when it said `No route to host'. - */ + handle_incoming_vpn_data(p); + + /* Old error stuff (FIXME: copy this to handle_incoming_vpn_data() + getsockopt(p->socket, SOL_SOCKET, SO_ERROR, &x, &l); syslog(LOG_ERR, _("Outgoing data socket error for %s (%s): %s"), p->name, p->hostname, strerror(x)); terminate_connection(p); + */ return; } @@ -1260,9 +1261,6 @@ cp } } - if(FD_ISSET(myself->socket, f)) - handle_incoming_vpn_data(); - if(FD_ISSET(myself->meta_socket, f)) handle_new_meta_connection(); cp @@ -1395,6 +1393,8 @@ cp if(FD_ISSET(tap_fd, &fset)) handle_tap_input(); } + + check_children(); } cp }