gateway: work around kernel IPIP module initialisation bug
[olsrd.git] / src / parser.c
index dfe5995..6132d74 100644 (file)
 #include "rebuild_packet.h"
 #include "net_os.h"
 #include "log.h"
-#include "print_packet.h"
 #include "net_olsr.h"
+#include "duplicate_handler.h"
 
-#ifdef WIN32
+#ifdef _WIN32
 #undef EWOULDBLOCK
 #define EWOULDBLOCK WSAEWOULDBLOCK
 #undef errno
 #define errno WSAGetLastError()
+char *StrError(unsigned int ErrNo);
 #undef strerror
 #define strerror(x) StrError(x)
-#endif
+#endif /* _WIN32 */
 
-/* Sven-Ola: On very slow devices used in huge networks
+    /* Sven-Ola: On very slow devices used in huge networks
  * the amount of lq_tc messages is so high, that the
  * recv() loop never ends. This is a small hack to end
  * the loop in this cases
@@ -78,14 +79,6 @@ struct packetparser_function_entry *packetparser_functions;
 static uint32_t inbuf_aligned[MAXMESSAGESIZE/sizeof(uint32_t) + 1];
 static char *inbuf = (char *)inbuf_aligned;
 
-static bool disp_pack_in = false;
-
-void
-parser_set_disp_pack_in(bool val)
-{
-  disp_pack_in = val;
-}
-
 /**
  *Initialize the parser.
  *
@@ -102,6 +95,26 @@ olsr_init_parser(void)
 }
 
 void
+olsr_destroy_parser(void) {
+  struct parse_function_entry *pe, *pe_next;
+  struct preprocessor_function_entry *ppe, *ppe_next;
+  struct packetparser_function_entry *pae, *pae_next;
+
+  for (pe = parse_functions; pe; pe = pe_next) {
+    pe_next = pe->next;
+    free (pe);
+  }
+  for (ppe = preprocessor_functions; ppe; ppe = ppe_next) {
+    ppe_next = ppe->next;
+    free (ppe);
+  }
+  for (pae = packetparser_functions; pae; pae = pae_next) {
+    pae_next = pae->next;
+    free(pae);
+  }
+}
+
+void
 olsr_parser_add_function(parse_function * function, uint32_t type)
 {
   struct parse_function_entry *new_entry;
@@ -241,33 +254,36 @@ olsr_packetparser_remove_function(packetparser_function * function)
  *Process a newly received OLSR packet. Checks the type
  *and to the neccessary convertions and call the
  *corresponding functions to handle the information.
- *@param from the sockaddr struct describing the sender
  *@param olsr the olsr struct containing the message
  *@param size the size of the message
- *@return nada
+ *@param in_if the incoming interface
+ *@param from_addr the sockaddr struct describing the sender
  */
 
 void
 parse_packet(struct olsr *olsr, int size, struct interface *in_if, union olsr_ip_addr *from_addr)
 {
   union olsr_message *m = (union olsr_message *)olsr->olsr_msg;
-  int count;
-  int msgsize;
+  uint32_t count;
+  uint32_t msgsize;
+  uint16_t seqno;
   struct parse_function_entry *entry;
   struct packetparser_function_entry *packetparser;
 
   count = size - ((char *)m - (char *)olsr);
 
-  if (count < MIN_PACKET_SIZE(olsr_cnf->ip_version))
+  /* minimum packet size is 4 */
+  if (count < 4)
     return;
 
   if (ntohs(olsr->olsr_packlen) !=(uint16_t) size) {
     struct ipaddr_str buf;
-    OLSR_PRINTF(1, "Size error detected in received packet.\nRecieved %d, in packet %d\n", size, ntohs(olsr->olsr_packlen));
+    OLSR_PRINTF(1, "Size error detected in received packet.\nReceived %d, in packet %d\n", size, ntohs(olsr->olsr_packlen));
 
     olsr_syslog(OLSR_LOG_ERR, " packet length error in  packet received from %s!", olsr_ip_to_string(&buf, from_addr));
     return;
   }
+
   // translate sequence number to host order
   olsr->olsr_seqno = ntohs(olsr->olsr_seqno);
 
@@ -280,38 +296,48 @@ parse_packet(struct olsr *olsr, int size, struct interface *in_if, union olsr_ip
 
   //printf("Message from %s\n\n", olsr_ip_to_string(&buf, from_addr));
 
-  /* Display packet */
-  if (disp_pack_in)
-    print_olsr_serialized_packet(stdout, (union olsr_packet *)olsr, size, from_addr);
-
-  if (olsr_cnf->ip_version == AF_INET)
-    msgsize = ntohs(m->v4.olsr_msgsize);
-  else
-    msgsize = ntohs(m->v6.olsr_msgsize);
-
   /*
    * Hysteresis update - for every OLSR package
    */
   if (olsr_cnf->use_hysteresis) {
     if (olsr_cnf->ip_version == AF_INET) {
       /* IPv4 */
-      update_hysteresis_incoming(from_addr, in_if, ntohs(olsr->olsr_seqno));
+      update_hysteresis_incoming(from_addr, in_if, olsr->olsr_seqno);
     } else {
       /* IPv6 */
-      update_hysteresis_incoming(from_addr, in_if, ntohs(olsr->olsr_seqno));
+      update_hysteresis_incoming(from_addr, in_if, olsr->olsr_seqno);
     }
   }
 
   for (; count > 0; m = (union olsr_message *)((char *)m + (msgsize))) {
     bool forward = true;
+    bool validated;
 
-    if (count < MIN_PACKET_SIZE(olsr_cnf->ip_version) + 8)
+    /* minimum message size is 8 + ipsize */
+    if (count < 8 + olsr_cnf->ipsize)
       break;
 
-    if (olsr_cnf->ip_version == AF_INET)
+    if (olsr_cnf->ip_version == AF_INET) {
       msgsize = ntohs(m->v4.olsr_msgsize);
-    else
+      seqno = ntohs(m->v4.seqno);
+    }
+    else {
       msgsize = ntohs(m->v6.olsr_msgsize);
+      seqno = ntohs(m->v6.seqno);
+    }
+
+    /* sanity check for msgsize */
+    if (msgsize < 8 + olsr_cnf->ipsize) {
+      struct ipaddr_str buf;
+      union olsr_ip_addr *msgorig = (union olsr_ip_addr *) &m->v4.originator;
+      OLSR_PRINTF(1, "Error, OLSR message from %s (type %d) is to small (%d bytes)"
+          ", ignoring all further content of the packet\n",
+          olsr_ip_to_string(&buf, msgorig), m->v4.olsr_msgtype, msgsize);
+      olsr_syslog(OLSR_LOG_ERR, "Error, OLSR message from %s (type %d) is too small (%d bytes)"
+          ", ignoring all further content of the packet\n",
+          olsr_ip_to_string(&buf, msgorig), m->v4.olsr_msgtype, msgsize);
+      break;
+    }
 
     if ((msgsize % 4) != 0) {
       struct ipaddr_str buf;
@@ -339,15 +365,6 @@ parse_packet(struct olsr *olsr, int size, struct interface *in_if, union olsr_ip
 
     count -= msgsize;
 
-    /* Check size of message */
-    if (count < 0) {
-      struct ipaddr_str buf;
-      OLSR_PRINTF(1, "packet length error in  packet received from %s!", olsr_ip_to_string(&buf, from_addr));
-
-      olsr_syslog(OLSR_LOG_ERR, " packet length error in  packet received from %s!", olsr_ip_to_string(&buf, from_addr));
-      break;
-    }
-
     /*RFC 3626 section 3.4:
      *  2    If the time to live of the message is less than or equal to
      *  '0' (zero), or if the message was sent by the receiving node
@@ -357,15 +374,18 @@ parse_packet(struct olsr *olsr, int size, struct interface *in_if, union olsr_ip
      */
 
     /* Should be the same for IPv4 and IPv6 */
-    if (ipequal((union olsr_ip_addr *)&m->v4.originator, &olsr_cnf->main_addr)
-        || !olsr_validate_address((union olsr_ip_addr *)&m->v4.originator)) {
+    validated = olsr_validate_address((union olsr_ip_addr *)&m->v4.originator);
+    if (ipequal((union olsr_ip_addr *)&m->v4.originator, &olsr_cnf->main_addr) || !validated) {
 #ifdef DEBUG
       struct ipaddr_str buf;
-#endif
-#ifdef DEBUG
       OLSR_PRINTF(3, "Not processing message originating from %s!\n",
                   olsr_ip_to_string(&buf, (union olsr_ip_addr *)&m->v4.originator));
-#endif
+#endif /* DEBUG */
+#ifndef NO_DUPLICATE_DETECTION_HANDLER
+      if (validated) {
+        olsr_test_originator_collision(m->v4.olsr_msgtype, seqno);
+      }
+#endif /* NO_DUPLICATE_DETECTION_HANDLER */
       continue;
     }
 
@@ -389,14 +409,15 @@ parse_packet(struct olsr *olsr, int size, struct interface *in_if, union olsr_ip
 
 /**
  *Processing OLSR data from socket. Reading data, setting
- *wich interface recieved the message, Sends IPC(if used)
+ *wich interface received the message, Sends IPC(if used)
  *and passes the packet on to parse_packet().
  *
  *@param fd the filedescriptor that data should be read from.
- *@return nada
+ *@param data unused
+ *@param flags unused
  */
 void
-olsr_input(int fd)
+olsr_input(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
 {
   struct interface *olsr_in_if;
   union olsr_ip_addr from_addr;
@@ -423,22 +444,26 @@ olsr_input(int fd)
     if (cc <= 0) {
       if (cc < 0 && errno != EWOULDBLOCK) {
         OLSR_PRINTF(1, "error recvfrom: %s", strerror(errno));
+#ifndef _WIN32
         olsr_syslog(OLSR_LOG_ERR, "error recvfrom: %m");
+#endif /* _WIN32 */
       }
       break;
     }
     if (olsr_cnf->ip_version == AF_INET) {
       /* IPv4 sender address */
-      from_addr.v4 = ((struct sockaddr_in *)&from)->sin_addr;
+      void * src = &((struct sockaddr_in *)&from)->sin_addr;
+      memcpy(&from_addr.v4, src, sizeof(from_addr.v4));
     } else {
       /* IPv6 sender address */
-      from_addr.v6 = ((struct sockaddr_in6 *)&from)->sin6_addr;
+      void * src = &((struct sockaddr_in6 *)&from)->sin6_addr;
+      memcpy(&from_addr.v6, src, sizeof(from_addr.v6));
     }
 
 #ifdef DEBUG
-    OLSR_PRINTF(5, "Recieved a packet from %s\n",
+    OLSR_PRINTF(5, "Received a packet from %s\n",
         olsr_ip_to_string(&buf, &from_addr));
-#endif
+#endif /* DEBUG */
 
     if ((olsr_cnf->ip_version == AF_INET) && (fromlen != sizeof(struct sockaddr_in)))
       break;
@@ -480,14 +505,15 @@ olsr_input(int fd)
 
 /**
  *Processing OLSR data from socket. Reading data, setting
- *wich interface recieved the message, Sends IPC(if used)
+ *wich interface received the message, Sends IPC(if used)
  *and passes the packet on to parse_packet().
  *
  *@param fd the filedescriptor that data should be read from.
- *@return nada
+ *@param data unused
+ *@param flags unused
  */
 void
-olsr_input_hostemu(int fd)
+olsr_input_hostemu(int fd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused)))
 {
   /* sockaddr_in6 is bigger than sockaddr !!!! */
   struct sockaddr_storage from;
@@ -501,7 +527,7 @@ olsr_input_hostemu(int fd)
   /* Host emulator receives IP address first to emulate
      direct link */
 
-  int cc = recv(fd, from_addr.v6.s6_addr, olsr_cnf->ipsize, 0);
+  int cc = recv(fd, (void*)from_addr.v6.s6_addr, olsr_cnf->ipsize, 0);
   if (cc != (int)olsr_cnf->ipsize) {
     fprintf(stderr, "Error receiving host-client IP hook(%d) %s!\n", cc, strerror(errno));
     memcpy(&from_addr, &((struct olsr *)inbuf)->olsr_msg->originator, olsr_cnf->ipsize);