diff --git a/app/src/main/java/com/proxy/shadowsocksr/SSRNatService.kt b/app/src/main/java/com/proxy/shadowsocksr/SSRNatService.kt index f960a12..bbdcd34 100644 --- a/app/src/main/java/com/proxy/shadowsocksr/SSRNatService.kt +++ b/app/src/main/java/com/proxy/shadowsocksr/SSRNatService.kt @@ -16,6 +16,7 @@ import android.util.Log import android.util.SparseArray import com.proxy.shadowsocksr.impl.SSRLocal import com.proxy.shadowsocksr.impl.SSRTunnel +import com.proxy.shadowsocksr.impl.UDPRelayServer import com.proxy.shadowsocksr.items.ConnectProfile import com.proxy.shadowsocksr.util.* import java.io.File @@ -35,6 +36,7 @@ class SSRNatService : Service() private var local: SSRLocal? = null private var tunnel: SSRTunnel? = null + private var udprs: UDPRelayServer? = null private var connProfile: ConnectProfile? = null @Volatile private var isNATConnected = false @@ -136,20 +138,19 @@ class SSRNatService : Service() return true; } + @Throws(Exception::class) private fun copyDaemonBin(file: String, out: File): Boolean { - val am: AssetManager = assets; val abi: String = Jni.getABI(); val buf: ByteArray = ByteArray( 1024 * 32);//most tf card have 16k or 32k logic unit size, may be 32k buffer is better try { - var create = out.createNewFile(); - if (!create) + if (!out.createNewFile()) { throw IOException("Create File Failed!"); } - val fis = am.open(abi + File.separator + file); + val fis = assets.open(abi + File.separator + file); val fos = FileOutputStream(out); var length: Int = fis.read(buf); while (length > 0) @@ -271,11 +272,20 @@ class SSRNatService : Service() private fun startTunnel() { - tunnel = SSRTunnel(connProfile!!.server, "127.0.0.1", "8.8.8.8", - connProfile!!.remotePort, 8163, 53, connProfile!!.cryptMethod, - connProfile!!.tcpProtocol, connProfile!!.obfsMethod, - connProfile!!.obfsParam, connProfile!!.passwd, false) - tunnel!!.start() + if (connProfile!!.dnsForward) + { + udprs = UDPRelayServer(connProfile!!.server, "127.0.0.1", connProfile!!.remotePort, + 8153, true, false, connProfile!!.cryptMethod, connProfile!!.passwd, "8.8.8.8", + 53) + } + else + { + tunnel = SSRTunnel(connProfile!!.server, "127.0.0.1", "8.8.8.8", + connProfile!!.remotePort, 8163, 53, connProfile!!.cryptMethod, + connProfile!!.tcpProtocol, connProfile!!.obfsMethod, + connProfile!!.obfsParam, connProfile!!.passwd, false) + } + if (udprs == null) tunnel!!.start() else udprs!!.start() } private fun startDnsDaemon() @@ -321,6 +331,11 @@ class SSRNatService : Service() tunnel!!.stopTunnel() tunnel = null } + if (udprs != null) + { + udprs!!.stopUDPRelayServer() + udprs = null + } try { android.os.Process.killProcess(pdnsdPID) @@ -371,11 +386,10 @@ class SSRNatService : Service() try { val ai = pm.getApplicationInfo(app, PackageManager.GET_ACTIVITIES) - Log.e("EXC","${ai.uid}") + Log.e("EXC", "${ai.uid}") uidSet.add(ai.uid) - http_sb.add( - (CommonUtils.iptables + CMD_IPTABLES_DNAT_ADD_SOCKS).replace("-t nat", - "-t nat -m owner --uid-owner ${ai.uid}")) + http_sb.add((CommonUtils.iptables + CMD_IPTABLES_DNAT_ADD_SOCKS) + .replace("-t nat", "-t nat -m owner --uid-owner ${ai.uid}")) } catch(ignored: Exception) { @@ -426,8 +440,8 @@ class SSRNatService : Service() // flushDns() // - val open = PendingIntent.getActivity(this@SSRNatService, -1, Intent( - this@SSRNatService, MainActivity::class.java), 0) + val open = PendingIntent.getActivity(this@SSRNatService, -1, + Intent(this@SSRNatService, MainActivity::class.java), 0) val notificationBuilder = NotificationCompat.Builder(this@SSRNatService) notificationBuilder .setWhen(0) @@ -463,7 +477,14 @@ class SSRNatService : Service() { stopSelf() } - + ShellUtil().runCmd(arrayOf("rm -f ${Consts.baseDir}pdnsd-nat.conf", + "rm -f ${Consts.baseDir}redsocks-nat.conf")); stopForeground(true) } + + override fun onDestroy() + { + stopRunner() + super.onDestroy() + } } diff --git a/app/src/main/java/com/proxy/shadowsocksr/SSRVPNService.java b/app/src/main/java/com/proxy/shadowsocksr/SSRVPNService.java index 4d429c5..a5a0c83 100644 --- a/app/src/main/java/com/proxy/shadowsocksr/SSRVPNService.java +++ b/app/src/main/java/com/proxy/shadowsocksr/SSRVPNService.java @@ -366,7 +366,7 @@ private void startSSRDaemon() connProfile.getLocalPort(), connProfile.getPasswd(), connProfile.getCryptMethod(), connProfile.getTcpProtocol(), connProfile.getObfsMethod(), connProfile.getObfsParam(), - true,aclList); + true, aclList); local.setOnNeedProtectTCPListener(this); local.start(); @@ -375,7 +375,8 @@ private void startSSRDaemon() { udprs = new UDPRelayServer(connProfile.getServer(), "127.0.0.1", connProfile.getRemotePort(), connProfile.getLocalPort(), - connProfile.getCryptMethod(), connProfile.getPasswd()); + false, true, connProfile.getCryptMethod(), + connProfile.getPasswd(), null, null); udprs.setOnNeedProtectUDPListener(this); udprs.start(); } @@ -383,10 +384,11 @@ private void startSSRDaemon() private void startDnsTunnel() { + tunnel = new SSRTunnel(connProfile.getServer(), "127.0.0.1", "8.8.8.8", connProfile.getRemotePort(), 8163, 53, connProfile.getCryptMethod(), connProfile.getTcpProtocol(), connProfile.getObfsMethod(), - connProfile.getObfsParam(), connProfile.getPasswd(),true); + connProfile.getObfsParam(), connProfile.getPasswd(), true); tunnel.setOnNeedProtectTCPListener(this); tunnel.start(); diff --git a/app/src/main/java/com/proxy/shadowsocksr/impl/SSRTunnel.kt b/app/src/main/java/com/proxy/shadowsocksr/impl/SSRTunnel.kt index c8e334b..54b8d71 100644 --- a/app/src/main/java/com/proxy/shadowsocksr/impl/SSRTunnel.kt +++ b/app/src/main/java/com/proxy/shadowsocksr/impl/SSRTunnel.kt @@ -24,7 +24,7 @@ class SSRTunnel(private val remoteIP: String, private val localIP: String, dnsIP { private var ssc: ServerSocketChannel? = null - private var dnsIp: ByteArray? = null + private var dnsIp: ByteArray?=null private var localThreadPool: ExecutorService? = null private var remoteThreadPool: ExecutorService? = null diff --git a/app/src/main/java/com/proxy/shadowsocksr/impl/UDPRelayServer.kt b/app/src/main/java/com/proxy/shadowsocksr/impl/UDPRelayServer.kt index 57fd020..3345be6 100644 --- a/app/src/main/java/com/proxy/shadowsocksr/impl/UDPRelayServer.kt +++ b/app/src/main/java/com/proxy/shadowsocksr/impl/UDPRelayServer.kt @@ -6,15 +6,18 @@ import android.util.LruCache import com.proxy.shadowsocksr.impl.interfaces.OnNeedProtectUDPListener import java.io.IOException +import java.net.InetAddress import java.net.InetSocketAddress import java.net.SocketAddress +import java.net.UnknownHostException import java.nio.ByteBuffer import java.nio.channels.DatagramChannel import java.util.concurrent.ExecutorService import java.util.concurrent.Executors class UDPRelayServer(private val remoteIP: String, private val localIP: String, private val remotePort: Int, private val localPort: Int, - cryptMethod: String, pwd: String) : Thread() + private val isTunnelMode: Boolean, private val isVPNMode: Boolean, + cryptMethod: String, pwd: String, dnsIp: String?, dnsPort: Int?) : Thread() { private var udpServer: DatagramChannel? = null private var isaLocal: InetSocketAddress? = null @@ -28,6 +31,9 @@ class UDPRelayServer(private val remoteIP: String, private val localIP: String, private val cache: LruCache + private var dnsIp: ByteArray? = null + private var dnsPort: Int? = null + private var onNeedProtectUDPListener: OnNeedProtectUDPListener? = null init @@ -35,6 +41,17 @@ class UDPRelayServer(private val remoteIP: String, private val localIP: String, cache = LruCache(64) crypto = UDPEncryptor(pwd, cryptMethod) ivLen = crypto.ivLen + if (isTunnelMode) + { + try + { + this.dnsIp = InetAddress.getByName(dnsIp).address + } + catch (ignored: UnknownHostException) + { + } + this.dnsPort = dnsPort + } } fun setOnNeedProtectUDPListener(onNeedProtectUDPListener: OnNeedProtectUDPListener) @@ -93,26 +110,46 @@ class UDPRelayServer(private val remoteIP: String, private val localIP: String, val localAddress = udpServer!!.receive(buf) // buf.flip() + // + val dataLocalIn: ByteArray val rcnt = buf.limit() - if (rcnt < 8) - { - Log.e("EXC", "LOCAL RECV SMALL PKG") - buf.clear()//not response small package - continue - } // - if (!(buf.get().toInt() == 0 && //RSV - buf.get().toInt() == 0 && //RSV - buf.get().toInt() == 0)) - //FRAG + if (isTunnelMode) + { //direct build target dns server socks5 request pkg + if (rcnt < 12) + { + Log.e("EXC", "LOCAL RECV SMALL PKG") + buf.clear()//not response small package + continue + } + dataLocalIn = ByteArray(7 + rcnt) + dataLocalIn[0] = 1 + System.arraycopy(dnsIp, 0, dataLocalIn, 1, 4) + dataLocalIn[5] = ((dnsPort!!.shr(8)) and 0xFF).toByte() + dataLocalIn[6] = (dnsPort!!.and(0xFF)).toByte() + buf.get(dataLocalIn, 7, dataLocalIn.size) + } + else { - Log.e("EXC", "LOCAL RECV NOT SOCKS5 UDP PKG") - buf.clear() - continue + if (rcnt < 8) + { + Log.e("EXC", "LOCAL RECV SMALL PKG") + buf.clear()//not response small package + continue + } + // + if (!(buf.get().toInt() == 0 && //RSV + buf.get().toInt() == 0 && //RSV + buf.get().toInt() == 0)) //FRAG + { + Log.e("EXC", "LOCAL RECV NOT SOCKS5 UDP PKG") + buf.clear() + continue + } + // + dataLocalIn = ByteArray(rcnt - 3) + buf.get(dataLocalIn) } - // - val dataLocalIn = ByteArray(rcnt - 3) - buf.get(dataLocalIn) val dataRemoteOut = crypto.encrypt(dataLocalIn) // var handler: UDPRemoteDataHandler? = cache.get(localAddress) @@ -121,19 +158,28 @@ class UDPRelayServer(private val remoteIP: String, private val localIP: String, val remoteChannel = DatagramChannel.open() remoteChannel.configureBlocking(true) remoteChannel.connect(isaRemote) - val isProtected = onNeedProtectUDPListener!!.onNeedProtectUDP( - remoteChannel.socket()) - if (isProtected) + if (isVPNMode) { + val isProtected = onNeedProtectUDPListener!!.onNeedProtectUDP( + remoteChannel.socket()) + if (isProtected) + { + handler = UDPRemoteDataHandler(localAddress, remoteChannel) + cache.put(localAddress, handler) + exec!!.execute(handler) + } + else + { + buf.clear() + continue + } + } + else + { //Nat mode need not protect handler = UDPRemoteDataHandler(localAddress, remoteChannel) cache.put(localAddress, handler) exec!!.execute(handler) } - else - { - buf.clear() - continue - } } handler.remoteChannel!!.write(ByteBuffer.wrap(dataRemoteOut)) // @@ -152,8 +198,6 @@ class UDPRelayServer(private val remoteIP: String, private val localIP: String, catch (ignored: Exception) { } - - buf.clear() } } @@ -170,7 +214,8 @@ class UDPRelayServer(private val remoteIP: String, private val localIP: String, while (isRunning) { val rcnt = remoteChannel!!.read(remoteReadBuf) - if (rcnt < ivLen + 8) + // + if (rcnt < ivLen + 1) { remoteReadBuf.clear()//not response small package, just drop. continue @@ -197,7 +242,6 @@ class UDPRelayServer(private val remoteIP: String, private val localIP: String, catch (ignored: IOException) { } - remoteChannel = null } diff --git a/app/src/main/java/com/proxy/shadowsocksr/util/ConfFileUtil.kt b/app/src/main/java/com/proxy/shadowsocksr/util/ConfFileUtil.kt index 81a9c21..0ef07cf 100644 --- a/app/src/main/java/com/proxy/shadowsocksr/util/ConfFileUtil.kt +++ b/app/src/main/java/com/proxy/shadowsocksr/util/ConfFileUtil.kt @@ -25,6 +25,7 @@ redsocks { port = %d; type = socks5; } + """ @JvmStatic const val PdNSdLocal = """global { perm_cache = 2048;