[Pkg-privacy-commits] [onioncat] 82/241: NDP code rewritten. Should be more robust and does also solicitation on socket reception.

Intrigeri intrigeri at moszumanska.debian.org
Wed Aug 26 16:16:35 UTC 2015


This is an automated email from the git hooks/post-receive script.

intrigeri pushed a commit to branch upstream-master
in repository onioncat.

commit 562f06f23350b40dbddf1e4258f98ca1588974cd
Author: eagle <eagle at 58e1ccc2-750e-0410-8d0d-f93ca75ab447>
Date:   Tue Dec 2 20:32:45 2008 +0000

    NDP code rewritten. Should be more robust and does also solicitation on socket reception.
    
    
    git-svn-id: https://www.cypherpunk.at/svn/onioncat/trunk@371 58e1ccc2-750e-0410-8d0d-f93ca75ab447
---
 config.h.in     |   3 +
 configure       |   3 +-
 configure.ac    |   2 +-
 src/ocat.h      |  31 +++++-
 src/ocatctrl.c  |   2 +-
 src/ocateth.c   | 310 ++++++++++++++++++++++++++++++++++++++------------------
 src/ocatroute.c |  27 +++--
 src/ocatsetup.c |   1 +
 src/ocatsocks.c |  12 +++
 src/ocattun.c   |   4 +-
 10 files changed, 273 insertions(+), 122 deletions(-)

diff --git a/config.h.in b/config.h.in
index 84200bf..53ef46c 100644
--- a/config.h.in
+++ b/config.h.in
@@ -18,6 +18,9 @@
 /* Define to 1 if you have the <linux/sockios.h> header file. */
 #undef HAVE_LINUX_SOCKIOS_H
 
+/* Define to 1 if you have the <netinet/if_ether.h> header file. */
+#undef HAVE_NETINET_IF_ETHER_H
+
 /* Define to 1 if you have the <netinet/in6.h> header file. */
 #undef HAVE_NETINET_IN6_H
 
diff --git a/configure b/configure
index cdcf02c..22581e4 100755
--- a/configure
+++ b/configure
@@ -3396,7 +3396,8 @@ fi
 
 
 
-for ac_header in sys/types.h sys/socket.h netinet/in.h netinet/in_systm.h netinet/ip.h netinet/ip6.h netinet/in6.h net/if.h net/if_tun.h linux/if_tun.h linux/sockios.h endian.h sys/endian.h
+
+for ac_header in sys/types.h sys/socket.h netinet/in.h netinet/in_systm.h netinet/ip.h netinet/ip6.h netinet/in6.h net/if.h net/if_tun.h linux/if_tun.h linux/sockios.h endian.h sys/endian.h netinet/if_ether.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 { echo "$as_me:$LINENO: checking for $ac_header" >&5
diff --git a/configure.ac b/configure.ac
index 92d5290..39a2085 100644
--- a/configure.ac
+++ b/configure.ac
@@ -25,7 +25,7 @@ AC_CHECK_LIB([pthread], [pthread_create])
 # Checks for header files.
 #AC_HEADER_STDC
 #AC_CHECK_HEADERS([arpa/inet.h fcntl.h netinet/in.h stdlib.h string.h sys/ioctl.h sys/socket.h unistd.h])
-AC_CHECK_HEADERS([sys/types.h sys/socket.h netinet/in.h netinet/in_systm.h netinet/ip.h netinet/ip6.h netinet/in6.h net/if.h net/if_tun.h linux/if_tun.h linux/sockios.h endian.h sys/endian.h], [], [],
+AC_CHECK_HEADERS([sys/types.h sys/socket.h netinet/in.h netinet/in_systm.h netinet/ip.h netinet/ip6.h netinet/in6.h net/if.h net/if_tun.h linux/if_tun.h linux/sockios.h endian.h sys/endian.h netinet/if_ether.h], [], [],
 [[
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
diff --git a/src/ocat.h b/src/ocat.h
index 0dcc3f3..5afa840 100644
--- a/src/ocat.h
+++ b/src/ocat.h
@@ -37,7 +37,10 @@
 #elif HAVE_SYS_ENDIAN_H
 #include <sys/endian.h>
 #endif
-#include <net/ethernet.h>
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
+#include <netinet/icmp6.h>
 #include <syslog.h>
 
 #ifndef ETHERTYPE_IPV6
@@ -119,6 +122,12 @@
 #define E_RT_NOTORGW -6
 #define E_RT_GWSELF -7
 
+#define E_ETH_TRUNC -8
+#define E_ETH_ILLDEST -9
+#define E_ETH_ILLPROTO -10
+#define E_ETH_INTERCEPT -11
+
+
 //! maximum number of MAC address entries in table
 #define MAX_MAC_ENTRY 128
 //! maximum age of MAC address in table
@@ -260,6 +269,19 @@ typedef struct MACTable
    time_t age;
 } MACTable_t;
 
+typedef struct ndp6
+{
+   struct ether_header eth;
+   struct ip6_hdr ip6;
+   union
+   {
+      struct icmp6_hdr icmp6;
+      struct nd_neighbor_solicit ndp_sol;
+      struct nd_neighbor_advert ndp_adv;
+   };
+   //struct nd_opt_hdr ndp_opt;
+} __attribute__((packed)) ndp6_t;
+
 /*
 // next header value for ocat internal use (RFC3692)
 #define OCAT_NEXT_HEADER 254
@@ -337,6 +359,10 @@ char *ipv6tonion(const struct in6_addr *, char *);
 int oniontipv6(const char *, struct in6_addr *);
 int oniontipv4(const char *, struct in_addr *, int);
 int has_tor_prefix(const struct in6_addr *);
+/*
+#define IN6_HAS_TOR_PREFIX(a) ((((__const uint32_t *) (a))[0] == ((__const uint32_t*)(TOR_PREFIX))[0]) \
+      && (((__const uint16_t*)(a))[2] == ((__const uint16_t*)(TOR_PREFIX))[2]))
+      */
 
 /* ocattun.c */
 #ifndef WITHOUT_TUN
@@ -397,10 +423,11 @@ void print_routes(FILE *);
 
 /* ocateth.c */
 int eth_check(char *, int);
-int mac_get_mac(const struct in6_addr *, uint8_t *);
+int mac_set(const struct in6_addr *, uint8_t *);
 void print_mac_tbl(FILE *);
 void mac_cleanup(void);
 char *mac_hw2str(const uint8_t *, char *);
+int ndp_solicit(const struct in6_addr *, const struct in6_addr *);
 
 /* ocatsocks.c */
 void socks_queue(const struct in6_addr *, int);
diff --git a/src/ocatctrl.c b/src/ocatctrl.c
index 174538f..1b0b1a0 100644
--- a/src/ocatctrl.c
+++ b/src/ocatctrl.c
@@ -36,7 +36,7 @@
 //#include <sys/select.h>
 //#include <sys/types.h>
 //#include <sys/stat.h>
-//#include <sys/socket.h>
+#include <sys/socket.h>
 //#include <sys/ioctl.h>
 //#ifdef HAVE_LINUX_SOCKIOS_H
 //#include <linux/sockios.h>
diff --git a/src/ocateth.c b/src/ocateth.c
index ec62cfc..9702196 100644
--- a/src/ocateth.c
+++ b/src/ocateth.c
@@ -47,9 +47,11 @@
 #ifdef HAVE_NETINET_IP_H
 #include <netinet/ip.h>
 #endif
-
-#include <net/ethernet.h>
+#include <netinet/in.h>
 #include <netinet/icmp6.h>
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
 
 #include "ocat.h"
 
@@ -61,6 +63,8 @@ static pthread_mutex_t mac_mutex_ = PTHREAD_MUTEX_INITIALIZER;
 
 /*! Pseudo header for IPv6 checksum calculation.
  *  RFC2460 8.1, (RFC1885 2.3) RFC2463, RFC1071. */
+/* RFC2461, rfc2462, RFC2464 ipv6 ethernet enc.
+ * 2373 addrassng ipv6 */
 
 /* IPv6 Ethernet Multicast: (MAC) 33:33:xx:xx:xx:xx, xx -> 4 lowest order bytes of IPv6 destination
  * Solicited-Node address: (IPv6) FF02:0:0:0:0:1:ffxx:xxxx, -> xx -> 3 lowest order bytes of IPv6 destination (RFC4291)
@@ -106,6 +110,8 @@ void print_mac_tbl(FILE *f)
 }
 
 
+/*! Scan MAC table for outages (age > MAX_MAC_AGE) and remove entries.
+ */
 void mac_cleanup(void)
 {
    int i;
@@ -125,7 +131,12 @@ void mac_cleanup(void)
 }
 
 
-int mac_get_mac(const struct in6_addr *in6, uint8_t *hwaddr)
+/*! Lookup an entry in the MAC-table by IP, update age.
+ *  If hwaddr != NULL and MAC eq 00:00:00:00:00:00 then copy MAC entry
+ *  from MAC table to hwaddr, otherwise copy hwaddr to MAC table.
+ *  @return -1 if no entry available, otherwise index of entry in table starting with 0.
+ */
+int mac_set(const struct in6_addr *in6, uint8_t *hwaddr)
 {
    int i;
 
@@ -134,7 +145,13 @@ int mac_get_mac(const struct in6_addr *in6, uint8_t *hwaddr)
    for (i = mac_cnt_ - 1; i >= 0; i--)
       if (IN6_ARE_ADDR_EQUAL(in6, &mac_tbl_[i].in6addr))
       {
-         memcpy(hwaddr, &mac_tbl_[i].hwaddr, ETHER_ADDR_LEN);
+         if (hwaddr)
+         {
+            if (!hwaddr[0] && !hwaddr[1] && !hwaddr[2] && !hwaddr[3] && !hwaddr[4] && !hwaddr[5])
+               memcpy(hwaddr, &mac_tbl_[i].hwaddr, ETHER_ADDR_LEN);
+            else
+               memcpy(&mac_tbl_[i].hwaddr, hwaddr, ETHER_ADDR_LEN);
+         }
          mac_tbl_[i].age = time(NULL);
          break;
       }
@@ -145,6 +162,11 @@ int mac_get_mac(const struct in6_addr *in6, uint8_t *hwaddr)
 }
 
 
+/*! Add MAC/IPv6-pair to MAC table.
+ *  @param hwaddr MAC address.
+ *  @param in6 IPv6 address.
+ *  @return Index of entry (starting with 0) or -1 if MAC table is full (MAX_MAC_ENTRY)
+ */
 int mac_add_entry(const uint8_t *hwaddr, const struct in6_addr *in6)
 {
    int e = -1;
@@ -167,6 +189,12 @@ int mac_add_entry(const uint8_t *hwaddr, const struct in6_addr *in6)
 }
 
 
+/*! Lookup entry by MAC address in MAC-table. It returns the first
+ *  occurence and updates the age.
+ *  @param hwaddr MAC address to search for.
+ *  @param in6 If not NULL, this buffer is filled with the IPv6 address.
+ *  @return Index of entry or -1 if no entry exists.
+ */
 int mac_get_ip(const uint8_t *hwaddr, struct in6_addr *in6)
 {
    int i;
@@ -176,7 +204,8 @@ int mac_get_ip(const uint8_t *hwaddr, struct in6_addr *in6)
    for (i = mac_cnt_ - 1; i >= 0; i--)
       if (!memcmp(hwaddr, &mac_tbl_[i].hwaddr, ETHER_ADDR_LEN))
       {
-         memcpy(in6, &mac_tbl_[i].in6addr, sizeof(struct in6_addr));
+         if (in6)
+            memcpy(in6, &mac_tbl_[i].in6addr, sizeof(struct in6_addr));
          mac_tbl_[i].age = time(NULL);
          break;
       }
@@ -187,9 +216,10 @@ int mac_get_ip(const uint8_t *hwaddr, struct in6_addr *in6)
 }
 
 
-/*! Calculate 16 bit one's complement sum (RFC1071).
+/*! Calculate 16 bit one's complement checksum (RFC1071) suitable for ICMPv6.
  *  @param buf Pointer to buffer.
  *  @param len Number of bytes in buffer.
+ *  @return Checksum of buffer.
  */
 uint16_t checksum(const uint16_t *buf, int len)
 {
@@ -213,12 +243,16 @@ uint16_t checksum(const uint16_t *buf, int len)
 }
 
 
+/*! Free checksum buffer.
+ */
 void free_ckbuf(uint16_t *buf)
 {
    free(buf);
 }
 
 
+/*! Malloc and fill buffer suitable for ICMPv6 checksum calculation.
+ */
 uint16_t *malloc_ckbuf(const struct in6_addr *src, const struct in6_addr *dst, uint16_t plen, uint8_t proto, const void *payload)
 {
    struct ip6_psh *psh;
@@ -240,129 +274,147 @@ uint16_t *malloc_ckbuf(const struct in6_addr *src, const struct in6_addr *dst, u
 }
 
 
-/*
-int ndp_(const struct in6_addr *in6)
+/*! Send NDP solicitation for dst to appropriate IPv6 multicast address.
+ *  @param src Source address.
+ *  @param dst Solicited target address.
+ *  @return Returns always 0.
+ */
+int ndp_solicit(const struct in6_addr *src, const struct in6_addr *dst)
 {
-   char buf[FRAME_SIZE];
-   struct ether_header *eh = (struct ether_header*) (buf + 4);
-   struct ip6_hdr *ip6 = (struct ip6_hdr*) (eh + 1); // ip6 header starts behind ether_header
-   struct nd_neighbor_solicit *nds = (struct nd_neighbor_solicit*) ip6;
-   struct nd_opt_hdr *ohd = (struct nd_opt_hdr*) (nds + 1);
-   uint16_t *ckb, cksum;
+   char buf[sizeof(ndp6_t) + sizeof(struct nd_opt_hdr) + 4 + ETHER_ADDR_LEN];
+   ndp6_t *ndp6 = (ndp6_t*) (buf + 4);
+   struct nd_opt_hdr *ohd = (struct nd_opt_hdr*) (ndp6 + 1);
+   uint16_t *ckb;
+   struct in6_addr mcastd = {{{0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0xff, 0, 0, 0}}};
+
+   // clear buffer and setup ipv6 multicast destination
+   memset(buf, 0, sizeof(buf));
+   memcpy(((char*) &mcastd) + 13, ((char*) dst) + 13, 3);
+
+   // tunnel header
+   *((uint32_t*) buf) = htonl(CNF(fhd_key[IPV6_KEY]));
+
+   // ethernet header
+   *((uint16_t*) ndp6->eth.ether_dhost) = 0x3333;
+   memcpy(&ndp6->eth.ether_dhost[2], ((char*) &mcastd) + 12, 4);
+   memcpy(ndp6->eth.ether_shost, CNF(ocat_hwaddr), ETHER_ADDR_LEN);
+   ndp6->eth.ether_type = htons(ETHERTYPE_IPV6);
+
+   // ipv6 header
+   ndp6->ip6.ip6_vfc = 0x60;
+   ndp6->ip6.ip6_plen = htons(sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_hdr) + ETHER_ADDR_LEN);
+   ndp6->ip6.ip6_nxt = IPPROTO_ICMPV6;
+   ndp6->ip6.ip6_hlim = 255;
+   memcpy(&ndp6->ip6.ip6_src, src, sizeof(struct in6_addr));
+   memcpy(&ndp6->ip6.ip6_dst, &mcastd, sizeof(struct in6_addr));
+
+   // icmpv6 header (partially)
+   ndp6->icmp6.icmp6_type = ND_NEIGHBOR_SOLICIT;
+
+   // ndp solicit header
+   memcpy(&ndp6->ndp_sol.nd_ns_target, dst, sizeof(struct in6_addr));
+
+   // icmpv6 ndp option
+   ohd->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
+   ohd->nd_opt_len = 1;
+   memcpy(ohd + 1, ndp6->eth.ether_shost, ETHER_ADDR_LEN);
+
+   // calculate checksum
+   ckb = malloc_ckbuf(&ndp6->ip6.ip6_src, &ndp6->ip6.ip6_dst, ntohs(ndp6->ip6.ip6_plen), IPPROTO_ICMPV6, &ndp6->icmp6);
+   ndp6->icmp6.icmp6_cksum = checksum(ckb, ntohs(ndp6->ip6.ip6_plen) + sizeof(struct ip6_psh));
+   free_ckbuf(ckb);
 
-   return -1;
+   log_debug("writing %d bytes ndp solicitation to tunfd %d", sizeof(buf), CNF(tunfd[1]));
+   if (write(CNF(tunfd[1]), buf, sizeof(buf)) < sizeof(buf))
+      log_msg(LOG_ERR, "short write to tun fd %d", CNF(tunfd[1]));
+
+   return 0;
 }
-*/
 
 
-int ndp_solicit(char *buf, int rlen)
+/*! Check neighbor solicitation and generate advertisement.
+ *  @param buf pointer to frame buffer.
+ *  @param rlen buffer length, must be at least sizeof(ICMPv6 header) + 4.
+ *  @return 0 if everything gone write, -1 on failure.
+ */
+int ndp_soladv(char *buf, int rlen)
 {
-   struct ether_header *eh = (struct ether_header*) (buf + 4);
-   struct ip6_hdr *ip6 = (struct ip6_hdr*) (eh + 1); // ip6 header starts behind ether_header
-   struct icmp6_hdr *icmp6 = (struct icmp6_hdr*) (ip6 + 1); // imcp6 header starts behind ip6 header
-   struct nd_neighbor_solicit *nds = (struct nd_neighbor_solicit*) icmp6;
-   struct nd_neighbor_advert *nda = (struct nd_neighbor_advert*) icmp6;
-   struct nd_opt_hdr *ohd = (struct nd_opt_hdr*) (nds + 1);
+   ndp6_t *ndp6 = (ndp6_t*) (buf + 4);
+   struct nd_opt_hdr *ohd = (struct nd_opt_hdr*) (ndp6 + 1);
    uint16_t *ckb, cksum;
-   struct in6_addr in6;
-   int minlen = 4 + sizeof(struct ether_header) + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
-
    char mb[100];
-//   uint8_t md[4] = {0xff};
-
-   if (rlen < minlen)
-   {
-      log_debug("frame too short for ICMP6 %d < %d", rlen, minlen);
-      return -1;
-   }
-
-   if (eh->ether_type != htons(ETHERTYPE_IPV6))
-   {
-      log_debug("protocol 0x%04x not implemented yet", htons(eh->ether_type));
-      return -1;
-   }
 
-   // check for right multicast destination on ethernet
-   if (eh->ether_dhost[2] != 0xff)
+   if (ndp6->eth.ether_dhost[0] & 1)
    {
-      log_debug("ethernet multicast destination %s cannot be solicited node address", mac_hw2str(eh->ether_dhost, mb));
-      return -1;
-   }
-
-   // check for right multicast destination in IPv6
-   if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || !IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
-   {
-      log_debug("IPv6 multicast destination not solicited node address");
-      return -1;
-   }
+      // check for right multicast destination on ethernet
+      if (ndp6->eth.ether_dhost[2] != 0xff)
+      {
+         log_debug("ethernet multicast destination %s cannot be solicited node address", mac_hw2str(ndp6->eth.ether_dhost, mb));
+         return -1;
+      }
 
-   if (!has_tor_prefix(&ip6->ip6_src))
-   {
-      log_debug("source IPv6 is not TOR ipv6");
-      return -1;
+      // check for right multicast destination in IPv6
+      if (!IN6_IS_ADDR_MULTICAST(&ndp6->ip6.ip6_dst) || !IN6_IS_ADDR_MC_LINKLOCAL(&ndp6->ip6.ip6_dst))
+      {
+         log_debug("IPv6 multicast destination not solicited node address");
+         return -1;
+      }
    }
 
-   if (ip6->ip6_nxt != IPPROTO_ICMPV6)
-   {
-      log_debug("frame contains not ICMPV6, next header = %d", ip6->ip6_nxt);
-      return -1;
-   }
+   ckb = malloc_ckbuf(&ndp6->ip6.ip6_src, &ndp6->ip6.ip6_dst, ntohs(ndp6->ip6.ip6_plen), IPPROTO_ICMPV6, &ndp6->icmp6);
+   cksum = checksum(ckb, ntohs(ndp6->ip6.ip6_plen) + sizeof(struct ip6_psh));
+   free_ckbuf(ckb);
 
-   if (icmp6->icmp6_type != ND_NEIGHBOR_SOLICIT)
+   if (cksum)
    {
-      log_debug("icmpv6 type %d not implemented", icmp6->icmp6_type);
+      log_msg(LOG_ERR, "icmpv6 checksum wrong");
       return -1;
    }
 
-   log_debug("ICMPv6 ND_NEIGHBOR_SOLICIT received");
-   minlen = minlen - sizeof(struct icmp6_hdr) + sizeof(struct nd_neighbor_solicit);
-   if (rlen < minlen)
+   // check for duplicate address detection
+   if (IN6_IS_ADDR_UNSPECIFIED(&ndp6->ip6.ip6_src))
    {
-      log_debug("frame too short for ND_NEIGHBOR_SOLICIT");
+      log_debug("duplicate address detection in progress");
+      //FIXME: we should check something more here. See RFC2462
       return -1;
    }
 
-   if (!has_tor_prefix(&nds->nd_ns_target))
+   if (!has_tor_prefix(&ndp6->ndp_sol.nd_ns_target))
+   //if (!IN6_HAS_TOR_PREFIX(&ndp6->ndp_sol.nd_ns_target))
    {
       log_debug("solicit target is not TOR IPv6");
       return -1;
    }
 
-   ckb = malloc_ckbuf(&ip6->ip6_src, &ip6->ip6_dst, ntohs(ip6->ip6_plen), IPPROTO_ICMPV6, icmp6);
-   cksum = checksum(ckb, ntohs(ip6->ip6_plen) + sizeof(struct ip6_psh));
-   free_ckbuf(ckb);
-   if (cksum)
-   {
-      log_msg(LOG_ERR, "icmpv6 checksum wrong");
-      return -1;
-   }
-
-
    log_debug("generating response");
-   // set MAC addresses in ethernet header and add MAC to table
-   if (mac_get_ip(eh->ether_shost, &in6) == -1)
-      if (mac_add_entry(eh->ether_shost, &ip6->ip6_src) == -1)
+   // add source MAC to table
+   if (mac_set(&ndp6->ip6.ip6_src, ndp6->eth.ether_shost) == -1)
+      if (mac_add_entry(ndp6->eth.ether_shost, &ndp6->ip6.ip6_src) == -1)
       {
          log_msg(LOG_ERR, "MAC table full");
          return -1;
       }
-   memcpy(eh->ether_dhost, eh->ether_shost, ETHER_ADDR_LEN);
-   memcpy(eh->ether_shost, CNF(ocat_hwaddr), ETHER_ADDR_LEN);
+
+   // set MAC addresses for response
+   memcpy(ndp6->eth.ether_dhost, ndp6->eth.ether_shost, ETHER_ADDR_LEN);
+   memcpy(ndp6->eth.ether_shost, CNF(ocat_hwaddr), ETHER_ADDR_LEN);
 
    // init ip6 header
-   memcpy(&ip6->ip6_dst, &ip6->ip6_src, sizeof(struct in6_addr));
-   memcpy(&ip6->ip6_src, &nds->nd_ns_target, sizeof(struct in6_addr));
+   memcpy(&ndp6->ip6.ip6_dst, &ndp6->ip6.ip6_src, sizeof(struct in6_addr));
+   memcpy(&ndp6->ip6.ip6_src, &ndp6->ndp_sol.nd_ns_target, sizeof(struct in6_addr));
 
    // init nda icmp6 header
-   nda->nd_na_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
-   nda->nd_na_hdr.icmp6_code = 0;
-   nda->nd_na_hdr.icmp6_cksum = 0;
-   nda->nd_na_flags_reserved = ND_NA_FLAG_SOLICITED;
+   ndp6->ndp_adv.nd_na_hdr.icmp6_type = ND_NEIGHBOR_ADVERT;
+   ndp6->ndp_adv.nd_na_hdr.icmp6_code = 0;
+   ndp6->ndp_adv.nd_na_hdr.icmp6_cksum = 0;
+   ndp6->ndp_adv.nd_na_flags_reserved = ND_NA_FLAG_SOLICITED;
+
+   //FIXME: setting target option does not check total frame length!
    ohd->nd_opt_type = ND_OPT_TARGET_LINKADDR;
    memcpy(ohd + 1, CNF(ocat_hwaddr), ETHER_ADDR_LEN);
 
-   ckb = malloc_ckbuf(&ip6->ip6_src, &ip6->ip6_dst, ntohs(ip6->ip6_plen), IPPROTO_ICMPV6, icmp6);
-   nda->nd_na_hdr.icmp6_cksum = checksum(ckb, ntohs(ip6->ip6_plen) + sizeof(struct ip6_psh));
+   ckb = malloc_ckbuf(&ndp6->ip6.ip6_src, &ndp6->ip6.ip6_dst, ntohs(ndp6->ip6.ip6_plen), IPPROTO_ICMPV6, &ndp6->icmp6);
+   ndp6->ndp_adv.nd_na_hdr.icmp6_cksum = checksum(ckb, ntohs(ndp6->ip6.ip6_plen) + sizeof(struct ip6_psh));
    free_ckbuf(ckb);
 
    log_debug("writing %d bytes to tunfd %d", rlen, CNF(tunfd[1]));
@@ -373,24 +425,80 @@ int ndp_solicit(char *buf, int rlen)
 }
 
 
-int eth_check(char *buf, int rlen)
+/*! Extract source ipv6 and MAC address and add/update MAC table.
+ *  FIXME: there should be some additional checks!
+ */
+int ndp_recadv(char *buf, int len)
 {
-    struct ether_header *eh = (struct ether_header*) (buf + 4);
+   ndp6_t *ndp6 = (ndp6_t*) (buf + 4);
+
+   // add source MAC to table
+   if (mac_set(&ndp6->ip6.ip6_src, ndp6->eth.ether_shost) == -1)
+      if (mac_add_entry(ndp6->eth.ether_shost, &ndp6->ip6.ip6_src) == -1)
+      {
+         log_msg(LOG_ERR, "MAC table full");
+         return -1;
+      }
+   return 0;
+}
+
 
-   if (!(eh->ether_dhost[0] & 1))
+int eth_ndp(char *buf, int len, int ndp_type)
+{
+   switch (ndp_type)
    {
-      log_debug("dest MAC is not multicast");
-      return -1;
+      case ND_NEIGHBOR_SOLICIT:
+         log_debug("ND_NEIGHBOR_SOLICIT received");
+         (void) ndp_soladv(buf, len);
+         return 0;
+
+      case ND_NEIGHBOR_ADVERT:
+         log_debug("ND_NEIGHBOR_ADVERT received");
+         (void) ndp_recadv(buf, len);
+         return 0;
    }
+   return -1;
+}
+
 
-   if (*((uint16_t*) &eh->ether_dhost) == 0x3333)
+/*! Check if destination MAC is designated for OnionCat and
+ *  L4-Protocol is ICMPv6.
+ *  @return 0 if packet does not match criteria, -1 else.
+ */
+int eth_check(char *buf, int len)
+{
+   ndp6_t *ndp6= (ndp6_t*) (buf + 4);
+
+   // check minimum frame length
+   if (len < sizeof(struct ether_header) + 4)
    {
-      log_debug("dest MAC is IPv6 multicast");
-      return ndp_solicit(buf, rlen);
+      log_msg(LOG_ERR, "frame too short, len = %d < 4 + %d", len, sizeof(struct ether_header));
+      return E_ETH_TRUNC;
    }
 
-   log_debug("unknown multicast MAC destination");
-   return -1;
-}
+   // check ethernet destination
+   if ((*((uint16_t*) &ndp6->eth.ether_dhost) != 0x3333) && memcmp(ndp6->eth.ether_dhost, CNF(ocat_hwaddr), ETHER_ADDR_LEN))
+   {
+      log_debug("unknown destination MAC");
+      return E_ETH_ILLDEST;
+   }
+
+   // check L3 protocol
+   if (ndp6->eth.ether_type != htons(ETHERTYPE_IPV6))
+   {
+      log_msg(LOG_ERR, "L3 protocol not implemented 0x%04x", ntohs(ndp6->eth.ether_type));
+      return E_ETH_ILLPROTO;
+   }
 
+   // check for ndp
+   if ((len >= sizeof(ndp6_t) + 4) && (ndp6->ip6.ip6_nxt == IPPROTO_ICMPV6))
+   {
+      log_debug("ICMPv6 frame intercepted, icmp6_type = %d", ndp6->icmp6.icmp6_type);
+      if (eth_ndp(buf, len, ndp6->icmp6.icmp6_type) != -1)
+         return E_ETH_INTERCEPT;
+   }
+
+   // else forward as usual
+   return 0;
+}
 
diff --git a/src/ocatroute.c b/src/ocatroute.c
index 9218d94..fd4b08b 100644
--- a/src/ocatroute.c
+++ b/src/ocatroute.c
@@ -48,8 +48,9 @@
 #ifdef HAVE_NETINET_IP_H
 #include <netinet/ip.h>
 #endif
-
-#include <net/ethernet.h>
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
 
 #include "ocat.h"
 
@@ -484,9 +485,11 @@ void *socket_receiver(void *p)
                   log_debug("creating ethernet header");
 
                   // FIXME: should differentiate between IPv6 and IP!!
-                  if (mac_get_mac(&((struct ip6_hdr*)peer->fragbuf)->ip6_dst, eh->ether_dhost) == -1)
+                  memset(eh->ether_dhost, 0, ETHER_ADDR_LEN);
+                  if (mac_set(&((struct ip6_hdr*)peer->fragbuf)->ip6_dst, eh->ether_dhost) == -1)
                   {
-                     log_debug("dest MAC unknown, must resolve...not implemented");
+                     log_debug("dest MAC unknown, resolving");
+                     ndp_solicit(&((struct ip6_hdr*)peer->fragbuf)->ip6_src, &((struct ip6_hdr*)peer->fragbuf)->ip6_dst);
                   }
                   else
                   {
@@ -514,7 +517,6 @@ void *socket_receiver(void *p)
                drop = 0;
             }
 
-
             peer->fraglen -= len;
             if (peer->fraglen)
             {
@@ -774,17 +776,12 @@ void packet_forwarder(void)
       // in case of TAP device handle ethernet header
       if (CNF(use_tap))
       {
-         if (!memcmp(eh->ether_dhost, CNF(ocat_hwaddr), ETHER_ADDR_LEN))
-            // remove ethernet header from buffer
-            // FIXME: it would be better to adjust pointers instead of moving data
-            memmove(eh, eh + 1, rlen - 4 - sizeof(struct ether_header));
-         else
-         {
-            log_debug("forwarding %d bytes eth handler", rlen);
-            //ndp_solicit(buf, rlen);
-            eth_check(buf, rlen);
+         if (eth_check(buf, rlen))
             continue;
-         }
+
+         // removing ethernet header
+         // FIXME: it would be better to adjust pointers instead of moving data
+         memmove(eh, eh + 1, rlen - 4 - sizeof(struct ether_header));
       }
 
       if (*((uint32_t*) buf) == CNF(fhd_key[IPV6_KEY]))
diff --git a/src/ocatsetup.c b/src/ocatsetup.c
index ac25ce5..f48cca8 100644
--- a/src/ocatsetup.c
+++ b/src/ocatsetup.c
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <arpa/inet.h>
+#include <sys/socket.h>
 
 #include "ocat.h"
 
diff --git a/src/ocatsocks.c b/src/ocatsocks.c
index b4630d7..645d54d 100644
--- a/src/ocatsocks.c
+++ b/src/ocatsocks.c
@@ -175,6 +175,17 @@ void *socks_connector(void *p)
    while (run)
    {
       pthread_mutex_lock(&socks_queue_mutex_);
+      for (;;)
+      {
+         for (squeue = &socks_queue_; *squeue; squeue = &(*squeue)->next)
+            if (!(*squeue)->state)
+               break;
+         if (*squeue)
+            break;
+         pthread_cond_wait(&socks_queue_cond_, &socks_queue_mutex_);
+      }
+
+      /*
       do
       {
          pthread_cond_wait(&socks_queue_cond_, &socks_queue_mutex_);
@@ -183,6 +194,7 @@ void *socks_connector(void *p)
                break;
       }
       while (!(*squeue));
+      */
 
       // spawn spare thread if there is no one left
       (*squeue)->state = SOCKS_CONNECTING;
diff --git a/src/ocattun.c b/src/ocattun.c
index d66d777..a76b582 100644
--- a/src/ocattun.c
+++ b/src/ocattun.c
@@ -46,7 +46,9 @@
 #ifdef HAVE_NET_IF_TUN_H
 #include <net/if_tun.h>
 #endif
-#include <net/ethernet.h>
+#ifdef HAVE_NETINET_IF_ETHER_H
+#include <netinet/if_ether.h>
+#endif
 
 #include "ocat.h"
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/onioncat.git



More information about the Pkg-privacy-commits mailing list