[Pkg-privacy-commits] [onioncat] 61/340: ocat now IPv4 aware

Ximin Luo infinity0 at moszumanska.debian.org
Sat Aug 22 13:04:25 UTC 2015


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

infinity0 pushed a commit to branch debian
in repository onioncat.

commit bfab06bdc0439360f3e21bc3acde12dbf63a7778
Author: eagle <eagle at 58e1ccc2-750e-0410-8d0d-f93ca75ab447>
Date:   Tue Sep 9 09:03:05 2008 +0000

    ocat now IPv4 aware
    
    git-svn-id: http://www.cypherpunk.at/svn/onioncat/trunk@275 58e1ccc2-750e-0410-8d0d-f93ca75ab447
---
 src/Makefile.am     |   2 +-
 src/Makefile.in     |   6 +-
 src/ocat.c          |  47 ++++++---
 src/ocat.h          |  46 ++++++++-
 src/ocatipv4route.c | 209 ++++++++++++++++++++++++++++++++++++++
 src/ocatlog.c       |   4 +-
 src/ocatpeer.c      |   2 +-
 src/ocatroute.c     | 287 +++++++++++++++++++++++++++++++++++++++++++---------
 src/ocatsetup.c     |   5 +-
 src/ocattun.c       |  78 +++++---------
 src/ocatv6conv.c    |  16 +++
 11 files changed, 584 insertions(+), 118 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index d182bc8..68b27e8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
 bin_PROGRAMS = ocat
-ocat_SOURCES = ocat.c ocatlog.c ocatroute.c ocatthread.c ocattun.c ocatv6conv.c ocatcompat.c ocatpeer.c ocatsetup.c
+ocat_SOURCES = ocat.c ocatlog.c ocatroute.c ocatthread.c ocattun.c ocatv6conv.c ocatcompat.c ocatpeer.c ocatsetup.c ocatipv4route.c
 include_HEADERS = ocat.h strlcpy.c strlcat.c
 
diff --git a/src/Makefile.in b/src/Makefile.in
index 719a3e3..e761638 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -47,7 +47,8 @@ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(bin_PROGRAMS)
 am_ocat_OBJECTS = ocat.$(OBJEXT) ocatlog.$(OBJEXT) ocatroute.$(OBJEXT) \
 	ocatthread.$(OBJEXT) ocattun.$(OBJEXT) ocatv6conv.$(OBJEXT) \
-	ocatcompat.$(OBJEXT) ocatpeer.$(OBJEXT) ocatsetup.$(OBJEXT)
+	ocatcompat.$(OBJEXT) ocatpeer.$(OBJEXT) ocatsetup.$(OBJEXT) \
+	ocatipv4route.$(OBJEXT)
 ocat_OBJECTS = $(am_ocat_OBJECTS)
 ocat_LDADD = $(LDADD)
 DEFAULT_INCLUDES = -I. at am__isrc@ -I$(top_builddir)
@@ -151,7 +152,7 @@ sysconfdir = @sysconfdir@
 target_alias = @target_alias@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-ocat_SOURCES = ocat.c ocatlog.c ocatroute.c ocatthread.c ocattun.c ocatv6conv.c ocatcompat.c ocatpeer.c ocatsetup.c
+ocat_SOURCES = ocat.c ocatlog.c ocatroute.c ocatthread.c ocattun.c ocatv6conv.c ocatcompat.c ocatpeer.c ocatsetup.c ocatipv4route.c
 include_HEADERS = ocat.h strlcpy.c strlcat.c
 all: all-am
 
@@ -221,6 +222,7 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ocat.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ocatcompat.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ocatipv4route.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ocatlog.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ocatpeer.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ocatroute.Po at am__quote@
diff --git a/src/ocat.c b/src/ocat.c
index 6f834c7..626756f 100644
--- a/src/ocat.c
+++ b/src/ocat.c
@@ -25,6 +25,8 @@
 #include <arpa/inet.h>
 #include <sys/socket.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <pwd.h>
 #include <errno.h>
 #include <time.h>
@@ -45,7 +47,8 @@ void usage(const char *s)
          "   -h                    display usage message\n"
          "   -C                    disable local controller interface\n"
          "   -d <n>                set debug level to n, default = %d\n"
-         "   -i <onion_hostname>   convert onion hostname to IPv6 and exit\n"
+         "   -f <config_file>      read config from config_file\n"
+         "   -i                    convert onion hostname to IPv6 and exit\n"
          "   -l <port>             set ocat listen port, default = %d\n"
          "   -o <ipv6_addr>        convert IPv6 address to onion url and exit\n"
          "   -r                    run as root, i.e. do not change uid/gid\n"
@@ -57,19 +60,21 @@ void usage(const char *s)
 #endif
          "   -u <user>             change UID to user, default = \"%s\"\n"
          "   -v                    validate packets from sockets, default = %d (validation not mature)\n"
+         "   -4                    enable IPv4 support (default = %d)\n"
          , PACKAGE_STRING, __DATE__, __TIME__, s,
          // option defaults start here
          OCAT_DIR, OCAT_CONNECT_LOG, setup.create_clog, setup.debug_level, setup.ocat_listen_port, setup.ocat_dest_port, setup.tor_socks_port, 
 #ifndef WITHOUT_TUN
          TUN_DEV,
 #endif
-         OCAT_UNAME, setup.vrec);
+         OCAT_UNAME, setup.vrec, setup.ipv4_enable
+            );
 }
 
 
 int main(int argc, char *argv[])
 {
-   char tunname[IFNAMSIZ] = "", *s, ip6addr[INET6_ADDRSTRLEN];
+   char tunname[IFNAMSIZ] = {0}, *s, ip6addr[INET6_ADDRSTRLEN];
    int c, runasroot = 0;
    struct passwd *pwd;
    int urlconv = 0;
@@ -77,7 +82,7 @@ int main(int argc, char *argv[])
    if (argc < 2)
       usage(argv[0]), exit(1);
 
-   while ((c = getopt(argc, argv, "aCd:hriopl:t:T:s:u:")) != -1)
+   while ((c = getopt(argc, argv, "aCd:f:hriopl:t:T:s:u:4")) != -1)
       switch (c)
       {
          case 'a':
@@ -92,6 +97,11 @@ int main(int argc, char *argv[])
             setup.debug_level = atoi(optarg);
             break;
 
+         case 'f':
+            setup.config_file = optarg;
+            setup.config_read = 0;
+            break;
+
          case 'i':
             urlconv = 1;
             break;
@@ -135,6 +145,10 @@ int main(int argc, char *argv[])
             setup.vrec = 1;
             break;
 
+         case '4':
+            setup.ipv4_enable = 1;
+            break;
+
          case 'h':
          default:
             usage(argv[0]);
@@ -149,8 +163,10 @@ int main(int argc, char *argv[])
 
    if (urlconv == 2)
    {
-      if (inet_pton(AF_INET6, argv[optind], &setup.ocat_addr) <= 0)
-         log_msg(L_ERROR, "%s", strerror(errno)), exit(1);
+      if ((c = inet_pton(AF_INET6, argv[optind], &setup.ocat_addr)) < 0)
+         log_msg(L_ERROR, "inet_pton failed: %s", strerror(errno)), exit(1);
+      else if (!c)
+         log_msg(L_ERROR, "%s is not a valid IPv6 address", argv[optind]), exit(1);
       if (!has_tor_prefix(&setup.ocat_addr))
          log_msg(L_ERROR, "address does not have TOR prefix"), exit(1);
       ipv6tonion(&setup.ocat_addr, setup.onion_url);
@@ -166,29 +182,36 @@ int main(int argc, char *argv[])
       log_msg(L_ERROR, "parameter seems not to be valid onion hostname"), exit(1);
    if (oniontipv6(setup.onion_url, &setup.ocat_addr) == -1)
       log_msg(L_ERROR, "parameter seems not to be valid onion hostname"), exit(1);
+   if (setup.ipv4_enable)
+      oniontipv4(setup.onion_url, &setup.ocat_addr4, ntohl(setup.ocat_addr4_mask));
 
    inet_ntop(AF_INET6, &setup.ocat_addr, ip6addr, INET6_ADDRSTRLEN);
 
    if (urlconv == 1)
    {
       printf("%s\n", ip6addr);
+      if (setup.ipv4_enable)
+         printf("%s\n", inet_ntoa(setup.ocat_addr4));
       exit(0);
    }
 
    log_msg(L_NOTICE, "%s (c) Bernhard R. Fischer -- compiled %s %s", PACKAGE_STRING, __DATE__, __TIME__);
 
+   if (setup.config_file)
+   {
+      log_msg(L_NOTICE, "reading config file %s", setup.config_file);
+      if ((c = open(setup.config_file, O_RDONLY)) == -1)
+         log_msg(L_ERROR, "error opening file: %s", strerror(errno)), exit(1);
+      ctrl_handler((void*) c);
+   }
+
 #ifndef WITHOUT_TUN
    // create TUN device
    setup.tunfd[0] = setup.tunfd[1] = tun_alloc(tunname, setup.ocat_addr);
-#ifdef TEST_TUN_HDR
-   test_tun_hdr();
-   if (setup.test_only)
-      exit(0);
-#endif
 #endif
 
    log_msg(L_NOTICE, "local IP is %s on %s", ip6addr, tunname);
-   log_debug("tun frameheader = 0x%08x", ntohl(setup.fhd_key));
+   log_debug("tun frameheader v6 = 0x%08x, v4 = 0x%08x", ntohl(setup.fhd_key[IPV6_KEY]), ntohl(setup.fhd_key[IPV4_KEY]));
 
    // start socket receiver thread
    run_ocat_thread("receiver", socket_receiver, NULL);
diff --git a/src/ocat.h b/src/ocat.h
index e1577e2..1c1663b 100644
--- a/src/ocat.h
+++ b/src/ocat.h
@@ -20,6 +20,7 @@
 
 #include "config.h"
 
+#include <stdio.h>
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
@@ -31,13 +32,24 @@
 #include <netinet/ip6.h>
 #endif
 #include <pthread.h>
+#include <endian.h>
 
 
+#ifndef ETHERTYPE_IPV6
+#define ETHERTYPE_IPV6 0x86dd
+#endif
 
 #define IP6HLEN sizeof(struct ip6_hdr)
 //! TOR prefix: FD87:D87E:EB43::/48
 #define TOR_PREFIX {0xfd,0x87,0xd8,0x7e,0xeb,0x43}
 #define TOR_PREFIX_LEN 48
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define TOR_PREFIX4 {0x0000000a}
+#define TOR_PREFIX4_MASK 0x000000ff
+#else
+#define TOR_PREFIX4 {0x0a000000}
+#define TOR_PREFIX4_MASK 0xff000000
+#endif
 #define MAXPEERS 1024
 //! Local listening port for incoming connections from TOR.
 #define OCAT_LISTEN_PORT 8060
@@ -94,11 +106,21 @@
 #define SOCKS_CONNECTING 1
 #define SOCKS_MAX_RETRY 3
 
+#define E_RT_NOMEM -1
+#define E_RT_DUP -2
+#define E_RT_ILLNM -3
+#define E_RT_SYNTAX -4
+#define E_RT_NULLPTR -5
+
+
+#define IPV4_KEY 0
+#define IPV6_KEY 1
+
 struct OcatSetup
 {
    //! frame header of local OS in network byte order
    //! it is initialized in ocattun.c
-   uint32_t fhd_key;
+   uint32_t fhd_key[2];
    //! TCP port of SOCKS port of local Tor proxy
    uint16_t tor_socks_port;
    //! reload port of OnionCat listening for connections
@@ -122,6 +144,11 @@ struct OcatSetup
    int controller;
    char *ocat_dir;
    char *tun_dev;
+   int ipv4_enable;
+   struct in_addr ocat_addr4;
+   int ocat_addr4_mask;
+   char *config_file;
+   int config_read;
 };
 
 typedef struct PacketQueue
@@ -176,6 +203,13 @@ typedef struct SocksQueue
    int state;
 } SocksQueue_t;
 
+typedef struct IPv4Route
+{
+   struct IPv4Route *next[2];    //!< next routes in binary tree
+   uint32_t dest;
+   uint32_t netmask;
+   struct in6_addr gw;
+} IPv4Route_t;
 
 /*
 // next header value for ocat internal use (RFC3692)
@@ -254,6 +288,7 @@ void log_msg(int, const char *, ...);
 /* ocatv6conv.c */
 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 *);
 
 /* ocattun.c */
@@ -271,6 +306,7 @@ void *socket_acceptor(void *);
 void *socks_connector(void *);
 void *socket_cleaner(void *);
 void *ocat_controller(void *);
+void *ctrl_handler(void *);
 
 /* ocatthread.c */
 const OcatThread_t *init_ocat_thread(const char *);
@@ -299,5 +335,13 @@ void delete_peer(OcatPeer_t *);
 /* ocatsetup.c */
 extern struct OcatSetup setup;
 
+/* ocatipv4route.c */
+//int ipv4_add_route(IPv4Route_t *);
+//IPv4Route_t *ipv4_lookup_route(uint32_t);
+struct in6_addr *ipv4_lookup_route(uint32_t);
+int parse_route(const char *);
+void print_routes(FILE *);
+
+
 #endif
 
diff --git a/src/ocatipv4route.c b/src/ocatipv4route.c
new file mode 100644
index 0000000..31fb715
--- /dev/null
+++ b/src/ocatipv4route.c
@@ -0,0 +1,209 @@
+/* Copyright 2008 Bernhard R. Fischer, Daniel Haslinger.
+ *
+ * This file is part of OnionCat.
+ *
+ * OnionCat is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * OnionCat is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OnionCat. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*! ocatipv4route.c
+ *  This file contains functions for managing IPv4 routing and
+ *  forwarding.
+ *
+ *  @author Bernhard R. Fischer <rahra _at_ cypherpunk at>
+ *  @version 2008/09/03-01
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "ocat.h"
+
+#define NMBIT(i,n) ((i&n)&~(n<<1))
+#define BRANCH(i,n) (NMBIT(i,n)!=0)
+
+
+static IPv4Route_t *rroot_ = NULL;
+static pthread_mutex_t route_mutex_ = PTHREAD_MUTEX_INITIALIZER;
+
+
+int ipv4_add_route__(IPv4Route_t *route, IPv4Route_t **root, uint32_t cur_nm)
+{
+   if (!(*root))
+   {
+      if (!(*root = calloc(1, sizeof(IPv4Route_t))))
+      {
+         log_msg(L_FATAL, "ipv4_add_route: %s", strerror(errno));
+         return E_RT_NOMEM;
+      }
+      (*root)->dest = route->dest & cur_nm;
+      (*root)->netmask = cur_nm;
+   }
+
+   if (route->netmask == cur_nm /*(*root)->netmask*/)
+   {
+      if (!memcmp(&(*root)->gw, &in6addr_any, sizeof(struct in6_addr)))
+      {
+         memcpy(&(*root)->gw, &route->gw, sizeof(struct in6_addr));
+         return 0;
+      }
+
+      if (!memcmp(&(*root)->gw, &route->gw, sizeof(struct in6_addr)))
+         return 0;
+
+      log_msg(L_ERROR, "route already exists");
+      return E_RT_DUP;
+   }
+
+   // break recursion in case of error
+   if (cur_nm == 0xffffffff)
+   {
+      log_msg(L_ERROR, "netmask error in netmask of route: %08x", route->netmask);
+      return E_RT_ILLNM;
+   }
+
+   //now branch to subs
+   cur_nm >>= 1;
+   cur_nm |= 0x80000000;
+
+   //return ipv4_add_route(&(*root)->next[((route->dest & cur_nm) & ~(cur_nm << 1)) != 0], cur_nm, route);
+   return ipv4_add_route__(route, &(*root)->next[BRANCH(route->dest, cur_nm)], cur_nm);
+}
+
+
+int ipv4_add_route(IPv4Route_t *route)
+{
+   int r;
+
+   pthread_mutex_lock(&route_mutex_);
+   r = ipv4_add_route__(route, &rroot_, 0);
+   pthread_mutex_unlock(&route_mutex_);
+
+   return r;
+}
+
+
+IPv4Route_t *ipv4_lookup_route__(uint32_t ip, IPv4Route_t *route, uint32_t cur_nm)
+{
+   if (!route)
+   {
+      log_debug("NULL route");
+      return NULL;
+   }
+
+   cur_nm >>= 1;
+   cur_nm |= 0x80000000;
+
+   if (route->next[BRANCH(ip, cur_nm)])
+      return ipv4_lookup_route__(ip, route->next[BRANCH(ip, cur_nm)], cur_nm);
+
+   //if (ip & (cur_nm << 1) == route->dest)
+   if (memcmp(&route->gw, &in6addr_any, sizeof(struct in6_addr)))
+      return route;
+
+   return NULL;
+}
+
+
+/*! Lookup a route to an ip address in routing table.
+ *  @param Ip to find a route for. The Ip must be given in host byte order.
+ *  @return Pointer to IPv6 TOR address. */
+struct in6_addr *ipv4_lookup_route(uint32_t ip)
+{
+   IPv4Route_t *r;
+
+   pthread_mutex_lock(&route_mutex_);
+   r = ipv4_lookup_route__(ip, rroot_, 0);
+   pthread_mutex_unlock(&route_mutex_);
+
+   return r ? &r->gw : NULL;
+}
+
+
+void ipv4_traverse(IPv4Route_t *route, void (func)(IPv4Route_t*, void*), void *p)
+{
+   if (!route)
+      return;
+
+   func(route, p);
+   ipv4_traverse(route->next[0], func, p);
+   ipv4_traverse(route->next[1], func, p);
+}
+
+
+void ipv4_print(IPv4Route_t *route, void *f)
+{
+   char addr[INET6_ADDRSTRLEN];
+   struct in_addr iaddr;
+
+   if (!memcmp(&route->gw, &in6addr_any, sizeof(struct in6_addr)))
+      return;
+
+   iaddr.s_addr = htonl(route->dest);
+   fprintf(f, "%s ", inet_ntoa(iaddr));
+   iaddr.s_addr = htonl(route->netmask);
+   fprintf(f, "%s ", inet_ntoa(iaddr));
+   inet_ntop(AF_INET6, &route->gw, addr, INET6_ADDRSTRLEN);
+   fprintf(f, "%s", addr);
+   fprintf(f, " %p", route);
+   fprintf(f, "\n");
+}
+
+
+void print_routes(FILE *f)
+{
+   ipv4_traverse(rroot_, ipv4_print, f);
+}
+
+
+int parse_route(const char *rs)
+{
+   char buf[strlen(rs) + 1], *s, *b;
+   IPv4Route_t route;
+
+   if (!rs)
+      return E_RT_NULLPTR;
+
+   log_debug("parsing route \"%s\"", rs);
+
+   strlcpy(buf, rs, strlen(rs) + 1);
+   if (!(s = strtok_r(buf, " \t", &b)))
+      return E_RT_SYNTAX;
+
+   if (inet_pton(AF_INET, s, &route.dest) != 1)
+      return E_RT_SYNTAX;
+
+   if (!(s = strtok_r(NULL, " \t", &b)))
+      return E_RT_SYNTAX;
+
+   if (inet_pton(AF_INET, s, &route.netmask) != 1)
+      return E_RT_SYNTAX;
+
+   if (!(s = strtok_r(NULL, " \t", &b)))
+      return E_RT_SYNTAX;
+
+   if (inet_pton(AF_INET6, s, &route.gw) != 1)
+      return E_RT_SYNTAX;
+
+   route.netmask = ntohl(route.netmask);
+   route.dest = ntohl(route.dest);
+
+   return ipv4_add_route(&route);
+}
+
diff --git a/src/ocatlog.c b/src/ocatlog.c
index 6164491..8f940df 100644
--- a/src/ocatlog.c
+++ b/src/ocatlog.c
@@ -99,11 +99,13 @@ void log_msg(int lf, const char *fmt, ...)
 
    va_start(ap, fmt);
    vlog_msgf(stderr, lf, fmt, ap);
+   va_end(ap);
    if (clog_ && (lf & L_FCONN))
    {
+      va_start(ap, fmt);
       vlog_msgf(clog_, lf, fmt, ap);
+      va_end(ap);
       (void) fflush(clog_);
    }
-   va_end(ap);
 }
 
diff --git a/src/ocatpeer.c b/src/ocatpeer.c
index 5daff47..7567e1a 100644
--- a/src/ocatpeer.c
+++ b/src/ocatpeer.c
@@ -98,7 +98,7 @@ OcatPeer_t *get_empty_peer(void)
       return NULL;
    }
 
-   peer->fraghdr = setup.fhd_key;
+   //peer->fraghdr = setup.fhd_key;
    if ((rc = pthread_mutex_init(&peer->mutex, NULL)))
    {
       log_msg(L_FATAL, "cannot init new peer mutex: \"%s\"", strerror(rc));
diff --git a/src/ocatroute.c b/src/ocatroute.c
index 0987ec8..bc3c6b8 100644
--- a/src/ocatroute.c
+++ b/src/ocatroute.c
@@ -41,6 +41,7 @@
 #ifdef HAVE_LINUX_SOCKIOS_H
 #include <linux/sockios.h>
 #endif
+#include <netinet/ip.h>
 
 #include "ocat.h"
 
@@ -213,18 +214,12 @@ void hex_code_header(const char *frame, int len, char *buf)
 }
 
 
-// do some packet validation
-int validate_frame(const struct ip6_hdr *ihd, int len)
+/*! Check if source and destination address has
+ *  the TOR IPv6 prefix.
+ *  @return 0 on error or packet length else. */
+int check_tor_prefix(const struct ip6_hdr *ihd)
 {
    char buf[INET6_ADDRSTRLEN];
-   char hexbuf[IP6HLEN * 3 + 1];
-
-   if ((ihd->ip6_vfc & 0xf0) != 0x60)
-   {
-      hex_code_header((char*) ihd, len > IP6HLEN ? IP6HLEN : len, hexbuf);
-      log_debug("header \"%s\"", hexbuf);
-      return 0;
-   }
 
    if (!has_tor_prefix(&ihd->ip6_dst))
    {
@@ -236,14 +231,23 @@ int validate_frame(const struct ip6_hdr *ihd, int len)
       log_msg(L_ERROR, "source address invalid. Remote ocat could not reply");
       return 0;
    }
-#ifdef TEST_TUN_HDR
-   if (is_testping(&ihd->ip6_dst))
+   return ntohs(ihd->ip6_plen);
+}
+
+
+// do some packet validation
+int validate_frame(const struct ip6_hdr *ihd, int len)
+{
+   char hexbuf[IP6HLEN * 3 + 1];
+
+   if ((ihd->ip6_vfc & 0xf0) != 0x60)
    {
-      log_debug("test ping detected");
+      hex_code_header((char*) ihd, len > IP6HLEN ? IP6HLEN : len, hexbuf);
+      log_debug("header \"%s\"", hexbuf);
       return 0;
    }
-#endif
-   return ntohs(ihd->ip6_plen);
+
+   return check_tor_prefix(ihd);
 }
 
 
@@ -290,11 +294,13 @@ int handle_http(const OcatPeer_t *peer)
 
 void *socket_receiver(void *p)
 {
-   int maxfd, len, plen;
+   int maxfd, len;
    char buf[FRAME_SIZE];
    char addr[INET6_ADDRSTRLEN];
    fd_set rset;
    OcatPeer_t *peer;
+   struct in6_addr *in6;
+   int drop = 0;
 
    if (pipe(lpfd_) < 0)
       log_msg(L_FATAL, "could not create pipe for socket_receiver: \"%s\"", strerror(errno)), exit(1);
@@ -398,7 +404,104 @@ void *socket_receiver(void *p)
          // update timestamp
          peer->time = time(NULL);
          peer->in += len;
+
+         while (peer->fraglen)
+         {
+            // incoming packet seems to be IPv6
+            if ((peer->fragbuf[0] & 0xf0) == 0x60)
+            {
+               log_debug("identified IPv6 packet");
+               if ((peer->fraglen < IP6HLEN) || (peer->fraglen < ntohs(((struct ip6_hdr*) peer->fragbuf)->ip6_plen) + IP6HLEN))
+               {
+                  log_debug("keeping %d bytes frag", peer->fraglen);
+                  break;
+               }
+
+               len = ntohs(((struct ip6_hdr*)peer->fragbuf)->ip6_plen) + IP6HLEN;
+               peer->fraghdr = setup.fhd_key[IPV6_KEY];
+/*
+               // set IP address if it is not set yet and frame is valid
+               if (!memcmp(&peer->addr, &in6addr_any, sizeof(struct in6_addr)))
+               {
+                  memcpy(&peer->addr, &((struct ip6_hdr*)peer->fragbuf)->ip6_src, sizeof(struct in6_addr));
+                  log_msg(L_NOTICE | L_FCONN, "incoming connection on %d from %s is now identified", peer->tcpfd,
+                     inet_ntop(AF_INET6, &peer->addr, addr, INET6_ADDRSTRLEN));
+               }*/
+            }
+            // incoming packet seems to be IPv4
+            else if ((peer->fragbuf[0] & 0xf0) == 0x40)
+            {
+               if ((peer->fragbuf[0] & 0x0f) < 5)
+               {
+                  log_debug("dropping packet, not IPv4 - resetting fragment buffer");
+                  peer->fraglen = 0;
+                  break;
+               }
                
+               log_debug("identified IPv4 packet");
+               if ((peer->fraglen < sizeof(struct iphdr)) || (peer->fraglen < ntohs(((struct iphdr*) peer->fragbuf)->tot_len)))
+               {
+                  log_debug("keeping %d bytes frag", peer->fraglen);
+                  break;
+               }
+
+               len = ntohs(((struct iphdr*) peer->fragbuf)->tot_len);
+               peer->fraghdr = setup.fhd_key[IPV4_KEY];
+            }
+            else
+            {
+               log_debug("fragment buffer reset");
+               peer->fraglen = 0;
+               break;
+            }
+
+            // set IP address if it is not set yet and frame is valid
+            if (!memcmp(&peer->addr, &in6addr_any, sizeof(struct in6_addr)))
+            {
+               if (peer->fraghdr == setup.fhd_key[IPV6_KEY])
+                  memcpy(&peer->addr, &((struct ip6_hdr*)peer->fragbuf)->ip6_src, sizeof(struct in6_addr));
+               else if (peer->fraghdr == setup.fhd_key[IPV4_KEY])
+               {
+                  // check if there is a route back
+                  if (!(in6 = ipv4_lookup_route(ntohl(((struct iphdr*) peer->fragbuf)->saddr))))
+                  {
+                     drop = 1;
+                     log_debug("no route back");
+                  }
+                  else
+                     memcpy(&peer->addr, in6, sizeof(struct in6_addr));
+               }
+
+               if (!drop)
+                  log_msg(L_NOTICE | L_FCONN, "incoming connection on %d from %s is now identified", peer->tcpfd,
+                     inet_ntop(AF_INET6, &peer->addr, addr, INET6_ADDRSTRLEN));
+            }
+
+            if (!drop)
+            {
+               log_debug("writing to tun %d framesize %d + 4", setup.tunfd[1], len);
+               if (write(setup.tunfd[1], &peer->fraghdr, len + 4) != (len + 4))
+                  log_msg(L_ERROR, "could not write %d bytes to tunnel %d", len + 4, setup.tunfd[1]);
+            }
+            else
+            {
+               log_msg(L_ERROR, "dropping packet with %d bytes", len);
+               drop = 0;
+            }
+
+
+            peer->fraglen -= len;
+            if (peer->fraglen)
+            {
+               log_debug("moving fragment. fragsize %d", peer->fraglen);
+               memmove(peer->fragbuf, peer->fragbuf + len, FRAME_SIZE - 4 - len);
+            }
+            else
+               log_debug("fragbuf empty");
+
+        } // while (peer->fraglen)
+
+#if 0
          while (peer->fraglen >= IP6HLEN)
          {
             // check frame
@@ -457,6 +560,8 @@ void *socket_receiver(void *p)
             else
                log_debug("fragbuf empty");
          } // while (peer->fraglen >= IP6HLEN)
+#endif
+
          unlock_peer(peer);
       } // while (maxfd)
    } // for (;;)
@@ -823,10 +928,9 @@ void *socks_connector(void *p)
 void packet_forwarder(void)
 {
    char buf[FRAME_SIZE];
-   struct ip6_hdr *ihd;
    int rlen;
-
-   ihd = (struct ip6_hdr*) &buf[4];
+   struct in6_addr *dest;
+   struct in_addr in;
 
    for (;;)
    {
@@ -845,19 +949,50 @@ void packet_forwarder(void)
 
       log_debug("received on tunfd %d, framesize %d + 4", setup.tunfd[0], rlen - 4);
 
-      if (!validate_frame(ihd, rlen - 4))
+      if (*((uint32_t*) buf) == setup.fhd_key[IPV6_KEY])
+      {
+         if (((rlen - 4) < IP6HLEN))
+         {
+            log_debug("IPv6 packet too short (%d bytes). dropping", rlen - 4);
+            continue;
+         }
+
+         if (!check_tor_prefix((struct ip6_hdr*) &buf[4]))
+         {
+            log_msg(L_ERROR, "dropping frame");
+            continue;
+         }
+
+         dest = &((struct ip6_hdr*) &buf[4])->ip6_dst;
+      }
+      else if (*((uint32_t*) buf) == setup.fhd_key[IPV4_KEY])
+      {
+         if (((rlen - 4) < sizeof(struct iphdr)))
+         {
+            log_debug("IPv4 packet too short (%d bytes). dropping", rlen - 4);
+            continue;
+         }
+
+         in.s_addr = ((struct iphdr*) &buf[4])->daddr;
+         if (!(dest = ipv4_lookup_route(ntohl(in.s_addr))))
+         {
+            log_msg(L_ERROR, "no route to destination %s, dropping frame.", inet_ntoa(in));
+            continue;
+         }
+      }
+      else
       {
-         log_msg(L_ERROR, "dropping frame");
+         log_msg(L_ERROR, "protocol 0x%08x not supported. dropping frame.", ntohl(*((uint32_t*) buf)));
          continue;
       }
 
       // now forward either directly or to the queue
-      if (forward_packet(&ihd->ip6_dst, buf + 4, rlen - 4) == E_FWD_NOPEER)
+      if (forward_packet(dest, buf + 4, rlen - 4) == E_FWD_NOPEER)
       {
          log_msg(L_NOTICE, "establishing new socks peer");
-         socks_queue(&ihd->ip6_dst);
+         socks_queue(dest);
          log_debug("queuing packet");
-         queue_packet(&ihd->ip6_dst, buf + 4, rlen - 4);
+         queue_packet(dest, buf + 4, rlen - 4);
       }
    }
 }
@@ -897,14 +1032,15 @@ void *socket_cleaner(void *ptr)
 }
 
 
-void _remtr(char *s)
+int _remtr(char *s)
 {
    if (!s[0])
-      return;
-   if (s[strlen(s) - 1] != '\n' && s[strlen(s) - 1] != '\r')
-      return;
-   s[strlen(s) - 1] = '\0';
-   _remtr(s);
+      return 0;
+   if (s[0] && (s[strlen(s) - 1] == '\n'))
+      s[strlen(s) - 1] = '\0';
+   if (s[0] && (s[strlen(s) - 1] == '\r'))
+      s[strlen(s) - 1] = '\0';
+   return strlen(s);
 }
 
 
@@ -915,10 +1051,9 @@ void _remtr(char *s)
 // FIXME: ctrl_handler probably is not thread-safe.
 void *ctrl_handler(void *p)
 {
-
-   int fd;
-   FILE *ff;
-   char buf[FRAME_SIZE], addrstr[INET6_ADDRSTRLEN], onionstr[ONION_NAME_SIZE], timestr[32];
+   int fd, c;
+   FILE *ff, *fo;
+   char buf[FRAME_SIZE], addrstr[INET6_ADDRSTRLEN], onionstr[ONION_NAME_SIZE], timestr[32], *s;
    int rlen, cfd;
    struct tm *tm;
    OcatThread_t *th;
@@ -929,30 +1064,69 @@ void *ctrl_handler(void *p)
    log_debug("thread detached");
 
    fd = (int) p;
-   if (!(ff = fdopen(fd, "r+")))
+   if (setup.config_read)
+   {
+      if (!(ff = fdopen(fd, "r+")))
+      {
+         log_msg(L_ERROR, "could not open %d for writing: %s", fd, strerror(errno));
+         return NULL;
+      }
+      log_debug("fd %d fdopen'ed", fd);
+      fo = ff;
+   }
+   else
    {
-      log_msg(L_ERROR, "could not open %d for writing", fd);
-      return NULL;
+      if (!(ff = fdopen(fd, "r")))
+      {
+         log_msg(L_ERROR, "could not open %d for reading: %s", fd, strerror(errno));
+         setup.config_read = 1;
+         return NULL;
+      }
+      log_debug("fd %d fdopen'ed", fd);
+      fo = stderr;
+      //setup.config_read = 1;
    }
-   log_debug("fd %d fdopen'ed", fd);
 
    for (;;)
    {
-      fprintf(ff, "> ");
+      if (setup.config_read)
+         fprintf(fo, "> ");
+
+      c = getc(ff);
+      if (c == EOF)
+      {
+         log_debug("EOF received.");
+         break;
+      }
+      else if (c == 4)
+      {
+         log_debug("^D received.");
+         break;
+      }
+      else
+      {
+         if (ungetc(c, ff) == EOF)
+         {
+            log_debug("received EOF on ungetc");
+            break;
+         }
+      }
+
       if (!fgets(buf, FRAME_SIZE, ff))
       {
          if (!feof(ff))
             log_msg(L_ERROR, "error reading from %d");
          break;
       }
-      // remove trailing \r\n character
-      _remtr(buf);
-      // continue if string now is empty
-      if (!buf[0])
+
+      if (!(rlen = _remtr(buf)))
+         continue;
+
+      if (!strtok_r(buf, " \t\r\n", &s))
          continue;
 
       // "exit"/"quit" => terminate thread
-      if (buf[0] == 4 || !strncmp(buf, "exit", 4) || !strncmp(buf, "quit", 4))
+      if (!strncmp(buf, "exit", 4) || !strncmp(buf, "quit", 4))
          break;
       // "status"
       else if (!strncmp(buf, "status", 6))
@@ -964,7 +1138,7 @@ void *ctrl_handler(void *p)
             {
                tm = localtime(&peer->otime);
                strftime(timestr, 32, "%c", tm);
-               fprintf(ff, "[%s]\n fd = %d\n addr = %s\n dir = \"%s\"\n idle = %lds\n bytes_in = %ld\n bytes_out = %ld\n setup_delay = %lds\n opening_time = \"%s\"\n",
+               fprintf(fo, "[%s]\n fd = %d\n addr = %s\n dir = \"%s\"\n idle = %lds\n bytes_in = %ld\n bytes_out = %ld\n setup_delay = %lds\n opening_time = \"%s\"\n",
                      ipv6tonion(&peer->addr, onionstr), peer->tcpfd,
                      inet_ntop(AF_INET6, &peer->addr, addrstr, INET6_ADDRSTRLEN),
                      peer->dir == PEER_INCOMING ? "in" : "out",
@@ -987,7 +1161,7 @@ void *ctrl_handler(void *p)
          if (!peer)
          {
             log_msg(L_NOTICE, "no peer with fd %d exists\n", cfd);
-            fprintf(ff, "no peer with fd %d exists\n", cfd);
+            fprintf(fo, "no peer with fd %d exists\n", cfd);
          }
          unlock_peers();
       }
@@ -1006,23 +1180,38 @@ void *ctrl_handler(void *p)
       }
       else if (!strncmp(buf, "fds", 3))
       {
-         fprintf(ff, "acceptor sockets: %d/%d\nconntroller sockets: %d/%d\n", sockfd_[0], sockfd_[1], ctrlfd_[0], ctrlfd_[1]);
+         fprintf(fo, "acceptor sockets: %d/%d\nconntroller sockets: %d/%d\n", sockfd_[0], sockfd_[1], ctrlfd_[0], ctrlfd_[1]);
+      }
+      else if (!strncmp(buf, "route", 5))
+      {
+         if (rlen > 6)
+         {
+            if ((c = parse_route(&buf[6])))
+               fprintf(ff, "ERR %d\n", c);
+         }
+         else
+            print_routes(fo);
       }
       else if (!strncmp(buf, "help", 4))
       {
-         fprintf(ff, "commands:\nexit\nquit\nterminate\nclose <n>\nstatus\nthreads\nfds\n");
+         fprintf(fo, "commands:\nexit\nquit\nterminate\nclose <n>\nstatus\nthreads\nfds\nroute [<destination IP> <netmask> <IPv6 gateway>]\n");
       }
       else
       {
-         fprintf(ff, "unknown command: \"%s\"\n", buf);
+         fprintf(fo, "ERR unknown command: \"%s\"\n", buf);
       }
    }
 
+   if (setup.config_read)
+      fprintf(fo, "Good bye!\n");
    log_msg(L_NOTICE | L_FCONN, "closing session %d", fd);
    if (fclose(ff) == EOF)
       log_msg(L_ERROR, "error closing control stream: \"%s\"", strerror(errno));
    // fclose also closes the fd according to the man page
 
+   if (!setup.config_read)
+      setup.config_read = 1;
+
    return NULL;
 }
 
diff --git a/src/ocatsetup.c b/src/ocatsetup.c
index ec63377..67e15b5 100644
--- a/src/ocatsetup.c
+++ b/src/ocatsetup.c
@@ -26,5 +26,8 @@
 
 #include "ocat.h"
 
-struct OcatSetup setup = {0, TOR_SOCKS_PORT, OCAT_LISTEN_PORT, OCAT_DEST_PORT, OCAT_CTRL_PORT, 0, {0, 1}, 4, OCAT_UNAME, {0}, {{{0}}}, 0, 0, 0, 0, 1, OCAT_DIR, TUN_DEV};
+struct OcatSetup setup = {{0, 0}, TOR_SOCKS_PORT, OCAT_LISTEN_PORT, OCAT_DEST_PORT, OCAT_CTRL_PORT, 0, {0, 1}, 4, OCAT_UNAME, {0}, {{{0}}}, 0, 0, 0, 0, 1, OCAT_DIR, TUN_DEV,
+   0, TOR_PREFIX4, TOR_PREFIX4_MASK,
+   NULL, 1
+};
 
diff --git a/src/ocattun.c b/src/ocattun.c
index a3c63b2..39df6f4 100644
--- a/src/ocattun.c
+++ b/src/ocattun.c
@@ -46,6 +46,7 @@
 #ifdef HAVE_NET_IF_TUN_H
 #include <net/if_tun.h>
 #endif
+#include <net/ethernet.h>
 
 #include "ocat.h"
 
@@ -58,36 +59,47 @@ int tun_alloc(char *dev, struct in6_addr addr)
    struct ifreq ifr;
    int fd;
    char astr[INET6_ADDRSTRLEN];
+   char astr4[INET_ADDRSTRLEN];
    char buf[FRAME_SIZE];
+   struct in_addr netmask = {setup.ocat_addr4_mask};
 
 	log_debug("opening tun \"%s\"", tun_dev_);
-   if( (fd = open(tun_dev_, O_RDWR)) < 0 )
+   if ((fd = open(tun_dev_, O_RDWR)) < 0)
       perror("open tun"), exit(1);
    inet_ntop(AF_INET6, &addr, astr, INET6_ADDRSTRLEN);
+   inet_ntop(AF_INET, &setup.ocat_addr4, astr4, INET_ADDRSTRLEN);
 
 #ifdef __linux__
 
    memset(&ifr, 0, sizeof(ifr));
    ifr.ifr_flags = IFF_TUN;
    //ifr.ifr_flags |= IFF_NO_PI;
-   if(*dev)
+   if (*dev)
       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
 
-   if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0)
+   if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0)
       perror("TUNSETIFF"), exit(1);
    strlcpy(dev, ifr.ifr_name, IFNAMSIZ);
-   sprintf(buf, "ifconfig tun0 add %s/%d up", astr, TOR_PREFIX_LEN);
+   sprintf(buf, "ifconfig %s add %s/%d up", dev, astr, TOR_PREFIX_LEN);
    log_msg(L_NOTICE, "configuring tun IP: \"%s\"", buf);
    if (system(buf) == -1)
       log_msg(L_ERROR, "could not exec \"%s\": \"%s\"", buf, strerror(errno));
+
+   // according to drivers/net/tun.c only IFF_MULTICAST and IFF_PROMISC are supported.
+/*   ifr.ifr_flags = IFF_UP | IFF_RUNNING | IFF_MULTICAST | IFF_NOARP;
+   if (ioctl(fd, SIOCSIFFLAGS, (void*) &ifr) < 0)
+      log_msg(L_ERROR, "could not set interface flags: \"%s\"", strerror(errno));
+      */
+
    // set tun frame header to ethertype IPv6
-   setup.fhd_key = htonl(0x86dd);
-   //setup.fhd_key = htonl(ETH_P_IPV6);
+   setup.fhd_key[IPV6_KEY] = htonl(ETHERTYPE_IPV6);
+   setup.fhd_key[IPV4_KEY] = htonl(ETHERTYPE_IP);
 
 #else
 
    // set tun frame header to address family AF_INET6 (FreeBSD = 0x1c, OpenBSD = 0x18)
-   setup.fhd_key = htonl(AF_INET6);
+   setup.fhd_key[IPV6_KEY] = htonl(AF_INET6);
+   setup.fhd_key[IPV4_KEY] = htonl(AF_INET);
 
 #ifdef __FreeBSD__
 
@@ -107,51 +119,17 @@ int tun_alloc(char *dev, struct in6_addr addr)
 
 #endif
 
-   return fd;
-}              
- 
-
-#ifdef TEST_TUN_HDR
-
-/*! This is a test function which detects the frame
- *  header of the local OS by sending a ping into
- *  the tun by a call to system("ping6..."). */
-void test_tun_hdr(void)
-{
-   struct in6_addr addr;
-   char addrstr[INET6_ADDRSTRLEN];
-   char buf[FRAME_SIZE];
-   int rlen;
-
-   if (oniontipv6("aaaaaaaaaaaaaaab", &addr) == -1)
-      log_msg(L_FATAL, "[test_tun_hdr] this should never happen..."), exit(1);
-
-   inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
-#ifdef __linux__
-   sprintf(buf, "ping6 -c 1 -w 1 %s >/dev/null 2>&1", addrstr);
-#else
-   //sprintf(buf, "ping6 -c 1 %s >/dev/null 2>&1", addrstr);
-   sprintf(buf, "ping6 -c 1 %s", addrstr);
-#endif
-   log_msg(L_NOTICE, "[test_tun_hdr] testing tun header: \"%s\"", buf);
-   // FIXME: This is somehow an unclean try to wait for ifconfig to finish
-   sleep(1);
-   if (system(buf) == -1)
-      log_msg(L_FATAL, "[test_tun_hdr] test failed: \"%s\"", strerror(errno));
-   rlen = read(tunfd_[0], buf, FRAME_SIZE);
-   log_debug("[test_tun_hdr] read %d bytes from %d, head = 0x%08x", rlen, tunfd_[0], ntohl(*((uint32_t*)buf)));
-
-   if ((buf[0] & 0xf0) == 0x60)
+   // setting up IPv4 address
+   if (setup.ipv4_enable)
    {
-      log_msg(L_NOTICE, "[test_tun_hdr] tun doesn't seem to have any frame header");
-      return;
+      sprintf(buf, "ifconfig %s %s netmask %s", dev, astr4, inet_ntoa(netmask));
+      log_msg(L_NOTICE, "configuring tun IP: \"%s\"", buf);
+      if (system(buf) == -1)
+         log_msg(L_ERROR, "could not exec \"%s\": \"%s\"", buf, strerror(errno));
    }
-   
-   setup.fhd_key = *((uint32_t*)buf);
-   log_msg(L_NOTICE, "[test_tun_hdr] using 0x%08x as local frame header", ntohl(setup.fhd_key));
-}
-
-#endif
 
+   return fd;
+}              
+ 
 #endif
 
diff --git a/src/ocatv6conv.c b/src/ocatv6conv.c
index abe9f89..1388a29 100644
--- a/src/ocatv6conv.c
+++ b/src/ocatv6conv.c
@@ -88,6 +88,22 @@ int oniontipv6(const char *onion, struct in6_addr *ip6)
 }
 
 
+int oniontipv4(const char *onion, struct in_addr *ip, int prefix_mask)
+{
+   struct in6_addr ip6;
+   //uint32_t netmask = 0xffffffff << (32 - prefix_len);
+   uint32_t netmask = prefix_mask;
+   uint32_t ip4;
+
+   if (oniontipv6(onion, &ip6))
+      return -1;
+   memcpy(&ip4, &ip6.s6_addr[12], sizeof(ip4));
+   ip4 &= htonl(~netmask);
+   ip->s_addr |= ip4;
+   return 0;
+}
+
+
 char *ipv6tonion(const struct in6_addr *ip6, char *onion)
 {
    int i;

-- 
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