@@ -103,6 +103,8 @@ class ConfigImporter @Inject constructor() {
103103 private const val MODE_NAIVE_SSH = " naive_ssh"
104104 private const val MODE_NAIVE = " naive"
105105 private const val MODE_SOCKS5 = " socks5"
106+ private const val MODE_VAYDNS = " vaydns"
107+ private const val MODE_VAYDNS_SSH = " vaydns_ssh"
106108 private const val FIELD_DELIMITER = " |"
107109 private const val RESOLVER_DELIMITER = " ,"
108110 private const val RESOLVER_PART_DELIMITER = " :"
@@ -252,12 +254,14 @@ class ConfigImporter @Inject constructor() {
252254 " 16" -> parseProfileV16(fields, lineNum)
253255 " 17" -> parseProfileV17(fields, lineNum)
254256 " 18" -> parseProfileV18(fields, lineNum)
257+ " 19" -> parseProfileV19(fields, lineNum)
258+ " 20" -> parseProfileV20(fields, lineNum)
255259 else -> {
256260 // Forward compatibility: try the highest known parser for newer versions.
257261 // Extra trailing fields are safely ignored (parsers only check minimum count).
258262 val versionNum = version.toIntOrNull()
259- if (versionNum != null && versionNum > 18 ) {
260- parseProfileV18 (fields, lineNum)
263+ if (versionNum != null && versionNum > 20 ) {
264+ parseProfileV20 (fields, lineNum)
261265 } else {
262266 ProfileParseResult .Error (" Line $lineNum : Unsupported version '$version '" )
263267 }
@@ -342,6 +346,8 @@ class ConfigImporter @Inject constructor() {
342346 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
343347 MODE_NAIVE -> TunnelType .NAIVE
344348 MODE_SOCKS5 -> TunnelType .SOCKS5
349+ MODE_VAYDNS -> TunnelType .VAYDNS
350+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
345351
346352 else -> {
347353 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -426,6 +432,8 @@ class ConfigImporter @Inject constructor() {
426432 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
427433 MODE_NAIVE -> TunnelType .NAIVE
428434 MODE_SOCKS5 -> TunnelType .SOCKS5
435+ MODE_VAYDNS -> TunnelType .VAYDNS
436+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
429437
430438 else -> {
431439 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -515,6 +523,8 @@ class ConfigImporter @Inject constructor() {
515523 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
516524 MODE_NAIVE -> TunnelType .NAIVE
517525 MODE_SOCKS5 -> TunnelType .SOCKS5
526+ MODE_VAYDNS -> TunnelType .VAYDNS
527+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
518528
519529 else -> {
520530 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -607,6 +617,8 @@ class ConfigImporter @Inject constructor() {
607617 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
608618 MODE_NAIVE -> TunnelType .NAIVE
609619 MODE_SOCKS5 -> TunnelType .SOCKS5
620+ MODE_VAYDNS -> TunnelType .VAYDNS
621+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
610622
611623 else -> {
612624 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -711,6 +723,8 @@ class ConfigImporter @Inject constructor() {
711723 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
712724 MODE_NAIVE -> TunnelType .NAIVE
713725 MODE_SOCKS5 -> TunnelType .SOCKS5
726+ MODE_VAYDNS -> TunnelType .VAYDNS
727+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
714728
715729 else -> {
716730 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -815,6 +829,8 @@ class ConfigImporter @Inject constructor() {
815829 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
816830 MODE_NAIVE -> TunnelType .NAIVE
817831 MODE_SOCKS5 -> TunnelType .SOCKS5
832+ MODE_VAYDNS -> TunnelType .VAYDNS
833+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
818834
819835 else -> {
820836 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -915,6 +931,8 @@ class ConfigImporter @Inject constructor() {
915931 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
916932 MODE_NAIVE -> TunnelType .NAIVE
917933 MODE_SOCKS5 -> TunnelType .SOCKS5
934+ MODE_VAYDNS -> TunnelType .VAYDNS
935+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
918936
919937 else -> {
920938 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -1026,6 +1044,8 @@ class ConfigImporter @Inject constructor() {
10261044 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
10271045 MODE_NAIVE -> TunnelType .NAIVE
10281046 MODE_SOCKS5 -> TunnelType .SOCKS5
1047+ MODE_VAYDNS -> TunnelType .VAYDNS
1048+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
10291049
10301050 else -> {
10311051 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -1158,6 +1178,8 @@ class ConfigImporter @Inject constructor() {
11581178 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
11591179 MODE_NAIVE -> TunnelType .NAIVE
11601180 MODE_SOCKS5 -> TunnelType .SOCKS5
1181+ MODE_VAYDNS -> TunnelType .VAYDNS
1182+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
11611183
11621184 else -> {
11631185 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -1292,6 +1314,8 @@ class ConfigImporter @Inject constructor() {
12921314 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
12931315 MODE_NAIVE -> TunnelType .NAIVE
12941316 MODE_SOCKS5 -> TunnelType .SOCKS5
1317+ MODE_VAYDNS -> TunnelType .VAYDNS
1318+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
12951319
12961320 else -> {
12971321 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -1433,6 +1457,8 @@ class ConfigImporter @Inject constructor() {
14331457 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
14341458 MODE_NAIVE -> TunnelType .NAIVE
14351459 MODE_SOCKS5 -> TunnelType .SOCKS5
1460+ MODE_VAYDNS -> TunnelType .VAYDNS
1461+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
14361462
14371463 else -> {
14381464 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -1575,6 +1601,8 @@ class ConfigImporter @Inject constructor() {
15751601 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
15761602 MODE_NAIVE -> TunnelType .NAIVE
15771603 MODE_SOCKS5 -> TunnelType .SOCKS5
1604+ MODE_VAYDNS -> TunnelType .VAYDNS
1605+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
15781606
15791607 else -> {
15801608 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -1734,6 +1762,8 @@ class ConfigImporter @Inject constructor() {
17341762 MODE_NAIVE_SSH -> TunnelType .NAIVE_SSH
17351763 MODE_NAIVE -> TunnelType .NAIVE
17361764 MODE_SOCKS5 -> TunnelType .SOCKS5
1765+ MODE_VAYDNS -> TunnelType .VAYDNS
1766+ MODE_VAYDNS_SSH -> TunnelType .VAYDNS_SSH
17371767
17381768 else -> {
17391769 return ProfileParseResult .Warning (" Line $lineNum : Unsupported tunnel type '$tunnelTypeStr ', skipping" )
@@ -1951,6 +1981,50 @@ class ConfigImporter @Inject constructor() {
19511981 return ProfileParseResult .Success (profile)
19521982 }
19531983
1984+ private fun parseProfileV19 (fields : List <String >, lineNum : Int ): ProfileParseResult {
1985+ // v19 extends v18 with 3 new VayDNS fields; fall back to v18 parser for the base fields
1986+ val baseResult = parseProfileV18(fields, lineNum)
1987+ if (baseResult !is ProfileParseResult .Success ) return baseResult
1988+
1989+ // Extract v19 fields (positions 41-43), defaulting if absent
1990+ val vaydnsDnsttCompat = if (fields.size > 41 ) fields[41 ] == " 1" else false
1991+ val vaydnsRecordType = if (fields.size > 42 ) fields[42 ].ifBlank { " txt" } else " txt"
1992+ val vaydnsMaxQnameLen = if (fields.size > 43 ) fields[43 ].toIntOrNull() ? : 101 else 101
1993+ val vaydnsRps = if (fields.size > 44 ) fields[44 ].toDoubleOrNull() ? : 0.0 else 0.0
1994+
1995+ val profile = baseResult.profile.copy(
1996+ vaydnsDnsttCompat = vaydnsDnsttCompat,
1997+ vaydnsRecordType = vaydnsRecordType,
1998+ vaydnsMaxQnameLen = vaydnsMaxQnameLen,
1999+ vaydnsRps = vaydnsRps
2000+ )
2001+
2002+ return ProfileParseResult .Success (profile)
2003+ }
2004+
2005+ private fun parseProfileV20 (fields : List <String >, lineNum : Int ): ProfileParseResult {
2006+ // v20 extends v19 with 5 new VayDNS advanced fields
2007+ val baseResult = parseProfileV19(fields, lineNum)
2008+ if (baseResult !is ProfileParseResult .Success ) return baseResult
2009+
2010+ // Extract v20 fields (positions 45-49), defaulting if absent
2011+ val vaydnsIdleTimeout = if (fields.size > 45 ) fields[45 ].toIntOrNull() ? : 0 else 0
2012+ val vaydnsKeepalive = if (fields.size > 46 ) fields[46 ].toIntOrNull() ? : 0 else 0
2013+ val vaydnsUdpTimeout = if (fields.size > 47 ) fields[47 ].toIntOrNull() ? : 0 else 0
2014+ val vaydnsMaxNumLabels = if (fields.size > 48 ) fields[48 ].toIntOrNull() ? : 0 else 0
2015+ val vaydnsClientIdSize = if (fields.size > 49 ) fields[49 ].toIntOrNull() ? : 0 else 0
2016+
2017+ val profile = baseResult.profile.copy(
2018+ vaydnsIdleTimeout = vaydnsIdleTimeout,
2019+ vaydnsKeepalive = vaydnsKeepalive,
2020+ vaydnsUdpTimeout = vaydnsUdpTimeout,
2021+ vaydnsMaxNumLabels = vaydnsMaxNumLabels,
2022+ vaydnsClientIdSize = vaydnsClientIdSize
2023+ )
2024+
2025+ return ProfileParseResult .Success (profile)
2026+ }
2027+
19542028 private fun parseResolvers (resolversStr : String ): List <DnsResolver > {
19552029 if (resolversStr.isBlank()) return emptyList()
19562030
0 commit comments