X-Git-Url: https://git.librecmc.org/?p=oweals%2Ftinc.git;a=blobdiff_plain;f=src%2Fnet.c;h=dd692e8e547e357e52ea073f273f88ca5a43565d;hp=32c66e8781054fdf07edaae72c28889eaad833b9;hb=afc05797077641baa33b024ffeaafd6cad3ff7a7;hpb=3b9802a542f1fa439321d3386763ec33989194b5 diff --git a/src/net.c b/src/net.c index 32c66e8..dd692e8 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.51 2000/10/29 00:46:43 guus Exp $ + $Id: net.c,v 1.35.4.66 2000/11/04 20:44:26 guus Exp $ */ #include "config.h" @@ -39,6 +39,9 @@ #include #include #include +#include +#include +#include #ifdef HAVE_TUNTAP #include LINUX_IF_TUN_H @@ -48,12 +51,11 @@ #include #include "conf.h" -#include "encr.h" +#include "connlist.h" +#include "meta.h" #include "net.h" #include "netutl.h" #include "protocol.h" -#include "meta.h" -#include "connlist.h" #include "subnet.h" #include "system.h" @@ -68,61 +70,96 @@ int total_socket_out = 0; config_t *upstreamcfg; static int seconds_till_retry; +int keylifetime = 0; +int keyexpires = 0; + char *unknown = NULL; +char *interface_name = NULL; /* Contains the name of the interface */ subnet_t mymac; /* - strip off the MAC adresses of an ethernet frame + Execute the given script. + This function doesn't really belong here. */ -void strip_mac_addresses(vpn_packet_t *p) +int execute_script(const char* name) { -cp - memmove(p->data, p->data + 12, p->len -= 12); -cp -} + char *scriptname; + pid_t pid; + char *s; -/* - reassemble MAC addresses -*/ -void add_mac_addresses(vpn_packet_t *p) -{ -cp - memcpy(p->data + 12, p->data, p->len); - p->len += 12; - p->data[0] = p->data[6] = 0xfe; - p->data[1] = p->data[7] = 0xfd; - /* Really evil pointer stuff just below! */ - *((ip_t*)(&p->data[2])) = (ip_t)(htonl(myself->address)); - *((ip_t*)(&p->data[8])) = *((ip_t*)(&p->data[26])); -cp + 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; int outlen, outpad; + EVP_CIPHER_CTX ctx; cp outpkt.len = inpkt->len; -/* - EVP_EncryptInit(cl->cipher_pktctx, cl->cipher_pkttype, cl->cipher_pktkey, NULL); - EVP_EncryptUpdate(cl->cipher_pktctx, outpkt.data, &outlen, inpkt->data, inpkt->len); - EVP_EncryptFinal(cl->cipher_pktctx, outpkt.data + outlen, &outpad); + + /* Encrypt the packet */ + + EVP_EncryptInit(&ctx, cl->cipher_pkttype, cl->cipher_pktkey, cl->cipher_pktkey + cl->cipher_pkttype->key_len); + EVP_EncryptUpdate(&ctx, outpkt.data, &outlen, inpkt->data, inpkt->len); + EVP_EncryptFinal(&ctx, outpkt.data + outlen, &outpad); outlen += outpad + 2; - Do encryption when everything else is fixed... -*/ +/* Bypass outlen = outpkt.len + 2; memcpy(&outpkt, inpkt, outlen); - +*/ + if(debug_lvl >= DEBUG_TRAFFIC) syslog(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"), outlen, cl->name, cl->hostname); 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"), @@ -137,19 +174,26 @@ int xrecv(vpn_packet_t *inpkt) { vpn_packet_t outpkt; int outlen, outpad; + EVP_CIPHER_CTX ctx; cp outpkt.len = inpkt->len; -/* - EVP_DecryptInit(myself->cipher_pktctx, myself->cipher_pkttype, myself->cipher_pktkey, NULL); - EVP_DecryptUpdate(myself->cipher_pktctx, outpkt.data, &outlen, inpkt->data, inpkt->len); - EVP_DecryptFinal(myself->cipher_pktctx, outpkt.data + outlen, &outpad); + + /* Decrypt the packet */ + + EVP_DecryptInit(&ctx, myself->cipher_pkttype, myself->cipher_pktkey, myself->cipher_pktkey + myself->cipher_pkttype->key_len); + EVP_DecryptUpdate(&ctx, outpkt.data, &outlen, inpkt->data, inpkt->len + 8); + EVP_DecryptFinal(&ctx, outpkt.data + outlen, &outpad); outlen += outpad; - Do decryption is everything else is fixed... -*/ +/* Bypass outlen = outpkt.len+2; memcpy(&outpkt, inpkt, outlen); +*/ + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_ERR, _("Writing packet of %d bytes to tap device"), + outpkt.len, outlen); + /* Fix mac address */ memcpy(outpkt.data, mymac.net.mac.address.x, 6); @@ -312,10 +356,21 @@ 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. */ @@ -330,7 +385,7 @@ cp if(!cl->status.validkey) { -/* Don't queue until everything else is fixed. +/* FIXME: Don't queue until everything else is fixed. if(debug_lvl >= DEBUG_TRAFFIC) syslog(LOG_INFO, _("No valid key known yet for %s (%s), queueing packet"), cl->name, cl->hostname); @@ -343,7 +398,7 @@ cp if(!cl->status.active) { -/* Don't queue until everything else is fixed. +/* FIXME: Don't queue until everything else is fixed. if(debug_lvl >= DEBUG_TRAFFIC) syslog(LOG_INFO, _("%s (%s) is not ready, queueing packet"), cl->name, cl->hostname); @@ -365,7 +420,6 @@ int setup_tap_fd(void) int nfd; const char *tapfname; config_t const *cfg; - char *envvar; struct ifreq ifr; cp @@ -415,9 +469,8 @@ cp /* Add name of network interface to environment (for scripts) */ ioctl(tap_fd, SIOCGIFNAME, (void *) &ifr); - asprintf(&envvar, "IFNAME=%s", ifr.ifr_name); - putenv(envvar); - free(envvar); + interface_name = xmalloc(strlen(ifr.ifr_name)); + strcpy(interface_name, ifr.ifr_name); cp return 0; @@ -442,20 +495,23 @@ cp if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { - syslog(LOG_ERR, _("setsockopt: %m")); + syslog(LOG_ERR, _("System call `%s' failed: %m"), + "setsockopt"); return -1; } if(setsockopt(nfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one))) { - syslog(LOG_ERR, _("setsockopt: %m")); + 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, _("fcntl: %m")); + syslog(LOG_ERR, _("System call `%s' failed: %m"), + "fcntl"); return -1; } @@ -485,7 +541,8 @@ cp if(listen(nfd, 3)) { - syslog(LOG_ERR, _("listen: %m")); + syslog(LOG_ERR, _("System call `%s' failed: %m"), + "listen"); return -1; } cp @@ -510,14 +567,16 @@ cp if(setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { - syslog(LOG_ERR, _("setsockopt: %m")); + 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, _("fcntl: %m")); + syslog(LOG_ERR, _("System call `%s' failed: %m"), + "fcntl"); return -1; } @@ -598,7 +657,7 @@ int setup_outgoing_connection(char *name) { conn_list_t *ncn; struct hostent *h; - config_t *cfg; + config_t const *cfg; cp if(check_id(name)) { @@ -645,7 +704,6 @@ cp ncn->buffer = xmalloc(MAXBUFSIZE); ncn->buflen = 0; ncn->last_ping_time = time(NULL); - ncn->want_ping = 0; conn_list_add(ncn); @@ -762,6 +820,24 @@ cp return -1; } + /* Generate packet encryption key */ + + myself->cipher_pkttype = EVP_bf_cfb(); + + myself->cipher_pktkeylength = myself->cipher_pkttype->key_len + myself->cipher_pkttype->iv_len; + + myself->cipher_pktkey = (char *)xmalloc(myself->cipher_pktkeylength); + RAND_bytes(myself->cipher_pktkey, myself->cipher_pktkeylength); + + if(!(cfg = get_config_val(config, keyexpire))) + keylifetime = 3600; + else + keylifetime = cfg->data.val; + + keyexpires = time(NULL) + keylifetime; + + /* Activate ourselves */ + myself->status.active = 1; syslog(LOG_NOTICE, _("Ready: listening on port %hd"), myself->port); @@ -808,12 +884,17 @@ cp int setup_network_connections(void) { config_t const *cfg; - char *scriptname; cp if((cfg = get_config_val(config, pingtimeout)) == NULL) - timeout = 5; + timeout = 60; else - timeout = cfg->data.val; + { + timeout = cfg->data.val; + if(timeout < 1) + { + timeout = 86400; + } + } if(setup_tap_fd() < 0) return -1; @@ -822,22 +903,8 @@ cp return -1; /* Run tinc-up script to further initialize the tap interface */ - - asprintf(&scriptname, "%s/tinc-up", confbase); - - if(!fork()) - { - - execl(scriptname, NULL); - - if(errno != ENOENT) - syslog(LOG_WARNING, _("Error while executing %s: %m"), scriptname); - - exit(0); - } - - free(scriptname); - + execute_script("tinc-up"); + if(!(cfg = get_config_val(config, connectto))) /* No upstream IP given, we're listen only. */ return 0; @@ -865,20 +932,11 @@ cp void close_network_connections(void) { conn_list_t *p; - char *scriptname; cp for(p = conn_list; p != NULL; p = p->next) { - if(p->status.dataopen) - { - shutdown(p->socket, 0); /* No more receptions */ - close(p->socket); - } - if(p->status.meta) - { - shutdown(p->meta_socket, 0); /* No more receptions */ - close(p->meta_socket); - } + p->status.active = 0; + terminate_connection(p); } if(myself) @@ -886,25 +944,15 @@ cp { close(myself->meta_socket); close(myself->socket); + free_conn_list(myself); + myself = NULL; } - /* Execute tinc-down script right before shutting down the interface */ - - asprintf(&scriptname, "%s/tinc-down", confbase); - - if(!fork()) - { - execl(scriptname, NULL); - - if(errno != ENOENT) - syslog(LOG_WARNING, _("Error while executing %s: %m"), scriptname); + close(tap_fd); - exit(0); - } - - free(scriptname); + /* Execute tinc-down script right after shutting down the interface */ + execute_script("tinc-down"); - close(tap_fd); destroy_conn_list(); syslog(LOG_NOTICE, _("Terminating")); @@ -969,7 +1017,8 @@ cp if(getpeername(sfd, &ci, &len) < 0) { - syslog(LOG_ERR, _("Error: getpeername: %m")); + syslog(LOG_ERR, _("System call `%s' failed: %m"), + "getpeername"); return NULL; } @@ -981,7 +1030,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"), @@ -1025,6 +1073,7 @@ int handle_incoming_vpn_data() 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) @@ -1039,18 +1088,17 @@ cp return -1; } - if(recvfrom(myself->socket, (char *) &(pkt.len), MTU, 0, &from, &fromlen) <= 0) + if((lenin = recvfrom(myself->socket, (char *) &(pkt.len), MTU, 0, &from, &fromlen)) <= 0) { syslog(LOG_ERR, _("Receiving packet failed: %m")); return -1; } -/* + if(debug_lvl >= DEBUG_TRAFFIC) { - syslog(LOG_DEBUG, _("Received packet of %d bytes from %d.%d.%d.%d"), pkt.len, - from.sa_addr[0], from.sa_addr[1], from.sa_addr[2], from.sa_addr[3]); + syslog(LOG_DEBUG, _("Received packet of %d bytes"), lenin); } -*/ + cp return xrecv(&pkt); } @@ -1065,9 +1113,7 @@ void terminate_connection(conn_list_t *cl) subnet_t *s; cp if(cl->status.remove) - { - return; - } + return; cl->status.remove = 1; @@ -1101,19 +1147,19 @@ cp for(s = cl->subnets; s; s = s->next) subnet_del(s); - /* Inactivate */ - - cl->status.active = 0; - /* Check if this was our outgoing connection */ - if(cl->status.outgoing) + if(cl->status.outgoing && cl->status.active) { signal(SIGALRM, sigalrm_handler); seconds_till_retry = 5; alarm(seconds_till_retry); syslog(LOG_NOTICE, _("Trying to re-establish outgoing connection in 5 seconds")); } + + /* Inactivate */ + + cl->status.active = 0; cp } @@ -1137,7 +1183,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"), @@ -1145,12 +1191,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; } } } @@ -1290,6 +1333,7 @@ void main_loop(void) struct timeval tv; int r; time_t last_ping_check; + int t; cp last_ping_check = time(NULL); @@ -1312,28 +1356,45 @@ cp if(sighup) { + syslog(LOG_INFO, _("Rereading configuration file and restarting in 5 seconds")); sighup = 0; -/* FIXME: reprogram this. - if(debug_lvl > 1) - syslog(LOG_INFO, _("Rereading configuration file")); close_network_connections(); - clear_config(); - if(read_config_file(&config, configfilename)) + clear_config(&config); + + if(read_server_config()) { syslog(LOG_ERR, _("Unable to reread configuration file, exiting")); exit(0); } + sleep(5); - setup_network_connections(); -*/ + + if(setup_network_connections()) + return; + continue; } - if(last_ping_check + timeout < time(NULL)) - /* Let's check if everybody is still alive */ + t = time(NULL); + + /* Let's check if everybody is still alive */ + + if(last_ping_check + timeout < t) { check_dead_connections(); last_ping_check = time(NULL); + + /* Should we regenerate our key? */ + + if(keyexpires < t) + { + if(debug_lvl >= DEBUG_STATUS) + syslog(LOG_INFO, _("Regenerating symmetric key")); + + RAND_bytes(myself->cipher_pktkey, myself->cipher_pktkeylength); + send_key_changed(myself, NULL); + keyexpires = time(NULL) + keylifetime; + } } if(r > 0)