From 2e915f8484ed3a8f31dce050c1a1e1d71048bcbd Mon Sep 17 00:00:00 2001 From: Mark Puha Date: Thu, 3 Jul 2025 16:54:49 +0200 Subject: [PATCH] feat: s3, s4 --- .../vpn/protocol/wireguard/Wireguard.kt | 2 + .../vpn/protocol/wireguard/WireguardConfig.kt | 52 ++++++++++++++++++- client/daemon/daemon.cpp | 27 ++++++---- client/daemon/interfaceconfig.cpp | 6 +++ client/daemon/interfaceconfig.h | 2 + client/platforms/ios/WGConfig.swift | 6 ++- .../linux/daemon/wireguardutilslinux.cpp | 6 +++ .../macos/daemon/wireguardutilsmacos.cpp | 6 +++ client/protocols/protocols_defs.h | 5 ++ .../server_scripts/awg/configure_container.sh | 2 + client/server_scripts/awg/template.conf | 2 + client/ui/models/protocols/awgConfigModel.cpp | 9 ++++ client/ui/models/protocols/awgConfigModel.h | 8 ++- .../ui/qml/Pages2/PageProtocolAwgSettings.qml | 50 ++++++++++++++++++ 14 files changed, 168 insertions(+), 15 deletions(-) diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt index bf3a525c..634bc5cd 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt @@ -120,6 +120,8 @@ open class Wireguard : Protocol() { configData.optStringOrNull("Jmax")?.let { setJmax(it.toInt()) } configData.optStringOrNull("S1")?.let { setS1(it.toInt()) } configData.optStringOrNull("S2")?.let { setS2(it.toInt()) } + configData.optStringOrNull("S3")?.let { setS3(it.toInt()) } + configData.optStringOrNull("S4")?.let { setS4(it.toInt()) } configData.optStringOrNull("H1")?.let { setH1(it.toLong()) } configData.optStringOrNull("H2")?.let { setH2(it.toLong()) } configData.optStringOrNull("H3")?.let { setH3(it.toLong()) } diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt index 65dfb34e..3e4c7060 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/WireguardConfig.kt @@ -20,10 +20,21 @@ open class WireguardConfig protected constructor( val jmax: Int?, val s1: Int?, val s2: Int?, + val s3: Int?, + val s4: Int?, val h1: Long?, val h2: Long?, val h3: Long?, - val h4: Long? + val h4: Long?, + var i1: String?, + var i2: String?, + var i3: String?, + var i4: String?, + var i5: String?, + var j1: String?, + var j2: String?, + var j3: String?, + var itime: Int? ) : ProtocolConfig(protocolConfigBuilder) { protected constructor(builder: Builder) : this( @@ -39,10 +50,21 @@ open class WireguardConfig protected constructor( builder.jmax, builder.s1, builder.s2, + builder.s3, + builder.s4, builder.h1, builder.h2, builder.h3, - builder.h4 + builder.h4, + builder.i1, + builder.i2, + builder.i3, + builder.i4, + builder.i5, + builder.j1, + builder.j2, + builder.j3, + builder.itime ) fun toWgUserspaceString(): String = with(StringBuilder()) { @@ -61,10 +83,21 @@ open class WireguardConfig protected constructor( appendLine("jmax=$jmax") appendLine("s1=$s1") appendLine("s2=$s2") + appendLine("s3=$s3") + appendLine("s4=$s4") appendLine("h1=$h1") appendLine("h2=$h2") appendLine("h3=$h3") appendLine("h4=$h4") + appendLine("i1=$i1") + appendLine("i2=$i2") + appendLine("i3=$i3") + appendLine("i4=$i4") + appendLine("i5=$i5") + appendLine("j1=$j1") + appendLine("j2=$j2") + appendLine("j3=$j3") + appendLine("itime=$itime") } } @@ -74,10 +107,21 @@ open class WireguardConfig protected constructor( if (jmax == null) throw BadConfigException("Parameter jmax is undefined") if (s1 == null) throw BadConfigException("Parameter s1 is undefined") if (s2 == null) throw BadConfigException("Parameter s2 is undefined") + if (s3 == null) throw BadConfigException("Parameter s3 is undefined") + if (s4 == null) throw BadConfigException("Parameter s4 is undefined") if (h1 == null) throw BadConfigException("Parameter h1 is undefined") if (h2 == null) throw BadConfigException("Parameter h2 is undefined") if (h3 == null) throw BadConfigException("Parameter h3 is undefined") if (h4 == null) throw BadConfigException("Parameter h4 is undefined") + if (i1 == null) throw BadConfigException("Parameter i1 is undefined") + if (i2 == null) throw BadConfigException("Parameter i2 is undefined") + if (i3 == null) throw BadConfigException("Parameter i3 is undefined") + if (i4 == null) throw BadConfigException("Parameter i4 is undefined") + if (i5 == null) throw BadConfigException("Parameter i5 is undefined") + if (j1 == null) throw BadConfigException("Parameter j1 is undefined") + if (j2 == null) throw BadConfigException("Parameter j2 is undefined") + if (j3 == null) throw BadConfigException("Parameter j3 is undefined") + if (itime == null) throw BadConfigException("Parameter itime is undefined") } open fun appendPeerLine(sb: StringBuilder) = with(sb) { @@ -117,6 +161,8 @@ open class WireguardConfig protected constructor( internal var jmax: Int? = null internal var s1: Int? = null internal var s2: Int? = null + internal var s3: Int? = null + internal var s4: Int? = null internal var h1: Long? = null internal var h2: Long? = null internal var h3: Long? = null @@ -148,6 +194,8 @@ open class WireguardConfig protected constructor( fun setJmax(jmax: Int) = apply { this.jmax = jmax } fun setS1(s1: Int) = apply { this.s1 = s1 } fun setS2(s2: Int) = apply { this.s2 = s2 } + fun setS1(s3: Int) = apply { this.s3 = s3 } + fun setS2(s4: Int) = apply { this.s4 = s4 } fun setH1(h1: Long) = apply { this.h1 = h1 } fun setH2(h2: Long) = apply { this.h2 = h2 } fun setH3(h3: Long) = apply { this.h3 = h3 } diff --git a/client/daemon/daemon.cpp b/client/daemon/daemon.cpp index 390cf641..2a54af08 100644 --- a/client/daemon/daemon.cpp +++ b/client/daemon/daemon.cpp @@ -391,6 +391,13 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) { if (!obj.value("S2").isNull()) { config.m_responsePacketJunkSize = obj.value("S2").toString(); } + if (!obj.value("S3").isNull()) { + config.m_cookieReplyPacketJunkSize = obj.value("S3").toString(); + } + if (!obj.value("S4").isNull()) { + config.m_transportPacketJunkSize = obj.value("S4").toString(); + } + if (!obj.value("H1").isNull()) { config.m_initPacketMagicHeader = obj.value("H1").toString(); } @@ -405,31 +412,31 @@ bool Daemon::parseConfig(const QJsonObject& obj, InterfaceConfig& config) { } if (!obj.value("I1").isNull()) { - config.m_specialJunk["I1"] = obj.value("I1").toString(); + config.m_specialJunk["I1"] = obj.value("I1").toString(); } if (!obj.value("I2").isNull()) { - config.m_specialJunk["I2"] = obj.value("I2").toString(); + config.m_specialJunk["I2"] = obj.value("I2").toString(); } if (!obj.value("I3").isNull()) { - config.m_specialJunk["I3"] = obj.value("I3").toString(); + config.m_specialJunk["I3"] = obj.value("I3").toString(); } if (!obj.value("I4").isNull()) { - config.m_specialJunk["I4"] = obj.value("I4").toString(); + config.m_specialJunk["I4"] = obj.value("I4").toString(); } if (!obj.value("I5").isNull()) { - config.m_specialJunk["I5"] = obj.value("I5").toString(); + config.m_specialJunk["I5"] = obj.value("I5").toString(); } if (!obj.value("J1").isNull()) { - config.m_controlledJunk["J1"] = obj.value("J1").toString(); + config.m_controlledJunk["J1"] = obj.value("J1").toString(); } if (!obj.value("J2").isNull()) { - config.m_controlledJunk["J2"] = obj.value("J2").toString(); + config.m_controlledJunk["J2"] = obj.value("J2").toString(); } if (!obj.value("J3").isNull()) { - config.m_controlledJunk["J3"] = obj.value("J3").toString(); + config.m_controlledJunk["J3"] = obj.value("J3").toString(); } if (!obj.value("Itime").isNull()) { - config.m_specialHandshakeTimeout = obj.value("Itime").toString(); + config.m_specialHandshakeTimeout = obj.value("Itime").toString(); } return true; @@ -474,7 +481,7 @@ bool Daemon::deactivate(bool emitSignals) { m_connections.clear(); // Delete the interface - return wgutils()->deleteInterface(); + return wgutils()->deleteInterface(); } QString Daemon::logs() { diff --git a/client/daemon/interfaceconfig.cpp b/client/daemon/interfaceconfig.cpp index c02d19f9..c062227b 100644 --- a/client/daemon/interfaceconfig.cpp +++ b/client/daemon/interfaceconfig.cpp @@ -125,6 +125,12 @@ QString InterfaceConfig::toWgConf(const QMap& extra) const { if (!m_responsePacketJunkSize.isNull()) { out << "S2 = " << m_responsePacketJunkSize << "\n"; } + if (!m_cookieReplyPacketJunkSize.isNull()) { + out << "S3 = " << m_cookieReplyPacketJunkSize << "\n"; + } + if (!m_transportPacketJunkSize.isNull()) { + out << "S4 = " << m_transportPacketJunkSize << "\n"; + } if (!m_initPacketMagicHeader.isNull()) { out << "H1 = " << m_initPacketMagicHeader << "\n"; } diff --git a/client/daemon/interfaceconfig.h b/client/daemon/interfaceconfig.h index 1cb432a0..e47f910a 100644 --- a/client/daemon/interfaceconfig.h +++ b/client/daemon/interfaceconfig.h @@ -49,6 +49,8 @@ class InterfaceConfig { QString m_junkPacketMaxSize; QString m_initPacketJunkSize; QString m_responsePacketJunkSize; + QString m_cookieReplyPacketJunkSize; + QString m_transportPacketJunkSize; QString m_initPacketMagicHeader; QString m_responsePacketMagicHeader; QString m_underloadPacketMagicHeader; diff --git a/client/platforms/ios/WGConfig.swift b/client/platforms/ios/WGConfig.swift index 0146950d..8f693387 100644 --- a/client/platforms/ios/WGConfig.swift +++ b/client/platforms/ios/WGConfig.swift @@ -4,7 +4,7 @@ struct WGConfig: Decodable { let initPacketMagicHeader, responsePacketMagicHeader: String? let underloadPacketMagicHeader, transportPacketMagicHeader: String? let junkPacketCount, junkPacketMinSize, junkPacketMaxSize: String? - let initPacketJunkSize, responsePacketJunkSize: String? + let initPacketJunkSize, responsePacketJunkSize, cookieReplyPacketJunkSize, transportPacketJunkSize: String? let specialJunk1, specialJunk2, specialJunk3, specialJunk4, specialJunk5: String? let controlledJunk1, controlledJunk2, controlledJunk3: String? let specialHandshakeTimeout: String? @@ -26,7 +26,7 @@ struct WGConfig: Decodable { case initPacketMagicHeader = "H1", responsePacketMagicHeader = "H2" case underloadPacketMagicHeader = "H3", transportPacketMagicHeader = "H4" case junkPacketCount = "Jc", junkPacketMinSize = "Jmin", junkPacketMaxSize = "Jmax" - case initPacketJunkSize = "S1", responsePacketJunkSize = "S2" + case initPacketJunkSize = "S1", responsePacketJunkSize = "S2", cookieReplyPacketJunkSize = "S3", transportPacketJunkSize = "S4" case specialJunk1 = "I1", specialJunk2 = "I2", specialJunk3 = "I3", specialJunk4 = "I4", specialJunk5 = "I5" case controlledJunk1 = "J1", controlledJunk2 = "J2", controlledJunk3 = "J3" case specialHandshakeTimeout = "Itime" @@ -53,6 +53,8 @@ struct WGConfig: Decodable { Jmax = \(junkPacketMaxSize!) S1 = \(initPacketJunkSize!) S2 = \(responsePacketJunkSize!) + S3 = \(cookieReplyPacketJunkSize!) + S4 = \(transportPacketJunkSize!) H1 = \(initPacketMagicHeader!) H2 = \(responsePacketMagicHeader!) H3 = \(underloadPacketMagicHeader!) diff --git a/client/platforms/linux/daemon/wireguardutilslinux.cpp b/client/platforms/linux/daemon/wireguardutilslinux.cpp index 58227581..ea0300a8 100644 --- a/client/platforms/linux/daemon/wireguardutilslinux.cpp +++ b/client/platforms/linux/daemon/wireguardutilslinux.cpp @@ -121,6 +121,12 @@ bool WireguardUtilsLinux::addInterface(const InterfaceConfig& config) { if (!config.m_responsePacketJunkSize.isEmpty()) { out << "s2=" << config.m_responsePacketJunkSize << "\n"; } + if (!config.m_cookieReplyPacketJunkSize.isEmpty()) { + out << "s3=" << config.m_cookieReplyPacketJunkSize << "\n"; + } + if (!config.m_transportPacketJunkSize.isEmpty()) { + out << "s4=" << config.m_transportPacketJunkSize << "\n"; + } if (!config.m_initPacketMagicHeader.isEmpty()) { out << "h1=" << config.m_initPacketMagicHeader << "\n"; } diff --git a/client/platforms/macos/daemon/wireguardutilsmacos.cpp b/client/platforms/macos/daemon/wireguardutilsmacos.cpp index 1d8aa6e0..bbd7e902 100644 --- a/client/platforms/macos/daemon/wireguardutilsmacos.cpp +++ b/client/platforms/macos/daemon/wireguardutilsmacos.cpp @@ -119,6 +119,12 @@ bool WireguardUtilsMacos::addInterface(const InterfaceConfig& config) { if (!config.m_responsePacketJunkSize.isEmpty()) { out << "s2=" << config.m_responsePacketJunkSize << "\n"; } + if (!config.m_cookieReplyPacketJunkSize.isEmpty()) { + out << "s3=" << config.m_cookieReplyPacketJunkSize << "\n"; + } + if (!config.m_transportPacketJunkSize.isEmpty()) { + out << "s4=" << config.m_transportPacketJunkSize << "\n"; + } if (!config.m_initPacketMagicHeader.isEmpty()) { out << "h1=" << config.m_initPacketMagicHeader << "\n"; } diff --git a/client/protocols/protocols_defs.h b/client/protocols/protocols_defs.h index e29201cb..25cdefda 100644 --- a/client/protocols/protocols_defs.h +++ b/client/protocols/protocols_defs.h @@ -72,6 +72,8 @@ namespace amnezia constexpr char junkPacketMaxSize[] = "Jmax"; constexpr char initPacketJunkSize[] = "S1"; constexpr char responsePacketJunkSize[] = "S2"; + constexpr char cookieReplyPacketJunkSize[] = "S3"; + constexpr char transportPacketJunkSize[] = "S4"; constexpr char initPacketMagicHeader[] = "H1"; constexpr char responsePacketMagicHeader[] = "H2"; constexpr char underloadPacketMagicHeader[] = "H3"; @@ -223,6 +225,9 @@ namespace amnezia constexpr char defaultJunkPacketMaxSize[] = "30"; constexpr char defaultInitPacketJunkSize[] = "15"; constexpr char defaultResponsePacketJunkSize[] = "18"; + constexpr char defaultCookieReplyPacketJunkSize[] = "20"; + constexpr char defaultTransportPacketJunkSize[] = "23"; + constexpr char defaultInitPacketMagicHeader[] = "1020325451"; constexpr char defaultResponsePacketMagicHeader[] = "3288052141"; constexpr char defaultTransportPacketMagicHeader[] = "2528465083"; diff --git a/client/server_scripts/awg/configure_container.sh b/client/server_scripts/awg/configure_container.sh index e327f080..a69fd1ff 100644 --- a/client/server_scripts/awg/configure_container.sh +++ b/client/server_scripts/awg/configure_container.sh @@ -19,6 +19,8 @@ Jmin = $JUNK_PACKET_MIN_SIZE Jmax = $JUNK_PACKET_MAX_SIZE S1 = $INIT_PACKET_JUNK_SIZE S2 = $RESPONSE_PACKET_JUNK_SIZE +S3 = $UNDERLOAD_PACKET_JUNK_SIZE +S4 = $TRANSPORT_PACKET_JUNK_SIZE H1 = $INIT_PACKET_MAGIC_HEADER H2 = $RESPONSE_PACKET_MAGIC_HEADER H3 = $UNDERLOAD_PACKET_MAGIC_HEADER diff --git a/client/server_scripts/awg/template.conf b/client/server_scripts/awg/template.conf index 79932806..33ec9abd 100644 --- a/client/server_scripts/awg/template.conf +++ b/client/server_scripts/awg/template.conf @@ -7,6 +7,8 @@ Jmin = $JUNK_PACKET_MIN_SIZE Jmax = $JUNK_PACKET_MAX_SIZE S1 = $INIT_PACKET_JUNK_SIZE S2 = $RESPONSE_PACKET_JUNK_SIZE +S3 = $UNDERLOAD_PACKET_JUNK_SIZE +S4 = $TRANSPORT_PACKET_JUNK_SIZE H1 = $INIT_PACKET_MAGIC_HEADER H2 = $RESPONSE_PACKET_MAGIC_HEADER H3 = $UNDERLOAD_PACKET_MAGIC_HEADER diff --git a/client/ui/models/protocols/awgConfigModel.cpp b/client/ui/models/protocols/awgConfigModel.cpp index a05aa64f..108e74e8 100644 --- a/client/ui/models/protocols/awgConfigModel.cpp +++ b/client/ui/models/protocols/awgConfigModel.cpp @@ -289,6 +289,9 @@ QHash AwgConfigModel::roleNames() const roles[ServerJunkPacketMaxSizeRole] = "serverJunkPacketMaxSize"; roles[ServerInitPacketJunkSizeRole] = "serverInitPacketJunkSize"; roles[ServerResponsePacketJunkSizeRole] = "serverResponsePacketJunkSize"; + roles[ServerCookieReplyPacketJunkSizeRole] = "serverCookieReplyPacketJunkSize"; + roles[ServerTransportPacketJunkSizeRole] = "serverTransportPacketJunkSize"; + roles[ServerInitPacketMagicHeaderRole] = "serverInitPacketMagicHeader"; roles[ServerResponsePacketMagicHeaderRole] = "serverResponsePacketMagicHeader"; roles[ServerUnderloadPacketMagicHeaderRole] = "serverUnderloadPacketMagicHeader"; @@ -340,6 +343,10 @@ AwgConfig::AwgConfig(const QJsonObject &serverProtocolConfig) serverProtocolConfig.value(config_key::initPacketJunkSize).toString(protocols::awg::defaultInitPacketJunkSize); serverResponsePacketJunkSize = serverProtocolConfig.value(config_key::responsePacketJunkSize) .toString(protocols::awg::defaultResponsePacketJunkSize); + serverCookieReplyPacketJunkSize = serverProtocolConfig.value(config_key::responsePacketJunkSize) + .toString(protocols::awg::defaultCookieReplyPacketJunkSize); + serverTransportPacketJunkSize = serverProtocolConfig.value(config_key::responsePacketJunkSize) + .toString(protocols::awg::defaultTransportPacketJunkSize); serverInitPacketMagicHeader = serverProtocolConfig.value(config_key::initPacketMagicHeader) .toString(protocols::awg::defaultInitPacketMagicHeader); serverResponsePacketMagicHeader = serverProtocolConfig.value(config_key::responsePacketMagicHeader) @@ -357,6 +364,8 @@ bool AwgConfig::hasEqualServerSettings(const AwgConfig &other) const || serverJunkPacketMaxSize != other.serverJunkPacketMaxSize || serverInitPacketJunkSize != other.serverInitPacketJunkSize || serverResponsePacketJunkSize != other.serverResponsePacketJunkSize + || serverCookieReplyPacketJunkSize != other.serverCookieReplyPacketJunkSize + || serverTransportPacketJunkSize != other.serverTransportPacketJunkSize || serverInitPacketMagicHeader != other.serverInitPacketMagicHeader || serverResponsePacketMagicHeader != other.serverResponsePacketMagicHeader || serverUnderloadPacketMagicHeader != other.serverUnderloadPacketMagicHeader diff --git a/client/ui/models/protocols/awgConfigModel.h b/client/ui/models/protocols/awgConfigModel.h index e1f38f71..9dd4a822 100644 --- a/client/ui/models/protocols/awgConfigModel.h +++ b/client/ui/models/protocols/awgConfigModel.h @@ -6,7 +6,8 @@ #include "containers/containers_defs.h" -namespace AwgConstant { +namespace AwgConstant +{ const int messageInitiationSize = 148; const int messageResponseSize = 92; } @@ -37,6 +38,8 @@ struct AwgConfig QString serverJunkPacketMaxSize; QString serverInitPacketJunkSize; QString serverResponsePacketJunkSize; + QString serverCookieReplyPacketJunkSize; + QString serverTransportPacketJunkSize; QString serverInitPacketMagicHeader; QString serverResponsePacketMagicHeader; QString serverUnderloadPacketMagicHeader; @@ -74,6 +77,9 @@ public: ServerJunkPacketMaxSizeRole, ServerInitPacketJunkSizeRole, ServerResponsePacketJunkSizeRole, + ServerCookieReplyPacketJunkSizeRole, + ServerTransportPacketJunkSizeRole, + ServerInitPacketMagicHeaderRole, ServerResponsePacketMagicHeaderRole, ServerUnderloadPacketMagicHeaderRole, diff --git a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml index 906e7ceb..6c3fda94 100644 --- a/client/ui/qml/Pages2/PageProtocolAwgSettings.qml +++ b/client/ui/qml/Pages2/PageProtocolAwgSettings.qml @@ -244,6 +244,54 @@ PageType { } } + TextFieldWithHeaderType { + id: cookieReplyPacketJunkSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + headerText: qsTr("S3 - Cookie reply packet junk size") + textField.text: serverCookieReplyPacketJunkSize + textField.validator: IntValidator { bottom: 0 } + + textField.onEditingFinished: { + if (textField.text !== serverCookieReplyPacketJunkSize) { + serverCookieReplyPacketJunkSize = textField.text + } + } + + checkEmptyText: true + + onActiveFocusChanged: { + if(activeFocus) { + listview.positionViewAtEnd() + } + } + } + + TextFieldWithHeaderType { + id: transportPacketJunkSizeTextField + Layout.fillWidth: true + Layout.topMargin: 16 + + headerText: qsTr("S4 - Transport packet junk size") + textField.text: serverTransportPacketJunkSize + textField.validator: IntValidator { bottom: 0 } + + textField.onEditingFinished: { + if (textField.text !== serverTransportPacketJunkSize) { + serverTransportPacketJunkSize = textField.text + } + } + + checkEmptyText: true + + onActiveFocusChanged: { + if(activeFocus) { + listview.positionViewAtEnd() + } + } + } + TextFieldWithHeaderType { id: initPacketMagicHeaderTextField Layout.fillWidth: true @@ -329,6 +377,8 @@ PageType { responsePacketMagicHeaderTextField.errorText === "" && initPacketMagicHeaderTextField.errorText === "" && responsePacketJunkSizeTextField.errorText === "" && + cookieReplyHeaderJunkTextField.errorText === "" && + transportHeaderJunkTextField.errorText === "" && initPacketJunkSizeTextField.errorText === "" && junkPacketMaxSizeTextField.errorText === "" && junkPacketMinSizeTextField.errorText === "" &&