- Added indirectdata and tcponly functionality.
[tinc] / src / net.c
index a42ebce..18e5951 100644 (file)
--- 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 <itimmermans@bigfoot.com>,
-                            2000 Guus Sliepen <guus@sliepen.warande.net>
+    Copyright (C) 1998-2001 Ivo Timmermans <itimmermans@bigfoot.com>,
+                  2000,2001 Guus Sliepen <guus@sliepen.warande.net>
 
     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.92 2001/01/07 20:19:29 guus Exp $
 */
 
 #include "config.h"
 #include <utils.h>
 #include <xalloc.h>
 #include <avl_tree.h>
+#include <list.h>
 
 #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.
 */
@@ -345,37 +227,49 @@ 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);
-*/
+
+      list_insert_tail(cl->queue, packet);
+
       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;
+
+  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);
 }
 
 /*
@@ -808,7 +702,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 +801,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;