[Pkg-privacy-commits] [onioncat] 61/241: ocat now IPv4 aware
Intrigeri
intrigeri at moszumanska.debian.org
Wed Aug 26 16:16:27 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 72fb9b44e670deea4e67fc657e981dbce93455ce
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: https://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