diff --git a/.gitignore b/.gitignore index 17457ebf..f206a7b5 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ local.sbt out/ #NDK +src/main/obj src/main/libs src/main/assets/armeabi src/main/assets/armeabi-v7a diff --git a/.travis.yml b/.travis.yml index c17a37db..70b978b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,5 +18,6 @@ install: - echo "y" | android update sdk --filter extra-android-m2repository --no-ui --no-https -a script: - cp local.properties.travis local.properties +- ./build.sh - sbt android:package-release - exit 0 diff --git a/README.md b/README.md index c3734691..48e5be89 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,9 @@ Help to translate shadowsocks: http://crowdin.net/project/shadowsocks/invite ```bash git submodule update --init + + # Build native binaries + ./build.sh # Build the App sbt clean android:package-release @@ -47,6 +50,9 @@ Help to translate shadowsocks: http://crowdin.net/project/shadowsocks/invite ```bash git submodule update --init + # Build native binaries + ./build.sh + # Build the apk sbt clean android:package-release ``` diff --git a/build.sh b/build.sh index 14cfaff6..d4bc155b 100755 --- a/build.sh +++ b/build.sh @@ -15,7 +15,7 @@ rm -rf assets/armeabi-v7a rm -rf assets/x86 mkdir -p assets/armeabi-v7a mkdir -p assets/x86 -for app in pdnsd redsocks ss-local ss-tunnel tun2socks +for app in pdnsd redsocks ss-local ss-tunnel do try mv libs/armeabi-v7a/$app assets/armeabi-v7a/ try mv libs/x86/$app assets/x86/ diff --git a/project/plugins.sbt b/project/plugins.sbt index ed5c6c6e..91289c7f 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,4 +2,6 @@ resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifact addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.3.10") -addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.6.0") +resolvers += Resolver.sbtPluginRepo("snapshots") + +addSbtPlugin("com.hanhuy.sbt" % "sbt-idea" % "1.7.0-SNAPSHOT") diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 23950b2d..3bb90fa4 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ + android:versionCode="85" + android:versionName="2.4.5"> @@ -18,7 +18,6 @@ * Contributions: * Transparent DNS: Copyright (C) Kerem Hadimli - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright @@ -13,7 +13,7 @@ * 3. Neither the name of the author nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE @@ -183,8 +183,6 @@ sock_fd_write(int sock, void *buf, ssize_t buflen, int fd) size = sendmsg(sock, &msg, 0); - if (size < 0) - perror ("sendmsg"); return size; } @@ -213,7 +211,6 @@ sock_fd_read(int sock, void *buf, ssize_t bufsize, int *fd) msg.msg_controllen = sizeof(cmsgu.control); size = recvmsg (sock, &msg, 0); if (size < 0) { - perror ("recvmsg"); return -1; } cmsg = CMSG_FIRSTHDR(&msg); @@ -450,7 +447,7 @@ static void daemonize(const char* path) { /* Change the file mode mask */ umask(0); - /* Open any logs here */ + /* Open any logs here */ /* Create a new SID for the child process */ sid = setsid(); @@ -474,10 +471,9 @@ static void daemonize(const char* path) { int recv_tun_fd (void) { - int s_fd, c_fd, fd_to_read; + int s_fd, fd_to_read; struct sockaddr_un addr; socklen_t addr_len; - char buf[16]; s_fd = socket(AF_UNIX, SOCK_STREAM, 0); if (s_fd < 0) { @@ -490,42 +486,25 @@ recv_tun_fd (void) addr_len = sizeof(struct sockaddr_un); memset(&addr, 0, addr_len); addr.sun_family = AF_UNIX; - snprintf(addr.sun_path + 1, 14, "tun2socks"); + addr.sun_path[0] = '\0'; + strcpy(addr.sun_path+1, "tun2socks"); - if (bind(s_fd, (struct sockaddr *) &addr, addr_len) != 0) + if (connect(s_fd, (struct sockaddr *)&addr, addr_len) != -1) { - BLog(BLOG_ERROR, "Error to bind local socket"); - close(s_fd); - return -1; - } + char buf[16]; - BLog(BLOG_NOTICE, "Bind socket"); + BLog(BLOG_NOTICE, "Connected"); - if (listen(s_fd, 5) != 0) - { - BLog(BLOG_ERROR, "Error to listen on local socket"); - close(s_fd); - return -1; - } - - BLog(BLOG_NOTICE, "Listen on socket"); - - if ((c_fd = accept(s_fd, (struct sockaddr *)&addr, &addr_len)) != -1) - { - char buf[1]; - - BLog(BLOG_NOTICE, "Accept a connection"); - - read(c_fd, buf, 1); - sock_fd_read(c_fd, buf, sizeof(buf), &fd_to_read); + read(s_fd, buf, 1); + sock_fd_read(s_fd, buf, sizeof(buf), &fd_to_read); buf[0] = 0; - write(c_fd, buf, 1); - close(c_fd); + write(s_fd, buf, 1); + close(s_fd); } else { - BLog(BLOG_ERROR, "Error to accept socket"); + BLog(BLOG_ERROR, "Error to connect: %s", strerror(errno)); close(s_fd); return -1; } @@ -543,17 +522,17 @@ int main (int argc, char **argv) if (argc <= 0) { return 1; } - + // open standard streams open_standard_streams(); - + // parse command-line arguments if (!parse_arguments(argc, argv)) { fprintf(stderr, "Failed to parse arguments\n"); print_help(argv[0]); goto fail0; } - + // handle --help and --version if (options.help) { print_version(); @@ -581,7 +560,7 @@ int main (int argc, char **argv) default: ASSERT(0); } - + // configure logger channels for (int i = 0; i < BLOG_NUM_CHANNELS; i++) { if (options.loglevels[i] >= 0) { @@ -598,52 +577,41 @@ int main (int argc, char **argv) if (options.pid) { daemonize(options.pid); } - - BLog(BLOG_NOTICE, "Receiving the tun fd"); - - // Wait to recevie tun fd - if (recv_tun_fd() == -1) { - BLog(BLOG_ERROR, "Failed to recv tun fd"); - return -1; - } - - BLog(BLOG_NOTICE, "Received the tun fd successfully"); - #endif - + // clear password contents pointer password_file_contents = NULL; - + // initialize network if (!BNetwork_GlobalInit()) { BLog(BLOG_ERROR, "BNetwork_GlobalInit failed"); goto fail1; } - + // process arguments if (!process_arguments()) { BLog(BLOG_ERROR, "Failed to process arguments"); goto fail1; } - + // init time BTime_Init(); - + // init reactor if (!BReactor_Init(&ss)) { BLog(BLOG_ERROR, "BReactor_Init failed"); goto fail1; } - + // set not quitting quitting = 0; - + // setup signal handler if (!BSignal_Init(&ss, signal_handler, NULL)) { BLog(BLOG_ERROR, "BSignal_Init failed"); goto fail2; } - + #ifdef ANDROID // use supplied file descriptor @@ -652,7 +620,7 @@ int main (int argc, char **argv) init_data.init_type = BTAP_INIT_FD; init_data.init.fd.fd = options.tun_fd; init_data.init.fd.mtu = options.tun_mtu; - + if (!BTap_Init2(&device, &ss, init_data, device_error_handler, NULL)) { BLog(BLOG_ERROR, "BTap_Init2 failed"); goto fail3; @@ -664,19 +632,19 @@ int main (int argc, char **argv) goto fail3; } #endif - + // NOTE: the order of the following is important: // first device writing must evaluate, // then lwip (so it can send packets to the device), // then device reading (so it can pass received packets to lwip). - + // init device reading PacketPassInterface_Init(&device_read_interface, BTap_GetMTU(&device), device_read_handler_send, NULL, BReactor_PendingGroup(&ss)); if (!SinglePacketBuffer_Init(&device_read_buffer, BTap_GetOutput(&device), &device_read_interface, BReactor_PendingGroup(&ss))) { BLog(BLOG_ERROR, "SinglePacketBuffer_Init failed"); goto fail4; } - + if (options.udpgw_remote_server_addr) { // compute maximum UDP payload size we need to pass through udpgw udp_mtu = BTap_GetMTU(&device) - (int)(sizeof(struct ipv4_header) + sizeof(struct udp_header)); @@ -689,14 +657,14 @@ int main (int argc, char **argv) if (udp_mtu < 0) { udp_mtu = 0; } - + // make sure our UDP payloads aren't too large for udpgw int udpgw_mtu = udpgw_compute_mtu(udp_mtu); if (udpgw_mtu < 0 || udpgw_mtu > PACKETPROTO_MAXPAYLOAD) { BLog(BLOG_ERROR, "device MTU is too large for UDP"); goto fail4a; } - + // init udpgw client if (!SocksUdpGwClient_Init(&udpgw_client, udp_mtu, DEFAULT_UDPGW_MAX_CONNECTIONS, options.udpgw_connection_buffer_size, UDPGW_KEEPALIVE_TIME, socks_server_addr, socks_auth_info, socks_num_auth_info, @@ -706,46 +674,46 @@ int main (int argc, char **argv) goto fail4a; } } - + // init lwip init job BPending_Init(&lwip_init_job, BReactor_PendingGroup(&ss), lwip_init_job_hadler, NULL); BPending_Set(&lwip_init_job); - + // init device write buffer if (!(device_write_buf = (uint8_t *)BAlloc(BTap_GetMTU(&device)))) { BLog(BLOG_ERROR, "BAlloc failed"); goto fail5; } - + // init TCP timer // it won't trigger before lwip is initialized, becuase the lwip init is a job BTimer_Init(&tcp_timer, TCP_TMR_INTERVAL, tcp_timer_handler, NULL); BReactor_SetTimer(&ss, &tcp_timer); - + // set no netif have_netif = 0; - + // set no listener listener = NULL; listener_ip6 = NULL; - + // init clients list LinkedList1_Init(&tcp_clients); - + // init number of clients num_clients = 0; // enter event loop BLog(BLOG_NOTICE, "entering event loop"); BReactor_Exec(&ss); - + // free clients LinkedList1Node *node; while (node = LinkedList1_GetFirst(&tcp_clients)) { struct tcp_client *client = UPPER_OBJECT(node, struct tcp_client, list_node); client_murder(client); } - + // free listener if (listener_ip6) { tcp_close(listener_ip6); @@ -753,22 +721,23 @@ int main (int argc, char **argv) if (listener) { tcp_close(listener); } - + // free netif if (have_netif) { netif_remove(&netif); } - - BReactor_RemoveTimer(&ss, &tcp_timer); - BFree(device_write_buf); #ifdef ANDROID + BLog(BLOG_NOTICE, "Free TCP connections"); tcp_remove(tcp_bound_pcbs); tcp_remove(tcp_active_pcbs); tcp_remove(tcp_tw_pcbs); free_connections(); #endif + BReactor_RemoveTimer(&ss, &tcp_timer); + BFree(device_write_buf); + fail5: BPending_Free(&lwip_init_job); if (options.udpgw_remote_server_addr) { @@ -789,19 +758,19 @@ fail1: BLog_Free(); fail0: DebugObjectGlobal_Finish(); - + return 1; } void terminate (void) { ASSERT(!quitting) - + BLog(BLOG_NOTICE, "tearing down"); - + // set quitting quitting = 1; - + // exit event loop BReactor_Quit(&ss, 1); } @@ -862,7 +831,7 @@ int parse_arguments (int argc, char *argv[]) if (argc <= 0) { return 0; } - + options.help = 0; options.version = 0; options.logger = LOGGER_STDOUT; @@ -893,7 +862,7 @@ int parse_arguments (int argc, char *argv[]) options.udpgw_max_connections = DEFAULT_UDPGW_MAX_CONNECTIONS; options.udpgw_connection_buffer_size = DEFAULT_UDPGW_CONNECTION_BUFFER_SIZE; options.udpgw_transparent_dns = 0; - + int i; for (i = 1; i < argc; i++) { char *arg = argv[i]; @@ -1078,7 +1047,7 @@ int parse_arguments (int argc, char *argv[]) else if (!strcmp(arg, "--append-source-to-username")) { options.append_source_to_username = 1; } -#ifdef ANDROID +#ifdef ANDROID else if (!strcmp(arg, "--enable-udprelay")) { options.udpgw_remote_server_addr = "0.0.0.0:0"; #else @@ -1127,38 +1096,38 @@ int parse_arguments (int argc, char *argv[]) return 0; } } - + if (options.help || options.version) { return 1; } - + if (!options.netif_ipaddr) { fprintf(stderr, "--netif-ipaddr is required\n"); return 0; } - + if (!options.netif_netmask) { fprintf(stderr, "--netif-netmask is required\n"); return 0; } - + if (!options.socks_server_addr) { fprintf(stderr, "--socks-server-addr is required\n"); return 0; } - + if (options.username) { if (!options.password && !options.password_file) { fprintf(stderr, "username given but password not given\n"); return 0; } - + if (options.password && options.password_file) { fprintf(stderr, "--password and --password-file cannot both be given\n"); return 0; } } - + return 1; } @@ -1175,7 +1144,7 @@ int process_arguments (void) BLog(BLOG_ERROR, "netif ipaddr: must be an IPv4 address"); return 0; } - + // resolve netif netmask if (!BIPAddr_Resolve(&netif_netmask, options.netif_netmask, 0)) { BLog(BLOG_ERROR, "netif netmask: BIPAddr_Resolve failed"); @@ -1185,7 +1154,7 @@ int process_arguments (void) BLog(BLOG_ERROR, "netif netmask: must be an IPv4 address"); return 0; } - + // parse IP6 address if (options.netif_ip6addr) { if (!ipaddr6_parse_ipv6_addr(options.netif_ip6addr, &netif_ip6addr)) { @@ -1193,17 +1162,17 @@ int process_arguments (void) return 0; } } - + // resolve SOCKS server address if (!BAddr_Parse2(&socks_server_addr, options.socks_server_addr, NULL, 0, 0)) { BLog(BLOG_ERROR, "socks server addr: BAddr_Parse2 failed"); return 0; } - + // add none socks authentication method socks_auth_info[0] = BSocksClient_auth_none(); socks_num_auth_info = 1; - + // add password socks authentication method if (options.username) { const char *password; @@ -1218,13 +1187,13 @@ int process_arguments (void) } password = (char *)password_file_contents; } - + socks_auth_info[socks_num_auth_info++] = BSocksClient_auth_password( options.username, strlen(options.username), password, password_len ); } - + // resolve remote udpgw server address if (options.udpgw_remote_server_addr) { if (!BAddr_Parse2(&udpgw_remote_server_addr, options.udpgw_remote_server_addr, NULL, 0, 0)) { @@ -1250,16 +1219,16 @@ int process_arguments (void) } } #endif - + return 1; } void signal_handler (void *unused) { ASSERT(!quitting) - + BLog(BLOG_NOTICE, "termination requested"); - + terminate(); } @@ -1282,15 +1251,15 @@ void lwip_init_job_hadler (void *unused) ASSERT(!have_netif) ASSERT(!listener) ASSERT(!listener_ip6) - + BLog(BLOG_DEBUG, "lwip init"); - + // NOTE: the device may fail during this, but there's no harm in not checking // for that at every step - + // init lwip lwip_init(); - + // make addresses for netif ip_addr_t addr; addr.addr = netif_ipaddr.ipv4; @@ -1298,77 +1267,77 @@ void lwip_init_job_hadler (void *unused) netmask.addr = netif_netmask.ipv4; ip_addr_t gw; ip_addr_set_any(&gw); - + // init netif if (!netif_add(&netif, &addr, &netmask, &gw, NULL, netif_init_func, netif_input_func)) { BLog(BLOG_ERROR, "netif_add failed"); goto fail; } have_netif = 1; - + // set netif up netif_set_up(&netif); - + // set netif pretend TCP netif_set_pretend_tcp(&netif, 1); - + // set netif default netif_set_default(&netif); - + if (options.netif_ip6addr) { // add IPv6 address memcpy(netif_ip6_addr(&netif, 0), netif_ip6addr.bytes, sizeof(netif_ip6addr.bytes)); netif_ip6_addr_set_state(&netif, 0, IP6_ADDR_VALID); } - + // init listener struct tcp_pcb *l = tcp_new(); if (!l) { BLog(BLOG_ERROR, "tcp_new failed"); goto fail; } - + // bind listener if (tcp_bind_to_netif(l, "ho0") != ERR_OK) { BLog(BLOG_ERROR, "tcp_bind_to_netif failed"); tcp_close(l); goto fail; } - + // listen listener if (!(listener = tcp_listen(l))) { BLog(BLOG_ERROR, "tcp_listen failed"); tcp_close(l); goto fail; } - + // setup listener accept handler tcp_accept(listener, listener_accept_func); - + if (options.netif_ip6addr) { struct tcp_pcb *l_ip6 = tcp_new_ip6(); if (!l_ip6) { BLog(BLOG_ERROR, "tcp_new_ip6 failed"); goto fail; } - + if (tcp_bind_to_netif(l_ip6, "ho0") != ERR_OK) { BLog(BLOG_ERROR, "tcp_bind_to_netif failed"); tcp_close(l_ip6); goto fail; } - + if (!(listener_ip6 = tcp_listen(l_ip6))) { BLog(BLOG_ERROR, "tcp_listen failed"); tcp_close(l_ip6); goto fail; } - + tcp_accept(listener_ip6, listener_accept_func); } - + return; - + fail: if (!quitting) { terminate(); @@ -1378,13 +1347,13 @@ fail: void tcp_timer_handler (void *unused) { ASSERT(!quitting) - + BLog(BLOG_DEBUG, "TCP timer"); - + // schedule next timer // TODO: calculate timeout so we don't drift BReactor_SetTimer(&ss, &tcp_timer); - + tcp_tmr(); return; } @@ -1392,9 +1361,9 @@ void tcp_timer_handler (void *unused) void device_error_handler (void *unused) { ASSERT(!quitting) - + BLog(BLOG_ERROR, "device error"); - + terminate(); return; } @@ -1403,9 +1372,9 @@ void device_read_handler_send (void *unused, uint8_t *data, int data_len) { ASSERT(!quitting) ASSERT(data_len >= 0) - + BLog(BLOG_DEBUG, "device: received packet"); - + // accept packet PacketPassInterface_Done(&device_read_interface); @@ -1415,12 +1384,12 @@ void device_read_handler_send (void *unused, uint8_t *data, int data_len) return; } #endif - + // process UDP directly if (process_device_udp_packet(data, data_len)) { return; } - + // obtain pbuf if (data_len > UINT16_MAX) { BLog(BLOG_WARNING, "device read: packet too large"); @@ -1431,10 +1400,10 @@ void device_read_handler_send (void *unused, uint8_t *data, int data_len) BLog(BLOG_WARNING, "device read: pbuf_alloc failed"); return; } - + // write packet to pbuf ASSERT_FORCE(pbuf_take(p, data, data_len) == ERR_OK) - + // pass pbuf to input if (netif.input(p, &netif) != ERR_OK) { BLog(BLOG_WARNING, "device read: input failed"); @@ -1446,42 +1415,42 @@ void device_read_handler_send (void *unused, uint8_t *data, int data_len) 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 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; @@ -1550,7 +1519,7 @@ int process_device_dns_packet (uint8_t *data, int data_len) goto fail; } } - + // update IPv4 header's checksum ipv4_header.checksum = hton16(0); ipv4_header.checksum = ipv4_checksum(&ipv4_header, NULL, 0); @@ -1567,22 +1536,22 @@ int process_device_dns_packet (uint8_t *data, int 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; } @@ -1591,40 +1560,40 @@ fail: int process_device_udp_packet (uint8_t *data, int data_len) { ASSERT(data_len >= 0) - + // do nothing if we don't have udpgw if (!options.udpgw_remote_server_addr) { goto fail; } - + BAddr local_addr; BAddr remote_addr; int is_dns; - + 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; @@ -1632,43 +1601,43 @@ int process_device_udp_packet (uint8_t *data, int data_len) if (checksum_in_packet != checksum_computed) { goto fail; } - + BLog(BLOG_INFO, "UDP: from device %d bytes", data_len); - + // construct addresses BAddr_InitIPv4(&local_addr, ipv4_header.source_address, udp_header.source_port); BAddr_InitIPv4(&remote_addr, ipv4_header.destination_address, udp_header.dest_port); - + // if transparent DNS is enabled, any packet arriving at out netif // address to port 53 is considered a DNS packet is_dns = (options.udpgw_transparent_dns && ipv4_header.destination_address == netif_ipaddr.ipv4 && udp_header.dest_port == hton16(53)); } break; - + case 6: { // ignore if IPv6 support is disabled if (!options.netif_ip6addr) { goto fail; } - + // ignore non-UDP packets if (data_len < sizeof(struct ipv6_header) || data[offsetof(struct ipv6_header, next_header)] != IPV6_NEXT_UDP) { goto fail; } - + // parse IPv6 header struct ipv6_header ipv6_header; if (!ipv6_check(data, data_len, &ipv6_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; @@ -1676,33 +1645,33 @@ int process_device_udp_packet (uint8_t *data, int data_len) if (checksum_in_packet != checksum_computed) { goto fail; } - + BLog(BLOG_INFO, "UDP/IPv6: from device %d bytes", data_len); - + // construct addresses BAddr_InitIPv6(&local_addr, ipv6_header.source_address, udp_header.source_port); BAddr_InitIPv6(&remote_addr, ipv6_header.destination_address, udp_header.dest_port); - + // TODO dns is_dns = 0; } break; - + default: { goto fail; } break; } - + // check payload length if (data_len > udp_mtu) { BLog(BLOG_ERROR, "packet is too large, cannot send to udpgw"); goto fail; } - + // submit packet to udpgw SocksUdpGwClient_SubmitPacket(&udpgw_client, local_addr, remote_addr, is_dns, data, data_len); - + return 1; - + fail: return 0; } @@ -1710,12 +1679,12 @@ fail: err_t netif_init_func (struct netif *netif) { BLog(BLOG_DEBUG, "netif func init"); - + netif->name[0] = 'h'; netif->name[1] = 'o'; netif->output = netif_output_func; netif->output_ip6 = netif_output_ip6_func; - + return ERR_OK; } @@ -1732,20 +1701,20 @@ err_t netif_output_ip6_func (struct netif *netif, struct pbuf *p, ip6_addr_t *ip err_t common_netif_output (struct netif *netif, struct pbuf *p) { SYNC_DECL - + BLog(BLOG_DEBUG, "device write: send packet"); - + if (quitting) { return ERR_OK; } - + // if there is just one chunk, send it directly, else via buffer if (!p->next) { if (p->len > BTap_GetMTU(&device)) { BLog(BLOG_WARNING, "netif func output: no space left"); goto out; } - + SYNC_FROMHERE BTap_Send(&device, (uint8_t *)p->payload, p->len); SYNC_COMMIT @@ -1759,12 +1728,12 @@ err_t common_netif_output (struct netif *netif, struct pbuf *p) memcpy(device_write_buf + len, p->payload, p->len); len += p->len; } while (p = p->next); - + SYNC_FROMHERE BTap_Send(&device, device_write_buf, len); SYNC_COMMIT } - + out: return ERR_OK; } @@ -1775,7 +1744,7 @@ err_t netif_input_func (struct pbuf *p, struct netif *inp) if (p->len > 0) { ip_version = (((uint8_t *)p->payload)[0] >> 4); } - + switch (ip_version) { case 4: { return ip_input(p, inp); @@ -1786,7 +1755,7 @@ err_t netif_input_func (struct pbuf *p, struct netif *inp) } } break; } - + pbuf_free(p); return ERR_OK; } @@ -1797,7 +1766,7 @@ void client_logfunc (struct tcp_client *client) BAddr_Print(&client->local_addr, local_addr_s); char remote_addr_s[BADDR_MAX_PRINT_LEN]; BAddr_Print(&client->remote_addr, remote_addr_s); - + BLog_Append("%05d (%s %s): ", num_clients, local_addr_s, remote_addr_s); } @@ -1812,11 +1781,11 @@ void client_log (struct tcp_client *client, int level, const char *fmt, ...) err_t listener_accept_func (void *arg, struct tcp_pcb *newpcb, err_t err) { ASSERT(err == ERR_OK) - + // signal accepted struct tcp_pcb *this_listener = (PCB_ISIPV6(newpcb) ? listener_ip6 : listener); tcp_accepted(this_listener); - + // allocate client structure struct tcp_client *client = (struct tcp_client *)malloc(sizeof(*client)); if (!client) { @@ -1824,20 +1793,20 @@ err_t listener_accept_func (void *arg, struct tcp_pcb *newpcb, err_t err) goto fail0; } client->socks_username = NULL; - + SYNC_DECL SYNC_FROMHERE - + // read addresses client->local_addr = baddr_from_lwip(PCB_ISIPV6(newpcb), &newpcb->local_ip, newpcb->local_port); client->remote_addr = baddr_from_lwip(PCB_ISIPV6(newpcb), &newpcb->remote_ip, newpcb->remote_port); - + // get destination address BAddr addr = client->local_addr; #ifdef OVERRIDE_DEST_ADDR ASSERT_FORCE(BAddr_Parse2(&addr, OVERRIDE_DEST_ADDR, NULL, 0, 1)) #endif - + // add source address to username if requested if (options.username && options.append_source_to_username) { char addr_str[BADDR_MAX_PRINT_LEN]; @@ -1849,56 +1818,56 @@ err_t listener_accept_func (void *arg, struct tcp_pcb *newpcb, err_t err) socks_auth_info[1].password.username = client->socks_username; socks_auth_info[1].password.username_len = strlen(client->socks_username); } - + // init SOCKS if (!BSocksClient_Init(&client->socks_client, socks_server_addr, socks_auth_info, socks_num_auth_info, addr, (BSocksClient_handler)client_socks_handler, client, &ss)) { BLog(BLOG_ERROR, "listener accept: BSocksClient_Init failed"); goto fail1; } - + // init dead vars DEAD_INIT(client->dead); DEAD_INIT(client->dead_client); - + // add to linked list LinkedList1_Append(&tcp_clients, &client->list_node); - + // increment counter ASSERT(num_clients >= 0) num_clients++; - + // set pcb client->pcb = newpcb; - + // set client not closed client->client_closed = 0; - + // setup handler argument tcp_arg(client->pcb, client); - + // setup handlers tcp_err(client->pcb, client_err_func); tcp_recv(client->pcb, client_recv_func); - + // setup buffer client->buf_used = 0; - + // set SOCKS not up, not closed client->socks_up = 0; client->socks_closed = 0; - + client_log(client, BLOG_INFO, "accepted"); - + DEAD_ENTER(client->dead_client) SYNC_COMMIT DEAD_LEAVE2(client->dead_client) if (DEAD_KILLED) { return ERR_ABRT; } - + return ERR_OK; - + fail1: SYNC_BREAK free(client->socks_username); @@ -1910,15 +1879,15 @@ fail0: void client_handle_freed_client (struct tcp_client *client) { ASSERT(!client->client_closed) - + // pcb was taken care of by the caller - + // kill client dead var DEAD_KILL(client->dead_client); - + // set client closed client->client_closed = 1; - + // if we have data to be sent to SOCKS and can send it, keep sending if (client->buf_used > 0 && !client->socks_closed) { client_log(client, BLOG_INFO, "waiting untill buffered data is sent to SOCKS"); @@ -1934,41 +1903,41 @@ void client_handle_freed_client (struct tcp_client *client) void client_free_client (struct tcp_client *client) { ASSERT(!client->client_closed) - + // remove callbacks tcp_err(client->pcb, NULL); tcp_recv(client->pcb, NULL); tcp_sent(client->pcb, NULL); - + // free pcb err_t err = tcp_close(client->pcb); if (err != ERR_OK) { client_log(client, BLOG_ERROR, "tcp_close failed (%d)", err); tcp_abort(client->pcb); } - + client_handle_freed_client(client); } void client_abort_client (struct tcp_client *client) { ASSERT(!client->client_closed) - + // remove callbacks tcp_err(client->pcb, NULL); tcp_recv(client->pcb, NULL); tcp_sent(client->pcb, NULL); - + // free pcb tcp_abort(client->pcb); - + client_handle_freed_client(client); } void client_free_socks (struct tcp_client *client) { ASSERT(!client->socks_closed) - + // stop sending to SOCKS if (client->socks_up) { // stop receiving from client @@ -1976,13 +1945,13 @@ void client_free_socks (struct tcp_client *client) tcp_recv(client->pcb, NULL); } } - + // free SOCKS BSocksClient_Free(&client->socks_client); - + // set SOCKS closed client->socks_closed = 1; - + // if we have data to be sent to the client and we can send it, keep sending if (client->socks_up && (client->socks_recv_buf_used >= 0 || client->socks_recv_tcp_pending > 0) && !client->client_closed) { client_log(client, BLOG_INFO, "waiting until buffered data is sent to client"); @@ -2003,26 +1972,26 @@ void client_murder (struct tcp_client *client) tcp_err(client->pcb, NULL); tcp_recv(client->pcb, NULL); tcp_sent(client->pcb, NULL); - + // abort tcp_abort(client->pcb); - + // kill client dead var DEAD_KILL(client->dead_client); - + // set client closed client->client_closed = 1; } - + // free SOCKS if (!client->socks_closed) { // free SOCKS BSocksClient_Free(&client->socks_client); - + // set SOCKS closed client->socks_closed = 1; } - + // dealloc entry client_dealloc(client); } @@ -2031,17 +2000,17 @@ void client_dealloc (struct tcp_client *client) { ASSERT(client->client_closed) ASSERT(client->socks_closed) - + // decrement counter ASSERT(num_clients > 0) num_clients--; - + // remove client entry LinkedList1_Remove(&tcp_clients, &client->list_node); - + // kill dead var DEAD_KILL(client->dead); - + // free memory free(client->socks_username); free(client); @@ -2051,9 +2020,9 @@ void client_err_func (void *arg, err_t err) { struct tcp_client *client = (struct tcp_client *)arg; ASSERT(!client->client_closed) - + client_log(client, BLOG_INFO, "client error (%d)", (int)err); - + // the pcb was taken care of by the caller client_handle_freed_client(client); } @@ -2064,29 +2033,29 @@ err_t client_recv_func (void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t e ASSERT(!client->client_closed) ASSERT(err == ERR_OK) // checked in lwIP source. Otherwise, I've no idea what should // be done with the pbuf in case of an error. - + if (!p) { client_log(client, BLOG_INFO, "client closed"); client_free_client(client); return ERR_ABRT; } - + ASSERT(p->tot_len > 0) - + // check if we have enough buffer if (p->tot_len > sizeof(client->buf) - client->buf_used) { client_log(client, BLOG_ERROR, "no buffer for data !?!"); return ERR_MEM; } - + // copy data to buffer ASSERT_EXECUTE(pbuf_copy_partial(p, client->buf + client->buf_used, p->tot_len, 0) == p->tot_len) client->buf_used += p->tot_len; - + // if there was nothing in the buffer before, and SOCKS is up, start send data if (client->buf_used == p->tot_len && client->socks_up) { ASSERT(!client->socks_closed) // this callback is removed when SOCKS is closed - + SYNC_DECL SYNC_FROMHERE client_send_to_socks(client); @@ -2097,33 +2066,33 @@ err_t client_recv_func (void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t e return ERR_ABRT; } } - + // free pbuff pbuf_free(p); - + return ERR_OK; } void client_socks_handler (struct tcp_client *client, int event) { ASSERT(!client->socks_closed) - + switch (event) { case BSOCKSCLIENT_EVENT_ERROR: { client_log(client, BLOG_INFO, "SOCKS error"); - + client_free_socks(client); } break; - + case BSOCKSCLIENT_EVENT_UP: { ASSERT(!client->socks_up) - + client_log(client, BLOG_INFO, "SOCKS up"); - + // init sending client->socks_send_if = BSocksClient_GetSendInterface(&client->socks_client); StreamPassInterface_Sender_Init(client->socks_send_if, (StreamPassInterface_handler_done)client_socks_send_handler_done, client); - + // init receiving client->socks_recv_if = BSocksClient_GetRecvInterface(&client->socks_client); StreamRecvInterface_Receiver_Init(client->socks_recv_if, (StreamRecvInterface_handler_done)client_socks_recv_handler_done, client); @@ -2132,29 +2101,29 @@ void client_socks_handler (struct tcp_client *client, int event) if (!client->client_closed) { tcp_sent(client->pcb, client_sent_func); } - + // set up client->socks_up = 1; - + // start sending data if there is any if (client->buf_used > 0) { client_send_to_socks(client); } - + // start receiving data if client is still up if (!client->client_closed) { client_socks_recv_initiate(client); } } break; - + case BSOCKSCLIENT_EVENT_ERROR_CLOSED: { ASSERT(client->socks_up) - + client_log(client, BLOG_INFO, "SOCKS closed"); - + client_free_socks(client); } break; - + default: ASSERT(0); } @@ -2165,7 +2134,7 @@ void client_send_to_socks (struct tcp_client *client) ASSERT(!client->socks_closed) ASSERT(client->socks_up) ASSERT(client->buf_used > 0) - + // schedule sending StreamPassInterface_Sender_Send(client->socks_send_if, client->buf, client->buf_used); } @@ -2177,16 +2146,16 @@ void client_socks_send_handler_done (struct tcp_client *client, int data_len) ASSERT(client->buf_used > 0) ASSERT(data_len > 0) ASSERT(data_len <= client->buf_used) - + // remove sent data from buffer memmove(client->buf, client->buf + data_len, client->buf_used - data_len); client->buf_used -= data_len; - + if (!client->client_closed) { // confirm sent data tcp_recved(client->pcb, data_len); } - + if (client->buf_used > 0) { // send any further data StreamPassInterface_Sender_Send(client->socks_send_if, client->buf, client->buf_used); @@ -2194,7 +2163,7 @@ void client_socks_send_handler_done (struct tcp_client *client, int data_len) else if (client->client_closed) { // client was closed we've sent everything we had buffered; we're done with it client_log(client, BLOG_INFO, "removing after client went down"); - + client_free_socks(client); } } @@ -2205,7 +2174,7 @@ void client_socks_recv_initiate (struct tcp_client *client) ASSERT(!client->socks_closed) ASSERT(client->socks_up) ASSERT(client->socks_recv_buf_used == -1) - + StreamRecvInterface_Receiver_Recv(client->socks_recv_if, client->socks_recv_buf, sizeof(client->socks_recv_buf)); } @@ -2216,22 +2185,22 @@ void client_socks_recv_handler_done (struct tcp_client *client, int data_len) ASSERT(!client->socks_closed) ASSERT(client->socks_up) ASSERT(client->socks_recv_buf_used == -1) - + // if client was closed, stop receiving if (client->client_closed) { return; } - + // set amount of data in buffer client->socks_recv_buf_used = data_len; client->socks_recv_buf_sent = 0; client->socks_recv_waiting = 0; - + // send to client if (client_socks_recv_send_out(client) < 0) { return; } - + // continue receiving if needed if (client->socks_recv_buf_used == -1) { client_socks_recv_initiate(client); @@ -2245,89 +2214,89 @@ int client_socks_recv_send_out (struct tcp_client *client) ASSERT(client->socks_recv_buf_used > 0) ASSERT(client->socks_recv_buf_sent < client->socks_recv_buf_used) ASSERT(!client->socks_recv_waiting) - + // return value -1 means tcp_abort() was done, // 0 means it wasn't and the client (pcb) is still up - + do { int to_write = bmin_int(client->socks_recv_buf_used - client->socks_recv_buf_sent, tcp_sndbuf(client->pcb)); if (to_write == 0) { break; } - + err_t err = tcp_write(client->pcb, client->socks_recv_buf + client->socks_recv_buf_sent, to_write, TCP_WRITE_FLAG_COPY); if (err != ERR_OK) { if (err == ERR_MEM) { break; } - + client_log(client, BLOG_INFO, "tcp_write failed (%d)", (int)err); - + client_abort_client(client); return -1; } - + client->socks_recv_buf_sent += to_write; client->socks_recv_tcp_pending += to_write; } while (client->socks_recv_buf_sent < client->socks_recv_buf_used); - + // start sending now err_t err = tcp_output(client->pcb); if (err != ERR_OK) { client_log(client, BLOG_INFO, "tcp_output failed (%d)", (int)err); - + client_abort_client(client); return -1; } - + // more data to queue? if (client->socks_recv_buf_sent < client->socks_recv_buf_used) { if (client->socks_recv_tcp_pending == 0) { client_log(client, BLOG_ERROR, "can't queue data, but all data was confirmed !?!"); - + client_abort_client(client); return -1; } - + // set waiting, continue in client_sent_func client->socks_recv_waiting = 1; return 0; } - + // everything was queued client->socks_recv_buf_used = -1; - + return 0; } err_t client_sent_func (void *arg, struct tcp_pcb *tpcb, u16_t len) { struct tcp_client *client = (struct tcp_client *)arg; - + ASSERT(!client->client_closed) ASSERT(client->socks_up) ASSERT(len > 0) ASSERT(len <= client->socks_recv_tcp_pending) - + // decrement pending client->socks_recv_tcp_pending -= len; - + // continue queuing if (client->socks_recv_buf_used > 0) { ASSERT(client->socks_recv_waiting) ASSERT(client->socks_recv_buf_sent < client->socks_recv_buf_used) - + // set not waiting client->socks_recv_waiting = 0; - + // possibly send more data if (client_socks_recv_send_out(client) < 0) { return ERR_ABRT; } - + // we just queued some data, so it can't have been confirmed yet ASSERT(client->socks_recv_tcp_pending > 0) - + // continue receiving if needed if (client->socks_recv_buf_used == -1 && !client->socks_closed) { SYNC_DECL @@ -2340,17 +2309,17 @@ err_t client_sent_func (void *arg, struct tcp_pcb *tpcb, u16_t len) return ERR_ABRT; } } - + return ERR_OK; } - + // have we sent everything after SOCKS was closed? if (client->socks_closed && client->socks_recv_tcp_pending == 0) { client_log(client, BLOG_INFO, "removing after SOCKS went down"); client_free_client(client); return ERR_ABRT; } - + return ERR_OK; } @@ -2360,9 +2329,9 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote ASSERT(local_addr.type == BADDR_TYPE_IPV4 || local_addr.type == BADDR_TYPE_IPV6) ASSERT(local_addr.type == remote_addr.type) ASSERT(data_len >= 0) - + int packet_length = 0; - + switch (local_addr.type) { case BADDR_TYPE_IPV4: { #ifdef ANDROID @@ -2370,14 +2339,14 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote #else BLog(BLOG_INFO, "UDP: from udpgw %d bytes", data_len); #endif - + if (data_len > UINT16_MAX - (sizeof(struct ipv4_header) + sizeof(struct udp_header)) || data_len > BTap_GetMTU(&device) - (int)(sizeof(struct ipv4_header) + sizeof(struct udp_header)) ) { BLog(BLOG_ERROR, "UDP: packet is too large"); return; } - + // build IP header struct ipv4_header iph; iph.version4_ihl4 = IPV4_MAKE_VERSION_IHL(sizeof(iph)); @@ -2391,7 +2360,7 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote iph.source_address = remote_addr.ipv4.ip; iph.destination_address = local_addr.ipv4.ip; iph.checksum = ipv4_checksum(&iph, NULL, 0); - + // build UDP header struct udp_header udph; udph.source_port = remote_addr.ipv4.port; @@ -2399,21 +2368,21 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote udph.length = hton16(sizeof(udph) + data_len); udph.checksum = hton16(0); udph.checksum = udp_checksum(&udph, data, data_len, iph.source_address, iph.destination_address); - + // write packet memcpy(device_write_buf, &iph, sizeof(iph)); memcpy(device_write_buf + sizeof(iph), &udph, sizeof(udph)); memcpy(device_write_buf + sizeof(iph) + sizeof(udph), data, data_len); packet_length = sizeof(iph) + sizeof(udph) + data_len; } break; - + case BADDR_TYPE_IPV6: { #ifdef ANDROID BLog(BLOG_INFO, "UDP/IPv6: from udprelay %d bytes", data_len); #else BLog(BLOG_INFO, "UDP/IPv6: from udpgw %d bytes", data_len); #endif - + if (!options.netif_ip6addr) { #ifdef ANDROID BLog(BLOG_ERROR, "got IPv6 packet from udprelay but IPv6 is disabled"); @@ -2422,14 +2391,14 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote #endif return; } - + if (data_len > UINT16_MAX - sizeof(struct udp_header) || data_len > BTap_GetMTU(&device) - (int)(sizeof(struct ipv6_header) + sizeof(struct udp_header)) ) { BLog(BLOG_ERROR, "UDP/IPv6: packet is too large"); return; } - + // build IPv6 header struct ipv6_header iph; iph.version4_tc4 = hton8((6 << 4)); @@ -2440,7 +2409,7 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote iph.hop_limit = hton8(64); memcpy(iph.source_address, remote_addr.ipv6.ip, 16); memcpy(iph.destination_address, local_addr.ipv6.ip, 16); - + // build UDP header struct udp_header udph; udph.source_port = remote_addr.ipv6.port; @@ -2448,7 +2417,7 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote udph.length = hton16(sizeof(udph) + data_len); udph.checksum = hton16(0); udph.checksum = udp_ip6_checksum(&udph, data, data_len, iph.source_address, iph.destination_address); - + // write packet memcpy(device_write_buf, &iph, sizeof(iph)); memcpy(device_write_buf + sizeof(iph), &udph, sizeof(udph)); @@ -2456,7 +2425,7 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote packet_length = sizeof(iph) + sizeof(udph) + data_len; } break; } - + // submit packet BTap_Send(&device, device_write_buf, packet_length); } diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index aa6d93b6..012cf9ae 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -123,7 +123,7 @@ object Shadowsocks { val FEATRUE_PREFS = Array(Key.route, Key.isGlobalProxy, Key.proxyedApps, Key.isUdpDns, Key.isAutoConnect) - val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL, Executable.TUN2SOCKS) + val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL) // Helper functions def updateListPreference(pref: Preference, value: String) { diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 96af50c7..5547cf34 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -45,7 +45,7 @@ import java.net.InetAddress import android.app._ import android.content._ import android.content.pm.{PackageInfo, PackageManager} -import android.net.{VpnService, LocalSocket, LocalSocketAddress} +import android.net.{LocalServerSocket, VpnService, LocalSocket, LocalSocketAddress} import android.os._ import android.support.v4.app.NotificationCompat import android.util.Log @@ -322,23 +322,25 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd) - Console.runCommand(cmd) + Tun2Socks.start(cmd.split(" ")) + } - Thread.sleep(300) - - // try { - val localSocket = new LocalSocket() - localSocket.setFileDescriptorsForSend(Array(conn.getFileDescriptor)) - val localAddr = new LocalSocketAddress("tun2socks") - localSocket.connect(localAddr) - val output = localSocket.getOutputStream - output.write(1) - output.flush() - output.close() - localSocket.close() - // } catch { - // case ex: Exception => // Ignored - // } + def startTunFdServer() { + spawn { + val fdServer = new LocalServerSocket("tun2socks") + try { + val localSocket = fdServer.accept() + localSocket.setFileDescriptorsForSend(Array(conn.getFileDescriptor)) + val output = localSocket.getOutputStream + output.write(1) + output.flush() + output.close() + localSocket.close() + fdServer.close() + } catch { + case ex: Exception => Log.e(TAG, "Exception", ex) // Ignored + } + } } /** Called when the activity is first created. */