This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new a706c662ef [FIX] EhloCommandHandler should handle domain label
starting by numbers (#3006)
a706c662ef is described below
commit a706c662ef465fd042d43ad806e8c7664a94a1d8
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon Apr 13 07:27:52 2026 +0200
[FIX] EhloCommandHandler should handle domain label starting by numbers
(#3006)
---
.../protocols/smtp/core/esmtp/EhloCmdHandler.java | 34 +++++++++-
.../smtp/core/esmtp/EhloCmdHandlerTest.java | 74 ++++++++++++++++++++++
2 files changed, 106 insertions(+), 2 deletions(-)
diff --git
a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java
b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java
index dfe322b447..8dca4f313f 100644
---
a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java
+++
b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandler.java
@@ -40,6 +40,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -63,6 +64,10 @@ public class EhloCmdHandler extends
AbstractHookableCmdHandler<HeloHook> impleme
private static final CharMatcher ALPHANUMERIC_MATCHER =
CharMatcher.inRange('a', 'z')
.or(CharMatcher.inRange('A', 'Z'))
.or(CharMatcher.inRange('0', '9'));
+ private static final CharMatcher LABEL_CHAR_MATCHER =
ALPHANUMERIC_MATCHER.or(CharMatcher.is('-'));
+ private static final Splitter LABEL_SPLITTER = Splitter.on('.');
+ private static final int MAX_HOSTNAME_LENGTH = 253;
+ private static final int MAX_LABEL_LENGTH = 63;
private List<EhloExtension> ehloExtensions;
@@ -102,16 +107,41 @@ public class EhloCmdHandler extends
AbstractHookableCmdHandler<HeloHook> impleme
return resp;
}
- private boolean isValid(String argument) {
+ boolean isValid(String argument) {
String hostname = unquote(argument);
// Without [] Guava attempt to parse IPV4
return InetAddresses.isUriInetAddress(hostname)
// Guava tries parsing IPv6 if and only if wrapped by []
|| InetAddresses.isUriInetAddress("[" +
removeEmIPV6Prefix(hostname) + "]")
+ // Guava's InternetDomainName requires labels to start with a
letter (RFC 1034),
+ // but RFC 1123 / RFC 5321 allow labels to start with a digit
(e.g. "2s1n").
+ // We keep Guava as a fast path and fall back to our own RFC 5321
validator.
|| InternetDomainName.isValid(hostname)
|| emClientCompatibility(hostname)
- || isAlphanumeric(hostname);
+ || isAlphanumeric(hostname)
+ || isRfc5321Hostname(hostname);
+ }
+
+ // RFC 5321 §4.1.2 / RFC 1123 §2.1: labels may start with a letter or
digit,
+ // contain letters/digits/hyphens, and must not start or end with a hyphen.
+ // Validated character-by-character to avoid any regex backtracking
(ReDoS).
+ private boolean isRfc5321Hostname(String hostname) {
+ if (hostname.isEmpty() || hostname.length() > MAX_HOSTNAME_LENGTH) {
+ return false;
+ }
+ return LABEL_SPLITTER.splitToStream(hostname)
+ .allMatch(this::isValidRfc1123Label);
+ }
+
+ private boolean isValidRfc1123Label(String label) {
+ if (label.isEmpty() || label.length() > MAX_LABEL_LENGTH) {
+ return false;
+ }
+ if (label.charAt(0) == '-' || label.charAt(label.length() - 1) == '-')
{
+ return false;
+ }
+ return LABEL_CHAR_MATCHER.matchesAllOf(label);
}
// CF JAMES-4046
https://issues.apache.org/jira/projects/JAMES/issues/JAMES-4066
diff --git
a/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandlerTest.java
b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandlerTest.java
new file mode 100644
index 0000000000..11752db707
--- /dev/null
+++
b/protocols/smtp/src/test/java/org/apache/james/protocols/smtp/core/esmtp/EhloCmdHandlerTest.java
@@ -0,0 +1,74 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.protocols.smtp.core.esmtp;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+class EhloCmdHandlerTest {
+
+ private final EhloCmdHandler handler = new EhloCmdHandler(new
RecordingMetricFactory());
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ // Standard domain names
+ "example.com",
+ "mail.example.com",
+ "sub.domain.example.org",
+ // RFC 1123: labels may start with a digit
+ "mx-ll-110-164-x-x.2s1n",
+ "1mail.example.com",
+ "123.example.com",
+ // Pure alphanumeric (single label, no dot)
+ "localhost",
+ "mailserver",
+ // IPv4
+ "192.168.1.1",
+ "10.0.0.1",
+ // IPv6 with brackets
+ "[::1]",
+ "[2001:db8::1]",
+ })
+ void isValidShouldAccept(String argument) {
+ assertThat(handler.isValid(argument)).isTrue();
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {
+ // Empty or blank
+ "",
+ // Labels starting or ending with hyphen
+ "-example.com",
+ "example-.com",
+ "example.-com",
+ "example.com-",
+ // Empty label (double dot)
+ "example..com",
+ // Invalid characters
+ "exam ple.com",
+ "example.com!",
+ })
+ void isValidShouldReject(String argument) {
+ assertThat(handler.isValid(argument)).isFalse();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]