Skip to content

Commit

Permalink
Allow communicate with tun file dscription opened by 3rd process
Browse files Browse the repository at this point in the history
  • Loading branch information
madafoo committed Mar 11, 2016
1 parent f069641 commit 34ad41c
Show file tree
Hide file tree
Showing 9 changed files with 600 additions and 3 deletions.
38 changes: 38 additions & 0 deletions admin/angel/Core.c
Expand Up @@ -28,6 +28,7 @@
#include "interface/Iface.h"
#include "util/events/UDPAddrIface.h"
#include "interface/tuntap/TUNInterface.h"
#include "interface/tuntap/AndroidWrapper.h"
#include "interface/UDPInterface_admin.h"
#ifdef HAS_ETH_INTERFACE
#include "interface/ETHInterface_admin.h"
Expand All @@ -43,6 +44,10 @@
#include "tunnel/IpTunnel_admin.h"
#include "tunnel/RouteGen_admin.h"
#include "util/events/EventBase.h"
#ifndef win32
#include "util/events/libuv/FileNo_admin.h"
#include "util/events/FileNo.h"
#endif
#include "util/events/Pipe.h"
#include "util/events/Timeout.h"
#include "util/Hex.h"
Expand Down Expand Up @@ -105,9 +110,33 @@ struct Context
struct EventBase* base;
struct NetCore* nc;
struct IpTunnel* ipTunnel;
#ifndef win32
struct FileNo_admin* fileno;
#endif
Identity
};

#ifndef win32
static void onFileNoReceived(void* vcontext, enum FileNo_Type type, int fileno)
{
struct Context* ctx = Identity_check((struct Context*) vcontext);
struct Jmp jmp;
Jmp_try(jmp) {
struct Pipe* p = Pipe_forFiles(fileno, fileno, ctx->base, &jmp.handler, ctx->alloc);
p->logger = ctx->logger;
if (type == FileNo_Type_ANDROID) {
struct AndroidWrapper* aw = AndroidWrapper_new(ctx->alloc, ctx->logger);
Iface_plumb(&aw->externalIf, &p->iface);
Iface_plumb(&aw->internalIf, &ctx->nc->tunAdapt->tunIf);
} else {
Iface_plumb(&p->iface, &ctx->nc->tunAdapt->tunIf);
}
} Jmp_catch {
Log_warn(ctx->logger, "Failed to configure fileno [%s]", jmp.message);
}
}
#endif

static void shutdown(void* vcontext)
{
struct Context* context = Identity_check((struct Context*) vcontext);
Expand Down Expand Up @@ -198,6 +227,11 @@ void Core_init(struct Allocator* alloc,
Iface_plumb(&nc->tunAdapt->ipTunnelIf, &ipTunnel->tunInterface);
Iface_plumb(&nc->upper->ipTunnelIf, &ipTunnel->nodeInterface);

#ifndef win32
struct FileNo_admin* fileno = FileNo_admin_new(admin, alloc, eventBase,
logger, eh, onFileNoReceived);
#endif

// The link between the Pathfinder and the core needs to be asynchronous.
struct Pathfinder* pf = Pathfinder_register(alloc, logger, eventBase, rand, admin);
struct ASynchronizer* pfAsync = ASynchronizer_new(alloc, eventBase, logger);
Expand Down Expand Up @@ -230,6 +264,10 @@ void Core_init(struct Allocator* alloc,
ctx->base = eventBase;
ctx->ipTunnel = ipTunnel;
ctx->nc = nc;
#ifndef win32
ctx->fileno = fileno;
ctx->fileno->userData = ctx;
#endif

Admin_registerFunction("Core_exit", adminExit, ctx, true, NULL, admin);

Expand Down
21 changes: 18 additions & 3 deletions client/Configurator.c
Expand Up @@ -263,13 +263,28 @@ static void tunInterface(Dict* ifaceConf, struct Allocator* tempAlloc, struct Co
}

// Setup the interface.
int64_t* tunfd = Dict_getInt(ifaceConf, String_CONST("tunfd"));
String* type = Dict_getString(ifaceConf, String_CONST("tunfdType"));
String* device = Dict_getString(ifaceConf, String_CONST("tunDevice"));

if (tunfd && *tunfd && !device) {
return;
}

Dict* args = Dict_new(tempAlloc);
if (device) {
Dict_putString(args, String_CONST("desiredTunName"), device, tempAlloc);
if (tunfd && *tunfd) {
Dict_putString(args, String_CONST("path"), device, tempAlloc);
if (type) {
Dict_putString(args, String_CONST("type"),
String_new(type->bytes, tempAlloc), tempAlloc);
}
rpcCall0(String_CONST("FileNo_import"), args, ctx, tempAlloc, NULL, false);
} else {
if (device) {
Dict_putString(args, String_CONST("desiredTunName"), device, tempAlloc);
}
rpcCall0(String_CONST("Core_initTunnel"), args, ctx, tempAlloc, NULL, false);
}
rpcCall0(String_CONST("Core_initTunnel"), args, ctx, tempAlloc, NULL, false);
}

static void ipTunnel(Dict* ifaceConf, struct Allocator* tempAlloc, struct Context* ctx)
Expand Down
6 changes: 6 additions & 0 deletions client/cjdroute2.c
Expand Up @@ -260,6 +260,12 @@ static int genconf(struct Random* rand, bool eth)
" {\n"
" // The type of interface (only TUNInterface is supported for now)\n"
" \"type\": \"TUNInterface\"\n"
" // The tun device is a file description or not.\n"
" // \"tunfd\" : 0,\n"
" // If tunfd value is not 0, the tunDevice should be used as the pipe path\n"
" // used to transfer the tun file description.\n"
" // The type of tunfd (only \"android\" is supported for now)\n"
" // \"tunfdType\" : \"\"\n"
#ifndef __APPLE__
"\n"
" // The name of a persistent TUN device to use.\n"
Expand Down
92 changes: 92 additions & 0 deletions interface/tuntap/AndroidWrapper.c
@@ -0,0 +1,92 @@
/* vim: set expandtab ts=4 sw=4: */
/*
* You may redistribute this program and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "interface/Iface.h"
#include "interface/tuntap/AndroidWrapper.h"
#include "util/platform/Sockaddr.h"
#include "memory/Allocator.h"
#include "util/Assert.h"
#include "util/Identity.h"
#include "wire/Ethernet.h"
#include "wire/Headers.h"
#include "wire/Message.h"
#include "wire/Error.h"

/**
* Android VpnService is expect you to read/write packet from the tun device
* file description opened by system process rather than in the cjd process,
* this InterfaceWrapper handle this case.
*/

struct AndroidWrapper_pvt
{
struct AndroidWrapper pub;
struct Log* logger;
Identity
};

static Iface_DEFUN incomingFromWire(struct Message* msg, struct Iface* externalIf)
{
struct AndroidWrapper_pvt* ctx =
Identity_containerOf(externalIf, struct AndroidWrapper_pvt, pub.externalIf);

if (!ctx->pub.internalIf.connectedIf) {
Log_debug(ctx->logger, "DROP message for android tun not inited");
return NULL;
}

int version = Headers_getIpVersion(msg->bytes);
uint16_t ethertype = 0;
if (version == 4) {
ethertype = Ethernet_TYPE_IP4;
} else if (version == 6) {
ethertype = Ethernet_TYPE_IP6;
} else {
Log_debug(ctx->logger, "Message is not IP/IPv6, dropped.");
return NULL;
}

Message_shift(msg, 4, NULL);
((uint16_t*) msg->bytes)[0] = 0;
((uint16_t*) msg->bytes)[1] = ethertype;

return Iface_next(&ctx->pub.internalIf, msg);
}

static Iface_DEFUN incomingFromUs(struct Message* msg, struct Iface* internalIf)
{
struct AndroidWrapper_pvt* ctx =
Identity_containerOf(internalIf, struct AndroidWrapper_pvt, pub.internalIf);

if (!ctx->pub.externalIf.connectedIf) {
Log_debug(ctx->logger, "DROP message for android tun not inited");
return NULL;
}

Message_shift(msg, -4, NULL);

return Iface_next(&ctx->pub.externalIf, msg);
}

struct AndroidWrapper* AndroidWrapper_new(struct Allocator* alloc, struct Log* log)
{
struct AndroidWrapper_pvt* context =
Allocator_calloc(alloc, sizeof(struct AndroidWrapper_pvt), 1);
Identity_set(context);
context->pub.externalIf.send = incomingFromWire;
context->pub.internalIf.send = incomingFromUs;
context->logger = log;

return &context->pub;
}
32 changes: 32 additions & 0 deletions interface/tuntap/AndroidWrapper.h
@@ -0,0 +1,32 @@
/* vim: set expandtab ts=4 sw=4: */
/*
* You may redistribute this program and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef AndroidWrapper_H
#define AndroidWrapper_H

#include "interface/Iface.h"
#include "memory/Allocator.h"
#include "util/log/Log.h"
#include "util/Linker.h"
Linker_require("interface/tuntap/AndroidWrapper.c");

struct AndroidWrapper
{
struct Iface internalIf;
struct Iface externalIf;
};

struct AndroidWrapper* AndroidWrapper_new(struct Allocator* alloc, struct Log* log);

#endif
63 changes: 63 additions & 0 deletions util/events/FileNo.h
@@ -0,0 +1,63 @@
/* vim: set expandtab ts=4 sw=4: */
/*
* You may redistribute this program and/or modify it under the terms of
* the GNU General Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FileNo_H
#define FileNo_H

#include "memory/Allocator.h"
#include "exception/Except.h"
#include "util/events/EventBase.h"
#include "util/Linker.h"
#include "util/log/Log.h"
Linker_require("util/events/libuv/FileNo.c");

struct FileNo;

enum FileNo_Type {
/** Normal tunfd type, no need other wrapper */
FileNo_Type_NORMAL = 0,

/** Android tunfd, need AndroidWrapper */
FileNo_Type_ANDROID
};

typedef void (* FileNo_callback)(void* context, enum FileNo_Type type, int fileno);

struct FileNo
{
/** The name of the file eg: "/tmp/cjdns_fileno_foo" */
const char* const pipePath;

void* userData;

enum FileNo_Type type;

struct EventBase* const base;

FileNo_callback onFileNoReceived;

struct Log* logger;
};

#define FileNo_PADDING_AMOUNT 512
#define FileNo_BUFFER_CAP 4000

struct FileNo* FileNo_new(const char* path,
struct EventBase* eb,
struct Except* eh,
struct Log* logger,
struct Allocator* userAlloc,
FileNo_callback recv_cb);

#endif

0 comments on commit 34ad41c

Please sign in to comment.