diff --git a/src/main/assets/pdnsd.conf b/src/main/assets/pdnsd.conf deleted file mode 100644 index 79ca809d..00000000 --- a/src/main/assets/pdnsd.conf +++ /dev/null @@ -1,33 +0,0 @@ -global { - perm_cache = 2048; - cache_dir = "/data/data/com.github.shadowsocks"; - server_ip = 0.0.0.0; - server_port = 8153; - query_method = tcp_only; - run_ipv4 = on; - min_ttl = 15m; - max_ttl = 1w; - timeout = 10; - daemon = on; - pid_file = "/data/data/com.github.shadowsocks/pdnsd.pid"; -} - -server { - label = "root-servers"; - - ip = 8.8.8.8 - , 8.8.4.4 - , 199.91.73.222 - , 178.79.131.110 - ; - - timeout = 5; -} - -rr { - name=localhost; - reverse=on; - a=127.0.0.1; - owner=localhost; - soa=localhost,root.localhost,42,86400,900,86400,86400; -} diff --git a/src/main/scala/com/github/shadowsocks/ShadowVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowVpnService.scala index 5bf33c75..d17ed422 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowVpnService.scala @@ -62,7 +62,7 @@ class ShadowVpnService extends VpnService { val TAG = "ShadowVpnService" val BASE = "/data/data/com.github.shadowsocks/" - val SHADOWSOCKS_CONF = "{\"server\": [%s], \"server_port\": %d, \"local_port\": %d, \"password\": %s, \"timeout\": %d}" + val MSG_CONNECT_FINISH = 1 val MSG_CONNECT_SUCCESS = 2 val MSG_CONNECT_FAIL = 3 @@ -136,19 +136,21 @@ class ShadowVpnService extends VpnService { } def startShadowsocksDaemon() { - 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) - if (BuildConfig.DEBUG) Log.d(TAG, cmd) - System.exec(cmd) - } + val cmd: String = (BASE + + "shadowsocks -b 127.0.0.1 -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) + if (BuildConfig.DEBUG) Log.d(TAG, cmd) + System.exec(cmd) } def startDnsDaemon() { val cmd: String = BASE + "pdnsd -c " + BASE + "pdnsd.conf" + val conf: String = Config.PDNSD.format("0.0.0.0") + Config.printToFile(new File(BASE + "pdnsd.conf"))(p => { + p.println(conf) + }) Utils.runCommand(cmd) } @@ -184,7 +186,6 @@ class ShadowVpnService extends VpnService { config = Extra.get(intent) - spawn { killProcesses() @@ -232,6 +233,11 @@ class ShadowVpnService extends VpnService { !t.isAlive } + def getLocalAddress: String = Utils.getIPv4Address match { + case Some(ip) if ip.split('.')(0) == "172" => PRIVATE_VLAN_10 + case _ => PRIVATE_VLAN_172 + } + def startVpn() { val address = config.proxy.split('.') @@ -239,10 +245,7 @@ class ShadowVpnService extends VpnService { val prefix2 = address.slice(0, 2).mkString(".") val prefix3 = address.slice(0, 3).mkString(".") - val localAddress = Utils.getIPv4Address match { - case Some(ip) if ip.split('.')(0) == "172" => PRIVATE_VLAN_10 - case _ => PRIVATE_VLAN_172 - } + val localAddress = getLocalAddress val builder = new Builder() builder @@ -301,7 +304,6 @@ class ShadowVpnService extends VpnService { val cmd = (BASE + "tun2socks --netif-ipaddr %s " - // + "--udpgw-remote-server-addr %s:7300 " + "--dnsgw %s:8153 " + "--netif-netmask 255.255.255.0 " + "--socks-server-addr 127.0.0.1:%d " @@ -316,9 +318,9 @@ class ShadowVpnService extends VpnService { /** Called when the activity is first created. */ def handleConnection: Boolean = { - startDnsDaemon() - startShadowsocksDaemon() startVpn() + startShadowsocksDaemon() + startDnsDaemon() true } @@ -405,6 +407,10 @@ class ShadowVpnService extends VpnService { sb ++= "kill -9 `cat /data/data/com.github.shadowsocks/tun2socks.pid`" ++= "\n" sb ++= "killall -9 tun2socks" ++= "\n" } + if (!waitForProcess("pdnsd")) { + sb ++= "kill -9 `cat /data/data/com.github.shadowsocks/pdnsd.pid`" ++= "\n" + sb ++= "killall -9 pdnsd" ++= "\n" + } Utils.runCommand(sb.toString()) } diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index 79c56c3b..5bbed62d 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -287,18 +287,20 @@ class Shadowsocks private def crash_recovery() { val sb = new StringBuilder - sb.append(Utils.getIptables).append(" -t nat -F OUTPUT").append("\n") sb.append("kill -9 `cat /data/data/com.github.shadowsocks/pdnsd.pid`").append("\n") sb.append("kill -9 `cat /data/data/com.github.shadowsocks/shadowsocks.pid`").append("\n") sb.append("kill -9 `cat /data/data/com.github.shadowsocks/tun2socks.pid`").append("\n") sb.append("killall -9 pdnsd").append("\n") sb.append("killall -9 shadowsocks").append("\n") sb.append("killall -9 tun2socks").append("\n") + sb.append("rm /data/data/com.github.shadowsocks/pdnsd.conf").append("\n") Utils.runCommand(sb.toString()) sb.clear() sb.append("kill -9 `cat /data/data/com.github.shadowsocks/redsocks.pid`").append("\n") sb.append("killall -9 redsocks").append("\n") + sb.append("rm /data/data/com.github.shadowsocks/redsocks.conf").append("\n") + sb.append(Utils.getIptables).append(" -t nat -F OUTPUT").append("\n") Utils.runRootCommand(sb.toString()) } @@ -534,7 +536,6 @@ class Shadowsocks def reset() { crash_recovery() - copyAssets("") copyAssets(Utils.getABI) Utils.runCommand("chmod 755 /data/data/com.github.shadowsocks/iptables\n" + "chmod 755 /data/data/com.github.shadowsocks/redsocks\n" diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala index 4a5f030d..54bc37f5 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala @@ -48,10 +48,7 @@ import android.os._ import android.support.v4.app.NotificationCompat import android.util.Log import com.google.analytics.tracking.android.EasyTracker -import java.io.BufferedReader -import java.io.FileNotFoundException -import java.io.FileReader -import java.io.IOException +import java.io._ import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method import org.apache.http.conn.util.InetAddressUtils @@ -59,8 +56,8 @@ import scala.collection._ import java.util.{TimerTask, Timer} import android.net.TrafficStats import android.graphics._ -import scala.Some import scala.concurrent.ops._ +import scala.Some case class TrafficStat(tx: Long, rx: Long, timestamp: Long) @@ -74,21 +71,7 @@ class ShadowsocksService extends Service { val TAG = "ShadowsocksService" val BASE = "/data/data/com.github.shadowsocks/" - val REDSOCKS_CONF = "base {" + - " log_debug = off;" + - " log_info = off;" + - " log = stderr;" + - " daemon = on;" + - " redirector = iptables;" + - "}" + - "redsocks {" + - " local_ip = 127.0.0.1;" + - " local_port = 8123;" + - " ip = 127.0.0.1;" + - " port = %d;" + - " type = socks5;" + - "}" - val SHADOWSOCKS_CONF = "{\"server\": [%s], \"server_port\": %d, \"local_port\": %d, \"password\": %s, \"timeout\": %d}" + val CMD_IPTABLES_RETURN = " -t nat -A OUTPUT -p tcp -d 0.0.0.0 -j RETURN\n" val CMD_IPTABLES_REDIRECT_ADD_SOCKS = " -t nat -A OUTPUT -p tcp " + "-j REDIRECT --to 8123\n" val CMD_IPTABLES_DNAT_ADD_SOCKS = " -t nat -A OUTPUT -p tcp " + @@ -169,20 +152,21 @@ class ShadowsocksService extends Service { } def startShadowsocksDaemon() { - 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) - if (BuildConfig.DEBUG) Log.d(TAG, cmd) - System.exec(cmd) - } + val cmd: String = (BASE + + "shadowsocks -b 127.0.0.1 -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) + if (BuildConfig.DEBUG) Log.d(TAG, cmd) + System.exec(cmd) } def startDnsDaemon() { val cmd: String = BASE + "pdnsd -c " + BASE + "pdnsd.conf" + val conf: String = Config.PDNSD.format("127.0.0.1") + Config.printToFile(new File(BASE + "pdnsd.conf"))(p => { + p.println(conf) + }) Utils.runCommand(cmd) } @@ -242,9 +226,12 @@ class ShadowsocksService extends Service { } def startRedsocksDaemon() { - val conf = REDSOCKS_CONF.format(config.localPort) + val conf = Config.REDSOCKS.format(config.localPort) val cmd = "%sredsocks -p %sredsocks.pid -c %sredsocks.conf".format(BASE, BASE, BASE) - Utils.runRootCommand("echo \"" + conf + "\" > " + BASE + "redsocks.conf\n" + cmd) + Config.printToFile(new File(BASE + "redsocks.conf"))(p => { + p.println(conf) + }) + Utils.runRootCommand(cmd) } def waitForProcess(name: String): Boolean = { @@ -426,7 +413,7 @@ class ShadowsocksService extends Service { } last = new TrafficStat(TrafficStats.getUidTxBytes(getApplicationInfo.uid), TrafficStats.getUidRxBytes(getApplicationInfo.uid), java.lang.System.currentTimeMillis()) - timer.schedule(task, TIMER_INTERVAL*1000, TIMER_INTERVAL*1000) + timer.schedule(task, TIMER_INTERVAL * 1000, TIMER_INTERVAL * 1000) } /** Called when the activity is closed. */ diff --git a/src/main/scala/com/github/shadowsocks/Utils.scala b/src/main/scala/com/github/shadowsocks/Utils.scala index 4c15505f..433e238b 100644 --- a/src/main/scala/com/github/shadowsocks/Utils.scala +++ b/src/main/scala/com/github/shadowsocks/Utils.scala @@ -52,6 +52,63 @@ import scala.Some import android.graphics.{Canvas, Bitmap} import android.app.ActivityManager +object Config { + val SHADOWSOCKS = "{\"server\": [%s], \"server_port\": %d, \"local_port\": %d, \"password\": %s, \"timeout\": %d}" + val REDSOCKS = "base {" + + " log_debug = off;" + + " log_info = off;" + + " log = stderr;" + + " daemon = on;" + + " redirector = iptables;" + + "}" + + "redsocks {" + + " local_ip = 127.0.0.1;" + + " local_port = 8123;" + + " ip = 127.0.0.1;" + + " port = %d;" + + " type = socks5;" + + "}" + val PDNSD = + """ + |global { + | perm_cache = 2048; + | cache_dir = "/data/data/com.github.shadowsocks"; + | server_ip = %s; + | server_port = 8153; + | query_method = tcp_only; + | run_ipv4 = on; + | min_ttl = 15m; + | max_ttl = 1w; + | timeout = 10; + | daemon = on; + | pid_file = "/data/data/com.github.shadowsocks/pdnsd.pid"; + |} + | + |server { + | label = "root-servers"; + | ip = 8.8.8.8, 8.8.4.4, 208.67.222.222, 208.67.220.220; + | timeout = 5; + |} + | + |rr { + | name=localhost; + | reverse=on; + | a=127.0.0.1; + | owner=localhost; + | soa=localhost,root.localhost,42,86400,900,86400,86400; + |} + """.stripMargin + + def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) { + val p = new java.io.PrintWriter(f) + try { op(p) } finally { p.close() } + } +} + +case class Config(isGlobalProxy: Boolean, isGFWList: Boolean, isBypassApps: Boolean, + var proxy: String, sitekey: String, encMethod: String, remotePort: Int, + localPort: Int, proxiedAppString: String) + object Key { val proxied = "Proxyed" @@ -73,10 +130,6 @@ object Key { val localPort = "port" } -case class Config(isGlobalProxy: Boolean, isGFWList: Boolean, isBypassApps: Boolean, - var proxy: String, sitekey: String, encMethod: String, remotePort: Int, - localPort: Int, proxiedAppString: String) - object State { val INIT = 0 val CONNECTING = 1