Skip to content

Commit 7a9b784

Browse files
committed
add kcp transport
1 parent 6735394 commit 7a9b784

9 files changed

Lines changed: 123 additions & 2 deletions

File tree

app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ public abstract class StandardV2RayBean extends AbstractBean {
5454
public String xhttpMode;
5555
public String xhttpExtra;
5656

57+
// --------------------------------------- kcp
58+
59+
public String mKcpSeed;
60+
public String headerType;
61+
5762
// --------------------------------------- ech
5863

5964
public Boolean enableECH;
@@ -120,11 +125,14 @@ public void initializeDefaultValues() {
120125

121126
if (JavaUtil.isNullOrBlank(xhttpMode)) xhttpMode = "auto";
122127
if (JavaUtil.isNullOrBlank(xhttpExtra)) xhttpExtra = "";
128+
129+
if (JavaUtil.isNullOrBlank(mKcpSeed)) mKcpSeed = "";
130+
if (JavaUtil.isNullOrBlank(headerType)) headerType = "none";
123131
}
124132

125133
@Override
126134
public void serialize(ByteBufferOutput output) {
127-
output.writeInt(5);
135+
output.writeInt(6);
128136
super.serialize(output);
129137
output.writeString(uuid);
130138
output.writeString(encryption);
@@ -167,6 +175,11 @@ public void serialize(ByteBufferOutput output) {
167175
output.writeString(xhttpExtra);
168176
break;
169177
}
178+
case "kcp": {
179+
output.writeString(mKcpSeed);
180+
output.writeString(headerType);
181+
break;
182+
}
170183
}
171184

172185
output.writeString(security);
@@ -245,6 +258,13 @@ public void deserialize(ByteBufferInput input) {
245258
}
246259
break;
247260
}
261+
case "kcp": {
262+
if (version >= 6) {
263+
mKcpSeed = input.readString();
264+
headerType = input.readString();
265+
}
266+
break;
267+
}
248268
}
249269

250270
security = input.readString();
@@ -298,6 +318,7 @@ public void deserialize(ByteBufferInput input) {
298318
}
299319

300320
// Note: xhttp fields are read in the switch case above when version >= 4
321+
// Note: kcp fields are read in the switch case above when version >= 6
301322
}
302323

303324
@Override

app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/V2RayFmt.kt

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import okhttp3.HttpUrl
1313
import okhttp3.HttpUrl.Companion.toHttpUrl
1414
import org.json.JSONObject
1515

16+
private val supportedKcpHeaderType = arrayOf(
17+
"none", "srtp", "utp", "wechat-video", "dtls", "wireguard"
18+
)
19+
1620
data class VmessQRCode(
1721
var v: String = "",
1822
var ps: String = "",
@@ -212,6 +216,16 @@ fun StandardV2RayBean.parseDuckSoft(url: HttpUrl) {
212216
}
213217
}
214218

219+
"kcp" -> {
220+
url.queryParameter("seed")?.let {
221+
mKcpSeed = it
222+
}
223+
url.queryParameter("headerType")?.let {
224+
if (it !in supportedKcpHeaderType) error("unsupported headerType")
225+
headerType = it
226+
}
227+
}
228+
215229
"ws" -> {
216230
url.queryParameter("host")?.let {
217231
host = it
@@ -511,6 +525,15 @@ fun StandardV2RayBean.toUriVMessVLESSTrojan(isTrojan: Boolean): String {
511525
}
512526
}
513527

528+
"kcp" -> {
529+
if (headerType.isNotBlank() && headerType != "none") {
530+
builder.addQueryParameter("headerType", headerType)
531+
}
532+
if (mKcpSeed.isNotBlank()) {
533+
builder.addQueryParameter("seed", mKcpSeed)
534+
}
535+
}
536+
514537
"xhttp" -> {
515538
if (host.isNotBlank()) {
516539
builder.addQueryParameter("host", host)
@@ -611,6 +634,23 @@ fun buildSingBoxOutboundStreamSettings(bean: StandardV2RayBean): V2RayTransportO
611634
}
612635
}
613636

637+
"kcp" -> {
638+
return V2RayTransportOptions_KCPOptions().apply {
639+
type = "kcp"
640+
mtu = 1350
641+
tti = 50
642+
uplink_capacity = 12
643+
downlink_capacity = 100
644+
congestion = false
645+
read_buffer_size = 1
646+
write_buffer_size = 1
647+
header_type = bean.headerType.takeIf { it.isNotBlank() } ?: "none"
648+
if (bean.mKcpSeed.isNotBlank()) {
649+
seed = bean.mKcpSeed
650+
}
651+
}
652+
}
653+
614654
"http" -> {
615655
return V2RayTransportOptions_HTTPOptions().apply {
616656
type = "http"

app/src/main/java/io/nekohasekai/sagernet/ui/profile/StandardV2RaySettingsActivity.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV
5656
private val xhttpExtra = pbm.add(PreferenceBinding(Type.Text, "xhttpExtra"))
5757
private val vlessEncryption = pbm.add(PreferenceBinding(Type.Text, "vlessEncryption"))
5858

59+
// KCP
60+
private val mKcpSeed = pbm.add(PreferenceBinding(Type.Text, "mKcpSeed"))
61+
private val headerType = pbm.add(PreferenceBinding(Type.Text, "headerType"))
62+
5963
override fun StandardV2RayBean.init() {
6064
if (this is TrojanBean) {
6165
this@StandardV2RaySettingsActivity.uuid.fieldName = "password"
@@ -156,6 +160,8 @@ abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV
156160
private fun updateView(network: String) {
157161
host.preference.isVisible = false
158162
path.preference.isVisible = false
163+
mKcpSeed.preference.isVisible = false
164+
headerType.preference.isVisible = false
159165
wsCategory.isVisible = false
160166
xhttpCategory.isVisible = false
161167

@@ -165,6 +171,11 @@ abstract class StandardV2RaySettingsActivity : ProfileSettingsActivity<StandardV
165171
path.preference.setTitle(R.string.http_path)
166172
}
167173

174+
"kcp" -> {
175+
mKcpSeed.preference.isVisible = true
176+
headerType.preference.isVisible = true
177+
}
178+
168179
"http" -> {
169180
host.preference.setTitle(R.string.http_host)
170181
path.preference.setTitle(R.string.http_path)

app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4669,6 +4669,28 @@ public static class V2RayTransportOptions_XHTTPOptions extends V2RayTransportOpt
46694669

46704670
}
46714671

4672+
public static class V2RayTransportOptions_KCPOptions extends V2RayTransportOptions {
4673+
4674+
public Integer mtu;
4675+
4676+
public Integer tti;
4677+
4678+
public Integer uplink_capacity;
4679+
4680+
public Integer downlink_capacity;
4681+
4682+
public Boolean congestion;
4683+
4684+
public Integer read_buffer_size;
4685+
4686+
public Integer write_buffer_size;
4687+
4688+
public String header_type;
4689+
4690+
public String seed;
4691+
4692+
}
4693+
46724694
// sing-box Options 生成器已经坏了,以下是从 husi 抄的
46734695

46744696
public static class Outbound_AnyTLSOptions extends Outbound {

app/src/main/res/values-zh-rCN/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@
186186
<string name="ws_path">WebSocket 路径</string>
187187
<string name="http_host">HTTP 主机</string>
188188
<string name="http_path">HTTP 路径</string>
189+
<string name="kcp_header_type">伪装头类型</string>
189190
<string name="show_bottom_bar">像 SagerNet 一样显示底栏</string>
190191
<string name="utls_fingerprint">uTLS 指纹</string>
191192
<string name="grpc_service_name">gRPC 服务名称</string>

app/src/main/res/values/arrays.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@
317317

318318
<string-array name="networks_value">
319319
<item>tcp</item>
320+
<item>kcp</item>
320321
<item>ws</item>
321322
<item>http</item>
322323
<item>quic</item>
@@ -325,6 +326,15 @@
325326
<item>xhttp</item>
326327
</string-array>
327328

329+
<string-array name="kcp_headers_value">
330+
<item>none</item>
331+
<item>srtp</item>
332+
<item>utp</item>
333+
<item>wechat-video</item>
334+
<item>dtls</item>
335+
<item>wireguard</item>
336+
</string-array>
337+
328338
<string-array name="xhttp_mode_entry">
329339
<item>auto</item>
330340
<item>packet-up</item>

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@
124124
<string name="ws_path">WebSocket Path</string>
125125
<string name="http_host">HTTP Host</string>
126126
<string name="http_path">HTTP Path</string>
127+
<string name="kcp_seed">mKCP Seed</string>
128+
<string name="kcp_header_type">Header Type</string>
127129
<string name="grpc_service_name">gRPC ServiceName</string>
128130
<string name="tls">Use TLS</string>
129131
<string name="sni">Server Name Indication</string>

app/src/main/res/xml/standard_v2ray_preferences.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@
7575
app:key="path"
7676
app:title="@string/http_path"
7777
app:useSimpleSummaryProvider="true" />
78+
<moe.matsuri.nb4a.ui.SimpleMenuPreference
79+
app:defaultValue="none"
80+
app:entries="@array/kcp_headers_value"
81+
app:entryValues="@array/kcp_headers_value"
82+
app:icon="@drawable/ic_baseline_texture_24"
83+
app:key="headerType"
84+
app:title="@string/kcp_header_type"
85+
app:useSimpleSummaryProvider="true" />
86+
<EditTextPreference
87+
app:dialogLayout="@layout/layout_password_dialog"
88+
app:icon="@drawable/ic_baseline_format_align_left_24"
89+
app:key="mKcpSeed"
90+
app:title="@string/kcp_seed"
91+
app:useSimpleSummaryProvider="true" />
7892
<moe.matsuri.nb4a.ui.SimpleMenuPreference
7993
app:entries="@array/transport_layer_encryption_value"
8094
app:entryValues="@array/transport_layer_encryption_value"
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export COMMIT_SING_BOX="de2e9954cf52623731dd6f791dd7085a096e10af"
1+
export COMMIT_SING_BOX="4cb4e8951886fa7f9c2b403e2b3e8afc5db52017"
22
export COMMIT_LIBNEKO="6a85c185d62435a5293ef70ac3b638ae3ee1efa7"

0 commit comments

Comments
 (0)