X-Git-Url: https://www.tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fnet.c;h=4a369ff737e7b5eec4163b6a27d154de55d97f10;hp=a42ebce43de590c42c43722c0f15eab3b1b89e7c;hb=9de5787574b21e94c80ddc60def2b3e514aff755;hpb=e924096f62655d711cd2d114a8d1ef0fecbb593b diff --git a/src/net.c b/src/net.c index a42ebce4..4a369ff7 100644 --- a/src/net.c +++ b/src/net.c @@ -1,7 +1,7 @@ /* net.c -- most of the network code - Copyright (C) 1998,1999,2000 Ivo Timmermans , - 2000 Guus Sliepen + Copyright (C) 1998-2001 Ivo Timmermans , + 2000,2001 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -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.89 2001/01/05 23:53:49 guus Exp $ + $Id: net.c,v 1.35.4.95 2001/02/25 16:04:00 guus Exp $ */ #include "config.h" @@ -72,10 +72,10 @@ #include #include #include +#include #include "conf.h" #include "connection.h" -#include "list.h" #include "meta.h" #include "net.h" #include "netutl.h" @@ -112,7 +112,7 @@ int xsend(connection_t *cl, vpn_packet_t *inpkt) cp outpkt.len = inpkt->len; - /* Encrypt the packet */ + /* Encrypt the packet. FIXME: we should use CBC, not CFB. */ 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); @@ -163,156 +163,38 @@ cp outlen = outpkt.len+2; memcpy(&outpkt, inpkt, outlen); */ - +cp + return receive_packet(cl, &outpkt); +} + +int receive_packet(connection_t *cl, vpn_packet_t *packet) +{ if(debug_lvl >= DEBUG_TRAFFIC) syslog(LOG_ERR, _("Writing packet of %d bytes to tap device"), - outpkt.len); + packet->len); /* Fix mac address */ - memcpy(outpkt.data, mymac.net.mac.address.x, 6); + memcpy(packet->data, mymac.net.mac.address.x, 6); if(taptype == TAP_TYPE_TUNTAP) { - if(write(tap_fd, outpkt.data, outpkt.len) < 0) + if(write(tap_fd, packet->data, packet->len) < 0) syslog(LOG_ERR, _("Can't write to tun/tap device: %m")); else - total_tap_out += outpkt.len; + total_tap_out += packet->len; } else /* ethertap */ { - if(write(tap_fd, outpkt.data - 2, outpkt.len + 2) < 0) + if(write(tap_fd, packet->data - 2, packet->len + 2) < 0) syslog(LOG_ERR, _("Can't write to ethertap device: %m")); else - total_tap_out += outpkt.len + 2; + total_tap_out += packet->len + 2; } cp return 0; } -/* - add the given packet of size s to the - queue q, be it the send or receive queue -*/ -void add_queue(packet_queue_t **q, void *packet, size_t s) -{ - queue_element_t *e; -cp - e = xmalloc(sizeof(*e)); - e->packet = xmalloc(s); - memcpy(e->packet, packet, s); - - if(!*q) - { - *q = xmalloc(sizeof(**q)); - (*q)->head = (*q)->tail = NULL; - } - - e->next = NULL; /* We insert at the tail */ - - if((*q)->tail) /* Do we have a tail? */ - { - (*q)->tail->next = e; - e->prev = (*q)->tail; - } - else /* No tail -> no head too */ - { - (*q)->head = e; - e->prev = NULL; - } - - (*q)->tail = e; -cp -} - -/* Remove a queue element */ -void del_queue(packet_queue_t **q, queue_element_t *e) -{ -cp - free(e->packet); - - if(e->next) /* There is a successor, so we are not tail */ - { - if(e->prev) /* There is a predecessor, so we are not head */ - { - e->next->prev = e->prev; - e->prev->next = e->next; - } - else /* We are head */ - { - e->next->prev = NULL; - (*q)->head = e->next; - } - } - else /* We are tail (or all alone!) */ - { - if(e->prev) /* We are not alone :) */ - { - e->prev->next = NULL; - (*q)->tail = e->prev; - } - else /* Adieu */ - { - free(*q); - *q = NULL; - } - } - - free(e); -cp -} - -/* - flush a queue by calling function for - each packet, and removing it when that - returned a zero exit code -*/ -void flush_queue(connection_t *cl, packet_queue_t **pq, - int (*function)(connection_t*,vpn_packet_t*)) -{ - queue_element_t *p, *next = NULL; -cp - for(p = (*pq)->head; p != NULL; ) - { - next = p->next; - - if(!function(cl, p->packet)) - del_queue(pq, p); - - p = next; - } - - if(debug_lvl >= DEBUG_TRAFFIC) - syslog(LOG_DEBUG, _("Queue flushed")); -cp -} - -/* - flush the send&recv queues - void because nothing goes wrong here, packets - remain in the queue if something goes wrong -*/ -void flush_queues(connection_t *cl) -{ -cp - if(cl->sq) - { - if(debug_lvl >= DEBUG_TRAFFIC) - syslog(LOG_DEBUG, _("Flushing send queue for %s (%s)"), - cl->name, cl->hostname); - flush_queue(cl, &(cl->sq), xsend); - } - - if(cl->rq) - { - if(debug_lvl >= DEBUG_TRAFFIC) - syslog(LOG_DEBUG, _("Flushing receive queue for %s (%s)"), - cl->name, cl->hostname); - flush_queue(cl, &(cl->rq), xrecv); - } -cp -} - /* send a packet to the given vpn ip. */ @@ -320,6 +202,7 @@ int send_packet(ip_t to, vpn_packet_t *packet) { connection_t *cl; subnet_t *subnet; + vpn_packet_t *copy; cp if((subnet = lookup_subnet_ipv4(&to)) == NULL) { @@ -345,37 +228,56 @@ cp return -1; } - /* If we ourselves have indirectdata flag set, we should send only to our uplink! */ + if(!cl->status.active) + { + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_INFO, _("%s (%s) is not active, dropping packet"), + cl->name, cl->hostname); + + return 0; + } - /* FIXME - check for indirection and reprogram it The Right Way(tm) this time. */ - if(!cl->status.validkey) { -/* 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); - add_queue(&(cl->sq), packet, packet->len + 2); -*/ + + /* Since packet is on the stack of handle_tap_input(), + we have to make a copy of it first. */ + + copy = xmalloc(sizeof(vpn_packet_t)); + memcpy(copy, packet, sizeof(vpn_packet_t)); + + list_insert_tail(cl->queue, copy); + if(!cl->status.waitingforkey) send_req_key(myself, cl); /* Keys should be sent to the host running the tincd */ return 0; } - if(!cl->status.active) + /* Check if it has to go via UDP or TCP... */ +cp + if(cl->options & OPTION_TCPONLY) + return send_tcppacket(cl, packet); + else + return xsend(cl, packet); +} + +void flush_queue(connection_t *cl) +{ + list_node_t *node, *next; +cp + if(debug_lvl >= DEBUG_TRAFFIC) + syslog(LOG_INFO, _("Flushing queue for %s (%s)"), cl->name, cl->hostname); + + for(node = cl->queue->head; node; node = next) { -/* 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); - add_queue(&(cl->sq), packet, packet->len + 2); -*/ - return 0; /* We don't want to mess up, do we? */ + next = node->next; + xsend(cl, (vpn_packet_t *)node->data); + list_delete_node(cl->queue, node); } - - /* can we send it? can we? can we? huh? */ cp - return xsend(cl, packet); } /* @@ -716,17 +618,24 @@ int read_rsa_public_key(connection_t *cl) { config_t const *cfg; FILE *fp; + char *fname; void *result; cp if(!cl->rsa_key) cl->rsa_key = RSA_new(); + /* First, check for simple PublicKey statement */ + if((cfg = get_config_val(cl->config, config_publickey))) { BN_hex2bn(&cl->rsa_key->n, cfg->data.ptr); BN_hex2bn(&cl->rsa_key->e, "FFFF"); + return 0; } - else if((cfg = get_config_val(cl->config, config_publickeyfile))) + + /* Else, check for PublicKeyFile statement and read it */ + + if((cfg = get_config_val(cl->config, config_publickeyfile))) { if(is_safe_path(cfg->data.ptr)) { @@ -744,17 +653,31 @@ cp cfg->data.ptr); return -1; } + return 0; } else return -1; } - else + + /* Else, check if a harnessed public key is in the config file */ + + asprintf(&fname, "%s/hosts/%s", confbase, cl->name); + if((fp = fopen(fname, "r"))) { - syslog(LOG_ERR, _("No public key for %s specified!"), cl->name); - return -1; + result = PEM_read_RSAPublicKey(fp, &cl->rsa_key, NULL, NULL); + fclose(fp); + free(fname); + if(result) + return 0; } + + free(fname); + + /* Nothing worked. */ + + syslog(LOG_ERR, _("No public key for %s specified!"), cl->name); cp - return 0; + return -1; } int read_rsa_private_key(void) @@ -808,7 +731,7 @@ int setup_myself(void) cp myself = new_connection(); - asprintf(&myself->hostname, "MYSELF"); /* FIXME? Do hostlookup on ourselves? */ + asprintf(&myself->hostname, "MYSELF"); myself->flags = 0; myself->protocol_version = PROT_CURRENT; @@ -907,6 +830,19 @@ cp keyexpires = time(NULL) + keylifetime; cp + /* Check some options */ + + if((cfg = get_config_val(config, config_indirectdata))) + { + if(cfg->data.val == stupid_true) + myself->options |= OPTION_INDIRECT; + } + + if((cfg = get_config_val(config, config_tcponly))) + { + if(cfg->data.val == stupid_true) + myself->options |= OPTION_TCPONLY; + } /* Activate ourselves */ myself->status.active = 1; @@ -1125,6 +1061,7 @@ cp { syslog(LOG_ERR, _("System call `%s' failed: %m"), "getpeername"); + close(sfd); return NULL; } @@ -1234,37 +1171,40 @@ cp if(cl->status.remove) return; - cl->status.remove = 1; - if(debug_lvl >= DEBUG_CONNECTIONS) syslog(LOG_NOTICE, _("Closing connection with %s (%s)"), cl->name, cl->hostname); + cl->status.remove = 1; + if(cl->socket) close(cl->socket); if(cl->status.meta) close(cl->meta_socket); - /* Find all connections that were lost because they were behind cl - (the connection that was dropped). */ - if(cl->status.meta) - for(node = connection_tree->head; node; node = node->next) - { - p = (connection_t *)node->data; - if(p->nexthop == cl && p != cl) - terminate_connection(p); - } - - /* Inform others of termination if it was still active */ - - if(cl->status.active) - for(node = connection_tree->head; node; node = node->next) - { - p = (connection_t *)node->data; - if(p->status.meta && p->status.active && p!=cl) - send_del_host(p, cl); /* Sounds like recursion, but p does not have a meta connection :) */ - } + { + + /* Find all connections that were lost because they were behind cl + (the connection that was dropped). */ + + for(node = connection_tree->head; node; node = node->next) + { + p = (connection_t *)node->data; + if(p->nexthop == cl && p != cl) + terminate_connection(p); + } + + /* Inform others of termination if it was still active */ + + if(cl->status.active) + for(node = connection_tree->head; node; node = node->next) + { + p = (connection_t *)node->data; + if(p->status.meta && p->status.active && p != cl) + send_del_host(p, cl); /* Sounds like recursion, but p does not have a meta connection :) */ + } + } /* Remove the associated subnets */