Merge branch 'dnsgw'
This commit is contained in:
Binary file not shown.
@@ -1,8 +1,8 @@
|
||||
global {
|
||||
perm_cache = 2048;
|
||||
cache_dir = "/data/data/com.github.shadowsocks";
|
||||
server_ip = 127.0.0.1;
|
||||
server_port = 8153;
|
||||
server_ip = 0.0.0.0;
|
||||
server_port = 8153;
|
||||
query_method = tcp_only;
|
||||
run_ipv4 = on;
|
||||
min_ttl = 15m;
|
||||
|
||||
Binary file not shown.
@@ -184,7 +184,7 @@ LOCAL_CFLAGS := -std=gnu99
|
||||
LOCAL_CFLAGS += -DBADVPN_THREADWORK_USE_PTHREAD -DBADVPN_LINUX -DBADVPN_BREACTOR_BADVPN -D_GNU_SOURCE
|
||||
LOCAL_CFLAGS += -DBADVPN_USE_SELFPIPE -DBADVPN_USE_EPOLL
|
||||
LOCAL_CFLAGS += -DBADVPN_LITTLE_ENDIAN -DBADVPN_THREAD_SAFE
|
||||
LOCAL_CFLAGS += -DANDROID
|
||||
LOCAL_CFLAGS += -DNDEBUG -DANDROID
|
||||
|
||||
LOCAL_C_INCLUDES:= \
|
||||
$(LOCAL_PATH)/badvpn/lwip/src/include/ipv4 \
|
||||
@@ -255,6 +255,8 @@ TUN2SOCKS_SOURCES := \
|
||||
|
||||
LOCAL_MODULE := tun2socks
|
||||
|
||||
LOCAL_LDLIBS := -ldl -llog
|
||||
|
||||
LOCAL_SRC_FILES := $(addprefix badvpn/, $(TUN2SOCKS_SOURCES))
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
|
||||
#include "BLog.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
#ifndef BADVPN_PLUGIN
|
||||
|
||||
struct _BLog_channel blog_channel_list[] = {
|
||||
@@ -51,12 +55,22 @@ static char *level_names[] = { NULL, "ERROR", "WARNING", "NOTICE", "INFO", "DEBU
|
||||
|
||||
static void stdout_log (int channel, int level, const char *msg)
|
||||
{
|
||||
#ifndef ANDROID
|
||||
fprintf(stdout, "%s(%s): %s\n", level_names[level], blog_global.channels[channel].name, msg);
|
||||
#else
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "tun2socks",
|
||||
"%s(%s): %s\n", level_names[level], blog_global.channels[channel].name, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void stderr_log (int channel, int level, const char *msg)
|
||||
{
|
||||
#ifndef ANDROID
|
||||
fprintf(stderr, "%s(%s): %s\n", level_names[level], blog_global.channels[channel].name, msg);
|
||||
#else
|
||||
__android_log_print(ANDROID_LOG_ERROR, "tun2socks",
|
||||
"%s(%s): %s\n", level_names[level], blog_global.channels[channel].name, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void stdout_stderr_free (void)
|
||||
|
||||
@@ -40,14 +40,6 @@
|
||||
#include <misc/debug.h>
|
||||
#include <base/BMutex.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
|
||||
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "tun2socks", __VA_ARGS__))
|
||||
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "tun2socks", __VA_ARGS__))
|
||||
|
||||
#endif
|
||||
|
||||
// auto-generated channel numbers and number of channels
|
||||
#include <generated/blog_channels_defines.h>
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ struct {
|
||||
int tun_fd;
|
||||
int tun_mtu;
|
||||
char *pid;
|
||||
char *dnsgw;
|
||||
#else
|
||||
char *tundev;
|
||||
#endif
|
||||
@@ -207,6 +208,11 @@ LinkedList1 tcp_clients;
|
||||
// number of clients
|
||||
int num_clients;
|
||||
|
||||
#ifdef ANDROID
|
||||
// Address of dnsgw
|
||||
BAddr dnsgw;
|
||||
#endif
|
||||
|
||||
static void terminate (void);
|
||||
static void print_help (const char *name);
|
||||
static void print_version (void);
|
||||
@@ -218,6 +224,9 @@ static void lwip_init_job_hadler (void *unused);
|
||||
static void tcp_timer_handler (void *unused);
|
||||
static void device_error_handler (void *unused);
|
||||
static void device_read_handler_send (void *unused, uint8_t *data, int data_len);
|
||||
#ifdef ANDROID
|
||||
static int process_device_dns_packet (uint8_t *data, int data_len);
|
||||
#endif
|
||||
static int process_device_udp_packet (uint8_t *data, int data_len);
|
||||
static err_t netif_init_func (struct netif *netif);
|
||||
static err_t netif_output_func (struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr);
|
||||
@@ -563,6 +572,7 @@ void print_help (const char *name)
|
||||
#ifdef ANDROID
|
||||
" [--tunfd <fd>]\n"
|
||||
" [--tunmtu <mtu>]\n"
|
||||
" [--dnsgw <dns_gateway_address>]\n"
|
||||
" [--pid <pid_file>]\n"
|
||||
#else
|
||||
" [--tundev <name>]\n"
|
||||
@@ -725,6 +735,14 @@ int parse_arguments (int argc, char *argv[])
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(arg, "--dnsgw")) {
|
||||
if (1 >= argc - i) {
|
||||
fprintf(stderr, "%s: requires an argument\n", arg);
|
||||
return 0;
|
||||
}
|
||||
options.dnsgw = argv[i + 1];
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(arg, "--pid")) {
|
||||
if (1 >= argc - i) {
|
||||
fprintf(stderr, "%s: requires an argument\n", arg);
|
||||
@@ -878,7 +896,7 @@ int parse_arguments (int argc, char *argv[])
|
||||
int process_arguments (void)
|
||||
{
|
||||
ASSERT(!password_file_contents)
|
||||
|
||||
|
||||
// resolve netif ipaddr
|
||||
if (!BIPAddr_Resolve(&netif_ipaddr, options.netif_ipaddr, 0)) {
|
||||
BLog(BLOG_ERROR, "netif ipaddr: BIPAddr_Resolve failed");
|
||||
@@ -945,6 +963,20 @@ int process_arguments (void)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
// resolve dnsgw addr
|
||||
if (options.dnsgw) {
|
||||
if (!BAddr_Parse2(&dnsgw, options.dnsgw, NULL, 0, 0)) {
|
||||
BLog(BLOG_ERROR, "dnsgw addr: BAddr_Parse2 failed");
|
||||
return 0;
|
||||
}
|
||||
if (dnsgw.type != BADDR_TYPE_IPV4) {
|
||||
BLog(BLOG_ERROR, "dnsgw addr: must be an IPv4 address");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1103,6 +1135,13 @@ void device_read_handler_send (void *unused, uint8_t *data, int data_len)
|
||||
|
||||
// accept packet
|
||||
PacketPassInterface_Done(&device_read_interface);
|
||||
|
||||
#ifdef ANDROID
|
||||
// process DNS directly
|
||||
if (process_device_dns_packet(data, data_len)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// process UDP directly
|
||||
if (process_device_udp_packet(data, data_len)) {
|
||||
@@ -1130,6 +1169,140 @@ void device_read_handler_send (void *unused, uint8_t *data, int data_len)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
int process_device_dns_packet (uint8_t *data, int data_len)
|
||||
{
|
||||
ASSERT(data_len >= 0)
|
||||
|
||||
// do nothing if we don't have dnsgw
|
||||
if (!options.dnsgw) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
static BAddr local_addr;
|
||||
static BAddr remote_addr;
|
||||
static int init = 0;
|
||||
|
||||
int to_dns;
|
||||
int from_dns;
|
||||
int packet_length = 0;
|
||||
|
||||
uint8_t ip_version = 0;
|
||||
if (data_len > 0) {
|
||||
ip_version = (data[0] >> 4);
|
||||
}
|
||||
|
||||
switch (ip_version) {
|
||||
case 4: {
|
||||
// ignore non-UDP packets
|
||||
if (data_len < sizeof(struct ipv4_header) || data[offsetof(struct ipv4_header, protocol)] != IPV4_PROTOCOL_UDP) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// parse IPv4 header
|
||||
struct ipv4_header ipv4_header;
|
||||
if (!ipv4_check(data, data_len, &ipv4_header, &data, &data_len)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// parse UDP
|
||||
struct udp_header udp_header;
|
||||
if (!udp_check(data, data_len, &udp_header, &data, &data_len)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// verify UDP checksum
|
||||
uint16_t checksum_in_packet = udp_header.checksum;
|
||||
udp_header.checksum = 0;
|
||||
uint16_t checksum_computed = udp_checksum(&udp_header, data, data_len, ipv4_header.source_address, ipv4_header.destination_address);
|
||||
if (checksum_in_packet != checksum_computed) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// to port 53 is considered a DNS packet
|
||||
to_dns = udp_header.dest_port == hton16(53);
|
||||
|
||||
// from port 8153 is considered a DNS packet
|
||||
from_dns = udp_header.source_port == dnsgw.ipv4.port;
|
||||
|
||||
// if not DNS packet, just bypass it.
|
||||
if (!to_dns && !from_dns) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// modify DNS packet
|
||||
if (to_dns) {
|
||||
BLog(BLOG_INFO, "UDP: to DNS %d bytes", data_len);
|
||||
|
||||
// construct addresses
|
||||
if (!init) {
|
||||
init = 1;
|
||||
BAddr_InitIPv4(&local_addr, ipv4_header.source_address, udp_header.source_port);
|
||||
BAddr_InitIPv4(&remote_addr, ipv4_header.destination_address, udp_header.dest_port);
|
||||
}
|
||||
|
||||
// build IP header
|
||||
ipv4_header.destination_address = dnsgw.ipv4.ip;
|
||||
ipv4_header.source_address = netif_ipaddr.ipv4;
|
||||
|
||||
// build UDP header
|
||||
udp_header.dest_port = dnsgw.ipv4.port;
|
||||
|
||||
} else if (from_dns) {
|
||||
|
||||
// if not initialized
|
||||
if (!init) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
BLog(BLOG_INFO, "UDP: from DNS %d bytes", data_len);
|
||||
|
||||
// build IP header
|
||||
ipv4_header.source_address = remote_addr.ipv4.ip;
|
||||
ipv4_header.destination_address = local_addr.ipv4.ip;
|
||||
|
||||
// build UDP header
|
||||
udp_header.source_port = remote_addr.ipv4.port;
|
||||
|
||||
}
|
||||
|
||||
// update IPv4 header's checksum
|
||||
ipv4_header.checksum = hton16(0);
|
||||
ipv4_header.checksum = ipv4_checksum(&ipv4_header, NULL, 0);
|
||||
|
||||
// update UDP header's checksum
|
||||
udp_header.checksum = hton16(0);
|
||||
udp_header.checksum = udp_checksum(&udp_header, data, data_len,
|
||||
ipv4_header.source_address, ipv4_header.destination_address);
|
||||
|
||||
// write packet
|
||||
memcpy(device_write_buf, &ipv4_header, sizeof(ipv4_header));
|
||||
memcpy(device_write_buf + sizeof(ipv4_header), &udp_header, sizeof(udp_header));
|
||||
memcpy(device_write_buf + sizeof(ipv4_header) + sizeof(udp_header), data, data_len);
|
||||
packet_length = sizeof(ipv4_header) + sizeof(udp_header) + data_len;
|
||||
|
||||
} break;
|
||||
|
||||
case 6: {
|
||||
// TODO: support IPv6 DNS Gateway
|
||||
goto fail;
|
||||
} break;
|
||||
|
||||
default: {
|
||||
goto fail;
|
||||
} break;
|
||||
}
|
||||
|
||||
// submit packet
|
||||
BTap_Send(&device, device_write_buf, packet_length);
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int process_device_udp_packet (uint8_t *data, int data_len)
|
||||
{
|
||||
ASSERT(data_len >= 0)
|
||||
|
||||
@@ -50,6 +50,7 @@ import android.net.VpnService
|
||||
import org.apache.http.conn.util.InetAddressUtils
|
||||
import android.os.Message
|
||||
import scala.Some
|
||||
import scala.concurrent.ops._
|
||||
|
||||
object ShadowVpnService {
|
||||
def isServiceStarted(context: Context): Boolean = {
|
||||
@@ -74,7 +75,6 @@ class ShadowVpnService extends VpnService {
|
||||
val PRIVATE_VLAN_172 = "172.30.254.%d"
|
||||
|
||||
var conn: ParcelFileDescriptor = null
|
||||
var udpgw: String = null
|
||||
var notificationManager: NotificationManager = null
|
||||
var receiver: BroadcastReceiver = null
|
||||
var apps: Array[ProxiedApp] = null
|
||||
@@ -136,18 +136,20 @@ class ShadowVpnService extends VpnService {
|
||||
}
|
||||
|
||||
def startShadowsocksDaemon() {
|
||||
new Thread {
|
||||
override def run() {
|
||||
val cmd: String = (BASE +
|
||||
"shadowsocks -s \"%s\" -p \"%d\" -l \"%d\" -k \"%s\" -m \"%s\" -f " +
|
||||
BASE +
|
||||
"shadowsocks.pid")
|
||||
.format(config.proxy, config.remotePort, config.localPort, config.sitekey,
|
||||
config.encMethod)
|
||||
Log.d(TAG, cmd)
|
||||
System.exec(cmd)
|
||||
}
|
||||
}.start()
|
||||
spawn {
|
||||
val cmd: String = (BASE +
|
||||
"shadowsocks -s \"%s\" -p \"%d\" -l \"%d\" -k \"%s\" -m \"%s\" -f " +
|
||||
BASE +
|
||||
"shadowsocks.pid")
|
||||
.format(config.proxy, config.remotePort, config.localPort, config.sitekey, config.encMethod)
|
||||
Log.d(TAG, cmd)
|
||||
System.exec(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
def startDnsDaemon() {
|
||||
val cmd: String = BASE + "pdnsd -c " + BASE + "pdnsd.conf"
|
||||
Utils.runCommand(cmd)
|
||||
}
|
||||
|
||||
def getVersionName: String = {
|
||||
@@ -182,43 +184,33 @@ class ShadowVpnService extends VpnService {
|
||||
|
||||
config = Extra.get(intent)
|
||||
|
||||
new Thread(new Runnable {
|
||||
def run() {
|
||||
|
||||
killProcesses()
|
||||
spawn {
|
||||
killProcesses()
|
||||
|
||||
// Resolve server address
|
||||
var resolved: Boolean = false
|
||||
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
|
||||
!InetAddressUtils.isIPv6Address(config.proxy)) {
|
||||
Utils.resolve(config.proxy, enableIPv6 = true) match {
|
||||
case Some(addr) =>
|
||||
config.proxy = addr
|
||||
resolved = true
|
||||
case None => resolved = false
|
||||
}
|
||||
} else {
|
||||
resolved = true
|
||||
// Resolve server address
|
||||
var resolved: Boolean = false
|
||||
if (!InetAddressUtils.isIPv4Address(config.proxy) &&
|
||||
!InetAddressUtils.isIPv6Address(config.proxy)) {
|
||||
Utils.resolve(config.proxy, enableIPv6 = true) match {
|
||||
case Some(addr) =>
|
||||
config.proxy = addr
|
||||
resolved = true
|
||||
case None => resolved = false
|
||||
}
|
||||
|
||||
// Resolve UDP gateway
|
||||
if (resolved) {
|
||||
Utils.resolve("u.maxcdn.info", enableIPv6 = false) match {
|
||||
case Some(host) => udpgw = host
|
||||
case None => resolved = false
|
||||
}
|
||||
}
|
||||
|
||||
if (resolved && handleConnection) {
|
||||
handler.sendEmptyMessageDelayed(MSG_CONNECT_SUCCESS, 300)
|
||||
} else {
|
||||
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
|
||||
handler.sendEmptyMessageDelayed(MSG_CONNECT_FAIL, 300)
|
||||
handler.sendEmptyMessageDelayed(MSG_STOP_SELF, 500)
|
||||
}
|
||||
handler.sendEmptyMessageDelayed(MSG_CONNECT_FINISH, 300)
|
||||
} else {
|
||||
resolved = true
|
||||
}
|
||||
}).start()
|
||||
|
||||
if (resolved && handleConnection) {
|
||||
handler.sendEmptyMessageDelayed(MSG_CONNECT_SUCCESS, 300)
|
||||
} else {
|
||||
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
|
||||
handler.sendEmptyMessageDelayed(MSG_CONNECT_FAIL, 300)
|
||||
handler.sendEmptyMessageDelayed(MSG_STOP_SELF, 500)
|
||||
}
|
||||
handler.sendEmptyMessageDelayed(MSG_CONNECT_FINISH, 300)
|
||||
}
|
||||
}
|
||||
|
||||
def waitForProcess(name: String): Boolean = {
|
||||
@@ -258,7 +250,6 @@ class ShadowVpnService extends VpnService {
|
||||
.setMtu(VPN_MTU)
|
||||
.addAddress(localAddress.format(1), 24)
|
||||
.addDnsServer("8.8.8.8")
|
||||
.addDnsServer("8.8.4.4")
|
||||
|
||||
if (InetAddressUtils.isIPv6Address(config.proxy)) {
|
||||
builder.addRoute("0.0.0.0", 0)
|
||||
@@ -310,19 +301,21 @@ class ShadowVpnService extends VpnService {
|
||||
|
||||
val cmd = (BASE +
|
||||
"tun2socks --netif-ipaddr %s "
|
||||
+ "--udpgw-remote-server-addr %s:7300 "
|
||||
// + "--udpgw-remote-server-addr %s:7300 "
|
||||
+ "--dnsgw %s:8153 "
|
||||
+ "--netif-netmask 255.255.255.0 "
|
||||
+ "--socks-server-addr 127.0.0.1:%d "
|
||||
+ "--tunfd %d "
|
||||
+ "--tunmtu %d "
|
||||
+ "--pid %stun2socks.pid")
|
||||
.format(localAddress.format(2), udpgw, config.localPort, fd, VPN_MTU, BASE)
|
||||
.format(localAddress.format(2), localAddress.format(1), config.localPort, fd, VPN_MTU, BASE)
|
||||
Log.d(TAG, cmd)
|
||||
System.exec(cmd)
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
def handleConnection: Boolean = {
|
||||
startDnsDaemon()
|
||||
startShadowsocksDaemon()
|
||||
startVpn()
|
||||
true
|
||||
@@ -384,11 +377,9 @@ class ShadowVpnService extends VpnService {
|
||||
unregisterReceiver(receiver)
|
||||
receiver = null
|
||||
}
|
||||
new Thread {
|
||||
override def run() {
|
||||
killProcesses()
|
||||
}
|
||||
}.start()
|
||||
spawn {
|
||||
killProcesses()
|
||||
}
|
||||
if (conn != null) {
|
||||
conn.close()
|
||||
conn = null
|
||||
|
||||
Reference in New Issue
Block a user