Files
shadowsocks-android/jni/obfsproxy/protocols/dummy.c
T

227 lines
5.2 KiB
C

/* Copyright 2011 Nick Mathewson, George Kadianakis
See LICENSE for other credits and copying information
*/
/**
* \file dummy.c
* \headerfile dummy.h
* \brief Implements the 'dummy' pluggable transport. A testing-only
* pluggable transport that leaves traffic intact
**/
#include "util.h"
#define PROTOCOL_DUMMY_PRIVATE
#include "dummy.h"
#include <event2/buffer.h>
/* type-safe downcast wrappers */
static inline dummy_config_t *
downcast_config(config_t *p)
{
return DOWNCAST(dummy_config_t, super, p);
}
static inline dummy_conn_t *
downcast_conn(conn_t *p)
{
return DOWNCAST(dummy_conn_t, super, p);
}
static inline dummy_circuit_t *
downcast_circuit(circuit_t *p)
{
return DOWNCAST(dummy_circuit_t, super, p);
}
/**
Helper: Parses 'options' and fills 'cfg'.
*/
static int
parse_and_set_options(int n_options, const char *const *options,
dummy_config_t *cfg)
{
const char* defport;
if (n_options < 1)
return -1;
if (!strcmp(options[0], "client")) {
defport = "48988"; /* bf5c */
cfg->mode = LSN_SIMPLE_CLIENT;
} else if (!strcmp(options[0], "socks")) {
defport = "23548"; /* 5bf5 */
cfg->mode = LSN_SOCKS_CLIENT;
} else if (!strcmp(options[0], "server")) {
defport = "11253"; /* 2bf5 */
cfg->mode = LSN_SIMPLE_SERVER;
} else
return -1;
if (n_options != (cfg->mode == LSN_SOCKS_CLIENT ? 2 : 3))
return -1;
cfg->listen_addr = resolve_address_port(options[1], 1, 1, defport);
if (!cfg->listen_addr)
return -1;
if (cfg->mode != LSN_SOCKS_CLIENT) {
cfg->target_addr = resolve_address_port(options[2], 1, 0, NULL);
if (!cfg->target_addr)
return -1;
}
return 0;
}
/* Deallocate 'cfg'. */
static void
dummy_config_free(config_t *c)
{
dummy_config_t *cfg = downcast_config(c);
if (cfg->listen_addr)
evutil_freeaddrinfo(cfg->listen_addr);
if (cfg->target_addr)
evutil_freeaddrinfo(cfg->target_addr);
free(cfg);
}
/**
Populate 'cfg' according to 'options', which is an array like this:
{"socks","127.0.0.1:6666"}
*/
static config_t *
dummy_config_create(int n_options, const char *const *options)
{
dummy_config_t *cfg = xzalloc(sizeof(dummy_config_t));
cfg->super.vtable = &dummy_vtable;
if (parse_and_set_options(n_options, options, cfg) == 0)
return &cfg->super;
dummy_config_free(&cfg->super);
log_warn("dummy syntax:\n"
"\tdummy <mode> <listen_address> [<target_address>]\n"
"\t\tmode ~ server|client|socks\n"
"\t\tlisten_address, target_address ~ host:port\n"
"\ttarget_address is required for server and client mode,\n"
"\tand forbidden for socks mode.\n"
"Examples:\n"
"\tobfsproxy dummy socks 127.0.0.1:5000\n"
"\tobfsproxy dummy client 127.0.0.1:5000 192.168.1.99:11253\n"
"\tobfsproxy dummy server 192.168.1.99:11253 127.0.0.1:9005");
return NULL;
}
/**
Return a config_t for a managed proxy listener.
*/
static config_t *
dummy_config_create_managed(int is_server, const char *protocol,
const char *bindaddr, const char *orport)
{
const char* defport;
dummy_config_t *cfg = xzalloc(sizeof(dummy_config_t));
cfg->super.vtable = &dummy_vtable;
if (is_server) {
defport = "11253"; /* 2bf5 */
cfg->mode = LSN_SIMPLE_SERVER;
} else {
defport = "23548"; /* 5bf5 */
cfg->mode = LSN_SOCKS_CLIENT;
}
cfg->listen_addr = resolve_address_port(bindaddr, 1, 1, defport);
if (!cfg->listen_addr)
goto err;
if (is_server) {
cfg->target_addr = resolve_address_port(orport, 1, 0, NULL);
if (!cfg->target_addr)
goto err;
}
return &cfg->super;
err:
dummy_config_free(&cfg->super);
return NULL;
}
/** Retrieve the 'n'th set of listen addresses for this configuration. */
static struct evutil_addrinfo *
dummy_config_get_listen_addrs(config_t *cfg, size_t n)
{
if (n > 0)
return 0;
return downcast_config(cfg)->listen_addr;
}
/* Retrieve the target address for this configuration. */
static struct evutil_addrinfo *
dummy_config_get_target_addr(config_t *cfg)
{
return downcast_config(cfg)->target_addr;
}
/*
This is called everytime we get a connection for the dummy
protocol.
*/
static conn_t *
dummy_conn_create(config_t *cfg)
{
dummy_conn_t *proto = xzalloc(sizeof(dummy_conn_t));
proto->super.cfg = cfg;
proto->super.mode = downcast_config(cfg)->mode;
return &proto->super;
}
static void
dummy_conn_free(conn_t *proto)
{
free(downcast_conn(proto));
}
static circuit_t *
dummy_circuit_create(config_t *cfg)
{
dummy_circuit_t *circuit = xzalloc(sizeof(dummy_circuit_t));
return &circuit->super;
}
static void
dummy_circuit_free(circuit_t *circ)
{
free(downcast_circuit(circ));
}
/** Dummy has no handshake */
static int
dummy_handshake(conn_t *proto, struct evbuffer *buf)
{
return 0;
}
/** send, receive - just copy */
static int
dummy_send(conn_t *proto, struct evbuffer *source, struct evbuffer *dest)
{
return evbuffer_add_buffer(dest,source);
}
static enum recv_ret
dummy_recv(conn_t *proto, struct evbuffer *source, struct evbuffer *dest)
{
if (evbuffer_add_buffer(dest,source)<0)
return RECV_BAD;
else
return RECV_GOOD;
}
DEFINE_PROTOCOL_VTABLE(dummy);