X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fnet.c;h=bc32b7cc7763e0e14eb27e23d1a2a64da042fba0;hp=f8f84bcd3b900fac5709b9425b302e6da1dd2fbe;hb=f95cc86d0c14ca4c47e5459af4bb6d1170baa9f5;hpb=ed0bf283e37642f9f7673f664713a16d916bd70f diff --git a/src/net.c b/src/net.c index f8f84bcd..bc32b7cc 100644 --- a/src/net.c +++ b/src/net.c @@ -17,7 +17,7 @@ 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.60 2000/11/04 11:49:57 guus Exp $ + $Id: net.c,v 1.35.4.68 2000/11/07 21:43:28 guus Exp $ */ #include "config.h" @@ -74,7 +74,6 @@ int keylifetime = 0; int keyexpires = 0; char *unknown = NULL; -char *interface_name = NULL; /* Contains the name of the interface */ subnet_t mymac; @@ -82,14 +81,11 @@ subnet_t mymac; Execute the given script. This function doesn't really belong here. */ -int execute_script(const char* name) +int execute_script(const char *name) { char *scriptname; pid_t pid; - char **env; - extern char **environment; /* From tincd.c; contains our env */ - - asprintf(&scriptname, "%s/%s", confbase, name); + char *s; if((pid = fork()) < 0) { @@ -100,22 +96,33 @@ int execute_script(const char* name) if(pid) { - free(scriptname); return 0; } /* Child here */ - env = xmalloc(sizeof(environment) + 1 * sizeof(char*)); - memcpy(&(env[1]), environment, sizeof(environment)); - asprintf(&(env[0]), "IFNAME=%s", interface_name); - execle(scriptname, NULL, env); + if(netname) + { + asprintf(&s, "NETNAME=%s", netname); + putenv(s); /* Don't free s! see man 3 putenv */ + } + else + { + unsetenv("NETNAME"); + } + + chdir(confbase); /* This cannot fail since we already read config files from this directory. */ + + asprintf(&scriptname, "%s/%s", confbase, name); + 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); } @@ -145,8 +152,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"), @@ -157,7 +162,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; @@ -281,7 +286,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 @@ -343,14 +348,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) { @@ -358,6 +376,7 @@ cp cl->name, cl->hostname); return -1; } + */ if(!cl->status.validkey) { @@ -399,7 +418,7 @@ int setup_tap_fd(void) 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 @@ -436,18 +455,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; } @@ -491,7 +503,7 @@ cp 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))) { @@ -504,7 +516,7 @@ 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); @@ -582,7 +594,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; @@ -651,7 +663,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); @@ -680,7 +692,6 @@ cp ncn->buffer = xmalloc(MAXBUFSIZE); ncn->buflen = 0; ncn->last_ping_time = time(NULL); - ncn->want_ping = 0; conn_list_add(ncn); @@ -695,6 +706,7 @@ cp int setup_myself(void) { config_t const *cfg; + config_t *next; subnet_t *net; cp myself = new_conn_list(); @@ -703,7 +715,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; @@ -717,7 +729,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; @@ -735,7 +747,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; @@ -751,22 +763,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; @@ -790,13 +802,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(); @@ -806,7 +811,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; @@ -827,7 +832,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. */ @@ -841,7 +846,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); @@ -862,10 +867,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; @@ -876,7 +887,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; @@ -885,7 +896,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); @@ -914,7 +925,6 @@ cp if(myself->status.active) { close(myself->meta_socket); - close(myself->socket); free_conn_list(myself); myself = NULL; } @@ -938,6 +948,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); @@ -949,6 +960,32 @@ cp return -1; } + if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) + { + 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) + { + 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))) + { + 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); @@ -1001,7 +1038,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"), @@ -1030,7 +1066,6 @@ cp } FD_SET(myself->meta_socket, fs); - FD_SET(myself->socket, fs); FD_SET(tap_fd, fs); cp } @@ -1040,18 +1075,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) @@ -1060,7 +1093,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; @@ -1068,11 +1101,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); } /* @@ -1155,7 +1189,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"), @@ -1163,12 +1197,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; } } } @@ -1213,7 +1244,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) { @@ -1223,16 +1253,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; } @@ -1245,9 +1274,6 @@ cp } } - if(FD_ISSET(myself->socket, f)) - handle_incoming_vpn_data(); - if(FD_ISSET(myself->meta_socket, f)) handle_new_meta_connection(); cp