Compare commits

...

3 Commits
1.6.7 ... 1.6.9

Author SHA1 Message Date
2dust
eb60e4a0e4 Merge pull request #1058 from yuhan6665/grpc
Grpc
2021-05-16 19:35:16 +08:00
yuhan6665
c3dfa8cedc Support gRPC import and export
New Format https://github.com/XTLS/Xray-core/issues/91
For Vmess QRcode https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
gRPC mode is mapped to "type"
2021-05-15 23:18:09 -04:00
yuhan6665
f58bf85b6d Update UI for gRPC
Separate transport header types for different networks
Change UI dynamically based on user selection of network
2021-05-15 23:04:58 -04:00
8 changed files with 90 additions and 43 deletions

View File

@@ -192,10 +192,10 @@ data class V2rayConfig(
} }
data class GrpcSettingsBean(var serviceName: String = "", data class GrpcSettingsBean(var serviceName: String = "",
val multiMode: Boolean? = null) var multiMode: Boolean? = null)
fun populateTransportSettings(transport: String, headerType: String?, host: String?, path: String?, seed: String?, fun populateTransportSettings(transport: String, headerType: String?, host: String?, path: String?, seed: String?,
quicSecurity: String?, key: String?): String { quicSecurity: String?, key: String?, mode: String?, serviceName: String?): String {
var sni = "" var sni = ""
network = transport network = transport
when (network) { when (network) {
@@ -250,7 +250,8 @@ data class V2rayConfig(
} }
"grpc" -> { "grpc" -> {
val grpcSetting = GrpcSettingsBean() val grpcSetting = GrpcSettingsBean()
grpcSetting.serviceName = path ?: "" grpcSetting.multiMode = mode == "multi"
grpcSetting.serviceName = serviceName ?: ""
sni = host ?: "" sni = host ?: ""
grpcSettings = grpcSetting grpcSettings = grpcSetting
} }
@@ -357,7 +358,7 @@ data class V2rayConfig(
} }
"grpc" -> { "grpc" -> {
val grpcSetting = streamSettings?.grpcSettings ?: return null val grpcSetting = streamSettings?.grpcSettings ?: return null
listOf("", listOf(if (grpcSetting.multiMode == true) "multi" else "gun",
"", "",
grpcSetting.serviceName) grpcSetting.serviceName)
} }

View File

@@ -5,6 +5,9 @@ import android.support.v7.app.AlertDialog
import android.text.TextUtils import android.text.TextUtils
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import com.tencent.mmkv.MMKV import com.tencent.mmkv.MMKV
import com.v2ray.ang.R import com.v2ray.ang.R
import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.EConfigType
@@ -28,6 +31,7 @@ import kotlinx.android.synthetic.main.activity_server_vmess.et_remarks
import kotlinx.android.synthetic.main.activity_server_vmess.et_request_host import kotlinx.android.synthetic.main.activity_server_vmess.et_request_host
import kotlinx.android.synthetic.main.activity_server_vmess.sp_allow_insecure import kotlinx.android.synthetic.main.activity_server_vmess.sp_allow_insecure
import kotlinx.android.synthetic.main.activity_server_vmess.sp_header_type import kotlinx.android.synthetic.main.activity_server_vmess.sp_header_type
import kotlinx.android.synthetic.main.activity_server_vmess.sp_header_type_title
import kotlinx.android.synthetic.main.activity_server_vmess.sp_network import kotlinx.android.synthetic.main.activity_server_vmess.sp_network
import kotlinx.android.synthetic.main.activity_server_vmess.sp_stream_security import kotlinx.android.synthetic.main.activity_server_vmess.sp_stream_security
@@ -56,8 +60,14 @@ class ServerActivity : BaseActivity() {
private val networks: Array<out String> by lazy { private val networks: Array<out String> by lazy {
resources.getStringArray(R.array.networks) resources.getStringArray(R.array.networks)
} }
private val headertypes: Array<out String> by lazy { private val tcpTypes: Array<out String> by lazy {
resources.getStringArray(R.array.headertypes) resources.getStringArray(R.array.header_type_tcp)
}
private val kcpAndQuicTypes: Array<out String> by lazy {
resources.getStringArray(R.array.header_type_kcp_and_quic)
}
private val grpcModes: Array<out String> by lazy {
resources.getStringArray(R.array.mode_type_grpc)
} }
private val streamSecuritys: Array<out String> by lazy { private val streamSecuritys: Array<out String> by lazy {
resources.getStringArray(R.array.streamsecurityxs) resources.getStringArray(R.array.streamsecurityxs)
@@ -79,6 +89,26 @@ class ServerActivity : BaseActivity() {
// EConfigType.VLESS -> setContentView(R.layout.activity_server_vless) // EConfigType.VLESS -> setContentView(R.layout.activity_server_vless)
// EConfigType.TROJAN -> setContentView(R.layout.activity_server_trojan) // EConfigType.TROJAN -> setContentView(R.layout.activity_server_trojan)
} }
sp_network?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val types = transportTypes(networks[position])
sp_header_type?.isEnabled = types.size > 1
val adapter = ArrayAdapter(this@ServerActivity, android.R.layout.simple_spinner_item, types)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
sp_header_type?.adapter = adapter
sp_header_type_title?.text = if (networks[position] == "grpc")
getString(R.string.server_lab_mode_type) else
getString(R.string.server_lab_head_type)
config?.getProxyOutbound()?.getTransportSettingDetails()?.let { transportDetails ->
sp_header_type.setSelection(Utils.arrayFind(types, transportDetails[0]))
et_request_host.text = Utils.getEditable(transportDetails[1])
et_path.text = Utils.getEditable(transportDetails[2])
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
// do nothing
}
}
if (config != null) { if (config != null) {
bindingServer(config) bindingServer(config)
} else { } else {
@@ -129,11 +159,6 @@ class ServerActivity : BaseActivity() {
if (network >= 0) { if (network >= 0) {
sp_network?.setSelection(network) sp_network?.setSelection(network)
} }
outbound.getTransportSettingDetails()?.let { transportDetails ->
sp_header_type.setSelection(Utils.arrayFind(headertypes, transportDetails[0]))
et_request_host.text = Utils.getEditable(transportDetails[1])
et_path.text = Utils.getEditable(transportDetails[2])
}
return true return true
} }
@@ -246,16 +271,20 @@ class ServerActivity : BaseActivity() {
} }
private fun saveStreamSettings(streamSetting: V2rayConfig.OutboundBean.StreamSettingsBean, config: ServerConfig) { private fun saveStreamSettings(streamSetting: V2rayConfig.OutboundBean.StreamSettingsBean, config: ServerConfig) {
val network = if (sp_network != null) networks[sp_network.selectedItemPosition] else DEFAULT_NETWORK
val type = if (sp_header_type != null) transportTypes(network)[sp_header_type.selectedItemPosition] else "";
val requestHost = if (et_request_host != null) et_request_host.text.toString().trim() else "" val requestHost = if (et_request_host != null) et_request_host.text.toString().trim() else ""
val path = if (et_path != null) et_path.text.toString().trim() else "" val path = if (et_path != null) et_path.text.toString().trim() else ""
var sni = streamSetting.populateTransportSettings( var sni = streamSetting.populateTransportSettings(
if (sp_network != null) networks[sp_network.selectedItemPosition] else DEFAULT_NETWORK, transport = network,
if (sp_header_type != null) headertypes[sp_header_type.selectedItemPosition] else "", headerType = type,
requestHost, host = requestHost,
path, path = path,
path, seed = path,
requestHost, quicSecurity = requestHost,
path key = path,
mode = type,
serviceName = path
) )
val allowInsecure = if (sp_allow_insecure == null || allowinsecures[sp_allow_insecure.selectedItemPosition].isBlank()) { val allowInsecure = if (sp_allow_insecure == null || allowinsecures[sp_allow_insecure.selectedItemPosition].isBlank()) {
false//settingsStorage?.decodeBool(PREF_ALLOW_INSECURE) ?: false false//settingsStorage?.decodeBool(PREF_ALLOW_INSECURE) ?: false
@@ -270,6 +299,18 @@ class ServerActivity : BaseActivity() {
) )
} }
private fun transportTypes(network: String?): Array<out String> {
return if (network == "tcp") {
tcpTypes
} else if (network == "kcp" || network == "quic") {
kcpAndQuicTypes
} else if (network == "grpc") {
grpcModes
} else {
arrayOf("---")
}
}
/** /**
* save server config * save server config
*/ */

View File

@@ -131,7 +131,8 @@ object AngConfigManager {
} }
config.outboundBean?.streamSettings?.let { streamSetting -> config.outboundBean?.streamSettings?.let { streamSetting ->
val sni = streamSetting.populateTransportSettings(vmessBean.network, vmessBean.headerType, val sni = streamSetting.populateTransportSettings(vmessBean.network, vmessBean.headerType,
vmessBean.requestHost, vmessBean.path, vmessBean.path, vmessBean.requestHost, vmessBean.path) vmessBean.requestHost, vmessBean.path, vmessBean.path, vmessBean.requestHost, vmessBean.path,
vmessBean.headerType, vmessBean.path)
// val allowInsecure = if (vmessBean.allowInsecure.isBlank()) { // val allowInsecure = if (vmessBean.allowInsecure.isBlank()) {
// settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false // settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
// } else { // } else {
@@ -209,7 +210,7 @@ object AngConfigManager {
vnext.users[0].alterId = Utils.parseInt(vmessQRCode.aid) vnext.users[0].alterId = Utils.parseInt(vmessQRCode.aid)
} }
val sni = streamSetting.populateTransportSettings(vmessQRCode.net, vmessQRCode.type, vmessQRCode.host, val sni = streamSetting.populateTransportSettings(vmessQRCode.net, vmessQRCode.type, vmessQRCode.host,
vmessQRCode.path, vmessQRCode.path, vmessQRCode.host, vmessQRCode.path) vmessQRCode.path, vmessQRCode.path, vmessQRCode.host, vmessQRCode.path, vmessQRCode.type, vmessQRCode.path)
streamSetting.populateTlsSettings(vmessQRCode.tls, allowInsecure, streamSetting.populateTlsSettings(vmessQRCode.tls, allowInsecure,
if (vmessQRCode.sni.isNotBlank()) vmessQRCode.sni else sni) if (vmessQRCode.sni.isNotBlank()) vmessQRCode.sni else sni)
} }
@@ -312,7 +313,8 @@ object AngConfigManager {
} }
val sni = streamSetting.populateTransportSettings(queryParam["type"] ?: "tcp", queryParam["headerType"], val sni = streamSetting.populateTransportSettings(queryParam["type"] ?: "tcp", queryParam["headerType"],
queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"]) queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"],
queryParam["mode"], queryParam["serviceName"])
streamSetting.populateTlsSettings(queryParam["security"] ?: "", allowInsecure, queryParam["sni"] ?: sni) streamSetting.populateTlsSettings(queryParam["security"] ?: "", allowInsecure, queryParam["sni"] ?: sni)
} }
if (config == null){ if (config == null){
@@ -337,7 +339,7 @@ object AngConfigManager {
val uri = URI(uriString) val uri = URI(uriString)
check(uri.scheme == "vmess") check(uri.scheme == "vmess")
val (_, protocol, tlsStr, uuid, alterId) = val (_, protocol, tlsStr, uuid, alterId) =
Regex("(tcp|http|ws|kcp|quic)(\\+tls)?:([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})-([0-9]+)") Regex("(tcp|http|ws|kcp|quic|grpc)(\\+tls)?:([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})-([0-9]+)")
.matchEntire(uri.userInfo)?.groupValues .matchEntire(uri.userInfo)?.groupValues
?: error("parse user info fail.") ?: error("parse user info fail.")
val tls = tlsStr.isNotBlank() val tls = tlsStr.isNotBlank()
@@ -357,8 +359,8 @@ object AngConfigManager {
val sni = streamSetting.populateTransportSettings(protocol, queryParam["type"], val sni = streamSetting.populateTransportSettings(protocol, queryParam["type"],
queryParam["host"]?.split("|")?.get(0) ?: "", queryParam["host"]?.split("|")?.get(0) ?: "",
queryParam["path"]?.takeIf { it.trim() != "/" } ?: "", queryParam["path"]?.takeIf { it.trim() != "/" } ?: "", queryParam["seed"], queryParam["security"],
queryParam["seed"], queryParam["security"], queryParam["key"]) queryParam["key"], queryParam["mode"], queryParam["serviceName"])
streamSetting.populateTlsSettings(if (tls) TLS else "", allowInsecure, sni) streamSetting.populateTlsSettings(if (tls) TLS else "", allowInsecure, sni)
true true
}.getOrElse { false } }.getOrElse { false }
@@ -501,6 +503,10 @@ object AngConfigManager {
dicQuery["quicSecurity"] = Utils.urlEncode(transportDetails[1]) dicQuery["quicSecurity"] = Utils.urlEncode(transportDetails[1])
dicQuery["key"] = Utils.urlEncode(transportDetails[2]) dicQuery["key"] = Utils.urlEncode(transportDetails[2])
} }
"grpc" -> {
dicQuery["mode"] = transportDetails[0]
dicQuery["serviceName"] = transportDetails[2]
}
} }
} }
val query = "?" + dicQuery.toList().joinToString( val query = "?" + dicQuery.toList().joinToString(

View File

@@ -174,6 +174,7 @@
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:id="@+id/sp_header_type_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/server_lab_head_type" /> android:text="@string/server_lab_head_type" />
@@ -181,8 +182,7 @@
<Spinner <Spinner
android:id="@+id/sp_header_type" android:id="@+id/sp_header_type"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/edit_height" android:layout_height="@dimen/edit_height" />
android:entries="@array/headertypes" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout

View File

@@ -43,8 +43,9 @@
<string name="server_lab_network">传输协议(network)</string> <string name="server_lab_network">传输协议(network)</string>
<string name="server_lab_more_function">功能设置(不清楚则保持默认值)</string> <string name="server_lab_more_function">功能设置(不清楚则保持默认值)</string>
<string name="server_lab_head_type">伪装类型(type)</string> <string name="server_lab_head_type">伪装类型(type)</string>
<string name="server_lab_mode_type">gRPC 传输模式 (mode)</string>
<string name="server_lab_request_host">伪装域名(host)(host/ws host/h2 host)/QUIC 加密方式</string> <string name="server_lab_request_host">伪装域名(host)(host/ws host/h2 host)/QUIC 加密方式</string>
<string name="server_lab_path">path(ws path/h2 path)/QUIC 加密密钥/kcp seed/grpc serviceName</string> <string name="server_lab_path">path(ws path/h2 path)/QUIC 加密密钥/kcp seed/gRPC serviceName</string>
<string name="server_lab_stream_security">底层传输安全(tls)</string> <string name="server_lab_stream_security">底层传输安全(tls)</string>
<string name="server_lab_allow_insecure">跳过证书验证(allowInsecure)</string> <string name="server_lab_allow_insecure">跳过证书验证(allowInsecure)</string>
<string name="server_lab_address3">服务器地址</string> <string name="server_lab_address3">服务器地址</string>

View File

@@ -43,8 +43,9 @@
<string name="server_lab_network">網路</string> <string name="server_lab_network">網路</string>
<string name="server_lab_more_function">更多功能</string> <string name="server_lab_more_function">更多功能</string>
<string name="server_lab_head_type">標頭類型</string> <string name="server_lab_head_type">標頭類型</string>
<string name="server_lab_mode_type">gRPC 傳輸模式 (mode)</string>
<string name="server_lab_request_host">要求主機(host)(host/ws host/h2 host)/QUIC加密方式</string> <string name="server_lab_request_host">要求主機(host)(host/ws host/h2 host)/QUIC加密方式</string>
<string name="server_lab_path">path(ws path/h2 path)/QUIC加密密鑰/kcp seed/grpc serviceName</string> <string name="server_lab_path">path(ws path/h2 path)/QUIC加密密鑰/kcp seed/gRPC serviceName</string>
<string name="server_lab_stream_security">傳輸層安全性(tls)</string> <string name="server_lab_stream_security">傳輸層安全性(tls)</string>
<string name="server_lab_allow_insecure">跳過證書驗證(allowInsecure)</string> <string name="server_lab_allow_insecure">跳過證書驗證(allowInsecure)</string>
<string name="server_lab_address3">伺服器位址</string> <string name="server_lab_address3">伺服器位址</string>

View File

@@ -27,9 +27,13 @@
<item>grpc</item> <item>grpc</item>
</string-array> </string-array>
<string-array name="headertypes" translatable="false"> <string-array name="header_type_tcp" translatable="false">
<item>none</item> <item>none</item>
<item>http</item> <item>http</item>
</string-array>
<string-array name="header_type_kcp_and_quic" translatable="false">
<item>none</item>
<item>srtp</item> <item>srtp</item>
<item>utp</item> <item>utp</item>
<item>wechat-video</item> <item>wechat-video</item>
@@ -37,18 +41,10 @@
<item>wireguard</item> <item>wireguard</item>
</string-array> </string-array>
<string-array name="headertypetcps" translatable="false"> <string-array name="mode_type_grpc" translatable="false">
<item>none</item> <item>gun</item>
<item>http</item> <item>multi</item>
</string-array> <!--Hide this option until core support it <item>guna</item>-->
<string-array name="headertypekcps" translatable="false">
<item>none</item>
<item>srtp</item>
<item>utp</item>
<item>wechat-video</item>
<item>dtls</item>
<item>wireguard</item>
</string-array> </string-array>
<string-array name="streamsecuritys" translatable="false"> <string-array name="streamsecuritys" translatable="false">

View File

@@ -40,11 +40,12 @@
<string name="server_lab_id">id</string> <string name="server_lab_id">id</string>
<string name="server_lab_alterid">alterId</string> <string name="server_lab_alterid">alterId</string>
<string name="server_lab_security">security</string> <string name="server_lab_security">security</string>
<string name="server_lab_network">network</string> <string name="server_lab_network">Network</string>
<string name="server_lab_more_function">more function</string> <string name="server_lab_more_function">more function</string>
<string name="server_lab_head_type">head type</string> <string name="server_lab_head_type">head type</string>
<string name="server_lab_mode_type">gRPC mode</string>
<string name="server_lab_request_host">request host(host/ws host/h2 host)/QUIC security</string> <string name="server_lab_request_host">request host(host/ws host/h2 host)/QUIC security</string>
<string name="server_lab_path">path(ws path/h2 path)/QUIC key/kcp seed/grpc serviceName</string> <string name="server_lab_path">path(ws path/h2 path)/QUIC key/kcp seed/gRPC serviceName</string>
<string name="server_lab_stream_security">tls</string> <string name="server_lab_stream_security">tls</string>
<string name="server_lab_allow_insecure">allowInsecure</string> <string name="server_lab_allow_insecure">allowInsecure</string>
<string name="server_lab_address3">address</string> <string name="server_lab_address3">address</string>