use internal hysteria & tuic

This commit is contained in:
arm64v8a 2023-08-08 16:57:39 +09:00
parent 814025e9e1
commit d1da522700
13 changed files with 318 additions and 56 deletions

View File

@ -176,6 +176,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var profileName by profileCacheStore.string(Key.PROFILE_NAME) var profileName by profileCacheStore.string(Key.PROFILE_NAME)
var serverAddress by profileCacheStore.string(Key.SERVER_ADDRESS) var serverAddress by profileCacheStore.string(Key.SERVER_ADDRESS)
var serverPort by profileCacheStore.stringToInt(Key.SERVER_PORT) var serverPort by profileCacheStore.stringToInt(Key.SERVER_PORT)
var serverPorts by profileCacheStore.string("serverPorts")
var serverUsername by profileCacheStore.string(Key.SERVER_USERNAME) var serverUsername by profileCacheStore.string(Key.SERVER_USERNAME)
var serverPassword by profileCacheStore.string(Key.SERVER_PASSWORD) var serverPassword by profileCacheStore.string(Key.SERVER_PASSWORD)
var serverPassword1 by profileCacheStore.string(Key.SERVER_PASSWORD1) var serverPassword1 by profileCacheStore.string(Key.SERVER_PASSWORD1)

View File

@ -296,7 +296,7 @@ data class ProxyEntity(
TYPE_TROJAN_GO -> true TYPE_TROJAN_GO -> true
TYPE_NAIVE -> true TYPE_NAIVE -> true
TYPE_HYSTERIA -> !hysteriaBean!!.canUseSingBox() TYPE_HYSTERIA -> !hysteriaBean!!.canUseSingBox()
TYPE_TUIC -> true TYPE_TUIC -> tuicBean!!.protocolVersion == 4
TYPE_NEKO -> true TYPE_NEKO -> true
else -> false else -> false
} }

View File

@ -13,7 +13,6 @@ import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.fmt.ConfigBuildResult.IndexEntity import io.nekohasekai.sagernet.fmt.ConfigBuildResult.IndexEntity
import io.nekohasekai.sagernet.fmt.hysteria.HysteriaBean import io.nekohasekai.sagernet.fmt.hysteria.HysteriaBean
import io.nekohasekai.sagernet.fmt.hysteria.buildSingBoxOutboundHysteriaBean import io.nekohasekai.sagernet.fmt.hysteria.buildSingBoxOutboundHysteriaBean
import io.nekohasekai.sagernet.fmt.hysteria.isMultiPort
import io.nekohasekai.sagernet.fmt.internal.ChainBean import io.nekohasekai.sagernet.fmt.internal.ChainBean
import io.nekohasekai.sagernet.fmt.shadowsocks.ShadowsocksBean import io.nekohasekai.sagernet.fmt.shadowsocks.ShadowsocksBean
import io.nekohasekai.sagernet.fmt.shadowsocks.buildSingBoxOutboundShadowsocksBean import io.nekohasekai.sagernet.fmt.shadowsocks.buildSingBoxOutboundShadowsocksBean
@ -22,6 +21,7 @@ import io.nekohasekai.sagernet.fmt.socks.buildSingBoxOutboundSocksBean
import io.nekohasekai.sagernet.fmt.ssh.SSHBean import io.nekohasekai.sagernet.fmt.ssh.SSHBean
import io.nekohasekai.sagernet.fmt.ssh.buildSingBoxOutboundSSHBean import io.nekohasekai.sagernet.fmt.ssh.buildSingBoxOutboundSSHBean
import io.nekohasekai.sagernet.fmt.tuic.TuicBean import io.nekohasekai.sagernet.fmt.tuic.TuicBean
import io.nekohasekai.sagernet.fmt.tuic.buildSingBoxOutboundTuicBean
import io.nekohasekai.sagernet.fmt.tuic.pluginId import io.nekohasekai.sagernet.fmt.tuic.pluginId
import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean
import io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundStandardV2RayBean import io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundStandardV2RayBean
@ -382,6 +382,9 @@ fun buildConfig(
is HysteriaBean -> is HysteriaBean ->
buildSingBoxOutboundHysteriaBean(bean).asMap() buildSingBoxOutboundHysteriaBean(bean).asMap()
is TuicBean ->
buildSingBoxOutboundTuicBean(bean).asMap()
is SOCKSBean -> is SOCKSBean ->
buildSingBoxOutboundSocksBean(bean).asMap() buildSingBoxOutboundSocksBean(bean).asMap()
@ -664,9 +667,7 @@ fun buildConfig(
// Bypass Lookup for the first profile // Bypass Lookup for the first profile
bypassDNSBeans.forEach { bypassDNSBeans.forEach {
var serverAddr = it.serverAddress var serverAddr = it.serverAddress
if (it is HysteriaBean && it.isMultiPort()) {
serverAddr = it.serverAddress.substringBeforeLast(":")
}
if (it is ConfigBean) { if (it is ConfigBean) {
var config = mutableMapOf<String, Any>() var config = mutableMapOf<String, Any>()
config = gson.fromJson(it.config, config.javaClass) config = gson.fromJson(it.config, config.javaClass)

View File

@ -9,6 +9,8 @@ import org.jetbrains.annotations.NotNull;
import io.nekohasekai.sagernet.fmt.AbstractBean; import io.nekohasekai.sagernet.fmt.AbstractBean;
import io.nekohasekai.sagernet.fmt.KryoConverters; import io.nekohasekai.sagernet.fmt.KryoConverters;
import io.nekohasekai.sagernet.ktx.NetsKt;
import kotlin.text.StringsKt;
public class HysteriaBean extends AbstractBean { public class HysteriaBean extends AbstractBean {
@ -38,6 +40,8 @@ public class HysteriaBean extends AbstractBean {
public Boolean disableMtuDiscovery; public Boolean disableMtuDiscovery;
public Integer hopInterval; public Integer hopInterval;
public String serverPorts;
@Override @Override
public boolean canMapping() { public boolean canMapping() {
return protocol != PROTOCOL_FAKETCP; return protocol != PROTOCOL_FAKETCP;
@ -62,11 +66,12 @@ public class HysteriaBean extends AbstractBean {
if (connectionReceiveWindow == null) connectionReceiveWindow = 0; if (connectionReceiveWindow == null) connectionReceiveWindow = 0;
if (disableMtuDiscovery == null) disableMtuDiscovery = false; if (disableMtuDiscovery == null) disableMtuDiscovery = false;
if (hopInterval == null) hopInterval = 10; if (hopInterval == null) hopInterval = 10;
if (serverPorts == null) serverPorts = "443";
} }
@Override @Override
public void serialize(ByteBufferOutput output) { public void serialize(ByteBufferOutput output) {
output.writeInt(5); output.writeInt(6);
super.serialize(output); super.serialize(output);
output.writeInt(authPayloadType); output.writeInt(authPayloadType);
output.writeString(authPayload); output.writeString(authPayload);
@ -84,6 +89,7 @@ public class HysteriaBean extends AbstractBean {
output.writeInt(connectionReceiveWindow); output.writeInt(connectionReceiveWindow);
output.writeBoolean(disableMtuDiscovery); output.writeBoolean(disableMtuDiscovery);
output.writeInt(hopInterval); output.writeInt(hopInterval);
output.writeString(serverPorts);
} }
@ -113,6 +119,17 @@ public class HysteriaBean extends AbstractBean {
if (version >= 5) { if (version >= 5) {
hopInterval = input.readInt(); hopInterval = input.readInt();
} }
if (version >= 6) {
serverPorts = input.readString();
} else {
// old update to new
if (HysteriaFmtKt.isMultiPort(serverAddress)) {
serverPorts = StringsKt.substringAfterLast(serverAddress, ":", serverAddress);
serverAddress = StringsKt.substringBeforeLast(serverAddress, ":", serverAddress);
} else {
serverPorts = serverPort.toString();
}
}
} }
@Override @Override
@ -128,10 +145,7 @@ public class HysteriaBean extends AbstractBean {
@Override @Override
public String displayAddress() { public String displayAddress() {
if (HysteriaFmtKt.isMultiPort(this)) { return NetsKt.wrapIPV6Host(serverAddress) + ":" + serverPorts;
return serverAddress;
}
return super.displayAddress();
} }
@Override @Override
@ -157,4 +171,4 @@ public class HysteriaBean extends AbstractBean {
return new HysteriaBean[size]; return new HysteriaBean[size];
} }
}; };
} }

View File

@ -18,11 +18,11 @@ fun parseHysteria(url: String): HysteriaBean {
) )
return HysteriaBean().apply { return HysteriaBean().apply {
serverAddress = link.host serverAddress = link.host
serverPort = link.port serverPorts = link.port.toString()
name = link.fragment name = link.fragment
link.queryParameter("mport")?.also { link.queryParameter("mport")?.also {
serverAddress = serverAddress.wrapIPV6Host() + ":" + it serverPorts = it
} }
link.queryParameter("peer")?.also { link.queryParameter("peer")?.also {
sni = it sni = it
@ -51,6 +51,7 @@ fun parseHysteria(url: String): HysteriaBean {
"faketcp" -> { "faketcp" -> {
protocol = HysteriaBean.PROTOCOL_FAKETCP protocol = HysteriaBean.PROTOCOL_FAKETCP
} }
"wechat-video" -> { "wechat-video" -> {
protocol = HysteriaBean.PROTOCOL_WECHAT_VIDEO protocol = HysteriaBean.PROTOCOL_WECHAT_VIDEO
} }
@ -60,9 +61,11 @@ fun parseHysteria(url: String): HysteriaBean {
} }
fun HysteriaBean.toUri(): String { fun HysteriaBean.toUri(): String {
val builder = linkBuilder().host(serverAddress.substringBeforeLast(":")).port(serverPort) val builder = linkBuilder()
if (isMultiPort()) { .host(serverAddress)
builder.addQueryParameter("mport", serverAddress.substringAfterLast(":")) .port(getFirstPort(serverPorts))
if (isMultiPort(displayAddress())) {
builder.addQueryParameter("mport", serverPorts)
} }
if (allowInsecure) { if (allowInsecure) {
builder.addQueryParameter("insecure", "1") builder.addQueryParameter("insecure", "1")
@ -86,6 +89,7 @@ fun HysteriaBean.toUri(): String {
HysteriaBean.PROTOCOL_FAKETCP -> { HysteriaBean.PROTOCOL_FAKETCP -> {
builder.addQueryParameter("protocol", "faketcp") builder.addQueryParameter("protocol", "faketcp")
} }
HysteriaBean.PROTOCOL_WECHAT_VIDEO -> { HysteriaBean.PROTOCOL_WECHAT_VIDEO -> {
builder.addQueryParameter("protocol", "wechat-video") builder.addQueryParameter("protocol", "wechat-video")
} }
@ -101,11 +105,8 @@ fun HysteriaBean.toUri(): String {
fun JSONObject.parseHysteria(): HysteriaBean { fun JSONObject.parseHysteria(): HysteriaBean {
return HysteriaBean().apply { return HysteriaBean().apply {
serverAddress = optString("server") serverAddress = optString("server").substringBeforeLast(":")
if (!isMultiPort()) { serverPorts = optString("server").substringAfterLast(":")
serverAddress = optString("server").substringBeforeLast(":")
serverPort = optString("server").substringAfterLast(":").toIntOrNull() ?: 443
}
uploadMbps = getIntNya("up_mbps") uploadMbps = getIntNya("up_mbps")
downloadMbps = getIntNya("down_mbps") downloadMbps = getIntNya("down_mbps")
obfuscation = getStr("obfs") obfuscation = getStr("obfs")
@ -122,6 +123,7 @@ fun JSONObject.parseHysteria(): HysteriaBean {
"faketcp" -> { "faketcp" -> {
protocol = HysteriaBean.PROTOCOL_FAKETCP protocol = HysteriaBean.PROTOCOL_FAKETCP
} }
"wechat-video" -> { "wechat-video" -> {
protocol = HysteriaBean.PROTOCOL_WECHAT_VIDEO protocol = HysteriaBean.PROTOCOL_WECHAT_VIDEO
} }
@ -139,11 +141,12 @@ fun JSONObject.parseHysteria(): HysteriaBean {
fun HysteriaBean.buildHysteriaConfig(port: Int, cacheFile: (() -> File)?): String { fun HysteriaBean.buildHysteriaConfig(port: Int, cacheFile: (() -> File)?): String {
return JSONObject().apply { return JSONObject().apply {
put("server", if (isMultiPort()) serverAddress else wrapUri()) put("server", displayAddress())
when (protocol) { when (protocol) {
HysteriaBean.PROTOCOL_FAKETCP -> { HysteriaBean.PROTOCOL_FAKETCP -> {
put("protocol", "faketcp") put("protocol", "faketcp")
} }
HysteriaBean.PROTOCOL_WECHAT_VIDEO -> { HysteriaBean.PROTOCOL_WECHAT_VIDEO -> {
put("protocol", "wechat-video") put("protocol", "wechat-video")
} }
@ -190,24 +193,33 @@ fun HysteriaBean.buildHysteriaConfig(port: Int, cacheFile: (() -> File)?): Strin
}.toStringPretty() }.toStringPretty()
} }
fun HysteriaBean.isMultiPort(): Boolean { fun isMultiPort(hyAddr: String): Boolean {
if (!serverAddress.contains(":")) return false if (!hyAddr.contains(":")) return false
val p = serverAddress.substringAfterLast(":") val p = hyAddr.substringAfterLast(":")
if (p.contains("-") || p.contains(",")) return true if (p.contains("-") || p.contains(",")) return true
return false return false
} }
fun getFirstPort(portStr: String): Int {
return portStr.substringBefore(":").substringBefore(",").toIntOrNull() ?: 443
}
fun HysteriaBean.canUseSingBox(): Boolean { fun HysteriaBean.canUseSingBox(): Boolean {
if (isMultiPort() || protocol != HysteriaBean.PROTOCOL_UDP) return false if (protocol != HysteriaBean.PROTOCOL_UDP) return false
return true return true
} }
fun buildSingBoxOutboundHysteriaBean(bean: HysteriaBean): SingBoxOptions.Outbound_HysteriaOptions { fun buildSingBoxOutboundHysteriaBean(bean: HysteriaBean): SingBoxOptions.Outbound_HysteriaOptions {
// No multi-port
return SingBoxOptions.Outbound_HysteriaOptions().apply { return SingBoxOptions.Outbound_HysteriaOptions().apply {
type = "hysteria" type = "hysteria"
server = bean.serverAddress server = bean.serverAddress
server_port = bean.serverPort val port = bean.serverPorts.toIntOrNull()
if (port != null) {
server_port = port
} else {
hop_ports = bean.serverPorts
}
hop_interval = bean.hopInterval
up_mbps = bean.uploadMbps up_mbps = bean.uploadMbps
down_mbps = bean.downloadMbps down_mbps = bean.downloadMbps
obfs = bean.obfuscation obfs = bean.obfuscation

View File

@ -2,6 +2,7 @@ package io.nekohasekai.sagernet.fmt.tuic
import io.nekohasekai.sagernet.fmt.LOCALHOST import io.nekohasekai.sagernet.fmt.LOCALHOST
import io.nekohasekai.sagernet.ktx.isIpAddress import io.nekohasekai.sagernet.ktx.isIpAddress
import moe.matsuri.nb4a.SingBoxOptions
import moe.matsuri.nb4a.utils.JavaUtil import moe.matsuri.nb4a.utils.JavaUtil
import moe.matsuri.nb4a.utils.Util import moe.matsuri.nb4a.utils.Util
import moe.matsuri.nb4a.utils.listByLineOrComma import moe.matsuri.nb4a.utils.listByLineOrComma
@ -9,6 +10,32 @@ import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File
fun buildSingBoxOutboundTuicBean(bean: TuicBean): SingBoxOptions.Outbound_TUICOptions {
return SingBoxOptions.Outbound_TUICOptions().apply {
type = "tuic"
server = bean.serverAddress
server_port = bean.serverPort
uuid = bean.uuid
password = bean.token
congestion_control = bean.congestionController
udp_relay_mode = bean.udpRelayMode
zero_rtt_handshake = bean.reduceRTT
tls = SingBoxOptions.OutboundTLSOptions().apply {
if (bean.sni.isNotBlank()) {
server_name = bean.sni
}
if (bean.alpn.isNotBlank()) {
alpn = bean.alpn.listByLineOrComma()
}
if (bean.caText.isNotBlank()) {
certificate = bean.caText
}
insecure = bean.allowInsecure
enabled = true
}
}
}
fun TuicBean.pluginId(): String { fun TuicBean.pluginId(): String {
return when (protocolVersion) { return when (protocolVersion) {
5 -> "tuic-v5-plugin" 5 -> "tuic-v5-plugin"

View File

@ -187,6 +187,7 @@ public abstract class StandardV2RayBean extends AbstractBean {
StandardV2RayBean bean = ((StandardV2RayBean) other); StandardV2RayBean bean = ((StandardV2RayBean) other);
bean.allowInsecure = allowInsecure; bean.allowInsecure = allowInsecure;
bean.utlsFingerprint = utlsFingerprint; bean.utlsFingerprint = utlsFingerprint;
bean.packetEncoding = packetEncoding;
} }
public boolean isVLESS() { public boolean isVLESS() {

View File

@ -311,8 +311,8 @@ object RawUpdater : GroupUpdater() {
} }
"xudp" -> if (opt.value.toString() == "true") { "xudp" -> if (opt.value.toString() == "true") {
bean.packetEncoding = 2 bean.packetEncoding = 2
} }
"network" -> { "network" -> {
bean.type = opt.value as String bean.type = opt.value as String
@ -511,8 +511,7 @@ object RawUpdater : GroupUpdater() {
} }
} }
if (hopPorts.isNotBlank()) { if (hopPorts.isNotBlank()) {
bean.serverAddress = bean.serverPorts = hopPorts
bean.serverAddress.wrapIPV6Host() + ":" + hopPorts
} }
proxies.add(bean) proxies.add(bean)
} }

View File

@ -18,7 +18,7 @@ class HysteriaSettingsActivity : ProfileSettingsActivity<HysteriaBean>() {
override fun HysteriaBean.init() { override fun HysteriaBean.init() {
DataStore.profileName = name DataStore.profileName = name
DataStore.serverAddress = serverAddress DataStore.serverAddress = serverAddress
DataStore.serverPort = serverPort DataStore.serverPorts = serverPorts
DataStore.serverObfs = obfuscation DataStore.serverObfs = obfuscation
DataStore.serverAuthType = authPayloadType DataStore.serverAuthType = authPayloadType
DataStore.serverProtocolVersion = protocol DataStore.serverProtocolVersion = protocol
@ -38,7 +38,7 @@ class HysteriaSettingsActivity : ProfileSettingsActivity<HysteriaBean>() {
override fun HysteriaBean.serialize() { override fun HysteriaBean.serialize() {
name = DataStore.profileName name = DataStore.profileName
serverAddress = DataStore.serverAddress serverAddress = DataStore.serverAddress
serverPort = DataStore.serverPort serverPorts = DataStore.serverPorts
obfuscation = DataStore.serverObfs obfuscation = DataStore.serverObfs
authPayloadType = DataStore.serverAuthType authPayloadType = DataStore.serverAuthType
authPayload = DataStore.serverPassword authPayload = DataStore.serverPassword
@ -82,10 +82,6 @@ class HysteriaSettingsActivity : ProfileSettingsActivity<HysteriaBean>() {
setOnBindEditTextListener(EditTextPreferenceModifiers.Number) setOnBindEditTextListener(EditTextPreferenceModifiers.Number)
} }
findPreference<EditTextPreference>(Key.SERVER_PORT)!!.apply {
setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
}
findPreference<EditTextPreference>(Key.SERVER_PASSWORD)!!.apply { findPreference<EditTextPreference>(Key.SERVER_PASSWORD)!!.apply {
summaryProvider = PasswordSummaryProvider summaryProvider = PasswordSummaryProvider
} }

View File

@ -60,16 +60,12 @@ class TuicSettingsActivity : ProfileSettingsActivity<TuicBean>() {
uuid = DataStore.serverUsername uuid = DataStore.serverUsername
} }
private lateinit var editConfigPreference: EditConfigPreference
override fun PreferenceFragmentCompat.createPreferences( override fun PreferenceFragmentCompat.createPreferences(
savedInstanceState: Bundle?, savedInstanceState: Bundle?,
rootKey: String?, rootKey: String?,
) { ) {
addPreferencesFromResource(R.xml.tuic_preferences) addPreferencesFromResource(R.xml.tuic_preferences)
editConfigPreference = findPreference(Key.SERVER_CONFIG)!!
val uuid = findPreference<EditTextPreference>(Key.SERVER_USERNAME)!! val uuid = findPreference<EditTextPreference>(Key.SERVER_USERNAME)!!
val mtu = findPreference<EditTextPreference>(Key.SERVER_MTU)!! val mtu = findPreference<EditTextPreference>(Key.SERVER_MTU)!!
val fastConnect = findPreference<SwitchPreference>(Key.SERVER_FAST_CONNECT)!! val fastConnect = findPreference<SwitchPreference>(Key.SERVER_FAST_CONNECT)!!
@ -103,12 +99,4 @@ class TuicSettingsActivity : ProfileSettingsActivity<TuicBean>() {
} }
} }
override fun onResume() {
super.onResume()
if (::editConfigPreference.isInitialized) {
editConfigPreference.notifyChanged()
}
}
} }

View File

@ -432,6 +432,10 @@ public class SingBoxOptions {
public OutboundTLSOptions tls; public OutboundTLSOptions tls;
public String hop_ports;
public Integer hop_interval;
} }
@ -469,6 +473,8 @@ public class SingBoxOptions {
// Generate note: option type: public VLESSInboundOptions VLESSOptions; // Generate note: option type: public VLESSInboundOptions VLESSOptions;
// Generate note: option type: public TUICInboundOptions TUICOptions;
} }
public static class InboundOptions extends SingBoxOption { public static class InboundOptions extends SingBoxOption {
@ -637,6 +643,8 @@ public class SingBoxOptions {
// Generate note: option type: public VLESSOutboundOptions VLESSOptions; // Generate note: option type: public VLESSOutboundOptions VLESSOptions;
// Generate note: option type: public TUICOutboundOptions TUICOptions;
// Generate note: option type: public SelectorOutboundOptions SelectorOptions; // Generate note: option type: public SelectorOutboundOptions SelectorOptions;
// Generate note: option type: public URLTestOutboundOptions URLTestOptions; // Generate note: option type: public URLTestOutboundOptions URLTestOptions;
@ -1936,6 +1944,120 @@ public class SingBoxOptions {
} }
public static class TUICInboundOptions extends SingBoxOption {
// Generate note: nested type ListenOptions
public String listen;
public Integer listen_port;
public Boolean tcp_fast_open;
public Boolean udp_fragment;
// Generate note: option type: public Boolean UDPFragmentDefault;
public Long udp_timeout;
public Boolean proxy_protocol;
public Boolean proxy_protocol_accept_no_header;
public String detour;
// Generate note: nested type InboundOptions
public Boolean sniff;
public Boolean sniff_override_destination;
public Long sniff_timeout;
public String domain_strategy;
// End of public InboundOptions ;
// End of public ListenOptions ;
public List<TUICUser> users;
public String congestion_control;
public Long auth_timeout;
public Boolean zero_rtt_handshake;
public Long heartbeat;
public InboundTLSOptions tls;
}
public static class TUICUser extends SingBoxOption {
public String name;
public String uuid;
public String password;
}
public static class TUICOutboundOptions extends SingBoxOption {
// Generate note: nested type DialerOptions
public String detour;
public String bind_interface;
public String inet4_bind_address;
public String inet6_bind_address;
public String protect_path;
public Integer routing_mark;
public Boolean reuse_addr;
public Long connect_timeout;
public Boolean tcp_fast_open;
public Boolean udp_fragment;
// Generate note: option type: public Boolean UDPFragmentDefault;
public String domain_strategy;
public Long fallback_delay;
// End of public DialerOptions ;
// Generate note: nested type ServerOptions
public String server;
public Integer server_port;
// End of public ServerOptions ;
public String uuid;
public String password;
public String congestion_control;
public String udp_relay_mode;
public Boolean zero_rtt_handshake;
public Long heartbeat;
public String network;
public OutboundTLSOptions tls;
}
public static class TunInboundOptions extends SingBoxOption { public static class TunInboundOptions extends SingBoxOption {
public String interface_name; public String interface_name;
@ -3023,6 +3145,53 @@ public class SingBoxOptions {
} }
public static class Inbound_TUICOptions extends Inbound {
// Generate note: nested type ListenOptions
public String listen;
public Integer listen_port;
public Boolean tcp_fast_open;
public Boolean udp_fragment;
public Long udp_timeout;
public Boolean proxy_protocol;
public Boolean proxy_protocol_accept_no_header;
public String detour;
// Generate note: nested type InboundOptions
public Boolean sniff;
public Boolean sniff_override_destination;
public Long sniff_timeout;
public String domain_strategy;
// End of public InboundOptions ;
// End of public ListenOptions ;
public List<TUICUser> users;
public String congestion_control;
public Long auth_timeout;
public Boolean zero_rtt_handshake;
public Long heartbeat;
public InboundTLSOptions tls;
}
public static class Outbound_DirectOptions extends Outbound { public static class Outbound_DirectOptions extends Outbound {
// Generate note: nested type DialerOptions // Generate note: nested type DialerOptions
@ -3445,6 +3614,10 @@ public class SingBoxOptions {
public OutboundTLSOptions tls; public OutboundTLSOptions tls;
public String hop_ports;
public Integer hop_interval;
} }
public static class Outbound_TorOptions extends Outbound { public static class Outbound_TorOptions extends Outbound {
@ -3695,6 +3868,61 @@ public class SingBoxOptions {
} }
public static class Outbound_TUICOptions extends Outbound {
// Generate note: nested type DialerOptions
public String detour;
public String bind_interface;
public String inet4_bind_address;
public String inet6_bind_address;
public String protect_path;
public Integer routing_mark;
public Boolean reuse_addr;
public Long connect_timeout;
public Boolean tcp_fast_open;
public Boolean udp_fragment;
public String domain_strategy;
public Long fallback_delay;
// End of public DialerOptions ;
// Generate note: nested type ServerOptions
public String server;
public Integer server_port;
// End of public ServerOptions ;
public String uuid;
public String password;
public String congestion_control;
public String udp_relay_mode;
public Boolean zero_rtt_handshake;
public Long heartbeat;
public String network;
public OutboundTLSOptions tls;
}
public static class Outbound_SelectorOptions extends Outbound { public static class Outbound_SelectorOptions extends Outbound {
public List<String> outbounds; public List<String> outbounds;

View File

@ -15,7 +15,7 @@
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<EditTextPreference <EditTextPreference
app:icon="@drawable/ic_maps_directions_boat" app:icon="@drawable/ic_maps_directions_boat"
app:key="serverPort" app:key="serverPorts"
app:title="@string/server_port" app:title="@string/server_port"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<EditTextPreference <EditTextPreference

View File

@ -91,11 +91,6 @@
app:key="serverMTU" app:key="serverMTU"
app:title="@string/mtu" app:title="@string/mtu"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<moe.matsuri.nb4a.ui.EditConfigPreference
app:icon="@drawable/ic_baseline_layers_24"
app:key="serverConfig"
app:title="@string/custom_config"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>