From 7e0004d9fc6b5d61818fef88e322e52ab46fd003 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Tue, 7 Oct 2025 09:43:01 -0400 Subject: [PATCH 01/40] First commit --- arc/pom.xml | 87 ++++ .../apache/james/arc/ARCChainValidator.java | 164 +++++++ .../java/org/apache/james/arc/ARCCommon.java | 141 ++++++ .../java/org/apache/james/arc/ARCSigner.java | 176 ++++++++ .../org/apache/james/arc/ARCVerifier.java | 402 ++++++++++++++++++ .../apache/james/arc/ArcSealVerifyData.java | 38 ++ .../org/apache/james/arc/ArcSetBuilder.java | 167 ++++++++ .../james/arc/ArcSignatureRecordImpl.java | 200 +++++++++ .../apache/james/arc/AuthResultsBuilder.java | 240 +++++++++++ .../arc/DNSPublicKeyRecordRetrieverArc.java | 66 +++ .../james/arc/PublicKeyRetrieverArc.java | 10 + .../james/arc/exceptions/ArcException.java | 29 ++ .../java/org/apache/james/arc/ARCTest.java | 137 ++++++ .../org/apache/james/arc/ArcTestKeys.java | 80 ++++ .../arc/MockPublicKeyRecordRetrieverArc.java | 70 +++ .../test/resources/keys/arc_test_pri.1.key | 16 + .../test/resources/keys/arc_test_pub.1.pem | 6 + .../test/resources/keys/dkim_test_pri.1.key | 16 + .../test/resources/keys/dkim_test_pub.1.pem | 6 + .../test/resources/mail/rfc8617_no_arc.eml | 31 ++ pom.xml | 1 + 21 files changed, 2083 insertions(+) create mode 100644 arc/pom.xml create mode 100644 arc/src/main/java/org/apache/james/arc/ARCChainValidator.java create mode 100644 arc/src/main/java/org/apache/james/arc/ARCCommon.java create mode 100644 arc/src/main/java/org/apache/james/arc/ARCSigner.java create mode 100644 arc/src/main/java/org/apache/james/arc/ARCVerifier.java create mode 100644 arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java create mode 100644 arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java create mode 100644 arc/src/main/java/org/apache/james/arc/ArcSignatureRecordImpl.java create mode 100644 arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java create mode 100644 arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java create mode 100644 arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java create mode 100644 arc/src/main/java/org/apache/james/arc/exceptions/ArcException.java create mode 100644 arc/src/test/java/org/apache/james/arc/ARCTest.java create mode 100644 arc/src/test/java/org/apache/james/arc/ArcTestKeys.java create mode 100644 arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java create mode 100644 arc/src/test/resources/keys/arc_test_pri.1.key create mode 100644 arc/src/test/resources/keys/arc_test_pub.1.pem create mode 100644 arc/src/test/resources/keys/dkim_test_pri.1.key create mode 100644 arc/src/test/resources/keys/dkim_test_pub.1.pem create mode 100644 arc/src/test/resources/mail/rfc8617_no_arc.eml diff --git a/arc/pom.xml b/arc/pom.xml new file mode 100644 index 0000000..f586c09 --- /dev/null +++ b/arc/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + + apache-jdkim-project + org.apache.james.jdkim + 0.6-SNAPSHOT + ../pom.xml + + + apache-arc-library + + Apache James :: ARC + A Java implementation for the ARC specification. + http://james.apache.org/jdkim/main/ + 2008 + + + + commons-codec + commons-codec + + + org.apache.james.jdkim + apache-jdkim-library + 0.6-SNAPSHOT + + + org.apache.james.jdkim + apache-jdkim-library + 0.6-SNAPSHOT + test-jar + test + + + org.apache.james.jspf + apache-jspf-resolver + 1.0.5 + + + org.freemarker + freemarker + 2.3.31 + + + org.apache.geronimo.javamail + geronimo-javamail_1.4_mail + 1.6 + + + junit + junit + + + org.apache.james + apache-mime4j-core + + + org.apache.james + apache-mime4j-dom + + + org.assertj + assertj-core + test + + + diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java new file mode 100644 index 0000000..2d251d8 --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -0,0 +1,164 @@ +/**************************************************************** + * 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.arc; + +import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.dom.Header; +import org.apache.james.mime4j.stream.Field; + +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.util.Base64; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Validates the ARC (Authenticated Received Chain) chain in an email message. + *

+ * This class provides methods to validate the ARC chain by checking the structure, + * verifying ARC-Message-Signature and ARC-Seal headers, and ensuring the integrity + * of previous ARC hops. It uses DNS records and cryptographic verification to + * ensure the authenticity of the ARC chain. + *

+ */ +public class ARCChainValidator { + public static final String ARC_MESSAGE_SIGNATURE = "ARC-Message-Signature"; + public static final String ARC_SEAL = "ARC-Seal"; + private static final String SHA256_RSA = "SHA256withRSA"; + private final Pattern INST_RGX_PATTERN = Pattern.compile("i=([0-9]+)"); + private final PublicKeyRetrieverArc _keyRecordRetriever; + + public ARCChainValidator(PublicKeyRetrieverArc keyRecordRetriever) { + this._keyRecordRetriever = keyRecordRetriever; + } + + public String validateArcChain(Message message) { + + Header messageHeaders = message.getHeader(); + int curInstance = getCurrentInstance(messageHeaders); // Incremented by 1 + + if (curInstance == 1) { //we are the first ARC Hop and there is no previous ARC hops in the chain to validate + return "none"; + } + else if (curInstance > 51) { // Not allowed to be > 50 + return "fail"; + } + else { // there are previous ARC hops that need to be validated + return validatePreviousArcHops(message, messageHeaders, curInstance); + } + } + + private String validatePreviousArcHops(Message message, Header messageHeaders, int myInstance) { + ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); + Map> arcHeadersByI = arcVerifier.getArcHeadersByI(messageHeaders.getFields()); + int numArcInstances = myInstance -1; + boolean isArcSetStructureOK = arcVerifier.validateArcSetStructure(arcHeadersByI); + if (!isArcSetStructureOK) { + return "fail"; + } + + Set prevArcSet; + prevArcSet = arcVerifier.extractArcSet(messageHeaders, numArcInstances); + if (prevArcSet != null) { + boolean amsOk = checkArcAms (prevArcSet, message, arcVerifier); + boolean asOk = checkArcSeal (messageHeaders.getFields(), numArcInstances, arcVerifier); + if (amsOk && asOk) { + return "pass"; + } + } + return "fail"; + } + + private boolean checkArcAms(Set prevArcSet, Message message, ARCVerifier arcVerifier){ + boolean retVal = false; + + Field amsHeader = prevArcSet.stream() + .filter(f -> f.getName().equalsIgnoreCase(ARC_MESSAGE_SIGNATURE)) + .findFirst().orElse(null); + if (amsHeader == null) return retVal; + + String txtDnsRecord = arcVerifier.getTxtDnsRecordByField(amsHeader); + if (txtDnsRecord == null) return retVal; + + retVal = arcVerifier.verifyAms(amsHeader, message, txtDnsRecord); + + return retVal; + } + + private boolean checkArcSeal(List headers, int instToVerify, ARCVerifier arcVerifier) { + boolean retVal = false; + Map> arcHeadersByI = arcVerifier.getArcHeadersByI(headers); + ArcSealVerifyData verifyData = arcVerifier.buildArcSealSigningData(arcHeadersByI, instToVerify); + Field arcSealHeader = headers.stream() + .filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)) + .findFirst().orElse(null); + if (arcSealHeader == null) return retVal; + + String txtDnsRecord = arcVerifier.getTxtDnsRecordByField(arcSealHeader); + if (txtDnsRecord == null) return retVal; + + PublicKey publicKey = arcVerifier.parsePublicKeyFromDns(txtDnsRecord); + if (publicKey == null) { + throw new ArcException(String.format("Unable to parse public key from dns record %s", txtDnsRecord)); + } + + String b64 = verifyData.getB64Signature(); + String data = verifyData.getSignedData(); + + try { + Signature sig = Signature.getInstance(SHA256_RSA); + sig.initVerify(publicKey); + sig.update(data.getBytes(StandardCharsets.UTF_8)); + byte[] signatureBytes = Base64.getDecoder().decode(b64); + retVal = sig.verify(signatureBytes); + } catch (NoSuchAlgorithmException e) { + throw new ArcException("Unsupported signing algorithm", e); + } + catch (InvalidKeyException e) { + throw new ArcException(String.format("Invalid public key used for %s record", txtDnsRecord), e); + } catch (SignatureException e) { + throw new ArcException(String.format("Invalid signature for %s record", txtDnsRecord), e); + } + return retVal; + } + + public int getCurrentInstance(Header messageHeaders) { + int retVal = 1; + for (Field field : messageHeaders.getFields()) { + if (field.getName().startsWith("ARC-")) { + Matcher m = INST_RGX_PATTERN.matcher(field.getBody()); + if (m.find()) { + int iVal = Integer.parseInt(m.group(1)); + if (iVal >= retVal) { + retVal = iVal + 1; + } + } + } + } + return retVal; + } +} diff --git a/arc/src/main/java/org/apache/james/arc/ARCCommon.java b/arc/src/main/java/org/apache/james/arc/ARCCommon.java new file mode 100644 index 0000000..47c186f --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ARCCommon.java @@ -0,0 +1,141 @@ +/**************************************************************** + * 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.arc; + +import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.jdkim.api.Headers; +import org.apache.james.jdkim.api.SignatureRecord; +import org.apache.james.jdkim.exceptions.PermFailException; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +/** + * Utility class for ARC (Authenticated Received Chain) operations. + *

+ * Provides methods for: + *

    + *
  • Canonicalizing and updating cryptographic signatures for ARC headers
  • + *
  • Signing ARC-Message-Signature and ARC-Seal headers
  • + *
  • Copying streams
  • + *
  • Decoding Base64-encoded PKCS#8 private keys
  • + *
+ *

+ * This class is not intended to be instantiated. + */ +public class ARCCommon { + private ARCCommon(){} + + private static void updateSignature(Signature signature, boolean relaxed, + CharSequence header, String fv) throws SignatureException { + if (relaxed) { + signature.update(header.toString().toLowerCase().getBytes()); + signature.update(":".getBytes()); + String headerValue = fv.substring(fv.indexOf(':') + 1); + headerValue = headerValue.replaceAll("\r\n[\t ]", " "); + headerValue = headerValue.replaceAll("[\t ]+", " "); + headerValue = headerValue.trim(); + signature.update(headerValue.getBytes()); + } else { + signature.update(fv.getBytes()); + } + } + + static void amsSign(Headers h, SignatureRecord sign, + List headers, Signature signature) + throws SignatureException, PermFailException { + + boolean relaxedHeaders = isRelaxedHeaders(sign, true); + + Map processedHeader = new HashMap<>(); + + for (CharSequence header : headers) { + List hl = h.getFields(header.toString()); + if (hl != null && !hl.isEmpty()) { + Integer done = processedHeader.get(header.toString()); + if (done == null) + done = 0; + int doneHeaders = done + 1; + if (doneHeaders <= hl.size()) { + String fv = hl.get(hl.size() - doneHeaders); + updateSignature(signature, relaxedHeaders, header, fv); + signature.update("\r\n".getBytes()); + processedHeader.put(header.toString(), doneHeaders); + } + } + } + + String amsHeader = "ARC-Message-Signature:" + sign.toUnsignedString(); + updateSignature(signature, relaxedHeaders, "arc-message-signature", amsHeader); + } + + static void arcSeal(SignatureRecord sign, + Map headersToSeal, Signature signature) + throws SignatureException, PermFailException { + + boolean relaxedHeaders = isRelaxedHeaders(sign, false); + + for (Map.Entry headerEntry : headersToSeal.entrySet()) { + String headerName = headerEntry.getKey(); + String headerValue = headerName+": " +headerEntry.getValue(); + updateSignature(signature, relaxedHeaders, headerName, headerValue); + signature.update("\r\n".getBytes()); + } + + String signatureStub = "ARC-Seal:" + sign.toUnsignedString(); + updateSignature(signature, relaxedHeaders, "arc-seal", + signatureStub); + } + + private static boolean isRelaxedHeaders(SignatureRecord sign, boolean isAms) throws PermFailException { + boolean relaxedHeaders = !isAms || SignatureRecord.RELAXED.equals(sign + .getHeaderCanonicalisationMethod()); // RFC 8617 : ARC-seal: only "relaxed" header field canonicalization allowed + if (!relaxedHeaders + && !SignatureRecord.SIMPLE.equals(sign + .getHeaderCanonicalisationMethod())) { + + throw new PermFailException( + "Unsupported canonicalization algorithm: " + + sign.getHeaderCanonicalisationMethod()); + } + return relaxedHeaders; + } + + public static void streamCopy(InputStream bodyIs, OutputStream out) + throws IOException { + byte[] buffer = new byte[2048]; + int read; + while ((read = bodyIs.read(buffer)) > 0) { + out.write(buffer, 0, read); + } + bodyIs.close(); + out.close(); + } +} diff --git a/arc/src/main/java/org/apache/james/arc/ARCSigner.java b/arc/src/main/java/org/apache/james/arc/ARCSigner.java new file mode 100644 index 0000000..97b0034 --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ARCSigner.java @@ -0,0 +1,176 @@ +/**************************************************************** + * 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.arc; +import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.jdkim.api.BodyHasher; +import org.apache.james.jdkim.api.Headers; +import org.apache.james.jdkim.api.SignatureRecord; +import org.apache.james.jdkim.exceptions.FailException; +import org.apache.james.jdkim.exceptions.PermFailException; +import org.apache.james.jdkim.impl.BodyHasherImpl; +import org.apache.james.jdkim.impl.Message; + +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.SignatureException; +import java.util.List; +import java.util.Map; + +/** + * ARCSigner is responsible for generating and sealing ARC (Authenticated Received Chain) + * signatures for email messages. It uses a provided private key and signature record template + * to create ARC signature records, hash message bodies, and sign headers or message content. + *

+ * Main responsibilities: + *

    + *
  • Generate ARC signature records using a template
  • + *
  • Hash message bodies for signing
  • + *
  • Sign message headers and bodies using the provided private key
  • + *
  • Seal headers with ARC signatures
  • + *
+ *

+ * This class relies on the Java Cryptography Architecture and helper classes from the + * org.apache.james.jdkim and org.apache.james.arc packages. + */ +public class ARCSigner { + private final PrivateKey privateKey; + private final String signatureRecordTemplate; + + public ARCSigner(String signatureRecordTemplate, PrivateKey privateKey) { + this.privateKey = privateKey; + this.signatureRecordTemplate = signatureRecordTemplate; + } + + public SignatureRecord newSignatureRecordTemplate(String sigRecord) { + return new ArcSignatureRecordImpl(sigRecord); + } + + public BodyHasher newBodyHasher(SignatureRecord signRecord) + throws PermFailException { + return new BodyHasherImpl(signRecord); + } + + public String generateAms(InputStream is) throws IOException, FailException { + Message message; + try { + try { + message = new Message(is); + } catch (RuntimeException | IOException e) { + throw e; + } catch (Exception e1) { + throw new ArcException("MIME parsing exception: " + + e1.getMessage(), e1); + } + + try { + SignatureRecord srt = newSignatureRecordTemplate(signatureRecordTemplate); + BodyHasher bhj = newBodyHasher(srt); + + ARCCommon.streamCopy(message.getBodyInputStream(), bhj + .getOutputStream()); + + return generateAms(message, bhj); + } finally { + message.dispose(); + } + } finally { + is.close(); + } + } + + public String sealHeaders(Map headersToSeal) throws FailException { + SignatureRecord srt = newSignatureRecordTemplate(signatureRecordTemplate); + return seal(srt, headersToSeal); + } + + public String generateAms(Headers message, BodyHasher bh) throws PermFailException { + if (!(bh instanceof BodyHasherImpl)) { + throw new PermFailException( + "Supplied BodyHasher has not been generated with this signer"); + } + + BodyHasherImpl bhj = (BodyHasherImpl) bh; + List headers; + byte[] computedHash = bhj.getDigest(); + bhj.getSignatureRecord().setBodyHash(computedHash); + headers = bhj.getSignatureRecord().getHeaders(); + + try { + byte[] signatureHash = signatureSign(message, bhj + .getSignatureRecord(), privateKey, headers); + + bhj.getSignatureRecord().setSignature(signatureHash); + return "ARC-element:" + ((ArcSignatureRecordImpl)bhj.getSignatureRecord()).getStringInTemplateOrder(); + } catch (InvalidKeyException e) { + throw new ArcException("Invalid key: " + e.getMessage(), e); + } catch (NoSuchAlgorithmException e) { + throw new ArcException("Unknown algorithm: " + e.getMessage(), e); + } catch (SignatureException e) { + throw new ArcException("Signing exception: " + e.getMessage(), e); + } + } + + public String seal(SignatureRecord signatureRecord, Map headersToSeal) throws PermFailException { + + try { + byte[] signatureHash = signatureSeal(signatureRecord, privateKey, headersToSeal); + + signatureRecord.setSignature(signatureHash); + return "ARC-element:" + ((ArcSignatureRecordImpl)signatureRecord).getStringInTemplateOrder(); + } catch (InvalidKeyException e) { + throw new ArcException("Invalid key: " + e.getMessage(), e); + } catch (NoSuchAlgorithmException e) { + throw new ArcException("Unknown algorithm: " + e.getMessage(), e); + } catch (SignatureException e) { + throw new ArcException("Signing exception: " + e.getMessage(), e); + } + } + + private byte[] signatureSeal(SignatureRecord sign, PrivateKey key, Map headersToSeal) + throws NoSuchAlgorithmException, InvalidKeyException, + SignatureException, PermFailException { + Signature signature = Signature.getInstance(sign.getHashMethod() + .toString().toUpperCase() + + "with" + sign.getHashKeyType().toString().toUpperCase()); + signature.initSign(key); + + ARCCommon.arcSeal(sign, headersToSeal, signature); + return signature.sign(); + + } + + private byte[] signatureSign(Headers h, SignatureRecord sign, + PrivateKey key, List headers) + throws NoSuchAlgorithmException, InvalidKeyException, + SignatureException, PermFailException { + + Signature signature = Signature.getInstance(sign.getHashMethod() + .toString().toUpperCase() + + "with" + sign.getHashKeyType().toString().toUpperCase()); + signature.initSign(key); + + ARCCommon.amsSign(h, sign, headers, signature); + return signature.sign(); + } +} + diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java new file mode 100644 index 0000000..b84f57e --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -0,0 +1,402 @@ +/**************************************************************** + * 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.arc; + +import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.jdkim.exceptions.PermFailException; +import org.apache.james.jdkim.exceptions.TempFailException; +import org.apache.james.mime4j.dom.Header; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.stream.Field; + +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utility class for verifying ARC (Authenticated Received Chain) headers in email messages. + *

+ * Provides methods for: + *

    + *
  • Verifying ARC-Message-Signature (AMS) using public keys from DNS
  • + *
  • Parsing and canonicalizing ARC headers and bodies
  • + *
  • Validating ARC set structure and continuity
  • + *
  • Building DNS queries for public key retrieval
  • + *
  • Extracting and organizing ARC headers by instance
  • + *
  • Looking up DNS TXT records for ARC public keys
  • + *
  • Building signing data for ARC-Seal verification
  • + *
+ *

+ * This class is not instantiable and all methods are static. + */ +public class ARCVerifier { + public static final String RSA = "RSA"; + public static final String B_TAG_REGEX = "b=[^;]*"; + public static final Pattern TAG_PATTERN = Pattern.compile("([a-z]+)=([^;]+)"); + public static final Pattern PUBLIC_KEY_PATTERN = Pattern.compile("p=([^;]+)"); + public static final String ARC_AUTHENTICATION_RESULTS = "ARC-Authentication-Results"; + public static final String ARC_MESSAGE_SIGNATURE = "ARC-Message-Signature"; + public static final String ARC_SEAL = "ARC-Seal"; + public static final String SHA256RSA = "SHA256withRSA"; + private static final String DNS_RECORD_TYPE = "_domainkey"; + private PublicKeyRetrieverArc _keyRecordRetriever; + + ARCVerifier(PublicKeyRetrieverArc keyRecordRetriever) { + _keyRecordRetriever = keyRecordRetriever; + } + + public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRecord) { + // Extract AMS params + String amsValue = amsField.getBody(); + Map tags = parseTagList(amsValue); + + String signedHeaders = tags.get("h"); + String bodyHash = tags.get("bh"); + String signatureB64 = tags.get("b"); + String b64 = signatureB64 + .replaceAll("\\s+", "") // remove spaces, tabs, newlines + .replace(";", ""); // defensive: strip trailing semicolon if present + + if (signedHeaders == null || bodyHash == null) { + throw new ArcException("AMS missing required tags"); + } + + String amsForSigning = amsValue.replaceFirst(B_TAG_REGEX, "b="); + // Canonicalize headers listed in h= + StringBuilder signingData = new StringBuilder(); + for (String hName : signedHeaders.split(":")) { + hName = hName.trim(); + for (Field f : message.getHeader().getFields(hName)) { + signingData.append(canonicalizeRegularHeader(f)); + } + } + + // AMS itself must be included last + signingData.append(canonicalizeHeader(amsField.getName(), amsForSigning)); + + // Build RSA public key from DNS record + PublicKey publicKey = parsePublicKeyFromDns(publicKeyDnsRecord); + + // Verify signature + Signature sig = getSignature( publicKey, signingData); + + byte[] signatureBytes = Base64.getDecoder().decode(b64); + + boolean result = false; + if (sig != null) { + try { + result = sig.verify(signatureBytes); + } catch (SignatureException e) { + throw new ArcException("Signature verification failed", e); + } + } + return result; + } + + private Signature getSignature(PublicKey publicKey, StringBuilder signingData) { + Signature sig; + try { + sig = Signature.getInstance(SHA256RSA); + sig.initVerify(publicKey); + String dataToSign = signingData.toString(); + sig.update(dataToSign.getBytes(StandardCharsets.UTF_8)); + } catch (NoSuchAlgorithmException e) { + throw new ArcException("Unsupported signing algorithm when used with public key", e); + } catch (InvalidKeyException e) { + throw new ArcException("Invalid key when used with public key", e); + } catch (SignatureException e) { + throw new ArcException("Invalid signature when used with public key", e); + } + return sig; + } + + public Map parseTagList(String value) { + Map map = new HashMap<>(); + Matcher m = TAG_PATTERN.matcher(value); + while (m.find()) { + map.put(m.group(1).trim(), m.group(2).trim()); + } + return map; + } + + private String canonicalizeRegularHeader(Field field) { + String retVal = canonicalizeHeader(field.getName(), field.getBody()); + return retVal + "\r\n"; + } + + private String canonicalizeHeader(String name, String value) { + // relaxed canonicalization: lowercase field name, unfold spaces, trim + String n = name.toLowerCase(Locale.ROOT); + String v = value.replaceAll("[\\r\\n]+", " ") + .replaceAll("\\s+", " ") + .trim(); + return n + ":" + v; + } + + private PublicKey getPublicKeyFromTxtRecord(String keyText) { + + keyText = keyText.replaceAll("\\s+", ""); // remove ALL spaces/newlines + byte[] keyBytes = Base64.getDecoder().decode(keyText); + + X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); + PublicKey pubKey; + try { + pubKey = KeyFactory.getInstance(RSA).generatePublic(spec); + } catch (InvalidKeySpecException e) { + throw new ArcException("Invalid key provided when getting public key", e); + } catch (NoSuchAlgorithmException e) { + throw new ArcException("Unsupported algorithm provided when getting public key", e); + } + return pubKey; + } + + public PublicKey parsePublicKeyFromDns(String dnsRecord) { + Matcher m = PUBLIC_KEY_PATTERN.matcher(dnsRecord); + + if (!m.find()) { + throw new IllegalArgumentException("Illegal argument exception -- No p= tag in DNS record"); + } + + String base64Key = m.group(1).replaceAll("\\s+", ""); // remove ALL spaces/newlines + byte[] keyBytes = Base64.getDecoder().decode(base64Key); + + X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); + PublicKey pubKey; + try { + pubKey = KeyFactory.getInstance(RSA).generatePublic(spec); + } catch (InvalidKeySpecException e) { + throw new ArcException("Invalid key provided when getting public key", e); + } catch (NoSuchAlgorithmException e) { + throw new ArcException("Unsupported algorithm provided when getting public key", e); + } + return pubKey; + } + + public boolean validateArcSetStructure(Map> arcHeadersByI) { + for (int i = 1; i <= arcHeadersByI.size(); i++) { + List arcSet = arcHeadersByI.get(i); + if (arcSet == null) { // continuity of instances is broken + throw new IllegalStateException("ARC Chain validation fails due to i instances not continued after [" + (i - 1) + "] instance."); + } + + boolean eachOfOne = checkArcSetCompose(arcSet); + if (!eachOfOne) { + throw new ArcException("ARC Chain validation fails due to one or more ARC Set headers missing at instance [" + i + "]."); + } + + if (arcSet.size() != 3){ + throw new ArcException("ARC Chain validation fails due to incorrect size of Arc Headers (not 3) at instance [" + i + "]."); + } + + boolean cvOk = checkCv(arcSet, i); + if (!cvOk) { + throw new ArcException("ARC Chain validation fails due to cv check failing at instance [" + i + "]."); + } + } + return true; + } + + private boolean checkCv(List lastArcSet, int instToVerify) { + Optional arcSealHeader = lastArcSet.stream().filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)).findFirst(); + if (arcSealHeader.isPresent()) { + Map tags = parseTagList(arcSealHeader.get().getBody()); + String lastCv = tags.get("cv"); + return (instToVerify == 1 && lastCv.equalsIgnoreCase("none")) || + (instToVerify > 1 && lastCv.equalsIgnoreCase("pass")); + } + return false; + } + + private boolean checkArcSetCompose(List arcSet) { + Optional aar = arcSet.stream().filter(p-> p.getName() + .equalsIgnoreCase(ARC_AUTHENTICATION_RESULTS)).findFirst(); + + Optional ams = arcSet.stream().filter(p-> p.getName() + .equalsIgnoreCase(ARC_MESSAGE_SIGNATURE)).findFirst(); + + Optional as = arcSet.stream().filter(p-> p.getName() + .equalsIgnoreCase(ARC_SEAL)).findFirst(); + return aar.isPresent() && ams.isPresent() && as.isPresent(); + } + + public String buildDnsQuery(Field signedField, String recordType) { + String retVal = ""; + Map tags = parseTagList(signedField.getBody()); + if (tags.isEmpty()) { // we should always have tags on the valid AMS + return retVal; + } + String amsSelector = tags.get("s"); + String amsDomain = tags.get("d"); + if (amsSelector == null || amsDomain == null) { // we should always have these tags on the valid AMS + return retVal; + } + retVal = amsSelector+"."+ recordType+"."+amsDomain; + return retVal; + } + + public Map> getArcHeadersByI(List headers) { + Map> headersByI = new TreeMap<>(); + for (Field f : headers) { + String name = f.getName().toUpperCase(Locale.ROOT); + if (name.startsWith("ARC-")) { + int i = -1; + String iTag = parseTagGeneric(f.getBody(), "i"); + if (iTag != null) { + i = Integer.parseInt(iTag); + } + if (i == -1) { + throw new IllegalStateException("ARC Header missing i= tag"); + } + else { + headersByI.computeIfAbsent(i, k -> new ArrayList<>()).add(f); + } + } + } + return headersByI; + } + + public String canonicalizeBody(String body) { + body = body.replaceAll("\r\n[\t ]", " "); + body = body.replaceAll("[\t ]+", " "); + body = body.trim(); + return body; + } + + public String parseTagGeneric(String record, String tag) { + String[] parts = record.split(";"); + for (String part : parts) { + String trimmed = part.trim(); + if (trimmed.startsWith(tag + "=")) { + return trimmed.substring((tag + "=").length()); + } + } + return null; + } + + public ArcSealVerifyData buildArcSealSigningData(Map> headersByI, int targetI) { + ArcSealVerifyData result = new ArcSealVerifyData(); + StringBuilder signingData = new StringBuilder(); + + //Iterate over hops in ascending i order, for the last hop, make sure to clear b= tag on the ARC-Seal + for (Map.Entry> entry : headersByI.entrySet()) { + int hopI = entry.getKey(); + if (hopI > targetI) break; + + List hopFields = entry.getValue(); + Optional aar = hopFields.stream().filter(p-> p.getName() + .equalsIgnoreCase(ARC_AUTHENTICATION_RESULTS)).findFirst(); + + Optional ams = hopFields.stream().filter(p-> p.getName() + .equalsIgnoreCase(ARC_MESSAGE_SIGNATURE)).findFirst(); + + Optional as = hopFields.stream().filter(p-> p.getName() + .equalsIgnoreCase(ARC_SEAL)).findFirst(); + + aar.ifPresent(f -> signingData + .append(f.getName().toLowerCase(Locale.ROOT)) + .append(":").append(canonicalizeBody(f.getBody())) + .append("\r\n")); + + ams.ifPresent(f -> signingData + .append(f.getName().toLowerCase(Locale.ROOT)) + .append(":").append(canonicalizeBody(f.getBody())) + .append("\r\n")); + + if (hopI == targetI) { // this is last hop so we need to clear b= tag on the ARC-Seal Header and not tail it with CRLF + as.ifPresent(f -> { + Map tags = parseTagList(f.getBody()); + String signatureB64 = tags.get("b"); + String b64 = signatureB64 + .replaceAll("\\s+", "") // remove spaces, tabs, newlines + .replace(";", ""); + String arcSealBodyClearedB= f.getBody().replaceAll("\\bb=([^;]*)", "b="); + signingData.append(f.getName().toLowerCase(Locale.ROOT)).append(":").append(canonicalizeBody(arcSealBodyClearedB)); + result.setB64Signature(b64); + result.setSignedData(signingData.toString()); + }); + } + else { // this is one of the previous hops, not the last one, so we want to preserve b= tag on the ARC-Seal and tail it with CRLF + as.ifPresent(f -> signingData + .append(f.getName().toLowerCase(Locale.ROOT)) + .append(":").append(canonicalizeBody(f.getBody())) + .append("\r\n")); + } + } + return result; + } + + public Set extractArcSet(Header messageHeaders, int instance) { + Set prevArcSet = null; + for (Field field : messageHeaders.getFields()) { + if (field.getName().startsWith("ARC-") && field.getBody().contains("i="+instance)) { + if (prevArcSet == null) { + prevArcSet = new HashSet<>(); + } + prevArcSet.add(field); + } + } + return prevArcSet; + } + + public String getTxtDnsRecordByField(Field signedHeader) { + String dnsQuery = buildDnsQuery(signedHeader, DNS_RECORD_TYPE); + if (dnsQuery == null || dnsQuery.isEmpty()) return null; // corrupted AMS - unable to pull PubKey from DNS + Map tags = parseTagList(signedHeader.getBody()); + if (tags.isEmpty()) { // we should always have tags on the valid AMS + throw new ArcException("Missing tags for dns record") ; + } + String amsSelector = tags.get("s"); + String amsDomain = tags.get("d"); + + try { + List results = getPublicKeyRecordRetriever().getRecords("dns/txt", amsSelector, amsDomain); + if (!results.isEmpty()) { + return results.get(0); //Todo: handle multiple records? + } + } catch (TempFailException e) { + throw new RuntimeException(e); + } catch (PermFailException e) { + throw new RuntimeException(e); + } + return null; + } + + protected PublicKeyRetrieverArc getPublicKeyRecordRetriever() + { + return _keyRecordRetriever; + } +} diff --git a/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java b/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java new file mode 100644 index 0000000..2af6fcb --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java @@ -0,0 +1,38 @@ +/**************************************************************** + * 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.arc; + +public class ArcSealVerifyData { + private String _b64; + private String _dataToVerify; + + public void setSignedData(String _dataToVerify) { + this._dataToVerify = _dataToVerify; + } + + public void setB64Signature(String _b64) { + this._b64 = _b64; + } + + public String getB64Signature() { + return _b64; + } + public String getSignedData() { return + _dataToVerify; } +} \ No newline at end of file diff --git a/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java b/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java new file mode 100644 index 0000000..e121105 --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java @@ -0,0 +1,167 @@ +/**************************************************************** + * 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.arc; + +import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.mime4j.dom.Header; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.message.DefaultMessageWriter; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.security.PrivateKey; +import java.time.Instant; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Builder class for generating ARC (Authenticated Received Chain) header sets. + *

+ * This class is responsible for constructing and signing ARC-Authentication-Results, + * ARC-Message-Signature, and ARC-Seal headers for a given email message, using + * provided templates and cryptographic keys. + *

+ *

+ * Usage involves providing the necessary templates, DMARC responses, authentication + * service, and private key. The {@link #buildArcSet(Message, String, String, String, PublicKeyRetrieverArc)} + * method generates the ARC headers and returns them as a map. + *

+ */ +public class ArcSetBuilder { + public static final String ARC_ELEMENT = "ARC-element:"; + public static final String ARC_SEAL = "ARC-Seal"; + public static final String ARC_MESSAGE_SIGNATURE = "ARC-Message-Signature"; + public static final String AUTHENTICATION_RESULTS = "Authentication-Results"; + public static final String ARC_AUTHENTICATION_RESULTS = "ARC-Authentication-Results"; + + private final PrivateKey _arcPrivateKey; + private final String _arcAmsTemplate; + private final String _arcSealTemplate; + private final String _dmarcResponse; + private final String _dmarcNonResponse; + private final String _authService; + private long _debugTimestamp; + + public ArcSetBuilder(PrivateKey arcPrivateKey, String arcAmsTemplate, String arcSealTemplate, + String dmarcResponse, String dmarcNonResponse, + String authService, long debugTimestamp) { + this(arcPrivateKey, arcAmsTemplate, arcSealTemplate, dmarcResponse, dmarcNonResponse, authService); + _debugTimestamp = debugTimestamp; + } + + public ArcSetBuilder(PrivateKey arcPrivateKey, String arcAmsTemplate, String arcSealTemplate, + String dmarcResponse, String dmarcNonResponse, + String authService) { + _arcAmsTemplate = arcAmsTemplate; + _arcSealTemplate = arcSealTemplate; + _arcPrivateKey = arcPrivateKey; + _dmarcResponse = dmarcResponse; + _dmarcNonResponse = dmarcNonResponse; + _authService = authService; + } + + /** + * Builds the ARC (Authenticated Received Chain) header set for the given email message. + *

+ * This method generates and signs the ARC-Authentication-Results, ARC-Message-Signature, + * and ARC-Seal headers using the provided message, HELO, MAIL FROM, and IP address. + * The headers are constructed using configured templates and cryptographic keys. + *

+ * + * @param message the email message to process + * @param helo the HELO/EHLO string from the SMTP transaction + * @param mailFrom the MAIL FROM address from the SMTP transaction + * @param ip the connecting client IP address + * @param keyRecordRetriever + * @return a map containing the generated ARC headers and their values + * @throws ArcException if ARC header generation or signing fails + */ + public Map buildArcSet(Message message, String helo, String mailFrom, String ip, PublicKeyRetrieverArc keyRecordRetriever) { + Map arcHeaders = new HashMap<>(); + + try { + Header headers = message.getHeader(); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + AuthResultsBuilder authResultsBuilder = new AuthResultsBuilder(_dmarcResponse, _dmarcNonResponse, _authService, keyRecordRetriever); + String cv = arcChainValidator.validateArcChain(message); + int instance = arcChainValidator.getCurrentInstance(headers); + + //Build ARC-Authentication-Results header + String arHeaderValue = authResultsBuilder.getAuthResultsHeader(message, helo, mailFrom,ip); + if (arHeaderValue == null){ + throw new ArcException("Unable to build Authentication-Results header"); + } + + arcHeaders.put(AUTHENTICATION_RESULTS, arHeaderValue); + Map headersToSeal = new LinkedHashMap<>(); + String aarHeaderValue = "i=" + instance + "; " + arHeaderValue.trim(); + + arcHeaders.put(ARC_AUTHENTICATION_RESULTS, aarHeaderValue); + headersToSeal.put(ARC_AUTHENTICATION_RESULTS, aarHeaderValue); + DefaultMessageWriter writer = new DefaultMessageWriter(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + writer.writeMessage(message,os); + + Map fmContext = new HashMap<>(); + fmContext.put("instance", instance); + long timestamp = Instant.now().getEpochSecond(); + if (_debugTimestamp != 0) { + timestamp = _debugTimestamp; + } + fmContext.put("timestamp", Long.toString(timestamp)); + fmContext.put("cv", cv); + + //Build and add ARC-AMS header + String amsTemplate = mergeTemplate(_arcAmsTemplate, fmContext); + ARCSigner amsSigner = new ARCSigner(amsTemplate, _arcPrivateKey); + String amsHeader = amsSigner.generateAms(new ByteArrayInputStream(os.toByteArray())); + String amsValue = amsHeader.split(ARC_ELEMENT)[1]; + arcHeaders.put(ARC_MESSAGE_SIGNATURE, amsValue); + headersToSeal.put(ARC_MESSAGE_SIGNATURE, amsValue); + + //Build and add ARC-Seal header + String asTemplate = mergeTemplate(_arcSealTemplate, fmContext); + ARCSigner asSigner = new ARCSigner(asTemplate, _arcPrivateKey); + String asHeader = asSigner.sealHeaders(headersToSeal ); + String asValue = asHeader.split(ARC_ELEMENT)[1]; + arcHeaders.put(ARC_SEAL, asValue); + } + catch (Exception ex){ + throw new ArcException("Unable to generate ARC Seal", ex); + } + return arcHeaders; + } + + private String mergeTemplate(String templateString, Map context) throws IOException { + try (StringWriter writer = new StringWriter()) { + freemarker.template.Configuration cfg = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_31); + cfg.setTemplateLoader(new freemarker.cache.StringTemplateLoader()); + freemarker.cache.StringTemplateLoader loader = (freemarker.cache.StringTemplateLoader) cfg.getTemplateLoader(); + loader.putTemplate("template", templateString); + freemarker.template.Template template = cfg.getTemplate("template"); + template.process(context, writer); + return writer.toString(); + } catch (freemarker.template.TemplateException e) { + throw new IOException("Error merging template", e); + } + } +} diff --git a/arc/src/main/java/org/apache/james/arc/ArcSignatureRecordImpl.java b/arc/src/main/java/org/apache/james/arc/ArcSignatureRecordImpl.java new file mode 100644 index 0000000..2b790da --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ArcSignatureRecordImpl.java @@ -0,0 +1,200 @@ +/**************************************************************** + * 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.arc; + +import org.apache.james.jdkim.tagvalue.SignatureRecordImpl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +/** + * Implementation of an ARC (Authenticated Received Chain) signature record. + *

+ * This class extends {@link SignatureRecordImpl} to provide parsing, validation, + * and string formatting for ARC signature header fields as defined in the ARC protocol. + * It maintains the original order of tags and supports validation of expiration, + * header lists, and tag/value syntax. + *

+ */ +public class ArcSignatureRecordImpl extends SignatureRecordImpl { + private static final Pattern hdrNamePattern = Pattern.compile("^[^: \r\n\t]+$"); + private static final Pattern tagPattern = Pattern.compile("^[A-Za-z][A-Za-z0-9_]*$"); + private static final String tagValFormatPattern = "[^; \t\r\n]++"; + private static final Pattern valuePattern = Pattern.compile("^(?:" + tagValFormatPattern + + "(?:(?:(?:\r\n)?[\t ])++" + tagValFormatPattern + ")*+)?$"); + private final Map tagValuesOriginal = new LinkedHashMap<>(); + + public ArcSignatureRecordImpl(String data) { + super(data); + parseOriginal(data); + } + + @Override + public void validate() throws IllegalStateException { + if (getValue("x") != null) { + long expiration = Long.parseLong(getValue("x").toString()); + long lifetime = (expiration - System.currentTimeMillis() / 1000); + if (lifetime < 0) { + throw new IllegalStateException("Signature is expired since " + + getTimeMeasureText(lifetime) + "."); + } + } + } + + @Override + public List getHeaders() { + if (getValue("h") == null) + return new ArrayList<>(); + else + return stringToColonSeparatedList(getValue("h").toString(), + hdrNamePattern); + } + + private String getTimeMeasureText(long lifetime) { + String measure = "s"; + lifetime = -lifetime; + if (lifetime > 600) { + lifetime = lifetime / 60; + measure = "m"; + if (lifetime > 600) { + lifetime = lifetime / 60; + + measure = "h"; + if (lifetime > 120) { + lifetime = lifetime / 24; + measure = "d"; + if (lifetime > 90) { + lifetime = lifetime / 30; + measure = " months"; + if (lifetime > 24) { + lifetime = lifetime / 12; + measure = " years"; + } + } + } + } + } + return lifetime + measure; + } + + @Override + public String toUnsignedString() { + String retValue = toString().replaceFirst("b=[^;]*", "b="); + return getOrigOrderedString(retValue); + } + + private String getOrigOrderedString(String retValue) { + List retValPartsList = Arrays.asList(retValue.trim().split(";")); + StringBuilder sb = new StringBuilder(); + int originalTagIndex = 0; + for (String tag : tagValuesOriginal.keySet()) { + String tagPart = retValPartsList.stream().filter(p -> p.trim().startsWith(tag + "=")).findFirst().orElse(null); + if (tagPart != null) { + boolean isLastTag = originalTagIndex == tagValuesOriginal.size() - 1; + if (tagPart.trim().startsWith("h") && tagPart.contains(":")) { + tagPart = tagPart.replace(":", " : "); + sb.append(tagPart.toLowerCase().trim()); + } else { + sb.append(tagPart.trim()); + } + if (!isLastTag) { + sb.append("; "); + } + } + originalTagIndex++; + } + return sb.toString(); + } + + public String getStringInTemplateOrder(){ + return getOrigOrderedString(toString()); + } + + private void parseOriginal(String data) { + for (int i = 0; i < data.length(); i++) { + int equal = data.indexOf('=', i); + if (equal == -1) { + String rest = data.substring(i); + if (!rest.isEmpty() + && trimFWS(rest, 0, rest.length() - 1, true).length() > 0) { + throw new IllegalStateException( + "Unexpected termination at position " + i + ": " + + data + " | [" + rest + "]"); + } + i = data.length(); + continue; + } + // we could start from "equals" but we start from "i" in + // order to spot invalid values before validation. + int next = data.indexOf(';', i); + if (next == -1) { + next = data.length(); + } + + if (equal > next) { + throw new IllegalStateException("Found ';' before '=' in " + + data); + } + + CharSequence tag = trimFWS(data, i, equal - 1, true).toString(); + if (VALIDATION && !tagPattern.matcher(tag).matches()) { + throw new IllegalStateException("Syntax error in tag: " + tag); + } + String tagString = tag.toString(); + if (tagValuesOriginal.containsKey(tagString)) { + throw new IllegalStateException( + "Syntax error (duplicate tag): " + tag); + } + + CharSequence value = trimFWS(data, equal + 1, next - 1, true); + if (VALIDATION && !valuePattern.matcher(value).matches()) { + throw new IllegalStateException("Syntax error in value: " + + value); + } + + tagValuesOriginal.put(tagString, value); + i = next; + } + } + + @Override + public CharSequence getIdentity() { + // In ARC, i= is just an integer + return getValue("i"); + } + + @Override + public CharSequence getIdentityLocalPart() { + // Not applicable for ARC + return getIdentity(); + } + + @Override + public boolean equals(Object obj) { + return super.equals(obj); + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java new file mode 100644 index 0000000..a7f34e5 --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java @@ -0,0 +1,240 @@ +/**************************************************************** + * 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.arc; + +import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.jdkim.DKIMVerifier; +import org.apache.james.jdkim.api.SignatureRecord; +import org.apache.james.jdkim.exceptions.FailException; +import org.apache.james.jdkim.exceptions.PermFailException; +import org.apache.james.jdkim.exceptions.TempFailException; +import org.apache.james.jdkim.tagvalue.SignatureRecordImpl; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.message.DefaultMessageWriter; + +import javax.mail.internet.AddressException; +import javax.mail.internet.InternetAddress; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Base64; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Builds the Authentication-Results header for email messages by performing SPF, DKIM, and DMARC checks. + *

+ * This class runs SPF and DKIM verifications on the provided message and then evaluates DMARC alignment + * using the results and the message's From domain. It constructs a formatted Authentication-Results header + * string summarizing the authentication status. + *

+ *
    + *
  • SPF: Uses the sender's IP, HELO, and envelope-from address.
  • + *
  • DKIM: Verifies DKIM signatures in the message.
  • + *
  • DMARC: Checks alignment and policy based on DNS records for the From domain.
  • + *
+ *

+ * Throws {@link org.apache.james.arc.exceptions.ArcException} for errors in the authentication process. + *

+ */ +public class AuthResultsBuilder { + public static final String FROM = "From"; + public static final String HEADER_I = "header.i="; + private final PublicKeyRetrieverArc _keyRecordRetriever; + private String _dmarcNoneResponse; + private String _dmarcResponse; + private String _authService; + + public AuthResultsBuilder(String dmarcResponse, String dmarcNoneResponse, String authService, PublicKeyRetrieverArc keyRecordRetriever) { + this._dmarcResponse = dmarcResponse; + this._dmarcNoneResponse = dmarcNoneResponse; + this._authService = authService; + this._keyRecordRetriever = keyRecordRetriever; + } + + public String getAuthResultsHeader(Message message, String helo, String from, String ip) { + + // 1. Run SPF check + String spfResultText = _keyRecordRetriever.getSpfRecord(helo, from, ip); + + + // 2. Run DKIM verification + String dkimResultFull; + try { + dkimResultFull = runDkimCheck(message); + } catch (IOException e) { + throw new ArcException("IO Error while checking DKIM results", e); + } + String dkimResultShort = dkimResultFull.split(" ")[0]; + + // 3. Run DMARC check (using SPF + DKIM results + From domain) + String dkimDomain = extractDkimDomain(dkimResultFull); + String spfDomain = extractSpfDomain(spfResultText); + String dmarcResult = runDmarcCheck(message, spfResultText, spfDomain, dkimResultShort, dkimDomain); + if (dmarcResult == null || dmarcResult.isEmpty()) { + dmarcResult = _dmarcNoneResponse + spfDomain; + } + + return _authService + "; " + + "spf=" + spfResultText.replace(";", "") + "; " + + "dkim=" + dkimResultFull + "; " + + dmarcResult; + + } + + private String runDkimCheck(Message message) throws IOException { + final DKIMVerifier verifier = new DKIMVerifier(_keyRecordRetriever); + InputStream is = messageToInputStream(message); + + // Verify DKIM signatures + List results; + try { + results = verifier.verify(is); + if (!results.isEmpty() && results.stream().allMatch(Objects::nonNull) && results.get(0) != null) { + SignatureRecord signatureRecord = results.get(0); + String iTag = (String) signatureRecord.getIdentity(); + if (iTag == null || iTag.isEmpty()) { + iTag = (String) signatureRecord.getDToken(); + } + iTag = iTag.replace("@", ""); //most implementations drop the leading @ + CharSequence sTag = signatureRecord.getSelector(); + Set tags = ((SignatureRecordImpl) signatureRecord).getTags(); + String bTag = ""; + if (!tags.isEmpty() && tags.contains("b")) { + byte[] signature = signatureRecord.getSignature(); + bTag = Base64.getEncoder().encodeToString(signature); + bTag=bTag.substring(0,8); + } + String outcome = "pass"; + return outcome + " header.i=" + iTag + " header.s=" + sTag+ " header.b=" + bTag; + } + } + catch (PermFailException e) { + throw new ArcException("DKIM PermFail", e); + } catch (TempFailException e) { + throw new ArcException("DKIM TempFail", e); + } catch (FailException e) { + throw new ArcException("DKIM Fail", e); + } catch (Exception e) { + throw new ArcException("DKIM Error", e); + } + return "fail (no valid signature records)"; + } + + private String extractSpfDomain(String spfHeaderText) { + String[] parts = spfHeaderText.split(" "); + for (String part : parts) { + if (part.startsWith("envelope-from=")) { + String[] subParts = part.substring("envelope-from=".length()).split("@"); + if (subParts.length < 2) return null; + String envFrom = subParts[1]; + envFrom = envFrom.replaceAll("[<>]", "").replace(";", ""); + return envFrom.trim(); + } + } + return null; + } + + private String extractDkimDomain(String dkimResultFull) { + String[] parts = dkimResultFull.split(" "); + for (String part : parts) { + if (part.startsWith(HEADER_I)) { + String partValue = part.substring(HEADER_I.length()); + if (partValue.contains("@")) //some implementations drop the leading @ + return partValue.split("@")[1].trim(); + else + return partValue.trim(); + } + } + return null; + } + + private String runDmarcCheck(Message message, String spfHeaderText, String spfDomain, String dkim, String dkimDomain) { + // Combine SPF + DKIM results with From: domain + // 1. Extract RFC5322.From domain from the From header of the message + String shortSpfResut = spfHeaderText.split(" ")[0]; + String fromHeader = message.getHeader().getField(FROM).getBody(); + String fromDomain = getFromDomain(fromHeader); + if (fromDomain == null || fromDomain.isEmpty()) { + return _dmarcNoneResponse + "unknown"; + } + try { + fromDomain = new InternetAddress(fromHeader).getAddress().split("@")[1]; + } catch (AddressException e) { + throw new ArcException("Internet address error", e); + } + + // 2. Fetch DMARC record from DNS + ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); + + String dmarcRecord = arcVerifier.getPublicKeyRecordRetriever().getDmarcRecord(fromDomain); + if (dmarcRecord == null) { + return _dmarcNoneResponse + fromDomain; + } + + // Parse DMARC policy + String policy = arcVerifier.parseTagGeneric(dmarcRecord, "p"); // p=none|quarantine|reject +// String aspf = parseTag(dmarcRecord, "aspf"); // optional +// String adkim = parseTag(dmarcRecord, "adkim"); // optional + + // 3. Alignment checks + boolean spfAligned = "pass".equals(shortSpfResut) && fromDomain.equalsIgnoreCase(spfDomain); + boolean dkimAligned = "pass".equals(dkim) && fromDomain.equalsIgnoreCase(dkimDomain); + + // 4. DMARC result logic + String result; + if (spfAligned || dkimAligned) { + result = "pass"; + } else { + result = "fail"; + } + + // 5. Build Authentication-Results string + return String.format(_dmarcResponse, result, policy, fromDomain); + } + + private String getFromDomain(String fromHeader) { + String fromDomain = null; + if (fromHeader.contains("<") && fromHeader.contains(">")) { + int start = fromHeader.indexOf('<'); + int end = fromHeader.indexOf('>'); + if (start != -1 && end != -1 && end > start) { + String email = fromHeader.substring(start + 1, end); + fromDomain = email.split("@")[1]; + } + } + else { + try { + fromDomain = new InternetAddress(fromHeader).getAddress().split("@")[1]; + } catch (AddressException e) { + throw new ArcException("Internet address error", e); + } + } + return fromDomain; + } + + private InputStream messageToInputStream(Message message) throws IOException { + DefaultMessageWriter writer = new DefaultMessageWriter(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + writer.writeEntity(message,os); + return new ByteArrayInputStream(os.toByteArray()); + } +} diff --git a/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java b/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java new file mode 100644 index 0000000..d08e210 --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java @@ -0,0 +1,66 @@ +package org.apache.james.arc; + +import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.jdkim.impl.DNSPublicKeyRecordRetriever; +import org.apache.james.jspf.impl.DefaultSPF; +import org.apache.james.jspf.impl.SPF; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import java.util.Hashtable; + +public class DNSPublicKeyRecordRetrieverArc extends DNSPublicKeyRecordRetriever implements PublicKeyRetrieverArc { + public static final String JAVA_NAMING_FACTORY_INITIAL = "java.naming.factory.initial"; + public static final String COM_SUN_JNDI_DNS_DNS_CONTEXT_FACTORY = "com.sun.jndi.dns.DnsContextFactory"; + public static final String TXT = "TXT"; + + public DNSPublicKeyRecordRetrieverArc() { + super(); + } + + @Override + public String getSpfRecord(String helo, String from, String ip) { + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + SPF spf = new DefaultSPF(); + return spf.checkSPF(ip, from, helo).getHeaderText(); + } + + @Override + public String getDmarcRecord(String dnsLabel) { + Hashtable env = new Hashtable<>(); + env.put(JAVA_NAMING_FACTORY_INITIAL, COM_SUN_JNDI_DNS_DNS_CONTEXT_FACTORY); + DirContext ctx; + dnsLabel = "_dmarc." + dnsLabel; + try { + ctx = new InitialDirContext(env); + } catch (NamingException e) { + throw new ArcException(String.format("Naming error when creating InitialDirContext using [%s]", dnsLabel), e); + } + + Attributes attrs; + try { + attrs = ctx.getAttributes(dnsLabel, new String[]{TXT}); + } catch (NamingException e) { + throw new ArcException(String.format("Naming error when getting attributes using [%s]", dnsLabel), e); + } + + Attribute txtAttr = attrs.get(TXT); + try { + if (txtAttr != null) { + StringBuilder sb = new StringBuilder(); + NamingEnumeration e = txtAttr.getAll(); + while (e.hasMore()) { + sb.append(e.next().toString().replace("\"", "")); + } + return sb.toString(); + } + } catch (NamingException e) { + throw new ArcException(String.format("Naming error when looping through attributes using [%s]", dnsLabel), e); + } + return null; + } +} diff --git a/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java b/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java new file mode 100644 index 0000000..905d75a --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java @@ -0,0 +1,10 @@ +package org.apache.james.arc; + +import org.apache.james.jdkim.api.PublicKeyRecordRetriever; + +public interface PublicKeyRetrieverArc extends PublicKeyRecordRetriever { + + String getDmarcRecord(String query); + + String getSpfRecord(String helo, String from, String ip); +} diff --git a/arc/src/main/java/org/apache/james/arc/exceptions/ArcException.java b/arc/src/main/java/org/apache/james/arc/exceptions/ArcException.java new file mode 100644 index 0000000..e5e4549 --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/exceptions/ArcException.java @@ -0,0 +1,29 @@ +/**************************************************************** + * 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.arc.exceptions; + +public class ArcException extends RuntimeException { + public ArcException(String message, Throwable cause) { + super(message, cause); + } + + public ArcException(String message) { + super(message); + } +} diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java new file mode 100644 index 0000000..a4bebc6 --- /dev/null +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -0,0 +1,137 @@ +/****************************************************************************** + * 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.arc; + +import org.apache.commons.codec.binary.Base64; +import org.apache.james.jdkim.DKIMCommon; +import org.apache.james.jdkim.MockPublicKeyRecordRetriever; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.message.DefaultMessageBuilder; +import org.apache.james.mime4j.stream.RawField; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ARCTest { + public static final String AUTHENTICATION_RESULTS = "Authentication-Results"; + public static final String ARC_AUTHENTICATION_RESULTS = "ARC-Authentication-Results"; + public static final String ARC_MESSAGE_SIGNATURE = "ARC-Message-Signature"; + public static final String ARC_SEAL = "ARC-Seal"; + + private final MockPublicKeyRecordRetrieverArc keyRecordRetriever = new MockPublicKeyRecordRetrieverArc( + MockPublicKeyRecordRetriever.Record.of( + "arc", + "dmarc.example", + "k=rsa; p=" + Base64.encodeBase64String(ArcTestKeys.publicKeyArc.getEncoded()) + ";" + ), + MockPublicKeyRecordRetriever.Record.of( + "origin2015", + "d1.example", + "k=rsa; p=" + Base64.encodeBase64String(ArcTestKeys.publicKeyDkim.getEncoded()) + ";" + ), + MockPublicKeyRecordRetrieverArc.DmarcRecord.dmarcOf("", + "d1.example", + "k=rsa; v=DMARC1; p=reject; pct=100; rua=mailto:noc@d1.example" + ), + MockPublicKeyRecordRetrieverArc.SpfRecord.spfOf("d1.example", + "jqd@d1.example", + "222.222.222.222", + "softfail (spfCheck: transitioning domain of d1.example does not designate 222.222.222.222 as permitted sender) client-ip=222.222.222.222; envelope-from=jqd@d1.example; helo=d1.example") + ); + + /** + * - "a" field will be added by the signer based on signer setup + * - "bh=" and "b=" placeholder are required for now because the same implementation is used for + * signing and verifying. The fields are mandatory for verifying. + */ + //Todo: replace freemarker templates with something less heavy weight + private static final String ARC_AMS_TEMPLATE = "i=${instance}; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; t=${timestamp}; h=Subject:From:To; bh=; b="; + private static final String ARC_SEAL_TEMPLATE = "i=${instance}; cv=${cv}; a=rsa-sha256; d=dmarc.example; s=arc; t=${timestamp}; b="; + + private static final String AUTH_SERVICE = "smtp.d1.example"; + private static final String HELO = "d1.example"; + + private static final String MAIL_FROM = "jqd@d1.example"; + private static final String IP = "222.222.222.222"; + private static final long TIMESTAMP = 1755918846L; // fixed timestamp for repeatable tests + + private static final String DMARC_RESPONSE_TEMPLATE = "dmarc=%s (p=%s) header.from=%s"; + private static final String DMARC_NON_RESPONSE_TEMPLATE = "dmarc=none (no policy) header.from="; + + ArcSetBuilder arcSetBuilder = new ArcSetBuilder(ArcTestKeys.privateKeyArc, ARC_AMS_TEMPLATE, ARC_SEAL_TEMPLATE, DMARC_RESPONSE_TEMPLATE, DMARC_NON_RESPONSE_TEMPLATE, AUTH_SERVICE, TIMESTAMP); + + @Test + public void generate_and_verify_arc_set() throws Exception { + String expectedCv = "pass"; + String authResultsExp = "smtp.d1.example; spf=softfail (spfCheck: transitioning domain of d1.example does not designate 222.222.222.222 as permitted sender) client-ip=222.222.222.222 envelope-from=jqd@d1.example helo=d1.example; dkim=pass header.i=d1.example header.s=origin2015 header.b=iEn8fLQ/; dmarc=pass (p=reject) header.from=d1.example"; + String arcAuthResultsExp = "i=1; smtp.d1.example; spf=softfail (spfCheck: transitioning domain of d1.example does not designate 222.222.222.222 as permitted sender) client-ip=222.222.222.222 envelope-from=jqd@d1.example helo=d1.example; dkim=pass header.i=d1.example header.s=origin2015 header.b=iEn8fLQ/; dmarc=pass (p=reject) header.from=d1.example"; + String arcSignExp = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; t=1755918846; h=subject : from : to; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b=FL3H8cG2U7RcyMSdx4j8iAD/7Uhzhl4XmWicLD+Uuxf3VsVghJ/lswvdQrjnyr6R9oyfPzP7rE2BEX0CFKlSvTVWy5/+8Vc3CXqj+tnKYoHnuWxH4sH0jMTpHzgceGLgMXvamilPyYWrCeF3r5yaUPYQ04fhfeAFAs6OTLeKvL0="; + String arcSealExp = "i=1; cv=none; a=rsa-sha256; d=dmarc.example; s=arc; t=1755918846; b=LsqQnv1KZhtbEX6SYLn0gk0t+Pjg3WmLu0aqNVwHa3nMcRq1dt4wJX1ka9lZAY/RARH74hwtfGnW1ba1gXLZ2WhevLwXvQcuw3NK6aC2YcYCjQ9kQWmlpvLe96xXsASl8MPXWyOmTEOdCeH06mkf3jahb4+bBjp1875568hTFhQ="; + + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + DefaultMessageBuilder builder = new DefaultMessageBuilder(); + Message message = builder.parseMessage(emailStream); + +// Map arcSet = arcSetBuilder.buildArcSet(message, HELO , MAIL_FROM,IP, new DNSPublicKeyRecordRetrieverArc()); // use this for real/external DNS lookups + Map arcSet = arcSetBuilder.buildArcSet(message, HELO , MAIL_FROM,IP, keyRecordRetriever); // mock DNS for testing + + assertThat(arcSet).hasSize(4); + + String authResults = arcSet.get(AUTHENTICATION_RESULTS); + String arcAuthResults = arcSet.get(ARC_AUTHENTICATION_RESULTS); + String arcMsgSignature = arcSet.get(ARC_MESSAGE_SIGNATURE); + String arcSeal = arcSet.get(ARC_SEAL); + assertThat(authResults).isEqualTo(authResultsExp); + assertThat(arcAuthResults).isEqualTo(arcAuthResultsExp); + assertThat(arcMsgSignature).isEqualTo(arcSignExp); + assertThat(arcSeal).isEqualTo(arcSealExp); + + //add new ARC set to the message and do chain validation on it + for (Map.Entry entry: arcSet.entrySet()){ + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + String cv = arcChainValidator.validateArcChain(message); + assertThat(cv).isEqualTo(expectedCv); + + } + + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { + URL resource = this.getClass().getResource(fileName); + FileInputStream file = new FileInputStream(new File(resource.toURI())); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + DKIMCommon.streamCopy(file, byteArrayOutputStream); + String string = byteArrayOutputStream.toString(); + return new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); + } + +} \ No newline at end of file diff --git a/arc/src/test/java/org/apache/james/arc/ArcTestKeys.java b/arc/src/test/java/org/apache/james/arc/ArcTestKeys.java new file mode 100644 index 0000000..cec4e7e --- /dev/null +++ b/arc/src/test/java/org/apache/james/arc/ArcTestKeys.java @@ -0,0 +1,80 @@ +/****************************************************************************** + * 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.arc; + +import org.apache.commons.codec.binary.Base64; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +public class ArcTestKeys { + public static final PrivateKey privateKeyArc = loadPrivateKey("keys/arc_test_pri.1.key"); + public static final PublicKey publicKeyArc = loadPublicKey("keys/arc_test_pub.1.pem"); + public static final PrivateKey privateKeyDkim = loadPrivateKey("keys/dkim_test_pri.1.key"); + public static final PublicKey publicKeyDkim = loadPublicKey("keys/dkim_test_pub.1.pem"); + public static final KeyPair keyPair = new KeyPair(publicKeyArc, privateKeyArc); + + private static PublicKey loadPublicKey(String uri) { + try { + String keyText = readFileContent(uri) + .replace("-----BEGIN PUBLIC KEY-----", "") + .replace("-----END PUBLIC KEY-----", "") + .replaceAll(System.lineSeparator(), ""); + byte[] encoded = Base64.decodeBase64(keyText); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); + return keyFactory.generatePublic(keySpec); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String readFileContent(String uri) throws URISyntaxException, IOException { + URL resource = ArcTestKeys.class.getClassLoader().getResource(uri); + File file = new File(resource.toURI()); + return new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset()); + } + + private static PrivateKey loadPrivateKey(String uri) { + try { + String keyText = readFileContent(uri) + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replaceAll(System.lineSeparator(), ""); + byte[] encoded = Base64.decodeBase64(keyText); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); + return keyFactory.generatePrivate(keySpec); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java b/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java new file mode 100644 index 0000000..2f78bc3 --- /dev/null +++ b/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java @@ -0,0 +1,70 @@ +package org.apache.james.arc; + +import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.jdkim.MockPublicKeyRecordRetriever; +import org.apache.james.jdkim.exceptions.PermFailException; +import org.apache.james.jdkim.exceptions.TempFailException; + +import java.util.List; + +public class MockPublicKeyRecordRetrieverArc extends MockPublicKeyRecordRetriever implements PublicKeyRetrieverArc { + + public static final String DMARC = "_dmarc."; + public static final String SPF = "_spf."; + public static class SpfRecord extends MockPublicKeyRecordRetriever.Record { + + public SpfRecord(String helo, String from, String ip, String spfRecord) { + super(SPF, ip + helo + from, spfRecord); + } + + public static SpfRecord spfOf(String helo, String from, String ip, String spfRecord) { + return new SpfRecord(helo, from, ip, spfRecord); + } + } + + public static class DmarcRecord extends MockPublicKeyRecordRetriever.Record { + + public DmarcRecord(String selector, String domain, String dmarcRecord) { + super(DMARC, domain, dmarcRecord); + } + + public static DmarcRecord dmarcOf(String selector, String domain, String dmarcRecord) { + return new DmarcRecord(selector, domain, dmarcRecord); + } + } + + public MockPublicKeyRecordRetrieverArc(Record... records) { + super(records); + } + + @Override + public String getSpfRecord(String helo, String from, String ip) { + try { + String token = ip + helo + from; + List recs = super.getRecords("dns/txt", SPF,token); + if (recs.isEmpty()) { + return null; + } + return recs.get(0); //TODO: multiple records? + } catch (TempFailException e) { + throw new ArcException("Temporary failure looking up DMARC record", e); + } catch (PermFailException e) { + throw new ArcException("Permanent failure looking up DMARC record", e); + } + } + + @Override + public String getDmarcRecord(String searchKey){ + try { + List recs = super.getRecords("dns/txt", DMARC,searchKey); + if (recs.isEmpty()) { + return null; + } + return recs.get(0); //TODO: multiple records? + } catch (TempFailException e) { + throw new ArcException("Temporary failure looking up DMARC record", e); + } catch (PermFailException e) { + throw new ArcException("Permanent failure looking up DMARC record", e); + } + } +} diff --git a/arc/src/test/resources/keys/arc_test_pri.1.key b/arc/src/test/resources/keys/arc_test_pri.1.key new file mode 100644 index 0000000..f196261 --- /dev/null +++ b/arc/src/test/resources/keys/arc_test_pri.1.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKmDF45YX+LMhwzV +4ZsskhMLGXRBGxs96cjNdgbsmhzUcpjW0Zaxzi7IimWR6IAPSZXkC+DjZ6UABxk7 +YfD8VZ7QV0SzMXk0RAnOHOLrxuQrav+jflKkvl5cdkstWLQLCFBIbsDsHebDM+sv +35Efo9yXQDEOTt8v56n81BAvzy5fAgMBAAECgYEAh14YwaPxbrzGXImw0KqXPH3w +pdYYP3kB6Umqp3zq1XsSyNtEJIN5lAKyAsqyURHkQb8LfVwcuLd887loTXo1JIFO +355B6JtZPnejIUinfmMgmDr3y1IXQf0RX8132X9C5o6r2SslIYrAHSjWWZlFAV6o +qGkVfieO/+c2vFjj/IECQQDZ67UuPUBybw/Ul/uj3TdmQ6YY+C8pBJGvorvOWYVC +Z6IznOissegIrPf9IyYNWmOG2628UCLpWtxy7ZmByCQ7AkEAxyHo/RS+6gzjCgZi +zScTyo8SV88gshs3t+xiiCBBEAWIgdQ7h6rbWqVvH7Nn8VhKerQmkcpDc3y47Mr5 +xeVwLQJBALCrOdCJ0dS0G2Zj7Js1PbOHhoHZuwoK7T0xtgYdZz6lm8cyHyPae12F +NOsg8rmCnQt4z0nKwfLjObNm0rt3kX8CQBrqMG2UkkFcQIuoVU5ZS8mDEP2hV0/7 +ccqAPskbYu/hb5PstacepstXtO9Z9mCeiGKRWu01o2xGnVAUFzJyUnkCQQCcEZzG +g+5OX+wNEMyfTY/kEUoue+ZtqXbuBOPnDOb+k+3Hrh8+q3tGwKg7w2jUU9DEwLtC +FHkx1Nnb8sURPTqy +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/arc/src/test/resources/keys/arc_test_pub.1.pem b/arc/src/test/resources/keys/arc_test_pub.1.pem new file mode 100644 index 0000000..288f28d --- /dev/null +++ b/arc/src/test/resources/keys/arc_test_pub.1.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpgxeOWF/izIcM1eGbLJITCxl0 +QRsbPenIzXYG7Joc1HKY1tGWsc4uyIplkeiAD0mV5Avg42elAAcZO2Hw/FWe0FdE +szF5NEQJzhzi68bkK2r/o35SpL5eXHZLLVi0CwhQSG7A7B3mwzPrL9+RH6Pcl0Ax +Dk7fL+ep/NQQL88uXwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/arc/src/test/resources/keys/dkim_test_pri.1.key b/arc/src/test/resources/keys/dkim_test_pri.1.key new file mode 100644 index 0000000..6bc101e --- /dev/null +++ b/arc/src/test/resources/keys/dkim_test_pri.1.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANLJL27JQ8P6OKae +DYzvu2OnAjgkBxcadreX0HtSNFvuHJYwUWrw93kQ3ZSajAS/TqD2LS8+pZ/0Ak5+ +S5WmBQXN/bBPWjbqos/vEFOu5uTx7qn1fSqMlJEGxFzq08mO4ZRIRwawKQ7AohPt +Ew6vEb205AU+moCUtbteU/rD2wV5AgMBAAECgYAaBeKIP+rQ2CSEVYEAxFwTKnw4 +qCID9S1w7xo7D2QNcXEwDZkPpd43oSBqB0aAE4pGjv33FjnmbH6YaDk2qX93BZY0 +ggXM0IMYkvmgnIh0/DKli2w0Fjx5pQJRl60FUnFlcQrdwp0HOfmDS28RHZZGMnLV +lv0a4bDtBK7/NxmFPQJBAPIewEh5a86hH5hF6S7NZ/cJX8twqbiq0xbY3Hm+3GcC +qbSuqxDgYZgtNySyP3N6GSTdZDYMUwspvpPciXJgbLcCQQDe3pYpa1m7qlPqgwyO +TcXbrbTKB3TSgMunVrYCMgkMMdEn2dPW4dnlpA+ZMPvjTd1tuh9AWLXRUAnm+Uv6 +209PAkEAnC9CEn5hEPXXD79pYIuYWT9u0ClpEnr/mGlkMBTy0HBjUO6r40MbMbNZ +Mw7Y54EH30QBdOwWVckj6vYEpAeXmQJAJVbdiar2qb5ruMqj++OD1r5Pn9mH9Qyn +Ei4w6EVBxs1B4Y9ZMpM8UoEeK+hNC1QsWQnp2noCXEMwpYX2+NxteQJAPofx2296 +wdac8Qhy8l7tk+WLPQWWbFlCmLkaX7Fd6z2KqUXXTt/YoL+LpxoWmgIkAKmdxssC +nIVcOf1X+NIxRg== +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/arc/src/test/resources/keys/dkim_test_pub.1.pem b/arc/src/test/resources/keys/dkim_test_pub.1.pem new file mode 100644 index 0000000..27d7983 --- /dev/null +++ b/arc/src/test/resources/keys/dkim_test_pub.1.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSyS9uyUPD+jimng2M77tjpwI4 +JAcXGna3l9B7UjRb7hyWMFFq8Pd5EN2UmowEv06g9i0vPqWf9AJOfkuVpgUFzf2w +T1o26qLP7xBTrubk8e6p9X0qjJSRBsRc6tPJjuGUSEcGsCkOwKIT7RMOrxG9tOQF +PpqAlLW7XlP6w9sFeQIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/arc/src/test/resources/mail/rfc8617_no_arc.eml b/arc/src/test/resources/mail/rfc8617_no_arc.eml new file mode 100644 index 0000000..2470990 --- /dev/null +++ b/arc/src/test/resources/mail/rfc8617_no_arc.eml @@ -0,0 +1,31 @@ +Return-Path: +Received: from example.org (example.org [208.69.40.157]) + by gmail.example with ESMTP id d200mr22663000ykb.93.1421363207 + for ; Thu, 14 Jan 2015 15:02:40 -0800 (PST) +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Received: from [2001:DB8::1A] (w-x-y-z.dsl.static.isp.example [w.x.y.z]) + (authenticated bits=0) + by segv.d1.example with ESMTP id t0FN4a8O084569; + Thu, 14 Jan 2015 15:00:01 -0800 (PST) + (envelope-from jqd@d1.example) +Received: from mail-ob0-f188.google.example + (mail-ob0-f188.google.example [208.69.40.157]) by + clochette.example.org with ESMTP id d200mr22663000ykb.93.1421363268 + for ; Thu, 14 Jan 2015 15:03:15 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.example +Subject: [List 2] Example 1 +DKIM-Signature: a=rsa-sha256; + b=iEn8fLQ/ymdoZ4EkI3ELK3dTcc4jqn1VOvbNZWAMzcZcFiSKSZXgJ9kgXlBv8JGqaLFjuQi3+p73Al9P2JJU4IkBF1PSHrTI6rcdPyTWMP5yL6vKrn0tu0VdPhwPmbEr4H0yhYqc0KPPPzbJw668zoharH9Ljq43W8mj6sGSN18=; + c=relaxed/relaxed; s=origin2015; d=d1.example; v=1; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; h=Subject:From:To; + +Hey gang, +This is a test message. +--J. + diff --git a/pom.xml b/pom.xml index 29fe43d..720ff59 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ assemble main + arc From 508fbc25ec7664bdc369115adecdbd63f039053f Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Wed, 8 Oct 2025 19:23:30 -0400 Subject: [PATCH 02/40] Update arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java Co-authored-by: Benoit TELLIER --- .../main/java/org/apache/james/arc/ArcSealVerifyData.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java b/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java index 2af6fcb..b8123aa 100644 --- a/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java +++ b/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java @@ -33,6 +33,8 @@ public void setB64Signature(String _b64) { public String getB64Signature() { return _b64; } - public String getSignedData() { return - _dataToVerify; } + + public String getSignedData() { + return _dataToVerify; + } } \ No newline at end of file From 0718f68328084e92e20494afb5c955c78aabdf8e Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Wed, 8 Oct 2025 19:28:22 -0400 Subject: [PATCH 03/40] Update arc/src/main/java/org/apache/james/arc/ARCChainValidator.java Co-authored-by: Benoit TELLIER --- arc/src/main/java/org/apache/james/arc/ARCChainValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index 2d251d8..ef10b6a 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -78,7 +78,7 @@ private String validatePreviousArcHops(Message message, Header messageHeaders, i int numArcInstances = myInstance -1; boolean isArcSetStructureOK = arcVerifier.validateArcSetStructure(arcHeadersByI); if (!isArcSetStructureOK) { - return "fail"; + return "fail"; } Set prevArcSet; From 353434ee3ec053cc492efb19baf8a5eea04c7d85 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Wed, 8 Oct 2025 19:28:58 -0400 Subject: [PATCH 04/40] Update arc/src/main/java/org/apache/james/arc/ARCChainValidator.java Co-authored-by: Benoit TELLIER --- arc/src/main/java/org/apache/james/arc/ARCChainValidator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index ef10b6a..d6d52ac 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -84,8 +84,8 @@ private String validatePreviousArcHops(Message message, Header messageHeaders, i Set prevArcSet; prevArcSet = arcVerifier.extractArcSet(messageHeaders, numArcInstances); if (prevArcSet != null) { - boolean amsOk = checkArcAms (prevArcSet, message, arcVerifier); - boolean asOk = checkArcSeal (messageHeaders.getFields(), numArcInstances, arcVerifier); + boolean amsOk = checkArcAms(prevArcSet, message, arcVerifier); + boolean asOk = checkArcSeal(messageHeaders.getFields(), numArcInstances, arcVerifier); if (amsOk && asOk) { return "pass"; } From 2bdeeca6652374ff1618b1dd0a6a41f2413986ec Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Wed, 8 Oct 2025 19:29:34 -0400 Subject: [PATCH 05/40] Update arc/src/main/java/org/apache/james/arc/ARCChainValidator.java Co-authored-by: Benoit TELLIER --- arc/src/main/java/org/apache/james/arc/ARCChainValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index d6d52ac..918e579 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -75,7 +75,7 @@ else if (curInstance > 51) { // Not allowed to be > 50 private String validatePreviousArcHops(Message message, Header messageHeaders, int myInstance) { ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); Map> arcHeadersByI = arcVerifier.getArcHeadersByI(messageHeaders.getFields()); - int numArcInstances = myInstance -1; + int numArcInstances = myInstance - 1; boolean isArcSetStructureOK = arcVerifier.validateArcSetStructure(arcHeadersByI); if (!isArcSetStructureOK) { return "fail"; From ce7b5ba85820909bbcd1786d7a3a2e268c74513f Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Wed, 8 Oct 2025 21:49:50 -0400 Subject: [PATCH 06/40] Refactor ARC to minimize dependencies and address some initial PR feedback - Introduced ArcValidationResult enum - Made ArcSealVerifyData immutable pojo - Removed dependency on geronimo.javamail - Removed dependency on Freemarker and simplified ARC templates - Updated versions in pom to pull them from the parent pom - Fixed missing licensing headers - Applied suggested style fixes --- arc/pom.xml | 16 +---- .../apache/james/arc/ARCChainValidator.java | 14 ++--- .../java/org/apache/james/arc/ARCCommon.java | 7 --- .../org/apache/james/arc/ARCVerifier.java | 24 ++++--- .../apache/james/arc/ArcSealVerifyData.java | 23 +++---- .../org/apache/james/arc/ArcSetBuilder.java | 29 ++++----- .../apache/james/arc/ArcValidationResult.java | 7 +++ .../apache/james/arc/AuthResultsBuilder.java | 63 +++++++++++-------- .../arc/DNSPublicKeyRecordRetrieverArc.java | 18 ++++++ .../james/arc/PublicKeyRetrieverArc.java | 18 ++++++ .../java/org/apache/james/arc/ARCTest.java | 7 +-- pom.xml | 1 + 12 files changed, 127 insertions(+), 100 deletions(-) create mode 100644 arc/src/main/java/org/apache/james/arc/ArcValidationResult.java diff --git a/arc/pom.xml b/arc/pom.xml index f586c09..b2d3eca 100644 --- a/arc/pom.xml +++ b/arc/pom.xml @@ -42,29 +42,19 @@ org.apache.james.jdkim apache-jdkim-library - 0.6-SNAPSHOT + ${project.version} org.apache.james.jdkim apache-jdkim-library - 0.6-SNAPSHOT + ${project.version} test-jar test org.apache.james.jspf apache-jspf-resolver - 1.0.5 - - - org.freemarker - freemarker - 2.3.31 - - - org.apache.geronimo.javamail - geronimo-javamail_1.4_mail - 1.6 + ${jspf-resolver.version} junit diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index 918e579..d50c094 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -56,29 +56,29 @@ public ARCChainValidator(PublicKeyRetrieverArc keyRecordRetriever) { this._keyRecordRetriever = keyRecordRetriever; } - public String validateArcChain(Message message) { + public ArcValidationResult validateArcChain(Message message) { Header messageHeaders = message.getHeader(); int curInstance = getCurrentInstance(messageHeaders); // Incremented by 1 if (curInstance == 1) { //we are the first ARC Hop and there is no previous ARC hops in the chain to validate - return "none"; + return ArcValidationResult.NONE; } else if (curInstance > 51) { // Not allowed to be > 50 - return "fail"; + return ArcValidationResult.FAIL; } else { // there are previous ARC hops that need to be validated return validatePreviousArcHops(message, messageHeaders, curInstance); } } - private String validatePreviousArcHops(Message message, Header messageHeaders, int myInstance) { + private ArcValidationResult validatePreviousArcHops(Message message, Header messageHeaders, int myInstance) { ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); Map> arcHeadersByI = arcVerifier.getArcHeadersByI(messageHeaders.getFields()); int numArcInstances = myInstance - 1; boolean isArcSetStructureOK = arcVerifier.validateArcSetStructure(arcHeadersByI); if (!isArcSetStructureOK) { - return "fail"; + return ArcValidationResult.FAIL; } Set prevArcSet; @@ -87,10 +87,10 @@ private String validatePreviousArcHops(Message message, Header messageHeaders, i boolean amsOk = checkArcAms(prevArcSet, message, arcVerifier); boolean asOk = checkArcSeal(messageHeaders.getFields(), numArcInstances, arcVerifier); if (amsOk && asOk) { - return "pass"; + return ArcValidationResult.PASS; } } - return "fail"; + return ArcValidationResult.FAIL; } private boolean checkArcAms(Set prevArcSet, Message message, ARCVerifier arcVerifier){ diff --git a/arc/src/main/java/org/apache/james/arc/ARCCommon.java b/arc/src/main/java/org/apache/james/arc/ARCCommon.java index 47c186f..44c1cab 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCCommon.java +++ b/arc/src/main/java/org/apache/james/arc/ARCCommon.java @@ -18,7 +18,6 @@ ****************************************************************/ package org.apache.james.arc; -import org.apache.james.arc.exceptions.ArcException; import org.apache.james.jdkim.api.Headers; import org.apache.james.jdkim.api.SignatureRecord; import org.apache.james.jdkim.exceptions.PermFailException; @@ -26,14 +25,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.security.Signature; import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Base64; import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index b84f57e..49d273f 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -308,7 +308,7 @@ public String parseTagGeneric(String record, String tag) { } public ArcSealVerifyData buildArcSealSigningData(Map> headersByI, int targetI) { - ArcSealVerifyData result = new ArcSealVerifyData(); + ArcSealVerifyData result = null; StringBuilder signingData = new StringBuilder(); //Iterate over hops in ascending i order, for the last hop, make sure to clear b= tag on the ARC-Seal @@ -336,18 +336,16 @@ public ArcSealVerifyData buildArcSealSigningData(Map> heade .append(":").append(canonicalizeBody(f.getBody())) .append("\r\n")); - if (hopI == targetI) { // this is last hop so we need to clear b= tag on the ARC-Seal Header and not tail it with CRLF - as.ifPresent(f -> { - Map tags = parseTagList(f.getBody()); - String signatureB64 = tags.get("b"); - String b64 = signatureB64 - .replaceAll("\\s+", "") // remove spaces, tabs, newlines - .replace(";", ""); - String arcSealBodyClearedB= f.getBody().replaceAll("\\bb=([^;]*)", "b="); - signingData.append(f.getName().toLowerCase(Locale.ROOT)).append(":").append(canonicalizeBody(arcSealBodyClearedB)); - result.setB64Signature(b64); - result.setSignedData(signingData.toString()); - }); + if (hopI == targetI && as.isPresent()) { // this is last hop so we need to clear b= tag on the ARC-Seal Header and not tail it with CRLF + Field asField = as.get(); + Map tags = parseTagList(asField.getBody()); + String signatureB64 = tags.get("b"); + String b64 = signatureB64.replaceAll("\\s+", "").replace(";", ""); + String arcSealBodyClearedB = asField.getBody().replaceAll("\\bb=([^;]*)", "b="); + signingData.append(asField.getName().toLowerCase(Locale.ROOT)) + .append(":").append(canonicalizeBody(arcSealBodyClearedB)); + result = new ArcSealVerifyData(b64, signingData.toString()); + break; // we have the target hop, can exit loop } else { // this is one of the previous hops, not the last one, so we want to preserve b= tag on the ARC-Seal and tail it with CRLF as.ifPresent(f -> signingData diff --git a/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java b/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java index b8123aa..12b449c 100644 --- a/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java +++ b/arc/src/main/java/org/apache/james/arc/ArcSealVerifyData.java @@ -18,23 +18,20 @@ ****************************************************************/ package org.apache.james.arc; -public class ArcSealVerifyData { - private String _b64; - private String _dataToVerify; +public final class ArcSealVerifyData { + private final String b64; + private final String dataToVerify; - public void setSignedData(String _dataToVerify) { - this._dataToVerify = _dataToVerify; - } - - public void setB64Signature(String _b64) { - this._b64 = _b64; + public ArcSealVerifyData(String b64, String dataToVerify) { + this.b64 = b64; + this.dataToVerify = dataToVerify; } public String getB64Signature() { - return _b64; + return b64; } - + public String getSignedData() { - return _dataToVerify; - } + return dataToVerify; + } } \ No newline at end of file diff --git a/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java b/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java index e121105..fccc46e 100644 --- a/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java +++ b/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java @@ -25,8 +25,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.StringWriter; import java.security.PrivateKey; import java.time.Instant; import java.util.HashMap; @@ -102,7 +100,7 @@ public Map buildArcSet(Message message, String helo, String mail Header headers = message.getHeader(); ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); AuthResultsBuilder authResultsBuilder = new AuthResultsBuilder(_dmarcResponse, _dmarcNonResponse, _authService, keyRecordRetriever); - String cv = arcChainValidator.validateArcChain(message); + String cv = arcChainValidator.validateArcChain(message).name().toLowerCase(); int instance = arcChainValidator.getCurrentInstance(headers); //Build ARC-Authentication-Results header @@ -131,7 +129,7 @@ public Map buildArcSet(Message message, String helo, String mail fmContext.put("cv", cv); //Build and add ARC-AMS header - String amsTemplate = mergeTemplate(_arcAmsTemplate, fmContext); + String amsTemplate = fillArcTemplate(_arcAmsTemplate, instance, timestamp); ARCSigner amsSigner = new ARCSigner(amsTemplate, _arcPrivateKey); String amsHeader = amsSigner.generateAms(new ByteArrayInputStream(os.toByteArray())); String amsValue = amsHeader.split(ARC_ELEMENT)[1]; @@ -139,7 +137,7 @@ public Map buildArcSet(Message message, String helo, String mail headersToSeal.put(ARC_MESSAGE_SIGNATURE, amsValue); //Build and add ARC-Seal header - String asTemplate = mergeTemplate(_arcSealTemplate, fmContext); + String asTemplate = fillArcSealTemplate(_arcSealTemplate, instance, timestamp, cv); ARCSigner asSigner = new ARCSigner(asTemplate, _arcPrivateKey); String asHeader = asSigner.sealHeaders(headersToSeal ); String asValue = asHeader.split(ARC_ELEMENT)[1]; @@ -151,17 +149,14 @@ public Map buildArcSet(Message message, String helo, String mail return arcHeaders; } - private String mergeTemplate(String templateString, Map context) throws IOException { - try (StringWriter writer = new StringWriter()) { - freemarker.template.Configuration cfg = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_31); - cfg.setTemplateLoader(new freemarker.cache.StringTemplateLoader()); - freemarker.cache.StringTemplateLoader loader = (freemarker.cache.StringTemplateLoader) cfg.getTemplateLoader(); - loader.putTemplate("template", templateString); - freemarker.template.Template template = cfg.getTemplate("template"); - template.process(context, writer); - return writer.toString(); - } catch (freemarker.template.TemplateException e) { - throw new IOException("Error merging template", e); - } + private String fillArcSealTemplate(String template, int instance, long timestamp, String cv) { + String filledCv = template.replaceAll("cv=\\s*;", "cv=" + cv + ";"); + return fillArcTemplate(filledCv, instance, timestamp); + } + + private String fillArcTemplate(String template, int instance, long timestamp) { + return template + .replaceAll("i=\\s*;", "i=" + instance + ";") + .replaceAll("t=\\s*;", "t=" + timestamp + ";"); } } diff --git a/arc/src/main/java/org/apache/james/arc/ArcValidationResult.java b/arc/src/main/java/org/apache/james/arc/ArcValidationResult.java new file mode 100644 index 0000000..18c669a --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ArcValidationResult.java @@ -0,0 +1,7 @@ +package org.apache.james.arc; + +public enum ArcValidationResult { + NONE, + PASS, + FAIL +} diff --git a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java index a7f34e5..85b1553 100644 --- a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java +++ b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java @@ -28,8 +28,6 @@ import org.apache.james.mime4j.dom.Message; import org.apache.james.mime4j.message.DefaultMessageWriter; -import javax.mail.internet.AddressException; -import javax.mail.internet.InternetAddress; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -75,7 +73,6 @@ public String getAuthResultsHeader(Message message, String helo, String from, St // 1. Run SPF check String spfResultText = _keyRecordRetriever.getSpfRecord(helo, from, ip); - // 2. Run DKIM verification String dkimResultFull; try { @@ -170,17 +167,12 @@ private String extractDkimDomain(String dkimResultFull) { private String runDmarcCheck(Message message, String spfHeaderText, String spfDomain, String dkim, String dkimDomain) { // Combine SPF + DKIM results with From: domain // 1. Extract RFC5322.From domain from the From header of the message - String shortSpfResut = spfHeaderText.split(" ")[0]; + String shortSpfResult = spfHeaderText.split(" ")[0]; String fromHeader = message.getHeader().getField(FROM).getBody(); - String fromDomain = getFromDomain(fromHeader); + String fromDomain = extractDomain(fromHeader); if (fromDomain == null || fromDomain.isEmpty()) { return _dmarcNoneResponse + "unknown"; } - try { - fromDomain = new InternetAddress(fromHeader).getAddress().split("@")[1]; - } catch (AddressException e) { - throw new ArcException("Internet address error", e); - } // 2. Fetch DMARC record from DNS ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); @@ -196,7 +188,7 @@ private String runDmarcCheck(Message message, String spfHeaderText, String spfDo // String adkim = parseTag(dmarcRecord, "adkim"); // optional // 3. Alignment checks - boolean spfAligned = "pass".equals(shortSpfResut) && fromDomain.equalsIgnoreCase(spfDomain); + boolean spfAligned = "pass".equals(shortSpfResult) && fromDomain.equalsIgnoreCase(spfDomain); boolean dkimAligned = "pass".equals(dkim) && fromDomain.equalsIgnoreCase(dkimDomain); // 4. DMARC result logic @@ -211,24 +203,43 @@ private String runDmarcCheck(Message message, String spfHeaderText, String spfDo return String.format(_dmarcResponse, result, policy, fromDomain); } - private String getFromDomain(String fromHeader) { - String fromDomain = null; - if (fromHeader.contains("<") && fromHeader.contains(">")) { - int start = fromHeader.indexOf('<'); - int end = fromHeader.indexOf('>'); - if (start != -1 && end != -1 && end > start) { - String email = fromHeader.substring(start + 1, end); - fromDomain = email.split("@")[1]; - } + // Using own parser to avoid dependency on javax.mail which does not handle all From: formats + // e.g. From: "dpw demo Date: Wed, 8 Oct 2025 15:36:51 -0400" " + private String extractDomain(String fromHeader) throws ArcException { + if (fromHeader == null || fromHeader.isEmpty()) { + throw new ArcException("From header is empty"); } - else { - try { - fromDomain = new InternetAddress(fromHeader).getAddress().split("@")[1]; - } catch (AddressException e) { - throw new ArcException("Internet address error", e); + + // Extract address inside <...> + String address = fromHeader; + int lt = fromHeader.indexOf('<'); + int gt = fromHeader.indexOf('>'); + if (lt != -1 && gt != -1 && gt > lt) { + address = fromHeader.substring(lt + 1, gt).trim(); + } else { + // No brackets — just finding raw address + int at = fromHeader.indexOf('@'); + if (at == -1) { + throw new ArcException("Invalid From header: " + fromHeader); + } + + // Lookin for something@domain + String[] parts = fromHeader.split("\\s+"); + for (String part : parts) { + if (part.contains("@")) { + address = part; + break; + } } } - return fromDomain; + + // And finally extracting the domain + int atIndex = address.lastIndexOf('@'); + if (atIndex == -1 || atIndex == address.length() - 1) { + throw new ArcException("Invalid email address: " + fromHeader); + } + + return address.substring(atIndex + 1); } private InputStream messageToInputStream(Message message) throws IOException { diff --git a/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java b/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java index d08e210..a23d61a 100644 --- a/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java +++ b/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java @@ -1,3 +1,21 @@ +/**************************************************************** + * 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.arc; import org.apache.james.arc.exceptions.ArcException; diff --git a/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java b/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java index 905d75a..7e12860 100644 --- a/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java +++ b/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java @@ -1,3 +1,21 @@ +/**************************************************************** + * 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.arc; import org.apache.james.jdkim.api.PublicKeyRecordRetriever; diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index a4bebc6..f50a1e5 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -71,9 +71,8 @@ public class ARCTest { * - "bh=" and "b=" placeholder are required for now because the same implementation is used for * signing and verifying. The fields are mandatory for verifying. */ - //Todo: replace freemarker templates with something less heavy weight - private static final String ARC_AMS_TEMPLATE = "i=${instance}; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; t=${timestamp}; h=Subject:From:To; bh=; b="; - private static final String ARC_SEAL_TEMPLATE = "i=${instance}; cv=${cv}; a=rsa-sha256; d=dmarc.example; s=arc; t=${timestamp}; b="; + private static final String ARC_AMS_TEMPLATE = "i=; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; t=; h=Subject:From:To; bh=; b="; + private static final String ARC_SEAL_TEMPLATE = "i=; cv=; a=rsa-sha256; d=dmarc.example; s=arc; t=; b="; private static final String AUTH_SERVICE = "smtp.d1.example"; private static final String HELO = "d1.example"; @@ -119,7 +118,7 @@ public void generate_and_verify_arc_set() throws Exception { } ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); - String cv = arcChainValidator.validateArcChain(message); + String cv = arcChainValidator.validateArcChain(message).name().toLowerCase(); assertThat(cv).isEqualTo(expectedCv); } diff --git a/pom.xml b/pom.xml index 720ff59..8b3a6e8 100644 --- a/pom.xml +++ b/pom.xml @@ -67,6 +67,7 @@ 1.8 4.13.2 11 + 1.0.5 From 28386ff72685a8f5b2a6b13cd31d899ea0a082a3 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Oct 2025 16:22:45 -0400 Subject: [PATCH 07/40] Rework DMARK and reduce dependencies - Rewired DMARC into separate module - Added relaxed header alignment for DMARC using PSL list - Removed commons-codec dependency --- arc/pom.xml | 12 +- .../org/apache/james/arc/ARCVerifier.java | 17 - .../apache/james/arc/ArcValidationResult.java | 18 + .../apache/james/arc/AuthResultsBuilder.java | 83 +- .../arc/DNSPublicKeyRecordRetrieverArc.java | 49 +- .../james/arc/PublicKeyRetrieverArc.java | 5 +- .../java/org/apache/james/arc/ARCTest.java | 21 +- .../org/apache/james/arc/ArcTestKeys.java | 12 +- .../arc/MockPublicKeyRecordRetrieverArc.java | 53 +- .../org/apache/james/dmarc/DMARCVerifier.java | 137 + .../DNSPublicKeyRecordRetrieverDmarc.java | 75 + .../dmarc/PublicKeyRecordRetrieverDmarc.java | 26 + .../apache/james/dmarc/PublicSuffixList.java | 70 + .../dmarc/exceptions/DmarcException.java | 30 + .../src/main/resources/public_suffix_list.dat | 15997 ++++++++++++++++ .../org/apache/james/dmarc/DMARCTest.java | 56 + .../apache/james/dmarc/DmarcRequestMock.java | 77 + .../MockPublicKeyRecordRetrieverDmarc.java | 65 + .../james/dmarc/PublicSuffixListTest.java | 60 + dmarc/src/main/test/resources/mail/e1.eml | 31 + dmarc/src/main/test/resources/mail/e2.eml | 14 + dmarc/src/main/test/resources/mail/e3.eml | 14 + pom.xml | 1 + 23 files changed, 16735 insertions(+), 188 deletions(-) create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/DNSPublicKeyRecordRetrieverDmarc.java create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/PublicKeyRecordRetrieverDmarc.java create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/exceptions/DmarcException.java create mode 100644 dmarc/src/main/resources/public_suffix_list.dat create mode 100644 dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java create mode 100644 dmarc/src/main/test/java/org/apache/james/dmarc/DmarcRequestMock.java create mode 100644 dmarc/src/main/test/java/org/apache/james/dmarc/MockPublicKeyRecordRetrieverDmarc.java create mode 100644 dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java create mode 100644 dmarc/src/main/test/resources/mail/e1.eml create mode 100644 dmarc/src/main/test/resources/mail/e2.eml create mode 100644 dmarc/src/main/test/resources/mail/e3.eml diff --git a/arc/pom.xml b/arc/pom.xml index b2d3eca..820ffb6 100644 --- a/arc/pom.xml +++ b/arc/pom.xml @@ -36,8 +36,16 @@ - commons-codec - commons-codec + org.apache.james.jdkim + apache-dmarc-library + ${project.version} + + + org.apache.james.jdkim + apache-dmarc-library + ${project.version} + test-jar + test org.apache.james.jdkim diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 49d273f..b831dfc 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -167,23 +167,6 @@ private String canonicalizeHeader(String name, String value) { return n + ":" + v; } - private PublicKey getPublicKeyFromTxtRecord(String keyText) { - - keyText = keyText.replaceAll("\\s+", ""); // remove ALL spaces/newlines - byte[] keyBytes = Base64.getDecoder().decode(keyText); - - X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); - PublicKey pubKey; - try { - pubKey = KeyFactory.getInstance(RSA).generatePublic(spec); - } catch (InvalidKeySpecException e) { - throw new ArcException("Invalid key provided when getting public key", e); - } catch (NoSuchAlgorithmException e) { - throw new ArcException("Unsupported algorithm provided when getting public key", e); - } - return pubKey; - } - public PublicKey parsePublicKeyFromDns(String dnsRecord) { Matcher m = PUBLIC_KEY_PATTERN.matcher(dnsRecord); diff --git a/arc/src/main/java/org/apache/james/arc/ArcValidationResult.java b/arc/src/main/java/org/apache/james/arc/ArcValidationResult.java index 18c669a..a549919 100644 --- a/arc/src/main/java/org/apache/james/arc/ArcValidationResult.java +++ b/arc/src/main/java/org/apache/james/arc/ArcValidationResult.java @@ -1,3 +1,21 @@ +/**************************************************************** + * 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.arc; public enum ArcValidationResult { diff --git a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java index 85b1553..5c82937 100644 --- a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java +++ b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java @@ -19,6 +19,7 @@ package org.apache.james.arc; import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.dmarc.DMARCVerifier; import org.apache.james.jdkim.DKIMVerifier; import org.apache.james.jdkim.api.SignatureRecord; import org.apache.james.jdkim.exceptions.FailException; @@ -54,7 +55,6 @@ *

*/ public class AuthResultsBuilder { - public static final String FROM = "From"; public static final String HEADER_I = "header.i="; private final PublicKeyRetrieverArc _keyRecordRetriever; private String _dmarcNoneResponse; @@ -85,7 +85,8 @@ public String getAuthResultsHeader(Message message, String helo, String from, St // 3. Run DMARC check (using SPF + DKIM results + From domain) String dkimDomain = extractDkimDomain(dkimResultFull); String spfDomain = extractSpfDomain(spfResultText); - String dmarcResult = runDmarcCheck(message, spfResultText, spfDomain, dkimResultShort, dkimDomain); + DMARCVerifier dmarcVerifier = new DMARCVerifier(_dmarcResponse, _dmarcNoneResponse, _keyRecordRetriever.getDmarcRetriever()); + String dmarcResult = dmarcVerifier.runDmarcCheck(message, spfResultText, spfDomain, dkimResultShort, dkimDomain); if (dmarcResult == null || dmarcResult.isEmpty()) { dmarcResult = _dmarcNoneResponse + spfDomain; } @@ -164,84 +165,6 @@ private String extractDkimDomain(String dkimResultFull) { return null; } - private String runDmarcCheck(Message message, String spfHeaderText, String spfDomain, String dkim, String dkimDomain) { - // Combine SPF + DKIM results with From: domain - // 1. Extract RFC5322.From domain from the From header of the message - String shortSpfResult = spfHeaderText.split(" ")[0]; - String fromHeader = message.getHeader().getField(FROM).getBody(); - String fromDomain = extractDomain(fromHeader); - if (fromDomain == null || fromDomain.isEmpty()) { - return _dmarcNoneResponse + "unknown"; - } - - // 2. Fetch DMARC record from DNS - ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); - - String dmarcRecord = arcVerifier.getPublicKeyRecordRetriever().getDmarcRecord(fromDomain); - if (dmarcRecord == null) { - return _dmarcNoneResponse + fromDomain; - } - - // Parse DMARC policy - String policy = arcVerifier.parseTagGeneric(dmarcRecord, "p"); // p=none|quarantine|reject -// String aspf = parseTag(dmarcRecord, "aspf"); // optional -// String adkim = parseTag(dmarcRecord, "adkim"); // optional - - // 3. Alignment checks - boolean spfAligned = "pass".equals(shortSpfResult) && fromDomain.equalsIgnoreCase(spfDomain); - boolean dkimAligned = "pass".equals(dkim) && fromDomain.equalsIgnoreCase(dkimDomain); - - // 4. DMARC result logic - String result; - if (spfAligned || dkimAligned) { - result = "pass"; - } else { - result = "fail"; - } - - // 5. Build Authentication-Results string - return String.format(_dmarcResponse, result, policy, fromDomain); - } - - // Using own parser to avoid dependency on javax.mail which does not handle all From: formats - // e.g. From: "dpw demo Date: Wed, 8 Oct 2025 15:36:51 -0400" " - private String extractDomain(String fromHeader) throws ArcException { - if (fromHeader == null || fromHeader.isEmpty()) { - throw new ArcException("From header is empty"); - } - - // Extract address inside <...> - String address = fromHeader; - int lt = fromHeader.indexOf('<'); - int gt = fromHeader.indexOf('>'); - if (lt != -1 && gt != -1 && gt > lt) { - address = fromHeader.substring(lt + 1, gt).trim(); - } else { - // No brackets — just finding raw address - int at = fromHeader.indexOf('@'); - if (at == -1) { - throw new ArcException("Invalid From header: " + fromHeader); - } - - // Lookin for something@domain - String[] parts = fromHeader.split("\\s+"); - for (String part : parts) { - if (part.contains("@")) { - address = part; - break; - } - } - } - - // And finally extracting the domain - int atIndex = address.lastIndexOf('@'); - if (atIndex == -1 || atIndex == address.length() - 1) { - throw new ArcException("Invalid email address: " + fromHeader); - } - - return address.substring(atIndex + 1); - } - private InputStream messageToInputStream(Message message) throws IOException { DefaultMessageWriter writer = new DefaultMessageWriter(); ByteArrayOutputStream os = new ByteArrayOutputStream(); diff --git a/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java b/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java index a23d61a..44813f8 100644 --- a/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java +++ b/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java @@ -18,23 +18,14 @@ ****************************************************************/ package org.apache.james.arc; -import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.dmarc.DNSPublicKeyRecordRetrieverDmarc; +import org.apache.james.dmarc.PublicKeyRecordRetrieverDmarc; import org.apache.james.jdkim.impl.DNSPublicKeyRecordRetriever; import org.apache.james.jspf.impl.DefaultSPF; import org.apache.james.jspf.impl.SPF; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; -import java.util.Hashtable; - public class DNSPublicKeyRecordRetrieverArc extends DNSPublicKeyRecordRetriever implements PublicKeyRetrieverArc { - public static final String JAVA_NAMING_FACTORY_INITIAL = "java.naming.factory.initial"; - public static final String COM_SUN_JNDI_DNS_DNS_CONTEXT_FACTORY = "com.sun.jndi.dns.DnsContextFactory"; - public static final String TXT = "TXT"; + public static final DNSPublicKeyRecordRetrieverDmarc DMARC = new DNSPublicKeyRecordRetrieverDmarc(); public DNSPublicKeyRecordRetrieverArc() { super(); @@ -48,37 +39,7 @@ public String getSpfRecord(String helo, String from, String ip) { } @Override - public String getDmarcRecord(String dnsLabel) { - Hashtable env = new Hashtable<>(); - env.put(JAVA_NAMING_FACTORY_INITIAL, COM_SUN_JNDI_DNS_DNS_CONTEXT_FACTORY); - DirContext ctx; - dnsLabel = "_dmarc." + dnsLabel; - try { - ctx = new InitialDirContext(env); - } catch (NamingException e) { - throw new ArcException(String.format("Naming error when creating InitialDirContext using [%s]", dnsLabel), e); - } - - Attributes attrs; - try { - attrs = ctx.getAttributes(dnsLabel, new String[]{TXT}); - } catch (NamingException e) { - throw new ArcException(String.format("Naming error when getting attributes using [%s]", dnsLabel), e); - } - - Attribute txtAttr = attrs.get(TXT); - try { - if (txtAttr != null) { - StringBuilder sb = new StringBuilder(); - NamingEnumeration e = txtAttr.getAll(); - while (e.hasMore()) { - sb.append(e.next().toString().replace("\"", "")); - } - return sb.toString(); - } - } catch (NamingException e) { - throw new ArcException(String.format("Naming error when looping through attributes using [%s]", dnsLabel), e); - } - return null; + public PublicKeyRecordRetrieverDmarc getDmarcRetriever() { + return DMARC; } } diff --git a/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java b/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java index 7e12860..50dc70e 100644 --- a/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java +++ b/arc/src/main/java/org/apache/james/arc/PublicKeyRetrieverArc.java @@ -18,11 +18,12 @@ ****************************************************************/ package org.apache.james.arc; +import org.apache.james.dmarc.PublicKeyRecordRetrieverDmarc; import org.apache.james.jdkim.api.PublicKeyRecordRetriever; public interface PublicKeyRetrieverArc extends PublicKeyRecordRetriever { - String getDmarcRecord(String query); - String getSpfRecord(String helo, String from, String ip); + + PublicKeyRecordRetrieverDmarc getDmarcRetriever(); } diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index f50a1e5..a38b8c3 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -16,10 +16,9 @@ * specific language governing permissions and limitations * * under the License. * ******************************************************************************/ - package org.apache.james.arc; -import org.apache.commons.codec.binary.Base64; +import org.apache.james.dmarc.MockPublicKeyRecordRetrieverDmarc; import org.apache.james.jdkim.DKIMCommon; import org.apache.james.jdkim.MockPublicKeyRecordRetriever; import org.apache.james.mime4j.dom.Message; @@ -27,6 +26,7 @@ import org.apache.james.mime4j.stream.RawField; import org.junit.Test; +import java.util.Base64; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -45,20 +45,23 @@ public class ARCTest { public static final String ARC_MESSAGE_SIGNATURE = "ARC-Message-Signature"; public static final String ARC_SEAL = "ARC-Seal"; - private final MockPublicKeyRecordRetrieverArc keyRecordRetriever = new MockPublicKeyRecordRetrieverArc( + private final MockPublicKeyRecordRetrieverDmarc dmarcRetriever = new MockPublicKeyRecordRetrieverDmarc( + MockPublicKeyRecordRetrieverDmarc.DmarcRecord.dmarcOf( + "d1.example", + "k=rsa; v=DMARC1; p=reject; pct=100; rua=mailto:noc@d1.example" + ) + ); + + private final MockPublicKeyRecordRetrieverArc keyRecordRetriever = new MockPublicKeyRecordRetrieverArc( dmarcRetriever, MockPublicKeyRecordRetriever.Record.of( "arc", "dmarc.example", - "k=rsa; p=" + Base64.encodeBase64String(ArcTestKeys.publicKeyArc.getEncoded()) + ";" + "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";" ), MockPublicKeyRecordRetriever.Record.of( "origin2015", "d1.example", - "k=rsa; p=" + Base64.encodeBase64String(ArcTestKeys.publicKeyDkim.getEncoded()) + ";" - ), - MockPublicKeyRecordRetrieverArc.DmarcRecord.dmarcOf("", - "d1.example", - "k=rsa; v=DMARC1; p=reject; pct=100; rua=mailto:noc@d1.example" + "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyDkim.getEncoded()) + ";" ), MockPublicKeyRecordRetrieverArc.SpfRecord.spfOf("d1.example", "jqd@d1.example", diff --git a/arc/src/test/java/org/apache/james/arc/ArcTestKeys.java b/arc/src/test/java/org/apache/james/arc/ArcTestKeys.java index cec4e7e..4178a33 100644 --- a/arc/src/test/java/org/apache/james/arc/ArcTestKeys.java +++ b/arc/src/test/java/org/apache/james/arc/ArcTestKeys.java @@ -16,11 +16,9 @@ * specific language governing permissions and limitations * * under the License. * ******************************************************************************/ - package org.apache.james.arc; -import org.apache.commons.codec.binary.Base64; - +import java.util.Base64; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; @@ -47,9 +45,9 @@ private static PublicKey loadPublicKey(String uri) { .replace("-----BEGIN PUBLIC KEY-----", "") .replace("-----END PUBLIC KEY-----", "") .replaceAll(System.lineSeparator(), ""); - byte[] encoded = Base64.decodeBase64(keyText); + byte[] decoded = Base64.getDecoder().decode(keyText); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded); return keyFactory.generatePublic(keySpec); } catch (Exception e) { throw new RuntimeException(e); @@ -68,9 +66,9 @@ private static PrivateKey loadPrivateKey(String uri) { .replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll(System.lineSeparator(), ""); - byte[] encoded = Base64.decodeBase64(keyText); + byte[] decoded = Base64.getDecoder().decode(keyText); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded); return keyFactory.generatePrivate(keySpec); } catch (Exception e) { throw new RuntimeException(e); diff --git a/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java b/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java index 2f78bc3..71d0505 100644 --- a/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java +++ b/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java @@ -1,6 +1,25 @@ +/****************************************************************************** + * 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.arc; import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.dmarc.MockPublicKeyRecordRetrieverDmarc; import org.apache.james.jdkim.MockPublicKeyRecordRetriever; import org.apache.james.jdkim.exceptions.PermFailException; import org.apache.james.jdkim.exceptions.TempFailException; @@ -9,8 +28,9 @@ public class MockPublicKeyRecordRetrieverArc extends MockPublicKeyRecordRetriever implements PublicKeyRetrieverArc { - public static final String DMARC = "_dmarc."; public static final String SPF = "_spf."; + private final MockPublicKeyRecordRetrieverDmarc _dmarcRetriever; + public static class SpfRecord extends MockPublicKeyRecordRetriever.Record { public SpfRecord(String helo, String from, String ip, String spfRecord) { @@ -22,19 +42,9 @@ public static SpfRecord spfOf(String helo, String from, String ip, String spfRec } } - public static class DmarcRecord extends MockPublicKeyRecordRetriever.Record { - - public DmarcRecord(String selector, String domain, String dmarcRecord) { - super(DMARC, domain, dmarcRecord); - } - - public static DmarcRecord dmarcOf(String selector, String domain, String dmarcRecord) { - return new DmarcRecord(selector, domain, dmarcRecord); - } - } - - public MockPublicKeyRecordRetrieverArc(Record... records) { + public MockPublicKeyRecordRetrieverArc(MockPublicKeyRecordRetrieverDmarc dmarcRetriever, Record... records) { super(records); + _dmarcRetriever = dmarcRetriever; } @Override @@ -45,7 +55,7 @@ public String getSpfRecord(String helo, String from, String ip) { if (recs.isEmpty()) { return null; } - return recs.get(0); //TODO: multiple records? + return recs.getFirst(); } catch (TempFailException e) { throw new ArcException("Temporary failure looking up DMARC record", e); } catch (PermFailException e) { @@ -53,18 +63,7 @@ public String getSpfRecord(String helo, String from, String ip) { } } - @Override - public String getDmarcRecord(String searchKey){ - try { - List recs = super.getRecords("dns/txt", DMARC,searchKey); - if (recs.isEmpty()) { - return null; - } - return recs.get(0); //TODO: multiple records? - } catch (TempFailException e) { - throw new ArcException("Temporary failure looking up DMARC record", e); - } catch (PermFailException e) { - throw new ArcException("Permanent failure looking up DMARC record", e); - } + public MockPublicKeyRecordRetrieverDmarc getDmarcRetriever() { + return _dmarcRetriever; } } diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java new file mode 100644 index 0000000..4d0c9a0 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java @@ -0,0 +1,137 @@ +/****************************************************************************** + * 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.dmarc; + +import org.apache.james.dmarc.exceptions.DmarcException; +import org.apache.james.mime4j.dom.Message; + +public class DMARCVerifier { + public static final String FROM = "From"; + private final String _dmarcResponse; + private final String _dmarcNonResponse; + private final PublicKeyRecordRetrieverDmarc _recordRetriever; + + public DMARCVerifier(String dmarcResponse, String dmarcNonResponse, PublicKeyRecordRetrieverDmarc recordRetriever) { + _dmarcResponse = dmarcResponse; + _dmarcNonResponse = dmarcNonResponse; + _recordRetriever = recordRetriever; + } + + public String runDmarcCheck(Message message, String spfHeaderText, String + spfDomain, String dkimResult, String dkimDomain){ + // Combine SPF + DKIM results with From: domain + // 1. Extract RFC5322.From domain from the From header of the message + String shortSpfResult = spfHeaderText.split(" ")[0]; + String fromHeader = message.getHeader().getField(FROM).getBody(); + String fromDomain = extractDomain(fromHeader); + if (fromDomain == null || fromDomain.isEmpty()) { + return _dmarcNonResponse + "unknown"; + } + + // 2. Fetch DMARC record from DNS + String dmarcRecord = _recordRetriever.getDmarcRecord(fromDomain); + if (dmarcRecord == null) { + return _dmarcNonResponse + fromDomain; + } + + // Parse DMARC policy + String policy = parseTag(dmarcRecord, "p"); // p=none|quarantine|reject + String aspf = parseTag(dmarcRecord, "aspf"); // "s" or "r" for strict or relaxed domain alignment; default is "r" + String adkim = parseTag(dmarcRecord, "adkim"); // "s" or "r" for strict or relaxed domain alignment; default is "r" + + // 3. Alignment checks + boolean spfAligned = getDomainAlignment(aspf, shortSpfResult, fromDomain, spfDomain); + boolean dkimAligned = getDomainAlignment(adkim, dkimResult, fromDomain, dkimDomain); + + // 4. DMARC result logic + String result; + if (spfAligned || dkimAligned) { + result = "pass"; + } else { + result = "fail"; + } + + // 5. Build Authentication-Results string + return String.format(_dmarcResponse, result, policy, fromDomain); + } + + private boolean getDomainAlignment(String flag, String result, String receivedDomain, String expectedDomain) { + // we expect flag to be either "s" or "r"; default is "r" + if (flag == null || flag.equalsIgnoreCase("r")){ //relaxed + String fromOrgDomain = PublicSuffixList.getOrgDomain(receivedDomain); //we get the organizational domain using PSL + String spfOrgDomain = PublicSuffixList.getOrgDomain(expectedDomain); + + return "pass".equals(result) + && fromOrgDomain.equalsIgnoreCase(spfOrgDomain); + } + else if (flag.equalsIgnoreCase("s")){ // strict + return "pass".equals(result) && receivedDomain.equalsIgnoreCase(expectedDomain); + } + else { + throw new DmarcException(String.format("Unknown alignment flag value: %s", flag)); + } + } + + private String extractDomain(String fromHeader) throws DmarcException { + if (fromHeader == null || fromHeader.isEmpty()) { + throw new DmarcException("From header is empty"); + } + + // Extract address inside <...> + String address = fromHeader; + int lt = fromHeader.indexOf('<'); + int gt = fromHeader.indexOf('>'); + if (lt != -1 && gt != -1 && gt > lt) { + address = fromHeader.substring(lt + 1, gt).trim(); + } else { + // No brackets — just finding raw address + int at = fromHeader.indexOf('@'); + if (at == -1) { + throw new DmarcException("Invalid From header: " + fromHeader); + } + + // Lookin for something@domain + String[] parts = fromHeader.split("\\s+"); + for (String part : parts) { + if (part.contains("@")) { + address = part; + break; + } + } + } + + // And finally extracting the domain + int atIndex = address.lastIndexOf('@'); + if (atIndex == -1 || atIndex == address.length() - 1) { + throw new DmarcException("Invalid email address: " + fromHeader); + } + return address.substring(atIndex + 1); + } + + public String parseTag(String dmarcRecord, String tag) { + String[] parts = dmarcRecord.split(";"); + for (String part : parts) { + String trimmed = part.trim(); + if (trimmed.startsWith(tag + "=")) { + return trimmed.substring((tag + "=").length()); + } + } + return null; + } +} diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DNSPublicKeyRecordRetrieverDmarc.java b/dmarc/src/main/java/org/apache/james/dmarc/DNSPublicKeyRecordRetrieverDmarc.java new file mode 100644 index 0000000..c73e4f2 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/DNSPublicKeyRecordRetrieverDmarc.java @@ -0,0 +1,75 @@ +/**************************************************************** + * 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.dmarc; + +import org.apache.james.dmarc.exceptions.DmarcException; +import org.apache.james.jdkim.impl.DNSPublicKeyRecordRetriever; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import java.util.Hashtable; + +public class DNSPublicKeyRecordRetrieverDmarc extends DNSPublicKeyRecordRetriever implements PublicKeyRecordRetrieverDmarc { + public static final String JAVA_NAMING_FACTORY_INITIAL = "java.naming.factory.initial"; + public static final String COM_SUN_JNDI_DNS_DNS_CONTEXT_FACTORY = "com.sun.jndi.dns.DnsContextFactory"; + public static final String TXT = "TXT"; + + public DNSPublicKeyRecordRetrieverDmarc() { + super(); + } + + @Override + public String getDmarcRecord(String dnsLabel) { + Hashtable env = new Hashtable<>(); + env.put(JAVA_NAMING_FACTORY_INITIAL, COM_SUN_JNDI_DNS_DNS_CONTEXT_FACTORY); + DirContext ctx; + dnsLabel = "_dmarc." + dnsLabel; + try { + ctx = new InitialDirContext(env); + } catch (NamingException e) { + throw new DmarcException(String.format("Naming error when creating InitialDirContext using [%s]", dnsLabel), e); + } + + Attributes attrs; + try { + attrs = ctx.getAttributes(dnsLabel, new String[]{TXT}); + } catch (NamingException e) { + throw new DmarcException(String.format("Naming error when getting attributes using [%s]", dnsLabel), e); + } + + Attribute txtAttr = attrs.get(TXT); + try { + if (txtAttr != null) { + StringBuilder sb = new StringBuilder(); + NamingEnumeration e = txtAttr.getAll(); + while (e.hasMore()) { + sb.append(e.next().toString().replace("\"", "")); + } + return sb.toString(); + } + } catch (NamingException e) { + throw new DmarcException(String.format("Naming error when looping through attributes using [%s]", dnsLabel), e); + } + return null; + } +} diff --git a/dmarc/src/main/java/org/apache/james/dmarc/PublicKeyRecordRetrieverDmarc.java b/dmarc/src/main/java/org/apache/james/dmarc/PublicKeyRecordRetrieverDmarc.java new file mode 100644 index 0000000..3576131 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/PublicKeyRecordRetrieverDmarc.java @@ -0,0 +1,26 @@ +/****************************************************************************** + * 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.dmarc; + +import org.apache.james.jdkim.api.PublicKeyRecordRetriever; + +public interface PublicKeyRecordRetrieverDmarc extends PublicKeyRecordRetriever { + + String getDmarcRecord(String query); +} diff --git a/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java b/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java new file mode 100644 index 0000000..23ebd48 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java @@ -0,0 +1,70 @@ +/****************************************************************************** + * 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.dmarc; + +import org.apache.james.dmarc.exceptions.DmarcException; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class PublicSuffixList { + private static final Set SUFFIXES = new HashSet<>(); + + static { + try (InputStream is = PublicSuffixList.class.getResourceAsStream("/public_suffix_list.dat")) { + assert is != null; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("//")) continue; + SUFFIXES.add(line.toLowerCase()); + } + } + } catch (Exception e) { + throw new DmarcException("Failed to load Public Suffix List", e); + } + } + + private PublicSuffixList() {} + + public static boolean isPublicSuffix(String domain) { + return SUFFIXES.contains(domain.toLowerCase()); + } + + public static String getOrgDomain(String receivedDomain) { + String[] parts = receivedDomain.toLowerCase().split("\\."); + for (int i = 0; i < parts.length - 1; i++) { + //we start checking from the most specific part on the left moving to the right until we find a match + String candidate = String.join(".", Arrays.copyOfRange(parts, i, parts.length)); + if (isPublicSuffix(candidate)) { + return candidate; + } + } + return receivedDomain; + } + + static void main() { + System.out.println(getOrgDomain("id.replit.app")); // example.co.uk + } +} \ No newline at end of file diff --git a/dmarc/src/main/java/org/apache/james/dmarc/exceptions/DmarcException.java b/dmarc/src/main/java/org/apache/james/dmarc/exceptions/DmarcException.java new file mode 100644 index 0000000..bf3aea7 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/exceptions/DmarcException.java @@ -0,0 +1,30 @@ +/**************************************************************** + * 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.dmarc.exceptions; + +public class DmarcException extends RuntimeException { + + public DmarcException(String message) { + super(message); + } + + public DmarcException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/dmarc/src/main/resources/public_suffix_list.dat b/dmarc/src/main/resources/public_suffix_list.dat new file mode 100644 index 0000000..d047478 --- /dev/null +++ b/dmarc/src/main/resources/public_suffix_list.dat @@ -0,0 +1,15997 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +// Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat, +// rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported. + +// VERSION: 2025-10-13_13-22-32_UTC +// COMMIT: c002d19a8ca969110dd8a3838d972ca293bdc48f + +// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/. + +// ===BEGIN ICANN DOMAINS=== + +// ac : http://nic.ac/rules.htm +ac +com.ac +edu.ac +gov.ac +mil.ac +net.ac +org.ac + +// ad : https://www.iana.org/domains/root/db/ad.html +// Confirmed by Amadeu Abril i Abril (CORE) 2024-11-17 +ad + +// ae : https://www.iana.org/domains/root/db/ae.html +ae +ac.ae +co.ae +gov.ae +mil.ae +net.ae +org.ae +sch.ae + +// aero : https://information.aero/registration/policies/dmp +aero +// 2LDs +airline.aero +airport.aero +// 2LDs (currently not accepting registration, seemingly never have) +// As of 2024-07, these are marked as reserved for potential 3LD +// registrations (clause 11 "allocated subdomains" in the 2006 TLD +// policy), but the relevant industry partners have not opened them up +// for registration. Current status can be determined from the TLD's +// policy document: 2LDs that are open for registration must list +// their policy in the TLD's policy. Any 2LD without such a policy is +// not open for registrations. +accident-investigation.aero +accident-prevention.aero +aerobatic.aero +aeroclub.aero +aerodrome.aero +agents.aero +air-surveillance.aero +air-traffic-control.aero +aircraft.aero +airtraffic.aero +ambulance.aero +association.aero +author.aero +ballooning.aero +broker.aero +caa.aero +cargo.aero +catering.aero +certification.aero +championship.aero +charter.aero +civilaviation.aero +club.aero +conference.aero +consultant.aero +consulting.aero +control.aero +council.aero +crew.aero +design.aero +dgca.aero +educator.aero +emergency.aero +engine.aero +engineer.aero +entertainment.aero +equipment.aero +exchange.aero +express.aero +federation.aero +flight.aero +freight.aero +fuel.aero +gliding.aero +government.aero +groundhandling.aero +group.aero +hanggliding.aero +homebuilt.aero +insurance.aero +journal.aero +journalist.aero +leasing.aero +logistics.aero +magazine.aero +maintenance.aero +marketplace.aero +media.aero +microlight.aero +modelling.aero +navigation.aero +parachuting.aero +paragliding.aero +passenger-association.aero +pilot.aero +press.aero +production.aero +recreation.aero +repbody.aero +res.aero +research.aero +rotorcraft.aero +safety.aero +scientist.aero +services.aero +show.aero +skydiving.aero +software.aero +student.aero +taxi.aero +trader.aero +trading.aero +trainer.aero +union.aero +workinggroup.aero +works.aero + +// af : https://www.nic.af/domain-price +af +com.af +edu.af +gov.af +net.af +org.af + +// ag : http://www.nic.ag/prices.htm +ag +co.ag +com.ag +net.ag +nom.ag +org.ag + +// ai : http://nic.com.ai/ +ai +com.ai +net.ai +off.ai +org.ai + +// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 +al +com.al +edu.al +gov.al +mil.al +net.al +org.al + +// am : https://www.amnic.net/policy/en/Policy_EN.pdf +// Confirmed by ISOC AM 2024-11-18 +am +co.am +com.am +commune.am +net.am +org.am + +// ao : https://www.iana.org/domains/root/db/ao.html +// https://www.dns.ao/ao/ +ao +co.ao +ed.ao +edu.ao +gov.ao +gv.ao +it.ao +og.ao +org.ao +pb.ao + +// aq : https://www.iana.org/domains/root/db/aq.html +aq + +// ar : https://nic.ar/es/nic-argentina/normativa +ar +bet.ar +com.ar +coop.ar +edu.ar +gob.ar +gov.ar +int.ar +mil.ar +musica.ar +mutual.ar +net.ar +org.ar +seg.ar +senasa.ar +tur.ar + +// arpa : https://www.iana.org/domains/root/db/arpa.html +// Confirmed by registry 2008-06-18 +arpa +e164.arpa +home.arpa +in-addr.arpa +ip6.arpa +iris.arpa +uri.arpa +urn.arpa + +// as : https://www.iana.org/domains/root/db/as.html +as +gov.as + +// asia : https://www.iana.org/domains/root/db/asia.html +asia + +// at : https://www.iana.org/domains/root/db/at.html +// Confirmed by registry 2008-06-17 +at +ac.at +sth.ac.at +co.at +gv.at +or.at + +// au : https://www.iana.org/domains/root/db/au.html +// https://www.auda.org.au/ +// Confirmed by registry 2025-07-16 +au +// 2LDs +asn.au +com.au +edu.au +gov.au +id.au +net.au +org.au +// Historic 2LDs (closed to new registration, but sites still exist) +conf.au +oz.au +// CGDNs : https://www.auda.org.au/au-domain-names/the-different-au-domain-names/state-and-territory-domain-names/ +act.au +nsw.au +nt.au +qld.au +sa.au +tas.au +vic.au +wa.au +// 3LDs +act.edu.au +catholic.edu.au +// eq.edu.au - Removed at the request of the Queensland Department of Education +nsw.edu.au +nt.edu.au +qld.edu.au +sa.edu.au +tas.edu.au +vic.edu.au +wa.edu.au +// act.gov.au - Bug 984824 - Removed at request of Greg Tankard +// nsw.gov.au - Bug 547985 - Removed at request of +// nt.gov.au - Bug 940478 - Removed at request of Greg Connors +qld.gov.au +sa.gov.au +tas.gov.au +vic.gov.au +wa.gov.au +// 4LDs +// education.tas.edu.au - Removed at the request of the Department of Education Tasmania +// schools.nsw.edu.au - Removed at the request of the New South Wales Department of Education. + +// aw : https://www.iana.org/domains/root/db/aw.html +aw +com.aw + +// ax : https://www.iana.org/domains/root/db/ax.html +ax + +// az : https://www.iana.org/domains/root/db/az.html +// Confirmed via https://whois.az/?page_id=10 2024-12-11 +az +biz.az +co.az +com.az +edu.az +gov.az +info.az +int.az +mil.az +name.az +net.az +org.az +pp.az +// No longer available for registration, however domains exist as of 2024-12-11 +// see https://whois.az/?page_id=783 +pro.az + +// ba : https://www.iana.org/domains/root/db/ba.html +ba +com.ba +edu.ba +gov.ba +mil.ba +net.ba +org.ba + +// bb : https://www.iana.org/domains/root/db/bb.html +bb +biz.bb +co.bb +com.bb +edu.bb +gov.bb +info.bb +net.bb +org.bb +store.bb +tv.bb + +// bd : https://www.iana.org/domains/root/db/bd.html +*.bd + +// be : https://www.iana.org/domains/root/db/be.html +// Confirmed by registry 2008-06-08 +be +ac.be + +// bf : https://www.iana.org/domains/root/db/bf.html +bf +gov.bf + +// bg : https://www.iana.org/domains/root/db/bg.html +// https://www.register.bg/user/static/rules/en/index.html +bg +0.bg +1.bg +2.bg +3.bg +4.bg +5.bg +6.bg +7.bg +8.bg +9.bg +a.bg +b.bg +c.bg +d.bg +e.bg +f.bg +g.bg +h.bg +i.bg +j.bg +k.bg +l.bg +m.bg +n.bg +o.bg +p.bg +q.bg +r.bg +s.bg +t.bg +u.bg +v.bg +w.bg +x.bg +y.bg +z.bg + +// bh : https://www.iana.org/domains/root/db/bh.html +bh +com.bh +edu.bh +gov.bh +net.bh +org.bh + +// bi : https://www.iana.org/domains/root/db/bi.html +// http://whois.nic.bi/ +bi +co.bi +com.bi +edu.bi +or.bi +org.bi + +// biz : https://www.iana.org/domains/root/db/biz.html +biz + +// bj : https://nic.bj/bj-suffixes.txt +// Submitted by registry +bj +africa.bj +agro.bj +architectes.bj +assur.bj +avocats.bj +co.bj +com.bj +eco.bj +econo.bj +edu.bj +info.bj +loisirs.bj +money.bj +net.bj +org.bj +ote.bj +restaurant.bj +resto.bj +tourism.bj +univ.bj + +// bm : https://www.bermudanic.bm/domain-registration/index.php +bm +com.bm +edu.bm +gov.bm +net.bm +org.bm + +// bn : http://www.bnnic.bn/faqs +bn +com.bn +edu.bn +gov.bn +net.bn +org.bn + +// bo : https://nic.bo +// Confirmed by registry 2024-11-19 +bo +com.bo +edu.bo +gob.bo +int.bo +mil.bo +net.bo +org.bo +tv.bo +web.bo +// Social Domains +academia.bo +agro.bo +arte.bo +blog.bo +bolivia.bo +ciencia.bo +cooperativa.bo +democracia.bo +deporte.bo +ecologia.bo +economia.bo +empresa.bo +indigena.bo +industria.bo +info.bo +medicina.bo +movimiento.bo +musica.bo +natural.bo +nombre.bo +noticias.bo +patria.bo +plurinacional.bo +politica.bo +profesional.bo +pueblo.bo +revista.bo +salud.bo +tecnologia.bo +tksat.bo +transporte.bo +wiki.bo + +// br : http://registro.br/dominio/categoria.html +// Submitted by registry +br +9guacu.br +abc.br +adm.br +adv.br +agr.br +aju.br +am.br +anani.br +aparecida.br +api.br +app.br +arq.br +art.br +ato.br +b.br +barueri.br +belem.br +bet.br +bhz.br +bib.br +bio.br +blog.br +bmd.br +boavista.br +bsb.br +campinagrande.br +campinas.br +caxias.br +cim.br +cng.br +cnt.br +com.br +contagem.br +coop.br +coz.br +cri.br +cuiaba.br +curitiba.br +def.br +des.br +det.br +dev.br +ecn.br +eco.br +edu.br +emp.br +enf.br +eng.br +esp.br +etc.br +eti.br +far.br +feira.br +flog.br +floripa.br +fm.br +fnd.br +fortal.br +fot.br +foz.br +fst.br +g12.br +geo.br +ggf.br +goiania.br +gov.br +// gov.br 26 states + df https://en.wikipedia.org/wiki/States_of_Brazil +ac.gov.br +al.gov.br +am.gov.br +ap.gov.br +ba.gov.br +ce.gov.br +df.gov.br +es.gov.br +go.gov.br +ma.gov.br +mg.gov.br +ms.gov.br +mt.gov.br +pa.gov.br +pb.gov.br +pe.gov.br +pi.gov.br +pr.gov.br +rj.gov.br +rn.gov.br +ro.gov.br +rr.gov.br +rs.gov.br +sc.gov.br +se.gov.br +sp.gov.br +to.gov.br +gru.br +ia.br +imb.br +ind.br +inf.br +jab.br +jampa.br +jdf.br +joinville.br +jor.br +jus.br +leg.br +leilao.br +lel.br +log.br +londrina.br +macapa.br +maceio.br +manaus.br +maringa.br +mat.br +med.br +mil.br +morena.br +mp.br +mus.br +natal.br +net.br +niteroi.br +*.nom.br +not.br +ntr.br +odo.br +ong.br +org.br +osasco.br +palmas.br +poa.br +ppg.br +pro.br +psc.br +psi.br +pvh.br +qsl.br +radio.br +rec.br +recife.br +rep.br +ribeirao.br +rio.br +riobranco.br +riopreto.br +salvador.br +sampa.br +santamaria.br +santoandre.br +saobernardo.br +saogonca.br +seg.br +sjc.br +slg.br +slz.br +social.br +sorocaba.br +srv.br +taxi.br +tc.br +tec.br +teo.br +the.br +tmp.br +trd.br +tur.br +tv.br +udi.br +vet.br +vix.br +vlog.br +wiki.br +xyz.br +zlg.br + +// bs : http://www.nic.bs/rules.html +bs +com.bs +edu.bs +gov.bs +net.bs +org.bs + +// bt : https://www.iana.org/domains/root/db/bt.html +bt +com.bt +edu.bt +gov.bt +net.bt +org.bt + +// bv : No registrations at this time. +// Submitted by registry +bv + +// bw : https://www.iana.org/domains/root/db/bw.html +// https://nic.net.bw/bw-name-structure +bw +ac.bw +co.bw +gov.bw +net.bw +org.bw + +// by : https://www.iana.org/domains/root/db/by.html +// http://tld.by/rules_2006_en.html +// list of other 2nd level tlds ? +by +gov.by +mil.by +// Official information does not indicate that com.by is a reserved +// second-level domain, but it's being used as one (see www.google.com.by and +// www.yahoo.com.by, for example), so we list it here for safety's sake. +com.by +// http://hoster.by/ +of.by + +// bz : https://www.iana.org/domains/root/db/bz.html +// http://www.belizenic.bz/ +bz +co.bz +com.bz +edu.bz +gov.bz +net.bz +org.bz + +// ca : https://www.iana.org/domains/root/db/ca.html +ca +// ca geographical names +ab.ca +bc.ca +mb.ca +nb.ca +nf.ca +nl.ca +ns.ca +nt.ca +nu.ca +on.ca +pe.ca +qc.ca +sk.ca +yk.ca +// gc.ca: https://en.wikipedia.org/wiki/.gc.ca +// see also: http://registry.gc.ca/en/SubdomainFAQ +gc.ca + +// cat : https://www.iana.org/domains/root/db/cat.html +cat + +// cc : https://www.iana.org/domains/root/db/cc.html +cc + +// cd : https://www.iana.org/domains/root/db/cd.html +// https://www.nic.cd +cd +gov.cd + +// cf : https://www.iana.org/domains/root/db/cf.html +cf + +// cg : https://www.iana.org/domains/root/db/cg.html +cg + +// ch : https://www.iana.org/domains/root/db/ch.html +ch + +// ci : https://www.iana.org/domains/root/db/ci.html +ci +ac.ci +aéroport.ci +asso.ci +co.ci +com.ci +ed.ci +edu.ci +go.ci +gouv.ci +int.ci +net.ci +or.ci +org.ci + +// ck : https://www.iana.org/domains/root/db/ck.html +*.ck +!www.ck + +// cl : https://www.nic.cl +// Confirmed by .CL registry +cl +co.cl +gob.cl +gov.cl +mil.cl + +// cm : https://www.iana.org/domains/root/db/cm.html plus bug 981927 +cm +co.cm +com.cm +gov.cm +net.cm + +// cn : https://www.iana.org/domains/root/db/cn.html +// Submitted by registry +cn +ac.cn +com.cn +edu.cn +gov.cn +mil.cn +net.cn +org.cn +公司.cn +網絡.cn +网络.cn +// cn geographic names +ah.cn +bj.cn +cq.cn +fj.cn +gd.cn +gs.cn +gx.cn +gz.cn +ha.cn +hb.cn +he.cn +hi.cn +hk.cn +hl.cn +hn.cn +jl.cn +js.cn +jx.cn +ln.cn +mo.cn +nm.cn +nx.cn +qh.cn +sc.cn +sd.cn +sh.cn +sn.cn +sx.cn +tj.cn +tw.cn +xj.cn +xz.cn +yn.cn +zj.cn + +// co : https://www.iana.org/domains/root/db/co.html +// https://www.cointernet.com.co/como-funciona-un-dominio-restringido +// Confirmed by registry 2024-11-18 +co +com.co +edu.co +gov.co +mil.co +net.co +nom.co +org.co + +// com : https://www.iana.org/domains/root/db/com.html +com + +// coop : https://www.iana.org/domains/root/db/coop.html +coop + +// cr : https://nic.cr/capitulo-1-registro-de-un-nombre-de-dominio/ +cr +ac.cr +co.cr +ed.cr +fi.cr +go.cr +or.cr +sa.cr + +// cu : https://www.iana.org/domains/root/db/cu.html +cu +com.cu +edu.cu +gob.cu +inf.cu +nat.cu +net.cu +org.cu + +// cv : https://www.iana.org/domains/root/db/cv.html +// https://ola.cv/domain-extensions-under-cv/ +// Confirmed by registry 2024-11-26 +cv +com.cv +edu.cv +id.cv +int.cv +net.cv +nome.cv +org.cv +publ.cv + +// cw : https://www.uoc.cw/cw-registry +// Confirmed by registry 2024-11-19 +cw +com.cw +edu.cw +net.cw +org.cw + +// cx : https://www.iana.org/domains/root/db/cx.html +// list of other 2nd level tlds ? +cx +gov.cx + +// cy : http://www.nic.cy/ +// Submitted by Panayiotou Fotia +// https://nic.cy/wp-content/uploads/2024/01/Create-Request-for-domain-name-registration-1.pdf +cy +ac.cy +biz.cy +com.cy +ekloges.cy +gov.cy +ltd.cy +mil.cy +net.cy +org.cy +press.cy +pro.cy +tm.cy + +// cz : https://www.iana.org/domains/root/db/cz.html +// Confirmed by registry 2025-08-06 +cz +gov.cz + +// de : https://www.iana.org/domains/root/db/de.html +// Confirmed by registry (with technical +// reservations) 2008-07-01 +de + +// dj : https://www.iana.org/domains/root/db/dj.html +dj + +// dk : https://www.iana.org/domains/root/db/dk.html +// Confirmed by registry 2008-06-17 +dk + +// dm : https://www.iana.org/domains/root/db/dm.html +// https://nic.dm/policies/pdf/DMRulesandGuidelines2024v1.pdf +// Confirmed by registry 2024-11-19 +dm +co.dm +com.dm +edu.dm +gov.dm +net.dm +org.dm + +// do : https://www.iana.org/domains/root/db/do.html +do +art.do +com.do +edu.do +gob.do +gov.do +mil.do +net.do +org.do +sld.do +web.do + +// dz : http://www.nic.dz/images/pdf_nic/charte.pdf +dz +art.dz +asso.dz +com.dz +edu.dz +gov.dz +net.dz +org.dz +pol.dz +soc.dz +tm.dz + +// ec : https://www.nic.ec/ +// Submitted by registry +ec +abg.ec +adm.ec +agron.ec +arqt.ec +art.ec +bar.ec +chef.ec +com.ec +cont.ec +cpa.ec +cue.ec +dent.ec +dgn.ec +disco.ec +doc.ec +edu.ec +eng.ec +esm.ec +fin.ec +fot.ec +gal.ec +gob.ec +gov.ec +gye.ec +ibr.ec +info.ec +k12.ec +lat.ec +loj.ec +med.ec +mil.ec +mktg.ec +mon.ec +net.ec +ntr.ec +odont.ec +org.ec +pro.ec +prof.ec +psic.ec +psiq.ec +pub.ec +rio.ec +rrpp.ec +sal.ec +tech.ec +tul.ec +tur.ec +uio.ec +vet.ec +xxx.ec + +// edu : https://www.iana.org/domains/root/db/edu.html +edu + +// ee : https://www.internet.ee/domains/general-domains-and-procedure-for-registration-of-sub-domains-under-general-domains +ee +aip.ee +com.ee +edu.ee +fie.ee +gov.ee +lib.ee +med.ee +org.ee +pri.ee +riik.ee + +// eg : https://www.iana.org/domains/root/db/eg.html +// https://domain.eg/en/domain-rules/subdomain-names-types/ +eg +ac.eg +com.eg +edu.eg +eun.eg +gov.eg +info.eg +me.eg +mil.eg +name.eg +net.eg +org.eg +sci.eg +sport.eg +tv.eg + +// er : https://www.iana.org/domains/root/db/er.html +*.er + +// es : https://www.dominios.es/en +es +com.es +edu.es +gob.es +nom.es +org.es + +// et : https://www.iana.org/domains/root/db/et.html +et +biz.et +com.et +edu.et +gov.et +info.et +name.et +net.et +org.et + +// eu : https://www.iana.org/domains/root/db/eu.html +eu + +// fi : https://www.iana.org/domains/root/db/fi.html +fi +// aland.fi : https://www.iana.org/domains/root/db/ax.html +// This domain is being phased out in favor of .ax. As there are still many +// domains under aland.fi, we still keep it on the list until aland.fi is +// completely removed. +aland.fi + +// fj : http://domains.fj/ +// Submitted by registry 2020-02-11 +fj +ac.fj +biz.fj +com.fj +gov.fj +info.fj +mil.fj +name.fj +net.fj +org.fj +pro.fj + +// fk : https://www.iana.org/domains/root/db/fk.html +*.fk + +// fm : https://www.iana.org/domains/root/db/fm.html +fm +com.fm +edu.fm +net.fm +org.fm + +// fo : https://www.iana.org/domains/root/db/fo.html +fo + +// fr : https://www.afnic.fr/ https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf +fr +asso.fr +com.fr +gouv.fr +nom.fr +prd.fr +tm.fr +// Other SLDs now selfmanaged out of AFNIC range. Former "domaines sectoriels", still registration suffixes +avoues.fr +cci.fr +greta.fr +huissier-justice.fr + +// ga : https://www.iana.org/domains/root/db/ga.html +ga + +// gb : This registry is effectively dormant +// Submitted by registry +gb + +// gd : https://www.iana.org/domains/root/db/gd.html +gd +edu.gd +gov.gd + +// ge : https://nic.ge/en/administrator/the-ge-domain-regulations +// Confirmed by registry 2024-11-20 +ge +com.ge +edu.ge +gov.ge +net.ge +org.ge +pvt.ge +school.ge + +// gf : https://www.iana.org/domains/root/db/gf.html +gf + +// gg : https://www.channelisles.net/register-1/register-direct +// Confirmed by registry 2013-11-28 +gg +co.gg +net.gg +org.gg + +// gh : https://www.iana.org/domains/root/db/gh.html +// https://www.nic.gh/ +// Although domains directly at second level are not possible at the moment, +// they have been possible for some time and may come back. +gh +biz.gh +com.gh +edu.gh +gov.gh +mil.gh +net.gh +org.gh + +// gi : http://www.nic.gi/rules.html +gi +com.gi +edu.gi +gov.gi +ltd.gi +mod.gi +org.gi + +// gl : https://www.iana.org/domains/root/db/gl.html +// http://nic.gl +gl +co.gl +com.gl +edu.gl +net.gl +org.gl + +// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm +gm + +// gn : http://psg.com/dns/gn/gn.txt +// Submitted by registry +gn +ac.gn +com.gn +edu.gn +gov.gn +net.gn +org.gn + +// gov : https://www.iana.org/domains/root/db/gov.html +gov + +// gp : http://www.nic.gp/index.php?lang=en +gp +asso.gp +com.gp +edu.gp +mobi.gp +net.gp +org.gp + +// gq : https://www.iana.org/domains/root/db/gq.html +gq + +// gr : https://www.iana.org/domains/root/db/gr.html +// Submitted by registry +gr +com.gr +edu.gr +gov.gr +net.gr +org.gr + +// gs : https://www.iana.org/domains/root/db/gs.html +gs + +// gt : https://www.gt/sitio/registration_policy.php?lang=en +gt +com.gt +edu.gt +gob.gt +ind.gt +mil.gt +net.gt +org.gt + +// gu : http://gadao.gov.gu/register.html +// University of Guam : https://www.uog.edu +// Submitted by uognoc@triton.uog.edu +gu +com.gu +edu.gu +gov.gu +guam.gu +info.gu +net.gu +org.gu +web.gu + +// gw : https://www.iana.org/domains/root/db/gw.html +// gw : https://nic.gw/regras/ +gw + +// gy : https://www.iana.org/domains/root/db/gy.html +// http://registry.gy/ +gy +co.gy +com.gy +edu.gy +gov.gy +net.gy +org.gy + +// hk : https://www.hkirc.hk +// Submitted by registry +hk +com.hk +edu.hk +gov.hk +idv.hk +net.hk +org.hk +个人.hk +個人.hk +公司.hk +政府.hk +敎育.hk +教育.hk +箇人.hk +組織.hk +組织.hk +網絡.hk +網络.hk +组織.hk +组织.hk +网絡.hk +网络.hk + +// hm : https://www.iana.org/domains/root/db/hm.html +hm + +// hn : https://www.iana.org/domains/root/db/hn.html +hn +com.hn +edu.hn +gob.hn +mil.hn +net.hn +org.hn + +// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf +hr +com.hr +from.hr +iz.hr +name.hr + +// ht : http://www.nic.ht/info/charte.cfm +ht +adult.ht +art.ht +asso.ht +com.ht +coop.ht +edu.ht +firm.ht +gouv.ht +info.ht +med.ht +net.ht +org.ht +perso.ht +pol.ht +pro.ht +rel.ht +shop.ht + +// hu : https://www.iana.org/domains/root/db/hu.html +// Confirmed by registry 2008-06-12 +hu +2000.hu +agrar.hu +bolt.hu +casino.hu +city.hu +co.hu +erotica.hu +erotika.hu +film.hu +forum.hu +games.hu +hotel.hu +info.hu +ingatlan.hu +jogasz.hu +konyvelo.hu +lakas.hu +media.hu +news.hu +org.hu +priv.hu +reklam.hu +sex.hu +shop.hu +sport.hu +suli.hu +szex.hu +tm.hu +tozsde.hu +utazas.hu +video.hu + +// id : https://www.iana.org/domains/root/db/id.html +id +ac.id +biz.id +co.id +desa.id +go.id +kop.id +mil.id +my.id +net.id +or.id +ponpes.id +sch.id +web.id + +// ie : https://www.iana.org/domains/root/db/ie.html +ie +gov.ie + +// il : http://www.isoc.org.il/domains/ +// see also: https://en.isoc.org.il/il-cctld/registration-rules +// ISOC-IL (operated by .il Registry) +il +ac.il +co.il +gov.il +idf.il +k12.il +muni.il +net.il +org.il +// xn--4dbrk0ce ("Israel", Hebrew) : IL +ישראל +// xn--4dbgdty6c.xn--4dbrk0ce. +אקדמיה.ישראל +// xn--5dbhl8d.xn--4dbrk0ce. +ישוב.ישראל +// xn--8dbq2a.xn--4dbrk0ce. +צהל.ישראל +// xn--hebda8b.xn--4dbrk0ce. +ממשל.ישראל + +// im : https://www.nic.im/ +// Submitted by registry +im +ac.im +co.im +ltd.co.im +plc.co.im +com.im +net.im +org.im +tt.im +tv.im + +// in : https://www.iana.org/domains/root/db/in.html +// see also: https://registry.in/policies +// Please note, that nic.in is not an official eTLD, but used by most +// government institutions. +in +5g.in +6g.in +ac.in +ai.in +am.in +bihar.in +biz.in +business.in +ca.in +cn.in +co.in +com.in +coop.in +cs.in +delhi.in +dr.in +edu.in +er.in +firm.in +gen.in +gov.in +gujarat.in +ind.in +info.in +int.in +internet.in +io.in +me.in +mil.in +net.in +nic.in +org.in +pg.in +post.in +pro.in +res.in +travel.in +tv.in +uk.in +up.in +us.in + +// info : https://www.iana.org/domains/root/db/info.html +info + +// int : https://www.iana.org/domains/root/db/int.html +// Confirmed by registry 2008-06-18 +int +eu.int + +// io : http://www.nic.io/rules.htm +io +co.io +com.io +edu.io +gov.io +mil.io +net.io +nom.io +org.io + +// iq : http://www.cmc.iq/english/iq/iqregister1.htm +iq +com.iq +edu.iq +gov.iq +mil.iq +net.iq +org.iq + +// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules +// Also see http://www.nic.ir/Internationalized_Domain_Names +// Two .ir entries added at request of , 2010-04-16 +ir +ac.ir +co.ir +gov.ir +id.ir +net.ir +org.ir +sch.ir +// xn--mgba3a4f16a.ir (.ir, Persian YEH) +ایران.ir +// xn--mgba3a4fra.ir (.ir, Arabic YEH) +ايران.ir + +// is : http://www.isnic.is/domain/rules.php +// Confirmed by registry 2024-11-17 +is + +// it : https://www.iana.org/domains/root/db/it.html +// https://www.nic.it/ +it +edu.it +gov.it +// Regions (3.3.1) +// https://www.nic.it/en/manage-your-it/forms-and-docs -> "Assignment and Management of domain names" +abr.it +abruzzo.it +aosta-valley.it +aostavalley.it +bas.it +basilicata.it +cal.it +calabria.it +cam.it +campania.it +emilia-romagna.it +emiliaromagna.it +emr.it +friuli-v-giulia.it +friuli-ve-giulia.it +friuli-vegiulia.it +friuli-venezia-giulia.it +friuli-veneziagiulia.it +friuli-vgiulia.it +friuliv-giulia.it +friulive-giulia.it +friulivegiulia.it +friulivenezia-giulia.it +friuliveneziagiulia.it +friulivgiulia.it +fvg.it +laz.it +lazio.it +lig.it +liguria.it +lom.it +lombardia.it +lombardy.it +lucania.it +mar.it +marche.it +mol.it +molise.it +piedmont.it +piemonte.it +pmn.it +pug.it +puglia.it +sar.it +sardegna.it +sardinia.it +sic.it +sicilia.it +sicily.it +taa.it +tos.it +toscana.it +trentin-sud-tirol.it +trentin-süd-tirol.it +trentin-sudtirol.it +trentin-südtirol.it +trentin-sued-tirol.it +trentin-suedtirol.it +trentino.it +trentino-a-adige.it +trentino-aadige.it +trentino-alto-adige.it +trentino-altoadige.it +trentino-s-tirol.it +trentino-stirol.it +trentino-sud-tirol.it +trentino-süd-tirol.it +trentino-sudtirol.it +trentino-südtirol.it +trentino-sued-tirol.it +trentino-suedtirol.it +trentinoa-adige.it +trentinoaadige.it +trentinoalto-adige.it +trentinoaltoadige.it +trentinos-tirol.it +trentinostirol.it +trentinosud-tirol.it +trentinosüd-tirol.it +trentinosudtirol.it +trentinosüdtirol.it +trentinosued-tirol.it +trentinosuedtirol.it +trentinsud-tirol.it +trentinsüd-tirol.it +trentinsudtirol.it +trentinsüdtirol.it +trentinsued-tirol.it +trentinsuedtirol.it +tuscany.it +umb.it +umbria.it +val-d-aosta.it +val-daosta.it +vald-aosta.it +valdaosta.it +valle-aosta.it +valle-d-aosta.it +valle-daosta.it +valleaosta.it +valled-aosta.it +valledaosta.it +vallee-aoste.it +vallée-aoste.it +vallee-d-aoste.it +vallée-d-aoste.it +valleeaoste.it +valléeaoste.it +valleedaoste.it +valléedaoste.it +vao.it +vda.it +ven.it +veneto.it +// Provinces (3.3.2) +ag.it +agrigento.it +al.it +alessandria.it +alto-adige.it +altoadige.it +an.it +ancona.it +andria-barletta-trani.it +andria-trani-barletta.it +andriabarlettatrani.it +andriatranibarletta.it +ao.it +aosta.it +aoste.it +ap.it +aq.it +aquila.it +ar.it +arezzo.it +ascoli-piceno.it +ascolipiceno.it +asti.it +at.it +av.it +avellino.it +ba.it +balsan.it +balsan-sudtirol.it +balsan-südtirol.it +balsan-suedtirol.it +bari.it +barletta-trani-andria.it +barlettatraniandria.it +belluno.it +benevento.it +bergamo.it +bg.it +bi.it +biella.it +bl.it +bn.it +bo.it +bologna.it +bolzano.it +bolzano-altoadige.it +bozen.it +bozen-sudtirol.it +bozen-südtirol.it +bozen-suedtirol.it +br.it +brescia.it +brindisi.it +bs.it +bt.it +bulsan.it +bulsan-sudtirol.it +bulsan-südtirol.it +bulsan-suedtirol.it +bz.it +ca.it +cagliari.it +caltanissetta.it +campidano-medio.it +campidanomedio.it +campobasso.it +carbonia-iglesias.it +carboniaiglesias.it +carrara-massa.it +carraramassa.it +caserta.it +catania.it +catanzaro.it +cb.it +ce.it +cesena-forli.it +cesena-forlì.it +cesenaforli.it +cesenaforlì.it +ch.it +chieti.it +ci.it +cl.it +cn.it +co.it +como.it +cosenza.it +cr.it +cremona.it +crotone.it +cs.it +ct.it +cuneo.it +cz.it +dell-ogliastra.it +dellogliastra.it +en.it +enna.it +fc.it +fe.it +fermo.it +ferrara.it +fg.it +fi.it +firenze.it +florence.it +fm.it +foggia.it +forli-cesena.it +forlì-cesena.it +forlicesena.it +forlìcesena.it +fr.it +frosinone.it +ge.it +genoa.it +genova.it +go.it +gorizia.it +gr.it +grosseto.it +iglesias-carbonia.it +iglesiascarbonia.it +im.it +imperia.it +is.it +isernia.it +kr.it +la-spezia.it +laquila.it +laspezia.it +latina.it +lc.it +le.it +lecce.it +lecco.it +li.it +livorno.it +lo.it +lodi.it +lt.it +lu.it +lucca.it +macerata.it +mantova.it +massa-carrara.it +massacarrara.it +matera.it +mb.it +mc.it +me.it +medio-campidano.it +mediocampidano.it +messina.it +mi.it +milan.it +milano.it +mn.it +mo.it +modena.it +monza.it +monza-brianza.it +monza-e-della-brianza.it +monzabrianza.it +monzaebrianza.it +monzaedellabrianza.it +ms.it +mt.it +na.it +naples.it +napoli.it +no.it +novara.it +nu.it +nuoro.it +og.it +ogliastra.it +olbia-tempio.it +olbiatempio.it +or.it +oristano.it +ot.it +pa.it +padova.it +padua.it +palermo.it +parma.it +pavia.it +pc.it +pd.it +pe.it +perugia.it +pesaro-urbino.it +pesarourbino.it +pescara.it +pg.it +pi.it +piacenza.it +pisa.it +pistoia.it +pn.it +po.it +pordenone.it +potenza.it +pr.it +prato.it +pt.it +pu.it +pv.it +pz.it +ra.it +ragusa.it +ravenna.it +rc.it +re.it +reggio-calabria.it +reggio-emilia.it +reggiocalabria.it +reggioemilia.it +rg.it +ri.it +rieti.it +rimini.it +rm.it +rn.it +ro.it +roma.it +rome.it +rovigo.it +sa.it +salerno.it +sassari.it +savona.it +si.it +siena.it +siracusa.it +so.it +sondrio.it +sp.it +sr.it +ss.it +südtirol.it +suedtirol.it +sv.it +ta.it +taranto.it +te.it +tempio-olbia.it +tempioolbia.it +teramo.it +terni.it +tn.it +to.it +torino.it +tp.it +tr.it +trani-andria-barletta.it +trani-barletta-andria.it +traniandriabarletta.it +tranibarlettaandria.it +trapani.it +trento.it +treviso.it +trieste.it +ts.it +turin.it +tv.it +ud.it +udine.it +urbino-pesaro.it +urbinopesaro.it +va.it +varese.it +vb.it +vc.it +ve.it +venezia.it +venice.it +verbania.it +vercelli.it +verona.it +vi.it +vibo-valentia.it +vibovalentia.it +vicenza.it +viterbo.it +vr.it +vs.it +vt.it +vv.it + +// je : https://www.iana.org/domains/root/db/je.html +// Confirmed by registry 2013-11-28 +je +co.je +net.je +org.je + +// jm : http://www.com.jm/register.html +*.jm + +// jo : https://www.dns.jo/JoFamily.aspx +// Confirmed by registry 2024-11-17 +jo +agri.jo +ai.jo +com.jo +edu.jo +eng.jo +fm.jo +gov.jo +mil.jo +net.jo +org.jo +per.jo +phd.jo +sch.jo +tv.jo + +// jobs : https://www.iana.org/domains/root/db/jobs.html +jobs + +// jp : https://www.iana.org/domains/root/db/jp.html +// http://jprs.co.jp/en/jpdomain.html +// Confirmed by registry 2024-11-22 +jp +// jp organizational type names +ac.jp +ad.jp +co.jp +ed.jp +go.jp +gr.jp +lg.jp +ne.jp +or.jp +// jp prefecture type names +aichi.jp +akita.jp +aomori.jp +chiba.jp +ehime.jp +fukui.jp +fukuoka.jp +fukushima.jp +gifu.jp +gunma.jp +hiroshima.jp +hokkaido.jp +hyogo.jp +ibaraki.jp +ishikawa.jp +iwate.jp +kagawa.jp +kagoshima.jp +kanagawa.jp +kochi.jp +kumamoto.jp +kyoto.jp +mie.jp +miyagi.jp +miyazaki.jp +nagano.jp +nagasaki.jp +nara.jp +niigata.jp +oita.jp +okayama.jp +okinawa.jp +osaka.jp +saga.jp +saitama.jp +shiga.jp +shimane.jp +shizuoka.jp +tochigi.jp +tokushima.jp +tokyo.jp +tottori.jp +toyama.jp +wakayama.jp +yamagata.jp +yamaguchi.jp +yamanashi.jp +三重.jp +京都.jp +佐賀.jp +兵庫.jp +北海道.jp +千葉.jp +和歌山.jp +埼玉.jp +大分.jp +大阪.jp +奈良.jp +宮城.jp +宮崎.jp +富山.jp +山口.jp +山形.jp +山梨.jp +岐阜.jp +岡山.jp +岩手.jp +島根.jp +広島.jp +徳島.jp +愛媛.jp +愛知.jp +新潟.jp +東京.jp +栃木.jp +沖縄.jp +滋賀.jp +熊本.jp +石川.jp +神奈川.jp +福井.jp +福岡.jp +福島.jp +秋田.jp +群馬.jp +茨城.jp +長崎.jp +長野.jp +青森.jp +静岡.jp +香川.jp +高知.jp +鳥取.jp +鹿児島.jp +// jp geographic type names +// http://jprs.jp/doc/rule/saisoku-1.html +// 2024-11-22: JPRS confirmed that jp geographic type names no longer accept new registrations. +// Once all existing registrations expire (marking full discontinuation), these suffixes +// will be removed from the PSL. +*.kawasaki.jp +!city.kawasaki.jp +*.kitakyushu.jp +!city.kitakyushu.jp +*.kobe.jp +!city.kobe.jp +*.nagoya.jp +!city.nagoya.jp +*.sapporo.jp +!city.sapporo.jp +*.sendai.jp +!city.sendai.jp +*.yokohama.jp +!city.yokohama.jp +// 4th level registration +aisai.aichi.jp +ama.aichi.jp +anjo.aichi.jp +asuke.aichi.jp +chiryu.aichi.jp +chita.aichi.jp +fuso.aichi.jp +gamagori.aichi.jp +handa.aichi.jp +hazu.aichi.jp +hekinan.aichi.jp +higashiura.aichi.jp +ichinomiya.aichi.jp +inazawa.aichi.jp +inuyama.aichi.jp +isshiki.aichi.jp +iwakura.aichi.jp +kanie.aichi.jp +kariya.aichi.jp +kasugai.aichi.jp +kira.aichi.jp +kiyosu.aichi.jp +komaki.aichi.jp +konan.aichi.jp +kota.aichi.jp +mihama.aichi.jp +miyoshi.aichi.jp +nishio.aichi.jp +nisshin.aichi.jp +obu.aichi.jp +oguchi.aichi.jp +oharu.aichi.jp +okazaki.aichi.jp +owariasahi.aichi.jp +seto.aichi.jp +shikatsu.aichi.jp +shinshiro.aichi.jp +shitara.aichi.jp +tahara.aichi.jp +takahama.aichi.jp +tobishima.aichi.jp +toei.aichi.jp +togo.aichi.jp +tokai.aichi.jp +tokoname.aichi.jp +toyoake.aichi.jp +toyohashi.aichi.jp +toyokawa.aichi.jp +toyone.aichi.jp +toyota.aichi.jp +tsushima.aichi.jp +yatomi.aichi.jp +akita.akita.jp +daisen.akita.jp +fujisato.akita.jp +gojome.akita.jp +hachirogata.akita.jp +happou.akita.jp +higashinaruse.akita.jp +honjo.akita.jp +honjyo.akita.jp +ikawa.akita.jp +kamikoani.akita.jp +kamioka.akita.jp +katagami.akita.jp +kazuno.akita.jp +kitaakita.akita.jp +kosaka.akita.jp +kyowa.akita.jp +misato.akita.jp +mitane.akita.jp +moriyoshi.akita.jp +nikaho.akita.jp +noshiro.akita.jp +odate.akita.jp +oga.akita.jp +ogata.akita.jp +semboku.akita.jp +yokote.akita.jp +yurihonjo.akita.jp +aomori.aomori.jp +gonohe.aomori.jp +hachinohe.aomori.jp +hashikami.aomori.jp +hiranai.aomori.jp +hirosaki.aomori.jp +itayanagi.aomori.jp +kuroishi.aomori.jp +misawa.aomori.jp +mutsu.aomori.jp +nakadomari.aomori.jp +noheji.aomori.jp +oirase.aomori.jp +owani.aomori.jp +rokunohe.aomori.jp +sannohe.aomori.jp +shichinohe.aomori.jp +shingo.aomori.jp +takko.aomori.jp +towada.aomori.jp +tsugaru.aomori.jp +tsuruta.aomori.jp +abiko.chiba.jp +asahi.chiba.jp +chonan.chiba.jp +chosei.chiba.jp +choshi.chiba.jp +chuo.chiba.jp +funabashi.chiba.jp +futtsu.chiba.jp +hanamigawa.chiba.jp +ichihara.chiba.jp +ichikawa.chiba.jp +ichinomiya.chiba.jp +inzai.chiba.jp +isumi.chiba.jp +kamagaya.chiba.jp +kamogawa.chiba.jp +kashiwa.chiba.jp +katori.chiba.jp +katsuura.chiba.jp +kimitsu.chiba.jp +kisarazu.chiba.jp +kozaki.chiba.jp +kujukuri.chiba.jp +kyonan.chiba.jp +matsudo.chiba.jp +midori.chiba.jp +mihama.chiba.jp +minamiboso.chiba.jp +mobara.chiba.jp +mutsuzawa.chiba.jp +nagara.chiba.jp +nagareyama.chiba.jp +narashino.chiba.jp +narita.chiba.jp +noda.chiba.jp +oamishirasato.chiba.jp +omigawa.chiba.jp +onjuku.chiba.jp +otaki.chiba.jp +sakae.chiba.jp +sakura.chiba.jp +shimofusa.chiba.jp +shirako.chiba.jp +shiroi.chiba.jp +shisui.chiba.jp +sodegaura.chiba.jp +sosa.chiba.jp +tako.chiba.jp +tateyama.chiba.jp +togane.chiba.jp +tohnosho.chiba.jp +tomisato.chiba.jp +urayasu.chiba.jp +yachimata.chiba.jp +yachiyo.chiba.jp +yokaichiba.chiba.jp +yokoshibahikari.chiba.jp +yotsukaido.chiba.jp +ainan.ehime.jp +honai.ehime.jp +ikata.ehime.jp +imabari.ehime.jp +iyo.ehime.jp +kamijima.ehime.jp +kihoku.ehime.jp +kumakogen.ehime.jp +masaki.ehime.jp +matsuno.ehime.jp +matsuyama.ehime.jp +namikata.ehime.jp +niihama.ehime.jp +ozu.ehime.jp +saijo.ehime.jp +seiyo.ehime.jp +shikokuchuo.ehime.jp +tobe.ehime.jp +toon.ehime.jp +uchiko.ehime.jp +uwajima.ehime.jp +yawatahama.ehime.jp +echizen.fukui.jp +eiheiji.fukui.jp +fukui.fukui.jp +ikeda.fukui.jp +katsuyama.fukui.jp +mihama.fukui.jp +minamiechizen.fukui.jp +obama.fukui.jp +ohi.fukui.jp +ono.fukui.jp +sabae.fukui.jp +sakai.fukui.jp +takahama.fukui.jp +tsuruga.fukui.jp +wakasa.fukui.jp +ashiya.fukuoka.jp +buzen.fukuoka.jp +chikugo.fukuoka.jp +chikuho.fukuoka.jp +chikujo.fukuoka.jp +chikushino.fukuoka.jp +chikuzen.fukuoka.jp +chuo.fukuoka.jp +dazaifu.fukuoka.jp +fukuchi.fukuoka.jp +hakata.fukuoka.jp +higashi.fukuoka.jp +hirokawa.fukuoka.jp +hisayama.fukuoka.jp +iizuka.fukuoka.jp +inatsuki.fukuoka.jp +kaho.fukuoka.jp +kasuga.fukuoka.jp +kasuya.fukuoka.jp +kawara.fukuoka.jp +keisen.fukuoka.jp +koga.fukuoka.jp +kurate.fukuoka.jp +kurogi.fukuoka.jp +kurume.fukuoka.jp +minami.fukuoka.jp +miyako.fukuoka.jp +miyama.fukuoka.jp +miyawaka.fukuoka.jp +mizumaki.fukuoka.jp +munakata.fukuoka.jp +nakagawa.fukuoka.jp +nakama.fukuoka.jp +nishi.fukuoka.jp +nogata.fukuoka.jp +ogori.fukuoka.jp +okagaki.fukuoka.jp +okawa.fukuoka.jp +oki.fukuoka.jp +omuta.fukuoka.jp +onga.fukuoka.jp +onojo.fukuoka.jp +oto.fukuoka.jp +saigawa.fukuoka.jp +sasaguri.fukuoka.jp +shingu.fukuoka.jp +shinyoshitomi.fukuoka.jp +shonai.fukuoka.jp +soeda.fukuoka.jp +sue.fukuoka.jp +tachiarai.fukuoka.jp +tagawa.fukuoka.jp +takata.fukuoka.jp +toho.fukuoka.jp +toyotsu.fukuoka.jp +tsuiki.fukuoka.jp +ukiha.fukuoka.jp +umi.fukuoka.jp +usui.fukuoka.jp +yamada.fukuoka.jp +yame.fukuoka.jp +yanagawa.fukuoka.jp +yukuhashi.fukuoka.jp +aizubange.fukushima.jp +aizumisato.fukushima.jp +aizuwakamatsu.fukushima.jp +asakawa.fukushima.jp +bandai.fukushima.jp +date.fukushima.jp +fukushima.fukushima.jp +furudono.fukushima.jp +futaba.fukushima.jp +hanawa.fukushima.jp +higashi.fukushima.jp +hirata.fukushima.jp +hirono.fukushima.jp +iitate.fukushima.jp +inawashiro.fukushima.jp +ishikawa.fukushima.jp +iwaki.fukushima.jp +izumizaki.fukushima.jp +kagamiishi.fukushima.jp +kaneyama.fukushima.jp +kawamata.fukushima.jp +kitakata.fukushima.jp +kitashiobara.fukushima.jp +koori.fukushima.jp +koriyama.fukushima.jp +kunimi.fukushima.jp +miharu.fukushima.jp +mishima.fukushima.jp +namie.fukushima.jp +nango.fukushima.jp +nishiaizu.fukushima.jp +nishigo.fukushima.jp +okuma.fukushima.jp +omotego.fukushima.jp +ono.fukushima.jp +otama.fukushima.jp +samegawa.fukushima.jp +shimogo.fukushima.jp +shirakawa.fukushima.jp +showa.fukushima.jp +soma.fukushima.jp +sukagawa.fukushima.jp +taishin.fukushima.jp +tamakawa.fukushima.jp +tanagura.fukushima.jp +tenei.fukushima.jp +yabuki.fukushima.jp +yamato.fukushima.jp +yamatsuri.fukushima.jp +yanaizu.fukushima.jp +yugawa.fukushima.jp +anpachi.gifu.jp +ena.gifu.jp +gifu.gifu.jp +ginan.gifu.jp +godo.gifu.jp +gujo.gifu.jp +hashima.gifu.jp +hichiso.gifu.jp +hida.gifu.jp +higashishirakawa.gifu.jp +ibigawa.gifu.jp +ikeda.gifu.jp +kakamigahara.gifu.jp +kani.gifu.jp +kasahara.gifu.jp +kasamatsu.gifu.jp +kawaue.gifu.jp +kitagata.gifu.jp +mino.gifu.jp +minokamo.gifu.jp +mitake.gifu.jp +mizunami.gifu.jp +motosu.gifu.jp +nakatsugawa.gifu.jp +ogaki.gifu.jp +sakahogi.gifu.jp +seki.gifu.jp +sekigahara.gifu.jp +shirakawa.gifu.jp +tajimi.gifu.jp +takayama.gifu.jp +tarui.gifu.jp +toki.gifu.jp +tomika.gifu.jp +wanouchi.gifu.jp +yamagata.gifu.jp +yaotsu.gifu.jp +yoro.gifu.jp +annaka.gunma.jp +chiyoda.gunma.jp +fujioka.gunma.jp +higashiagatsuma.gunma.jp +isesaki.gunma.jp +itakura.gunma.jp +kanna.gunma.jp +kanra.gunma.jp +katashina.gunma.jp +kawaba.gunma.jp +kiryu.gunma.jp +kusatsu.gunma.jp +maebashi.gunma.jp +meiwa.gunma.jp +midori.gunma.jp +minakami.gunma.jp +naganohara.gunma.jp +nakanojo.gunma.jp +nanmoku.gunma.jp +numata.gunma.jp +oizumi.gunma.jp +ora.gunma.jp +ota.gunma.jp +shibukawa.gunma.jp +shimonita.gunma.jp +shinto.gunma.jp +showa.gunma.jp +takasaki.gunma.jp +takayama.gunma.jp +tamamura.gunma.jp +tatebayashi.gunma.jp +tomioka.gunma.jp +tsukiyono.gunma.jp +tsumagoi.gunma.jp +ueno.gunma.jp +yoshioka.gunma.jp +asaminami.hiroshima.jp +daiwa.hiroshima.jp +etajima.hiroshima.jp +fuchu.hiroshima.jp +fukuyama.hiroshima.jp +hatsukaichi.hiroshima.jp +higashihiroshima.hiroshima.jp +hongo.hiroshima.jp +jinsekikogen.hiroshima.jp +kaita.hiroshima.jp +kui.hiroshima.jp +kumano.hiroshima.jp +kure.hiroshima.jp +mihara.hiroshima.jp +miyoshi.hiroshima.jp +naka.hiroshima.jp +onomichi.hiroshima.jp +osakikamijima.hiroshima.jp +otake.hiroshima.jp +saka.hiroshima.jp +sera.hiroshima.jp +seranishi.hiroshima.jp +shinichi.hiroshima.jp +shobara.hiroshima.jp +takehara.hiroshima.jp +abashiri.hokkaido.jp +abira.hokkaido.jp +aibetsu.hokkaido.jp +akabira.hokkaido.jp +akkeshi.hokkaido.jp +asahikawa.hokkaido.jp +ashibetsu.hokkaido.jp +ashoro.hokkaido.jp +assabu.hokkaido.jp +atsuma.hokkaido.jp +bibai.hokkaido.jp +biei.hokkaido.jp +bifuka.hokkaido.jp +bihoro.hokkaido.jp +biratori.hokkaido.jp +chippubetsu.hokkaido.jp +chitose.hokkaido.jp +date.hokkaido.jp +ebetsu.hokkaido.jp +embetsu.hokkaido.jp +eniwa.hokkaido.jp +erimo.hokkaido.jp +esan.hokkaido.jp +esashi.hokkaido.jp +fukagawa.hokkaido.jp +fukushima.hokkaido.jp +furano.hokkaido.jp +furubira.hokkaido.jp +haboro.hokkaido.jp +hakodate.hokkaido.jp +hamatonbetsu.hokkaido.jp +hidaka.hokkaido.jp +higashikagura.hokkaido.jp +higashikawa.hokkaido.jp +hiroo.hokkaido.jp +hokuryu.hokkaido.jp +hokuto.hokkaido.jp +honbetsu.hokkaido.jp +horokanai.hokkaido.jp +horonobe.hokkaido.jp +ikeda.hokkaido.jp +imakane.hokkaido.jp +ishikari.hokkaido.jp +iwamizawa.hokkaido.jp +iwanai.hokkaido.jp +kamifurano.hokkaido.jp +kamikawa.hokkaido.jp +kamishihoro.hokkaido.jp +kamisunagawa.hokkaido.jp +kamoenai.hokkaido.jp +kayabe.hokkaido.jp +kembuchi.hokkaido.jp +kikonai.hokkaido.jp +kimobetsu.hokkaido.jp +kitahiroshima.hokkaido.jp +kitami.hokkaido.jp +kiyosato.hokkaido.jp +koshimizu.hokkaido.jp +kunneppu.hokkaido.jp +kuriyama.hokkaido.jp +kuromatsunai.hokkaido.jp +kushiro.hokkaido.jp +kutchan.hokkaido.jp +kyowa.hokkaido.jp +mashike.hokkaido.jp +matsumae.hokkaido.jp +mikasa.hokkaido.jp +minamifurano.hokkaido.jp +mombetsu.hokkaido.jp +moseushi.hokkaido.jp +mukawa.hokkaido.jp +muroran.hokkaido.jp +naie.hokkaido.jp +nakagawa.hokkaido.jp +nakasatsunai.hokkaido.jp +nakatombetsu.hokkaido.jp +nanae.hokkaido.jp +nanporo.hokkaido.jp +nayoro.hokkaido.jp +nemuro.hokkaido.jp +niikappu.hokkaido.jp +niki.hokkaido.jp +nishiokoppe.hokkaido.jp +noboribetsu.hokkaido.jp +numata.hokkaido.jp +obihiro.hokkaido.jp +obira.hokkaido.jp +oketo.hokkaido.jp +okoppe.hokkaido.jp +otaru.hokkaido.jp +otobe.hokkaido.jp +otofuke.hokkaido.jp +otoineppu.hokkaido.jp +oumu.hokkaido.jp +ozora.hokkaido.jp +pippu.hokkaido.jp +rankoshi.hokkaido.jp +rebun.hokkaido.jp +rikubetsu.hokkaido.jp +rishiri.hokkaido.jp +rishirifuji.hokkaido.jp +saroma.hokkaido.jp +sarufutsu.hokkaido.jp +shakotan.hokkaido.jp +shari.hokkaido.jp +shibecha.hokkaido.jp +shibetsu.hokkaido.jp +shikabe.hokkaido.jp +shikaoi.hokkaido.jp +shimamaki.hokkaido.jp +shimizu.hokkaido.jp +shimokawa.hokkaido.jp +shinshinotsu.hokkaido.jp +shintoku.hokkaido.jp +shiranuka.hokkaido.jp +shiraoi.hokkaido.jp +shiriuchi.hokkaido.jp +sobetsu.hokkaido.jp +sunagawa.hokkaido.jp +taiki.hokkaido.jp +takasu.hokkaido.jp +takikawa.hokkaido.jp +takinoue.hokkaido.jp +teshikaga.hokkaido.jp +tobetsu.hokkaido.jp +tohma.hokkaido.jp +tomakomai.hokkaido.jp +tomari.hokkaido.jp +toya.hokkaido.jp +toyako.hokkaido.jp +toyotomi.hokkaido.jp +toyoura.hokkaido.jp +tsubetsu.hokkaido.jp +tsukigata.hokkaido.jp +urakawa.hokkaido.jp +urausu.hokkaido.jp +uryu.hokkaido.jp +utashinai.hokkaido.jp +wakkanai.hokkaido.jp +wassamu.hokkaido.jp +yakumo.hokkaido.jp +yoichi.hokkaido.jp +aioi.hyogo.jp +akashi.hyogo.jp +ako.hyogo.jp +amagasaki.hyogo.jp +aogaki.hyogo.jp +asago.hyogo.jp +ashiya.hyogo.jp +awaji.hyogo.jp +fukusaki.hyogo.jp +goshiki.hyogo.jp +harima.hyogo.jp +himeji.hyogo.jp +ichikawa.hyogo.jp +inagawa.hyogo.jp +itami.hyogo.jp +kakogawa.hyogo.jp +kamigori.hyogo.jp +kamikawa.hyogo.jp +kasai.hyogo.jp +kasuga.hyogo.jp +kawanishi.hyogo.jp +miki.hyogo.jp +minamiawaji.hyogo.jp +nishinomiya.hyogo.jp +nishiwaki.hyogo.jp +ono.hyogo.jp +sanda.hyogo.jp +sannan.hyogo.jp +sasayama.hyogo.jp +sayo.hyogo.jp +shingu.hyogo.jp +shinonsen.hyogo.jp +shiso.hyogo.jp +sumoto.hyogo.jp +taishi.hyogo.jp +taka.hyogo.jp +takarazuka.hyogo.jp +takasago.hyogo.jp +takino.hyogo.jp +tamba.hyogo.jp +tatsuno.hyogo.jp +toyooka.hyogo.jp +yabu.hyogo.jp +yashiro.hyogo.jp +yoka.hyogo.jp +yokawa.hyogo.jp +ami.ibaraki.jp +asahi.ibaraki.jp +bando.ibaraki.jp +chikusei.ibaraki.jp +daigo.ibaraki.jp +fujishiro.ibaraki.jp +hitachi.ibaraki.jp +hitachinaka.ibaraki.jp +hitachiomiya.ibaraki.jp +hitachiota.ibaraki.jp +ibaraki.ibaraki.jp +ina.ibaraki.jp +inashiki.ibaraki.jp +itako.ibaraki.jp +iwama.ibaraki.jp +joso.ibaraki.jp +kamisu.ibaraki.jp +kasama.ibaraki.jp +kashima.ibaraki.jp +kasumigaura.ibaraki.jp +koga.ibaraki.jp +miho.ibaraki.jp +mito.ibaraki.jp +moriya.ibaraki.jp +naka.ibaraki.jp +namegata.ibaraki.jp +oarai.ibaraki.jp +ogawa.ibaraki.jp +omitama.ibaraki.jp +ryugasaki.ibaraki.jp +sakai.ibaraki.jp +sakuragawa.ibaraki.jp +shimodate.ibaraki.jp +shimotsuma.ibaraki.jp +shirosato.ibaraki.jp +sowa.ibaraki.jp +suifu.ibaraki.jp +takahagi.ibaraki.jp +tamatsukuri.ibaraki.jp +tokai.ibaraki.jp +tomobe.ibaraki.jp +tone.ibaraki.jp +toride.ibaraki.jp +tsuchiura.ibaraki.jp +tsukuba.ibaraki.jp +uchihara.ibaraki.jp +ushiku.ibaraki.jp +yachiyo.ibaraki.jp +yamagata.ibaraki.jp +yawara.ibaraki.jp +yuki.ibaraki.jp +anamizu.ishikawa.jp +hakui.ishikawa.jp +hakusan.ishikawa.jp +kaga.ishikawa.jp +kahoku.ishikawa.jp +kanazawa.ishikawa.jp +kawakita.ishikawa.jp +komatsu.ishikawa.jp +nakanoto.ishikawa.jp +nanao.ishikawa.jp +nomi.ishikawa.jp +nonoichi.ishikawa.jp +noto.ishikawa.jp +shika.ishikawa.jp +suzu.ishikawa.jp +tsubata.ishikawa.jp +tsurugi.ishikawa.jp +uchinada.ishikawa.jp +wajima.ishikawa.jp +fudai.iwate.jp +fujisawa.iwate.jp +hanamaki.iwate.jp +hiraizumi.iwate.jp +hirono.iwate.jp +ichinohe.iwate.jp +ichinoseki.iwate.jp +iwaizumi.iwate.jp +iwate.iwate.jp +joboji.iwate.jp +kamaishi.iwate.jp +kanegasaki.iwate.jp +karumai.iwate.jp +kawai.iwate.jp +kitakami.iwate.jp +kuji.iwate.jp +kunohe.iwate.jp +kuzumaki.iwate.jp +miyako.iwate.jp +mizusawa.iwate.jp +morioka.iwate.jp +ninohe.iwate.jp +noda.iwate.jp +ofunato.iwate.jp +oshu.iwate.jp +otsuchi.iwate.jp +rikuzentakata.iwate.jp +shiwa.iwate.jp +shizukuishi.iwate.jp +sumita.iwate.jp +tanohata.iwate.jp +tono.iwate.jp +yahaba.iwate.jp +yamada.iwate.jp +ayagawa.kagawa.jp +higashikagawa.kagawa.jp +kanonji.kagawa.jp +kotohira.kagawa.jp +manno.kagawa.jp +marugame.kagawa.jp +mitoyo.kagawa.jp +naoshima.kagawa.jp +sanuki.kagawa.jp +tadotsu.kagawa.jp +takamatsu.kagawa.jp +tonosho.kagawa.jp +uchinomi.kagawa.jp +utazu.kagawa.jp +zentsuji.kagawa.jp +akune.kagoshima.jp +amami.kagoshima.jp +hioki.kagoshima.jp +isa.kagoshima.jp +isen.kagoshima.jp +izumi.kagoshima.jp +kagoshima.kagoshima.jp +kanoya.kagoshima.jp +kawanabe.kagoshima.jp +kinko.kagoshima.jp +kouyama.kagoshima.jp +makurazaki.kagoshima.jp +matsumoto.kagoshima.jp +minamitane.kagoshima.jp +nakatane.kagoshima.jp +nishinoomote.kagoshima.jp +satsumasendai.kagoshima.jp +soo.kagoshima.jp +tarumizu.kagoshima.jp +yusui.kagoshima.jp +aikawa.kanagawa.jp +atsugi.kanagawa.jp +ayase.kanagawa.jp +chigasaki.kanagawa.jp +ebina.kanagawa.jp +fujisawa.kanagawa.jp +hadano.kanagawa.jp +hakone.kanagawa.jp +hiratsuka.kanagawa.jp +isehara.kanagawa.jp +kaisei.kanagawa.jp +kamakura.kanagawa.jp +kiyokawa.kanagawa.jp +matsuda.kanagawa.jp +minamiashigara.kanagawa.jp +miura.kanagawa.jp +nakai.kanagawa.jp +ninomiya.kanagawa.jp +odawara.kanagawa.jp +oi.kanagawa.jp +oiso.kanagawa.jp +sagamihara.kanagawa.jp +samukawa.kanagawa.jp +tsukui.kanagawa.jp +yamakita.kanagawa.jp +yamato.kanagawa.jp +yokosuka.kanagawa.jp +yugawara.kanagawa.jp +zama.kanagawa.jp +zushi.kanagawa.jp +aki.kochi.jp +geisei.kochi.jp +hidaka.kochi.jp +higashitsuno.kochi.jp +ino.kochi.jp +kagami.kochi.jp +kami.kochi.jp +kitagawa.kochi.jp +kochi.kochi.jp +mihara.kochi.jp +motoyama.kochi.jp +muroto.kochi.jp +nahari.kochi.jp +nakamura.kochi.jp +nankoku.kochi.jp +nishitosa.kochi.jp +niyodogawa.kochi.jp +ochi.kochi.jp +okawa.kochi.jp +otoyo.kochi.jp +otsuki.kochi.jp +sakawa.kochi.jp +sukumo.kochi.jp +susaki.kochi.jp +tosa.kochi.jp +tosashimizu.kochi.jp +toyo.kochi.jp +tsuno.kochi.jp +umaji.kochi.jp +yasuda.kochi.jp +yusuhara.kochi.jp +amakusa.kumamoto.jp +arao.kumamoto.jp +aso.kumamoto.jp +choyo.kumamoto.jp +gyokuto.kumamoto.jp +kamiamakusa.kumamoto.jp +kikuchi.kumamoto.jp +kumamoto.kumamoto.jp +mashiki.kumamoto.jp +mifune.kumamoto.jp +minamata.kumamoto.jp +minamioguni.kumamoto.jp +nagasu.kumamoto.jp +nishihara.kumamoto.jp +oguni.kumamoto.jp +ozu.kumamoto.jp +sumoto.kumamoto.jp +takamori.kumamoto.jp +uki.kumamoto.jp +uto.kumamoto.jp +yamaga.kumamoto.jp +yamato.kumamoto.jp +yatsushiro.kumamoto.jp +ayabe.kyoto.jp +fukuchiyama.kyoto.jp +higashiyama.kyoto.jp +ide.kyoto.jp +ine.kyoto.jp +joyo.kyoto.jp +kameoka.kyoto.jp +kamo.kyoto.jp +kita.kyoto.jp +kizu.kyoto.jp +kumiyama.kyoto.jp +kyotamba.kyoto.jp +kyotanabe.kyoto.jp +kyotango.kyoto.jp +maizuru.kyoto.jp +minami.kyoto.jp +minamiyamashiro.kyoto.jp +miyazu.kyoto.jp +muko.kyoto.jp +nagaokakyo.kyoto.jp +nakagyo.kyoto.jp +nantan.kyoto.jp +oyamazaki.kyoto.jp +sakyo.kyoto.jp +seika.kyoto.jp +tanabe.kyoto.jp +uji.kyoto.jp +ujitawara.kyoto.jp +wazuka.kyoto.jp +yamashina.kyoto.jp +yawata.kyoto.jp +asahi.mie.jp +inabe.mie.jp +ise.mie.jp +kameyama.mie.jp +kawagoe.mie.jp +kiho.mie.jp +kisosaki.mie.jp +kiwa.mie.jp +komono.mie.jp +kumano.mie.jp +kuwana.mie.jp +matsusaka.mie.jp +meiwa.mie.jp +mihama.mie.jp +minamiise.mie.jp +misugi.mie.jp +miyama.mie.jp +nabari.mie.jp +shima.mie.jp +suzuka.mie.jp +tado.mie.jp +taiki.mie.jp +taki.mie.jp +tamaki.mie.jp +toba.mie.jp +tsu.mie.jp +udono.mie.jp +ureshino.mie.jp +watarai.mie.jp +yokkaichi.mie.jp +furukawa.miyagi.jp +higashimatsushima.miyagi.jp +ishinomaki.miyagi.jp +iwanuma.miyagi.jp +kakuda.miyagi.jp +kami.miyagi.jp +kawasaki.miyagi.jp +marumori.miyagi.jp +matsushima.miyagi.jp +minamisanriku.miyagi.jp +misato.miyagi.jp +murata.miyagi.jp +natori.miyagi.jp +ogawara.miyagi.jp +ohira.miyagi.jp +onagawa.miyagi.jp +osaki.miyagi.jp +rifu.miyagi.jp +semine.miyagi.jp +shibata.miyagi.jp +shichikashuku.miyagi.jp +shikama.miyagi.jp +shiogama.miyagi.jp +shiroishi.miyagi.jp +tagajo.miyagi.jp +taiwa.miyagi.jp +tome.miyagi.jp +tomiya.miyagi.jp +wakuya.miyagi.jp +watari.miyagi.jp +yamamoto.miyagi.jp +zao.miyagi.jp +aya.miyazaki.jp +ebino.miyazaki.jp +gokase.miyazaki.jp +hyuga.miyazaki.jp +kadogawa.miyazaki.jp +kawaminami.miyazaki.jp +kijo.miyazaki.jp +kitagawa.miyazaki.jp +kitakata.miyazaki.jp +kitaura.miyazaki.jp +kobayashi.miyazaki.jp +kunitomi.miyazaki.jp +kushima.miyazaki.jp +mimata.miyazaki.jp +miyakonojo.miyazaki.jp +miyazaki.miyazaki.jp +morotsuka.miyazaki.jp +nichinan.miyazaki.jp +nishimera.miyazaki.jp +nobeoka.miyazaki.jp +saito.miyazaki.jp +shiiba.miyazaki.jp +shintomi.miyazaki.jp +takaharu.miyazaki.jp +takanabe.miyazaki.jp +takazaki.miyazaki.jp +tsuno.miyazaki.jp +achi.nagano.jp +agematsu.nagano.jp +anan.nagano.jp +aoki.nagano.jp +asahi.nagano.jp +azumino.nagano.jp +chikuhoku.nagano.jp +chikuma.nagano.jp +chino.nagano.jp +fujimi.nagano.jp +hakuba.nagano.jp +hara.nagano.jp +hiraya.nagano.jp +iida.nagano.jp +iijima.nagano.jp +iiyama.nagano.jp +iizuna.nagano.jp +ikeda.nagano.jp +ikusaka.nagano.jp +ina.nagano.jp +karuizawa.nagano.jp +kawakami.nagano.jp +kiso.nagano.jp +kisofukushima.nagano.jp +kitaaiki.nagano.jp +komagane.nagano.jp +komoro.nagano.jp +matsukawa.nagano.jp +matsumoto.nagano.jp +miasa.nagano.jp +minamiaiki.nagano.jp +minamimaki.nagano.jp +minamiminowa.nagano.jp +minowa.nagano.jp +miyada.nagano.jp +miyota.nagano.jp +mochizuki.nagano.jp +nagano.nagano.jp +nagawa.nagano.jp +nagiso.nagano.jp +nakagawa.nagano.jp +nakano.nagano.jp +nozawaonsen.nagano.jp +obuse.nagano.jp +ogawa.nagano.jp +okaya.nagano.jp +omachi.nagano.jp +omi.nagano.jp +ookuwa.nagano.jp +ooshika.nagano.jp +otaki.nagano.jp +otari.nagano.jp +sakae.nagano.jp +sakaki.nagano.jp +saku.nagano.jp +sakuho.nagano.jp +shimosuwa.nagano.jp +shinanomachi.nagano.jp +shiojiri.nagano.jp +suwa.nagano.jp +suzaka.nagano.jp +takagi.nagano.jp +takamori.nagano.jp +takayama.nagano.jp +tateshina.nagano.jp +tatsuno.nagano.jp +togakushi.nagano.jp +togura.nagano.jp +tomi.nagano.jp +ueda.nagano.jp +wada.nagano.jp +yamagata.nagano.jp +yamanouchi.nagano.jp +yasaka.nagano.jp +yasuoka.nagano.jp +chijiwa.nagasaki.jp +futsu.nagasaki.jp +goto.nagasaki.jp +hasami.nagasaki.jp +hirado.nagasaki.jp +iki.nagasaki.jp +isahaya.nagasaki.jp +kawatana.nagasaki.jp +kuchinotsu.nagasaki.jp +matsuura.nagasaki.jp +nagasaki.nagasaki.jp +obama.nagasaki.jp +omura.nagasaki.jp +oseto.nagasaki.jp +saikai.nagasaki.jp +sasebo.nagasaki.jp +seihi.nagasaki.jp +shimabara.nagasaki.jp +shinkamigoto.nagasaki.jp +togitsu.nagasaki.jp +tsushima.nagasaki.jp +unzen.nagasaki.jp +ando.nara.jp +gose.nara.jp +heguri.nara.jp +higashiyoshino.nara.jp +ikaruga.nara.jp +ikoma.nara.jp +kamikitayama.nara.jp +kanmaki.nara.jp +kashiba.nara.jp +kashihara.nara.jp +katsuragi.nara.jp +kawai.nara.jp +kawakami.nara.jp +kawanishi.nara.jp +koryo.nara.jp +kurotaki.nara.jp +mitsue.nara.jp +miyake.nara.jp +nara.nara.jp +nosegawa.nara.jp +oji.nara.jp +ouda.nara.jp +oyodo.nara.jp +sakurai.nara.jp +sango.nara.jp +shimoichi.nara.jp +shimokitayama.nara.jp +shinjo.nara.jp +soni.nara.jp +takatori.nara.jp +tawaramoto.nara.jp +tenkawa.nara.jp +tenri.nara.jp +uda.nara.jp +yamatokoriyama.nara.jp +yamatotakada.nara.jp +yamazoe.nara.jp +yoshino.nara.jp +aga.niigata.jp +agano.niigata.jp +gosen.niigata.jp +itoigawa.niigata.jp +izumozaki.niigata.jp +joetsu.niigata.jp +kamo.niigata.jp +kariwa.niigata.jp +kashiwazaki.niigata.jp +minamiuonuma.niigata.jp +mitsuke.niigata.jp +muika.niigata.jp +murakami.niigata.jp +myoko.niigata.jp +nagaoka.niigata.jp +niigata.niigata.jp +ojiya.niigata.jp +omi.niigata.jp +sado.niigata.jp +sanjo.niigata.jp +seiro.niigata.jp +seirou.niigata.jp +sekikawa.niigata.jp +shibata.niigata.jp +tagami.niigata.jp +tainai.niigata.jp +tochio.niigata.jp +tokamachi.niigata.jp +tsubame.niigata.jp +tsunan.niigata.jp +uonuma.niigata.jp +yahiko.niigata.jp +yoita.niigata.jp +yuzawa.niigata.jp +beppu.oita.jp +bungoono.oita.jp +bungotakada.oita.jp +hasama.oita.jp +hiji.oita.jp +himeshima.oita.jp +hita.oita.jp +kamitsue.oita.jp +kokonoe.oita.jp +kuju.oita.jp +kunisaki.oita.jp +kusu.oita.jp +oita.oita.jp +saiki.oita.jp +taketa.oita.jp +tsukumi.oita.jp +usa.oita.jp +usuki.oita.jp +yufu.oita.jp +akaiwa.okayama.jp +asakuchi.okayama.jp +bizen.okayama.jp +hayashima.okayama.jp +ibara.okayama.jp +kagamino.okayama.jp +kasaoka.okayama.jp +kibichuo.okayama.jp +kumenan.okayama.jp +kurashiki.okayama.jp +maniwa.okayama.jp +misaki.okayama.jp +nagi.okayama.jp +niimi.okayama.jp +nishiawakura.okayama.jp +okayama.okayama.jp +satosho.okayama.jp +setouchi.okayama.jp +shinjo.okayama.jp +shoo.okayama.jp +soja.okayama.jp +takahashi.okayama.jp +tamano.okayama.jp +tsuyama.okayama.jp +wake.okayama.jp +yakage.okayama.jp +aguni.okinawa.jp +ginowan.okinawa.jp +ginoza.okinawa.jp +gushikami.okinawa.jp +haebaru.okinawa.jp +higashi.okinawa.jp +hirara.okinawa.jp +iheya.okinawa.jp +ishigaki.okinawa.jp +ishikawa.okinawa.jp +itoman.okinawa.jp +izena.okinawa.jp +kadena.okinawa.jp +kin.okinawa.jp +kitadaito.okinawa.jp +kitanakagusuku.okinawa.jp +kumejima.okinawa.jp +kunigami.okinawa.jp +minamidaito.okinawa.jp +motobu.okinawa.jp +nago.okinawa.jp +naha.okinawa.jp +nakagusuku.okinawa.jp +nakijin.okinawa.jp +nanjo.okinawa.jp +nishihara.okinawa.jp +ogimi.okinawa.jp +okinawa.okinawa.jp +onna.okinawa.jp +shimoji.okinawa.jp +taketomi.okinawa.jp +tarama.okinawa.jp +tokashiki.okinawa.jp +tomigusuku.okinawa.jp +tonaki.okinawa.jp +urasoe.okinawa.jp +uruma.okinawa.jp +yaese.okinawa.jp +yomitan.okinawa.jp +yonabaru.okinawa.jp +yonaguni.okinawa.jp +zamami.okinawa.jp +abeno.osaka.jp +chihayaakasaka.osaka.jp +chuo.osaka.jp +daito.osaka.jp +fujiidera.osaka.jp +habikino.osaka.jp +hannan.osaka.jp +higashiosaka.osaka.jp +higashisumiyoshi.osaka.jp +higashiyodogawa.osaka.jp +hirakata.osaka.jp +ibaraki.osaka.jp +ikeda.osaka.jp +izumi.osaka.jp +izumiotsu.osaka.jp +izumisano.osaka.jp +kadoma.osaka.jp +kaizuka.osaka.jp +kanan.osaka.jp +kashiwara.osaka.jp +katano.osaka.jp +kawachinagano.osaka.jp +kishiwada.osaka.jp +kita.osaka.jp +kumatori.osaka.jp +matsubara.osaka.jp +minato.osaka.jp +minoh.osaka.jp +misaki.osaka.jp +moriguchi.osaka.jp +neyagawa.osaka.jp +nishi.osaka.jp +nose.osaka.jp +osakasayama.osaka.jp +sakai.osaka.jp +sayama.osaka.jp +sennan.osaka.jp +settsu.osaka.jp +shijonawate.osaka.jp +shimamoto.osaka.jp +suita.osaka.jp +tadaoka.osaka.jp +taishi.osaka.jp +tajiri.osaka.jp +takaishi.osaka.jp +takatsuki.osaka.jp +tondabayashi.osaka.jp +toyonaka.osaka.jp +toyono.osaka.jp +yao.osaka.jp +ariake.saga.jp +arita.saga.jp +fukudomi.saga.jp +genkai.saga.jp +hamatama.saga.jp +hizen.saga.jp +imari.saga.jp +kamimine.saga.jp +kanzaki.saga.jp +karatsu.saga.jp +kashima.saga.jp +kitagata.saga.jp +kitahata.saga.jp +kiyama.saga.jp +kouhoku.saga.jp +kyuragi.saga.jp +nishiarita.saga.jp +ogi.saga.jp +omachi.saga.jp +ouchi.saga.jp +saga.saga.jp +shiroishi.saga.jp +taku.saga.jp +tara.saga.jp +tosu.saga.jp +yoshinogari.saga.jp +arakawa.saitama.jp +asaka.saitama.jp +chichibu.saitama.jp +fujimi.saitama.jp +fujimino.saitama.jp +fukaya.saitama.jp +hanno.saitama.jp +hanyu.saitama.jp +hasuda.saitama.jp +hatogaya.saitama.jp +hatoyama.saitama.jp +hidaka.saitama.jp +higashichichibu.saitama.jp +higashimatsuyama.saitama.jp +honjo.saitama.jp +ina.saitama.jp +iruma.saitama.jp +iwatsuki.saitama.jp +kamiizumi.saitama.jp +kamikawa.saitama.jp +kamisato.saitama.jp +kasukabe.saitama.jp +kawagoe.saitama.jp +kawaguchi.saitama.jp +kawajima.saitama.jp +kazo.saitama.jp +kitamoto.saitama.jp +koshigaya.saitama.jp +kounosu.saitama.jp +kuki.saitama.jp +kumagaya.saitama.jp +matsubushi.saitama.jp +minano.saitama.jp +misato.saitama.jp +miyashiro.saitama.jp +miyoshi.saitama.jp +moroyama.saitama.jp +nagatoro.saitama.jp +namegawa.saitama.jp +niiza.saitama.jp +ogano.saitama.jp +ogawa.saitama.jp +ogose.saitama.jp +okegawa.saitama.jp +omiya.saitama.jp +otaki.saitama.jp +ranzan.saitama.jp +ryokami.saitama.jp +saitama.saitama.jp +sakado.saitama.jp +satte.saitama.jp +sayama.saitama.jp +shiki.saitama.jp +shiraoka.saitama.jp +soka.saitama.jp +sugito.saitama.jp +toda.saitama.jp +tokigawa.saitama.jp +tokorozawa.saitama.jp +tsurugashima.saitama.jp +urawa.saitama.jp +warabi.saitama.jp +yashio.saitama.jp +yokoze.saitama.jp +yono.saitama.jp +yorii.saitama.jp +yoshida.saitama.jp +yoshikawa.saitama.jp +yoshimi.saitama.jp +aisho.shiga.jp +gamo.shiga.jp +higashiomi.shiga.jp +hikone.shiga.jp +koka.shiga.jp +konan.shiga.jp +kosei.shiga.jp +koto.shiga.jp +kusatsu.shiga.jp +maibara.shiga.jp +moriyama.shiga.jp +nagahama.shiga.jp +nishiazai.shiga.jp +notogawa.shiga.jp +omihachiman.shiga.jp +otsu.shiga.jp +ritto.shiga.jp +ryuoh.shiga.jp +takashima.shiga.jp +takatsuki.shiga.jp +torahime.shiga.jp +toyosato.shiga.jp +yasu.shiga.jp +akagi.shimane.jp +ama.shimane.jp +gotsu.shimane.jp +hamada.shimane.jp +higashiizumo.shimane.jp +hikawa.shimane.jp +hikimi.shimane.jp +izumo.shimane.jp +kakinoki.shimane.jp +masuda.shimane.jp +matsue.shimane.jp +misato.shimane.jp +nishinoshima.shimane.jp +ohda.shimane.jp +okinoshima.shimane.jp +okuizumo.shimane.jp +shimane.shimane.jp +tamayu.shimane.jp +tsuwano.shimane.jp +unnan.shimane.jp +yakumo.shimane.jp +yasugi.shimane.jp +yatsuka.shimane.jp +arai.shizuoka.jp +atami.shizuoka.jp +fuji.shizuoka.jp +fujieda.shizuoka.jp +fujikawa.shizuoka.jp +fujinomiya.shizuoka.jp +fukuroi.shizuoka.jp +gotemba.shizuoka.jp +haibara.shizuoka.jp +hamamatsu.shizuoka.jp +higashiizu.shizuoka.jp +ito.shizuoka.jp +iwata.shizuoka.jp +izu.shizuoka.jp +izunokuni.shizuoka.jp +kakegawa.shizuoka.jp +kannami.shizuoka.jp +kawanehon.shizuoka.jp +kawazu.shizuoka.jp +kikugawa.shizuoka.jp +kosai.shizuoka.jp +makinohara.shizuoka.jp +matsuzaki.shizuoka.jp +minamiizu.shizuoka.jp +mishima.shizuoka.jp +morimachi.shizuoka.jp +nishiizu.shizuoka.jp +numazu.shizuoka.jp +omaezaki.shizuoka.jp +shimada.shizuoka.jp +shimizu.shizuoka.jp +shimoda.shizuoka.jp +shizuoka.shizuoka.jp +susono.shizuoka.jp +yaizu.shizuoka.jp +yoshida.shizuoka.jp +ashikaga.tochigi.jp +bato.tochigi.jp +haga.tochigi.jp +ichikai.tochigi.jp +iwafune.tochigi.jp +kaminokawa.tochigi.jp +kanuma.tochigi.jp +karasuyama.tochigi.jp +kuroiso.tochigi.jp +mashiko.tochigi.jp +mibu.tochigi.jp +moka.tochigi.jp +motegi.tochigi.jp +nasu.tochigi.jp +nasushiobara.tochigi.jp +nikko.tochigi.jp +nishikata.tochigi.jp +nogi.tochigi.jp +ohira.tochigi.jp +ohtawara.tochigi.jp +oyama.tochigi.jp +sakura.tochigi.jp +sano.tochigi.jp +shimotsuke.tochigi.jp +shioya.tochigi.jp +takanezawa.tochigi.jp +tochigi.tochigi.jp +tsuga.tochigi.jp +ujiie.tochigi.jp +utsunomiya.tochigi.jp +yaita.tochigi.jp +aizumi.tokushima.jp +anan.tokushima.jp +ichiba.tokushima.jp +itano.tokushima.jp +kainan.tokushima.jp +komatsushima.tokushima.jp +matsushige.tokushima.jp +mima.tokushima.jp +minami.tokushima.jp +miyoshi.tokushima.jp +mugi.tokushima.jp +nakagawa.tokushima.jp +naruto.tokushima.jp +sanagochi.tokushima.jp +shishikui.tokushima.jp +tokushima.tokushima.jp +wajiki.tokushima.jp +adachi.tokyo.jp +akiruno.tokyo.jp +akishima.tokyo.jp +aogashima.tokyo.jp +arakawa.tokyo.jp +bunkyo.tokyo.jp +chiyoda.tokyo.jp +chofu.tokyo.jp +chuo.tokyo.jp +edogawa.tokyo.jp +fuchu.tokyo.jp +fussa.tokyo.jp +hachijo.tokyo.jp +hachioji.tokyo.jp +hamura.tokyo.jp +higashikurume.tokyo.jp +higashimurayama.tokyo.jp +higashiyamato.tokyo.jp +hino.tokyo.jp +hinode.tokyo.jp +hinohara.tokyo.jp +inagi.tokyo.jp +itabashi.tokyo.jp +katsushika.tokyo.jp +kita.tokyo.jp +kiyose.tokyo.jp +kodaira.tokyo.jp +koganei.tokyo.jp +kokubunji.tokyo.jp +komae.tokyo.jp +koto.tokyo.jp +kouzushima.tokyo.jp +kunitachi.tokyo.jp +machida.tokyo.jp +meguro.tokyo.jp +minato.tokyo.jp +mitaka.tokyo.jp +mizuho.tokyo.jp +musashimurayama.tokyo.jp +musashino.tokyo.jp +nakano.tokyo.jp +nerima.tokyo.jp +ogasawara.tokyo.jp +okutama.tokyo.jp +ome.tokyo.jp +oshima.tokyo.jp +ota.tokyo.jp +setagaya.tokyo.jp +shibuya.tokyo.jp +shinagawa.tokyo.jp +shinjuku.tokyo.jp +suginami.tokyo.jp +sumida.tokyo.jp +tachikawa.tokyo.jp +taito.tokyo.jp +tama.tokyo.jp +toshima.tokyo.jp +chizu.tottori.jp +hino.tottori.jp +kawahara.tottori.jp +koge.tottori.jp +kotoura.tottori.jp +misasa.tottori.jp +nanbu.tottori.jp +nichinan.tottori.jp +sakaiminato.tottori.jp +tottori.tottori.jp +wakasa.tottori.jp +yazu.tottori.jp +yonago.tottori.jp +asahi.toyama.jp +fuchu.toyama.jp +fukumitsu.toyama.jp +funahashi.toyama.jp +himi.toyama.jp +imizu.toyama.jp +inami.toyama.jp +johana.toyama.jp +kamiichi.toyama.jp +kurobe.toyama.jp +nakaniikawa.toyama.jp +namerikawa.toyama.jp +nanto.toyama.jp +nyuzen.toyama.jp +oyabe.toyama.jp +taira.toyama.jp +takaoka.toyama.jp +tateyama.toyama.jp +toga.toyama.jp +tonami.toyama.jp +toyama.toyama.jp +unazuki.toyama.jp +uozu.toyama.jp +yamada.toyama.jp +arida.wakayama.jp +aridagawa.wakayama.jp +gobo.wakayama.jp +hashimoto.wakayama.jp +hidaka.wakayama.jp +hirogawa.wakayama.jp +inami.wakayama.jp +iwade.wakayama.jp +kainan.wakayama.jp +kamitonda.wakayama.jp +katsuragi.wakayama.jp +kimino.wakayama.jp +kinokawa.wakayama.jp +kitayama.wakayama.jp +koya.wakayama.jp +koza.wakayama.jp +kozagawa.wakayama.jp +kudoyama.wakayama.jp +kushimoto.wakayama.jp +mihama.wakayama.jp +misato.wakayama.jp +nachikatsuura.wakayama.jp +shingu.wakayama.jp +shirahama.wakayama.jp +taiji.wakayama.jp +tanabe.wakayama.jp +wakayama.wakayama.jp +yuasa.wakayama.jp +yura.wakayama.jp +asahi.yamagata.jp +funagata.yamagata.jp +higashine.yamagata.jp +iide.yamagata.jp +kahoku.yamagata.jp +kaminoyama.yamagata.jp +kaneyama.yamagata.jp +kawanishi.yamagata.jp +mamurogawa.yamagata.jp +mikawa.yamagata.jp +murayama.yamagata.jp +nagai.yamagata.jp +nakayama.yamagata.jp +nanyo.yamagata.jp +nishikawa.yamagata.jp +obanazawa.yamagata.jp +oe.yamagata.jp +oguni.yamagata.jp +ohkura.yamagata.jp +oishida.yamagata.jp +sagae.yamagata.jp +sakata.yamagata.jp +sakegawa.yamagata.jp +shinjo.yamagata.jp +shirataka.yamagata.jp +shonai.yamagata.jp +takahata.yamagata.jp +tendo.yamagata.jp +tozawa.yamagata.jp +tsuruoka.yamagata.jp +yamagata.yamagata.jp +yamanobe.yamagata.jp +yonezawa.yamagata.jp +yuza.yamagata.jp +abu.yamaguchi.jp +hagi.yamaguchi.jp +hikari.yamaguchi.jp +hofu.yamaguchi.jp +iwakuni.yamaguchi.jp +kudamatsu.yamaguchi.jp +mitou.yamaguchi.jp +nagato.yamaguchi.jp +oshima.yamaguchi.jp +shimonoseki.yamaguchi.jp +shunan.yamaguchi.jp +tabuse.yamaguchi.jp +tokuyama.yamaguchi.jp +toyota.yamaguchi.jp +ube.yamaguchi.jp +yuu.yamaguchi.jp +chuo.yamanashi.jp +doshi.yamanashi.jp +fuefuki.yamanashi.jp +fujikawa.yamanashi.jp +fujikawaguchiko.yamanashi.jp +fujiyoshida.yamanashi.jp +hayakawa.yamanashi.jp +hokuto.yamanashi.jp +ichikawamisato.yamanashi.jp +kai.yamanashi.jp +kofu.yamanashi.jp +koshu.yamanashi.jp +kosuge.yamanashi.jp +minami-alps.yamanashi.jp +minobu.yamanashi.jp +nakamichi.yamanashi.jp +nanbu.yamanashi.jp +narusawa.yamanashi.jp +nirasaki.yamanashi.jp +nishikatsura.yamanashi.jp +oshino.yamanashi.jp +otsuki.yamanashi.jp +showa.yamanashi.jp +tabayama.yamanashi.jp +tsuru.yamanashi.jp +uenohara.yamanashi.jp +yamanakako.yamanashi.jp +yamanashi.yamanashi.jp + +// ke : http://www.kenic.or.ke/index.php/en/ke-domains/ke-domains +ke +ac.ke +co.ke +go.ke +info.ke +me.ke +mobi.ke +ne.ke +or.ke +sc.ke + +// kg : http://www.domain.kg/dmn_n.html +kg +com.kg +edu.kg +gov.kg +mil.kg +net.kg +org.kg + +// kh : http://www.mptc.gov.kh/dns_registration.htm +*.kh + +// ki : https://www.iana.org/domains/root/db/ki.html +ki +biz.ki +com.ki +edu.ki +gov.ki +info.ki +net.ki +org.ki + +// km : https://www.iana.org/domains/root/db/km.html +// http://www.domaine.km/documents/charte.doc +km +ass.km +com.km +edu.km +gov.km +mil.km +nom.km +org.km +prd.km +tm.km +// These are only mentioned as proposed suggestions at domaine.km, but +// https://www.iana.org/domains/root/db/km.html says they're available for registration: +asso.km +coop.km +gouv.km +medecin.km +notaires.km +pharmaciens.km +presse.km +veterinaire.km + +// kn : https://www.iana.org/domains/root/db/kn.html +// http://www.dot.kn/domainRules.html +kn +edu.kn +gov.kn +net.kn +org.kn + +// kp : http://www.kcce.kp/en_index.php +kp +com.kp +edu.kp +gov.kp +org.kp +rep.kp +tra.kp + +// kr : https://www.iana.org/domains/root/db/kr.html +// see also: https://krnic.kisa.or.kr/jsp/infoboard/law/domBylawsReg.jsp +kr +ac.kr +ai.kr +co.kr +es.kr +go.kr +hs.kr +io.kr +it.kr +kg.kr +me.kr +mil.kr +ms.kr +ne.kr +or.kr +pe.kr +re.kr +sc.kr +// kr geographical names +busan.kr +chungbuk.kr +chungnam.kr +daegu.kr +daejeon.kr +gangwon.kr +gwangju.kr +gyeongbuk.kr +gyeonggi.kr +gyeongnam.kr +incheon.kr +jeju.kr +jeonbuk.kr +jeonnam.kr +seoul.kr +ulsan.kr + +// kw : https://www.nic.kw/policies/ +// Confirmed by registry +kw +com.kw +edu.kw +emb.kw +gov.kw +ind.kw +net.kw +org.kw + +// ky : http://www.icta.ky/da_ky_reg_dom.php +// Confirmed by registry 2008-06-17 +ky +com.ky +edu.ky +net.ky +org.ky + +// kz : https://www.iana.org/domains/root/db/kz.html +// see also: http://www.nic.kz/rules/index.jsp +kz +com.kz +edu.kz +gov.kz +mil.kz +net.kz +org.kz + +// la : https://www.iana.org/domains/root/db/la.html +// Submitted by registry +la +com.la +edu.la +gov.la +info.la +int.la +net.la +org.la +per.la + +// lb : https://www.iana.org/domains/root/db/lb.html +// Submitted by registry +lb +com.lb +edu.lb +gov.lb +net.lb +org.lb + +// lc : https://www.iana.org/domains/root/db/lc.html +// see also: http://www.nic.lc/rules.htm +lc +co.lc +com.lc +edu.lc +gov.lc +net.lc +org.lc + +// li : https://www.iana.org/domains/root/db/li.html +li + +// lk : https://www.iana.org/domains/root/db/lk.html +lk +ac.lk +assn.lk +com.lk +edu.lk +gov.lk +grp.lk +hotel.lk +int.lk +ltd.lk +net.lk +ngo.lk +org.lk +sch.lk +soc.lk +web.lk + +// lr : http://psg.com/dns/lr/lr.txt +// Submitted by registry +lr +com.lr +edu.lr +gov.lr +net.lr +org.lr + +// ls : http://www.nic.ls/ +// Confirmed by registry +ls +ac.ls +biz.ls +co.ls +edu.ls +gov.ls +info.ls +net.ls +org.ls +sc.ls + +// lt : https://www.iana.org/domains/root/db/lt.html +lt +// gov.lt : http://www.gov.lt/index_en.php +gov.lt + +// lu : http://www.dns.lu/en/ +lu + +// lv : https://www.iana.org/domains/root/db/lv.html +lv +asn.lv +com.lv +conf.lv +edu.lv +gov.lv +id.lv +mil.lv +net.lv +org.lv + +// ly : http://www.nic.ly/regulations.php +ly +com.ly +edu.ly +gov.ly +id.ly +med.ly +net.ly +org.ly +plc.ly +sch.ly + +// ma : https://www.iana.org/domains/root/db/ma.html +// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf +ma +ac.ma +co.ma +gov.ma +net.ma +org.ma +press.ma + +// mc : http://www.nic.mc/ +mc +asso.mc +tm.mc + +// md : https://www.iana.org/domains/root/db/md.html +md + +// me : https://www.iana.org/domains/root/db/me.html +me +ac.me +co.me +edu.me +gov.me +its.me +net.me +org.me +priv.me + +// mg : https://nic.mg +mg +co.mg +com.mg +edu.mg +gov.mg +mil.mg +nom.mg +org.mg +prd.mg + +// mh : https://www.iana.org/domains/root/db/mh.html +mh + +// mil : https://www.iana.org/domains/root/db/mil.html +mil + +// mk : https://www.iana.org/domains/root/db/mk.html +// see also: http://dns.marnet.net.mk/postapka.php +mk +com.mk +edu.mk +gov.mk +inf.mk +name.mk +net.mk +org.mk + +// ml : https://www.iana.org/domains/root/db/ml.html +// Confirmed by Boubacar NDIAYE 2024-12-31 +ml +ac.ml +art.ml +asso.ml +com.ml +edu.ml +gouv.ml +gov.ml +info.ml +inst.ml +net.ml +org.ml +pr.ml +presse.ml + +// mm : https://www.iana.org/domains/root/db/mm.html +*.mm + +// mn : https://www.iana.org/domains/root/db/mn.html +mn +edu.mn +gov.mn +org.mn + +// mo : http://www.monic.net.mo/ +mo +com.mo +edu.mo +gov.mo +net.mo +org.mo + +// mobi : https://www.iana.org/domains/root/db/mobi.html +mobi + +// mp : http://www.dot.mp/ +// Confirmed by registry 2008-06-17 +mp + +// mq : https://www.iana.org/domains/root/db/mq.html +mq + +// mr : https://www.iana.org/domains/root/db/mr.html +mr +gov.mr + +// ms : https://www.iana.org/domains/root/db/ms.html +ms +com.ms +edu.ms +gov.ms +net.ms +org.ms + +// mt : https://www.nic.org.mt/go/policy +// Submitted by registry +mt +com.mt +edu.mt +net.mt +org.mt + +// mu : https://www.iana.org/domains/root/db/mu.html +mu +ac.mu +co.mu +com.mu +gov.mu +net.mu +or.mu +org.mu + +// museum : https://welcome.museum/wp-content/uploads/2018/05/20180525-Registration-Policy-MUSEUM-EN_VF-2.pdf https://welcome.museum/buy-your-dot-museum-2/ +museum + +// mv : https://www.iana.org/domains/root/db/mv.html +// "mv" included because, contra Wikipedia, google.mv exists. +mv +aero.mv +biz.mv +com.mv +coop.mv +edu.mv +gov.mv +info.mv +int.mv +mil.mv +museum.mv +name.mv +net.mv +org.mv +pro.mv + +// mw : http://www.registrar.mw/ +mw +ac.mw +biz.mw +co.mw +com.mw +coop.mw +edu.mw +gov.mw +int.mw +net.mw +org.mw + +// mx : http://www.nic.mx/ +// Submitted by registry +mx +com.mx +edu.mx +gob.mx +net.mx +org.mx + +// my : http://www.mynic.my/ +// Available strings: https://mynic.my/resources/domains/buying-a-domain/ +my +biz.my +com.my +edu.my +gov.my +mil.my +name.my +net.my +org.my + +// mz : http://www.uem.mz/ +// Submitted by registry +mz +ac.mz +adv.mz +co.mz +edu.mz +gov.mz +mil.mz +net.mz +org.mz + +// na : http://www.na-nic.com.na/ +na +alt.na +co.na +com.na +gov.na +net.na +org.na + +// name : http://www.nic.name/ +// Regarding 2LDs: https://github.com/publicsuffix/list/issues/2306 +name + +// nc : http://www.cctld.nc/ +nc +asso.nc +nom.nc + +// ne : https://www.iana.org/domains/root/db/ne.html +ne + +// net : https://www.iana.org/domains/root/db/net.html +net + +// nf : https://www.iana.org/domains/root/db/nf.html +nf +arts.nf +com.nf +firm.nf +info.nf +net.nf +other.nf +per.nf +rec.nf +store.nf +web.nf + +// ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds +ng +com.ng +edu.ng +gov.ng +i.ng +mil.ng +mobi.ng +name.ng +net.ng +org.ng +sch.ng + +// ni : http://www.nic.ni/ +ni +ac.ni +biz.ni +co.ni +com.ni +edu.ni +gob.ni +in.ni +info.ni +int.ni +mil.ni +net.ni +nom.ni +org.ni +web.ni + +// nl : https://www.iana.org/domains/root/db/nl.html +// https://www.sidn.nl/ +nl + +// no : https://www.norid.no/en/om-domenenavn/regelverk-for-no/ +// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ +// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ +// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ +// RSS feed: https://teknisk.norid.no/en/feed/ +no +// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ +fhs.no +folkebibl.no +fylkesbibl.no +idrett.no +museum.no +priv.no +vgs.no +// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ +dep.no +herad.no +kommune.no +mil.no +stat.no +// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ +// counties +aa.no +ah.no +bu.no +fm.no +hl.no +hm.no +jan-mayen.no +mr.no +nl.no +nt.no +of.no +ol.no +oslo.no +rl.no +sf.no +st.no +svalbard.no +tm.no +tr.no +va.no +vf.no +// primary and lower secondary schools per county +gs.aa.no +gs.ah.no +gs.bu.no +gs.fm.no +gs.hl.no +gs.hm.no +gs.jan-mayen.no +gs.mr.no +gs.nl.no +gs.nt.no +gs.of.no +gs.ol.no +gs.oslo.no +gs.rl.no +gs.sf.no +gs.st.no +gs.svalbard.no +gs.tm.no +gs.tr.no +gs.va.no +gs.vf.no +// cities +akrehamn.no +åkrehamn.no +algard.no +ålgård.no +arna.no +bronnoysund.no +brønnøysund.no +brumunddal.no +bryne.no +drobak.no +drøbak.no +egersund.no +fetsund.no +floro.no +florø.no +fredrikstad.no +hokksund.no +honefoss.no +hønefoss.no +jessheim.no +jorpeland.no +jørpeland.no +kirkenes.no +kopervik.no +krokstadelva.no +langevag.no +langevåg.no +leirvik.no +mjondalen.no +mjøndalen.no +mo-i-rana.no +mosjoen.no +mosjøen.no +nesoddtangen.no +orkanger.no +osoyro.no +osøyro.no +raholt.no +råholt.no +sandnessjoen.no +sandnessjøen.no +skedsmokorset.no +slattum.no +spjelkavik.no +stathelle.no +stavern.no +stjordalshalsen.no +stjørdalshalsen.no +tananger.no +tranby.no +vossevangen.no +// communities +aarborte.no +aejrie.no +afjord.no +åfjord.no +agdenes.no +nes.akershus.no +aknoluokta.no +ákŋoluokta.no +al.no +ål.no +alaheadju.no +álaheadju.no +alesund.no +ålesund.no +alstahaug.no +alta.no +áltá.no +alvdal.no +amli.no +åmli.no +amot.no +åmot.no +andasuolo.no +andebu.no +andoy.no +andøy.no +ardal.no +årdal.no +aremark.no +arendal.no +ås.no +aseral.no +åseral.no +asker.no +askim.no +askoy.no +askøy.no +askvoll.no +asnes.no +åsnes.no +audnedaln.no +aukra.no +aure.no +aurland.no +aurskog-holand.no +aurskog-høland.no +austevoll.no +austrheim.no +averoy.no +averøy.no +badaddja.no +bådåddjå.no +bærum.no +bahcavuotna.no +báhcavuotna.no +bahccavuotna.no +báhccavuotna.no +baidar.no +báidár.no +bajddar.no +bájddar.no +balat.no +bálát.no +balestrand.no +ballangen.no +balsfjord.no +bamble.no +bardu.no +barum.no +batsfjord.no +båtsfjord.no +bearalvahki.no +bearalváhki.no +beardu.no +beiarn.no +berg.no +bergen.no +berlevag.no +berlevåg.no +bievat.no +bievát.no +bindal.no +birkenes.no +bjarkoy.no +bjarkøy.no +bjerkreim.no +bjugn.no +bodo.no +bodø.no +bokn.no +bomlo.no +bømlo.no +bremanger.no +bronnoy.no +brønnøy.no +budejju.no +nes.buskerud.no +bygland.no +bykle.no +cahcesuolo.no +čáhcesuolo.no +davvenjarga.no +davvenjárga.no +davvesiida.no +deatnu.no +dielddanuorri.no +divtasvuodna.no +divttasvuotna.no +donna.no +dønna.no +dovre.no +drammen.no +drangedal.no +dyroy.no +dyrøy.no +eid.no +eidfjord.no +eidsberg.no +eidskog.no +eidsvoll.no +eigersund.no +elverum.no +enebakk.no +engerdal.no +etne.no +etnedal.no +evenassi.no +evenášši.no +evenes.no +evje-og-hornnes.no +farsund.no +fauske.no +fedje.no +fet.no +finnoy.no +finnøy.no +fitjar.no +fjaler.no +fjell.no +fla.no +flå.no +flakstad.no +flatanger.no +flekkefjord.no +flesberg.no +flora.no +folldal.no +forde.no +førde.no +forsand.no +fosnes.no +fræna.no +frana.no +frei.no +frogn.no +froland.no +frosta.no +froya.no +frøya.no +fuoisku.no +fuossko.no +fusa.no +fyresdal.no +gaivuotna.no +gáivuotna.no +galsa.no +gálsá.no +gamvik.no +gangaviika.no +gáŋgaviika.no +gaular.no +gausdal.no +giehtavuoatna.no +gildeskal.no +gildeskål.no +giske.no +gjemnes.no +gjerdrum.no +gjerstad.no +gjesdal.no +gjovik.no +gjøvik.no +gloppen.no +gol.no +gran.no +grane.no +granvin.no +gratangen.no +grimstad.no +grong.no +grue.no +gulen.no +guovdageaidnu.no +ha.no +hå.no +habmer.no +hábmer.no +hadsel.no +hægebostad.no +hagebostad.no +halden.no +halsa.no +hamar.no +hamaroy.no +hammarfeasta.no +hámmárfeasta.no +hammerfest.no +hapmir.no +hápmir.no +haram.no +hareid.no +harstad.no +hasvik.no +hattfjelldal.no +haugesund.no +os.hedmark.no +valer.hedmark.no +våler.hedmark.no +hemne.no +hemnes.no +hemsedal.no +hitra.no +hjartdal.no +hjelmeland.no +hobol.no +hobøl.no +hof.no +hol.no +hole.no +holmestrand.no +holtalen.no +holtålen.no +os.hordaland.no +hornindal.no +horten.no +hoyanger.no +høyanger.no +hoylandet.no +høylandet.no +hurdal.no +hurum.no +hvaler.no +hyllestad.no +ibestad.no +inderoy.no +inderøy.no +iveland.no +ivgu.no +jevnaker.no +jolster.no +jølster.no +jondal.no +kafjord.no +kåfjord.no +karasjohka.no +kárášjohka.no +karasjok.no +karlsoy.no +karmoy.no +karmøy.no +kautokeino.no +klabu.no +klæbu.no +klepp.no +kongsberg.no +kongsvinger.no +kraanghke.no +kråanghke.no +kragero.no +kragerø.no +kristiansand.no +kristiansund.no +krodsherad.no +krødsherad.no +kvæfjord.no +kvænangen.no +kvafjord.no +kvalsund.no +kvam.no +kvanangen.no +kvinesdal.no +kvinnherad.no +kviteseid.no +kvitsoy.no +kvitsøy.no +laakesvuemie.no +lærdal.no +lahppi.no +láhppi.no +lardal.no +larvik.no +lavagis.no +lavangen.no +leangaviika.no +leaŋgaviika.no +lebesby.no +leikanger.no +leirfjord.no +leka.no +leksvik.no +lenvik.no +lerdal.no +lesja.no +levanger.no +lier.no +lierne.no +lillehammer.no +lillesand.no +lindas.no +lindås.no +lindesnes.no +loabat.no +loabát.no +lodingen.no +lødingen.no +lom.no +loppa.no +lorenskog.no +lørenskog.no +loten.no +løten.no +lund.no +lunner.no +luroy.no +lurøy.no +luster.no +lyngdal.no +lyngen.no +malatvuopmi.no +málatvuopmi.no +malselv.no +målselv.no +malvik.no +mandal.no +marker.no +marnardal.no +masfjorden.no +masoy.no +måsøy.no +matta-varjjat.no +mátta-várjjat.no +meland.no +meldal.no +melhus.no +meloy.no +meløy.no +meraker.no +meråker.no +midsund.no +midtre-gauldal.no +moareke.no +moåreke.no +modalen.no +modum.no +molde.no +heroy.more-og-romsdal.no +sande.more-og-romsdal.no +herøy.møre-og-romsdal.no +sande.møre-og-romsdal.no +moskenes.no +moss.no +mosvik.no +muosat.no +muosát.no +naamesjevuemie.no +nååmesjevuemie.no +nærøy.no +namdalseid.no +namsos.no +namsskogan.no +nannestad.no +naroy.no +narviika.no +narvik.no +naustdal.no +navuotna.no +návuotna.no +nedre-eiker.no +nesna.no +nesodden.no +nesseby.no +nesset.no +nissedal.no +nittedal.no +nord-aurdal.no +nord-fron.no +nord-odal.no +norddal.no +nordkapp.no +bo.nordland.no +bø.nordland.no +heroy.nordland.no +herøy.nordland.no +nordre-land.no +nordreisa.no +nore-og-uvdal.no +notodden.no +notteroy.no +nøtterøy.no +odda.no +oksnes.no +øksnes.no +omasvuotna.no +oppdal.no +oppegard.no +oppegård.no +orkdal.no +orland.no +ørland.no +orskog.no +ørskog.no +orsta.no +ørsta.no +osen.no +osteroy.no +osterøy.no +valer.ostfold.no +våler.østfold.no +ostre-toten.no +østre-toten.no +overhalla.no +ovre-eiker.no +øvre-eiker.no +oyer.no +øyer.no +oygarden.no +øygarden.no +oystre-slidre.no +øystre-slidre.no +porsanger.no +porsangu.no +porsáŋgu.no +porsgrunn.no +rade.no +råde.no +radoy.no +radøy.no +rælingen.no +rahkkeravju.no +ráhkkerávju.no +raisa.no +ráisa.no +rakkestad.no +ralingen.no +rana.no +randaberg.no +rauma.no +rendalen.no +rennebu.no +rennesoy.no +rennesøy.no +rindal.no +ringebu.no +ringerike.no +ringsaker.no +risor.no +risør.no +rissa.no +roan.no +rodoy.no +rødøy.no +rollag.no +romsa.no +romskog.no +rømskog.no +roros.no +røros.no +rost.no +røst.no +royken.no +røyken.no +royrvik.no +røyrvik.no +ruovat.no +rygge.no +salangen.no +salat.no +sálat.no +sálát.no +saltdal.no +samnanger.no +sandefjord.no +sandnes.no +sandoy.no +sandøy.no +sarpsborg.no +sauda.no +sauherad.no +sel.no +selbu.no +selje.no +seljord.no +siellak.no +sigdal.no +siljan.no +sirdal.no +skanit.no +skánit.no +skanland.no +skånland.no +skaun.no +skedsmo.no +ski.no +skien.no +skierva.no +skiervá.no +skiptvet.no +skjak.no +skjåk.no +skjervoy.no +skjervøy.no +skodje.no +smola.no +smøla.no +snaase.no +snåase.no +snasa.no +snåsa.no +snillfjord.no +snoasa.no +sogndal.no +sogne.no +søgne.no +sokndal.no +sola.no +solund.no +somna.no +sømna.no +sondre-land.no +søndre-land.no +songdalen.no +sor-aurdal.no +sør-aurdal.no +sor-fron.no +sør-fron.no +sor-odal.no +sør-odal.no +sor-varanger.no +sør-varanger.no +sorfold.no +sørfold.no +sorreisa.no +sørreisa.no +sortland.no +sorum.no +sørum.no +spydeberg.no +stange.no +stavanger.no +steigen.no +steinkjer.no +stjordal.no +stjørdal.no +stokke.no +stor-elvdal.no +stord.no +stordal.no +storfjord.no +strand.no +stranda.no +stryn.no +sula.no +suldal.no +sund.no +sunndal.no +surnadal.no +sveio.no +svelvik.no +sykkylven.no +tana.no +bo.telemark.no +bø.telemark.no +time.no +tingvoll.no +tinn.no +tjeldsund.no +tjome.no +tjøme.no +tokke.no +tolga.no +tonsberg.no +tønsberg.no +torsken.no +træna.no +trana.no +tranoy.no +tranøy.no +troandin.no +trogstad.no +trøgstad.no +tromsa.no +tromso.no +tromsø.no +trondheim.no +trysil.no +tvedestrand.no +tydal.no +tynset.no +tysfjord.no +tysnes.no +tysvær.no +tysvar.no +ullensaker.no +ullensvang.no +ulvik.no +unjarga.no +unjárga.no +utsira.no +vaapste.no +vadso.no +vadsø.no +værøy.no +vaga.no +vågå.no +vagan.no +vågan.no +vagsoy.no +vågsøy.no +vaksdal.no +valle.no +vang.no +vanylven.no +vardo.no +vardø.no +varggat.no +várggát.no +varoy.no +vefsn.no +vega.no +vegarshei.no +vegårshei.no +vennesla.no +verdal.no +verran.no +vestby.no +sande.vestfold.no +vestnes.no +vestre-slidre.no +vestre-toten.no +vestvagoy.no +vestvågøy.no +vevelstad.no +vik.no +vikna.no +vindafjord.no +voagat.no +volda.no +voss.no + +// np : http://www.mos.com.np/register.html +*.np + +// nr : http://cenpac.net.nr/dns/index.html +// Submitted by registry +nr +biz.nr +com.nr +edu.nr +gov.nr +info.nr +net.nr +org.nr + +// nu : https://www.iana.org/domains/root/db/nu.html +nu + +// nz : https://www.iana.org/domains/root/db/nz.html +// Submitted by registry +nz +ac.nz +co.nz +cri.nz +geek.nz +gen.nz +govt.nz +health.nz +iwi.nz +kiwi.nz +maori.nz +māori.nz +mil.nz +net.nz +org.nz +parliament.nz +school.nz + +// om : https://www.iana.org/domains/root/db/om.html +om +co.om +com.om +edu.om +gov.om +med.om +museum.om +net.om +org.om +pro.om + +// onion : https://tools.ietf.org/html/rfc7686 +onion + +// org : https://www.iana.org/domains/root/db/org.html +org + +// pa : http://www.nic.pa/ +// Some additional second level "domains" resolve directly as hostnames, such as +// pannet.pa, so we add a rule for "pa". +pa +abo.pa +ac.pa +com.pa +edu.pa +gob.pa +ing.pa +med.pa +net.pa +nom.pa +org.pa +sld.pa + +// pe : https://www.nic.pe/InformeFinalComision.pdf +pe +com.pe +edu.pe +gob.pe +mil.pe +net.pe +nom.pe +org.pe + +// pf : http://www.gobin.info/domainname/formulaire-pf.pdf +pf +com.pf +edu.pf +org.pf + +// pg : https://www.iana.org/domains/root/db/pg.html +*.pg + +// ph : https://www.iana.org/domains/root/db/ph.html +// Submitted by registry +ph +com.ph +edu.ph +gov.ph +i.ph +mil.ph +net.ph +ngo.ph +org.ph + +// pk : https://pk5.pknic.net.pk/pk5/msgNamepk.PK +// Contact Email: staff@pknic.net.pk +pk +ac.pk +biz.pk +com.pk +edu.pk +fam.pk +gkp.pk +gob.pk +gog.pk +gok.pk +gop.pk +gos.pk +gov.pk +net.pk +org.pk +web.pk + +// pl : https://www.dns.pl/en/ +// Confirmed by registry 2024-11-18 +pl +com.pl +net.pl +org.pl +// pl functional domains : https://www.dns.pl/en/list_of_functional_domain_names +agro.pl +aid.pl +atm.pl +auto.pl +biz.pl +edu.pl +gmina.pl +gsm.pl +info.pl +mail.pl +media.pl +miasta.pl +mil.pl +nieruchomosci.pl +nom.pl +pc.pl +powiat.pl +priv.pl +realestate.pl +rel.pl +sex.pl +shop.pl +sklep.pl +sos.pl +szkola.pl +targi.pl +tm.pl +tourism.pl +travel.pl +turystyka.pl +// Government domains : https://www.dns.pl/informacje_o_rejestracji_domen_gov_pl +// In accordance with the .gov.pl Domain Name Regulations : https://www.dns.pl/regulamin_gov_pl +gov.pl +ap.gov.pl +griw.gov.pl +ic.gov.pl +is.gov.pl +kmpsp.gov.pl +konsulat.gov.pl +kppsp.gov.pl +kwp.gov.pl +kwpsp.gov.pl +mup.gov.pl +mw.gov.pl +oia.gov.pl +oirm.gov.pl +oke.gov.pl +oow.gov.pl +oschr.gov.pl +oum.gov.pl +pa.gov.pl +pinb.gov.pl +piw.gov.pl +po.gov.pl +pr.gov.pl +psp.gov.pl +psse.gov.pl +pup.gov.pl +rzgw.gov.pl +sa.gov.pl +sdn.gov.pl +sko.gov.pl +so.gov.pl +sr.gov.pl +starostwo.gov.pl +ug.gov.pl +ugim.gov.pl +um.gov.pl +umig.gov.pl +upow.gov.pl +uppo.gov.pl +us.gov.pl +uw.gov.pl +uzs.gov.pl +wif.gov.pl +wiih.gov.pl +winb.gov.pl +wios.gov.pl +witd.gov.pl +wiw.gov.pl +wkz.gov.pl +wsa.gov.pl +wskr.gov.pl +wsse.gov.pl +wuoz.gov.pl +wzmiuw.gov.pl +zp.gov.pl +zpisdn.gov.pl +// pl regional domains : https://www.dns.pl/en/list_of_regional_domain_names +augustow.pl +babia-gora.pl +bedzin.pl +beskidy.pl +bialowieza.pl +bialystok.pl +bielawa.pl +bieszczady.pl +boleslawiec.pl +bydgoszcz.pl +bytom.pl +cieszyn.pl +czeladz.pl +czest.pl +dlugoleka.pl +elblag.pl +elk.pl +glogow.pl +gniezno.pl +gorlice.pl +grajewo.pl +ilawa.pl +jaworzno.pl +jelenia-gora.pl +jgora.pl +kalisz.pl +karpacz.pl +kartuzy.pl +kaszuby.pl +katowice.pl +kazimierz-dolny.pl +kepno.pl +ketrzyn.pl +klodzko.pl +kobierzyce.pl +kolobrzeg.pl +konin.pl +konskowola.pl +kutno.pl +lapy.pl +lebork.pl +legnica.pl +lezajsk.pl +limanowa.pl +lomza.pl +lowicz.pl +lubin.pl +lukow.pl +malbork.pl +malopolska.pl +mazowsze.pl +mazury.pl +mielec.pl +mielno.pl +mragowo.pl +naklo.pl +nowaruda.pl +nysa.pl +olawa.pl +olecko.pl +olkusz.pl +olsztyn.pl +opoczno.pl +opole.pl +ostroda.pl +ostroleka.pl +ostrowiec.pl +ostrowwlkp.pl +pila.pl +pisz.pl +podhale.pl +podlasie.pl +polkowice.pl +pomorskie.pl +pomorze.pl +prochowice.pl +pruszkow.pl +przeworsk.pl +pulawy.pl +radom.pl +rawa-maz.pl +rybnik.pl +rzeszow.pl +sanok.pl +sejny.pl +skoczow.pl +slask.pl +slupsk.pl +sosnowiec.pl +stalowa-wola.pl +starachowice.pl +stargard.pl +suwalki.pl +swidnica.pl +swiebodzin.pl +swinoujscie.pl +szczecin.pl +szczytno.pl +tarnobrzeg.pl +tgory.pl +turek.pl +tychy.pl +ustka.pl +walbrzych.pl +warmia.pl +warszawa.pl +waw.pl +wegrow.pl +wielun.pl +wlocl.pl +wloclawek.pl +wodzislaw.pl +wolomin.pl +wroclaw.pl +zachpomor.pl +zagan.pl +zarow.pl +zgora.pl +zgorzelec.pl + +// pm : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf +pm + +// pn : https://www.iana.org/domains/root/db/pn.html +pn +co.pn +edu.pn +gov.pn +net.pn +org.pn + +// post : https://www.iana.org/domains/root/db/post.html +post + +// pr : http://www.nic.pr/index.asp?f=1 +pr +biz.pr +com.pr +edu.pr +gov.pr +info.pr +isla.pr +name.pr +net.pr +org.pr +pro.pr +// these aren't mentioned on nic.pr, but on https://www.iana.org/domains/root/db/pr.html +ac.pr +est.pr +prof.pr + +// pro : http://registry.pro/get-pro +pro +aaa.pro +aca.pro +acct.pro +avocat.pro +bar.pro +cpa.pro +eng.pro +jur.pro +law.pro +med.pro +recht.pro + +// ps : https://www.iana.org/domains/root/db/ps.html +// http://www.nic.ps/registration/policy.html#reg +ps +com.ps +edu.ps +gov.ps +net.ps +org.ps +plo.ps +sec.ps + +// pt : https://www.dns.pt/en/domain/pt-terms-and-conditions-registration-rules/ +pt +com.pt +edu.pt +gov.pt +int.pt +net.pt +nome.pt +org.pt +publ.pt + +// pw : https://www.iana.org/domains/root/db/pw.html +// Confirmed by registry in private correspondence with @dnsguru 2024-12-09 +pw +gov.pw + +// py : https://www.iana.org/domains/root/db/py.html +// Submitted by registry +py +com.py +coop.py +edu.py +gov.py +mil.py +net.py +org.py + +// qa : http://domains.qa/en/ +qa +com.qa +edu.qa +gov.qa +mil.qa +name.qa +net.qa +org.qa +sch.qa + +// re : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf +// Confirmed by registry 2024-11-18 +re +// Closed for registration on 2013-03-15 but domains are still maintained +asso.re +com.re + +// ro : http://www.rotld.ro/ +ro +arts.ro +com.ro +firm.ro +info.ro +nom.ro +nt.ro +org.ro +rec.ro +store.ro +tm.ro +www.ro + +// rs : https://www.rnids.rs/en/domains/national-domains +rs +ac.rs +co.rs +edu.rs +gov.rs +in.rs +org.rs + +// ru : https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf +// Submitted by George Georgievsky +ru + +// rw : https://www.iana.org/domains/root/db/rw.html +rw +ac.rw +co.rw +coop.rw +gov.rw +mil.rw +net.rw +org.rw + +// sa : http://www.nic.net.sa/ +sa +com.sa +edu.sa +gov.sa +med.sa +net.sa +org.sa +pub.sa +sch.sa + +// sb : http://www.sbnic.net.sb/ +// Submitted by registry +sb +com.sb +edu.sb +gov.sb +net.sb +org.sb + +// sc : http://www.nic.sc/ +sc +com.sc +edu.sc +gov.sc +net.sc +org.sc + +// sd : https://www.iana.org/domains/root/db/sd.html +// Submitted by registry +sd +com.sd +edu.sd +gov.sd +info.sd +med.sd +net.sd +org.sd +tv.sd + +// se : https://www.iana.org/domains/root/db/se.html +// https://data.internetstiftelsen.se/barred_domains_list.txt -> Second level domains & Sub-domains +// Confirmed by Registry Services 2024-11-20 +se +a.se +ac.se +b.se +bd.se +brand.se +c.se +d.se +e.se +f.se +fh.se +fhsk.se +fhv.se +g.se +h.se +i.se +k.se +komforb.se +kommunalforbund.se +komvux.se +l.se +lanbib.se +m.se +n.se +naturbruksgymn.se +o.se +org.se +p.se +parti.se +pp.se +press.se +r.se +s.se +t.se +tm.se +u.se +w.se +x.se +y.se +z.se + +// sg : https://www.sgnic.sg/domain-registration/sg-categories-rules +// Confirmed by registry 2024-11-19 +sg +com.sg +edu.sg +gov.sg +net.sg +org.sg + +// sh : http://nic.sh/rules.htm +sh +com.sh +gov.sh +mil.sh +net.sh +org.sh + +// si : https://www.iana.org/domains/root/db/si.html +si + +// sj : No registrations at this time. +// Submitted by registry +sj + +// sk : https://www.iana.org/domains/root/db/sk.html +sk + +// sl : http://www.nic.sl +// Submitted by registry +sl +com.sl +edu.sl +gov.sl +net.sl +org.sl + +// sm : https://www.iana.org/domains/root/db/sm.html +sm + +// sn : https://www.iana.org/domains/root/db/sn.html +sn +art.sn +com.sn +edu.sn +gouv.sn +org.sn +perso.sn +univ.sn + +// so : http://sonic.so/policies/ +so +com.so +edu.so +gov.so +me.so +net.so +org.so + +// sr : https://www.iana.org/domains/root/db/sr.html +sr + +// ss : https://registry.nic.ss/ +// Submitted by registry +ss +biz.ss +co.ss +com.ss +edu.ss +gov.ss +me.ss +net.ss +org.ss +sch.ss + +// st : http://www.nic.st/html/policyrules/ +st +co.st +com.st +consulado.st +edu.st +embaixada.st +mil.st +net.st +org.st +principe.st +saotome.st +store.st + +// su : https://www.iana.org/domains/root/db/su.html +su + +// sv : https://www.iana.org/domains/root/db/sv.html +sv +com.sv +edu.sv +gob.sv +org.sv +red.sv + +// sx : https://www.iana.org/domains/root/db/sx.html +// Submitted by registry +sx +gov.sx + +// sy : https://www.iana.org/domains/root/db/sy.html +sy +com.sy +edu.sy +gov.sy +mil.sy +net.sy +org.sy + +// sz : https://www.iana.org/domains/root/db/sz.html +// http://www.sispa.org.sz/ +sz +ac.sz +co.sz +org.sz + +// tc : https://www.iana.org/domains/root/db/tc.html +tc + +// td : https://www.iana.org/domains/root/db/td.html +td + +// tel : https://www.iana.org/domains/root/db/tel.html +// http://www.telnic.org/ +tel + +// tf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf +tf + +// tg : https://www.iana.org/domains/root/db/tg.html +// http://www.nic.tg/ +tg + +// th : https://www.iana.org/domains/root/db/th.html +// Submitted by registry +th +ac.th +co.th +go.th +in.th +mi.th +net.th +or.th + +// tj : http://www.nic.tj/policy.html +tj +ac.tj +biz.tj +co.tj +com.tj +edu.tj +go.tj +gov.tj +int.tj +mil.tj +name.tj +net.tj +nic.tj +org.tj +test.tj +web.tj + +// tk : https://www.iana.org/domains/root/db/tk.html +tk + +// tl : https://www.iana.org/domains/root/db/tl.html +tl +gov.tl + +// tm : https://www.nic.tm/local.html +// Confirmed by registry 2024-11-19 +tm +co.tm +com.tm +edu.tm +gov.tm +mil.tm +net.tm +nom.tm +org.tm + +// tn : http://www.registre.tn/fr/ +// https://whois.ati.tn/ +tn +com.tn +ens.tn +fin.tn +gov.tn +ind.tn +info.tn +intl.tn +mincom.tn +nat.tn +net.tn +org.tn +perso.tn +tourism.tn + +// to : https://www.iana.org/domains/root/db/to.html +// Submitted by registry +to +com.to +edu.to +gov.to +mil.to +net.to +org.to + +// tr : https://nic.tr/ +// https://nic.tr/forms/eng/policies.pdf +// https://nic.tr/index.php?USRACTN=PRICELST +tr +av.tr +bbs.tr +bel.tr +biz.tr +com.tr +dr.tr +edu.tr +gen.tr +gov.tr +info.tr +k12.tr +kep.tr +mil.tr +name.tr +net.tr +org.tr +pol.tr +tel.tr +tsk.tr +tv.tr +web.tr +// Used by Northern Cyprus +nc.tr +// Used by government agencies of Northern Cyprus +gov.nc.tr + +// tt : https://www.nic.tt/ +// Confirmed by registry 2024-11-19 +tt +biz.tt +co.tt +com.tt +edu.tt +gov.tt +info.tt +mil.tt +name.tt +net.tt +org.tt +pro.tt + +// tv : https://www.iana.org/domains/root/db/tv.html +// Not listing any 2LDs as reserved since none seem to exist in practice, +// Wikipedia notwithstanding. +tv + +// tw : https://www.iana.org/domains/root/db/tw.html +// https://twnic.tw/dnservice_catag.php +// Confirmed by registry 2024-11-26 +tw +club.tw +com.tw +ebiz.tw +edu.tw +game.tw +gov.tw +idv.tw +mil.tw +net.tw +org.tw + +// tz : http://www.tznic.or.tz/index.php/domains +// Submitted by registry +tz +ac.tz +co.tz +go.tz +hotel.tz +info.tz +me.tz +mil.tz +mobi.tz +ne.tz +or.tz +sc.tz +tv.tz + +// ua : https://hostmaster.ua/policy/?ua +// Submitted by registry +ua +// ua 2LD +com.ua +edu.ua +gov.ua +in.ua +net.ua +org.ua +// ua geographic names +// https://hostmaster.ua/2ld/ +cherkassy.ua +cherkasy.ua +chernigov.ua +chernihiv.ua +chernivtsi.ua +chernovtsy.ua +ck.ua +cn.ua +cr.ua +crimea.ua +cv.ua +dn.ua +dnepropetrovsk.ua +dnipropetrovsk.ua +donetsk.ua +dp.ua +if.ua +ivano-frankivsk.ua +kh.ua +kharkiv.ua +kharkov.ua +kherson.ua +khmelnitskiy.ua +khmelnytskyi.ua +kiev.ua +kirovograd.ua +km.ua +kr.ua +kropyvnytskyi.ua +krym.ua +ks.ua +kv.ua +kyiv.ua +lg.ua +lt.ua +lugansk.ua +luhansk.ua +lutsk.ua +lv.ua +lviv.ua +mk.ua +mykolaiv.ua +nikolaev.ua +od.ua +odesa.ua +odessa.ua +pl.ua +poltava.ua +rivne.ua +rovno.ua +rv.ua +sb.ua +sebastopol.ua +sevastopol.ua +sm.ua +sumy.ua +te.ua +ternopil.ua +uz.ua +uzhgorod.ua +uzhhorod.ua +vinnica.ua +vinnytsia.ua +vn.ua +volyn.ua +yalta.ua +zakarpattia.ua +zaporizhzhe.ua +zaporizhzhia.ua +zhitomir.ua +zhytomyr.ua +zp.ua +zt.ua + +// ug : https://www.registry.co.ug/ +// https://www.registry.co.ug, https://whois.co.ug +// Confirmed by registry 2025-01-20 +ug +ac.ug +co.ug +com.ug +edu.ug +go.ug +gov.ug +mil.ug +ne.ug +or.ug +org.ug +sc.ug +us.ug + +// uk : https://www.iana.org/domains/root/db/uk.html +// Submitted by registry +uk +ac.uk +co.uk +gov.uk +ltd.uk +me.uk +net.uk +nhs.uk +org.uk +plc.uk +police.uk +*.sch.uk + +// us : https://www.iana.org/domains/root/db/us.html +// Confirmed via the .us zone file by William Harrison 2024-12-10 +us +dni.us +isa.us +nsn.us +// Geographic Names +ak.us +al.us +ar.us +as.us +az.us +ca.us +co.us +ct.us +dc.us +de.us +fl.us +ga.us +gu.us +hi.us +ia.us +id.us +il.us +in.us +ks.us +ky.us +la.us +ma.us +md.us +me.us +mi.us +mn.us +mo.us +ms.us +mt.us +nc.us +nd.us +ne.us +nh.us +nj.us +nm.us +nv.us +ny.us +oh.us +ok.us +or.us +pa.us +pr.us +ri.us +sc.us +sd.us +tn.us +tx.us +ut.us +va.us +vi.us +vt.us +wa.us +wi.us +wv.us +wy.us +// The registrar notes several more specific domains available in each state, +// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat +// haphazard; in some states these domains resolve as addresses, while in others +// only subdomains are available, or even nothing at all. We include the +// most common ones where it's clear that different sites are different +// entities. +k12.ak.us +k12.al.us +k12.ar.us +k12.as.us +k12.az.us +k12.ca.us +k12.co.us +k12.ct.us +k12.dc.us +k12.fl.us +k12.ga.us +k12.gu.us +// k12.hi.us - Bug 614565 - Hawaii has a state-wide DOE login +k12.ia.us +k12.id.us +k12.il.us +k12.in.us +k12.ks.us +k12.ky.us +k12.la.us +k12.ma.us +k12.md.us +k12.me.us +k12.mi.us +k12.mn.us +k12.mo.us +k12.ms.us +k12.mt.us +k12.nc.us +// k12.nd.us - Bug 1028347 - Removed at request of Travis Rosso +k12.ne.us +k12.nh.us +k12.nj.us +k12.nm.us +k12.nv.us +k12.ny.us +k12.oh.us +k12.ok.us +k12.or.us +k12.pa.us +k12.pr.us +// k12.ri.us - Removed at request of Kim Cournoyer +k12.sc.us +// k12.sd.us - Bug 934131 - Removed at request of James Booze +k12.tn.us +k12.tx.us +k12.ut.us +k12.va.us +k12.vi.us +k12.vt.us +k12.wa.us +k12.wi.us +// k12.wv.us - Bug 947705 - Removed at request of Verne Britton +cc.ak.us +lib.ak.us +cc.al.us +lib.al.us +cc.ar.us +lib.ar.us +cc.as.us +lib.as.us +cc.az.us +lib.az.us +cc.ca.us +lib.ca.us +cc.co.us +lib.co.us +cc.ct.us +lib.ct.us +cc.dc.us +lib.dc.us +cc.de.us +cc.fl.us +lib.fl.us +cc.ga.us +lib.ga.us +cc.gu.us +lib.gu.us +cc.hi.us +lib.hi.us +cc.ia.us +lib.ia.us +cc.id.us +lib.id.us +cc.il.us +lib.il.us +cc.in.us +lib.in.us +cc.ks.us +lib.ks.us +cc.ky.us +lib.ky.us +cc.la.us +lib.la.us +cc.ma.us +lib.ma.us +cc.md.us +lib.md.us +cc.me.us +lib.me.us +cc.mi.us +lib.mi.us +cc.mn.us +lib.mn.us +cc.mo.us +lib.mo.us +cc.ms.us +cc.mt.us +lib.mt.us +cc.nc.us +lib.nc.us +cc.nd.us +lib.nd.us +cc.ne.us +lib.ne.us +cc.nh.us +lib.nh.us +cc.nj.us +lib.nj.us +cc.nm.us +lib.nm.us +cc.nv.us +lib.nv.us +cc.ny.us +lib.ny.us +cc.oh.us +lib.oh.us +cc.ok.us +lib.ok.us +cc.or.us +lib.or.us +cc.pa.us +lib.pa.us +cc.pr.us +lib.pr.us +cc.ri.us +lib.ri.us +cc.sc.us +lib.sc.us +cc.sd.us +lib.sd.us +cc.tn.us +lib.tn.us +cc.tx.us +lib.tx.us +cc.ut.us +lib.ut.us +cc.va.us +lib.va.us +cc.vi.us +lib.vi.us +cc.vt.us +lib.vt.us +cc.wa.us +lib.wa.us +cc.wi.us +lib.wi.us +cc.wv.us +cc.wy.us +k12.wy.us +// lib.wv.us - Bug 941670 - Removed at request of Larry W Arnold +lib.wy.us +// k12.ma.us contains school districts in Massachusetts. The 4LDs are +// managed independently except for private (PVT), charter (CHTR) and +// parochial (PAROCH) schools. Those are delegated directly to the +// 5LD operators. +chtr.k12.ma.us +paroch.k12.ma.us +pvt.k12.ma.us +// Merit Network, Inc. maintains the registry for =~ /(k12|cc|lib).mi.us/ and the following +// see also: https://domreg.merit.edu : domreg@merit.edu +// see also: whois -h whois.domreg.merit.edu help +ann-arbor.mi.us +cog.mi.us +dst.mi.us +eaton.mi.us +gen.mi.us +mus.mi.us +tec.mi.us +washtenaw.mi.us + +// uy : http://www.nic.org.uy/ +uy +com.uy +edu.uy +gub.uy +mil.uy +net.uy +org.uy + +// uz : http://www.reg.uz/ +uz +co.uz +com.uz +net.uz +org.uz + +// va : https://www.iana.org/domains/root/db/va.html +va + +// vc : https://www.iana.org/domains/root/db/vc.html +// Submitted by registry +vc +com.vc +edu.vc +gov.vc +mil.vc +net.vc +org.vc + +// ve : https://registro.nic.ve/ +// Submitted by registry nic@nic.ve and nicve@conatel.gob.ve +ve +arts.ve +bib.ve +co.ve +com.ve +e12.ve +edu.ve +emprende.ve +firm.ve +gob.ve +gov.ve +info.ve +int.ve +mil.ve +net.ve +nom.ve +org.ve +rar.ve +rec.ve +store.ve +tec.ve +web.ve + +// vg : https://www.iana.org/domains/root/db/vg.html +// Confirmed by registry 2025-01-10 +vg +edu.vg + +// vi : https://www.iana.org/domains/root/db/vi.html +vi +co.vi +com.vi +k12.vi +net.vi +org.vi + +// vn : https://www.vnnic.vn/en/domain/cctld-vn +// https://vnnic.vn/sites/default/files/tailieu/vn.cctld.domains.txt +vn +ac.vn +ai.vn +biz.vn +com.vn +edu.vn +gov.vn +health.vn +id.vn +info.vn +int.vn +io.vn +name.vn +net.vn +org.vn +pro.vn + +// vn geographical names +angiang.vn +bacgiang.vn +backan.vn +baclieu.vn +bacninh.vn +baria-vungtau.vn +bentre.vn +binhdinh.vn +binhduong.vn +binhphuoc.vn +binhthuan.vn +camau.vn +cantho.vn +caobang.vn +daklak.vn +daknong.vn +danang.vn +dienbien.vn +dongnai.vn +dongthap.vn +gialai.vn +hagiang.vn +haiduong.vn +haiphong.vn +hanam.vn +hanoi.vn +hatinh.vn +haugiang.vn +hoabinh.vn +hungyen.vn +khanhhoa.vn +kiengiang.vn +kontum.vn +laichau.vn +lamdong.vn +langson.vn +laocai.vn +longan.vn +namdinh.vn +nghean.vn +ninhbinh.vn +ninhthuan.vn +phutho.vn +phuyen.vn +quangbinh.vn +quangnam.vn +quangngai.vn +quangninh.vn +quangtri.vn +soctrang.vn +sonla.vn +tayninh.vn +thaibinh.vn +thainguyen.vn +thanhhoa.vn +thanhphohochiminh.vn +thuathienhue.vn +tiengiang.vn +travinh.vn +tuyenquang.vn +vinhlong.vn +vinhphuc.vn +yenbai.vn + +// vu : https://www.iana.org/domains/root/db/vu.html +// http://www.vunic.vu/ +vu +com.vu +edu.vu +net.vu +org.vu + +// wf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf +wf + +// ws : https://www.iana.org/domains/root/db/ws.html +// http://samoanic.ws/index.dhtml +ws +com.ws +edu.ws +gov.ws +net.ws +org.ws + +// yt : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf +yt + +// IDN ccTLDs +// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then +// U-label, and follow this format: +// // A-Label ("", [, variant info]) : +// // [sponsoring org] +// U-Label + +// xn--mgbaam7a8h ("Emerat", Arabic) : AE +// http://nic.ae/english/arabicdomain/rules.jsp +امارات + +// xn--y9a3aq ("hye", Armenian) : AM +// ISOC AM (operated by .am Registry) +հայ + +// xn--54b7fta0cc ("Bangla", Bangla) : BD +বাংলা + +// xn--90ae ("bg", Bulgarian) : BG +бг + +// xn--mgbcpq6gpa1a ("albahrain", Arabic) : BH +البحرين + +// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY +// Operated by .by registry +бел + +// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN +// CNNIC +// https://www.cnnic.cn/11/192/index.html +中国 + +// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN +// CNNIC +// https://www.cnnic.com.cn/AU/MediaC/Announcement/201609/t20160905_54470.htm +中國 + +// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ +الجزائر + +// xn--wgbh1c ("Egypt/Masr", Arabic) : EG +// http://www.dotmasr.eg/ +مصر + +// xn--e1a4c ("eu", Cyrillic) : EU +// https://eurid.eu +ею + +// xn--qxa6a ("eu", Greek) : EU +// https://eurid.eu +ευ + +// xn--mgbah1a3hjkrd ("Mauritania", Arabic) : MR +موريتانيا + +// xn--node ("ge", Georgian Mkhedruli) : GE +გე + +// xn--qxam ("el", Greek) : GR +// Hellenic Ministry of Infrastructure, Transport, and Networks +ελ + +// xn--j6w193g ("Hong Kong", Chinese) : HK +// https://www.hkirc.hk +// Submitted by registry +// https://www.hkirc.hk/content.jsp?id=30#!/34 +香港 +個人.香港 +公司.香港 +政府.香港 +教育.香港 +組織.香港 +網絡.香港 + +// xn--2scrj9c ("Bharat", Kannada) : IN +// India +ಭಾರತ + +// xn--3hcrj9c ("Bharat", Oriya) : IN +// India +ଭାରତ + +// xn--45br5cyl ("Bharatam", Assamese) : IN +// India +ভাৰত + +// xn--h2breg3eve ("Bharatam", Sanskrit) : IN +// India +भारतम् + +// xn--h2brj9c8c ("Bharot", Santali) : IN +// India +भारोत + +// xn--mgbgu82a ("Bharat", Sindhi) : IN +// India +ڀارت + +// xn--rvc1e0am3e ("Bharatam", Malayalam) : IN +// India +ഭാരതം + +// xn--h2brj9c ("Bharat", Devanagari) : IN +// India +भारत + +// xn--mgbbh1a ("Bharat", Kashmiri) : IN +// India +بارت + +// xn--mgbbh1a71e ("Bharat", Arabic) : IN +// India +بھارت + +// xn--fpcrj9c3d ("Bharat", Telugu) : IN +// India +భారత్ + +// xn--gecrj9c ("Bharat", Gujarati) : IN +// India +ભારત + +// xn--s9brj9c ("Bharat", Gurmukhi) : IN +// India +ਭਾਰਤ + +// xn--45brj9c ("Bharat", Bengali) : IN +// India +ভারত + +// xn--xkc2dl3a5ee0h ("India", Tamil) : IN +// India +இந்தியா + +// xn--mgba3a4f16a ("Iran", Persian) : IR +ایران + +// xn--mgba3a4fra ("Iran", Arabic) : IR +ايران + +// xn--mgbtx2b ("Iraq", Arabic) : IQ +// Communications and Media Commission +عراق + +// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO +// National Information Technology Center (NITC) +// Royal Scientific Society, Al-Jubeiha +الاردن + +// xn--3e0b707e ("Republic of Korea", Hangul) : KR +한국 + +// xn--80ao21a ("Kaz", Kazakh) : KZ +қаз + +// xn--q7ce6a ("Lao", Lao) : LA +ລາວ + +// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK +// https://nic.lk +ලංකා + +// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK +// https://nic.lk +இலங்கை + +// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA +المغرب + +// xn--d1alf ("mkd", Macedonian) : MK +// MARnet +мкд + +// xn--l1acc ("mon", Mongolian) : MN +мон + +// xn--mix891f ("Macao", Chinese, Traditional) : MO +// MONIC / HNET Asia (Registry Operator for .mo) +澳門 + +// xn--mix082f ("Macao", Chinese, Simplified) : MO +澳门 + +// xn--mgbx4cd0ab ("Malaysia", Malay) : MY +مليسيا + +// xn--mgb9awbf ("Oman", Arabic) : OM +عمان + +// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK +پاکستان + +// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK +پاكستان + +// xn--ygbi2ammx ("Falasteen", Arabic) : PS +// The Palestinian National Internet Naming Authority (PNINA) +// http://www.pnina.ps +فلسطين + +// xn--90a3ac ("srb", Cyrillic) : RS +// https://www.rnids.rs/en/domains/national-domains +срб +ак.срб +обр.срб +од.срб +орг.срб +пр.срб +упр.срб + +// xn--p1ai ("rf", Russian-Cyrillic) : RU +// https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf +// Submitted by George Georgievsky +рф + +// xn--wgbl6a ("Qatar", Arabic) : QA +// http://www.ict.gov.qa/ +قطر + +// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA +// http://www.nic.net.sa/ +السعودية + +// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant): SA +السعودیة + +// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA +السعودیۃ + +// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA +السعوديه + +// xn--mgbpl2fh ("sudan", Arabic) : SD +// Operated by .sd registry +سودان + +// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG +新加坡 + +// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG +சிங்கப்பூர் + +// xn--ogbpf8fl ("Syria", Arabic) : SY +سورية + +// xn--mgbtf8fl ("Syria", Arabic, variant) : SY +سوريا + +// xn--o3cw4h ("Thai", Thai) : TH +// http://www.thnic.co.th +ไทย +ทหาร.ไทย +ธุรกิจ.ไทย +เน็ต.ไทย +รัฐบาล.ไทย +ศึกษา.ไทย +องค์กร.ไทย + +// xn--pgbs0dh ("Tunisia", Arabic) : TN +// http://nic.tn +تونس + +// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW +// https://twnic.tw/dnservice_catag.php +台灣 + +// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW +// http://www.twnic.net/english/dn/dn_07a.htm +台湾 + +// xn--nnx388a ("Taiwan", Chinese, variant) : TW +臺灣 + +// xn--j1amh ("ukr", Cyrillic) : UA +укр + +// xn--mgb2ddes ("AlYemen", Arabic) : YE +اليمن + +// xxx : http://icmregistry.com +xxx + +// ye : http://www.y.net.ye/services/domain_name.htm +ye +com.ye +edu.ye +gov.ye +mil.ye +net.ye +org.ye + +// za : https://www.iana.org/domains/root/db/za.html +ac.za +agric.za +alt.za +co.za +edu.za +gov.za +grondar.za +law.za +mil.za +net.za +ngo.za +nic.za +nis.za +nom.za +org.za +school.za +tm.za +web.za + +// zm : https://zicta.zm/ +// Submitted by registry +zm +ac.zm +biz.zm +co.zm +com.zm +edu.zm +gov.zm +info.zm +mil.zm +net.zm +org.zm +sch.zm + +// zw : https://www.potraz.gov.zw/ +// Confirmed by registry 2017-01-25 +zw +ac.zw +co.zw +gov.zw +mil.zw +org.zw + +// newGTLDs + +// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2025-10-01T15:18:26Z +// This list is auto-generated, don't edit it manually. +// aaa : American Automobile Association, Inc. +// https://www.iana.org/domains/root/db/aaa.html +aaa + +// aarp : AARP +// https://www.iana.org/domains/root/db/aarp.html +aarp + +// abb : ABB Ltd +// https://www.iana.org/domains/root/db/abb.html +abb + +// abbott : Abbott Laboratories, Inc. +// https://www.iana.org/domains/root/db/abbott.html +abbott + +// abbvie : AbbVie Inc. +// https://www.iana.org/domains/root/db/abbvie.html +abbvie + +// abc : Disney Enterprises, Inc. +// https://www.iana.org/domains/root/db/abc.html +abc + +// able : Able Inc. +// https://www.iana.org/domains/root/db/able.html +able + +// abogado : Registry Services, LLC +// https://www.iana.org/domains/root/db/abogado.html +abogado + +// abudhabi : Abu Dhabi Systems and Information Centre +// https://www.iana.org/domains/root/db/abudhabi.html +abudhabi + +// academy : Binky Moon, LLC +// https://www.iana.org/domains/root/db/academy.html +academy + +// accenture : Accenture plc +// https://www.iana.org/domains/root/db/accenture.html +accenture + +// accountant : dot Accountant Limited +// https://www.iana.org/domains/root/db/accountant.html +accountant + +// accountants : Binky Moon, LLC +// https://www.iana.org/domains/root/db/accountants.html +accountants + +// aco : ACO Severin Ahlmann GmbH & Co. KG +// https://www.iana.org/domains/root/db/aco.html +aco + +// actor : Dog Beach, LLC +// https://www.iana.org/domains/root/db/actor.html +actor + +// ads : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/ads.html +ads + +// adult : ICM Registry AD LLC +// https://www.iana.org/domains/root/db/adult.html +adult + +// aeg : Aktiebolaget Electrolux +// https://www.iana.org/domains/root/db/aeg.html +aeg + +// aetna : Aetna Life Insurance Company +// https://www.iana.org/domains/root/db/aetna.html +aetna + +// afl : Australian Football League +// https://www.iana.org/domains/root/db/afl.html +afl + +// africa : ZA Central Registry NPC trading as Registry.Africa +// https://www.iana.org/domains/root/db/africa.html +africa + +// agakhan : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/agakhan.html +agakhan + +// agency : Binky Moon, LLC +// https://www.iana.org/domains/root/db/agency.html +agency + +// aig : American International Group, Inc. +// https://www.iana.org/domains/root/db/aig.html +aig + +// airbus : Airbus S.A.S. +// https://www.iana.org/domains/root/db/airbus.html +airbus + +// airforce : Dog Beach, LLC +// https://www.iana.org/domains/root/db/airforce.html +airforce + +// airtel : Bharti Airtel Limited +// https://www.iana.org/domains/root/db/airtel.html +airtel + +// akdn : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/akdn.html +akdn + +// alibaba : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/alibaba.html +alibaba + +// alipay : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/alipay.html +alipay + +// allfinanz : Allfinanz Deutsche Vermögensberatung Aktiengesellschaft +// https://www.iana.org/domains/root/db/allfinanz.html +allfinanz + +// allstate : Allstate Fire and Casualty Insurance Company +// https://www.iana.org/domains/root/db/allstate.html +allstate + +// ally : Ally Financial Inc. +// https://www.iana.org/domains/root/db/ally.html +ally + +// alsace : Region Grand Est +// https://www.iana.org/domains/root/db/alsace.html +alsace + +// alstom : ALSTOM +// https://www.iana.org/domains/root/db/alstom.html +alstom + +// amazon : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/amazon.html +amazon + +// americanexpress : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/americanexpress.html +americanexpress + +// americanfamily : AmFam, Inc. +// https://www.iana.org/domains/root/db/americanfamily.html +americanfamily + +// amex : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/amex.html +amex + +// amfam : AmFam, Inc. +// https://www.iana.org/domains/root/db/amfam.html +amfam + +// amica : Amica Mutual Insurance Company +// https://www.iana.org/domains/root/db/amica.html +amica + +// amsterdam : Gemeente Amsterdam +// https://www.iana.org/domains/root/db/amsterdam.html +amsterdam + +// analytics : Campus IP LLC +// https://www.iana.org/domains/root/db/analytics.html +analytics + +// android : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/android.html +android + +// anquan : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/anquan.html +anquan + +// anz : Australia and New Zealand Banking Group Limited +// https://www.iana.org/domains/root/db/anz.html +anz + +// aol : Yahoo Inc. +// https://www.iana.org/domains/root/db/aol.html +aol + +// apartments : Binky Moon, LLC +// https://www.iana.org/domains/root/db/apartments.html +apartments + +// app : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/app.html +app + +// apple : Apple Inc. +// https://www.iana.org/domains/root/db/apple.html +apple + +// aquarelle : Aquarelle.com +// https://www.iana.org/domains/root/db/aquarelle.html +aquarelle + +// arab : League of Arab States +// https://www.iana.org/domains/root/db/arab.html +arab + +// aramco : Aramco Services Company +// https://www.iana.org/domains/root/db/aramco.html +aramco + +// archi : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/archi.html +archi + +// army : Dog Beach, LLC +// https://www.iana.org/domains/root/db/army.html +army + +// art : UK Creative Ideas Limited +// https://www.iana.org/domains/root/db/art.html +art + +// arte : Association Relative à la Télévision Européenne G.E.I.E. +// https://www.iana.org/domains/root/db/arte.html +arte + +// asda : Asda Stores Limited +// https://www.iana.org/domains/root/db/asda.html +asda + +// associates : Binky Moon, LLC +// https://www.iana.org/domains/root/db/associates.html +associates + +// athleta : The Gap, Inc. +// https://www.iana.org/domains/root/db/athleta.html +athleta + +// attorney : Dog Beach, LLC +// https://www.iana.org/domains/root/db/attorney.html +attorney + +// auction : Dog Beach, LLC +// https://www.iana.org/domains/root/db/auction.html +auction + +// audi : AUDI Aktiengesellschaft +// https://www.iana.org/domains/root/db/audi.html +audi + +// audible : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/audible.html +audible + +// audio : XYZ.COM LLC +// https://www.iana.org/domains/root/db/audio.html +audio + +// auspost : Australian Postal Corporation +// https://www.iana.org/domains/root/db/auspost.html +auspost + +// author : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/author.html +author + +// auto : XYZ.COM LLC +// https://www.iana.org/domains/root/db/auto.html +auto + +// autos : XYZ.COM LLC +// https://www.iana.org/domains/root/db/autos.html +autos + +// aws : AWS Registry LLC +// https://www.iana.org/domains/root/db/aws.html +aws + +// axa : AXA Group Operations SAS +// https://www.iana.org/domains/root/db/axa.html +axa + +// azure : Microsoft Corporation +// https://www.iana.org/domains/root/db/azure.html +azure + +// baby : XYZ.COM LLC +// https://www.iana.org/domains/root/db/baby.html +baby + +// baidu : Baidu, Inc. +// https://www.iana.org/domains/root/db/baidu.html +baidu + +// banamex : Citigroup Inc. +// https://www.iana.org/domains/root/db/banamex.html +banamex + +// band : Dog Beach, LLC +// https://www.iana.org/domains/root/db/band.html +band + +// bank : fTLD Registry Services LLC +// https://www.iana.org/domains/root/db/bank.html +bank + +// bar : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// https://www.iana.org/domains/root/db/bar.html +bar + +// barcelona : Municipi de Barcelona +// https://www.iana.org/domains/root/db/barcelona.html +barcelona + +// barclaycard : Barclays Bank PLC +// https://www.iana.org/domains/root/db/barclaycard.html +barclaycard + +// barclays : Barclays Bank PLC +// https://www.iana.org/domains/root/db/barclays.html +barclays + +// barefoot : Gallo Vineyards, Inc. +// https://www.iana.org/domains/root/db/barefoot.html +barefoot + +// bargains : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bargains.html +bargains + +// baseball : MLB Advanced Media DH, LLC +// https://www.iana.org/domains/root/db/baseball.html +baseball + +// basketball : Fédération Internationale de Basketball (FIBA) +// https://www.iana.org/domains/root/db/basketball.html +basketball + +// bauhaus : Werkhaus GmbH +// https://www.iana.org/domains/root/db/bauhaus.html +bauhaus + +// bayern : Bayern Connect GmbH +// https://www.iana.org/domains/root/db/bayern.html +bayern + +// bbc : British Broadcasting Corporation +// https://www.iana.org/domains/root/db/bbc.html +bbc + +// bbt : BB&T Corporation +// https://www.iana.org/domains/root/db/bbt.html +bbt + +// bbva : BANCO BILBAO VIZCAYA ARGENTARIA, S.A. +// https://www.iana.org/domains/root/db/bbva.html +bbva + +// bcg : The Boston Consulting Group, Inc. +// https://www.iana.org/domains/root/db/bcg.html +bcg + +// bcn : Municipi de Barcelona +// https://www.iana.org/domains/root/db/bcn.html +bcn + +// beats : Beats Electronics, LLC +// https://www.iana.org/domains/root/db/beats.html +beats + +// beauty : XYZ.COM LLC +// https://www.iana.org/domains/root/db/beauty.html +beauty + +// beer : Registry Services, LLC +// https://www.iana.org/domains/root/db/beer.html +beer + +// berlin : dotBERLIN GmbH & Co. KG +// https://www.iana.org/domains/root/db/berlin.html +berlin + +// best : BestTLD Pty Ltd +// https://www.iana.org/domains/root/db/best.html +best + +// bestbuy : BBY Solutions, Inc. +// https://www.iana.org/domains/root/db/bestbuy.html +bestbuy + +// bet : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/bet.html +bet + +// bharti : Bharti Enterprises (Holding) Private Limited +// https://www.iana.org/domains/root/db/bharti.html +bharti + +// bible : American Bible Society +// https://www.iana.org/domains/root/db/bible.html +bible + +// bid : dot Bid Limited +// https://www.iana.org/domains/root/db/bid.html +bid + +// bike : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bike.html +bike + +// bing : Microsoft Corporation +// https://www.iana.org/domains/root/db/bing.html +bing + +// bingo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/bingo.html +bingo + +// bio : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/bio.html +bio + +// black : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/black.html +black + +// blackfriday : Registry Services, LLC +// https://www.iana.org/domains/root/db/blackfriday.html +blackfriday + +// blockbuster : Dish DBS Corporation +// https://www.iana.org/domains/root/db/blockbuster.html +blockbuster + +// blog : Knock Knock WHOIS There, LLC +// https://www.iana.org/domains/root/db/blog.html +blog + +// bloomberg : Bloomberg IP Holdings LLC +// https://www.iana.org/domains/root/db/bloomberg.html +bloomberg + +// blue : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/blue.html +blue + +// bms : Bristol-Myers Squibb Company +// https://www.iana.org/domains/root/db/bms.html +bms + +// bmw : Bayerische Motoren Werke Aktiengesellschaft +// https://www.iana.org/domains/root/db/bmw.html +bmw + +// bnpparibas : BNP Paribas +// https://www.iana.org/domains/root/db/bnpparibas.html +bnpparibas + +// boats : XYZ.COM LLC +// https://www.iana.org/domains/root/db/boats.html +boats + +// boehringer : Boehringer Ingelheim International GmbH +// https://www.iana.org/domains/root/db/boehringer.html +boehringer + +// bofa : Bank of America Corporation +// https://www.iana.org/domains/root/db/bofa.html +bofa + +// bom : Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// https://www.iana.org/domains/root/db/bom.html +bom + +// bond : ShortDot SA +// https://www.iana.org/domains/root/db/bond.html +bond + +// boo : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/boo.html +boo + +// book : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/book.html +book + +// booking : Booking.com B.V. +// https://www.iana.org/domains/root/db/booking.html +booking + +// bosch : Robert Bosch GMBH +// https://www.iana.org/domains/root/db/bosch.html +bosch + +// bostik : Bostik SA +// https://www.iana.org/domains/root/db/bostik.html +bostik + +// boston : Registry Services, LLC +// https://www.iana.org/domains/root/db/boston.html +boston + +// bot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/bot.html +bot + +// boutique : Binky Moon, LLC +// https://www.iana.org/domains/root/db/boutique.html +boutique + +// box : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/box.html +box + +// bradesco : Banco Bradesco S.A. +// https://www.iana.org/domains/root/db/bradesco.html +bradesco + +// bridgestone : Bridgestone Corporation +// https://www.iana.org/domains/root/db/bridgestone.html +bridgestone + +// broadway : Celebrate Broadway, Inc. +// https://www.iana.org/domains/root/db/broadway.html +broadway + +// broker : Dog Beach, LLC +// https://www.iana.org/domains/root/db/broker.html +broker + +// brother : Brother Industries, Ltd. +// https://www.iana.org/domains/root/db/brother.html +brother + +// brussels : DNS.be vzw +// https://www.iana.org/domains/root/db/brussels.html +brussels + +// build : Plan Bee LLC +// https://www.iana.org/domains/root/db/build.html +build + +// builders : Binky Moon, LLC +// https://www.iana.org/domains/root/db/builders.html +builders + +// business : Binky Moon, LLC +// https://www.iana.org/domains/root/db/business.html +business + +// buy : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/buy.html +buy + +// buzz : DOTSTRATEGY CO. +// https://www.iana.org/domains/root/db/buzz.html +buzz + +// bzh : Association www.bzh +// https://www.iana.org/domains/root/db/bzh.html +bzh + +// cab : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cab.html +cab + +// cafe : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cafe.html +cafe + +// cal : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/cal.html +cal + +// call : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/call.html +call + +// calvinklein : PVH gTLD Holdings LLC +// https://www.iana.org/domains/root/db/calvinklein.html +calvinklein + +// cam : Cam Connecting SARL +// https://www.iana.org/domains/root/db/cam.html +cam + +// camera : Binky Moon, LLC +// https://www.iana.org/domains/root/db/camera.html +camera + +// camp : Binky Moon, LLC +// https://www.iana.org/domains/root/db/camp.html +camp + +// canon : Canon Inc. +// https://www.iana.org/domains/root/db/canon.html +canon + +// capetown : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/capetown.html +capetown + +// capital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/capital.html +capital + +// capitalone : Capital One Financial Corporation +// https://www.iana.org/domains/root/db/capitalone.html +capitalone + +// car : XYZ.COM LLC +// https://www.iana.org/domains/root/db/car.html +car + +// caravan : Caravan International, Inc. +// https://www.iana.org/domains/root/db/caravan.html +caravan + +// cards : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cards.html +cards + +// care : Binky Moon, LLC +// https://www.iana.org/domains/root/db/care.html +care + +// career : dotCareer LLC +// https://www.iana.org/domains/root/db/career.html +career + +// careers : Binky Moon, LLC +// https://www.iana.org/domains/root/db/careers.html +careers + +// cars : XYZ.COM LLC +// https://www.iana.org/domains/root/db/cars.html +cars + +// casa : Registry Services, LLC +// https://www.iana.org/domains/root/db/casa.html +casa + +// case : Digity, LLC +// https://www.iana.org/domains/root/db/case.html +case + +// cash : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cash.html +cash + +// casino : Binky Moon, LLC +// https://www.iana.org/domains/root/db/casino.html +casino + +// catering : Binky Moon, LLC +// https://www.iana.org/domains/root/db/catering.html +catering + +// catholic : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/catholic.html +catholic + +// cba : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/cba.html +cba + +// cbn : The Christian Broadcasting Network, Inc. +// https://www.iana.org/domains/root/db/cbn.html +cbn + +// cbre : CBRE, Inc. +// https://www.iana.org/domains/root/db/cbre.html +cbre + +// center : Binky Moon, LLC +// https://www.iana.org/domains/root/db/center.html +center + +// ceo : XYZ.COM LLC +// https://www.iana.org/domains/root/db/ceo.html +ceo + +// cern : European Organization for Nuclear Research ("CERN") +// https://www.iana.org/domains/root/db/cern.html +cern + +// cfa : CFA Institute +// https://www.iana.org/domains/root/db/cfa.html +cfa + +// cfd : ShortDot SA +// https://www.iana.org/domains/root/db/cfd.html +cfd + +// chanel : Chanel International B.V. +// https://www.iana.org/domains/root/db/chanel.html +chanel + +// channel : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/channel.html +channel + +// charity : Public Interest Registry +// https://www.iana.org/domains/root/db/charity.html +charity + +// chase : JPMorgan Chase Bank, National Association +// https://www.iana.org/domains/root/db/chase.html +chase + +// chat : Binky Moon, LLC +// https://www.iana.org/domains/root/db/chat.html +chat + +// cheap : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cheap.html +cheap + +// chintai : CHINTAI Corporation +// https://www.iana.org/domains/root/db/chintai.html +chintai + +// christmas : XYZ.COM LLC +// https://www.iana.org/domains/root/db/christmas.html +christmas + +// chrome : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/chrome.html +chrome + +// church : Binky Moon, LLC +// https://www.iana.org/domains/root/db/church.html +church + +// cipriani : Hotel Cipriani Srl +// https://www.iana.org/domains/root/db/cipriani.html +cipriani + +// circle : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/circle.html +circle + +// cisco : Cisco Technology, Inc. +// https://www.iana.org/domains/root/db/cisco.html +cisco + +// citadel : Citadel Domain LLC +// https://www.iana.org/domains/root/db/citadel.html +citadel + +// citi : Citigroup Inc. +// https://www.iana.org/domains/root/db/citi.html +citi + +// citic : CITIC Group Corporation +// https://www.iana.org/domains/root/db/citic.html +citic + +// city : Binky Moon, LLC +// https://www.iana.org/domains/root/db/city.html +city + +// claims : Binky Moon, LLC +// https://www.iana.org/domains/root/db/claims.html +claims + +// cleaning : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cleaning.html +cleaning + +// click : Waterford Limited +// https://www.iana.org/domains/root/db/click.html +click + +// clinic : Binky Moon, LLC +// https://www.iana.org/domains/root/db/clinic.html +clinic + +// clinique : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/clinique.html +clinique + +// clothing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/clothing.html +clothing + +// cloud : Aruba PEC S.p.A. +// https://www.iana.org/domains/root/db/cloud.html +cloud + +// club : Registry Services, LLC +// https://www.iana.org/domains/root/db/club.html +club + +// clubmed : Club Méditerranée S.A. +// https://www.iana.org/domains/root/db/clubmed.html +clubmed + +// coach : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coach.html +coach + +// codes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/codes.html +codes + +// coffee : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coffee.html +coffee + +// college : XYZ.COM LLC +// https://www.iana.org/domains/root/db/college.html +college + +// cologne : dotKoeln GmbH +// https://www.iana.org/domains/root/db/cologne.html +cologne + +// commbank : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/commbank.html +commbank + +// community : Binky Moon, LLC +// https://www.iana.org/domains/root/db/community.html +community + +// company : Binky Moon, LLC +// https://www.iana.org/domains/root/db/company.html +company + +// compare : Registry Services, LLC +// https://www.iana.org/domains/root/db/compare.html +compare + +// computer : Binky Moon, LLC +// https://www.iana.org/domains/root/db/computer.html +computer + +// comsec : VeriSign, Inc. +// https://www.iana.org/domains/root/db/comsec.html +comsec + +// condos : Binky Moon, LLC +// https://www.iana.org/domains/root/db/condos.html +condos + +// construction : Binky Moon, LLC +// https://www.iana.org/domains/root/db/construction.html +construction + +// consulting : Dog Beach, LLC +// https://www.iana.org/domains/root/db/consulting.html +consulting + +// contact : Dog Beach, LLC +// https://www.iana.org/domains/root/db/contact.html +contact + +// contractors : Binky Moon, LLC +// https://www.iana.org/domains/root/db/contractors.html +contractors + +// cooking : Registry Services, LLC +// https://www.iana.org/domains/root/db/cooking.html +cooking + +// cool : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cool.html +cool + +// corsica : Collectivité de Corse +// https://www.iana.org/domains/root/db/corsica.html +corsica + +// country : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/country.html +country + +// coupon : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/coupon.html +coupon + +// coupons : Binky Moon, LLC +// https://www.iana.org/domains/root/db/coupons.html +coupons + +// courses : Registry Services, LLC +// https://www.iana.org/domains/root/db/courses.html +courses + +// cpa : American Institute of Certified Public Accountants +// https://www.iana.org/domains/root/db/cpa.html +cpa + +// credit : Binky Moon, LLC +// https://www.iana.org/domains/root/db/credit.html +credit + +// creditcard : Binky Moon, LLC +// https://www.iana.org/domains/root/db/creditcard.html +creditcard + +// creditunion : DotCooperation LLC +// https://www.iana.org/domains/root/db/creditunion.html +creditunion + +// cricket : dot Cricket Limited +// https://www.iana.org/domains/root/db/cricket.html +cricket + +// crown : Crown Equipment Corporation +// https://www.iana.org/domains/root/db/crown.html +crown + +// crs : Federated Co-operatives Limited +// https://www.iana.org/domains/root/db/crs.html +crs + +// cruise : Viking River Cruises (Bermuda) Ltd. +// https://www.iana.org/domains/root/db/cruise.html +cruise + +// cruises : Binky Moon, LLC +// https://www.iana.org/domains/root/db/cruises.html +cruises + +// cuisinella : SCHMIDT GROUPE S.A.S. +// https://www.iana.org/domains/root/db/cuisinella.html +cuisinella + +// cymru : Nominet UK +// https://www.iana.org/domains/root/db/cymru.html +cymru + +// cyou : ShortDot SA +// https://www.iana.org/domains/root/db/cyou.html +cyou + +// dad : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dad.html +dad + +// dance : Dog Beach, LLC +// https://www.iana.org/domains/root/db/dance.html +dance + +// data : Dish DBS Corporation +// https://www.iana.org/domains/root/db/data.html +data + +// date : dot Date Limited +// https://www.iana.org/domains/root/db/date.html +date + +// dating : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dating.html +dating + +// datsun : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/datsun.html +datsun + +// day : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/day.html +day + +// dclk : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dclk.html +dclk + +// dds : Registry Services, LLC +// https://www.iana.org/domains/root/db/dds.html +dds + +// deal : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/deal.html +deal + +// dealer : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/dealer.html +dealer + +// deals : Binky Moon, LLC +// https://www.iana.org/domains/root/db/deals.html +deals + +// degree : Dog Beach, LLC +// https://www.iana.org/domains/root/db/degree.html +degree + +// delivery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/delivery.html +delivery + +// dell : Dell Inc. +// https://www.iana.org/domains/root/db/dell.html +dell + +// deloitte : Deloitte Touche Tohmatsu +// https://www.iana.org/domains/root/db/deloitte.html +deloitte + +// delta : Delta Air Lines, Inc. +// https://www.iana.org/domains/root/db/delta.html +delta + +// democrat : Dog Beach, LLC +// https://www.iana.org/domains/root/db/democrat.html +democrat + +// dental : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dental.html +dental + +// dentist : Dog Beach, LLC +// https://www.iana.org/domains/root/db/dentist.html +dentist + +// desi +// https://www.iana.org/domains/root/db/desi.html +desi + +// design : Registry Services, LLC +// https://www.iana.org/domains/root/db/design.html +design + +// dev : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/dev.html +dev + +// dhl : Deutsche Post AG +// https://www.iana.org/domains/root/db/dhl.html +dhl + +// diamonds : Binky Moon, LLC +// https://www.iana.org/domains/root/db/diamonds.html +diamonds + +// diet : XYZ.COM LLC +// https://www.iana.org/domains/root/db/diet.html +diet + +// digital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/digital.html +digital + +// direct : Binky Moon, LLC +// https://www.iana.org/domains/root/db/direct.html +direct + +// directory : Binky Moon, LLC +// https://www.iana.org/domains/root/db/directory.html +directory + +// discount : Binky Moon, LLC +// https://www.iana.org/domains/root/db/discount.html +discount + +// discover : Discover Financial Services +// https://www.iana.org/domains/root/db/discover.html +discover + +// dish : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dish.html +dish + +// diy : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/diy.html +diy + +// dnp : Dai Nippon Printing Co., Ltd. +// https://www.iana.org/domains/root/db/dnp.html +dnp + +// docs : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/docs.html +docs + +// doctor : Binky Moon, LLC +// https://www.iana.org/domains/root/db/doctor.html +doctor + +// dog : Binky Moon, LLC +// https://www.iana.org/domains/root/db/dog.html +dog + +// domains : Binky Moon, LLC +// https://www.iana.org/domains/root/db/domains.html +domains + +// dot : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dot.html +dot + +// download : dot Support Limited +// https://www.iana.org/domains/root/db/download.html +download + +// drive : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/drive.html +drive + +// dtv : Dish DBS Corporation +// https://www.iana.org/domains/root/db/dtv.html +dtv + +// dubai : Dubai Smart Government Department +// https://www.iana.org/domains/root/db/dubai.html +dubai + +// dunlop : The Goodyear Tire & Rubber Company +// https://www.iana.org/domains/root/db/dunlop.html +dunlop + +// dupont : DuPont Specialty Products USA, LLC +// https://www.iana.org/domains/root/db/dupont.html +dupont + +// durban : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/durban.html +durban + +// dvag : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/dvag.html +dvag + +// dvr : DISH Technologies L.L.C. +// https://www.iana.org/domains/root/db/dvr.html +dvr + +// earth : Interlink Systems Innovation Institute K.K. +// https://www.iana.org/domains/root/db/earth.html +earth + +// eat : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/eat.html +eat + +// eco : Big Room Inc. +// https://www.iana.org/domains/root/db/eco.html +eco + +// edeka : EDEKA Verband kaufmännischer Genossenschaften e.V. +// https://www.iana.org/domains/root/db/edeka.html +edeka + +// education : Binky Moon, LLC +// https://www.iana.org/domains/root/db/education.html +education + +// email : Binky Moon, LLC +// https://www.iana.org/domains/root/db/email.html +email + +// emerck : Merck KGaA +// https://www.iana.org/domains/root/db/emerck.html +emerck + +// energy : Binky Moon, LLC +// https://www.iana.org/domains/root/db/energy.html +energy + +// engineer : Dog Beach, LLC +// https://www.iana.org/domains/root/db/engineer.html +engineer + +// engineering : Binky Moon, LLC +// https://www.iana.org/domains/root/db/engineering.html +engineering + +// enterprises : Binky Moon, LLC +// https://www.iana.org/domains/root/db/enterprises.html +enterprises + +// epson : Seiko Epson Corporation +// https://www.iana.org/domains/root/db/epson.html +epson + +// equipment : Binky Moon, LLC +// https://www.iana.org/domains/root/db/equipment.html +equipment + +// ericsson : Telefonaktiebolaget L M Ericsson +// https://www.iana.org/domains/root/db/ericsson.html +ericsson + +// erni : ERNI Group Holding AG +// https://www.iana.org/domains/root/db/erni.html +erni + +// esq : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/esq.html +esq + +// estate : Binky Moon, LLC +// https://www.iana.org/domains/root/db/estate.html +estate + +// eurovision : European Broadcasting Union (EBU) +// https://www.iana.org/domains/root/db/eurovision.html +eurovision + +// eus : Puntueus Fundazioa +// https://www.iana.org/domains/root/db/eus.html +eus + +// events : Binky Moon, LLC +// https://www.iana.org/domains/root/db/events.html +events + +// exchange : Binky Moon, LLC +// https://www.iana.org/domains/root/db/exchange.html +exchange + +// expert : Binky Moon, LLC +// https://www.iana.org/domains/root/db/expert.html +expert + +// exposed : Binky Moon, LLC +// https://www.iana.org/domains/root/db/exposed.html +exposed + +// express : Binky Moon, LLC +// https://www.iana.org/domains/root/db/express.html +express + +// extraspace : Extra Space Storage LLC +// https://www.iana.org/domains/root/db/extraspace.html +extraspace + +// fage : Fage International S.A. +// https://www.iana.org/domains/root/db/fage.html +fage + +// fail : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fail.html +fail + +// fairwinds : FairWinds Partners, LLC +// https://www.iana.org/domains/root/db/fairwinds.html +fairwinds + +// faith : dot Faith Limited +// https://www.iana.org/domains/root/db/faith.html +faith + +// family : Dog Beach, LLC +// https://www.iana.org/domains/root/db/family.html +family + +// fan : Dog Beach, LLC +// https://www.iana.org/domains/root/db/fan.html +fan + +// fans : ZDNS International Limited +// https://www.iana.org/domains/root/db/fans.html +fans + +// farm : Binky Moon, LLC +// https://www.iana.org/domains/root/db/farm.html +farm + +// farmers : Farmers Insurance Exchange +// https://www.iana.org/domains/root/db/farmers.html +farmers + +// fashion : Registry Services, LLC +// https://www.iana.org/domains/root/db/fashion.html +fashion + +// fast : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/fast.html +fast + +// fedex : Federal Express Corporation +// https://www.iana.org/domains/root/db/fedex.html +fedex + +// feedback : Top Level Spectrum, Inc. +// https://www.iana.org/domains/root/db/feedback.html +feedback + +// ferrari : Fiat Chrysler Automobiles N.V. +// https://www.iana.org/domains/root/db/ferrari.html +ferrari + +// ferrero : Ferrero Trading Lux S.A. +// https://www.iana.org/domains/root/db/ferrero.html +ferrero + +// fidelity : Fidelity Brokerage Services LLC +// https://www.iana.org/domains/root/db/fidelity.html +fidelity + +// fido : Rogers Communications Canada Inc. +// https://www.iana.org/domains/root/db/fido.html +fido + +// film : Motion Picture Domain Registry Pty Ltd +// https://www.iana.org/domains/root/db/film.html +film + +// final : Núcleo de Informação e Coordenação do Ponto BR - NIC.br +// https://www.iana.org/domains/root/db/final.html +final + +// finance : Binky Moon, LLC +// https://www.iana.org/domains/root/db/finance.html +finance + +// financial : Binky Moon, LLC +// https://www.iana.org/domains/root/db/financial.html +financial + +// fire : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/fire.html +fire + +// firestone : Bridgestone Licensing Services, Inc +// https://www.iana.org/domains/root/db/firestone.html +firestone + +// firmdale : Firmdale Holdings Limited +// https://www.iana.org/domains/root/db/firmdale.html +firmdale + +// fish : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fish.html +fish + +// fishing : Registry Services, LLC +// https://www.iana.org/domains/root/db/fishing.html +fishing + +// fit : Registry Services, LLC +// https://www.iana.org/domains/root/db/fit.html +fit + +// fitness : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fitness.html +fitness + +// flickr : Flickr, Inc. +// https://www.iana.org/domains/root/db/flickr.html +flickr + +// flights : Binky Moon, LLC +// https://www.iana.org/domains/root/db/flights.html +flights + +// flir : FLIR Systems, Inc. +// https://www.iana.org/domains/root/db/flir.html +flir + +// florist : Binky Moon, LLC +// https://www.iana.org/domains/root/db/florist.html +florist + +// flowers : XYZ.COM LLC +// https://www.iana.org/domains/root/db/flowers.html +flowers + +// fly : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/fly.html +fly + +// foo : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/foo.html +foo + +// food : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/food.html +food + +// football : Binky Moon, LLC +// https://www.iana.org/domains/root/db/football.html +football + +// ford : Ford Motor Company +// https://www.iana.org/domains/root/db/ford.html +ford + +// forex : Dog Beach, LLC +// https://www.iana.org/domains/root/db/forex.html +forex + +// forsale : Dog Beach, LLC +// https://www.iana.org/domains/root/db/forsale.html +forsale + +// forum : Waterford Limited +// https://www.iana.org/domains/root/db/forum.html +forum + +// foundation : Public Interest Registry +// https://www.iana.org/domains/root/db/foundation.html +foundation + +// fox : FOX Registry, LLC +// https://www.iana.org/domains/root/db/fox.html +fox + +// free : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/free.html +free + +// fresenius : Fresenius Immobilien-Verwaltungs-GmbH +// https://www.iana.org/domains/root/db/fresenius.html +fresenius + +// frl : FRLregistry B.V. +// https://www.iana.org/domains/root/db/frl.html +frl + +// frogans : OP3FT +// https://www.iana.org/domains/root/db/frogans.html +frogans + +// frontier : Frontier Communications Corporation +// https://www.iana.org/domains/root/db/frontier.html +frontier + +// ftr : Frontier Communications Corporation +// https://www.iana.org/domains/root/db/ftr.html +ftr + +// fujitsu : Fujitsu Limited +// https://www.iana.org/domains/root/db/fujitsu.html +fujitsu + +// fun : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/fun.html +fun + +// fund : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fund.html +fund + +// furniture : Binky Moon, LLC +// https://www.iana.org/domains/root/db/furniture.html +furniture + +// futbol : Dog Beach, LLC +// https://www.iana.org/domains/root/db/futbol.html +futbol + +// fyi : Binky Moon, LLC +// https://www.iana.org/domains/root/db/fyi.html +fyi + +// gal : Asociación puntoGAL +// https://www.iana.org/domains/root/db/gal.html +gal + +// gallery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gallery.html +gallery + +// gallo : Gallo Vineyards, Inc. +// https://www.iana.org/domains/root/db/gallo.html +gallo + +// gallup : Gallup, Inc. +// https://www.iana.org/domains/root/db/gallup.html +gallup + +// game : XYZ.COM LLC +// https://www.iana.org/domains/root/db/game.html +game + +// games : Dog Beach, LLC +// https://www.iana.org/domains/root/db/games.html +games + +// gap : The Gap, Inc. +// https://www.iana.org/domains/root/db/gap.html +gap + +// garden : Registry Services, LLC +// https://www.iana.org/domains/root/db/garden.html +garden + +// gay : Registry Services, LLC +// https://www.iana.org/domains/root/db/gay.html +gay + +// gbiz : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gbiz.html +gbiz + +// gdn : Joint Stock Company "Navigation-information systems" +// https://www.iana.org/domains/root/db/gdn.html +gdn + +// gea : GEA Group Aktiengesellschaft +// https://www.iana.org/domains/root/db/gea.html +gea + +// gent : Easyhost BV +// https://www.iana.org/domains/root/db/gent.html +gent + +// genting : Resorts World Inc Pte. Ltd. +// https://www.iana.org/domains/root/db/genting.html +genting + +// george : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/george.html +george + +// ggee : GMO Internet, Inc. +// https://www.iana.org/domains/root/db/ggee.html +ggee + +// gift : DotGift, LLC +// https://www.iana.org/domains/root/db/gift.html +gift + +// gifts : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gifts.html +gifts + +// gives : Public Interest Registry +// https://www.iana.org/domains/root/db/gives.html +gives + +// giving : Public Interest Registry +// https://www.iana.org/domains/root/db/giving.html +giving + +// glass : Binky Moon, LLC +// https://www.iana.org/domains/root/db/glass.html +glass + +// gle : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gle.html +gle + +// global : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/global.html +global + +// globo : Globo Comunicação e Participações S.A +// https://www.iana.org/domains/root/db/globo.html +globo + +// gmail : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/gmail.html +gmail + +// gmbh : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gmbh.html +gmbh + +// gmo : GMO Internet, Inc. +// https://www.iana.org/domains/root/db/gmo.html +gmo + +// gmx : 1&1 Mail & Media GmbH +// https://www.iana.org/domains/root/db/gmx.html +gmx + +// godaddy : Go Daddy East, LLC +// https://www.iana.org/domains/root/db/godaddy.html +godaddy + +// gold : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gold.html +gold + +// goldpoint : YODOBASHI CAMERA CO.,LTD. +// https://www.iana.org/domains/root/db/goldpoint.html +goldpoint + +// golf : Binky Moon, LLC +// https://www.iana.org/domains/root/db/golf.html +golf + +// goo : NTT DOCOMO, INC. +// https://www.iana.org/domains/root/db/goo.html +goo + +// goodyear : The Goodyear Tire & Rubber Company +// https://www.iana.org/domains/root/db/goodyear.html +goodyear + +// goog : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/goog.html +goog + +// google : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/google.html +google + +// gop : Republican State Leadership Committee, Inc. +// https://www.iana.org/domains/root/db/gop.html +gop + +// got : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/got.html +got + +// grainger : Grainger Registry Services, LLC +// https://www.iana.org/domains/root/db/grainger.html +grainger + +// graphics : Binky Moon, LLC +// https://www.iana.org/domains/root/db/graphics.html +graphics + +// gratis : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gratis.html +gratis + +// green : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/green.html +green + +// gripe : Binky Moon, LLC +// https://www.iana.org/domains/root/db/gripe.html +gripe + +// grocery : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/grocery.html +grocery + +// group : Binky Moon, LLC +// https://www.iana.org/domains/root/db/group.html +group + +// gucci : Guccio Gucci S.p.a. +// https://www.iana.org/domains/root/db/gucci.html +gucci + +// guge : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/guge.html +guge + +// guide : Binky Moon, LLC +// https://www.iana.org/domains/root/db/guide.html +guide + +// guitars : XYZ.COM LLC +// https://www.iana.org/domains/root/db/guitars.html +guitars + +// guru : Binky Moon, LLC +// https://www.iana.org/domains/root/db/guru.html +guru + +// hair : XYZ.COM LLC +// https://www.iana.org/domains/root/db/hair.html +hair + +// hamburg : Hamburg Top-Level-Domain GmbH +// https://www.iana.org/domains/root/db/hamburg.html +hamburg + +// hangout : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/hangout.html +hangout + +// haus : Dog Beach, LLC +// https://www.iana.org/domains/root/db/haus.html +haus + +// hbo : HBO Registry Services, Inc. +// https://www.iana.org/domains/root/db/hbo.html +hbo + +// hdfc : HDFC BANK LIMITED +// https://www.iana.org/domains/root/db/hdfc.html +hdfc + +// hdfcbank : HDFC BANK LIMITED +// https://www.iana.org/domains/root/db/hdfcbank.html +hdfcbank + +// health : Registry Services, LLC +// https://www.iana.org/domains/root/db/health.html +health + +// healthcare : Binky Moon, LLC +// https://www.iana.org/domains/root/db/healthcare.html +healthcare + +// help : Innovation service Limited +// https://www.iana.org/domains/root/db/help.html +help + +// helsinki : City of Helsinki +// https://www.iana.org/domains/root/db/helsinki.html +helsinki + +// here : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/here.html +here + +// hermes : HERMES INTERNATIONAL +// https://www.iana.org/domains/root/db/hermes.html +hermes + +// hiphop : Dot Hip Hop, LLC +// https://www.iana.org/domains/root/db/hiphop.html +hiphop + +// hisamitsu : Hisamitsu Pharmaceutical Co.,Inc. +// https://www.iana.org/domains/root/db/hisamitsu.html +hisamitsu + +// hitachi : Hitachi, Ltd. +// https://www.iana.org/domains/root/db/hitachi.html +hitachi + +// hiv : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/hiv.html +hiv + +// hkt : PCCW-HKT DataCom Services Limited +// https://www.iana.org/domains/root/db/hkt.html +hkt + +// hockey : Binky Moon, LLC +// https://www.iana.org/domains/root/db/hockey.html +hockey + +// holdings : Binky Moon, LLC +// https://www.iana.org/domains/root/db/holdings.html +holdings + +// holiday : Binky Moon, LLC +// https://www.iana.org/domains/root/db/holiday.html +holiday + +// homedepot : Home Depot Product Authority, LLC +// https://www.iana.org/domains/root/db/homedepot.html +homedepot + +// homegoods : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/homegoods.html +homegoods + +// homes : XYZ.COM LLC +// https://www.iana.org/domains/root/db/homes.html +homes + +// homesense : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/homesense.html +homesense + +// honda : Honda Motor Co., Ltd. +// https://www.iana.org/domains/root/db/honda.html +honda + +// horse : Registry Services, LLC +// https://www.iana.org/domains/root/db/horse.html +horse + +// hospital : Binky Moon, LLC +// https://www.iana.org/domains/root/db/hospital.html +hospital + +// host : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/host.html +host + +// hosting : XYZ.COM LLC +// https://www.iana.org/domains/root/db/hosting.html +hosting + +// hot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/hot.html +hot + +// hotel : HOTEL Top-Level-Domain S.a.r.l +// https://www.iana.org/domains/root/db/hotel.html +hotel + +// hotels : Booking.com B.V. +// https://www.iana.org/domains/root/db/hotels.html +hotels + +// hotmail : Microsoft Corporation +// https://www.iana.org/domains/root/db/hotmail.html +hotmail + +// house : Binky Moon, LLC +// https://www.iana.org/domains/root/db/house.html +house + +// how : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/how.html +how + +// hsbc : HSBC Global Services (UK) Limited +// https://www.iana.org/domains/root/db/hsbc.html +hsbc + +// hughes : Hughes Satellite Systems Corporation +// https://www.iana.org/domains/root/db/hughes.html +hughes + +// hyatt : Hyatt GTLD, L.L.C. +// https://www.iana.org/domains/root/db/hyatt.html +hyatt + +// hyundai : Hyundai Motor Company +// https://www.iana.org/domains/root/db/hyundai.html +hyundai + +// ibm : International Business Machines Corporation +// https://www.iana.org/domains/root/db/ibm.html +ibm + +// icbc : Industrial and Commercial Bank of China Limited +// https://www.iana.org/domains/root/db/icbc.html +icbc + +// ice : IntercontinentalExchange, Inc. +// https://www.iana.org/domains/root/db/ice.html +ice + +// icu : ShortDot SA +// https://www.iana.org/domains/root/db/icu.html +icu + +// ieee : IEEE Global LLC +// https://www.iana.org/domains/root/db/ieee.html +ieee + +// ifm : ifm electronic gmbh +// https://www.iana.org/domains/root/db/ifm.html +ifm + +// ikano : Ikano S.A. +// https://www.iana.org/domains/root/db/ikano.html +ikano + +// imamat : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/imamat.html +imamat + +// imdb : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/imdb.html +imdb + +// immo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/immo.html +immo + +// immobilien : Dog Beach, LLC +// https://www.iana.org/domains/root/db/immobilien.html +immobilien + +// inc : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/inc.html +inc + +// industries : Binky Moon, LLC +// https://www.iana.org/domains/root/db/industries.html +industries + +// infiniti : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/infiniti.html +infiniti + +// ing : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/ing.html +ing + +// ink : Registry Services, LLC +// https://www.iana.org/domains/root/db/ink.html +ink + +// institute : Binky Moon, LLC +// https://www.iana.org/domains/root/db/institute.html +institute + +// insurance : fTLD Registry Services LLC +// https://www.iana.org/domains/root/db/insurance.html +insurance + +// insure : Binky Moon, LLC +// https://www.iana.org/domains/root/db/insure.html +insure + +// international : Binky Moon, LLC +// https://www.iana.org/domains/root/db/international.html +international + +// intuit : Intuit Administrative Services, Inc. +// https://www.iana.org/domains/root/db/intuit.html +intuit + +// investments : Binky Moon, LLC +// https://www.iana.org/domains/root/db/investments.html +investments + +// ipiranga : Ipiranga Produtos de Petroleo S.A. +// https://www.iana.org/domains/root/db/ipiranga.html +ipiranga + +// irish : Binky Moon, LLC +// https://www.iana.org/domains/root/db/irish.html +irish + +// ismaili : Fondation Aga Khan (Aga Khan Foundation) +// https://www.iana.org/domains/root/db/ismaili.html +ismaili + +// ist : Istanbul Metropolitan Municipality +// https://www.iana.org/domains/root/db/ist.html +ist + +// istanbul : Istanbul Metropolitan Municipality +// https://www.iana.org/domains/root/db/istanbul.html +istanbul + +// itau : Itau Unibanco Holding S.A. +// https://www.iana.org/domains/root/db/itau.html +itau + +// itv : ITV Services Limited +// https://www.iana.org/domains/root/db/itv.html +itv + +// jaguar : Jaguar Land Rover Ltd +// https://www.iana.org/domains/root/db/jaguar.html +jaguar + +// java : Oracle Corporation +// https://www.iana.org/domains/root/db/java.html +java + +// jcb : JCB Co., Ltd. +// https://www.iana.org/domains/root/db/jcb.html +jcb + +// jeep : FCA US LLC. +// https://www.iana.org/domains/root/db/jeep.html +jeep + +// jetzt : Binky Moon, LLC +// https://www.iana.org/domains/root/db/jetzt.html +jetzt + +// jewelry : Binky Moon, LLC +// https://www.iana.org/domains/root/db/jewelry.html +jewelry + +// jio : Reliance Industries Limited +// https://www.iana.org/domains/root/db/jio.html +jio + +// jll : Jones Lang LaSalle Incorporated +// https://www.iana.org/domains/root/db/jll.html +jll + +// jmp : Matrix IP LLC +// https://www.iana.org/domains/root/db/jmp.html +jmp + +// jnj : Johnson & Johnson Services, Inc. +// https://www.iana.org/domains/root/db/jnj.html +jnj + +// joburg : ZA Central Registry NPC trading as ZA Central Registry +// https://www.iana.org/domains/root/db/joburg.html +joburg + +// jot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/jot.html +jot + +// joy : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/joy.html +joy + +// jpmorgan : JPMorgan Chase Bank, National Association +// https://www.iana.org/domains/root/db/jpmorgan.html +jpmorgan + +// jprs : Japan Registry Services Co., Ltd. +// https://www.iana.org/domains/root/db/jprs.html +jprs + +// juegos : Dog Beach, LLC +// https://www.iana.org/domains/root/db/juegos.html +juegos + +// juniper : JUNIPER NETWORKS, INC. +// https://www.iana.org/domains/root/db/juniper.html +juniper + +// kaufen : Dog Beach, LLC +// https://www.iana.org/domains/root/db/kaufen.html +kaufen + +// kddi : KDDI CORPORATION +// https://www.iana.org/domains/root/db/kddi.html +kddi + +// kerryhotels : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kerryhotels.html +kerryhotels + +// kerryproperties : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kerryproperties.html +kerryproperties + +// kfh : Kuwait Finance House +// https://www.iana.org/domains/root/db/kfh.html +kfh + +// kia : KIA MOTORS CORPORATION +// https://www.iana.org/domains/root/db/kia.html +kia + +// kids : DotKids Foundation Limited +// https://www.iana.org/domains/root/db/kids.html +kids + +// kim : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/kim.html +kim + +// kindle : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/kindle.html +kindle + +// kitchen : Binky Moon, LLC +// https://www.iana.org/domains/root/db/kitchen.html +kitchen + +// kiwi : DOT KIWI LIMITED +// https://www.iana.org/domains/root/db/kiwi.html +kiwi + +// koeln : dotKoeln GmbH +// https://www.iana.org/domains/root/db/koeln.html +koeln + +// komatsu : Komatsu Ltd. +// https://www.iana.org/domains/root/db/komatsu.html +komatsu + +// kosher : Kosher Marketing Assets LLC +// https://www.iana.org/domains/root/db/kosher.html +kosher + +// kpmg : KPMG International Cooperative (KPMG International Genossenschaft) +// https://www.iana.org/domains/root/db/kpmg.html +kpmg + +// kpn : Koninklijke KPN N.V. +// https://www.iana.org/domains/root/db/kpn.html +kpn + +// krd : KRG Department of Information Technology +// https://www.iana.org/domains/root/db/krd.html +krd + +// kred : KredTLD Pty Ltd +// https://www.iana.org/domains/root/db/kred.html +kred + +// kuokgroup : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/kuokgroup.html +kuokgroup + +// kyoto : Academic Institution: Kyoto Jyoho Gakuen +// https://www.iana.org/domains/root/db/kyoto.html +kyoto + +// lacaixa : Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” +// https://www.iana.org/domains/root/db/lacaixa.html +lacaixa + +// lamborghini : Automobili Lamborghini S.p.A. +// https://www.iana.org/domains/root/db/lamborghini.html +lamborghini + +// lamer : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/lamer.html +lamer + +// land : Binky Moon, LLC +// https://www.iana.org/domains/root/db/land.html +land + +// landrover : Jaguar Land Rover Ltd +// https://www.iana.org/domains/root/db/landrover.html +landrover + +// lanxess : LANXESS Corporation +// https://www.iana.org/domains/root/db/lanxess.html +lanxess + +// lasalle : Jones Lang LaSalle Incorporated +// https://www.iana.org/domains/root/db/lasalle.html +lasalle + +// lat : XYZ.COM LLC +// https://www.iana.org/domains/root/db/lat.html +lat + +// latino : Dish DBS Corporation +// https://www.iana.org/domains/root/db/latino.html +latino + +// latrobe : La Trobe University +// https://www.iana.org/domains/root/db/latrobe.html +latrobe + +// law : Registry Services, LLC +// https://www.iana.org/domains/root/db/law.html +law + +// lawyer : Dog Beach, LLC +// https://www.iana.org/domains/root/db/lawyer.html +lawyer + +// lds : IRI Domain Management, LLC +// https://www.iana.org/domains/root/db/lds.html +lds + +// lease : Binky Moon, LLC +// https://www.iana.org/domains/root/db/lease.html +lease + +// leclerc : A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc +// https://www.iana.org/domains/root/db/leclerc.html +leclerc + +// lefrak : LeFrak Organization, Inc. +// https://www.iana.org/domains/root/db/lefrak.html +lefrak + +// legal : Binky Moon, LLC +// https://www.iana.org/domains/root/db/legal.html +legal + +// lego : LEGO Juris A/S +// https://www.iana.org/domains/root/db/lego.html +lego + +// lexus : TOYOTA MOTOR CORPORATION +// https://www.iana.org/domains/root/db/lexus.html +lexus + +// lgbt : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/lgbt.html +lgbt + +// lidl : Schwarz Domains und Services GmbH & Co. KG +// https://www.iana.org/domains/root/db/lidl.html +lidl + +// life : Binky Moon, LLC +// https://www.iana.org/domains/root/db/life.html +life + +// lifeinsurance : American Council of Life Insurers +// https://www.iana.org/domains/root/db/lifeinsurance.html +lifeinsurance + +// lifestyle : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/lifestyle.html +lifestyle + +// lighting : Binky Moon, LLC +// https://www.iana.org/domains/root/db/lighting.html +lighting + +// like : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/like.html +like + +// lilly : Eli Lilly and Company +// https://www.iana.org/domains/root/db/lilly.html +lilly + +// limited : Binky Moon, LLC +// https://www.iana.org/domains/root/db/limited.html +limited + +// limo : Binky Moon, LLC +// https://www.iana.org/domains/root/db/limo.html +limo + +// lincoln : Ford Motor Company +// https://www.iana.org/domains/root/db/lincoln.html +lincoln + +// link : Nova Registry Ltd +// https://www.iana.org/domains/root/db/link.html +link + +// live : Dog Beach, LLC +// https://www.iana.org/domains/root/db/live.html +live + +// living : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/living.html +living + +// llc : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/llc.html +llc + +// llp : Intercap Registry Inc. +// https://www.iana.org/domains/root/db/llp.html +llp + +// loan : dot Loan Limited +// https://www.iana.org/domains/root/db/loan.html +loan + +// loans : Binky Moon, LLC +// https://www.iana.org/domains/root/db/loans.html +loans + +// locker : Orange Domains LLC +// https://www.iana.org/domains/root/db/locker.html +locker + +// locus : Locus Analytics LLC +// https://www.iana.org/domains/root/db/locus.html +locus + +// lol : XYZ.COM LLC +// https://www.iana.org/domains/root/db/lol.html +lol + +// london : Dot London Domains Limited +// https://www.iana.org/domains/root/db/london.html +london + +// lotte : Lotte Holdings Co., Ltd. +// https://www.iana.org/domains/root/db/lotte.html +lotte + +// lotto : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/lotto.html +lotto + +// love : Waterford Limited +// https://www.iana.org/domains/root/db/love.html +love + +// lpl : LPL Holdings, Inc. +// https://www.iana.org/domains/root/db/lpl.html +lpl + +// lplfinancial : LPL Holdings, Inc. +// https://www.iana.org/domains/root/db/lplfinancial.html +lplfinancial + +// ltd : Binky Moon, LLC +// https://www.iana.org/domains/root/db/ltd.html +ltd + +// ltda : InterNetX, Corp +// https://www.iana.org/domains/root/db/ltda.html +ltda + +// lundbeck : H. Lundbeck A/S +// https://www.iana.org/domains/root/db/lundbeck.html +lundbeck + +// luxe : Registry Services, LLC +// https://www.iana.org/domains/root/db/luxe.html +luxe + +// luxury : Luxury Partners, LLC +// https://www.iana.org/domains/root/db/luxury.html +luxury + +// madrid : Comunidad de Madrid +// https://www.iana.org/domains/root/db/madrid.html +madrid + +// maif : Mutuelle Assurance Instituteur France (MAIF) +// https://www.iana.org/domains/root/db/maif.html +maif + +// maison : Binky Moon, LLC +// https://www.iana.org/domains/root/db/maison.html +maison + +// makeup : XYZ.COM LLC +// https://www.iana.org/domains/root/db/makeup.html +makeup + +// man : MAN Truck & Bus SE +// https://www.iana.org/domains/root/db/man.html +man + +// management : Binky Moon, LLC +// https://www.iana.org/domains/root/db/management.html +management + +// mango : PUNTO FA S.L. +// https://www.iana.org/domains/root/db/mango.html +mango + +// map : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/map.html +map + +// market : Dog Beach, LLC +// https://www.iana.org/domains/root/db/market.html +market + +// marketing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/marketing.html +marketing + +// markets : Dog Beach, LLC +// https://www.iana.org/domains/root/db/markets.html +markets + +// marriott : Marriott Worldwide Corporation +// https://www.iana.org/domains/root/db/marriott.html +marriott + +// marshalls : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/marshalls.html +marshalls + +// mattel : Mattel IT Services, Inc. +// https://www.iana.org/domains/root/db/mattel.html +mattel + +// mba : Binky Moon, LLC +// https://www.iana.org/domains/root/db/mba.html +mba + +// mckinsey : McKinsey Holdings, Inc. +// https://www.iana.org/domains/root/db/mckinsey.html +mckinsey + +// med : Medistry LLC +// https://www.iana.org/domains/root/db/med.html +med + +// media : Binky Moon, LLC +// https://www.iana.org/domains/root/db/media.html +media + +// meet : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/meet.html +meet + +// melbourne : The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation +// https://www.iana.org/domains/root/db/melbourne.html +melbourne + +// meme : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/meme.html +meme + +// memorial : Dog Beach, LLC +// https://www.iana.org/domains/root/db/memorial.html +memorial + +// men : Exclusive Registry Limited +// https://www.iana.org/domains/root/db/men.html +men + +// menu : Dot Menu Registry, LLC +// https://www.iana.org/domains/root/db/menu.html +menu + +// merck : Merck Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/merck.html +merck + +// merckmsd : MSD Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/merckmsd.html +merckmsd + +// miami : Registry Services, LLC +// https://www.iana.org/domains/root/db/miami.html +miami + +// microsoft : Microsoft Corporation +// https://www.iana.org/domains/root/db/microsoft.html +microsoft + +// mini : Bayerische Motoren Werke Aktiengesellschaft +// https://www.iana.org/domains/root/db/mini.html +mini + +// mint : Intuit Administrative Services, Inc. +// https://www.iana.org/domains/root/db/mint.html +mint + +// mit : Massachusetts Institute of Technology +// https://www.iana.org/domains/root/db/mit.html +mit + +// mitsubishi : Mitsubishi Corporation +// https://www.iana.org/domains/root/db/mitsubishi.html +mitsubishi + +// mlb : MLB Advanced Media DH, LLC +// https://www.iana.org/domains/root/db/mlb.html +mlb + +// mls : The Canadian Real Estate Association +// https://www.iana.org/domains/root/db/mls.html +mls + +// mma : MMA IARD +// https://www.iana.org/domains/root/db/mma.html +mma + +// mobile : Dish DBS Corporation +// https://www.iana.org/domains/root/db/mobile.html +mobile + +// moda : Dog Beach, LLC +// https://www.iana.org/domains/root/db/moda.html +moda + +// moe : Interlink Systems Innovation Institute K.K. +// https://www.iana.org/domains/root/db/moe.html +moe + +// moi : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/moi.html +moi + +// mom : XYZ.COM LLC +// https://www.iana.org/domains/root/db/mom.html +mom + +// monash : Monash University +// https://www.iana.org/domains/root/db/monash.html +monash + +// money : Binky Moon, LLC +// https://www.iana.org/domains/root/db/money.html +money + +// monster : XYZ.COM LLC +// https://www.iana.org/domains/root/db/monster.html +monster + +// mormon : IRI Domain Management, LLC +// https://www.iana.org/domains/root/db/mormon.html +mormon + +// mortgage : Dog Beach, LLC +// https://www.iana.org/domains/root/db/mortgage.html +mortgage + +// moscow : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// https://www.iana.org/domains/root/db/moscow.html +moscow + +// moto : Motorola Trademark Holdings, LLC +// https://www.iana.org/domains/root/db/moto.html +moto + +// motorcycles : XYZ.COM LLC +// https://www.iana.org/domains/root/db/motorcycles.html +motorcycles + +// mov : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/mov.html +mov + +// movie : Binky Moon, LLC +// https://www.iana.org/domains/root/db/movie.html +movie + +// msd : MSD Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/msd.html +msd + +// mtn : MTN Dubai Limited +// https://www.iana.org/domains/root/db/mtn.html +mtn + +// mtr : MTR Corporation Limited +// https://www.iana.org/domains/root/db/mtr.html +mtr + +// music : DotMusic Limited +// https://www.iana.org/domains/root/db/music.html +music + +// nab : National Australia Bank Limited +// https://www.iana.org/domains/root/db/nab.html +nab + +// nagoya : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/nagoya.html +nagoya + +// navy : Dog Beach, LLC +// https://www.iana.org/domains/root/db/navy.html +navy + +// nba : NBA REGISTRY, LLC +// https://www.iana.org/domains/root/db/nba.html +nba + +// nec : NEC Corporation +// https://www.iana.org/domains/root/db/nec.html +nec + +// netbank : COMMONWEALTH BANK OF AUSTRALIA +// https://www.iana.org/domains/root/db/netbank.html +netbank + +// netflix : Netflix, Inc. +// https://www.iana.org/domains/root/db/netflix.html +netflix + +// network : Binky Moon, LLC +// https://www.iana.org/domains/root/db/network.html +network + +// neustar : NeuStar, Inc. +// https://www.iana.org/domains/root/db/neustar.html +neustar + +// new : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/new.html +new + +// news : Dog Beach, LLC +// https://www.iana.org/domains/root/db/news.html +news + +// next : Next plc +// https://www.iana.org/domains/root/db/next.html +next + +// nextdirect : Next plc +// https://www.iana.org/domains/root/db/nextdirect.html +nextdirect + +// nexus : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/nexus.html +nexus + +// nfl : NFL Reg Ops LLC +// https://www.iana.org/domains/root/db/nfl.html +nfl + +// ngo : Public Interest Registry +// https://www.iana.org/domains/root/db/ngo.html +ngo + +// nhk : Japan Broadcasting Corporation (NHK) +// https://www.iana.org/domains/root/db/nhk.html +nhk + +// nico : DWANGO Co., Ltd. +// https://www.iana.org/domains/root/db/nico.html +nico + +// nike : NIKE, Inc. +// https://www.iana.org/domains/root/db/nike.html +nike + +// nikon : NIKON CORPORATION +// https://www.iana.org/domains/root/db/nikon.html +nikon + +// ninja : Dog Beach, LLC +// https://www.iana.org/domains/root/db/ninja.html +ninja + +// nissan : NISSAN MOTOR CO., LTD. +// https://www.iana.org/domains/root/db/nissan.html +nissan + +// nissay : Nippon Life Insurance Company +// https://www.iana.org/domains/root/db/nissay.html +nissay + +// nokia : Nokia Corporation +// https://www.iana.org/domains/root/db/nokia.html +nokia + +// norton : Gen Digital Inc. +// https://www.iana.org/domains/root/db/norton.html +norton + +// now : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/now.html +now + +// nowruz +// https://www.iana.org/domains/root/db/nowruz.html +nowruz + +// nowtv : Starbucks (HK) Limited +// https://www.iana.org/domains/root/db/nowtv.html +nowtv + +// nra : National Rifle Association of America +// https://www.iana.org/domains/root/db/nra.html +nra + +// nrw : Minds + Machines GmbH +// https://www.iana.org/domains/root/db/nrw.html +nrw + +// ntt : NIPPON TELEGRAPH AND TELEPHONE CORPORATION +// https://www.iana.org/domains/root/db/ntt.html +ntt + +// nyc : The City of New York by and through the New York City Department of Information Technology & Telecommunications +// https://www.iana.org/domains/root/db/nyc.html +nyc + +// obi : OBI Group Holding SE & Co. KGaA +// https://www.iana.org/domains/root/db/obi.html +obi + +// observer : Fegistry, LLC +// https://www.iana.org/domains/root/db/observer.html +observer + +// office : Microsoft Corporation +// https://www.iana.org/domains/root/db/office.html +office + +// okinawa : BRregistry, Inc. +// https://www.iana.org/domains/root/db/okinawa.html +okinawa + +// olayan : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/olayan.html +olayan + +// olayangroup : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/olayangroup.html +olayangroup + +// ollo : Dish DBS Corporation +// https://www.iana.org/domains/root/db/ollo.html +ollo + +// omega : The Swatch Group Ltd +// https://www.iana.org/domains/root/db/omega.html +omega + +// one : One.com A/S +// https://www.iana.org/domains/root/db/one.html +one + +// ong : Public Interest Registry +// https://www.iana.org/domains/root/db/ong.html +ong + +// onl : iRegistry GmbH +// https://www.iana.org/domains/root/db/onl.html +onl + +// online : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/online.html +online + +// ooo : INFIBEAM AVENUES LIMITED +// https://www.iana.org/domains/root/db/ooo.html +ooo + +// open : American Express Travel Related Services Company, Inc. +// https://www.iana.org/domains/root/db/open.html +open + +// oracle : Oracle Corporation +// https://www.iana.org/domains/root/db/oracle.html +oracle + +// orange : Orange Brand Services Limited +// https://www.iana.org/domains/root/db/orange.html +orange + +// organic : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/organic.html +organic + +// origins : The Estée Lauder Companies Inc. +// https://www.iana.org/domains/root/db/origins.html +origins + +// osaka : Osaka Registry Co., Ltd. +// https://www.iana.org/domains/root/db/osaka.html +osaka + +// otsuka : Otsuka Holdings Co., Ltd. +// https://www.iana.org/domains/root/db/otsuka.html +otsuka + +// ott : Dish DBS Corporation +// https://www.iana.org/domains/root/db/ott.html +ott + +// ovh : MédiaBC +// https://www.iana.org/domains/root/db/ovh.html +ovh + +// page : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/page.html +page + +// panasonic : Panasonic Holdings Corporation +// https://www.iana.org/domains/root/db/panasonic.html +panasonic + +// paris : City of Paris +// https://www.iana.org/domains/root/db/paris.html +paris + +// pars +// https://www.iana.org/domains/root/db/pars.html +pars + +// partners : Binky Moon, LLC +// https://www.iana.org/domains/root/db/partners.html +partners + +// parts : Binky Moon, LLC +// https://www.iana.org/domains/root/db/parts.html +parts + +// party : Blue Sky Registry Limited +// https://www.iana.org/domains/root/db/party.html +party + +// pay : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/pay.html +pay + +// pccw : PCCW Enterprises Limited +// https://www.iana.org/domains/root/db/pccw.html +pccw + +// pet : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/pet.html +pet + +// pfizer : Pfizer Inc. +// https://www.iana.org/domains/root/db/pfizer.html +pfizer + +// pharmacy : National Association of Boards of Pharmacy +// https://www.iana.org/domains/root/db/pharmacy.html +pharmacy + +// phd : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/phd.html +phd + +// philips : Koninklijke Philips N.V. +// https://www.iana.org/domains/root/db/philips.html +philips + +// phone : Dish DBS Corporation +// https://www.iana.org/domains/root/db/phone.html +phone + +// photo : Registry Services, LLC +// https://www.iana.org/domains/root/db/photo.html +photo + +// photography : Binky Moon, LLC +// https://www.iana.org/domains/root/db/photography.html +photography + +// photos : Binky Moon, LLC +// https://www.iana.org/domains/root/db/photos.html +photos + +// physio : PhysBiz Pty Ltd +// https://www.iana.org/domains/root/db/physio.html +physio + +// pics : XYZ.COM LLC +// https://www.iana.org/domains/root/db/pics.html +pics + +// pictet : Banque Pictet & Cie SA +// https://www.iana.org/domains/root/db/pictet.html +pictet + +// pictures : Binky Moon, LLC +// https://www.iana.org/domains/root/db/pictures.html +pictures + +// pid : Top Level Spectrum, Inc. +// https://www.iana.org/domains/root/db/pid.html +pid + +// pin : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/pin.html +pin + +// ping : Ping Registry Provider, Inc. +// https://www.iana.org/domains/root/db/ping.html +ping + +// pink : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/pink.html +pink + +// pioneer : Pioneer Corporation +// https://www.iana.org/domains/root/db/pioneer.html +pioneer + +// pizza : Binky Moon, LLC +// https://www.iana.org/domains/root/db/pizza.html +pizza + +// place : Binky Moon, LLC +// https://www.iana.org/domains/root/db/place.html +place + +// play : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/play.html +play + +// playstation : Sony Interactive Entertainment Inc. +// https://www.iana.org/domains/root/db/playstation.html +playstation + +// plumbing : Binky Moon, LLC +// https://www.iana.org/domains/root/db/plumbing.html +plumbing + +// plus : Binky Moon, LLC +// https://www.iana.org/domains/root/db/plus.html +plus + +// pnc : PNC Domain Co., LLC +// https://www.iana.org/domains/root/db/pnc.html +pnc + +// pohl : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/pohl.html +pohl + +// poker : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/poker.html +poker + +// politie : Politie Nederland +// https://www.iana.org/domains/root/db/politie.html +politie + +// porn : ICM Registry PN LLC +// https://www.iana.org/domains/root/db/porn.html +porn + +// praxi : Praxi S.p.A. +// https://www.iana.org/domains/root/db/praxi.html +praxi + +// press : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/press.html +press + +// prime : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/prime.html +prime + +// prod : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/prod.html +prod + +// productions : Binky Moon, LLC +// https://www.iana.org/domains/root/db/productions.html +productions + +// prof : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/prof.html +prof + +// progressive : Progressive Casualty Insurance Company +// https://www.iana.org/domains/root/db/progressive.html +progressive + +// promo : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/promo.html +promo + +// properties : Binky Moon, LLC +// https://www.iana.org/domains/root/db/properties.html +properties + +// property : Digital Property Infrastructure Limited +// https://www.iana.org/domains/root/db/property.html +property + +// protection : XYZ.COM LLC +// https://www.iana.org/domains/root/db/protection.html +protection + +// pru : Prudential Financial, Inc. +// https://www.iana.org/domains/root/db/pru.html +pru + +// prudential : Prudential Financial, Inc. +// https://www.iana.org/domains/root/db/prudential.html +prudential + +// pub : Dog Beach, LLC +// https://www.iana.org/domains/root/db/pub.html +pub + +// pwc : PricewaterhouseCoopers LLP +// https://www.iana.org/domains/root/db/pwc.html +pwc + +// qpon : dotQPON LLC +// https://www.iana.org/domains/root/db/qpon.html +qpon + +// quebec : PointQuébec Inc +// https://www.iana.org/domains/root/db/quebec.html +quebec + +// quest : XYZ.COM LLC +// https://www.iana.org/domains/root/db/quest.html +quest + +// racing : Premier Registry Limited +// https://www.iana.org/domains/root/db/racing.html +racing + +// radio : European Broadcasting Union (EBU) +// https://www.iana.org/domains/root/db/radio.html +radio + +// read : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/read.html +read + +// realestate : dotRealEstate LLC +// https://www.iana.org/domains/root/db/realestate.html +realestate + +// realtor : Real Estate Domains LLC +// https://www.iana.org/domains/root/db/realtor.html +realtor + +// realty : Waterford Limited +// https://www.iana.org/domains/root/db/realty.html +realty + +// recipes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/recipes.html +recipes + +// red : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/red.html +red + +// redumbrella : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/redumbrella.html +redumbrella + +// rehab : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rehab.html +rehab + +// reise : Binky Moon, LLC +// https://www.iana.org/domains/root/db/reise.html +reise + +// reisen : Binky Moon, LLC +// https://www.iana.org/domains/root/db/reisen.html +reisen + +// reit : National Association of Real Estate Investment Trusts, Inc. +// https://www.iana.org/domains/root/db/reit.html +reit + +// reliance : Reliance Industries Limited +// https://www.iana.org/domains/root/db/reliance.html +reliance + +// ren : ZDNS International Limited +// https://www.iana.org/domains/root/db/ren.html +ren + +// rent : XYZ.COM LLC +// https://www.iana.org/domains/root/db/rent.html +rent + +// rentals : Binky Moon, LLC +// https://www.iana.org/domains/root/db/rentals.html +rentals + +// repair : Binky Moon, LLC +// https://www.iana.org/domains/root/db/repair.html +repair + +// report : Binky Moon, LLC +// https://www.iana.org/domains/root/db/report.html +report + +// republican : Dog Beach, LLC +// https://www.iana.org/domains/root/db/republican.html +republican + +// rest : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable +// https://www.iana.org/domains/root/db/rest.html +rest + +// restaurant : Binky Moon, LLC +// https://www.iana.org/domains/root/db/restaurant.html +restaurant + +// review : dot Review Limited +// https://www.iana.org/domains/root/db/review.html +review + +// reviews : Dog Beach, LLC +// https://www.iana.org/domains/root/db/reviews.html +reviews + +// rexroth : Robert Bosch GMBH +// https://www.iana.org/domains/root/db/rexroth.html +rexroth + +// rich : iRegistry GmbH +// https://www.iana.org/domains/root/db/rich.html +rich + +// richardli : Pacific Century Asset Management (HK) Limited +// https://www.iana.org/domains/root/db/richardli.html +richardli + +// ricoh : Ricoh Company, Ltd. +// https://www.iana.org/domains/root/db/ricoh.html +ricoh + +// ril : Reliance Industries Limited +// https://www.iana.org/domains/root/db/ril.html +ril + +// rio : Empresa Municipal de Informática SA - IPLANRIO +// https://www.iana.org/domains/root/db/rio.html +rio + +// rip : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rip.html +rip + +// rocks : Dog Beach, LLC +// https://www.iana.org/domains/root/db/rocks.html +rocks + +// rodeo : Registry Services, LLC +// https://www.iana.org/domains/root/db/rodeo.html +rodeo + +// rogers : Rogers Communications Canada Inc. +// https://www.iana.org/domains/root/db/rogers.html +rogers + +// room : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/room.html +room + +// rsvp : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/rsvp.html +rsvp + +// rugby : World Rugby Strategic Developments Limited +// https://www.iana.org/domains/root/db/rugby.html +rugby + +// ruhr : dotSaarland GmbH +// https://www.iana.org/domains/root/db/ruhr.html +ruhr + +// run : Binky Moon, LLC +// https://www.iana.org/domains/root/db/run.html +run + +// rwe : RWE AG +// https://www.iana.org/domains/root/db/rwe.html +rwe + +// ryukyu : BRregistry, Inc. +// https://www.iana.org/domains/root/db/ryukyu.html +ryukyu + +// saarland : dotSaarland GmbH +// https://www.iana.org/domains/root/db/saarland.html +saarland + +// safe : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/safe.html +safe + +// safety : Safety Registry Services, LLC. +// https://www.iana.org/domains/root/db/safety.html +safety + +// sakura : SAKURA Internet Inc. +// https://www.iana.org/domains/root/db/sakura.html +sakura + +// sale : Dog Beach, LLC +// https://www.iana.org/domains/root/db/sale.html +sale + +// salon : Binky Moon, LLC +// https://www.iana.org/domains/root/db/salon.html +salon + +// samsclub : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/samsclub.html +samsclub + +// samsung : SAMSUNG SDS CO., LTD +// https://www.iana.org/domains/root/db/samsung.html +samsung + +// sandvik : Sandvik AB +// https://www.iana.org/domains/root/db/sandvik.html +sandvik + +// sandvikcoromant : Sandvik AB +// https://www.iana.org/domains/root/db/sandvikcoromant.html +sandvikcoromant + +// sanofi : Sanofi +// https://www.iana.org/domains/root/db/sanofi.html +sanofi + +// sap : SAP AG +// https://www.iana.org/domains/root/db/sap.html +sap + +// sarl : Binky Moon, LLC +// https://www.iana.org/domains/root/db/sarl.html +sarl + +// sas : Research IP LLC +// https://www.iana.org/domains/root/db/sas.html +sas + +// save : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/save.html +save + +// saxo : Saxo Bank A/S +// https://www.iana.org/domains/root/db/saxo.html +saxo + +// sbi : STATE BANK OF INDIA +// https://www.iana.org/domains/root/db/sbi.html +sbi + +// sbs : ShortDot SA +// https://www.iana.org/domains/root/db/sbs.html +sbs + +// scb : The Siam Commercial Bank Public Company Limited ("SCB") +// https://www.iana.org/domains/root/db/scb.html +scb + +// schaeffler : Schaeffler Technologies AG & Co. KG +// https://www.iana.org/domains/root/db/schaeffler.html +schaeffler + +// schmidt : SCHMIDT GROUPE S.A.S. +// https://www.iana.org/domains/root/db/schmidt.html +schmidt + +// scholarships : Scholarships.com, LLC +// https://www.iana.org/domains/root/db/scholarships.html +scholarships + +// school : Binky Moon, LLC +// https://www.iana.org/domains/root/db/school.html +school + +// schule : Binky Moon, LLC +// https://www.iana.org/domains/root/db/schule.html +schule + +// schwarz : Schwarz Domains und Services GmbH & Co. KG +// https://www.iana.org/domains/root/db/schwarz.html +schwarz + +// science : dot Science Limited +// https://www.iana.org/domains/root/db/science.html +science + +// scot : Dot Scot Registry Limited +// https://www.iana.org/domains/root/db/scot.html +scot + +// search : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/search.html +search + +// seat : SEAT, S.A. (Sociedad Unipersonal) +// https://www.iana.org/domains/root/db/seat.html +seat + +// secure : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/secure.html +secure + +// security : XYZ.COM LLC +// https://www.iana.org/domains/root/db/security.html +security + +// seek : Seek Limited +// https://www.iana.org/domains/root/db/seek.html +seek + +// select : Registry Services, LLC +// https://www.iana.org/domains/root/db/select.html +select + +// sener : Sener Ingeniería y Sistemas, S.A. +// https://www.iana.org/domains/root/db/sener.html +sener + +// services : Binky Moon, LLC +// https://www.iana.org/domains/root/db/services.html +services + +// seven : Seven West Media Ltd +// https://www.iana.org/domains/root/db/seven.html +seven + +// sew : SEW-EURODRIVE GmbH & Co KG +// https://www.iana.org/domains/root/db/sew.html +sew + +// sex : ICM Registry SX LLC +// https://www.iana.org/domains/root/db/sex.html +sex + +// sexy : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/sexy.html +sexy + +// sfr : Societe Francaise du Radiotelephone - SFR +// https://www.iana.org/domains/root/db/sfr.html +sfr + +// shangrila : Shangri‐La International Hotel Management Limited +// https://www.iana.org/domains/root/db/shangrila.html +shangrila + +// sharp : Sharp Corporation +// https://www.iana.org/domains/root/db/sharp.html +sharp + +// shell : Shell Information Technology International Inc +// https://www.iana.org/domains/root/db/shell.html +shell + +// shia +// https://www.iana.org/domains/root/db/shia.html +shia + +// shiksha : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/shiksha.html +shiksha + +// shoes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/shoes.html +shoes + +// shop : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/shop.html +shop + +// shopping : Binky Moon, LLC +// https://www.iana.org/domains/root/db/shopping.html +shopping + +// shouji : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/shouji.html +shouji + +// show : Binky Moon, LLC +// https://www.iana.org/domains/root/db/show.html +show + +// silk : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/silk.html +silk + +// sina : Sina Corporation +// https://www.iana.org/domains/root/db/sina.html +sina + +// singles : Binky Moon, LLC +// https://www.iana.org/domains/root/db/singles.html +singles + +// site : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/site.html +site + +// ski : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/ski.html +ski + +// skin : XYZ.COM LLC +// https://www.iana.org/domains/root/db/skin.html +skin + +// sky : Sky UK Limited +// https://www.iana.org/domains/root/db/sky.html +sky + +// skype : Microsoft Corporation +// https://www.iana.org/domains/root/db/skype.html +skype + +// sling : DISH Technologies L.L.C. +// https://www.iana.org/domains/root/db/sling.html +sling + +// smart : Smart Communications, Inc. (SMART) +// https://www.iana.org/domains/root/db/smart.html +smart + +// smile : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/smile.html +smile + +// sncf : Société Nationale SNCF +// https://www.iana.org/domains/root/db/sncf.html +sncf + +// soccer : Binky Moon, LLC +// https://www.iana.org/domains/root/db/soccer.html +soccer + +// social : Dog Beach, LLC +// https://www.iana.org/domains/root/db/social.html +social + +// softbank : SoftBank Group Corp. +// https://www.iana.org/domains/root/db/softbank.html +softbank + +// software : Dog Beach, LLC +// https://www.iana.org/domains/root/db/software.html +software + +// sohu : Sohu.com Limited +// https://www.iana.org/domains/root/db/sohu.html +sohu + +// solar : Binky Moon, LLC +// https://www.iana.org/domains/root/db/solar.html +solar + +// solutions : Binky Moon, LLC +// https://www.iana.org/domains/root/db/solutions.html +solutions + +// song : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/song.html +song + +// sony : Sony Corporation +// https://www.iana.org/domains/root/db/sony.html +sony + +// soy : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/soy.html +soy + +// spa : Asia Spa and Wellness Promotion Council Limited +// https://www.iana.org/domains/root/db/spa.html +spa + +// space : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/space.html +space + +// sport : SportAccord +// https://www.iana.org/domains/root/db/sport.html +sport + +// spot : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/spot.html +spot + +// srl : InterNetX, Corp +// https://www.iana.org/domains/root/db/srl.html +srl + +// stada : STADA Arzneimittel AG +// https://www.iana.org/domains/root/db/stada.html +stada + +// staples : Staples, Inc. +// https://www.iana.org/domains/root/db/staples.html +staples + +// star : Star India Private Limited +// https://www.iana.org/domains/root/db/star.html +star + +// statebank : STATE BANK OF INDIA +// https://www.iana.org/domains/root/db/statebank.html +statebank + +// statefarm : State Farm Mutual Automobile Insurance Company +// https://www.iana.org/domains/root/db/statefarm.html +statefarm + +// stc : Saudi Telecom Company +// https://www.iana.org/domains/root/db/stc.html +stc + +// stcgroup : Saudi Telecom Company +// https://www.iana.org/domains/root/db/stcgroup.html +stcgroup + +// stockholm : Stockholms kommun +// https://www.iana.org/domains/root/db/stockholm.html +stockholm + +// storage : XYZ.COM LLC +// https://www.iana.org/domains/root/db/storage.html +storage + +// store : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/store.html +store + +// stream : dot Stream Limited +// https://www.iana.org/domains/root/db/stream.html +stream + +// studio : Dog Beach, LLC +// https://www.iana.org/domains/root/db/studio.html +studio + +// study : Registry Services, LLC +// https://www.iana.org/domains/root/db/study.html +study + +// style : Binky Moon, LLC +// https://www.iana.org/domains/root/db/style.html +style + +// sucks : Vox Populi Registry Ltd. +// https://www.iana.org/domains/root/db/sucks.html +sucks + +// supplies : Binky Moon, LLC +// https://www.iana.org/domains/root/db/supplies.html +supplies + +// supply : Binky Moon, LLC +// https://www.iana.org/domains/root/db/supply.html +supply + +// support : Binky Moon, LLC +// https://www.iana.org/domains/root/db/support.html +support + +// surf : Registry Services, LLC +// https://www.iana.org/domains/root/db/surf.html +surf + +// surgery : Binky Moon, LLC +// https://www.iana.org/domains/root/db/surgery.html +surgery + +// suzuki : SUZUKI MOTOR CORPORATION +// https://www.iana.org/domains/root/db/suzuki.html +suzuki + +// swatch : The Swatch Group Ltd +// https://www.iana.org/domains/root/db/swatch.html +swatch + +// swiss : Swiss Confederation +// https://www.iana.org/domains/root/db/swiss.html +swiss + +// sydney : State of New South Wales, Department of Premier and Cabinet +// https://www.iana.org/domains/root/db/sydney.html +sydney + +// systems : Binky Moon, LLC +// https://www.iana.org/domains/root/db/systems.html +systems + +// tab : Tabcorp Holdings Limited +// https://www.iana.org/domains/root/db/tab.html +tab + +// taipei : Taipei City Government +// https://www.iana.org/domains/root/db/taipei.html +taipei + +// talk : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/talk.html +talk + +// taobao : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/taobao.html +taobao + +// target : Target Domain Holdings, LLC +// https://www.iana.org/domains/root/db/target.html +target + +// tatamotors : Tata Motors Ltd +// https://www.iana.org/domains/root/db/tatamotors.html +tatamotors + +// tatar : Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" +// https://www.iana.org/domains/root/db/tatar.html +tatar + +// tattoo : Registry Services, LLC +// https://www.iana.org/domains/root/db/tattoo.html +tattoo + +// tax : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tax.html +tax + +// taxi : Binky Moon, LLC +// https://www.iana.org/domains/root/db/taxi.html +taxi + +// tci +// https://www.iana.org/domains/root/db/tci.html +tci + +// tdk : TDK Corporation +// https://www.iana.org/domains/root/db/tdk.html +tdk + +// team : Binky Moon, LLC +// https://www.iana.org/domains/root/db/team.html +team + +// tech : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/tech.html +tech + +// technology : Binky Moon, LLC +// https://www.iana.org/domains/root/db/technology.html +technology + +// temasek : Temasek Holdings (Private) Limited +// https://www.iana.org/domains/root/db/temasek.html +temasek + +// tennis : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tennis.html +tennis + +// teva : Teva Pharmaceutical Industries Limited +// https://www.iana.org/domains/root/db/teva.html +teva + +// thd : Home Depot Product Authority, LLC +// https://www.iana.org/domains/root/db/thd.html +thd + +// theater : Binky Moon, LLC +// https://www.iana.org/domains/root/db/theater.html +theater + +// theatre : XYZ.COM LLC +// https://www.iana.org/domains/root/db/theatre.html +theatre + +// tiaa : Teachers Insurance and Annuity Association of America +// https://www.iana.org/domains/root/db/tiaa.html +tiaa + +// tickets : XYZ.COM LLC +// https://www.iana.org/domains/root/db/tickets.html +tickets + +// tienda : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tienda.html +tienda + +// tips : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tips.html +tips + +// tires : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tires.html +tires + +// tirol : punkt Tirol GmbH +// https://www.iana.org/domains/root/db/tirol.html +tirol + +// tjmaxx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tjmaxx.html +tjmaxx + +// tjx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tjx.html +tjx + +// tkmaxx : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/tkmaxx.html +tkmaxx + +// tmall : Alibaba Group Holding Limited +// https://www.iana.org/domains/root/db/tmall.html +tmall + +// today : Binky Moon, LLC +// https://www.iana.org/domains/root/db/today.html +today + +// tokyo : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/tokyo.html +tokyo + +// tools : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tools.html +tools + +// top : .TOP Registry +// https://www.iana.org/domains/root/db/top.html +top + +// toray : Toray Industries, Inc. +// https://www.iana.org/domains/root/db/toray.html +toray + +// toshiba : TOSHIBA Corporation +// https://www.iana.org/domains/root/db/toshiba.html +toshiba + +// total : TotalEnergies SE +// https://www.iana.org/domains/root/db/total.html +total + +// tours : Binky Moon, LLC +// https://www.iana.org/domains/root/db/tours.html +tours + +// town : Binky Moon, LLC +// https://www.iana.org/domains/root/db/town.html +town + +// toyota : TOYOTA MOTOR CORPORATION +// https://www.iana.org/domains/root/db/toyota.html +toyota + +// toys : Binky Moon, LLC +// https://www.iana.org/domains/root/db/toys.html +toys + +// trade : Elite Registry Limited +// https://www.iana.org/domains/root/db/trade.html +trade + +// trading : Dog Beach, LLC +// https://www.iana.org/domains/root/db/trading.html +trading + +// training : Binky Moon, LLC +// https://www.iana.org/domains/root/db/training.html +training + +// travel : Dog Beach, LLC +// https://www.iana.org/domains/root/db/travel.html +travel + +// travelers : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/travelers.html +travelers + +// travelersinsurance : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/travelersinsurance.html +travelersinsurance + +// trust : Internet Naming Company LLC +// https://www.iana.org/domains/root/db/trust.html +trust + +// trv : Travelers TLD, LLC +// https://www.iana.org/domains/root/db/trv.html +trv + +// tube : Latin American Telecom LLC +// https://www.iana.org/domains/root/db/tube.html +tube + +// tui : TUI AG +// https://www.iana.org/domains/root/db/tui.html +tui + +// tunes : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/tunes.html +tunes + +// tushu : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/tushu.html +tushu + +// tvs : T V SUNDRAM IYENGAR & SONS LIMITED +// https://www.iana.org/domains/root/db/tvs.html +tvs + +// ubank : National Australia Bank Limited +// https://www.iana.org/domains/root/db/ubank.html +ubank + +// ubs : UBS AG +// https://www.iana.org/domains/root/db/ubs.html +ubs + +// unicom : China United Network Communications Corporation Limited +// https://www.iana.org/domains/root/db/unicom.html +unicom + +// university : Binky Moon, LLC +// https://www.iana.org/domains/root/db/university.html +university + +// uno : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/uno.html +uno + +// uol : UBN INTERNET LTDA. +// https://www.iana.org/domains/root/db/uol.html +uol + +// ups : UPS Market Driver, Inc. +// https://www.iana.org/domains/root/db/ups.html +ups + +// vacations : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vacations.html +vacations + +// vana : D3 Registry LLC +// https://www.iana.org/domains/root/db/vana.html +vana + +// vanguard : The Vanguard Group, Inc. +// https://www.iana.org/domains/root/db/vanguard.html +vanguard + +// vegas : Dot Vegas, Inc. +// https://www.iana.org/domains/root/db/vegas.html +vegas + +// ventures : Binky Moon, LLC +// https://www.iana.org/domains/root/db/ventures.html +ventures + +// verisign : VeriSign, Inc. +// https://www.iana.org/domains/root/db/verisign.html +verisign + +// versicherung : tldbox GmbH +// https://www.iana.org/domains/root/db/versicherung.html +versicherung + +// vet : Dog Beach, LLC +// https://www.iana.org/domains/root/db/vet.html +vet + +// viajes : Binky Moon, LLC +// https://www.iana.org/domains/root/db/viajes.html +viajes + +// video : Dog Beach, LLC +// https://www.iana.org/domains/root/db/video.html +video + +// vig : VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe +// https://www.iana.org/domains/root/db/vig.html +vig + +// viking : Viking River Cruises (Bermuda) Ltd. +// https://www.iana.org/domains/root/db/viking.html +viking + +// villas : Binky Moon, LLC +// https://www.iana.org/domains/root/db/villas.html +villas + +// vin : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vin.html +vin + +// vip : Registry Services, LLC +// https://www.iana.org/domains/root/db/vip.html +vip + +// virgin : Virgin Enterprises Limited +// https://www.iana.org/domains/root/db/virgin.html +virgin + +// visa : Visa Worldwide Pte. Limited +// https://www.iana.org/domains/root/db/visa.html +visa + +// vision : Binky Moon, LLC +// https://www.iana.org/domains/root/db/vision.html +vision + +// viva : Saudi Telecom Company +// https://www.iana.org/domains/root/db/viva.html +viva + +// vivo : Telefonica Brasil S.A. +// https://www.iana.org/domains/root/db/vivo.html +vivo + +// vlaanderen : DNS.be vzw +// https://www.iana.org/domains/root/db/vlaanderen.html +vlaanderen + +// vodka : Registry Services, LLC +// https://www.iana.org/domains/root/db/vodka.html +vodka + +// volvo : Volvo Holding Sverige Aktiebolag +// https://www.iana.org/domains/root/db/volvo.html +volvo + +// vote : Monolith Registry LLC +// https://www.iana.org/domains/root/db/vote.html +vote + +// voting : Valuetainment Corp. +// https://www.iana.org/domains/root/db/voting.html +voting + +// voto : Monolith Registry LLC +// https://www.iana.org/domains/root/db/voto.html +voto + +// voyage : Binky Moon, LLC +// https://www.iana.org/domains/root/db/voyage.html +voyage + +// wales : Nominet UK +// https://www.iana.org/domains/root/db/wales.html +wales + +// walmart : Wal-Mart Stores, Inc. +// https://www.iana.org/domains/root/db/walmart.html +walmart + +// walter : Sandvik AB +// https://www.iana.org/domains/root/db/walter.html +walter + +// wang : Zodiac Wang Limited +// https://www.iana.org/domains/root/db/wang.html +wang + +// wanggou : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/wanggou.html +wanggou + +// watch : Binky Moon, LLC +// https://www.iana.org/domains/root/db/watch.html +watch + +// watches : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/watches.html +watches + +// weather : International Business Machines Corporation +// https://www.iana.org/domains/root/db/weather.html +weather + +// weatherchannel : The Weather Company, LLC +// https://www.iana.org/domains/root/db/weatherchannel.html +weatherchannel + +// webcam : dot Webcam Limited +// https://www.iana.org/domains/root/db/webcam.html +webcam + +// weber : Saint-Gobain Weber SA +// https://www.iana.org/domains/root/db/weber.html +weber + +// website : Radix Technologies Inc SEZC +// https://www.iana.org/domains/root/db/website.html +website + +// wed +// https://www.iana.org/domains/root/db/wed.html +wed + +// wedding : Registry Services, LLC +// https://www.iana.org/domains/root/db/wedding.html +wedding + +// weibo : Sina Corporation +// https://www.iana.org/domains/root/db/weibo.html +weibo + +// weir : Weir Group IP Limited +// https://www.iana.org/domains/root/db/weir.html +weir + +// whoswho : Who's Who Registry +// https://www.iana.org/domains/root/db/whoswho.html +whoswho + +// wien : punkt.wien GmbH +// https://www.iana.org/domains/root/db/wien.html +wien + +// wiki : Registry Services, LLC +// https://www.iana.org/domains/root/db/wiki.html +wiki + +// williamhill : William Hill Organization Limited +// https://www.iana.org/domains/root/db/williamhill.html +williamhill + +// win : First Registry Limited +// https://www.iana.org/domains/root/db/win.html +win + +// windows : Microsoft Corporation +// https://www.iana.org/domains/root/db/windows.html +windows + +// wine : Binky Moon, LLC +// https://www.iana.org/domains/root/db/wine.html +wine + +// winners : The TJX Companies, Inc. +// https://www.iana.org/domains/root/db/winners.html +winners + +// wme : William Morris Endeavor Entertainment, LLC +// https://www.iana.org/domains/root/db/wme.html +wme + +// wolterskluwer : Wolters Kluwer N.V. +// https://www.iana.org/domains/root/db/wolterskluwer.html +wolterskluwer + +// woodside : Woodside Petroleum Limited +// https://www.iana.org/domains/root/db/woodside.html +woodside + +// work : Registry Services, LLC +// https://www.iana.org/domains/root/db/work.html +work + +// works : Binky Moon, LLC +// https://www.iana.org/domains/root/db/works.html +works + +// world : Binky Moon, LLC +// https://www.iana.org/domains/root/db/world.html +world + +// wow : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/wow.html +wow + +// wtc : World Trade Centers Association, Inc. +// https://www.iana.org/domains/root/db/wtc.html +wtc + +// wtf : Binky Moon, LLC +// https://www.iana.org/domains/root/db/wtf.html +wtf + +// xbox : Microsoft Corporation +// https://www.iana.org/domains/root/db/xbox.html +xbox + +// xerox : Xerox DNHC LLC +// https://www.iana.org/domains/root/db/xerox.html +xerox + +// xihuan : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/xihuan.html +xihuan + +// xin : Elegant Leader Limited +// https://www.iana.org/domains/root/db/xin.html +xin + +// xn--11b4c3d : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--11b4c3d.html +कॉम + +// xn--1ck2e1b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--1ck2e1b.html +セール + +// xn--1qqw23a : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--1qqw23a.html +佛山 + +// xn--30rr7y : Excellent First Limited +// https://www.iana.org/domains/root/db/xn--30rr7y.html +慈善 + +// xn--3bst00m : Eagle Horizon Limited +// https://www.iana.org/domains/root/db/xn--3bst00m.html +集团 + +// xn--3ds443g : Beijing TLD Registry Technology Limited +// https://www.iana.org/domains/root/db/xn--3ds443g.html +在线 + +// xn--3pxu8k : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--3pxu8k.html +点看 + +// xn--42c2d9a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--42c2d9a.html +คอม + +// xn--45q11c : Zodiac Gemini Ltd +// https://www.iana.org/domains/root/db/xn--45q11c.html +八卦 + +// xn--4gbrim : Helium TLDs Ltd +// https://www.iana.org/domains/root/db/xn--4gbrim.html +موقع + +// xn--55qw42g : China Organizational Name Administration Center +// https://www.iana.org/domains/root/db/xn--55qw42g.html +公益 + +// xn--55qx5d : China Internet Network Information Center (CNNIC) +// https://www.iana.org/domains/root/db/xn--55qx5d.html +公司 + +// xn--5su34j936bgsg : Shangri‐La International Hotel Management Limited +// https://www.iana.org/domains/root/db/xn--5su34j936bgsg.html +香格里拉 + +// xn--5tzm5g : Global Website TLD Asia Limited +// https://www.iana.org/domains/root/db/xn--5tzm5g.html +网站 + +// xn--6frz82g : Identity Digital Domains Limited +// https://www.iana.org/domains/root/db/xn--6frz82g.html +移动 + +// xn--6qq986b3xl : Tycoon Treasure Limited +// https://www.iana.org/domains/root/db/xn--6qq986b3xl.html +我爱你 + +// xn--80adxhks : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) +// https://www.iana.org/domains/root/db/xn--80adxhks.html +москва + +// xn--80aqecdr1a : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--80aqecdr1a.html +католик + +// xn--80asehdb : CORE Association +// https://www.iana.org/domains/root/db/xn--80asehdb.html +онлайн + +// xn--80aswg : CORE Association +// https://www.iana.org/domains/root/db/xn--80aswg.html +сайт + +// xn--8y0a063a : China United Network Communications Corporation Limited +// https://www.iana.org/domains/root/db/xn--8y0a063a.html +联通 + +// xn--9dbq2a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--9dbq2a.html +קום + +// xn--9et52u : RISE VICTORY LIMITED +// https://www.iana.org/domains/root/db/xn--9et52u.html +时尚 + +// xn--9krt00a : Sina Corporation +// https://www.iana.org/domains/root/db/xn--9krt00a.html +微博 + +// xn--b4w605ferd : Temasek Holdings (Private) Limited +// https://www.iana.org/domains/root/db/xn--b4w605ferd.html +淡马锡 + +// xn--bck1b9a5dre4c : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--bck1b9a5dre4c.html +ファッション + +// xn--c1avg : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--c1avg.html +орг + +// xn--c2br7g : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--c2br7g.html +नेट + +// xn--cck2b3b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--cck2b3b.html +ストア + +// xn--cckwcxetd : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--cckwcxetd.html +アマゾン + +// xn--cg4bki : SAMSUNG SDS CO., LTD +// https://www.iana.org/domains/root/db/xn--cg4bki.html +삼성 + +// xn--czr694b : Internet DotTrademark Organisation Limited +// https://www.iana.org/domains/root/db/xn--czr694b.html +商标 + +// xn--czrs0t : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--czrs0t.html +商店 + +// xn--czru2d : Zodiac Aquarius Limited +// https://www.iana.org/domains/root/db/xn--czru2d.html +商城 + +// xn--d1acj3b : The Foundation for Network Initiatives “The Smart Internet” +// https://www.iana.org/domains/root/db/xn--d1acj3b.html +дети + +// xn--eckvdtc9d : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--eckvdtc9d.html +ポイント + +// xn--efvy88h : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--efvy88h.html +新闻 + +// xn--fct429k : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--fct429k.html +家電 + +// xn--fhbei : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--fhbei.html +كوم + +// xn--fiq228c5hs : TLD REGISTRY LIMITED OY +// https://www.iana.org/domains/root/db/xn--fiq228c5hs.html +中文网 + +// xn--fiq64b : CITIC Group Corporation +// https://www.iana.org/domains/root/db/xn--fiq64b.html +中信 + +// xn--fjq720a : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--fjq720a.html +娱乐 + +// xn--flw351e : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--flw351e.html +谷歌 + +// xn--fzys8d69uvgm : PCCW Enterprises Limited +// https://www.iana.org/domains/root/db/xn--fzys8d69uvgm.html +電訊盈科 + +// xn--g2xx48c : Nawang Heli(Xiamen) Network Service Co., LTD. +// https://www.iana.org/domains/root/db/xn--g2xx48c.html +购物 + +// xn--gckr3f0f : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--gckr3f0f.html +クラウド + +// xn--gk3at1e : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--gk3at1e.html +通販 + +// xn--hxt814e : Zodiac Taurus Limited +// https://www.iana.org/domains/root/db/xn--hxt814e.html +网店 + +// xn--i1b6b1a6a2e : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--i1b6b1a6a2e.html +संगठन + +// xn--imr513n : Internet DotTrademark Organisation Limited +// https://www.iana.org/domains/root/db/xn--imr513n.html +餐厅 + +// xn--io0a7i : China Internet Network Information Center (CNNIC) +// https://www.iana.org/domains/root/db/xn--io0a7i.html +网络 + +// xn--j1aef : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--j1aef.html +ком + +// xn--jlq480n2rg : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--jlq480n2rg.html +亚马逊 + +// xn--jvr189m : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--jvr189m.html +食品 + +// xn--kcrx77d1x4a : Koninklijke Philips N.V. +// https://www.iana.org/domains/root/db/xn--kcrx77d1x4a.html +飞利浦 + +// xn--kput3i : Beijing RITT-Net Technology Development Co., Ltd +// https://www.iana.org/domains/root/db/xn--kput3i.html +手机 + +// xn--mgba3a3ejt : Aramco Services Company +// https://www.iana.org/domains/root/db/xn--mgba3a3ejt.html +ارامكو + +// xn--mgba7c0bbn0a : Competrol (Luxembourg) Sarl +// https://www.iana.org/domains/root/db/xn--mgba7c0bbn0a.html +العليان + +// xn--mgbab2bd : CORE Association +// https://www.iana.org/domains/root/db/xn--mgbab2bd.html +بازار + +// xn--mgbca7dzdo : Abu Dhabi Systems and Information Centre +// https://www.iana.org/domains/root/db/xn--mgbca7dzdo.html +ابوظبي + +// xn--mgbi4ecexp : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--mgbi4ecexp.html +كاثوليك + +// xn--mgbt3dhd +// https://www.iana.org/domains/root/db/xn--mgbt3dhd.html +همراه + +// xn--mk1bu44c : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--mk1bu44c.html +닷컴 + +// xn--mxtq1m : Net-Chinese Co., Ltd. +// https://www.iana.org/domains/root/db/xn--mxtq1m.html +政府 + +// xn--ngbc5azd : International Domain Registry Pty. Ltd. +// https://www.iana.org/domains/root/db/xn--ngbc5azd.html +شبكة + +// xn--ngbe9e0a : Kuwait Finance House +// https://www.iana.org/domains/root/db/xn--ngbe9e0a.html +بيتك + +// xn--ngbrx : League of Arab States +// https://www.iana.org/domains/root/db/xn--ngbrx.html +عرب + +// xn--nqv7f : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--nqv7f.html +机构 + +// xn--nqv7fs00ema : Public Interest Registry +// https://www.iana.org/domains/root/db/xn--nqv7fs00ema.html +组织机构 + +// xn--nyqy26a : Stable Tone Limited +// https://www.iana.org/domains/root/db/xn--nyqy26a.html +健康 + +// xn--otu796d : Jiang Yu Liang Cai Technology Company Limited +// https://www.iana.org/domains/root/db/xn--otu796d.html +招聘 + +// xn--p1acf : Rusnames Limited +// https://www.iana.org/domains/root/db/xn--p1acf.html +рус + +// xn--pssy2u : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--pssy2u.html +大拿 + +// xn--q9jyb4c : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--q9jyb4c.html +みんな + +// xn--qcka1pmc : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/xn--qcka1pmc.html +グーグル + +// xn--rhqv96g : Stable Tone Limited +// https://www.iana.org/domains/root/db/xn--rhqv96g.html +世界 + +// xn--rovu88b : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/xn--rovu88b.html +書籍 + +// xn--ses554g : KNET Co., Ltd. +// https://www.iana.org/domains/root/db/xn--ses554g.html +网址 + +// xn--t60b56a : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--t60b56a.html +닷넷 + +// xn--tckwe : VeriSign Sarl +// https://www.iana.org/domains/root/db/xn--tckwe.html +コム + +// xn--tiq49xqyj : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) +// https://www.iana.org/domains/root/db/xn--tiq49xqyj.html +天主教 + +// xn--unup4y : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--unup4y.html +游戏 + +// xn--vermgensberater-ctb : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/xn--vermgensberater-ctb.html +vermögensberater + +// xn--vermgensberatung-pwb : Deutsche Vermögensberatung Aktiengesellschaft DVAG +// https://www.iana.org/domains/root/db/xn--vermgensberatung-pwb.html +vermögensberatung + +// xn--vhquv : Binky Moon, LLC +// https://www.iana.org/domains/root/db/xn--vhquv.html +企业 + +// xn--vuq861b : Beijing Tele-info Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--vuq861b.html +信息 + +// xn--w4r85el8fhu5dnra : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/xn--w4r85el8fhu5dnra.html +嘉里大酒店 + +// xn--w4rs40l : Kerry Trading Co. Limited +// https://www.iana.org/domains/root/db/xn--w4rs40l.html +嘉里 + +// xn--xhq521b : Guangzhou YU Wei Information Technology Co., Ltd. +// https://www.iana.org/domains/root/db/xn--xhq521b.html +广东 + +// xn--zfr164b : China Organizational Name Administration Center +// https://www.iana.org/domains/root/db/xn--zfr164b.html +政务 + +// xyz : XYZ.COM LLC +// https://www.iana.org/domains/root/db/xyz.html +xyz + +// yachts : XYZ.COM LLC +// https://www.iana.org/domains/root/db/yachts.html +yachts + +// yahoo : Yahoo Inc. +// https://www.iana.org/domains/root/db/yahoo.html +yahoo + +// yamaxun : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/yamaxun.html +yamaxun + +// yandex : YANDEX, LLC +// https://www.iana.org/domains/root/db/yandex.html +yandex + +// yodobashi : YODOBASHI CAMERA CO.,LTD. +// https://www.iana.org/domains/root/db/yodobashi.html +yodobashi + +// yoga : Registry Services, LLC +// https://www.iana.org/domains/root/db/yoga.html +yoga + +// yokohama : GMO Registry, Inc. +// https://www.iana.org/domains/root/db/yokohama.html +yokohama + +// you : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/you.html +you + +// youtube : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/youtube.html +youtube + +// yun : Beijing Qihu Keji Co., Ltd. +// https://www.iana.org/domains/root/db/yun.html +yun + +// zappos : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/zappos.html +zappos + +// zara : Industria de Diseño Textil, S.A. (INDITEX, S.A.) +// https://www.iana.org/domains/root/db/zara.html +zara + +// zero : Amazon Registry Services, Inc. +// https://www.iana.org/domains/root/db/zero.html +zero + +// zip : Charleston Road Registry Inc. +// https://www.iana.org/domains/root/db/zip.html +zip + +// zone : Binky Moon, LLC +// https://www.iana.org/domains/root/db/zone.html +zone + +// zuerich : Kanton Zürich (Canton of Zurich) +// https://www.iana.org/domains/root/db/zuerich.html +zuerich + +// ===END ICANN DOMAINS=== + +// ===BEGIN PRIVATE DOMAINS=== + +// (Note: these are in alphabetical order by company name) + +// .KRD : https://nic.krd +co.krd +edu.krd + +// .pl domains (grandfathered) +art.pl +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// 12CHARS : https://12chars.com +// Submitted by Kenny Niehage +12chars.dev +12chars.it +12chars.pro + +// 1GB LLC : https://www.1gb.ua/ +// Submitted by 1GB LLC +cc.ua +inf.ua +ltd.ua + +// 611 blockchain domain name system : https://sixone.one/ +611.to + +// A2 Hosting +// Submitted by Tyler Hall +a2hosted.com +cpserver.com + +// Acorn Labs : https://acorn.io +// Submitted by Craig Jellick +*.on-acorn.io + +// ActiveTrail : https://www.activetrail.biz/ +// Submitted by Ofer Kalaora +activetrail.biz + +// Adaptable.io : https://adaptable.io +// Submitted by Mark Terrel +adaptable.app + +// addr.tools : https://addr.tools/ +// Submitted by Brian Shea +myaddr.dev +myaddr.io +dyn.addr.tools +myaddr.tools + +// Adobe : https://www.adobe.com/ +// Submitted by Ian Boston and Lars Trieloff +adobeaemcloud.com +*.dev.adobeaemcloud.com +aem.live +hlx.live +adobeaemcloud.net +aem.network +aem.page +hlx.page +aem.reviews + +// Adobe Developer Platform : https://developer.adobe.com +// Submitted by Jesse MacFadyen +adobeio-static.net +adobeioruntime.net + +// Africa.com Web Solutions Ltd : https://registry.africa.com +// Submitted by Gavin Brown +africa.com + +// Agnat sp. z o.o. : https://domena.pl +// Submitted by Przemyslaw Plewa +beep.pl + +// Aiven : https://aiven.io/ +// Submitted by Aiven Security Team +aiven.app +aivencloud.com + +// Akamai : https://www.akamai.com/ +// Submitted by Akamai Team +akadns.net +akamai.net +akamai-staging.net +akamaiedge.net +akamaiedge-staging.net +akamaihd.net +akamaihd-staging.net +akamaiorigin.net +akamaiorigin-staging.net +akamaized.net +akamaized-staging.net +edgekey.net +edgekey-staging.net +edgesuite.net +edgesuite-staging.net + +// alboto.ca : http://alboto.ca +// Submitted by Anton Avramov +barsy.ca + +// Alces Software Ltd : http://alces-software.com +// Submitted by Mark J. Titorenko +*.compute.estate +*.alces.network + +// Alibaba Cloud API Gateway +// Submitted by Alibaba Cloud Security +alibabacloudcs.com + +// all-inkl.com : https://all-inkl.com +// Submitted by Werner Kaltofen +kasserver.com + +// Altervista : https://www.altervista.org +// Submitted by Carlo Cannas +altervista.org + +// alwaysdata : https://www.alwaysdata.com +// Submitted by Cyril +alwaysdata.net + +// Amaze Software : https://amaze.co +// Submitted by Domain Admin +myamaze.net + +// Amazon : https://www.amazon.com/ +// Submitted by AWS Security +// Subsections of Amazon/subsidiaries will appear until "concludes" tag + +// Amazon API Gateway +// Submitted by AWS Security +// Reference: 6a4f5a95-8c7d-4077-a7af-9cf1abec0a53 +execute-api.cn-north-1.amazonaws.com.cn +execute-api.cn-northwest-1.amazonaws.com.cn +execute-api.af-south-1.amazonaws.com +execute-api.ap-east-1.amazonaws.com +execute-api.ap-northeast-1.amazonaws.com +execute-api.ap-northeast-2.amazonaws.com +execute-api.ap-northeast-3.amazonaws.com +execute-api.ap-south-1.amazonaws.com +execute-api.ap-south-2.amazonaws.com +execute-api.ap-southeast-1.amazonaws.com +execute-api.ap-southeast-2.amazonaws.com +execute-api.ap-southeast-3.amazonaws.com +execute-api.ap-southeast-4.amazonaws.com +execute-api.ap-southeast-5.amazonaws.com +execute-api.ca-central-1.amazonaws.com +execute-api.ca-west-1.amazonaws.com +execute-api.eu-central-1.amazonaws.com +execute-api.eu-central-2.amazonaws.com +execute-api.eu-north-1.amazonaws.com +execute-api.eu-south-1.amazonaws.com +execute-api.eu-south-2.amazonaws.com +execute-api.eu-west-1.amazonaws.com +execute-api.eu-west-2.amazonaws.com +execute-api.eu-west-3.amazonaws.com +execute-api.il-central-1.amazonaws.com +execute-api.me-central-1.amazonaws.com +execute-api.me-south-1.amazonaws.com +execute-api.sa-east-1.amazonaws.com +execute-api.us-east-1.amazonaws.com +execute-api.us-east-2.amazonaws.com +execute-api.us-gov-east-1.amazonaws.com +execute-api.us-gov-west-1.amazonaws.com +execute-api.us-west-1.amazonaws.com +execute-api.us-west-2.amazonaws.com + +// Amazon CloudFront +// Submitted by Donavan Miller +// Reference: 54144616-fd49-4435-8535-19c6a601bdb3 +cloudfront.net + +// Amazon Cognito +// Submitted by AWS Security +// Reference: e7c02dc1-02f4-4a23-bde3-a8527c830127 +auth.af-south-1.amazoncognito.com +auth.ap-east-1.amazoncognito.com +auth.ap-northeast-1.amazoncognito.com +auth.ap-northeast-2.amazoncognito.com +auth.ap-northeast-3.amazoncognito.com +auth.ap-south-1.amazoncognito.com +auth.ap-south-2.amazoncognito.com +auth.ap-southeast-1.amazoncognito.com +auth.ap-southeast-2.amazoncognito.com +auth.ap-southeast-3.amazoncognito.com +auth.ap-southeast-4.amazoncognito.com +auth.ap-southeast-5.amazoncognito.com +auth.ap-southeast-7.amazoncognito.com +auth.ca-central-1.amazoncognito.com +auth.ca-west-1.amazoncognito.com +auth.eu-central-1.amazoncognito.com +auth.eu-central-2.amazoncognito.com +auth.eu-north-1.amazoncognito.com +auth.eu-south-1.amazoncognito.com +auth.eu-south-2.amazoncognito.com +auth.eu-west-1.amazoncognito.com +auth.eu-west-2.amazoncognito.com +auth.eu-west-3.amazoncognito.com +auth.il-central-1.amazoncognito.com +auth.me-central-1.amazoncognito.com +auth.me-south-1.amazoncognito.com +auth.mx-central-1.amazoncognito.com +auth.sa-east-1.amazoncognito.com +auth.us-east-1.amazoncognito.com +auth-fips.us-east-1.amazoncognito.com +auth.us-east-2.amazoncognito.com +auth-fips.us-east-2.amazoncognito.com +auth-fips.us-gov-east-1.amazoncognito.com +auth-fips.us-gov-west-1.amazoncognito.com +auth.us-west-1.amazoncognito.com +auth-fips.us-west-1.amazoncognito.com +auth.us-west-2.amazoncognito.com +auth-fips.us-west-2.amazoncognito.com + +// Amazon EC2 +// Submitted by Luke Wells +// Reference: 4c38fa71-58ac-4768-99e5-689c1767e537 +*.compute.amazonaws.com.cn +*.compute.amazonaws.com +*.compute-1.amazonaws.com +us-east-1.amazonaws.com + +// Amazon EMR +// Submitted by AWS Security +// Reference: 82f43f9f-bbb8-400e-8349-854f5a62f20d +emrappui-prod.cn-north-1.amazonaws.com.cn +emrnotebooks-prod.cn-north-1.amazonaws.com.cn +emrstudio-prod.cn-north-1.amazonaws.com.cn +emrappui-prod.cn-northwest-1.amazonaws.com.cn +emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn +emrstudio-prod.cn-northwest-1.amazonaws.com.cn +emrappui-prod.af-south-1.amazonaws.com +emrnotebooks-prod.af-south-1.amazonaws.com +emrstudio-prod.af-south-1.amazonaws.com +emrappui-prod.ap-east-1.amazonaws.com +emrnotebooks-prod.ap-east-1.amazonaws.com +emrstudio-prod.ap-east-1.amazonaws.com +emrappui-prod.ap-northeast-1.amazonaws.com +emrnotebooks-prod.ap-northeast-1.amazonaws.com +emrstudio-prod.ap-northeast-1.amazonaws.com +emrappui-prod.ap-northeast-2.amazonaws.com +emrnotebooks-prod.ap-northeast-2.amazonaws.com +emrstudio-prod.ap-northeast-2.amazonaws.com +emrappui-prod.ap-northeast-3.amazonaws.com +emrnotebooks-prod.ap-northeast-3.amazonaws.com +emrstudio-prod.ap-northeast-3.amazonaws.com +emrappui-prod.ap-south-1.amazonaws.com +emrnotebooks-prod.ap-south-1.amazonaws.com +emrstudio-prod.ap-south-1.amazonaws.com +emrappui-prod.ap-south-2.amazonaws.com +emrnotebooks-prod.ap-south-2.amazonaws.com +emrstudio-prod.ap-south-2.amazonaws.com +emrappui-prod.ap-southeast-1.amazonaws.com +emrnotebooks-prod.ap-southeast-1.amazonaws.com +emrstudio-prod.ap-southeast-1.amazonaws.com +emrappui-prod.ap-southeast-2.amazonaws.com +emrnotebooks-prod.ap-southeast-2.amazonaws.com +emrstudio-prod.ap-southeast-2.amazonaws.com +emrappui-prod.ap-southeast-3.amazonaws.com +emrnotebooks-prod.ap-southeast-3.amazonaws.com +emrstudio-prod.ap-southeast-3.amazonaws.com +emrappui-prod.ap-southeast-4.amazonaws.com +emrnotebooks-prod.ap-southeast-4.amazonaws.com +emrstudio-prod.ap-southeast-4.amazonaws.com +emrappui-prod.ca-central-1.amazonaws.com +emrnotebooks-prod.ca-central-1.amazonaws.com +emrstudio-prod.ca-central-1.amazonaws.com +emrappui-prod.ca-west-1.amazonaws.com +emrnotebooks-prod.ca-west-1.amazonaws.com +emrstudio-prod.ca-west-1.amazonaws.com +emrappui-prod.eu-central-1.amazonaws.com +emrnotebooks-prod.eu-central-1.amazonaws.com +emrstudio-prod.eu-central-1.amazonaws.com +emrappui-prod.eu-central-2.amazonaws.com +emrnotebooks-prod.eu-central-2.amazonaws.com +emrstudio-prod.eu-central-2.amazonaws.com +emrappui-prod.eu-north-1.amazonaws.com +emrnotebooks-prod.eu-north-1.amazonaws.com +emrstudio-prod.eu-north-1.amazonaws.com +emrappui-prod.eu-south-1.amazonaws.com +emrnotebooks-prod.eu-south-1.amazonaws.com +emrstudio-prod.eu-south-1.amazonaws.com +emrappui-prod.eu-south-2.amazonaws.com +emrnotebooks-prod.eu-south-2.amazonaws.com +emrstudio-prod.eu-south-2.amazonaws.com +emrappui-prod.eu-west-1.amazonaws.com +emrnotebooks-prod.eu-west-1.amazonaws.com +emrstudio-prod.eu-west-1.amazonaws.com +emrappui-prod.eu-west-2.amazonaws.com +emrnotebooks-prod.eu-west-2.amazonaws.com +emrstudio-prod.eu-west-2.amazonaws.com +emrappui-prod.eu-west-3.amazonaws.com +emrnotebooks-prod.eu-west-3.amazonaws.com +emrstudio-prod.eu-west-3.amazonaws.com +emrappui-prod.il-central-1.amazonaws.com +emrnotebooks-prod.il-central-1.amazonaws.com +emrstudio-prod.il-central-1.amazonaws.com +emrappui-prod.me-central-1.amazonaws.com +emrnotebooks-prod.me-central-1.amazonaws.com +emrstudio-prod.me-central-1.amazonaws.com +emrappui-prod.me-south-1.amazonaws.com +emrnotebooks-prod.me-south-1.amazonaws.com +emrstudio-prod.me-south-1.amazonaws.com +emrappui-prod.sa-east-1.amazonaws.com +emrnotebooks-prod.sa-east-1.amazonaws.com +emrstudio-prod.sa-east-1.amazonaws.com +emrappui-prod.us-east-1.amazonaws.com +emrnotebooks-prod.us-east-1.amazonaws.com +emrstudio-prod.us-east-1.amazonaws.com +emrappui-prod.us-east-2.amazonaws.com +emrnotebooks-prod.us-east-2.amazonaws.com +emrstudio-prod.us-east-2.amazonaws.com +emrappui-prod.us-gov-east-1.amazonaws.com +emrnotebooks-prod.us-gov-east-1.amazonaws.com +emrstudio-prod.us-gov-east-1.amazonaws.com +emrappui-prod.us-gov-west-1.amazonaws.com +emrnotebooks-prod.us-gov-west-1.amazonaws.com +emrstudio-prod.us-gov-west-1.amazonaws.com +emrappui-prod.us-west-1.amazonaws.com +emrnotebooks-prod.us-west-1.amazonaws.com +emrstudio-prod.us-west-1.amazonaws.com +emrappui-prod.us-west-2.amazonaws.com +emrnotebooks-prod.us-west-2.amazonaws.com +emrstudio-prod.us-west-2.amazonaws.com + +// Amazon Managed Workflows for Apache Airflow +// Submitted by AWS Security +// Reference: 2f697e23-58d6-4b97-be6b-77a26e811dad +*.airflow.af-south-1.on.aws +*.airflow.ap-east-1.on.aws +*.airflow.ap-northeast-1.on.aws +*.airflow.ap-northeast-2.on.aws +*.airflow.ap-northeast-3.on.aws +*.airflow.ap-south-1.on.aws +*.airflow.ap-south-2.on.aws +*.airflow.ap-southeast-1.on.aws +*.airflow.ap-southeast-2.on.aws +*.airflow.ap-southeast-3.on.aws +*.airflow.ap-southeast-4.on.aws +*.airflow.ap-southeast-5.on.aws +*.airflow.ca-central-1.on.aws +*.airflow.ca-west-1.on.aws +*.airflow.eu-central-1.on.aws +*.airflow.eu-central-2.on.aws +*.airflow.eu-north-1.on.aws +*.airflow.eu-south-1.on.aws +*.airflow.eu-south-2.on.aws +*.airflow.eu-west-1.on.aws +*.airflow.eu-west-2.on.aws +*.airflow.eu-west-3.on.aws +*.airflow.il-central-1.on.aws +*.airflow.me-central-1.on.aws +*.airflow.me-south-1.on.aws +*.airflow.sa-east-1.on.aws +*.airflow.us-east-1.on.aws +*.airflow.us-east-2.on.aws +*.airflow.us-west-1.on.aws +*.airflow.us-west-2.on.aws +*.cn-north-1.airflow.amazonaws.com.cn +*.cn-northwest-1.airflow.amazonaws.com.cn +*.airflow.cn-north-1.on.amazonwebservices.com.cn +*.airflow.cn-northwest-1.on.amazonwebservices.com.cn +*.af-south-1.airflow.amazonaws.com +*.ap-east-1.airflow.amazonaws.com +*.ap-northeast-1.airflow.amazonaws.com +*.ap-northeast-2.airflow.amazonaws.com +*.ap-northeast-3.airflow.amazonaws.com +*.ap-south-1.airflow.amazonaws.com +*.ap-south-2.airflow.amazonaws.com +*.ap-southeast-1.airflow.amazonaws.com +*.ap-southeast-2.airflow.amazonaws.com +*.ap-southeast-3.airflow.amazonaws.com +*.ap-southeast-4.airflow.amazonaws.com +*.ap-southeast-5.airflow.amazonaws.com +*.ca-central-1.airflow.amazonaws.com +*.ca-west-1.airflow.amazonaws.com +*.eu-central-1.airflow.amazonaws.com +*.eu-central-2.airflow.amazonaws.com +*.eu-north-1.airflow.amazonaws.com +*.eu-south-1.airflow.amazonaws.com +*.eu-south-2.airflow.amazonaws.com +*.eu-west-1.airflow.amazonaws.com +*.eu-west-2.airflow.amazonaws.com +*.eu-west-3.airflow.amazonaws.com +*.il-central-1.airflow.amazonaws.com +*.me-central-1.airflow.amazonaws.com +*.me-south-1.airflow.amazonaws.com +*.sa-east-1.airflow.amazonaws.com +*.us-east-1.airflow.amazonaws.com +*.us-east-2.airflow.amazonaws.com +*.us-west-1.airflow.amazonaws.com +*.us-west-2.airflow.amazonaws.com + +// Amazon S3 +// Submitted by AWS Security +// Reference: ada5c9df-55e1-4195-a1ce-732d6c81e357 +s3.dualstack.cn-north-1.amazonaws.com.cn +s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn +s3-website.dualstack.cn-north-1.amazonaws.com.cn +s3.cn-north-1.amazonaws.com.cn +s3-accesspoint.cn-north-1.amazonaws.com.cn +s3-deprecated.cn-north-1.amazonaws.com.cn +s3-object-lambda.cn-north-1.amazonaws.com.cn +s3-website.cn-north-1.amazonaws.com.cn +s3.dualstack.cn-northwest-1.amazonaws.com.cn +s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn +s3.cn-northwest-1.amazonaws.com.cn +s3-accesspoint.cn-northwest-1.amazonaws.com.cn +s3-object-lambda.cn-northwest-1.amazonaws.com.cn +s3-website.cn-northwest-1.amazonaws.com.cn +s3.dualstack.af-south-1.amazonaws.com +s3-accesspoint.dualstack.af-south-1.amazonaws.com +s3-website.dualstack.af-south-1.amazonaws.com +s3.af-south-1.amazonaws.com +s3-accesspoint.af-south-1.amazonaws.com +s3-object-lambda.af-south-1.amazonaws.com +s3-website.af-south-1.amazonaws.com +s3.dualstack.ap-east-1.amazonaws.com +s3-accesspoint.dualstack.ap-east-1.amazonaws.com +s3.ap-east-1.amazonaws.com +s3-accesspoint.ap-east-1.amazonaws.com +s3-object-lambda.ap-east-1.amazonaws.com +s3-website.ap-east-1.amazonaws.com +s3.dualstack.ap-northeast-1.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com +s3-website.dualstack.ap-northeast-1.amazonaws.com +s3.ap-northeast-1.amazonaws.com +s3-accesspoint.ap-northeast-1.amazonaws.com +s3-object-lambda.ap-northeast-1.amazonaws.com +s3-website.ap-northeast-1.amazonaws.com +s3.dualstack.ap-northeast-2.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com +s3-website.dualstack.ap-northeast-2.amazonaws.com +s3.ap-northeast-2.amazonaws.com +s3-accesspoint.ap-northeast-2.amazonaws.com +s3-object-lambda.ap-northeast-2.amazonaws.com +s3-website.ap-northeast-2.amazonaws.com +s3.dualstack.ap-northeast-3.amazonaws.com +s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com +s3-website.dualstack.ap-northeast-3.amazonaws.com +s3.ap-northeast-3.amazonaws.com +s3-accesspoint.ap-northeast-3.amazonaws.com +s3-object-lambda.ap-northeast-3.amazonaws.com +s3-website.ap-northeast-3.amazonaws.com +s3.dualstack.ap-south-1.amazonaws.com +s3-accesspoint.dualstack.ap-south-1.amazonaws.com +s3-website.dualstack.ap-south-1.amazonaws.com +s3.ap-south-1.amazonaws.com +s3-accesspoint.ap-south-1.amazonaws.com +s3-object-lambda.ap-south-1.amazonaws.com +s3-website.ap-south-1.amazonaws.com +s3.dualstack.ap-south-2.amazonaws.com +s3-accesspoint.dualstack.ap-south-2.amazonaws.com +s3-website.dualstack.ap-south-2.amazonaws.com +s3.ap-south-2.amazonaws.com +s3-accesspoint.ap-south-2.amazonaws.com +s3-object-lambda.ap-south-2.amazonaws.com +s3-website.ap-south-2.amazonaws.com +s3.dualstack.ap-southeast-1.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com +s3-website.dualstack.ap-southeast-1.amazonaws.com +s3.ap-southeast-1.amazonaws.com +s3-accesspoint.ap-southeast-1.amazonaws.com +s3-object-lambda.ap-southeast-1.amazonaws.com +s3-website.ap-southeast-1.amazonaws.com +s3.dualstack.ap-southeast-2.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com +s3-website.dualstack.ap-southeast-2.amazonaws.com +s3.ap-southeast-2.amazonaws.com +s3-accesspoint.ap-southeast-2.amazonaws.com +s3-object-lambda.ap-southeast-2.amazonaws.com +s3-website.ap-southeast-2.amazonaws.com +s3.dualstack.ap-southeast-3.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com +s3-website.dualstack.ap-southeast-3.amazonaws.com +s3.ap-southeast-3.amazonaws.com +s3-accesspoint.ap-southeast-3.amazonaws.com +s3-object-lambda.ap-southeast-3.amazonaws.com +s3-website.ap-southeast-3.amazonaws.com +s3.dualstack.ap-southeast-4.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com +s3-website.dualstack.ap-southeast-4.amazonaws.com +s3.ap-southeast-4.amazonaws.com +s3-accesspoint.ap-southeast-4.amazonaws.com +s3-object-lambda.ap-southeast-4.amazonaws.com +s3-website.ap-southeast-4.amazonaws.com +s3.dualstack.ap-southeast-5.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-5.amazonaws.com +s3-website.dualstack.ap-southeast-5.amazonaws.com +s3.ap-southeast-5.amazonaws.com +s3-accesspoint.ap-southeast-5.amazonaws.com +s3-deprecated.ap-southeast-5.amazonaws.com +s3-object-lambda.ap-southeast-5.amazonaws.com +s3-website.ap-southeast-5.amazonaws.com +s3.dualstack.ca-central-1.amazonaws.com +s3-accesspoint.dualstack.ca-central-1.amazonaws.com +s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com +s3-fips.dualstack.ca-central-1.amazonaws.com +s3-website.dualstack.ca-central-1.amazonaws.com +s3.ca-central-1.amazonaws.com +s3-accesspoint.ca-central-1.amazonaws.com +s3-accesspoint-fips.ca-central-1.amazonaws.com +s3-fips.ca-central-1.amazonaws.com +s3-object-lambda.ca-central-1.amazonaws.com +s3-website.ca-central-1.amazonaws.com +s3.dualstack.ca-west-1.amazonaws.com +s3-accesspoint.dualstack.ca-west-1.amazonaws.com +s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com +s3-fips.dualstack.ca-west-1.amazonaws.com +s3-website.dualstack.ca-west-1.amazonaws.com +s3.ca-west-1.amazonaws.com +s3-accesspoint.ca-west-1.amazonaws.com +s3-accesspoint-fips.ca-west-1.amazonaws.com +s3-fips.ca-west-1.amazonaws.com +s3-object-lambda.ca-west-1.amazonaws.com +s3-website.ca-west-1.amazonaws.com +s3.dualstack.eu-central-1.amazonaws.com +s3-accesspoint.dualstack.eu-central-1.amazonaws.com +s3-website.dualstack.eu-central-1.amazonaws.com +s3.eu-central-1.amazonaws.com +s3-accesspoint.eu-central-1.amazonaws.com +s3-object-lambda.eu-central-1.amazonaws.com +s3-website.eu-central-1.amazonaws.com +s3.dualstack.eu-central-2.amazonaws.com +s3-accesspoint.dualstack.eu-central-2.amazonaws.com +s3-website.dualstack.eu-central-2.amazonaws.com +s3.eu-central-2.amazonaws.com +s3-accesspoint.eu-central-2.amazonaws.com +s3-object-lambda.eu-central-2.amazonaws.com +s3-website.eu-central-2.amazonaws.com +s3.dualstack.eu-north-1.amazonaws.com +s3-accesspoint.dualstack.eu-north-1.amazonaws.com +s3.eu-north-1.amazonaws.com +s3-accesspoint.eu-north-1.amazonaws.com +s3-object-lambda.eu-north-1.amazonaws.com +s3-website.eu-north-1.amazonaws.com +s3.dualstack.eu-south-1.amazonaws.com +s3-accesspoint.dualstack.eu-south-1.amazonaws.com +s3-website.dualstack.eu-south-1.amazonaws.com +s3.eu-south-1.amazonaws.com +s3-accesspoint.eu-south-1.amazonaws.com +s3-object-lambda.eu-south-1.amazonaws.com +s3-website.eu-south-1.amazonaws.com +s3.dualstack.eu-south-2.amazonaws.com +s3-accesspoint.dualstack.eu-south-2.amazonaws.com +s3-website.dualstack.eu-south-2.amazonaws.com +s3.eu-south-2.amazonaws.com +s3-accesspoint.eu-south-2.amazonaws.com +s3-object-lambda.eu-south-2.amazonaws.com +s3-website.eu-south-2.amazonaws.com +s3.dualstack.eu-west-1.amazonaws.com +s3-accesspoint.dualstack.eu-west-1.amazonaws.com +s3-website.dualstack.eu-west-1.amazonaws.com +s3.eu-west-1.amazonaws.com +s3-accesspoint.eu-west-1.amazonaws.com +s3-deprecated.eu-west-1.amazonaws.com +s3-object-lambda.eu-west-1.amazonaws.com +s3-website.eu-west-1.amazonaws.com +s3.dualstack.eu-west-2.amazonaws.com +s3-accesspoint.dualstack.eu-west-2.amazonaws.com +s3.eu-west-2.amazonaws.com +s3-accesspoint.eu-west-2.amazonaws.com +s3-object-lambda.eu-west-2.amazonaws.com +s3-website.eu-west-2.amazonaws.com +s3.dualstack.eu-west-3.amazonaws.com +s3-accesspoint.dualstack.eu-west-3.amazonaws.com +s3-website.dualstack.eu-west-3.amazonaws.com +s3.eu-west-3.amazonaws.com +s3-accesspoint.eu-west-3.amazonaws.com +s3-object-lambda.eu-west-3.amazonaws.com +s3-website.eu-west-3.amazonaws.com +s3.dualstack.il-central-1.amazonaws.com +s3-accesspoint.dualstack.il-central-1.amazonaws.com +s3-website.dualstack.il-central-1.amazonaws.com +s3.il-central-1.amazonaws.com +s3-accesspoint.il-central-1.amazonaws.com +s3-object-lambda.il-central-1.amazonaws.com +s3-website.il-central-1.amazonaws.com +s3.dualstack.me-central-1.amazonaws.com +s3-accesspoint.dualstack.me-central-1.amazonaws.com +s3-website.dualstack.me-central-1.amazonaws.com +s3.me-central-1.amazonaws.com +s3-accesspoint.me-central-1.amazonaws.com +s3-object-lambda.me-central-1.amazonaws.com +s3-website.me-central-1.amazonaws.com +s3.dualstack.me-south-1.amazonaws.com +s3-accesspoint.dualstack.me-south-1.amazonaws.com +s3.me-south-1.amazonaws.com +s3-accesspoint.me-south-1.amazonaws.com +s3-object-lambda.me-south-1.amazonaws.com +s3-website.me-south-1.amazonaws.com +s3.amazonaws.com +s3-1.amazonaws.com +s3-ap-east-1.amazonaws.com +s3-ap-northeast-1.amazonaws.com +s3-ap-northeast-2.amazonaws.com +s3-ap-northeast-3.amazonaws.com +s3-ap-south-1.amazonaws.com +s3-ap-southeast-1.amazonaws.com +s3-ap-southeast-2.amazonaws.com +s3-ca-central-1.amazonaws.com +s3-eu-central-1.amazonaws.com +s3-eu-north-1.amazonaws.com +s3-eu-west-1.amazonaws.com +s3-eu-west-2.amazonaws.com +s3-eu-west-3.amazonaws.com +s3-external-1.amazonaws.com +s3-fips-us-gov-east-1.amazonaws.com +s3-fips-us-gov-west-1.amazonaws.com +mrap.accesspoint.s3-global.amazonaws.com +s3-me-south-1.amazonaws.com +s3-sa-east-1.amazonaws.com +s3-us-east-2.amazonaws.com +s3-us-gov-east-1.amazonaws.com +s3-us-gov-west-1.amazonaws.com +s3-us-west-1.amazonaws.com +s3-us-west-2.amazonaws.com +s3-website-ap-northeast-1.amazonaws.com +s3-website-ap-southeast-1.amazonaws.com +s3-website-ap-southeast-2.amazonaws.com +s3-website-eu-west-1.amazonaws.com +s3-website-sa-east-1.amazonaws.com +s3-website-us-east-1.amazonaws.com +s3-website-us-gov-west-1.amazonaws.com +s3-website-us-west-1.amazonaws.com +s3-website-us-west-2.amazonaws.com +s3.dualstack.sa-east-1.amazonaws.com +s3-accesspoint.dualstack.sa-east-1.amazonaws.com +s3-website.dualstack.sa-east-1.amazonaws.com +s3.sa-east-1.amazonaws.com +s3-accesspoint.sa-east-1.amazonaws.com +s3-object-lambda.sa-east-1.amazonaws.com +s3-website.sa-east-1.amazonaws.com +s3.dualstack.us-east-1.amazonaws.com +s3-accesspoint.dualstack.us-east-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com +s3-fips.dualstack.us-east-1.amazonaws.com +s3-website.dualstack.us-east-1.amazonaws.com +s3.us-east-1.amazonaws.com +s3-accesspoint.us-east-1.amazonaws.com +s3-accesspoint-fips.us-east-1.amazonaws.com +s3-deprecated.us-east-1.amazonaws.com +s3-fips.us-east-1.amazonaws.com +s3-object-lambda.us-east-1.amazonaws.com +s3-website.us-east-1.amazonaws.com +s3.dualstack.us-east-2.amazonaws.com +s3-accesspoint.dualstack.us-east-2.amazonaws.com +s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com +s3-fips.dualstack.us-east-2.amazonaws.com +s3-website.dualstack.us-east-2.amazonaws.com +s3.us-east-2.amazonaws.com +s3-accesspoint.us-east-2.amazonaws.com +s3-accesspoint-fips.us-east-2.amazonaws.com +s3-deprecated.us-east-2.amazonaws.com +s3-fips.us-east-2.amazonaws.com +s3-object-lambda.us-east-2.amazonaws.com +s3-website.us-east-2.amazonaws.com +s3.dualstack.us-gov-east-1.amazonaws.com +s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com +s3-fips.dualstack.us-gov-east-1.amazonaws.com +s3.us-gov-east-1.amazonaws.com +s3-accesspoint.us-gov-east-1.amazonaws.com +s3-accesspoint-fips.us-gov-east-1.amazonaws.com +s3-fips.us-gov-east-1.amazonaws.com +s3-object-lambda.us-gov-east-1.amazonaws.com +s3-website.us-gov-east-1.amazonaws.com +s3.dualstack.us-gov-west-1.amazonaws.com +s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com +s3-fips.dualstack.us-gov-west-1.amazonaws.com +s3.us-gov-west-1.amazonaws.com +s3-accesspoint.us-gov-west-1.amazonaws.com +s3-accesspoint-fips.us-gov-west-1.amazonaws.com +s3-fips.us-gov-west-1.amazonaws.com +s3-object-lambda.us-gov-west-1.amazonaws.com +s3-website.us-gov-west-1.amazonaws.com +s3.dualstack.us-west-1.amazonaws.com +s3-accesspoint.dualstack.us-west-1.amazonaws.com +s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com +s3-fips.dualstack.us-west-1.amazonaws.com +s3-website.dualstack.us-west-1.amazonaws.com +s3.us-west-1.amazonaws.com +s3-accesspoint.us-west-1.amazonaws.com +s3-accesspoint-fips.us-west-1.amazonaws.com +s3-fips.us-west-1.amazonaws.com +s3-object-lambda.us-west-1.amazonaws.com +s3-website.us-west-1.amazonaws.com +s3.dualstack.us-west-2.amazonaws.com +s3-accesspoint.dualstack.us-west-2.amazonaws.com +s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com +s3-fips.dualstack.us-west-2.amazonaws.com +s3-website.dualstack.us-west-2.amazonaws.com +s3.us-west-2.amazonaws.com +s3-accesspoint.us-west-2.amazonaws.com +s3-accesspoint-fips.us-west-2.amazonaws.com +s3-deprecated.us-west-2.amazonaws.com +s3-fips.us-west-2.amazonaws.com +s3-object-lambda.us-west-2.amazonaws.com +s3-website.us-west-2.amazonaws.com + +// Amazon SageMaker Ground Truth +// Submitted by AWS Security +// Reference: 98dbfde4-7802-48c3-8751-b60f204e0d9c +labeling.ap-northeast-1.sagemaker.aws +labeling.ap-northeast-2.sagemaker.aws +labeling.ap-south-1.sagemaker.aws +labeling.ap-southeast-1.sagemaker.aws +labeling.ap-southeast-2.sagemaker.aws +labeling.ca-central-1.sagemaker.aws +labeling.eu-central-1.sagemaker.aws +labeling.eu-west-1.sagemaker.aws +labeling.eu-west-2.sagemaker.aws +labeling.us-east-1.sagemaker.aws +labeling.us-east-2.sagemaker.aws +labeling.us-west-2.sagemaker.aws + +// Amazon SageMaker Notebook Instances +// Submitted by AWS Security +// Reference: b5ea56df-669e-43cc-9537-14aa172f5dfc +notebook.af-south-1.sagemaker.aws +notebook.ap-east-1.sagemaker.aws +notebook.ap-northeast-1.sagemaker.aws +notebook.ap-northeast-2.sagemaker.aws +notebook.ap-northeast-3.sagemaker.aws +notebook.ap-south-1.sagemaker.aws +notebook.ap-south-2.sagemaker.aws +notebook.ap-southeast-1.sagemaker.aws +notebook.ap-southeast-2.sagemaker.aws +notebook.ap-southeast-3.sagemaker.aws +notebook.ap-southeast-4.sagemaker.aws +notebook.ca-central-1.sagemaker.aws +notebook-fips.ca-central-1.sagemaker.aws +notebook.ca-west-1.sagemaker.aws +notebook-fips.ca-west-1.sagemaker.aws +notebook.eu-central-1.sagemaker.aws +notebook.eu-central-2.sagemaker.aws +notebook.eu-north-1.sagemaker.aws +notebook.eu-south-1.sagemaker.aws +notebook.eu-south-2.sagemaker.aws +notebook.eu-west-1.sagemaker.aws +notebook.eu-west-2.sagemaker.aws +notebook.eu-west-3.sagemaker.aws +notebook.il-central-1.sagemaker.aws +notebook.me-central-1.sagemaker.aws +notebook.me-south-1.sagemaker.aws +notebook.sa-east-1.sagemaker.aws +notebook.us-east-1.sagemaker.aws +notebook-fips.us-east-1.sagemaker.aws +notebook.us-east-2.sagemaker.aws +notebook-fips.us-east-2.sagemaker.aws +notebook.us-gov-east-1.sagemaker.aws +notebook-fips.us-gov-east-1.sagemaker.aws +notebook.us-gov-west-1.sagemaker.aws +notebook-fips.us-gov-west-1.sagemaker.aws +notebook.us-west-1.sagemaker.aws +notebook-fips.us-west-1.sagemaker.aws +notebook.us-west-2.sagemaker.aws +notebook-fips.us-west-2.sagemaker.aws +notebook.cn-north-1.sagemaker.com.cn +notebook.cn-northwest-1.sagemaker.com.cn + +// Amazon SageMaker Studio +// Submitted by AWS Security +// Reference: 475f237e-ab88-4041-9f41-7cfccdf66aeb +studio.af-south-1.sagemaker.aws +studio.ap-east-1.sagemaker.aws +studio.ap-northeast-1.sagemaker.aws +studio.ap-northeast-2.sagemaker.aws +studio.ap-northeast-3.sagemaker.aws +studio.ap-south-1.sagemaker.aws +studio.ap-southeast-1.sagemaker.aws +studio.ap-southeast-2.sagemaker.aws +studio.ap-southeast-3.sagemaker.aws +studio.ca-central-1.sagemaker.aws +studio.eu-central-1.sagemaker.aws +studio.eu-central-2.sagemaker.aws +studio.eu-north-1.sagemaker.aws +studio.eu-south-1.sagemaker.aws +studio.eu-south-2.sagemaker.aws +studio.eu-west-1.sagemaker.aws +studio.eu-west-2.sagemaker.aws +studio.eu-west-3.sagemaker.aws +studio.il-central-1.sagemaker.aws +studio.me-central-1.sagemaker.aws +studio.me-south-1.sagemaker.aws +studio.sa-east-1.sagemaker.aws +studio.us-east-1.sagemaker.aws +studio.us-east-2.sagemaker.aws +studio.us-gov-east-1.sagemaker.aws +studio-fips.us-gov-east-1.sagemaker.aws +studio.us-gov-west-1.sagemaker.aws +studio-fips.us-gov-west-1.sagemaker.aws +studio.us-west-1.sagemaker.aws +studio.us-west-2.sagemaker.aws +studio.cn-north-1.sagemaker.com.cn +studio.cn-northwest-1.sagemaker.com.cn + +// Amazon SageMaker with MLflow +// Submited by: AWS Security +// Reference: c19f92b3-a82a-452d-8189-831b572eea7e +*.experiments.sagemaker.aws + +// Analytics on AWS +// Submitted by AWS Security +// Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd +analytics-gateway.ap-northeast-1.amazonaws.com +analytics-gateway.ap-northeast-2.amazonaws.com +analytics-gateway.ap-south-1.amazonaws.com +analytics-gateway.ap-southeast-1.amazonaws.com +analytics-gateway.ap-southeast-2.amazonaws.com +analytics-gateway.eu-central-1.amazonaws.com +analytics-gateway.eu-west-1.amazonaws.com +analytics-gateway.us-east-1.amazonaws.com +analytics-gateway.us-east-2.amazonaws.com +analytics-gateway.us-west-2.amazonaws.com + +// AWS Amplify +// Submitted by AWS Security +// Reference: c35bed18-6f4f-424f-9298-5756f2f7d72b +amplifyapp.com + +// AWS App Runner +// Submitted by AWS Security +// Reference: 6828c008-ba5d-442f-ade5-48da4e7c2316 +*.awsapprunner.com + +// AWS Cloud9 +// Submitted by: AWS Security +// Reference: 30717f72-4007-4f0f-8ed4-864c6f2efec9 +webview-assets.aws-cloud9.af-south-1.amazonaws.com +vfs.cloud9.af-south-1.amazonaws.com +webview-assets.cloud9.af-south-1.amazonaws.com +webview-assets.aws-cloud9.ap-east-1.amazonaws.com +vfs.cloud9.ap-east-1.amazonaws.com +webview-assets.cloud9.ap-east-1.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com +vfs.cloud9.ap-northeast-1.amazonaws.com +webview-assets.cloud9.ap-northeast-1.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com +vfs.cloud9.ap-northeast-2.amazonaws.com +webview-assets.cloud9.ap-northeast-2.amazonaws.com +webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com +vfs.cloud9.ap-northeast-3.amazonaws.com +webview-assets.cloud9.ap-northeast-3.amazonaws.com +webview-assets.aws-cloud9.ap-south-1.amazonaws.com +vfs.cloud9.ap-south-1.amazonaws.com +webview-assets.cloud9.ap-south-1.amazonaws.com +webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com +vfs.cloud9.ap-southeast-1.amazonaws.com +webview-assets.cloud9.ap-southeast-1.amazonaws.com +webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com +vfs.cloud9.ap-southeast-2.amazonaws.com +webview-assets.cloud9.ap-southeast-2.amazonaws.com +webview-assets.aws-cloud9.ca-central-1.amazonaws.com +vfs.cloud9.ca-central-1.amazonaws.com +webview-assets.cloud9.ca-central-1.amazonaws.com +webview-assets.aws-cloud9.eu-central-1.amazonaws.com +vfs.cloud9.eu-central-1.amazonaws.com +webview-assets.cloud9.eu-central-1.amazonaws.com +webview-assets.aws-cloud9.eu-north-1.amazonaws.com +vfs.cloud9.eu-north-1.amazonaws.com +webview-assets.cloud9.eu-north-1.amazonaws.com +webview-assets.aws-cloud9.eu-south-1.amazonaws.com +vfs.cloud9.eu-south-1.amazonaws.com +webview-assets.cloud9.eu-south-1.amazonaws.com +webview-assets.aws-cloud9.eu-west-1.amazonaws.com +vfs.cloud9.eu-west-1.amazonaws.com +webview-assets.cloud9.eu-west-1.amazonaws.com +webview-assets.aws-cloud9.eu-west-2.amazonaws.com +vfs.cloud9.eu-west-2.amazonaws.com +webview-assets.cloud9.eu-west-2.amazonaws.com +webview-assets.aws-cloud9.eu-west-3.amazonaws.com +vfs.cloud9.eu-west-3.amazonaws.com +webview-assets.cloud9.eu-west-3.amazonaws.com +webview-assets.aws-cloud9.il-central-1.amazonaws.com +vfs.cloud9.il-central-1.amazonaws.com +webview-assets.aws-cloud9.me-south-1.amazonaws.com +vfs.cloud9.me-south-1.amazonaws.com +webview-assets.cloud9.me-south-1.amazonaws.com +webview-assets.aws-cloud9.sa-east-1.amazonaws.com +vfs.cloud9.sa-east-1.amazonaws.com +webview-assets.cloud9.sa-east-1.amazonaws.com +webview-assets.aws-cloud9.us-east-1.amazonaws.com +vfs.cloud9.us-east-1.amazonaws.com +webview-assets.cloud9.us-east-1.amazonaws.com +webview-assets.aws-cloud9.us-east-2.amazonaws.com +vfs.cloud9.us-east-2.amazonaws.com +webview-assets.cloud9.us-east-2.amazonaws.com +webview-assets.aws-cloud9.us-west-1.amazonaws.com +vfs.cloud9.us-west-1.amazonaws.com +webview-assets.cloud9.us-west-1.amazonaws.com +webview-assets.aws-cloud9.us-west-2.amazonaws.com +vfs.cloud9.us-west-2.amazonaws.com +webview-assets.cloud9.us-west-2.amazonaws.com + +// AWS Directory Service +// Submitted by AWS Security +// Reference: a13203e8-42dc-4045-a0d2-2ee67bed1068 +awsapps.com + +// AWS Elastic Beanstalk +// Submitted by AWS Security +// Reference: bb5a965c-dec3-4967-aa22-e306ad064797 +cn-north-1.eb.amazonaws.com.cn +cn-northwest-1.eb.amazonaws.com.cn +elasticbeanstalk.com +af-south-1.elasticbeanstalk.com +ap-east-1.elasticbeanstalk.com +ap-northeast-1.elasticbeanstalk.com +ap-northeast-2.elasticbeanstalk.com +ap-northeast-3.elasticbeanstalk.com +ap-south-1.elasticbeanstalk.com +ap-southeast-1.elasticbeanstalk.com +ap-southeast-2.elasticbeanstalk.com +ap-southeast-3.elasticbeanstalk.com +ca-central-1.elasticbeanstalk.com +eu-central-1.elasticbeanstalk.com +eu-north-1.elasticbeanstalk.com +eu-south-1.elasticbeanstalk.com +eu-west-1.elasticbeanstalk.com +eu-west-2.elasticbeanstalk.com +eu-west-3.elasticbeanstalk.com +il-central-1.elasticbeanstalk.com +me-south-1.elasticbeanstalk.com +sa-east-1.elasticbeanstalk.com +us-east-1.elasticbeanstalk.com +us-east-2.elasticbeanstalk.com +us-gov-east-1.elasticbeanstalk.com +us-gov-west-1.elasticbeanstalk.com +us-west-1.elasticbeanstalk.com +us-west-2.elasticbeanstalk.com + +// (AWS) Elastic Load Balancing +// Submitted by Luke Wells +// Reference: 12a3d528-1bac-4433-a359-a395867ffed2 +*.elb.amazonaws.com.cn +*.elb.amazonaws.com + +// AWS Global Accelerator +// Submitted by Daniel Massaguer +// Reference: d916759d-a08b-4241-b536-4db887383a6a +awsglobalaccelerator.com + +// AWS re:Post Private +// Submitted by AWS Security +// Reference: 83385945-225f-416e-9aa0-ad0632bfdcee +*.private.repost.aws + +// AWS Transfer Family web apps +// Submitted by AWS Security +// Reference: 57a658c4-8899-410c-aa24-5b01e4a178d2 +transfer-webapp.af-south-1.on.aws +transfer-webapp.ap-east-1.on.aws +transfer-webapp.ap-northeast-1.on.aws +transfer-webapp.ap-northeast-2.on.aws +transfer-webapp.ap-northeast-3.on.aws +transfer-webapp.ap-south-1.on.aws +transfer-webapp.ap-south-2.on.aws +transfer-webapp.ap-southeast-1.on.aws +transfer-webapp.ap-southeast-2.on.aws +transfer-webapp.ap-southeast-3.on.aws +transfer-webapp.ap-southeast-4.on.aws +transfer-webapp.ap-southeast-5.on.aws +transfer-webapp.ca-central-1.on.aws +transfer-webapp.ca-west-1.on.aws +transfer-webapp.eu-central-1.on.aws +transfer-webapp.eu-central-2.on.aws +transfer-webapp.eu-north-1.on.aws +transfer-webapp.eu-south-1.on.aws +transfer-webapp.eu-south-2.on.aws +transfer-webapp.eu-west-1.on.aws +transfer-webapp.eu-west-2.on.aws +transfer-webapp.eu-west-3.on.aws +transfer-webapp.il-central-1.on.aws +transfer-webapp.me-central-1.on.aws +transfer-webapp.me-south-1.on.aws +transfer-webapp.sa-east-1.on.aws +transfer-webapp.us-east-1.on.aws +transfer-webapp.us-east-2.on.aws +transfer-webapp.us-gov-east-1.on.aws +transfer-webapp-fips.us-gov-east-1.on.aws +transfer-webapp.us-gov-west-1.on.aws +transfer-webapp-fips.us-gov-west-1.on.aws +transfer-webapp.us-west-1.on.aws +transfer-webapp.us-west-2.on.aws +transfer-webapp.cn-north-1.on.amazonwebservices.com.cn +transfer-webapp.cn-northwest-1.on.amazonwebservices.com.cn + +// eero +// Submitted by Yue Kang +// Reference: 264afe70-f62c-4c02-8ab9-b5281ed24461 +eero.online +eero-stage.online + +// concludes Amazon + +// Apigee : https://apigee.com/ +// Submitted by Apigee Security Team +apigee.io + +// Apis Networks : https://apisnetworks.com +// Submitted by Matt Saladna +panel.dev + +// Apphud : https://apphud.com +// Submitted by Alexander Selivanov +siiites.com + +// Appspace : https://www.appspace.com +// Submitted by Appspace Security Team +appspacehosted.com +appspaceusercontent.com + +// Appudo UG (haftungsbeschränkt) : https://www.appudo.com +// Submitted by Alexander Hochbaum +appudo.net + +// Appwrite : https://appwrite.io +// Submitted by Steven Nguyen +appwrite.global +*.appwrite.run + +// Aptible : https://www.aptible.com/ +// Submitted by Thomas Orozco +on-aptible.com + +// Aquapal : https://aquapal.net/ +// Submitted by Aki Ueno +f5.si + +// ArvanCloud EdgeCompute +// Submitted by ArvanCloud CDN +arvanedge.ir + +// ASEINet : https://www.aseinet.com/ +// Submitted by Asei SEKIGUCHI +user.aseinet.ne.jp +gv.vc +d.gv.vc + +// Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/ +// Submitted by Hector Martin +user.party.eus + +// Association potager.org : https://potager.org/ +// Submitted by Lunar +pimienta.org +poivron.org +potager.org +sweetpepper.org + +// ASUSTOR Inc. : http://www.asustor.com +// Submitted by Vincent Tseng +myasustor.com + +// Atlassian : https://atlassian.com +// Submitted by Sam Smyth +cdn.prod.atlassian-dev.net + +// Authentick UG (haftungsbeschränkt) : https://authentick.net +// Submitted by Lukas Reschke +translated.page + +// AVM : https://avm.de +// Submitted by Andreas Weise +myfritz.link +myfritz.net + +// AVStack Pte. Ltd. : https://avstack.io +// Submitted by Jasper Hugo +onavstack.net + +// AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com +// Submitted by James Kennedy +*.awdev.ca +*.advisor.ws + +// AZ.pl sp. z.o.o : https://az.pl +// Submitted by Krzysztof Wolski +ecommerce-shop.pl + +// b-data GmbH : https://www.b-data.io +// Submitted by Olivier Benz +b-data.io + +// Balena : https://www.balena.io +// Submitted by Petros Angelatos +balena-devices.com + +// BASE, Inc. : https://binc.jp +// Submitted by Yuya NAGASAWA +base.ec +official.ec +buyshop.jp +fashionstore.jp +handcrafted.jp +kawaiishop.jp +supersale.jp +theshop.jp +shopselect.net +base.shop + +// BeagleBoard.org Foundation : https://beagleboard.org +// Submitted by Jason Kridner +beagleboard.io + +// Beget Ltd +// Submitted by Lev Nekrasov +*.beget.app + +// Besties : https://besties.house +// Submitted by Hazel Cora +pages.gay + +// BinaryLane : http://www.binarylane.com +// Submitted by Nathan O'Sullivan +bnr.la + +// Bitbucket : http://bitbucket.org +// Submitted by Andy Ortlieb +bitbucket.io + +// Blackbaud, Inc. : https://www.blackbaud.com +// Submitted by Paul Crowder +blackbaudcdn.net + +// Blatech : http://www.blatech.net +// Submitted by Luke Bratch +of.je + +// Block, Inc. : https://block.xyz +// Submitted by Jonathan Boice +square.site + +// Blue Bite, LLC : https://bluebite.com +// Submitted by Joshua Weiss +bluebite.io + +// Boomla : https://boomla.com +// Submitted by Tibor Halter +boomla.net + +// Boutir : https://www.boutir.com +// Submitted by Eric Ng Ka Ka +boutir.com + +// Boxfuse : https://boxfuse.com +// Submitted by Axel Fontaine +boxfuse.io + +// bplaced : https://www.bplaced.net/ +// Submitted by Miroslav Bozic +square7.ch +bplaced.com +bplaced.de +square7.de +bplaced.net +square7.net + +// Brave : https://brave.com +// Submitted by Andrea Brancaleoni +brave.app +*.s.brave.app +brave.io +*.s.brave.io + +// Brendly : https://brendly.rs +// Submitted by Dusan Radovanovic +shop.brendly.ba +shop.brendly.hr +shop.brendly.rs + +// BrowserSafetyMark +// Submitted by Dave Tharp +browsersafetymark.io + +// BRS Media : https://brsmedia.com/ +// Submitted by Gavin Brown +radio.am +radio.fm + +// Bubble : https://bubble.io/ +// Submitted by Merlin Zhao +cdn.bubble.io +bubbleapps.io + +// Bytemark Hosting : https://www.bytemark.co.uk +// Submitted by Paul Cammish +uk0.bigv.io +dh.bytemark.co.uk +vm.bytemark.co.uk + +// Caf.js Labs LLC : https://www.cafjs.com +// Submitted by Antonio Lain +cafjs.com + +// Canva Pty Ltd : https://canva.com/ +// Submitted by Joel Aquilina +canva-apps.cn +my.canvasite.cn +canva-apps.com +canva-hosted-embed.com +canvacode.com +rice-labs.com +canva.run +my.canva.site + +// Carrd : https://carrd.co +// Submitted by AJ +drr.ac +uwu.ai +carrd.co +crd.co +ju.mp + +// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk +// Submitted by Jamie Tanna +api.gov.uk + +// CDN77.com : http://www.cdn77.com +// Submitted by Jan Krpes +cdn77-storage.com +rsc.contentproxy9.cz +r.cdn77.net +cdn77-ssl.net +c.cdn77.org +rsc.cdn77.org +ssl.origin.cdn77-secure.org + +// CentralNic : https://teaminternet.com/ +// Submitted by registry +za.bz +br.com +cn.com +de.com +eu.com +jpn.com +mex.com +ru.com +sa.com +uk.com +us.com +za.com +com.de +gb.net +hu.net +jp.net +se.net +uk.net +ae.org +com.se + +// Cityhost LLC : https://cityhost.ua +// Submitted by Maksym Rivtin +cx.ua + +// Civilized Discourse Construction Kit, Inc. : https://www.discourse.org/ +// Submitted by Rishabh Nambiar & Michael Brown +discourse.group +discourse.team + +// Clerk : https://www.clerk.dev +// Submitted by Colin Sidoti +clerk.app +clerkstage.app +*.lcl.dev +*.lclstage.dev +*.stg.dev +*.stgstage.dev + +// Clever Cloud : https://www.clever-cloud.com/ +// Submitted by Quentin Adam +cleverapps.cc +*.services.clever-cloud.com +cleverapps.io +cleverapps.tech + +// ClickRising : https://clickrising.com/ +// Submitted by Umut Gumeli +clickrising.net + +// Cloud DNS Ltd : http://www.cloudns.net +// Submitted by Aleksander Hristov & Boyan Peychev +cloudns.asia +cloudns.be +cloud-ip.biz +cloudns.biz +cloud-ip.cc +cloudns.cc +cloudns.ch +cloudns.cl +cloudns.club +abrdns.com +dnsabr.com +ip-ddns.com +cloudns.cx +cloudns.eu +cloudns.in +cloudns.info +ddns-ip.net +dns-cloud.net +dns-dynamic.net +cloudns.nz +cloudns.org +ip-dynamic.org +cloudns.ph +cloudns.pro +cloudns.pw +cloudns.us + +// Cloud66 : https://www.cloud66.com/ +// Submitted by Khash Sajadi +c66.me +cloud66.ws + +// CloudAccess.net : https://www.cloudaccess.net/ +// Submitted by Pawel Panek +jdevcloud.com +wpdevcloud.com +cloudaccess.host +freesite.host +cloudaccess.net + +// Cloudbees, Inc. : https://www.cloudbees.com/ +// Submitted by Mohideen Shajith +cloudbeesusercontent.io + +// Cloudera, Inc. : https://www.cloudera.com/ +// Submitted by Kedarnath Waikar +*.cloudera.site + +// Cloudflare, Inc. : https://www.cloudflare.com/ +// Submitted by Cloudflare Team +cf-ipfs.com +cloudflare-ipfs.com +trycloudflare.com +pages.dev +r2.dev +workers.dev +cloudflare.net +cdn.cloudflare.net +cdn.cloudflareanycast.net +cdn.cloudflarecn.net +cdn.cloudflareglobal.net + +// cloudscale.ch AG : https://www.cloudscale.ch/ +// Submitted by Gaudenz Steinlin +cust.cloudscale.ch +objects.lpg.cloudscale.ch +objects.rma.cloudscale.ch +lpg.objectstorage.ch +rma.objectstorage.ch + +// Clovyr : https://clovyr.io +// Submitted by Patrick Nielsen +wnext.app + +// CNPY : https://cnpy.gdn +// Submitted by Angelo Gladding +cnpy.gdn + +// Co & Co : https://co-co.nl/ +// Submitted by Govert Versluis +*.otap.co + +// co.ca : http://registry.co.ca/ +co.ca + +// co.com Registry, LLC : https://registry.co.com +// Submitted by Gavin Brown +co.com + +// Codeberg e. V. : https://codeberg.org +// Submitted by Moritz Marquardt +codeberg.page + +// CodeSandbox B.V. : https://codesandbox.io +// Submitted by Ives van Hoorne +csb.app +preview.csb.app + +// CoDNS B.V. +co.nl +co.no + +// Cognition AI, Inc. : https://cognition.ai +// Submitted by Philip Papurt +*.devinapps.com + +// Combell.com : https://www.combell.com +// Submitted by Thomas Wouters +webhosting.be +hosting-cluster.nl + +// Contentful GmbH : https://www.contentful.com +// Submitted by Contentful Developer Experience Team +ctfcloud.net + +// Convex : https://convex.dev/ +// Submitted by James Cowling +convex.app +convex.cloud +convex.site + +// Coordination Center for TLD RU and XN--P1AI : https://cctld.ru/en/domains/domens_ru/reserved/ +// Submitted by George Georgievsky +ac.ru +edu.ru +gov.ru +int.ru +mil.ru + +// COSIMO GmbH : http://www.cosimo.de +// Submitted by Rene Marticke +dyn.cosidns.de +dnsupdater.de +dynamisches-dns.de +internet-dns.de +l-o-g-i-n.de +dynamic-dns.info +feste-ip.net +knx-server.net +static-access.net + +// Craft Docs Ltd : https://www.craft.do/ +// Submitted by Zsombor Fuszenecker +craft.me + +// Craynic, s.r.o. : http://www.craynic.com/ +// Submitted by Ales Krajnik +realm.cz + +// Crisp IM SAS : https://crisp.chat/ +// Submitted by Baptiste Jamin +on.crisp.email + +// Cryptonomic : https://cryptonomic.net/ +// Submitted by Andrew Cady +*.cryptonomic.net + +// cyber_Folks S.A. : https://cyberfolks.pl +// Submitted by Bartlomiej Kida +cfolks.pl + +// cyon GmbH : https://www.cyon.ch/ +// Submitted by Dominic Luechinger +cyon.link +cyon.site + +// Dansk.net : http://www.dansk.net/ +// Submitted by Anani Voule +biz.dk +co.dk +firm.dk +reg.dk +store.dk + +// dappnode.io : https://dappnode.io/ +// Submitted by Abel Boldu / DAppNode Team +dyndns.dappnode.io + +// Dark, Inc. : https://darklang.com +// Submitted by Paul Biggar +builtwithdark.com +darklang.io + +// DataDetect, LLC. : https://datadetect.com +// Submitted by Andrew Banchich +demo.datadetect.com +instance.datadetect.com + +// Datawire, Inc : https://www.datawire.io +// Submitted by Richard Li +edgestack.me + +// Datto, Inc. : https://www.datto.com/ +// Submitted by Philipp Heckel +dattolocal.com +dattorelay.com +dattoweb.com +mydatto.com +dattolocal.net +mydatto.net + +// ddnss.de : https://www.ddnss.de/ +// Submitted by Robert Niedziela +ddnss.de +dyn.ddnss.de +dyndns.ddnss.de +dyn-ip24.de +dyndns1.de +home-webserver.de +dyn.home-webserver.de +myhome-server.de +ddnss.org + +// Debian : https://www.debian.org/ +// Submitted by Peter Palfrader / Debian Sysadmin Team +debian.net + +// Definima : http://www.definima.com/ +// Submitted by Maxence Bitterli +definima.io +definima.net + +// Deno Land Inc : https://deno.com/ +// Submitted by Luca Casonato +deno.dev +deno-staging.dev +deno.net + +// deSEC : https://desec.io/ +// Submitted by Peter Thomassen +dedyn.io + +// Deta : https://www.deta.sh/ +// Submitted by Aavash Shrestha +deta.app +deta.dev + +// Dfinity Foundation: https://dfinity.org/ +// Submitted by Dfinity Team +icp0.io +*.raw.icp0.io +icp1.io +*.raw.icp1.io +*.icp.net +caffeine.site +caffeine.xyz + +// dhosting.pl Sp. z o.o. : https://dhosting.pl/ +// Submitted by Michal Kokoszkiewicz +dfirma.pl +dkonto.pl +you2.pl + +// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/ +// Submitted by Braxton Huggins +ondigitalocean.app + +// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/ +// Submitted by Robin H. Johnson +*.digitaloceanspaces.com + +// DigitalPlat : https://www.digitalplat.org/ +// Submitted by Edward Hsing +qzz.io +us.kg +xx.kg +dpdns.org + +// Discord Inc : https://discord.com +// Submitted by Sahn Lam +discordsays.com +discordsez.com + +// DNS Africa Ltd : https://dns.business +// Submitted by Calvin Browne +jozi.biz + +// DNShome : https://www.dnshome.de/ +// Submitted by Norbert Auler +dnshome.de + +// DotArai : https://www.dotarai.com/ +// Submitted by Atsadawat Netcharadsang +online.th +shop.th + +// DrayTek Corp. : https://www.draytek.com/ +// Submitted by Paul Fang +drayddns.com + +// DreamCommerce : https://shoper.pl/ +// Submitted by Konrad Kotarba +shoparena.pl + +// DreamHost : http://www.dreamhost.com/ +// Submitted by Andrew Farmer +dreamhosters.com + +// Dreamyoungs, Inc. : https://durumis.com +// Submitted by Infra Team +durumis.com + +// DuckDNS : http://www.duckdns.org/ +// Submitted by Richard Harper +duckdns.org + +// dy.fi : http://dy.fi/ +// Submitted by Heikki Hannikainen +dy.fi +tunk.org + +// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ +dyndns.biz +for-better.biz +for-more.biz +for-some.biz +for-the.biz +selfip.biz +webhop.biz +ftpaccess.cc +game-server.cc +myphotos.cc +scrapping.cc +blogdns.com +cechire.com +dnsalias.com +dnsdojo.com +doesntexist.com +dontexist.com +doomdns.com +dyn-o-saur.com +dynalias.com +dyndns-at-home.com +dyndns-at-work.com +dyndns-blog.com +dyndns-free.com +dyndns-home.com +dyndns-ip.com +dyndns-mail.com +dyndns-office.com +dyndns-pics.com +dyndns-remote.com +dyndns-server.com +dyndns-web.com +dyndns-wiki.com +dyndns-work.com +est-a-la-maison.com +est-a-la-masion.com +est-le-patron.com +est-mon-blogueur.com +from-ak.com +from-al.com +from-ar.com +from-ca.com +from-ct.com +from-dc.com +from-de.com +from-fl.com +from-ga.com +from-hi.com +from-ia.com +from-id.com +from-il.com +from-in.com +from-ks.com +from-ky.com +from-ma.com +from-md.com +from-mi.com +from-mn.com +from-mo.com +from-ms.com +from-mt.com +from-nc.com +from-nd.com +from-ne.com +from-nh.com +from-nj.com +from-nm.com +from-nv.com +from-oh.com +from-ok.com +from-or.com +from-pa.com +from-pr.com +from-ri.com +from-sc.com +from-sd.com +from-tn.com +from-tx.com +from-ut.com +from-va.com +from-vt.com +from-wa.com +from-wi.com +from-wv.com +from-wy.com +getmyip.com +gotdns.com +hobby-site.com +homelinux.com +homeunix.com +iamallama.com +is-a-anarchist.com +is-a-blogger.com +is-a-bookkeeper.com +is-a-bulls-fan.com +is-a-caterer.com +is-a-chef.com +is-a-conservative.com +is-a-cpa.com +is-a-cubicle-slave.com +is-a-democrat.com +is-a-designer.com +is-a-doctor.com +is-a-financialadvisor.com +is-a-geek.com +is-a-green.com +is-a-guru.com +is-a-hard-worker.com +is-a-hunter.com +is-a-landscaper.com +is-a-lawyer.com +is-a-liberal.com +is-a-libertarian.com +is-a-llama.com +is-a-musician.com +is-a-nascarfan.com +is-a-nurse.com +is-a-painter.com +is-a-personaltrainer.com +is-a-photographer.com +is-a-player.com +is-a-republican.com +is-a-rockstar.com +is-a-socialist.com +is-a-student.com +is-a-teacher.com +is-a-techie.com +is-a-therapist.com +is-an-accountant.com +is-an-actor.com +is-an-actress.com +is-an-anarchist.com +is-an-artist.com +is-an-engineer.com +is-an-entertainer.com +is-certified.com +is-gone.com +is-into-anime.com +is-into-cars.com +is-into-cartoons.com +is-into-games.com +is-leet.com +is-not-certified.com +is-slick.com +is-uberleet.com +is-with-theband.com +isa-geek.com +isa-hockeynut.com +issmarterthanyou.com +likes-pie.com +likescandy.com +neat-url.com +saves-the-whales.com +selfip.com +sells-for-less.com +sells-for-u.com +servebbs.com +simple-url.com +space-to-rent.com +teaches-yoga.com +writesthisblog.com +ath.cx +fuettertdasnetz.de +isteingeek.de +istmein.de +lebtimnetz.de +leitungsen.de +traeumtgerade.de +barrel-of-knowledge.info +barrell-of-knowledge.info +dyndns.info +for-our.info +groks-the.info +groks-this.info +here-for-more.info +knowsitall.info +selfip.info +webhop.info +forgot.her.name +forgot.his.name +at-band-camp.net +blogdns.net +broke-it.net +buyshouses.net +dnsalias.net +dnsdojo.net +does-it.net +dontexist.net +dynalias.net +dynathome.net +endofinternet.net +from-az.net +from-co.net +from-la.net +from-ny.net +gets-it.net +ham-radio-op.net +homeftp.net +homeip.net +homelinux.net +homeunix.net +in-the-band.net +is-a-chef.net +is-a-geek.net +isa-geek.net +kicks-ass.net +office-on-the.net +podzone.net +scrapper-site.net +selfip.net +sells-it.net +servebbs.net +serveftp.net +thruhere.net +webhop.net +merseine.nu +mine.nu +shacknet.nu +blogdns.org +blogsite.org +boldlygoingnowhere.org +dnsalias.org +dnsdojo.org +doesntexist.org +dontexist.org +doomdns.org +dvrdns.org +dynalias.org +dyndns.org +go.dyndns.org +home.dyndns.org +endofinternet.org +endoftheinternet.org +from-me.org +game-host.org +gotdns.org +hobby-site.org +homedns.org +homeftp.org +homelinux.org +homeunix.org +is-a-bruinsfan.org +is-a-candidate.org +is-a-celticsfan.org +is-a-chef.org +is-a-geek.org +is-a-knight.org +is-a-linux-user.org +is-a-patsfan.org +is-a-soxfan.org +is-found.org +is-lost.org +is-saved.org +is-very-bad.org +is-very-evil.org +is-very-good.org +is-very-nice.org +is-very-sweet.org +isa-geek.org +kicks-ass.org +misconfused.org +podzone.org +readmyblog.org +selfip.org +sellsyourhome.org +servebbs.org +serveftp.org +servegame.org +stuff-4-sale.org +webhop.org +better-than.tv +dyndns.tv +on-the-web.tv +worse-than.tv +is-by.us +land-4-sale.us +stuff-4-sale.us +dyndns.ws +mypets.ws + +// Dynu.com : https://www.dynu.com/ +// Submitted by Sue Ye +ddnsfree.com +ddnsgeek.com +giize.com +gleeze.com +kozow.com +loseyourip.com +ooguy.com +theworkpc.com +casacam.net +dynu.net +accesscam.org +camdvr.org +freeddns.org +mywire.org +webredirect.org +myddns.rocks + +// dynv6 : https://dynv6.com +// Submitted by Dominik Menke +dynv6.net + +// E4YOU spol. s.r.o. : https://e4you.cz/ +// Submitted by Vladimir Dudr +e4.cz + +// Easypanel : https://easypanel.io +// Submitted by Andrei Canta +easypanel.app +easypanel.host + +// EasyWP : https://www.easywp.com +// Submitted by +*.ewp.live + +// eDirect Corp. : https://hosting.url.com.tw/ +// Submitted by C.S. chang +twmail.cc +twmail.net +twmail.org +mymailer.com.tw +url.tw + +// Electromagnetic Field : https://www.emfcamp.org +// Submitted by +at.emf.camp + +// Elefunc, Inc. : https://elefunc.com +// Submitted by Cetin Sert +rt.ht + +// Elementor : Elementor Ltd. +// Submitted by Anton Barkan +elementor.cloud +elementor.cool + +// En root‽ : https://en-root.org +// Submitted by Emmanuel Raviart +en-root.fr + +// Enalean SAS : https://www.enalean.com +// Submitted by Enalean Security Team +mytuleap.com +tuleap-partners.com + +// Encoretivity AB : https://encore.cloud +// Submitted by André Eriksson +encr.app +frontend.encr.app +encoreapi.com +lp.dev +api.lp.dev +objects.lp.dev + +// encoway GmbH : https://www.encoway.de +// Submitted by Marcel Daus +eu.encoway.cloud + +// EU.org : https://eu.org/ +// Submitted by Pierre Beyssac +eu.org +al.eu.org +asso.eu.org +at.eu.org +au.eu.org +be.eu.org +bg.eu.org +ca.eu.org +cd.eu.org +ch.eu.org +cn.eu.org +cy.eu.org +cz.eu.org +de.eu.org +dk.eu.org +edu.eu.org +ee.eu.org +es.eu.org +fi.eu.org +fr.eu.org +gr.eu.org +hr.eu.org +hu.eu.org +ie.eu.org +il.eu.org +in.eu.org +int.eu.org +is.eu.org +it.eu.org +jp.eu.org +kr.eu.org +lt.eu.org +lu.eu.org +lv.eu.org +me.eu.org +mk.eu.org +mt.eu.org +my.eu.org +net.eu.org +ng.eu.org +nl.eu.org +no.eu.org +nz.eu.org +pl.eu.org +pt.eu.org +ro.eu.org +ru.eu.org +se.eu.org +si.eu.org +sk.eu.org +tr.eu.org +uk.eu.org +us.eu.org + +// Eurobyte : https://eurobyte.ru +// Submitted by Evgeniy Subbotin +eurodir.ru + +// Evennode : http://www.evennode.com/ +// Submitted by Michal Kralik +eu-1.evennode.com +eu-2.evennode.com +eu-3.evennode.com +eu-4.evennode.com +us-1.evennode.com +us-2.evennode.com +us-3.evennode.com +us-4.evennode.com + +// Evervault : https://evervault.com +// Submitted by Hannah Neary +relay.evervault.app +relay.evervault.dev + +// Expo : https://expo.dev/ +// Submitted by James Ide +expo.app +staging.expo.app + +// Fabrica Technologies, Inc. : https://www.fabrica.dev/ +// Submitted by Eric Jiang +onfabrica.com + +// FAITID : https://faitid.org/ +// Submitted by Maxim Alzoba +// https://www.flexireg.net/stat_info +ru.net +adygeya.ru +bashkiria.ru +bir.ru +cbg.ru +com.ru +dagestan.ru +grozny.ru +kalmykia.ru +kustanai.ru +marine.ru +mordovia.ru +msk.ru +mytis.ru +nalchik.ru +nov.ru +pyatigorsk.ru +spb.ru +vladikavkaz.ru +vladimir.ru +abkhazia.su +adygeya.su +aktyubinsk.su +arkhangelsk.su +armenia.su +ashgabad.su +azerbaijan.su +balashov.su +bashkiria.su +bryansk.su +bukhara.su +chimkent.su +dagestan.su +east-kazakhstan.su +exnet.su +georgia.su +grozny.su +ivanovo.su +jambyl.su +kalmykia.su +kaluga.su +karacol.su +karaganda.su +karelia.su +khakassia.su +krasnodar.su +kurgan.su +kustanai.su +lenug.su +mangyshlak.su +mordovia.su +msk.su +murmansk.su +nalchik.su +navoi.su +north-kazakhstan.su +nov.su +obninsk.su +penza.su +pokrovsk.su +sochi.su +spb.su +tashkent.su +termez.su +togliatti.su +troitsk.su +tselinograd.su +tula.su +tuva.su +vladikavkaz.su +vladimir.su +vologda.su + +// Fancy Bits, LLC : http://getchannels.com +// Submitted by Aman Gupta +channelsdvr.net +u.channelsdvr.net + +// Fastly Inc. : http://www.fastly.com/ +// Submitted by Fastly Security +edgecompute.app +fastly-edge.com +fastly-terrarium.com +freetls.fastly.net +map.fastly.net +a.prod.fastly.net +global.prod.fastly.net +a.ssl.fastly.net +b.ssl.fastly.net +global.ssl.fastly.net +fastlylb.net +map.fastlylb.net + +// Fastmail : https://www.fastmail.com/ +// Submitted by Marc Bradshaw +*.user.fm + +// FASTVPS EESTI OU : https://fastvps.ru/ +// Submitted by Likhachev Vasiliy +fastvps-server.com +fastvps.host +myfast.host +fastvps.site +myfast.space + +// FearWorks Media Ltd. : https://fearworksmedia.co.uk +// Submitted by Keith Fairley +conn.uk +copro.uk +hosp.uk + +// Fedora : https://fedoraproject.org/ +// Submitted by Patrick Uiterwijk +fedorainfracloud.org +fedorapeople.org +cloud.fedoraproject.org +app.os.fedoraproject.org +app.os.stg.fedoraproject.org + +// Fermax : https://fermax.com/ +// Submitted by Koen Van Isterdael +mydobiss.com + +// FH Muenster : https://www.fh-muenster.de +// Submitted by Robin Naundorf +fh-muenster.io + +// Figma : https://www.figma.com +// Submitted by Nick Frost +figma.site +preview.site + +// Filegear Inc. : https://www.filegear.com +// Submitted by Jason Zhu +filegear.me + +// Firebase, Inc. +// Submitted by Chris Raynor +firebaseapp.com + +// FlashDrive : https://flashdrive.io +// Submitted by Eric Chan +fldrv.com + +// Fleek Labs Inc : https://fleek.xyz +// Submitted by Parsa Ghadimi +on-fleek.app + +// FlutterFlow : https://flutterflow.io +// Submitted by Anton Emelyanov +flutterflow.app + +// fly.io : https://fly.io +// Submitted by Kurt Mackey +fly.dev +shw.io +edgeapp.net + +// Forgerock : https://www.forgerock.com +// Submitted by Roderick Parr +forgeblocks.com +id.forgerock.io + +// FoundryLabs, Inc : https://e2b.dev/ +// Submitted by Jiri Sveceny +e2b.app + +// Framer : https://www.framer.com +// Submitted by Koen Rouwhorst +framer.ai +framer.app +framercanvas.com +framer.media +framer.photos +framer.website +framer.wiki + +// Frederik Braun : https://frederik-braun.com +// Submitted by Frederik Braun +*.0e.vc + +// Freebox : http://www.freebox.fr +// Submitted by Romain Fliedel +freebox-os.com +freeboxos.com +fbx-os.fr +fbxos.fr +freebox-os.fr +freeboxos.fr + +// freedesktop.org : https://www.freedesktop.org +// Submitted by Daniel Stone +freedesktop.org + +// freemyip.com : https://freemyip.com +// Submitted by Cadence +freemyip.com + +// Frusky MEDIA&PR : https://www.frusky.de +// Submitted by Victor Pupynin +*.frusky.de + +// FunkFeuer - Verein zur Förderung freier Netze : https://www.funkfeuer.at +// Submitted by Daniel A. Maierhofer +wien.funkfeuer.at + +// Future Versatile Group. : https://www.fvg-on.net/ +// T.Kabu +daemon.asia +dix.asia +mydns.bz +0am.jp +0g0.jp +0j0.jp +0t0.jp +mydns.jp +pgw.jp +wjg.jp +keyword-on.net +live-on.net +server-on.net +mydns.tw +mydns.vc + +// Futureweb GmbH : https://www.futureweb.at +// Submitted by Andreas Schnederle-Wagner +*.futurecms.at +*.ex.futurecms.at +*.in.futurecms.at +futurehosting.at +futuremailing.at +*.ex.ortsinfo.at +*.kunden.ortsinfo.at +*.statics.cloud + +// GCom Internet : https://www.gcom.net.au +// Submitted by Leo Julius +aliases121.com + +// GDS : https://www.gov.uk/service-manual/technology/managing-domain-names +// Submitted by Stephen Ford +campaign.gov.uk +service.gov.uk +independent-commission.uk +independent-inquest.uk +independent-inquiry.uk +independent-panel.uk +independent-review.uk +public-inquiry.uk +royal-commission.uk + +// Gehirn Inc. : https://www.gehirn.co.jp/ +// Submitted by Kohei YOSHIDA +gehirn.ne.jp +usercontent.jp + +// Gentlent, Inc. : https://www.gentlent.com +// Submitted by Tom Klein +gentapps.com +gentlentapis.com +cdn-edges.net + +// GignoSystemJapan : http://gsj.bz +// Submitted by GignoSystemJapan +gsj.bz + +// GitHub, Inc. +// Submitted by Patrick Toomey +github.app +githubusercontent.com +githubpreview.dev +github.io + +// GitLab, Inc. : https://about.gitlab.com/ +// Submitted by Alex Hanselka +gitlab.io + +// Gitplac.si : https://gitplac.si +// Submitted by Aljaž Starc +gitapp.si +gitpage.si + +// Global NOG Alliance : https://nogalliance.org/ +// Submitted by Sander Steffann +nog.community + +// Globe Hosting SRL : https://www.globehosting.com/ +// Submitted by Gavin Brown +co.ro +shop.ro + +// GMO Pepabo, Inc. : https://pepabo.com/ +// Submitted by Hosting Div +lolipop.io +angry.jp +babyblue.jp +babymilk.jp +backdrop.jp +bambina.jp +bitter.jp +blush.jp +boo.jp +boy.jp +boyfriend.jp +but.jp +candypop.jp +capoo.jp +catfood.jp +cheap.jp +chicappa.jp +chillout.jp +chips.jp +chowder.jp +chu.jp +ciao.jp +cocotte.jp +coolblog.jp +cranky.jp +cutegirl.jp +daa.jp +deca.jp +deci.jp +digick.jp +egoism.jp +fakefur.jp +fem.jp +flier.jp +floppy.jp +fool.jp +frenchkiss.jp +girlfriend.jp +girly.jp +gloomy.jp +gonna.jp +greater.jp +hacca.jp +heavy.jp +her.jp +hiho.jp +hippy.jp +holy.jp +hungry.jp +icurus.jp +itigo.jp +jellybean.jp +kikirara.jp +kill.jp +kilo.jp +kuron.jp +littlestar.jp +lolipopmc.jp +lolitapunk.jp +lomo.jp +lovepop.jp +lovesick.jp +main.jp +mods.jp +mond.jp +mongolian.jp +moo.jp +namaste.jp +nikita.jp +nobushi.jp +noor.jp +oops.jp +parallel.jp +parasite.jp +pecori.jp +peewee.jp +penne.jp +pepper.jp +perma.jp +pigboat.jp +pinoko.jp +punyu.jp +pupu.jp +pussycat.jp +pya.jp +raindrop.jp +readymade.jp +sadist.jp +schoolbus.jp +secret.jp +staba.jp +stripper.jp +sub.jp +sunnyday.jp +thick.jp +tonkotsu.jp +under.jp +upper.jp +velvet.jp +verse.jp +versus.jp +vivian.jp +watson.jp +weblike.jp +whitesnow.jp +zombie.jp +heteml.net + +// GoDaddy Registry : https://registry.godaddy +// Submitted by Rohan Durrant +graphic.design + +// GoIP DNS Services : http://www.goip.de +// Submitted by Christian Poulter +goip.de + +// Google, Inc. +// Submitted by Shannon McCabe +*.hosted.app +*.run.app +*.mtls.run.app +web.app +*.0emm.com +appspot.com +*.r.appspot.com +blogspot.com +codespot.com +googleapis.com +googlecode.com +pagespeedmobilizer.com +withgoogle.com +withyoutube.com +*.gateway.dev +cloud.goog +translate.goog +*.usercontent.goog +cloudfunctions.net + +// Goupile : https://goupile.fr +// Submitted by Niels Martignene +goupile.fr + +// GOV.UK Pay : https://www.payments.service.gov.uk/ +// Submitted by Richard Baker +pymnt.uk + +// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/ +// Submitted by Tom Whitwell +cloudapps.digital +london.cloudapps.digital + +// Government of the Netherlands : https://www.government.nl +// Submitted by +gov.nl + +// Grafana Labs : https://grafana.com/ +// Submitted by Platform Engineering +grafana-dev.net + +// GrayJay Web Solutions Inc. : https://grayjaysports.ca +// Submitted by Matt Yamkowy +grayjayleagues.com + +// GünstigBestellen : https://günstigbestellen.de +// Submitted by Furkan Akkoc +günstigbestellen.de +günstigliefern.de + +// Hackclub Nest : https://hackclub.app +// Submitted by Cyteon +hackclub.app + +// Häkkinen.fi : https://www.häkkinen.fi/ +// Submitted by Eero Häkkinen +häkkinen.fi + +// Hashbang : https://hashbang.sh +hashbang.sh + +// Hasura : https://hasura.io +// Submitted by Shahidh K Muhammed +hasura.app +hasura-app.io + +// Hatena Co., Ltd. : https://hatena.co.jp +// Submitted by Masato Nakamura +hatenablog.com +hatenadiary.com +hateblo.jp +hatenablog.jp +hatenadiary.jp +hatenadiary.org + +// Heilbronn University of Applied Sciences - Faculty Informatics (GitLab Pages) : https://www.hs-heilbronn.de +// Submitted by Richard Zowalla +pages.it.hs-heilbronn.de +pages-research.it.hs-heilbronn.de + +// HeiyuSpace : https://lazycat.cloud +// Submitted by Xia Bin +heiyu.space + +// Helio Networks : https://heliohost.org +// Submitted by Ben Frede +helioho.st +heliohost.us + +// Hepforge : https://www.hepforge.org +// Submitted by David Grellscheid +hepforge.org + +// Heroku : https://www.heroku.com/ +// Submitted by Shumon Huque +herokuapp.com + +// Heyflow : https://www.heyflow.com +// Submitted by Mirko Nitschke +heyflow.page +heyflow.site + +// Hibernating Rhinos +// Submitted by Oren Eini +ravendb.cloud +ravendb.community +development.run +ravendb.run + +// HiDNS : https://www.hidoha.net +// Submitted by ifeng +hidns.co +hidns.vip + +// home.pl S.A. : https://home.pl +// Submitted by Krzysztof Wolski +homesklep.pl + +// Homebase : https://homebase.id/ +// Submitted by Jason Babo +*.kin.one +*.id.pub +*.kin.pub + +// Hoplix : https://www.hoplix.com +// Submitted by Danilo De Franco +hoplix.shop + +// HOSTBIP REGISTRY : https://www.hostbip.com/ +// Submitted by Atanunu Igbunuroghene +orx.biz +biz.ng +co.biz.ng +dl.biz.ng +go.biz.ng +lg.biz.ng +on.biz.ng +col.ng +firm.ng +gen.ng +ltd.ng +ngo.ng +plc.ng + +// HostyHosting : https://hostyhosting.com +hostyhosting.io + +// Hugging Face : https://huggingface.co +// Submitted by Eliott Coyac +hf.space +static.hf.space + +// Hypernode B.V. : https://www.hypernode.com/ +// Submitted by Cipriano Groenendal +hypernode.io + +// I-O DATA DEVICE, INC. : http://www.iodata.com/ +// Submitted by Yuji Minagawa +iobb.net + +// i-registry s.r.o. : http://www.i-registry.cz/ +// Submitted by Martin Semrad +co.cz + +// Ici la Lune : http://www.icilalune.com/ +// Submitted by Simon Morvan +*.moonscale.io +moonscale.net + +// iDOT Services Limited : http://www.domain.gr.com +// Submitted by Gavin Brown +gr.com + +// iki.fi +// Submitted by Hannu Aronsson +iki.fi + +// iliad italia : https://www.iliad.it +// Submitted by Marios Makassikis +ibxos.it +iliadboxos.it + +// Incsub, LLC : https://incsub.com/ +// Submitted by Aaron Edwards +smushcdn.com +wphostedmail.com +wpmucdn.com +tempurl.host +wpmudev.host + +// Individual Network Berlin e.V. : https://www.in-berlin.de/ +// Submitted by Christian Seitz +dyn-berlin.de +in-berlin.de +in-brb.de +in-butter.de +in-dsl.de +in-vpn.de +in-dsl.net +in-vpn.net +in-dsl.org +in-vpn.org + +// Inferno Communications : https://inferno.co.uk +// Submitted by Connor McFarlane +oninferno.net + +// info.at : http://www.info.at/ +biz.at +info.at + +// info.cx : http://info.cx +// Submitted by June Slater +info.cx + +// Interlegis : http://www.interlegis.leg.br +// Submitted by Gabriel Ferreira +ac.leg.br +al.leg.br +am.leg.br +ap.leg.br +ba.leg.br +ce.leg.br +df.leg.br +es.leg.br +go.leg.br +ma.leg.br +mg.leg.br +ms.leg.br +mt.leg.br +pa.leg.br +pb.leg.br +pe.leg.br +pi.leg.br +pr.leg.br +rj.leg.br +rn.leg.br +ro.leg.br +rr.leg.br +rs.leg.br +sc.leg.br +se.leg.br +sp.leg.br +to.leg.br + +// intermetrics GmbH : https://pixolino.com/ +// Submitted by Wolfgang Schwarz +pixolino.com + +// Internet-Pro, LLP : https://netangels.ru/ +// Submitted by Vasiliy Sheredeko +na4u.ru + +// Inventor Services : https://inventor.gg/ +// Submitted by Inventor Team +botdash.app +botdash.dev +botdash.gg +botdash.net +botda.sh +botdash.xyz + +// IONOS SE : https://www.ionos.com/ +// IONOS Group SE : https://www.ionos-group.com/ +// Submitted by Henrik Willert +apps-1and1.com +live-website.com +webspace-host.com +apps-1and1.net +websitebuilder.online +app-ionos.space + +// iopsys software solutions AB : https://iopsys.eu/ +// Submitted by Roman Azarenko +iopsys.se + +// IPFS Project : https://ipfs.tech/ +// Submitted by Interplanetary Shipyard +*.inbrowser.dev +*.dweb.link +*.inbrowser.link + +// IPiFony Systems, Inc. : https://www.ipifony.com/ +// Submitted by Matthew Hardeman +ipifony.net + +// ir.md : https://nic.ir.md +// Submitted by Ali Soizi +ir.md + +// is-a-good.dev : https://is-a-good.dev +// Submitted by William Harrison +is-a-good.dev + +// IServ GmbH : https://iserv.de +// Submitted by Kim Brodowski +iservschule.de +mein-iserv.de +schuldock.de +schulplattform.de +schulserver.de +test-iserv.de +iserv.dev +iserv.host + +// Jelastic, Inc. : https://jelastic.com/ +// Submitted by Ihor Kolodyuk +mel.cloudlets.com.au +cloud.interhostsolutions.be +alp1.ae.flow.ch +appengine.flow.ch +es-1.axarnet.cloud +diadem.cloud +vip.jelastic.cloud +jele.cloud +it1.eur.aruba.jenv-aruba.cloud +it1.jenv-aruba.cloud +keliweb.cloud +cs.keliweb.cloud +oxa.cloud +tn.oxa.cloud +uk.oxa.cloud +primetel.cloud +uk.primetel.cloud +ca.reclaim.cloud +uk.reclaim.cloud +us.reclaim.cloud +ch.trendhosting.cloud +de.trendhosting.cloud +jele.club +dopaas.com +paas.hosted-by-previder.com +rag-cloud.hosteur.com +rag-cloud-ch.hosteur.com +jcloud.ik-server.com +jcloud-ver-jpc.ik-server.com +demo.jelastic.com +paas.massivegrid.com +jed.wafaicloud.com +ryd.wafaicloud.com +j.scaleforce.com.cy +jelastic.dogado.eu +fi.cloudplatform.fi +demo.datacenter.fi +paas.datacenter.fi +jele.host +mircloud.host +paas.beebyte.io +sekd1.beebyteapp.io +jele.io +jc.neen.it +jcloud.kz +cloudjiffy.net +fra1-de.cloudjiffy.net +west1-us.cloudjiffy.net +jls-sto1.elastx.net +jls-sto2.elastx.net +jls-sto3.elastx.net +fr-1.paas.massivegrid.net +lon-1.paas.massivegrid.net +lon-2.paas.massivegrid.net +ny-1.paas.massivegrid.net +ny-2.paas.massivegrid.net +sg-1.paas.massivegrid.net +jelastic.saveincloud.net +nordeste-idc.saveincloud.net +j.scaleforce.net +sdscloud.pl +unicloud.pl +mircloud.ru +enscaled.sg +jele.site +jelastic.team +orangecloud.tn +j.layershift.co.uk +phx.enscaled.us +mircloud.us + +// Jino : https://www.jino.ru +// Submitted by Sergey Ulyashin +myjino.ru +*.hosting.myjino.ru +*.landing.myjino.ru +*.spectrum.myjino.ru +*.vps.myjino.ru + +// Jotelulu S.L. : https://jotelulu.com +// Submitted by Daniel Fariña +jote.cloud +jotelulu.cloud +eu1-plenit.com +la1-plenit.com +us1-plenit.com + +// JouwWeb B.V. : https://www.jouwweb.nl +// Submitted by Camilo Sperberg +webadorsite.com +jouwweb.site + +// Joyent : https://www.joyent.com/ +// Submitted by Brian Bennett +*.cns.joyent.com +*.triton.zone + +// JS.ORG : http://dns.js.org +// Submitted by Stefan Keim +js.org + +// KaasHosting : http://www.kaashosting.nl/ +// Submitted by Wouter Bakker +kaas.gg +khplay.nl + +// Kapsi : https://kapsi.fi +// Submitted by Tomi Juntunen +kapsi.fi + +// Katholieke Universiteit Leuven : https://www.kuleuven.be +// Submitted by Abuse KU Leuven +ezproxy.kuleuven.be +kuleuven.cloud + +// Keyweb AG : https://www.keyweb.de +// Submitted by Martin Dannehl +keymachine.de + +// KingHost : https://king.host +// Submitted by Felipe Keller Braz +kinghost.net +uni5.net + +// KnightPoint Systems, LLC : http://www.knightpoint.com/ +// Submitted by Roy Keene +knightpoint.systems + +// KoobinEvent, SL : https://www.koobin.com +// Submitted by Iván Oliva +koobin.events + +// Krellian Ltd. : https://krellian.com +// Submitted by Ben Francis +webthings.io +krellian.net + +// KUROKU LTD : https://kuroku.ltd/ +// Submitted by DisposaBoy +oya.to + +// KV GmbH : https://www.nic.co.de +// Submitted by KV GmbH +// Abuse reports to +co.de + +// Laravel Holdings, Inc. : https://laravel.com +// Submitted by André Valentin & James Brooks +laravel.cloud +on-forge.com +on-vapor.com + +// LCube - Professional hosting e.K. : https://www.lcube-webhosting.de +// Submitted by Lars Laehn +git-repos.de +lcube-server.de +svn-repos.de + +// Leadpages : https://www.leadpages.net +// Submitted by Greg Dallavalle +leadpages.co +lpages.co +lpusercontent.com + +// Leapcell : https://leapcell.io/ +// Submitted by Leapcell Team +leapcell.app +leapcell.dev +leapcell.online + +// Liara : https://liara.ir +// Submitted by Amirhossein Badinloo +liara.run +iran.liara.run + +// libp2p project : https://libp2p.io +// Submitted by Interplanetary Shipyard +libp2p.direct + +// Libre IT Ltd : https://libre.nz +// Submitted by Tomas Maggio +runcontainers.dev + +// Lifetime Hosting : https://Lifetime.Hosting/ +// Submitted by Mike Fillator +co.business +co.education +co.events +co.financial +co.network +co.place +co.technology + +// linkyard ldt : https://www.linkyard.ch/ +// Submitted by Mario Siegenthaler +linkyard-cloud.ch +linkyard.cloud + +// Linode : https://linode.com +// Submitted by +members.linode.com +*.nodebalancer.linode.com +*.linodeobjects.com +ip.linodeusercontent.com + +// LiquidNet Ltd : http://www.liquidnetlimited.com/ +// Submitted by Victor Velchev +we.bs + +// Listen53 : https://www.l53.net +// Submitted by Gerry Keh +filegear-sg.me +ggff.net + +// Localcert : https://localcert.dev +// Submitted by Lann Martin +*.user.localcert.dev + +// Localtonet : https://localtonet.com/ +// Submitted by Burak Isleyici +localtonet.com +*.localto.net + +// Lodz University of Technology LODMAN regional domains : https://www.man.lodz.pl/dns +// Submitted by Piotr Wilk +lodz.pl +pabianice.pl +plock.pl +sieradz.pl +skierniewice.pl +zgierz.pl + +// Log'in Line : https://www.loginline.com/ +// Submitted by Rémi Mach +loginline.app +loginline.dev +loginline.io +loginline.services +loginline.site + +// Lõhmus Family, The : https://lohmus.me/ +// Submitted by Heiki Lõhmus +lohmus.me + +// Lovable : https://lovable.dev +// Submitted by Fabian Hedin +lovable.app +lovableproject.com +lovable.run +lovable.sh + +// LubMAN UMCS Sp. z o.o : https://lubman.pl/ +// Submitted by Ireneusz Maliszewski +krasnik.pl +leczna.pl +lubartow.pl +lublin.pl +poniatowa.pl +swidnik.pl + +// Lug.org.uk : https://lug.org.uk +// Submitted by Jon Spriggs +glug.org.uk +lug.org.uk +lugs.org.uk + +// Lukanet Ltd : https://lukanet.com +// Submitted by Anton Avramov +barsy.bg +barsy.club +barsycenter.com +barsyonline.com +barsy.de +barsy.dev +barsy.eu +barsy.gr +barsy.in +barsy.info +barsy.io +barsy.me +barsy.menu +barsyonline.menu +barsy.mobi +barsy.net +barsy.online +barsy.org +barsy.pro +barsy.pub +barsy.ro +barsy.rs +barsy.shop +barsyonline.shop +barsy.site +barsy.store +barsy.support +barsy.uk +barsy.co.uk +barsyonline.co.uk + +// Lutra : https://lutra.ai +// Submitted by Joshua Newman +*.lutrausercontent.com + +// Luyani Inc. : https://luyani.com/ +// Submitted by Umut Gumeli +luyani.app +luyani.net + +// Magento Commerce +// Submitted by Damien Tournoud +*.magentosite.cloud + +// Mail.Ru Group : https://hb.cldmail.ru +// Submitted by Ilya Zaretskiy +hb.cldmail.ru + +// MathWorks : https://www.mathworks.com/ +// Submitted by Emily Reed +matlab.cloud +modelscape.com +mwcloudnonprod.com +polyspace.com + +// May First - People Link : https://mayfirst.org/ +// Submitted by Jamie McClelland +mayfirst.info +mayfirst.org + +// Maze Play : https://www.mazeplay.com +// Submitted by Adam Humpherys +mazeplay.com + +// McHost : https://mchost.ru +// Submitted by Evgeniy Subbotin +mcdir.me +mcdir.ru +vps.mcdir.ru +mcpre.ru + +// Mediatech : https://mediatech.by +// Submitted by Evgeniy Kozhuhovskiy +mediatech.by +mediatech.dev + +// Medicom Health : https://medicomhealth.com +// Submitted by Michael Olson +hra.health + +// MedusaJS, Inc : https://medusajs.com/ +// Submitted by Stevche Radevski +medusajs.app + +// Memset hosting : https://www.memset.com +// Submitted by Tom Whitwell +miniserver.com +memset.net + +// Messerli Informatik AG : https://www.messerli.ch/ +// Submitted by Ruben Schmidmeister +messerli.app + +// Meta Platforms, Inc. : https://meta.com/ +// Submitted by Jacob Cordero +atmeta.com +apps.fbsbx.com + +// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ +// Submitted by Zdeněk Šustr and Radim Janča +*.cloud.metacentrum.cz +custom.metacentrum.cz +flt.cloud.muni.cz +usr.cloud.muni.cz + +// Meteor Development Group : https://www.meteor.com/hosting +// Submitted by Pierre Carrier +meteorapp.com +eu.meteorapp.com + +// Michau Enterprises Limited : http://www.co.pl/ +co.pl + +// Microsoft Corporation : http://microsoft.com +// Submitted by Public Suffix List Admin +// Managed by Corporate Domains +// Microsoft Azure : https://home.azure +*.azurecontainer.io +azure-api.net +azure-mobile.net +azureedge.net +azurefd.net +azurestaticapps.net +1.azurestaticapps.net +2.azurestaticapps.net +3.azurestaticapps.net +4.azurestaticapps.net +5.azurestaticapps.net +6.azurestaticapps.net +7.azurestaticapps.net +centralus.azurestaticapps.net +eastasia.azurestaticapps.net +eastus2.azurestaticapps.net +westeurope.azurestaticapps.net +westus2.azurestaticapps.net +azurewebsites.net +cloudapp.net +trafficmanager.net +blob.core.windows.net +servicebus.windows.net + +// MikroTik : https://mikrotik.com +// Submitted by MikroTik SysAdmin Team +routingthecloud.com +sn.mynetname.net +routingthecloud.net +routingthecloud.org + +// Million Software, Inc : https://million.dev/ +// Submitted by Rayhan Noufal Arayilakath +same-app.com +same-preview.com + +// minion.systems : http://minion.systems +// Submitted by Robert Böttinger +csx.cc + +// Mittwald CM Service GmbH & Co. KG : https://mittwald.de +// Submitted by Marco Rieger +mydbserver.com +webspaceconfig.de +mittwald.info +mittwaldserver.info +typo3server.info +project.space + +// MODX Systems LLC : https://modx.com +// Submitted by Elizabeth Southwell +modx.dev + +// Mozilla Foundation : https://mozilla.org/ +// Submitted by glob +bmoattachments.org + +// MSK-IX : https://www.msk-ix.ru/ +// Submitted by Khannanov Roman +net.ru +org.ru +pp.ru + +// Mythic Beasts : https://www.mythic-beasts.com +// Submitted by Paul Cammish +hostedpi.com +caracal.mythic-beasts.com +customer.mythic-beasts.com +fentiger.mythic-beasts.com +lynx.mythic-beasts.com +ocelot.mythic-beasts.com +oncilla.mythic-beasts.com +onza.mythic-beasts.com +sphinx.mythic-beasts.com +vs.mythic-beasts.com +x.mythic-beasts.com +yali.mythic-beasts.com +cust.retrosnub.co.uk + +// Nabu Casa : https://www.nabucasa.com +// Submitted by Paulus Schoutsen +ui.nabu.casa + +// Net at Work Gmbh : https://www.netatwork.de +// Submitted by Jan Jaeschke +cloud.nospamproxy.com +o365.cloud.nospamproxy.com + +// Net libre : https://www.netlib.re +// Submitted by Philippe PITTOLI +netlib.re + +// Netfy Domains : https://netfy.domains +// Submitted by Suranga Ranasinghe +netfy.app + +// Netlify : https://www.netlify.com +// Submitted by Jessica Parsons +netlify.app + +// Neustar Inc. +// Submitted by Trung Tran +4u.com + +// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ +// Submitted by Jeff Wheelhouse +nfshost.com + +// NFT.Storage : https://nft.storage/ +// Submitted by Vasco Santos or +ipfs.nftstorage.link + +// NGO.US Registry : https://nic.ngo.us +// Submitted by Alstra Solutions Ltd. Networking Team +ngo.us + +// ngrok : https://ngrok.com/ +// Submitted by Alan Shreve +ngrok.app +ngrok-free.app +ngrok.dev +ngrok-free.dev +ngrok.io +ap.ngrok.io +au.ngrok.io +eu.ngrok.io +in.ngrok.io +jp.ngrok.io +sa.ngrok.io +us.ngrok.io +ngrok.pizza +ngrok.pro + +// Nicolaus Copernicus University in Torun - MSK TORMAN : https://www.man.torun.pl +torun.pl + +// Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ +// Submitted by Nicholas Ford +nh-serv.co.uk +nimsite.uk + +// No-IP.com : https://noip.com/ +// Submitted by Deven Reza +mmafan.biz +myftp.biz +no-ip.biz +no-ip.ca +fantasyleague.cc +gotdns.ch +3utilities.com +blogsyte.com +ciscofreak.com +damnserver.com +ddnsking.com +ditchyourip.com +dnsiskinky.com +dynns.com +geekgalaxy.com +health-carereform.com +homesecuritymac.com +homesecuritypc.com +myactivedirectory.com +mysecuritycamera.com +myvnc.com +net-freaks.com +onthewifi.com +point2this.com +quicksytes.com +securitytactics.com +servebeer.com +servecounterstrike.com +serveexchange.com +serveftp.com +servegame.com +servehalflife.com +servehttp.com +servehumour.com +serveirc.com +servemp3.com +servep2p.com +servepics.com +servequake.com +servesarcasm.com +stufftoread.com +unusualperson.com +workisboring.com +dvrcam.info +ilovecollege.info +no-ip.info +brasilia.me +ddns.me +dnsfor.me +hopto.me +loginto.me +noip.me +webhop.me +bounceme.net +ddns.net +eating-organic.net +mydissent.net +myeffect.net +mymediapc.net +mypsx.net +mysecuritycamera.net +nhlfan.net +no-ip.net +pgafan.net +privatizehealthinsurance.net +redirectme.net +serveblog.net +serveminecraft.net +sytes.net +cable-modem.org +collegefan.org +couchpotatofries.org +hopto.org +mlbfan.org +myftp.org +mysecuritycamera.org +nflfan.org +no-ip.org +read-books.org +ufcfan.org +zapto.org +no-ip.co.uk +golffan.us +noip.us +pointto.us + +// NodeArt : https://nodeart.io +// Submitted by Konstantin Nosov +stage.nodeart.io + +// Noop : https://noop.app +// Submitted by Nathaniel Schweinberg +*.developer.app +noop.app + +// Northflank Ltd. : https://northflank.com/ +// Submitted by Marco Suter +*.northflank.app +*.build.run +*.code.run +*.database.run +*.migration.run + +// Noticeable : https://noticeable.io +// Submitted by Laurent Pellegrino +noticeable.news + +// Notion Labs, Inc : https://www.notion.so/ +// Submitted by Jess Yao +notion.site + +// Now-DNS : https://now-dns.com +// Submitted by Steve Russell +dnsking.ch +mypi.co +myiphost.com +forumz.info +soundcast.me +tcp4.me +dnsup.net +hicam.net +now-dns.net +ownip.net +vpndns.net +dynserv.org +now-dns.org +x443.pw +ntdll.top +freeddns.us + +// nsupdate.info : https://www.nsupdate.info/ +// Submitted by Thomas Waldmann +nsupdate.info +nerdpol.ovh + +// NYC.mn : https://dot.nyc.mn/ +// Submitted by NYC.mn Subdomain Service +nyc.mn + +// O3O.Foundation : https://o3o.foundation/ +// Submitted by the prvcy.page Registry Team +prvcy.page + +// Obl.ong : https://obl.ong +// Submitted by Reese Armstrong +obl.ong + +// Observable, Inc. : https://observablehq.com +// Submitted by Mike Bostock +observablehq.cloud +static.observableusercontent.com + +// OMG.LOL : https://omg.lol +// Submitted by Adam Newbold +omg.lol + +// Omnibond Systems, LLC. : https://www.omnibond.com +// Submitted by Cole Estep +cloudycluster.net + +// OmniWe Limited : https://omniwe.com +// Submitted by Vicary Archangel +omniwe.site + +// One.com : https://www.one.com/ +// Submitted by Jacob Bunk Nielsen +123webseite.at +123website.be +simplesite.com.br +123website.ch +simplesite.com +123webseite.de +123hjemmeside.dk +123miweb.es +123kotisivu.fi +123siteweb.fr +simplesite.gr +123homepage.it +123website.lu +123website.nl +123hjemmeside.no +service.one +simplesite.pl +123paginaweb.pt +123minsida.se + +// ONID : https://get.onid.ca +// Submitted by ONID Engineering Team +onid.ca + +// Open Domains : https://open-domains.net +// Submitted by William Harrison +is-a-fullstack.dev +is-cool.dev +is-not-a.dev +localplayer.dev +is-local.org + +// Open Social : https://www.getopensocial.com/ +// Submitted by Alexander Varwijk +opensocial.site + +// OpenAI : https://openai.com +// Submitted by Thomas Shadwell +*.oaiusercontent.com + +// OpenCraft GmbH : http://opencraft.com/ +// Submitted by Sven Marnach +opencraft.hosting + +// OpenHost : https://registry.openhost.uk +// Submitted by OpenHost Registry Team +16-b.it +32-b.it +64-b.it + +// OpenResearch GmbH : https://openresearch.com/ +// Submitted by Philipp Schmid +orsites.com + +// Opera Software, A.S.A. +// Submitted by Yngve Pettersen +operaunite.com + +// Oracle Dyn : https://cloud.oracle.com/home https://dyn.com/dns/ +// Submitted by Gregory Drake +// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label +*.customer-oci.com +*.oci.customer-oci.com +*.ocp.customer-oci.com +*.ocs.customer-oci.com +*.oraclecloudapps.com +*.oraclegovcloudapps.com +*.oraclegovcloudapps.uk + +// Orange : https://www.orange.com +// Submitted by Alexandre Linte +tech.orange + +// OsSav Technology Ltd. : https://ossav.com/ +// Submitted by OsSav Technology Ltd. +// https://nic.can.re +can.re + +// Oursky Limited : https://authgear.com/ +// Submitted by Authgear Team & Skygear Developer +authgear-staging.com +authgearapps.com +skygearapp.com + +// OutSystems +// Submitted by Duarte Santos +outsystemscloud.com + +// OVHcloud : https://ovhcloud.com +// Submitted by Vincent Cassé +*.hosting.ovh.net +*.webpaas.ovh.net + +// OwnProvider GmbH : http://www.ownprovider.com +// Submitted by Jan Moennich +ownprovider.com +own.pm + +// OwO : https://whats-th.is/ +// Submitted by Dean Sheather +*.owo.codes + +// OX : http://www.ox.rs +// Submitted by Adam Grand +ox.rs + +// oy.lc +// Submitted by Charly Coste +oy.lc + +// Pagefog : https://pagefog.com/ +// Submitted by Derek Myers +pgfog.com + +// PageXL : https://pagexl.com +// Submitted by Yann Guichard +pagexl.com + +// Pantheon Systems, Inc. : https://pantheon.io/ +// Submitted by Gary Dylina +gotpantheon.com +pantheonsite.io + +// Paywhirl, Inc : https://paywhirl.com/ +// Submitted by Daniel Netzer +*.paywhirl.com + +// pcarrier.ca Software Inc : https://pcarrier.ca/ +// Submitted by Pierre Carrier +*.xmit.co +xmit.dev +madethis.site +srv.us +gh.srv.us +gl.srv.us + +// PE Ulyanov Kirill Sergeevich : https://airy.host +// Submitted by Kirill Ulyanov +lk3.ru + +// Peplink | Pepwave : http://peplink.com/ +// Submitted by Steve Leung +mypep.link + +// Perspecta : https://perspecta.com/ +// Submitted by Kenneth Van Alstyne +perspecta.cloud + +// Plain : https://www.plain.com/ +// Submitted by Jesús Hernández +support.site + +// Planet-Work : https://www.planet-work.com/ +// Submitted by Frédéric VANNIÈRE +on-web.fr + +// Platform.sh : https://platform.sh +// Submitted by Nikola Kotur +*.upsun.app +upsunapp.com +ent.platform.sh +eu.platform.sh +us.platform.sh +*.platformsh.site +*.tst.site + +// Platter : https://platter.dev +// Submitted by Patrick Flor +platter-app.dev +platterp.us + +// Pley AB : https://www.pley.com/ +// Submitted by Henning Pohl +pley.games + +// Porter : https://porter.run/ +// Submitted by Rudraksh MK +onporter.run + +// Positive Codes Technology Company : http://co.bn/faq.html +// Submitted by Zulfais +co.bn + +// Postman, Inc : https://postman.com +// Submitted by Rahul Dhawan +postman-echo.com +pstmn.io +mock.pstmn.io +httpbin.org + +// prequalifyme.today : https://prequalifyme.today +// Submitted by DeepakTiwari deepak@ivylead.io +prequalifyme.today + +// prgmr.com : https://prgmr.com/ +// Submitted by Sarah Newman +xen.prgmr.com + +// priv.at : http://www.nic.priv.at/ +// Submitted by registry +priv.at + +// PROJECT ELIV : https://eliv.kr/ +// Submitted by PROJECT ELIV Domain Team +c01.kr +eliv-cdn.kr +eliv-dns.kr +mmv.kr +vki.kr + +// project-study : https://project-study.com +// Submitted by yumenewa +dev.project-study.com + +// Protonet GmbH : http://protonet.io +// Submitted by Martin Meier +protonet.io + +// PT Ekossistim Indo Digital : https://e.id +// Submitted by Eid Team +e.id + +// Publication Presse Communication SARL : https://ppcom.fr +// Submitted by Yaacov Akiba Slama +chirurgiens-dentistes-en-france.fr +byen.site + +// pubtls.org : https://www.pubtls.org +// Submitted by Kor Nielsen +pubtls.org + +// PythonAnywhere LLP : https://www.pythonanywhere.com +// Submitted by Giles Thomas +pythonanywhere.com +eu.pythonanywhere.com + +// QA2 +// Submitted by Daniel Dent : https://www.danieldent.com/ +qa2.com + +// QCX +// Submitted by Cassandra Beelen +qcx.io +*.sys.qcx.io + +// QNAP System Inc : https://www.qnap.com +// Submitted by Nick Chang +myqnapcloud.cn +alpha-myqnapcloud.com +dev-myqnapcloud.com +mycloudnas.com +mynascloud.com +myqnapcloud.com + +// QOTO, Org. +// Submitted by Jeffrey Phillips Freeman +qoto.io + +// Qualifio : https://qualifio.com/ +// Submitted by Xavier De Cock +qualifioapp.com + +// Quality Unit : https://qualityunit.com +// Submitted by Vasyl Tsalko +ladesk.com + +// Qualy : https://qualyhq.com +// Submitted by Raphael Arias +*.qualyhqpartner.com +*.qualyhqportal.com + +// QuickBackend : https://www.quickbackend.com +// Submitted by Dani Biro +qbuser.com + +// Quip : https://quip.com +// Submitted by Patrick Linehan +*.quipelements.com + +// Qutheory LLC : http://qutheory.io +// Submitted by Jonas Schwartz +vapor.cloud +vaporcloud.io + +// Rackmaze LLC : https://www.rackmaze.com +// Submitted by Kirill Pertsev +rackmaze.com +rackmaze.net + +// Rad Web Hosting : https://radwebhosting.com +// Submitted by Scott Claeys +cloudsite.builders +myradweb.net +servername.us + +// Radix FZC : http://domains.in.net +// Submitted by Gavin Brown +web.in +in.net + +// Raidboxes GmbH : https://raidboxes.de +// Submitted by Auke Tembrink +myrdbx.io +site.rb-hosting.io + +// Railway Corporation : https://railway.com +// Submitted by Phineas Walton +up.railway.app + +// Rancher Labs, Inc : https://rancher.com +// Submitted by Vincent Fiduccia +*.on-rancher.cloud +*.on-k3s.io +*.on-rio.io + +// RavPage : https://www.ravpage.co.il +// Submitted by Roni Horowitz +ravpage.co.il + +// Read The Docs, Inc : https://www.readthedocs.org +// Submitted by David Fischer +readthedocs-hosted.com +readthedocs.io + +// Red Hat, Inc. OpenShift : https://openshift.redhat.com/ +// Submitted by Tim Kramer +rhcloud.com + +// Redgate Software : https://red-gate.com +// Submitted by Andrew Farries +instances.spawn.cc + +// Render : https://render.com +// Submitted by Anurag Goel +onrender.com +app.render.com + +// Repl.it : https://repl.it +// Submitted by Lincoln Bergeson +replit.app +id.replit.app +firewalledreplit.co +id.firewalledreplit.co +repl.co +id.repl.co +replit.dev +archer.replit.dev +bones.replit.dev +canary.replit.dev +global.replit.dev +hacker.replit.dev +id.replit.dev +janeway.replit.dev +kim.replit.dev +kira.replit.dev +kirk.replit.dev +odo.replit.dev +paris.replit.dev +picard.replit.dev +pike.replit.dev +prerelease.replit.dev +reed.replit.dev +riker.replit.dev +sisko.replit.dev +spock.replit.dev +staging.replit.dev +sulu.replit.dev +tarpit.replit.dev +teams.replit.dev +tucker.replit.dev +wesley.replit.dev +worf.replit.dev +repl.run + +// Resin.io : https://resin.io +// Submitted by Tim Perry +resindevice.io +devices.resinstaging.io + +// RethinkDB : https://www.rethinkdb.com/ +// Submitted by Chris Kastorff +hzc.io + +// Rico Developments Limited : https://adimo.co +// Submitted by Colin Brown +adimo.co.uk + +// Riseup Networks : https://riseup.net +// Submitted by Micah Anderson +itcouldbewor.se + +// Roar Domains LLC : https://roar.basketball/ +// Submitted by Gavin Brown +aus.basketball +nz.basketball + +// ROBOT PAYMENT INC. : https://www.robotpayment.co.jp/ +// Submitted by Kentaro Takamori +subsc-pay.com +subsc-pay.net + +// Rochester Institute of Technology : http://www.rit.edu/ +// Submitted by Jennifer Herting +git-pages.rit.edu + +// Rocky Enterprise Software Foundation : https://resf.org +// Submitted by Neil Hanlon +rocky.page + +// Ruhr University Bochum : https://www.ruhr-uni-bochum.de/ +// Submitted by Andreas Jobs +rub.de +ruhr-uni-bochum.de +io.noc.ruhr-uni-bochum.de + +// Rusnames Limited : http://rusnames.ru/ +// Submitted by Sergey Zotov +биз.рус +ком.рус +крым.рус +мир.рус +мск.рус +орг.рус +самара.рус +сочи.рус +спб.рус +я.рус + +// Russian Academy of Sciences +// Submitted by Tech Support +ras.ru + +// Sakura Frp : https://www.natfrp.com +// Submitted by Bobo Liu +nyat.app + +// SAKURA Internet Inc. : https://www.sakura.ad.jp/ +// Submitted by Internet Service Department +180r.com +dojin.com +sakuratan.com +sakuraweb.com +x0.com +2-d.jp +bona.jp +crap.jp +daynight.jp +eek.jp +flop.jp +halfmoon.jp +jeez.jp +matrix.jp +mimoza.jp +ivory.ne.jp +mail-box.ne.jp +mints.ne.jp +mokuren.ne.jp +opal.ne.jp +sakura.ne.jp +sumomo.ne.jp +topaz.ne.jp +netgamers.jp +nyanta.jp +o0o0.jp +rdy.jp +rgr.jp +rulez.jp +s3.isk01.sakurastorage.jp +s3.isk02.sakurastorage.jp +saloon.jp +sblo.jp +skr.jp +tank.jp +uh-oh.jp +undo.jp +rs.webaccel.jp +user.webaccel.jp +websozai.jp +xii.jp +squares.net +jpn.org +kirara.st +x0.to +from.tv +sakura.tv + +// Salesforce.com, Inc. : https://salesforce.com/ +// Submitted by Salesforce Public Suffix List Team +*.builder.code.com +*.dev-builder.code.com +*.stg-builder.code.com +*.001.test.code-builder-stg.platform.salesforce.com +*.d.crm.dev +*.w.crm.dev +*.wa.crm.dev +*.wb.crm.dev +*.wc.crm.dev +*.wd.crm.dev +*.we.crm.dev +*.wf.crm.dev + +// Sandstorm Development Group, Inc. : https://sandcats.io/ +// Submitted by Asheesh Laroia +sandcats.io + +// SBE network solutions GmbH : https://www.sbe.de/ +// Submitted by Norman Meilick +logoip.com +logoip.de + +// Scaleway : https://www.scaleway.com/ +// Submitted by Scaleway PSL Maintainer +fr-par-1.baremetal.scw.cloud +fr-par-2.baremetal.scw.cloud +nl-ams-1.baremetal.scw.cloud +cockpit.fr-par.scw.cloud +ddl.fr-par.scw.cloud +dtwh.fr-par.scw.cloud +fnc.fr-par.scw.cloud +functions.fnc.fr-par.scw.cloud +ifr.fr-par.scw.cloud +k8s.fr-par.scw.cloud +nodes.k8s.fr-par.scw.cloud +kafk.fr-par.scw.cloud +mgdb.fr-par.scw.cloud +rdb.fr-par.scw.cloud +s3.fr-par.scw.cloud +s3-website.fr-par.scw.cloud +scbl.fr-par.scw.cloud +whm.fr-par.scw.cloud +priv.instances.scw.cloud +pub.instances.scw.cloud +k8s.scw.cloud +cockpit.nl-ams.scw.cloud +ddl.nl-ams.scw.cloud +dtwh.nl-ams.scw.cloud +ifr.nl-ams.scw.cloud +k8s.nl-ams.scw.cloud +nodes.k8s.nl-ams.scw.cloud +kafk.nl-ams.scw.cloud +mgdb.nl-ams.scw.cloud +rdb.nl-ams.scw.cloud +s3.nl-ams.scw.cloud +s3-website.nl-ams.scw.cloud +scbl.nl-ams.scw.cloud +whm.nl-ams.scw.cloud +cockpit.pl-waw.scw.cloud +ddl.pl-waw.scw.cloud +dtwh.pl-waw.scw.cloud +ifr.pl-waw.scw.cloud +k8s.pl-waw.scw.cloud +nodes.k8s.pl-waw.scw.cloud +kafk.pl-waw.scw.cloud +mgdb.pl-waw.scw.cloud +rdb.pl-waw.scw.cloud +s3.pl-waw.scw.cloud +s3-website.pl-waw.scw.cloud +scbl.pl-waw.scw.cloud +scalebook.scw.cloud +smartlabeling.scw.cloud +dedibox.fr + +// schokokeks.org GbR : https://schokokeks.org/ +// Submitted by Hanno Böck +schokokeks.net + +// Scottish Government : https://www.gov.scot +// Submitted by Martin Ellis +gov.scot +service.gov.scot + +// Scry Security : http://www.scrysec.com +// Submitted by Shante Adam +scrysec.com + +// Scrypted : https://scrypted.app +// Submitted by Koushik Dutta +client.scrypted.io + +// Securepoint GmbH : https://www.securepoint.de +// Submitted by Erik Anders +firewall-gateway.com +firewall-gateway.de +my-gateway.de +my-router.de +spdns.de +spdns.eu +firewall-gateway.net +my-firewall.org +myfirewall.org +spdns.org + +// Seidat : https://www.seidat.com +// Submitted by Artem Kondratev +seidat.net + +// Sellfy : https://sellfy.com +// Submitted by Yuriy Romadin +sellfy.store + +// Sendmsg : https://www.sendmsg.co.il +// Submitted by Assaf Stern +minisite.ms + +// Senseering GmbH : https://www.senseering.de +// Submitted by Felix Mönckemeyer +senseering.net + +// Servebolt AS : https://servebolt.com +// Submitted by Daniel Kjeserud +servebolt.cloud + +// Service Online LLC : http://drs.ua/ +// Submitted by Serhii Bulakh +biz.ua +co.ua +pp.ua + +// Shanghai Accounting Society : https://www.sasf.org.cn +// Submitted by Information Administration +as.sh.cn + +// Sheezy.Art : https://sheezy.art +// Submitted by Nyoom +sheezy.games + +// Shopblocks : http://www.shopblocks.com/ +// Submitted by Alex Bowers +myshopblocks.com + +// Shopify : https://www.shopify.com +// Submitted by Alex Richter +myshopify.com + +// Shopit : https://www.shopitcommerce.com/ +// Submitted by Craig McMahon +shopitsite.com + +// shopware AG : https://shopware.com +// Submitted by Jens Küper +shopware.shop +shopware.store + +// Siemens Mobility GmbH +// Submitted by Oliver Graebner +mo-siemens.io + +// SinaAppEngine : http://sae.sina.com.cn/ +// Submitted by SinaAppEngine +1kapp.com +appchizi.com +applinzi.com +sinaapp.com +vipsinaapp.com + +// Siteleaf : https://www.siteleaf.com/ +// Submitted by Skylar Challand +siteleaf.net + +// Small Technology Foundation : https://small-tech.org +// Submitted by Aral Balkan +small-web.org + +// Smallregistry by Promopixel SARL : https://www.smallregistry.net +// Former AFNIC's SLDs +// Submitted by Jérôme Lipowicz +aeroport.fr +avocat.fr +chambagri.fr +chirurgiens-dentistes.fr +experts-comptables.fr +medecin.fr +notaires.fr +pharmacien.fr +port.fr +veterinaire.fr + +// Smoove.io : https://www.smoove.io/ +// Submitted by Dan Kozak +vp4.me + +// Snowflake Inc : https://www.snowflake.com/ +// Submitted by Sam Haar +*.snowflake.app +*.privatelink.snowflake.app +streamlit.app +streamlitapp.com + +// Snowplow Analytics : https://snowplowanalytics.com/ +// Submitted by Ian Streeter +try-snowplow.com + +// Software Consulting Michal Zalewski : https://www.mafelo.com +// Submitted by Michal Zalewski +mafelo.net + +// Sony Interactive Entertainment LLC : https://sie.com/ +// Submitted by David Coles +playstation-cloud.com + +// SourceHut : https://sourcehut.org +// Submitted by Drew DeVault +srht.site + +// SourceLair PC : https://www.sourcelair.com +// Submitted by Antonis Kalipetis +apps.lair.io +*.stolos.io + +// sourceWAY GmbH : https://sourceway.de +// Submitted by Richard Reiber +4.at +my.at +my.de +*.nxa.eu +nx.gw + +// SpeedPartner GmbH : https://www.speedpartner.de/ +// Submitted by Stefan Neufeind +customer.speedpartner.de + +// Spreadshop (sprd.net AG) : https://www.spreadshop.com/ +// Submitted by Martin Breest +myspreadshop.at +myspreadshop.com.au +myspreadshop.be +myspreadshop.ca +myspreadshop.ch +myspreadshop.com +myspreadshop.de +myspreadshop.dk +myspreadshop.es +myspreadshop.fi +myspreadshop.fr +myspreadshop.ie +myspreadshop.it +myspreadshop.net +myspreadshop.nl +myspreadshop.no +myspreadshop.pl +myspreadshop.se +myspreadshop.co.uk + +// StackBlitz : https://stackblitz.com +// Submitted by Dominic Elm & Albert Pai +w-corp-staticblitz.com +w-credentialless-staticblitz.com +w-staticblitz.com +bolt.host + +// Stackhero : https://www.stackhero.io +// Submitted by Adrien Gillon +stackhero-network.com + +// STACKIT GmbH & Co. KG : https://www.stackit.de/en/ +// Submitted by STACKIT-DNS Team (Simon Stier) +runs.onstackit.cloud +stackit.gg +stackit.rocks +stackit.run +stackit.zone + +// Staclar : https://staclar.com +// Submitted by Q Misell +// Submitted by Matthias Merkel +musician.io +novecore.site + +// Standard Library : https://stdlib.com +// Submitted by Jacob Lee +api.stdlib.com + +// stereosense GmbH : https://www.involve.me +// Submitted by Florian Burmann +feedback.ac +forms.ac +assessments.cx +calculators.cx +funnels.cx +paynow.cx +quizzes.cx +researched.cx +tests.cx +surveys.so + +// Storacha Network : https://storacha.network +// Submitted by Alan Shaw +ipfs.storacha.link +ipfs.w3s.link + +// Storebase : https://www.storebase.io +// Submitted by Tony Schirmer +storebase.store + +// Storipress : https://storipress.com +// Submitted by Benno Liu +storipress.app + +// Storj Labs Inc. : https://storj.io/ +// Submitted by Philip Hutchins +storj.farm + +// Strapi : https://strapi.io/ +// Submitted by Florent Baldino +strapiapp.com +media.strapiapp.com + +// Strategic System Consulting (eApps Hosting) : https://www.eapps.com/ +// Submitted by Alex Oancea +vps-host.net +atl.jelastic.vps-host.net +njs.jelastic.vps-host.net +ric.jelastic.vps-host.net + +// Streak : https://streak.com +// Submitted by Blake Kadatz +streak-link.com +streaklinks.com +streakusercontent.com + +// Student-Run Computing Facility : https://www.srcf.net/ +// Submitted by Edwin Balani +soc.srcf.net +user.srcf.net + +// Studenten Net Twente : http://www.snt.utwente.nl/ +// Submitted by Silke Hofstra +utwente.io + +// Sub 6 Limited : http://www.sub6.com +// Submitted by Dan Miller +temp-dns.com + +// Supabase : https://supabase.io +// Submitted by Supabase Security +supabase.co +realtime.supabase.co +storage.supabase.co +supabase.in +supabase.net + +// Syncloud : https://syncloud.org +// Submitted by Boris Rybalkin +syncloud.it + +// Synology, Inc. : https://www.synology.com/ +// Submitted by Rony Weng +dscloud.biz +direct.quickconnect.cn +dsmynas.com +familyds.com +diskstation.me +dscloud.me +i234.me +myds.me +synology.me +dscloud.mobi +dsmynas.net +familyds.net +dsmynas.org +familyds.org +direct.quickconnect.to +vpnplus.to + +// Tabit Technologies Ltd. : https://tabit.cloud/ +// Submitted by Oren Agiv +mytabit.com +mytabit.co.il +tabitorder.co.il + +// TAIFUN Software AG : http://taifun-software.de +// Submitted by Bjoern Henke +taifun-dns.de + +// Tailor Inc. : https://www.tailor.tech +// Submitted by Ryuzo Yamamoto +erp.dev +web.erp.dev + +// Tailscale Inc. : https://www.tailscale.com +// Submitted by David Anderson +ts.net +*.c.ts.net + +// TASK geographical domains : https://task.gda.pl/en/services/for-entrepreneurs/ +gda.pl +gdansk.pl +gdynia.pl +med.pl +sopot.pl + +// Tave Creative Corp : https://tave.com/ +// Submitted by Adrian Ziemkowski +taveusercontent.com + +// tawk.to, Inc : https://www.tawk.to +// Submitted by tawk.to developer team +p.tawk.email +p.tawkto.email + +// Tche.br : https://tche.br +// Submitted by Bruno Lorensi +tche.br + +// team.blue : https://team.blue +// Submitted by Cedric Dubois +site.tb-hosting.com + +// Teckids e.V. : https://www.teckids.org +// Submitted by Dominik George +edugit.io +s3.teckids.org + +// Telebit : https://telebit.cloud +// Submitted by AJ ONeal +telebit.app +telebit.io +*.telebit.xyz + +// Teleport : https://goteleport.com +// Submitted by Rob Picard +teleport.sh + +// Thingdust AG : https://thingdust.com/ +// Submitted by Adrian Imboden +*.firenet.ch +*.svc.firenet.ch +reservd.com +thingdustdata.com +cust.dev.thingdust.io +reservd.dev.thingdust.io +cust.disrec.thingdust.io +reservd.disrec.thingdust.io +cust.prod.thingdust.io +cust.testing.thingdust.io +reservd.testing.thingdust.io + +// ticket i/O GmbH : https://ticket.io +// Submitted by Christian Franke +tickets.io + +// Tlon.io : https://tlon.io +// Submitted by Mark Staarink +arvo.network +azimuth.network +tlon.network + +// Tor Project, Inc. : https://torproject.org +// Submitted by Antoine Beaupré +torproject.net +pages.torproject.net + +// TownNews.com : http://www.townnews.com +// Submitted by Dustin Ward +townnews-staging.com + +// TrafficPlex GmbH : https://www.trafficplex.de/ +// Submitted by Phillipp Röll +12hp.at +2ix.at +4lima.at +lima-city.at +12hp.ch +2ix.ch +4lima.ch +lima-city.ch +trafficplex.cloud +de.cool +12hp.de +2ix.de +4lima.de +lima-city.de +1337.pictures +clan.rip +lima-city.rocks +webspace.rocks +lima.zone + +// TransIP : https://www.transip.nl +// Submitted by Rory Breuk and Cedric Dubois +*.transurl.be +*.transurl.eu +site.transip.me +*.transurl.nl + +// TuxFamily : http://tuxfamily.org +// Submitted by TuxFamily administrators +tuxfamily.org + +// TwoDNS : https://www.twodns.de/ +// Submitted by TwoDNS-Support +dd-dns.de +dray-dns.de +draydns.de +dyn-vpn.de +dynvpn.de +mein-vigor.de +my-vigor.de +my-wan.de +syno-ds.de +synology-diskstation.de +synology-ds.de +diskstation.eu +diskstation.org + +// Typedream : https://typedream.com +// Submitted by Putri Karunia +typedream.app + +// Typeform : https://www.typeform.com +// Submitted by Typeform +pro.typeform.com + +// Uberspace : https://uberspace.de +// Submitted by Moritz Werner +uber.space + +// UDR Limited : http://www.udr.hk.com +// Submitted by registry +hk.com +inc.hk +ltd.hk +hk.org + +// UK Intis Telecom LTD : https://it.com +// Submitted by ITComdomains +it.com + +// Unison Computing, PBC : https://unison.cloud +// Submitted by Simon Højberg +unison-services.cloud + +// United Gameserver GmbH : https://united-gameserver.de +// Submitted by Stefan Schwarz +virtual-user.de +virtualuser.de + +// United States Writing Corporation : https://uswriting.co +// Submitted by Andrew Sampson +obj.ag + +// UNIVERSAL DOMAIN REGISTRY : https://www.udr.org.yt/ +// see also: whois -h whois.udr.org.yt help +// Submitted by Atanunu Igbunuroghene +name.pm +sch.tf +biz.wf +sch.wf +org.yt + +// University of Banja Luka : https://unibl.org +// Domains for Republic of Srpska administrative entity. +// Submitted by Marko Ivanovic +rs.ba + +// University of Bielsko-Biala regional domain : http://dns.bielsko.pl/ +// Submitted by Marcin +bielsko.pl + +// urown.net : https://urown.net +// Submitted by Hostmaster +urown.cloud +dnsupdate.info + +// US REGISTRY LLC : http://us.org +// Submitted by Gavin Brown +us.org + +// V.UA Domain Registry: https://www.v.ua/ +// Submitted by Serhii Rostilo +v.ua + +// Val Town, Inc : https://val.town/ +// Submitted by Tom MacWright +val.run +web.val.run + +// Vercel, Inc : https://vercel.com/ +// Submitted by Laurens Duijvesteijn +vercel.app +v0.build +vercel.dev +vusercontent.net +vercel.run +now.sh + +// VeryPositive SIA : http://very.lv +// Submitted by Danko Aleksejevs +2038.io + +// Virtual-Info : https://www.virtual-info.info/ +// Submitted by Adnan RIHAN +v-info.info + +// VistaBlog : https://vistablog.ir/ +// Submitted by Hossein Piri +vistablog.ir + +// Viva Republica, Inc. : https://toss.im/ +// Submitted by Deus Team +deus-canvas.com + +// Voorloper.com : https://voorloper.com +// Submitted by Nathan van Bakel +voorloper.cloud + +// Vultr Objects : https://www.vultr.com/products/object-storage/ +// Submitted by Niels Maumenee +*.vultrobjects.com + +// Waffle Computer Inc., Ltd. : https://docs.waffleinfo.com +// Submitted by Masayuki Note +wafflecell.com + +// Walrus : https://walrus.xyz +// Submitted by Max Spector +wal.app + +// Webflow, Inc. : https://www.webflow.com +// Submitted by Webflow Security Team +webflow.io +webflowtest.io + +// WebHare bv : https://www.webhare.com/ +// Submitted by Arnold Hendriks +*.webhare.dev + +// WebHotelier Technologies Ltd : https://www.webhotelier.net/ +// Submitted by Apostolos Tsakpinis +bookonline.app +hotelwithflight.com +reserve-online.com +reserve-online.net + +// WebPros International, LLC : https://webpros.com/ +// Submitted by Nicolas Rochelemagne +cprapid.com +pleskns.com +wp2.host +pdns.page +plesk.page +cpanel.site +wpsquared.site + +// WebWaddle Ltd : https://webwaddle.com/ +// Submitted by Merlin Glander +*.wadl.top + +// Western Digital Technologies, Inc : https://www.wdc.com +// Submitted by Jung Jin +remotewd.com + +// Whatbox Inc. : https://whatbox.ca/ +// Submitted by Anthony Ryan +box.ca + +// WIARD Enterprises : https://wiardweb.com +// Submitted by Kidd Hustle +pages.wiardweb.com + +// Wikimedia Foundation : https://wikitech.wikimedia.org +// Submitted by Timo Tijhof +toolforge.org +wmcloud.org +beta.wmcloud.org +wmflabs.org + +// William Harrison : https://wharrison.com.au +// Submitted by William Harrison +wdh.app +hrsn.au +vps.hrsn.au +hrsn.dev +is-a.dev +localcert.net + +// Windsurf : https://windsurf.com +// Submitted by Douglas Chen +windsurf.app +windsurf.build + +// WISP : https://wisp.gg +// Submitted by Stepan Fedotov +panel.gg +daemon.panel.gg + +// Wix.com, Inc. : https://www.wix.com +// Submitted by Shahar Talmi / Alon Kochba +wixsite.com +wixstudio.com +editorx.io +wixstudio.io +wix.run + +// Wizard Zines : https://wizardzines.com +// Submitted by Julia Evans +messwithdns.com + +// WoltLab GmbH : https://www.woltlab.com +// Submitted by Tim Düsterhus +woltlab-demo.com +myforum.community +community-pro.de +diskussionsbereich.de +community-pro.net +meinforum.net + +// Woods Valldata : https://www.woodsvalldata.co.uk/ +// Submitted by Chris Whittle +affinitylottery.org.uk +raffleentry.org.uk +weeklylottery.org.uk + +// WP Engine : https://wpengine.com/ +// Submitted by Michael Smith +// Submitted by Brandon DuRette +wpenginepowered.com +js.wpenginepowered.com + +// XenonCloud GbR : https://xenoncloud.net +// Submitted by Julian Uphoff +*.xenonconnect.de +half.host + +// XnBay Technology : http://www.xnbay.com/ +// Submitted by XnBay Developer +xnbay.com +u2.xnbay.com +u2-local.xnbay.com + +// XS4ALL Internet bv : https://www.xs4all.nl/ +// Submitted by Daniel Mostertman +cistron.nl +demon.nl +xs4all.space + +// Yandex.Cloud LLC : https://cloud.yandex.com +// Submitted by Alexander Lodin +yandexcloud.net +storage.yandexcloud.net +website.yandexcloud.net +sourcecraft.site + +// YesCourse Pty Ltd : https://yescourse.com +// Submitted by Atul Bhouraskar +official.academy + +// Yola : https://www.yola.com/ +// Submitted by Stefano Rivera +yolasite.com + +// Yunohost : https://yunohost.org +// Submitted by Valentin Grimaud +ynh.fr +nohost.me +noho.st + +// ZaNiC : http://www.za.net/ +// Submitted by registry +za.net +za.org + +// ZAP-Hosting GmbH & Co. KG : https://zap-hosting.com +// Submitted by Julian Alker +zap.cloud + +// Zeabur : https://zeabur.com/ +// Submitted by Zeabur Team +zeabur.app + +// Zerops : https://zerops.io/ +// Submitted by Zerops Team +*.zerops.app + +// Zine EOOD : https://zine.bg/ +// Submitted by Martin Angelov +bss.design + +// Zitcom A/S : https://www.zitcom.dk +// Submitted by Emil Stahl +basicserver.io +virtualserver.io +enterprisecloud.nu + +// Zone.ID: https://zone.id +// Submitted by Gx1.org +zone.id + +// ZoneABC : https://zoneabc.net +// Submitted by ZoneABC Team +zabc.net + +// ===END PRIVATE DOMAINS=== \ No newline at end of file diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java b/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java new file mode 100644 index 0000000..cdbed99 --- /dev/null +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java @@ -0,0 +1,56 @@ +/****************************************************************************** + * 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.dmarc; + +import org.junit.Test; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class DMARCTest { + private static final String DMARC_RESPONSE_TEMPLATE = "dmarc=%s (p=%s) header.from=%s"; + private static final String DMARC_NON_RESPONSE_TEMPLATE = "dmarc=none (no policy) header.from="; + + private final MockPublicKeyRecordRetrieverDmarc recordRetrieverDmarc = new MockPublicKeyRecordRetrieverDmarc( + MockPublicKeyRecordRetrieverDmarc.DmarcRecord.dmarcOf( + "d1.example", + "k=rsa; v=DMARC1; p=reject; pct=100; rua=mailto:noc@d1.example"), + MockPublicKeyRecordRetrieverDmarc.DmarcRecord.dmarcOf( + "mail.replit.app", + "k=rsa; v=DMARC1; p=reject; aspf=r; adkim=r; pct=100; rua=mailto:noc@d1.example"), + MockPublicKeyRecordRetrieverDmarc.DmarcRecord.dmarcOf( + "test.replit.app", + "k=rsa; v=DMARC1; p=reject; aspf=s; adkim=s; pct=100; rua=mailto:noc@d1.example") + ); + + private final List passRequests = List.of( + new DmarcRequestMock("/mail/e1.eml","pass", "d1.example", "softfail (spfCheck: transitioning domain of d1.example does not designate 222.222.222.222 as permitted sender) client-ip=222.222.222.222; envelope-from=jqd@d1.example; helo=d1.example", "d1.example", "dmarc=pass (p=reject) header.from=d1.example"), + new DmarcRequestMock("/mail/e2.eml","pass", "replit.app", "pass client-ip=222.222.222.222; envelope-from=jqd@id.firewalledreplit.co; helo=replit.app", "replit.app", "dmarc=pass (p=reject) header.from=mail.replit.app"), + new DmarcRequestMock("/mail/e3.eml","pass", "replit.app", "pass client-ip=222.222.222.222; envelope-from=jqd@id.firewalledreplit.co; helo=replit.app", "replit.app", "dmarc=fail (p=reject) header.from=test.replit.app") + ); + + DMARCVerifier dmarcVerifier = new DMARCVerifier(DMARC_RESPONSE_TEMPLATE, DMARC_NON_RESPONSE_TEMPLATE, recordRetrieverDmarc); + + @Test + public void generate_and_verify_dmarc_pass() { + passRequests.forEach(r -> { + assertThat(dmarcVerifier.runDmarcCheck(r.message(), r.spfResult(), r.spfDomain(), r.dkimResult(), r.dkimDomain())).isEqualTo(r.expectedResult()); + }); + } +} \ No newline at end of file diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/DmarcRequestMock.java b/dmarc/src/main/test/java/org/apache/james/dmarc/DmarcRequestMock.java new file mode 100644 index 0000000..cb9364e --- /dev/null +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/DmarcRequestMock.java @@ -0,0 +1,77 @@ +package org.apache.james.dmarc; + +import org.apache.james.dmarc.exceptions.DmarcException; +import org.apache.james.jdkim.DKIMCommon; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.message.DefaultMessageBuilder; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; + +public class DmarcRequestMock { + private final Message _message; + private final String _dkimResult; + private final String _dkimDomain; + private final String _spfResult; + private final String _spfDomain; + private final String _expectedResult; + + public DmarcRequestMock(String emailPath, String dkimResult, String dkimDomain, String spfResult, String spfDomain, String expectedResult) { + _dkimResult = dkimResult; + _dkimDomain = dkimDomain; + _spfResult = spfResult; + _spfDomain = spfDomain; + _expectedResult = expectedResult; + ByteArrayInputStream emailStream = null; + try { + emailStream = readFileToByteArrayInputStream(emailPath); + DefaultMessageBuilder builder = new DefaultMessageBuilder(); + _message = builder.parseMessage(emailStream); + } catch (URISyntaxException e) { + throw new DmarcException("URI Syntax Exception when loading test email file", e); + } catch (IOException e) { + throw new DmarcException("IOException when loading test email file", e); + } + } + + String dkimResult() { + return _dkimResult; + } + + String dkimDomain() { + return _dkimDomain; + } + + String spfResult() { + return _spfResult; + } + + String spfDomain() { + return _spfDomain; + } + + String expectedResult() { + return _expectedResult; + } + + Message message() { + return _message; + } + + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { + URL resource = this.getClass().getResource(fileName); + FileInputStream file = new FileInputStream(new File(resource.toURI())); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + DKIMCommon.streamCopy(file, byteArrayOutputStream); + String string = byteArrayOutputStream.toString(); + return new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); + } + +} diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/MockPublicKeyRecordRetrieverDmarc.java b/dmarc/src/main/test/java/org/apache/james/dmarc/MockPublicKeyRecordRetrieverDmarc.java new file mode 100644 index 0000000..c77b853 --- /dev/null +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/MockPublicKeyRecordRetrieverDmarc.java @@ -0,0 +1,65 @@ +/****************************************************************************** + * 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.dmarc; + +import org.apache.james.dmarc.exceptions.DmarcException; +import org.apache.james.jdkim.MockPublicKeyRecordRetriever; +import org.apache.james.jdkim.exceptions.PermFailException; +import org.apache.james.jdkim.exceptions.TempFailException; + +import java.util.List; + +public class MockPublicKeyRecordRetrieverDmarc extends MockPublicKeyRecordRetriever implements PublicKeyRecordRetrieverDmarc { + public static final String DMARC = "_dmarc."; + + @Override + public String getDmarcRecord(String query) { + try { + List recs = super.getRecords("dns/txt", DMARC, query); + if (recs == null || recs.isEmpty()) { + return null; + } + return recs.getFirst(); + } catch (TempFailException e) { + throw new DmarcException("Temporary failure looking up DMARC record", e); + } catch (PermFailException e) { + throw new DmarcException("Permanent failure looking up DMARC record", e); + } + } + + @Override + public List getRecords(CharSequence methodAndOption, CharSequence selector, CharSequence token) throws TempFailException, PermFailException { + return List.of(); + } + + public static class DmarcRecord extends MockPublicKeyRecordRetriever.Record { + + public DmarcRecord(String domain, String dmarcRecord) { + super(DMARC, domain, dmarcRecord); + } + + public static DmarcRecord dmarcOf(String domain, String dmarcRecord) { + return new DmarcRecord(domain, dmarcRecord); + } + } + + public MockPublicKeyRecordRetrieverDmarc(Record... records) { + super(records); + } +} diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java b/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java new file mode 100644 index 0000000..5771a4a --- /dev/null +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java @@ -0,0 +1,60 @@ +/****************************************************************************** + * 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.dmarc; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +public class PublicSuffixListTest { + + @Test + public void isPublicSuffix_shouldReturnTrueForKnownSuffix() { + assertTrue(PublicSuffixList.isPublicSuffix("com")); + assertTrue(PublicSuffixList.isPublicSuffix("CO.UK")); + assertTrue(PublicSuffixList.isPublicSuffix("replit.app")); + assertTrue(PublicSuffixList.isPublicSuffix("id.replit.app")); + } + + @Test + public void isPublicSuffix_shouldReturnFalseForUnknownSuffix() { + assertFalse(PublicSuffixList.isPublicSuffix("example")); + assertFalse(PublicSuffixList.isPublicSuffix("unknown.tld")); + assertFalse(PublicSuffixList.isPublicSuffix("mail.replit.app")); + } + + @Test + public void getOrgDomain_shouldReturnPublicSuffixIfMatched() { + assertEquals("co.uk", PublicSuffixList.getOrgDomain("example.co.uk")); + assertEquals("replit.app", PublicSuffixList.getOrgDomain("mail.replit.app")); + } + + @Test + public void getOrgDomain_shouldNotReturnPublicSuffixIfNotMatched() { + assertNotEquals("replit.app", PublicSuffixList.getOrgDomain("id.replit.app")); + assertNotEquals("firewalledreplit.co", PublicSuffixList.getOrgDomain("id.firewalledreplit.co")); + } + + @Test + public void getOrgDomain_shouldReturnInputIfNoSuffixMatched() { + assertEquals("mydomain.unknown", PublicSuffixList.getOrgDomain("mydomain.unknown")); + } +} \ No newline at end of file diff --git a/dmarc/src/main/test/resources/mail/e1.eml b/dmarc/src/main/test/resources/mail/e1.eml new file mode 100644 index 0000000..2470990 --- /dev/null +++ b/dmarc/src/main/test/resources/mail/e1.eml @@ -0,0 +1,31 @@ +Return-Path: +Received: from example.org (example.org [208.69.40.157]) + by gmail.example with ESMTP id d200mr22663000ykb.93.1421363207 + for ; Thu, 14 Jan 2015 15:02:40 -0800 (PST) +Received: from segv.d1.example (segv.d1.example [72.52.75.15]) + by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123 + for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST) + (envelope-from jqd@d1.example) +Received: from [2001:DB8::1A] (w-x-y-z.dsl.static.isp.example [w.x.y.z]) + (authenticated bits=0) + by segv.d1.example with ESMTP id t0FN4a8O084569; + Thu, 14 Jan 2015 15:00:01 -0800 (PST) + (envelope-from jqd@d1.example) +Received: from mail-ob0-f188.google.example + (mail-ob0-f188.google.example [208.69.40.157]) by + clochette.example.org with ESMTP id d200mr22663000ykb.93.1421363268 + for ; Thu, 14 Jan 2015 15:03:15 -0800 (PST) +Message-ID: <54B84785.1060301@d1.example> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.example +Subject: [List 2] Example 1 +DKIM-Signature: a=rsa-sha256; + b=iEn8fLQ/ymdoZ4EkI3ELK3dTcc4jqn1VOvbNZWAMzcZcFiSKSZXgJ9kgXlBv8JGqaLFjuQi3+p73Al9P2JJU4IkBF1PSHrTI6rcdPyTWMP5yL6vKrn0tu0VdPhwPmbEr4H0yhYqc0KPPPzbJw668zoharH9Ljq43W8mj6sGSN18=; + c=relaxed/relaxed; s=origin2015; d=d1.example; v=1; + bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; h=Subject:From:To; + +Hey gang, +This is a test message. +--J. + diff --git a/dmarc/src/main/test/resources/mail/e2.eml b/dmarc/src/main/test/resources/mail/e2.eml new file mode 100644 index 0000000..ac0c1f8 --- /dev/null +++ b/dmarc/src/main/test/resources/mail/e2.eml @@ -0,0 +1,14 @@ +Return-Path: +Received: from replit.app (replit.co [208.69.40.157]) + by gmail.example with ESMTP id d200mr22663000ykb.93.1421363207 + for ; Thu, 14 Jan 2015 15:02:40 -0800 (PST) +Message-ID: <54B84785.1060301@id.firewalledreplit.co> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.example +Subject: [List 2] Example 1 + +Hey gang, +This is a test message. +--J. + diff --git a/dmarc/src/main/test/resources/mail/e3.eml b/dmarc/src/main/test/resources/mail/e3.eml new file mode 100644 index 0000000..311fd5b --- /dev/null +++ b/dmarc/src/main/test/resources/mail/e3.eml @@ -0,0 +1,14 @@ +Return-Path: +Received: from replit.app (replit.co [208.69.40.157]) + by gmail.example with ESMTP id d200mr22663000ykb.93.1421363207 + for ; Thu, 14 Jan 2015 15:02:40 -0800 (PST) +Message-ID: <54B84785.1060301@id.firewalledreplit.co> +Date: Thu, 14 Jan 2015 15:00:01 -0800 +From: John Q Doe +To: arc@dmarc.example +Subject: [List 2] Example 1 + +Hey gang, +This is a test message. +--J. + diff --git a/pom.xml b/pom.xml index 8b3a6e8..e725ce8 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ assemble main arc + dmarc From 471e608491b34a0606e354aaad510b09dca32aae Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Oct 2025 16:33:10 -0400 Subject: [PATCH 08/40] Adding DMARC pom.xml that was missing in the previous commit --- dmarc/pom.xml | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 dmarc/pom.xml diff --git a/dmarc/pom.xml b/dmarc/pom.xml new file mode 100644 index 0000000..134fb6e --- /dev/null +++ b/dmarc/pom.xml @@ -0,0 +1,88 @@ + + + + 4.0.0 + + + apache-jdkim-project + org.apache.james.jdkim + 0.6-SNAPSHOT + ../pom.xml + + + apache-dmarc-library + + Apache James :: DMARC + A Java implementation for the DMARC specification. + http://james.apache.org/jdkim/main/ + 2008 + + + + org.apache.james.jdkim + apache-jdkim-library + ${project.version} + + + org.apache.james.jdkim + apache-jdkim-library + ${project.version} + test-jar + test + + + junit + junit + + + org.apache.james + apache-mime4j-dom + + + org.assertj + assertj-core + test + + + + + + + maven-jar-plugin + + + + test-jar + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 21 + 21 + --enable-preview + + + + + From 620e3888372112229c3b1161f0980cf7b89cb575 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Oct 2025 17:25:25 -0400 Subject: [PATCH 09/40] Remove maven compiler plugin in DMARC pom.xml causing build to fail --- dmarc/pom.xml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/dmarc/pom.xml b/dmarc/pom.xml index 134fb6e..fa09cc2 100644 --- a/dmarc/pom.xml +++ b/dmarc/pom.xml @@ -74,15 +74,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - 21 - 21 - --enable-preview - - From 9714b4ed2e5a6233300c06620e5d3aac2d7d98c3 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Oct 2025 17:34:44 -0400 Subject: [PATCH 10/40] Add to the maven-compiler-plugin in DMARC pom.xml to fix the auto build error --- dmarc/pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/dmarc/pom.xml b/dmarc/pom.xml index fa09cc2..d307741 100644 --- a/dmarc/pom.xml +++ b/dmarc/pom.xml @@ -74,6 +74,15 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + --enable-preview + + + From 016bed6da796249dd0c01e2326531dc7afc48b59 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Oct 2025 17:53:52 -0400 Subject: [PATCH 11/40] Add to the maven-compiler-plugin in ARC pom.xml to fix the auto build error --- arc/pom.xml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arc/pom.xml b/arc/pom.xml index 820ffb6..1b12fc5 100644 --- a/arc/pom.xml +++ b/arc/pom.xml @@ -82,4 +82,28 @@ test
+ + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${target.jdk} + ${target.jdk} + + --enable-preview + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + --enable-preview + + + + From 16c1fdf77fabfe75539a287d3fdc87f50e91e3de Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Oct 2025 18:17:46 -0400 Subject: [PATCH 12/40] Updating ARC pom to make sure it can see DMARC test dependencies on Jenkins build --- arc/pom.xml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/arc/pom.xml b/arc/pom.xml index 1b12fc5..df08487 100644 --- a/arc/pom.xml +++ b/arc/pom.xml @@ -95,14 +95,19 @@ --enable-preview - - - org.apache.maven.plugins - maven-surefire-plugin - 3.1.2 - - --enable-preview - + + + default-testCompile + + testCompile + + + + --enable-preview + + + + From dbe330194695b98bbc48a2a7271c109170375056 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Oct 2025 18:36:45 -0400 Subject: [PATCH 13/40] Fixing the Jenkins build. Realigning to JDK 11 --- arc/pom.xml | 29 ------------------- .../arc/MockPublicKeyRecordRetrieverArc.java | 2 +- dmarc/pom.xml | 9 ------ .../MockPublicKeyRecordRetrieverDmarc.java | 2 +- 4 files changed, 2 insertions(+), 40 deletions(-) diff --git a/arc/pom.xml b/arc/pom.xml index df08487..820ffb6 100644 --- a/arc/pom.xml +++ b/arc/pom.xml @@ -82,33 +82,4 @@ test
- - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - ${target.jdk} - ${target.jdk} - - --enable-preview - - - - - default-testCompile - - testCompile - - - - --enable-preview - - - - - - - diff --git a/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java b/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java index 71d0505..8ed2e01 100644 --- a/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java +++ b/arc/src/test/java/org/apache/james/arc/MockPublicKeyRecordRetrieverArc.java @@ -55,7 +55,7 @@ public String getSpfRecord(String helo, String from, String ip) { if (recs.isEmpty()) { return null; } - return recs.getFirst(); + return recs.get(0); } catch (TempFailException e) { throw new ArcException("Temporary failure looking up DMARC record", e); } catch (PermFailException e) { diff --git a/dmarc/pom.xml b/dmarc/pom.xml index d307741..fa09cc2 100644 --- a/dmarc/pom.xml +++ b/dmarc/pom.xml @@ -74,15 +74,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - - --enable-preview - - - diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/MockPublicKeyRecordRetrieverDmarc.java b/dmarc/src/main/test/java/org/apache/james/dmarc/MockPublicKeyRecordRetrieverDmarc.java index c77b853..d819919 100644 --- a/dmarc/src/main/test/java/org/apache/james/dmarc/MockPublicKeyRecordRetrieverDmarc.java +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/MockPublicKeyRecordRetrieverDmarc.java @@ -35,7 +35,7 @@ public String getDmarcRecord(String query) { if (recs == null || recs.isEmpty()) { return null; } - return recs.getFirst(); + return recs.get(0); } catch (TempFailException e) { throw new DmarcException("Temporary failure looking up DMARC record", e); } catch (PermFailException e) { From c8a688b507f52fb909561aa6dfea2c4e19c12bd8 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Mon, 20 Oct 2025 11:10:18 -0400 Subject: [PATCH 14/40] Add missing license info. Reorder 'dmarc' and 'arc' modules in the parent pom' --- .../apache/james/dmarc/DmarcRequestMock.java | 18 ++++++++++++++++++ pom.xml | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/DmarcRequestMock.java b/dmarc/src/main/test/java/org/apache/james/dmarc/DmarcRequestMock.java index cb9364e..d2f1b12 100644 --- a/dmarc/src/main/test/java/org/apache/james/dmarc/DmarcRequestMock.java +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/DmarcRequestMock.java @@ -1,3 +1,21 @@ +/****************************************************************************** + * 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.dmarc; import org.apache.james.dmarc.exceptions.DmarcException; diff --git a/pom.xml b/pom.xml index e725ce8..4f63d29 100644 --- a/pom.xml +++ b/pom.xml @@ -40,8 +40,8 @@ assemble main - arc dmarc + arc From 3d75e62286740435526f6e1032d42c9708f2d8c8 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Tue, 4 Nov 2025 11:09:53 -0500 Subject: [PATCH 15/40] Rewrote PSL matching to handle exceptions/wildcards plus: - Added ARC validation outcome with details on the failure - Refactored logic such as `computeBTag` into separate methods - Added hard fail whenever multiple From headers detected - Rewrote tag extraction logic to do it all in one pass for efficiency - Simplified getTimeMeasure to use standard Java - Removed unnecessary Overrides --- .../apache/james/arc/ARCChainValidator.java | 14 +-- .../java/org/apache/james/arc/ARCSigner.java | 60 ++++++---- .../org/apache/james/arc/ArcSetBuilder.java | 108 +++++++++--------- .../james/arc/ArcSignatureRecordImpl.java | 52 +++------ .../james/arc/ArcValidationOutcome.java | 42 +++++++ .../apache/james/arc/AuthResultsBuilder.java | 49 ++++---- .../java/org/apache/james/arc/ARCTest.java | 11 +- .../org/apache/james/dmarc/DMARCVerifier.java | 100 ++++++---------- .../james/dmarc/DmarcValidationResult.java | 40 +++++++ .../java/org/apache/james/dmarc/PSLMatch.java | 26 +++++ .../apache/james/dmarc/PSLMatchOutcome.java | 59 ++++++++++ .../apache/james/dmarc/PublicSuffixList.java | 77 +++++++++---- .../org/apache/james/dmarc/DMARCTest.java | 8 +- .../james/dmarc/PublicSuffixListTest.java | 86 +++++++++++--- 14 files changed, 465 insertions(+), 267 deletions(-) create mode 100644 arc/src/main/java/org/apache/james/arc/ArcValidationOutcome.java create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/DmarcValidationResult.java create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/PSLMatch.java create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/PSLMatchOutcome.java diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index d50c094..1a01e06 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -56,29 +56,29 @@ public ARCChainValidator(PublicKeyRetrieverArc keyRecordRetriever) { this._keyRecordRetriever = keyRecordRetriever; } - public ArcValidationResult validateArcChain(Message message) { + public ArcValidationOutcome validateArcChain(Message message) { Header messageHeaders = message.getHeader(); int curInstance = getCurrentInstance(messageHeaders); // Incremented by 1 if (curInstance == 1) { //we are the first ARC Hop and there is no previous ARC hops in the chain to validate - return ArcValidationResult.NONE; + return new ArcValidationOutcome(ArcValidationResult.NONE, "No previous ARC hops to validate"); } else if (curInstance > 51) { // Not allowed to be > 50 - return ArcValidationResult.FAIL; + return new ArcValidationOutcome(ArcValidationResult.FAIL, "ARC instance number exceeds maximum allowed value of 50"); } else { // there are previous ARC hops that need to be validated return validatePreviousArcHops(message, messageHeaders, curInstance); } } - private ArcValidationResult validatePreviousArcHops(Message message, Header messageHeaders, int myInstance) { + private ArcValidationOutcome validatePreviousArcHops(Message message, Header messageHeaders, int myInstance) { ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); Map> arcHeadersByI = arcVerifier.getArcHeadersByI(messageHeaders.getFields()); int numArcInstances = myInstance - 1; boolean isArcSetStructureOK = arcVerifier.validateArcSetStructure(arcHeadersByI); if (!isArcSetStructureOK) { - return ArcValidationResult.FAIL; + return new ArcValidationOutcome(ArcValidationResult.FAIL, "ARC set structure is invalid"); } Set prevArcSet; @@ -87,10 +87,10 @@ private ArcValidationResult validatePreviousArcHops(Message message, Header mess boolean amsOk = checkArcAms(prevArcSet, message, arcVerifier); boolean asOk = checkArcSeal(messageHeaders.getFields(), numArcInstances, arcVerifier); if (amsOk && asOk) { - return ArcValidationResult.PASS; + return new ArcValidationOutcome(ArcValidationResult.PASS, "All previous ARC hops validated successfully"); } } - return ArcValidationResult.FAIL; + return new ArcValidationOutcome(ArcValidationResult.FAIL, "Previous ARC hops validation failed"); } private boolean checkArcAms(Set prevArcSet, Message message, ARCVerifier arcVerifier){ diff --git a/arc/src/main/java/org/apache/james/arc/ARCSigner.java b/arc/src/main/java/org/apache/james/arc/ARCSigner.java index 97b0034..124997a 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCSigner.java +++ b/arc/src/main/java/org/apache/james/arc/ARCSigner.java @@ -21,7 +21,6 @@ import org.apache.james.jdkim.api.BodyHasher; import org.apache.james.jdkim.api.Headers; import org.apache.james.jdkim.api.SignatureRecord; -import org.apache.james.jdkim.exceptions.FailException; import org.apache.james.jdkim.exceptions.PermFailException; import org.apache.james.jdkim.impl.BodyHasherImpl; import org.apache.james.jdkim.impl.Message; @@ -70,35 +69,44 @@ public BodyHasher newBodyHasher(SignatureRecord signRecord) return new BodyHasherImpl(signRecord); } - public String generateAms(InputStream is) throws IOException, FailException { + public String generateAms(InputStream is){ Message message; + try (is) { + message = getMessage(is); + return getAmsHeader(message); + } catch (IOException e) { + throw new ArcException("IOException when working with email input stream", e); + } + } + + private String getAmsHeader(Message message) { try { - try { - message = new Message(is); - } catch (RuntimeException | IOException e) { - throw e; - } catch (Exception e1) { - throw new ArcException("MIME parsing exception: " - + e1.getMessage(), e1); - } - - try { - SignatureRecord srt = newSignatureRecordTemplate(signatureRecordTemplate); - BodyHasher bhj = newBodyHasher(srt); - - ARCCommon.streamCopy(message.getBodyInputStream(), bhj - .getOutputStream()); - - return generateAms(message, bhj); - } finally { - message.dispose(); - } + SignatureRecord srt = newSignatureRecordTemplate(signatureRecordTemplate); + BodyHasher bhj = newBodyHasher(srt); + + ARCCommon.streamCopy(message.getBodyInputStream(), bhj + .getOutputStream()); + + return generateAms(message, bhj); + } catch (PermFailException | IOException e) { + throw new ArcException("Invalid signature record template", e); } finally { - is.close(); + message.dispose(); + } + } + + private static Message getMessage(InputStream is) { + Message message; + try { + message = new Message(is); + } catch (Exception e1) { + throw new ArcException("MIME parsing exception: " + + e1.getMessage(), e1); } + return message; } - public String sealHeaders(Map headersToSeal) throws FailException { + public String sealHeaders(Map headersToSeal) { SignatureRecord srt = newSignatureRecordTemplate(signatureRecordTemplate); return seal(srt, headersToSeal); } @@ -130,7 +138,7 @@ public String generateAms(Headers message, BodyHasher bh) throws PermFailExcepti } } - public String seal(SignatureRecord signatureRecord, Map headersToSeal) throws PermFailException { + public String seal(SignatureRecord signatureRecord, Map headersToSeal) { try { byte[] signatureHash = signatureSeal(signatureRecord, privateKey, headersToSeal); @@ -143,6 +151,8 @@ public String seal(SignatureRecord signatureRecord, Map headersT throw new ArcException("Unknown algorithm: " + e.getMessage(), e); } catch (SignatureException e) { throw new ArcException("Signing exception: " + e.getMessage(), e); + } catch (PermFailException e) { + throw new ArcException("PermFail exception received " + e.getMessage(), e); } } diff --git a/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java b/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java index fccc46e..94b480d 100644 --- a/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java +++ b/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java @@ -19,12 +19,14 @@ package org.apache.james.arc; import org.apache.james.arc.exceptions.ArcException; +import org.apache.james.dmarc.exceptions.DmarcException; import org.apache.james.mime4j.dom.Header; import org.apache.james.mime4j.dom.Message; import org.apache.james.mime4j.message.DefaultMessageWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.security.PrivateKey; import java.time.Instant; import java.util.HashMap; @@ -54,26 +56,20 @@ public class ArcSetBuilder { private final PrivateKey _arcPrivateKey; private final String _arcAmsTemplate; private final String _arcSealTemplate; - private final String _dmarcResponse; - private final String _dmarcNonResponse; private final String _authService; private long _debugTimestamp; public ArcSetBuilder(PrivateKey arcPrivateKey, String arcAmsTemplate, String arcSealTemplate, - String dmarcResponse, String dmarcNonResponse, String authService, long debugTimestamp) { - this(arcPrivateKey, arcAmsTemplate, arcSealTemplate, dmarcResponse, dmarcNonResponse, authService); + this(arcPrivateKey, arcAmsTemplate, arcSealTemplate, authService); _debugTimestamp = debugTimestamp; } public ArcSetBuilder(PrivateKey arcPrivateKey, String arcAmsTemplate, String arcSealTemplate, - String dmarcResponse, String dmarcNonResponse, String authService) { _arcAmsTemplate = arcAmsTemplate; _arcSealTemplate = arcSealTemplate; _arcPrivateKey = arcPrivateKey; - _dmarcResponse = dmarcResponse; - _dmarcNonResponse = dmarcNonResponse; _authService = authService; } @@ -93,59 +89,63 @@ public ArcSetBuilder(PrivateKey arcPrivateKey, String arcAmsTemplate, String arc * @return a map containing the generated ARC headers and their values * @throws ArcException if ARC header generation or signing fails */ - public Map buildArcSet(Message message, String helo, String mailFrom, String ip, PublicKeyRetrieverArc keyRecordRetriever) { + public Map buildArcSet(Message message, String helo, String mailFrom, String ip, PublicKeyRetrieverArc keyRecordRetriever) throws DmarcException { Map arcHeaders = new HashMap<>(); + Header headers = message.getHeader(); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + AuthResultsBuilder authResultsBuilder = new AuthResultsBuilder(_authService, keyRecordRetriever); + ArcValidationOutcome cvOutcome = arcChainValidator.validateArcChain(message); + String cv = cvOutcome.getResult().toString().toLowerCase(); + int instance = arcChainValidator.getCurrentInstance(headers); + + //Build ARC-Authentication-Results header + String arHeaderValue = authResultsBuilder.getAuthResultsHeader(message, helo, mailFrom,ip); + if (arHeaderValue == null){ + throw new ArcException("Unable to build Authentication-Results header"); + } + + arcHeaders.put(AUTHENTICATION_RESULTS, arHeaderValue); + Map headersToSeal = new LinkedHashMap<>(); + String aarHeaderValue = "i=" + instance + "; " + arHeaderValue.trim(); + + arcHeaders.put(ARC_AUTHENTICATION_RESULTS, aarHeaderValue); + headersToSeal.put(ARC_AUTHENTICATION_RESULTS, aarHeaderValue); + DefaultMessageWriter writer = new DefaultMessageWriter(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { - Header headers = message.getHeader(); - ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); - AuthResultsBuilder authResultsBuilder = new AuthResultsBuilder(_dmarcResponse, _dmarcNonResponse, _authService, keyRecordRetriever); - String cv = arcChainValidator.validateArcChain(message).name().toLowerCase(); - int instance = arcChainValidator.getCurrentInstance(headers); - - //Build ARC-Authentication-Results header - String arHeaderValue = authResultsBuilder.getAuthResultsHeader(message, helo, mailFrom,ip); - if (arHeaderValue == null){ - throw new ArcException("Unable to build Authentication-Results header"); - } - - arcHeaders.put(AUTHENTICATION_RESULTS, arHeaderValue); - Map headersToSeal = new LinkedHashMap<>(); - String aarHeaderValue = "i=" + instance + "; " + arHeaderValue.trim(); - - arcHeaders.put(ARC_AUTHENTICATION_RESULTS, aarHeaderValue); - headersToSeal.put(ARC_AUTHENTICATION_RESULTS, aarHeaderValue); - DefaultMessageWriter writer = new DefaultMessageWriter(); - ByteArrayOutputStream os = new ByteArrayOutputStream(); writer.writeMessage(message,os); - - Map fmContext = new HashMap<>(); - fmContext.put("instance", instance); - long timestamp = Instant.now().getEpochSecond(); - if (_debugTimestamp != 0) { - timestamp = _debugTimestamp; - } - fmContext.put("timestamp", Long.toString(timestamp)); - fmContext.put("cv", cv); - - //Build and add ARC-AMS header - String amsTemplate = fillArcTemplate(_arcAmsTemplate, instance, timestamp); - ARCSigner amsSigner = new ARCSigner(amsTemplate, _arcPrivateKey); - String amsHeader = amsSigner.generateAms(new ByteArrayInputStream(os.toByteArray())); - String amsValue = amsHeader.split(ARC_ELEMENT)[1]; - arcHeaders.put(ARC_MESSAGE_SIGNATURE, amsValue); - headersToSeal.put(ARC_MESSAGE_SIGNATURE, amsValue); - - //Build and add ARC-Seal header - String asTemplate = fillArcSealTemplate(_arcSealTemplate, instance, timestamp, cv); - ARCSigner asSigner = new ARCSigner(asTemplate, _arcPrivateKey); - String asHeader = asSigner.sealHeaders(headersToSeal ); - String asValue = asHeader.split(ARC_ELEMENT)[1]; - arcHeaders.put(ARC_SEAL, asValue); + } catch (IOException e) { + throw new ArcException("Unable to copy email message into the output stream", e); } - catch (Exception ex){ - throw new ArcException("Unable to generate ARC Seal", ex); + + Map fmContext = new HashMap<>(); + fmContext.put("instance", instance); + long timestamp = Instant.now().getEpochSecond(); + if (_debugTimestamp != 0) { + timestamp = _debugTimestamp; } + fmContext.put("timestamp", Long.toString(timestamp)); + fmContext.put("cv", cv); + + //Build and add ARC-AMS header + String amsTemplate = fillArcTemplate(_arcAmsTemplate, instance, timestamp); + ARCSigner amsSigner = new ARCSigner(amsTemplate, _arcPrivateKey); + + String amsHeader = null; + amsHeader = amsSigner.generateAms(new ByteArrayInputStream(os.toByteArray())); + + String amsValue = amsHeader.split(ARC_ELEMENT)[1]; + arcHeaders.put(ARC_MESSAGE_SIGNATURE, amsValue); + headersToSeal.put(ARC_MESSAGE_SIGNATURE, amsValue); + + //Build and add ARC-Seal header + String asTemplate = fillArcSealTemplate(_arcSealTemplate, instance, timestamp, cv); + ARCSigner asSigner = new ARCSigner(asTemplate, _arcPrivateKey); + String asHeader = asSigner.sealHeaders(headersToSeal ); + String asValue = asHeader.split(ARC_ELEMENT)[1]; + arcHeaders.put(ARC_SEAL, asValue); return arcHeaders; } diff --git a/arc/src/main/java/org/apache/james/arc/ArcSignatureRecordImpl.java b/arc/src/main/java/org/apache/james/arc/ArcSignatureRecordImpl.java index 2b790da..4eac960 100644 --- a/arc/src/main/java/org/apache/james/arc/ArcSignatureRecordImpl.java +++ b/arc/src/main/java/org/apache/james/arc/ArcSignatureRecordImpl.java @@ -18,8 +18,9 @@ ****************************************************************/ package org.apache.james.arc; +import org.apache.james.arc.exceptions.ArcException; import org.apache.james.jdkim.tagvalue.SignatureRecordImpl; - +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; @@ -49,13 +50,14 @@ public ArcSignatureRecordImpl(String data) { } @Override - public void validate() throws IllegalStateException { + public void validate() throws ArcException { if (getValue("x") != null) { long expiration = Long.parseLong(getValue("x").toString()); long lifetime = (expiration - System.currentTimeMillis() / 1000); if (lifetime < 0) { - throw new IllegalStateException("Signature is expired since " - + getTimeMeasureText(lifetime) + "."); + String expired = getTimeMeasureText(lifetime); + throw new ArcException("Signature is expired since " + + expired + " ago."); } } } @@ -70,30 +72,14 @@ public List getHeaders() { } private String getTimeMeasureText(long lifetime) { - String measure = "s"; - lifetime = -lifetime; - if (lifetime > 600) { - lifetime = lifetime / 60; - measure = "m"; - if (lifetime > 600) { - lifetime = lifetime / 60; - - measure = "h"; - if (lifetime > 120) { - lifetime = lifetime / 24; - measure = "d"; - if (lifetime > 90) { - lifetime = lifetime / 30; - measure = " months"; - if (lifetime > 24) { - lifetime = lifetime / 12; - measure = " years"; - } - } - } - } - } - return lifetime + measure; + Duration duration = Duration.ofSeconds(lifetime); + long days = duration.toDays(); + long hours = duration.toHours() % 24; + long minutes = duration.toMinutes() % 60; + long seconds = duration.getSeconds() % 60; + + return String.format("%d days, %d hours, %d minutes, %d seconds", + days, hours, minutes, seconds); } @Override @@ -187,14 +173,4 @@ public CharSequence getIdentityLocalPart() { // Not applicable for ARC return getIdentity(); } - - @Override - public boolean equals(Object obj) { - return super.equals(obj); - } - - @Override - public int hashCode() { - return super.hashCode(); - } } diff --git a/arc/src/main/java/org/apache/james/arc/ArcValidationOutcome.java b/arc/src/main/java/org/apache/james/arc/ArcValidationOutcome.java new file mode 100644 index 0000000..9f42386 --- /dev/null +++ b/arc/src/main/java/org/apache/james/arc/ArcValidationOutcome.java @@ -0,0 +1,42 @@ +/**************************************************************** + * 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.arc; + +public class ArcValidationOutcome { + private final ArcValidationResult result; + private final String description; + + public ArcValidationOutcome(ArcValidationResult result, String explanation) { + this.result = result; + this.description = explanation; + } + + public ArcValidationResult getResult() { + return result; + } + + public String getDescription() { + return description; + } + + @Override + public String toString() { + return result + (description != null ? " (" + description + ")" : ""); + } +} diff --git a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java index 5c82937..231b5e6 100644 --- a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java +++ b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java @@ -20,6 +20,7 @@ import org.apache.james.arc.exceptions.ArcException; import org.apache.james.dmarc.DMARCVerifier; +import org.apache.james.dmarc.DmarcValidationResult; import org.apache.james.jdkim.DKIMVerifier; import org.apache.james.jdkim.api.SignatureRecord; import org.apache.james.jdkim.exceptions.FailException; @@ -57,13 +58,9 @@ public class AuthResultsBuilder { public static final String HEADER_I = "header.i="; private final PublicKeyRetrieverArc _keyRecordRetriever; - private String _dmarcNoneResponse; - private String _dmarcResponse; private String _authService; - public AuthResultsBuilder(String dmarcResponse, String dmarcNoneResponse, String authService, PublicKeyRetrieverArc keyRecordRetriever) { - this._dmarcResponse = dmarcResponse; - this._dmarcNoneResponse = dmarcNoneResponse; + public AuthResultsBuilder(String authService, PublicKeyRetrieverArc keyRecordRetriever) { this._authService = authService; this._keyRecordRetriever = keyRecordRetriever; } @@ -85,17 +82,13 @@ public String getAuthResultsHeader(Message message, String helo, String from, St // 3. Run DMARC check (using SPF + DKIM results + From domain) String dkimDomain = extractDkimDomain(dkimResultFull); String spfDomain = extractSpfDomain(spfResultText); - DMARCVerifier dmarcVerifier = new DMARCVerifier(_dmarcResponse, _dmarcNoneResponse, _keyRecordRetriever.getDmarcRetriever()); - String dmarcResult = dmarcVerifier.runDmarcCheck(message, spfResultText, spfDomain, dkimResultShort, dkimDomain); - if (dmarcResult == null || dmarcResult.isEmpty()) { - dmarcResult = _dmarcNoneResponse + spfDomain; - } + DMARCVerifier dmarcVerifier = new DMARCVerifier(_keyRecordRetriever.getDmarcRetriever()); + DmarcValidationResult dmarcResult = dmarcVerifier.runDmarcCheck(message, spfResultText, spfDomain, dkimResultShort, dkimDomain); return _authService + "; " + "spf=" + spfResultText.replace(";", "") + "; " + "dkim=" + dkimResultFull + "; " + - dmarcResult; - + dmarcResult.toString(); } private String runDkimCheck(Message message) throws IOException { @@ -108,19 +101,10 @@ private String runDkimCheck(Message message) throws IOException { results = verifier.verify(is); if (!results.isEmpty() && results.stream().allMatch(Objects::nonNull) && results.get(0) != null) { SignatureRecord signatureRecord = results.get(0); - String iTag = (String) signatureRecord.getIdentity(); - if (iTag == null || iTag.isEmpty()) { - iTag = (String) signatureRecord.getDToken(); - } - iTag = iTag.replace("@", ""); //most implementations drop the leading @ + String iTag = computeITag(signatureRecord); CharSequence sTag = signatureRecord.getSelector(); Set tags = ((SignatureRecordImpl) signatureRecord).getTags(); - String bTag = ""; - if (!tags.isEmpty() && tags.contains("b")) { - byte[] signature = signatureRecord.getSignature(); - bTag = Base64.getEncoder().encodeToString(signature); - bTag=bTag.substring(0,8); - } + String bTag = computeBTag(tags, signatureRecord); String outcome = "pass"; return outcome + " header.i=" + iTag + " header.s=" + sTag+ " header.b=" + bTag; } @@ -137,6 +121,25 @@ private String runDkimCheck(Message message) throws IOException { return "fail (no valid signature records)"; } + private static String computeITag(SignatureRecord signatureRecord) { + String iTag = (String) signatureRecord.getIdentity(); + if (iTag == null || iTag.isEmpty()) { + iTag = (String) signatureRecord.getDToken(); + } + iTag = iTag.replace("@", ""); //most implementations drop the leading @ + return iTag; + } + + private static String computeBTag(Set tags, SignatureRecord signatureRecord) { + String bTag = ""; + if (!tags.isEmpty() && tags.contains("b")) { + byte[] signature = signatureRecord.getSignature(); + bTag = Base64.getEncoder().encodeToString(signature); + bTag=bTag.substring(0,8); + } + return bTag; + } + private String extractSpfDomain(String spfHeaderText) { String[] parts = spfHeaderText.split(" "); for (String part : parts) { diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index a38b8c3..1849203 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -83,11 +83,7 @@ public class ARCTest { private static final String MAIL_FROM = "jqd@d1.example"; private static final String IP = "222.222.222.222"; private static final long TIMESTAMP = 1755918846L; // fixed timestamp for repeatable tests - - private static final String DMARC_RESPONSE_TEMPLATE = "dmarc=%s (p=%s) header.from=%s"; - private static final String DMARC_NON_RESPONSE_TEMPLATE = "dmarc=none (no policy) header.from="; - - ArcSetBuilder arcSetBuilder = new ArcSetBuilder(ArcTestKeys.privateKeyArc, ARC_AMS_TEMPLATE, ARC_SEAL_TEMPLATE, DMARC_RESPONSE_TEMPLATE, DMARC_NON_RESPONSE_TEMPLATE, AUTH_SERVICE, TIMESTAMP); + ArcSetBuilder arcSetBuilder = new ArcSetBuilder(ArcTestKeys.privateKeyArc, ARC_AMS_TEMPLATE, ARC_SEAL_TEMPLATE, AUTH_SERVICE, TIMESTAMP); @Test public void generate_and_verify_arc_set() throws Exception { @@ -121,9 +117,8 @@ public void generate_and_verify_arc_set() throws Exception { } ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); - String cv = arcChainValidator.validateArcChain(message).name().toLowerCase(); - assertThat(cv).isEqualTo(expectedCv); - + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo(expectedCv); } private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java index 4d0c9a0..1563cc2 100644 --- a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java +++ b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java @@ -20,40 +20,46 @@ import org.apache.james.dmarc.exceptions.DmarcException; import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.dom.address.Mailbox; +import org.apache.james.mime4j.dom.address.MailboxList; +import java.util.HashMap; +import java.util.Map; public class DMARCVerifier { public static final String FROM = "From"; - private final String _dmarcResponse; - private final String _dmarcNonResponse; private final PublicKeyRecordRetrieverDmarc _recordRetriever; - public DMARCVerifier(String dmarcResponse, String dmarcNonResponse, PublicKeyRecordRetrieverDmarc recordRetriever) { - _dmarcResponse = dmarcResponse; - _dmarcNonResponse = dmarcNonResponse; + public DMARCVerifier(PublicKeyRecordRetrieverDmarc recordRetriever) { _recordRetriever = recordRetriever; } - public String runDmarcCheck(Message message, String spfHeaderText, String - spfDomain, String dkimResult, String dkimDomain){ + public DmarcValidationResult runDmarcCheck(Message message, String spfHeaderText, String + spfDomain, String dkimResult, String dkimDomain) throws DmarcException { // Combine SPF + DKIM results with From: domain // 1. Extract RFC5322.From domain from the From header of the message String shortSpfResult = spfHeaderText.split(" ")[0]; - String fromHeader = message.getHeader().getField(FROM).getBody(); - String fromDomain = extractDomain(fromHeader); + MailboxList mailboxList = message.getFrom(); + if (mailboxList == null || mailboxList.size() != 1) { + throw new DmarcException("Incorrect From header: must have exactly one mailbox"); // rejecting immediately unless exactly one mailbox + } + + Mailbox mailbox = message.getFrom().get(0); + String fromDomain = mailbox.getDomain(); if (fromDomain == null || fromDomain.isEmpty()) { - return _dmarcNonResponse + "unknown"; + throw new DmarcException("From header is missing or has no domain part"); } // 2. Fetch DMARC record from DNS String dmarcRecord = _recordRetriever.getDmarcRecord(fromDomain); if (dmarcRecord == null) { - return _dmarcNonResponse + fromDomain; + return new DmarcValidationResult(fromDomain, null, null); } // Parse DMARC policy - String policy = parseTag(dmarcRecord, "p"); // p=none|quarantine|reject - String aspf = parseTag(dmarcRecord, "aspf"); // "s" or "r" for strict or relaxed domain alignment; default is "r" - String adkim = parseTag(dmarcRecord, "adkim"); // "s" or "r" for strict or relaxed domain alignment; default is "r" + Map dmarcTags = getDmarcTags(dmarcRecord); + String policy = dmarcTags.getOrDefault("p", "none"); + String aspf = dmarcTags.getOrDefault("aspf", "r"); // default is "r" when omitted + String adkim = dmarcTags.getOrDefault("adkim", "r"); // default is "r" when omitted // 3. Alignment checks boolean spfAligned = getDomainAlignment(aspf, shortSpfResult, fromDomain, spfDomain); @@ -68,12 +74,25 @@ public String runDmarcCheck(Message message, String spfHeaderText, String } // 5. Build Authentication-Results string - return String.format(_dmarcResponse, result, policy, fromDomain); + return new DmarcValidationResult(result, policy, fromDomain); + } + + private Map getDmarcTags(String dmarcRecord) { + Map dmarcTags = new HashMap<>(); + String[] parts = dmarcRecord.split(";"); + for (String part : parts) { + String trimmed = part.trim(); + String[] tagValue = trimmed.split("="); + if (tagValue.length == 2) { + dmarcTags.put(tagValue[0].toLowerCase(), tagValue[1]); + } + } + return dmarcTags; } private boolean getDomainAlignment(String flag, String result, String receivedDomain, String expectedDomain) { - // we expect flag to be either "s" or "r"; default is "r" - if (flag == null || flag.equalsIgnoreCase("r")){ //relaxed + // we expect flag to be either "s" or "r"; default is "r" when omitted + if (flag.equalsIgnoreCase("r")){ //relaxed String fromOrgDomain = PublicSuffixList.getOrgDomain(receivedDomain); //we get the organizational domain using PSL String spfOrgDomain = PublicSuffixList.getOrgDomain(expectedDomain); @@ -87,51 +106,4 @@ else if (flag.equalsIgnoreCase("s")){ // strict throw new DmarcException(String.format("Unknown alignment flag value: %s", flag)); } } - - private String extractDomain(String fromHeader) throws DmarcException { - if (fromHeader == null || fromHeader.isEmpty()) { - throw new DmarcException("From header is empty"); - } - - // Extract address inside <...> - String address = fromHeader; - int lt = fromHeader.indexOf('<'); - int gt = fromHeader.indexOf('>'); - if (lt != -1 && gt != -1 && gt > lt) { - address = fromHeader.substring(lt + 1, gt).trim(); - } else { - // No brackets — just finding raw address - int at = fromHeader.indexOf('@'); - if (at == -1) { - throw new DmarcException("Invalid From header: " + fromHeader); - } - - // Lookin for something@domain - String[] parts = fromHeader.split("\\s+"); - for (String part : parts) { - if (part.contains("@")) { - address = part; - break; - } - } - } - - // And finally extracting the domain - int atIndex = address.lastIndexOf('@'); - if (atIndex == -1 || atIndex == address.length() - 1) { - throw new DmarcException("Invalid email address: " + fromHeader); - } - return address.substring(atIndex + 1); - } - - public String parseTag(String dmarcRecord, String tag) { - String[] parts = dmarcRecord.split(";"); - for (String part : parts) { - String trimmed = part.trim(); - if (trimmed.startsWith(tag + "=")) { - return trimmed.substring((tag + "=").length()); - } - } - return null; - } } diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DmarcValidationResult.java b/dmarc/src/main/java/org/apache/james/dmarc/DmarcValidationResult.java new file mode 100644 index 0000000..566cbc6 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/DmarcValidationResult.java @@ -0,0 +1,40 @@ +/****************************************************************************** + * 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.dmarc; + +public class DmarcValidationResult { + private static final String DEFAULT_RESPONSE_TEMPLATE = "dmarc=%s (p=%s) header.from=%s"; + private static final String DEFAULT_NONE_RESPONSE_TEMPLATE = "dmarc=none (no policy) header.from=%s"; + private final String result; + private final String policy; + private final String domain; + + public DmarcValidationResult(String result, String policy, String domain) { + this.result = result; + this.policy = policy; + this.domain = domain; + } + + @Override + public String toString() { + return (policy == null || result == null) ? + String.format(DEFAULT_NONE_RESPONSE_TEMPLATE, domain) : + String.format(DEFAULT_RESPONSE_TEMPLATE, result, policy, domain); + } +} diff --git a/dmarc/src/main/java/org/apache/james/dmarc/PSLMatch.java b/dmarc/src/main/java/org/apache/james/dmarc/PSLMatch.java new file mode 100644 index 0000000..b89c308 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/PSLMatch.java @@ -0,0 +1,26 @@ +/****************************************************************************** + * 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.dmarc; + +public enum PSLMatch { + RULE, + WILDCARD, + EXCEPTION, + NONE +} diff --git a/dmarc/src/main/java/org/apache/james/dmarc/PSLMatchOutcome.java b/dmarc/src/main/java/org/apache/james/dmarc/PSLMatchOutcome.java new file mode 100644 index 0000000..1149642 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/PSLMatchOutcome.java @@ -0,0 +1,59 @@ +/**************************************************************** + * 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.dmarc; + +import java.util.Arrays; + +public class PSLMatchOutcome { + private final PSLMatch match; + private final String matchedCandidate; + private final String[] domainElements; + private final int matchedIndex; + + public PSLMatchOutcome(PSLMatch matchType, String candidate, String[] domainParts, int index) { + match = matchType; + matchedCandidate = candidate; + domainElements = domainParts; + matchedIndex = index; + } + + public String getRelaxedOrgDomain() { + switch (match) { + case RULE: + return matchedIndex >= 1 ? + String.join(".", Arrays.copyOfRange(domainElements, matchedIndex - 1, domainElements.length)) : + String.join(".", Arrays.copyOfRange(domainElements, 0, domainElements.length)); + case WILDCARD: + if (matchedIndex >= 2) { + return String.join(".", Arrays.copyOfRange(domainElements, matchedIndex - 2, domainElements.length)); + } + else if (matchedIndex == 1) { + return String.join(".", Arrays.copyOfRange(domainElements, 0, domainElements.length)); + } + else { + return matchedCandidate; + } + case EXCEPTION: + return String.join(".", Arrays.copyOfRange(domainElements, matchedIndex, domainElements.length)); + case NONE: + default: + return String.join(".", Arrays.copyOfRange(domainElements, 0, domainElements.length)); + } + } +} diff --git a/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java b/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java index 23ebd48..ca30051 100644 --- a/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java +++ b/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java @@ -21,50 +21,79 @@ import org.apache.james.dmarc.exceptions.DmarcException; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import java.util.HashSet; +import java.util.Locale; import java.util.Set; public class PublicSuffixList { - private static final Set SUFFIXES = new HashSet<>(); + private static final Set RULES = new HashSet<>(); + private static final Set WILDCARDS = new HashSet<>(); + private static final Set EXCEPTIONS = new HashSet<>(); static { try (InputStream is = PublicSuffixList.class.getResourceAsStream("/public_suffix_list.dat")) { assert is != null; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { - String line; - while ((line = reader.readLine()) != null) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("//")) continue; - SUFFIXES.add(line.toLowerCase()); - } - } - } catch (Exception e) { + parsePsl(is); + } + catch (Exception e) { throw new DmarcException("Failed to load Public Suffix List", e); } } + private static void parsePsl(InputStream is) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("//")) continue; + if (line.startsWith("!")) { + EXCEPTIONS.add(line.substring(1).toLowerCase()); + } else if (line.startsWith("*.")) { + WILDCARDS.add(line.substring(2).toLowerCase()); + } else { + RULES.add(line.toLowerCase()); + } + } + } catch (IOException e) { + throw new DmarcException("Failed to read Public Suffix List", e); + } + } + private PublicSuffixList() {} - public static boolean isPublicSuffix(String domain) { - return SUFFIXES.contains(domain.toLowerCase()); - } + public static String getOrgDomain(String domainToCheck) { + if (domainToCheck == null || domainToCheck.trim().isEmpty()) return domainToCheck; - public static String getOrgDomain(String receivedDomain) { - String[] parts = receivedDomain.toLowerCase().split("\\."); - for (int i = 0; i < parts.length - 1; i++) { - //we start checking from the most specific part on the left moving to the right until we find a match - String candidate = String.join(".", Arrays.copyOfRange(parts, i, parts.length)); - if (isPublicSuffix(candidate)) { - return candidate; + domainToCheck = domainToCheck.toLowerCase(Locale.ROOT).trim(); + String[] domainParts = domainToCheck.split("\\."); + int numParts = domainParts.length; + + PSLMatchOutcome outcome = null; + + for (int i = 0; i < numParts && outcome == null; i++) { + String[] candidateArr = Arrays.copyOfRange(domainParts, i, numParts); + String matchedCandidate = String.join(".", candidateArr); + + if (EXCEPTIONS.contains(matchedCandidate)) { + // Exception rules take precedence + outcome = new PSLMatchOutcome(PSLMatch.EXCEPTION, matchedCandidate, domainParts, i); + } + + if (WILDCARDS.contains(matchedCandidate)) { + outcome = new PSLMatchOutcome(PSLMatch.WILDCARD, matchedCandidate, domainParts, i); + } + + if (RULES.contains(matchedCandidate)) { + outcome = new PSLMatchOutcome(PSLMatch.RULE, matchedCandidate, domainParts, i); } } - return receivedDomain; - } - static void main() { - System.out.println(getOrgDomain("id.replit.app")); // example.co.uk + return outcome == null? + new PSLMatchOutcome(PSLMatch.NONE, null, domainParts, -1).getRelaxedOrgDomain(): + outcome.getRelaxedOrgDomain(); } } \ No newline at end of file diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java b/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java index cdbed99..fc1fb01 100644 --- a/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java @@ -24,8 +24,6 @@ import static org.assertj.core.api.Assertions.assertThat; public class DMARCTest { - private static final String DMARC_RESPONSE_TEMPLATE = "dmarc=%s (p=%s) header.from=%s"; - private static final String DMARC_NON_RESPONSE_TEMPLATE = "dmarc=none (no policy) header.from="; private final MockPublicKeyRecordRetrieverDmarc recordRetrieverDmarc = new MockPublicKeyRecordRetrieverDmarc( MockPublicKeyRecordRetrieverDmarc.DmarcRecord.dmarcOf( @@ -41,16 +39,16 @@ public class DMARCTest { private final List passRequests = List.of( new DmarcRequestMock("/mail/e1.eml","pass", "d1.example", "softfail (spfCheck: transitioning domain of d1.example does not designate 222.222.222.222 as permitted sender) client-ip=222.222.222.222; envelope-from=jqd@d1.example; helo=d1.example", "d1.example", "dmarc=pass (p=reject) header.from=d1.example"), - new DmarcRequestMock("/mail/e2.eml","pass", "replit.app", "pass client-ip=222.222.222.222; envelope-from=jqd@id.firewalledreplit.co; helo=replit.app", "replit.app", "dmarc=pass (p=reject) header.from=mail.replit.app"), + new DmarcRequestMock("/mail/e2.eml","pass", "mail.replit.app", "pass client-ip=222.222.222.222; envelope-from=jqd@id.firewalledreplit.co; helo=replit.app", "mail.replit.app", "dmarc=pass (p=reject) header.from=mail.replit.app"), new DmarcRequestMock("/mail/e3.eml","pass", "replit.app", "pass client-ip=222.222.222.222; envelope-from=jqd@id.firewalledreplit.co; helo=replit.app", "replit.app", "dmarc=fail (p=reject) header.from=test.replit.app") ); - DMARCVerifier dmarcVerifier = new DMARCVerifier(DMARC_RESPONSE_TEMPLATE, DMARC_NON_RESPONSE_TEMPLATE, recordRetrieverDmarc); + DMARCVerifier dmarcVerifier = new DMARCVerifier(recordRetrieverDmarc); @Test public void generate_and_verify_dmarc_pass() { passRequests.forEach(r -> { - assertThat(dmarcVerifier.runDmarcCheck(r.message(), r.spfResult(), r.spfDomain(), r.dkimResult(), r.dkimDomain())).isEqualTo(r.expectedResult()); + assertThat(dmarcVerifier.runDmarcCheck(r.message(), r.spfResult(), r.spfDomain(), r.dkimResult(), r.dkimDomain()).toString()).hasToString(r.expectedResult()); }); } } \ No newline at end of file diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java b/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java index 5771a4a..984f377 100644 --- a/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java @@ -20,41 +20,89 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; public class PublicSuffixListTest { + /* + `example.com` does not exist in the PSL, only `com` does + so returning the `com` plus one label before it. + */ @Test - public void isPublicSuffix_shouldReturnTrueForKnownSuffix() { - assertTrue(PublicSuffixList.isPublicSuffix("com")); - assertTrue(PublicSuffixList.isPublicSuffix("CO.UK")); - assertTrue(PublicSuffixList.isPublicSuffix("replit.app")); - assertTrue(PublicSuffixList.isPublicSuffix("id.replit.app")); + public void getOrgDomain_simpleMatch() { + assertEquals("example.com", PublicSuffixList.getOrgDomain("example.com")); + assertEquals("example.com", PublicSuffixList.getOrgDomain("aaa.example.com")); + assertEquals("example.com", PublicSuffixList.getOrgDomain("bbb.aaa.example.com")); } + /* + Domains not covered by PSL → fallback + (should just return original domain) + */ @Test - public void isPublicSuffix_shouldReturnFalseForUnknownSuffix() { - assertFalse(PublicSuffixList.isPublicSuffix("example")); - assertFalse(PublicSuffixList.isPublicSuffix("unknown.tld")); - assertFalse(PublicSuffixList.isPublicSuffix("mail.replit.app")); + public void getOrgDomain_noPslMatch() { + assertEquals("unknown.private", PublicSuffixList.getOrgDomain("unknown.private")); + assertEquals("my.localdomain", PublicSuffixList.getOrgDomain("my.localdomain")); + assertEquals("service.internal", PublicSuffixList.getOrgDomain("service.internal")); } @Test public void getOrgDomain_shouldReturnPublicSuffixIfMatched() { - assertEquals("co.uk", PublicSuffixList.getOrgDomain("example.co.uk")); - assertEquals("replit.app", PublicSuffixList.getOrgDomain("mail.replit.app")); + assertEquals("example.co.uk", PublicSuffixList.getOrgDomain("example.co.uk")); + assertEquals("mail.replit.app", PublicSuffixList.getOrgDomain("mail.replit.app")); } + /* + *.sapporo.jp is a wild card rule + */ @Test - public void getOrgDomain_shouldNotReturnPublicSuffixIfNotMatched() { - assertNotEquals("replit.app", PublicSuffixList.getOrgDomain("id.replit.app")); - assertNotEquals("firewalledreplit.co", PublicSuffixList.getOrgDomain("id.firewalledreplit.co")); + public void getOrgDomain_wildCardMatched() { + assertEquals("sapporo.jp", PublicSuffixList.getOrgDomain("sapporo.jp")); + assertEquals("abc.sapporo.jp", PublicSuffixList.getOrgDomain("abc.sapporo.jp")); + assertEquals("foo.abc.sapporo.jp", PublicSuffixList.getOrgDomain("foo.abc.sapporo.jp")); + assertEquals("foo.abc.sapporo.jp", PublicSuffixList.getOrgDomain("bar.foo.abc.sapporo.jp")); } + /* + !city.sapporo.jp is an exception rule + */ @Test - public void getOrgDomain_shouldReturnInputIfNoSuffixMatched() { - assertEquals("mydomain.unknown", PublicSuffixList.getOrgDomain("mydomain.unknown")); + public void getOrgDomain_exceptionsMatched() { + assertEquals("city.sapporo.jp", PublicSuffixList.getOrgDomain("city.sapporo.jp")); + assertEquals("city.sapporo.jp", PublicSuffixList.getOrgDomain("abc.city.sapporo.jp")); + assertEquals("city.sapporo.jp", PublicSuffixList.getOrgDomain("x.y.city.sapporo.jp")); + } + + /* + *.ck + !www.ck + Wildcard with exception + */ + @Test + public void getOrgDomain_wildCardAndExceptionCombo() { + assertEquals("www.ck", PublicSuffixList.getOrgDomain("www.ck")); // exception + assertEquals("www.ck", PublicSuffixList.getOrgDomain("a.www.ck")); // exception overrides wildcard + assertEquals("abc.ck", PublicSuffixList.getOrgDomain("abc.ck")); // wildcard + one left + assertEquals("foo.abc.ck", PublicSuffixList.getOrgDomain("foo.abc.ck")); // wildcard + two left + assertEquals("foo.abc.ck", PublicSuffixList.getOrgDomain("bar.foo.abc.ck")); // wildcard + two. we stop at two left labels + } + + /* + single-label domains should return themselves + */ + @Test + public void getOrgDomain_singleLabel() { + assertEquals("localhost", PublicSuffixList.getOrgDomain("localhost")); + assertEquals("com", PublicSuffixList.getOrgDomain("com")); + assertEquals("example", PublicSuffixList.getOrgDomain("example")); + } + + /* + PSL match with internationalized domain names (IDN) + */ + @Test + public void getOrgDomain_openAiWildcard() { + assertEquals("三重.jp", PublicSuffixList.getOrgDomain("三重.jp")); //Bare PSL match + assertEquals("北海道.三重.jp", PublicSuffixList.getOrgDomain("北海道.三重.jp")); //PSL + one left + assertEquals("北海道.三重.jp", PublicSuffixList.getOrgDomain("大分.北海道.三重.jp")); //PSL + two left } } \ No newline at end of file From 3bddd76313b0e9a619db8d1985a43aaede3f6b50 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 27 Mar 2026 17:42:49 -0400 Subject: [PATCH 16/40] Updated README to reflect the purpose of the fork --- README.adoc | 95 +++++++++-------------------------------------------- 1 file changed, 15 insertions(+), 80 deletions(-) diff --git a/README.adoc b/README.adoc index 64e0546..787fccc 100644 --- a/README.adoc +++ b/README.adoc @@ -1,88 +1,23 @@ -= JAMES jDKIM library += JAMES jDKIM fork with ARC support +This repository is a fork of Apache James jDKIM that adds ARC (Authenticated Received Chain) signing and related mail authentication capabilities alongside +the original DKIM functionality. -Library dealing with parsing and crytography to sign and verify DKIM signatures. +It is intended for experimentation and integration work around RFC 8617 in Java-based mail processing workflows. -The mailet has been moved to James project: https://github.com/apache/james-project/tree/master/server/mailet/dkim +Original upstream project: +https://github.com/apache/james-jdkim -== Usage +The mailet has been moved to the James project: +https://github.com/apache/james-project/tree/master/server/mailet/dkim -A full example is available in -https://github.com/apache/james-jdkim/blob/master/main/src/test/java/org/apache/james/jdkim/DKIMTest.java[DKIMTest] +Then add this after == Usage: -=== Signing +== Fork-specific additions -Signing a mime message can be achieved using the following snippet +This fork extends the original Apache James jDKIM codebase with ARC-related functionality. -[source,java] ----- -import java.io.InputStream; -import java.security.PrivateKey; - -String signatureTemplate = "v=1; a=rsa-sha256; c=simple; d=messiah.edu; h=date:from:subject; q=dns/txt; s=selector2;"; - -PrivateKey privateKey = null; -DKIMSigner dkimSigner = new DKIMSigner(signatureTemplate, privateKey); -// You need to provide the input stream of the mime message, it will be parsed -// by mime4j -InputStream stream = null; -String signature = dkimSigner.sign(inputStream); -// `signature` contains the full header -// DKIM-Signature: a=rsa-sha256; q=dns/txt; b=Axa8s/g...U1SIw==; c=simple; s=selector2; d=messiah.edu; v=1; bh=6pQ...6g=; h=date:from:subject; ----- - -More advanced usage such as including multiple signatures can be found in -https://github.com/apache/james-jdkim/blob/master/main/src/test/java/org/apache/james/jdkim/DKIMTest.java[DKIMTest] - -=== Verifying - -Verifying a mime message DKIM signatures can be achieved using the following -snippet. The verifier always verifies all the signatures. - -[source,java] ----- -import java.io.InputStream; -// You can override the resolver in the constructor, use your own -// implementation of a retriever or use multiple implementations using a -// `MultiplexingPublicKeyRecordRetriever` -PublicKeyRecordRetriever keyRecordRetriever = new DNSPublicKeyRecordRetriever(); -DKIMVerifier verifier = new DKIMVerifier(keyRecordRetriever); -InputStream stream = null; // you need to provide the input stream of the mime message -List verifiedSignatures = verifier.verify(stream); -// `verifiedSignatures` contains only the signatures that have successfully -// passed the validation. -// If you want to query all the results including all the failures, you can -// retrieve them from the verifier -List results = verifier.getResults(); ----- - -== Cryptography Notice - ----- - This distribution includes cryptographic software. The country in - which you currently reside may have restrictions on the import, - possession, use, and/or re-export to another country, of - encryption software. BEFORE using any encryption software, please - check your country's laws, regulations and policies concerning the - import, possession, or use, and re-export of encryption software, to - see if this is permitted. See http://www.wassenaar.org for more - information. - - The U.S. Government Department of Commerce, Bureau of Industry and - Security (BIS), has classified this software as Export Commodity - Control Number (ECCN) 5D002.C.1, which includes information security - software using or performing cryptographic functions with asymmetric - algorithms. The form and manner of this Apache Software Foundation - distribution makes it eligible for export under the License Exception - ENC Technology Software Unrestricted (TSU) exception (see the BIS - Export Administration Regulations, Section 740.13) for both object - code and source code. - - The following provides more details on the included cryptographic - software: - - - jDKIM includes code designed to work with Java SE Security - - Export classifications and source links can be found - at http://www.apache.org/licenses/exports/. ----- \ No newline at end of file +Current fork-specific focus includes: +- ARC signing support +- ARC chain handling +- Mail authentication extensions related to RFC 8617 From bdca306d348d932908664e16c265b12629a969d2 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 27 Mar 2026 18:30:51 -0400 Subject: [PATCH 17/40] Update README.adoc Removed typos --- README.adoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.adoc b/README.adoc index 787fccc..a9b9971 100644 --- a/README.adoc +++ b/README.adoc @@ -11,8 +11,6 @@ https://github.com/apache/james-jdkim The mailet has been moved to the James project: https://github.com/apache/james-project/tree/master/server/mailet/dkim -Then add this after == Usage: - == Fork-specific additions This fork extends the original Apache James jDKIM codebase with ARC-related functionality. From 6e69d2a555a4a469b81e4e66063db3bd6e70aedd Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sat, 28 Mar 2026 14:06:53 -0400 Subject: [PATCH 18/40] Fix site build and ARC/DMARC test support --- dmarc/pom.xml | 6 ++++++ .../apache/james/jdkim/tagvalue/SignatureRecordImpl.java | 4 ++-- src/site/site.xml | 5 ----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dmarc/pom.xml b/dmarc/pom.xml index fa09cc2..a1f3f1f 100644 --- a/dmarc/pom.xml +++ b/dmarc/pom.xml @@ -63,6 +63,12 @@ + src/main/test/java + + + src/main/test/resources + + maven-jar-plugin diff --git a/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java b/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java index c2cfc88..79dd59d 100644 --- a/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java +++ b/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java @@ -274,12 +274,12 @@ public List getRecordLookupMethods() { } public void setSignature(byte[] newSignature) { - String signature = new String(Base64.getMimeDecoder().decode(newSignature)); + String signature = new String(Base64.getEncoder().encode(newSignature)); setValue("b", signature); } public void setBodyHash(byte[] newBodyHash) { - String bodyHash = new String(Base64.getMimeDecoder().decode(newBodyHash)); + String bodyHash = new String(Base64.getEncoder().encode(newBodyHash)); setValue("bh", bodyHash); // If a t=; parameter is present in the signature, make sure to // fill it with the current timestamp diff --git a/src/site/site.xml b/src/site/site.xml index 0caafe5..5b3e776 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -33,11 +33,6 @@ - - - - - Date: Thu, 16 Apr 2026 16:44:30 -0400 Subject: [PATCH 19/40] Add cv_fail_i1_ams_invalid test: assert cv=fail when ARC-Message-Signature b= is cryptographically invalid --- .../java/org/apache/james/arc/ARCTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 1849203..9d9a316 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -85,6 +85,8 @@ public class ARCTest { private static final long TIMESTAMP = 1755918846L; // fixed timestamp for repeatable tests ArcSetBuilder arcSetBuilder = new ArcSetBuilder(ArcTestKeys.privateKeyArc, ARC_AMS_TEMPLATE, ARC_SEAL_TEMPLATE, AUTH_SERVICE, TIMESTAMP); + // Happy path: signs a fresh message (no prior ARC chain), pins the exact header values produced, + // then validates the resulting i=1 chain and asserts cv=pass. @Test public void generate_and_verify_arc_set() throws Exception { String expectedCv = "pass"; @@ -121,6 +123,30 @@ public void generate_and_verify_arc_set() throws Exception { assertThat(cv.getResult().toString().toLowerCase()).isEqualTo(expectedCv); } + // cv_fail_i1_ams_invalid: builds a valid i=1 ARC set, then replaces the AMS b= signature with + // wrong bytes before adding headers to the message, expecting chain validation to return cv=fail. + @Test + public void validate_arc_chain_fails_when_ams_signature_is_invalid() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + // Replace b= with 128 zero bytes (correct RSA key length but wrong value) so sig.verify() returns false + String fakeB64 = Base64.getEncoder().encodeToString(new byte[128]); + String corruptedAms = arcSet.get(ARC_MESSAGE_SIGNATURE) + .replaceAll("; b=.*$", "; b=" + fakeB64); + arcSet.put(ARC_MESSAGE_SIGNATURE, corruptedAms); + + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { URL resource = this.getClass().getResource(fileName); FileInputStream file = new FileInputStream(new File(resource.toURI())); From 399e245a24bee6d04a8a9a319d874feea76df725 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 10:20:13 -0400 Subject: [PATCH 20/40] Add cv_fail_i1_as_invalid test: assert cv=fail when ARC-Seal b= is cryptographically invalid --- .../java/org/apache/james/arc/ARCTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 9d9a316..c37de17 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -147,6 +147,30 @@ public void validate_arc_chain_fails_when_ams_signature_is_invalid() throws Exce assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // cv_fail_i1_as_invalid: builds a valid i=1 ARC set, then replaces the ARC-Seal b= signature with + // wrong bytes before adding headers to the message, expecting chain validation to return cv=fail. + @Test + public void validate_arc_chain_fails_when_arc_seal_signature_is_invalid() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + // Replace b= with 128 zero bytes (correct RSA key length but wrong value) so sig.verify() returns false + String fakeB64 = Base64.getEncoder().encodeToString(new byte[128]); + String corruptedSeal = arcSet.get(ARC_SEAL) + .replaceAll("; b=.*$", "; b=" + fakeB64); + arcSet.put(ARC_SEAL, corruptedSeal); + + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { URL resource = this.getClass().getResource(fileName); FileInputStream file = new FileInputStream(new File(resource.toURI())); From 101c79c5da1e2c83c6ea2dc48e006e8dbc2931dc Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 10:37:52 -0400 Subject: [PATCH 21/40] Fix ARCChainValidator to return cv=fail instead of throwing when ARC chain structure is invalid. Also add cv_fail_i1_as_pass and cv_fail_i1_as_cv_fail tests: assert cv=fail when ARC-Seal cv= is invalid on first hop --- .../apache/james/arc/ARCChainValidator.java | 7 +++- .../java/org/apache/james/arc/ARCTest.java | 42 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index 1a01e06..bd408e9 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -76,7 +76,12 @@ private ArcValidationOutcome validatePreviousArcHops(Message message, Header mes ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); Map> arcHeadersByI = arcVerifier.getArcHeadersByI(messageHeaders.getFields()); int numArcInstances = myInstance - 1; - boolean isArcSetStructureOK = arcVerifier.validateArcSetStructure(arcHeadersByI); + boolean isArcSetStructureOK; + try { + isArcSetStructureOK = arcVerifier.validateArcSetStructure(arcHeadersByI); + } catch (ArcException | IllegalStateException e) { + return new ArcValidationOutcome(ArcValidationResult.FAIL, e.getMessage()); + } if (!isArcSetStructureOK) { return new ArcValidationOutcome(ArcValidationResult.FAIL, "ARC set structure is invalid"); } diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index c37de17..485782a 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -171,6 +171,48 @@ public void validate_arc_chain_fails_when_arc_seal_signature_is_invalid() throws assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // cv_fail_i1_as_pass: the ARC-Seal at i=1 must always carry cv=none (there is no prior chain to + // have passed). If it says cv=pass, the structure is invalid and the chain must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_cv_is_pass_on_first_hop() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + String tamperedSeal = arcSet.get(ARC_SEAL).replace("cv=none", "cv=pass"); + arcSet.put(ARC_SEAL, tamperedSeal); + + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i1_as_cv_fail: the ARC-Seal at i=1 carrying cv=fail means the chain was declared + // broken from the very first hop, so validation must return cv=fail. + @Test + public void validate_arc_chain_fails_when_arc_seal_cv_is_fail_on_first_hop() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + String tamperedSeal = arcSet.get(ARC_SEAL).replace("cv=none", "cv=fail"); + arcSet.put(ARC_SEAL, tamperedSeal); + + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { URL resource = this.getClass().getResource(fileName); FileInputStream file = new FileInputStream(new File(resource.toURI())); From aa008e5ac8b32a8d088ec565c78ea0f6a6866bc9 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 15:56:24 -0400 Subject: [PATCH 22/40] Add 10 cv_fail_i2_* tests: assert cv=fail for all structural and signature failures in a two-hop ARC chain --- .../java/org/apache/james/arc/ARCTest.java | 256 ++++++++++++++++++ 1 file changed, 256 insertions(+) diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 485782a..4d34205 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -26,7 +26,9 @@ import org.apache.james.mime4j.stream.RawField; import org.junit.Test; +import org.apache.james.mime4j.stream.Field; import java.util.Base64; +import java.util.List; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -171,6 +173,44 @@ public void validate_arc_chain_fails_when_arc_seal_signature_is_invalid() throws assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // cv_fail_i1_ams_na: if the ARC-Message-Signature header is absent from the i=1 set entirely, + // the chain is structurally incomplete and must be rejected with cv=fail. + @Test + public void validate_arc_chain_fails_when_ams_header_is_missing() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + arcSet.remove(ARC_MESSAGE_SIGNATURE); + + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i1_as_na: if the ARC-Seal header is absent from the i=1 set entirely, + // the chain is structurally incomplete and must be rejected with cv=fail. + @Test + public void validate_arc_chain_fails_when_arc_seal_header_is_missing() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + arcSet.remove(ARC_SEAL); + + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // cv_fail_i1_as_pass: the ARC-Seal at i=1 must always carry cv=none (there is no prior chain to // have passed). If it says cv=pass, the structure is invalid and the chain must be rejected. @Test @@ -213,6 +253,222 @@ public void validate_arc_chain_fails_when_arc_seal_cv_is_fail_on_first_hop() thr assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // cv_empty: a completely empty message (no headers, no body) has no ARC chain — the validator + // must return cv=none rather than crash or return cv=fail. + @Test + public void validate_arc_chain_returns_none_for_empty_message() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream(new byte[0])); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("none"); + } + + // cv_no_headers: a message with no headers at all has no ARC chain — the validator must return + // cv=none gracefully without throwing. + @Test + public void validate_arc_chain_returns_none_for_message_with_no_headers() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream("\r\nbody text here".getBytes(StandardCharsets.UTF_8))); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("none"); + } + + // cv_no_body: a message that has headers but no body is legal — the validator must process the + // (absent) ARC chain normally and return cv=none when no ARC headers are present. + @Test + public void validate_arc_chain_returns_none_for_message_with_no_body() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream("From: sender@example.com\r\nTo: recipient@example.com\r\nSubject: test\r\n\r\n" + .getBytes(StandardCharsets.UTF_8))); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("none"); + } + + // cv_fail_i2_ams_na: in a two-hop chain, if the ARC-Message-Signature for i=2 is missing, the + // chain is structurally incomplete and must be rejected with cv=fail. + @Test + public void validate_arc_chain_fails_when_i2_ams_is_missing() throws Exception { + Message message = buildTwoHopChain(); + removeHeaderByInstanceAndType(message, ARC_MESSAGE_SIGNATURE, "i=2"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_ams_invalid: in a two-hop chain, if the ARC-Message-Signature at i=2 has a bad + // cryptographic signature, the chain must be rejected even if i=1 was valid. + @Test + public void validate_arc_chain_fails_when_i2_ams_signature_is_invalid() throws Exception { + Message message = buildTwoHopChain(); + corruptSignatureOnHeader(message, ARC_MESSAGE_SIGNATURE, "i=2"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_as2_na: in a two-hop chain, if the ARC-Seal for i=2 is missing, the chain is + // structurally incomplete and must be rejected with cv=fail. + @Test + public void validate_arc_chain_fails_when_i2_arc_seal_is_missing() throws Exception { + Message message = buildTwoHopChain(); + removeHeaderByInstanceAndType(message, ARC_SEAL, "i=2"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_as2_invalid: in a two-hop chain, if the ARC-Seal at i=2 has been tampered with, + // the chain must be rejected with cv=fail. + @Test + public void validate_arc_chain_fails_when_i2_arc_seal_signature_is_invalid() throws Exception { + Message message = buildTwoHopChain(); + corruptSignatureOnHeader(message, ARC_SEAL, "i=2"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_as2_none: the ARC-Seal at i=2 must carry cv=pass because i=1 was valid. If it + // incorrectly says cv=none, the chain structure is wrong and must be rejected. + @Test + public void validate_arc_chain_fails_when_i2_arc_seal_cv_is_none() throws Exception { + Message message = buildTwoHopChain(); + replaceTagOnHeader(message, ARC_SEAL, "i=2", "cv=pass", "cv=none"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_as2_fail: if the ARC-Seal at i=2 says cv=fail, the chain must be rejected. + @Test + public void validate_arc_chain_fails_when_i2_arc_seal_cv_is_fail() throws Exception { + Message message = buildTwoHopChain(); + replaceTagOnHeader(message, ARC_SEAL, "i=2", "cv=pass", "cv=fail"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_as1_na: in a two-hop chain, if the ARC-Seal from i=1 is missing, the second + // server's seal cannot be verified and the chain must be rejected. + @Test + public void validate_arc_chain_fails_when_i1_arc_seal_is_missing_in_two_hop_chain() throws Exception { + Message message = buildTwoHopChain(); + removeHeaderByInstanceAndType(message, ARC_SEAL, "i=1"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_as1_invalid: in a two-hop chain, if the i=1 ARC-Seal has a bad signature, the + // entire chain must be rejected even if i=2 looks fine. + @Test + public void validate_arc_chain_fails_when_i1_arc_seal_signature_is_invalid_in_two_hop_chain() throws Exception { + Message message = buildTwoHopChain(); + corruptSignatureOnHeader(message, ARC_SEAL, "i=1"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_as1_pass: in a two-hop chain, the i=1 ARC-Seal must say cv=none (not cv=pass). + // If it says cv=pass, the chain structure is wrong and must be rejected. + @Test + public void validate_arc_chain_fails_when_i1_arc_seal_cv_is_pass_in_two_hop_chain() throws Exception { + Message message = buildTwoHopChain(); + replaceTagOnHeader(message, ARC_SEAL, "i=1", "cv=none", "cv=pass"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_fail_i2_as1_fail: in a two-hop chain, if the i=1 ARC-Seal says cv=fail, the chain was + // already declared broken at hop one and the whole chain must be rejected. + @Test + public void validate_arc_chain_fails_when_i1_arc_seal_cv_is_fail_in_two_hop_chain() throws Exception { + Message message = buildTwoHopChain(); + replaceTagOnHeader(message, ARC_SEAL, "i=1", "cv=none", "cv=fail"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // Builds a valid two-hop ARC chain: applies i=1 to the base message, then applies i=2 on top. + private Message buildTwoHopChain() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + Map arcSet1 = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + for (Map.Entry entry : arcSet1.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + Map arcSet2 = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + for (Map.Entry entry : arcSet2.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + return message; + } + + // Removes the first header matching the given name that contains the given instance tag (e.g. "i=2"). + private void removeHeaderByInstanceAndType(Message message, String headerName, String instanceTag) { + Field toRemove = message.getHeader().getFields().stream() + .filter(f -> f.getName().equalsIgnoreCase(headerName) && f.getBody().contains(instanceTag)) + .findFirst().orElseThrow(() -> new AssertionError("Header not found: " + headerName + " with " + instanceTag)); + message.getHeader().removeFields(toRemove.getName()); + message.getHeader().getFields().stream() + .filter(f -> f.getName().equalsIgnoreCase(headerName) && !f.getBody().contains(instanceTag)) + .forEach(f -> message.getHeader().addField(f)); + } + + // Replaces the b= signature on a specific ARC header (identified by name + instance tag) with 128 zero bytes. + private void corruptSignatureOnHeader(Message message, String headerName, String instanceTag) { + String fakeB64 = Base64.getEncoder().encodeToString(new byte[128]); + List fields = new java.util.ArrayList<>(message.getHeader().getFields()); + message.getHeader().removeFields(headerName); + for (Field f : fields) { + if (f.getName().equalsIgnoreCase(headerName)) { + if (f.getBody().contains(instanceTag)) { + String corrupted = f.getBody().replaceAll("; b=.*$", "; b=" + fakeB64); + message.getHeader().addField(new RawField(f.getName(), corrupted)); + } else { + message.getHeader().addField(f); + } + } + } + } + + // Replaces a tag value (e.g. "cv=pass" → "cv=none") on the first matching header with the given instance tag. + private void replaceTagOnHeader(Message message, String headerName, String instanceTag, String oldVal, String newVal) { + List fields = new java.util.ArrayList<>(message.getHeader().getFields()); + message.getHeader().removeFields(headerName); + for (Field f : fields) { + if (f.getName().equalsIgnoreCase(headerName)) { + if (f.getBody().contains(instanceTag)) { + message.getHeader().addField(new RawField(f.getName(), f.getBody().replace(oldVal, newVal))); + } else { + message.getHeader().addField(f); + } + } + } + } + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { URL resource = this.getClass().getResource(fileName); FileInputStream file = new FileInputStream(new File(resource.toURI())); From db78f243a946f4f6df546cfe0cd954315aef4bd2 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 16:15:46 -0400 Subject: [PATCH 23/40] Fix a bug in ARC-Seal to cover all prior hop headers as per RFC 8617; Also add cv_pass_i2..i5 and cv_pass_i2_1_ams1_invalid tests --- .../java/org/apache/james/arc/ARCCommon.java | 4 +- .../java/org/apache/james/arc/ARCSigner.java | 6 +- .../org/apache/james/arc/ArcSetBuilder.java | 28 +++++-- .../java/org/apache/james/arc/ARCTest.java | 77 ++++++++++++++++--- 4 files changed, 96 insertions(+), 19 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCCommon.java b/arc/src/main/java/org/apache/james/arc/ARCCommon.java index 44c1cab..09ea6c0 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCCommon.java +++ b/arc/src/main/java/org/apache/james/arc/ARCCommon.java @@ -90,12 +90,12 @@ static void amsSign(Headers h, SignatureRecord sign, } static void arcSeal(SignatureRecord sign, - Map headersToSeal, Signature signature) + List> headersToSeal, Signature signature) throws SignatureException, PermFailException { boolean relaxedHeaders = isRelaxedHeaders(sign, false); - for (Map.Entry headerEntry : headersToSeal.entrySet()) { + for (Map.Entry headerEntry : headersToSeal) { String headerName = headerEntry.getKey(); String headerValue = headerName+": " +headerEntry.getValue(); updateSignature(signature, relaxedHeaders, headerName, headerValue); diff --git a/arc/src/main/java/org/apache/james/arc/ARCSigner.java b/arc/src/main/java/org/apache/james/arc/ARCSigner.java index 124997a..74335f1 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCSigner.java +++ b/arc/src/main/java/org/apache/james/arc/ARCSigner.java @@ -106,7 +106,7 @@ private static Message getMessage(InputStream is) { return message; } - public String sealHeaders(Map headersToSeal) { + public String sealHeaders(List> headersToSeal) { SignatureRecord srt = newSignatureRecordTemplate(signatureRecordTemplate); return seal(srt, headersToSeal); } @@ -138,7 +138,7 @@ public String generateAms(Headers message, BodyHasher bh) throws PermFailExcepti } } - public String seal(SignatureRecord signatureRecord, Map headersToSeal) { + public String seal(SignatureRecord signatureRecord, List> headersToSeal) { try { byte[] signatureHash = signatureSeal(signatureRecord, privateKey, headersToSeal); @@ -156,7 +156,7 @@ public String seal(SignatureRecord signatureRecord, Map headersT } } - private byte[] signatureSeal(SignatureRecord sign, PrivateKey key, Map headersToSeal) + private byte[] signatureSeal(SignatureRecord sign, PrivateKey key, List> headersToSeal) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, PermFailException { Signature signature = Signature.getInstance(sign.getHashMethod() diff --git a/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java b/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java index 94b480d..6ca5d51 100644 --- a/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java +++ b/arc/src/main/java/org/apache/james/arc/ArcSetBuilder.java @@ -29,8 +29,13 @@ import java.io.IOException; import java.security.PrivateKey; import java.time.Instant; +import org.apache.james.mime4j.stream.Field; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; -import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; /** @@ -106,11 +111,24 @@ public Map buildArcSet(Message message, String helo, String mail } arcHeaders.put(AUTHENTICATION_RESULTS, arHeaderValue); - Map headersToSeal = new LinkedHashMap<>(); - String aarHeaderValue = "i=" + instance + "; " + arHeaderValue.trim(); + // Collect all prior ARC headers (i=1..instance-1) in spec-required order: AAR, AMS, AS per hop + List> headersToSeal = new ArrayList<>(); + ARCVerifier arcVerifier = new ARCVerifier(keyRecordRetriever); + Map> priorArcHeaders = arcVerifier.getArcHeadersByI(headers.getFields()); + for (Map.Entry> hopEntry : priorArcHeaders.entrySet()) { + List hopFields = hopEntry.getValue(); + for (String arcHdrName : Arrays.asList(ARC_AUTHENTICATION_RESULTS, ARC_MESSAGE_SIGNATURE, ARC_SEAL)) { + hopFields.stream() + .filter(f -> f.getName().equalsIgnoreCase(arcHdrName)) + .findFirst() + .ifPresent(f -> headersToSeal.add(new AbstractMap.SimpleEntry<>(f.getName(), f.getBody()))); + } + } + + String aarHeaderValue = "i=" + instance + "; " + arHeaderValue.trim(); arcHeaders.put(ARC_AUTHENTICATION_RESULTS, aarHeaderValue); - headersToSeal.put(ARC_AUTHENTICATION_RESULTS, aarHeaderValue); + headersToSeal.add(new AbstractMap.SimpleEntry<>(ARC_AUTHENTICATION_RESULTS, aarHeaderValue)); DefaultMessageWriter writer = new DefaultMessageWriter(); ByteArrayOutputStream os = new ByteArrayOutputStream(); @@ -138,7 +156,7 @@ public Map buildArcSet(Message message, String helo, String mail String amsValue = amsHeader.split(ARC_ELEMENT)[1]; arcHeaders.put(ARC_MESSAGE_SIGNATURE, amsValue); - headersToSeal.put(ARC_MESSAGE_SIGNATURE, amsValue); + headersToSeal.add(new AbstractMap.SimpleEntry<>(ARC_MESSAGE_SIGNATURE, amsValue)); //Build and add ARC-Seal header String asTemplate = fillArcSealTemplate(_arcSealTemplate, instance, timestamp, cv); diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 4d34205..05cf062 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -409,19 +409,78 @@ public void validate_arc_chain_fails_when_i1_arc_seal_cv_is_fail_in_two_hop_chai assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // cv_pass_i2_1: a message that passed through two mail servers, each adding a valid ARC set, + // should validate as cv=pass. + @Test + public void validate_arc_chain_passes_for_valid_two_hop_chain() throws Exception { + Message message = buildNHopChain(2); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + + // cv_pass_i2_2: same two-hop happy path using a second message variant, confirming validation + // is not tied to a single email structure. + @Test + public void validate_arc_chain_passes_for_valid_two_hop_chain_variant2() throws Exception { + Message message = buildNHopChain(2); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + + // cv_pass_i2_1_ams1_invalid: if the i=1 ARC-Message-Signature is corrupted after the chain was + // built, the overall chain must be rejected even if the i=2 seal is intact. + @Test + public void validate_arc_chain_fails_when_i1_ams_corrupted_after_chain_built() throws Exception { + Message message = buildNHopChain(2); + corruptSignatureOnHeader(message, ARC_MESSAGE_SIGNATURE, "i=1"); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_pass_i3_1: a three-hop chain where every ARC set is valid should validate as cv=pass. + @Test + public void validate_arc_chain_passes_for_valid_three_hop_chain() throws Exception { + Message message = buildNHopChain(3); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + + // cv_pass_i4_1: a four-hop chain where every ARC set is valid should validate as cv=pass. + @Test + public void validate_arc_chain_passes_for_valid_four_hop_chain() throws Exception { + Message message = buildNHopChain(4); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + + // cv_pass_i5_1: a five-hop chain where every ARC set is valid should validate as cv=pass. + @Test + public void validate_arc_chain_passes_for_valid_five_hop_chain() throws Exception { + Message message = buildNHopChain(5); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + // Builds a valid two-hop ARC chain: applies i=1 to the base message, then applies i=2 on top. private Message buildTwoHopChain() throws Exception { + return buildNHopChain(2); + } + + // Builds a valid N-hop ARC chain by repeatedly applying a new ARC set to the same message. + private Message buildNHopChain(int n) throws Exception { ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); Message message = new DefaultMessageBuilder().parseMessage(emailStream); - - Map arcSet1 = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); - for (Map.Entry entry : arcSet1.entrySet()) { - message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); - } - - Map arcSet2 = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); - for (Map.Entry entry : arcSet2.entrySet()) { - message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + for (int hop = 0; hop < n; hop++) { + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } } return message; } From d2eba4347994c4852c65730c4112542f50c3df46 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 17:28:27 -0400 Subject: [PATCH 24/40] Add AMS structural validation tests and fix uncaught exceptions for malformed i= tags --- .../apache/james/arc/ARCChainValidator.java | 7 +- .../java/org/apache/james/arc/ARCTest.java | 90 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index bd408e9..3d03939 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -74,7 +74,12 @@ else if (curInstance > 51) { // Not allowed to be > 50 private ArcValidationOutcome validatePreviousArcHops(Message message, Header messageHeaders, int myInstance) { ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); - Map> arcHeadersByI = arcVerifier.getArcHeadersByI(messageHeaders.getFields()); + Map> arcHeadersByI; + try { + arcHeadersByI = arcVerifier.getArcHeadersByI(messageHeaders.getFields()); + } catch (IllegalStateException | NumberFormatException e) { + return new ArcValidationOutcome(ArcValidationResult.FAIL, e.getMessage()); + } int numArcInstances = myInstance - 1; boolean isArcSetStructureOK; try { diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 05cf062..9b49803 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -467,6 +467,96 @@ public void validate_arc_chain_passes_for_valid_five_hop_chain() throws Exceptio assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); } + // ams_struct_i_na: an ARC-Message-Signature with no i= tag at all must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_has_no_instance_tag() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replaceFirst("i=1;\\s*", ""); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_struct_i_empty: an ARC-Message-Signature with i= but no value (i=;) must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_has_empty_instance_tag() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replaceFirst("i=1;", "i=;"); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_struct_i_zero: an ARC-Message-Signature with i=0 must be rejected — instance numbers start at 1. + @Test + public void validate_arc_chain_fails_when_ams_has_zero_instance_tag() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replaceFirst("i=1;", "i=0;"); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_struct_i_invalid: an ARC-Message-Signature with a non-numeric i= value must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_has_non_numeric_instance_tag() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replaceFirst("i=1;", "i=abc;"); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_struct_dup: two ARC-Message-Signature headers both claiming i=1 make the set ambiguous and + // must be rejected — each instance number must appear exactly once. + @Test + public void validate_arc_chain_fails_when_ams_is_duplicated_at_same_instance() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + // Add a second AMS header at i=1 — duplicates the instance number + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, arcSet.get(ARC_MESSAGE_SIGNATURE))); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_struct_missing: an ARC-Seal at i=1 with no corresponding ARC-Message-Signature means the + // set is incomplete and must be rejected — covered by validate_arc_chain_fails_when_ams_header_is_missing. + // Builds a valid two-hop ARC chain: applies i=1 to the base message, then applies i=2 on top. private Message buildTwoHopChain() throws Exception { return buildNHopChain(2); From af9ee1710a98ff207885a42b6780fa75352f208e Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 17:41:16 -0400 Subject: [PATCH 25/40] Add AMS tag format validation tests and fix null-safe DNS result handling --- .../org/apache/james/arc/ARCVerifier.java | 2 +- .../java/org/apache/james/arc/ARCTest.java | 127 ++++++++++++++++++ 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index b831dfc..ef3311e 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -365,7 +365,7 @@ public String getTxtDnsRecordByField(Field signedHeader) { try { List results = getPublicKeyRecordRetriever().getRecords("dns/txt", amsSelector, amsDomain); - if (!results.isEmpty()) { + if (results != null && !results.isEmpty()) { return results.get(0); //Todo: handle multiple records? } } catch (TempFailException e) { diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 9b49803..51deaa7 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -557,6 +557,133 @@ public void validate_arc_chain_fails_when_ams_is_duplicated_at_same_instance() t // ams_struct_missing: an ARC-Seal at i=1 with no corresponding ARC-Message-Signature means the // set is incomplete and must be rejected — covered by validate_arc_chain_fails_when_ams_header_is_missing. + // ams_format_tags_unknown: an unrecognised tag in the ARC-Message-Signature must be silently ignored, + // so a chain signed with an extra z= tag must still validate as cv=pass. + @Test + public void validate_arc_chain_passes_when_ams_has_unknown_tag() throws Exception { + String templateWithUnknownTag = "i=; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; z=test; t=; h=Subject:From:To; bh=; b="; + ArcSetBuilder builderWithUnknownTag = new ArcSetBuilder(ArcTestKeys.privateKeyArc, templateWithUnknownTag, ARC_SEAL_TEMPLATE, AUTH_SERVICE, TIMESTAMP); + + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = builderWithUnknownTag.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + + // ams_format_inv_tag_key: a tag key starting with a digit (e.g. 1s=arc) is not a valid tag name + // and the selector cannot be resolved, so the chain must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_has_invalid_tag_key_character() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replace("s=arc", "1s=arc"); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_format_tags_dup: if the same tag key appears twice in an ARC-Message-Signature, the second + // value overrides the first, resolving to a different selector that is not in DNS, causing failure. + @Test + public void validate_arc_chain_fails_when_ams_has_duplicate_tag() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE) + "; s=invalid"; + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_format_tags_key_case: tag keys are case-sensitive — S=arc does not provide the s= tag, + // so the selector cannot be found and the chain must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_uses_uppercase_tag_key() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replace("s=arc", "S=arc"); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_format_tags_val_case: modifying a tag value's case (e.g. a=RSA-SHA256) changes the + // signed bytes so the signature no longer verifies, and the chain must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_tag_value_has_wrong_case() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replace("a=rsa-sha256", "a=RSA-SHA256"); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_format_tags_wsp: whitespace inside a tag value (s=ar c) changes the DNS selector name to + // one that does not exist, so the public key cannot be retrieved and the chain must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_tag_value_contains_whitespace() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replace("s=arc", "s=ar c"); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_format_tags_sc: an extra semicolon inside a tag value splits the value, making the s= tag + // resolve to a truncated selector that is not in DNS, so the chain must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_tag_value_contains_semicolon() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + String malformedAms = arcSet.get(ARC_MESSAGE_SIGNATURE).replace("s=arc", "s=ar;c"); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, malformedAms)); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // Builds a valid two-hop ARC chain: applies i=1 to the base message, then applies i=2 on top. private Message buildTwoHopChain() throws Exception { return buildNHopChain(2); From 0f048c21a71d8ad383d64d7e4ab80cf1bc6c0e27 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 18:06:59 -0400 Subject: [PATCH 26/40] Add canonicalization tests for body whitespace and header normalization --- .../java/org/apache/james/arc/ARCTest.java | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 51deaa7..85c589a 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -557,6 +557,202 @@ public void validate_arc_chain_fails_when_ams_is_duplicated_at_same_instance() t // ams_struct_missing: an ARC-Seal at i=1 with no corresponding ARC-Message-Signature means the // set is incomplete and must be rejected — covered by validate_arc_chain_fails_when_ams_header_is_missing. + // Pre-filled template used for direct ARCSigner canonicalization tests. + private static final String CANON_TEST_TEMPLATE = + "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; t=" + TIMESTAMP + + "; h=Subject:From:To; bh=; b="; + + // Minimal base email used for canonicalization tests. + private static final String BASE_EMAIL = + "From: jqd@d1.example\r\n" + + "To: arc@example.com\r\n" + + "Subject: test\r\n" + + "\r\n" + + "Hello world\r\n"; + + // Signs a raw email byte string directly with ARCSigner and returns "ARC-element:". + private String signRawEmail(String rawEmail) { + ARCSigner signer = new ARCSigner(CANON_TEST_TEMPLATE, ArcTestKeys.privateKeyArc); + return signer.generateAms(new ByteArrayInputStream(rawEmail.getBytes(StandardCharsets.UTF_8))); + } + + // Extracts a tag value from an AMS record (with or without the "ARC-element:" prefix). + private String extractAmsTag(String ams, String tagName) { + String body = ams.replaceFirst("^ARC-element:", ""); + for (String part : body.split(";")) { + String t = part.trim(); + if (t.startsWith(tagName + "=")) { + return t.substring((tagName + "=").length()).trim(); + } + } + return null; + } + + // message_body_eol_wsp: trailing whitespace on a body line must be stripped before body hashing, + // so two messages that differ only in trailing spaces produce the same bh=. + @Test + public void body_hash_is_invariant_under_body_line_trailing_whitespace() { + String variant = BASE_EMAIL.replace("Hello world\r\n", "Hello world \r\n"); + assertThat(extractAmsTag(signRawEmail(BASE_EMAIL), "bh")) + .isEqualTo(extractAmsTag(signRawEmail(variant), "bh")); + } + + // message_body_inl_wsp: runs of whitespace inside a body line must be collapsed to one space + // before body hashing, so double spaces produce the same bh= as single spaces. + @Test + public void body_hash_is_invariant_under_body_inline_whitespace() { + String variant = BASE_EMAIL.replace("Hello world\r\n", "Hello world\r\n"); + assertThat(extractAmsTag(signRawEmail(BASE_EMAIL), "bh")) + .isEqualTo(extractAmsTag(signRawEmail(variant), "bh")); + } + + // message_body_end_lines: trailing blank lines at the end of the body must be ignored when + // computing the body hash, so extra blank lines produce the same bh=. + @Test + public void body_hash_is_invariant_under_trailing_blank_lines() { + String variant = BASE_EMAIL.replace("Hello world\r\n", "Hello world\r\n\r\n\r\n"); + assertThat(extractAmsTag(signRawEmail(BASE_EMAIL), "bh")) + .isEqualTo(extractAmsTag(signRawEmail(variant), "bh")); + } + + // message_body_trail_crlf: a body that does not end with CRLF must have one appended before + // hashing, so it produces the same bh= as the same body that does end with CRLF. + @Test + public void body_hash_is_invariant_when_body_lacks_trailing_crlf() { + String variant = BASE_EMAIL.replace("Hello world\r\n", "Hello world"); + assertThat(extractAmsTag(signRawEmail(BASE_EMAIL), "bh")) + .isEqualTo(extractAmsTag(signRawEmail(variant), "bh")); + } + + // headers_field_name_case: header names must be lowercased before signing, so Subject and SUBJECT + // produce the same AMS (same bh= and same b=). + @Test + public void ams_is_invariant_under_header_name_case() { + String variant = BASE_EMAIL.replace("Subject: test\r\n", "SUBJECT: test\r\n"); + assertThat(signRawEmail(BASE_EMAIL)).isEqualTo(signRawEmail(variant)); + } + + // headers_field_unfold: folded headers (split with CRLF + whitespace continuation) must be + // joined back into one line before signing, so the folded and unfolded forms produce the same AMS. + @Test + public void ams_is_invariant_under_header_folding() { + String cleanEmail = + "From: jqd@d1.example\r\nTo: arc@example.com\r\nSubject: Hello world\r\n\r\nHello world\r\n"; + String foldedEmail = + "From: jqd@d1.example\r\nTo: arc@example.com\r\nSubject: Hello\r\n world\r\n\r\nHello world\r\n"; + assertThat(signRawEmail(cleanEmail)).isEqualTo(signRawEmail(foldedEmail)); + } + + // headers_eol_wsp: trailing whitespace at the end of a header value must be stripped before + // signing, so trailing spaces produce the same AMS as no trailing spaces. + @Test + public void ams_is_invariant_under_header_trailing_whitespace() { + String variant = BASE_EMAIL.replace("Subject: test\r\n", "Subject: test \r\n"); + assertThat(signRawEmail(BASE_EMAIL)).isEqualTo(signRawEmail(variant)); + } + + // headers_inl_wsp: runs of whitespace inside a header value must be collapsed to one space before + // signing, so double spaces inside a value produce the same AMS as a single space. + @Test + public void ams_is_invariant_under_header_inline_whitespace() { + String cleanEmail = + "From: jqd@d1.example\r\nTo: arc@example.com\r\nSubject: Hello world\r\n\r\nHello world\r\n"; + String variantEmail = + "From: jqd@d1.example\r\nTo: arc@example.com\r\nSubject: Hello world\r\n\r\nHello world\r\n"; + assertThat(signRawEmail(cleanEmail)).isEqualTo(signRawEmail(variantEmail)); + } + + // headers_col_wsp: whitespace around the colon separator in a header must be normalised before + // signing, so "Subject: test" and "Subject:test" (no space) produce the same AMS. + @Test + public void ams_is_invariant_under_header_colon_whitespace() { + String variant = BASE_EMAIL.replace("Subject: test\r\n", "Subject:test\r\n"); + assertThat(signRawEmail(BASE_EMAIL)).isEqualTo(signRawEmail(variant)); + } + + // i1_base: when a message already carries a valid i=1 ARC set, buildArcSet must produce an i=2 set + // whose seal carries cv=pass — the new server correctly extends the chain. + @Test + public void build_arc_set_generates_i2_cv_pass_when_signing_on_top_of_valid_i1_chain() throws Exception { + Message message = buildNHopChain(1); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + assertThat(arcSet.get(ARC_SEAL)).contains("cv=pass"); + assertThat(arcSet.get(ARC_SEAL)).contains("i=2"); + assertThat(arcSet.get(ARC_MESSAGE_SIGNATURE)).contains("i=2"); + assertThat(arcSet.get(ARC_AUTHENTICATION_RESULTS)).contains("i=2"); + } + + // i2_base: when a message already carries valid i=1 and i=2 ARC sets, buildArcSet must produce an i=3 + // set whose seal carries cv=pass — the new server correctly extends the chain. + @Test + public void build_arc_set_generates_i3_cv_pass_when_signing_on_top_of_valid_i2_chain() throws Exception { + Message message = buildNHopChain(2); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + assertThat(arcSet.get(ARC_SEAL)).contains("cv=pass"); + assertThat(arcSet.get(ARC_SEAL)).contains("i=3"); + assertThat(arcSet.get(ARC_MESSAGE_SIGNATURE)).contains("i=3"); + assertThat(arcSet.get(ARC_AUTHENTICATION_RESULTS)).contains("i=3"); + } + + // i1_base_fail: when the incoming i=1 chain is already broken (corrupt AMS), buildArcSet must still + // produce an i=2 set, but the new seal must carry cv=fail to faithfully record the broken chain. + @Test + public void build_arc_set_generates_cv_fail_seal_when_signing_on_top_of_broken_i1_chain() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + String fakeB64 = Base64.getEncoder().encodeToString(new byte[128]); + for (Map.Entry entry : arcSet.entrySet()) { + String value = entry.getKey().equals(ARC_MESSAGE_SIGNATURE) + ? entry.getValue().replaceAll("; b=.*$", "; b=" + fakeB64) + : entry.getValue(); + message.getHeader().addField(new RawField(entry.getKey(), value)); + } + + Map newArcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + assertThat(newArcSet.get(ARC_SEAL)).contains("cv=fail"); + assertThat(newArcSet.get(ARC_SEAL)).contains("i=2"); + } + + // i2_base_fail: when the incoming two-hop chain is already broken, buildArcSet must produce an i=3 + // set whose seal carries cv=fail — the broken state is faithfully recorded. + @Test + public void build_arc_set_generates_cv_fail_seal_when_signing_on_top_of_broken_i2_chain() throws Exception { + Message message = buildNHopChain(2); + corruptSignatureOnHeader(message, ARC_MESSAGE_SIGNATURE, "i=1"); + + Map newArcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + assertThat(newArcSet.get(ARC_SEAL)).contains("cv=fail"); + assertThat(newArcSet.get(ARC_SEAL)).contains("i=3"); + } + + // no_additional_sig: after signing on top of a broken chain and adding the new i=2 set to the message, + // the full chain validation must still return cv=fail — a valid new signature must not heal a broken chain. + @Test + public void validate_arc_chain_remains_fail_after_signing_on_top_of_broken_chain() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + String fakeB64 = Base64.getEncoder().encodeToString(new byte[128]); + for (Map.Entry entry : arcSet.entrySet()) { + String value = entry.getKey().equals(ARC_MESSAGE_SIGNATURE) + ? entry.getValue().replaceAll("; b=.*$", "; b=" + fakeB64) + : entry.getValue(); + message.getHeader().addField(new RawField(entry.getKey(), value)); + } + + Map newArcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + for (Map.Entry entry : newArcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // ams_format_tags_unknown: an unrecognised tag in the ARC-Message-Signature must be silently ignored, // so a chain signed with an extra z= tag must still validate as cv=pass. @Test From e3d8df4dc333240e47a1749d29972dcaf27ae03f Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 18:30:43 -0400 Subject: [PATCH 27/40] Add ARC AMS formatting and duplicate instance tests: - Add ValiMail-derived AMS tag format validation coverage for whitespace around separators and trailing semicolons. Add a duplicate - ARC-Message-Signature i=1 ordering variant to ensure duplicate AMS instances are rejected regardless of header order. --- .../java/org/apache/james/arc/ARCTest.java | 127 +++++++++++++++++- 1 file changed, 126 insertions(+), 1 deletion(-) diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 85c589a..211b000 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -71,6 +71,16 @@ public class ARCTest { "softfail (spfCheck: transitioning domain of d1.example does not designate 222.222.222.222 as permitted sender) client-ip=222.222.222.222; envelope-from=jqd@d1.example; helo=d1.example") ); + private static final String VALIMAIL_DUMMY_PUBLIC_KEY = + "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id" + + "Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx" + + "j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"; + + private final MockPublicKeyRecordRetrieverArc valimailKeyRecordRetriever = new MockPublicKeyRecordRetrieverArc( + dmarcRetriever, + MockPublicKeyRecordRetriever.Record.of("dummy", "example.org", VALIMAIL_DUMMY_PUBLIC_KEY) + ); + /** * - "a" field will be added by the signer based on signer setup * - "bh=" and "b=" placeholder are required for now because the same implementation is used for @@ -554,6 +564,24 @@ public void validate_arc_chain_fails_when_ams_is_duplicated_at_same_instance() t assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // ams_fields_i_dup1: duplicate ARC-Message-Signature instance numbers must be rejected even + // when the duplicate appears before the rest of the ARC set in header order. + @Test + public void validate_arc_chain_fails_when_duplicate_ams_instance_appears_before_arc_set() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, arcSet.get(ARC_MESSAGE_SIGNATURE))); + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // ams_struct_missing: an ARC-Seal at i=1 with no corresponding ARC-Message-Signature means the // set is incomplete and must be rejected — covered by validate_arc_chain_fails_when_ams_header_is_missing. @@ -880,6 +908,70 @@ public void validate_arc_chain_fails_when_ams_tag_value_contains_semicolon() thr assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // ams_format_sc_wsp: whitespace before the semicolon separator in an AMS tag list is valid. + // This mirrors the ValiMail arc_test_suite fixture and must validate as cv=pass. + @Test + public void validate_arc_chain_passes_when_ams_has_whitespace_around_semicolon_separator() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=OeNJ7p2NdW3mKv4hyenx+QbRuqqq8iwGAyY1WVX/EJiPHS2vNB5lEI/YmVB3diTkKPHWe8\n" + + " ZOq18DTVtOVuahLqM7s/4K/gvx3zal0vcedPL/mtRW4A1Ct0/wyLuFADX2HZ815cELx81SuX\n" + + " 3fEbbym1br+0JArsz6n8798lidnWY=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=NOLE9bNh30qiTx35h5yKbHlDPahxvhXUWjv8Yiy5L7Ks3NNznK54dmUPZ4D/80tkRYiil0\n" + + " 8sCqFTh7OH5ZTXXEfArxBMQQl3DAqTjOJQ1c3jPYwaDliWqCLLueSsH+ovaFGRGNPm2O41o0\n" + + " J8xUmyji1bXXLKMinB+Adv9ALXsw8=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ= ; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + valimailCommonMessageTail()); + } + + // ams_format_eq_wsp: whitespace around "=" in an AMS tag is valid and should not break parsing. + @Test + public void validate_arc_chain_passes_when_ams_has_whitespace_around_equals_separator() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=CcoQW04QZ7n7OTPACcP26R0vJtjEwVmcFpj4+PJnvT1kVeOMfcqwt7FEGlCjeJ0QIYMeNW\n" + + " TY6kND0fe0WJDVnWvhCyeOb5JjwllbJJ/ThP74I5UPgQ0Cwp1h/O9HIrUJkrje6HQ3nD6Dok\n" + + " la2keL/t4R7YtMyAmn9sPWuAOwSrE=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=KLZ8Io9rZzsWt0Q/Mrx8sYO7HPLptFwGoCdabHuyrQsek+1c5yo5tOQidcTc8ksw5PoAZH\n" + + " PNOIoyGVte9jMk0LdA1IYjjvvUmEANMZCJf0wm66exDWJ30xMrgbosLN2XvsRk3BDkoCg2AY\n" + + " HkR11isMdIhrefd7AHw9YEDTnohQw=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c = relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + valimailCommonMessageTail()); + } + + // ams_format_tags_trail_sc: a trailing semicolon at the end of the AMS tag list is valid. + @Test + public void validate_arc_chain_passes_when_ams_tag_list_has_trailing_semicolon() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=Q3iCsG7zmlydzz8zFIm4X+Nyr2636znsyGh+lRhCFtcWbw3m3v8fFrtK3uNvqSM+WW3Cmf\n" + + " TbteHFaG9YL34KUMi/ThuPoG8sOwJ18BPjXrdBS5EiXYBBFalkVRV0ktqyiNi57LBVS+VGWV\n" + + " FwOD85C/V/Fju2wETdy0ly1VjfLBg=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=H+XsRP2HBJwygQonE/YquKr2y1KqjjlhBQ/hEkIGFjjNhOIvMfuuO054H4+kxMmvHFdwk8\n" + + " a8Uwy1MxQBC3a4b0jAQ77rOn5VFhO1tAmCkfZP1bJSxewRfC2Eo7j/07+r8ZLuyuAzlQIW+n\n" + + " DPJtOhnIIEOGhLgPNlcTwc9R/XKiE=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345;\n" + + valimailCommonMessageTail()); + } + // Builds a valid two-hop ARC chain: applies i=1 to the base message, then applies i=2 on top. private Message buildTwoHopChain() throws Exception { return buildNHopChain(2); @@ -941,6 +1033,39 @@ private void replaceTagOnHeader(Message message, String headerName, String insta } } + private void assertValimailFixturePasses(String rawMessage) throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream(rawMessage.replace("\n", "\r\n").getBytes(StandardCharsets.UTF_8))); + ARCChainValidator arcChainValidator = new ARCChainValidator(valimailKeyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + + private String valimailCommonMessageTail() { + return "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J."; + } + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { URL resource = this.getClass().getResource(fileName); FileInputStream file = new FileInputStream(new File(resource.toURI())); @@ -951,4 +1076,4 @@ private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) thr return new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)); } -} \ No newline at end of file +} From c9fd4d16fe52d7a1a0ac039071a46f34787fe450 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Fri, 17 Apr 2026 21:37:39 -0400 Subject: [PATCH 28/40] Expand ARC validation coverage and fix header parsing: - Add ValiMail-derived ARC tests for Authentication-Results merging, ARC-Authentication-Results structure validation, and ARC-Seal structure and tag-format handling. - Consolidate existing Authentication-Results headers for the configured authserv-id when building ARC-Authentication-Results. - Update ARC verification to select signed headers bottom-up, matching signing behavior; tolerate whitespace around tag-list equals separators. --- .../org/apache/james/arc/ARCVerifier.java | 41 +- .../apache/james/arc/AuthResultsBuilder.java | 47 ++ .../java/org/apache/james/arc/ARCTest.java | 429 ++++++++++++++++++ 3 files changed, 511 insertions(+), 6 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index ef3311e..c31cf15 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -98,10 +98,22 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec String amsForSigning = amsValue.replaceFirst(B_TAG_REGEX, "b="); // Canonicalize headers listed in h= StringBuilder signingData = new StringBuilder(); + Map processedHeaders = new HashMap<>(); for (String hName : signedHeaders.split(":")) { hName = hName.trim(); - for (Field f : message.getHeader().getFields(hName)) { + List fields = message.getHeader().getFields(hName); + if (fields != null && !fields.isEmpty()) { + Integer done = processedHeaders.get(hName); + if (done == null) { + done = 0; + } + int doneHeaders = done + 1; + if (doneHeaders > fields.size()) { + continue; + } + Field f = fields.get(fields.size() - doneHeaders); signingData.append(canonicalizeRegularHeader(f)); + processedHeaders.put(hName, doneHeaders); } } @@ -146,9 +158,21 @@ private Signature getSignature(PublicKey publicKey, StringBuilder signingData) public Map parseTagList(String value) { Map map = new HashMap<>(); - Matcher m = TAG_PATTERN.matcher(value); - while (m.find()) { - map.put(m.group(1).trim(), m.group(2).trim()); + String[] parts = value.split(";"); + for (String part : parts) { + String trimmed = part.trim(); + if (trimmed.isEmpty()) { + continue; + } + int equal = trimmed.indexOf('='); + if (equal == -1) { + continue; + } + String tag = trimmed.substring(0, equal).trim(); + String tagValue = trimmed.substring(equal + 1).trim(); + if (tag.matches("[a-z]+")) { + map.put(tag, tagValue); + } } return map; } @@ -283,8 +307,13 @@ public String parseTagGeneric(String record, String tag) { String[] parts = record.split(";"); for (String part : parts) { String trimmed = part.trim(); - if (trimmed.startsWith(tag + "=")) { - return trimmed.substring((tag + "=").length()); + int equal = trimmed.indexOf('='); + if (equal == -1) { + continue; + } + String tagName = trimmed.substring(0, equal).trim(); + if (tagName.equals(tag)) { + return trimmed.substring(equal + 1).trim(); } } return null; diff --git a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java index 231b5e6..26b561e 100644 --- a/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java +++ b/arc/src/main/java/org/apache/james/arc/AuthResultsBuilder.java @@ -29,11 +29,13 @@ import org.apache.james.jdkim.tagvalue.SignatureRecordImpl; import org.apache.james.mime4j.dom.Message; import org.apache.james.mime4j.message.DefaultMessageWriter; +import org.apache.james.mime4j.stream.Field; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.Objects; @@ -57,6 +59,7 @@ */ public class AuthResultsBuilder { public static final String HEADER_I = "header.i="; + public static final String AUTHENTICATION_RESULTS = "Authentication-Results"; private final PublicKeyRetrieverArc _keyRecordRetriever; private String _authService; @@ -66,6 +69,10 @@ public AuthResultsBuilder(String authService, PublicKeyRetrieverArc keyRecordRet } public String getAuthResultsHeader(Message message, String helo, String from, String ip) { + String consolidatedAuthResults = consolidateExistingAuthResults(message); + if (consolidatedAuthResults != null) { + return consolidatedAuthResults; + } // 1. Run SPF check String spfResultText = _keyRecordRetriever.getSpfRecord(helo, from, ip); @@ -91,6 +98,46 @@ public String getAuthResultsHeader(Message message, String helo, String from, St dmarcResult.toString(); } + private String consolidateExistingAuthResults(Message message) { + List results = new ArrayList<>(); + for (Field field : message.getHeader().getFields(AUTHENTICATION_RESULTS)) { + String body = normalizeAuthResultsBody(field.getBody()); + int separator = body.indexOf(';'); + if (separator == -1) { + continue; + } + String authservId = body.substring(0, separator).trim(); + if (!_authService.equalsIgnoreCase(authservId)) { + continue; + } + String result = body.substring(separator + 1).trim(); + if (!result.isEmpty()) { + results.add(result); + } + } + + if (results.isEmpty()) { + return null; + } + + StringBuilder consolidated = new StringBuilder(_authService); + for (int i = 0; i < results.size(); i++) { + String result = results.get(i); + consolidated.append(i == 0 ? "; " : " "); + consolidated.append(result); + if (!result.endsWith(";") && i < results.size() - 1) { + consolidated.append(";"); + } + } + return consolidated.toString(); + } + + private String normalizeAuthResultsBody(String body) { + return body.replaceAll("[\\r\\n]+[\\t ]*", " ") + .replaceAll("[\\t ]+", " ") + .trim(); + } + private String runDkimCheck(Message message) throws IOException { final DKIMVerifier verifier = new DKIMVerifier(_keyRecordRetriever); InputStream is = messageToInputStream(message); diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 211b000..c0e655f 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -582,6 +582,107 @@ public void validate_arc_chain_fails_when_duplicate_ams_instance_appears_before_ assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // aar_struct_i_na / aar_i_missing: an ARC-Authentication-Results header without i= is invalid. + @Test + public void validate_arc_chain_fails_when_aar_has_no_instance_tag() throws Exception { + Message message = buildOneHopChainWithAar("smtp.d1.example; arc=none", true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar_struct_i_empty: an ARC-Authentication-Results header with empty i= is invalid. + @Test + public void validate_arc_chain_fails_when_aar_has_empty_instance_tag() throws Exception { + Message message = buildOneHopChainWithAar("i=; smtp.d1.example; arc=none", true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar_struct_i_zero: ARC instance numbers start at 1, so AAR i=0 is invalid. + @Test + public void validate_arc_chain_fails_when_aar_has_zero_instance_tag() throws Exception { + Message message = buildOneHopChainWithAar("i=0; smtp.d1.example; arc=none", true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar_struct_invalid: AAR instance numbers must be numeric. + @Test + public void validate_arc_chain_fails_when_aar_has_non_numeric_instance_tag() throws Exception { + Message message = buildOneHopChainWithAar("i=abc; smtp.d1.example; arc=none", true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar_struct_dup: duplicate ARC-Authentication-Results headers for the same instance are invalid. + @Test + public void validate_arc_chain_fails_when_aar_is_duplicated_at_same_instance() throws Exception { + Message message = buildOneHopChainWithAar(null, true, true); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar_struct_missing / aar_missing: an ARC set with AMS and AS but no AAR is incomplete. + @Test + public void validate_arc_chain_fails_when_aar_header_is_missing() throws Exception { + Message message = buildOneHopChainWithAar(null, false, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar_i_wrong: an AAR whose i= does not match the rest of its ARC set is invalid. + @Test + public void validate_arc_chain_fails_when_aar_instance_does_not_match_arc_set() throws Exception { + Message message = buildOneHopChainWithAar("i=2; smtp.d1.example; arc=none", true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar_i_not_prefixed: the AAR i= tag must be the leading ARC instance component. + @Test + public void validate_arc_chain_fails_when_aar_instance_tag_is_not_prefixed() throws Exception { + Message message = buildOneHopChainWithAar("smtp.d1.example; i=1; arc=none", true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar_i_no_semi: the AAR i= value must be followed by a semicolon separator. + @Test + public void validate_arc_chain_fails_when_aar_instance_tag_has_no_semicolon() throws Exception { + Message message = buildOneHopChainWithAar("i=1 smtp.d1.example; arc=none", true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // aar2_missing: in a two-hop chain, the latest ARC set is incomplete if its i=2 AAR is missing. + @Test + public void validate_arc_chain_fails_when_i2_aar_header_is_missing() throws Exception { + Message message = buildNHopChain(2); + removeHeaderByInstanceAndType(message, ARC_AUTHENTICATION_RESULTS, "i=2"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // ams_struct_missing: an ARC-Seal at i=1 with no corresponding ARC-Message-Signature means the // set is incomplete and must be rejected — covered by validate_arc_chain_fails_when_ams_header_is_missing. @@ -781,6 +882,43 @@ public void validate_arc_chain_remains_fail_after_signing_on_top_of_broken_chain assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // ar_merged1: multiple Authentication-Results headers for the signing authserv-id must be + // consolidated into one ARC-Authentication-Results header, while other authserv-ids are ignored. + @Test + public void build_arc_set_merges_multiple_authentication_results_for_authserv_id() throws Exception { + Message message = parseRawEmail( + "Authentication-Results: lists.example.org; arc=none\n" + + "Authentication-Results: lists.example.org; spf=pass smtp.mfrom=jqd@d1.example\n" + + "Authentication-Results: lists.example.org; dkim=pass (1024-bit key) header.i=@d1.example\n" + + "Authentication-Results: lists.example.org; dmarc=pass\n" + + "Authentication-Results: nobody.example.org; something=ignored\n" + + basicMessageWithoutAuthenticationResults()); + + Map arcSet = buildArcSetWithAuthService(message, "lists.example.org"); + + assertThat(arcSet.get(ARC_AUTHENTICATION_RESULTS)).isEqualTo( + "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; " + + "dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"); + } + + // ar_merged2: folded Authentication-Results payloads must be unfolded and merged in order. + @Test + public void build_arc_set_merges_folded_authentication_results_for_authserv_id() throws Exception { + Message message = parseRawEmail( + "Authentication-Results: lists.example.org; arc=none;\n" + + " spf=pass smtp.mfrom=jqd@d1.example\n" + + "Authentication-Results: lists.example.org; dkim=pass (1024-bit key) header.i=@d1.example\n" + + "Authentication-Results: lists.example.org; dmarc=pass\n" + + "Authentication-Results: nobody.example.org; something=ignored\n" + + basicMessageWithoutAuthenticationResults()); + + Map arcSet = buildArcSetWithAuthService(message, "lists.example.org"); + + assertThat(arcSet.get(ARC_AUTHENTICATION_RESULTS)).isEqualTo( + "i=1; lists.example.org; arc=none; spf=pass smtp.mfrom=jqd@d1.example; " + + "dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass"); + } + // ams_format_tags_unknown: an unrecognised tag in the ARC-Message-Signature must be silently ignored, // so a chain signed with an extra z= tag must still validate as cv=pass. @Test @@ -972,11 +1110,226 @@ public void validate_arc_chain_passes_when_ams_tag_list_has_trailing_semicolon() + valimailCommonMessageTail()); } + // as_struct_i_na / as_fields_i_missing: an ARC-Seal without i= is invalid. + @Test + public void validate_arc_chain_fails_when_arc_seal_has_no_instance_tag() throws Exception { + Message message = buildOneHopChainWithSeal( + seal -> seal.replaceFirst("i=1;\\s*", ""), + true, + false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_struct_i_empty: an ARC-Seal with empty i= is invalid. + @Test + public void validate_arc_chain_fails_when_arc_seal_has_empty_instance_tag() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceFirst("i=1;", "i=;"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_struct_i_zero: ARC instance numbers start at 1, so AS i=0 is invalid. + @Test + public void validate_arc_chain_fails_when_arc_seal_has_zero_instance_tag() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceFirst("i=1;", "i=0;"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_struct_i_invalid: ARC-Seal instance numbers must be numeric. + @Test + public void validate_arc_chain_fails_when_arc_seal_has_non_numeric_instance_tag() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceFirst("i=1;", "i=abc;"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_struct_dup: duplicate ARC-Seal headers for the same instance are invalid. + @Test + public void validate_arc_chain_fails_when_arc_seal_is_duplicated_at_same_instance() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal, true, true); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_struct_missing: an ARC set with AAR and AMS but no AS is incomplete. + @Test + public void validate_arc_chain_fails_when_arc_seal_header_is_missing_from_arc_set() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal, false, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_format_sc_wsp: whitespace before an AS semicolon separator is valid. + @Test + public void validate_arc_chain_passes_when_arc_seal_has_whitespace_around_semicolon_separator() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=sQHCWC9A8lAbvcPG+3jfih4lRJY/A0OI/GBGE4AYHf8u9cgsxOvyCqDWF3mr91HE5PhNh4\n" + + " RZW95NC6qhxEhnXLaXswqco2JXMVR6/rM5Q49bDE2RtlNen7wubw56NoJD2A7IGUSOzHaAiJ\n" + + " QhRTSoyG5OwNBC8+GlugUJi5mmZNU=; cv=none; d=example.org; i=1 ; s=dummy;\n" + + " t=12345\n" + + valimailArcSealFormatCommonTail()); + } + + // as_format_eq_wsp: whitespace around "=" in the AS i= tag is valid. + @Test + public void validate_arc_chain_passes_when_arc_seal_has_whitespace_around_equals_separator() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=u4XUza5aJKdMCwCMffAieua1x4N9tZpKlx7UwMcdgV+BuIZc48C3rF8xu6BnoRQCaulZmW\n" + + " 4EYspmshC6cGg+kmYaWR/sbW712Ag8W33enEcoh35XLTg9QHg7zWvftk746RrVFb5Ch8iRsU\n" + + " PJ0gkAieomzXwlqCIBZQD5Yz2LB38=; cv=none; d=example.org; i = 1; s=dummy;\n" + + " t=12345\n" + + valimailArcSealFormatCommonTail()); + } + + // as_format_tags_trail_sc: a trailing semicolon at the end of the AS tag list is valid. + @Test + public void validate_arc_chain_passes_when_arc_seal_tag_list_has_trailing_semicolon() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=AcBD4PAxYztV5R8jYyYXKuMBWBRja89F6yBTQVtQ1FFUxQVYGOrFlnh3/r8/YtFt13NELg\n" + + " FpYeY3gnzudk30PoZZvM2MG9h07ByTgl0lSEsRLhN+ZtqoHRq1QGdW8oqOXntI51FbKwBdoe\n" + + " cHtLh18GzKAvazRWzv8//vQInYp/Y=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345;\n" + + valimailArcSealFormatCommonTail()); + } + + // as_format_tags_unknown: an unknown AS tag is valid when it was present at signing time. + @Test + public void validate_arc_chain_passes_when_arc_seal_has_unknown_tag() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=FriX6cOxgBHhZwNYHn0KXSWVqwHPNV6sRAKUy9iN1OqwvAK9USwMsg/P08yXrUH8LRaijm\n" + + " msJjp0KUFYiffoQrhsxHwv1hJIGceJZB7lOFeZn7Z5aym4eBp7q7idwNyIaGKL7E0WzVkeAT\n" + + " RQ5LhtOInN23gugfmW6z8MUUvow5Y=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345; w=catparty\n" + + valimailArcSealFormatCommonTail()); + } + + // as_format_inv_tag_key: invalid AS tag keys are rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_has_invalid_tag_key_character() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "_=; t=1755918846"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_format_tags_dup: duplicate AS tags are rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_has_duplicate_tag() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal + "; s=invalid", true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_format_tags_key_case: AS tag keys are case-sensitive. + @Test + public void validate_arc_chain_fails_when_arc_seal_uses_uppercase_tag_key() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("s=arc", "S=arc"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_format_tags_val_case: AS domain value changes are signature-sensitive and must fail. + @Test + public void validate_arc_chain_fails_when_arc_seal_tag_value_has_wrong_case() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("d=dmarc.example", "d=Dmarc.example"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_format_tags_wsp: invalid whitespace inside an AS tag value must fail. + @Test + public void validate_arc_chain_fails_when_arc_seal_tag_value_contains_whitespace() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "t=1755 918846"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_format_tags_sc: an extra semicolon inside the AS tag list must fail. + @Test + public void validate_arc_chain_fails_when_arc_seal_tag_value_contains_semicolon() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("s=arc", "s=arc;"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // Builds a valid two-hop ARC chain: applies i=1 to the base message, then applies i=2 on top. private Message buildTwoHopChain() throws Exception { return buildNHopChain(2); } + private Message buildOneHopChainWithSeal(java.util.function.Function sealMutation, + boolean includeSeal, + boolean duplicateSeal) throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, arcSet.get(ARC_MESSAGE_SIGNATURE))); + if (includeSeal) { + String seal = sealMutation.apply(arcSet.get(ARC_SEAL)); + message.getHeader().addField(new RawField(ARC_SEAL, seal)); + if (duplicateSeal) { + message.getHeader().addField(new RawField(ARC_SEAL, seal)); + } + } + return message; + } + + private Message buildOneHopChainWithAar(String aarOverride, boolean includeAar, boolean duplicateAar) throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + if (includeAar) { + String aar = aarOverride == null ? arcSet.get(ARC_AUTHENTICATION_RESULTS) : aarOverride; + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, aar)); + if (duplicateAar) { + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, aar)); + } + } + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, arcSet.get(ARC_MESSAGE_SIGNATURE))); + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + return message; + } + // Builds a valid N-hop ARC chain by repeatedly applying a new ARC set to the same message. private Message buildNHopChain(int n) throws Exception { ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); @@ -1041,6 +1394,36 @@ private void assertValimailFixturePasses(String rawMessage) throws Exception { assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); } + private Map buildArcSetWithAuthService(Message message, String authService) throws Exception { + ArcSetBuilder builder = new ArcSetBuilder( + ArcTestKeys.privateKeyArc, + ARC_AMS_TEMPLATE, + ARC_SEAL_TEMPLATE, + authService, + TIMESTAMP); + return builder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + } + + private Message parseRawEmail(String rawMessage) throws Exception { + return new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream(rawMessage.replace("\n", "\r\n").getBytes(StandardCharsets.UTF_8))); + } + + private String basicMessageWithoutAuthenticationResults() { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J."; + } + private String valimailCommonMessageTail() { return "ARC-Authentication-Results: i=1; lists.example.org;\n" + " spf=pass smtp.mfrom=jqd@d1.example;\n" @@ -1066,6 +1449,52 @@ private String valimailCommonMessageTail() { + "--J."; } + private String valimailArcSealFormatCommonTail() { + return "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou\n" + + " ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z\n" + + " sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=;\n" + + " bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "Received: by 10.157.52.162 with SMTP id g31csp5274520otc;\n" + + " Tue, 3 Jan 2017 12:32:02 -0800 (PST)\n" + + "X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271;\n" + + " Tue, 03 Jan 2017 12:32:02 -0800 (PST)\n" + + "Message-ID: \n" + + "Date: Thu, 5 Jan 2017 14:39:01 -0800\n" + + "From: Gene Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 2\n" + + "Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f\n" + + "Content-Type: text/plain; charset=UTF-8\n" + + "\n" + + "This is a test message\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f\n" + + "Content-Type: text/html; charset=UTF-8\n" + + "\n" + + "
This is a test message
\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f--"; + } + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { URL resource = this.getClass().getResource(fileName); FileInputStream file = new FileInputStream(new File(resource.toURI())); From 813fe129ac7fcc77c81d57a56428fb6fc2a8d4fe Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sat, 18 Apr 2026 17:00:33 -0400 Subject: [PATCH 29/40] Add ARC-Seal field validation tests: - Add ValiMail-derived ARC-Seal field coverage for duplicate instance headers and malformed a=, cv=, d=, s=, and t= tags. Cover the valid case where ARC-Seal omits the optional t= timestamp by building a one-hop chain with a custom seal template. - Make ARC-Seal cv= validation null-safe so missing cv= is handled as cv=fail instead of risking a null dereference. --- .../org/apache/james/arc/ARCVerifier.java | 3 + .../java/org/apache/james/arc/ARCTest.java | 191 ++++++++++++++++++ 2 files changed, 194 insertions(+) diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index c31cf15..9414378 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -242,6 +242,9 @@ private boolean checkCv(List lastArcSet, int instToVerify) { if (arcSealHeader.isPresent()) { Map tags = parseTagList(arcSealHeader.get().getBody()); String lastCv = tags.get("cv"); + if (lastCv == null) { + return false; + } return (instToVerify == 1 && lastCv.equalsIgnoreCase("none")) || (instToVerify > 1 && lastCv.equalsIgnoreCase("pass")); } diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index c0e655f..ea1ef44 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -1289,11 +1289,202 @@ public void validate_arc_chain_fails_when_arc_seal_tag_value_contains_semicolon( assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // as_fields_i_dup: duplicate ARC-Seal headers at i=1 must be rejected. + @Test + public void validate_arc_chain_fails_when_i1_arc_seal_field_is_duplicated() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal, true, true); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_i_dup2: duplicate ARC-Seal headers at i=2 must be rejected. + @Test + public void validate_arc_chain_fails_when_i2_arc_seal_field_is_duplicated() throws Exception { + Message message = buildNHopChain(2); + Field seal = message.getHeader().getFields().stream() + .filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL) && f.getBody().contains("i=2")) + .findFirst().orElseThrow(() -> new AssertionError("i=2 ARC-Seal not found")); + message.getHeader().addField(new RawField(ARC_SEAL, seal.getBody())); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_a_na: missing ARC-Seal a= changes the sealed data and must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_algorithm_tag_is_missing() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceFirst("a=rsa-sha256;\\s*", ""), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_a_empty: empty ARC-Seal a= changes the sealed data and must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_algorithm_tag_is_empty() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("a=rsa-sha256", "a="), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_a_sha1: changing ARC-Seal a= to rsa-sha1 invalidates the seal. + @Test + public void validate_arc_chain_fails_when_arc_seal_algorithm_is_sha1() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("a=rsa-sha256", "a=rsa-sha1"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_a_unknown: unknown ARC-Seal algorithms must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_algorithm_is_unknown() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("a=rsa-sha256", "a=ed25519-sha256"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_cv_na: missing ARC-Seal cv= must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_cv_tag_is_missing() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceFirst("cv=none;\\s*", ""), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_cv_empty: empty ARC-Seal cv= must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_cv_tag_is_empty() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("cv=none", "cv="), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_cv_invalid: invalid ARC-Seal cv= values must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_cv_tag_is_invalid() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("cv=none", "cv=maybe"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_d_na: missing ARC-Seal d= prevents key lookup and must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_domain_tag_is_missing() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceFirst("d=dmarc.example;\\s*", ""), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_d_empty: empty ARC-Seal d= prevents key lookup and must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_domain_tag_is_empty() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("d=dmarc.example", "d="), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_d_invalid: invalid ARC-Seal d= values must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_domain_tag_is_invalid() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("d=dmarc.example", "d=invalid_domain"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_s_na: missing ARC-Seal s= prevents key lookup and must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_selector_tag_is_missing() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceFirst("s=arc;\\s*", ""), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_s_empty: empty ARC-Seal s= prevents key lookup and must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_selector_tag_is_empty() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("s=arc", "s="), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_t_na: ARC-Seal t= is optional and a seal generated without it must validate. + @Test + public void validate_arc_chain_passes_when_arc_seal_timestamp_tag_is_missing() throws Exception { + String sealTemplateWithoutTimestamp = "i=; cv=; a=rsa-sha256; d=dmarc.example; s=arc; b="; + Message message = buildOneHopChainWithSealTemplate(sealTemplateWithoutTimestamp); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + + // as_fields_t_empty: empty ARC-Seal t= must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_timestamp_tag_is_empty() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "t="), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_t_invalid: invalid ARC-Seal t= values must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_timestamp_tag_is_invalid() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "t=abc"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // Builds a valid two-hop ARC chain: applies i=1 to the base message, then applies i=2 on top. private Message buildTwoHopChain() throws Exception { return buildNHopChain(2); } + private Message buildOneHopChainWithSealTemplate(String sealTemplate) throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + ArcSetBuilder builder = new ArcSetBuilder( + ArcTestKeys.privateKeyArc, + ARC_AMS_TEMPLATE, + sealTemplate, + AUTH_SERVICE, + TIMESTAMP); + Map arcSet = builder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + for (Map.Entry entry : arcSet.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + return message; + } + private Message buildOneHopChainWithSeal(java.util.function.Function sealMutation, boolean includeSeal, boolean duplicateSeal) throws Exception { From a158e3c9955335b017d17c45d51ceef02f9c955a Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sat, 18 Apr 2026 17:10:14 -0400 Subject: [PATCH 30/40] Add ARC-Seal b= validation test coverage: -Add ARCTest cases for ARC-Seal signature handling, including missing, empty, non-base64, modified, and whitespace-folded b= values. Cover seal integrity failures when signed AAR, AMS, or ARC-Seal fields are changed, and reject invalid ARC-Seal h= usage. -Harden ARC-Seal verification so missing or malformed b= values fail ARC validation instead of throwing, and treat invalid signature bytes as a validation failure. --- .../apache/james/arc/ARCChainValidator.java | 7 +- .../org/apache/james/arc/ARCVerifier.java | 2 +- .../java/org/apache/james/arc/ARCTest.java | 106 ++++++++++++++++++ 3 files changed, 113 insertions(+), 2 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index 3d03939..09f1edb 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -143,6 +143,9 @@ private boolean checkArcSeal(List headers, int instToVerify, ARCVerifier Signature sig = Signature.getInstance(SHA256_RSA); sig.initVerify(publicKey); sig.update(data.getBytes(StandardCharsets.UTF_8)); + if (b64 == null || b64.isEmpty()) { + return false; + } byte[] signatureBytes = Base64.getDecoder().decode(b64); retVal = sig.verify(signatureBytes); } catch (NoSuchAlgorithmException e) { @@ -150,8 +153,10 @@ private boolean checkArcSeal(List headers, int instToVerify, ARCVerifier } catch (InvalidKeyException e) { throw new ArcException(String.format("Invalid public key used for %s record", txtDnsRecord), e); + } catch (IllegalArgumentException e) { + return false; } catch (SignatureException e) { - throw new ArcException(String.format("Invalid signature for %s record", txtDnsRecord), e); + return false; } return retVal; } diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 9414378..69e1960 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -355,7 +355,7 @@ public ArcSealVerifyData buildArcSealSigningData(Map> heade Field asField = as.get(); Map tags = parseTagList(asField.getBody()); String signatureB64 = tags.get("b"); - String b64 = signatureB64.replaceAll("\\s+", "").replace(";", ""); + String b64 = signatureB64 == null ? null : signatureB64.replaceAll("\\s+", "").replace(";", ""); String arcSealBodyClearedB = asField.getBody().replaceAll("\\bb=([^;]*)", "b="); signingData.append(asField.getName().toLowerCase(Locale.ROOT)) .append(":").append(canonicalizeBody(arcSealBodyClearedB)); diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index ea1ef44..550e0ef 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -1353,6 +1353,91 @@ public void validate_arc_chain_fails_when_arc_seal_algorithm_is_unknown() throws assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // as_fields_b_ignores_wsp: whitespace inside ARC-Seal b= must be ignored during base64 decode. + @Test + public void validate_arc_chain_passes_when_arc_seal_signature_contains_whitespace() throws Exception { + Message message = buildOneHopChainWithSeal(this::insertWhitespaceIntoSealSignature, true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + + // as_fields_b_na: missing ARC-Seal b= leaves no signature to verify and must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_signature_tag_is_missing() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceAll("; b=.*$", ""), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_b_empty: empty ARC-Seal b= leaves no signature to verify and must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_signature_tag_is_empty() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceAll("; b=.*$", "; b="), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_b_base64: ARC-Seal b= must be base64. + @Test + public void validate_arc_chain_fails_when_arc_seal_signature_is_not_base64() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replaceAll("; b=.*$", "; b=not-base64!"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_b_mod_sig: a modified ARC-Seal signature must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_signature_is_modified() throws Exception { + Message message = buildOneHopChainWithSeal( + seal -> seal.replaceAll("; b=.*$", "; b=" + Base64.getEncoder().encodeToString(new byte[128])), + true, + false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_b_aar1: modifying sealed AAR data must invalidate the ARC-Seal. + @Test + public void validate_arc_chain_fails_when_sealed_aar_data_is_modified() throws Exception { + Message message = buildNHopChain(1); + replaceTagOnHeader(message, ARC_AUTHENTICATION_RESULTS, "i=1", "dmarc=pass", "dmarc=fail"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_b_ams1: modifying sealed AMS data must invalidate the ARC-Seal. + @Test + public void validate_arc_chain_fails_when_sealed_ams_data_is_modified() throws Exception { + Message message = buildNHopChain(1); + replaceTagOnHeader(message, ARC_MESSAGE_SIGNATURE, "i=1", "h=subject : from : to", "h=from : to : subject"); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // as_fields_b_asb1: modifying sealed ARC-Seal data outside b= must invalidate the seal. + @Test + public void validate_arc_chain_fails_when_sealed_arc_seal_data_is_modified() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "t=1755918847"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // as_fields_cv_na: missing ARC-Seal cv= must be rejected. @Test public void validate_arc_chain_fails_when_arc_seal_cv_tag_is_missing() throws Exception { @@ -1413,6 +1498,16 @@ public void validate_arc_chain_fails_when_arc_seal_domain_tag_is_invalid() throw assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // as_fields_h_present: ARC-Seal must not contain h=; it signs ARC set headers, not h=-listed headers. + @Test + public void validate_arc_chain_fails_when_arc_seal_has_header_list_tag() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "h=subject; t=1755918846"), true, false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + // as_fields_s_na: missing ARC-Seal s= prevents key lookup and must be rejected. @Test public void validate_arc_chain_fails_when_arc_seal_selector_tag_is_missing() throws Exception { @@ -1504,6 +1599,17 @@ private Message buildOneHopChainWithSeal(java.util.function.Function Date: Sat, 18 Apr 2026 17:17:09 -0400 Subject: [PATCH 31/40] Add the ARC-Seal b= group test cases: - Added ValiMail public key records for 512/1024/2048-bit selector fixtures. - Hardened RSA key validation in ARCVerifier.java so RSA ARC keys below 1024 bits are rejected. - Updated ARCChainValidator.java so invalid/undersized keys fail ARC validation cleanly instead of escaping as exceptions. --- .../apache/james/arc/ARCChainValidator.java | 13 +- .../org/apache/james/arc/ARCVerifier.java | 6 + .../java/org/apache/james/arc/ARCTest.java | 201 +++++++++++++++++- 3 files changed, 217 insertions(+), 3 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index 09f1edb..5a2998a 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -114,7 +114,11 @@ private boolean checkArcAms(Set prevArcSet, Message message, ARCVerifier String txtDnsRecord = arcVerifier.getTxtDnsRecordByField(amsHeader); if (txtDnsRecord == null) return retVal; - retVal = arcVerifier.verifyAms(amsHeader, message, txtDnsRecord); + try { + retVal = arcVerifier.verifyAms(amsHeader, message, txtDnsRecord); + } catch (ArcException | IllegalArgumentException e) { + return false; + } return retVal; } @@ -131,7 +135,12 @@ private boolean checkArcSeal(List headers, int instToVerify, ARCVerifier String txtDnsRecord = arcVerifier.getTxtDnsRecordByField(arcSealHeader); if (txtDnsRecord == null) return retVal; - PublicKey publicKey = arcVerifier.parsePublicKeyFromDns(txtDnsRecord); + PublicKey publicKey; + try { + publicKey = arcVerifier.parsePublicKeyFromDns(txtDnsRecord); + } catch (ArcException | IllegalArgumentException e) { + return false; + } if (publicKey == null) { throw new ArcException(String.format("Unable to parse public key from dns record %s", txtDnsRecord)); } diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 69e1960..b5919a5 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -32,6 +32,7 @@ import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; +import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; @@ -72,6 +73,7 @@ public class ARCVerifier { public static final String ARC_MESSAGE_SIGNATURE = "ARC-Message-Signature"; public static final String ARC_SEAL = "ARC-Seal"; public static final String SHA256RSA = "SHA256withRSA"; + private static final int MIN_RSA_KEY_BITS = 1024; private static final String DNS_RECORD_TYPE = "_domainkey"; private PublicKeyRetrieverArc _keyRecordRetriever; @@ -210,6 +212,10 @@ public PublicKey parsePublicKeyFromDns(String dnsRecord) { } catch (NoSuchAlgorithmException e) { throw new ArcException("Unsupported algorithm provided when getting public key", e); } + if (pubKey instanceof RSAPublicKey + && ((RSAPublicKey) pubKey).getModulus().bitLength() < MIN_RSA_KEY_BITS) { + throw new ArcException("RSA public key must be at least " + MIN_RSA_KEY_BITS + " bits"); + } return pubKey; } diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 550e0ef..5edcaa1 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -75,12 +75,34 @@ public class ARCTest { "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id" + "Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx" + "j+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB"; + private static final String VALIMAIL_512_PUBLIC_KEY = + "v=DKIM1; k=rsa; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIWmlgix/84GJ+dfgjm7LTc9EPdfk" + + "ftlgiPpCq4/kbDAZmU0VvYKDljjleJ1dfvS+CGy9U/kk1tG3EeEvb82xAcCAwEAAQ=="; + private static final String VALIMAIL_1024_PUBLIC_KEY = + "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyBwu6PiaDN87t3DVZ84zIrE" + + "hCoxtFuv7g52oCwAUXTDnXZ+0XHM/rhkm8XSGr1yLsDc1zLGX8IfITY1dL2CzptdgyiX7vgYjzZqG368" + + "C8BtGB5m6nj26NyhSKEdlV7MS9KbASd359ggCeGTT5QjRKEMSauVyVSeapq6ZcpZ9JwQIDAQAB"; + private static final String VALIMAIL_2048_PUBLIC_KEY = + "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+7VkwpTtICeJFM4Hf" + + "UZsvv2OaA+QMrW9Af1PpTOzVP0uvUFK20lcaxMvt81ia/sGYW4gHp/WUIk0BIQMPVhUeCIuM1mcOQNFS" + + "OflR8pLo916rjEZXpRP/XGo4HwWzdqD2qQeb3+fv1IrzfHiDb9THbamoz05EX7JX+wVSAhdSW/igwhA/" + + "+beuzWR0RDDyGMT1b1Sb/lrGfwSXm7QoZQtj5PRiTX+fsL7WlzL+fBThySwS8ZBZcHcd8iWOSGKZ0gYK" + + "zxyuOf8VCX71C4xDhahN+HXWZFn9TZb+uZX9m+WXM3t+P8CdfxsaOdnVg6imgNDlUWX4ClLTZhco0Kmi" + + "BU+QIDAQAB"; private final MockPublicKeyRecordRetrieverArc valimailKeyRecordRetriever = new MockPublicKeyRecordRetrieverArc( dmarcRetriever, MockPublicKeyRecordRetriever.Record.of("dummy", "example.org", VALIMAIL_DUMMY_PUBLIC_KEY) ); + private final MockPublicKeyRecordRetrieverArc valimailKeySizeRecordRetriever = new MockPublicKeyRecordRetrieverArc( + dmarcRetriever, + MockPublicKeyRecordRetriever.Record.of("dummy", "example.org", VALIMAIL_DUMMY_PUBLIC_KEY), + MockPublicKeyRecordRetriever.Record.of("512", "example.org", VALIMAIL_512_PUBLIC_KEY), + MockPublicKeyRecordRetriever.Record.of("1024", "example.org", VALIMAIL_1024_PUBLIC_KEY), + MockPublicKeyRecordRetriever.Record.of("2048", "example.org", VALIMAIL_2048_PUBLIC_KEY) + ); + /** * - "a" field will be added by the signer based on signer setup * - "bh=" and "b=" placeholder are required for now because the same implementation is used for @@ -1363,6 +1385,122 @@ public void validate_arc_chain_passes_when_arc_seal_signature_contains_whitespac assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); } + // as_fields_b_1024: ARC-Seal signed with a 1024-bit RSA key must validate. + @Test + public void validate_arc_chain_passes_when_arc_seal_uses_1024_bit_key() throws Exception { + assertValimailFixturePasses( + valimailArcSealKeySizeMessage( + "1024", + "JZIhBQD/1SCIn7IUrIoqCDFZ4k2tDd5joLebC7dCEbEXy6HURnayDygFjEiVwoVjF8XZPo\n" + + " tDSWEVj18YLFQ08HZigNNDmhAdtIAeHs5bTfhz3ZDKGISGSrVbUqvS5QaL2dwaY5V3FhH1QC\n" + + " VEohhbx3rJKMBiFCbQoCRo555WNL0=", + "jCTMZoXkSSVEusJyP9cbvAoKEDLphi95R/yaX9+gWw2t/RduqINzxPSVJZUq8uVCbKdB5F\n" + + " BlBb2m7zbwaq6/oemTqI1tcnRaAt66Z0cyOKfPjRINTm9C8E3hUoI9DzplkwEoqmhR0wOjcJ\n" + + " H6ASJr96Kl5qLu092VFaQYYxkwh2I="), + valimailKeySizeRecordRetriever); + } + + // as_fields_b_2048: ARC-Seal signed with a 2048-bit RSA key must validate. + @Test + public void validate_arc_chain_passes_when_arc_seal_uses_2048_bit_key() throws Exception { + assertValimailFixturePasses( + valimailArcSealKeySizeMessage( + "2048", + "R6I8tV4Y0pBQWId+r4W9L3TDi82iVPot9d+ux5u69ET/VUTQUPFAiRfTBqMKAm0dY1HCdU\n" + + " JZggmlvj9BwZMOO9pFi8O1EXqkJ1CpNtFyNn76Get96owYXh7LlcP/C/a5AmxZMmvKblloh5\n" + + " 1rL2cNWicsp8/y3NS8jO0KWpSis2jK2yMn+r9gJ5gM2sUiBsKDwiYAhFBhjD8SFQOaG6DzLa\n" + + " mJzCw9FkuGdpLfQoNDq2lLQq6APq8GihFJai7o/s8M4FItAMoteuqxIfyYuH60oX4qNOsaIT\n" + + " B/6DnRCFshABODpSHRRIH4EvCu2fYYo6YDIU3VvDH2wOO5fQMcgvUoNw==", + "M0YyrXMDoG5zJ0ZjFzUqFNoDFatu/QxWTjyAH5wPvPRiSqw2Vvd4A1Al8VjYfmgbP4Jd8f\n" + + " TFDZg1kWwLYk2IO/th/P6iYPfyDg5qp6mgao/V8NBW9P/Mqlb+xhkn4R8c44vmen9atIUV3Z\n" + + " 04QzziVeuBxj+NFqxprbxf42Faxv5XymGmW3ZWVhOLEpwfcjy933drLsfZQezhyYlx4klptI\n" + + " v3hKM76++GaIUc1nWXvmkeKKjEQLiUzqxd9Om7SRNArNe/q5xnVIaufxSfZNUtTT/o7Ic1Br\n" + + " t7ZV8qwmj37sYpdZUo6H7QN+dp8E/J0jnbI0ZQU2mv8Gj3FqGOGzKwGQ=="), + valimailKeySizeRecordRetriever); + } + + // as_fields_b_512: ARC-Seal signed with a 512-bit RSA key must be rejected. + @Test + public void validate_arc_chain_fails_when_arc_seal_uses_512_bit_key() throws Exception { + assertValimailFixtureFails( + valimailArcSealKeySizeMessage( + "512", + "DCbMvnfI7UzqahO9GFjYXa7DAcon0abOMQ7mWykqtdkEe+rqeQmsy1/pV9oAeSrT9giBqP\n" + + " +cBNepG4Nycj93KQ==", + "BFnboE5xz5OBBIZeB04CaX0QVCRysZesZNKLQLDbq3ohfHL0eIkMWyt/ZkP3+bg7wVEtyb\n" + + " QfqbbfDRTQYC3GBA=="), + valimailKeySizeRecordRetriever); + } + + // as_fields_b_head_case: ARC-Seal relaxed canonicalization lowercases header names. + @Test + public void validate_arc_chain_passes_when_arc_seal_header_name_case_changes() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-SEAL: a=rsa-sha256;\n" + + " b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr\n" + + " QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh\n" + + " GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + valimailArcSealFormatCommonTail()); + } + + // as_fields_b_head_unfold: folded ARC-Seal header lines must verify under relaxed canonicalization. + @Test + public void validate_arc_chain_passes_when_arc_seal_signature_header_is_unfolded() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh\n" + + " GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + valimailArcSealFormatCommonTail()); + } + + // as_fields_b_eol_wsp: trailing line whitespace must be stripped during AS verification. + @Test + public void validate_arc_chain_passes_when_arc_seal_signature_has_end_of_line_whitespace() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr \n" + + " QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh\n" + + " GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + valimailArcSealFormatCommonTail()); + } + + // as_fields_b_inl_wsp: repeated inline whitespace must be reduced during AS verification. + @Test + public void validate_arc_chain_passes_when_arc_seal_header_has_extra_inline_whitespace() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr\n" + + " QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh\n" + + " GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + valimailArcSealFormatCommonTail()); + } + + // as_fields_b_col_wsp: whitespace around the ARC-Seal field-name colon must be ignored. + @Test + public void validate_arc_chain_passes_when_arc_seal_header_has_whitespace_after_colon() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr\n" + + " QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh\n" + + " GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + valimailArcSealFormatCommonTail()); + } + // as_fields_b_na: missing ARC-Seal b= leaves no signature to verify and must be rejected. @Test public void validate_arc_chain_fails_when_arc_seal_signature_tag_is_missing() throws Exception { @@ -1684,13 +1822,25 @@ private void replaceTagOnHeader(Message message, String headerName, String insta } private void assertValimailFixturePasses(String rawMessage) throws Exception { + assertValimailFixturePasses(rawMessage, valimailKeyRecordRetriever); + } + + private void assertValimailFixturePasses(String rawMessage, MockPublicKeyRecordRetrieverArc publicKeyRetriever) throws Exception { Message message = new DefaultMessageBuilder().parseMessage( new ByteArrayInputStream(rawMessage.replace("\n", "\r\n").getBytes(StandardCharsets.UTF_8))); - ARCChainValidator arcChainValidator = new ARCChainValidator(valimailKeyRecordRetriever); + ARCChainValidator arcChainValidator = new ARCChainValidator(publicKeyRetriever); ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); } + private void assertValimailFixtureFails(String rawMessage, MockPublicKeyRecordRetrieverArc publicKeyRetriever) throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream(rawMessage.replace("\n", "\r\n").getBytes(StandardCharsets.UTF_8))); + ARCChainValidator arcChainValidator = new ARCChainValidator(publicKeyRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + private Map buildArcSetWithAuthService(Message message, String authService) throws Exception { ArcSetBuilder builder = new ArcSetBuilder( ArcTestKeys.privateKeyArc, @@ -1792,6 +1942,55 @@ private String valimailArcSealFormatCommonTail() { + "--001a113e15fcdd0f9e0545366e8f--"; } + private String valimailArcSealKeySizeMessage(String selector, String arcSealSignature, String arcMessageSignature) { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=" + arcSealSignature + "; cv=none; d=example.org; i=1; s=" + selector + ";\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=" + arcMessageSignature + ";\n" + + " bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=" + selector + "; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "Received: by 10.157.52.162 with SMTP id g31csp5274520otc;\n" + + " Tue, 3 Jan 2017 12:32:02 -0800 (PST)\n" + + "X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271;\n" + + " Tue, 03 Jan 2017 12:32:02 -0800 (PST)\n" + + "Message-ID: \n" + + "Date: Thu, 5 Jan 2017 14:39:01 -0800\n" + + "From: Gene Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 2\n" + + "Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f\n" + + "Content-Type: text/plain; charset=UTF-8\n" + + "\n" + + "This is a test message\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f\n" + + "Content-Type: text/html; charset=UTF-8\n" + + "\n" + + "
This is a test message
\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f--"; + } + private ByteArrayInputStream readFileToByteArrayInputStream(String fileName) throws URISyntaxException, IOException { URL resource = this.getClass().getResource(fileName); FileInputStream file = new FileInputStream(new File(resource.toURI())); From 280356f670bc21733919800d35ace9dfe54be354 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sat, 18 Apr 2026 17:30:49 -0400 Subject: [PATCH 32/40] Added more AMS field validation coverage: -Add ARC-Message-Signature tests for duplicate instance handling, algorithm validation, signature b= parsing, and relaxed signed-header canonicalization. Cover missing, empty, unsupported, non-base64, and modified AMS signature values, plus ValiMail fixtures for signed header case, folding, whitespace, and tamper failures. -Reject AMS verification when a=rsa-sha256 is absent or b= is missing or empty so malformed signatures fail validation cleanly. --- .../org/apache/james/arc/ARCVerifier.java | 4 + .../java/org/apache/james/arc/ARCTest.java | 325 ++++++++++++++++++ 2 files changed, 329 insertions(+) diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index b5919a5..0c0d3b9 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -86,9 +86,13 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec String amsValue = amsField.getBody(); Map tags = parseTagList(amsValue); + String algorithm = tags.get("a"); String signedHeaders = tags.get("h"); String bodyHash = tags.get("bh"); String signatureB64 = tags.get("b"); + if (!"rsa-sha256".equals(algorithm) || signatureB64 == null || signatureB64.isEmpty()) { + return false; + } String b64 = signatureB64 .replaceAll("\\s+", "") // remove spaces, tabs, newlines .replace(";", ""); // defensive: strip trailing semicolon if present diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 5edcaa1..953d2f9 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -604,6 +604,289 @@ public void validate_arc_chain_fails_when_duplicate_ams_instance_appears_before_ assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // ams_fields_i_dup2: duplicate ARC-Message-Signature instance numbers must be rejected when + // the duplicate appears after the existing AMS header. + @Test + public void validate_arc_chain_fails_when_duplicate_ams_instance_appears_after_arc_set() throws Exception { + Message message = buildOneHopChainWithAms(ams -> ams, true); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_a_na: AMS without a= does not declare a supported signature algorithm. + @Test + public void validate_arc_chain_fails_when_ams_algorithm_tag_is_missing() throws Exception { + Message message = buildOneHopChainWithAms(ams -> ams.replaceFirst("a=rsa-sha256;\\s*", ""), false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_a_empty: AMS with an empty a= does not declare a supported signature algorithm. + @Test + public void validate_arc_chain_fails_when_ams_algorithm_tag_is_empty() throws Exception { + Message message = buildOneHopChainWithAms(ams -> ams.replace("a=rsa-sha256", "a="), false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_a_sha1: rsa-sha1 is not supported for AMS verification. + @Test + public void validate_arc_chain_fails_when_ams_algorithm_is_sha1() throws Exception { + Message message = buildOneHopChainWithAms(ams -> ams.replace("a=rsa-sha256", "a=rsa-sha1"), false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_a_unknown: unknown AMS signature algorithms must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_algorithm_is_unknown() throws Exception { + Message message = buildOneHopChainWithAms(ams -> ams.replace("a=rsa-sha256", "a=ed25519-sha256"), false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_b_ignores_wsp: whitespace inside AMS b= must be ignored during base64 decode. + @Test + public void validate_arc_chain_passes_when_ams_signature_contains_whitespace() throws Exception { + assertValimailFixturePasses( + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=L8GsQ6v/7miEWKMGu16QVCPF6IT8j9+DV/ZHzgm86gi5m2JYAq+BlkmiIDofRPW+QzAq85\n" + + " 2UlxwI2NZrhyAKgtM4FKO7+84P1eYwJKh57DZfCyUpqRx1Je2+vzT8ZggXQWYjFEu36MTDFX\n" + + " fRKVqPV3omyP+CFBzjJFFDLehJaPk=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=QsRzR /UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm\n" + + " 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE\n" + + " cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + valimailCommonMessageTail()); + } + + // ams_fields_b_na: missing AMS b= leaves no message signature to verify and must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_signature_tag_is_missing() throws Exception { + Message message = buildOneHopChainWithAms(ams -> ams.replaceAll("; b=.*$", ""), false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_b_empty: empty AMS b= leaves no message signature to verify and must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_signature_tag_is_empty() throws Exception { + Message message = buildOneHopChainWithAms(ams -> ams.replaceAll("; b=.*$", "; b="), false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_b_base64: AMS b= must be base64. + @Test + public void validate_arc_chain_fails_when_ams_signature_is_not_base64() throws Exception { + Message message = buildOneHopChainWithAms(ams -> ams.replaceAll("; b=.*$", "; b=not-base64!"), false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_b_mod_sig: a modified AMS signature must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_signature_is_modified() throws Exception { + Message message = buildOneHopChainWithAms( + ams -> ams.replaceAll("; b=.*$", "; b=" + Base64.getEncoder().encodeToString(new byte[128])), + false); + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // ams_fields_b_head_case: AMS relaxed canonicalization lowercases signed header names. + @Test + public void validate_arc_chain_passes_when_signed_header_name_case_changes() throws Exception { + assertValimailFixturePasses(valimailAmsCanonicalizationMessage( + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "FROM: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J.")); + } + + // ams_fields_b_head_unfold: folded signed headers must verify under relaxed canonicalization. + @Test + public void validate_arc_chain_passes_when_signed_header_is_folded() throws Exception { + assertValimailFixturePasses(valimailAmsCanonicalizationMessage( + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe\n" + + " \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J.")); + } + + // ams_fields_b_eol_wsp: signed-header line-end whitespace must be stripped. + @Test + public void validate_arc_chain_passes_when_signed_header_has_end_of_line_whitespace() throws Exception { + assertValimailFixturePasses(valimailAmsCanonicalizationMessage( + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J.")); + } + + // ams_fields_b_inl_wsp: repeated inline whitespace in signed headers must be reduced. + @Test + public void validate_arc_chain_passes_when_signed_header_has_extra_inline_whitespace() throws Exception { + assertValimailFixturePasses(valimailAmsCanonicalizationMessage( + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J.")); + } + + // ams_fields_b_col_wsp: whitespace after signed-header colons must be stripped. + @Test + public void validate_arc_chain_passes_when_signed_headers_have_colon_whitespace() throws Exception { + assertValimailFixturePasses(valimailAmsCanonicalizationMessage( + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J.")); + } + + // ams_fields_b_mod_headers1: modifying a signed From header must invalidate AMS. + @Test + public void validate_arc_chain_fails_when_signed_from_header_is_modified() throws Exception { + assertValimailFixtureFails(valimailAmsCanonicalizationMessage( + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J.")); + } + + // ams_fields_b_mod_headers2: modifying a signed Subject header must invalidate AMS. + @Test + public void validate_arc_chain_fails_when_signed_subject_header_is_modified() throws Exception { + assertValimailFixtureFails(valimailAmsCanonicalizationMessage( + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1 (Mod)\n" + + "\n" + + "Hey gang,\n" + + "This is a test message.\n" + + "--J.")); + } + // aar_struct_i_na / aar_i_missing: an ARC-Authentication-Results header without i= is invalid. @Test public void validate_arc_chain_fails_when_aar_has_no_instance_tag() throws Exception { @@ -1737,6 +2020,22 @@ private Message buildOneHopChainWithSeal(java.util.function.Function amsMutation, + boolean duplicateAms) throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, arcSet.get(ARC_AUTHENTICATION_RESULTS))); + String ams = amsMutation.apply(arcSet.get(ARC_MESSAGE_SIGNATURE)); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, ams)); + if (duplicateAms) { + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, ams)); + } + message.getHeader().addField(new RawField(ARC_SEAL, arcSet.get(ARC_SEAL))); + return message; + } + private String insertWhitespaceIntoSealSignature(String seal) { java.util.regex.Matcher matcher = java.util.regex.Pattern.compile("; b=([^;]+)$").matcher(seal); if (!matcher.find()) { @@ -1841,6 +2140,10 @@ private void assertValimailFixtureFails(String rawMessage, MockPublicKeyRecordRe assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + private void assertValimailFixtureFails(String rawMessage) throws Exception { + assertValimailFixtureFails(rawMessage, valimailKeyRecordRetriever); + } + private Map buildArcSetWithAuthService(Message message, String authService) throws Exception { ArcSetBuilder builder = new ArcSetBuilder( ArcTestKeys.privateKeyArc, @@ -1896,6 +2199,28 @@ private String valimailCommonMessageTail() { + "--J."; } + private String valimailAmsCanonicalizationMessage(String signedMessageTail) { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ\n" + + " 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn\n" + + " QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm\n" + + " 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE\n" + + " cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + signedMessageTail; + } + private String valimailArcSealFormatCommonTail() { return "ARC-Message-Signature: a=rsa-sha256;\n" + " b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou\n" From 8be878ec67b409aa112d22d7a18e076613cb0b4b Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sat, 18 Apr 2026 17:50:51 -0400 Subject: [PATCH 33/40] Add ARC body hash and key fixture coverage: - Add ValiMail ARC validation coverage for no-chain base messages, single-hop pass fixtures, missing and malformed ARC public keys, and AMS/AS selector-domain independence. - Add AMS bh= validation coverage for whitespace-tolerant body hashes, simple and relaxed body canonicalization, missing/empty/non-base64 body hash tags, modified body hashes, and modified message bodies. - Verify AMS body hashes before accepting ARC-Message-Signature by decoding bh=, applying the AMS body canonicalization mode, and comparing the computed SHA-256 digest. Reject malformed or unsupported body hash inputs cleanly while preserving existing multipart fixture behavior when the Mime4j DOM parser cannot reconstruct a raw multipart body. --- .../org/apache/james/arc/ARCVerifier.java | 143 ++++++- .../java/org/apache/james/arc/ARCTest.java | 375 +++++++++++++++++- 2 files changed, 510 insertions(+), 8 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 0c0d3b9..5b97fd6 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -21,13 +21,23 @@ import org.apache.james.arc.exceptions.ArcException; import org.apache.james.jdkim.exceptions.PermFailException; import org.apache.james.jdkim.exceptions.TempFailException; +import org.apache.james.mime4j.dom.Body; +import org.apache.james.mime4j.dom.Entity; import org.apache.james.mime4j.dom.Header; import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.dom.Multipart; +import org.apache.james.mime4j.dom.SingleBody; +import org.apache.james.mime4j.io.EOLConvertingInputStream; +import org.apache.james.mime4j.stream.NameValuePair; import org.apache.james.mime4j.stream.Field; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.KeyFactory; +import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.Signature; @@ -36,6 +46,7 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; +import java.util.Arrays; import java.util.Base64; import java.util.HashMap; import java.util.HashSet; @@ -90,16 +101,20 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec String signedHeaders = tags.get("h"); String bodyHash = tags.get("bh"); String signatureB64 = tags.get("b"); - if (!"rsa-sha256".equals(algorithm) || signatureB64 == null || signatureB64.isEmpty()) { + if (!"rsa-sha256".equals(algorithm) || bodyHash == null || bodyHash.isEmpty() + || signatureB64 == null || signatureB64.isEmpty()) { return false; } String b64 = signatureB64 .replaceAll("\\s+", "") // remove spaces, tabs, newlines .replace(";", ""); // defensive: strip trailing semicolon if present - if (signedHeaders == null || bodyHash == null) { + if (signedHeaders == null) { throw new ArcException("AMS missing required tags"); } + if (!verifyAmsBodyHash(tags, message)) { + return false; + } String amsForSigning = amsValue.replaceFirst(B_TAG_REGEX, "b="); // Canonicalize headers listed in h= @@ -145,6 +160,130 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec return result; } + private boolean verifyAmsBodyHash(Map tags, Message message) { + String bodyHash = tags.get("bh"); + String bodyCanonicalization = getBodyCanonicalization(tags.get("c")); + if (bodyCanonicalization == null) { + return false; + } + + byte[] expectedBodyHash; + try { + expectedBodyHash = Base64.getDecoder().decode(bodyHash.replaceAll("\\s+", "")); + } catch (IllegalArgumentException e) { + return false; + } + + byte[] computedBodyHash; + try { + if (message.getBody() == null) { + return true; + } + MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); + byte[] bodyBytes = readBodyBytes(message.getBody()); + if (bodyBytes.length == 0 && message.getBody() instanceof Multipart) { + return true; + } + byte[] canonicalizedBody = "relaxed".equals(bodyCanonicalization) + ? canonicalizeRelaxedBody(bodyBytes) + : canonicalizeSimpleBody(bodyBytes); + computedBodyHash = messageDigest.digest(canonicalizedBody); + } catch (IOException | NoSuchAlgorithmException e) { + return false; + } + return Arrays.equals(expectedBodyHash, computedBodyHash); + } + + private byte[] readBodyBytes(Body body) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + writeBody(body, out); + return out.toByteArray(); + } + + private void writeBody(Body body, ByteArrayOutputStream out) throws IOException { + if (body instanceof SingleBody) { + copy(new EOLConvertingInputStream(((SingleBody) body).getInputStream()), out); + } else if (body instanceof Multipart) { + writeMultipart((Multipart) body, out); + } + } + + private void writeMultipart(Multipart multipart, ByteArrayOutputStream out) throws IOException { + String boundary = getBoundary(multipart); + if (boundary == null) { + return; + } + for (Entity part : multipart.getBodyParts()) { + out.write(("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8)); + for (Field field : part.getHeader().getFields()) { + out.write((field.getName() + ": " + field.getBody() + "\r\n").getBytes(StandardCharsets.UTF_8)); + } + out.write("\r\n".getBytes(StandardCharsets.UTF_8)); + writeBody(part.getBody(), out); + out.write("\r\n".getBytes(StandardCharsets.UTF_8)); + } + out.write(("--" + boundary + "--").getBytes(StandardCharsets.UTF_8)); + } + + private String getBoundary(Multipart multipart) { + for (NameValuePair parameter : multipart.getContentTypeParameters()) { + if ("boundary".equalsIgnoreCase(parameter.getName())) { + return parameter.getValue(); + } + } + return null; + } + + private void copy(InputStream inputStream, ByteArrayOutputStream out) throws IOException { + try (InputStream in = inputStream) { + byte[] buffer = new byte[2048]; + int read; + while ((read = in.read(buffer)) > 0) { + out.write(buffer, 0, read); + } + } + } + + private byte[] canonicalizeSimpleBody(byte[] body) { + String normalized = new String(body, StandardCharsets.UTF_8).replaceAll("(?\n" + + "Received: by 10.157.52.162 with SMTP id g31csp5274520otc;\n" + + " Tue, 3 Jan 2017 12:32:02 -0800 (PST)\n" + + "X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271;\n" + + " Tue, 03 Jan 2017 12:32:02 -0800 (PST)\n" + + "Message-ID: \n" + + "Date: Tue, 3 Jan 2017 12:31:41 -080\n" + + "From: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 2\n" + + "Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f\n" + + "Content-Type: text/plain; charset=UTF-8\n" + + "\n" + + "This is a test message\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f\n" + + "Content-Type: text/html; charset=UTF-8\n" + + "\n" + + "
This is a test message
\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f--"; + } + + private String baseMessageOneSignedTail() { + return baseMessageOneSignedHeaders() + baseMessageOneBody(); + } + + private String baseMessageOneSignedHeaders() { + return "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 1\n" + + "\n"; + } + + private String baseMessageOneBody() { + return "Hey gang,\n" + + "This is a test message.\n" + + "--J."; + } + private String valimailCommonMessageTail() { return "ARC-Authentication-Results: i=1; lists.example.org;\n" + " spf=pass smtp.mfrom=jqd@d1.example;\n" @@ -2199,6 +2438,130 @@ private String valimailCommonMessageTail() { + "--J."; } + private String valimailPublicKeyMessage(String arcSealDomain, String arcSealSelector, String arcSealSignature) { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=" + arcSealSignature + "; cv=none; d=" + arcSealDomain + "; i=1; s=" + arcSealSelector + ";\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm\n" + + " 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE\n" + + " cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + baseMessageOneSignedTail(); + } + + private String valimailSingleHopBaseTwoMessage() { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=RkKDOauVsqcsTEFv6NVE6J0sxj8LUE4kfwRzs0CvMg/+KOqRDQoFxxJsJkI77EHZqcSgwr\n" + + " QKpt6aKsl2zyUovVhAppT65S0+vo+h3utd3f8jph++1uiAUhVf57PihDC/GcdhyRGa6YNQGh\n" + + " GoArSHaJKb06/qF5OBif8o9lmRC8E=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou\n" + + " ryKgNA4XhUt4EybBXOn1dlrMA07dDIUFOUE7n+8QsvX1Drii8aBIpiu+O894oBEDSYcd1R+z\n" + + " sZIdXhOjB/Lt4sTE1h5IT2p3UctgY=;\n" + + " bh=dHN66dCNljBC18wb03I1K6hlBvV0qqsKoDsetl+jxb8=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "Received: by 10.157.52.162 with SMTP id g31csp5274520otc;\n" + + " Tue, 3 Jan 2017 12:32:02 -0800 (PST)\n" + + "X-Received: by 10.36.31.84 with SMTP id d81mr49584685itd.26.1483475522271;\n" + + " Tue, 03 Jan 2017 12:32:02 -0800 (PST)\n" + + "Message-ID: \n" + + "Date: Thu, 5 Jan 2017 14:39:01 -0800\n" + + "From: Gene Q Doe \n" + + "To: arc@dmarc.org\n" + + "Subject: Example 2\n" + + "Content-Type: multipart/alternative; boundary=001a113e15fcdd0f9e0545366e8f\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f\n" + + "Content-Type: text/plain; charset=UTF-8\n" + + "\n" + + "This is a test message\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f\n" + + "Content-Type: text/html; charset=UTF-8\n" + + "\n" + + "
This is a test message
\n" + + "\n" + + "--001a113e15fcdd0f9e0545366e8f--"; + } + + private String valimailSimpleBodyHashMessage(String body) { + return valimailAmsBodyHashMessage( + "d6sLFV7dCrZT/WzJil6ZyWcA/W5tJGLkP+yx1Fln+uZdjkswYMjvPkO2V2kvMrh2GBgjee\n" + + " j9QiqfGHsJvGqAKrFVzxHEsgVA0IYN6tI5wTKMLgu09b8BeHUr49/XnBEemjbgO8W9n9SCyX\n" + + " hKjsZK5b5ZIYBqjCSDZUwWRWfJywk=", + "c+pRG+RBumfEVWDAjHVupy4hZHN2F/AMLHoj6Vha9px35oo6eoyMxxOFUvBgVIUVphuSwV\n" + + " 198baYTV6Of9DHw44VS5rf6MDZNtVc8lwm8ei8aSAgzSnuhnr0jW2j134QTsEL1TK1bWfs+l\n" + + " QGXDBN5AUDsbk4jN5akoDqmH7gNlc=", + "KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=", + "relaxed/simple", + body); + } + + private String valimailInvalidBodyHashMessage(String bodyHash) { + return valimailAmsBodyHashMessage( + "YoXbDMNRVADrsGTtqAuMLWVnRIj62jQOSDFCX875c5ksVoWcKstnor+cGw/PJnz0cPuFGH\n" + + " +vjw3y+tcgBDDbK1qBVyMUpHrahTLL/0IY2jMzoLgPYz7Yawv/gpn7GlyXL72Vdr58s/nEfk\n" + + " le/2NmfPZjlUezbwsw+UHbuqT5V38=", + "m5y+bcsy0duHt1KxJ2EakY2mOpwIrFaHD60tlw1PmqNdy4M7XLGTnA10R7k1OsFAQNQdZM\n" + + " n1aKsKDpYuRX21avSuDxximXFwkcWYevOqUmaklFXiWyJVXd9fHId0sEtNt0L28HInLwHeCf\n" + + " IPYbUuddJ8wRWei04RZjqdybh4f2o=", + bodyHash, + "relaxed/relaxed", + baseMessageOneBody()); + } + + private String valimailAmsBodyHashMessage( + String arcSealSignature, + String arcMessageSignature, + String bodyHash, + String canonicalization, + String body) { + String bodyHashTag = bodyHash == null ? "" : " bh=" + bodyHash + "; "; + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=" + arcSealSignature + "; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=" + arcMessageSignature + ";\n" + + bodyHashTag + "c=" + canonicalization + ";\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + baseMessageOneSignedHeaders() + + body; + } + private String valimailAmsCanonicalizationMessage(String signedMessageTail) { return "MIME-Version: 1.0\n" + "Return-Path: \n" From b6baca4b53227be0d84ddef55603a022a116e270 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sat, 18 Apr 2026 17:59:52 -0400 Subject: [PATCH 34/40] Added ValiMail coverage tests in ARCTest for "c=" edge cases: - Updated ARCVerifier to parse AMS canonicalization as header/body modes. - Added support for AMS simple header canonicalization in addition to relaxed. - Rejects empty/invalid c= values before accepting AMS. --- .../org/apache/james/arc/ARCVerifier.java | 49 +++++-- .../java/org/apache/james/arc/ARCTest.java | 136 ++++++++++++++++++ 2 files changed, 170 insertions(+), 15 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 5b97fd6..b038fe1 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -112,7 +112,8 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec if (signedHeaders == null) { throw new ArcException("AMS missing required tags"); } - if (!verifyAmsBodyHash(tags, message)) { + Canonicalization canonicalization = getCanonicalization(tags.get("c")); + if (canonicalization == null || !verifyAmsBodyHash(tags, message, canonicalization.body)) { return false; } @@ -133,13 +134,13 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec continue; } Field f = fields.get(fields.size() - doneHeaders); - signingData.append(canonicalizeRegularHeader(f)); + signingData.append(canonicalizeRegularHeader(f, canonicalization.header)); processedHeaders.put(hName, doneHeaders); } } // AMS itself must be included last - signingData.append(canonicalizeHeader(amsField.getName(), amsForSigning)); + signingData.append(canonicalizeHeader(amsField.getName(), amsForSigning, canonicalization.header)); // Build RSA public key from DNS record PublicKey publicKey = parsePublicKeyFromDns(publicKeyDnsRecord); @@ -160,13 +161,8 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec return result; } - private boolean verifyAmsBodyHash(Map tags, Message message) { + private boolean verifyAmsBodyHash(Map tags, Message message, String bodyCanonicalization) { String bodyHash = tags.get("bh"); - String bodyCanonicalization = getBodyCanonicalization(tags.get("c")); - if (bodyCanonicalization == null) { - return false; - } - byte[] expectedBodyHash; try { expectedBodyHash = Base64.getDecoder().decode(bodyHash.replaceAll("\\s+", "")); @@ -268,20 +264,29 @@ private byte[] canonicalizeRelaxedBody(byte[] body) { return relaxed.toString().getBytes(StandardCharsets.UTF_8); } - private String getBodyCanonicalization(String canonicalization) { + private Canonicalization getCanonicalization(String canonicalization) { + String headerCanonicalization; String bodyCanonicalization; if (canonicalization == null) { + headerCanonicalization = "relaxed"; bodyCanonicalization = "simple"; } else if (canonicalization.isEmpty()) { return null; } else { String[] parts = canonicalization.split("/", -1); - bodyCanonicalization = parts.length == 1 ? parts[0] : parts[1]; + if (parts.length > 2) { + return null; + } + headerCanonicalization = parts[0]; + bodyCanonicalization = parts.length == 1 ? "simple" : parts[1]; + } + if (!"simple".equals(headerCanonicalization) && !"relaxed".equals(headerCanonicalization)) { + return null; } if (!"simple".equals(bodyCanonicalization) && !"relaxed".equals(bodyCanonicalization)) { return null; } - return bodyCanonicalization; + return new Canonicalization(headerCanonicalization, bodyCanonicalization); } private Signature getSignature(PublicKey publicKey, StringBuilder signingData) { @@ -322,12 +327,16 @@ public Map parseTagList(String value) { return map; } - private String canonicalizeRegularHeader(Field field) { - String retVal = canonicalizeHeader(field.getName(), field.getBody()); + private String canonicalizeRegularHeader(Field field, String headerCanonicalization) { + String retVal = canonicalizeHeader(field.getName(), field.getBody(), headerCanonicalization); return retVal + "\r\n"; } - private String canonicalizeHeader(String name, String value) { + private String canonicalizeHeader(String name, String value, String headerCanonicalization) { + if ("simple".equals(headerCanonicalization)) { + String separator = value.startsWith(" ") || value.startsWith("\t") ? ":" : ": "; + return name + separator + value; + } // relaxed canonicalization: lowercase field name, unfold spaces, trim String n = name.toLowerCase(Locale.ROOT); String v = value.replaceAll("[\\r\\n]+", " ") @@ -336,6 +345,16 @@ private String canonicalizeHeader(String name, String value) { return n + ":" + v; } + private static class Canonicalization { + private final String header; + private final String body; + + private Canonicalization(String header, String body) { + this.header = header; + this.body = body; + } + } + public PublicKey parsePublicKeyFromDns(String dnsRecord) { Matcher m = PUBLIC_KEY_PATTERN.matcher(dnsRecord); diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 5fc3952..9e47617 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -1068,6 +1068,98 @@ public void validate_arc_chain_fails_when_ams_signed_body_is_modified() throws E + "--J.")); } + // ams_fields_c_na: missing c= uses the default simple/simple canonicalization. + @Test + public void validate_arc_chain_passes_when_ams_canonicalization_tag_is_missing() throws Exception { + assertValimailFixturePasses(valimailAmsCanonicalizationTagMessage( + "ygcIhWO/8u3FP5h+7kQH7X9Yqxs0MIHuMUA6PapmNf+8CP5Fb/mY/mZ5aUcLxJNozQ2oUU\n" + + " ukkGEysRaqm5uTJMhiy4YjZgJqMRVka3xMGeIaSw1PiugVu015l8wKR1ollDSN7POJaajQBC\n" + + " /4mUnAUFfND8OqfE/VimB6flYiUJ8=", + "1+WHHTxU+XLWVsbRsvjlW2kMRRhmGE+OE9jxnmLt4ryEa/AezAflCMmVzM7r1dKwxJA1oc\n" + + " YmkN0ga0CO/nxSvB9XR0dsg/TH7TTSQKIllCRxsmGLt+jG/9Mw5yTRxtBOOuFK4xbHbFbCLU\n" + + " vRCry9p9YZpoAemnEb24tm9vjlrsQ=", + "KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=", + null, + "from:to:date:subject:mime-version:arc-authentication-results", + baseMessageOneSignedTail())); + } + + // ams_fields_c_empty: empty c= must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_canonicalization_tag_is_empty() throws Exception { + assertValimailFixtureFails(valimailAmsCanonicalizationTagMessage( + "eTLQqvFomQqHaOc36izhl5UMp6wVe8vGsLLuPCraumms100F7tOUhRpAII90YkwX0AK+RT\n" + + " 5ij+3Ngk2sQRpMupfFTgeF1olGU+jt943VkFbmSYXYp0AwBe4TGsLugWmfkUy2sGBSC1Rv7n\n" + + " ZaC9m6Y2bNMJcwix1EAuFFV6ck1Wg=", + "QdAvD1bnatYxK/JQCvI1uSuKxOYC+oR7wqg/twCt+zAFm8Tvu+fZpO79+TSx+cLAETXKNT\n" + + " 6mgQLaLROfq3sNf8tP0f/4oqzMUb6Ybz2syHL7hkmC6Za5Ii8RDKwMSc8lmvJk6HXUKgsndZ\n" + + " vWsQCfv+jyLmfDfCI8v9WP7xa2UEU=", + "KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=", + "", + "from:to:date:subject:mime-version:arc-authentication-results", + baseMessageOneSignedTail())); + } + + // ams_fields_c_rr: relaxed/relaxed canonicalization must be honored. + @Test + public void validate_arc_chain_passes_with_relaxed_header_and_relaxed_body_canonicalization() throws Exception { + assertValimailFixturePasses(valimailAmsCanonicalizationMessage( + baseMessageOneSignedHeaders() + + "Hey gang, \n" + + "This is a test message.\n" + + "--J.")); + } + + // ams_fields_c_rs: relaxed/simple canonicalization must be honored. + @Test + public void validate_arc_chain_passes_with_relaxed_header_and_simple_body_canonicalization() throws Exception { + assertValimailFixturePasses(valimailSimpleBodyHashMessage(baseMessageOneBody())); + } + + // ams_fields_c_sr: simple/relaxed canonicalization must be honored. + @Test + public void validate_arc_chain_passes_with_simple_header_and_relaxed_body_canonicalization() throws Exception { + assertValimailFixturePasses(valimailSimpleHeaderCanonicalizationMessage( + "rhXdX7jNW4wMS/SjYKBYC9eW6q5KnnQ7UGICE45CsYhwEoi38c3nM+91lvM3zhUILxo51X\n" + + " htsrMDLw5TJeZdiCqgXhQZmSEzR+KEdnu2oidezrK/hUzYPlKdO59EQgGIiDAmIRoKZ6+rGV\n" + + " fUCltnyjA07a9KpIpeXRKT3WDCE6A=", + "RWHWmB6euT01CXN0PJKCrmmoPPGc+pxxurfyJBjnNzkTizZKD7XwHLqTuNPaRG7PULU6ffq8FQ7IivdffwqXNj4L3ttpKNIjfsndMFvn5lpKZGfvJZfjTmbTJMhF4CCJZZm7l1xy7LbYMaMb12WY47vXOe9RNjW7jQyw8iqctcA=", + "KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=", + "simple/relaxed", + baseMessageOneBody())); + } + + // ams_fields_c_ss: simple/simple canonicalization must be honored. + @Test + public void validate_arc_chain_passes_with_simple_header_and_simple_body_canonicalization() throws Exception { + assertValimailFixturePasses(valimailSimpleHeaderCanonicalizationMessage( + "X9qtjasr0URzC564MZz0bwckcIVnBW9yUZP+xt4rStU7MIuuo266KZ1V/e5tbg/MOCZJ2m\n" + + " 3hvKRsVy1fMeIus2RVBg88zwfjyRMsJBC+zKV8oONpIcxriN8imZcaeWdcfsghbAFBM3viCE\n" + + " MdvebSvInMfz0vZsD1DJBYTjPel8w=", + "fv7KIaPfZRTQynzpQ7Gkg3thdZn78iGc5L1hTQoWrY1nSaE3pqQTHsGDW7+FRquewwFoakGLSERxBnC67Sdvw9Exv+/CEs/spqRrDjNygkCf/BIZcURb2nXXFHqPy31X6r2bufWKj6Lbo+5MCyaS2tWkV+KoZhUpolYSo0CoGfk=", + "hhFbTjokraRYc/Af+8v4zyKm/9ApHGkBSLO129NtPbo=", + "simple/simple", + "Hey gang, \n" + + "This is a test message.\n" + + "--J.")); + } + + // ams_fields_c_invalid: unknown canonicalization names must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_canonicalization_tag_is_invalid() throws Exception { + assertValimailFixtureFails(valimailAmsCanonicalizationTagMessage( + "YYGtMgeVAGSLLMZ0k9D0yRRzsfKpbHCoqfLAKz+Du2++GE82Dvz2OT60ebG9m6vmT6nT1t\n" + + " D+rMJnTXIZDUPZ6BLH8rLo8jMb33cBV5NzBD3SDYqWA7OOkYrMGRGmoMfxpcGV8m77YykscT\n" + + " +cpxxA2Ytld+YTd0mTtxdOCN3T1M4=", + "DJZENNFBf+SwDthFmU1ztUBIsKRAAaUdY9CjuGXejv8T29jf3q3EDUz6OnMevRWiSLj4ED\n" + + " gymMDJNGSTUaz3N85KmzWrTJ7QOLNke1H9L9kkfEFowatF8fW5cV/7Y6Ubzh0e1626TELeE+\n" + + " kvczpXT7prdjJZZjQAbDuHsWXkOys=", + "KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=", + "pancake/waffle", + "from:to:date:subject:mime-version:arc-authentication-results", + baseMessageOneSignedTail())); + } + // aar_struct_i_na / aar_i_missing: an ARC-Authentication-Results header without i= is invalid. @Test public void validate_arc_chain_fails_when_aar_has_no_instance_tag() throws Exception { @@ -2584,6 +2676,50 @@ private String valimailAmsCanonicalizationMessage(String signedMessageTail) { + signedMessageTail; } + private String valimailAmsCanonicalizationTagMessage( + String arcSealSignature, + String arcMessageSignature, + String bodyHash, + String canonicalization, + String signedHeaders, + String signedMessageTail) { + String canonicalizationTag = canonicalization == null ? "" : " c=" + canonicalization + ";"; + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=" + arcSealSignature + "; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=" + arcMessageSignature + ";\n" + + " bh=" + bodyHash + ";" + canonicalizationTag + "\n" + + " d=example.org; h=" + signedHeaders + ";\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + signedMessageTail; + } + + private String valimailSimpleHeaderCanonicalizationMessage( + String arcSealSignature, + String arcMessageSignature, + String bodyHash, + String canonicalization, + String body) { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=" + arcSealSignature + "; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256; b=" + arcMessageSignature + + "; bh=" + bodyHash + "; c=" + canonicalization + + "; d=example.org; h=From:To:Date:Subject:MIME-Version:ARC-Authentication-Results; i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org; spf=pass smtp.mfrom=jqd@d1.example; dkim=pass (1024-bit key) header.i=@d1.example; dmarc=pass\n" + + baseMessageOneSignedHeaders() + + body; + } + private String valimailArcSealFormatCommonTail() { return "ARC-Message-Signature: a=rsa-sha256;\n" + " b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou\n" From 99d1325a0d4bc582dd265ae23dd7d3eb8191cb72 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sat, 18 Apr 2026 18:08:08 -0400 Subject: [PATCH 35/40] Added AMS tag validation in ARCVerifier: - d= is required, non-empty, and must look like a valid domain. - s= is required, non-empty, and must look like a valid selector. - t= remains optional, but if present must be numeric. --- .../org/apache/james/arc/ARCVerifier.java | 17 +- .../java/org/apache/james/arc/ARCTest.java | 146 ++++++++++++++++++ 2 files changed, 162 insertions(+), 1 deletion(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index b038fe1..4a750a4 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -84,6 +84,8 @@ public class ARCVerifier { public static final String ARC_MESSAGE_SIGNATURE = "ARC-Message-Signature"; public static final String ARC_SEAL = "ARC-Seal"; public static final String SHA256RSA = "SHA256withRSA"; + private static final Pattern DOMAIN_PATTERN = Pattern.compile("(?i)^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$"); + private static final Pattern SELECTOR_PATTERN = Pattern.compile("(?i)^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$"); private static final int MIN_RSA_KEY_BITS = 1024; private static final String DNS_RECORD_TYPE = "_domainkey"; private PublicKeyRetrieverArc _keyRecordRetriever; @@ -101,7 +103,7 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec String signedHeaders = tags.get("h"); String bodyHash = tags.get("bh"); String signatureB64 = tags.get("b"); - if (!"rsa-sha256".equals(algorithm) || bodyHash == null || bodyHash.isEmpty() + if (!validateAmsTags(tags) || !"rsa-sha256".equals(algorithm) || bodyHash == null || bodyHash.isEmpty() || signatureB64 == null || signatureB64.isEmpty()) { return false; } @@ -161,6 +163,19 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec return result; } + private boolean validateAmsTags(Map tags) { + String domain = tags.get("d"); + String selector = tags.get("s"); + String timestamp = tags.get("t"); + if (domain == null || domain.isEmpty() || !DOMAIN_PATTERN.matcher(domain).matches()) { + return false; + } + if (selector == null || selector.isEmpty() || !SELECTOR_PATTERN.matcher(selector).matches()) { + return false; + } + return timestamp == null || timestamp.matches("\\d+"); + } + private boolean verifyAmsBodyHash(Map tags, Message message, String bodyCanonicalization) { String bodyHash = tags.get("bh"); byte[] expectedBodyHash; diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 9e47617..62d5979 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -1160,6 +1160,126 @@ public void validate_arc_chain_fails_when_ams_canonicalization_tag_is_invalid() baseMessageOneSignedTail())); } + // ams_fields_d_na: missing AMS d= prevents public-key lookup and must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_domain_tag_is_missing() throws Exception { + assertValimailFixtureFails(valimailAmsTagFieldsMessage( + "xPtYeQQruf8zzJ9kUrMESmH9ooORAIArDB3MhPcaL+0fgmuc99fprb+aMaSqY6OdZvAEoO\n" + + " EBczyfdtlGKcqLqa5qpXYlukRfG3q8mlOd+8UU1u1bikCzfT/JI8PNerzaoxlksJfmt8zJT0\n" + + " f40IWBJnoRpPNqJSBFb8acvLVZFcQ=", + "iDLI16Dzhtt9CmHLpkUXy7d5legcVvxkPMStdfrYQfNfpwVia165ca2lGI7Sx79pCoMmy3\n" + + " sSWBrLHsTQkKylsGswc0br0ycquKhxHgQh0WChxQd6ITVGQvFO/wZJd2jtE5E/KDbPKDjEio\n" + + " qLfCWpVe2KT1UZ89V+E9tg0T5TgwY=", + null, + "dummy", + "12345")); + } + + // ams_fields_d_empty: empty AMS d= must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_domain_tag_is_empty() throws Exception { + assertValimailFixtureFails(valimailAmsTagFieldsMessage( + "Nn38++8Vf80guievTz8fSFN9VjbPdeRVR5LmvzRt0IMRzZ75FThtzO1VM0grGeUj+D39ri\n" + + " 0ZwIgNyVtZXfG17FEO5BGQq4ZddLQoWHLKTeOWXL59FPhGRJkxiKNefS2c5YqZQ0NI8VkKY0\n" + + " HQlX6AeD/CHHE/bpcg7fFB5/WWnLE=", + "yKCB5xEcyzGr2+mbXWsVDHDZB1PYe9MqqTWySS7Y32uFObEA/MNJmt5yPnZLScwQUhzeTc\n" + + " WL701aDMyPmlYlGnqxl2/QkvEw5hZNfOmD5gltxTlIabWyRrC1Qq/1RS2zDqvF2Qf8SJL1U7\n" + + " gL6jf82iBTT61ckhPraYGIdgI9hlo=", + "", + "dummy", + "12345")); + } + + // ams_fields_d_invalid: invalid AMS d= domain syntax must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_domain_tag_is_invalid() throws Exception { + assertValimailFixtureFails(valimailAmsTagFieldsMessage( + "G8wYXXsNzfrmW5ob/HLkPkg0hz37d0O01HmLr8E8IQUPAa4lywxmOekn0bmKfOvK5p77Dz\n" + + " JEue+awK3gHG7/obHdRLamg8cYxmj4qfR6Ay0baikigUF4Wyt77JsVUqCC1qedRNcRN3IGPx\n" + + " 7rrNSyzVlIWYPal3pQZc3E1ClpG2I=", + "rllEQ7rbed0w+ixVEkL/jiUZrjyDdTQ1d+qnNGEvpzzjh2xFla14BKDcXo7q/aX25lxl0e\n" + + " yzw6yf5PFJC6JWqj5h3sFtLO6hS+E0DXyPZx0ok9tNiv7QV4YqY9fWeA64OZD183DKISDZnD\n" + + " mx/r0Svb5thGZvzvyfuAQapHke/Rk=", + "example...", + "dummy", + "12345")); + } + + // ams_fields_s_na: missing AMS s= prevents public-key lookup and must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_selector_tag_is_missing() throws Exception { + assertValimailFixtureFails(valimailAmsTagFieldsMessage( + "zlVnN6R6lixbru5oAlqBAalgQAcbqVJi0fZe8u57TJTTLHNl+LRLeQRsLQ4OcZ2n5XLTSZ\n" + + " ZAEsfzFQWeFruAnDpA7yT7/YTUYvQM7KdVzx4vl4FSTllt1wb0UJ0SNjlNGiudA94D43LOsx\n" + + " CsESqhYaVWRz4gLkD2P6FfqZLGCZg=", + "1yhACoFkMMv54Xwy9PCxFazQ8BtUb99MhAUEk4Xwq7gVqDoyND9X+pa8CGMYSNUOn2I4tx\n" + + " 4PyDzLhPNf+a4AciBNvFhHwK4lljIQAS514NuaNfv3PR0KDkkoXYv8J1EkI9yAyvOzl5Ka2B\n" + + " 2yNTkGi6GucEwUlu2Qrk0RYhOYOVM=", + "example.org", + null, + "12345")); + } + + // ams_fields_s_empty: empty AMS s= must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_selector_tag_is_empty() throws Exception { + assertValimailFixtureFails(valimailAmsTagFieldsMessage( + "iUyd0NGqGiWwg11FiLSmb+053tfp1baKV04kpufd+RESTCeMHlAHj/N2ZyLCHnCZSfgDTb\n" + + " hJy5KSpxO1nsSOlG/FsI6zwfEWCEP91aNjzEQxrX9iCg/zihZ9uv3wgmSOasjjt2kVGCcJUM\n" + + " iLpzGuccZW6C0S8QyOA8ClL0cHnrs=", + "DMnmzfNSgbRhHJmeSr5Ahc9FzG0ZFQxd7FVPrmmbpB78dtA4tjLUywkekiqhABliJzs0ut\n" + + " zzkNYHyP0hlxGTaYOQ6OgV+1loymJCJDin9FhPV62CGOBXznuaRxFI+aWKHjW6SFFrZplQHG\n" + + " UQcAeHg8Dd8tdKV4dgUnuW+aphtiQ=", + "example.org", + "", + "12345")); + } + + // ams_fields_t_na: AMS t= is optional and a signature generated without it must validate. + @Test + public void validate_arc_chain_passes_when_ams_timestamp_tag_is_missing() throws Exception { + assertValimailFixturePasses(valimailAmsTagFieldsMessage( + "rx+UjBcicBZ6s5/J7S5oMw3YVWAWg+q4Sb4XqR0tMmhOyhjLq7702sEFlEDHJjdTuTVMg+\n" + + " c2qwv/XucEGW8/i4AMzNgkzpwk1Icsr0GHGbR7Jm8V+k6Z08tvQ4x1UaYgrTKmSQeyKq8rQQ\n" + + " rRdzsqqX73OFp/cKLa42T3JVTrQpc=", + "iRbmo9I0Qn8ZELD2xJ754eoEATUfoRxli5qMUi3AQTwGLHU6oaLFsAP7JDYjRm6al3XGp8\n" + + " 73NpnbncM6dnqlBvKK5OmekgztBKiyo7w0Uj6NZbq2KJXYiVW2vAbVkNwy4vPNhMHVTbD/xB\n" + + " PWROiovFOL0q2mHDT1KKLiSzEfrWA=", + "example.org", + "dummy", + null)); + } + + // ams_fields_t_empty: empty AMS t= must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_timestamp_tag_is_empty() throws Exception { + assertValimailFixtureFails(valimailAmsTagFieldsMessage( + "J1fBm2GXu8CCXApvRsyBIITcTcJ4MdgwPIUK2e+vU57BId7RYv2i7/ORWrImxasfuFD17v\n" + + " oU0TUpKqBmD/o6ZdLcgxg72iaYN7CoN9uK9Vr1llrVHuhJa4WUW0XG+a3XqKB2PXJh0LckJu\n" + + " 215qpJ4wqx+/6aGVuxQp5LXwktEDM=", + "GO1zQzqzWlsUbs6Rag7bYFPB2LgxCLkex8PRM+4/IbysgHm1TVtsPCVAAYp8+MK8UDyuuR\n" + + " s3wgba6Zgh08O4F3MGn5ouJmplCkS/mF1MTAuWF1BiBkzYTdNmwhESK3GBTDNgTzBwa0upsw\n" + + " aYiT87hDd1aqIKekvR3ZyEtZAN0Bc=", + "example.org", + "dummy", + "")); + } + + // ams_fields_t_invalid: non-numeric AMS t= must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_timestamp_tag_is_invalid() throws Exception { + assertValimailFixtureFails(valimailAmsTagFieldsMessage( + "g1Xr4aSSeSDH0CUBae/NLjI30AgmGDwAdG5BC2c/OuTKGROcimWkt3ikql9YlvBv/3O8AQ\n" + + " fe1XJqEq8EwFpKgk2YvMiWV4YKWPGb4DVNn/N2nk79o2KH/DlXNU4fLGvae9leiu1E+KJERC\n" + + " /sYt7EA0rffMCWMjfHivWEx1swomo=", + "B9XbvvEBkWcBoOY6hBRGeJLsADsuzM0ZRvpeBWgF/nx8itykfMZmdeVPzVY5SI7MRCi8jp\n" + + " +RtfP938tY75D6wfNd4+mrDkHyEQFAiE+UlYWjZOGx69go2UQyN5+wocPHHps4n9j279es08\n" + + " zmmxQXWG8wuoq53Y1CfrwNyniO824=", + "example.org", + "dummy", + "icecream")); + } + // aar_struct_i_na / aar_i_missing: an ARC-Authentication-Results header without i= is invalid. @Test public void validate_arc_chain_fails_when_aar_has_no_instance_tag() throws Exception { @@ -2720,6 +2840,32 @@ private String valimailSimpleHeaderCanonicalizationMessage( + body; } + private String valimailAmsTagFieldsMessage( + String arcSealSignature, + String arcMessageSignature, + String domain, + String selector, + String timestamp) { + String domainTag = domain == null ? "" : "d=" + domain + "; "; + String selectorTag = selector == null ? "" : "s=" + selector; + String timestampTag = timestamp == null ? "" : "; t=" + timestamp; + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=" + arcSealSignature + "; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=" + arcMessageSignature + ";\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " " + domainTag + "h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; " + selectorTag + timestampTag + "\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + baseMessageOneSignedTail(); + } + private String valimailArcSealFormatCommonTail() { return "ARC-Message-Signature: a=rsa-sha256;\n" + " b=SMBCg/tHQkIAIzx7OFir0bMhCxk/zaMOx1nyOSAviXW88ERohOFOXIkBVGe74xfJDSh9ou\n" From 02bef533d3da0c9b69f172efae01ee1e4dcc7f15 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sat, 18 Apr 2026 18:24:28 -0400 Subject: [PATCH 36/40] Add remaining ARC h= and first-hop signing test coverage: - Add ValiMail fixture-backed tests for the remaining AMS h= signed-header cases, covering empty h=, whitespace and folded separators, case-insensitive header names, duplicate header selection, missing headers, omitted h=, header order failures, and ARC header inclusion behavior. - Reject ARC-Seal in the AMS h= signed-header list so messages that include arc-seal in AMS signing data fail validation as expected by the upstream test suite, while preserving the allowed arc-message-signature case. - Add explicit first-hop signing coverage for messages without an incoming ARC chain, asserting that generated ARC sets start at i=1 and seal with cv=none. --- .../org/apache/james/arc/ARCVerifier.java | 10 + .../java/org/apache/james/arc/ARCTest.java | 357 ++++++++++++++++++ 2 files changed, 367 insertions(+) diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 4a750a4..74ba23e 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -114,6 +114,9 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec if (signedHeaders == null) { throw new ArcException("AMS missing required tags"); } + if (signsArcSealHeader(signedHeaders)) { + return false; + } Canonicalization canonicalization = getCanonicalization(tags.get("c")); if (canonicalization == null || !verifyAmsBodyHash(tags, message, canonicalization.body)) { return false; @@ -163,6 +166,13 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec return result; } + private boolean signsArcSealHeader(String signedHeaders) { + return Arrays.stream(signedHeaders.split(":")) + .map(String::trim) + .map(headerName -> headerName.toLowerCase(Locale.US)) + .anyMatch("arc-seal"::equals); + } + private boolean validateAmsTags(Map tags) { String domain = tags.get("d"); String selector = tags.get("s"); diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 62d5979..62f16c3 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -173,6 +173,19 @@ public void generate_and_verify_arc_set() throws Exception { assertThat(cv.getResult().toString().toLowerCase()).isEqualTo(expectedCv); } + // i0_base: signing a message with no incoming ARC chain starts at i=1 and seals cv=none. + @Test + public void build_arc_set_for_message_without_arc_chain_uses_first_instance_and_cv_none() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + + assertThat(arcSet.get(ARC_AUTHENTICATION_RESULTS)).startsWith("i=1;"); + assertThat(arcSet.get(ARC_MESSAGE_SIGNATURE)).contains("i=1;"); + assertThat(arcSet.get(ARC_SEAL)).contains("i=1; cv=none;"); + } + // cv_fail_i1_ams_invalid: builds a valid i=1 ARC set, then replaces the AMS b= signature with // wrong bytes before adding headers to the message, expecting chain validation to return cv=fail. @Test @@ -1205,6 +1218,190 @@ public void validate_arc_chain_fails_when_ams_domain_tag_is_invalid() throws Exc "12345")); } + // ams_fields_h_empty: upstream suite accepts an empty AMS h= tag. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_tag_is_empty() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersMessage( + "V/iPFUptKaruDTBpwKcf5i6nu54GxrG3ss2bfPqqT3I5MGMyRmtE+J0kOVtU9qtHIhXUng\n" + + " Iezv5+gCOIf2jP1eYGvhN2Wmkf2zsShG6+Rfpnp9fih71C1f6fh6Qp4tTUhB6ww4ZOTKtVdv\n" + + " H0C2s/5in4RLMxS0FUWge8CvlTnGs=", + "ex6hirqdOz1yO1SZE3ALisw3dj1La5L4qHcv8/ttCs1qGajzw0zEtUyMnskTPQnt9cxxF3\n" + + " T74KRXlPVN/4Aqn+K/Q4NHtOW9vyuLt9ek9Vm6/xvZ10KTMrxv24u0eLnsigC6NfablL4wAM\n" + + " epZDlyjf/HPBd0yVLQL8yFDtQ5fE0=", + "", + "MIME-Version: 1.0\n", + baseMessageOneSignedTail())); + } + + // ams_fields_h_cws1: whitespace around AMS h= colon separators must be ignored. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_have_whitespace_around_colons() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersMessage( + "0+WA3Dpt9Y1lJ5wkoOZsh6KXEQFv0YE+ykvXAdS5t1toEui1UWzLyKWxSD/H/Xc6eCaQZM\n" + + " ji4IxybZ4OrIdV0yRe1fGqYN/bJ3KnkuzrHpaikXRWxXdX8tiIu5+I+HmERxuGzGqHdNv2zj\n" + + " 5L8PNAsGs4LDg3xQXEe3FQAvis9OA=", + "Lq5Sy1R3C0RaTxKWfggKBJ2MOdgAHeFy1nELK1c+CFnxdvSL+OxuvSxk8HYv7YMJDTR4Na\n" + + " 1D5GaFedB1uYVQsz1T5e3p9B+54W4bObByD14WvTGKV3ys8FlOf4MdRIlD4o6N3INfHrNbYX\n" + + " zwPKjkoYbteAEQ/kTpjESOpm131io=", + "from : to : date : subject : mime-version : arc-authentication-results", + "MIME-Version: 1.0\n", + baseMessageOneSignedTail())); + } + + // ams_fields_h_cws2: folded whitespace around AMS h= colon separators must be ignored. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_have_folded_whitespace_around_colons() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersMessage( + "0+WA3Dpt9Y1lJ5wkoOZsh6KXEQFv0YE+ykvXAdS5t1toEui1UWzLyKWxSD/H/Xc6eCaQZM\n" + + " ji4IxybZ4OrIdV0yRe1fGqYN/bJ3KnkuzrHpaikXRWxXdX8tiIu5+I+HmERxuGzGqHdNv2zj\n" + + " 5L8PNAsGs4LDg3xQXEe3FQAvis9OA=", + "Lq5Sy1R3C0RaTxKWfggKBJ2MOdgAHeFy1nELK1c+CFnxdvSL+OxuvSxk8HYv7YMJDTR4Na\n" + + " 1D5GaFedB1uYVQsz1T5e3p9B+54W4bObByD14WvTGKV3ys8FlOf4MdRIlD4o6N3INfHrNbYX\n" + + " zwPKjkoYbteAEQ/kTpjESOpm131io=", + "from : to : date : subject : mime-version :\n" + + " arc-authentication-results", + "MIME-Version: 1.0\n", + baseMessageOneSignedTail())); + } + + // ams_fields_h_case: AMS h= header names are case-insensitive. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_use_mixed_case() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersMessage( + "me1uYrnpt5Cdjkfj+bqK8X6abs8TET4r5Wp6e6ZuZ2FAtSzfx8WdnHCnBLUj7t/PR+EGne\n" + + " h4auyljzkm2gz09I0MbaYkd+xDmkRoN2WrFotceq+iROoDLf2NgZJb3SfDcVFp8emRMyyaGL\n" + + " WAtshPjJWnjoNfm+3clEpXzPw4WM4=", + "OCzwOGeJy6YL07Rh1A970C9pAK2YJeXr0rDVVbsd/aOxTeKbrIxOfQsJ5hYaze0aeE5U0p\n" + + " y/45cz4Jg07Ch61xZ0G3R3ne4eXxPauAU6QKPwr45HxO2gDywmNruiJP0JPTzcC9SVV/YjyL\n" + + " OGobZNIwUWR1hEkd5/UuAXHk23Q4g=", + "From:To:Date:Subject:Mime-version:Arc-authentication-results", + "MIME-Version: 1.0\n", + baseMessageOneSignedTail())); + } + + // ams_fields_h_dup1: duplicate signed headers must be selected from the bottom up. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_duplicate_existing_header_in_bottom_up_order() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersMessage( + "tv8fgth8OQw5DylJlW253wBM12VcMvjFLj+TwonVXPiSPJ1hV7F24q0rgmYeVhSBK/+4Ou\n" + + " kPW3e9oqILXx95sXrE4fiiz46//FtZK7z0YVzy/B3QpR7fGxzzA5uVoUh4WNd0oQEejwDKss\n" + + " ILrzkyu6fDUZ1kLeKyk3clE7b/NJo=", + "rGZpmx8nA8Fe0yQ319Ns+DPmwx9ToC7Z5Ba5NNGYtmXF87xboR0Cy7yxlJ2ek6j8WqCRXI\n" + + " jKV32tgZBXu5upoveTLBGzSe+NPTL2SkU2nFnktJjjPwTiPAYyXVBY1Uy7uSv9dT+wfB4Hvg\n" + + " Hm/nSrzqTBOxPsND1F1b2rzE1elQo=", + "from:to:to:date:subject:mime-version:arc-authentication-results", + "MIME-Version: 1.0\n", + baseMessageOneSignedTailWithTwoToHeaders())); + } + + // ams_fields_h_non_existant: signing a non-existent header is allowed. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_include_non_existent_header() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersMessage( + "cEfCkdG3zAUpq2XMYEvcI8e+nD53NUuUr/NQ74UBTzSVJBOsNQKADtUWqYirSlB9AFeEIq\n" + + " VGstwfXqh5TiMv1Uk9O04vM7WxrmMsqZI+GiRQvtaanfZQMcaYME1pCURdkDbMK/MOUGV+W2\n" + + " j9anSPB91SOQruKUDtqgwq8z87Ajc=", + "QHma3KzZiiP6Yq5jWp+mLznldNAMpK9ffvI87mbvEFFd1YSfoJu9JrxtBgv3/MEBFHLPm9\n" + + " qTii8g+94xOLgp/LEC/dM2E/u7yPAKKMz5fMzJfwqSGAGyBg2f12Mkyaqs3dzv97nZTZFkj8\n" + + " mHCV6SHNfnC+lkIs5XpJNRtddvolQ=", + "from:to:date:subject:mime-version:arc-authentication-results", + "", + baseMessageOneSignedTail())); + } + + // ams_fields_h_non_existant_dup: duplicate non-existent signed headers are allowed. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_include_duplicate_non_existent_header() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersMessage( + "akTog4W3hR16mF9pNZIhHzcceyST1LHWaIsDPobRX6iy5jBRbpb+lyKlcyZmS02T2kFYG9\n" + + " iOWQ6UZruiQXQu/u/GSkn0RSCwHWTfb25YqrQBLwH7pki4bDGHrTSrGbuYnFEHadYl2B8Gxo\n" + + " UXYn2/XBBil6Dkku2SswdN6RZhhoM=", + "CvqFe5bB3kFEFvITOTVx7VcrJQBT5aAtUJjX0h1L1Gh0MtUQofgKfOakgKr5kUIxv2foZY\n" + + " KJzwNSuUNnDyY87HJeT02j4JlpYnj0+PzB8xjW2Kj4/4TrLMkcJsfC2wujZClzXW65uCsFEb\n" + + " 0ht8EEQis3581f6/S2V+2pHxvqRiM=", + "from:to:date:subject:mime-version:arc-authentication-results:mime-version", + "", + baseMessageOneSignedTail())); + } + + // ams_fields_h_mis_hdr: blank header names in AMS h= are ignored. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_include_blank_header_name() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersMessage( + "FCq5UA4xGNozfvMgZkQ0Wpu4Q0dkGbrNvMKc0SNQnbObHCA84DNwUUp+I41h5ZvwQBAGxf\n" + + " hvUfjmsMFHBtsYj/aQ5kkehVPkOZ/6hengnO0IJs78Ab/5eivdD7MRLuShcTWd9qx32dVFJD\n" + + " yx8qIaRZplvJYl30ry7sOJQu4qSZk=", + "4TbROXpBlHvYUMMvecTyaEqk0DtgISmfrz9L7QEizbAaI6vgDPu1xD8LSj4CfHpak6GMde\n" + + " zpqtfiITgVTBKbkZi2kuFQwmu5xWsReExZEiNq7Tr6L5iObGjL0A27RIBj4znEmO6mk2Umnl\n" + + " +c6LR5XzyE65FGLZ+9nSH2U12klzI=", + "from:to::date:subject:mime-version:arc-authentication-results", + "MIME-Version: 1.0\n", + baseMessageOneSignedTail())); + } + + // ams_fields_h_includes_ams: upstream suite currently permits including AMS in h=. + @Test + public void validate_arc_chain_passes_when_ams_signed_headers_include_arc_message_signature() throws Exception { + assertValimailFixturePasses(valimailAmsSignedHeadersIncludesAmsMessage()); + } + + // ams_fields_h_na: AMS h= is required. + @Test + public void validate_arc_chain_fails_when_ams_signed_headers_tag_is_missing() throws Exception { + assertValimailFixtureFails(valimailAmsMissingSignedHeadersMessage()); + } + + // ams_fields_h_dup2: duplicate signed headers in the wrong bottom-up order are rejected. + @Test + public void validate_arc_chain_fails_when_ams_signed_headers_duplicate_existing_header_in_wrong_order() throws Exception { + assertValimailFixtureFails(valimailAmsSignedHeadersMessage( + "tv8fgth8OQw5DylJlW253wBM12VcMvjFLj+TwonVXPiSPJ1hV7F24q0rgmYeVhSBK/+4Ou\n" + + " kPW3e9oqILXx95sXrE4fiiz46//FtZK7z0YVzy/B3QpR7fGxzzA5uVoUh4WNd0oQEejwDKss\n" + + " ILrzkyu6fDUZ1kLeKyk3clE7b/NJo=", + "rGZpmx8nA8Fe0yQ319Ns+DPmwx9ToC7Z5Ba5NNGYtmXF87xboR0Cy7yxlJ2ek6j8WqCRXI\n" + + " jKV32tgZBXu5upoveTLBGzSe+NPTL2SkU2nFnktJjjPwTiPAYyXVBY1Uy7uSv9dT+wfB4Hvg\n" + + " Hm/nSrzqTBOxPsND1F1b2rzE1elQo=", + "from:to:to:date:subject:mime-version:arc-authentication-results", + "MIME-Version: 1.0\n", + baseMessageOneSignedTailWithTwoToHeadersInReverseOrder())); + } + + // ams_fields_h_order: misordered signed headers must not validate. + @Test + public void validate_arc_chain_fails_when_ams_signed_headers_are_misordered() throws Exception { + assertValimailFixtureFails(valimailAmsSignedHeadersMessage( + "vTCiDmh8p+YFqH8WSxCrLVT3IS1Xmt35hs9y2Fb4EriRTTEmD7lWa0UrCe9j/a3yftcMAb\n" + + " 8W01KgTrdIhmUMF7YrElyT1cGc0ChGHmdkuA2MpVBnLJMCgtXEQkWcVRne38KB9P+GLvr5uD\n" + + " nBOjOJNoBt4Nt+Y8zCKG/tN2RetKk=", + "2o+Wl1gzbDmg4Hv5q52M7V+E6KBhMISVmqTDrk1HfOgMJwJ+0v8Nl18EjbL+iOTu6Vxz9+\n" + + " 1m64cPsNr1Tgm79jjqugOKDI/yaU7h4DaFMmN54tGX8j1ElMXSl8ghcfaknApLU060vKVUoo\n" + + " F2GfD1qo+SSox3wkZNkPQdGKjNmQM=", + "from:to:date:subject:mime-version:arc-authentication-results", + "MIME-Version: 1.0\n", + baseMessageOneSignedTail())); + } + + // ams_fields_h_empty_added: a header added after signing a missing header must be rejected. + @Test + public void validate_arc_chain_fails_when_previously_missing_ams_signed_header_is_added() throws Exception { + assertValimailFixtureFails(valimailAmsSignedHeadersMessage( + "cEfCkdG3zAUpq2XMYEvcI8e+nD53NUuUr/NQ74UBTzSVJBOsNQKADtUWqYirSlB9AFeEIq\n" + + " VGstwfXqh5TiMv1Uk9O04vM7WxrmMsqZI+GiRQvtaanfZQMcaYME1pCURdkDbMK/MOUGV+W2\n" + + " j9anSPB91SOQruKUDtqgwq8z87Ajc=", + "QHma3KzZiiP6Yq5jWp+mLznldNAMpK9ffvI87mbvEFFd1YSfoJu9JrxtBgv3/MEBFHLPm9\n" + + " qTii8g+94xOLgp/LEC/dM2E/u7yPAKKMz5fMzJfwqSGAGyBg2f12Mkyaqs3dzv97nZTZFkj8\n" + + " mHCV6SHNfnC+lkIs5XpJNRtddvolQ=", + "from:to:date:subject:mime-version:arc-authentication-results", + "MIME-Version: 1.0\n", + baseMessageOneSignedTail())); + } + + // ams_fields_h_includes_as: including ARC-Seal in AMS h= must be rejected. + @Test + public void validate_arc_chain_fails_when_ams_signed_headers_include_arc_seal() throws Exception { + assertValimailFixtureFails(valimailAmsSignedHeadersIncludesAsMessage()); + } + // ams_fields_s_na: missing AMS s= prevents public-key lookup and must be rejected. @Test public void validate_arc_chain_fails_when_ams_selector_tag_is_missing() throws Exception { @@ -2601,6 +2798,46 @@ private String baseMessageOneSignedTail() { return baseMessageOneSignedHeaders() + baseMessageOneBody(); } + private String baseMessageOneSignedTailWithTwoToHeaders() { + return "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: morty@dmarc.org\n" + + "To: evil_morty@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + baseMessageOneBody(); + } + + private String baseMessageOneSignedTailWithTwoToHeadersInReverseOrder() { + return "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" + + " for ; Thu, 14 Jan 2015 15:01:30 -0800 (PST)\n" + + " (envelope-from jqd@d1.example)\n" + + "Authentication-Results: lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "Received: by 10.157.14.6 with HTTP; Tue, 3 Jan 2017 12:22:54 -0800 (PST)\n" + + "Message-ID: <54B84785.1060301@d1.example.org>\n" + + "Date: Thu, 14 Jan 2015 15:00:01 -0800\n" + + "From: John Q Doe \n" + + "To: evil_morty@dmarc.org\n" + + "To: morty@dmarc.org\n" + + "Subject: Example 1\n" + + "\n" + + baseMessageOneBody(); + } + private String baseMessageOneSignedHeaders() { return "Received: from segv.d1.example (segv.d1.example [72.52.75.15])\n" + " by lists.example.org (8.14.5/8.14.5) with ESMTP id t0EKaNU9010123\n" @@ -2821,6 +3058,126 @@ private String valimailAmsCanonicalizationTagMessage( + signedMessageTail; } + private String valimailAmsMissingSignedHeadersMessage() { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=O9vrOnKLOdZXxa46F8RDPTzqW14JYE7idGn0AfedcpWh58mPFE9jXHeaMda5L59thiQrJN\n" + + " T7Smno713R6DU9CfvnOvq8rQXCJ6D7GzWFhhOn6wEbjTaFQQ3jHn67XVDVnb4yjLElVhixob\n" + + " pG5ouN8U1TPqPWf+41wrIrCd5Mocw=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=RidA92CmsCgK81At2aPnlGuFlbvNT5IdWz7Z/6j765oabi0LEDkpB+2q+C5TJfc28Gj0Ok\n" + + " gghf2ykPbb7WniSvCue66fvUYaABU5m84urSzGd3MG3F47vTzCQ5qLah7E0UssP2QbP2b1Rt\n" + + " Hry/RlkOzlWeSlxpCcPvArmmcADTc=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + baseMessageOneSignedTail(); + } + + private String valimailAmsSignedHeadersMessage( + String arcSealSignature, + String arcMessageSignature, + String signedHeaders, + String initialHeaders, + String signedMessageTail) { + return initialHeaders + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=" + arcSealSignature + "; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=" + arcMessageSignature + ";\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=" + signedHeaders + ";\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + signedMessageTail; + } + + private String valimailAmsSignedHeadersIncludesAmsMessage() { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=XSOc6bESO7Ek4iCPyVXVE7aR8HUBBOXdOKmFpJO/3DI8rLRHHfRT9XAML3OsBE2RYj+0yd\n" + + " ypsBg8UQEewpY6Z5KEUhxfzwaBGObKr1pgwjkYiOBpPTV1Xfv1lGT+1qlJtBR2AGJauCEs7G\n" + + " fNzwa3MI+iO9E8g6aO/m9Mk1BlLHY=; cv=pass; d=example.org; i=2; s=dummy;\n" + + " t=12346\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=vpypMlcZNGmeVETFS/+v/Uk9npQE1LhY8tha0XTaeeNMgK1fzWaxvUHY0cuumuzK2pU25O\n" + + " uWTt08QEXczUR/BLmiZaYUWQV8qGOAv5umtEshqjB+0KPg5W09N20vQp8OXMQrenjZz0YPsy\n" + + " VweEidqd3HAcWSbZgW3jAFKXHGSXc=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:arc-message-signature:date:subject:mime-version:arc-authentication-results;\n" + + " i=2; s=dummy; t=12346\n" + + "ARC-Authentication-Results: i=2; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ\n" + + " 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn\n" + + " QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm\n" + + " 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE\n" + + " cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + baseMessageOneSignedTail(); + } + + private String valimailAmsSignedHeadersIncludesAsMessage() { + return "MIME-Version: 1.0\n" + + "Return-Path: \n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=OuFcuRk6CdaxxeBmCdvzoFxM6G0xmA3XNh1F243uPQsstHJ+T0csqD6PADig/UPV/Aj6fQ\n" + + " kAOsyZOzIK1X9ZCZLB2idFymnyWtYc2spNgCiSfwQiQuS3SFVUtr+Y7v58PtyAy2HCb2pA5I\n" + + " OIY1WjbK1Pd4SrJbZ4/M0d0wgFt7g=; cv=pass; d=example.org; i=2; s=dummy;\n" + + " t=12346\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=T5uPa/aCBkG1PK5dsSgO5US5yVvKnf/DAsyxMDCLVgw3auULB52XaLkZbc5KAcbGwz4KQZ\n" + + " H8TTB1qbdHGyUpA/1Tq4QveM4z1x/s/2gK/thnoW0wWEHu5frgmd3tVg8kEjrmU6HOJ1SNYq\n" + + " Qgjxvsd/OwpjYsfOjODwgyGDR/doE=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:arc-seal:date:subject:mime-version:arc-authentication-results;\n" + + " i=2; s=dummy; t=12346\n" + + "ARC-Authentication-Results: i=2; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + "ARC-Seal: a=rsa-sha256;\n" + + " b=dOdFEyhrk/tw5wl3vMIogoxhaVsKJkrkEhnAcq2XqOLSQhPpGzhGBJzR7k1sWGokon3TmQ\n" + + " 7TX9zQLO6ikRpwd/pUswiRW5DBupy58fefuclXJAhErsrebfvfiueGyhHXV7C1LyJTztywzn\n" + + " QGG4SCciU/FTlsJ0QANrnLRoadfps=; cv=none; d=example.org; i=1; s=dummy;\n" + + " t=12345\n" + + "ARC-Message-Signature: a=rsa-sha256;\n" + + " b=QsRzR/UqwRfVLBc1TnoQomlVw5qi6jp08q8lHpBSl4RehWyHQtY3uOIAGdghDk/mO+/Xpm\n" + + " 9JA5UVrPyDV0f+2q/YAHuwvP11iCkBQkocmFvgTSxN8H+DwFFPrVVUudQYZV7UDDycXoM6UE\n" + + " cdfzLLzVNPOAHEDIi/uzoV4sUqZ18=;\n" + + " bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; c=relaxed/relaxed;\n" + + " d=example.org; h=from:to:date:subject:mime-version:arc-authentication-results;\n" + + " i=1; s=dummy; t=12345\n" + + "ARC-Authentication-Results: i=1; lists.example.org;\n" + + " spf=pass smtp.mfrom=jqd@d1.example;\n" + + " dkim=pass (1024-bit key) header.i=@d1.example;\n" + + " dmarc=pass\n" + + baseMessageOneSignedTail(); + } + private String valimailSimpleHeaderCanonicalizationMessage( String arcSealSignature, String arcMessageSignature, From 3fa047f34231a0317c93e7c977c39da4e1e5ed11 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Sun, 26 Apr 2026 11:56:58 -0400 Subject: [PATCH 37/40] Harden ARC validation and replace bundled PSL: - Validate every ARC-Message-Signature in multi-hop chains and use the ARC-Seal key from the instance being verified. - Parse ARC i= tags numerically, enforce the valid 1..50 range, and avoid i=1 matching i=10. - Harden AMS verification for unsupported algorithms, x=/t= expiry, no-body bh= checks, and reject ARC-Seal h= tags. - Fix multipart body reconstruction to emit CRLF after the closing boundary. - Return DMARC permerror for malformed From headers instead of throwing. - Replace the bundled public suffix list with Guava InternetDomainName and add Guava as a managed DMARC dependency. - Remove the SPF thread context classloader workaround. - Add ARC and DMARC regression tests for the validation, canonicalization, and malformed input cases above. - Refresh README ARC/DMARC documentation while preserving upstream DKIM content. --- README.adoc | 218 +- .../apache/james/arc/ARCChainValidator.java | 26 +- .../org/apache/james/arc/ARCVerifier.java | 107 +- .../arc/DNSPublicKeyRecordRetrieverArc.java | 1 - .../java/org/apache/james/arc/ARCTest.java | 225 + dmarc/pom.xml | 4 + .../org/apache/james/dmarc/DMARCVerifier.java | 4 +- .../james/dmarc/DmarcValidationResult.java | 10 + .../apache/james/dmarc/PublicSuffixList.java | 83 +- .../src/main/resources/public_suffix_list.dat | 15997 ---------------- .../org/apache/james/dmarc/DMARCTest.java | 51 +- .../james/dmarc/PublicSuffixListTest.java | 4 +- pom.xml | 6 + 13 files changed, 620 insertions(+), 16116 deletions(-) delete mode 100644 dmarc/src/main/resources/public_suffix_list.dat diff --git a/README.adoc b/README.adoc index a9b9971..90580aa 100644 --- a/README.adoc +++ b/README.adoc @@ -1,21 +1,211 @@ -= JAMES jDKIM fork with ARC support += JAMES jDKIM library -This repository is a fork of Apache James jDKIM that adds ARC (Authenticated Received Chain) signing and related mail authentication capabilities alongside -the original DKIM functionality. -It is intended for experimentation and integration work around RFC 8617 in Java-based mail processing workflows. +Library dealing with parsing and cryptography to sign and verify DKIM signatures. +It also provides DMARC verification and ARC (Authenticated Received Chain) +support for Java-based mail processing workflows. -Original upstream project: -https://github.com/apache/james-jdkim +The mailet has been moved to James project: https://github.com/apache/james-project/tree/master/server/mailet/dkim -The mailet has been moved to the James project: -https://github.com/apache/james-project/tree/master/server/mailet/dkim +== Usage -== Fork-specific additions +A full example is available in +https://github.com/apache/james-jdkim/blob/master/main/src/test/java/org/apache/james/jdkim/DKIMTest.java[DKIMTest] -This fork extends the original Apache James jDKIM codebase with ARC-related functionality. +=== Signing -Current fork-specific focus includes: -- ARC signing support -- ARC chain handling -- Mail authentication extensions related to RFC 8617 +Signing a mime message can be achieved using the following snippet + +[source,java] +---- +import java.io.InputStream; +import java.security.PrivateKey; + +String signatureTemplate = "v=1; a=rsa-sha256; c=simple; d=messiah.edu; h=date:from:subject; q=dns/txt; s=selector2;"; + +PrivateKey privateKey = null; +DKIMSigner dkimSigner = new DKIMSigner(signatureTemplate, privateKey); +// You need to provide the input stream of the mime message, it will be parsed +// by mime4j +InputStream stream = null; +String signature = dkimSigner.sign(inputStream); +// `signature` contains the full header +// DKIM-Signature: a=rsa-sha256; q=dns/txt; b=Axa8s/g...U1SIw==; c=simple; s=selector2; d=messiah.edu; v=1; bh=6pQ...6g=; h=date:from:subject; +---- + +More advanced usage such as including multiple signatures can be found in +https://github.com/apache/james-jdkim/blob/master/main/src/test/java/org/apache/james/jdkim/DKIMTest.java[DKIMTest] + +=== Verifying + +Verifying a mime message DKIM signatures can be achieved using the following +snippet. The verifier always verifies all the signatures. + +[source,java] +---- +import java.io.InputStream; +// You can override the resolver in the constructor, use your own +// implementation of a retriever or use multiple implementations using a +// `MultiplexingPublicKeyRecordRetriever` +PublicKeyRecordRetriever keyRecordRetriever = new DNSPublicKeyRecordRetriever(); +DKIMVerifier verifier = new DKIMVerifier(keyRecordRetriever); +InputStream stream = null; // you need to provide the input stream of the mime message +List verifiedSignatures = verifier.verify(stream); +// `verifiedSignatures` contains only the signatures that have successfully +// passed the validation. +// If you want to query all the results including all the failures, you can +// retrieve them from the verifier +List results = verifier.getResults(); +---- + +=== Checking DMARC + +DMARC verification combines SPF and DKIM results with the RFC5322 `From` +domain and the domain DMARC policy. + +[source,java] +---- +import org.apache.james.dmarc.DMARCVerifier; +import org.apache.james.dmarc.DmarcValidationResult; +import org.apache.james.dmarc.PublicKeyRecordRetrieverDmarc; +import org.apache.james.mime4j.dom.Message; + +PublicKeyRecordRetrieverDmarc recordRetriever = null; +Message message = null; + +DMARCVerifier dmarcVerifier = new DMARCVerifier(recordRetriever); +DmarcValidationResult dmarcResult = dmarcVerifier.runDmarcCheck( + message, + "pass client-ip=192.0.2.1; envelope-from=sender@example.org", + "example.org", + "pass", + "example.org"); + +String authenticationResult = dmarcResult.toString(); +---- + +More complete DMARC examples can be found in +https://github.com/apache/james-jdkim/blob/master/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java[DMARCTest]. + +== ARC Support + +ARC support adds RFC 8617 signing and validation for intermediaries that need to +preserve authentication results across forwarding hops. + +=== Building An ARC Set + +Generating ARC headers for a MIME message can be achieved using the following +snippet. + +[source,java] +---- +import java.io.InputStream; +import java.security.PrivateKey; +import java.util.Map; + +import org.apache.james.arc.ArcSetBuilder; +import org.apache.james.arc.PublicKeyRetrieverArc; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.message.DefaultMessageBuilder; + +String amsTemplate = "i=; a=rsa-sha256; c=relaxed/relaxed; d=example.org; s=arc; t=; h=Subject:From:To; bh=; b="; +String sealTemplate = "i=; cv=; a=rsa-sha256; d=example.org; s=arc; t=; b="; + +PrivateKey privateKey = null; +InputStream stream = null; +Message message = new DefaultMessageBuilder().parseMessage(stream); + +ArcSetBuilder arcSetBuilder = new ArcSetBuilder( + privateKey, + amsTemplate, + sealTemplate, + "mx.example.org", + System.currentTimeMillis() / 1000); + +PublicKeyRetrieverArc keyRecordRetriever = null; +Map arcSet = arcSetBuilder.buildArcSet( + message, + "mail.example.org", + "sender@example.org", + "192.0.2.1", + keyRecordRetriever); + +String authenticationResults = arcSet.get("Authentication-Results"); +String arcAuthenticationResults = arcSet.get("ARC-Authentication-Results"); +String arcMessageSignature = arcSet.get("ARC-Message-Signature"); +String arcSeal = arcSet.get("ARC-Seal"); +---- + +The generated map contains the ARC headers for the current hop, ready to be +added to the message. + +=== Validating An ARC Chain + +Validating ARC headers on a MIME message can be achieved using the following +snippet. + +[source,java] +---- +import java.io.InputStream; + +import org.apache.james.arc.ARCChainValidator; +import org.apache.james.arc.ArcValidationOutcome; +import org.apache.james.arc.PublicKeyRetrieverArc; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.message.DefaultMessageBuilder; + +PublicKeyRetrieverArc keyRecordRetriever = null; +InputStream stream = null; +Message message = new DefaultMessageBuilder().parseMessage(stream); + +ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); +ArcValidationOutcome validation = arcChainValidator.validateArcChain(message); + +String chainValidation = validation.getResult().toString(); +String description = validation.getDescription(); +---- + +More complete ARC usage can be found in +https://github.com/apache/james-jdkim/blob/master/arc/src/test/java/org/apache/james/arc/ARCTest.java[ARCTest]. + +== Test Coverage + +ARC functionality is covered by tests in +https://github.com/apache/james-jdkim/blob/master/arc/src/test/java/org/apache/james/arc/ARCTest.java[ARCTest]. +The coverage is based on the ARC protocol requirements from +https://datatracker.ietf.org/doc/html/rfc8617[RFC 8617] and on the public +https://github.com/ValiMail/arc_test_suite[ValiMail ARC test suite]. The tests +exercise ARC set creation, chain validation, ARC-Seal verification, +ARC-Message-Signature canonicalization, body hash handling, required tag +validation, and malformed or tampered ARC header cases. + +== Cryptography Notice + +---- + This distribution includes cryptographic software. The country in + which you currently reside may have restrictions on the import, + possession, use, and/or re-export to another country, of + encryption software. BEFORE using any encryption software, please + check your country's laws, regulations and policies concerning the + import, possession, or use, and re-export of encryption software, to + see if this is permitted. See http://www.wassenaar.org for more + information. + + The U.S. Government Department of Commerce, Bureau of Industry and + Security (BIS), has classified this software as Export Commodity + Control Number (ECCN) 5D002.C.1, which includes information security + software using or performing cryptographic functions with asymmetric + algorithms. The form and manner of this Apache Software Foundation + distribution makes it eligible for export under the License Exception + ENC Technology Software Unrestricted (TSU) exception (see the BIS + Export Administration Regulations, Section 740.13) for both object + code and source code. + + The following provides more details on the included cryptographic + software: + + - jDKIM includes code designed to work with Java SE Security + + Export classifications and source links can be found + at http://www.apache.org/licenses/exports/. +---- diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index 5a2998a..e881ceb 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -91,15 +91,22 @@ private ArcValidationOutcome validatePreviousArcHops(Message message, Header mes return new ArcValidationOutcome(ArcValidationResult.FAIL, "ARC set structure is invalid"); } - Set prevArcSet; - prevArcSet = arcVerifier.extractArcSet(messageHeaders, numArcInstances); - if (prevArcSet != null) { - boolean amsOk = checkArcAms(prevArcSet, message, arcVerifier); - boolean asOk = checkArcSeal(messageHeaders.getFields(), numArcInstances, arcVerifier); - if (amsOk && asOk) { - return new ArcValidationOutcome(ArcValidationResult.PASS, "All previous ARC hops validated successfully"); + // RFC 8617 section 5.2: verify AMS for every instance from i=1 to i=N. + for (int i = 1; i <= numArcInstances; i++) { + Set arcSet = arcVerifier.extractArcSet(messageHeaders, i); + if (arcSet == null || !checkArcAms(arcSet, message, arcVerifier)) { + return new ArcValidationOutcome(ArcValidationResult.FAIL, "Previous ARC hops validation failed"); } } + boolean asOk; + try { + asOk = checkArcSeal(messageHeaders.getFields(), numArcInstances, arcVerifier); + } catch (ArcException | IllegalArgumentException e) { + return new ArcValidationOutcome(ArcValidationResult.FAIL, e.getMessage()); + } + if (asOk) { + return new ArcValidationOutcome(ArcValidationResult.PASS, "All previous ARC hops validated successfully"); + } return new ArcValidationOutcome(ArcValidationResult.FAIL, "Previous ARC hops validation failed"); } @@ -127,10 +134,13 @@ private boolean checkArcSeal(List headers, int instToVerify, ARCVerifier boolean retVal = false; Map> arcHeadersByI = arcVerifier.getArcHeadersByI(headers); ArcSealVerifyData verifyData = arcVerifier.buildArcSealSigningData(arcHeadersByI, instToVerify); - Field arcSealHeader = headers.stream() + Field arcSealHeader = arcHeadersByI.get(instToVerify).stream() .filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)) .findFirst().orElse(null); if (arcSealHeader == null) return retVal; + String algorithm = arcVerifier.parseTagGeneric(arcSealHeader.getBody(), "a"); + if (algorithm == null || algorithm.isEmpty()) return false; + arcVerifier.validateSupportedAlgorithm(ARC_SEAL, algorithm); String txtDnsRecord = arcVerifier.getTxtDnsRecordByField(arcSealHeader); if (txtDnsRecord == null) return retVal; diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 74ba23e..79d95d1 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -87,6 +87,8 @@ public class ARCVerifier { private static final Pattern DOMAIN_PATTERN = Pattern.compile("(?i)^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$"); private static final Pattern SELECTOR_PATTERN = Pattern.compile("(?i)^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$"); private static final int MIN_RSA_KEY_BITS = 1024; + private static final int MIN_ARC_INSTANCE = 1; + private static final int MAX_ARC_INSTANCE = 50; private static final String DNS_RECORD_TYPE = "_domainkey"; private PublicKeyRetrieverArc _keyRecordRetriever; @@ -103,10 +105,12 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec String signedHeaders = tags.get("h"); String bodyHash = tags.get("bh"); String signatureB64 = tags.get("b"); - if (!validateAmsTags(tags) || !"rsa-sha256".equals(algorithm) || bodyHash == null || bodyHash.isEmpty() + if (!validateAmsTags(tags) || algorithm == null || algorithm.isEmpty() || bodyHash == null || bodyHash.isEmpty() || signatureB64 == null || signatureB64.isEmpty()) { return false; } + validateSupportedAlgorithm("ARC-Message-Signature", algorithm); + validateAmsTimestamp(tags); String b64 = signatureB64 .replaceAll("\\s+", "") // remove spaces, tabs, newlines .replace(";", ""); // defensive: strip trailing semicolon if present @@ -166,6 +170,12 @@ public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRec return result; } + void validateSupportedAlgorithm(String headerName, String algorithm) { + if (!"rsa-sha256".equals(algorithm)) { + throw new ArcException(headerName + " uses unsupported algorithm: " + algorithm); + } + } + private boolean signsArcSealHeader(String signedHeaders) { return Arrays.stream(signedHeaders.split(":")) .map(String::trim) @@ -177,13 +187,31 @@ private boolean validateAmsTags(Map tags) { String domain = tags.get("d"); String selector = tags.get("s"); String timestamp = tags.get("t"); + String expiration = tags.get("x"); if (domain == null || domain.isEmpty() || !DOMAIN_PATTERN.matcher(domain).matches()) { return false; } if (selector == null || selector.isEmpty() || !SELECTOR_PATTERN.matcher(selector).matches()) { return false; } - return timestamp == null || timestamp.matches("\\d+"); + return (timestamp == null || timestamp.matches("\\d+")) + && (expiration == null || expiration.matches("\\d+")); + } + + private void validateAmsTimestamp(Map tags) { + String timestamp = tags.get("t"); + String expiration = tags.get("x"); + if (expiration == null) { + return; + } + long expirationEpoch = Long.parseLong(expiration); + if (timestamp != null && expirationEpoch <= Long.parseLong(timestamp)) { + throw new ArcException("AMS x= expiration must be greater than t= timestamp"); + } + long now = System.currentTimeMillis() / 1000; + if (expirationEpoch < now) { + throw new ArcException("AMS signature is expired"); + } } private boolean verifyAmsBodyHash(Map tags, Message message, String bodyCanonicalization) { @@ -197,17 +225,12 @@ private boolean verifyAmsBodyHash(Map tags, Message message, Str byte[] computedBodyHash; try { - if (message.getBody() == null) { - return true; - } MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); - byte[] bodyBytes = readBodyBytes(message.getBody()); + byte[] bodyBytes = message.getBody() == null ? new byte[0] : readBodyBytes(message.getBody()); if (bodyBytes.length == 0 && message.getBody() instanceof Multipart) { return true; } - byte[] canonicalizedBody = "relaxed".equals(bodyCanonicalization) - ? canonicalizeRelaxedBody(bodyBytes) - : canonicalizeSimpleBody(bodyBytes); + byte[] canonicalizedBody = canonicalizeBody(bodyBytes, bodyCanonicalization); computedBodyHash = messageDigest.digest(canonicalizedBody); } catch (IOException | NoSuchAlgorithmException e) { return false; @@ -243,7 +266,7 @@ private void writeMultipart(Multipart multipart, ByteArrayOutputStream out) thro writeBody(part.getBody(), out); out.write("\r\n".getBytes(StandardCharsets.UTF_8)); } - out.write(("--" + boundary + "--").getBytes(StandardCharsets.UTF_8)); + out.write(("--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8)); } private String getBoundary(Multipart multipart) { @@ -271,6 +294,12 @@ private byte[] canonicalizeSimpleBody(byte[] body) { return (normalized + "\r\n").getBytes(StandardCharsets.UTF_8); } + private byte[] canonicalizeBody(byte[] body, String bodyCanonicalization) { + return "relaxed".equals(bodyCanonicalization) + ? canonicalizeRelaxedBody(body) + : canonicalizeSimpleBody(body); + } + private byte[] canonicalizeRelaxedBody(byte[] body) { String normalized = new String(body, StandardCharsets.UTF_8).replaceAll("(?> arcHeadersByI) if (!cvOk) { throw new ArcException("ARC Chain validation fails due to cv check failing at instance [" + i + "]."); } + + boolean sealTagsOk = checkArcSealTags(arcSet); + if (!sealTagsOk) { + throw new ArcException("ARC Chain validation fails due to invalid ARC-Seal tags at instance [" + i + "]."); + } } return true; } + private boolean checkArcSealTags(List arcSet) { + Optional arcSealHeader = arcSet.stream() + .filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)) + .findFirst(); + return arcSealHeader + .map(field -> !parseTagList(field.getBody()).containsKey("h")) + .orElse(false); + } + private boolean checkCv(List lastArcSet, int instToVerify) { Optional arcSealHeader = lastArcSet.stream().filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)).findFirst(); if (arcSealHeader.isPresent()) { @@ -476,22 +519,30 @@ public Map> getArcHeadersByI(List headers) { for (Field f : headers) { String name = f.getName().toUpperCase(Locale.ROOT); if (name.startsWith("ARC-")) { - int i = -1; - String iTag = parseTagGeneric(f.getBody(), "i"); - if (iTag != null) { - i = Integer.parseInt(iTag); - } - if (i == -1) { - throw new IllegalStateException("ARC Header missing i= tag"); - } - else { - headersByI.computeIfAbsent(i, k -> new ArrayList<>()).add(f); - } + int i = parseArcInstance(f); + headersByI.computeIfAbsent(i, k -> new ArrayList<>()).add(f); } } return headersByI; } + private int parseArcInstance(Field field) { + String iTag = parseTagGeneric(field.getBody(), "i"); + if (iTag == null) { + throw new IllegalStateException("ARC Header missing i= tag"); + } + int instance; + try { + instance = Integer.parseInt(iTag); + } catch (NumberFormatException e) { + throw new IllegalStateException("ARC Header has invalid i= tag", e); + } + if (instance < MIN_ARC_INSTANCE || instance > MAX_ARC_INSTANCE) { + throw new IllegalStateException("ARC Header i= tag must be between 1 and 50"); + } + return instance; + } + public String canonicalizeBody(String body) { body = body.replaceAll("\r\n[\t ]", " "); body = body.replaceAll("[\t ]+", " "); @@ -568,7 +619,7 @@ public ArcSealVerifyData buildArcSealSigningData(Map> heade public Set extractArcSet(Header messageHeaders, int instance) { Set prevArcSet = null; for (Field field : messageHeaders.getFields()) { - if (field.getName().startsWith("ARC-") && field.getBody().contains("i="+instance)) { + if (field.getName().startsWith("ARC-") && hasArcInstance(field, instance)) { if (prevArcSet == null) { prevArcSet = new HashSet<>(); } @@ -578,6 +629,18 @@ public Set extractArcSet(Header messageHeaders, int instance) { return prevArcSet; } + private boolean hasArcInstance(Field field, int instance) { + String iTag = parseTagGeneric(field.getBody(), "i"); + if (iTag == null) { + return false; + } + try { + return Integer.parseInt(iTag) == instance; + } catch (NumberFormatException e) { + return false; + } + } + public String getTxtDnsRecordByField(Field signedHeader) { String dnsQuery = buildDnsQuery(signedHeader, DNS_RECORD_TYPE); if (dnsQuery == null || dnsQuery.isEmpty()) return null; // corrupted AMS - unable to pull PubKey from DNS diff --git a/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java b/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java index 44813f8..18719dd 100644 --- a/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java +++ b/arc/src/main/java/org/apache/james/arc/DNSPublicKeyRecordRetrieverArc.java @@ -33,7 +33,6 @@ public DNSPublicKeyRecordRetrieverArc() { @Override public String getSpfRecord(String helo, String from, String ip) { - Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); SPF spf = new DefaultSPF(); return spf.checkSPF(ip, from, helo).getHeaderText(); } diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 62f16c3..080f688 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -18,11 +18,16 @@ ******************************************************************************/ package org.apache.james.arc; +import org.apache.james.arc.exceptions.ArcException; import org.apache.james.dmarc.MockPublicKeyRecordRetrieverDmarc; import org.apache.james.jdkim.DKIMCommon; import org.apache.james.jdkim.MockPublicKeyRecordRetriever; +import org.apache.james.mime4j.dom.Body; import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.message.BodyPartBuilder; import org.apache.james.mime4j.message.DefaultMessageBuilder; +import org.apache.james.mime4j.message.MultipartBuilder; +import org.apache.james.mime4j.stream.NameValuePair; import org.apache.james.mime4j.stream.RawField; import org.junit.Test; @@ -34,12 +39,16 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.security.Signature; import java.util.Map; +import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class ARCTest { public static final String AUTHENTICATION_RESULTS = "Authentication-Results"; @@ -71,6 +80,28 @@ public class ARCTest { "softfail (spfCheck: transitioning domain of d1.example does not designate 222.222.222.222 as permitted sender) client-ip=222.222.222.222; envelope-from=jqd@d1.example; helo=d1.example") ); + private final MockPublicKeyRecordRetrieverArc mixedArcKeyRecordRetriever = new MockPublicKeyRecordRetrieverArc( dmarcRetriever, + MockPublicKeyRecordRetriever.Record.of( + "arc", + "dmarc.example", + "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";" + ), + MockPublicKeyRecordRetriever.Record.of( + "arc-alt", + "alt.example", + "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyDkim.getEncoded()) + ";" + ), + MockPublicKeyRecordRetriever.Record.of( + "origin2015", + "d1.example", + "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyDkim.getEncoded()) + ";" + ), + MockPublicKeyRecordRetrieverArc.SpfRecord.spfOf("d1.example", + "jqd@d1.example", + "222.222.222.222", + "softfail (spfCheck: transitioning domain of d1.example does not designate 222.222.222.222 as permitted sender) client-ip=222.222.222.222; envelope-from=jqd@d1.example; helo=d1.example") + ); + private static final String VALIMAIL_DUMMY_PUBLIC_KEY = "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3id" + "Y6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lx" @@ -562,6 +593,62 @@ public void validate_arc_chain_fails_when_i1_ams_corrupted_after_chain_built() t assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + // cv_fail_i2_1_ams1_invalid_resigned: if a forwarder corrupts i=1 AMS and then re-seals the chain + // at i=2 (so i=2 AS honestly covers the corrupted i=1 AMS), the chain must still be rejected + // because the validator must independently verify every AMS, not just the last one. + @Test + public void validate_arc_chain_fails_when_i1_ams_corrupted_and_chain_resigned_at_i2() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + + // Build valid i=1 ARC set + Map hop1 = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + for (Map.Entry entry : hop1.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + // Corrupt i=1 AMS before hop 2 seals the chain + corruptSignatureOnHeader(message, ARC_MESSAGE_SIGNATURE, "i=1"); + + // Build i=2 ARC set over the already-corrupted chain; i=2 AS honestly covers corrupted i=1 AMS + Map hop2 = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + for (Map.Entry entry : hop2.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + } + + // cv_pass_i2_as_keys_differ: ARC-Seal verification must use the key from the seal being verified, + // not an earlier seal in the chain. + @Test + public void validate_arc_chain_passes_when_latest_arc_seal_uses_different_key_than_previous_seal() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + ArcSetBuilder altArcSetBuilder = new ArcSetBuilder( + ArcTestKeys.privateKeyDkim, + "i=; a=rsa-sha256; c=relaxed/relaxed; d=alt.example; s=arc-alt; t=; h=Subject:From:To; bh=; b=", + "i=; cv=; a=rsa-sha256; d=alt.example; s=arc-alt; t=; b=", + AUTH_SERVICE, + TIMESTAMP); + + Map hop1 = altArcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, mixedArcKeyRecordRetriever); + for (Map.Entry entry : hop1.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + Map hop2 = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, mixedArcKeyRecordRetriever); + for (Map.Entry entry : hop2.entrySet()) { + message.getHeader().addField(new RawField(entry.getKey(), entry.getValue())); + } + + ARCChainValidator arcChainValidator = new ARCChainValidator(mixedArcKeyRecordRetriever); + ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); + assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); + } + // cv_pass_i3_1: a three-hop chain where every ARC set is valid should validate as cv=pass. @Test public void validate_arc_chain_passes_for_valid_three_hop_chain() throws Exception { @@ -589,6 +676,48 @@ public void validate_arc_chain_passes_for_valid_five_hop_chain() throws Exceptio assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("pass"); } + // arc_set_extract_i10: extracting i=1 must not accidentally include i=10 ARC headers. + @Test + public void extract_arc_set_matches_exact_instance_number() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream("Subject: exact instance test\n\nbody".getBytes(StandardCharsets.UTF_8))); + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, "i=1; mx.example; arc=none")); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, "i=1; d=example.org; s=arc; b=one")); + message.getHeader().addField(new RawField(ARC_SEAL, "i=1; cv=none; d=example.org; s=arc; b=one")); + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, "i=10; mx.example; arc=pass")); + message.getHeader().addField(new RawField(ARC_MESSAGE_SIGNATURE, "i=10; d=example.org; s=arc; b=ten")); + message.getHeader().addField(new RawField(ARC_SEAL, "i=10; cv=pass; d=example.org; s=arc; b=ten")); + ARCVerifier arcVerifier = new ARCVerifier(keyRecordRetriever); + + Set arcSet = arcVerifier.extractArcSet(message.getHeader(), 1); + + assertThat(arcSet).hasSize(3); + assertThat(arcSet) + .allMatch(field -> "1".equals(arcVerifier.parseTagGeneric(field.getBody(), "i"))); + } + + @Test + public void arc_header_grouping_rejects_zero_instance_number() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream("Subject: invalid instance test\n\nbody".getBytes(StandardCharsets.UTF_8))); + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, "i=0; mx.example; arc=none")); + + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever).getArcHeadersByI(message.getHeader().getFields())) + .isInstanceOf(IllegalStateException.class) + .hasMessage("ARC Header i= tag must be between 1 and 50"); + } + + @Test + public void arc_header_grouping_rejects_instance_number_above_fifty() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream("Subject: invalid instance test\n\nbody".getBytes(StandardCharsets.UTF_8))); + message.getHeader().addField(new RawField(ARC_AUTHENTICATION_RESULTS, "i=51; mx.example; arc=pass")); + + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever).getArcHeadersByI(message.getHeader().getFields())) + .isInstanceOf(IllegalStateException.class) + .hasMessage("ARC Header i= tag must be between 1 and 50"); + } + // ams_struct_i_na: an ARC-Message-Signature with no i= tag at all must be rejected. @Test public void validate_arc_chain_fails_when_ams_has_no_instance_tag() throws Exception { @@ -735,6 +864,20 @@ public void validate_arc_chain_fails_when_ams_algorithm_is_sha1() throws Excepti assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + @Test + public void verify_ams_throws_clear_exception_when_algorithm_is_sha1() throws Exception { + ByteArrayInputStream emailStream = readFileToByteArrayInputStream("/mail/rfc8617_no_arc.eml"); + Message message = new DefaultMessageBuilder().parseMessage(emailStream); + Map arcSet = arcSetBuilder.buildArcSet(message, HELO, MAIL_FROM, IP, keyRecordRetriever); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, + arcSet.get(ARC_MESSAGE_SIGNATURE).replace("a=rsa-sha256", "a=rsa-sha1")); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever).verifyAms(amsField, message, publicKeyDnsRecord)) + .isInstanceOf(ArcException.class) + .hasMessage("ARC-Message-Signature uses unsupported algorithm: rsa-sha1"); + } + // ams_fields_a_unknown: unknown AMS signature algorithms must be rejected. @Test public void validate_arc_chain_fails_when_ams_algorithm_is_unknown() throws Exception { @@ -1047,6 +1190,21 @@ public void validate_arc_chain_passes_when_relaxed_body_has_no_extra_trailing_cr baseMessageOneSignedHeaders() + baseMessageOneBody())); } + @Test + public void multipart_body_reconstruction_adds_crlf_after_closing_boundary() throws Exception { + Body body = MultipartBuilder.create("alternative") + .addContentTypeParameter(new NameValuePair("boundary", "abc")) + .addBodyPart(BodyPartBuilder.create() + .setContentType("text/plain") + .setBody("plain", StandardCharsets.UTF_8)) + .build(); + + byte[] bodyBytes = readBodyBytesWithVerifier(body); + + assertThat(new String(bodyBytes, StandardCharsets.UTF_8)) + .endsWith("--abc--\r\n"); + } + // ams_fields_bh_na: missing bh= must be rejected. @Test public void validate_arc_chain_fails_when_ams_body_hash_tag_is_missing() throws Exception { @@ -1071,6 +1229,22 @@ public void validate_arc_chain_fails_when_ams_body_hash_is_modified() throws Exc assertValimailFixtureFails(valimailInvalidBodyHashMessage("Z3JlbWxpbnM=")); } + @Test + public void verify_ams_fails_when_no_body_message_has_wrong_body_hash() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( + ("From: sender@example.org\r\n" + + "To: recipient@example.org\r\n" + + "Subject: no body\r\n").getBytes(StandardCharsets.UTF_8))); + String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " + + "t=12345; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + + assertThat(new ARCVerifier(keyRecordRetriever).verifyAms(amsField, message, publicKeyDnsRecord)) + .isFalse(); + } + // ams_fields_bh_mod_body: body changes outside relaxed canonicalization must be rejected. @Test public void validate_arc_chain_fails_when_ams_signed_body_is_modified() throws Exception { @@ -1477,6 +1651,40 @@ public void validate_arc_chain_fails_when_ams_timestamp_tag_is_invalid() throws "icecream")); } + @Test + public void verify_ams_throws_clear_exception_when_signature_is_expired() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( + ("From: sender@example.org\r\n" + + "To: recipient@example.org\r\n" + + "Subject: expired ams\r\n").getBytes(StandardCharsets.UTF_8))); + String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " + + "t=1; x=2; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever).verifyAms(amsField, message, publicKeyDnsRecord)) + .isInstanceOf(ArcException.class) + .hasMessage("AMS signature is expired"); + } + + @Test + public void verify_ams_throws_clear_exception_when_expiration_is_not_after_timestamp() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( + ("From: sender@example.org\r\n" + + "To: recipient@example.org\r\n" + + "Subject: invalid ams lifetime\r\n").getBytes(StandardCharsets.UTF_8))); + String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " + + "t=200; x=100; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever).verifyAms(amsField, message, publicKeyDnsRecord)) + .isInstanceOf(ArcException.class) + .hasMessage("AMS x= expiration must be greater than t= timestamp"); + } + // aar_struct_i_na / aar_i_missing: an ARC-Authentication-Results header without i= is invalid. @Test public void validate_arc_chain_fails_when_aar_has_no_instance_tag() throws Exception { @@ -2986,6 +3194,23 @@ private String valimailInvalidBodyHashMessage(String bodyHash) { baseMessageOneBody()); } + private String signRelaxedAmsForNoBodyMessage(Message message, String amsWithoutSignature) throws Exception { + String signingData = "from:" + message.getHeader().getField("From").getBody() + "\r\n" + + "to:" + message.getHeader().getField("To").getBody() + "\r\n" + + "subject:" + message.getHeader().getField("Subject").getBody() + "\r\n" + + "arc-message-signature:" + amsWithoutSignature; + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(ArcTestKeys.privateKeyArc); + signature.update(signingData.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(signature.sign()); + } + + private byte[] readBodyBytesWithVerifier(Body body) throws Exception { + Method readBodyBytes = ARCVerifier.class.getDeclaredMethod("readBodyBytes", Body.class); + readBodyBytes.setAccessible(true); + return (byte[]) readBodyBytes.invoke(new ARCVerifier(keyRecordRetriever), body); + } + private String valimailAmsBodyHashMessage( String arcSealSignature, String arcMessageSignature, diff --git a/dmarc/pom.xml b/dmarc/pom.xml index a1f3f1f..ac550af 100644 --- a/dmarc/pom.xml +++ b/dmarc/pom.xml @@ -55,6 +55,10 @@ org.apache.james apache-mime4j-dom + + com.google.guava + guava + org.assertj assertj-core diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java index 1563cc2..c51be12 100644 --- a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java +++ b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java @@ -40,13 +40,13 @@ public DmarcValidationResult runDmarcCheck(Message message, String spfHeaderText String shortSpfResult = spfHeaderText.split(" ")[0]; MailboxList mailboxList = message.getFrom(); if (mailboxList == null || mailboxList.size() != 1) { - throw new DmarcException("Incorrect From header: must have exactly one mailbox"); // rejecting immediately unless exactly one mailbox + return new DmarcValidationResult("permerror", null, null, "From header must contain exactly one mailbox"); } Mailbox mailbox = message.getFrom().get(0); String fromDomain = mailbox.getDomain(); if (fromDomain == null || fromDomain.isEmpty()) { - throw new DmarcException("From header is missing or has no domain part"); + return new DmarcValidationResult("permerror", null, null, "From header is missing a domain"); } // 2. Fetch DMARC record from DNS diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DmarcValidationResult.java b/dmarc/src/main/java/org/apache/james/dmarc/DmarcValidationResult.java index 566cbc6..8f26d1e 100644 --- a/dmarc/src/main/java/org/apache/james/dmarc/DmarcValidationResult.java +++ b/dmarc/src/main/java/org/apache/james/dmarc/DmarcValidationResult.java @@ -21,18 +21,28 @@ public class DmarcValidationResult { private static final String DEFAULT_RESPONSE_TEMPLATE = "dmarc=%s (p=%s) header.from=%s"; private static final String DEFAULT_NONE_RESPONSE_TEMPLATE = "dmarc=none (no policy) header.from=%s"; + private static final String DEFAULT_ERROR_RESPONSE_TEMPLATE = "dmarc=%s reason=\"%s\""; private final String result; private final String policy; private final String domain; + private final String reason; public DmarcValidationResult(String result, String policy, String domain) { + this(result, policy, domain, null); + } + + public DmarcValidationResult(String result, String policy, String domain, String reason) { this.result = result; this.policy = policy; this.domain = domain; + this.reason = reason; } @Override public String toString() { + if ("permerror".equals(result) && reason != null) { + return String.format(DEFAULT_ERROR_RESPONSE_TEMPLATE, result, reason); + } return (policy == null || result == null) ? String.format(DEFAULT_NONE_RESPONSE_TEMPLATE, domain) : String.format(DEFAULT_RESPONSE_TEMPLATE, result, policy, domain); diff --git a/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java b/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java index ca30051..6f2fed5 100644 --- a/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java +++ b/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java @@ -18,82 +18,27 @@ ******************************************************************************/ package org.apache.james.dmarc; -import org.apache.james.dmarc.exceptions.DmarcException; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Arrays; -import java.util.HashSet; import java.util.Locale; -import java.util.Set; - -public class PublicSuffixList { - private static final Set RULES = new HashSet<>(); - private static final Set WILDCARDS = new HashSet<>(); - private static final Set EXCEPTIONS = new HashSet<>(); - static { - try (InputStream is = PublicSuffixList.class.getResourceAsStream("/public_suffix_list.dat")) { - assert is != null; - parsePsl(is); - } - catch (Exception e) { - throw new DmarcException("Failed to load Public Suffix List", e); - } - } - - private static void parsePsl(InputStream is) { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { - String line; - while ((line = reader.readLine()) != null) { - line = line.trim(); - if (line.isEmpty() || line.startsWith("//")) continue; - if (line.startsWith("!")) { - EXCEPTIONS.add(line.substring(1).toLowerCase()); - } else if (line.startsWith("*.")) { - WILDCARDS.add(line.substring(2).toLowerCase()); - } else { - RULES.add(line.toLowerCase()); - } - } - } catch (IOException e) { - throw new DmarcException("Failed to read Public Suffix List", e); - } - } +import com.google.common.net.InternetDomainName; +public class PublicSuffixList { private PublicSuffixList() {} public static String getOrgDomain(String domainToCheck) { - if (domainToCheck == null || domainToCheck.trim().isEmpty()) return domainToCheck; - - domainToCheck = domainToCheck.toLowerCase(Locale.ROOT).trim(); - String[] domainParts = domainToCheck.split("\\."); - int numParts = domainParts.length; - - PSLMatchOutcome outcome = null; - - for (int i = 0; i < numParts && outcome == null; i++) { - String[] candidateArr = Arrays.copyOfRange(domainParts, i, numParts); - String matchedCandidate = String.join(".", candidateArr); - - if (EXCEPTIONS.contains(matchedCandidate)) { - // Exception rules take precedence - outcome = new PSLMatchOutcome(PSLMatch.EXCEPTION, matchedCandidate, domainParts, i); - } - - if (WILDCARDS.contains(matchedCandidate)) { - outcome = new PSLMatchOutcome(PSLMatch.WILDCARD, matchedCandidate, domainParts, i); - } + if (domainToCheck == null || domainToCheck.trim().isEmpty()) { + return domainToCheck; + } - if (RULES.contains(matchedCandidate)) { - outcome = new PSLMatchOutcome(PSLMatch.RULE, matchedCandidate, domainParts, i); + String normalizedDomain = domainToCheck.toLowerCase(Locale.ROOT).trim(); + try { + InternetDomainName domainName = InternetDomainName.from(normalizedDomain); + if (domainName.isUnderPublicSuffix()) { + return domainName.topPrivateDomain().toString(); } + return normalizedDomain; + } catch (IllegalArgumentException e) { + return normalizedDomain; } - - return outcome == null? - new PSLMatchOutcome(PSLMatch.NONE, null, domainParts, -1).getRelaxedOrgDomain(): - outcome.getRelaxedOrgDomain(); } -} \ No newline at end of file +} diff --git a/dmarc/src/main/resources/public_suffix_list.dat b/dmarc/src/main/resources/public_suffix_list.dat deleted file mode 100644 index d047478..0000000 --- a/dmarc/src/main/resources/public_suffix_list.dat +++ /dev/null @@ -1,15997 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -// Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat, -// rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported. - -// VERSION: 2025-10-13_13-22-32_UTC -// COMMIT: c002d19a8ca969110dd8a3838d972ca293bdc48f - -// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/. - -// ===BEGIN ICANN DOMAINS=== - -// ac : http://nic.ac/rules.htm -ac -com.ac -edu.ac -gov.ac -mil.ac -net.ac -org.ac - -// ad : https://www.iana.org/domains/root/db/ad.html -// Confirmed by Amadeu Abril i Abril (CORE) 2024-11-17 -ad - -// ae : https://www.iana.org/domains/root/db/ae.html -ae -ac.ae -co.ae -gov.ae -mil.ae -net.ae -org.ae -sch.ae - -// aero : https://information.aero/registration/policies/dmp -aero -// 2LDs -airline.aero -airport.aero -// 2LDs (currently not accepting registration, seemingly never have) -// As of 2024-07, these are marked as reserved for potential 3LD -// registrations (clause 11 "allocated subdomains" in the 2006 TLD -// policy), but the relevant industry partners have not opened them up -// for registration. Current status can be determined from the TLD's -// policy document: 2LDs that are open for registration must list -// their policy in the TLD's policy. Any 2LD without such a policy is -// not open for registrations. -accident-investigation.aero -accident-prevention.aero -aerobatic.aero -aeroclub.aero -aerodrome.aero -agents.aero -air-surveillance.aero -air-traffic-control.aero -aircraft.aero -airtraffic.aero -ambulance.aero -association.aero -author.aero -ballooning.aero -broker.aero -caa.aero -cargo.aero -catering.aero -certification.aero -championship.aero -charter.aero -civilaviation.aero -club.aero -conference.aero -consultant.aero -consulting.aero -control.aero -council.aero -crew.aero -design.aero -dgca.aero -educator.aero -emergency.aero -engine.aero -engineer.aero -entertainment.aero -equipment.aero -exchange.aero -express.aero -federation.aero -flight.aero -freight.aero -fuel.aero -gliding.aero -government.aero -groundhandling.aero -group.aero -hanggliding.aero -homebuilt.aero -insurance.aero -journal.aero -journalist.aero -leasing.aero -logistics.aero -magazine.aero -maintenance.aero -marketplace.aero -media.aero -microlight.aero -modelling.aero -navigation.aero -parachuting.aero -paragliding.aero -passenger-association.aero -pilot.aero -press.aero -production.aero -recreation.aero -repbody.aero -res.aero -research.aero -rotorcraft.aero -safety.aero -scientist.aero -services.aero -show.aero -skydiving.aero -software.aero -student.aero -taxi.aero -trader.aero -trading.aero -trainer.aero -union.aero -workinggroup.aero -works.aero - -// af : https://www.nic.af/domain-price -af -com.af -edu.af -gov.af -net.af -org.af - -// ag : http://www.nic.ag/prices.htm -ag -co.ag -com.ag -net.ag -nom.ag -org.ag - -// ai : http://nic.com.ai/ -ai -com.ai -net.ai -off.ai -org.ai - -// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 -al -com.al -edu.al -gov.al -mil.al -net.al -org.al - -// am : https://www.amnic.net/policy/en/Policy_EN.pdf -// Confirmed by ISOC AM 2024-11-18 -am -co.am -com.am -commune.am -net.am -org.am - -// ao : https://www.iana.org/domains/root/db/ao.html -// https://www.dns.ao/ao/ -ao -co.ao -ed.ao -edu.ao -gov.ao -gv.ao -it.ao -og.ao -org.ao -pb.ao - -// aq : https://www.iana.org/domains/root/db/aq.html -aq - -// ar : https://nic.ar/es/nic-argentina/normativa -ar -bet.ar -com.ar -coop.ar -edu.ar -gob.ar -gov.ar -int.ar -mil.ar -musica.ar -mutual.ar -net.ar -org.ar -seg.ar -senasa.ar -tur.ar - -// arpa : https://www.iana.org/domains/root/db/arpa.html -// Confirmed by registry 2008-06-18 -arpa -e164.arpa -home.arpa -in-addr.arpa -ip6.arpa -iris.arpa -uri.arpa -urn.arpa - -// as : https://www.iana.org/domains/root/db/as.html -as -gov.as - -// asia : https://www.iana.org/domains/root/db/asia.html -asia - -// at : https://www.iana.org/domains/root/db/at.html -// Confirmed by registry 2008-06-17 -at -ac.at -sth.ac.at -co.at -gv.at -or.at - -// au : https://www.iana.org/domains/root/db/au.html -// https://www.auda.org.au/ -// Confirmed by registry 2025-07-16 -au -// 2LDs -asn.au -com.au -edu.au -gov.au -id.au -net.au -org.au -// Historic 2LDs (closed to new registration, but sites still exist) -conf.au -oz.au -// CGDNs : https://www.auda.org.au/au-domain-names/the-different-au-domain-names/state-and-territory-domain-names/ -act.au -nsw.au -nt.au -qld.au -sa.au -tas.au -vic.au -wa.au -// 3LDs -act.edu.au -catholic.edu.au -// eq.edu.au - Removed at the request of the Queensland Department of Education -nsw.edu.au -nt.edu.au -qld.edu.au -sa.edu.au -tas.edu.au -vic.edu.au -wa.edu.au -// act.gov.au - Bug 984824 - Removed at request of Greg Tankard -// nsw.gov.au - Bug 547985 - Removed at request of -// nt.gov.au - Bug 940478 - Removed at request of Greg Connors -qld.gov.au -sa.gov.au -tas.gov.au -vic.gov.au -wa.gov.au -// 4LDs -// education.tas.edu.au - Removed at the request of the Department of Education Tasmania -// schools.nsw.edu.au - Removed at the request of the New South Wales Department of Education. - -// aw : https://www.iana.org/domains/root/db/aw.html -aw -com.aw - -// ax : https://www.iana.org/domains/root/db/ax.html -ax - -// az : https://www.iana.org/domains/root/db/az.html -// Confirmed via https://whois.az/?page_id=10 2024-12-11 -az -biz.az -co.az -com.az -edu.az -gov.az -info.az -int.az -mil.az -name.az -net.az -org.az -pp.az -// No longer available for registration, however domains exist as of 2024-12-11 -// see https://whois.az/?page_id=783 -pro.az - -// ba : https://www.iana.org/domains/root/db/ba.html -ba -com.ba -edu.ba -gov.ba -mil.ba -net.ba -org.ba - -// bb : https://www.iana.org/domains/root/db/bb.html -bb -biz.bb -co.bb -com.bb -edu.bb -gov.bb -info.bb -net.bb -org.bb -store.bb -tv.bb - -// bd : https://www.iana.org/domains/root/db/bd.html -*.bd - -// be : https://www.iana.org/domains/root/db/be.html -// Confirmed by registry 2008-06-08 -be -ac.be - -// bf : https://www.iana.org/domains/root/db/bf.html -bf -gov.bf - -// bg : https://www.iana.org/domains/root/db/bg.html -// https://www.register.bg/user/static/rules/en/index.html -bg -0.bg -1.bg -2.bg -3.bg -4.bg -5.bg -6.bg -7.bg -8.bg -9.bg -a.bg -b.bg -c.bg -d.bg -e.bg -f.bg -g.bg -h.bg -i.bg -j.bg -k.bg -l.bg -m.bg -n.bg -o.bg -p.bg -q.bg -r.bg -s.bg -t.bg -u.bg -v.bg -w.bg -x.bg -y.bg -z.bg - -// bh : https://www.iana.org/domains/root/db/bh.html -bh -com.bh -edu.bh -gov.bh -net.bh -org.bh - -// bi : https://www.iana.org/domains/root/db/bi.html -// http://whois.nic.bi/ -bi -co.bi -com.bi -edu.bi -or.bi -org.bi - -// biz : https://www.iana.org/domains/root/db/biz.html -biz - -// bj : https://nic.bj/bj-suffixes.txt -// Submitted by registry -bj -africa.bj -agro.bj -architectes.bj -assur.bj -avocats.bj -co.bj -com.bj -eco.bj -econo.bj -edu.bj -info.bj -loisirs.bj -money.bj -net.bj -org.bj -ote.bj -restaurant.bj -resto.bj -tourism.bj -univ.bj - -// bm : https://www.bermudanic.bm/domain-registration/index.php -bm -com.bm -edu.bm -gov.bm -net.bm -org.bm - -// bn : http://www.bnnic.bn/faqs -bn -com.bn -edu.bn -gov.bn -net.bn -org.bn - -// bo : https://nic.bo -// Confirmed by registry 2024-11-19 -bo -com.bo -edu.bo -gob.bo -int.bo -mil.bo -net.bo -org.bo -tv.bo -web.bo -// Social Domains -academia.bo -agro.bo -arte.bo -blog.bo -bolivia.bo -ciencia.bo -cooperativa.bo -democracia.bo -deporte.bo -ecologia.bo -economia.bo -empresa.bo -indigena.bo -industria.bo -info.bo -medicina.bo -movimiento.bo -musica.bo -natural.bo -nombre.bo -noticias.bo -patria.bo -plurinacional.bo -politica.bo -profesional.bo -pueblo.bo -revista.bo -salud.bo -tecnologia.bo -tksat.bo -transporte.bo -wiki.bo - -// br : http://registro.br/dominio/categoria.html -// Submitted by registry -br -9guacu.br -abc.br -adm.br -adv.br -agr.br -aju.br -am.br -anani.br -aparecida.br -api.br -app.br -arq.br -art.br -ato.br -b.br -barueri.br -belem.br -bet.br -bhz.br -bib.br -bio.br -blog.br -bmd.br -boavista.br -bsb.br -campinagrande.br -campinas.br -caxias.br -cim.br -cng.br -cnt.br -com.br -contagem.br -coop.br -coz.br -cri.br -cuiaba.br -curitiba.br -def.br -des.br -det.br -dev.br -ecn.br -eco.br -edu.br -emp.br -enf.br -eng.br -esp.br -etc.br -eti.br -far.br -feira.br -flog.br -floripa.br -fm.br -fnd.br -fortal.br -fot.br -foz.br -fst.br -g12.br -geo.br -ggf.br -goiania.br -gov.br -// gov.br 26 states + df https://en.wikipedia.org/wiki/States_of_Brazil -ac.gov.br -al.gov.br -am.gov.br -ap.gov.br -ba.gov.br -ce.gov.br -df.gov.br -es.gov.br -go.gov.br -ma.gov.br -mg.gov.br -ms.gov.br -mt.gov.br -pa.gov.br -pb.gov.br -pe.gov.br -pi.gov.br -pr.gov.br -rj.gov.br -rn.gov.br -ro.gov.br -rr.gov.br -rs.gov.br -sc.gov.br -se.gov.br -sp.gov.br -to.gov.br -gru.br -ia.br -imb.br -ind.br -inf.br -jab.br -jampa.br -jdf.br -joinville.br -jor.br -jus.br -leg.br -leilao.br -lel.br -log.br -londrina.br -macapa.br -maceio.br -manaus.br -maringa.br -mat.br -med.br -mil.br -morena.br -mp.br -mus.br -natal.br -net.br -niteroi.br -*.nom.br -not.br -ntr.br -odo.br -ong.br -org.br -osasco.br -palmas.br -poa.br -ppg.br -pro.br -psc.br -psi.br -pvh.br -qsl.br -radio.br -rec.br -recife.br -rep.br -ribeirao.br -rio.br -riobranco.br -riopreto.br -salvador.br -sampa.br -santamaria.br -santoandre.br -saobernardo.br -saogonca.br -seg.br -sjc.br -slg.br -slz.br -social.br -sorocaba.br -srv.br -taxi.br -tc.br -tec.br -teo.br -the.br -tmp.br -trd.br -tur.br -tv.br -udi.br -vet.br -vix.br -vlog.br -wiki.br -xyz.br -zlg.br - -// bs : http://www.nic.bs/rules.html -bs -com.bs -edu.bs -gov.bs -net.bs -org.bs - -// bt : https://www.iana.org/domains/root/db/bt.html -bt -com.bt -edu.bt -gov.bt -net.bt -org.bt - -// bv : No registrations at this time. -// Submitted by registry -bv - -// bw : https://www.iana.org/domains/root/db/bw.html -// https://nic.net.bw/bw-name-structure -bw -ac.bw -co.bw -gov.bw -net.bw -org.bw - -// by : https://www.iana.org/domains/root/db/by.html -// http://tld.by/rules_2006_en.html -// list of other 2nd level tlds ? -by -gov.by -mil.by -// Official information does not indicate that com.by is a reserved -// second-level domain, but it's being used as one (see www.google.com.by and -// www.yahoo.com.by, for example), so we list it here for safety's sake. -com.by -// http://hoster.by/ -of.by - -// bz : https://www.iana.org/domains/root/db/bz.html -// http://www.belizenic.bz/ -bz -co.bz -com.bz -edu.bz -gov.bz -net.bz -org.bz - -// ca : https://www.iana.org/domains/root/db/ca.html -ca -// ca geographical names -ab.ca -bc.ca -mb.ca -nb.ca -nf.ca -nl.ca -ns.ca -nt.ca -nu.ca -on.ca -pe.ca -qc.ca -sk.ca -yk.ca -// gc.ca: https://en.wikipedia.org/wiki/.gc.ca -// see also: http://registry.gc.ca/en/SubdomainFAQ -gc.ca - -// cat : https://www.iana.org/domains/root/db/cat.html -cat - -// cc : https://www.iana.org/domains/root/db/cc.html -cc - -// cd : https://www.iana.org/domains/root/db/cd.html -// https://www.nic.cd -cd -gov.cd - -// cf : https://www.iana.org/domains/root/db/cf.html -cf - -// cg : https://www.iana.org/domains/root/db/cg.html -cg - -// ch : https://www.iana.org/domains/root/db/ch.html -ch - -// ci : https://www.iana.org/domains/root/db/ci.html -ci -ac.ci -aéroport.ci -asso.ci -co.ci -com.ci -ed.ci -edu.ci -go.ci -gouv.ci -int.ci -net.ci -or.ci -org.ci - -// ck : https://www.iana.org/domains/root/db/ck.html -*.ck -!www.ck - -// cl : https://www.nic.cl -// Confirmed by .CL registry -cl -co.cl -gob.cl -gov.cl -mil.cl - -// cm : https://www.iana.org/domains/root/db/cm.html plus bug 981927 -cm -co.cm -com.cm -gov.cm -net.cm - -// cn : https://www.iana.org/domains/root/db/cn.html -// Submitted by registry -cn -ac.cn -com.cn -edu.cn -gov.cn -mil.cn -net.cn -org.cn -公司.cn -網絡.cn -网络.cn -// cn geographic names -ah.cn -bj.cn -cq.cn -fj.cn -gd.cn -gs.cn -gx.cn -gz.cn -ha.cn -hb.cn -he.cn -hi.cn -hk.cn -hl.cn -hn.cn -jl.cn -js.cn -jx.cn -ln.cn -mo.cn -nm.cn -nx.cn -qh.cn -sc.cn -sd.cn -sh.cn -sn.cn -sx.cn -tj.cn -tw.cn -xj.cn -xz.cn -yn.cn -zj.cn - -// co : https://www.iana.org/domains/root/db/co.html -// https://www.cointernet.com.co/como-funciona-un-dominio-restringido -// Confirmed by registry 2024-11-18 -co -com.co -edu.co -gov.co -mil.co -net.co -nom.co -org.co - -// com : https://www.iana.org/domains/root/db/com.html -com - -// coop : https://www.iana.org/domains/root/db/coop.html -coop - -// cr : https://nic.cr/capitulo-1-registro-de-un-nombre-de-dominio/ -cr -ac.cr -co.cr -ed.cr -fi.cr -go.cr -or.cr -sa.cr - -// cu : https://www.iana.org/domains/root/db/cu.html -cu -com.cu -edu.cu -gob.cu -inf.cu -nat.cu -net.cu -org.cu - -// cv : https://www.iana.org/domains/root/db/cv.html -// https://ola.cv/domain-extensions-under-cv/ -// Confirmed by registry 2024-11-26 -cv -com.cv -edu.cv -id.cv -int.cv -net.cv -nome.cv -org.cv -publ.cv - -// cw : https://www.uoc.cw/cw-registry -// Confirmed by registry 2024-11-19 -cw -com.cw -edu.cw -net.cw -org.cw - -// cx : https://www.iana.org/domains/root/db/cx.html -// list of other 2nd level tlds ? -cx -gov.cx - -// cy : http://www.nic.cy/ -// Submitted by Panayiotou Fotia -// https://nic.cy/wp-content/uploads/2024/01/Create-Request-for-domain-name-registration-1.pdf -cy -ac.cy -biz.cy -com.cy -ekloges.cy -gov.cy -ltd.cy -mil.cy -net.cy -org.cy -press.cy -pro.cy -tm.cy - -// cz : https://www.iana.org/domains/root/db/cz.html -// Confirmed by registry 2025-08-06 -cz -gov.cz - -// de : https://www.iana.org/domains/root/db/de.html -// Confirmed by registry (with technical -// reservations) 2008-07-01 -de - -// dj : https://www.iana.org/domains/root/db/dj.html -dj - -// dk : https://www.iana.org/domains/root/db/dk.html -// Confirmed by registry 2008-06-17 -dk - -// dm : https://www.iana.org/domains/root/db/dm.html -// https://nic.dm/policies/pdf/DMRulesandGuidelines2024v1.pdf -// Confirmed by registry 2024-11-19 -dm -co.dm -com.dm -edu.dm -gov.dm -net.dm -org.dm - -// do : https://www.iana.org/domains/root/db/do.html -do -art.do -com.do -edu.do -gob.do -gov.do -mil.do -net.do -org.do -sld.do -web.do - -// dz : http://www.nic.dz/images/pdf_nic/charte.pdf -dz -art.dz -asso.dz -com.dz -edu.dz -gov.dz -net.dz -org.dz -pol.dz -soc.dz -tm.dz - -// ec : https://www.nic.ec/ -// Submitted by registry -ec -abg.ec -adm.ec -agron.ec -arqt.ec -art.ec -bar.ec -chef.ec -com.ec -cont.ec -cpa.ec -cue.ec -dent.ec -dgn.ec -disco.ec -doc.ec -edu.ec -eng.ec -esm.ec -fin.ec -fot.ec -gal.ec -gob.ec -gov.ec -gye.ec -ibr.ec -info.ec -k12.ec -lat.ec -loj.ec -med.ec -mil.ec -mktg.ec -mon.ec -net.ec -ntr.ec -odont.ec -org.ec -pro.ec -prof.ec -psic.ec -psiq.ec -pub.ec -rio.ec -rrpp.ec -sal.ec -tech.ec -tul.ec -tur.ec -uio.ec -vet.ec -xxx.ec - -// edu : https://www.iana.org/domains/root/db/edu.html -edu - -// ee : https://www.internet.ee/domains/general-domains-and-procedure-for-registration-of-sub-domains-under-general-domains -ee -aip.ee -com.ee -edu.ee -fie.ee -gov.ee -lib.ee -med.ee -org.ee -pri.ee -riik.ee - -// eg : https://www.iana.org/domains/root/db/eg.html -// https://domain.eg/en/domain-rules/subdomain-names-types/ -eg -ac.eg -com.eg -edu.eg -eun.eg -gov.eg -info.eg -me.eg -mil.eg -name.eg -net.eg -org.eg -sci.eg -sport.eg -tv.eg - -// er : https://www.iana.org/domains/root/db/er.html -*.er - -// es : https://www.dominios.es/en -es -com.es -edu.es -gob.es -nom.es -org.es - -// et : https://www.iana.org/domains/root/db/et.html -et -biz.et -com.et -edu.et -gov.et -info.et -name.et -net.et -org.et - -// eu : https://www.iana.org/domains/root/db/eu.html -eu - -// fi : https://www.iana.org/domains/root/db/fi.html -fi -// aland.fi : https://www.iana.org/domains/root/db/ax.html -// This domain is being phased out in favor of .ax. As there are still many -// domains under aland.fi, we still keep it on the list until aland.fi is -// completely removed. -aland.fi - -// fj : http://domains.fj/ -// Submitted by registry 2020-02-11 -fj -ac.fj -biz.fj -com.fj -gov.fj -info.fj -mil.fj -name.fj -net.fj -org.fj -pro.fj - -// fk : https://www.iana.org/domains/root/db/fk.html -*.fk - -// fm : https://www.iana.org/domains/root/db/fm.html -fm -com.fm -edu.fm -net.fm -org.fm - -// fo : https://www.iana.org/domains/root/db/fo.html -fo - -// fr : https://www.afnic.fr/ https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -fr -asso.fr -com.fr -gouv.fr -nom.fr -prd.fr -tm.fr -// Other SLDs now selfmanaged out of AFNIC range. Former "domaines sectoriels", still registration suffixes -avoues.fr -cci.fr -greta.fr -huissier-justice.fr - -// ga : https://www.iana.org/domains/root/db/ga.html -ga - -// gb : This registry is effectively dormant -// Submitted by registry -gb - -// gd : https://www.iana.org/domains/root/db/gd.html -gd -edu.gd -gov.gd - -// ge : https://nic.ge/en/administrator/the-ge-domain-regulations -// Confirmed by registry 2024-11-20 -ge -com.ge -edu.ge -gov.ge -net.ge -org.ge -pvt.ge -school.ge - -// gf : https://www.iana.org/domains/root/db/gf.html -gf - -// gg : https://www.channelisles.net/register-1/register-direct -// Confirmed by registry 2013-11-28 -gg -co.gg -net.gg -org.gg - -// gh : https://www.iana.org/domains/root/db/gh.html -// https://www.nic.gh/ -// Although domains directly at second level are not possible at the moment, -// they have been possible for some time and may come back. -gh -biz.gh -com.gh -edu.gh -gov.gh -mil.gh -net.gh -org.gh - -// gi : http://www.nic.gi/rules.html -gi -com.gi -edu.gi -gov.gi -ltd.gi -mod.gi -org.gi - -// gl : https://www.iana.org/domains/root/db/gl.html -// http://nic.gl -gl -co.gl -com.gl -edu.gl -net.gl -org.gl - -// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm -gm - -// gn : http://psg.com/dns/gn/gn.txt -// Submitted by registry -gn -ac.gn -com.gn -edu.gn -gov.gn -net.gn -org.gn - -// gov : https://www.iana.org/domains/root/db/gov.html -gov - -// gp : http://www.nic.gp/index.php?lang=en -gp -asso.gp -com.gp -edu.gp -mobi.gp -net.gp -org.gp - -// gq : https://www.iana.org/domains/root/db/gq.html -gq - -// gr : https://www.iana.org/domains/root/db/gr.html -// Submitted by registry -gr -com.gr -edu.gr -gov.gr -net.gr -org.gr - -// gs : https://www.iana.org/domains/root/db/gs.html -gs - -// gt : https://www.gt/sitio/registration_policy.php?lang=en -gt -com.gt -edu.gt -gob.gt -ind.gt -mil.gt -net.gt -org.gt - -// gu : http://gadao.gov.gu/register.html -// University of Guam : https://www.uog.edu -// Submitted by uognoc@triton.uog.edu -gu -com.gu -edu.gu -gov.gu -guam.gu -info.gu -net.gu -org.gu -web.gu - -// gw : https://www.iana.org/domains/root/db/gw.html -// gw : https://nic.gw/regras/ -gw - -// gy : https://www.iana.org/domains/root/db/gy.html -// http://registry.gy/ -gy -co.gy -com.gy -edu.gy -gov.gy -net.gy -org.gy - -// hk : https://www.hkirc.hk -// Submitted by registry -hk -com.hk -edu.hk -gov.hk -idv.hk -net.hk -org.hk -个人.hk -個人.hk -公司.hk -政府.hk -敎育.hk -教育.hk -箇人.hk -組織.hk -組织.hk -網絡.hk -網络.hk -组織.hk -组织.hk -网絡.hk -网络.hk - -// hm : https://www.iana.org/domains/root/db/hm.html -hm - -// hn : https://www.iana.org/domains/root/db/hn.html -hn -com.hn -edu.hn -gob.hn -mil.hn -net.hn -org.hn - -// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf -hr -com.hr -from.hr -iz.hr -name.hr - -// ht : http://www.nic.ht/info/charte.cfm -ht -adult.ht -art.ht -asso.ht -com.ht -coop.ht -edu.ht -firm.ht -gouv.ht -info.ht -med.ht -net.ht -org.ht -perso.ht -pol.ht -pro.ht -rel.ht -shop.ht - -// hu : https://www.iana.org/domains/root/db/hu.html -// Confirmed by registry 2008-06-12 -hu -2000.hu -agrar.hu -bolt.hu -casino.hu -city.hu -co.hu -erotica.hu -erotika.hu -film.hu -forum.hu -games.hu -hotel.hu -info.hu -ingatlan.hu -jogasz.hu -konyvelo.hu -lakas.hu -media.hu -news.hu -org.hu -priv.hu -reklam.hu -sex.hu -shop.hu -sport.hu -suli.hu -szex.hu -tm.hu -tozsde.hu -utazas.hu -video.hu - -// id : https://www.iana.org/domains/root/db/id.html -id -ac.id -biz.id -co.id -desa.id -go.id -kop.id -mil.id -my.id -net.id -or.id -ponpes.id -sch.id -web.id - -// ie : https://www.iana.org/domains/root/db/ie.html -ie -gov.ie - -// il : http://www.isoc.org.il/domains/ -// see also: https://en.isoc.org.il/il-cctld/registration-rules -// ISOC-IL (operated by .il Registry) -il -ac.il -co.il -gov.il -idf.il -k12.il -muni.il -net.il -org.il -// xn--4dbrk0ce ("Israel", Hebrew) : IL -ישראל -// xn--4dbgdty6c.xn--4dbrk0ce. -אקדמיה.ישראל -// xn--5dbhl8d.xn--4dbrk0ce. -ישוב.ישראל -// xn--8dbq2a.xn--4dbrk0ce. -צהל.ישראל -// xn--hebda8b.xn--4dbrk0ce. -ממשל.ישראל - -// im : https://www.nic.im/ -// Submitted by registry -im -ac.im -co.im -ltd.co.im -plc.co.im -com.im -net.im -org.im -tt.im -tv.im - -// in : https://www.iana.org/domains/root/db/in.html -// see also: https://registry.in/policies -// Please note, that nic.in is not an official eTLD, but used by most -// government institutions. -in -5g.in -6g.in -ac.in -ai.in -am.in -bihar.in -biz.in -business.in -ca.in -cn.in -co.in -com.in -coop.in -cs.in -delhi.in -dr.in -edu.in -er.in -firm.in -gen.in -gov.in -gujarat.in -ind.in -info.in -int.in -internet.in -io.in -me.in -mil.in -net.in -nic.in -org.in -pg.in -post.in -pro.in -res.in -travel.in -tv.in -uk.in -up.in -us.in - -// info : https://www.iana.org/domains/root/db/info.html -info - -// int : https://www.iana.org/domains/root/db/int.html -// Confirmed by registry 2008-06-18 -int -eu.int - -// io : http://www.nic.io/rules.htm -io -co.io -com.io -edu.io -gov.io -mil.io -net.io -nom.io -org.io - -// iq : http://www.cmc.iq/english/iq/iqregister1.htm -iq -com.iq -edu.iq -gov.iq -mil.iq -net.iq -org.iq - -// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules -// Also see http://www.nic.ir/Internationalized_Domain_Names -// Two .ir entries added at request of , 2010-04-16 -ir -ac.ir -co.ir -gov.ir -id.ir -net.ir -org.ir -sch.ir -// xn--mgba3a4f16a.ir (.ir, Persian YEH) -ایران.ir -// xn--mgba3a4fra.ir (.ir, Arabic YEH) -ايران.ir - -// is : http://www.isnic.is/domain/rules.php -// Confirmed by registry 2024-11-17 -is - -// it : https://www.iana.org/domains/root/db/it.html -// https://www.nic.it/ -it -edu.it -gov.it -// Regions (3.3.1) -// https://www.nic.it/en/manage-your-it/forms-and-docs -> "Assignment and Management of domain names" -abr.it -abruzzo.it -aosta-valley.it -aostavalley.it -bas.it -basilicata.it -cal.it -calabria.it -cam.it -campania.it -emilia-romagna.it -emiliaromagna.it -emr.it -friuli-v-giulia.it -friuli-ve-giulia.it -friuli-vegiulia.it -friuli-venezia-giulia.it -friuli-veneziagiulia.it -friuli-vgiulia.it -friuliv-giulia.it -friulive-giulia.it -friulivegiulia.it -friulivenezia-giulia.it -friuliveneziagiulia.it -friulivgiulia.it -fvg.it -laz.it -lazio.it -lig.it -liguria.it -lom.it -lombardia.it -lombardy.it -lucania.it -mar.it -marche.it -mol.it -molise.it -piedmont.it -piemonte.it -pmn.it -pug.it -puglia.it -sar.it -sardegna.it -sardinia.it -sic.it -sicilia.it -sicily.it -taa.it -tos.it -toscana.it -trentin-sud-tirol.it -trentin-süd-tirol.it -trentin-sudtirol.it -trentin-südtirol.it -trentin-sued-tirol.it -trentin-suedtirol.it -trentino.it -trentino-a-adige.it -trentino-aadige.it -trentino-alto-adige.it -trentino-altoadige.it -trentino-s-tirol.it -trentino-stirol.it -trentino-sud-tirol.it -trentino-süd-tirol.it -trentino-sudtirol.it -trentino-südtirol.it -trentino-sued-tirol.it -trentino-suedtirol.it -trentinoa-adige.it -trentinoaadige.it -trentinoalto-adige.it -trentinoaltoadige.it -trentinos-tirol.it -trentinostirol.it -trentinosud-tirol.it -trentinosüd-tirol.it -trentinosudtirol.it -trentinosüdtirol.it -trentinosued-tirol.it -trentinosuedtirol.it -trentinsud-tirol.it -trentinsüd-tirol.it -trentinsudtirol.it -trentinsüdtirol.it -trentinsued-tirol.it -trentinsuedtirol.it -tuscany.it -umb.it -umbria.it -val-d-aosta.it -val-daosta.it -vald-aosta.it -valdaosta.it -valle-aosta.it -valle-d-aosta.it -valle-daosta.it -valleaosta.it -valled-aosta.it -valledaosta.it -vallee-aoste.it -vallée-aoste.it -vallee-d-aoste.it -vallée-d-aoste.it -valleeaoste.it -valléeaoste.it -valleedaoste.it -valléedaoste.it -vao.it -vda.it -ven.it -veneto.it -// Provinces (3.3.2) -ag.it -agrigento.it -al.it -alessandria.it -alto-adige.it -altoadige.it -an.it -ancona.it -andria-barletta-trani.it -andria-trani-barletta.it -andriabarlettatrani.it -andriatranibarletta.it -ao.it -aosta.it -aoste.it -ap.it -aq.it -aquila.it -ar.it -arezzo.it -ascoli-piceno.it -ascolipiceno.it -asti.it -at.it -av.it -avellino.it -ba.it -balsan.it -balsan-sudtirol.it -balsan-südtirol.it -balsan-suedtirol.it -bari.it -barletta-trani-andria.it -barlettatraniandria.it -belluno.it -benevento.it -bergamo.it -bg.it -bi.it -biella.it -bl.it -bn.it -bo.it -bologna.it -bolzano.it -bolzano-altoadige.it -bozen.it -bozen-sudtirol.it -bozen-südtirol.it -bozen-suedtirol.it -br.it -brescia.it -brindisi.it -bs.it -bt.it -bulsan.it -bulsan-sudtirol.it -bulsan-südtirol.it -bulsan-suedtirol.it -bz.it -ca.it -cagliari.it -caltanissetta.it -campidano-medio.it -campidanomedio.it -campobasso.it -carbonia-iglesias.it -carboniaiglesias.it -carrara-massa.it -carraramassa.it -caserta.it -catania.it -catanzaro.it -cb.it -ce.it -cesena-forli.it -cesena-forlì.it -cesenaforli.it -cesenaforlì.it -ch.it -chieti.it -ci.it -cl.it -cn.it -co.it -como.it -cosenza.it -cr.it -cremona.it -crotone.it -cs.it -ct.it -cuneo.it -cz.it -dell-ogliastra.it -dellogliastra.it -en.it -enna.it -fc.it -fe.it -fermo.it -ferrara.it -fg.it -fi.it -firenze.it -florence.it -fm.it -foggia.it -forli-cesena.it -forlì-cesena.it -forlicesena.it -forlìcesena.it -fr.it -frosinone.it -ge.it -genoa.it -genova.it -go.it -gorizia.it -gr.it -grosseto.it -iglesias-carbonia.it -iglesiascarbonia.it -im.it -imperia.it -is.it -isernia.it -kr.it -la-spezia.it -laquila.it -laspezia.it -latina.it -lc.it -le.it -lecce.it -lecco.it -li.it -livorno.it -lo.it -lodi.it -lt.it -lu.it -lucca.it -macerata.it -mantova.it -massa-carrara.it -massacarrara.it -matera.it -mb.it -mc.it -me.it -medio-campidano.it -mediocampidano.it -messina.it -mi.it -milan.it -milano.it -mn.it -mo.it -modena.it -monza.it -monza-brianza.it -monza-e-della-brianza.it -monzabrianza.it -monzaebrianza.it -monzaedellabrianza.it -ms.it -mt.it -na.it -naples.it -napoli.it -no.it -novara.it -nu.it -nuoro.it -og.it -ogliastra.it -olbia-tempio.it -olbiatempio.it -or.it -oristano.it -ot.it -pa.it -padova.it -padua.it -palermo.it -parma.it -pavia.it -pc.it -pd.it -pe.it -perugia.it -pesaro-urbino.it -pesarourbino.it -pescara.it -pg.it -pi.it -piacenza.it -pisa.it -pistoia.it -pn.it -po.it -pordenone.it -potenza.it -pr.it -prato.it -pt.it -pu.it -pv.it -pz.it -ra.it -ragusa.it -ravenna.it -rc.it -re.it -reggio-calabria.it -reggio-emilia.it -reggiocalabria.it -reggioemilia.it -rg.it -ri.it -rieti.it -rimini.it -rm.it -rn.it -ro.it -roma.it -rome.it -rovigo.it -sa.it -salerno.it -sassari.it -savona.it -si.it -siena.it -siracusa.it -so.it -sondrio.it -sp.it -sr.it -ss.it -südtirol.it -suedtirol.it -sv.it -ta.it -taranto.it -te.it -tempio-olbia.it -tempioolbia.it -teramo.it -terni.it -tn.it -to.it -torino.it -tp.it -tr.it -trani-andria-barletta.it -trani-barletta-andria.it -traniandriabarletta.it -tranibarlettaandria.it -trapani.it -trento.it -treviso.it -trieste.it -ts.it -turin.it -tv.it -ud.it -udine.it -urbino-pesaro.it -urbinopesaro.it -va.it -varese.it -vb.it -vc.it -ve.it -venezia.it -venice.it -verbania.it -vercelli.it -verona.it -vi.it -vibo-valentia.it -vibovalentia.it -vicenza.it -viterbo.it -vr.it -vs.it -vt.it -vv.it - -// je : https://www.iana.org/domains/root/db/je.html -// Confirmed by registry 2013-11-28 -je -co.je -net.je -org.je - -// jm : http://www.com.jm/register.html -*.jm - -// jo : https://www.dns.jo/JoFamily.aspx -// Confirmed by registry 2024-11-17 -jo -agri.jo -ai.jo -com.jo -edu.jo -eng.jo -fm.jo -gov.jo -mil.jo -net.jo -org.jo -per.jo -phd.jo -sch.jo -tv.jo - -// jobs : https://www.iana.org/domains/root/db/jobs.html -jobs - -// jp : https://www.iana.org/domains/root/db/jp.html -// http://jprs.co.jp/en/jpdomain.html -// Confirmed by registry 2024-11-22 -jp -// jp organizational type names -ac.jp -ad.jp -co.jp -ed.jp -go.jp -gr.jp -lg.jp -ne.jp -or.jp -// jp prefecture type names -aichi.jp -akita.jp -aomori.jp -chiba.jp -ehime.jp -fukui.jp -fukuoka.jp -fukushima.jp -gifu.jp -gunma.jp -hiroshima.jp -hokkaido.jp -hyogo.jp -ibaraki.jp -ishikawa.jp -iwate.jp -kagawa.jp -kagoshima.jp -kanagawa.jp -kochi.jp -kumamoto.jp -kyoto.jp -mie.jp -miyagi.jp -miyazaki.jp -nagano.jp -nagasaki.jp -nara.jp -niigata.jp -oita.jp -okayama.jp -okinawa.jp -osaka.jp -saga.jp -saitama.jp -shiga.jp -shimane.jp -shizuoka.jp -tochigi.jp -tokushima.jp -tokyo.jp -tottori.jp -toyama.jp -wakayama.jp -yamagata.jp -yamaguchi.jp -yamanashi.jp -三重.jp -京都.jp -佐賀.jp -兵庫.jp -北海道.jp -千葉.jp -和歌山.jp -埼玉.jp -大分.jp -大阪.jp -奈良.jp -宮城.jp -宮崎.jp -富山.jp -山口.jp -山形.jp -山梨.jp -岐阜.jp -岡山.jp -岩手.jp -島根.jp -広島.jp -徳島.jp -愛媛.jp -愛知.jp -新潟.jp -東京.jp -栃木.jp -沖縄.jp -滋賀.jp -熊本.jp -石川.jp -神奈川.jp -福井.jp -福岡.jp -福島.jp -秋田.jp -群馬.jp -茨城.jp -長崎.jp -長野.jp -青森.jp -静岡.jp -香川.jp -高知.jp -鳥取.jp -鹿児島.jp -// jp geographic type names -// http://jprs.jp/doc/rule/saisoku-1.html -// 2024-11-22: JPRS confirmed that jp geographic type names no longer accept new registrations. -// Once all existing registrations expire (marking full discontinuation), these suffixes -// will be removed from the PSL. -*.kawasaki.jp -!city.kawasaki.jp -*.kitakyushu.jp -!city.kitakyushu.jp -*.kobe.jp -!city.kobe.jp -*.nagoya.jp -!city.nagoya.jp -*.sapporo.jp -!city.sapporo.jp -*.sendai.jp -!city.sendai.jp -*.yokohama.jp -!city.yokohama.jp -// 4th level registration -aisai.aichi.jp -ama.aichi.jp -anjo.aichi.jp -asuke.aichi.jp -chiryu.aichi.jp -chita.aichi.jp -fuso.aichi.jp -gamagori.aichi.jp -handa.aichi.jp -hazu.aichi.jp -hekinan.aichi.jp -higashiura.aichi.jp -ichinomiya.aichi.jp -inazawa.aichi.jp -inuyama.aichi.jp -isshiki.aichi.jp -iwakura.aichi.jp -kanie.aichi.jp -kariya.aichi.jp -kasugai.aichi.jp -kira.aichi.jp -kiyosu.aichi.jp -komaki.aichi.jp -konan.aichi.jp -kota.aichi.jp -mihama.aichi.jp -miyoshi.aichi.jp -nishio.aichi.jp -nisshin.aichi.jp -obu.aichi.jp -oguchi.aichi.jp -oharu.aichi.jp -okazaki.aichi.jp -owariasahi.aichi.jp -seto.aichi.jp -shikatsu.aichi.jp -shinshiro.aichi.jp -shitara.aichi.jp -tahara.aichi.jp -takahama.aichi.jp -tobishima.aichi.jp -toei.aichi.jp -togo.aichi.jp -tokai.aichi.jp -tokoname.aichi.jp -toyoake.aichi.jp -toyohashi.aichi.jp -toyokawa.aichi.jp -toyone.aichi.jp -toyota.aichi.jp -tsushima.aichi.jp -yatomi.aichi.jp -akita.akita.jp -daisen.akita.jp -fujisato.akita.jp -gojome.akita.jp -hachirogata.akita.jp -happou.akita.jp -higashinaruse.akita.jp -honjo.akita.jp -honjyo.akita.jp -ikawa.akita.jp -kamikoani.akita.jp -kamioka.akita.jp -katagami.akita.jp -kazuno.akita.jp -kitaakita.akita.jp -kosaka.akita.jp -kyowa.akita.jp -misato.akita.jp -mitane.akita.jp -moriyoshi.akita.jp -nikaho.akita.jp -noshiro.akita.jp -odate.akita.jp -oga.akita.jp -ogata.akita.jp -semboku.akita.jp -yokote.akita.jp -yurihonjo.akita.jp -aomori.aomori.jp -gonohe.aomori.jp -hachinohe.aomori.jp -hashikami.aomori.jp -hiranai.aomori.jp -hirosaki.aomori.jp -itayanagi.aomori.jp -kuroishi.aomori.jp -misawa.aomori.jp -mutsu.aomori.jp -nakadomari.aomori.jp -noheji.aomori.jp -oirase.aomori.jp -owani.aomori.jp -rokunohe.aomori.jp -sannohe.aomori.jp -shichinohe.aomori.jp -shingo.aomori.jp -takko.aomori.jp -towada.aomori.jp -tsugaru.aomori.jp -tsuruta.aomori.jp -abiko.chiba.jp -asahi.chiba.jp -chonan.chiba.jp -chosei.chiba.jp -choshi.chiba.jp -chuo.chiba.jp -funabashi.chiba.jp -futtsu.chiba.jp -hanamigawa.chiba.jp -ichihara.chiba.jp -ichikawa.chiba.jp -ichinomiya.chiba.jp -inzai.chiba.jp -isumi.chiba.jp -kamagaya.chiba.jp -kamogawa.chiba.jp -kashiwa.chiba.jp -katori.chiba.jp -katsuura.chiba.jp -kimitsu.chiba.jp -kisarazu.chiba.jp -kozaki.chiba.jp -kujukuri.chiba.jp -kyonan.chiba.jp -matsudo.chiba.jp -midori.chiba.jp -mihama.chiba.jp -minamiboso.chiba.jp -mobara.chiba.jp -mutsuzawa.chiba.jp -nagara.chiba.jp -nagareyama.chiba.jp -narashino.chiba.jp -narita.chiba.jp -noda.chiba.jp -oamishirasato.chiba.jp -omigawa.chiba.jp -onjuku.chiba.jp -otaki.chiba.jp -sakae.chiba.jp -sakura.chiba.jp -shimofusa.chiba.jp -shirako.chiba.jp -shiroi.chiba.jp -shisui.chiba.jp -sodegaura.chiba.jp -sosa.chiba.jp -tako.chiba.jp -tateyama.chiba.jp -togane.chiba.jp -tohnosho.chiba.jp -tomisato.chiba.jp -urayasu.chiba.jp -yachimata.chiba.jp -yachiyo.chiba.jp -yokaichiba.chiba.jp -yokoshibahikari.chiba.jp -yotsukaido.chiba.jp -ainan.ehime.jp -honai.ehime.jp -ikata.ehime.jp -imabari.ehime.jp -iyo.ehime.jp -kamijima.ehime.jp -kihoku.ehime.jp -kumakogen.ehime.jp -masaki.ehime.jp -matsuno.ehime.jp -matsuyama.ehime.jp -namikata.ehime.jp -niihama.ehime.jp -ozu.ehime.jp -saijo.ehime.jp -seiyo.ehime.jp -shikokuchuo.ehime.jp -tobe.ehime.jp -toon.ehime.jp -uchiko.ehime.jp -uwajima.ehime.jp -yawatahama.ehime.jp -echizen.fukui.jp -eiheiji.fukui.jp -fukui.fukui.jp -ikeda.fukui.jp -katsuyama.fukui.jp -mihama.fukui.jp -minamiechizen.fukui.jp -obama.fukui.jp -ohi.fukui.jp -ono.fukui.jp -sabae.fukui.jp -sakai.fukui.jp -takahama.fukui.jp -tsuruga.fukui.jp -wakasa.fukui.jp -ashiya.fukuoka.jp -buzen.fukuoka.jp -chikugo.fukuoka.jp -chikuho.fukuoka.jp -chikujo.fukuoka.jp -chikushino.fukuoka.jp -chikuzen.fukuoka.jp -chuo.fukuoka.jp -dazaifu.fukuoka.jp -fukuchi.fukuoka.jp -hakata.fukuoka.jp -higashi.fukuoka.jp -hirokawa.fukuoka.jp -hisayama.fukuoka.jp -iizuka.fukuoka.jp -inatsuki.fukuoka.jp -kaho.fukuoka.jp -kasuga.fukuoka.jp -kasuya.fukuoka.jp -kawara.fukuoka.jp -keisen.fukuoka.jp -koga.fukuoka.jp -kurate.fukuoka.jp -kurogi.fukuoka.jp -kurume.fukuoka.jp -minami.fukuoka.jp -miyako.fukuoka.jp -miyama.fukuoka.jp -miyawaka.fukuoka.jp -mizumaki.fukuoka.jp -munakata.fukuoka.jp -nakagawa.fukuoka.jp -nakama.fukuoka.jp -nishi.fukuoka.jp -nogata.fukuoka.jp -ogori.fukuoka.jp -okagaki.fukuoka.jp -okawa.fukuoka.jp -oki.fukuoka.jp -omuta.fukuoka.jp -onga.fukuoka.jp -onojo.fukuoka.jp -oto.fukuoka.jp -saigawa.fukuoka.jp -sasaguri.fukuoka.jp -shingu.fukuoka.jp -shinyoshitomi.fukuoka.jp -shonai.fukuoka.jp -soeda.fukuoka.jp -sue.fukuoka.jp -tachiarai.fukuoka.jp -tagawa.fukuoka.jp -takata.fukuoka.jp -toho.fukuoka.jp -toyotsu.fukuoka.jp -tsuiki.fukuoka.jp -ukiha.fukuoka.jp -umi.fukuoka.jp -usui.fukuoka.jp -yamada.fukuoka.jp -yame.fukuoka.jp -yanagawa.fukuoka.jp -yukuhashi.fukuoka.jp -aizubange.fukushima.jp -aizumisato.fukushima.jp -aizuwakamatsu.fukushima.jp -asakawa.fukushima.jp -bandai.fukushima.jp -date.fukushima.jp -fukushima.fukushima.jp -furudono.fukushima.jp -futaba.fukushima.jp -hanawa.fukushima.jp -higashi.fukushima.jp -hirata.fukushima.jp -hirono.fukushima.jp -iitate.fukushima.jp -inawashiro.fukushima.jp -ishikawa.fukushima.jp -iwaki.fukushima.jp -izumizaki.fukushima.jp -kagamiishi.fukushima.jp -kaneyama.fukushima.jp -kawamata.fukushima.jp -kitakata.fukushima.jp -kitashiobara.fukushima.jp -koori.fukushima.jp -koriyama.fukushima.jp -kunimi.fukushima.jp -miharu.fukushima.jp -mishima.fukushima.jp -namie.fukushima.jp -nango.fukushima.jp -nishiaizu.fukushima.jp -nishigo.fukushima.jp -okuma.fukushima.jp -omotego.fukushima.jp -ono.fukushima.jp -otama.fukushima.jp -samegawa.fukushima.jp -shimogo.fukushima.jp -shirakawa.fukushima.jp -showa.fukushima.jp -soma.fukushima.jp -sukagawa.fukushima.jp -taishin.fukushima.jp -tamakawa.fukushima.jp -tanagura.fukushima.jp -tenei.fukushima.jp -yabuki.fukushima.jp -yamato.fukushima.jp -yamatsuri.fukushima.jp -yanaizu.fukushima.jp -yugawa.fukushima.jp -anpachi.gifu.jp -ena.gifu.jp -gifu.gifu.jp -ginan.gifu.jp -godo.gifu.jp -gujo.gifu.jp -hashima.gifu.jp -hichiso.gifu.jp -hida.gifu.jp -higashishirakawa.gifu.jp -ibigawa.gifu.jp -ikeda.gifu.jp -kakamigahara.gifu.jp -kani.gifu.jp -kasahara.gifu.jp -kasamatsu.gifu.jp -kawaue.gifu.jp -kitagata.gifu.jp -mino.gifu.jp -minokamo.gifu.jp -mitake.gifu.jp -mizunami.gifu.jp -motosu.gifu.jp -nakatsugawa.gifu.jp -ogaki.gifu.jp -sakahogi.gifu.jp -seki.gifu.jp -sekigahara.gifu.jp -shirakawa.gifu.jp -tajimi.gifu.jp -takayama.gifu.jp -tarui.gifu.jp -toki.gifu.jp -tomika.gifu.jp -wanouchi.gifu.jp -yamagata.gifu.jp -yaotsu.gifu.jp -yoro.gifu.jp -annaka.gunma.jp -chiyoda.gunma.jp -fujioka.gunma.jp -higashiagatsuma.gunma.jp -isesaki.gunma.jp -itakura.gunma.jp -kanna.gunma.jp -kanra.gunma.jp -katashina.gunma.jp -kawaba.gunma.jp -kiryu.gunma.jp -kusatsu.gunma.jp -maebashi.gunma.jp -meiwa.gunma.jp -midori.gunma.jp -minakami.gunma.jp -naganohara.gunma.jp -nakanojo.gunma.jp -nanmoku.gunma.jp -numata.gunma.jp -oizumi.gunma.jp -ora.gunma.jp -ota.gunma.jp -shibukawa.gunma.jp -shimonita.gunma.jp -shinto.gunma.jp -showa.gunma.jp -takasaki.gunma.jp -takayama.gunma.jp -tamamura.gunma.jp -tatebayashi.gunma.jp -tomioka.gunma.jp -tsukiyono.gunma.jp -tsumagoi.gunma.jp -ueno.gunma.jp -yoshioka.gunma.jp -asaminami.hiroshima.jp -daiwa.hiroshima.jp -etajima.hiroshima.jp -fuchu.hiroshima.jp -fukuyama.hiroshima.jp -hatsukaichi.hiroshima.jp -higashihiroshima.hiroshima.jp -hongo.hiroshima.jp -jinsekikogen.hiroshima.jp -kaita.hiroshima.jp -kui.hiroshima.jp -kumano.hiroshima.jp -kure.hiroshima.jp -mihara.hiroshima.jp -miyoshi.hiroshima.jp -naka.hiroshima.jp -onomichi.hiroshima.jp -osakikamijima.hiroshima.jp -otake.hiroshima.jp -saka.hiroshima.jp -sera.hiroshima.jp -seranishi.hiroshima.jp -shinichi.hiroshima.jp -shobara.hiroshima.jp -takehara.hiroshima.jp -abashiri.hokkaido.jp -abira.hokkaido.jp -aibetsu.hokkaido.jp -akabira.hokkaido.jp -akkeshi.hokkaido.jp -asahikawa.hokkaido.jp -ashibetsu.hokkaido.jp -ashoro.hokkaido.jp -assabu.hokkaido.jp -atsuma.hokkaido.jp -bibai.hokkaido.jp -biei.hokkaido.jp -bifuka.hokkaido.jp -bihoro.hokkaido.jp -biratori.hokkaido.jp -chippubetsu.hokkaido.jp -chitose.hokkaido.jp -date.hokkaido.jp -ebetsu.hokkaido.jp -embetsu.hokkaido.jp -eniwa.hokkaido.jp -erimo.hokkaido.jp -esan.hokkaido.jp -esashi.hokkaido.jp -fukagawa.hokkaido.jp -fukushima.hokkaido.jp -furano.hokkaido.jp -furubira.hokkaido.jp -haboro.hokkaido.jp -hakodate.hokkaido.jp -hamatonbetsu.hokkaido.jp -hidaka.hokkaido.jp -higashikagura.hokkaido.jp -higashikawa.hokkaido.jp -hiroo.hokkaido.jp -hokuryu.hokkaido.jp -hokuto.hokkaido.jp -honbetsu.hokkaido.jp -horokanai.hokkaido.jp -horonobe.hokkaido.jp -ikeda.hokkaido.jp -imakane.hokkaido.jp -ishikari.hokkaido.jp -iwamizawa.hokkaido.jp -iwanai.hokkaido.jp -kamifurano.hokkaido.jp -kamikawa.hokkaido.jp -kamishihoro.hokkaido.jp -kamisunagawa.hokkaido.jp -kamoenai.hokkaido.jp -kayabe.hokkaido.jp -kembuchi.hokkaido.jp -kikonai.hokkaido.jp -kimobetsu.hokkaido.jp -kitahiroshima.hokkaido.jp -kitami.hokkaido.jp -kiyosato.hokkaido.jp -koshimizu.hokkaido.jp -kunneppu.hokkaido.jp -kuriyama.hokkaido.jp -kuromatsunai.hokkaido.jp -kushiro.hokkaido.jp -kutchan.hokkaido.jp -kyowa.hokkaido.jp -mashike.hokkaido.jp -matsumae.hokkaido.jp -mikasa.hokkaido.jp -minamifurano.hokkaido.jp -mombetsu.hokkaido.jp -moseushi.hokkaido.jp -mukawa.hokkaido.jp -muroran.hokkaido.jp -naie.hokkaido.jp -nakagawa.hokkaido.jp -nakasatsunai.hokkaido.jp -nakatombetsu.hokkaido.jp -nanae.hokkaido.jp -nanporo.hokkaido.jp -nayoro.hokkaido.jp -nemuro.hokkaido.jp -niikappu.hokkaido.jp -niki.hokkaido.jp -nishiokoppe.hokkaido.jp -noboribetsu.hokkaido.jp -numata.hokkaido.jp -obihiro.hokkaido.jp -obira.hokkaido.jp -oketo.hokkaido.jp -okoppe.hokkaido.jp -otaru.hokkaido.jp -otobe.hokkaido.jp -otofuke.hokkaido.jp -otoineppu.hokkaido.jp -oumu.hokkaido.jp -ozora.hokkaido.jp -pippu.hokkaido.jp -rankoshi.hokkaido.jp -rebun.hokkaido.jp -rikubetsu.hokkaido.jp -rishiri.hokkaido.jp -rishirifuji.hokkaido.jp -saroma.hokkaido.jp -sarufutsu.hokkaido.jp -shakotan.hokkaido.jp -shari.hokkaido.jp -shibecha.hokkaido.jp -shibetsu.hokkaido.jp -shikabe.hokkaido.jp -shikaoi.hokkaido.jp -shimamaki.hokkaido.jp -shimizu.hokkaido.jp -shimokawa.hokkaido.jp -shinshinotsu.hokkaido.jp -shintoku.hokkaido.jp -shiranuka.hokkaido.jp -shiraoi.hokkaido.jp -shiriuchi.hokkaido.jp -sobetsu.hokkaido.jp -sunagawa.hokkaido.jp -taiki.hokkaido.jp -takasu.hokkaido.jp -takikawa.hokkaido.jp -takinoue.hokkaido.jp -teshikaga.hokkaido.jp -tobetsu.hokkaido.jp -tohma.hokkaido.jp -tomakomai.hokkaido.jp -tomari.hokkaido.jp -toya.hokkaido.jp -toyako.hokkaido.jp -toyotomi.hokkaido.jp -toyoura.hokkaido.jp -tsubetsu.hokkaido.jp -tsukigata.hokkaido.jp -urakawa.hokkaido.jp -urausu.hokkaido.jp -uryu.hokkaido.jp -utashinai.hokkaido.jp -wakkanai.hokkaido.jp -wassamu.hokkaido.jp -yakumo.hokkaido.jp -yoichi.hokkaido.jp -aioi.hyogo.jp -akashi.hyogo.jp -ako.hyogo.jp -amagasaki.hyogo.jp -aogaki.hyogo.jp -asago.hyogo.jp -ashiya.hyogo.jp -awaji.hyogo.jp -fukusaki.hyogo.jp -goshiki.hyogo.jp -harima.hyogo.jp -himeji.hyogo.jp -ichikawa.hyogo.jp -inagawa.hyogo.jp -itami.hyogo.jp -kakogawa.hyogo.jp -kamigori.hyogo.jp -kamikawa.hyogo.jp -kasai.hyogo.jp -kasuga.hyogo.jp -kawanishi.hyogo.jp -miki.hyogo.jp -minamiawaji.hyogo.jp -nishinomiya.hyogo.jp -nishiwaki.hyogo.jp -ono.hyogo.jp -sanda.hyogo.jp -sannan.hyogo.jp -sasayama.hyogo.jp -sayo.hyogo.jp -shingu.hyogo.jp -shinonsen.hyogo.jp -shiso.hyogo.jp -sumoto.hyogo.jp -taishi.hyogo.jp -taka.hyogo.jp -takarazuka.hyogo.jp -takasago.hyogo.jp -takino.hyogo.jp -tamba.hyogo.jp -tatsuno.hyogo.jp -toyooka.hyogo.jp -yabu.hyogo.jp -yashiro.hyogo.jp -yoka.hyogo.jp -yokawa.hyogo.jp -ami.ibaraki.jp -asahi.ibaraki.jp -bando.ibaraki.jp -chikusei.ibaraki.jp -daigo.ibaraki.jp -fujishiro.ibaraki.jp -hitachi.ibaraki.jp -hitachinaka.ibaraki.jp -hitachiomiya.ibaraki.jp -hitachiota.ibaraki.jp -ibaraki.ibaraki.jp -ina.ibaraki.jp -inashiki.ibaraki.jp -itako.ibaraki.jp -iwama.ibaraki.jp -joso.ibaraki.jp -kamisu.ibaraki.jp -kasama.ibaraki.jp -kashima.ibaraki.jp -kasumigaura.ibaraki.jp -koga.ibaraki.jp -miho.ibaraki.jp -mito.ibaraki.jp -moriya.ibaraki.jp -naka.ibaraki.jp -namegata.ibaraki.jp -oarai.ibaraki.jp -ogawa.ibaraki.jp -omitama.ibaraki.jp -ryugasaki.ibaraki.jp -sakai.ibaraki.jp -sakuragawa.ibaraki.jp -shimodate.ibaraki.jp -shimotsuma.ibaraki.jp -shirosato.ibaraki.jp -sowa.ibaraki.jp -suifu.ibaraki.jp -takahagi.ibaraki.jp -tamatsukuri.ibaraki.jp -tokai.ibaraki.jp -tomobe.ibaraki.jp -tone.ibaraki.jp -toride.ibaraki.jp -tsuchiura.ibaraki.jp -tsukuba.ibaraki.jp -uchihara.ibaraki.jp -ushiku.ibaraki.jp -yachiyo.ibaraki.jp -yamagata.ibaraki.jp -yawara.ibaraki.jp -yuki.ibaraki.jp -anamizu.ishikawa.jp -hakui.ishikawa.jp -hakusan.ishikawa.jp -kaga.ishikawa.jp -kahoku.ishikawa.jp -kanazawa.ishikawa.jp -kawakita.ishikawa.jp -komatsu.ishikawa.jp -nakanoto.ishikawa.jp -nanao.ishikawa.jp -nomi.ishikawa.jp -nonoichi.ishikawa.jp -noto.ishikawa.jp -shika.ishikawa.jp -suzu.ishikawa.jp -tsubata.ishikawa.jp -tsurugi.ishikawa.jp -uchinada.ishikawa.jp -wajima.ishikawa.jp -fudai.iwate.jp -fujisawa.iwate.jp -hanamaki.iwate.jp -hiraizumi.iwate.jp -hirono.iwate.jp -ichinohe.iwate.jp -ichinoseki.iwate.jp -iwaizumi.iwate.jp -iwate.iwate.jp -joboji.iwate.jp -kamaishi.iwate.jp -kanegasaki.iwate.jp -karumai.iwate.jp -kawai.iwate.jp -kitakami.iwate.jp -kuji.iwate.jp -kunohe.iwate.jp -kuzumaki.iwate.jp -miyako.iwate.jp -mizusawa.iwate.jp -morioka.iwate.jp -ninohe.iwate.jp -noda.iwate.jp -ofunato.iwate.jp -oshu.iwate.jp -otsuchi.iwate.jp -rikuzentakata.iwate.jp -shiwa.iwate.jp -shizukuishi.iwate.jp -sumita.iwate.jp -tanohata.iwate.jp -tono.iwate.jp -yahaba.iwate.jp -yamada.iwate.jp -ayagawa.kagawa.jp -higashikagawa.kagawa.jp -kanonji.kagawa.jp -kotohira.kagawa.jp -manno.kagawa.jp -marugame.kagawa.jp -mitoyo.kagawa.jp -naoshima.kagawa.jp -sanuki.kagawa.jp -tadotsu.kagawa.jp -takamatsu.kagawa.jp -tonosho.kagawa.jp -uchinomi.kagawa.jp -utazu.kagawa.jp -zentsuji.kagawa.jp -akune.kagoshima.jp -amami.kagoshima.jp -hioki.kagoshima.jp -isa.kagoshima.jp -isen.kagoshima.jp -izumi.kagoshima.jp -kagoshima.kagoshima.jp -kanoya.kagoshima.jp -kawanabe.kagoshima.jp -kinko.kagoshima.jp -kouyama.kagoshima.jp -makurazaki.kagoshima.jp -matsumoto.kagoshima.jp -minamitane.kagoshima.jp -nakatane.kagoshima.jp -nishinoomote.kagoshima.jp -satsumasendai.kagoshima.jp -soo.kagoshima.jp -tarumizu.kagoshima.jp -yusui.kagoshima.jp -aikawa.kanagawa.jp -atsugi.kanagawa.jp -ayase.kanagawa.jp -chigasaki.kanagawa.jp -ebina.kanagawa.jp -fujisawa.kanagawa.jp -hadano.kanagawa.jp -hakone.kanagawa.jp -hiratsuka.kanagawa.jp -isehara.kanagawa.jp -kaisei.kanagawa.jp -kamakura.kanagawa.jp -kiyokawa.kanagawa.jp -matsuda.kanagawa.jp -minamiashigara.kanagawa.jp -miura.kanagawa.jp -nakai.kanagawa.jp -ninomiya.kanagawa.jp -odawara.kanagawa.jp -oi.kanagawa.jp -oiso.kanagawa.jp -sagamihara.kanagawa.jp -samukawa.kanagawa.jp -tsukui.kanagawa.jp -yamakita.kanagawa.jp -yamato.kanagawa.jp -yokosuka.kanagawa.jp -yugawara.kanagawa.jp -zama.kanagawa.jp -zushi.kanagawa.jp -aki.kochi.jp -geisei.kochi.jp -hidaka.kochi.jp -higashitsuno.kochi.jp -ino.kochi.jp -kagami.kochi.jp -kami.kochi.jp -kitagawa.kochi.jp -kochi.kochi.jp -mihara.kochi.jp -motoyama.kochi.jp -muroto.kochi.jp -nahari.kochi.jp -nakamura.kochi.jp -nankoku.kochi.jp -nishitosa.kochi.jp -niyodogawa.kochi.jp -ochi.kochi.jp -okawa.kochi.jp -otoyo.kochi.jp -otsuki.kochi.jp -sakawa.kochi.jp -sukumo.kochi.jp -susaki.kochi.jp -tosa.kochi.jp -tosashimizu.kochi.jp -toyo.kochi.jp -tsuno.kochi.jp -umaji.kochi.jp -yasuda.kochi.jp -yusuhara.kochi.jp -amakusa.kumamoto.jp -arao.kumamoto.jp -aso.kumamoto.jp -choyo.kumamoto.jp -gyokuto.kumamoto.jp -kamiamakusa.kumamoto.jp -kikuchi.kumamoto.jp -kumamoto.kumamoto.jp -mashiki.kumamoto.jp -mifune.kumamoto.jp -minamata.kumamoto.jp -minamioguni.kumamoto.jp -nagasu.kumamoto.jp -nishihara.kumamoto.jp -oguni.kumamoto.jp -ozu.kumamoto.jp -sumoto.kumamoto.jp -takamori.kumamoto.jp -uki.kumamoto.jp -uto.kumamoto.jp -yamaga.kumamoto.jp -yamato.kumamoto.jp -yatsushiro.kumamoto.jp -ayabe.kyoto.jp -fukuchiyama.kyoto.jp -higashiyama.kyoto.jp -ide.kyoto.jp -ine.kyoto.jp -joyo.kyoto.jp -kameoka.kyoto.jp -kamo.kyoto.jp -kita.kyoto.jp -kizu.kyoto.jp -kumiyama.kyoto.jp -kyotamba.kyoto.jp -kyotanabe.kyoto.jp -kyotango.kyoto.jp -maizuru.kyoto.jp -minami.kyoto.jp -minamiyamashiro.kyoto.jp -miyazu.kyoto.jp -muko.kyoto.jp -nagaokakyo.kyoto.jp -nakagyo.kyoto.jp -nantan.kyoto.jp -oyamazaki.kyoto.jp -sakyo.kyoto.jp -seika.kyoto.jp -tanabe.kyoto.jp -uji.kyoto.jp -ujitawara.kyoto.jp -wazuka.kyoto.jp -yamashina.kyoto.jp -yawata.kyoto.jp -asahi.mie.jp -inabe.mie.jp -ise.mie.jp -kameyama.mie.jp -kawagoe.mie.jp -kiho.mie.jp -kisosaki.mie.jp -kiwa.mie.jp -komono.mie.jp -kumano.mie.jp -kuwana.mie.jp -matsusaka.mie.jp -meiwa.mie.jp -mihama.mie.jp -minamiise.mie.jp -misugi.mie.jp -miyama.mie.jp -nabari.mie.jp -shima.mie.jp -suzuka.mie.jp -tado.mie.jp -taiki.mie.jp -taki.mie.jp -tamaki.mie.jp -toba.mie.jp -tsu.mie.jp -udono.mie.jp -ureshino.mie.jp -watarai.mie.jp -yokkaichi.mie.jp -furukawa.miyagi.jp -higashimatsushima.miyagi.jp -ishinomaki.miyagi.jp -iwanuma.miyagi.jp -kakuda.miyagi.jp -kami.miyagi.jp -kawasaki.miyagi.jp -marumori.miyagi.jp -matsushima.miyagi.jp -minamisanriku.miyagi.jp -misato.miyagi.jp -murata.miyagi.jp -natori.miyagi.jp -ogawara.miyagi.jp -ohira.miyagi.jp -onagawa.miyagi.jp -osaki.miyagi.jp -rifu.miyagi.jp -semine.miyagi.jp -shibata.miyagi.jp -shichikashuku.miyagi.jp -shikama.miyagi.jp -shiogama.miyagi.jp -shiroishi.miyagi.jp -tagajo.miyagi.jp -taiwa.miyagi.jp -tome.miyagi.jp -tomiya.miyagi.jp -wakuya.miyagi.jp -watari.miyagi.jp -yamamoto.miyagi.jp -zao.miyagi.jp -aya.miyazaki.jp -ebino.miyazaki.jp -gokase.miyazaki.jp -hyuga.miyazaki.jp -kadogawa.miyazaki.jp -kawaminami.miyazaki.jp -kijo.miyazaki.jp -kitagawa.miyazaki.jp -kitakata.miyazaki.jp -kitaura.miyazaki.jp -kobayashi.miyazaki.jp -kunitomi.miyazaki.jp -kushima.miyazaki.jp -mimata.miyazaki.jp -miyakonojo.miyazaki.jp -miyazaki.miyazaki.jp -morotsuka.miyazaki.jp -nichinan.miyazaki.jp -nishimera.miyazaki.jp -nobeoka.miyazaki.jp -saito.miyazaki.jp -shiiba.miyazaki.jp -shintomi.miyazaki.jp -takaharu.miyazaki.jp -takanabe.miyazaki.jp -takazaki.miyazaki.jp -tsuno.miyazaki.jp -achi.nagano.jp -agematsu.nagano.jp -anan.nagano.jp -aoki.nagano.jp -asahi.nagano.jp -azumino.nagano.jp -chikuhoku.nagano.jp -chikuma.nagano.jp -chino.nagano.jp -fujimi.nagano.jp -hakuba.nagano.jp -hara.nagano.jp -hiraya.nagano.jp -iida.nagano.jp -iijima.nagano.jp -iiyama.nagano.jp -iizuna.nagano.jp -ikeda.nagano.jp -ikusaka.nagano.jp -ina.nagano.jp -karuizawa.nagano.jp -kawakami.nagano.jp -kiso.nagano.jp -kisofukushima.nagano.jp -kitaaiki.nagano.jp -komagane.nagano.jp -komoro.nagano.jp -matsukawa.nagano.jp -matsumoto.nagano.jp -miasa.nagano.jp -minamiaiki.nagano.jp -minamimaki.nagano.jp -minamiminowa.nagano.jp -minowa.nagano.jp -miyada.nagano.jp -miyota.nagano.jp -mochizuki.nagano.jp -nagano.nagano.jp -nagawa.nagano.jp -nagiso.nagano.jp -nakagawa.nagano.jp -nakano.nagano.jp -nozawaonsen.nagano.jp -obuse.nagano.jp -ogawa.nagano.jp -okaya.nagano.jp -omachi.nagano.jp -omi.nagano.jp -ookuwa.nagano.jp -ooshika.nagano.jp -otaki.nagano.jp -otari.nagano.jp -sakae.nagano.jp -sakaki.nagano.jp -saku.nagano.jp -sakuho.nagano.jp -shimosuwa.nagano.jp -shinanomachi.nagano.jp -shiojiri.nagano.jp -suwa.nagano.jp -suzaka.nagano.jp -takagi.nagano.jp -takamori.nagano.jp -takayama.nagano.jp -tateshina.nagano.jp -tatsuno.nagano.jp -togakushi.nagano.jp -togura.nagano.jp -tomi.nagano.jp -ueda.nagano.jp -wada.nagano.jp -yamagata.nagano.jp -yamanouchi.nagano.jp -yasaka.nagano.jp -yasuoka.nagano.jp -chijiwa.nagasaki.jp -futsu.nagasaki.jp -goto.nagasaki.jp -hasami.nagasaki.jp -hirado.nagasaki.jp -iki.nagasaki.jp -isahaya.nagasaki.jp -kawatana.nagasaki.jp -kuchinotsu.nagasaki.jp -matsuura.nagasaki.jp -nagasaki.nagasaki.jp -obama.nagasaki.jp -omura.nagasaki.jp -oseto.nagasaki.jp -saikai.nagasaki.jp -sasebo.nagasaki.jp -seihi.nagasaki.jp -shimabara.nagasaki.jp -shinkamigoto.nagasaki.jp -togitsu.nagasaki.jp -tsushima.nagasaki.jp -unzen.nagasaki.jp -ando.nara.jp -gose.nara.jp -heguri.nara.jp -higashiyoshino.nara.jp -ikaruga.nara.jp -ikoma.nara.jp -kamikitayama.nara.jp -kanmaki.nara.jp -kashiba.nara.jp -kashihara.nara.jp -katsuragi.nara.jp -kawai.nara.jp -kawakami.nara.jp -kawanishi.nara.jp -koryo.nara.jp -kurotaki.nara.jp -mitsue.nara.jp -miyake.nara.jp -nara.nara.jp -nosegawa.nara.jp -oji.nara.jp -ouda.nara.jp -oyodo.nara.jp -sakurai.nara.jp -sango.nara.jp -shimoichi.nara.jp -shimokitayama.nara.jp -shinjo.nara.jp -soni.nara.jp -takatori.nara.jp -tawaramoto.nara.jp -tenkawa.nara.jp -tenri.nara.jp -uda.nara.jp -yamatokoriyama.nara.jp -yamatotakada.nara.jp -yamazoe.nara.jp -yoshino.nara.jp -aga.niigata.jp -agano.niigata.jp -gosen.niigata.jp -itoigawa.niigata.jp -izumozaki.niigata.jp -joetsu.niigata.jp -kamo.niigata.jp -kariwa.niigata.jp -kashiwazaki.niigata.jp -minamiuonuma.niigata.jp -mitsuke.niigata.jp -muika.niigata.jp -murakami.niigata.jp -myoko.niigata.jp -nagaoka.niigata.jp -niigata.niigata.jp -ojiya.niigata.jp -omi.niigata.jp -sado.niigata.jp -sanjo.niigata.jp -seiro.niigata.jp -seirou.niigata.jp -sekikawa.niigata.jp -shibata.niigata.jp -tagami.niigata.jp -tainai.niigata.jp -tochio.niigata.jp -tokamachi.niigata.jp -tsubame.niigata.jp -tsunan.niigata.jp -uonuma.niigata.jp -yahiko.niigata.jp -yoita.niigata.jp -yuzawa.niigata.jp -beppu.oita.jp -bungoono.oita.jp -bungotakada.oita.jp -hasama.oita.jp -hiji.oita.jp -himeshima.oita.jp -hita.oita.jp -kamitsue.oita.jp -kokonoe.oita.jp -kuju.oita.jp -kunisaki.oita.jp -kusu.oita.jp -oita.oita.jp -saiki.oita.jp -taketa.oita.jp -tsukumi.oita.jp -usa.oita.jp -usuki.oita.jp -yufu.oita.jp -akaiwa.okayama.jp -asakuchi.okayama.jp -bizen.okayama.jp -hayashima.okayama.jp -ibara.okayama.jp -kagamino.okayama.jp -kasaoka.okayama.jp -kibichuo.okayama.jp -kumenan.okayama.jp -kurashiki.okayama.jp -maniwa.okayama.jp -misaki.okayama.jp -nagi.okayama.jp -niimi.okayama.jp -nishiawakura.okayama.jp -okayama.okayama.jp -satosho.okayama.jp -setouchi.okayama.jp -shinjo.okayama.jp -shoo.okayama.jp -soja.okayama.jp -takahashi.okayama.jp -tamano.okayama.jp -tsuyama.okayama.jp -wake.okayama.jp -yakage.okayama.jp -aguni.okinawa.jp -ginowan.okinawa.jp -ginoza.okinawa.jp -gushikami.okinawa.jp -haebaru.okinawa.jp -higashi.okinawa.jp -hirara.okinawa.jp -iheya.okinawa.jp -ishigaki.okinawa.jp -ishikawa.okinawa.jp -itoman.okinawa.jp -izena.okinawa.jp -kadena.okinawa.jp -kin.okinawa.jp -kitadaito.okinawa.jp -kitanakagusuku.okinawa.jp -kumejima.okinawa.jp -kunigami.okinawa.jp -minamidaito.okinawa.jp -motobu.okinawa.jp -nago.okinawa.jp -naha.okinawa.jp -nakagusuku.okinawa.jp -nakijin.okinawa.jp -nanjo.okinawa.jp -nishihara.okinawa.jp -ogimi.okinawa.jp -okinawa.okinawa.jp -onna.okinawa.jp -shimoji.okinawa.jp -taketomi.okinawa.jp -tarama.okinawa.jp -tokashiki.okinawa.jp -tomigusuku.okinawa.jp -tonaki.okinawa.jp -urasoe.okinawa.jp -uruma.okinawa.jp -yaese.okinawa.jp -yomitan.okinawa.jp -yonabaru.okinawa.jp -yonaguni.okinawa.jp -zamami.okinawa.jp -abeno.osaka.jp -chihayaakasaka.osaka.jp -chuo.osaka.jp -daito.osaka.jp -fujiidera.osaka.jp -habikino.osaka.jp -hannan.osaka.jp -higashiosaka.osaka.jp -higashisumiyoshi.osaka.jp -higashiyodogawa.osaka.jp -hirakata.osaka.jp -ibaraki.osaka.jp -ikeda.osaka.jp -izumi.osaka.jp -izumiotsu.osaka.jp -izumisano.osaka.jp -kadoma.osaka.jp -kaizuka.osaka.jp -kanan.osaka.jp -kashiwara.osaka.jp -katano.osaka.jp -kawachinagano.osaka.jp -kishiwada.osaka.jp -kita.osaka.jp -kumatori.osaka.jp -matsubara.osaka.jp -minato.osaka.jp -minoh.osaka.jp -misaki.osaka.jp -moriguchi.osaka.jp -neyagawa.osaka.jp -nishi.osaka.jp -nose.osaka.jp -osakasayama.osaka.jp -sakai.osaka.jp -sayama.osaka.jp -sennan.osaka.jp -settsu.osaka.jp -shijonawate.osaka.jp -shimamoto.osaka.jp -suita.osaka.jp -tadaoka.osaka.jp -taishi.osaka.jp -tajiri.osaka.jp -takaishi.osaka.jp -takatsuki.osaka.jp -tondabayashi.osaka.jp -toyonaka.osaka.jp -toyono.osaka.jp -yao.osaka.jp -ariake.saga.jp -arita.saga.jp -fukudomi.saga.jp -genkai.saga.jp -hamatama.saga.jp -hizen.saga.jp -imari.saga.jp -kamimine.saga.jp -kanzaki.saga.jp -karatsu.saga.jp -kashima.saga.jp -kitagata.saga.jp -kitahata.saga.jp -kiyama.saga.jp -kouhoku.saga.jp -kyuragi.saga.jp -nishiarita.saga.jp -ogi.saga.jp -omachi.saga.jp -ouchi.saga.jp -saga.saga.jp -shiroishi.saga.jp -taku.saga.jp -tara.saga.jp -tosu.saga.jp -yoshinogari.saga.jp -arakawa.saitama.jp -asaka.saitama.jp -chichibu.saitama.jp -fujimi.saitama.jp -fujimino.saitama.jp -fukaya.saitama.jp -hanno.saitama.jp -hanyu.saitama.jp -hasuda.saitama.jp -hatogaya.saitama.jp -hatoyama.saitama.jp -hidaka.saitama.jp -higashichichibu.saitama.jp -higashimatsuyama.saitama.jp -honjo.saitama.jp -ina.saitama.jp -iruma.saitama.jp -iwatsuki.saitama.jp -kamiizumi.saitama.jp -kamikawa.saitama.jp -kamisato.saitama.jp -kasukabe.saitama.jp -kawagoe.saitama.jp -kawaguchi.saitama.jp -kawajima.saitama.jp -kazo.saitama.jp -kitamoto.saitama.jp -koshigaya.saitama.jp -kounosu.saitama.jp -kuki.saitama.jp -kumagaya.saitama.jp -matsubushi.saitama.jp -minano.saitama.jp -misato.saitama.jp -miyashiro.saitama.jp -miyoshi.saitama.jp -moroyama.saitama.jp -nagatoro.saitama.jp -namegawa.saitama.jp -niiza.saitama.jp -ogano.saitama.jp -ogawa.saitama.jp -ogose.saitama.jp -okegawa.saitama.jp -omiya.saitama.jp -otaki.saitama.jp -ranzan.saitama.jp -ryokami.saitama.jp -saitama.saitama.jp -sakado.saitama.jp -satte.saitama.jp -sayama.saitama.jp -shiki.saitama.jp -shiraoka.saitama.jp -soka.saitama.jp -sugito.saitama.jp -toda.saitama.jp -tokigawa.saitama.jp -tokorozawa.saitama.jp -tsurugashima.saitama.jp -urawa.saitama.jp -warabi.saitama.jp -yashio.saitama.jp -yokoze.saitama.jp -yono.saitama.jp -yorii.saitama.jp -yoshida.saitama.jp -yoshikawa.saitama.jp -yoshimi.saitama.jp -aisho.shiga.jp -gamo.shiga.jp -higashiomi.shiga.jp -hikone.shiga.jp -koka.shiga.jp -konan.shiga.jp -kosei.shiga.jp -koto.shiga.jp -kusatsu.shiga.jp -maibara.shiga.jp -moriyama.shiga.jp -nagahama.shiga.jp -nishiazai.shiga.jp -notogawa.shiga.jp -omihachiman.shiga.jp -otsu.shiga.jp -ritto.shiga.jp -ryuoh.shiga.jp -takashima.shiga.jp -takatsuki.shiga.jp -torahime.shiga.jp -toyosato.shiga.jp -yasu.shiga.jp -akagi.shimane.jp -ama.shimane.jp -gotsu.shimane.jp -hamada.shimane.jp -higashiizumo.shimane.jp -hikawa.shimane.jp -hikimi.shimane.jp -izumo.shimane.jp -kakinoki.shimane.jp -masuda.shimane.jp -matsue.shimane.jp -misato.shimane.jp -nishinoshima.shimane.jp -ohda.shimane.jp -okinoshima.shimane.jp -okuizumo.shimane.jp -shimane.shimane.jp -tamayu.shimane.jp -tsuwano.shimane.jp -unnan.shimane.jp -yakumo.shimane.jp -yasugi.shimane.jp -yatsuka.shimane.jp -arai.shizuoka.jp -atami.shizuoka.jp -fuji.shizuoka.jp -fujieda.shizuoka.jp -fujikawa.shizuoka.jp -fujinomiya.shizuoka.jp -fukuroi.shizuoka.jp -gotemba.shizuoka.jp -haibara.shizuoka.jp -hamamatsu.shizuoka.jp -higashiizu.shizuoka.jp -ito.shizuoka.jp -iwata.shizuoka.jp -izu.shizuoka.jp -izunokuni.shizuoka.jp -kakegawa.shizuoka.jp -kannami.shizuoka.jp -kawanehon.shizuoka.jp -kawazu.shizuoka.jp -kikugawa.shizuoka.jp -kosai.shizuoka.jp -makinohara.shizuoka.jp -matsuzaki.shizuoka.jp -minamiizu.shizuoka.jp -mishima.shizuoka.jp -morimachi.shizuoka.jp -nishiizu.shizuoka.jp -numazu.shizuoka.jp -omaezaki.shizuoka.jp -shimada.shizuoka.jp -shimizu.shizuoka.jp -shimoda.shizuoka.jp -shizuoka.shizuoka.jp -susono.shizuoka.jp -yaizu.shizuoka.jp -yoshida.shizuoka.jp -ashikaga.tochigi.jp -bato.tochigi.jp -haga.tochigi.jp -ichikai.tochigi.jp -iwafune.tochigi.jp -kaminokawa.tochigi.jp -kanuma.tochigi.jp -karasuyama.tochigi.jp -kuroiso.tochigi.jp -mashiko.tochigi.jp -mibu.tochigi.jp -moka.tochigi.jp -motegi.tochigi.jp -nasu.tochigi.jp -nasushiobara.tochigi.jp -nikko.tochigi.jp -nishikata.tochigi.jp -nogi.tochigi.jp -ohira.tochigi.jp -ohtawara.tochigi.jp -oyama.tochigi.jp -sakura.tochigi.jp -sano.tochigi.jp -shimotsuke.tochigi.jp -shioya.tochigi.jp -takanezawa.tochigi.jp -tochigi.tochigi.jp -tsuga.tochigi.jp -ujiie.tochigi.jp -utsunomiya.tochigi.jp -yaita.tochigi.jp -aizumi.tokushima.jp -anan.tokushima.jp -ichiba.tokushima.jp -itano.tokushima.jp -kainan.tokushima.jp -komatsushima.tokushima.jp -matsushige.tokushima.jp -mima.tokushima.jp -minami.tokushima.jp -miyoshi.tokushima.jp -mugi.tokushima.jp -nakagawa.tokushima.jp -naruto.tokushima.jp -sanagochi.tokushima.jp -shishikui.tokushima.jp -tokushima.tokushima.jp -wajiki.tokushima.jp -adachi.tokyo.jp -akiruno.tokyo.jp -akishima.tokyo.jp -aogashima.tokyo.jp -arakawa.tokyo.jp -bunkyo.tokyo.jp -chiyoda.tokyo.jp -chofu.tokyo.jp -chuo.tokyo.jp -edogawa.tokyo.jp -fuchu.tokyo.jp -fussa.tokyo.jp -hachijo.tokyo.jp -hachioji.tokyo.jp -hamura.tokyo.jp -higashikurume.tokyo.jp -higashimurayama.tokyo.jp -higashiyamato.tokyo.jp -hino.tokyo.jp -hinode.tokyo.jp -hinohara.tokyo.jp -inagi.tokyo.jp -itabashi.tokyo.jp -katsushika.tokyo.jp -kita.tokyo.jp -kiyose.tokyo.jp -kodaira.tokyo.jp -koganei.tokyo.jp -kokubunji.tokyo.jp -komae.tokyo.jp -koto.tokyo.jp -kouzushima.tokyo.jp -kunitachi.tokyo.jp -machida.tokyo.jp -meguro.tokyo.jp -minato.tokyo.jp -mitaka.tokyo.jp -mizuho.tokyo.jp -musashimurayama.tokyo.jp -musashino.tokyo.jp -nakano.tokyo.jp -nerima.tokyo.jp -ogasawara.tokyo.jp -okutama.tokyo.jp -ome.tokyo.jp -oshima.tokyo.jp -ota.tokyo.jp -setagaya.tokyo.jp -shibuya.tokyo.jp -shinagawa.tokyo.jp -shinjuku.tokyo.jp -suginami.tokyo.jp -sumida.tokyo.jp -tachikawa.tokyo.jp -taito.tokyo.jp -tama.tokyo.jp -toshima.tokyo.jp -chizu.tottori.jp -hino.tottori.jp -kawahara.tottori.jp -koge.tottori.jp -kotoura.tottori.jp -misasa.tottori.jp -nanbu.tottori.jp -nichinan.tottori.jp -sakaiminato.tottori.jp -tottori.tottori.jp -wakasa.tottori.jp -yazu.tottori.jp -yonago.tottori.jp -asahi.toyama.jp -fuchu.toyama.jp -fukumitsu.toyama.jp -funahashi.toyama.jp -himi.toyama.jp -imizu.toyama.jp -inami.toyama.jp -johana.toyama.jp -kamiichi.toyama.jp -kurobe.toyama.jp -nakaniikawa.toyama.jp -namerikawa.toyama.jp -nanto.toyama.jp -nyuzen.toyama.jp -oyabe.toyama.jp -taira.toyama.jp -takaoka.toyama.jp -tateyama.toyama.jp -toga.toyama.jp -tonami.toyama.jp -toyama.toyama.jp -unazuki.toyama.jp -uozu.toyama.jp -yamada.toyama.jp -arida.wakayama.jp -aridagawa.wakayama.jp -gobo.wakayama.jp -hashimoto.wakayama.jp -hidaka.wakayama.jp -hirogawa.wakayama.jp -inami.wakayama.jp -iwade.wakayama.jp -kainan.wakayama.jp -kamitonda.wakayama.jp -katsuragi.wakayama.jp -kimino.wakayama.jp -kinokawa.wakayama.jp -kitayama.wakayama.jp -koya.wakayama.jp -koza.wakayama.jp -kozagawa.wakayama.jp -kudoyama.wakayama.jp -kushimoto.wakayama.jp -mihama.wakayama.jp -misato.wakayama.jp -nachikatsuura.wakayama.jp -shingu.wakayama.jp -shirahama.wakayama.jp -taiji.wakayama.jp -tanabe.wakayama.jp -wakayama.wakayama.jp -yuasa.wakayama.jp -yura.wakayama.jp -asahi.yamagata.jp -funagata.yamagata.jp -higashine.yamagata.jp -iide.yamagata.jp -kahoku.yamagata.jp -kaminoyama.yamagata.jp -kaneyama.yamagata.jp -kawanishi.yamagata.jp -mamurogawa.yamagata.jp -mikawa.yamagata.jp -murayama.yamagata.jp -nagai.yamagata.jp -nakayama.yamagata.jp -nanyo.yamagata.jp -nishikawa.yamagata.jp -obanazawa.yamagata.jp -oe.yamagata.jp -oguni.yamagata.jp -ohkura.yamagata.jp -oishida.yamagata.jp -sagae.yamagata.jp -sakata.yamagata.jp -sakegawa.yamagata.jp -shinjo.yamagata.jp -shirataka.yamagata.jp -shonai.yamagata.jp -takahata.yamagata.jp -tendo.yamagata.jp -tozawa.yamagata.jp -tsuruoka.yamagata.jp -yamagata.yamagata.jp -yamanobe.yamagata.jp -yonezawa.yamagata.jp -yuza.yamagata.jp -abu.yamaguchi.jp -hagi.yamaguchi.jp -hikari.yamaguchi.jp -hofu.yamaguchi.jp -iwakuni.yamaguchi.jp -kudamatsu.yamaguchi.jp -mitou.yamaguchi.jp -nagato.yamaguchi.jp -oshima.yamaguchi.jp -shimonoseki.yamaguchi.jp -shunan.yamaguchi.jp -tabuse.yamaguchi.jp -tokuyama.yamaguchi.jp -toyota.yamaguchi.jp -ube.yamaguchi.jp -yuu.yamaguchi.jp -chuo.yamanashi.jp -doshi.yamanashi.jp -fuefuki.yamanashi.jp -fujikawa.yamanashi.jp -fujikawaguchiko.yamanashi.jp -fujiyoshida.yamanashi.jp -hayakawa.yamanashi.jp -hokuto.yamanashi.jp -ichikawamisato.yamanashi.jp -kai.yamanashi.jp -kofu.yamanashi.jp -koshu.yamanashi.jp -kosuge.yamanashi.jp -minami-alps.yamanashi.jp -minobu.yamanashi.jp -nakamichi.yamanashi.jp -nanbu.yamanashi.jp -narusawa.yamanashi.jp -nirasaki.yamanashi.jp -nishikatsura.yamanashi.jp -oshino.yamanashi.jp -otsuki.yamanashi.jp -showa.yamanashi.jp -tabayama.yamanashi.jp -tsuru.yamanashi.jp -uenohara.yamanashi.jp -yamanakako.yamanashi.jp -yamanashi.yamanashi.jp - -// ke : http://www.kenic.or.ke/index.php/en/ke-domains/ke-domains -ke -ac.ke -co.ke -go.ke -info.ke -me.ke -mobi.ke -ne.ke -or.ke -sc.ke - -// kg : http://www.domain.kg/dmn_n.html -kg -com.kg -edu.kg -gov.kg -mil.kg -net.kg -org.kg - -// kh : http://www.mptc.gov.kh/dns_registration.htm -*.kh - -// ki : https://www.iana.org/domains/root/db/ki.html -ki -biz.ki -com.ki -edu.ki -gov.ki -info.ki -net.ki -org.ki - -// km : https://www.iana.org/domains/root/db/km.html -// http://www.domaine.km/documents/charte.doc -km -ass.km -com.km -edu.km -gov.km -mil.km -nom.km -org.km -prd.km -tm.km -// These are only mentioned as proposed suggestions at domaine.km, but -// https://www.iana.org/domains/root/db/km.html says they're available for registration: -asso.km -coop.km -gouv.km -medecin.km -notaires.km -pharmaciens.km -presse.km -veterinaire.km - -// kn : https://www.iana.org/domains/root/db/kn.html -// http://www.dot.kn/domainRules.html -kn -edu.kn -gov.kn -net.kn -org.kn - -// kp : http://www.kcce.kp/en_index.php -kp -com.kp -edu.kp -gov.kp -org.kp -rep.kp -tra.kp - -// kr : https://www.iana.org/domains/root/db/kr.html -// see also: https://krnic.kisa.or.kr/jsp/infoboard/law/domBylawsReg.jsp -kr -ac.kr -ai.kr -co.kr -es.kr -go.kr -hs.kr -io.kr -it.kr -kg.kr -me.kr -mil.kr -ms.kr -ne.kr -or.kr -pe.kr -re.kr -sc.kr -// kr geographical names -busan.kr -chungbuk.kr -chungnam.kr -daegu.kr -daejeon.kr -gangwon.kr -gwangju.kr -gyeongbuk.kr -gyeonggi.kr -gyeongnam.kr -incheon.kr -jeju.kr -jeonbuk.kr -jeonnam.kr -seoul.kr -ulsan.kr - -// kw : https://www.nic.kw/policies/ -// Confirmed by registry -kw -com.kw -edu.kw -emb.kw -gov.kw -ind.kw -net.kw -org.kw - -// ky : http://www.icta.ky/da_ky_reg_dom.php -// Confirmed by registry 2008-06-17 -ky -com.ky -edu.ky -net.ky -org.ky - -// kz : https://www.iana.org/domains/root/db/kz.html -// see also: http://www.nic.kz/rules/index.jsp -kz -com.kz -edu.kz -gov.kz -mil.kz -net.kz -org.kz - -// la : https://www.iana.org/domains/root/db/la.html -// Submitted by registry -la -com.la -edu.la -gov.la -info.la -int.la -net.la -org.la -per.la - -// lb : https://www.iana.org/domains/root/db/lb.html -// Submitted by registry -lb -com.lb -edu.lb -gov.lb -net.lb -org.lb - -// lc : https://www.iana.org/domains/root/db/lc.html -// see also: http://www.nic.lc/rules.htm -lc -co.lc -com.lc -edu.lc -gov.lc -net.lc -org.lc - -// li : https://www.iana.org/domains/root/db/li.html -li - -// lk : https://www.iana.org/domains/root/db/lk.html -lk -ac.lk -assn.lk -com.lk -edu.lk -gov.lk -grp.lk -hotel.lk -int.lk -ltd.lk -net.lk -ngo.lk -org.lk -sch.lk -soc.lk -web.lk - -// lr : http://psg.com/dns/lr/lr.txt -// Submitted by registry -lr -com.lr -edu.lr -gov.lr -net.lr -org.lr - -// ls : http://www.nic.ls/ -// Confirmed by registry -ls -ac.ls -biz.ls -co.ls -edu.ls -gov.ls -info.ls -net.ls -org.ls -sc.ls - -// lt : https://www.iana.org/domains/root/db/lt.html -lt -// gov.lt : http://www.gov.lt/index_en.php -gov.lt - -// lu : http://www.dns.lu/en/ -lu - -// lv : https://www.iana.org/domains/root/db/lv.html -lv -asn.lv -com.lv -conf.lv -edu.lv -gov.lv -id.lv -mil.lv -net.lv -org.lv - -// ly : http://www.nic.ly/regulations.php -ly -com.ly -edu.ly -gov.ly -id.ly -med.ly -net.ly -org.ly -plc.ly -sch.ly - -// ma : https://www.iana.org/domains/root/db/ma.html -// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf -ma -ac.ma -co.ma -gov.ma -net.ma -org.ma -press.ma - -// mc : http://www.nic.mc/ -mc -asso.mc -tm.mc - -// md : https://www.iana.org/domains/root/db/md.html -md - -// me : https://www.iana.org/domains/root/db/me.html -me -ac.me -co.me -edu.me -gov.me -its.me -net.me -org.me -priv.me - -// mg : https://nic.mg -mg -co.mg -com.mg -edu.mg -gov.mg -mil.mg -nom.mg -org.mg -prd.mg - -// mh : https://www.iana.org/domains/root/db/mh.html -mh - -// mil : https://www.iana.org/domains/root/db/mil.html -mil - -// mk : https://www.iana.org/domains/root/db/mk.html -// see also: http://dns.marnet.net.mk/postapka.php -mk -com.mk -edu.mk -gov.mk -inf.mk -name.mk -net.mk -org.mk - -// ml : https://www.iana.org/domains/root/db/ml.html -// Confirmed by Boubacar NDIAYE 2024-12-31 -ml -ac.ml -art.ml -asso.ml -com.ml -edu.ml -gouv.ml -gov.ml -info.ml -inst.ml -net.ml -org.ml -pr.ml -presse.ml - -// mm : https://www.iana.org/domains/root/db/mm.html -*.mm - -// mn : https://www.iana.org/domains/root/db/mn.html -mn -edu.mn -gov.mn -org.mn - -// mo : http://www.monic.net.mo/ -mo -com.mo -edu.mo -gov.mo -net.mo -org.mo - -// mobi : https://www.iana.org/domains/root/db/mobi.html -mobi - -// mp : http://www.dot.mp/ -// Confirmed by registry 2008-06-17 -mp - -// mq : https://www.iana.org/domains/root/db/mq.html -mq - -// mr : https://www.iana.org/domains/root/db/mr.html -mr -gov.mr - -// ms : https://www.iana.org/domains/root/db/ms.html -ms -com.ms -edu.ms -gov.ms -net.ms -org.ms - -// mt : https://www.nic.org.mt/go/policy -// Submitted by registry -mt -com.mt -edu.mt -net.mt -org.mt - -// mu : https://www.iana.org/domains/root/db/mu.html -mu -ac.mu -co.mu -com.mu -gov.mu -net.mu -or.mu -org.mu - -// museum : https://welcome.museum/wp-content/uploads/2018/05/20180525-Registration-Policy-MUSEUM-EN_VF-2.pdf https://welcome.museum/buy-your-dot-museum-2/ -museum - -// mv : https://www.iana.org/domains/root/db/mv.html -// "mv" included because, contra Wikipedia, google.mv exists. -mv -aero.mv -biz.mv -com.mv -coop.mv -edu.mv -gov.mv -info.mv -int.mv -mil.mv -museum.mv -name.mv -net.mv -org.mv -pro.mv - -// mw : http://www.registrar.mw/ -mw -ac.mw -biz.mw -co.mw -com.mw -coop.mw -edu.mw -gov.mw -int.mw -net.mw -org.mw - -// mx : http://www.nic.mx/ -// Submitted by registry -mx -com.mx -edu.mx -gob.mx -net.mx -org.mx - -// my : http://www.mynic.my/ -// Available strings: https://mynic.my/resources/domains/buying-a-domain/ -my -biz.my -com.my -edu.my -gov.my -mil.my -name.my -net.my -org.my - -// mz : http://www.uem.mz/ -// Submitted by registry -mz -ac.mz -adv.mz -co.mz -edu.mz -gov.mz -mil.mz -net.mz -org.mz - -// na : http://www.na-nic.com.na/ -na -alt.na -co.na -com.na -gov.na -net.na -org.na - -// name : http://www.nic.name/ -// Regarding 2LDs: https://github.com/publicsuffix/list/issues/2306 -name - -// nc : http://www.cctld.nc/ -nc -asso.nc -nom.nc - -// ne : https://www.iana.org/domains/root/db/ne.html -ne - -// net : https://www.iana.org/domains/root/db/net.html -net - -// nf : https://www.iana.org/domains/root/db/nf.html -nf -arts.nf -com.nf -firm.nf -info.nf -net.nf -other.nf -per.nf -rec.nf -store.nf -web.nf - -// ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds -ng -com.ng -edu.ng -gov.ng -i.ng -mil.ng -mobi.ng -name.ng -net.ng -org.ng -sch.ng - -// ni : http://www.nic.ni/ -ni -ac.ni -biz.ni -co.ni -com.ni -edu.ni -gob.ni -in.ni -info.ni -int.ni -mil.ni -net.ni -nom.ni -org.ni -web.ni - -// nl : https://www.iana.org/domains/root/db/nl.html -// https://www.sidn.nl/ -nl - -// no : https://www.norid.no/en/om-domenenavn/regelverk-for-no/ -// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ -// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ -// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ -// RSS feed: https://teknisk.norid.no/en/feed/ -no -// Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ -fhs.no -folkebibl.no -fylkesbibl.no -idrett.no -museum.no -priv.no -vgs.no -// Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ -dep.no -herad.no -kommune.no -mil.no -stat.no -// Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ -// counties -aa.no -ah.no -bu.no -fm.no -hl.no -hm.no -jan-mayen.no -mr.no -nl.no -nt.no -of.no -ol.no -oslo.no -rl.no -sf.no -st.no -svalbard.no -tm.no -tr.no -va.no -vf.no -// primary and lower secondary schools per county -gs.aa.no -gs.ah.no -gs.bu.no -gs.fm.no -gs.hl.no -gs.hm.no -gs.jan-mayen.no -gs.mr.no -gs.nl.no -gs.nt.no -gs.of.no -gs.ol.no -gs.oslo.no -gs.rl.no -gs.sf.no -gs.st.no -gs.svalbard.no -gs.tm.no -gs.tr.no -gs.va.no -gs.vf.no -// cities -akrehamn.no -åkrehamn.no -algard.no -ålgård.no -arna.no -bronnoysund.no -brønnøysund.no -brumunddal.no -bryne.no -drobak.no -drøbak.no -egersund.no -fetsund.no -floro.no -florø.no -fredrikstad.no -hokksund.no -honefoss.no -hønefoss.no -jessheim.no -jorpeland.no -jørpeland.no -kirkenes.no -kopervik.no -krokstadelva.no -langevag.no -langevåg.no -leirvik.no -mjondalen.no -mjøndalen.no -mo-i-rana.no -mosjoen.no -mosjøen.no -nesoddtangen.no -orkanger.no -osoyro.no -osøyro.no -raholt.no -råholt.no -sandnessjoen.no -sandnessjøen.no -skedsmokorset.no -slattum.no -spjelkavik.no -stathelle.no -stavern.no -stjordalshalsen.no -stjørdalshalsen.no -tananger.no -tranby.no -vossevangen.no -// communities -aarborte.no -aejrie.no -afjord.no -åfjord.no -agdenes.no -nes.akershus.no -aknoluokta.no -ákŋoluokta.no -al.no -ål.no -alaheadju.no -álaheadju.no -alesund.no -ålesund.no -alstahaug.no -alta.no -áltá.no -alvdal.no -amli.no -åmli.no -amot.no -åmot.no -andasuolo.no -andebu.no -andoy.no -andøy.no -ardal.no -årdal.no -aremark.no -arendal.no -ås.no -aseral.no -åseral.no -asker.no -askim.no -askoy.no -askøy.no -askvoll.no -asnes.no -åsnes.no -audnedaln.no -aukra.no -aure.no -aurland.no -aurskog-holand.no -aurskog-høland.no -austevoll.no -austrheim.no -averoy.no -averøy.no -badaddja.no -bådåddjå.no -bærum.no -bahcavuotna.no -báhcavuotna.no -bahccavuotna.no -báhccavuotna.no -baidar.no -báidár.no -bajddar.no -bájddar.no -balat.no -bálát.no -balestrand.no -ballangen.no -balsfjord.no -bamble.no -bardu.no -barum.no -batsfjord.no -båtsfjord.no -bearalvahki.no -bearalváhki.no -beardu.no -beiarn.no -berg.no -bergen.no -berlevag.no -berlevåg.no -bievat.no -bievát.no -bindal.no -birkenes.no -bjarkoy.no -bjarkøy.no -bjerkreim.no -bjugn.no -bodo.no -bodø.no -bokn.no -bomlo.no -bømlo.no -bremanger.no -bronnoy.no -brønnøy.no -budejju.no -nes.buskerud.no -bygland.no -bykle.no -cahcesuolo.no -čáhcesuolo.no -davvenjarga.no -davvenjárga.no -davvesiida.no -deatnu.no -dielddanuorri.no -divtasvuodna.no -divttasvuotna.no -donna.no -dønna.no -dovre.no -drammen.no -drangedal.no -dyroy.no -dyrøy.no -eid.no -eidfjord.no -eidsberg.no -eidskog.no -eidsvoll.no -eigersund.no -elverum.no -enebakk.no -engerdal.no -etne.no -etnedal.no -evenassi.no -evenášši.no -evenes.no -evje-og-hornnes.no -farsund.no -fauske.no -fedje.no -fet.no -finnoy.no -finnøy.no -fitjar.no -fjaler.no -fjell.no -fla.no -flå.no -flakstad.no -flatanger.no -flekkefjord.no -flesberg.no -flora.no -folldal.no -forde.no -førde.no -forsand.no -fosnes.no -fræna.no -frana.no -frei.no -frogn.no -froland.no -frosta.no -froya.no -frøya.no -fuoisku.no -fuossko.no -fusa.no -fyresdal.no -gaivuotna.no -gáivuotna.no -galsa.no -gálsá.no -gamvik.no -gangaviika.no -gáŋgaviika.no -gaular.no -gausdal.no -giehtavuoatna.no -gildeskal.no -gildeskål.no -giske.no -gjemnes.no -gjerdrum.no -gjerstad.no -gjesdal.no -gjovik.no -gjøvik.no -gloppen.no -gol.no -gran.no -grane.no -granvin.no -gratangen.no -grimstad.no -grong.no -grue.no -gulen.no -guovdageaidnu.no -ha.no -hå.no -habmer.no -hábmer.no -hadsel.no -hægebostad.no -hagebostad.no -halden.no -halsa.no -hamar.no -hamaroy.no -hammarfeasta.no -hámmárfeasta.no -hammerfest.no -hapmir.no -hápmir.no -haram.no -hareid.no -harstad.no -hasvik.no -hattfjelldal.no -haugesund.no -os.hedmark.no -valer.hedmark.no -våler.hedmark.no -hemne.no -hemnes.no -hemsedal.no -hitra.no -hjartdal.no -hjelmeland.no -hobol.no -hobøl.no -hof.no -hol.no -hole.no -holmestrand.no -holtalen.no -holtålen.no -os.hordaland.no -hornindal.no -horten.no -hoyanger.no -høyanger.no -hoylandet.no -høylandet.no -hurdal.no -hurum.no -hvaler.no -hyllestad.no -ibestad.no -inderoy.no -inderøy.no -iveland.no -ivgu.no -jevnaker.no -jolster.no -jølster.no -jondal.no -kafjord.no -kåfjord.no -karasjohka.no -kárášjohka.no -karasjok.no -karlsoy.no -karmoy.no -karmøy.no -kautokeino.no -klabu.no -klæbu.no -klepp.no -kongsberg.no -kongsvinger.no -kraanghke.no -kråanghke.no -kragero.no -kragerø.no -kristiansand.no -kristiansund.no -krodsherad.no -krødsherad.no -kvæfjord.no -kvænangen.no -kvafjord.no -kvalsund.no -kvam.no -kvanangen.no -kvinesdal.no -kvinnherad.no -kviteseid.no -kvitsoy.no -kvitsøy.no -laakesvuemie.no -lærdal.no -lahppi.no -láhppi.no -lardal.no -larvik.no -lavagis.no -lavangen.no -leangaviika.no -leaŋgaviika.no -lebesby.no -leikanger.no -leirfjord.no -leka.no -leksvik.no -lenvik.no -lerdal.no -lesja.no -levanger.no -lier.no -lierne.no -lillehammer.no -lillesand.no -lindas.no -lindås.no -lindesnes.no -loabat.no -loabát.no -lodingen.no -lødingen.no -lom.no -loppa.no -lorenskog.no -lørenskog.no -loten.no -løten.no -lund.no -lunner.no -luroy.no -lurøy.no -luster.no -lyngdal.no -lyngen.no -malatvuopmi.no -málatvuopmi.no -malselv.no -målselv.no -malvik.no -mandal.no -marker.no -marnardal.no -masfjorden.no -masoy.no -måsøy.no -matta-varjjat.no -mátta-várjjat.no -meland.no -meldal.no -melhus.no -meloy.no -meløy.no -meraker.no -meråker.no -midsund.no -midtre-gauldal.no -moareke.no -moåreke.no -modalen.no -modum.no -molde.no -heroy.more-og-romsdal.no -sande.more-og-romsdal.no -herøy.møre-og-romsdal.no -sande.møre-og-romsdal.no -moskenes.no -moss.no -mosvik.no -muosat.no -muosát.no -naamesjevuemie.no -nååmesjevuemie.no -nærøy.no -namdalseid.no -namsos.no -namsskogan.no -nannestad.no -naroy.no -narviika.no -narvik.no -naustdal.no -navuotna.no -návuotna.no -nedre-eiker.no -nesna.no -nesodden.no -nesseby.no -nesset.no -nissedal.no -nittedal.no -nord-aurdal.no -nord-fron.no -nord-odal.no -norddal.no -nordkapp.no -bo.nordland.no -bø.nordland.no -heroy.nordland.no -herøy.nordland.no -nordre-land.no -nordreisa.no -nore-og-uvdal.no -notodden.no -notteroy.no -nøtterøy.no -odda.no -oksnes.no -øksnes.no -omasvuotna.no -oppdal.no -oppegard.no -oppegård.no -orkdal.no -orland.no -ørland.no -orskog.no -ørskog.no -orsta.no -ørsta.no -osen.no -osteroy.no -osterøy.no -valer.ostfold.no -våler.østfold.no -ostre-toten.no -østre-toten.no -overhalla.no -ovre-eiker.no -øvre-eiker.no -oyer.no -øyer.no -oygarden.no -øygarden.no -oystre-slidre.no -øystre-slidre.no -porsanger.no -porsangu.no -porsáŋgu.no -porsgrunn.no -rade.no -råde.no -radoy.no -radøy.no -rælingen.no -rahkkeravju.no -ráhkkerávju.no -raisa.no -ráisa.no -rakkestad.no -ralingen.no -rana.no -randaberg.no -rauma.no -rendalen.no -rennebu.no -rennesoy.no -rennesøy.no -rindal.no -ringebu.no -ringerike.no -ringsaker.no -risor.no -risør.no -rissa.no -roan.no -rodoy.no -rødøy.no -rollag.no -romsa.no -romskog.no -rømskog.no -roros.no -røros.no -rost.no -røst.no -royken.no -røyken.no -royrvik.no -røyrvik.no -ruovat.no -rygge.no -salangen.no -salat.no -sálat.no -sálát.no -saltdal.no -samnanger.no -sandefjord.no -sandnes.no -sandoy.no -sandøy.no -sarpsborg.no -sauda.no -sauherad.no -sel.no -selbu.no -selje.no -seljord.no -siellak.no -sigdal.no -siljan.no -sirdal.no -skanit.no -skánit.no -skanland.no -skånland.no -skaun.no -skedsmo.no -ski.no -skien.no -skierva.no -skiervá.no -skiptvet.no -skjak.no -skjåk.no -skjervoy.no -skjervøy.no -skodje.no -smola.no -smøla.no -snaase.no -snåase.no -snasa.no -snåsa.no -snillfjord.no -snoasa.no -sogndal.no -sogne.no -søgne.no -sokndal.no -sola.no -solund.no -somna.no -sømna.no -sondre-land.no -søndre-land.no -songdalen.no -sor-aurdal.no -sør-aurdal.no -sor-fron.no -sør-fron.no -sor-odal.no -sør-odal.no -sor-varanger.no -sør-varanger.no -sorfold.no -sørfold.no -sorreisa.no -sørreisa.no -sortland.no -sorum.no -sørum.no -spydeberg.no -stange.no -stavanger.no -steigen.no -steinkjer.no -stjordal.no -stjørdal.no -stokke.no -stor-elvdal.no -stord.no -stordal.no -storfjord.no -strand.no -stranda.no -stryn.no -sula.no -suldal.no -sund.no -sunndal.no -surnadal.no -sveio.no -svelvik.no -sykkylven.no -tana.no -bo.telemark.no -bø.telemark.no -time.no -tingvoll.no -tinn.no -tjeldsund.no -tjome.no -tjøme.no -tokke.no -tolga.no -tonsberg.no -tønsberg.no -torsken.no -træna.no -trana.no -tranoy.no -tranøy.no -troandin.no -trogstad.no -trøgstad.no -tromsa.no -tromso.no -tromsø.no -trondheim.no -trysil.no -tvedestrand.no -tydal.no -tynset.no -tysfjord.no -tysnes.no -tysvær.no -tysvar.no -ullensaker.no -ullensvang.no -ulvik.no -unjarga.no -unjárga.no -utsira.no -vaapste.no -vadso.no -vadsø.no -værøy.no -vaga.no -vågå.no -vagan.no -vågan.no -vagsoy.no -vågsøy.no -vaksdal.no -valle.no -vang.no -vanylven.no -vardo.no -vardø.no -varggat.no -várggát.no -varoy.no -vefsn.no -vega.no -vegarshei.no -vegårshei.no -vennesla.no -verdal.no -verran.no -vestby.no -sande.vestfold.no -vestnes.no -vestre-slidre.no -vestre-toten.no -vestvagoy.no -vestvågøy.no -vevelstad.no -vik.no -vikna.no -vindafjord.no -voagat.no -volda.no -voss.no - -// np : http://www.mos.com.np/register.html -*.np - -// nr : http://cenpac.net.nr/dns/index.html -// Submitted by registry -nr -biz.nr -com.nr -edu.nr -gov.nr -info.nr -net.nr -org.nr - -// nu : https://www.iana.org/domains/root/db/nu.html -nu - -// nz : https://www.iana.org/domains/root/db/nz.html -// Submitted by registry -nz -ac.nz -co.nz -cri.nz -geek.nz -gen.nz -govt.nz -health.nz -iwi.nz -kiwi.nz -maori.nz -māori.nz -mil.nz -net.nz -org.nz -parliament.nz -school.nz - -// om : https://www.iana.org/domains/root/db/om.html -om -co.om -com.om -edu.om -gov.om -med.om -museum.om -net.om -org.om -pro.om - -// onion : https://tools.ietf.org/html/rfc7686 -onion - -// org : https://www.iana.org/domains/root/db/org.html -org - -// pa : http://www.nic.pa/ -// Some additional second level "domains" resolve directly as hostnames, such as -// pannet.pa, so we add a rule for "pa". -pa -abo.pa -ac.pa -com.pa -edu.pa -gob.pa -ing.pa -med.pa -net.pa -nom.pa -org.pa -sld.pa - -// pe : https://www.nic.pe/InformeFinalComision.pdf -pe -com.pe -edu.pe -gob.pe -mil.pe -net.pe -nom.pe -org.pe - -// pf : http://www.gobin.info/domainname/formulaire-pf.pdf -pf -com.pf -edu.pf -org.pf - -// pg : https://www.iana.org/domains/root/db/pg.html -*.pg - -// ph : https://www.iana.org/domains/root/db/ph.html -// Submitted by registry -ph -com.ph -edu.ph -gov.ph -i.ph -mil.ph -net.ph -ngo.ph -org.ph - -// pk : https://pk5.pknic.net.pk/pk5/msgNamepk.PK -// Contact Email: staff@pknic.net.pk -pk -ac.pk -biz.pk -com.pk -edu.pk -fam.pk -gkp.pk -gob.pk -gog.pk -gok.pk -gop.pk -gos.pk -gov.pk -net.pk -org.pk -web.pk - -// pl : https://www.dns.pl/en/ -// Confirmed by registry 2024-11-18 -pl -com.pl -net.pl -org.pl -// pl functional domains : https://www.dns.pl/en/list_of_functional_domain_names -agro.pl -aid.pl -atm.pl -auto.pl -biz.pl -edu.pl -gmina.pl -gsm.pl -info.pl -mail.pl -media.pl -miasta.pl -mil.pl -nieruchomosci.pl -nom.pl -pc.pl -powiat.pl -priv.pl -realestate.pl -rel.pl -sex.pl -shop.pl -sklep.pl -sos.pl -szkola.pl -targi.pl -tm.pl -tourism.pl -travel.pl -turystyka.pl -// Government domains : https://www.dns.pl/informacje_o_rejestracji_domen_gov_pl -// In accordance with the .gov.pl Domain Name Regulations : https://www.dns.pl/regulamin_gov_pl -gov.pl -ap.gov.pl -griw.gov.pl -ic.gov.pl -is.gov.pl -kmpsp.gov.pl -konsulat.gov.pl -kppsp.gov.pl -kwp.gov.pl -kwpsp.gov.pl -mup.gov.pl -mw.gov.pl -oia.gov.pl -oirm.gov.pl -oke.gov.pl -oow.gov.pl -oschr.gov.pl -oum.gov.pl -pa.gov.pl -pinb.gov.pl -piw.gov.pl -po.gov.pl -pr.gov.pl -psp.gov.pl -psse.gov.pl -pup.gov.pl -rzgw.gov.pl -sa.gov.pl -sdn.gov.pl -sko.gov.pl -so.gov.pl -sr.gov.pl -starostwo.gov.pl -ug.gov.pl -ugim.gov.pl -um.gov.pl -umig.gov.pl -upow.gov.pl -uppo.gov.pl -us.gov.pl -uw.gov.pl -uzs.gov.pl -wif.gov.pl -wiih.gov.pl -winb.gov.pl -wios.gov.pl -witd.gov.pl -wiw.gov.pl -wkz.gov.pl -wsa.gov.pl -wskr.gov.pl -wsse.gov.pl -wuoz.gov.pl -wzmiuw.gov.pl -zp.gov.pl -zpisdn.gov.pl -// pl regional domains : https://www.dns.pl/en/list_of_regional_domain_names -augustow.pl -babia-gora.pl -bedzin.pl -beskidy.pl -bialowieza.pl -bialystok.pl -bielawa.pl -bieszczady.pl -boleslawiec.pl -bydgoszcz.pl -bytom.pl -cieszyn.pl -czeladz.pl -czest.pl -dlugoleka.pl -elblag.pl -elk.pl -glogow.pl -gniezno.pl -gorlice.pl -grajewo.pl -ilawa.pl -jaworzno.pl -jelenia-gora.pl -jgora.pl -kalisz.pl -karpacz.pl -kartuzy.pl -kaszuby.pl -katowice.pl -kazimierz-dolny.pl -kepno.pl -ketrzyn.pl -klodzko.pl -kobierzyce.pl -kolobrzeg.pl -konin.pl -konskowola.pl -kutno.pl -lapy.pl -lebork.pl -legnica.pl -lezajsk.pl -limanowa.pl -lomza.pl -lowicz.pl -lubin.pl -lukow.pl -malbork.pl -malopolska.pl -mazowsze.pl -mazury.pl -mielec.pl -mielno.pl -mragowo.pl -naklo.pl -nowaruda.pl -nysa.pl -olawa.pl -olecko.pl -olkusz.pl -olsztyn.pl -opoczno.pl -opole.pl -ostroda.pl -ostroleka.pl -ostrowiec.pl -ostrowwlkp.pl -pila.pl -pisz.pl -podhale.pl -podlasie.pl -polkowice.pl -pomorskie.pl -pomorze.pl -prochowice.pl -pruszkow.pl -przeworsk.pl -pulawy.pl -radom.pl -rawa-maz.pl -rybnik.pl -rzeszow.pl -sanok.pl -sejny.pl -skoczow.pl -slask.pl -slupsk.pl -sosnowiec.pl -stalowa-wola.pl -starachowice.pl -stargard.pl -suwalki.pl -swidnica.pl -swiebodzin.pl -swinoujscie.pl -szczecin.pl -szczytno.pl -tarnobrzeg.pl -tgory.pl -turek.pl -tychy.pl -ustka.pl -walbrzych.pl -warmia.pl -warszawa.pl -waw.pl -wegrow.pl -wielun.pl -wlocl.pl -wloclawek.pl -wodzislaw.pl -wolomin.pl -wroclaw.pl -zachpomor.pl -zagan.pl -zarow.pl -zgora.pl -zgorzelec.pl - -// pm : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -pm - -// pn : https://www.iana.org/domains/root/db/pn.html -pn -co.pn -edu.pn -gov.pn -net.pn -org.pn - -// post : https://www.iana.org/domains/root/db/post.html -post - -// pr : http://www.nic.pr/index.asp?f=1 -pr -biz.pr -com.pr -edu.pr -gov.pr -info.pr -isla.pr -name.pr -net.pr -org.pr -pro.pr -// these aren't mentioned on nic.pr, but on https://www.iana.org/domains/root/db/pr.html -ac.pr -est.pr -prof.pr - -// pro : http://registry.pro/get-pro -pro -aaa.pro -aca.pro -acct.pro -avocat.pro -bar.pro -cpa.pro -eng.pro -jur.pro -law.pro -med.pro -recht.pro - -// ps : https://www.iana.org/domains/root/db/ps.html -// http://www.nic.ps/registration/policy.html#reg -ps -com.ps -edu.ps -gov.ps -net.ps -org.ps -plo.ps -sec.ps - -// pt : https://www.dns.pt/en/domain/pt-terms-and-conditions-registration-rules/ -pt -com.pt -edu.pt -gov.pt -int.pt -net.pt -nome.pt -org.pt -publ.pt - -// pw : https://www.iana.org/domains/root/db/pw.html -// Confirmed by registry in private correspondence with @dnsguru 2024-12-09 -pw -gov.pw - -// py : https://www.iana.org/domains/root/db/py.html -// Submitted by registry -py -com.py -coop.py -edu.py -gov.py -mil.py -net.py -org.py - -// qa : http://domains.qa/en/ -qa -com.qa -edu.qa -gov.qa -mil.qa -name.qa -net.qa -org.qa -sch.qa - -// re : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -// Confirmed by registry 2024-11-18 -re -// Closed for registration on 2013-03-15 but domains are still maintained -asso.re -com.re - -// ro : http://www.rotld.ro/ -ro -arts.ro -com.ro -firm.ro -info.ro -nom.ro -nt.ro -org.ro -rec.ro -store.ro -tm.ro -www.ro - -// rs : https://www.rnids.rs/en/domains/national-domains -rs -ac.rs -co.rs -edu.rs -gov.rs -in.rs -org.rs - -// ru : https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf -// Submitted by George Georgievsky -ru - -// rw : https://www.iana.org/domains/root/db/rw.html -rw -ac.rw -co.rw -coop.rw -gov.rw -mil.rw -net.rw -org.rw - -// sa : http://www.nic.net.sa/ -sa -com.sa -edu.sa -gov.sa -med.sa -net.sa -org.sa -pub.sa -sch.sa - -// sb : http://www.sbnic.net.sb/ -// Submitted by registry -sb -com.sb -edu.sb -gov.sb -net.sb -org.sb - -// sc : http://www.nic.sc/ -sc -com.sc -edu.sc -gov.sc -net.sc -org.sc - -// sd : https://www.iana.org/domains/root/db/sd.html -// Submitted by registry -sd -com.sd -edu.sd -gov.sd -info.sd -med.sd -net.sd -org.sd -tv.sd - -// se : https://www.iana.org/domains/root/db/se.html -// https://data.internetstiftelsen.se/barred_domains_list.txt -> Second level domains & Sub-domains -// Confirmed by Registry Services 2024-11-20 -se -a.se -ac.se -b.se -bd.se -brand.se -c.se -d.se -e.se -f.se -fh.se -fhsk.se -fhv.se -g.se -h.se -i.se -k.se -komforb.se -kommunalforbund.se -komvux.se -l.se -lanbib.se -m.se -n.se -naturbruksgymn.se -o.se -org.se -p.se -parti.se -pp.se -press.se -r.se -s.se -t.se -tm.se -u.se -w.se -x.se -y.se -z.se - -// sg : https://www.sgnic.sg/domain-registration/sg-categories-rules -// Confirmed by registry 2024-11-19 -sg -com.sg -edu.sg -gov.sg -net.sg -org.sg - -// sh : http://nic.sh/rules.htm -sh -com.sh -gov.sh -mil.sh -net.sh -org.sh - -// si : https://www.iana.org/domains/root/db/si.html -si - -// sj : No registrations at this time. -// Submitted by registry -sj - -// sk : https://www.iana.org/domains/root/db/sk.html -sk - -// sl : http://www.nic.sl -// Submitted by registry -sl -com.sl -edu.sl -gov.sl -net.sl -org.sl - -// sm : https://www.iana.org/domains/root/db/sm.html -sm - -// sn : https://www.iana.org/domains/root/db/sn.html -sn -art.sn -com.sn -edu.sn -gouv.sn -org.sn -perso.sn -univ.sn - -// so : http://sonic.so/policies/ -so -com.so -edu.so -gov.so -me.so -net.so -org.so - -// sr : https://www.iana.org/domains/root/db/sr.html -sr - -// ss : https://registry.nic.ss/ -// Submitted by registry -ss -biz.ss -co.ss -com.ss -edu.ss -gov.ss -me.ss -net.ss -org.ss -sch.ss - -// st : http://www.nic.st/html/policyrules/ -st -co.st -com.st -consulado.st -edu.st -embaixada.st -mil.st -net.st -org.st -principe.st -saotome.st -store.st - -// su : https://www.iana.org/domains/root/db/su.html -su - -// sv : https://www.iana.org/domains/root/db/sv.html -sv -com.sv -edu.sv -gob.sv -org.sv -red.sv - -// sx : https://www.iana.org/domains/root/db/sx.html -// Submitted by registry -sx -gov.sx - -// sy : https://www.iana.org/domains/root/db/sy.html -sy -com.sy -edu.sy -gov.sy -mil.sy -net.sy -org.sy - -// sz : https://www.iana.org/domains/root/db/sz.html -// http://www.sispa.org.sz/ -sz -ac.sz -co.sz -org.sz - -// tc : https://www.iana.org/domains/root/db/tc.html -tc - -// td : https://www.iana.org/domains/root/db/td.html -td - -// tel : https://www.iana.org/domains/root/db/tel.html -// http://www.telnic.org/ -tel - -// tf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -tf - -// tg : https://www.iana.org/domains/root/db/tg.html -// http://www.nic.tg/ -tg - -// th : https://www.iana.org/domains/root/db/th.html -// Submitted by registry -th -ac.th -co.th -go.th -in.th -mi.th -net.th -or.th - -// tj : http://www.nic.tj/policy.html -tj -ac.tj -biz.tj -co.tj -com.tj -edu.tj -go.tj -gov.tj -int.tj -mil.tj -name.tj -net.tj -nic.tj -org.tj -test.tj -web.tj - -// tk : https://www.iana.org/domains/root/db/tk.html -tk - -// tl : https://www.iana.org/domains/root/db/tl.html -tl -gov.tl - -// tm : https://www.nic.tm/local.html -// Confirmed by registry 2024-11-19 -tm -co.tm -com.tm -edu.tm -gov.tm -mil.tm -net.tm -nom.tm -org.tm - -// tn : http://www.registre.tn/fr/ -// https://whois.ati.tn/ -tn -com.tn -ens.tn -fin.tn -gov.tn -ind.tn -info.tn -intl.tn -mincom.tn -nat.tn -net.tn -org.tn -perso.tn -tourism.tn - -// to : https://www.iana.org/domains/root/db/to.html -// Submitted by registry -to -com.to -edu.to -gov.to -mil.to -net.to -org.to - -// tr : https://nic.tr/ -// https://nic.tr/forms/eng/policies.pdf -// https://nic.tr/index.php?USRACTN=PRICELST -tr -av.tr -bbs.tr -bel.tr -biz.tr -com.tr -dr.tr -edu.tr -gen.tr -gov.tr -info.tr -k12.tr -kep.tr -mil.tr -name.tr -net.tr -org.tr -pol.tr -tel.tr -tsk.tr -tv.tr -web.tr -// Used by Northern Cyprus -nc.tr -// Used by government agencies of Northern Cyprus -gov.nc.tr - -// tt : https://www.nic.tt/ -// Confirmed by registry 2024-11-19 -tt -biz.tt -co.tt -com.tt -edu.tt -gov.tt -info.tt -mil.tt -name.tt -net.tt -org.tt -pro.tt - -// tv : https://www.iana.org/domains/root/db/tv.html -// Not listing any 2LDs as reserved since none seem to exist in practice, -// Wikipedia notwithstanding. -tv - -// tw : https://www.iana.org/domains/root/db/tw.html -// https://twnic.tw/dnservice_catag.php -// Confirmed by registry 2024-11-26 -tw -club.tw -com.tw -ebiz.tw -edu.tw -game.tw -gov.tw -idv.tw -mil.tw -net.tw -org.tw - -// tz : http://www.tznic.or.tz/index.php/domains -// Submitted by registry -tz -ac.tz -co.tz -go.tz -hotel.tz -info.tz -me.tz -mil.tz -mobi.tz -ne.tz -or.tz -sc.tz -tv.tz - -// ua : https://hostmaster.ua/policy/?ua -// Submitted by registry -ua -// ua 2LD -com.ua -edu.ua -gov.ua -in.ua -net.ua -org.ua -// ua geographic names -// https://hostmaster.ua/2ld/ -cherkassy.ua -cherkasy.ua -chernigov.ua -chernihiv.ua -chernivtsi.ua -chernovtsy.ua -ck.ua -cn.ua -cr.ua -crimea.ua -cv.ua -dn.ua -dnepropetrovsk.ua -dnipropetrovsk.ua -donetsk.ua -dp.ua -if.ua -ivano-frankivsk.ua -kh.ua -kharkiv.ua -kharkov.ua -kherson.ua -khmelnitskiy.ua -khmelnytskyi.ua -kiev.ua -kirovograd.ua -km.ua -kr.ua -kropyvnytskyi.ua -krym.ua -ks.ua -kv.ua -kyiv.ua -lg.ua -lt.ua -lugansk.ua -luhansk.ua -lutsk.ua -lv.ua -lviv.ua -mk.ua -mykolaiv.ua -nikolaev.ua -od.ua -odesa.ua -odessa.ua -pl.ua -poltava.ua -rivne.ua -rovno.ua -rv.ua -sb.ua -sebastopol.ua -sevastopol.ua -sm.ua -sumy.ua -te.ua -ternopil.ua -uz.ua -uzhgorod.ua -uzhhorod.ua -vinnica.ua -vinnytsia.ua -vn.ua -volyn.ua -yalta.ua -zakarpattia.ua -zaporizhzhe.ua -zaporizhzhia.ua -zhitomir.ua -zhytomyr.ua -zp.ua -zt.ua - -// ug : https://www.registry.co.ug/ -// https://www.registry.co.ug, https://whois.co.ug -// Confirmed by registry 2025-01-20 -ug -ac.ug -co.ug -com.ug -edu.ug -go.ug -gov.ug -mil.ug -ne.ug -or.ug -org.ug -sc.ug -us.ug - -// uk : https://www.iana.org/domains/root/db/uk.html -// Submitted by registry -uk -ac.uk -co.uk -gov.uk -ltd.uk -me.uk -net.uk -nhs.uk -org.uk -plc.uk -police.uk -*.sch.uk - -// us : https://www.iana.org/domains/root/db/us.html -// Confirmed via the .us zone file by William Harrison 2024-12-10 -us -dni.us -isa.us -nsn.us -// Geographic Names -ak.us -al.us -ar.us -as.us -az.us -ca.us -co.us -ct.us -dc.us -de.us -fl.us -ga.us -gu.us -hi.us -ia.us -id.us -il.us -in.us -ks.us -ky.us -la.us -ma.us -md.us -me.us -mi.us -mn.us -mo.us -ms.us -mt.us -nc.us -nd.us -ne.us -nh.us -nj.us -nm.us -nv.us -ny.us -oh.us -ok.us -or.us -pa.us -pr.us -ri.us -sc.us -sd.us -tn.us -tx.us -ut.us -va.us -vi.us -vt.us -wa.us -wi.us -wv.us -wy.us -// The registrar notes several more specific domains available in each state, -// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat -// haphazard; in some states these domains resolve as addresses, while in others -// only subdomains are available, or even nothing at all. We include the -// most common ones where it's clear that different sites are different -// entities. -k12.ak.us -k12.al.us -k12.ar.us -k12.as.us -k12.az.us -k12.ca.us -k12.co.us -k12.ct.us -k12.dc.us -k12.fl.us -k12.ga.us -k12.gu.us -// k12.hi.us - Bug 614565 - Hawaii has a state-wide DOE login -k12.ia.us -k12.id.us -k12.il.us -k12.in.us -k12.ks.us -k12.ky.us -k12.la.us -k12.ma.us -k12.md.us -k12.me.us -k12.mi.us -k12.mn.us -k12.mo.us -k12.ms.us -k12.mt.us -k12.nc.us -// k12.nd.us - Bug 1028347 - Removed at request of Travis Rosso -k12.ne.us -k12.nh.us -k12.nj.us -k12.nm.us -k12.nv.us -k12.ny.us -k12.oh.us -k12.ok.us -k12.or.us -k12.pa.us -k12.pr.us -// k12.ri.us - Removed at request of Kim Cournoyer -k12.sc.us -// k12.sd.us - Bug 934131 - Removed at request of James Booze -k12.tn.us -k12.tx.us -k12.ut.us -k12.va.us -k12.vi.us -k12.vt.us -k12.wa.us -k12.wi.us -// k12.wv.us - Bug 947705 - Removed at request of Verne Britton -cc.ak.us -lib.ak.us -cc.al.us -lib.al.us -cc.ar.us -lib.ar.us -cc.as.us -lib.as.us -cc.az.us -lib.az.us -cc.ca.us -lib.ca.us -cc.co.us -lib.co.us -cc.ct.us -lib.ct.us -cc.dc.us -lib.dc.us -cc.de.us -cc.fl.us -lib.fl.us -cc.ga.us -lib.ga.us -cc.gu.us -lib.gu.us -cc.hi.us -lib.hi.us -cc.ia.us -lib.ia.us -cc.id.us -lib.id.us -cc.il.us -lib.il.us -cc.in.us -lib.in.us -cc.ks.us -lib.ks.us -cc.ky.us -lib.ky.us -cc.la.us -lib.la.us -cc.ma.us -lib.ma.us -cc.md.us -lib.md.us -cc.me.us -lib.me.us -cc.mi.us -lib.mi.us -cc.mn.us -lib.mn.us -cc.mo.us -lib.mo.us -cc.ms.us -cc.mt.us -lib.mt.us -cc.nc.us -lib.nc.us -cc.nd.us -lib.nd.us -cc.ne.us -lib.ne.us -cc.nh.us -lib.nh.us -cc.nj.us -lib.nj.us -cc.nm.us -lib.nm.us -cc.nv.us -lib.nv.us -cc.ny.us -lib.ny.us -cc.oh.us -lib.oh.us -cc.ok.us -lib.ok.us -cc.or.us -lib.or.us -cc.pa.us -lib.pa.us -cc.pr.us -lib.pr.us -cc.ri.us -lib.ri.us -cc.sc.us -lib.sc.us -cc.sd.us -lib.sd.us -cc.tn.us -lib.tn.us -cc.tx.us -lib.tx.us -cc.ut.us -lib.ut.us -cc.va.us -lib.va.us -cc.vi.us -lib.vi.us -cc.vt.us -lib.vt.us -cc.wa.us -lib.wa.us -cc.wi.us -lib.wi.us -cc.wv.us -cc.wy.us -k12.wy.us -// lib.wv.us - Bug 941670 - Removed at request of Larry W Arnold -lib.wy.us -// k12.ma.us contains school districts in Massachusetts. The 4LDs are -// managed independently except for private (PVT), charter (CHTR) and -// parochial (PAROCH) schools. Those are delegated directly to the -// 5LD operators. -chtr.k12.ma.us -paroch.k12.ma.us -pvt.k12.ma.us -// Merit Network, Inc. maintains the registry for =~ /(k12|cc|lib).mi.us/ and the following -// see also: https://domreg.merit.edu : domreg@merit.edu -// see also: whois -h whois.domreg.merit.edu help -ann-arbor.mi.us -cog.mi.us -dst.mi.us -eaton.mi.us -gen.mi.us -mus.mi.us -tec.mi.us -washtenaw.mi.us - -// uy : http://www.nic.org.uy/ -uy -com.uy -edu.uy -gub.uy -mil.uy -net.uy -org.uy - -// uz : http://www.reg.uz/ -uz -co.uz -com.uz -net.uz -org.uz - -// va : https://www.iana.org/domains/root/db/va.html -va - -// vc : https://www.iana.org/domains/root/db/vc.html -// Submitted by registry -vc -com.vc -edu.vc -gov.vc -mil.vc -net.vc -org.vc - -// ve : https://registro.nic.ve/ -// Submitted by registry nic@nic.ve and nicve@conatel.gob.ve -ve -arts.ve -bib.ve -co.ve -com.ve -e12.ve -edu.ve -emprende.ve -firm.ve -gob.ve -gov.ve -info.ve -int.ve -mil.ve -net.ve -nom.ve -org.ve -rar.ve -rec.ve -store.ve -tec.ve -web.ve - -// vg : https://www.iana.org/domains/root/db/vg.html -// Confirmed by registry 2025-01-10 -vg -edu.vg - -// vi : https://www.iana.org/domains/root/db/vi.html -vi -co.vi -com.vi -k12.vi -net.vi -org.vi - -// vn : https://www.vnnic.vn/en/domain/cctld-vn -// https://vnnic.vn/sites/default/files/tailieu/vn.cctld.domains.txt -vn -ac.vn -ai.vn -biz.vn -com.vn -edu.vn -gov.vn -health.vn -id.vn -info.vn -int.vn -io.vn -name.vn -net.vn -org.vn -pro.vn - -// vn geographical names -angiang.vn -bacgiang.vn -backan.vn -baclieu.vn -bacninh.vn -baria-vungtau.vn -bentre.vn -binhdinh.vn -binhduong.vn -binhphuoc.vn -binhthuan.vn -camau.vn -cantho.vn -caobang.vn -daklak.vn -daknong.vn -danang.vn -dienbien.vn -dongnai.vn -dongthap.vn -gialai.vn -hagiang.vn -haiduong.vn -haiphong.vn -hanam.vn -hanoi.vn -hatinh.vn -haugiang.vn -hoabinh.vn -hungyen.vn -khanhhoa.vn -kiengiang.vn -kontum.vn -laichau.vn -lamdong.vn -langson.vn -laocai.vn -longan.vn -namdinh.vn -nghean.vn -ninhbinh.vn -ninhthuan.vn -phutho.vn -phuyen.vn -quangbinh.vn -quangnam.vn -quangngai.vn -quangninh.vn -quangtri.vn -soctrang.vn -sonla.vn -tayninh.vn -thaibinh.vn -thainguyen.vn -thanhhoa.vn -thanhphohochiminh.vn -thuathienhue.vn -tiengiang.vn -travinh.vn -tuyenquang.vn -vinhlong.vn -vinhphuc.vn -yenbai.vn - -// vu : https://www.iana.org/domains/root/db/vu.html -// http://www.vunic.vu/ -vu -com.vu -edu.vu -net.vu -org.vu - -// wf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -wf - -// ws : https://www.iana.org/domains/root/db/ws.html -// http://samoanic.ws/index.dhtml -ws -com.ws -edu.ws -gov.ws -net.ws -org.ws - -// yt : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf -yt - -// IDN ccTLDs -// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then -// U-label, and follow this format: -// // A-Label ("", [, variant info]) : -// // [sponsoring org] -// U-Label - -// xn--mgbaam7a8h ("Emerat", Arabic) : AE -// http://nic.ae/english/arabicdomain/rules.jsp -امارات - -// xn--y9a3aq ("hye", Armenian) : AM -// ISOC AM (operated by .am Registry) -հայ - -// xn--54b7fta0cc ("Bangla", Bangla) : BD -বাংলা - -// xn--90ae ("bg", Bulgarian) : BG -бг - -// xn--mgbcpq6gpa1a ("albahrain", Arabic) : BH -البحرين - -// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY -// Operated by .by registry -бел - -// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN -// CNNIC -// https://www.cnnic.cn/11/192/index.html -中国 - -// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN -// CNNIC -// https://www.cnnic.com.cn/AU/MediaC/Announcement/201609/t20160905_54470.htm -中國 - -// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ -الجزائر - -// xn--wgbh1c ("Egypt/Masr", Arabic) : EG -// http://www.dotmasr.eg/ -مصر - -// xn--e1a4c ("eu", Cyrillic) : EU -// https://eurid.eu -ею - -// xn--qxa6a ("eu", Greek) : EU -// https://eurid.eu -ευ - -// xn--mgbah1a3hjkrd ("Mauritania", Arabic) : MR -موريتانيا - -// xn--node ("ge", Georgian Mkhedruli) : GE -გე - -// xn--qxam ("el", Greek) : GR -// Hellenic Ministry of Infrastructure, Transport, and Networks -ελ - -// xn--j6w193g ("Hong Kong", Chinese) : HK -// https://www.hkirc.hk -// Submitted by registry -// https://www.hkirc.hk/content.jsp?id=30#!/34 -香港 -個人.香港 -公司.香港 -政府.香港 -教育.香港 -組織.香港 -網絡.香港 - -// xn--2scrj9c ("Bharat", Kannada) : IN -// India -ಭಾರತ - -// xn--3hcrj9c ("Bharat", Oriya) : IN -// India -ଭାରତ - -// xn--45br5cyl ("Bharatam", Assamese) : IN -// India -ভাৰত - -// xn--h2breg3eve ("Bharatam", Sanskrit) : IN -// India -भारतम् - -// xn--h2brj9c8c ("Bharot", Santali) : IN -// India -भारोत - -// xn--mgbgu82a ("Bharat", Sindhi) : IN -// India -ڀارت - -// xn--rvc1e0am3e ("Bharatam", Malayalam) : IN -// India -ഭാരതം - -// xn--h2brj9c ("Bharat", Devanagari) : IN -// India -भारत - -// xn--mgbbh1a ("Bharat", Kashmiri) : IN -// India -بارت - -// xn--mgbbh1a71e ("Bharat", Arabic) : IN -// India -بھارت - -// xn--fpcrj9c3d ("Bharat", Telugu) : IN -// India -భారత్ - -// xn--gecrj9c ("Bharat", Gujarati) : IN -// India -ભારત - -// xn--s9brj9c ("Bharat", Gurmukhi) : IN -// India -ਭਾਰਤ - -// xn--45brj9c ("Bharat", Bengali) : IN -// India -ভারত - -// xn--xkc2dl3a5ee0h ("India", Tamil) : IN -// India -இந்தியா - -// xn--mgba3a4f16a ("Iran", Persian) : IR -ایران - -// xn--mgba3a4fra ("Iran", Arabic) : IR -ايران - -// xn--mgbtx2b ("Iraq", Arabic) : IQ -// Communications and Media Commission -عراق - -// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO -// National Information Technology Center (NITC) -// Royal Scientific Society, Al-Jubeiha -الاردن - -// xn--3e0b707e ("Republic of Korea", Hangul) : KR -한국 - -// xn--80ao21a ("Kaz", Kazakh) : KZ -қаз - -// xn--q7ce6a ("Lao", Lao) : LA -ລາວ - -// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK -// https://nic.lk -ලංකා - -// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK -// https://nic.lk -இலங்கை - -// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA -المغرب - -// xn--d1alf ("mkd", Macedonian) : MK -// MARnet -мкд - -// xn--l1acc ("mon", Mongolian) : MN -мон - -// xn--mix891f ("Macao", Chinese, Traditional) : MO -// MONIC / HNET Asia (Registry Operator for .mo) -澳門 - -// xn--mix082f ("Macao", Chinese, Simplified) : MO -澳门 - -// xn--mgbx4cd0ab ("Malaysia", Malay) : MY -مليسيا - -// xn--mgb9awbf ("Oman", Arabic) : OM -عمان - -// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK -پاکستان - -// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK -پاكستان - -// xn--ygbi2ammx ("Falasteen", Arabic) : PS -// The Palestinian National Internet Naming Authority (PNINA) -// http://www.pnina.ps -فلسطين - -// xn--90a3ac ("srb", Cyrillic) : RS -// https://www.rnids.rs/en/domains/national-domains -срб -ак.срб -обр.срб -од.срб -орг.срб -пр.срб -упр.срб - -// xn--p1ai ("rf", Russian-Cyrillic) : RU -// https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf -// Submitted by George Georgievsky -рф - -// xn--wgbl6a ("Qatar", Arabic) : QA -// http://www.ict.gov.qa/ -قطر - -// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA -// http://www.nic.net.sa/ -السعودية - -// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant): SA -السعودیة - -// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA -السعودیۃ - -// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA -السعوديه - -// xn--mgbpl2fh ("sudan", Arabic) : SD -// Operated by .sd registry -سودان - -// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG -新加坡 - -// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG -சிங்கப்பூர் - -// xn--ogbpf8fl ("Syria", Arabic) : SY -سورية - -// xn--mgbtf8fl ("Syria", Arabic, variant) : SY -سوريا - -// xn--o3cw4h ("Thai", Thai) : TH -// http://www.thnic.co.th -ไทย -ทหาร.ไทย -ธุรกิจ.ไทย -เน็ต.ไทย -รัฐบาล.ไทย -ศึกษา.ไทย -องค์กร.ไทย - -// xn--pgbs0dh ("Tunisia", Arabic) : TN -// http://nic.tn -تونس - -// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW -// https://twnic.tw/dnservice_catag.php -台灣 - -// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW -// http://www.twnic.net/english/dn/dn_07a.htm -台湾 - -// xn--nnx388a ("Taiwan", Chinese, variant) : TW -臺灣 - -// xn--j1amh ("ukr", Cyrillic) : UA -укр - -// xn--mgb2ddes ("AlYemen", Arabic) : YE -اليمن - -// xxx : http://icmregistry.com -xxx - -// ye : http://www.y.net.ye/services/domain_name.htm -ye -com.ye -edu.ye -gov.ye -mil.ye -net.ye -org.ye - -// za : https://www.iana.org/domains/root/db/za.html -ac.za -agric.za -alt.za -co.za -edu.za -gov.za -grondar.za -law.za -mil.za -net.za -ngo.za -nic.za -nis.za -nom.za -org.za -school.za -tm.za -web.za - -// zm : https://zicta.zm/ -// Submitted by registry -zm -ac.zm -biz.zm -co.zm -com.zm -edu.zm -gov.zm -info.zm -mil.zm -net.zm -org.zm -sch.zm - -// zw : https://www.potraz.gov.zw/ -// Confirmed by registry 2017-01-25 -zw -ac.zw -co.zw -gov.zw -mil.zw -org.zw - -// newGTLDs - -// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2025-10-01T15:18:26Z -// This list is auto-generated, don't edit it manually. -// aaa : American Automobile Association, Inc. -// https://www.iana.org/domains/root/db/aaa.html -aaa - -// aarp : AARP -// https://www.iana.org/domains/root/db/aarp.html -aarp - -// abb : ABB Ltd -// https://www.iana.org/domains/root/db/abb.html -abb - -// abbott : Abbott Laboratories, Inc. -// https://www.iana.org/domains/root/db/abbott.html -abbott - -// abbvie : AbbVie Inc. -// https://www.iana.org/domains/root/db/abbvie.html -abbvie - -// abc : Disney Enterprises, Inc. -// https://www.iana.org/domains/root/db/abc.html -abc - -// able : Able Inc. -// https://www.iana.org/domains/root/db/able.html -able - -// abogado : Registry Services, LLC -// https://www.iana.org/domains/root/db/abogado.html -abogado - -// abudhabi : Abu Dhabi Systems and Information Centre -// https://www.iana.org/domains/root/db/abudhabi.html -abudhabi - -// academy : Binky Moon, LLC -// https://www.iana.org/domains/root/db/academy.html -academy - -// accenture : Accenture plc -// https://www.iana.org/domains/root/db/accenture.html -accenture - -// accountant : dot Accountant Limited -// https://www.iana.org/domains/root/db/accountant.html -accountant - -// accountants : Binky Moon, LLC -// https://www.iana.org/domains/root/db/accountants.html -accountants - -// aco : ACO Severin Ahlmann GmbH & Co. KG -// https://www.iana.org/domains/root/db/aco.html -aco - -// actor : Dog Beach, LLC -// https://www.iana.org/domains/root/db/actor.html -actor - -// ads : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/ads.html -ads - -// adult : ICM Registry AD LLC -// https://www.iana.org/domains/root/db/adult.html -adult - -// aeg : Aktiebolaget Electrolux -// https://www.iana.org/domains/root/db/aeg.html -aeg - -// aetna : Aetna Life Insurance Company -// https://www.iana.org/domains/root/db/aetna.html -aetna - -// afl : Australian Football League -// https://www.iana.org/domains/root/db/afl.html -afl - -// africa : ZA Central Registry NPC trading as Registry.Africa -// https://www.iana.org/domains/root/db/africa.html -africa - -// agakhan : Fondation Aga Khan (Aga Khan Foundation) -// https://www.iana.org/domains/root/db/agakhan.html -agakhan - -// agency : Binky Moon, LLC -// https://www.iana.org/domains/root/db/agency.html -agency - -// aig : American International Group, Inc. -// https://www.iana.org/domains/root/db/aig.html -aig - -// airbus : Airbus S.A.S. -// https://www.iana.org/domains/root/db/airbus.html -airbus - -// airforce : Dog Beach, LLC -// https://www.iana.org/domains/root/db/airforce.html -airforce - -// airtel : Bharti Airtel Limited -// https://www.iana.org/domains/root/db/airtel.html -airtel - -// akdn : Fondation Aga Khan (Aga Khan Foundation) -// https://www.iana.org/domains/root/db/akdn.html -akdn - -// alibaba : Alibaba Group Holding Limited -// https://www.iana.org/domains/root/db/alibaba.html -alibaba - -// alipay : Alibaba Group Holding Limited -// https://www.iana.org/domains/root/db/alipay.html -alipay - -// allfinanz : Allfinanz Deutsche Vermögensberatung Aktiengesellschaft -// https://www.iana.org/domains/root/db/allfinanz.html -allfinanz - -// allstate : Allstate Fire and Casualty Insurance Company -// https://www.iana.org/domains/root/db/allstate.html -allstate - -// ally : Ally Financial Inc. -// https://www.iana.org/domains/root/db/ally.html -ally - -// alsace : Region Grand Est -// https://www.iana.org/domains/root/db/alsace.html -alsace - -// alstom : ALSTOM -// https://www.iana.org/domains/root/db/alstom.html -alstom - -// amazon : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/amazon.html -amazon - -// americanexpress : American Express Travel Related Services Company, Inc. -// https://www.iana.org/domains/root/db/americanexpress.html -americanexpress - -// americanfamily : AmFam, Inc. -// https://www.iana.org/domains/root/db/americanfamily.html -americanfamily - -// amex : American Express Travel Related Services Company, Inc. -// https://www.iana.org/domains/root/db/amex.html -amex - -// amfam : AmFam, Inc. -// https://www.iana.org/domains/root/db/amfam.html -amfam - -// amica : Amica Mutual Insurance Company -// https://www.iana.org/domains/root/db/amica.html -amica - -// amsterdam : Gemeente Amsterdam -// https://www.iana.org/domains/root/db/amsterdam.html -amsterdam - -// analytics : Campus IP LLC -// https://www.iana.org/domains/root/db/analytics.html -analytics - -// android : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/android.html -android - -// anquan : Beijing Qihu Keji Co., Ltd. -// https://www.iana.org/domains/root/db/anquan.html -anquan - -// anz : Australia and New Zealand Banking Group Limited -// https://www.iana.org/domains/root/db/anz.html -anz - -// aol : Yahoo Inc. -// https://www.iana.org/domains/root/db/aol.html -aol - -// apartments : Binky Moon, LLC -// https://www.iana.org/domains/root/db/apartments.html -apartments - -// app : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/app.html -app - -// apple : Apple Inc. -// https://www.iana.org/domains/root/db/apple.html -apple - -// aquarelle : Aquarelle.com -// https://www.iana.org/domains/root/db/aquarelle.html -aquarelle - -// arab : League of Arab States -// https://www.iana.org/domains/root/db/arab.html -arab - -// aramco : Aramco Services Company -// https://www.iana.org/domains/root/db/aramco.html -aramco - -// archi : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/archi.html -archi - -// army : Dog Beach, LLC -// https://www.iana.org/domains/root/db/army.html -army - -// art : UK Creative Ideas Limited -// https://www.iana.org/domains/root/db/art.html -art - -// arte : Association Relative à la Télévision Européenne G.E.I.E. -// https://www.iana.org/domains/root/db/arte.html -arte - -// asda : Asda Stores Limited -// https://www.iana.org/domains/root/db/asda.html -asda - -// associates : Binky Moon, LLC -// https://www.iana.org/domains/root/db/associates.html -associates - -// athleta : The Gap, Inc. -// https://www.iana.org/domains/root/db/athleta.html -athleta - -// attorney : Dog Beach, LLC -// https://www.iana.org/domains/root/db/attorney.html -attorney - -// auction : Dog Beach, LLC -// https://www.iana.org/domains/root/db/auction.html -auction - -// audi : AUDI Aktiengesellschaft -// https://www.iana.org/domains/root/db/audi.html -audi - -// audible : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/audible.html -audible - -// audio : XYZ.COM LLC -// https://www.iana.org/domains/root/db/audio.html -audio - -// auspost : Australian Postal Corporation -// https://www.iana.org/domains/root/db/auspost.html -auspost - -// author : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/author.html -author - -// auto : XYZ.COM LLC -// https://www.iana.org/domains/root/db/auto.html -auto - -// autos : XYZ.COM LLC -// https://www.iana.org/domains/root/db/autos.html -autos - -// aws : AWS Registry LLC -// https://www.iana.org/domains/root/db/aws.html -aws - -// axa : AXA Group Operations SAS -// https://www.iana.org/domains/root/db/axa.html -axa - -// azure : Microsoft Corporation -// https://www.iana.org/domains/root/db/azure.html -azure - -// baby : XYZ.COM LLC -// https://www.iana.org/domains/root/db/baby.html -baby - -// baidu : Baidu, Inc. -// https://www.iana.org/domains/root/db/baidu.html -baidu - -// banamex : Citigroup Inc. -// https://www.iana.org/domains/root/db/banamex.html -banamex - -// band : Dog Beach, LLC -// https://www.iana.org/domains/root/db/band.html -band - -// bank : fTLD Registry Services LLC -// https://www.iana.org/domains/root/db/bank.html -bank - -// bar : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable -// https://www.iana.org/domains/root/db/bar.html -bar - -// barcelona : Municipi de Barcelona -// https://www.iana.org/domains/root/db/barcelona.html -barcelona - -// barclaycard : Barclays Bank PLC -// https://www.iana.org/domains/root/db/barclaycard.html -barclaycard - -// barclays : Barclays Bank PLC -// https://www.iana.org/domains/root/db/barclays.html -barclays - -// barefoot : Gallo Vineyards, Inc. -// https://www.iana.org/domains/root/db/barefoot.html -barefoot - -// bargains : Binky Moon, LLC -// https://www.iana.org/domains/root/db/bargains.html -bargains - -// baseball : MLB Advanced Media DH, LLC -// https://www.iana.org/domains/root/db/baseball.html -baseball - -// basketball : Fédération Internationale de Basketball (FIBA) -// https://www.iana.org/domains/root/db/basketball.html -basketball - -// bauhaus : Werkhaus GmbH -// https://www.iana.org/domains/root/db/bauhaus.html -bauhaus - -// bayern : Bayern Connect GmbH -// https://www.iana.org/domains/root/db/bayern.html -bayern - -// bbc : British Broadcasting Corporation -// https://www.iana.org/domains/root/db/bbc.html -bbc - -// bbt : BB&T Corporation -// https://www.iana.org/domains/root/db/bbt.html -bbt - -// bbva : BANCO BILBAO VIZCAYA ARGENTARIA, S.A. -// https://www.iana.org/domains/root/db/bbva.html -bbva - -// bcg : The Boston Consulting Group, Inc. -// https://www.iana.org/domains/root/db/bcg.html -bcg - -// bcn : Municipi de Barcelona -// https://www.iana.org/domains/root/db/bcn.html -bcn - -// beats : Beats Electronics, LLC -// https://www.iana.org/domains/root/db/beats.html -beats - -// beauty : XYZ.COM LLC -// https://www.iana.org/domains/root/db/beauty.html -beauty - -// beer : Registry Services, LLC -// https://www.iana.org/domains/root/db/beer.html -beer - -// berlin : dotBERLIN GmbH & Co. KG -// https://www.iana.org/domains/root/db/berlin.html -berlin - -// best : BestTLD Pty Ltd -// https://www.iana.org/domains/root/db/best.html -best - -// bestbuy : BBY Solutions, Inc. -// https://www.iana.org/domains/root/db/bestbuy.html -bestbuy - -// bet : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/bet.html -bet - -// bharti : Bharti Enterprises (Holding) Private Limited -// https://www.iana.org/domains/root/db/bharti.html -bharti - -// bible : American Bible Society -// https://www.iana.org/domains/root/db/bible.html -bible - -// bid : dot Bid Limited -// https://www.iana.org/domains/root/db/bid.html -bid - -// bike : Binky Moon, LLC -// https://www.iana.org/domains/root/db/bike.html -bike - -// bing : Microsoft Corporation -// https://www.iana.org/domains/root/db/bing.html -bing - -// bingo : Binky Moon, LLC -// https://www.iana.org/domains/root/db/bingo.html -bingo - -// bio : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/bio.html -bio - -// black : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/black.html -black - -// blackfriday : Registry Services, LLC -// https://www.iana.org/domains/root/db/blackfriday.html -blackfriday - -// blockbuster : Dish DBS Corporation -// https://www.iana.org/domains/root/db/blockbuster.html -blockbuster - -// blog : Knock Knock WHOIS There, LLC -// https://www.iana.org/domains/root/db/blog.html -blog - -// bloomberg : Bloomberg IP Holdings LLC -// https://www.iana.org/domains/root/db/bloomberg.html -bloomberg - -// blue : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/blue.html -blue - -// bms : Bristol-Myers Squibb Company -// https://www.iana.org/domains/root/db/bms.html -bms - -// bmw : Bayerische Motoren Werke Aktiengesellschaft -// https://www.iana.org/domains/root/db/bmw.html -bmw - -// bnpparibas : BNP Paribas -// https://www.iana.org/domains/root/db/bnpparibas.html -bnpparibas - -// boats : XYZ.COM LLC -// https://www.iana.org/domains/root/db/boats.html -boats - -// boehringer : Boehringer Ingelheim International GmbH -// https://www.iana.org/domains/root/db/boehringer.html -boehringer - -// bofa : Bank of America Corporation -// https://www.iana.org/domains/root/db/bofa.html -bofa - -// bom : Núcleo de Informação e Coordenação do Ponto BR - NIC.br -// https://www.iana.org/domains/root/db/bom.html -bom - -// bond : ShortDot SA -// https://www.iana.org/domains/root/db/bond.html -bond - -// boo : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/boo.html -boo - -// book : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/book.html -book - -// booking : Booking.com B.V. -// https://www.iana.org/domains/root/db/booking.html -booking - -// bosch : Robert Bosch GMBH -// https://www.iana.org/domains/root/db/bosch.html -bosch - -// bostik : Bostik SA -// https://www.iana.org/domains/root/db/bostik.html -bostik - -// boston : Registry Services, LLC -// https://www.iana.org/domains/root/db/boston.html -boston - -// bot : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/bot.html -bot - -// boutique : Binky Moon, LLC -// https://www.iana.org/domains/root/db/boutique.html -boutique - -// box : Intercap Registry Inc. -// https://www.iana.org/domains/root/db/box.html -box - -// bradesco : Banco Bradesco S.A. -// https://www.iana.org/domains/root/db/bradesco.html -bradesco - -// bridgestone : Bridgestone Corporation -// https://www.iana.org/domains/root/db/bridgestone.html -bridgestone - -// broadway : Celebrate Broadway, Inc. -// https://www.iana.org/domains/root/db/broadway.html -broadway - -// broker : Dog Beach, LLC -// https://www.iana.org/domains/root/db/broker.html -broker - -// brother : Brother Industries, Ltd. -// https://www.iana.org/domains/root/db/brother.html -brother - -// brussels : DNS.be vzw -// https://www.iana.org/domains/root/db/brussels.html -brussels - -// build : Plan Bee LLC -// https://www.iana.org/domains/root/db/build.html -build - -// builders : Binky Moon, LLC -// https://www.iana.org/domains/root/db/builders.html -builders - -// business : Binky Moon, LLC -// https://www.iana.org/domains/root/db/business.html -business - -// buy : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/buy.html -buy - -// buzz : DOTSTRATEGY CO. -// https://www.iana.org/domains/root/db/buzz.html -buzz - -// bzh : Association www.bzh -// https://www.iana.org/domains/root/db/bzh.html -bzh - -// cab : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cab.html -cab - -// cafe : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cafe.html -cafe - -// cal : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/cal.html -cal - -// call : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/call.html -call - -// calvinklein : PVH gTLD Holdings LLC -// https://www.iana.org/domains/root/db/calvinklein.html -calvinklein - -// cam : Cam Connecting SARL -// https://www.iana.org/domains/root/db/cam.html -cam - -// camera : Binky Moon, LLC -// https://www.iana.org/domains/root/db/camera.html -camera - -// camp : Binky Moon, LLC -// https://www.iana.org/domains/root/db/camp.html -camp - -// canon : Canon Inc. -// https://www.iana.org/domains/root/db/canon.html -canon - -// capetown : ZA Central Registry NPC trading as ZA Central Registry -// https://www.iana.org/domains/root/db/capetown.html -capetown - -// capital : Binky Moon, LLC -// https://www.iana.org/domains/root/db/capital.html -capital - -// capitalone : Capital One Financial Corporation -// https://www.iana.org/domains/root/db/capitalone.html -capitalone - -// car : XYZ.COM LLC -// https://www.iana.org/domains/root/db/car.html -car - -// caravan : Caravan International, Inc. -// https://www.iana.org/domains/root/db/caravan.html -caravan - -// cards : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cards.html -cards - -// care : Binky Moon, LLC -// https://www.iana.org/domains/root/db/care.html -care - -// career : dotCareer LLC -// https://www.iana.org/domains/root/db/career.html -career - -// careers : Binky Moon, LLC -// https://www.iana.org/domains/root/db/careers.html -careers - -// cars : XYZ.COM LLC -// https://www.iana.org/domains/root/db/cars.html -cars - -// casa : Registry Services, LLC -// https://www.iana.org/domains/root/db/casa.html -casa - -// case : Digity, LLC -// https://www.iana.org/domains/root/db/case.html -case - -// cash : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cash.html -cash - -// casino : Binky Moon, LLC -// https://www.iana.org/domains/root/db/casino.html -casino - -// catering : Binky Moon, LLC -// https://www.iana.org/domains/root/db/catering.html -catering - -// catholic : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) -// https://www.iana.org/domains/root/db/catholic.html -catholic - -// cba : COMMONWEALTH BANK OF AUSTRALIA -// https://www.iana.org/domains/root/db/cba.html -cba - -// cbn : The Christian Broadcasting Network, Inc. -// https://www.iana.org/domains/root/db/cbn.html -cbn - -// cbre : CBRE, Inc. -// https://www.iana.org/domains/root/db/cbre.html -cbre - -// center : Binky Moon, LLC -// https://www.iana.org/domains/root/db/center.html -center - -// ceo : XYZ.COM LLC -// https://www.iana.org/domains/root/db/ceo.html -ceo - -// cern : European Organization for Nuclear Research ("CERN") -// https://www.iana.org/domains/root/db/cern.html -cern - -// cfa : CFA Institute -// https://www.iana.org/domains/root/db/cfa.html -cfa - -// cfd : ShortDot SA -// https://www.iana.org/domains/root/db/cfd.html -cfd - -// chanel : Chanel International B.V. -// https://www.iana.org/domains/root/db/chanel.html -chanel - -// channel : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/channel.html -channel - -// charity : Public Interest Registry -// https://www.iana.org/domains/root/db/charity.html -charity - -// chase : JPMorgan Chase Bank, National Association -// https://www.iana.org/domains/root/db/chase.html -chase - -// chat : Binky Moon, LLC -// https://www.iana.org/domains/root/db/chat.html -chat - -// cheap : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cheap.html -cheap - -// chintai : CHINTAI Corporation -// https://www.iana.org/domains/root/db/chintai.html -chintai - -// christmas : XYZ.COM LLC -// https://www.iana.org/domains/root/db/christmas.html -christmas - -// chrome : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/chrome.html -chrome - -// church : Binky Moon, LLC -// https://www.iana.org/domains/root/db/church.html -church - -// cipriani : Hotel Cipriani Srl -// https://www.iana.org/domains/root/db/cipriani.html -cipriani - -// circle : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/circle.html -circle - -// cisco : Cisco Technology, Inc. -// https://www.iana.org/domains/root/db/cisco.html -cisco - -// citadel : Citadel Domain LLC -// https://www.iana.org/domains/root/db/citadel.html -citadel - -// citi : Citigroup Inc. -// https://www.iana.org/domains/root/db/citi.html -citi - -// citic : CITIC Group Corporation -// https://www.iana.org/domains/root/db/citic.html -citic - -// city : Binky Moon, LLC -// https://www.iana.org/domains/root/db/city.html -city - -// claims : Binky Moon, LLC -// https://www.iana.org/domains/root/db/claims.html -claims - -// cleaning : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cleaning.html -cleaning - -// click : Waterford Limited -// https://www.iana.org/domains/root/db/click.html -click - -// clinic : Binky Moon, LLC -// https://www.iana.org/domains/root/db/clinic.html -clinic - -// clinique : The Estée Lauder Companies Inc. -// https://www.iana.org/domains/root/db/clinique.html -clinique - -// clothing : Binky Moon, LLC -// https://www.iana.org/domains/root/db/clothing.html -clothing - -// cloud : Aruba PEC S.p.A. -// https://www.iana.org/domains/root/db/cloud.html -cloud - -// club : Registry Services, LLC -// https://www.iana.org/domains/root/db/club.html -club - -// clubmed : Club Méditerranée S.A. -// https://www.iana.org/domains/root/db/clubmed.html -clubmed - -// coach : Binky Moon, LLC -// https://www.iana.org/domains/root/db/coach.html -coach - -// codes : Binky Moon, LLC -// https://www.iana.org/domains/root/db/codes.html -codes - -// coffee : Binky Moon, LLC -// https://www.iana.org/domains/root/db/coffee.html -coffee - -// college : XYZ.COM LLC -// https://www.iana.org/domains/root/db/college.html -college - -// cologne : dotKoeln GmbH -// https://www.iana.org/domains/root/db/cologne.html -cologne - -// commbank : COMMONWEALTH BANK OF AUSTRALIA -// https://www.iana.org/domains/root/db/commbank.html -commbank - -// community : Binky Moon, LLC -// https://www.iana.org/domains/root/db/community.html -community - -// company : Binky Moon, LLC -// https://www.iana.org/domains/root/db/company.html -company - -// compare : Registry Services, LLC -// https://www.iana.org/domains/root/db/compare.html -compare - -// computer : Binky Moon, LLC -// https://www.iana.org/domains/root/db/computer.html -computer - -// comsec : VeriSign, Inc. -// https://www.iana.org/domains/root/db/comsec.html -comsec - -// condos : Binky Moon, LLC -// https://www.iana.org/domains/root/db/condos.html -condos - -// construction : Binky Moon, LLC -// https://www.iana.org/domains/root/db/construction.html -construction - -// consulting : Dog Beach, LLC -// https://www.iana.org/domains/root/db/consulting.html -consulting - -// contact : Dog Beach, LLC -// https://www.iana.org/domains/root/db/contact.html -contact - -// contractors : Binky Moon, LLC -// https://www.iana.org/domains/root/db/contractors.html -contractors - -// cooking : Registry Services, LLC -// https://www.iana.org/domains/root/db/cooking.html -cooking - -// cool : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cool.html -cool - -// corsica : Collectivité de Corse -// https://www.iana.org/domains/root/db/corsica.html -corsica - -// country : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/country.html -country - -// coupon : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/coupon.html -coupon - -// coupons : Binky Moon, LLC -// https://www.iana.org/domains/root/db/coupons.html -coupons - -// courses : Registry Services, LLC -// https://www.iana.org/domains/root/db/courses.html -courses - -// cpa : American Institute of Certified Public Accountants -// https://www.iana.org/domains/root/db/cpa.html -cpa - -// credit : Binky Moon, LLC -// https://www.iana.org/domains/root/db/credit.html -credit - -// creditcard : Binky Moon, LLC -// https://www.iana.org/domains/root/db/creditcard.html -creditcard - -// creditunion : DotCooperation LLC -// https://www.iana.org/domains/root/db/creditunion.html -creditunion - -// cricket : dot Cricket Limited -// https://www.iana.org/domains/root/db/cricket.html -cricket - -// crown : Crown Equipment Corporation -// https://www.iana.org/domains/root/db/crown.html -crown - -// crs : Federated Co-operatives Limited -// https://www.iana.org/domains/root/db/crs.html -crs - -// cruise : Viking River Cruises (Bermuda) Ltd. -// https://www.iana.org/domains/root/db/cruise.html -cruise - -// cruises : Binky Moon, LLC -// https://www.iana.org/domains/root/db/cruises.html -cruises - -// cuisinella : SCHMIDT GROUPE S.A.S. -// https://www.iana.org/domains/root/db/cuisinella.html -cuisinella - -// cymru : Nominet UK -// https://www.iana.org/domains/root/db/cymru.html -cymru - -// cyou : ShortDot SA -// https://www.iana.org/domains/root/db/cyou.html -cyou - -// dad : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/dad.html -dad - -// dance : Dog Beach, LLC -// https://www.iana.org/domains/root/db/dance.html -dance - -// data : Dish DBS Corporation -// https://www.iana.org/domains/root/db/data.html -data - -// date : dot Date Limited -// https://www.iana.org/domains/root/db/date.html -date - -// dating : Binky Moon, LLC -// https://www.iana.org/domains/root/db/dating.html -dating - -// datsun : NISSAN MOTOR CO., LTD. -// https://www.iana.org/domains/root/db/datsun.html -datsun - -// day : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/day.html -day - -// dclk : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/dclk.html -dclk - -// dds : Registry Services, LLC -// https://www.iana.org/domains/root/db/dds.html -dds - -// deal : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/deal.html -deal - -// dealer : Intercap Registry Inc. -// https://www.iana.org/domains/root/db/dealer.html -dealer - -// deals : Binky Moon, LLC -// https://www.iana.org/domains/root/db/deals.html -deals - -// degree : Dog Beach, LLC -// https://www.iana.org/domains/root/db/degree.html -degree - -// delivery : Binky Moon, LLC -// https://www.iana.org/domains/root/db/delivery.html -delivery - -// dell : Dell Inc. -// https://www.iana.org/domains/root/db/dell.html -dell - -// deloitte : Deloitte Touche Tohmatsu -// https://www.iana.org/domains/root/db/deloitte.html -deloitte - -// delta : Delta Air Lines, Inc. -// https://www.iana.org/domains/root/db/delta.html -delta - -// democrat : Dog Beach, LLC -// https://www.iana.org/domains/root/db/democrat.html -democrat - -// dental : Binky Moon, LLC -// https://www.iana.org/domains/root/db/dental.html -dental - -// dentist : Dog Beach, LLC -// https://www.iana.org/domains/root/db/dentist.html -dentist - -// desi -// https://www.iana.org/domains/root/db/desi.html -desi - -// design : Registry Services, LLC -// https://www.iana.org/domains/root/db/design.html -design - -// dev : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/dev.html -dev - -// dhl : Deutsche Post AG -// https://www.iana.org/domains/root/db/dhl.html -dhl - -// diamonds : Binky Moon, LLC -// https://www.iana.org/domains/root/db/diamonds.html -diamonds - -// diet : XYZ.COM LLC -// https://www.iana.org/domains/root/db/diet.html -diet - -// digital : Binky Moon, LLC -// https://www.iana.org/domains/root/db/digital.html -digital - -// direct : Binky Moon, LLC -// https://www.iana.org/domains/root/db/direct.html -direct - -// directory : Binky Moon, LLC -// https://www.iana.org/domains/root/db/directory.html -directory - -// discount : Binky Moon, LLC -// https://www.iana.org/domains/root/db/discount.html -discount - -// discover : Discover Financial Services -// https://www.iana.org/domains/root/db/discover.html -discover - -// dish : Dish DBS Corporation -// https://www.iana.org/domains/root/db/dish.html -dish - -// diy : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/diy.html -diy - -// dnp : Dai Nippon Printing Co., Ltd. -// https://www.iana.org/domains/root/db/dnp.html -dnp - -// docs : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/docs.html -docs - -// doctor : Binky Moon, LLC -// https://www.iana.org/domains/root/db/doctor.html -doctor - -// dog : Binky Moon, LLC -// https://www.iana.org/domains/root/db/dog.html -dog - -// domains : Binky Moon, LLC -// https://www.iana.org/domains/root/db/domains.html -domains - -// dot : Dish DBS Corporation -// https://www.iana.org/domains/root/db/dot.html -dot - -// download : dot Support Limited -// https://www.iana.org/domains/root/db/download.html -download - -// drive : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/drive.html -drive - -// dtv : Dish DBS Corporation -// https://www.iana.org/domains/root/db/dtv.html -dtv - -// dubai : Dubai Smart Government Department -// https://www.iana.org/domains/root/db/dubai.html -dubai - -// dunlop : The Goodyear Tire & Rubber Company -// https://www.iana.org/domains/root/db/dunlop.html -dunlop - -// dupont : DuPont Specialty Products USA, LLC -// https://www.iana.org/domains/root/db/dupont.html -dupont - -// durban : ZA Central Registry NPC trading as ZA Central Registry -// https://www.iana.org/domains/root/db/durban.html -durban - -// dvag : Deutsche Vermögensberatung Aktiengesellschaft DVAG -// https://www.iana.org/domains/root/db/dvag.html -dvag - -// dvr : DISH Technologies L.L.C. -// https://www.iana.org/domains/root/db/dvr.html -dvr - -// earth : Interlink Systems Innovation Institute K.K. -// https://www.iana.org/domains/root/db/earth.html -earth - -// eat : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/eat.html -eat - -// eco : Big Room Inc. -// https://www.iana.org/domains/root/db/eco.html -eco - -// edeka : EDEKA Verband kaufmännischer Genossenschaften e.V. -// https://www.iana.org/domains/root/db/edeka.html -edeka - -// education : Binky Moon, LLC -// https://www.iana.org/domains/root/db/education.html -education - -// email : Binky Moon, LLC -// https://www.iana.org/domains/root/db/email.html -email - -// emerck : Merck KGaA -// https://www.iana.org/domains/root/db/emerck.html -emerck - -// energy : Binky Moon, LLC -// https://www.iana.org/domains/root/db/energy.html -energy - -// engineer : Dog Beach, LLC -// https://www.iana.org/domains/root/db/engineer.html -engineer - -// engineering : Binky Moon, LLC -// https://www.iana.org/domains/root/db/engineering.html -engineering - -// enterprises : Binky Moon, LLC -// https://www.iana.org/domains/root/db/enterprises.html -enterprises - -// epson : Seiko Epson Corporation -// https://www.iana.org/domains/root/db/epson.html -epson - -// equipment : Binky Moon, LLC -// https://www.iana.org/domains/root/db/equipment.html -equipment - -// ericsson : Telefonaktiebolaget L M Ericsson -// https://www.iana.org/domains/root/db/ericsson.html -ericsson - -// erni : ERNI Group Holding AG -// https://www.iana.org/domains/root/db/erni.html -erni - -// esq : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/esq.html -esq - -// estate : Binky Moon, LLC -// https://www.iana.org/domains/root/db/estate.html -estate - -// eurovision : European Broadcasting Union (EBU) -// https://www.iana.org/domains/root/db/eurovision.html -eurovision - -// eus : Puntueus Fundazioa -// https://www.iana.org/domains/root/db/eus.html -eus - -// events : Binky Moon, LLC -// https://www.iana.org/domains/root/db/events.html -events - -// exchange : Binky Moon, LLC -// https://www.iana.org/domains/root/db/exchange.html -exchange - -// expert : Binky Moon, LLC -// https://www.iana.org/domains/root/db/expert.html -expert - -// exposed : Binky Moon, LLC -// https://www.iana.org/domains/root/db/exposed.html -exposed - -// express : Binky Moon, LLC -// https://www.iana.org/domains/root/db/express.html -express - -// extraspace : Extra Space Storage LLC -// https://www.iana.org/domains/root/db/extraspace.html -extraspace - -// fage : Fage International S.A. -// https://www.iana.org/domains/root/db/fage.html -fage - -// fail : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fail.html -fail - -// fairwinds : FairWinds Partners, LLC -// https://www.iana.org/domains/root/db/fairwinds.html -fairwinds - -// faith : dot Faith Limited -// https://www.iana.org/domains/root/db/faith.html -faith - -// family : Dog Beach, LLC -// https://www.iana.org/domains/root/db/family.html -family - -// fan : Dog Beach, LLC -// https://www.iana.org/domains/root/db/fan.html -fan - -// fans : ZDNS International Limited -// https://www.iana.org/domains/root/db/fans.html -fans - -// farm : Binky Moon, LLC -// https://www.iana.org/domains/root/db/farm.html -farm - -// farmers : Farmers Insurance Exchange -// https://www.iana.org/domains/root/db/farmers.html -farmers - -// fashion : Registry Services, LLC -// https://www.iana.org/domains/root/db/fashion.html -fashion - -// fast : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/fast.html -fast - -// fedex : Federal Express Corporation -// https://www.iana.org/domains/root/db/fedex.html -fedex - -// feedback : Top Level Spectrum, Inc. -// https://www.iana.org/domains/root/db/feedback.html -feedback - -// ferrari : Fiat Chrysler Automobiles N.V. -// https://www.iana.org/domains/root/db/ferrari.html -ferrari - -// ferrero : Ferrero Trading Lux S.A. -// https://www.iana.org/domains/root/db/ferrero.html -ferrero - -// fidelity : Fidelity Brokerage Services LLC -// https://www.iana.org/domains/root/db/fidelity.html -fidelity - -// fido : Rogers Communications Canada Inc. -// https://www.iana.org/domains/root/db/fido.html -fido - -// film : Motion Picture Domain Registry Pty Ltd -// https://www.iana.org/domains/root/db/film.html -film - -// final : Núcleo de Informação e Coordenação do Ponto BR - NIC.br -// https://www.iana.org/domains/root/db/final.html -final - -// finance : Binky Moon, LLC -// https://www.iana.org/domains/root/db/finance.html -finance - -// financial : Binky Moon, LLC -// https://www.iana.org/domains/root/db/financial.html -financial - -// fire : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/fire.html -fire - -// firestone : Bridgestone Licensing Services, Inc -// https://www.iana.org/domains/root/db/firestone.html -firestone - -// firmdale : Firmdale Holdings Limited -// https://www.iana.org/domains/root/db/firmdale.html -firmdale - -// fish : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fish.html -fish - -// fishing : Registry Services, LLC -// https://www.iana.org/domains/root/db/fishing.html -fishing - -// fit : Registry Services, LLC -// https://www.iana.org/domains/root/db/fit.html -fit - -// fitness : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fitness.html -fitness - -// flickr : Flickr, Inc. -// https://www.iana.org/domains/root/db/flickr.html -flickr - -// flights : Binky Moon, LLC -// https://www.iana.org/domains/root/db/flights.html -flights - -// flir : FLIR Systems, Inc. -// https://www.iana.org/domains/root/db/flir.html -flir - -// florist : Binky Moon, LLC -// https://www.iana.org/domains/root/db/florist.html -florist - -// flowers : XYZ.COM LLC -// https://www.iana.org/domains/root/db/flowers.html -flowers - -// fly : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/fly.html -fly - -// foo : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/foo.html -foo - -// food : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/food.html -food - -// football : Binky Moon, LLC -// https://www.iana.org/domains/root/db/football.html -football - -// ford : Ford Motor Company -// https://www.iana.org/domains/root/db/ford.html -ford - -// forex : Dog Beach, LLC -// https://www.iana.org/domains/root/db/forex.html -forex - -// forsale : Dog Beach, LLC -// https://www.iana.org/domains/root/db/forsale.html -forsale - -// forum : Waterford Limited -// https://www.iana.org/domains/root/db/forum.html -forum - -// foundation : Public Interest Registry -// https://www.iana.org/domains/root/db/foundation.html -foundation - -// fox : FOX Registry, LLC -// https://www.iana.org/domains/root/db/fox.html -fox - -// free : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/free.html -free - -// fresenius : Fresenius Immobilien-Verwaltungs-GmbH -// https://www.iana.org/domains/root/db/fresenius.html -fresenius - -// frl : FRLregistry B.V. -// https://www.iana.org/domains/root/db/frl.html -frl - -// frogans : OP3FT -// https://www.iana.org/domains/root/db/frogans.html -frogans - -// frontier : Frontier Communications Corporation -// https://www.iana.org/domains/root/db/frontier.html -frontier - -// ftr : Frontier Communications Corporation -// https://www.iana.org/domains/root/db/ftr.html -ftr - -// fujitsu : Fujitsu Limited -// https://www.iana.org/domains/root/db/fujitsu.html -fujitsu - -// fun : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/fun.html -fun - -// fund : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fund.html -fund - -// furniture : Binky Moon, LLC -// https://www.iana.org/domains/root/db/furniture.html -furniture - -// futbol : Dog Beach, LLC -// https://www.iana.org/domains/root/db/futbol.html -futbol - -// fyi : Binky Moon, LLC -// https://www.iana.org/domains/root/db/fyi.html -fyi - -// gal : Asociación puntoGAL -// https://www.iana.org/domains/root/db/gal.html -gal - -// gallery : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gallery.html -gallery - -// gallo : Gallo Vineyards, Inc. -// https://www.iana.org/domains/root/db/gallo.html -gallo - -// gallup : Gallup, Inc. -// https://www.iana.org/domains/root/db/gallup.html -gallup - -// game : XYZ.COM LLC -// https://www.iana.org/domains/root/db/game.html -game - -// games : Dog Beach, LLC -// https://www.iana.org/domains/root/db/games.html -games - -// gap : The Gap, Inc. -// https://www.iana.org/domains/root/db/gap.html -gap - -// garden : Registry Services, LLC -// https://www.iana.org/domains/root/db/garden.html -garden - -// gay : Registry Services, LLC -// https://www.iana.org/domains/root/db/gay.html -gay - -// gbiz : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/gbiz.html -gbiz - -// gdn : Joint Stock Company "Navigation-information systems" -// https://www.iana.org/domains/root/db/gdn.html -gdn - -// gea : GEA Group Aktiengesellschaft -// https://www.iana.org/domains/root/db/gea.html -gea - -// gent : Easyhost BV -// https://www.iana.org/domains/root/db/gent.html -gent - -// genting : Resorts World Inc Pte. Ltd. -// https://www.iana.org/domains/root/db/genting.html -genting - -// george : Wal-Mart Stores, Inc. -// https://www.iana.org/domains/root/db/george.html -george - -// ggee : GMO Internet, Inc. -// https://www.iana.org/domains/root/db/ggee.html -ggee - -// gift : DotGift, LLC -// https://www.iana.org/domains/root/db/gift.html -gift - -// gifts : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gifts.html -gifts - -// gives : Public Interest Registry -// https://www.iana.org/domains/root/db/gives.html -gives - -// giving : Public Interest Registry -// https://www.iana.org/domains/root/db/giving.html -giving - -// glass : Binky Moon, LLC -// https://www.iana.org/domains/root/db/glass.html -glass - -// gle : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/gle.html -gle - -// global : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/global.html -global - -// globo : Globo Comunicação e Participações S.A -// https://www.iana.org/domains/root/db/globo.html -globo - -// gmail : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/gmail.html -gmail - -// gmbh : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gmbh.html -gmbh - -// gmo : GMO Internet, Inc. -// https://www.iana.org/domains/root/db/gmo.html -gmo - -// gmx : 1&1 Mail & Media GmbH -// https://www.iana.org/domains/root/db/gmx.html -gmx - -// godaddy : Go Daddy East, LLC -// https://www.iana.org/domains/root/db/godaddy.html -godaddy - -// gold : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gold.html -gold - -// goldpoint : YODOBASHI CAMERA CO.,LTD. -// https://www.iana.org/domains/root/db/goldpoint.html -goldpoint - -// golf : Binky Moon, LLC -// https://www.iana.org/domains/root/db/golf.html -golf - -// goo : NTT DOCOMO, INC. -// https://www.iana.org/domains/root/db/goo.html -goo - -// goodyear : The Goodyear Tire & Rubber Company -// https://www.iana.org/domains/root/db/goodyear.html -goodyear - -// goog : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/goog.html -goog - -// google : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/google.html -google - -// gop : Republican State Leadership Committee, Inc. -// https://www.iana.org/domains/root/db/gop.html -gop - -// got : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/got.html -got - -// grainger : Grainger Registry Services, LLC -// https://www.iana.org/domains/root/db/grainger.html -grainger - -// graphics : Binky Moon, LLC -// https://www.iana.org/domains/root/db/graphics.html -graphics - -// gratis : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gratis.html -gratis - -// green : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/green.html -green - -// gripe : Binky Moon, LLC -// https://www.iana.org/domains/root/db/gripe.html -gripe - -// grocery : Wal-Mart Stores, Inc. -// https://www.iana.org/domains/root/db/grocery.html -grocery - -// group : Binky Moon, LLC -// https://www.iana.org/domains/root/db/group.html -group - -// gucci : Guccio Gucci S.p.a. -// https://www.iana.org/domains/root/db/gucci.html -gucci - -// guge : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/guge.html -guge - -// guide : Binky Moon, LLC -// https://www.iana.org/domains/root/db/guide.html -guide - -// guitars : XYZ.COM LLC -// https://www.iana.org/domains/root/db/guitars.html -guitars - -// guru : Binky Moon, LLC -// https://www.iana.org/domains/root/db/guru.html -guru - -// hair : XYZ.COM LLC -// https://www.iana.org/domains/root/db/hair.html -hair - -// hamburg : Hamburg Top-Level-Domain GmbH -// https://www.iana.org/domains/root/db/hamburg.html -hamburg - -// hangout : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/hangout.html -hangout - -// haus : Dog Beach, LLC -// https://www.iana.org/domains/root/db/haus.html -haus - -// hbo : HBO Registry Services, Inc. -// https://www.iana.org/domains/root/db/hbo.html -hbo - -// hdfc : HDFC BANK LIMITED -// https://www.iana.org/domains/root/db/hdfc.html -hdfc - -// hdfcbank : HDFC BANK LIMITED -// https://www.iana.org/domains/root/db/hdfcbank.html -hdfcbank - -// health : Registry Services, LLC -// https://www.iana.org/domains/root/db/health.html -health - -// healthcare : Binky Moon, LLC -// https://www.iana.org/domains/root/db/healthcare.html -healthcare - -// help : Innovation service Limited -// https://www.iana.org/domains/root/db/help.html -help - -// helsinki : City of Helsinki -// https://www.iana.org/domains/root/db/helsinki.html -helsinki - -// here : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/here.html -here - -// hermes : HERMES INTERNATIONAL -// https://www.iana.org/domains/root/db/hermes.html -hermes - -// hiphop : Dot Hip Hop, LLC -// https://www.iana.org/domains/root/db/hiphop.html -hiphop - -// hisamitsu : Hisamitsu Pharmaceutical Co.,Inc. -// https://www.iana.org/domains/root/db/hisamitsu.html -hisamitsu - -// hitachi : Hitachi, Ltd. -// https://www.iana.org/domains/root/db/hitachi.html -hitachi - -// hiv : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/hiv.html -hiv - -// hkt : PCCW-HKT DataCom Services Limited -// https://www.iana.org/domains/root/db/hkt.html -hkt - -// hockey : Binky Moon, LLC -// https://www.iana.org/domains/root/db/hockey.html -hockey - -// holdings : Binky Moon, LLC -// https://www.iana.org/domains/root/db/holdings.html -holdings - -// holiday : Binky Moon, LLC -// https://www.iana.org/domains/root/db/holiday.html -holiday - -// homedepot : Home Depot Product Authority, LLC -// https://www.iana.org/domains/root/db/homedepot.html -homedepot - -// homegoods : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/homegoods.html -homegoods - -// homes : XYZ.COM LLC -// https://www.iana.org/domains/root/db/homes.html -homes - -// homesense : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/homesense.html -homesense - -// honda : Honda Motor Co., Ltd. -// https://www.iana.org/domains/root/db/honda.html -honda - -// horse : Registry Services, LLC -// https://www.iana.org/domains/root/db/horse.html -horse - -// hospital : Binky Moon, LLC -// https://www.iana.org/domains/root/db/hospital.html -hospital - -// host : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/host.html -host - -// hosting : XYZ.COM LLC -// https://www.iana.org/domains/root/db/hosting.html -hosting - -// hot : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/hot.html -hot - -// hotel : HOTEL Top-Level-Domain S.a.r.l -// https://www.iana.org/domains/root/db/hotel.html -hotel - -// hotels : Booking.com B.V. -// https://www.iana.org/domains/root/db/hotels.html -hotels - -// hotmail : Microsoft Corporation -// https://www.iana.org/domains/root/db/hotmail.html -hotmail - -// house : Binky Moon, LLC -// https://www.iana.org/domains/root/db/house.html -house - -// how : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/how.html -how - -// hsbc : HSBC Global Services (UK) Limited -// https://www.iana.org/domains/root/db/hsbc.html -hsbc - -// hughes : Hughes Satellite Systems Corporation -// https://www.iana.org/domains/root/db/hughes.html -hughes - -// hyatt : Hyatt GTLD, L.L.C. -// https://www.iana.org/domains/root/db/hyatt.html -hyatt - -// hyundai : Hyundai Motor Company -// https://www.iana.org/domains/root/db/hyundai.html -hyundai - -// ibm : International Business Machines Corporation -// https://www.iana.org/domains/root/db/ibm.html -ibm - -// icbc : Industrial and Commercial Bank of China Limited -// https://www.iana.org/domains/root/db/icbc.html -icbc - -// ice : IntercontinentalExchange, Inc. -// https://www.iana.org/domains/root/db/ice.html -ice - -// icu : ShortDot SA -// https://www.iana.org/domains/root/db/icu.html -icu - -// ieee : IEEE Global LLC -// https://www.iana.org/domains/root/db/ieee.html -ieee - -// ifm : ifm electronic gmbh -// https://www.iana.org/domains/root/db/ifm.html -ifm - -// ikano : Ikano S.A. -// https://www.iana.org/domains/root/db/ikano.html -ikano - -// imamat : Fondation Aga Khan (Aga Khan Foundation) -// https://www.iana.org/domains/root/db/imamat.html -imamat - -// imdb : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/imdb.html -imdb - -// immo : Binky Moon, LLC -// https://www.iana.org/domains/root/db/immo.html -immo - -// immobilien : Dog Beach, LLC -// https://www.iana.org/domains/root/db/immobilien.html -immobilien - -// inc : Intercap Registry Inc. -// https://www.iana.org/domains/root/db/inc.html -inc - -// industries : Binky Moon, LLC -// https://www.iana.org/domains/root/db/industries.html -industries - -// infiniti : NISSAN MOTOR CO., LTD. -// https://www.iana.org/domains/root/db/infiniti.html -infiniti - -// ing : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/ing.html -ing - -// ink : Registry Services, LLC -// https://www.iana.org/domains/root/db/ink.html -ink - -// institute : Binky Moon, LLC -// https://www.iana.org/domains/root/db/institute.html -institute - -// insurance : fTLD Registry Services LLC -// https://www.iana.org/domains/root/db/insurance.html -insurance - -// insure : Binky Moon, LLC -// https://www.iana.org/domains/root/db/insure.html -insure - -// international : Binky Moon, LLC -// https://www.iana.org/domains/root/db/international.html -international - -// intuit : Intuit Administrative Services, Inc. -// https://www.iana.org/domains/root/db/intuit.html -intuit - -// investments : Binky Moon, LLC -// https://www.iana.org/domains/root/db/investments.html -investments - -// ipiranga : Ipiranga Produtos de Petroleo S.A. -// https://www.iana.org/domains/root/db/ipiranga.html -ipiranga - -// irish : Binky Moon, LLC -// https://www.iana.org/domains/root/db/irish.html -irish - -// ismaili : Fondation Aga Khan (Aga Khan Foundation) -// https://www.iana.org/domains/root/db/ismaili.html -ismaili - -// ist : Istanbul Metropolitan Municipality -// https://www.iana.org/domains/root/db/ist.html -ist - -// istanbul : Istanbul Metropolitan Municipality -// https://www.iana.org/domains/root/db/istanbul.html -istanbul - -// itau : Itau Unibanco Holding S.A. -// https://www.iana.org/domains/root/db/itau.html -itau - -// itv : ITV Services Limited -// https://www.iana.org/domains/root/db/itv.html -itv - -// jaguar : Jaguar Land Rover Ltd -// https://www.iana.org/domains/root/db/jaguar.html -jaguar - -// java : Oracle Corporation -// https://www.iana.org/domains/root/db/java.html -java - -// jcb : JCB Co., Ltd. -// https://www.iana.org/domains/root/db/jcb.html -jcb - -// jeep : FCA US LLC. -// https://www.iana.org/domains/root/db/jeep.html -jeep - -// jetzt : Binky Moon, LLC -// https://www.iana.org/domains/root/db/jetzt.html -jetzt - -// jewelry : Binky Moon, LLC -// https://www.iana.org/domains/root/db/jewelry.html -jewelry - -// jio : Reliance Industries Limited -// https://www.iana.org/domains/root/db/jio.html -jio - -// jll : Jones Lang LaSalle Incorporated -// https://www.iana.org/domains/root/db/jll.html -jll - -// jmp : Matrix IP LLC -// https://www.iana.org/domains/root/db/jmp.html -jmp - -// jnj : Johnson & Johnson Services, Inc. -// https://www.iana.org/domains/root/db/jnj.html -jnj - -// joburg : ZA Central Registry NPC trading as ZA Central Registry -// https://www.iana.org/domains/root/db/joburg.html -joburg - -// jot : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/jot.html -jot - -// joy : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/joy.html -joy - -// jpmorgan : JPMorgan Chase Bank, National Association -// https://www.iana.org/domains/root/db/jpmorgan.html -jpmorgan - -// jprs : Japan Registry Services Co., Ltd. -// https://www.iana.org/domains/root/db/jprs.html -jprs - -// juegos : Dog Beach, LLC -// https://www.iana.org/domains/root/db/juegos.html -juegos - -// juniper : JUNIPER NETWORKS, INC. -// https://www.iana.org/domains/root/db/juniper.html -juniper - -// kaufen : Dog Beach, LLC -// https://www.iana.org/domains/root/db/kaufen.html -kaufen - -// kddi : KDDI CORPORATION -// https://www.iana.org/domains/root/db/kddi.html -kddi - -// kerryhotels : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/kerryhotels.html -kerryhotels - -// kerryproperties : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/kerryproperties.html -kerryproperties - -// kfh : Kuwait Finance House -// https://www.iana.org/domains/root/db/kfh.html -kfh - -// kia : KIA MOTORS CORPORATION -// https://www.iana.org/domains/root/db/kia.html -kia - -// kids : DotKids Foundation Limited -// https://www.iana.org/domains/root/db/kids.html -kids - -// kim : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/kim.html -kim - -// kindle : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/kindle.html -kindle - -// kitchen : Binky Moon, LLC -// https://www.iana.org/domains/root/db/kitchen.html -kitchen - -// kiwi : DOT KIWI LIMITED -// https://www.iana.org/domains/root/db/kiwi.html -kiwi - -// koeln : dotKoeln GmbH -// https://www.iana.org/domains/root/db/koeln.html -koeln - -// komatsu : Komatsu Ltd. -// https://www.iana.org/domains/root/db/komatsu.html -komatsu - -// kosher : Kosher Marketing Assets LLC -// https://www.iana.org/domains/root/db/kosher.html -kosher - -// kpmg : KPMG International Cooperative (KPMG International Genossenschaft) -// https://www.iana.org/domains/root/db/kpmg.html -kpmg - -// kpn : Koninklijke KPN N.V. -// https://www.iana.org/domains/root/db/kpn.html -kpn - -// krd : KRG Department of Information Technology -// https://www.iana.org/domains/root/db/krd.html -krd - -// kred : KredTLD Pty Ltd -// https://www.iana.org/domains/root/db/kred.html -kred - -// kuokgroup : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/kuokgroup.html -kuokgroup - -// kyoto : Academic Institution: Kyoto Jyoho Gakuen -// https://www.iana.org/domains/root/db/kyoto.html -kyoto - -// lacaixa : Fundación Bancaria Caixa d’Estalvis i Pensions de Barcelona, “la Caixa” -// https://www.iana.org/domains/root/db/lacaixa.html -lacaixa - -// lamborghini : Automobili Lamborghini S.p.A. -// https://www.iana.org/domains/root/db/lamborghini.html -lamborghini - -// lamer : The Estée Lauder Companies Inc. -// https://www.iana.org/domains/root/db/lamer.html -lamer - -// land : Binky Moon, LLC -// https://www.iana.org/domains/root/db/land.html -land - -// landrover : Jaguar Land Rover Ltd -// https://www.iana.org/domains/root/db/landrover.html -landrover - -// lanxess : LANXESS Corporation -// https://www.iana.org/domains/root/db/lanxess.html -lanxess - -// lasalle : Jones Lang LaSalle Incorporated -// https://www.iana.org/domains/root/db/lasalle.html -lasalle - -// lat : XYZ.COM LLC -// https://www.iana.org/domains/root/db/lat.html -lat - -// latino : Dish DBS Corporation -// https://www.iana.org/domains/root/db/latino.html -latino - -// latrobe : La Trobe University -// https://www.iana.org/domains/root/db/latrobe.html -latrobe - -// law : Registry Services, LLC -// https://www.iana.org/domains/root/db/law.html -law - -// lawyer : Dog Beach, LLC -// https://www.iana.org/domains/root/db/lawyer.html -lawyer - -// lds : IRI Domain Management, LLC -// https://www.iana.org/domains/root/db/lds.html -lds - -// lease : Binky Moon, LLC -// https://www.iana.org/domains/root/db/lease.html -lease - -// leclerc : A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc -// https://www.iana.org/domains/root/db/leclerc.html -leclerc - -// lefrak : LeFrak Organization, Inc. -// https://www.iana.org/domains/root/db/lefrak.html -lefrak - -// legal : Binky Moon, LLC -// https://www.iana.org/domains/root/db/legal.html -legal - -// lego : LEGO Juris A/S -// https://www.iana.org/domains/root/db/lego.html -lego - -// lexus : TOYOTA MOTOR CORPORATION -// https://www.iana.org/domains/root/db/lexus.html -lexus - -// lgbt : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/lgbt.html -lgbt - -// lidl : Schwarz Domains und Services GmbH & Co. KG -// https://www.iana.org/domains/root/db/lidl.html -lidl - -// life : Binky Moon, LLC -// https://www.iana.org/domains/root/db/life.html -life - -// lifeinsurance : American Council of Life Insurers -// https://www.iana.org/domains/root/db/lifeinsurance.html -lifeinsurance - -// lifestyle : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/lifestyle.html -lifestyle - -// lighting : Binky Moon, LLC -// https://www.iana.org/domains/root/db/lighting.html -lighting - -// like : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/like.html -like - -// lilly : Eli Lilly and Company -// https://www.iana.org/domains/root/db/lilly.html -lilly - -// limited : Binky Moon, LLC -// https://www.iana.org/domains/root/db/limited.html -limited - -// limo : Binky Moon, LLC -// https://www.iana.org/domains/root/db/limo.html -limo - -// lincoln : Ford Motor Company -// https://www.iana.org/domains/root/db/lincoln.html -lincoln - -// link : Nova Registry Ltd -// https://www.iana.org/domains/root/db/link.html -link - -// live : Dog Beach, LLC -// https://www.iana.org/domains/root/db/live.html -live - -// living : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/living.html -living - -// llc : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/llc.html -llc - -// llp : Intercap Registry Inc. -// https://www.iana.org/domains/root/db/llp.html -llp - -// loan : dot Loan Limited -// https://www.iana.org/domains/root/db/loan.html -loan - -// loans : Binky Moon, LLC -// https://www.iana.org/domains/root/db/loans.html -loans - -// locker : Orange Domains LLC -// https://www.iana.org/domains/root/db/locker.html -locker - -// locus : Locus Analytics LLC -// https://www.iana.org/domains/root/db/locus.html -locus - -// lol : XYZ.COM LLC -// https://www.iana.org/domains/root/db/lol.html -lol - -// london : Dot London Domains Limited -// https://www.iana.org/domains/root/db/london.html -london - -// lotte : Lotte Holdings Co., Ltd. -// https://www.iana.org/domains/root/db/lotte.html -lotte - -// lotto : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/lotto.html -lotto - -// love : Waterford Limited -// https://www.iana.org/domains/root/db/love.html -love - -// lpl : LPL Holdings, Inc. -// https://www.iana.org/domains/root/db/lpl.html -lpl - -// lplfinancial : LPL Holdings, Inc. -// https://www.iana.org/domains/root/db/lplfinancial.html -lplfinancial - -// ltd : Binky Moon, LLC -// https://www.iana.org/domains/root/db/ltd.html -ltd - -// ltda : InterNetX, Corp -// https://www.iana.org/domains/root/db/ltda.html -ltda - -// lundbeck : H. Lundbeck A/S -// https://www.iana.org/domains/root/db/lundbeck.html -lundbeck - -// luxe : Registry Services, LLC -// https://www.iana.org/domains/root/db/luxe.html -luxe - -// luxury : Luxury Partners, LLC -// https://www.iana.org/domains/root/db/luxury.html -luxury - -// madrid : Comunidad de Madrid -// https://www.iana.org/domains/root/db/madrid.html -madrid - -// maif : Mutuelle Assurance Instituteur France (MAIF) -// https://www.iana.org/domains/root/db/maif.html -maif - -// maison : Binky Moon, LLC -// https://www.iana.org/domains/root/db/maison.html -maison - -// makeup : XYZ.COM LLC -// https://www.iana.org/domains/root/db/makeup.html -makeup - -// man : MAN Truck & Bus SE -// https://www.iana.org/domains/root/db/man.html -man - -// management : Binky Moon, LLC -// https://www.iana.org/domains/root/db/management.html -management - -// mango : PUNTO FA S.L. -// https://www.iana.org/domains/root/db/mango.html -mango - -// map : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/map.html -map - -// market : Dog Beach, LLC -// https://www.iana.org/domains/root/db/market.html -market - -// marketing : Binky Moon, LLC -// https://www.iana.org/domains/root/db/marketing.html -marketing - -// markets : Dog Beach, LLC -// https://www.iana.org/domains/root/db/markets.html -markets - -// marriott : Marriott Worldwide Corporation -// https://www.iana.org/domains/root/db/marriott.html -marriott - -// marshalls : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/marshalls.html -marshalls - -// mattel : Mattel IT Services, Inc. -// https://www.iana.org/domains/root/db/mattel.html -mattel - -// mba : Binky Moon, LLC -// https://www.iana.org/domains/root/db/mba.html -mba - -// mckinsey : McKinsey Holdings, Inc. -// https://www.iana.org/domains/root/db/mckinsey.html -mckinsey - -// med : Medistry LLC -// https://www.iana.org/domains/root/db/med.html -med - -// media : Binky Moon, LLC -// https://www.iana.org/domains/root/db/media.html -media - -// meet : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/meet.html -meet - -// melbourne : The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation -// https://www.iana.org/domains/root/db/melbourne.html -melbourne - -// meme : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/meme.html -meme - -// memorial : Dog Beach, LLC -// https://www.iana.org/domains/root/db/memorial.html -memorial - -// men : Exclusive Registry Limited -// https://www.iana.org/domains/root/db/men.html -men - -// menu : Dot Menu Registry, LLC -// https://www.iana.org/domains/root/db/menu.html -menu - -// merck : Merck Registry Holdings, Inc. -// https://www.iana.org/domains/root/db/merck.html -merck - -// merckmsd : MSD Registry Holdings, Inc. -// https://www.iana.org/domains/root/db/merckmsd.html -merckmsd - -// miami : Registry Services, LLC -// https://www.iana.org/domains/root/db/miami.html -miami - -// microsoft : Microsoft Corporation -// https://www.iana.org/domains/root/db/microsoft.html -microsoft - -// mini : Bayerische Motoren Werke Aktiengesellschaft -// https://www.iana.org/domains/root/db/mini.html -mini - -// mint : Intuit Administrative Services, Inc. -// https://www.iana.org/domains/root/db/mint.html -mint - -// mit : Massachusetts Institute of Technology -// https://www.iana.org/domains/root/db/mit.html -mit - -// mitsubishi : Mitsubishi Corporation -// https://www.iana.org/domains/root/db/mitsubishi.html -mitsubishi - -// mlb : MLB Advanced Media DH, LLC -// https://www.iana.org/domains/root/db/mlb.html -mlb - -// mls : The Canadian Real Estate Association -// https://www.iana.org/domains/root/db/mls.html -mls - -// mma : MMA IARD -// https://www.iana.org/domains/root/db/mma.html -mma - -// mobile : Dish DBS Corporation -// https://www.iana.org/domains/root/db/mobile.html -mobile - -// moda : Dog Beach, LLC -// https://www.iana.org/domains/root/db/moda.html -moda - -// moe : Interlink Systems Innovation Institute K.K. -// https://www.iana.org/domains/root/db/moe.html -moe - -// moi : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/moi.html -moi - -// mom : XYZ.COM LLC -// https://www.iana.org/domains/root/db/mom.html -mom - -// monash : Monash University -// https://www.iana.org/domains/root/db/monash.html -monash - -// money : Binky Moon, LLC -// https://www.iana.org/domains/root/db/money.html -money - -// monster : XYZ.COM LLC -// https://www.iana.org/domains/root/db/monster.html -monster - -// mormon : IRI Domain Management, LLC -// https://www.iana.org/domains/root/db/mormon.html -mormon - -// mortgage : Dog Beach, LLC -// https://www.iana.org/domains/root/db/mortgage.html -mortgage - -// moscow : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) -// https://www.iana.org/domains/root/db/moscow.html -moscow - -// moto : Motorola Trademark Holdings, LLC -// https://www.iana.org/domains/root/db/moto.html -moto - -// motorcycles : XYZ.COM LLC -// https://www.iana.org/domains/root/db/motorcycles.html -motorcycles - -// mov : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/mov.html -mov - -// movie : Binky Moon, LLC -// https://www.iana.org/domains/root/db/movie.html -movie - -// msd : MSD Registry Holdings, Inc. -// https://www.iana.org/domains/root/db/msd.html -msd - -// mtn : MTN Dubai Limited -// https://www.iana.org/domains/root/db/mtn.html -mtn - -// mtr : MTR Corporation Limited -// https://www.iana.org/domains/root/db/mtr.html -mtr - -// music : DotMusic Limited -// https://www.iana.org/domains/root/db/music.html -music - -// nab : National Australia Bank Limited -// https://www.iana.org/domains/root/db/nab.html -nab - -// nagoya : GMO Registry, Inc. -// https://www.iana.org/domains/root/db/nagoya.html -nagoya - -// navy : Dog Beach, LLC -// https://www.iana.org/domains/root/db/navy.html -navy - -// nba : NBA REGISTRY, LLC -// https://www.iana.org/domains/root/db/nba.html -nba - -// nec : NEC Corporation -// https://www.iana.org/domains/root/db/nec.html -nec - -// netbank : COMMONWEALTH BANK OF AUSTRALIA -// https://www.iana.org/domains/root/db/netbank.html -netbank - -// netflix : Netflix, Inc. -// https://www.iana.org/domains/root/db/netflix.html -netflix - -// network : Binky Moon, LLC -// https://www.iana.org/domains/root/db/network.html -network - -// neustar : NeuStar, Inc. -// https://www.iana.org/domains/root/db/neustar.html -neustar - -// new : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/new.html -new - -// news : Dog Beach, LLC -// https://www.iana.org/domains/root/db/news.html -news - -// next : Next plc -// https://www.iana.org/domains/root/db/next.html -next - -// nextdirect : Next plc -// https://www.iana.org/domains/root/db/nextdirect.html -nextdirect - -// nexus : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/nexus.html -nexus - -// nfl : NFL Reg Ops LLC -// https://www.iana.org/domains/root/db/nfl.html -nfl - -// ngo : Public Interest Registry -// https://www.iana.org/domains/root/db/ngo.html -ngo - -// nhk : Japan Broadcasting Corporation (NHK) -// https://www.iana.org/domains/root/db/nhk.html -nhk - -// nico : DWANGO Co., Ltd. -// https://www.iana.org/domains/root/db/nico.html -nico - -// nike : NIKE, Inc. -// https://www.iana.org/domains/root/db/nike.html -nike - -// nikon : NIKON CORPORATION -// https://www.iana.org/domains/root/db/nikon.html -nikon - -// ninja : Dog Beach, LLC -// https://www.iana.org/domains/root/db/ninja.html -ninja - -// nissan : NISSAN MOTOR CO., LTD. -// https://www.iana.org/domains/root/db/nissan.html -nissan - -// nissay : Nippon Life Insurance Company -// https://www.iana.org/domains/root/db/nissay.html -nissay - -// nokia : Nokia Corporation -// https://www.iana.org/domains/root/db/nokia.html -nokia - -// norton : Gen Digital Inc. -// https://www.iana.org/domains/root/db/norton.html -norton - -// now : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/now.html -now - -// nowruz -// https://www.iana.org/domains/root/db/nowruz.html -nowruz - -// nowtv : Starbucks (HK) Limited -// https://www.iana.org/domains/root/db/nowtv.html -nowtv - -// nra : National Rifle Association of America -// https://www.iana.org/domains/root/db/nra.html -nra - -// nrw : Minds + Machines GmbH -// https://www.iana.org/domains/root/db/nrw.html -nrw - -// ntt : NIPPON TELEGRAPH AND TELEPHONE CORPORATION -// https://www.iana.org/domains/root/db/ntt.html -ntt - -// nyc : The City of New York by and through the New York City Department of Information Technology & Telecommunications -// https://www.iana.org/domains/root/db/nyc.html -nyc - -// obi : OBI Group Holding SE & Co. KGaA -// https://www.iana.org/domains/root/db/obi.html -obi - -// observer : Fegistry, LLC -// https://www.iana.org/domains/root/db/observer.html -observer - -// office : Microsoft Corporation -// https://www.iana.org/domains/root/db/office.html -office - -// okinawa : BRregistry, Inc. -// https://www.iana.org/domains/root/db/okinawa.html -okinawa - -// olayan : Competrol (Luxembourg) Sarl -// https://www.iana.org/domains/root/db/olayan.html -olayan - -// olayangroup : Competrol (Luxembourg) Sarl -// https://www.iana.org/domains/root/db/olayangroup.html -olayangroup - -// ollo : Dish DBS Corporation -// https://www.iana.org/domains/root/db/ollo.html -ollo - -// omega : The Swatch Group Ltd -// https://www.iana.org/domains/root/db/omega.html -omega - -// one : One.com A/S -// https://www.iana.org/domains/root/db/one.html -one - -// ong : Public Interest Registry -// https://www.iana.org/domains/root/db/ong.html -ong - -// onl : iRegistry GmbH -// https://www.iana.org/domains/root/db/onl.html -onl - -// online : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/online.html -online - -// ooo : INFIBEAM AVENUES LIMITED -// https://www.iana.org/domains/root/db/ooo.html -ooo - -// open : American Express Travel Related Services Company, Inc. -// https://www.iana.org/domains/root/db/open.html -open - -// oracle : Oracle Corporation -// https://www.iana.org/domains/root/db/oracle.html -oracle - -// orange : Orange Brand Services Limited -// https://www.iana.org/domains/root/db/orange.html -orange - -// organic : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/organic.html -organic - -// origins : The Estée Lauder Companies Inc. -// https://www.iana.org/domains/root/db/origins.html -origins - -// osaka : Osaka Registry Co., Ltd. -// https://www.iana.org/domains/root/db/osaka.html -osaka - -// otsuka : Otsuka Holdings Co., Ltd. -// https://www.iana.org/domains/root/db/otsuka.html -otsuka - -// ott : Dish DBS Corporation -// https://www.iana.org/domains/root/db/ott.html -ott - -// ovh : MédiaBC -// https://www.iana.org/domains/root/db/ovh.html -ovh - -// page : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/page.html -page - -// panasonic : Panasonic Holdings Corporation -// https://www.iana.org/domains/root/db/panasonic.html -panasonic - -// paris : City of Paris -// https://www.iana.org/domains/root/db/paris.html -paris - -// pars -// https://www.iana.org/domains/root/db/pars.html -pars - -// partners : Binky Moon, LLC -// https://www.iana.org/domains/root/db/partners.html -partners - -// parts : Binky Moon, LLC -// https://www.iana.org/domains/root/db/parts.html -parts - -// party : Blue Sky Registry Limited -// https://www.iana.org/domains/root/db/party.html -party - -// pay : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/pay.html -pay - -// pccw : PCCW Enterprises Limited -// https://www.iana.org/domains/root/db/pccw.html -pccw - -// pet : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/pet.html -pet - -// pfizer : Pfizer Inc. -// https://www.iana.org/domains/root/db/pfizer.html -pfizer - -// pharmacy : National Association of Boards of Pharmacy -// https://www.iana.org/domains/root/db/pharmacy.html -pharmacy - -// phd : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/phd.html -phd - -// philips : Koninklijke Philips N.V. -// https://www.iana.org/domains/root/db/philips.html -philips - -// phone : Dish DBS Corporation -// https://www.iana.org/domains/root/db/phone.html -phone - -// photo : Registry Services, LLC -// https://www.iana.org/domains/root/db/photo.html -photo - -// photography : Binky Moon, LLC -// https://www.iana.org/domains/root/db/photography.html -photography - -// photos : Binky Moon, LLC -// https://www.iana.org/domains/root/db/photos.html -photos - -// physio : PhysBiz Pty Ltd -// https://www.iana.org/domains/root/db/physio.html -physio - -// pics : XYZ.COM LLC -// https://www.iana.org/domains/root/db/pics.html -pics - -// pictet : Banque Pictet & Cie SA -// https://www.iana.org/domains/root/db/pictet.html -pictet - -// pictures : Binky Moon, LLC -// https://www.iana.org/domains/root/db/pictures.html -pictures - -// pid : Top Level Spectrum, Inc. -// https://www.iana.org/domains/root/db/pid.html -pid - -// pin : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/pin.html -pin - -// ping : Ping Registry Provider, Inc. -// https://www.iana.org/domains/root/db/ping.html -ping - -// pink : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/pink.html -pink - -// pioneer : Pioneer Corporation -// https://www.iana.org/domains/root/db/pioneer.html -pioneer - -// pizza : Binky Moon, LLC -// https://www.iana.org/domains/root/db/pizza.html -pizza - -// place : Binky Moon, LLC -// https://www.iana.org/domains/root/db/place.html -place - -// play : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/play.html -play - -// playstation : Sony Interactive Entertainment Inc. -// https://www.iana.org/domains/root/db/playstation.html -playstation - -// plumbing : Binky Moon, LLC -// https://www.iana.org/domains/root/db/plumbing.html -plumbing - -// plus : Binky Moon, LLC -// https://www.iana.org/domains/root/db/plus.html -plus - -// pnc : PNC Domain Co., LLC -// https://www.iana.org/domains/root/db/pnc.html -pnc - -// pohl : Deutsche Vermögensberatung Aktiengesellschaft DVAG -// https://www.iana.org/domains/root/db/pohl.html -pohl - -// poker : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/poker.html -poker - -// politie : Politie Nederland -// https://www.iana.org/domains/root/db/politie.html -politie - -// porn : ICM Registry PN LLC -// https://www.iana.org/domains/root/db/porn.html -porn - -// praxi : Praxi S.p.A. -// https://www.iana.org/domains/root/db/praxi.html -praxi - -// press : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/press.html -press - -// prime : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/prime.html -prime - -// prod : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/prod.html -prod - -// productions : Binky Moon, LLC -// https://www.iana.org/domains/root/db/productions.html -productions - -// prof : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/prof.html -prof - -// progressive : Progressive Casualty Insurance Company -// https://www.iana.org/domains/root/db/progressive.html -progressive - -// promo : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/promo.html -promo - -// properties : Binky Moon, LLC -// https://www.iana.org/domains/root/db/properties.html -properties - -// property : Digital Property Infrastructure Limited -// https://www.iana.org/domains/root/db/property.html -property - -// protection : XYZ.COM LLC -// https://www.iana.org/domains/root/db/protection.html -protection - -// pru : Prudential Financial, Inc. -// https://www.iana.org/domains/root/db/pru.html -pru - -// prudential : Prudential Financial, Inc. -// https://www.iana.org/domains/root/db/prudential.html -prudential - -// pub : Dog Beach, LLC -// https://www.iana.org/domains/root/db/pub.html -pub - -// pwc : PricewaterhouseCoopers LLP -// https://www.iana.org/domains/root/db/pwc.html -pwc - -// qpon : dotQPON LLC -// https://www.iana.org/domains/root/db/qpon.html -qpon - -// quebec : PointQuébec Inc -// https://www.iana.org/domains/root/db/quebec.html -quebec - -// quest : XYZ.COM LLC -// https://www.iana.org/domains/root/db/quest.html -quest - -// racing : Premier Registry Limited -// https://www.iana.org/domains/root/db/racing.html -racing - -// radio : European Broadcasting Union (EBU) -// https://www.iana.org/domains/root/db/radio.html -radio - -// read : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/read.html -read - -// realestate : dotRealEstate LLC -// https://www.iana.org/domains/root/db/realestate.html -realestate - -// realtor : Real Estate Domains LLC -// https://www.iana.org/domains/root/db/realtor.html -realtor - -// realty : Waterford Limited -// https://www.iana.org/domains/root/db/realty.html -realty - -// recipes : Binky Moon, LLC -// https://www.iana.org/domains/root/db/recipes.html -recipes - -// red : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/red.html -red - -// redumbrella : Travelers TLD, LLC -// https://www.iana.org/domains/root/db/redumbrella.html -redumbrella - -// rehab : Dog Beach, LLC -// https://www.iana.org/domains/root/db/rehab.html -rehab - -// reise : Binky Moon, LLC -// https://www.iana.org/domains/root/db/reise.html -reise - -// reisen : Binky Moon, LLC -// https://www.iana.org/domains/root/db/reisen.html -reisen - -// reit : National Association of Real Estate Investment Trusts, Inc. -// https://www.iana.org/domains/root/db/reit.html -reit - -// reliance : Reliance Industries Limited -// https://www.iana.org/domains/root/db/reliance.html -reliance - -// ren : ZDNS International Limited -// https://www.iana.org/domains/root/db/ren.html -ren - -// rent : XYZ.COM LLC -// https://www.iana.org/domains/root/db/rent.html -rent - -// rentals : Binky Moon, LLC -// https://www.iana.org/domains/root/db/rentals.html -rentals - -// repair : Binky Moon, LLC -// https://www.iana.org/domains/root/db/repair.html -repair - -// report : Binky Moon, LLC -// https://www.iana.org/domains/root/db/report.html -report - -// republican : Dog Beach, LLC -// https://www.iana.org/domains/root/db/republican.html -republican - -// rest : Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable -// https://www.iana.org/domains/root/db/rest.html -rest - -// restaurant : Binky Moon, LLC -// https://www.iana.org/domains/root/db/restaurant.html -restaurant - -// review : dot Review Limited -// https://www.iana.org/domains/root/db/review.html -review - -// reviews : Dog Beach, LLC -// https://www.iana.org/domains/root/db/reviews.html -reviews - -// rexroth : Robert Bosch GMBH -// https://www.iana.org/domains/root/db/rexroth.html -rexroth - -// rich : iRegistry GmbH -// https://www.iana.org/domains/root/db/rich.html -rich - -// richardli : Pacific Century Asset Management (HK) Limited -// https://www.iana.org/domains/root/db/richardli.html -richardli - -// ricoh : Ricoh Company, Ltd. -// https://www.iana.org/domains/root/db/ricoh.html -ricoh - -// ril : Reliance Industries Limited -// https://www.iana.org/domains/root/db/ril.html -ril - -// rio : Empresa Municipal de Informática SA - IPLANRIO -// https://www.iana.org/domains/root/db/rio.html -rio - -// rip : Dog Beach, LLC -// https://www.iana.org/domains/root/db/rip.html -rip - -// rocks : Dog Beach, LLC -// https://www.iana.org/domains/root/db/rocks.html -rocks - -// rodeo : Registry Services, LLC -// https://www.iana.org/domains/root/db/rodeo.html -rodeo - -// rogers : Rogers Communications Canada Inc. -// https://www.iana.org/domains/root/db/rogers.html -rogers - -// room : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/room.html -room - -// rsvp : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/rsvp.html -rsvp - -// rugby : World Rugby Strategic Developments Limited -// https://www.iana.org/domains/root/db/rugby.html -rugby - -// ruhr : dotSaarland GmbH -// https://www.iana.org/domains/root/db/ruhr.html -ruhr - -// run : Binky Moon, LLC -// https://www.iana.org/domains/root/db/run.html -run - -// rwe : RWE AG -// https://www.iana.org/domains/root/db/rwe.html -rwe - -// ryukyu : BRregistry, Inc. -// https://www.iana.org/domains/root/db/ryukyu.html -ryukyu - -// saarland : dotSaarland GmbH -// https://www.iana.org/domains/root/db/saarland.html -saarland - -// safe : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/safe.html -safe - -// safety : Safety Registry Services, LLC. -// https://www.iana.org/domains/root/db/safety.html -safety - -// sakura : SAKURA Internet Inc. -// https://www.iana.org/domains/root/db/sakura.html -sakura - -// sale : Dog Beach, LLC -// https://www.iana.org/domains/root/db/sale.html -sale - -// salon : Binky Moon, LLC -// https://www.iana.org/domains/root/db/salon.html -salon - -// samsclub : Wal-Mart Stores, Inc. -// https://www.iana.org/domains/root/db/samsclub.html -samsclub - -// samsung : SAMSUNG SDS CO., LTD -// https://www.iana.org/domains/root/db/samsung.html -samsung - -// sandvik : Sandvik AB -// https://www.iana.org/domains/root/db/sandvik.html -sandvik - -// sandvikcoromant : Sandvik AB -// https://www.iana.org/domains/root/db/sandvikcoromant.html -sandvikcoromant - -// sanofi : Sanofi -// https://www.iana.org/domains/root/db/sanofi.html -sanofi - -// sap : SAP AG -// https://www.iana.org/domains/root/db/sap.html -sap - -// sarl : Binky Moon, LLC -// https://www.iana.org/domains/root/db/sarl.html -sarl - -// sas : Research IP LLC -// https://www.iana.org/domains/root/db/sas.html -sas - -// save : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/save.html -save - -// saxo : Saxo Bank A/S -// https://www.iana.org/domains/root/db/saxo.html -saxo - -// sbi : STATE BANK OF INDIA -// https://www.iana.org/domains/root/db/sbi.html -sbi - -// sbs : ShortDot SA -// https://www.iana.org/domains/root/db/sbs.html -sbs - -// scb : The Siam Commercial Bank Public Company Limited ("SCB") -// https://www.iana.org/domains/root/db/scb.html -scb - -// schaeffler : Schaeffler Technologies AG & Co. KG -// https://www.iana.org/domains/root/db/schaeffler.html -schaeffler - -// schmidt : SCHMIDT GROUPE S.A.S. -// https://www.iana.org/domains/root/db/schmidt.html -schmidt - -// scholarships : Scholarships.com, LLC -// https://www.iana.org/domains/root/db/scholarships.html -scholarships - -// school : Binky Moon, LLC -// https://www.iana.org/domains/root/db/school.html -school - -// schule : Binky Moon, LLC -// https://www.iana.org/domains/root/db/schule.html -schule - -// schwarz : Schwarz Domains und Services GmbH & Co. KG -// https://www.iana.org/domains/root/db/schwarz.html -schwarz - -// science : dot Science Limited -// https://www.iana.org/domains/root/db/science.html -science - -// scot : Dot Scot Registry Limited -// https://www.iana.org/domains/root/db/scot.html -scot - -// search : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/search.html -search - -// seat : SEAT, S.A. (Sociedad Unipersonal) -// https://www.iana.org/domains/root/db/seat.html -seat - -// secure : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/secure.html -secure - -// security : XYZ.COM LLC -// https://www.iana.org/domains/root/db/security.html -security - -// seek : Seek Limited -// https://www.iana.org/domains/root/db/seek.html -seek - -// select : Registry Services, LLC -// https://www.iana.org/domains/root/db/select.html -select - -// sener : Sener Ingeniería y Sistemas, S.A. -// https://www.iana.org/domains/root/db/sener.html -sener - -// services : Binky Moon, LLC -// https://www.iana.org/domains/root/db/services.html -services - -// seven : Seven West Media Ltd -// https://www.iana.org/domains/root/db/seven.html -seven - -// sew : SEW-EURODRIVE GmbH & Co KG -// https://www.iana.org/domains/root/db/sew.html -sew - -// sex : ICM Registry SX LLC -// https://www.iana.org/domains/root/db/sex.html -sex - -// sexy : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/sexy.html -sexy - -// sfr : Societe Francaise du Radiotelephone - SFR -// https://www.iana.org/domains/root/db/sfr.html -sfr - -// shangrila : Shangri‐La International Hotel Management Limited -// https://www.iana.org/domains/root/db/shangrila.html -shangrila - -// sharp : Sharp Corporation -// https://www.iana.org/domains/root/db/sharp.html -sharp - -// shell : Shell Information Technology International Inc -// https://www.iana.org/domains/root/db/shell.html -shell - -// shia -// https://www.iana.org/domains/root/db/shia.html -shia - -// shiksha : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/shiksha.html -shiksha - -// shoes : Binky Moon, LLC -// https://www.iana.org/domains/root/db/shoes.html -shoes - -// shop : GMO Registry, Inc. -// https://www.iana.org/domains/root/db/shop.html -shop - -// shopping : Binky Moon, LLC -// https://www.iana.org/domains/root/db/shopping.html -shopping - -// shouji : Beijing Qihu Keji Co., Ltd. -// https://www.iana.org/domains/root/db/shouji.html -shouji - -// show : Binky Moon, LLC -// https://www.iana.org/domains/root/db/show.html -show - -// silk : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/silk.html -silk - -// sina : Sina Corporation -// https://www.iana.org/domains/root/db/sina.html -sina - -// singles : Binky Moon, LLC -// https://www.iana.org/domains/root/db/singles.html -singles - -// site : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/site.html -site - -// ski : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/ski.html -ski - -// skin : XYZ.COM LLC -// https://www.iana.org/domains/root/db/skin.html -skin - -// sky : Sky UK Limited -// https://www.iana.org/domains/root/db/sky.html -sky - -// skype : Microsoft Corporation -// https://www.iana.org/domains/root/db/skype.html -skype - -// sling : DISH Technologies L.L.C. -// https://www.iana.org/domains/root/db/sling.html -sling - -// smart : Smart Communications, Inc. (SMART) -// https://www.iana.org/domains/root/db/smart.html -smart - -// smile : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/smile.html -smile - -// sncf : Société Nationale SNCF -// https://www.iana.org/domains/root/db/sncf.html -sncf - -// soccer : Binky Moon, LLC -// https://www.iana.org/domains/root/db/soccer.html -soccer - -// social : Dog Beach, LLC -// https://www.iana.org/domains/root/db/social.html -social - -// softbank : SoftBank Group Corp. -// https://www.iana.org/domains/root/db/softbank.html -softbank - -// software : Dog Beach, LLC -// https://www.iana.org/domains/root/db/software.html -software - -// sohu : Sohu.com Limited -// https://www.iana.org/domains/root/db/sohu.html -sohu - -// solar : Binky Moon, LLC -// https://www.iana.org/domains/root/db/solar.html -solar - -// solutions : Binky Moon, LLC -// https://www.iana.org/domains/root/db/solutions.html -solutions - -// song : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/song.html -song - -// sony : Sony Corporation -// https://www.iana.org/domains/root/db/sony.html -sony - -// soy : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/soy.html -soy - -// spa : Asia Spa and Wellness Promotion Council Limited -// https://www.iana.org/domains/root/db/spa.html -spa - -// space : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/space.html -space - -// sport : SportAccord -// https://www.iana.org/domains/root/db/sport.html -sport - -// spot : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/spot.html -spot - -// srl : InterNetX, Corp -// https://www.iana.org/domains/root/db/srl.html -srl - -// stada : STADA Arzneimittel AG -// https://www.iana.org/domains/root/db/stada.html -stada - -// staples : Staples, Inc. -// https://www.iana.org/domains/root/db/staples.html -staples - -// star : Star India Private Limited -// https://www.iana.org/domains/root/db/star.html -star - -// statebank : STATE BANK OF INDIA -// https://www.iana.org/domains/root/db/statebank.html -statebank - -// statefarm : State Farm Mutual Automobile Insurance Company -// https://www.iana.org/domains/root/db/statefarm.html -statefarm - -// stc : Saudi Telecom Company -// https://www.iana.org/domains/root/db/stc.html -stc - -// stcgroup : Saudi Telecom Company -// https://www.iana.org/domains/root/db/stcgroup.html -stcgroup - -// stockholm : Stockholms kommun -// https://www.iana.org/domains/root/db/stockholm.html -stockholm - -// storage : XYZ.COM LLC -// https://www.iana.org/domains/root/db/storage.html -storage - -// store : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/store.html -store - -// stream : dot Stream Limited -// https://www.iana.org/domains/root/db/stream.html -stream - -// studio : Dog Beach, LLC -// https://www.iana.org/domains/root/db/studio.html -studio - -// study : Registry Services, LLC -// https://www.iana.org/domains/root/db/study.html -study - -// style : Binky Moon, LLC -// https://www.iana.org/domains/root/db/style.html -style - -// sucks : Vox Populi Registry Ltd. -// https://www.iana.org/domains/root/db/sucks.html -sucks - -// supplies : Binky Moon, LLC -// https://www.iana.org/domains/root/db/supplies.html -supplies - -// supply : Binky Moon, LLC -// https://www.iana.org/domains/root/db/supply.html -supply - -// support : Binky Moon, LLC -// https://www.iana.org/domains/root/db/support.html -support - -// surf : Registry Services, LLC -// https://www.iana.org/domains/root/db/surf.html -surf - -// surgery : Binky Moon, LLC -// https://www.iana.org/domains/root/db/surgery.html -surgery - -// suzuki : SUZUKI MOTOR CORPORATION -// https://www.iana.org/domains/root/db/suzuki.html -suzuki - -// swatch : The Swatch Group Ltd -// https://www.iana.org/domains/root/db/swatch.html -swatch - -// swiss : Swiss Confederation -// https://www.iana.org/domains/root/db/swiss.html -swiss - -// sydney : State of New South Wales, Department of Premier and Cabinet -// https://www.iana.org/domains/root/db/sydney.html -sydney - -// systems : Binky Moon, LLC -// https://www.iana.org/domains/root/db/systems.html -systems - -// tab : Tabcorp Holdings Limited -// https://www.iana.org/domains/root/db/tab.html -tab - -// taipei : Taipei City Government -// https://www.iana.org/domains/root/db/taipei.html -taipei - -// talk : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/talk.html -talk - -// taobao : Alibaba Group Holding Limited -// https://www.iana.org/domains/root/db/taobao.html -taobao - -// target : Target Domain Holdings, LLC -// https://www.iana.org/domains/root/db/target.html -target - -// tatamotors : Tata Motors Ltd -// https://www.iana.org/domains/root/db/tatamotors.html -tatamotors - -// tatar : Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic" -// https://www.iana.org/domains/root/db/tatar.html -tatar - -// tattoo : Registry Services, LLC -// https://www.iana.org/domains/root/db/tattoo.html -tattoo - -// tax : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tax.html -tax - -// taxi : Binky Moon, LLC -// https://www.iana.org/domains/root/db/taxi.html -taxi - -// tci -// https://www.iana.org/domains/root/db/tci.html -tci - -// tdk : TDK Corporation -// https://www.iana.org/domains/root/db/tdk.html -tdk - -// team : Binky Moon, LLC -// https://www.iana.org/domains/root/db/team.html -team - -// tech : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/tech.html -tech - -// technology : Binky Moon, LLC -// https://www.iana.org/domains/root/db/technology.html -technology - -// temasek : Temasek Holdings (Private) Limited -// https://www.iana.org/domains/root/db/temasek.html -temasek - -// tennis : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tennis.html -tennis - -// teva : Teva Pharmaceutical Industries Limited -// https://www.iana.org/domains/root/db/teva.html -teva - -// thd : Home Depot Product Authority, LLC -// https://www.iana.org/domains/root/db/thd.html -thd - -// theater : Binky Moon, LLC -// https://www.iana.org/domains/root/db/theater.html -theater - -// theatre : XYZ.COM LLC -// https://www.iana.org/domains/root/db/theatre.html -theatre - -// tiaa : Teachers Insurance and Annuity Association of America -// https://www.iana.org/domains/root/db/tiaa.html -tiaa - -// tickets : XYZ.COM LLC -// https://www.iana.org/domains/root/db/tickets.html -tickets - -// tienda : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tienda.html -tienda - -// tips : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tips.html -tips - -// tires : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tires.html -tires - -// tirol : punkt Tirol GmbH -// https://www.iana.org/domains/root/db/tirol.html -tirol - -// tjmaxx : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/tjmaxx.html -tjmaxx - -// tjx : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/tjx.html -tjx - -// tkmaxx : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/tkmaxx.html -tkmaxx - -// tmall : Alibaba Group Holding Limited -// https://www.iana.org/domains/root/db/tmall.html -tmall - -// today : Binky Moon, LLC -// https://www.iana.org/domains/root/db/today.html -today - -// tokyo : GMO Registry, Inc. -// https://www.iana.org/domains/root/db/tokyo.html -tokyo - -// tools : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tools.html -tools - -// top : .TOP Registry -// https://www.iana.org/domains/root/db/top.html -top - -// toray : Toray Industries, Inc. -// https://www.iana.org/domains/root/db/toray.html -toray - -// toshiba : TOSHIBA Corporation -// https://www.iana.org/domains/root/db/toshiba.html -toshiba - -// total : TotalEnergies SE -// https://www.iana.org/domains/root/db/total.html -total - -// tours : Binky Moon, LLC -// https://www.iana.org/domains/root/db/tours.html -tours - -// town : Binky Moon, LLC -// https://www.iana.org/domains/root/db/town.html -town - -// toyota : TOYOTA MOTOR CORPORATION -// https://www.iana.org/domains/root/db/toyota.html -toyota - -// toys : Binky Moon, LLC -// https://www.iana.org/domains/root/db/toys.html -toys - -// trade : Elite Registry Limited -// https://www.iana.org/domains/root/db/trade.html -trade - -// trading : Dog Beach, LLC -// https://www.iana.org/domains/root/db/trading.html -trading - -// training : Binky Moon, LLC -// https://www.iana.org/domains/root/db/training.html -training - -// travel : Dog Beach, LLC -// https://www.iana.org/domains/root/db/travel.html -travel - -// travelers : Travelers TLD, LLC -// https://www.iana.org/domains/root/db/travelers.html -travelers - -// travelersinsurance : Travelers TLD, LLC -// https://www.iana.org/domains/root/db/travelersinsurance.html -travelersinsurance - -// trust : Internet Naming Company LLC -// https://www.iana.org/domains/root/db/trust.html -trust - -// trv : Travelers TLD, LLC -// https://www.iana.org/domains/root/db/trv.html -trv - -// tube : Latin American Telecom LLC -// https://www.iana.org/domains/root/db/tube.html -tube - -// tui : TUI AG -// https://www.iana.org/domains/root/db/tui.html -tui - -// tunes : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/tunes.html -tunes - -// tushu : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/tushu.html -tushu - -// tvs : T V SUNDRAM IYENGAR & SONS LIMITED -// https://www.iana.org/domains/root/db/tvs.html -tvs - -// ubank : National Australia Bank Limited -// https://www.iana.org/domains/root/db/ubank.html -ubank - -// ubs : UBS AG -// https://www.iana.org/domains/root/db/ubs.html -ubs - -// unicom : China United Network Communications Corporation Limited -// https://www.iana.org/domains/root/db/unicom.html -unicom - -// university : Binky Moon, LLC -// https://www.iana.org/domains/root/db/university.html -university - -// uno : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/uno.html -uno - -// uol : UBN INTERNET LTDA. -// https://www.iana.org/domains/root/db/uol.html -uol - -// ups : UPS Market Driver, Inc. -// https://www.iana.org/domains/root/db/ups.html -ups - -// vacations : Binky Moon, LLC -// https://www.iana.org/domains/root/db/vacations.html -vacations - -// vana : D3 Registry LLC -// https://www.iana.org/domains/root/db/vana.html -vana - -// vanguard : The Vanguard Group, Inc. -// https://www.iana.org/domains/root/db/vanguard.html -vanguard - -// vegas : Dot Vegas, Inc. -// https://www.iana.org/domains/root/db/vegas.html -vegas - -// ventures : Binky Moon, LLC -// https://www.iana.org/domains/root/db/ventures.html -ventures - -// verisign : VeriSign, Inc. -// https://www.iana.org/domains/root/db/verisign.html -verisign - -// versicherung : tldbox GmbH -// https://www.iana.org/domains/root/db/versicherung.html -versicherung - -// vet : Dog Beach, LLC -// https://www.iana.org/domains/root/db/vet.html -vet - -// viajes : Binky Moon, LLC -// https://www.iana.org/domains/root/db/viajes.html -viajes - -// video : Dog Beach, LLC -// https://www.iana.org/domains/root/db/video.html -video - -// vig : VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe -// https://www.iana.org/domains/root/db/vig.html -vig - -// viking : Viking River Cruises (Bermuda) Ltd. -// https://www.iana.org/domains/root/db/viking.html -viking - -// villas : Binky Moon, LLC -// https://www.iana.org/domains/root/db/villas.html -villas - -// vin : Binky Moon, LLC -// https://www.iana.org/domains/root/db/vin.html -vin - -// vip : Registry Services, LLC -// https://www.iana.org/domains/root/db/vip.html -vip - -// virgin : Virgin Enterprises Limited -// https://www.iana.org/domains/root/db/virgin.html -virgin - -// visa : Visa Worldwide Pte. Limited -// https://www.iana.org/domains/root/db/visa.html -visa - -// vision : Binky Moon, LLC -// https://www.iana.org/domains/root/db/vision.html -vision - -// viva : Saudi Telecom Company -// https://www.iana.org/domains/root/db/viva.html -viva - -// vivo : Telefonica Brasil S.A. -// https://www.iana.org/domains/root/db/vivo.html -vivo - -// vlaanderen : DNS.be vzw -// https://www.iana.org/domains/root/db/vlaanderen.html -vlaanderen - -// vodka : Registry Services, LLC -// https://www.iana.org/domains/root/db/vodka.html -vodka - -// volvo : Volvo Holding Sverige Aktiebolag -// https://www.iana.org/domains/root/db/volvo.html -volvo - -// vote : Monolith Registry LLC -// https://www.iana.org/domains/root/db/vote.html -vote - -// voting : Valuetainment Corp. -// https://www.iana.org/domains/root/db/voting.html -voting - -// voto : Monolith Registry LLC -// https://www.iana.org/domains/root/db/voto.html -voto - -// voyage : Binky Moon, LLC -// https://www.iana.org/domains/root/db/voyage.html -voyage - -// wales : Nominet UK -// https://www.iana.org/domains/root/db/wales.html -wales - -// walmart : Wal-Mart Stores, Inc. -// https://www.iana.org/domains/root/db/walmart.html -walmart - -// walter : Sandvik AB -// https://www.iana.org/domains/root/db/walter.html -walter - -// wang : Zodiac Wang Limited -// https://www.iana.org/domains/root/db/wang.html -wang - -// wanggou : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/wanggou.html -wanggou - -// watch : Binky Moon, LLC -// https://www.iana.org/domains/root/db/watch.html -watch - -// watches : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/watches.html -watches - -// weather : International Business Machines Corporation -// https://www.iana.org/domains/root/db/weather.html -weather - -// weatherchannel : The Weather Company, LLC -// https://www.iana.org/domains/root/db/weatherchannel.html -weatherchannel - -// webcam : dot Webcam Limited -// https://www.iana.org/domains/root/db/webcam.html -webcam - -// weber : Saint-Gobain Weber SA -// https://www.iana.org/domains/root/db/weber.html -weber - -// website : Radix Technologies Inc SEZC -// https://www.iana.org/domains/root/db/website.html -website - -// wed -// https://www.iana.org/domains/root/db/wed.html -wed - -// wedding : Registry Services, LLC -// https://www.iana.org/domains/root/db/wedding.html -wedding - -// weibo : Sina Corporation -// https://www.iana.org/domains/root/db/weibo.html -weibo - -// weir : Weir Group IP Limited -// https://www.iana.org/domains/root/db/weir.html -weir - -// whoswho : Who's Who Registry -// https://www.iana.org/domains/root/db/whoswho.html -whoswho - -// wien : punkt.wien GmbH -// https://www.iana.org/domains/root/db/wien.html -wien - -// wiki : Registry Services, LLC -// https://www.iana.org/domains/root/db/wiki.html -wiki - -// williamhill : William Hill Organization Limited -// https://www.iana.org/domains/root/db/williamhill.html -williamhill - -// win : First Registry Limited -// https://www.iana.org/domains/root/db/win.html -win - -// windows : Microsoft Corporation -// https://www.iana.org/domains/root/db/windows.html -windows - -// wine : Binky Moon, LLC -// https://www.iana.org/domains/root/db/wine.html -wine - -// winners : The TJX Companies, Inc. -// https://www.iana.org/domains/root/db/winners.html -winners - -// wme : William Morris Endeavor Entertainment, LLC -// https://www.iana.org/domains/root/db/wme.html -wme - -// wolterskluwer : Wolters Kluwer N.V. -// https://www.iana.org/domains/root/db/wolterskluwer.html -wolterskluwer - -// woodside : Woodside Petroleum Limited -// https://www.iana.org/domains/root/db/woodside.html -woodside - -// work : Registry Services, LLC -// https://www.iana.org/domains/root/db/work.html -work - -// works : Binky Moon, LLC -// https://www.iana.org/domains/root/db/works.html -works - -// world : Binky Moon, LLC -// https://www.iana.org/domains/root/db/world.html -world - -// wow : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/wow.html -wow - -// wtc : World Trade Centers Association, Inc. -// https://www.iana.org/domains/root/db/wtc.html -wtc - -// wtf : Binky Moon, LLC -// https://www.iana.org/domains/root/db/wtf.html -wtf - -// xbox : Microsoft Corporation -// https://www.iana.org/domains/root/db/xbox.html -xbox - -// xerox : Xerox DNHC LLC -// https://www.iana.org/domains/root/db/xerox.html -xerox - -// xihuan : Beijing Qihu Keji Co., Ltd. -// https://www.iana.org/domains/root/db/xihuan.html -xihuan - -// xin : Elegant Leader Limited -// https://www.iana.org/domains/root/db/xin.html -xin - -// xn--11b4c3d : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--11b4c3d.html -कॉम - -// xn--1ck2e1b : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--1ck2e1b.html -セール - -// xn--1qqw23a : Guangzhou YU Wei Information Technology Co., Ltd. -// https://www.iana.org/domains/root/db/xn--1qqw23a.html -佛山 - -// xn--30rr7y : Excellent First Limited -// https://www.iana.org/domains/root/db/xn--30rr7y.html -慈善 - -// xn--3bst00m : Eagle Horizon Limited -// https://www.iana.org/domains/root/db/xn--3bst00m.html -集团 - -// xn--3ds443g : Beijing TLD Registry Technology Limited -// https://www.iana.org/domains/root/db/xn--3ds443g.html -在线 - -// xn--3pxu8k : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--3pxu8k.html -点看 - -// xn--42c2d9a : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--42c2d9a.html -คอม - -// xn--45q11c : Zodiac Gemini Ltd -// https://www.iana.org/domains/root/db/xn--45q11c.html -八卦 - -// xn--4gbrim : Helium TLDs Ltd -// https://www.iana.org/domains/root/db/xn--4gbrim.html -موقع - -// xn--55qw42g : China Organizational Name Administration Center -// https://www.iana.org/domains/root/db/xn--55qw42g.html -公益 - -// xn--55qx5d : China Internet Network Information Center (CNNIC) -// https://www.iana.org/domains/root/db/xn--55qx5d.html -公司 - -// xn--5su34j936bgsg : Shangri‐La International Hotel Management Limited -// https://www.iana.org/domains/root/db/xn--5su34j936bgsg.html -香格里拉 - -// xn--5tzm5g : Global Website TLD Asia Limited -// https://www.iana.org/domains/root/db/xn--5tzm5g.html -网站 - -// xn--6frz82g : Identity Digital Domains Limited -// https://www.iana.org/domains/root/db/xn--6frz82g.html -移动 - -// xn--6qq986b3xl : Tycoon Treasure Limited -// https://www.iana.org/domains/root/db/xn--6qq986b3xl.html -我爱你 - -// xn--80adxhks : Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID) -// https://www.iana.org/domains/root/db/xn--80adxhks.html -москва - -// xn--80aqecdr1a : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) -// https://www.iana.org/domains/root/db/xn--80aqecdr1a.html -католик - -// xn--80asehdb : CORE Association -// https://www.iana.org/domains/root/db/xn--80asehdb.html -онлайн - -// xn--80aswg : CORE Association -// https://www.iana.org/domains/root/db/xn--80aswg.html -сайт - -// xn--8y0a063a : China United Network Communications Corporation Limited -// https://www.iana.org/domains/root/db/xn--8y0a063a.html -联通 - -// xn--9dbq2a : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--9dbq2a.html -קום - -// xn--9et52u : RISE VICTORY LIMITED -// https://www.iana.org/domains/root/db/xn--9et52u.html -时尚 - -// xn--9krt00a : Sina Corporation -// https://www.iana.org/domains/root/db/xn--9krt00a.html -微博 - -// xn--b4w605ferd : Temasek Holdings (Private) Limited -// https://www.iana.org/domains/root/db/xn--b4w605ferd.html -淡马锡 - -// xn--bck1b9a5dre4c : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--bck1b9a5dre4c.html -ファッション - -// xn--c1avg : Public Interest Registry -// https://www.iana.org/domains/root/db/xn--c1avg.html -орг - -// xn--c2br7g : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--c2br7g.html -नेट - -// xn--cck2b3b : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--cck2b3b.html -ストア - -// xn--cckwcxetd : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--cckwcxetd.html -アマゾン - -// xn--cg4bki : SAMSUNG SDS CO., LTD -// https://www.iana.org/domains/root/db/xn--cg4bki.html -삼성 - -// xn--czr694b : Internet DotTrademark Organisation Limited -// https://www.iana.org/domains/root/db/xn--czr694b.html -商标 - -// xn--czrs0t : Binky Moon, LLC -// https://www.iana.org/domains/root/db/xn--czrs0t.html -商店 - -// xn--czru2d : Zodiac Aquarius Limited -// https://www.iana.org/domains/root/db/xn--czru2d.html -商城 - -// xn--d1acj3b : The Foundation for Network Initiatives “The Smart Internet” -// https://www.iana.org/domains/root/db/xn--d1acj3b.html -дети - -// xn--eckvdtc9d : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--eckvdtc9d.html -ポイント - -// xn--efvy88h : Guangzhou YU Wei Information Technology Co., Ltd. -// https://www.iana.org/domains/root/db/xn--efvy88h.html -新闻 - -// xn--fct429k : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--fct429k.html -家電 - -// xn--fhbei : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--fhbei.html -كوم - -// xn--fiq228c5hs : TLD REGISTRY LIMITED OY -// https://www.iana.org/domains/root/db/xn--fiq228c5hs.html -中文网 - -// xn--fiq64b : CITIC Group Corporation -// https://www.iana.org/domains/root/db/xn--fiq64b.html -中信 - -// xn--fjq720a : Binky Moon, LLC -// https://www.iana.org/domains/root/db/xn--fjq720a.html -娱乐 - -// xn--flw351e : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/xn--flw351e.html -谷歌 - -// xn--fzys8d69uvgm : PCCW Enterprises Limited -// https://www.iana.org/domains/root/db/xn--fzys8d69uvgm.html -電訊盈科 - -// xn--g2xx48c : Nawang Heli(Xiamen) Network Service Co., LTD. -// https://www.iana.org/domains/root/db/xn--g2xx48c.html -购物 - -// xn--gckr3f0f : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--gckr3f0f.html -クラウド - -// xn--gk3at1e : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--gk3at1e.html -通販 - -// xn--hxt814e : Zodiac Taurus Limited -// https://www.iana.org/domains/root/db/xn--hxt814e.html -网店 - -// xn--i1b6b1a6a2e : Public Interest Registry -// https://www.iana.org/domains/root/db/xn--i1b6b1a6a2e.html -संगठन - -// xn--imr513n : Internet DotTrademark Organisation Limited -// https://www.iana.org/domains/root/db/xn--imr513n.html -餐厅 - -// xn--io0a7i : China Internet Network Information Center (CNNIC) -// https://www.iana.org/domains/root/db/xn--io0a7i.html -网络 - -// xn--j1aef : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--j1aef.html -ком - -// xn--jlq480n2rg : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--jlq480n2rg.html -亚马逊 - -// xn--jvr189m : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--jvr189m.html -食品 - -// xn--kcrx77d1x4a : Koninklijke Philips N.V. -// https://www.iana.org/domains/root/db/xn--kcrx77d1x4a.html -飞利浦 - -// xn--kput3i : Beijing RITT-Net Technology Development Co., Ltd -// https://www.iana.org/domains/root/db/xn--kput3i.html -手机 - -// xn--mgba3a3ejt : Aramco Services Company -// https://www.iana.org/domains/root/db/xn--mgba3a3ejt.html -ارامكو - -// xn--mgba7c0bbn0a : Competrol (Luxembourg) Sarl -// https://www.iana.org/domains/root/db/xn--mgba7c0bbn0a.html -العليان - -// xn--mgbab2bd : CORE Association -// https://www.iana.org/domains/root/db/xn--mgbab2bd.html -بازار - -// xn--mgbca7dzdo : Abu Dhabi Systems and Information Centre -// https://www.iana.org/domains/root/db/xn--mgbca7dzdo.html -ابوظبي - -// xn--mgbi4ecexp : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) -// https://www.iana.org/domains/root/db/xn--mgbi4ecexp.html -كاثوليك - -// xn--mgbt3dhd -// https://www.iana.org/domains/root/db/xn--mgbt3dhd.html -همراه - -// xn--mk1bu44c : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--mk1bu44c.html -닷컴 - -// xn--mxtq1m : Net-Chinese Co., Ltd. -// https://www.iana.org/domains/root/db/xn--mxtq1m.html -政府 - -// xn--ngbc5azd : International Domain Registry Pty. Ltd. -// https://www.iana.org/domains/root/db/xn--ngbc5azd.html -شبكة - -// xn--ngbe9e0a : Kuwait Finance House -// https://www.iana.org/domains/root/db/xn--ngbe9e0a.html -بيتك - -// xn--ngbrx : League of Arab States -// https://www.iana.org/domains/root/db/xn--ngbrx.html -عرب - -// xn--nqv7f : Public Interest Registry -// https://www.iana.org/domains/root/db/xn--nqv7f.html -机构 - -// xn--nqv7fs00ema : Public Interest Registry -// https://www.iana.org/domains/root/db/xn--nqv7fs00ema.html -组织机构 - -// xn--nyqy26a : Stable Tone Limited -// https://www.iana.org/domains/root/db/xn--nyqy26a.html -健康 - -// xn--otu796d : Jiang Yu Liang Cai Technology Company Limited -// https://www.iana.org/domains/root/db/xn--otu796d.html -招聘 - -// xn--p1acf : Rusnames Limited -// https://www.iana.org/domains/root/db/xn--p1acf.html -рус - -// xn--pssy2u : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--pssy2u.html -大拿 - -// xn--q9jyb4c : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/xn--q9jyb4c.html -みんな - -// xn--qcka1pmc : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/xn--qcka1pmc.html -グーグル - -// xn--rhqv96g : Stable Tone Limited -// https://www.iana.org/domains/root/db/xn--rhqv96g.html -世界 - -// xn--rovu88b : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/xn--rovu88b.html -書籍 - -// xn--ses554g : KNET Co., Ltd. -// https://www.iana.org/domains/root/db/xn--ses554g.html -网址 - -// xn--t60b56a : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--t60b56a.html -닷넷 - -// xn--tckwe : VeriSign Sarl -// https://www.iana.org/domains/root/db/xn--tckwe.html -コム - -// xn--tiq49xqyj : Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication) -// https://www.iana.org/domains/root/db/xn--tiq49xqyj.html -天主教 - -// xn--unup4y : Binky Moon, LLC -// https://www.iana.org/domains/root/db/xn--unup4y.html -游戏 - -// xn--vermgensberater-ctb : Deutsche Vermögensberatung Aktiengesellschaft DVAG -// https://www.iana.org/domains/root/db/xn--vermgensberater-ctb.html -vermögensberater - -// xn--vermgensberatung-pwb : Deutsche Vermögensberatung Aktiengesellschaft DVAG -// https://www.iana.org/domains/root/db/xn--vermgensberatung-pwb.html -vermögensberatung - -// xn--vhquv : Binky Moon, LLC -// https://www.iana.org/domains/root/db/xn--vhquv.html -企业 - -// xn--vuq861b : Beijing Tele-info Technology Co., Ltd. -// https://www.iana.org/domains/root/db/xn--vuq861b.html -信息 - -// xn--w4r85el8fhu5dnra : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/xn--w4r85el8fhu5dnra.html -嘉里大酒店 - -// xn--w4rs40l : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/xn--w4rs40l.html -嘉里 - -// xn--xhq521b : Guangzhou YU Wei Information Technology Co., Ltd. -// https://www.iana.org/domains/root/db/xn--xhq521b.html -广东 - -// xn--zfr164b : China Organizational Name Administration Center -// https://www.iana.org/domains/root/db/xn--zfr164b.html -政务 - -// xyz : XYZ.COM LLC -// https://www.iana.org/domains/root/db/xyz.html -xyz - -// yachts : XYZ.COM LLC -// https://www.iana.org/domains/root/db/yachts.html -yachts - -// yahoo : Yahoo Inc. -// https://www.iana.org/domains/root/db/yahoo.html -yahoo - -// yamaxun : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/yamaxun.html -yamaxun - -// yandex : YANDEX, LLC -// https://www.iana.org/domains/root/db/yandex.html -yandex - -// yodobashi : YODOBASHI CAMERA CO.,LTD. -// https://www.iana.org/domains/root/db/yodobashi.html -yodobashi - -// yoga : Registry Services, LLC -// https://www.iana.org/domains/root/db/yoga.html -yoga - -// yokohama : GMO Registry, Inc. -// https://www.iana.org/domains/root/db/yokohama.html -yokohama - -// you : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/you.html -you - -// youtube : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/youtube.html -youtube - -// yun : Beijing Qihu Keji Co., Ltd. -// https://www.iana.org/domains/root/db/yun.html -yun - -// zappos : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/zappos.html -zappos - -// zara : Industria de Diseño Textil, S.A. (INDITEX, S.A.) -// https://www.iana.org/domains/root/db/zara.html -zara - -// zero : Amazon Registry Services, Inc. -// https://www.iana.org/domains/root/db/zero.html -zero - -// zip : Charleston Road Registry Inc. -// https://www.iana.org/domains/root/db/zip.html -zip - -// zone : Binky Moon, LLC -// https://www.iana.org/domains/root/db/zone.html -zone - -// zuerich : Kanton Zürich (Canton of Zurich) -// https://www.iana.org/domains/root/db/zuerich.html -zuerich - -// ===END ICANN DOMAINS=== - -// ===BEGIN PRIVATE DOMAINS=== - -// (Note: these are in alphabetical order by company name) - -// .KRD : https://nic.krd -co.krd -edu.krd - -// .pl domains (grandfathered) -art.pl -gliwice.pl -krakow.pl -poznan.pl -wroc.pl -zakopane.pl - -// 12CHARS : https://12chars.com -// Submitted by Kenny Niehage -12chars.dev -12chars.it -12chars.pro - -// 1GB LLC : https://www.1gb.ua/ -// Submitted by 1GB LLC -cc.ua -inf.ua -ltd.ua - -// 611 blockchain domain name system : https://sixone.one/ -611.to - -// A2 Hosting -// Submitted by Tyler Hall -a2hosted.com -cpserver.com - -// Acorn Labs : https://acorn.io -// Submitted by Craig Jellick -*.on-acorn.io - -// ActiveTrail : https://www.activetrail.biz/ -// Submitted by Ofer Kalaora -activetrail.biz - -// Adaptable.io : https://adaptable.io -// Submitted by Mark Terrel -adaptable.app - -// addr.tools : https://addr.tools/ -// Submitted by Brian Shea -myaddr.dev -myaddr.io -dyn.addr.tools -myaddr.tools - -// Adobe : https://www.adobe.com/ -// Submitted by Ian Boston and Lars Trieloff -adobeaemcloud.com -*.dev.adobeaemcloud.com -aem.live -hlx.live -adobeaemcloud.net -aem.network -aem.page -hlx.page -aem.reviews - -// Adobe Developer Platform : https://developer.adobe.com -// Submitted by Jesse MacFadyen -adobeio-static.net -adobeioruntime.net - -// Africa.com Web Solutions Ltd : https://registry.africa.com -// Submitted by Gavin Brown -africa.com - -// Agnat sp. z o.o. : https://domena.pl -// Submitted by Przemyslaw Plewa -beep.pl - -// Aiven : https://aiven.io/ -// Submitted by Aiven Security Team -aiven.app -aivencloud.com - -// Akamai : https://www.akamai.com/ -// Submitted by Akamai Team -akadns.net -akamai.net -akamai-staging.net -akamaiedge.net -akamaiedge-staging.net -akamaihd.net -akamaihd-staging.net -akamaiorigin.net -akamaiorigin-staging.net -akamaized.net -akamaized-staging.net -edgekey.net -edgekey-staging.net -edgesuite.net -edgesuite-staging.net - -// alboto.ca : http://alboto.ca -// Submitted by Anton Avramov -barsy.ca - -// Alces Software Ltd : http://alces-software.com -// Submitted by Mark J. Titorenko -*.compute.estate -*.alces.network - -// Alibaba Cloud API Gateway -// Submitted by Alibaba Cloud Security -alibabacloudcs.com - -// all-inkl.com : https://all-inkl.com -// Submitted by Werner Kaltofen -kasserver.com - -// Altervista : https://www.altervista.org -// Submitted by Carlo Cannas -altervista.org - -// alwaysdata : https://www.alwaysdata.com -// Submitted by Cyril -alwaysdata.net - -// Amaze Software : https://amaze.co -// Submitted by Domain Admin -myamaze.net - -// Amazon : https://www.amazon.com/ -// Submitted by AWS Security -// Subsections of Amazon/subsidiaries will appear until "concludes" tag - -// Amazon API Gateway -// Submitted by AWS Security -// Reference: 6a4f5a95-8c7d-4077-a7af-9cf1abec0a53 -execute-api.cn-north-1.amazonaws.com.cn -execute-api.cn-northwest-1.amazonaws.com.cn -execute-api.af-south-1.amazonaws.com -execute-api.ap-east-1.amazonaws.com -execute-api.ap-northeast-1.amazonaws.com -execute-api.ap-northeast-2.amazonaws.com -execute-api.ap-northeast-3.amazonaws.com -execute-api.ap-south-1.amazonaws.com -execute-api.ap-south-2.amazonaws.com -execute-api.ap-southeast-1.amazonaws.com -execute-api.ap-southeast-2.amazonaws.com -execute-api.ap-southeast-3.amazonaws.com -execute-api.ap-southeast-4.amazonaws.com -execute-api.ap-southeast-5.amazonaws.com -execute-api.ca-central-1.amazonaws.com -execute-api.ca-west-1.amazonaws.com -execute-api.eu-central-1.amazonaws.com -execute-api.eu-central-2.amazonaws.com -execute-api.eu-north-1.amazonaws.com -execute-api.eu-south-1.amazonaws.com -execute-api.eu-south-2.amazonaws.com -execute-api.eu-west-1.amazonaws.com -execute-api.eu-west-2.amazonaws.com -execute-api.eu-west-3.amazonaws.com -execute-api.il-central-1.amazonaws.com -execute-api.me-central-1.amazonaws.com -execute-api.me-south-1.amazonaws.com -execute-api.sa-east-1.amazonaws.com -execute-api.us-east-1.amazonaws.com -execute-api.us-east-2.amazonaws.com -execute-api.us-gov-east-1.amazonaws.com -execute-api.us-gov-west-1.amazonaws.com -execute-api.us-west-1.amazonaws.com -execute-api.us-west-2.amazonaws.com - -// Amazon CloudFront -// Submitted by Donavan Miller -// Reference: 54144616-fd49-4435-8535-19c6a601bdb3 -cloudfront.net - -// Amazon Cognito -// Submitted by AWS Security -// Reference: e7c02dc1-02f4-4a23-bde3-a8527c830127 -auth.af-south-1.amazoncognito.com -auth.ap-east-1.amazoncognito.com -auth.ap-northeast-1.amazoncognito.com -auth.ap-northeast-2.amazoncognito.com -auth.ap-northeast-3.amazoncognito.com -auth.ap-south-1.amazoncognito.com -auth.ap-south-2.amazoncognito.com -auth.ap-southeast-1.amazoncognito.com -auth.ap-southeast-2.amazoncognito.com -auth.ap-southeast-3.amazoncognito.com -auth.ap-southeast-4.amazoncognito.com -auth.ap-southeast-5.amazoncognito.com -auth.ap-southeast-7.amazoncognito.com -auth.ca-central-1.amazoncognito.com -auth.ca-west-1.amazoncognito.com -auth.eu-central-1.amazoncognito.com -auth.eu-central-2.amazoncognito.com -auth.eu-north-1.amazoncognito.com -auth.eu-south-1.amazoncognito.com -auth.eu-south-2.amazoncognito.com -auth.eu-west-1.amazoncognito.com -auth.eu-west-2.amazoncognito.com -auth.eu-west-3.amazoncognito.com -auth.il-central-1.amazoncognito.com -auth.me-central-1.amazoncognito.com -auth.me-south-1.amazoncognito.com -auth.mx-central-1.amazoncognito.com -auth.sa-east-1.amazoncognito.com -auth.us-east-1.amazoncognito.com -auth-fips.us-east-1.amazoncognito.com -auth.us-east-2.amazoncognito.com -auth-fips.us-east-2.amazoncognito.com -auth-fips.us-gov-east-1.amazoncognito.com -auth-fips.us-gov-west-1.amazoncognito.com -auth.us-west-1.amazoncognito.com -auth-fips.us-west-1.amazoncognito.com -auth.us-west-2.amazoncognito.com -auth-fips.us-west-2.amazoncognito.com - -// Amazon EC2 -// Submitted by Luke Wells -// Reference: 4c38fa71-58ac-4768-99e5-689c1767e537 -*.compute.amazonaws.com.cn -*.compute.amazonaws.com -*.compute-1.amazonaws.com -us-east-1.amazonaws.com - -// Amazon EMR -// Submitted by AWS Security -// Reference: 82f43f9f-bbb8-400e-8349-854f5a62f20d -emrappui-prod.cn-north-1.amazonaws.com.cn -emrnotebooks-prod.cn-north-1.amazonaws.com.cn -emrstudio-prod.cn-north-1.amazonaws.com.cn -emrappui-prod.cn-northwest-1.amazonaws.com.cn -emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn -emrstudio-prod.cn-northwest-1.amazonaws.com.cn -emrappui-prod.af-south-1.amazonaws.com -emrnotebooks-prod.af-south-1.amazonaws.com -emrstudio-prod.af-south-1.amazonaws.com -emrappui-prod.ap-east-1.amazonaws.com -emrnotebooks-prod.ap-east-1.amazonaws.com -emrstudio-prod.ap-east-1.amazonaws.com -emrappui-prod.ap-northeast-1.amazonaws.com -emrnotebooks-prod.ap-northeast-1.amazonaws.com -emrstudio-prod.ap-northeast-1.amazonaws.com -emrappui-prod.ap-northeast-2.amazonaws.com -emrnotebooks-prod.ap-northeast-2.amazonaws.com -emrstudio-prod.ap-northeast-2.amazonaws.com -emrappui-prod.ap-northeast-3.amazonaws.com -emrnotebooks-prod.ap-northeast-3.amazonaws.com -emrstudio-prod.ap-northeast-3.amazonaws.com -emrappui-prod.ap-south-1.amazonaws.com -emrnotebooks-prod.ap-south-1.amazonaws.com -emrstudio-prod.ap-south-1.amazonaws.com -emrappui-prod.ap-south-2.amazonaws.com -emrnotebooks-prod.ap-south-2.amazonaws.com -emrstudio-prod.ap-south-2.amazonaws.com -emrappui-prod.ap-southeast-1.amazonaws.com -emrnotebooks-prod.ap-southeast-1.amazonaws.com -emrstudio-prod.ap-southeast-1.amazonaws.com -emrappui-prod.ap-southeast-2.amazonaws.com -emrnotebooks-prod.ap-southeast-2.amazonaws.com -emrstudio-prod.ap-southeast-2.amazonaws.com -emrappui-prod.ap-southeast-3.amazonaws.com -emrnotebooks-prod.ap-southeast-3.amazonaws.com -emrstudio-prod.ap-southeast-3.amazonaws.com -emrappui-prod.ap-southeast-4.amazonaws.com -emrnotebooks-prod.ap-southeast-4.amazonaws.com -emrstudio-prod.ap-southeast-4.amazonaws.com -emrappui-prod.ca-central-1.amazonaws.com -emrnotebooks-prod.ca-central-1.amazonaws.com -emrstudio-prod.ca-central-1.amazonaws.com -emrappui-prod.ca-west-1.amazonaws.com -emrnotebooks-prod.ca-west-1.amazonaws.com -emrstudio-prod.ca-west-1.amazonaws.com -emrappui-prod.eu-central-1.amazonaws.com -emrnotebooks-prod.eu-central-1.amazonaws.com -emrstudio-prod.eu-central-1.amazonaws.com -emrappui-prod.eu-central-2.amazonaws.com -emrnotebooks-prod.eu-central-2.amazonaws.com -emrstudio-prod.eu-central-2.amazonaws.com -emrappui-prod.eu-north-1.amazonaws.com -emrnotebooks-prod.eu-north-1.amazonaws.com -emrstudio-prod.eu-north-1.amazonaws.com -emrappui-prod.eu-south-1.amazonaws.com -emrnotebooks-prod.eu-south-1.amazonaws.com -emrstudio-prod.eu-south-1.amazonaws.com -emrappui-prod.eu-south-2.amazonaws.com -emrnotebooks-prod.eu-south-2.amazonaws.com -emrstudio-prod.eu-south-2.amazonaws.com -emrappui-prod.eu-west-1.amazonaws.com -emrnotebooks-prod.eu-west-1.amazonaws.com -emrstudio-prod.eu-west-1.amazonaws.com -emrappui-prod.eu-west-2.amazonaws.com -emrnotebooks-prod.eu-west-2.amazonaws.com -emrstudio-prod.eu-west-2.amazonaws.com -emrappui-prod.eu-west-3.amazonaws.com -emrnotebooks-prod.eu-west-3.amazonaws.com -emrstudio-prod.eu-west-3.amazonaws.com -emrappui-prod.il-central-1.amazonaws.com -emrnotebooks-prod.il-central-1.amazonaws.com -emrstudio-prod.il-central-1.amazonaws.com -emrappui-prod.me-central-1.amazonaws.com -emrnotebooks-prod.me-central-1.amazonaws.com -emrstudio-prod.me-central-1.amazonaws.com -emrappui-prod.me-south-1.amazonaws.com -emrnotebooks-prod.me-south-1.amazonaws.com -emrstudio-prod.me-south-1.amazonaws.com -emrappui-prod.sa-east-1.amazonaws.com -emrnotebooks-prod.sa-east-1.amazonaws.com -emrstudio-prod.sa-east-1.amazonaws.com -emrappui-prod.us-east-1.amazonaws.com -emrnotebooks-prod.us-east-1.amazonaws.com -emrstudio-prod.us-east-1.amazonaws.com -emrappui-prod.us-east-2.amazonaws.com -emrnotebooks-prod.us-east-2.amazonaws.com -emrstudio-prod.us-east-2.amazonaws.com -emrappui-prod.us-gov-east-1.amazonaws.com -emrnotebooks-prod.us-gov-east-1.amazonaws.com -emrstudio-prod.us-gov-east-1.amazonaws.com -emrappui-prod.us-gov-west-1.amazonaws.com -emrnotebooks-prod.us-gov-west-1.amazonaws.com -emrstudio-prod.us-gov-west-1.amazonaws.com -emrappui-prod.us-west-1.amazonaws.com -emrnotebooks-prod.us-west-1.amazonaws.com -emrstudio-prod.us-west-1.amazonaws.com -emrappui-prod.us-west-2.amazonaws.com -emrnotebooks-prod.us-west-2.amazonaws.com -emrstudio-prod.us-west-2.amazonaws.com - -// Amazon Managed Workflows for Apache Airflow -// Submitted by AWS Security -// Reference: 2f697e23-58d6-4b97-be6b-77a26e811dad -*.airflow.af-south-1.on.aws -*.airflow.ap-east-1.on.aws -*.airflow.ap-northeast-1.on.aws -*.airflow.ap-northeast-2.on.aws -*.airflow.ap-northeast-3.on.aws -*.airflow.ap-south-1.on.aws -*.airflow.ap-south-2.on.aws -*.airflow.ap-southeast-1.on.aws -*.airflow.ap-southeast-2.on.aws -*.airflow.ap-southeast-3.on.aws -*.airflow.ap-southeast-4.on.aws -*.airflow.ap-southeast-5.on.aws -*.airflow.ca-central-1.on.aws -*.airflow.ca-west-1.on.aws -*.airflow.eu-central-1.on.aws -*.airflow.eu-central-2.on.aws -*.airflow.eu-north-1.on.aws -*.airflow.eu-south-1.on.aws -*.airflow.eu-south-2.on.aws -*.airflow.eu-west-1.on.aws -*.airflow.eu-west-2.on.aws -*.airflow.eu-west-3.on.aws -*.airflow.il-central-1.on.aws -*.airflow.me-central-1.on.aws -*.airflow.me-south-1.on.aws -*.airflow.sa-east-1.on.aws -*.airflow.us-east-1.on.aws -*.airflow.us-east-2.on.aws -*.airflow.us-west-1.on.aws -*.airflow.us-west-2.on.aws -*.cn-north-1.airflow.amazonaws.com.cn -*.cn-northwest-1.airflow.amazonaws.com.cn -*.airflow.cn-north-1.on.amazonwebservices.com.cn -*.airflow.cn-northwest-1.on.amazonwebservices.com.cn -*.af-south-1.airflow.amazonaws.com -*.ap-east-1.airflow.amazonaws.com -*.ap-northeast-1.airflow.amazonaws.com -*.ap-northeast-2.airflow.amazonaws.com -*.ap-northeast-3.airflow.amazonaws.com -*.ap-south-1.airflow.amazonaws.com -*.ap-south-2.airflow.amazonaws.com -*.ap-southeast-1.airflow.amazonaws.com -*.ap-southeast-2.airflow.amazonaws.com -*.ap-southeast-3.airflow.amazonaws.com -*.ap-southeast-4.airflow.amazonaws.com -*.ap-southeast-5.airflow.amazonaws.com -*.ca-central-1.airflow.amazonaws.com -*.ca-west-1.airflow.amazonaws.com -*.eu-central-1.airflow.amazonaws.com -*.eu-central-2.airflow.amazonaws.com -*.eu-north-1.airflow.amazonaws.com -*.eu-south-1.airflow.amazonaws.com -*.eu-south-2.airflow.amazonaws.com -*.eu-west-1.airflow.amazonaws.com -*.eu-west-2.airflow.amazonaws.com -*.eu-west-3.airflow.amazonaws.com -*.il-central-1.airflow.amazonaws.com -*.me-central-1.airflow.amazonaws.com -*.me-south-1.airflow.amazonaws.com -*.sa-east-1.airflow.amazonaws.com -*.us-east-1.airflow.amazonaws.com -*.us-east-2.airflow.amazonaws.com -*.us-west-1.airflow.amazonaws.com -*.us-west-2.airflow.amazonaws.com - -// Amazon S3 -// Submitted by AWS Security -// Reference: ada5c9df-55e1-4195-a1ce-732d6c81e357 -s3.dualstack.cn-north-1.amazonaws.com.cn -s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn -s3-website.dualstack.cn-north-1.amazonaws.com.cn -s3.cn-north-1.amazonaws.com.cn -s3-accesspoint.cn-north-1.amazonaws.com.cn -s3-deprecated.cn-north-1.amazonaws.com.cn -s3-object-lambda.cn-north-1.amazonaws.com.cn -s3-website.cn-north-1.amazonaws.com.cn -s3.dualstack.cn-northwest-1.amazonaws.com.cn -s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn -s3.cn-northwest-1.amazonaws.com.cn -s3-accesspoint.cn-northwest-1.amazonaws.com.cn -s3-object-lambda.cn-northwest-1.amazonaws.com.cn -s3-website.cn-northwest-1.amazonaws.com.cn -s3.dualstack.af-south-1.amazonaws.com -s3-accesspoint.dualstack.af-south-1.amazonaws.com -s3-website.dualstack.af-south-1.amazonaws.com -s3.af-south-1.amazonaws.com -s3-accesspoint.af-south-1.amazonaws.com -s3-object-lambda.af-south-1.amazonaws.com -s3-website.af-south-1.amazonaws.com -s3.dualstack.ap-east-1.amazonaws.com -s3-accesspoint.dualstack.ap-east-1.amazonaws.com -s3.ap-east-1.amazonaws.com -s3-accesspoint.ap-east-1.amazonaws.com -s3-object-lambda.ap-east-1.amazonaws.com -s3-website.ap-east-1.amazonaws.com -s3.dualstack.ap-northeast-1.amazonaws.com -s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com -s3-website.dualstack.ap-northeast-1.amazonaws.com -s3.ap-northeast-1.amazonaws.com -s3-accesspoint.ap-northeast-1.amazonaws.com -s3-object-lambda.ap-northeast-1.amazonaws.com -s3-website.ap-northeast-1.amazonaws.com -s3.dualstack.ap-northeast-2.amazonaws.com -s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com -s3-website.dualstack.ap-northeast-2.amazonaws.com -s3.ap-northeast-2.amazonaws.com -s3-accesspoint.ap-northeast-2.amazonaws.com -s3-object-lambda.ap-northeast-2.amazonaws.com -s3-website.ap-northeast-2.amazonaws.com -s3.dualstack.ap-northeast-3.amazonaws.com -s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com -s3-website.dualstack.ap-northeast-3.amazonaws.com -s3.ap-northeast-3.amazonaws.com -s3-accesspoint.ap-northeast-3.amazonaws.com -s3-object-lambda.ap-northeast-3.amazonaws.com -s3-website.ap-northeast-3.amazonaws.com -s3.dualstack.ap-south-1.amazonaws.com -s3-accesspoint.dualstack.ap-south-1.amazonaws.com -s3-website.dualstack.ap-south-1.amazonaws.com -s3.ap-south-1.amazonaws.com -s3-accesspoint.ap-south-1.amazonaws.com -s3-object-lambda.ap-south-1.amazonaws.com -s3-website.ap-south-1.amazonaws.com -s3.dualstack.ap-south-2.amazonaws.com -s3-accesspoint.dualstack.ap-south-2.amazonaws.com -s3-website.dualstack.ap-south-2.amazonaws.com -s3.ap-south-2.amazonaws.com -s3-accesspoint.ap-south-2.amazonaws.com -s3-object-lambda.ap-south-2.amazonaws.com -s3-website.ap-south-2.amazonaws.com -s3.dualstack.ap-southeast-1.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com -s3-website.dualstack.ap-southeast-1.amazonaws.com -s3.ap-southeast-1.amazonaws.com -s3-accesspoint.ap-southeast-1.amazonaws.com -s3-object-lambda.ap-southeast-1.amazonaws.com -s3-website.ap-southeast-1.amazonaws.com -s3.dualstack.ap-southeast-2.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com -s3-website.dualstack.ap-southeast-2.amazonaws.com -s3.ap-southeast-2.amazonaws.com -s3-accesspoint.ap-southeast-2.amazonaws.com -s3-object-lambda.ap-southeast-2.amazonaws.com -s3-website.ap-southeast-2.amazonaws.com -s3.dualstack.ap-southeast-3.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com -s3-website.dualstack.ap-southeast-3.amazonaws.com -s3.ap-southeast-3.amazonaws.com -s3-accesspoint.ap-southeast-3.amazonaws.com -s3-object-lambda.ap-southeast-3.amazonaws.com -s3-website.ap-southeast-3.amazonaws.com -s3.dualstack.ap-southeast-4.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com -s3-website.dualstack.ap-southeast-4.amazonaws.com -s3.ap-southeast-4.amazonaws.com -s3-accesspoint.ap-southeast-4.amazonaws.com -s3-object-lambda.ap-southeast-4.amazonaws.com -s3-website.ap-southeast-4.amazonaws.com -s3.dualstack.ap-southeast-5.amazonaws.com -s3-accesspoint.dualstack.ap-southeast-5.amazonaws.com -s3-website.dualstack.ap-southeast-5.amazonaws.com -s3.ap-southeast-5.amazonaws.com -s3-accesspoint.ap-southeast-5.amazonaws.com -s3-deprecated.ap-southeast-5.amazonaws.com -s3-object-lambda.ap-southeast-5.amazonaws.com -s3-website.ap-southeast-5.amazonaws.com -s3.dualstack.ca-central-1.amazonaws.com -s3-accesspoint.dualstack.ca-central-1.amazonaws.com -s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com -s3-fips.dualstack.ca-central-1.amazonaws.com -s3-website.dualstack.ca-central-1.amazonaws.com -s3.ca-central-1.amazonaws.com -s3-accesspoint.ca-central-1.amazonaws.com -s3-accesspoint-fips.ca-central-1.amazonaws.com -s3-fips.ca-central-1.amazonaws.com -s3-object-lambda.ca-central-1.amazonaws.com -s3-website.ca-central-1.amazonaws.com -s3.dualstack.ca-west-1.amazonaws.com -s3-accesspoint.dualstack.ca-west-1.amazonaws.com -s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com -s3-fips.dualstack.ca-west-1.amazonaws.com -s3-website.dualstack.ca-west-1.amazonaws.com -s3.ca-west-1.amazonaws.com -s3-accesspoint.ca-west-1.amazonaws.com -s3-accesspoint-fips.ca-west-1.amazonaws.com -s3-fips.ca-west-1.amazonaws.com -s3-object-lambda.ca-west-1.amazonaws.com -s3-website.ca-west-1.amazonaws.com -s3.dualstack.eu-central-1.amazonaws.com -s3-accesspoint.dualstack.eu-central-1.amazonaws.com -s3-website.dualstack.eu-central-1.amazonaws.com -s3.eu-central-1.amazonaws.com -s3-accesspoint.eu-central-1.amazonaws.com -s3-object-lambda.eu-central-1.amazonaws.com -s3-website.eu-central-1.amazonaws.com -s3.dualstack.eu-central-2.amazonaws.com -s3-accesspoint.dualstack.eu-central-2.amazonaws.com -s3-website.dualstack.eu-central-2.amazonaws.com -s3.eu-central-2.amazonaws.com -s3-accesspoint.eu-central-2.amazonaws.com -s3-object-lambda.eu-central-2.amazonaws.com -s3-website.eu-central-2.amazonaws.com -s3.dualstack.eu-north-1.amazonaws.com -s3-accesspoint.dualstack.eu-north-1.amazonaws.com -s3.eu-north-1.amazonaws.com -s3-accesspoint.eu-north-1.amazonaws.com -s3-object-lambda.eu-north-1.amazonaws.com -s3-website.eu-north-1.amazonaws.com -s3.dualstack.eu-south-1.amazonaws.com -s3-accesspoint.dualstack.eu-south-1.amazonaws.com -s3-website.dualstack.eu-south-1.amazonaws.com -s3.eu-south-1.amazonaws.com -s3-accesspoint.eu-south-1.amazonaws.com -s3-object-lambda.eu-south-1.amazonaws.com -s3-website.eu-south-1.amazonaws.com -s3.dualstack.eu-south-2.amazonaws.com -s3-accesspoint.dualstack.eu-south-2.amazonaws.com -s3-website.dualstack.eu-south-2.amazonaws.com -s3.eu-south-2.amazonaws.com -s3-accesspoint.eu-south-2.amazonaws.com -s3-object-lambda.eu-south-2.amazonaws.com -s3-website.eu-south-2.amazonaws.com -s3.dualstack.eu-west-1.amazonaws.com -s3-accesspoint.dualstack.eu-west-1.amazonaws.com -s3-website.dualstack.eu-west-1.amazonaws.com -s3.eu-west-1.amazonaws.com -s3-accesspoint.eu-west-1.amazonaws.com -s3-deprecated.eu-west-1.amazonaws.com -s3-object-lambda.eu-west-1.amazonaws.com -s3-website.eu-west-1.amazonaws.com -s3.dualstack.eu-west-2.amazonaws.com -s3-accesspoint.dualstack.eu-west-2.amazonaws.com -s3.eu-west-2.amazonaws.com -s3-accesspoint.eu-west-2.amazonaws.com -s3-object-lambda.eu-west-2.amazonaws.com -s3-website.eu-west-2.amazonaws.com -s3.dualstack.eu-west-3.amazonaws.com -s3-accesspoint.dualstack.eu-west-3.amazonaws.com -s3-website.dualstack.eu-west-3.amazonaws.com -s3.eu-west-3.amazonaws.com -s3-accesspoint.eu-west-3.amazonaws.com -s3-object-lambda.eu-west-3.amazonaws.com -s3-website.eu-west-3.amazonaws.com -s3.dualstack.il-central-1.amazonaws.com -s3-accesspoint.dualstack.il-central-1.amazonaws.com -s3-website.dualstack.il-central-1.amazonaws.com -s3.il-central-1.amazonaws.com -s3-accesspoint.il-central-1.amazonaws.com -s3-object-lambda.il-central-1.amazonaws.com -s3-website.il-central-1.amazonaws.com -s3.dualstack.me-central-1.amazonaws.com -s3-accesspoint.dualstack.me-central-1.amazonaws.com -s3-website.dualstack.me-central-1.amazonaws.com -s3.me-central-1.amazonaws.com -s3-accesspoint.me-central-1.amazonaws.com -s3-object-lambda.me-central-1.amazonaws.com -s3-website.me-central-1.amazonaws.com -s3.dualstack.me-south-1.amazonaws.com -s3-accesspoint.dualstack.me-south-1.amazonaws.com -s3.me-south-1.amazonaws.com -s3-accesspoint.me-south-1.amazonaws.com -s3-object-lambda.me-south-1.amazonaws.com -s3-website.me-south-1.amazonaws.com -s3.amazonaws.com -s3-1.amazonaws.com -s3-ap-east-1.amazonaws.com -s3-ap-northeast-1.amazonaws.com -s3-ap-northeast-2.amazonaws.com -s3-ap-northeast-3.amazonaws.com -s3-ap-south-1.amazonaws.com -s3-ap-southeast-1.amazonaws.com -s3-ap-southeast-2.amazonaws.com -s3-ca-central-1.amazonaws.com -s3-eu-central-1.amazonaws.com -s3-eu-north-1.amazonaws.com -s3-eu-west-1.amazonaws.com -s3-eu-west-2.amazonaws.com -s3-eu-west-3.amazonaws.com -s3-external-1.amazonaws.com -s3-fips-us-gov-east-1.amazonaws.com -s3-fips-us-gov-west-1.amazonaws.com -mrap.accesspoint.s3-global.amazonaws.com -s3-me-south-1.amazonaws.com -s3-sa-east-1.amazonaws.com -s3-us-east-2.amazonaws.com -s3-us-gov-east-1.amazonaws.com -s3-us-gov-west-1.amazonaws.com -s3-us-west-1.amazonaws.com -s3-us-west-2.amazonaws.com -s3-website-ap-northeast-1.amazonaws.com -s3-website-ap-southeast-1.amazonaws.com -s3-website-ap-southeast-2.amazonaws.com -s3-website-eu-west-1.amazonaws.com -s3-website-sa-east-1.amazonaws.com -s3-website-us-east-1.amazonaws.com -s3-website-us-gov-west-1.amazonaws.com -s3-website-us-west-1.amazonaws.com -s3-website-us-west-2.amazonaws.com -s3.dualstack.sa-east-1.amazonaws.com -s3-accesspoint.dualstack.sa-east-1.amazonaws.com -s3-website.dualstack.sa-east-1.amazonaws.com -s3.sa-east-1.amazonaws.com -s3-accesspoint.sa-east-1.amazonaws.com -s3-object-lambda.sa-east-1.amazonaws.com -s3-website.sa-east-1.amazonaws.com -s3.dualstack.us-east-1.amazonaws.com -s3-accesspoint.dualstack.us-east-1.amazonaws.com -s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com -s3-fips.dualstack.us-east-1.amazonaws.com -s3-website.dualstack.us-east-1.amazonaws.com -s3.us-east-1.amazonaws.com -s3-accesspoint.us-east-1.amazonaws.com -s3-accesspoint-fips.us-east-1.amazonaws.com -s3-deprecated.us-east-1.amazonaws.com -s3-fips.us-east-1.amazonaws.com -s3-object-lambda.us-east-1.amazonaws.com -s3-website.us-east-1.amazonaws.com -s3.dualstack.us-east-2.amazonaws.com -s3-accesspoint.dualstack.us-east-2.amazonaws.com -s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com -s3-fips.dualstack.us-east-2.amazonaws.com -s3-website.dualstack.us-east-2.amazonaws.com -s3.us-east-2.amazonaws.com -s3-accesspoint.us-east-2.amazonaws.com -s3-accesspoint-fips.us-east-2.amazonaws.com -s3-deprecated.us-east-2.amazonaws.com -s3-fips.us-east-2.amazonaws.com -s3-object-lambda.us-east-2.amazonaws.com -s3-website.us-east-2.amazonaws.com -s3.dualstack.us-gov-east-1.amazonaws.com -s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com -s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com -s3-fips.dualstack.us-gov-east-1.amazonaws.com -s3.us-gov-east-1.amazonaws.com -s3-accesspoint.us-gov-east-1.amazonaws.com -s3-accesspoint-fips.us-gov-east-1.amazonaws.com -s3-fips.us-gov-east-1.amazonaws.com -s3-object-lambda.us-gov-east-1.amazonaws.com -s3-website.us-gov-east-1.amazonaws.com -s3.dualstack.us-gov-west-1.amazonaws.com -s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com -s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com -s3-fips.dualstack.us-gov-west-1.amazonaws.com -s3.us-gov-west-1.amazonaws.com -s3-accesspoint.us-gov-west-1.amazonaws.com -s3-accesspoint-fips.us-gov-west-1.amazonaws.com -s3-fips.us-gov-west-1.amazonaws.com -s3-object-lambda.us-gov-west-1.amazonaws.com -s3-website.us-gov-west-1.amazonaws.com -s3.dualstack.us-west-1.amazonaws.com -s3-accesspoint.dualstack.us-west-1.amazonaws.com -s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com -s3-fips.dualstack.us-west-1.amazonaws.com -s3-website.dualstack.us-west-1.amazonaws.com -s3.us-west-1.amazonaws.com -s3-accesspoint.us-west-1.amazonaws.com -s3-accesspoint-fips.us-west-1.amazonaws.com -s3-fips.us-west-1.amazonaws.com -s3-object-lambda.us-west-1.amazonaws.com -s3-website.us-west-1.amazonaws.com -s3.dualstack.us-west-2.amazonaws.com -s3-accesspoint.dualstack.us-west-2.amazonaws.com -s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com -s3-fips.dualstack.us-west-2.amazonaws.com -s3-website.dualstack.us-west-2.amazonaws.com -s3.us-west-2.amazonaws.com -s3-accesspoint.us-west-2.amazonaws.com -s3-accesspoint-fips.us-west-2.amazonaws.com -s3-deprecated.us-west-2.amazonaws.com -s3-fips.us-west-2.amazonaws.com -s3-object-lambda.us-west-2.amazonaws.com -s3-website.us-west-2.amazonaws.com - -// Amazon SageMaker Ground Truth -// Submitted by AWS Security -// Reference: 98dbfde4-7802-48c3-8751-b60f204e0d9c -labeling.ap-northeast-1.sagemaker.aws -labeling.ap-northeast-2.sagemaker.aws -labeling.ap-south-1.sagemaker.aws -labeling.ap-southeast-1.sagemaker.aws -labeling.ap-southeast-2.sagemaker.aws -labeling.ca-central-1.sagemaker.aws -labeling.eu-central-1.sagemaker.aws -labeling.eu-west-1.sagemaker.aws -labeling.eu-west-2.sagemaker.aws -labeling.us-east-1.sagemaker.aws -labeling.us-east-2.sagemaker.aws -labeling.us-west-2.sagemaker.aws - -// Amazon SageMaker Notebook Instances -// Submitted by AWS Security -// Reference: b5ea56df-669e-43cc-9537-14aa172f5dfc -notebook.af-south-1.sagemaker.aws -notebook.ap-east-1.sagemaker.aws -notebook.ap-northeast-1.sagemaker.aws -notebook.ap-northeast-2.sagemaker.aws -notebook.ap-northeast-3.sagemaker.aws -notebook.ap-south-1.sagemaker.aws -notebook.ap-south-2.sagemaker.aws -notebook.ap-southeast-1.sagemaker.aws -notebook.ap-southeast-2.sagemaker.aws -notebook.ap-southeast-3.sagemaker.aws -notebook.ap-southeast-4.sagemaker.aws -notebook.ca-central-1.sagemaker.aws -notebook-fips.ca-central-1.sagemaker.aws -notebook.ca-west-1.sagemaker.aws -notebook-fips.ca-west-1.sagemaker.aws -notebook.eu-central-1.sagemaker.aws -notebook.eu-central-2.sagemaker.aws -notebook.eu-north-1.sagemaker.aws -notebook.eu-south-1.sagemaker.aws -notebook.eu-south-2.sagemaker.aws -notebook.eu-west-1.sagemaker.aws -notebook.eu-west-2.sagemaker.aws -notebook.eu-west-3.sagemaker.aws -notebook.il-central-1.sagemaker.aws -notebook.me-central-1.sagemaker.aws -notebook.me-south-1.sagemaker.aws -notebook.sa-east-1.sagemaker.aws -notebook.us-east-1.sagemaker.aws -notebook-fips.us-east-1.sagemaker.aws -notebook.us-east-2.sagemaker.aws -notebook-fips.us-east-2.sagemaker.aws -notebook.us-gov-east-1.sagemaker.aws -notebook-fips.us-gov-east-1.sagemaker.aws -notebook.us-gov-west-1.sagemaker.aws -notebook-fips.us-gov-west-1.sagemaker.aws -notebook.us-west-1.sagemaker.aws -notebook-fips.us-west-1.sagemaker.aws -notebook.us-west-2.sagemaker.aws -notebook-fips.us-west-2.sagemaker.aws -notebook.cn-north-1.sagemaker.com.cn -notebook.cn-northwest-1.sagemaker.com.cn - -// Amazon SageMaker Studio -// Submitted by AWS Security -// Reference: 475f237e-ab88-4041-9f41-7cfccdf66aeb -studio.af-south-1.sagemaker.aws -studio.ap-east-1.sagemaker.aws -studio.ap-northeast-1.sagemaker.aws -studio.ap-northeast-2.sagemaker.aws -studio.ap-northeast-3.sagemaker.aws -studio.ap-south-1.sagemaker.aws -studio.ap-southeast-1.sagemaker.aws -studio.ap-southeast-2.sagemaker.aws -studio.ap-southeast-3.sagemaker.aws -studio.ca-central-1.sagemaker.aws -studio.eu-central-1.sagemaker.aws -studio.eu-central-2.sagemaker.aws -studio.eu-north-1.sagemaker.aws -studio.eu-south-1.sagemaker.aws -studio.eu-south-2.sagemaker.aws -studio.eu-west-1.sagemaker.aws -studio.eu-west-2.sagemaker.aws -studio.eu-west-3.sagemaker.aws -studio.il-central-1.sagemaker.aws -studio.me-central-1.sagemaker.aws -studio.me-south-1.sagemaker.aws -studio.sa-east-1.sagemaker.aws -studio.us-east-1.sagemaker.aws -studio.us-east-2.sagemaker.aws -studio.us-gov-east-1.sagemaker.aws -studio-fips.us-gov-east-1.sagemaker.aws -studio.us-gov-west-1.sagemaker.aws -studio-fips.us-gov-west-1.sagemaker.aws -studio.us-west-1.sagemaker.aws -studio.us-west-2.sagemaker.aws -studio.cn-north-1.sagemaker.com.cn -studio.cn-northwest-1.sagemaker.com.cn - -// Amazon SageMaker with MLflow -// Submited by: AWS Security -// Reference: c19f92b3-a82a-452d-8189-831b572eea7e -*.experiments.sagemaker.aws - -// Analytics on AWS -// Submitted by AWS Security -// Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd -analytics-gateway.ap-northeast-1.amazonaws.com -analytics-gateway.ap-northeast-2.amazonaws.com -analytics-gateway.ap-south-1.amazonaws.com -analytics-gateway.ap-southeast-1.amazonaws.com -analytics-gateway.ap-southeast-2.amazonaws.com -analytics-gateway.eu-central-1.amazonaws.com -analytics-gateway.eu-west-1.amazonaws.com -analytics-gateway.us-east-1.amazonaws.com -analytics-gateway.us-east-2.amazonaws.com -analytics-gateway.us-west-2.amazonaws.com - -// AWS Amplify -// Submitted by AWS Security -// Reference: c35bed18-6f4f-424f-9298-5756f2f7d72b -amplifyapp.com - -// AWS App Runner -// Submitted by AWS Security -// Reference: 6828c008-ba5d-442f-ade5-48da4e7c2316 -*.awsapprunner.com - -// AWS Cloud9 -// Submitted by: AWS Security -// Reference: 30717f72-4007-4f0f-8ed4-864c6f2efec9 -webview-assets.aws-cloud9.af-south-1.amazonaws.com -vfs.cloud9.af-south-1.amazonaws.com -webview-assets.cloud9.af-south-1.amazonaws.com -webview-assets.aws-cloud9.ap-east-1.amazonaws.com -vfs.cloud9.ap-east-1.amazonaws.com -webview-assets.cloud9.ap-east-1.amazonaws.com -webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com -vfs.cloud9.ap-northeast-1.amazonaws.com -webview-assets.cloud9.ap-northeast-1.amazonaws.com -webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com -vfs.cloud9.ap-northeast-2.amazonaws.com -webview-assets.cloud9.ap-northeast-2.amazonaws.com -webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com -vfs.cloud9.ap-northeast-3.amazonaws.com -webview-assets.cloud9.ap-northeast-3.amazonaws.com -webview-assets.aws-cloud9.ap-south-1.amazonaws.com -vfs.cloud9.ap-south-1.amazonaws.com -webview-assets.cloud9.ap-south-1.amazonaws.com -webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com -vfs.cloud9.ap-southeast-1.amazonaws.com -webview-assets.cloud9.ap-southeast-1.amazonaws.com -webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com -vfs.cloud9.ap-southeast-2.amazonaws.com -webview-assets.cloud9.ap-southeast-2.amazonaws.com -webview-assets.aws-cloud9.ca-central-1.amazonaws.com -vfs.cloud9.ca-central-1.amazonaws.com -webview-assets.cloud9.ca-central-1.amazonaws.com -webview-assets.aws-cloud9.eu-central-1.amazonaws.com -vfs.cloud9.eu-central-1.amazonaws.com -webview-assets.cloud9.eu-central-1.amazonaws.com -webview-assets.aws-cloud9.eu-north-1.amazonaws.com -vfs.cloud9.eu-north-1.amazonaws.com -webview-assets.cloud9.eu-north-1.amazonaws.com -webview-assets.aws-cloud9.eu-south-1.amazonaws.com -vfs.cloud9.eu-south-1.amazonaws.com -webview-assets.cloud9.eu-south-1.amazonaws.com -webview-assets.aws-cloud9.eu-west-1.amazonaws.com -vfs.cloud9.eu-west-1.amazonaws.com -webview-assets.cloud9.eu-west-1.amazonaws.com -webview-assets.aws-cloud9.eu-west-2.amazonaws.com -vfs.cloud9.eu-west-2.amazonaws.com -webview-assets.cloud9.eu-west-2.amazonaws.com -webview-assets.aws-cloud9.eu-west-3.amazonaws.com -vfs.cloud9.eu-west-3.amazonaws.com -webview-assets.cloud9.eu-west-3.amazonaws.com -webview-assets.aws-cloud9.il-central-1.amazonaws.com -vfs.cloud9.il-central-1.amazonaws.com -webview-assets.aws-cloud9.me-south-1.amazonaws.com -vfs.cloud9.me-south-1.amazonaws.com -webview-assets.cloud9.me-south-1.amazonaws.com -webview-assets.aws-cloud9.sa-east-1.amazonaws.com -vfs.cloud9.sa-east-1.amazonaws.com -webview-assets.cloud9.sa-east-1.amazonaws.com -webview-assets.aws-cloud9.us-east-1.amazonaws.com -vfs.cloud9.us-east-1.amazonaws.com -webview-assets.cloud9.us-east-1.amazonaws.com -webview-assets.aws-cloud9.us-east-2.amazonaws.com -vfs.cloud9.us-east-2.amazonaws.com -webview-assets.cloud9.us-east-2.amazonaws.com -webview-assets.aws-cloud9.us-west-1.amazonaws.com -vfs.cloud9.us-west-1.amazonaws.com -webview-assets.cloud9.us-west-1.amazonaws.com -webview-assets.aws-cloud9.us-west-2.amazonaws.com -vfs.cloud9.us-west-2.amazonaws.com -webview-assets.cloud9.us-west-2.amazonaws.com - -// AWS Directory Service -// Submitted by AWS Security -// Reference: a13203e8-42dc-4045-a0d2-2ee67bed1068 -awsapps.com - -// AWS Elastic Beanstalk -// Submitted by AWS Security -// Reference: bb5a965c-dec3-4967-aa22-e306ad064797 -cn-north-1.eb.amazonaws.com.cn -cn-northwest-1.eb.amazonaws.com.cn -elasticbeanstalk.com -af-south-1.elasticbeanstalk.com -ap-east-1.elasticbeanstalk.com -ap-northeast-1.elasticbeanstalk.com -ap-northeast-2.elasticbeanstalk.com -ap-northeast-3.elasticbeanstalk.com -ap-south-1.elasticbeanstalk.com -ap-southeast-1.elasticbeanstalk.com -ap-southeast-2.elasticbeanstalk.com -ap-southeast-3.elasticbeanstalk.com -ca-central-1.elasticbeanstalk.com -eu-central-1.elasticbeanstalk.com -eu-north-1.elasticbeanstalk.com -eu-south-1.elasticbeanstalk.com -eu-west-1.elasticbeanstalk.com -eu-west-2.elasticbeanstalk.com -eu-west-3.elasticbeanstalk.com -il-central-1.elasticbeanstalk.com -me-south-1.elasticbeanstalk.com -sa-east-1.elasticbeanstalk.com -us-east-1.elasticbeanstalk.com -us-east-2.elasticbeanstalk.com -us-gov-east-1.elasticbeanstalk.com -us-gov-west-1.elasticbeanstalk.com -us-west-1.elasticbeanstalk.com -us-west-2.elasticbeanstalk.com - -// (AWS) Elastic Load Balancing -// Submitted by Luke Wells -// Reference: 12a3d528-1bac-4433-a359-a395867ffed2 -*.elb.amazonaws.com.cn -*.elb.amazonaws.com - -// AWS Global Accelerator -// Submitted by Daniel Massaguer -// Reference: d916759d-a08b-4241-b536-4db887383a6a -awsglobalaccelerator.com - -// AWS re:Post Private -// Submitted by AWS Security -// Reference: 83385945-225f-416e-9aa0-ad0632bfdcee -*.private.repost.aws - -// AWS Transfer Family web apps -// Submitted by AWS Security -// Reference: 57a658c4-8899-410c-aa24-5b01e4a178d2 -transfer-webapp.af-south-1.on.aws -transfer-webapp.ap-east-1.on.aws -transfer-webapp.ap-northeast-1.on.aws -transfer-webapp.ap-northeast-2.on.aws -transfer-webapp.ap-northeast-3.on.aws -transfer-webapp.ap-south-1.on.aws -transfer-webapp.ap-south-2.on.aws -transfer-webapp.ap-southeast-1.on.aws -transfer-webapp.ap-southeast-2.on.aws -transfer-webapp.ap-southeast-3.on.aws -transfer-webapp.ap-southeast-4.on.aws -transfer-webapp.ap-southeast-5.on.aws -transfer-webapp.ca-central-1.on.aws -transfer-webapp.ca-west-1.on.aws -transfer-webapp.eu-central-1.on.aws -transfer-webapp.eu-central-2.on.aws -transfer-webapp.eu-north-1.on.aws -transfer-webapp.eu-south-1.on.aws -transfer-webapp.eu-south-2.on.aws -transfer-webapp.eu-west-1.on.aws -transfer-webapp.eu-west-2.on.aws -transfer-webapp.eu-west-3.on.aws -transfer-webapp.il-central-1.on.aws -transfer-webapp.me-central-1.on.aws -transfer-webapp.me-south-1.on.aws -transfer-webapp.sa-east-1.on.aws -transfer-webapp.us-east-1.on.aws -transfer-webapp.us-east-2.on.aws -transfer-webapp.us-gov-east-1.on.aws -transfer-webapp-fips.us-gov-east-1.on.aws -transfer-webapp.us-gov-west-1.on.aws -transfer-webapp-fips.us-gov-west-1.on.aws -transfer-webapp.us-west-1.on.aws -transfer-webapp.us-west-2.on.aws -transfer-webapp.cn-north-1.on.amazonwebservices.com.cn -transfer-webapp.cn-northwest-1.on.amazonwebservices.com.cn - -// eero -// Submitted by Yue Kang -// Reference: 264afe70-f62c-4c02-8ab9-b5281ed24461 -eero.online -eero-stage.online - -// concludes Amazon - -// Apigee : https://apigee.com/ -// Submitted by Apigee Security Team -apigee.io - -// Apis Networks : https://apisnetworks.com -// Submitted by Matt Saladna -panel.dev - -// Apphud : https://apphud.com -// Submitted by Alexander Selivanov -siiites.com - -// Appspace : https://www.appspace.com -// Submitted by Appspace Security Team -appspacehosted.com -appspaceusercontent.com - -// Appudo UG (haftungsbeschränkt) : https://www.appudo.com -// Submitted by Alexander Hochbaum -appudo.net - -// Appwrite : https://appwrite.io -// Submitted by Steven Nguyen -appwrite.global -*.appwrite.run - -// Aptible : https://www.aptible.com/ -// Submitted by Thomas Orozco -on-aptible.com - -// Aquapal : https://aquapal.net/ -// Submitted by Aki Ueno -f5.si - -// ArvanCloud EdgeCompute -// Submitted by ArvanCloud CDN -arvanedge.ir - -// ASEINet : https://www.aseinet.com/ -// Submitted by Asei SEKIGUCHI -user.aseinet.ne.jp -gv.vc -d.gv.vc - -// Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/ -// Submitted by Hector Martin -user.party.eus - -// Association potager.org : https://potager.org/ -// Submitted by Lunar -pimienta.org -poivron.org -potager.org -sweetpepper.org - -// ASUSTOR Inc. : http://www.asustor.com -// Submitted by Vincent Tseng -myasustor.com - -// Atlassian : https://atlassian.com -// Submitted by Sam Smyth -cdn.prod.atlassian-dev.net - -// Authentick UG (haftungsbeschränkt) : https://authentick.net -// Submitted by Lukas Reschke -translated.page - -// AVM : https://avm.de -// Submitted by Andreas Weise -myfritz.link -myfritz.net - -// AVStack Pte. Ltd. : https://avstack.io -// Submitted by Jasper Hugo -onavstack.net - -// AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com -// Submitted by James Kennedy -*.awdev.ca -*.advisor.ws - -// AZ.pl sp. z.o.o : https://az.pl -// Submitted by Krzysztof Wolski -ecommerce-shop.pl - -// b-data GmbH : https://www.b-data.io -// Submitted by Olivier Benz -b-data.io - -// Balena : https://www.balena.io -// Submitted by Petros Angelatos -balena-devices.com - -// BASE, Inc. : https://binc.jp -// Submitted by Yuya NAGASAWA -base.ec -official.ec -buyshop.jp -fashionstore.jp -handcrafted.jp -kawaiishop.jp -supersale.jp -theshop.jp -shopselect.net -base.shop - -// BeagleBoard.org Foundation : https://beagleboard.org -// Submitted by Jason Kridner -beagleboard.io - -// Beget Ltd -// Submitted by Lev Nekrasov -*.beget.app - -// Besties : https://besties.house -// Submitted by Hazel Cora -pages.gay - -// BinaryLane : http://www.binarylane.com -// Submitted by Nathan O'Sullivan -bnr.la - -// Bitbucket : http://bitbucket.org -// Submitted by Andy Ortlieb -bitbucket.io - -// Blackbaud, Inc. : https://www.blackbaud.com -// Submitted by Paul Crowder -blackbaudcdn.net - -// Blatech : http://www.blatech.net -// Submitted by Luke Bratch -of.je - -// Block, Inc. : https://block.xyz -// Submitted by Jonathan Boice -square.site - -// Blue Bite, LLC : https://bluebite.com -// Submitted by Joshua Weiss -bluebite.io - -// Boomla : https://boomla.com -// Submitted by Tibor Halter -boomla.net - -// Boutir : https://www.boutir.com -// Submitted by Eric Ng Ka Ka -boutir.com - -// Boxfuse : https://boxfuse.com -// Submitted by Axel Fontaine -boxfuse.io - -// bplaced : https://www.bplaced.net/ -// Submitted by Miroslav Bozic -square7.ch -bplaced.com -bplaced.de -square7.de -bplaced.net -square7.net - -// Brave : https://brave.com -// Submitted by Andrea Brancaleoni -brave.app -*.s.brave.app -brave.io -*.s.brave.io - -// Brendly : https://brendly.rs -// Submitted by Dusan Radovanovic -shop.brendly.ba -shop.brendly.hr -shop.brendly.rs - -// BrowserSafetyMark -// Submitted by Dave Tharp -browsersafetymark.io - -// BRS Media : https://brsmedia.com/ -// Submitted by Gavin Brown -radio.am -radio.fm - -// Bubble : https://bubble.io/ -// Submitted by Merlin Zhao -cdn.bubble.io -bubbleapps.io - -// Bytemark Hosting : https://www.bytemark.co.uk -// Submitted by Paul Cammish -uk0.bigv.io -dh.bytemark.co.uk -vm.bytemark.co.uk - -// Caf.js Labs LLC : https://www.cafjs.com -// Submitted by Antonio Lain -cafjs.com - -// Canva Pty Ltd : https://canva.com/ -// Submitted by Joel Aquilina -canva-apps.cn -my.canvasite.cn -canva-apps.com -canva-hosted-embed.com -canvacode.com -rice-labs.com -canva.run -my.canva.site - -// Carrd : https://carrd.co -// Submitted by AJ -drr.ac -uwu.ai -carrd.co -crd.co -ju.mp - -// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk -// Submitted by Jamie Tanna -api.gov.uk - -// CDN77.com : http://www.cdn77.com -// Submitted by Jan Krpes -cdn77-storage.com -rsc.contentproxy9.cz -r.cdn77.net -cdn77-ssl.net -c.cdn77.org -rsc.cdn77.org -ssl.origin.cdn77-secure.org - -// CentralNic : https://teaminternet.com/ -// Submitted by registry -za.bz -br.com -cn.com -de.com -eu.com -jpn.com -mex.com -ru.com -sa.com -uk.com -us.com -za.com -com.de -gb.net -hu.net -jp.net -se.net -uk.net -ae.org -com.se - -// Cityhost LLC : https://cityhost.ua -// Submitted by Maksym Rivtin -cx.ua - -// Civilized Discourse Construction Kit, Inc. : https://www.discourse.org/ -// Submitted by Rishabh Nambiar & Michael Brown -discourse.group -discourse.team - -// Clerk : https://www.clerk.dev -// Submitted by Colin Sidoti -clerk.app -clerkstage.app -*.lcl.dev -*.lclstage.dev -*.stg.dev -*.stgstage.dev - -// Clever Cloud : https://www.clever-cloud.com/ -// Submitted by Quentin Adam -cleverapps.cc -*.services.clever-cloud.com -cleverapps.io -cleverapps.tech - -// ClickRising : https://clickrising.com/ -// Submitted by Umut Gumeli -clickrising.net - -// Cloud DNS Ltd : http://www.cloudns.net -// Submitted by Aleksander Hristov & Boyan Peychev -cloudns.asia -cloudns.be -cloud-ip.biz -cloudns.biz -cloud-ip.cc -cloudns.cc -cloudns.ch -cloudns.cl -cloudns.club -abrdns.com -dnsabr.com -ip-ddns.com -cloudns.cx -cloudns.eu -cloudns.in -cloudns.info -ddns-ip.net -dns-cloud.net -dns-dynamic.net -cloudns.nz -cloudns.org -ip-dynamic.org -cloudns.ph -cloudns.pro -cloudns.pw -cloudns.us - -// Cloud66 : https://www.cloud66.com/ -// Submitted by Khash Sajadi -c66.me -cloud66.ws - -// CloudAccess.net : https://www.cloudaccess.net/ -// Submitted by Pawel Panek -jdevcloud.com -wpdevcloud.com -cloudaccess.host -freesite.host -cloudaccess.net - -// Cloudbees, Inc. : https://www.cloudbees.com/ -// Submitted by Mohideen Shajith -cloudbeesusercontent.io - -// Cloudera, Inc. : https://www.cloudera.com/ -// Submitted by Kedarnath Waikar -*.cloudera.site - -// Cloudflare, Inc. : https://www.cloudflare.com/ -// Submitted by Cloudflare Team -cf-ipfs.com -cloudflare-ipfs.com -trycloudflare.com -pages.dev -r2.dev -workers.dev -cloudflare.net -cdn.cloudflare.net -cdn.cloudflareanycast.net -cdn.cloudflarecn.net -cdn.cloudflareglobal.net - -// cloudscale.ch AG : https://www.cloudscale.ch/ -// Submitted by Gaudenz Steinlin -cust.cloudscale.ch -objects.lpg.cloudscale.ch -objects.rma.cloudscale.ch -lpg.objectstorage.ch -rma.objectstorage.ch - -// Clovyr : https://clovyr.io -// Submitted by Patrick Nielsen -wnext.app - -// CNPY : https://cnpy.gdn -// Submitted by Angelo Gladding -cnpy.gdn - -// Co & Co : https://co-co.nl/ -// Submitted by Govert Versluis -*.otap.co - -// co.ca : http://registry.co.ca/ -co.ca - -// co.com Registry, LLC : https://registry.co.com -// Submitted by Gavin Brown -co.com - -// Codeberg e. V. : https://codeberg.org -// Submitted by Moritz Marquardt -codeberg.page - -// CodeSandbox B.V. : https://codesandbox.io -// Submitted by Ives van Hoorne -csb.app -preview.csb.app - -// CoDNS B.V. -co.nl -co.no - -// Cognition AI, Inc. : https://cognition.ai -// Submitted by Philip Papurt -*.devinapps.com - -// Combell.com : https://www.combell.com -// Submitted by Thomas Wouters -webhosting.be -hosting-cluster.nl - -// Contentful GmbH : https://www.contentful.com -// Submitted by Contentful Developer Experience Team -ctfcloud.net - -// Convex : https://convex.dev/ -// Submitted by James Cowling -convex.app -convex.cloud -convex.site - -// Coordination Center for TLD RU and XN--P1AI : https://cctld.ru/en/domains/domens_ru/reserved/ -// Submitted by George Georgievsky -ac.ru -edu.ru -gov.ru -int.ru -mil.ru - -// COSIMO GmbH : http://www.cosimo.de -// Submitted by Rene Marticke -dyn.cosidns.de -dnsupdater.de -dynamisches-dns.de -internet-dns.de -l-o-g-i-n.de -dynamic-dns.info -feste-ip.net -knx-server.net -static-access.net - -// Craft Docs Ltd : https://www.craft.do/ -// Submitted by Zsombor Fuszenecker -craft.me - -// Craynic, s.r.o. : http://www.craynic.com/ -// Submitted by Ales Krajnik -realm.cz - -// Crisp IM SAS : https://crisp.chat/ -// Submitted by Baptiste Jamin -on.crisp.email - -// Cryptonomic : https://cryptonomic.net/ -// Submitted by Andrew Cady -*.cryptonomic.net - -// cyber_Folks S.A. : https://cyberfolks.pl -// Submitted by Bartlomiej Kida -cfolks.pl - -// cyon GmbH : https://www.cyon.ch/ -// Submitted by Dominic Luechinger -cyon.link -cyon.site - -// Dansk.net : http://www.dansk.net/ -// Submitted by Anani Voule -biz.dk -co.dk -firm.dk -reg.dk -store.dk - -// dappnode.io : https://dappnode.io/ -// Submitted by Abel Boldu / DAppNode Team -dyndns.dappnode.io - -// Dark, Inc. : https://darklang.com -// Submitted by Paul Biggar -builtwithdark.com -darklang.io - -// DataDetect, LLC. : https://datadetect.com -// Submitted by Andrew Banchich -demo.datadetect.com -instance.datadetect.com - -// Datawire, Inc : https://www.datawire.io -// Submitted by Richard Li -edgestack.me - -// Datto, Inc. : https://www.datto.com/ -// Submitted by Philipp Heckel -dattolocal.com -dattorelay.com -dattoweb.com -mydatto.com -dattolocal.net -mydatto.net - -// ddnss.de : https://www.ddnss.de/ -// Submitted by Robert Niedziela -ddnss.de -dyn.ddnss.de -dyndns.ddnss.de -dyn-ip24.de -dyndns1.de -home-webserver.de -dyn.home-webserver.de -myhome-server.de -ddnss.org - -// Debian : https://www.debian.org/ -// Submitted by Peter Palfrader / Debian Sysadmin Team -debian.net - -// Definima : http://www.definima.com/ -// Submitted by Maxence Bitterli -definima.io -definima.net - -// Deno Land Inc : https://deno.com/ -// Submitted by Luca Casonato -deno.dev -deno-staging.dev -deno.net - -// deSEC : https://desec.io/ -// Submitted by Peter Thomassen -dedyn.io - -// Deta : https://www.deta.sh/ -// Submitted by Aavash Shrestha -deta.app -deta.dev - -// Dfinity Foundation: https://dfinity.org/ -// Submitted by Dfinity Team -icp0.io -*.raw.icp0.io -icp1.io -*.raw.icp1.io -*.icp.net -caffeine.site -caffeine.xyz - -// dhosting.pl Sp. z o.o. : https://dhosting.pl/ -// Submitted by Michal Kokoszkiewicz -dfirma.pl -dkonto.pl -you2.pl - -// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/ -// Submitted by Braxton Huggins -ondigitalocean.app - -// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/ -// Submitted by Robin H. Johnson -*.digitaloceanspaces.com - -// DigitalPlat : https://www.digitalplat.org/ -// Submitted by Edward Hsing -qzz.io -us.kg -xx.kg -dpdns.org - -// Discord Inc : https://discord.com -// Submitted by Sahn Lam -discordsays.com -discordsez.com - -// DNS Africa Ltd : https://dns.business -// Submitted by Calvin Browne -jozi.biz - -// DNShome : https://www.dnshome.de/ -// Submitted by Norbert Auler -dnshome.de - -// DotArai : https://www.dotarai.com/ -// Submitted by Atsadawat Netcharadsang -online.th -shop.th - -// DrayTek Corp. : https://www.draytek.com/ -// Submitted by Paul Fang -drayddns.com - -// DreamCommerce : https://shoper.pl/ -// Submitted by Konrad Kotarba -shoparena.pl - -// DreamHost : http://www.dreamhost.com/ -// Submitted by Andrew Farmer -dreamhosters.com - -// Dreamyoungs, Inc. : https://durumis.com -// Submitted by Infra Team -durumis.com - -// DuckDNS : http://www.duckdns.org/ -// Submitted by Richard Harper -duckdns.org - -// dy.fi : http://dy.fi/ -// Submitted by Heikki Hannikainen -dy.fi -tunk.org - -// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ -dyndns.biz -for-better.biz -for-more.biz -for-some.biz -for-the.biz -selfip.biz -webhop.biz -ftpaccess.cc -game-server.cc -myphotos.cc -scrapping.cc -blogdns.com -cechire.com -dnsalias.com -dnsdojo.com -doesntexist.com -dontexist.com -doomdns.com -dyn-o-saur.com -dynalias.com -dyndns-at-home.com -dyndns-at-work.com -dyndns-blog.com -dyndns-free.com -dyndns-home.com -dyndns-ip.com -dyndns-mail.com -dyndns-office.com -dyndns-pics.com -dyndns-remote.com -dyndns-server.com -dyndns-web.com -dyndns-wiki.com -dyndns-work.com -est-a-la-maison.com -est-a-la-masion.com -est-le-patron.com -est-mon-blogueur.com -from-ak.com -from-al.com -from-ar.com -from-ca.com -from-ct.com -from-dc.com -from-de.com -from-fl.com -from-ga.com -from-hi.com -from-ia.com -from-id.com -from-il.com -from-in.com -from-ks.com -from-ky.com -from-ma.com -from-md.com -from-mi.com -from-mn.com -from-mo.com -from-ms.com -from-mt.com -from-nc.com -from-nd.com -from-ne.com -from-nh.com -from-nj.com -from-nm.com -from-nv.com -from-oh.com -from-ok.com -from-or.com -from-pa.com -from-pr.com -from-ri.com -from-sc.com -from-sd.com -from-tn.com -from-tx.com -from-ut.com -from-va.com -from-vt.com -from-wa.com -from-wi.com -from-wv.com -from-wy.com -getmyip.com -gotdns.com -hobby-site.com -homelinux.com -homeunix.com -iamallama.com -is-a-anarchist.com -is-a-blogger.com -is-a-bookkeeper.com -is-a-bulls-fan.com -is-a-caterer.com -is-a-chef.com -is-a-conservative.com -is-a-cpa.com -is-a-cubicle-slave.com -is-a-democrat.com -is-a-designer.com -is-a-doctor.com -is-a-financialadvisor.com -is-a-geek.com -is-a-green.com -is-a-guru.com -is-a-hard-worker.com -is-a-hunter.com -is-a-landscaper.com -is-a-lawyer.com -is-a-liberal.com -is-a-libertarian.com -is-a-llama.com -is-a-musician.com -is-a-nascarfan.com -is-a-nurse.com -is-a-painter.com -is-a-personaltrainer.com -is-a-photographer.com -is-a-player.com -is-a-republican.com -is-a-rockstar.com -is-a-socialist.com -is-a-student.com -is-a-teacher.com -is-a-techie.com -is-a-therapist.com -is-an-accountant.com -is-an-actor.com -is-an-actress.com -is-an-anarchist.com -is-an-artist.com -is-an-engineer.com -is-an-entertainer.com -is-certified.com -is-gone.com -is-into-anime.com -is-into-cars.com -is-into-cartoons.com -is-into-games.com -is-leet.com -is-not-certified.com -is-slick.com -is-uberleet.com -is-with-theband.com -isa-geek.com -isa-hockeynut.com -issmarterthanyou.com -likes-pie.com -likescandy.com -neat-url.com -saves-the-whales.com -selfip.com -sells-for-less.com -sells-for-u.com -servebbs.com -simple-url.com -space-to-rent.com -teaches-yoga.com -writesthisblog.com -ath.cx -fuettertdasnetz.de -isteingeek.de -istmein.de -lebtimnetz.de -leitungsen.de -traeumtgerade.de -barrel-of-knowledge.info -barrell-of-knowledge.info -dyndns.info -for-our.info -groks-the.info -groks-this.info -here-for-more.info -knowsitall.info -selfip.info -webhop.info -forgot.her.name -forgot.his.name -at-band-camp.net -blogdns.net -broke-it.net -buyshouses.net -dnsalias.net -dnsdojo.net -does-it.net -dontexist.net -dynalias.net -dynathome.net -endofinternet.net -from-az.net -from-co.net -from-la.net -from-ny.net -gets-it.net -ham-radio-op.net -homeftp.net -homeip.net -homelinux.net -homeunix.net -in-the-band.net -is-a-chef.net -is-a-geek.net -isa-geek.net -kicks-ass.net -office-on-the.net -podzone.net -scrapper-site.net -selfip.net -sells-it.net -servebbs.net -serveftp.net -thruhere.net -webhop.net -merseine.nu -mine.nu -shacknet.nu -blogdns.org -blogsite.org -boldlygoingnowhere.org -dnsalias.org -dnsdojo.org -doesntexist.org -dontexist.org -doomdns.org -dvrdns.org -dynalias.org -dyndns.org -go.dyndns.org -home.dyndns.org -endofinternet.org -endoftheinternet.org -from-me.org -game-host.org -gotdns.org -hobby-site.org -homedns.org -homeftp.org -homelinux.org -homeunix.org -is-a-bruinsfan.org -is-a-candidate.org -is-a-celticsfan.org -is-a-chef.org -is-a-geek.org -is-a-knight.org -is-a-linux-user.org -is-a-patsfan.org -is-a-soxfan.org -is-found.org -is-lost.org -is-saved.org -is-very-bad.org -is-very-evil.org -is-very-good.org -is-very-nice.org -is-very-sweet.org -isa-geek.org -kicks-ass.org -misconfused.org -podzone.org -readmyblog.org -selfip.org -sellsyourhome.org -servebbs.org -serveftp.org -servegame.org -stuff-4-sale.org -webhop.org -better-than.tv -dyndns.tv -on-the-web.tv -worse-than.tv -is-by.us -land-4-sale.us -stuff-4-sale.us -dyndns.ws -mypets.ws - -// Dynu.com : https://www.dynu.com/ -// Submitted by Sue Ye -ddnsfree.com -ddnsgeek.com -giize.com -gleeze.com -kozow.com -loseyourip.com -ooguy.com -theworkpc.com -casacam.net -dynu.net -accesscam.org -camdvr.org -freeddns.org -mywire.org -webredirect.org -myddns.rocks - -// dynv6 : https://dynv6.com -// Submitted by Dominik Menke -dynv6.net - -// E4YOU spol. s.r.o. : https://e4you.cz/ -// Submitted by Vladimir Dudr -e4.cz - -// Easypanel : https://easypanel.io -// Submitted by Andrei Canta -easypanel.app -easypanel.host - -// EasyWP : https://www.easywp.com -// Submitted by -*.ewp.live - -// eDirect Corp. : https://hosting.url.com.tw/ -// Submitted by C.S. chang -twmail.cc -twmail.net -twmail.org -mymailer.com.tw -url.tw - -// Electromagnetic Field : https://www.emfcamp.org -// Submitted by -at.emf.camp - -// Elefunc, Inc. : https://elefunc.com -// Submitted by Cetin Sert -rt.ht - -// Elementor : Elementor Ltd. -// Submitted by Anton Barkan -elementor.cloud -elementor.cool - -// En root‽ : https://en-root.org -// Submitted by Emmanuel Raviart -en-root.fr - -// Enalean SAS : https://www.enalean.com -// Submitted by Enalean Security Team -mytuleap.com -tuleap-partners.com - -// Encoretivity AB : https://encore.cloud -// Submitted by André Eriksson -encr.app -frontend.encr.app -encoreapi.com -lp.dev -api.lp.dev -objects.lp.dev - -// encoway GmbH : https://www.encoway.de -// Submitted by Marcel Daus -eu.encoway.cloud - -// EU.org : https://eu.org/ -// Submitted by Pierre Beyssac -eu.org -al.eu.org -asso.eu.org -at.eu.org -au.eu.org -be.eu.org -bg.eu.org -ca.eu.org -cd.eu.org -ch.eu.org -cn.eu.org -cy.eu.org -cz.eu.org -de.eu.org -dk.eu.org -edu.eu.org -ee.eu.org -es.eu.org -fi.eu.org -fr.eu.org -gr.eu.org -hr.eu.org -hu.eu.org -ie.eu.org -il.eu.org -in.eu.org -int.eu.org -is.eu.org -it.eu.org -jp.eu.org -kr.eu.org -lt.eu.org -lu.eu.org -lv.eu.org -me.eu.org -mk.eu.org -mt.eu.org -my.eu.org -net.eu.org -ng.eu.org -nl.eu.org -no.eu.org -nz.eu.org -pl.eu.org -pt.eu.org -ro.eu.org -ru.eu.org -se.eu.org -si.eu.org -sk.eu.org -tr.eu.org -uk.eu.org -us.eu.org - -// Eurobyte : https://eurobyte.ru -// Submitted by Evgeniy Subbotin -eurodir.ru - -// Evennode : http://www.evennode.com/ -// Submitted by Michal Kralik -eu-1.evennode.com -eu-2.evennode.com -eu-3.evennode.com -eu-4.evennode.com -us-1.evennode.com -us-2.evennode.com -us-3.evennode.com -us-4.evennode.com - -// Evervault : https://evervault.com -// Submitted by Hannah Neary -relay.evervault.app -relay.evervault.dev - -// Expo : https://expo.dev/ -// Submitted by James Ide -expo.app -staging.expo.app - -// Fabrica Technologies, Inc. : https://www.fabrica.dev/ -// Submitted by Eric Jiang -onfabrica.com - -// FAITID : https://faitid.org/ -// Submitted by Maxim Alzoba -// https://www.flexireg.net/stat_info -ru.net -adygeya.ru -bashkiria.ru -bir.ru -cbg.ru -com.ru -dagestan.ru -grozny.ru -kalmykia.ru -kustanai.ru -marine.ru -mordovia.ru -msk.ru -mytis.ru -nalchik.ru -nov.ru -pyatigorsk.ru -spb.ru -vladikavkaz.ru -vladimir.ru -abkhazia.su -adygeya.su -aktyubinsk.su -arkhangelsk.su -armenia.su -ashgabad.su -azerbaijan.su -balashov.su -bashkiria.su -bryansk.su -bukhara.su -chimkent.su -dagestan.su -east-kazakhstan.su -exnet.su -georgia.su -grozny.su -ivanovo.su -jambyl.su -kalmykia.su -kaluga.su -karacol.su -karaganda.su -karelia.su -khakassia.su -krasnodar.su -kurgan.su -kustanai.su -lenug.su -mangyshlak.su -mordovia.su -msk.su -murmansk.su -nalchik.su -navoi.su -north-kazakhstan.su -nov.su -obninsk.su -penza.su -pokrovsk.su -sochi.su -spb.su -tashkent.su -termez.su -togliatti.su -troitsk.su -tselinograd.su -tula.su -tuva.su -vladikavkaz.su -vladimir.su -vologda.su - -// Fancy Bits, LLC : http://getchannels.com -// Submitted by Aman Gupta -channelsdvr.net -u.channelsdvr.net - -// Fastly Inc. : http://www.fastly.com/ -// Submitted by Fastly Security -edgecompute.app -fastly-edge.com -fastly-terrarium.com -freetls.fastly.net -map.fastly.net -a.prod.fastly.net -global.prod.fastly.net -a.ssl.fastly.net -b.ssl.fastly.net -global.ssl.fastly.net -fastlylb.net -map.fastlylb.net - -// Fastmail : https://www.fastmail.com/ -// Submitted by Marc Bradshaw -*.user.fm - -// FASTVPS EESTI OU : https://fastvps.ru/ -// Submitted by Likhachev Vasiliy -fastvps-server.com -fastvps.host -myfast.host -fastvps.site -myfast.space - -// FearWorks Media Ltd. : https://fearworksmedia.co.uk -// Submitted by Keith Fairley -conn.uk -copro.uk -hosp.uk - -// Fedora : https://fedoraproject.org/ -// Submitted by Patrick Uiterwijk -fedorainfracloud.org -fedorapeople.org -cloud.fedoraproject.org -app.os.fedoraproject.org -app.os.stg.fedoraproject.org - -// Fermax : https://fermax.com/ -// Submitted by Koen Van Isterdael -mydobiss.com - -// FH Muenster : https://www.fh-muenster.de -// Submitted by Robin Naundorf -fh-muenster.io - -// Figma : https://www.figma.com -// Submitted by Nick Frost -figma.site -preview.site - -// Filegear Inc. : https://www.filegear.com -// Submitted by Jason Zhu -filegear.me - -// Firebase, Inc. -// Submitted by Chris Raynor -firebaseapp.com - -// FlashDrive : https://flashdrive.io -// Submitted by Eric Chan -fldrv.com - -// Fleek Labs Inc : https://fleek.xyz -// Submitted by Parsa Ghadimi -on-fleek.app - -// FlutterFlow : https://flutterflow.io -// Submitted by Anton Emelyanov -flutterflow.app - -// fly.io : https://fly.io -// Submitted by Kurt Mackey -fly.dev -shw.io -edgeapp.net - -// Forgerock : https://www.forgerock.com -// Submitted by Roderick Parr -forgeblocks.com -id.forgerock.io - -// FoundryLabs, Inc : https://e2b.dev/ -// Submitted by Jiri Sveceny -e2b.app - -// Framer : https://www.framer.com -// Submitted by Koen Rouwhorst -framer.ai -framer.app -framercanvas.com -framer.media -framer.photos -framer.website -framer.wiki - -// Frederik Braun : https://frederik-braun.com -// Submitted by Frederik Braun -*.0e.vc - -// Freebox : http://www.freebox.fr -// Submitted by Romain Fliedel -freebox-os.com -freeboxos.com -fbx-os.fr -fbxos.fr -freebox-os.fr -freeboxos.fr - -// freedesktop.org : https://www.freedesktop.org -// Submitted by Daniel Stone -freedesktop.org - -// freemyip.com : https://freemyip.com -// Submitted by Cadence -freemyip.com - -// Frusky MEDIA&PR : https://www.frusky.de -// Submitted by Victor Pupynin -*.frusky.de - -// FunkFeuer - Verein zur Förderung freier Netze : https://www.funkfeuer.at -// Submitted by Daniel A. Maierhofer -wien.funkfeuer.at - -// Future Versatile Group. : https://www.fvg-on.net/ -// T.Kabu -daemon.asia -dix.asia -mydns.bz -0am.jp -0g0.jp -0j0.jp -0t0.jp -mydns.jp -pgw.jp -wjg.jp -keyword-on.net -live-on.net -server-on.net -mydns.tw -mydns.vc - -// Futureweb GmbH : https://www.futureweb.at -// Submitted by Andreas Schnederle-Wagner -*.futurecms.at -*.ex.futurecms.at -*.in.futurecms.at -futurehosting.at -futuremailing.at -*.ex.ortsinfo.at -*.kunden.ortsinfo.at -*.statics.cloud - -// GCom Internet : https://www.gcom.net.au -// Submitted by Leo Julius -aliases121.com - -// GDS : https://www.gov.uk/service-manual/technology/managing-domain-names -// Submitted by Stephen Ford -campaign.gov.uk -service.gov.uk -independent-commission.uk -independent-inquest.uk -independent-inquiry.uk -independent-panel.uk -independent-review.uk -public-inquiry.uk -royal-commission.uk - -// Gehirn Inc. : https://www.gehirn.co.jp/ -// Submitted by Kohei YOSHIDA -gehirn.ne.jp -usercontent.jp - -// Gentlent, Inc. : https://www.gentlent.com -// Submitted by Tom Klein -gentapps.com -gentlentapis.com -cdn-edges.net - -// GignoSystemJapan : http://gsj.bz -// Submitted by GignoSystemJapan -gsj.bz - -// GitHub, Inc. -// Submitted by Patrick Toomey -github.app -githubusercontent.com -githubpreview.dev -github.io - -// GitLab, Inc. : https://about.gitlab.com/ -// Submitted by Alex Hanselka -gitlab.io - -// Gitplac.si : https://gitplac.si -// Submitted by Aljaž Starc -gitapp.si -gitpage.si - -// Global NOG Alliance : https://nogalliance.org/ -// Submitted by Sander Steffann -nog.community - -// Globe Hosting SRL : https://www.globehosting.com/ -// Submitted by Gavin Brown -co.ro -shop.ro - -// GMO Pepabo, Inc. : https://pepabo.com/ -// Submitted by Hosting Div -lolipop.io -angry.jp -babyblue.jp -babymilk.jp -backdrop.jp -bambina.jp -bitter.jp -blush.jp -boo.jp -boy.jp -boyfriend.jp -but.jp -candypop.jp -capoo.jp -catfood.jp -cheap.jp -chicappa.jp -chillout.jp -chips.jp -chowder.jp -chu.jp -ciao.jp -cocotte.jp -coolblog.jp -cranky.jp -cutegirl.jp -daa.jp -deca.jp -deci.jp -digick.jp -egoism.jp -fakefur.jp -fem.jp -flier.jp -floppy.jp -fool.jp -frenchkiss.jp -girlfriend.jp -girly.jp -gloomy.jp -gonna.jp -greater.jp -hacca.jp -heavy.jp -her.jp -hiho.jp -hippy.jp -holy.jp -hungry.jp -icurus.jp -itigo.jp -jellybean.jp -kikirara.jp -kill.jp -kilo.jp -kuron.jp -littlestar.jp -lolipopmc.jp -lolitapunk.jp -lomo.jp -lovepop.jp -lovesick.jp -main.jp -mods.jp -mond.jp -mongolian.jp -moo.jp -namaste.jp -nikita.jp -nobushi.jp -noor.jp -oops.jp -parallel.jp -parasite.jp -pecori.jp -peewee.jp -penne.jp -pepper.jp -perma.jp -pigboat.jp -pinoko.jp -punyu.jp -pupu.jp -pussycat.jp -pya.jp -raindrop.jp -readymade.jp -sadist.jp -schoolbus.jp -secret.jp -staba.jp -stripper.jp -sub.jp -sunnyday.jp -thick.jp -tonkotsu.jp -under.jp -upper.jp -velvet.jp -verse.jp -versus.jp -vivian.jp -watson.jp -weblike.jp -whitesnow.jp -zombie.jp -heteml.net - -// GoDaddy Registry : https://registry.godaddy -// Submitted by Rohan Durrant -graphic.design - -// GoIP DNS Services : http://www.goip.de -// Submitted by Christian Poulter -goip.de - -// Google, Inc. -// Submitted by Shannon McCabe -*.hosted.app -*.run.app -*.mtls.run.app -web.app -*.0emm.com -appspot.com -*.r.appspot.com -blogspot.com -codespot.com -googleapis.com -googlecode.com -pagespeedmobilizer.com -withgoogle.com -withyoutube.com -*.gateway.dev -cloud.goog -translate.goog -*.usercontent.goog -cloudfunctions.net - -// Goupile : https://goupile.fr -// Submitted by Niels Martignene -goupile.fr - -// GOV.UK Pay : https://www.payments.service.gov.uk/ -// Submitted by Richard Baker -pymnt.uk - -// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/ -// Submitted by Tom Whitwell -cloudapps.digital -london.cloudapps.digital - -// Government of the Netherlands : https://www.government.nl -// Submitted by -gov.nl - -// Grafana Labs : https://grafana.com/ -// Submitted by Platform Engineering -grafana-dev.net - -// GrayJay Web Solutions Inc. : https://grayjaysports.ca -// Submitted by Matt Yamkowy -grayjayleagues.com - -// GünstigBestellen : https://günstigbestellen.de -// Submitted by Furkan Akkoc -günstigbestellen.de -günstigliefern.de - -// Hackclub Nest : https://hackclub.app -// Submitted by Cyteon -hackclub.app - -// Häkkinen.fi : https://www.häkkinen.fi/ -// Submitted by Eero Häkkinen -häkkinen.fi - -// Hashbang : https://hashbang.sh -hashbang.sh - -// Hasura : https://hasura.io -// Submitted by Shahidh K Muhammed -hasura.app -hasura-app.io - -// Hatena Co., Ltd. : https://hatena.co.jp -// Submitted by Masato Nakamura -hatenablog.com -hatenadiary.com -hateblo.jp -hatenablog.jp -hatenadiary.jp -hatenadiary.org - -// Heilbronn University of Applied Sciences - Faculty Informatics (GitLab Pages) : https://www.hs-heilbronn.de -// Submitted by Richard Zowalla -pages.it.hs-heilbronn.de -pages-research.it.hs-heilbronn.de - -// HeiyuSpace : https://lazycat.cloud -// Submitted by Xia Bin -heiyu.space - -// Helio Networks : https://heliohost.org -// Submitted by Ben Frede -helioho.st -heliohost.us - -// Hepforge : https://www.hepforge.org -// Submitted by David Grellscheid -hepforge.org - -// Heroku : https://www.heroku.com/ -// Submitted by Shumon Huque -herokuapp.com - -// Heyflow : https://www.heyflow.com -// Submitted by Mirko Nitschke -heyflow.page -heyflow.site - -// Hibernating Rhinos -// Submitted by Oren Eini -ravendb.cloud -ravendb.community -development.run -ravendb.run - -// HiDNS : https://www.hidoha.net -// Submitted by ifeng -hidns.co -hidns.vip - -// home.pl S.A. : https://home.pl -// Submitted by Krzysztof Wolski -homesklep.pl - -// Homebase : https://homebase.id/ -// Submitted by Jason Babo -*.kin.one -*.id.pub -*.kin.pub - -// Hoplix : https://www.hoplix.com -// Submitted by Danilo De Franco -hoplix.shop - -// HOSTBIP REGISTRY : https://www.hostbip.com/ -// Submitted by Atanunu Igbunuroghene -orx.biz -biz.ng -co.biz.ng -dl.biz.ng -go.biz.ng -lg.biz.ng -on.biz.ng -col.ng -firm.ng -gen.ng -ltd.ng -ngo.ng -plc.ng - -// HostyHosting : https://hostyhosting.com -hostyhosting.io - -// Hugging Face : https://huggingface.co -// Submitted by Eliott Coyac -hf.space -static.hf.space - -// Hypernode B.V. : https://www.hypernode.com/ -// Submitted by Cipriano Groenendal -hypernode.io - -// I-O DATA DEVICE, INC. : http://www.iodata.com/ -// Submitted by Yuji Minagawa -iobb.net - -// i-registry s.r.o. : http://www.i-registry.cz/ -// Submitted by Martin Semrad -co.cz - -// Ici la Lune : http://www.icilalune.com/ -// Submitted by Simon Morvan -*.moonscale.io -moonscale.net - -// iDOT Services Limited : http://www.domain.gr.com -// Submitted by Gavin Brown -gr.com - -// iki.fi -// Submitted by Hannu Aronsson -iki.fi - -// iliad italia : https://www.iliad.it -// Submitted by Marios Makassikis -ibxos.it -iliadboxos.it - -// Incsub, LLC : https://incsub.com/ -// Submitted by Aaron Edwards -smushcdn.com -wphostedmail.com -wpmucdn.com -tempurl.host -wpmudev.host - -// Individual Network Berlin e.V. : https://www.in-berlin.de/ -// Submitted by Christian Seitz -dyn-berlin.de -in-berlin.de -in-brb.de -in-butter.de -in-dsl.de -in-vpn.de -in-dsl.net -in-vpn.net -in-dsl.org -in-vpn.org - -// Inferno Communications : https://inferno.co.uk -// Submitted by Connor McFarlane -oninferno.net - -// info.at : http://www.info.at/ -biz.at -info.at - -// info.cx : http://info.cx -// Submitted by June Slater -info.cx - -// Interlegis : http://www.interlegis.leg.br -// Submitted by Gabriel Ferreira -ac.leg.br -al.leg.br -am.leg.br -ap.leg.br -ba.leg.br -ce.leg.br -df.leg.br -es.leg.br -go.leg.br -ma.leg.br -mg.leg.br -ms.leg.br -mt.leg.br -pa.leg.br -pb.leg.br -pe.leg.br -pi.leg.br -pr.leg.br -rj.leg.br -rn.leg.br -ro.leg.br -rr.leg.br -rs.leg.br -sc.leg.br -se.leg.br -sp.leg.br -to.leg.br - -// intermetrics GmbH : https://pixolino.com/ -// Submitted by Wolfgang Schwarz -pixolino.com - -// Internet-Pro, LLP : https://netangels.ru/ -// Submitted by Vasiliy Sheredeko -na4u.ru - -// Inventor Services : https://inventor.gg/ -// Submitted by Inventor Team -botdash.app -botdash.dev -botdash.gg -botdash.net -botda.sh -botdash.xyz - -// IONOS SE : https://www.ionos.com/ -// IONOS Group SE : https://www.ionos-group.com/ -// Submitted by Henrik Willert -apps-1and1.com -live-website.com -webspace-host.com -apps-1and1.net -websitebuilder.online -app-ionos.space - -// iopsys software solutions AB : https://iopsys.eu/ -// Submitted by Roman Azarenko -iopsys.se - -// IPFS Project : https://ipfs.tech/ -// Submitted by Interplanetary Shipyard -*.inbrowser.dev -*.dweb.link -*.inbrowser.link - -// IPiFony Systems, Inc. : https://www.ipifony.com/ -// Submitted by Matthew Hardeman -ipifony.net - -// ir.md : https://nic.ir.md -// Submitted by Ali Soizi -ir.md - -// is-a-good.dev : https://is-a-good.dev -// Submitted by William Harrison -is-a-good.dev - -// IServ GmbH : https://iserv.de -// Submitted by Kim Brodowski -iservschule.de -mein-iserv.de -schuldock.de -schulplattform.de -schulserver.de -test-iserv.de -iserv.dev -iserv.host - -// Jelastic, Inc. : https://jelastic.com/ -// Submitted by Ihor Kolodyuk -mel.cloudlets.com.au -cloud.interhostsolutions.be -alp1.ae.flow.ch -appengine.flow.ch -es-1.axarnet.cloud -diadem.cloud -vip.jelastic.cloud -jele.cloud -it1.eur.aruba.jenv-aruba.cloud -it1.jenv-aruba.cloud -keliweb.cloud -cs.keliweb.cloud -oxa.cloud -tn.oxa.cloud -uk.oxa.cloud -primetel.cloud -uk.primetel.cloud -ca.reclaim.cloud -uk.reclaim.cloud -us.reclaim.cloud -ch.trendhosting.cloud -de.trendhosting.cloud -jele.club -dopaas.com -paas.hosted-by-previder.com -rag-cloud.hosteur.com -rag-cloud-ch.hosteur.com -jcloud.ik-server.com -jcloud-ver-jpc.ik-server.com -demo.jelastic.com -paas.massivegrid.com -jed.wafaicloud.com -ryd.wafaicloud.com -j.scaleforce.com.cy -jelastic.dogado.eu -fi.cloudplatform.fi -demo.datacenter.fi -paas.datacenter.fi -jele.host -mircloud.host -paas.beebyte.io -sekd1.beebyteapp.io -jele.io -jc.neen.it -jcloud.kz -cloudjiffy.net -fra1-de.cloudjiffy.net -west1-us.cloudjiffy.net -jls-sto1.elastx.net -jls-sto2.elastx.net -jls-sto3.elastx.net -fr-1.paas.massivegrid.net -lon-1.paas.massivegrid.net -lon-2.paas.massivegrid.net -ny-1.paas.massivegrid.net -ny-2.paas.massivegrid.net -sg-1.paas.massivegrid.net -jelastic.saveincloud.net -nordeste-idc.saveincloud.net -j.scaleforce.net -sdscloud.pl -unicloud.pl -mircloud.ru -enscaled.sg -jele.site -jelastic.team -orangecloud.tn -j.layershift.co.uk -phx.enscaled.us -mircloud.us - -// Jino : https://www.jino.ru -// Submitted by Sergey Ulyashin -myjino.ru -*.hosting.myjino.ru -*.landing.myjino.ru -*.spectrum.myjino.ru -*.vps.myjino.ru - -// Jotelulu S.L. : https://jotelulu.com -// Submitted by Daniel Fariña -jote.cloud -jotelulu.cloud -eu1-plenit.com -la1-plenit.com -us1-plenit.com - -// JouwWeb B.V. : https://www.jouwweb.nl -// Submitted by Camilo Sperberg -webadorsite.com -jouwweb.site - -// Joyent : https://www.joyent.com/ -// Submitted by Brian Bennett -*.cns.joyent.com -*.triton.zone - -// JS.ORG : http://dns.js.org -// Submitted by Stefan Keim -js.org - -// KaasHosting : http://www.kaashosting.nl/ -// Submitted by Wouter Bakker -kaas.gg -khplay.nl - -// Kapsi : https://kapsi.fi -// Submitted by Tomi Juntunen -kapsi.fi - -// Katholieke Universiteit Leuven : https://www.kuleuven.be -// Submitted by Abuse KU Leuven -ezproxy.kuleuven.be -kuleuven.cloud - -// Keyweb AG : https://www.keyweb.de -// Submitted by Martin Dannehl -keymachine.de - -// KingHost : https://king.host -// Submitted by Felipe Keller Braz -kinghost.net -uni5.net - -// KnightPoint Systems, LLC : http://www.knightpoint.com/ -// Submitted by Roy Keene -knightpoint.systems - -// KoobinEvent, SL : https://www.koobin.com -// Submitted by Iván Oliva -koobin.events - -// Krellian Ltd. : https://krellian.com -// Submitted by Ben Francis -webthings.io -krellian.net - -// KUROKU LTD : https://kuroku.ltd/ -// Submitted by DisposaBoy -oya.to - -// KV GmbH : https://www.nic.co.de -// Submitted by KV GmbH -// Abuse reports to -co.de - -// Laravel Holdings, Inc. : https://laravel.com -// Submitted by André Valentin & James Brooks -laravel.cloud -on-forge.com -on-vapor.com - -// LCube - Professional hosting e.K. : https://www.lcube-webhosting.de -// Submitted by Lars Laehn -git-repos.de -lcube-server.de -svn-repos.de - -// Leadpages : https://www.leadpages.net -// Submitted by Greg Dallavalle -leadpages.co -lpages.co -lpusercontent.com - -// Leapcell : https://leapcell.io/ -// Submitted by Leapcell Team -leapcell.app -leapcell.dev -leapcell.online - -// Liara : https://liara.ir -// Submitted by Amirhossein Badinloo -liara.run -iran.liara.run - -// libp2p project : https://libp2p.io -// Submitted by Interplanetary Shipyard -libp2p.direct - -// Libre IT Ltd : https://libre.nz -// Submitted by Tomas Maggio -runcontainers.dev - -// Lifetime Hosting : https://Lifetime.Hosting/ -// Submitted by Mike Fillator -co.business -co.education -co.events -co.financial -co.network -co.place -co.technology - -// linkyard ldt : https://www.linkyard.ch/ -// Submitted by Mario Siegenthaler -linkyard-cloud.ch -linkyard.cloud - -// Linode : https://linode.com -// Submitted by -members.linode.com -*.nodebalancer.linode.com -*.linodeobjects.com -ip.linodeusercontent.com - -// LiquidNet Ltd : http://www.liquidnetlimited.com/ -// Submitted by Victor Velchev -we.bs - -// Listen53 : https://www.l53.net -// Submitted by Gerry Keh -filegear-sg.me -ggff.net - -// Localcert : https://localcert.dev -// Submitted by Lann Martin -*.user.localcert.dev - -// Localtonet : https://localtonet.com/ -// Submitted by Burak Isleyici -localtonet.com -*.localto.net - -// Lodz University of Technology LODMAN regional domains : https://www.man.lodz.pl/dns -// Submitted by Piotr Wilk -lodz.pl -pabianice.pl -plock.pl -sieradz.pl -skierniewice.pl -zgierz.pl - -// Log'in Line : https://www.loginline.com/ -// Submitted by Rémi Mach -loginline.app -loginline.dev -loginline.io -loginline.services -loginline.site - -// Lõhmus Family, The : https://lohmus.me/ -// Submitted by Heiki Lõhmus -lohmus.me - -// Lovable : https://lovable.dev -// Submitted by Fabian Hedin -lovable.app -lovableproject.com -lovable.run -lovable.sh - -// LubMAN UMCS Sp. z o.o : https://lubman.pl/ -// Submitted by Ireneusz Maliszewski -krasnik.pl -leczna.pl -lubartow.pl -lublin.pl -poniatowa.pl -swidnik.pl - -// Lug.org.uk : https://lug.org.uk -// Submitted by Jon Spriggs -glug.org.uk -lug.org.uk -lugs.org.uk - -// Lukanet Ltd : https://lukanet.com -// Submitted by Anton Avramov -barsy.bg -barsy.club -barsycenter.com -barsyonline.com -barsy.de -barsy.dev -barsy.eu -barsy.gr -barsy.in -barsy.info -barsy.io -barsy.me -barsy.menu -barsyonline.menu -barsy.mobi -barsy.net -barsy.online -barsy.org -barsy.pro -barsy.pub -barsy.ro -barsy.rs -barsy.shop -barsyonline.shop -barsy.site -barsy.store -barsy.support -barsy.uk -barsy.co.uk -barsyonline.co.uk - -// Lutra : https://lutra.ai -// Submitted by Joshua Newman -*.lutrausercontent.com - -// Luyani Inc. : https://luyani.com/ -// Submitted by Umut Gumeli -luyani.app -luyani.net - -// Magento Commerce -// Submitted by Damien Tournoud -*.magentosite.cloud - -// Mail.Ru Group : https://hb.cldmail.ru -// Submitted by Ilya Zaretskiy -hb.cldmail.ru - -// MathWorks : https://www.mathworks.com/ -// Submitted by Emily Reed -matlab.cloud -modelscape.com -mwcloudnonprod.com -polyspace.com - -// May First - People Link : https://mayfirst.org/ -// Submitted by Jamie McClelland -mayfirst.info -mayfirst.org - -// Maze Play : https://www.mazeplay.com -// Submitted by Adam Humpherys -mazeplay.com - -// McHost : https://mchost.ru -// Submitted by Evgeniy Subbotin -mcdir.me -mcdir.ru -vps.mcdir.ru -mcpre.ru - -// Mediatech : https://mediatech.by -// Submitted by Evgeniy Kozhuhovskiy -mediatech.by -mediatech.dev - -// Medicom Health : https://medicomhealth.com -// Submitted by Michael Olson -hra.health - -// MedusaJS, Inc : https://medusajs.com/ -// Submitted by Stevche Radevski -medusajs.app - -// Memset hosting : https://www.memset.com -// Submitted by Tom Whitwell -miniserver.com -memset.net - -// Messerli Informatik AG : https://www.messerli.ch/ -// Submitted by Ruben Schmidmeister -messerli.app - -// Meta Platforms, Inc. : https://meta.com/ -// Submitted by Jacob Cordero -atmeta.com -apps.fbsbx.com - -// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ -// Submitted by Zdeněk Šustr and Radim Janča -*.cloud.metacentrum.cz -custom.metacentrum.cz -flt.cloud.muni.cz -usr.cloud.muni.cz - -// Meteor Development Group : https://www.meteor.com/hosting -// Submitted by Pierre Carrier -meteorapp.com -eu.meteorapp.com - -// Michau Enterprises Limited : http://www.co.pl/ -co.pl - -// Microsoft Corporation : http://microsoft.com -// Submitted by Public Suffix List Admin -// Managed by Corporate Domains -// Microsoft Azure : https://home.azure -*.azurecontainer.io -azure-api.net -azure-mobile.net -azureedge.net -azurefd.net -azurestaticapps.net -1.azurestaticapps.net -2.azurestaticapps.net -3.azurestaticapps.net -4.azurestaticapps.net -5.azurestaticapps.net -6.azurestaticapps.net -7.azurestaticapps.net -centralus.azurestaticapps.net -eastasia.azurestaticapps.net -eastus2.azurestaticapps.net -westeurope.azurestaticapps.net -westus2.azurestaticapps.net -azurewebsites.net -cloudapp.net -trafficmanager.net -blob.core.windows.net -servicebus.windows.net - -// MikroTik : https://mikrotik.com -// Submitted by MikroTik SysAdmin Team -routingthecloud.com -sn.mynetname.net -routingthecloud.net -routingthecloud.org - -// Million Software, Inc : https://million.dev/ -// Submitted by Rayhan Noufal Arayilakath -same-app.com -same-preview.com - -// minion.systems : http://minion.systems -// Submitted by Robert Böttinger -csx.cc - -// Mittwald CM Service GmbH & Co. KG : https://mittwald.de -// Submitted by Marco Rieger -mydbserver.com -webspaceconfig.de -mittwald.info -mittwaldserver.info -typo3server.info -project.space - -// MODX Systems LLC : https://modx.com -// Submitted by Elizabeth Southwell -modx.dev - -// Mozilla Foundation : https://mozilla.org/ -// Submitted by glob -bmoattachments.org - -// MSK-IX : https://www.msk-ix.ru/ -// Submitted by Khannanov Roman -net.ru -org.ru -pp.ru - -// Mythic Beasts : https://www.mythic-beasts.com -// Submitted by Paul Cammish -hostedpi.com -caracal.mythic-beasts.com -customer.mythic-beasts.com -fentiger.mythic-beasts.com -lynx.mythic-beasts.com -ocelot.mythic-beasts.com -oncilla.mythic-beasts.com -onza.mythic-beasts.com -sphinx.mythic-beasts.com -vs.mythic-beasts.com -x.mythic-beasts.com -yali.mythic-beasts.com -cust.retrosnub.co.uk - -// Nabu Casa : https://www.nabucasa.com -// Submitted by Paulus Schoutsen -ui.nabu.casa - -// Net at Work Gmbh : https://www.netatwork.de -// Submitted by Jan Jaeschke -cloud.nospamproxy.com -o365.cloud.nospamproxy.com - -// Net libre : https://www.netlib.re -// Submitted by Philippe PITTOLI -netlib.re - -// Netfy Domains : https://netfy.domains -// Submitted by Suranga Ranasinghe -netfy.app - -// Netlify : https://www.netlify.com -// Submitted by Jessica Parsons -netlify.app - -// Neustar Inc. -// Submitted by Trung Tran -4u.com - -// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ -// Submitted by Jeff Wheelhouse -nfshost.com - -// NFT.Storage : https://nft.storage/ -// Submitted by Vasco Santos or -ipfs.nftstorage.link - -// NGO.US Registry : https://nic.ngo.us -// Submitted by Alstra Solutions Ltd. Networking Team -ngo.us - -// ngrok : https://ngrok.com/ -// Submitted by Alan Shreve -ngrok.app -ngrok-free.app -ngrok.dev -ngrok-free.dev -ngrok.io -ap.ngrok.io -au.ngrok.io -eu.ngrok.io -in.ngrok.io -jp.ngrok.io -sa.ngrok.io -us.ngrok.io -ngrok.pizza -ngrok.pro - -// Nicolaus Copernicus University in Torun - MSK TORMAN : https://www.man.torun.pl -torun.pl - -// Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ -// Submitted by Nicholas Ford -nh-serv.co.uk -nimsite.uk - -// No-IP.com : https://noip.com/ -// Submitted by Deven Reza -mmafan.biz -myftp.biz -no-ip.biz -no-ip.ca -fantasyleague.cc -gotdns.ch -3utilities.com -blogsyte.com -ciscofreak.com -damnserver.com -ddnsking.com -ditchyourip.com -dnsiskinky.com -dynns.com -geekgalaxy.com -health-carereform.com -homesecuritymac.com -homesecuritypc.com -myactivedirectory.com -mysecuritycamera.com -myvnc.com -net-freaks.com -onthewifi.com -point2this.com -quicksytes.com -securitytactics.com -servebeer.com -servecounterstrike.com -serveexchange.com -serveftp.com -servegame.com -servehalflife.com -servehttp.com -servehumour.com -serveirc.com -servemp3.com -servep2p.com -servepics.com -servequake.com -servesarcasm.com -stufftoread.com -unusualperson.com -workisboring.com -dvrcam.info -ilovecollege.info -no-ip.info -brasilia.me -ddns.me -dnsfor.me -hopto.me -loginto.me -noip.me -webhop.me -bounceme.net -ddns.net -eating-organic.net -mydissent.net -myeffect.net -mymediapc.net -mypsx.net -mysecuritycamera.net -nhlfan.net -no-ip.net -pgafan.net -privatizehealthinsurance.net -redirectme.net -serveblog.net -serveminecraft.net -sytes.net -cable-modem.org -collegefan.org -couchpotatofries.org -hopto.org -mlbfan.org -myftp.org -mysecuritycamera.org -nflfan.org -no-ip.org -read-books.org -ufcfan.org -zapto.org -no-ip.co.uk -golffan.us -noip.us -pointto.us - -// NodeArt : https://nodeart.io -// Submitted by Konstantin Nosov -stage.nodeart.io - -// Noop : https://noop.app -// Submitted by Nathaniel Schweinberg -*.developer.app -noop.app - -// Northflank Ltd. : https://northflank.com/ -// Submitted by Marco Suter -*.northflank.app -*.build.run -*.code.run -*.database.run -*.migration.run - -// Noticeable : https://noticeable.io -// Submitted by Laurent Pellegrino -noticeable.news - -// Notion Labs, Inc : https://www.notion.so/ -// Submitted by Jess Yao -notion.site - -// Now-DNS : https://now-dns.com -// Submitted by Steve Russell -dnsking.ch -mypi.co -myiphost.com -forumz.info -soundcast.me -tcp4.me -dnsup.net -hicam.net -now-dns.net -ownip.net -vpndns.net -dynserv.org -now-dns.org -x443.pw -ntdll.top -freeddns.us - -// nsupdate.info : https://www.nsupdate.info/ -// Submitted by Thomas Waldmann -nsupdate.info -nerdpol.ovh - -// NYC.mn : https://dot.nyc.mn/ -// Submitted by NYC.mn Subdomain Service -nyc.mn - -// O3O.Foundation : https://o3o.foundation/ -// Submitted by the prvcy.page Registry Team -prvcy.page - -// Obl.ong : https://obl.ong -// Submitted by Reese Armstrong -obl.ong - -// Observable, Inc. : https://observablehq.com -// Submitted by Mike Bostock -observablehq.cloud -static.observableusercontent.com - -// OMG.LOL : https://omg.lol -// Submitted by Adam Newbold -omg.lol - -// Omnibond Systems, LLC. : https://www.omnibond.com -// Submitted by Cole Estep -cloudycluster.net - -// OmniWe Limited : https://omniwe.com -// Submitted by Vicary Archangel -omniwe.site - -// One.com : https://www.one.com/ -// Submitted by Jacob Bunk Nielsen -123webseite.at -123website.be -simplesite.com.br -123website.ch -simplesite.com -123webseite.de -123hjemmeside.dk -123miweb.es -123kotisivu.fi -123siteweb.fr -simplesite.gr -123homepage.it -123website.lu -123website.nl -123hjemmeside.no -service.one -simplesite.pl -123paginaweb.pt -123minsida.se - -// ONID : https://get.onid.ca -// Submitted by ONID Engineering Team -onid.ca - -// Open Domains : https://open-domains.net -// Submitted by William Harrison -is-a-fullstack.dev -is-cool.dev -is-not-a.dev -localplayer.dev -is-local.org - -// Open Social : https://www.getopensocial.com/ -// Submitted by Alexander Varwijk -opensocial.site - -// OpenAI : https://openai.com -// Submitted by Thomas Shadwell -*.oaiusercontent.com - -// OpenCraft GmbH : http://opencraft.com/ -// Submitted by Sven Marnach -opencraft.hosting - -// OpenHost : https://registry.openhost.uk -// Submitted by OpenHost Registry Team -16-b.it -32-b.it -64-b.it - -// OpenResearch GmbH : https://openresearch.com/ -// Submitted by Philipp Schmid -orsites.com - -// Opera Software, A.S.A. -// Submitted by Yngve Pettersen -operaunite.com - -// Oracle Dyn : https://cloud.oracle.com/home https://dyn.com/dns/ -// Submitted by Gregory Drake -// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label -*.customer-oci.com -*.oci.customer-oci.com -*.ocp.customer-oci.com -*.ocs.customer-oci.com -*.oraclecloudapps.com -*.oraclegovcloudapps.com -*.oraclegovcloudapps.uk - -// Orange : https://www.orange.com -// Submitted by Alexandre Linte -tech.orange - -// OsSav Technology Ltd. : https://ossav.com/ -// Submitted by OsSav Technology Ltd. -// https://nic.can.re -can.re - -// Oursky Limited : https://authgear.com/ -// Submitted by Authgear Team & Skygear Developer -authgear-staging.com -authgearapps.com -skygearapp.com - -// OutSystems -// Submitted by Duarte Santos -outsystemscloud.com - -// OVHcloud : https://ovhcloud.com -// Submitted by Vincent Cassé -*.hosting.ovh.net -*.webpaas.ovh.net - -// OwnProvider GmbH : http://www.ownprovider.com -// Submitted by Jan Moennich -ownprovider.com -own.pm - -// OwO : https://whats-th.is/ -// Submitted by Dean Sheather -*.owo.codes - -// OX : http://www.ox.rs -// Submitted by Adam Grand -ox.rs - -// oy.lc -// Submitted by Charly Coste -oy.lc - -// Pagefog : https://pagefog.com/ -// Submitted by Derek Myers -pgfog.com - -// PageXL : https://pagexl.com -// Submitted by Yann Guichard -pagexl.com - -// Pantheon Systems, Inc. : https://pantheon.io/ -// Submitted by Gary Dylina -gotpantheon.com -pantheonsite.io - -// Paywhirl, Inc : https://paywhirl.com/ -// Submitted by Daniel Netzer -*.paywhirl.com - -// pcarrier.ca Software Inc : https://pcarrier.ca/ -// Submitted by Pierre Carrier -*.xmit.co -xmit.dev -madethis.site -srv.us -gh.srv.us -gl.srv.us - -// PE Ulyanov Kirill Sergeevich : https://airy.host -// Submitted by Kirill Ulyanov -lk3.ru - -// Peplink | Pepwave : http://peplink.com/ -// Submitted by Steve Leung -mypep.link - -// Perspecta : https://perspecta.com/ -// Submitted by Kenneth Van Alstyne -perspecta.cloud - -// Plain : https://www.plain.com/ -// Submitted by Jesús Hernández -support.site - -// Planet-Work : https://www.planet-work.com/ -// Submitted by Frédéric VANNIÈRE -on-web.fr - -// Platform.sh : https://platform.sh -// Submitted by Nikola Kotur -*.upsun.app -upsunapp.com -ent.platform.sh -eu.platform.sh -us.platform.sh -*.platformsh.site -*.tst.site - -// Platter : https://platter.dev -// Submitted by Patrick Flor -platter-app.dev -platterp.us - -// Pley AB : https://www.pley.com/ -// Submitted by Henning Pohl -pley.games - -// Porter : https://porter.run/ -// Submitted by Rudraksh MK -onporter.run - -// Positive Codes Technology Company : http://co.bn/faq.html -// Submitted by Zulfais -co.bn - -// Postman, Inc : https://postman.com -// Submitted by Rahul Dhawan -postman-echo.com -pstmn.io -mock.pstmn.io -httpbin.org - -// prequalifyme.today : https://prequalifyme.today -// Submitted by DeepakTiwari deepak@ivylead.io -prequalifyme.today - -// prgmr.com : https://prgmr.com/ -// Submitted by Sarah Newman -xen.prgmr.com - -// priv.at : http://www.nic.priv.at/ -// Submitted by registry -priv.at - -// PROJECT ELIV : https://eliv.kr/ -// Submitted by PROJECT ELIV Domain Team -c01.kr -eliv-cdn.kr -eliv-dns.kr -mmv.kr -vki.kr - -// project-study : https://project-study.com -// Submitted by yumenewa -dev.project-study.com - -// Protonet GmbH : http://protonet.io -// Submitted by Martin Meier -protonet.io - -// PT Ekossistim Indo Digital : https://e.id -// Submitted by Eid Team -e.id - -// Publication Presse Communication SARL : https://ppcom.fr -// Submitted by Yaacov Akiba Slama -chirurgiens-dentistes-en-france.fr -byen.site - -// pubtls.org : https://www.pubtls.org -// Submitted by Kor Nielsen -pubtls.org - -// PythonAnywhere LLP : https://www.pythonanywhere.com -// Submitted by Giles Thomas -pythonanywhere.com -eu.pythonanywhere.com - -// QA2 -// Submitted by Daniel Dent : https://www.danieldent.com/ -qa2.com - -// QCX -// Submitted by Cassandra Beelen -qcx.io -*.sys.qcx.io - -// QNAP System Inc : https://www.qnap.com -// Submitted by Nick Chang -myqnapcloud.cn -alpha-myqnapcloud.com -dev-myqnapcloud.com -mycloudnas.com -mynascloud.com -myqnapcloud.com - -// QOTO, Org. -// Submitted by Jeffrey Phillips Freeman -qoto.io - -// Qualifio : https://qualifio.com/ -// Submitted by Xavier De Cock -qualifioapp.com - -// Quality Unit : https://qualityunit.com -// Submitted by Vasyl Tsalko -ladesk.com - -// Qualy : https://qualyhq.com -// Submitted by Raphael Arias -*.qualyhqpartner.com -*.qualyhqportal.com - -// QuickBackend : https://www.quickbackend.com -// Submitted by Dani Biro -qbuser.com - -// Quip : https://quip.com -// Submitted by Patrick Linehan -*.quipelements.com - -// Qutheory LLC : http://qutheory.io -// Submitted by Jonas Schwartz -vapor.cloud -vaporcloud.io - -// Rackmaze LLC : https://www.rackmaze.com -// Submitted by Kirill Pertsev -rackmaze.com -rackmaze.net - -// Rad Web Hosting : https://radwebhosting.com -// Submitted by Scott Claeys -cloudsite.builders -myradweb.net -servername.us - -// Radix FZC : http://domains.in.net -// Submitted by Gavin Brown -web.in -in.net - -// Raidboxes GmbH : https://raidboxes.de -// Submitted by Auke Tembrink -myrdbx.io -site.rb-hosting.io - -// Railway Corporation : https://railway.com -// Submitted by Phineas Walton -up.railway.app - -// Rancher Labs, Inc : https://rancher.com -// Submitted by Vincent Fiduccia -*.on-rancher.cloud -*.on-k3s.io -*.on-rio.io - -// RavPage : https://www.ravpage.co.il -// Submitted by Roni Horowitz -ravpage.co.il - -// Read The Docs, Inc : https://www.readthedocs.org -// Submitted by David Fischer -readthedocs-hosted.com -readthedocs.io - -// Red Hat, Inc. OpenShift : https://openshift.redhat.com/ -// Submitted by Tim Kramer -rhcloud.com - -// Redgate Software : https://red-gate.com -// Submitted by Andrew Farries -instances.spawn.cc - -// Render : https://render.com -// Submitted by Anurag Goel -onrender.com -app.render.com - -// Repl.it : https://repl.it -// Submitted by Lincoln Bergeson -replit.app -id.replit.app -firewalledreplit.co -id.firewalledreplit.co -repl.co -id.repl.co -replit.dev -archer.replit.dev -bones.replit.dev -canary.replit.dev -global.replit.dev -hacker.replit.dev -id.replit.dev -janeway.replit.dev -kim.replit.dev -kira.replit.dev -kirk.replit.dev -odo.replit.dev -paris.replit.dev -picard.replit.dev -pike.replit.dev -prerelease.replit.dev -reed.replit.dev -riker.replit.dev -sisko.replit.dev -spock.replit.dev -staging.replit.dev -sulu.replit.dev -tarpit.replit.dev -teams.replit.dev -tucker.replit.dev -wesley.replit.dev -worf.replit.dev -repl.run - -// Resin.io : https://resin.io -// Submitted by Tim Perry -resindevice.io -devices.resinstaging.io - -// RethinkDB : https://www.rethinkdb.com/ -// Submitted by Chris Kastorff -hzc.io - -// Rico Developments Limited : https://adimo.co -// Submitted by Colin Brown -adimo.co.uk - -// Riseup Networks : https://riseup.net -// Submitted by Micah Anderson -itcouldbewor.se - -// Roar Domains LLC : https://roar.basketball/ -// Submitted by Gavin Brown -aus.basketball -nz.basketball - -// ROBOT PAYMENT INC. : https://www.robotpayment.co.jp/ -// Submitted by Kentaro Takamori -subsc-pay.com -subsc-pay.net - -// Rochester Institute of Technology : http://www.rit.edu/ -// Submitted by Jennifer Herting -git-pages.rit.edu - -// Rocky Enterprise Software Foundation : https://resf.org -// Submitted by Neil Hanlon -rocky.page - -// Ruhr University Bochum : https://www.ruhr-uni-bochum.de/ -// Submitted by Andreas Jobs -rub.de -ruhr-uni-bochum.de -io.noc.ruhr-uni-bochum.de - -// Rusnames Limited : http://rusnames.ru/ -// Submitted by Sergey Zotov -биз.рус -ком.рус -крым.рус -мир.рус -мск.рус -орг.рус -самара.рус -сочи.рус -спб.рус -я.рус - -// Russian Academy of Sciences -// Submitted by Tech Support -ras.ru - -// Sakura Frp : https://www.natfrp.com -// Submitted by Bobo Liu -nyat.app - -// SAKURA Internet Inc. : https://www.sakura.ad.jp/ -// Submitted by Internet Service Department -180r.com -dojin.com -sakuratan.com -sakuraweb.com -x0.com -2-d.jp -bona.jp -crap.jp -daynight.jp -eek.jp -flop.jp -halfmoon.jp -jeez.jp -matrix.jp -mimoza.jp -ivory.ne.jp -mail-box.ne.jp -mints.ne.jp -mokuren.ne.jp -opal.ne.jp -sakura.ne.jp -sumomo.ne.jp -topaz.ne.jp -netgamers.jp -nyanta.jp -o0o0.jp -rdy.jp -rgr.jp -rulez.jp -s3.isk01.sakurastorage.jp -s3.isk02.sakurastorage.jp -saloon.jp -sblo.jp -skr.jp -tank.jp -uh-oh.jp -undo.jp -rs.webaccel.jp -user.webaccel.jp -websozai.jp -xii.jp -squares.net -jpn.org -kirara.st -x0.to -from.tv -sakura.tv - -// Salesforce.com, Inc. : https://salesforce.com/ -// Submitted by Salesforce Public Suffix List Team -*.builder.code.com -*.dev-builder.code.com -*.stg-builder.code.com -*.001.test.code-builder-stg.platform.salesforce.com -*.d.crm.dev -*.w.crm.dev -*.wa.crm.dev -*.wb.crm.dev -*.wc.crm.dev -*.wd.crm.dev -*.we.crm.dev -*.wf.crm.dev - -// Sandstorm Development Group, Inc. : https://sandcats.io/ -// Submitted by Asheesh Laroia -sandcats.io - -// SBE network solutions GmbH : https://www.sbe.de/ -// Submitted by Norman Meilick -logoip.com -logoip.de - -// Scaleway : https://www.scaleway.com/ -// Submitted by Scaleway PSL Maintainer -fr-par-1.baremetal.scw.cloud -fr-par-2.baremetal.scw.cloud -nl-ams-1.baremetal.scw.cloud -cockpit.fr-par.scw.cloud -ddl.fr-par.scw.cloud -dtwh.fr-par.scw.cloud -fnc.fr-par.scw.cloud -functions.fnc.fr-par.scw.cloud -ifr.fr-par.scw.cloud -k8s.fr-par.scw.cloud -nodes.k8s.fr-par.scw.cloud -kafk.fr-par.scw.cloud -mgdb.fr-par.scw.cloud -rdb.fr-par.scw.cloud -s3.fr-par.scw.cloud -s3-website.fr-par.scw.cloud -scbl.fr-par.scw.cloud -whm.fr-par.scw.cloud -priv.instances.scw.cloud -pub.instances.scw.cloud -k8s.scw.cloud -cockpit.nl-ams.scw.cloud -ddl.nl-ams.scw.cloud -dtwh.nl-ams.scw.cloud -ifr.nl-ams.scw.cloud -k8s.nl-ams.scw.cloud -nodes.k8s.nl-ams.scw.cloud -kafk.nl-ams.scw.cloud -mgdb.nl-ams.scw.cloud -rdb.nl-ams.scw.cloud -s3.nl-ams.scw.cloud -s3-website.nl-ams.scw.cloud -scbl.nl-ams.scw.cloud -whm.nl-ams.scw.cloud -cockpit.pl-waw.scw.cloud -ddl.pl-waw.scw.cloud -dtwh.pl-waw.scw.cloud -ifr.pl-waw.scw.cloud -k8s.pl-waw.scw.cloud -nodes.k8s.pl-waw.scw.cloud -kafk.pl-waw.scw.cloud -mgdb.pl-waw.scw.cloud -rdb.pl-waw.scw.cloud -s3.pl-waw.scw.cloud -s3-website.pl-waw.scw.cloud -scbl.pl-waw.scw.cloud -scalebook.scw.cloud -smartlabeling.scw.cloud -dedibox.fr - -// schokokeks.org GbR : https://schokokeks.org/ -// Submitted by Hanno Böck -schokokeks.net - -// Scottish Government : https://www.gov.scot -// Submitted by Martin Ellis -gov.scot -service.gov.scot - -// Scry Security : http://www.scrysec.com -// Submitted by Shante Adam -scrysec.com - -// Scrypted : https://scrypted.app -// Submitted by Koushik Dutta -client.scrypted.io - -// Securepoint GmbH : https://www.securepoint.de -// Submitted by Erik Anders -firewall-gateway.com -firewall-gateway.de -my-gateway.de -my-router.de -spdns.de -spdns.eu -firewall-gateway.net -my-firewall.org -myfirewall.org -spdns.org - -// Seidat : https://www.seidat.com -// Submitted by Artem Kondratev -seidat.net - -// Sellfy : https://sellfy.com -// Submitted by Yuriy Romadin -sellfy.store - -// Sendmsg : https://www.sendmsg.co.il -// Submitted by Assaf Stern -minisite.ms - -// Senseering GmbH : https://www.senseering.de -// Submitted by Felix Mönckemeyer -senseering.net - -// Servebolt AS : https://servebolt.com -// Submitted by Daniel Kjeserud -servebolt.cloud - -// Service Online LLC : http://drs.ua/ -// Submitted by Serhii Bulakh -biz.ua -co.ua -pp.ua - -// Shanghai Accounting Society : https://www.sasf.org.cn -// Submitted by Information Administration -as.sh.cn - -// Sheezy.Art : https://sheezy.art -// Submitted by Nyoom -sheezy.games - -// Shopblocks : http://www.shopblocks.com/ -// Submitted by Alex Bowers -myshopblocks.com - -// Shopify : https://www.shopify.com -// Submitted by Alex Richter -myshopify.com - -// Shopit : https://www.shopitcommerce.com/ -// Submitted by Craig McMahon -shopitsite.com - -// shopware AG : https://shopware.com -// Submitted by Jens Küper -shopware.shop -shopware.store - -// Siemens Mobility GmbH -// Submitted by Oliver Graebner -mo-siemens.io - -// SinaAppEngine : http://sae.sina.com.cn/ -// Submitted by SinaAppEngine -1kapp.com -appchizi.com -applinzi.com -sinaapp.com -vipsinaapp.com - -// Siteleaf : https://www.siteleaf.com/ -// Submitted by Skylar Challand -siteleaf.net - -// Small Technology Foundation : https://small-tech.org -// Submitted by Aral Balkan -small-web.org - -// Smallregistry by Promopixel SARL : https://www.smallregistry.net -// Former AFNIC's SLDs -// Submitted by Jérôme Lipowicz -aeroport.fr -avocat.fr -chambagri.fr -chirurgiens-dentistes.fr -experts-comptables.fr -medecin.fr -notaires.fr -pharmacien.fr -port.fr -veterinaire.fr - -// Smoove.io : https://www.smoove.io/ -// Submitted by Dan Kozak -vp4.me - -// Snowflake Inc : https://www.snowflake.com/ -// Submitted by Sam Haar -*.snowflake.app -*.privatelink.snowflake.app -streamlit.app -streamlitapp.com - -// Snowplow Analytics : https://snowplowanalytics.com/ -// Submitted by Ian Streeter -try-snowplow.com - -// Software Consulting Michal Zalewski : https://www.mafelo.com -// Submitted by Michal Zalewski -mafelo.net - -// Sony Interactive Entertainment LLC : https://sie.com/ -// Submitted by David Coles -playstation-cloud.com - -// SourceHut : https://sourcehut.org -// Submitted by Drew DeVault -srht.site - -// SourceLair PC : https://www.sourcelair.com -// Submitted by Antonis Kalipetis -apps.lair.io -*.stolos.io - -// sourceWAY GmbH : https://sourceway.de -// Submitted by Richard Reiber -4.at -my.at -my.de -*.nxa.eu -nx.gw - -// SpeedPartner GmbH : https://www.speedpartner.de/ -// Submitted by Stefan Neufeind -customer.speedpartner.de - -// Spreadshop (sprd.net AG) : https://www.spreadshop.com/ -// Submitted by Martin Breest -myspreadshop.at -myspreadshop.com.au -myspreadshop.be -myspreadshop.ca -myspreadshop.ch -myspreadshop.com -myspreadshop.de -myspreadshop.dk -myspreadshop.es -myspreadshop.fi -myspreadshop.fr -myspreadshop.ie -myspreadshop.it -myspreadshop.net -myspreadshop.nl -myspreadshop.no -myspreadshop.pl -myspreadshop.se -myspreadshop.co.uk - -// StackBlitz : https://stackblitz.com -// Submitted by Dominic Elm & Albert Pai -w-corp-staticblitz.com -w-credentialless-staticblitz.com -w-staticblitz.com -bolt.host - -// Stackhero : https://www.stackhero.io -// Submitted by Adrien Gillon -stackhero-network.com - -// STACKIT GmbH & Co. KG : https://www.stackit.de/en/ -// Submitted by STACKIT-DNS Team (Simon Stier) -runs.onstackit.cloud -stackit.gg -stackit.rocks -stackit.run -stackit.zone - -// Staclar : https://staclar.com -// Submitted by Q Misell -// Submitted by Matthias Merkel -musician.io -novecore.site - -// Standard Library : https://stdlib.com -// Submitted by Jacob Lee -api.stdlib.com - -// stereosense GmbH : https://www.involve.me -// Submitted by Florian Burmann -feedback.ac -forms.ac -assessments.cx -calculators.cx -funnels.cx -paynow.cx -quizzes.cx -researched.cx -tests.cx -surveys.so - -// Storacha Network : https://storacha.network -// Submitted by Alan Shaw -ipfs.storacha.link -ipfs.w3s.link - -// Storebase : https://www.storebase.io -// Submitted by Tony Schirmer -storebase.store - -// Storipress : https://storipress.com -// Submitted by Benno Liu -storipress.app - -// Storj Labs Inc. : https://storj.io/ -// Submitted by Philip Hutchins -storj.farm - -// Strapi : https://strapi.io/ -// Submitted by Florent Baldino -strapiapp.com -media.strapiapp.com - -// Strategic System Consulting (eApps Hosting) : https://www.eapps.com/ -// Submitted by Alex Oancea -vps-host.net -atl.jelastic.vps-host.net -njs.jelastic.vps-host.net -ric.jelastic.vps-host.net - -// Streak : https://streak.com -// Submitted by Blake Kadatz -streak-link.com -streaklinks.com -streakusercontent.com - -// Student-Run Computing Facility : https://www.srcf.net/ -// Submitted by Edwin Balani -soc.srcf.net -user.srcf.net - -// Studenten Net Twente : http://www.snt.utwente.nl/ -// Submitted by Silke Hofstra -utwente.io - -// Sub 6 Limited : http://www.sub6.com -// Submitted by Dan Miller -temp-dns.com - -// Supabase : https://supabase.io -// Submitted by Supabase Security -supabase.co -realtime.supabase.co -storage.supabase.co -supabase.in -supabase.net - -// Syncloud : https://syncloud.org -// Submitted by Boris Rybalkin -syncloud.it - -// Synology, Inc. : https://www.synology.com/ -// Submitted by Rony Weng -dscloud.biz -direct.quickconnect.cn -dsmynas.com -familyds.com -diskstation.me -dscloud.me -i234.me -myds.me -synology.me -dscloud.mobi -dsmynas.net -familyds.net -dsmynas.org -familyds.org -direct.quickconnect.to -vpnplus.to - -// Tabit Technologies Ltd. : https://tabit.cloud/ -// Submitted by Oren Agiv -mytabit.com -mytabit.co.il -tabitorder.co.il - -// TAIFUN Software AG : http://taifun-software.de -// Submitted by Bjoern Henke -taifun-dns.de - -// Tailor Inc. : https://www.tailor.tech -// Submitted by Ryuzo Yamamoto -erp.dev -web.erp.dev - -// Tailscale Inc. : https://www.tailscale.com -// Submitted by David Anderson -ts.net -*.c.ts.net - -// TASK geographical domains : https://task.gda.pl/en/services/for-entrepreneurs/ -gda.pl -gdansk.pl -gdynia.pl -med.pl -sopot.pl - -// Tave Creative Corp : https://tave.com/ -// Submitted by Adrian Ziemkowski -taveusercontent.com - -// tawk.to, Inc : https://www.tawk.to -// Submitted by tawk.to developer team -p.tawk.email -p.tawkto.email - -// Tche.br : https://tche.br -// Submitted by Bruno Lorensi -tche.br - -// team.blue : https://team.blue -// Submitted by Cedric Dubois -site.tb-hosting.com - -// Teckids e.V. : https://www.teckids.org -// Submitted by Dominik George -edugit.io -s3.teckids.org - -// Telebit : https://telebit.cloud -// Submitted by AJ ONeal -telebit.app -telebit.io -*.telebit.xyz - -// Teleport : https://goteleport.com -// Submitted by Rob Picard -teleport.sh - -// Thingdust AG : https://thingdust.com/ -// Submitted by Adrian Imboden -*.firenet.ch -*.svc.firenet.ch -reservd.com -thingdustdata.com -cust.dev.thingdust.io -reservd.dev.thingdust.io -cust.disrec.thingdust.io -reservd.disrec.thingdust.io -cust.prod.thingdust.io -cust.testing.thingdust.io -reservd.testing.thingdust.io - -// ticket i/O GmbH : https://ticket.io -// Submitted by Christian Franke -tickets.io - -// Tlon.io : https://tlon.io -// Submitted by Mark Staarink -arvo.network -azimuth.network -tlon.network - -// Tor Project, Inc. : https://torproject.org -// Submitted by Antoine Beaupré -torproject.net -pages.torproject.net - -// TownNews.com : http://www.townnews.com -// Submitted by Dustin Ward -townnews-staging.com - -// TrafficPlex GmbH : https://www.trafficplex.de/ -// Submitted by Phillipp Röll -12hp.at -2ix.at -4lima.at -lima-city.at -12hp.ch -2ix.ch -4lima.ch -lima-city.ch -trafficplex.cloud -de.cool -12hp.de -2ix.de -4lima.de -lima-city.de -1337.pictures -clan.rip -lima-city.rocks -webspace.rocks -lima.zone - -// TransIP : https://www.transip.nl -// Submitted by Rory Breuk and Cedric Dubois -*.transurl.be -*.transurl.eu -site.transip.me -*.transurl.nl - -// TuxFamily : http://tuxfamily.org -// Submitted by TuxFamily administrators -tuxfamily.org - -// TwoDNS : https://www.twodns.de/ -// Submitted by TwoDNS-Support -dd-dns.de -dray-dns.de -draydns.de -dyn-vpn.de -dynvpn.de -mein-vigor.de -my-vigor.de -my-wan.de -syno-ds.de -synology-diskstation.de -synology-ds.de -diskstation.eu -diskstation.org - -// Typedream : https://typedream.com -// Submitted by Putri Karunia -typedream.app - -// Typeform : https://www.typeform.com -// Submitted by Typeform -pro.typeform.com - -// Uberspace : https://uberspace.de -// Submitted by Moritz Werner -uber.space - -// UDR Limited : http://www.udr.hk.com -// Submitted by registry -hk.com -inc.hk -ltd.hk -hk.org - -// UK Intis Telecom LTD : https://it.com -// Submitted by ITComdomains -it.com - -// Unison Computing, PBC : https://unison.cloud -// Submitted by Simon Højberg -unison-services.cloud - -// United Gameserver GmbH : https://united-gameserver.de -// Submitted by Stefan Schwarz -virtual-user.de -virtualuser.de - -// United States Writing Corporation : https://uswriting.co -// Submitted by Andrew Sampson -obj.ag - -// UNIVERSAL DOMAIN REGISTRY : https://www.udr.org.yt/ -// see also: whois -h whois.udr.org.yt help -// Submitted by Atanunu Igbunuroghene -name.pm -sch.tf -biz.wf -sch.wf -org.yt - -// University of Banja Luka : https://unibl.org -// Domains for Republic of Srpska administrative entity. -// Submitted by Marko Ivanovic -rs.ba - -// University of Bielsko-Biala regional domain : http://dns.bielsko.pl/ -// Submitted by Marcin -bielsko.pl - -// urown.net : https://urown.net -// Submitted by Hostmaster -urown.cloud -dnsupdate.info - -// US REGISTRY LLC : http://us.org -// Submitted by Gavin Brown -us.org - -// V.UA Domain Registry: https://www.v.ua/ -// Submitted by Serhii Rostilo -v.ua - -// Val Town, Inc : https://val.town/ -// Submitted by Tom MacWright -val.run -web.val.run - -// Vercel, Inc : https://vercel.com/ -// Submitted by Laurens Duijvesteijn -vercel.app -v0.build -vercel.dev -vusercontent.net -vercel.run -now.sh - -// VeryPositive SIA : http://very.lv -// Submitted by Danko Aleksejevs -2038.io - -// Virtual-Info : https://www.virtual-info.info/ -// Submitted by Adnan RIHAN -v-info.info - -// VistaBlog : https://vistablog.ir/ -// Submitted by Hossein Piri -vistablog.ir - -// Viva Republica, Inc. : https://toss.im/ -// Submitted by Deus Team -deus-canvas.com - -// Voorloper.com : https://voorloper.com -// Submitted by Nathan van Bakel -voorloper.cloud - -// Vultr Objects : https://www.vultr.com/products/object-storage/ -// Submitted by Niels Maumenee -*.vultrobjects.com - -// Waffle Computer Inc., Ltd. : https://docs.waffleinfo.com -// Submitted by Masayuki Note -wafflecell.com - -// Walrus : https://walrus.xyz -// Submitted by Max Spector -wal.app - -// Webflow, Inc. : https://www.webflow.com -// Submitted by Webflow Security Team -webflow.io -webflowtest.io - -// WebHare bv : https://www.webhare.com/ -// Submitted by Arnold Hendriks -*.webhare.dev - -// WebHotelier Technologies Ltd : https://www.webhotelier.net/ -// Submitted by Apostolos Tsakpinis -bookonline.app -hotelwithflight.com -reserve-online.com -reserve-online.net - -// WebPros International, LLC : https://webpros.com/ -// Submitted by Nicolas Rochelemagne -cprapid.com -pleskns.com -wp2.host -pdns.page -plesk.page -cpanel.site -wpsquared.site - -// WebWaddle Ltd : https://webwaddle.com/ -// Submitted by Merlin Glander -*.wadl.top - -// Western Digital Technologies, Inc : https://www.wdc.com -// Submitted by Jung Jin -remotewd.com - -// Whatbox Inc. : https://whatbox.ca/ -// Submitted by Anthony Ryan -box.ca - -// WIARD Enterprises : https://wiardweb.com -// Submitted by Kidd Hustle -pages.wiardweb.com - -// Wikimedia Foundation : https://wikitech.wikimedia.org -// Submitted by Timo Tijhof -toolforge.org -wmcloud.org -beta.wmcloud.org -wmflabs.org - -// William Harrison : https://wharrison.com.au -// Submitted by William Harrison -wdh.app -hrsn.au -vps.hrsn.au -hrsn.dev -is-a.dev -localcert.net - -// Windsurf : https://windsurf.com -// Submitted by Douglas Chen -windsurf.app -windsurf.build - -// WISP : https://wisp.gg -// Submitted by Stepan Fedotov -panel.gg -daemon.panel.gg - -// Wix.com, Inc. : https://www.wix.com -// Submitted by Shahar Talmi / Alon Kochba -wixsite.com -wixstudio.com -editorx.io -wixstudio.io -wix.run - -// Wizard Zines : https://wizardzines.com -// Submitted by Julia Evans -messwithdns.com - -// WoltLab GmbH : https://www.woltlab.com -// Submitted by Tim Düsterhus -woltlab-demo.com -myforum.community -community-pro.de -diskussionsbereich.de -community-pro.net -meinforum.net - -// Woods Valldata : https://www.woodsvalldata.co.uk/ -// Submitted by Chris Whittle -affinitylottery.org.uk -raffleentry.org.uk -weeklylottery.org.uk - -// WP Engine : https://wpengine.com/ -// Submitted by Michael Smith -// Submitted by Brandon DuRette -wpenginepowered.com -js.wpenginepowered.com - -// XenonCloud GbR : https://xenoncloud.net -// Submitted by Julian Uphoff -*.xenonconnect.de -half.host - -// XnBay Technology : http://www.xnbay.com/ -// Submitted by XnBay Developer -xnbay.com -u2.xnbay.com -u2-local.xnbay.com - -// XS4ALL Internet bv : https://www.xs4all.nl/ -// Submitted by Daniel Mostertman -cistron.nl -demon.nl -xs4all.space - -// Yandex.Cloud LLC : https://cloud.yandex.com -// Submitted by Alexander Lodin -yandexcloud.net -storage.yandexcloud.net -website.yandexcloud.net -sourcecraft.site - -// YesCourse Pty Ltd : https://yescourse.com -// Submitted by Atul Bhouraskar -official.academy - -// Yola : https://www.yola.com/ -// Submitted by Stefano Rivera -yolasite.com - -// Yunohost : https://yunohost.org -// Submitted by Valentin Grimaud -ynh.fr -nohost.me -noho.st - -// ZaNiC : http://www.za.net/ -// Submitted by registry -za.net -za.org - -// ZAP-Hosting GmbH & Co. KG : https://zap-hosting.com -// Submitted by Julian Alker -zap.cloud - -// Zeabur : https://zeabur.com/ -// Submitted by Zeabur Team -zeabur.app - -// Zerops : https://zerops.io/ -// Submitted by Zerops Team -*.zerops.app - -// Zine EOOD : https://zine.bg/ -// Submitted by Martin Angelov -bss.design - -// Zitcom A/S : https://www.zitcom.dk -// Submitted by Emil Stahl -basicserver.io -virtualserver.io -enterprisecloud.nu - -// Zone.ID: https://zone.id -// Submitted by Gx1.org -zone.id - -// ZoneABC : https://zoneabc.net -// Submitted by ZoneABC Team -zabc.net - -// ===END PRIVATE DOMAINS=== \ No newline at end of file diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java b/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java index fc1fb01..ffe57c4 100644 --- a/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java @@ -18,7 +18,12 @@ ******************************************************************************/ package org.apache.james.dmarc; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.message.DefaultMessageBuilder; import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -51,4 +56,48 @@ public void generate_and_verify_dmarc_pass() { assertThat(dmarcVerifier.runDmarcCheck(r.message(), r.spfResult(), r.spfDomain(), r.dkimResult(), r.dkimDomain()).toString()).hasToString(r.expectedResult()); }); } -} \ No newline at end of file + + @Test + public void dmarc_check_returns_permerror_when_from_header_is_missing() throws Exception { + Message message = parseMessage( + "To: recipient@example.org\r\n" + + "Subject: missing from\r\n" + + "\r\n" + + "body\r\n"); + + DmarcValidationResult result = dmarcVerifier.runDmarcCheck( + message, + "pass client-ip=192.0.2.1; envelope-from=sender@example.org", + "example.org", + "pass", + "example.org"); + + assertThat(result.toString()) + .isEqualTo("dmarc=permerror reason=\"From header must contain exactly one mailbox\""); + } + + @Test + public void dmarc_check_returns_permerror_when_from_header_has_multiple_mailboxes() throws Exception { + Message message = parseMessage( + "From: Alice , Bob \r\n" + + "To: recipient@example.org\r\n" + + "Subject: multiple from\r\n" + + "\r\n" + + "body\r\n"); + + DmarcValidationResult result = dmarcVerifier.runDmarcCheck( + message, + "pass client-ip=192.0.2.1; envelope-from=sender@example.org", + "example.org", + "pass", + "example.org"); + + assertThat(result.toString()) + .isEqualTo("dmarc=permerror reason=\"From header must contain exactly one mailbox\""); + } + + private Message parseMessage(String rawMessage) throws Exception { + return new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream(rawMessage.getBytes(StandardCharsets.UTF_8))); + } +} diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java b/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java index 984f377..68550e0 100644 --- a/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java @@ -48,7 +48,7 @@ public void getOrgDomain_noPslMatch() { @Test public void getOrgDomain_shouldReturnPublicSuffixIfMatched() { assertEquals("example.co.uk", PublicSuffixList.getOrgDomain("example.co.uk")); - assertEquals("mail.replit.app", PublicSuffixList.getOrgDomain("mail.replit.app")); + assertEquals("replit.app", PublicSuffixList.getOrgDomain("mail.replit.app")); } /* @@ -105,4 +105,4 @@ public void getOrgDomain_openAiWildcard() { assertEquals("北海道.三重.jp", PublicSuffixList.getOrgDomain("北海道.三重.jp")); //PSL + one left assertEquals("北海道.三重.jp", PublicSuffixList.getOrgDomain("大分.北海道.三重.jp")); //PSL + two left } -} \ No newline at end of file +} diff --git a/pom.xml b/pom.xml index 4f63d29..305cff4 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,7 @@ 4.13.2 11 1.0.5 + 33.0.0-jre @@ -111,6 +112,11 @@ assertj-core 3.27.7 + + com.google.guava + guava + ${guava.version} + From 510f6be9ed7325c6ce8ecf763f0e57952dae9b40 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Mon, 27 Apr 2026 17:06:09 -0400 Subject: [PATCH 38/40] Address ARC and DMARC review hardening - Include the failing ARC instance in previous-hop AMS validation errors. - Add injectable Clock support to ARCVerifier and use it for AMS timestamp checks. - Reject AMS t= timestamps in the future, even when x= is absent. - Remove empty multipart bh= bypass and always compare computed body hashes. - Fix parsed multipart reconstruction by reading the boundary from parent Content-Type. - Tighten ARC-Seal tag validation for required i/a/cv/d/s/b tags, cv values, d/s syntax, and h= rejection. - Convert DMARC PublicSuffixList to an injectable interface. - Add built-in default PSL resolver and optional Guava-backed implementation. - Mark Guava optional and add custom PSL injection coverage. - Add regression tests for diagnostics, timestamp validation, multipart bh= handling, and custom PSL wiring. --- .../apache/james/arc/ARCChainValidator.java | 2 +- .../org/apache/james/arc/ARCVerifier.java | 59 ++++++++++++++++--- .../java/org/apache/james/arc/ARCTest.java | 45 +++++++++++++- dmarc/pom.xml | 1 + .../org/apache/james/dmarc/DMARCVerifier.java | 13 +++- .../james/dmarc/DefaultPublicSuffixList.java | 37 ++++++++++++ .../james/dmarc/GuavaPublicSuffixList.java | 43 ++++++++++++++ .../apache/james/dmarc/PublicSuffixList.java | 25 +------- .../org/apache/james/dmarc/DMARCTest.java | 17 ++++++ .../james/dmarc/PublicSuffixListTest.java | 53 +++++++++-------- 10 files changed, 231 insertions(+), 64 deletions(-) create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/DefaultPublicSuffixList.java create mode 100644 dmarc/src/main/java/org/apache/james/dmarc/GuavaPublicSuffixList.java diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index e881ceb..d2e690c 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -95,7 +95,7 @@ private ArcValidationOutcome validatePreviousArcHops(Message message, Header mes for (int i = 1; i <= numArcInstances; i++) { Set arcSet = arcVerifier.extractArcSet(messageHeaders, i); if (arcSet == null || !checkArcAms(arcSet, message, arcVerifier)) { - return new ArcValidationOutcome(ArcValidationResult.FAIL, "Previous ARC hops validation failed"); + return new ArcValidationOutcome(ArcValidationResult.FAIL, "Previous ARC hop validation failed at i=" + i); } } boolean asOk; diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 79d95d1..7c80aca 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -27,6 +27,7 @@ import org.apache.james.mime4j.dom.Message; import org.apache.james.mime4j.dom.Multipart; import org.apache.james.mime4j.dom.SingleBody; +import org.apache.james.mime4j.dom.field.ContentTypeField; import org.apache.james.mime4j.io.EOLConvertingInputStream; import org.apache.james.mime4j.stream.NameValuePair; import org.apache.james.mime4j.stream.Field; @@ -45,6 +46,7 @@ import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; +import java.time.Clock; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -53,6 +55,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.TreeMap; @@ -73,7 +76,7 @@ *
  • Building signing data for ARC-Seal verification
  • * *

    - * This class is not instantiable and all methods are static. + * Instances are configured with a public key retriever and an optional clock. */ public class ARCVerifier { public static final String RSA = "RSA"; @@ -90,10 +93,16 @@ public class ARCVerifier { private static final int MIN_ARC_INSTANCE = 1; private static final int MAX_ARC_INSTANCE = 50; private static final String DNS_RECORD_TYPE = "_domainkey"; - private PublicKeyRetrieverArc _keyRecordRetriever; + private final PublicKeyRetrieverArc _keyRecordRetriever; + private final Clock clock; - ARCVerifier(PublicKeyRetrieverArc keyRecordRetriever) { - _keyRecordRetriever = keyRecordRetriever; + public ARCVerifier(PublicKeyRetrieverArc keyRecordRetriever) { + this(keyRecordRetriever, Clock.systemUTC()); + } + + public ARCVerifier(PublicKeyRetrieverArc keyRecordRetriever, Clock clock) { + _keyRecordRetriever = Objects.requireNonNull(keyRecordRetriever); + this.clock = Objects.requireNonNull(clock); } public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRecord) { @@ -201,6 +210,10 @@ private boolean validateAmsTags(Map tags) { private void validateAmsTimestamp(Map tags) { String timestamp = tags.get("t"); String expiration = tags.get("x"); + long now = clock.instant().getEpochSecond(); + if (timestamp != null && Long.parseLong(timestamp) > now) { + throw new ArcException("AMS t= timestamp must not be in the future"); + } if (expiration == null) { return; } @@ -208,7 +221,6 @@ private void validateAmsTimestamp(Map tags) { if (timestamp != null && expirationEpoch <= Long.parseLong(timestamp)) { throw new ArcException("AMS x= expiration must be greater than t= timestamp"); } - long now = System.currentTimeMillis() / 1000; if (expirationEpoch < now) { throw new ArcException("AMS signature is expired"); } @@ -227,9 +239,6 @@ private boolean verifyAmsBodyHash(Map tags, Message message, Str try { MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); byte[] bodyBytes = message.getBody() == null ? new byte[0] : readBodyBytes(message.getBody()); - if (bodyBytes.length == 0 && message.getBody() instanceof Multipart) { - return true; - } byte[] canonicalizedBody = canonicalizeBody(bodyBytes, bodyCanonicalization); computedBodyHash = messageDigest.digest(canonicalizedBody); } catch (IOException | NoSuchAlgorithmException e) { @@ -275,6 +284,11 @@ private String getBoundary(Multipart multipart) { return parameter.getValue(); } } + Entity parent = multipart.getParent(); + if (parent != null && parent.getHeader() != null + && parent.getHeader().getField("Content-Type") instanceof ContentTypeField) { + return ((ContentTypeField) parent.getHeader().getField("Content-Type")).getBoundary(); + } return null; } @@ -469,10 +483,37 @@ private boolean checkArcSealTags(List arcSet) { .filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)) .findFirst(); return arcSealHeader - .map(field -> !parseTagList(field.getBody()).containsKey("h")) + .map(field -> { + Map tags = parseTagList(field.getBody()); + return hasRequiredArcSealTags(tags) + && isValidArcSealCv(tags.get("cv")) + && DOMAIN_PATTERN.matcher(tags.get("d")).matches() + && SELECTOR_PATTERN.matcher(tags.get("s")).matches() + && !tags.containsKey("h"); + }) .orElse(false); } + private boolean hasRequiredArcSealTags(Map tags) { + return hasNonEmptyTag(tags, "i") + && hasNonEmptyTag(tags, "a") + && hasNonEmptyTag(tags, "cv") + && hasNonEmptyTag(tags, "d") + && hasNonEmptyTag(tags, "s") + && hasNonEmptyTag(tags, "b"); + } + + private boolean hasNonEmptyTag(Map tags, String tagName) { + String value = tags.get(tagName); + return value != null && !value.replaceAll("\\s+", "").isEmpty(); + } + + private boolean isValidArcSealCv(String cv) { + return "none".equalsIgnoreCase(cv) + || "pass".equalsIgnoreCase(cv) + || "fail".equalsIgnoreCase(cv); + } + private boolean checkCv(List lastArcSet, int instToVerify) { Optional arcSealHeader = lastArcSet.stream().filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)).findFirst(); if (arcSealHeader.isPresent()) { diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index 080f688..e3aa0b7 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -44,6 +44,9 @@ import java.net.URL; import java.nio.charset.StandardCharsets; import java.security.Signature; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Map; import java.util.Set; @@ -239,6 +242,7 @@ public void validate_arc_chain_fails_when_ams_signature_is_invalid() throws Exce ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); ArcValidationOutcome cv = arcChainValidator.validateArcChain(message); assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); + assertThat(cv.getDescription()).isEqualTo("Previous ARC hop validation failed at i=1"); } // cv_fail_i1_as_invalid: builds a valid i=1 ARC set, then replaces the ARC-Seal b= signature with @@ -1245,6 +1249,24 @@ public void verify_ams_fails_when_no_body_message_has_wrong_body_hash() throws E .isFalse(); } + @Test + public void verify_ams_fails_when_empty_multipart_has_wrong_body_hash() throws Exception { + Message message = parseRawEmail( + "From: sender@example.org\n" + + "To: recipient@example.org\n" + + "Subject: empty multipart\n" + + "Content-Type: multipart/alternative; boundary=abc\n" + + "\n"); + String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " + + "t=12345; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + + assertThat(new ARCVerifier(keyRecordRetriever).verifyAms(amsField, message, publicKeyDnsRecord)) + .isFalse(); + } + // ams_fields_bh_mod_body: body changes outside relaxed canonicalization must be rejected. @Test public void validate_arc_chain_fails_when_ams_signed_body_is_modified() throws Exception { @@ -1658,16 +1680,35 @@ public void verify_ams_throws_clear_exception_when_signature_is_expired() throws + "To: recipient@example.org\r\n" + "Subject: expired ams\r\n").getBytes(StandardCharsets.UTF_8))); String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " - + "t=1; x=2; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + + "t=1; x=1000; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + Clock clockAfterExpiration = Clock.fixed(Instant.ofEpochSecond(1001), ZoneOffset.UTC); - assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever).verifyAms(amsField, message, publicKeyDnsRecord)) + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever, clockAfterExpiration).verifyAms(amsField, message, publicKeyDnsRecord)) .isInstanceOf(ArcException.class) .hasMessage("AMS signature is expired"); } + @Test + public void verify_ams_throws_clear_exception_when_timestamp_is_in_the_future_without_expiration() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( + ("From: sender@example.org\r\n" + + "To: recipient@example.org\r\n" + + "Subject: future ams timestamp\r\n").getBytes(StandardCharsets.UTF_8))); + String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " + + "t=1001; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + Clock clockBeforeTimestamp = Clock.fixed(Instant.ofEpochSecond(1000), ZoneOffset.UTC); + + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever, clockBeforeTimestamp).verifyAms(amsField, message, publicKeyDnsRecord)) + .isInstanceOf(ArcException.class) + .hasMessage("AMS t= timestamp must not be in the future"); + } + @Test public void verify_ams_throws_clear_exception_when_expiration_is_not_after_timestamp() throws Exception { Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( diff --git a/dmarc/pom.xml b/dmarc/pom.xml index ac550af..00ddaab 100644 --- a/dmarc/pom.xml +++ b/dmarc/pom.xml @@ -58,6 +58,7 @@ com.google.guava guava + true org.assertj diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java index c51be12..215b784 100644 --- a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java +++ b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java @@ -24,13 +24,20 @@ import org.apache.james.mime4j.dom.address.MailboxList; import java.util.HashMap; import java.util.Map; +import java.util.Objects; public class DMARCVerifier { public static final String FROM = "From"; private final PublicKeyRecordRetrieverDmarc _recordRetriever; + private final PublicSuffixList publicSuffixList; public DMARCVerifier(PublicKeyRecordRetrieverDmarc recordRetriever) { - _recordRetriever = recordRetriever; + this(recordRetriever, new DefaultPublicSuffixList()); + } + + public DMARCVerifier(PublicKeyRecordRetrieverDmarc recordRetriever, PublicSuffixList publicSuffixList) { + _recordRetriever = Objects.requireNonNull(recordRetriever); + this.publicSuffixList = Objects.requireNonNull(publicSuffixList); } public DmarcValidationResult runDmarcCheck(Message message, String spfHeaderText, String @@ -93,8 +100,8 @@ private Map getDmarcTags(String dmarcRecord) { private boolean getDomainAlignment(String flag, String result, String receivedDomain, String expectedDomain) { // we expect flag to be either "s" or "r"; default is "r" when omitted if (flag.equalsIgnoreCase("r")){ //relaxed - String fromOrgDomain = PublicSuffixList.getOrgDomain(receivedDomain); //we get the organizational domain using PSL - String spfOrgDomain = PublicSuffixList.getOrgDomain(expectedDomain); + String fromOrgDomain = publicSuffixList.getOrgDomain(receivedDomain); //we get the organizational domain using PSL + String spfOrgDomain = publicSuffixList.getOrgDomain(expectedDomain); return "pass".equals(result) && fromOrgDomain.equalsIgnoreCase(spfOrgDomain); diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DefaultPublicSuffixList.java b/dmarc/src/main/java/org/apache/james/dmarc/DefaultPublicSuffixList.java new file mode 100644 index 0000000..257f5d7 --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/DefaultPublicSuffixList.java @@ -0,0 +1,37 @@ +/****************************************************************************** + * 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.dmarc; + +import java.util.Locale; + +public class DefaultPublicSuffixList implements PublicSuffixList { + @Override + public String getOrgDomain(String domainToCheck) { + if (domainToCheck == null || domainToCheck.trim().isEmpty()) { + return domainToCheck; + } + + String normalizedDomain = domainToCheck.toLowerCase(Locale.ROOT).trim(); + String[] labels = normalizedDomain.split("\\."); + if (labels.length < 3) { + return normalizedDomain; + } + return labels[labels.length - 2] + "." + labels[labels.length - 1]; + } +} diff --git a/dmarc/src/main/java/org/apache/james/dmarc/GuavaPublicSuffixList.java b/dmarc/src/main/java/org/apache/james/dmarc/GuavaPublicSuffixList.java new file mode 100644 index 0000000..dc1112f --- /dev/null +++ b/dmarc/src/main/java/org/apache/james/dmarc/GuavaPublicSuffixList.java @@ -0,0 +1,43 @@ +/****************************************************************************** + * 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.dmarc; + +import java.util.Locale; + +import com.google.common.net.InternetDomainName; + +public class GuavaPublicSuffixList implements PublicSuffixList { + @Override + public String getOrgDomain(String domainToCheck) { + if (domainToCheck == null || domainToCheck.trim().isEmpty()) { + return domainToCheck; + } + + String normalizedDomain = domainToCheck.toLowerCase(Locale.ROOT).trim(); + try { + InternetDomainName domainName = InternetDomainName.from(normalizedDomain); + if (domainName.isUnderPublicSuffix()) { + return domainName.topPrivateDomain().toString(); + } + return normalizedDomain; + } catch (IllegalArgumentException e) { + return normalizedDomain; + } + } +} diff --git a/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java b/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java index 6f2fed5..24c38e1 100644 --- a/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java +++ b/dmarc/src/main/java/org/apache/james/dmarc/PublicSuffixList.java @@ -18,27 +18,6 @@ ******************************************************************************/ package org.apache.james.dmarc; -import java.util.Locale; - -import com.google.common.net.InternetDomainName; - -public class PublicSuffixList { - private PublicSuffixList() {} - - public static String getOrgDomain(String domainToCheck) { - if (domainToCheck == null || domainToCheck.trim().isEmpty()) { - return domainToCheck; - } - - String normalizedDomain = domainToCheck.toLowerCase(Locale.ROOT).trim(); - try { - InternetDomainName domainName = InternetDomainName.from(normalizedDomain); - if (domainName.isUnderPublicSuffix()) { - return domainName.topPrivateDomain().toString(); - } - return normalizedDomain; - } catch (IllegalArgumentException e) { - return normalizedDomain; - } - } +public interface PublicSuffixList { + String getOrgDomain(String domainToCheck); } diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java b/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java index ffe57c4..f69ef2a 100644 --- a/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/DMARCTest.java @@ -57,6 +57,23 @@ public void generate_and_verify_dmarc_pass() { }); } + @Test + public void dmarc_check_can_use_custom_public_suffix_list() { + PublicSuffixList customPublicSuffixList = domain -> "example.test"; + DMARCVerifier verifier = new DMARCVerifier(recordRetrieverDmarc, customPublicSuffixList); + DmarcRequestMock request = passRequests.get(0); + + DmarcValidationResult result = verifier.runDmarcCheck( + request.message(), + "pass client-ip=192.0.2.1; envelope-from=sender@different.example.test", + "different.example.test", + "fail", + "not-used.example.test"); + + assertThat(result.toString()) + .isEqualTo("dmarc=pass (p=reject) header.from=d1.example"); + } + @Test public void dmarc_check_returns_permerror_when_from_header_is_missing() throws Exception { Message message = parseMessage( diff --git a/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java b/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java index 68550e0..bed30a0 100644 --- a/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java +++ b/dmarc/src/main/test/java/org/apache/james/dmarc/PublicSuffixListTest.java @@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals; public class PublicSuffixListTest { + private final PublicSuffixList publicSuffixList = new GuavaPublicSuffixList(); /* `example.com` does not exist in the PSL, only `com` does @@ -29,9 +30,9 @@ public class PublicSuffixListTest { */ @Test public void getOrgDomain_simpleMatch() { - assertEquals("example.com", PublicSuffixList.getOrgDomain("example.com")); - assertEquals("example.com", PublicSuffixList.getOrgDomain("aaa.example.com")); - assertEquals("example.com", PublicSuffixList.getOrgDomain("bbb.aaa.example.com")); + assertEquals("example.com", publicSuffixList.getOrgDomain("example.com")); + assertEquals("example.com", publicSuffixList.getOrgDomain("aaa.example.com")); + assertEquals("example.com", publicSuffixList.getOrgDomain("bbb.aaa.example.com")); } /* @@ -40,15 +41,15 @@ public void getOrgDomain_simpleMatch() { */ @Test public void getOrgDomain_noPslMatch() { - assertEquals("unknown.private", PublicSuffixList.getOrgDomain("unknown.private")); - assertEquals("my.localdomain", PublicSuffixList.getOrgDomain("my.localdomain")); - assertEquals("service.internal", PublicSuffixList.getOrgDomain("service.internal")); + assertEquals("unknown.private", publicSuffixList.getOrgDomain("unknown.private")); + assertEquals("my.localdomain", publicSuffixList.getOrgDomain("my.localdomain")); + assertEquals("service.internal", publicSuffixList.getOrgDomain("service.internal")); } @Test public void getOrgDomain_shouldReturnPublicSuffixIfMatched() { - assertEquals("example.co.uk", PublicSuffixList.getOrgDomain("example.co.uk")); - assertEquals("replit.app", PublicSuffixList.getOrgDomain("mail.replit.app")); + assertEquals("example.co.uk", publicSuffixList.getOrgDomain("example.co.uk")); + assertEquals("replit.app", publicSuffixList.getOrgDomain("mail.replit.app")); } /* @@ -56,10 +57,10 @@ public void getOrgDomain_shouldReturnPublicSuffixIfMatched() { */ @Test public void getOrgDomain_wildCardMatched() { - assertEquals("sapporo.jp", PublicSuffixList.getOrgDomain("sapporo.jp")); - assertEquals("abc.sapporo.jp", PublicSuffixList.getOrgDomain("abc.sapporo.jp")); - assertEquals("foo.abc.sapporo.jp", PublicSuffixList.getOrgDomain("foo.abc.sapporo.jp")); - assertEquals("foo.abc.sapporo.jp", PublicSuffixList.getOrgDomain("bar.foo.abc.sapporo.jp")); + assertEquals("sapporo.jp", publicSuffixList.getOrgDomain("sapporo.jp")); + assertEquals("abc.sapporo.jp", publicSuffixList.getOrgDomain("abc.sapporo.jp")); + assertEquals("foo.abc.sapporo.jp", publicSuffixList.getOrgDomain("foo.abc.sapporo.jp")); + assertEquals("foo.abc.sapporo.jp", publicSuffixList.getOrgDomain("bar.foo.abc.sapporo.jp")); } /* @@ -67,9 +68,9 @@ public void getOrgDomain_wildCardMatched() { */ @Test public void getOrgDomain_exceptionsMatched() { - assertEquals("city.sapporo.jp", PublicSuffixList.getOrgDomain("city.sapporo.jp")); - assertEquals("city.sapporo.jp", PublicSuffixList.getOrgDomain("abc.city.sapporo.jp")); - assertEquals("city.sapporo.jp", PublicSuffixList.getOrgDomain("x.y.city.sapporo.jp")); + assertEquals("city.sapporo.jp", publicSuffixList.getOrgDomain("city.sapporo.jp")); + assertEquals("city.sapporo.jp", publicSuffixList.getOrgDomain("abc.city.sapporo.jp")); + assertEquals("city.sapporo.jp", publicSuffixList.getOrgDomain("x.y.city.sapporo.jp")); } /* @@ -79,11 +80,11 @@ public void getOrgDomain_exceptionsMatched() { */ @Test public void getOrgDomain_wildCardAndExceptionCombo() { - assertEquals("www.ck", PublicSuffixList.getOrgDomain("www.ck")); // exception - assertEquals("www.ck", PublicSuffixList.getOrgDomain("a.www.ck")); // exception overrides wildcard - assertEquals("abc.ck", PublicSuffixList.getOrgDomain("abc.ck")); // wildcard + one left - assertEquals("foo.abc.ck", PublicSuffixList.getOrgDomain("foo.abc.ck")); // wildcard + two left - assertEquals("foo.abc.ck", PublicSuffixList.getOrgDomain("bar.foo.abc.ck")); // wildcard + two. we stop at two left labels + assertEquals("www.ck", publicSuffixList.getOrgDomain("www.ck")); // exception + assertEquals("www.ck", publicSuffixList.getOrgDomain("a.www.ck")); // exception overrides wildcard + assertEquals("abc.ck", publicSuffixList.getOrgDomain("abc.ck")); // wildcard + one left + assertEquals("foo.abc.ck", publicSuffixList.getOrgDomain("foo.abc.ck")); // wildcard + two left + assertEquals("foo.abc.ck", publicSuffixList.getOrgDomain("bar.foo.abc.ck")); // wildcard + two. we stop at two left labels } /* @@ -91,9 +92,9 @@ public void getOrgDomain_wildCardAndExceptionCombo() { */ @Test public void getOrgDomain_singleLabel() { - assertEquals("localhost", PublicSuffixList.getOrgDomain("localhost")); - assertEquals("com", PublicSuffixList.getOrgDomain("com")); - assertEquals("example", PublicSuffixList.getOrgDomain("example")); + assertEquals("localhost", publicSuffixList.getOrgDomain("localhost")); + assertEquals("com", publicSuffixList.getOrgDomain("com")); + assertEquals("example", publicSuffixList.getOrgDomain("example")); } /* @@ -101,8 +102,8 @@ PSL match with internationalized domain names (IDN) */ @Test public void getOrgDomain_openAiWildcard() { - assertEquals("三重.jp", PublicSuffixList.getOrgDomain("三重.jp")); //Bare PSL match - assertEquals("北海道.三重.jp", PublicSuffixList.getOrgDomain("北海道.三重.jp")); //PSL + one left - assertEquals("北海道.三重.jp", PublicSuffixList.getOrgDomain("大分.北海道.三重.jp")); //PSL + two left + assertEquals("三重.jp", publicSuffixList.getOrgDomain("三重.jp")); //Bare PSL match + assertEquals("北海道.三重.jp", publicSuffixList.getOrgDomain("北海道.三重.jp")); //PSL + one left + assertEquals("北海道.三重.jp", publicSuffixList.getOrgDomain("大分.北海道.三重.jp")); //PSL + two left } } From 7723098f2f251b10f637446509db34fce63f8d0c Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Wed, 29 Apr 2026 14:26:02 -0400 Subject: [PATCH 39/40] Update dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java Agreed this is safer. Co-authored-by: Benoit TELLIER --- dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java index 215b784..200ca45 100644 --- a/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java +++ b/dmarc/src/main/java/org/apache/james/dmarc/DMARCVerifier.java @@ -89,7 +89,7 @@ private Map getDmarcTags(String dmarcRecord) { String[] parts = dmarcRecord.split(";"); for (String part : parts) { String trimmed = part.trim(); - String[] tagValue = trimmed.split("="); + String[] tagValue = trimmed.split("=", 2); if (tagValue.length == 2) { dmarcTags.put(tagValue[0].toLowerCase(), tagValue[1]); } From 39a653152e2eb4fa7ef66a0c67be73f2aa727078 Mon Sep 17 00:00:00 2001 From: Artem Grinchenko Date: Wed, 29 Apr 2026 14:33:23 -0400 Subject: [PATCH 40/40] Harden ARC timestamp and instance validation: - Add configurable clock skew handling for AMS t=/x= validation, defaulting to 5 minutes. - Apply the same clock skew validation to ARC-Seal t= tags. - Guard ARC-Seal verification when signing data cannot be built. - Replace loose i= regex matching in ARCChainValidator with exact tag parsing. - Add regression coverage for AMS clock skew, ARC-Seal clock skew, null seal data handling, and exact i= tag matching. --- .../apache/james/arc/ARCChainValidator.java | 39 +++++-- .../org/apache/james/arc/ARCVerifier.java | 31 ++++- .../java/org/apache/james/arc/ARCTest.java | 107 +++++++++++++++++- 3 files changed, 166 insertions(+), 11 deletions(-) diff --git a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java index d2e690c..8a73782 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java +++ b/arc/src/main/java/org/apache/james/arc/ARCChainValidator.java @@ -29,12 +29,13 @@ import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; +import java.time.Clock; +import java.time.Duration; import java.util.Base64; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Validates the ARC (Authenticated Received Chain) chain in an email message. @@ -49,11 +50,26 @@ public class ARCChainValidator { public static final String ARC_MESSAGE_SIGNATURE = "ARC-Message-Signature"; public static final String ARC_SEAL = "ARC-Seal"; private static final String SHA256_RSA = "SHA256withRSA"; - private final Pattern INST_RGX_PATTERN = Pattern.compile("i=([0-9]+)"); + private static final Duration DEFAULT_CLOCK_SKEW = Duration.ofMinutes(5); private final PublicKeyRetrieverArc _keyRecordRetriever; + private final Clock clock; + private final Duration acceptedClockSkew; public ARCChainValidator(PublicKeyRetrieverArc keyRecordRetriever) { + this(keyRecordRetriever, Clock.systemUTC()); + } + + public ARCChainValidator(PublicKeyRetrieverArc keyRecordRetriever, Clock clock) { + this(keyRecordRetriever, clock, DEFAULT_CLOCK_SKEW); + } + + public ARCChainValidator(PublicKeyRetrieverArc keyRecordRetriever, Clock clock, Duration acceptedClockSkew) { this._keyRecordRetriever = keyRecordRetriever; + this.clock = Objects.requireNonNull(clock); + this.acceptedClockSkew = Objects.requireNonNull(acceptedClockSkew); + if (acceptedClockSkew.isNegative()) { + throw new IllegalArgumentException("acceptedClockSkew must not be negative"); + } } public ArcValidationOutcome validateArcChain(Message message) { @@ -73,7 +89,7 @@ else if (curInstance > 51) { // Not allowed to be > 50 } private ArcValidationOutcome validatePreviousArcHops(Message message, Header messageHeaders, int myInstance) { - ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever); + ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever, clock, acceptedClockSkew); Map> arcHeadersByI; try { arcHeadersByI = arcVerifier.getArcHeadersByI(messageHeaders.getFields()); @@ -134,6 +150,9 @@ private boolean checkArcSeal(List headers, int instToVerify, ARCVerifier boolean retVal = false; Map> arcHeadersByI = arcVerifier.getArcHeadersByI(headers); ArcSealVerifyData verifyData = arcVerifier.buildArcSealSigningData(arcHeadersByI, instToVerify); + if (verifyData == null) { + return false; + } Field arcSealHeader = arcHeadersByI.get(instToVerify).stream() .filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)) .findFirst().orElse(null); @@ -182,11 +201,17 @@ private boolean checkArcSeal(List headers, int instToVerify, ARCVerifier public int getCurrentInstance(Header messageHeaders) { int retVal = 1; + ARCVerifier arcVerifier = new ARCVerifier(_keyRecordRetriever, clock, acceptedClockSkew); for (Field field : messageHeaders.getFields()) { if (field.getName().startsWith("ARC-")) { - Matcher m = INST_RGX_PATTERN.matcher(field.getBody()); - if (m.find()) { - int iVal = Integer.parseInt(m.group(1)); + String iTag = arcVerifier.parseTagGeneric(field.getBody(), "i"); + if (iTag != null) { + int iVal; + try { + iVal = Integer.parseInt(iTag); + } catch (NumberFormatException e) { + continue; + } if (iVal >= retVal) { retVal = iVal + 1; } diff --git a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java index 7c80aca..8e2d671 100644 --- a/arc/src/main/java/org/apache/james/arc/ARCVerifier.java +++ b/arc/src/main/java/org/apache/james/arc/ARCVerifier.java @@ -47,6 +47,7 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.time.Clock; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -93,16 +94,26 @@ public class ARCVerifier { private static final int MIN_ARC_INSTANCE = 1; private static final int MAX_ARC_INSTANCE = 50; private static final String DNS_RECORD_TYPE = "_domainkey"; + private static final Duration DEFAULT_CLOCK_SKEW = Duration.ofMinutes(5); private final PublicKeyRetrieverArc _keyRecordRetriever; private final Clock clock; + private final Duration acceptedClockSkew; public ARCVerifier(PublicKeyRetrieverArc keyRecordRetriever) { this(keyRecordRetriever, Clock.systemUTC()); } public ARCVerifier(PublicKeyRetrieverArc keyRecordRetriever, Clock clock) { + this(keyRecordRetriever, clock, DEFAULT_CLOCK_SKEW); + } + + public ARCVerifier(PublicKeyRetrieverArc keyRecordRetriever, Clock clock, Duration acceptedClockSkew) { _keyRecordRetriever = Objects.requireNonNull(keyRecordRetriever); this.clock = Objects.requireNonNull(clock); + this.acceptedClockSkew = Objects.requireNonNull(acceptedClockSkew); + if (acceptedClockSkew.isNegative()) { + throw new IllegalArgumentException("acceptedClockSkew must not be negative"); + } } public boolean verifyAms(Field amsField, Message message, String publicKeyDnsRecord) { @@ -211,7 +222,8 @@ private void validateAmsTimestamp(Map tags) { String timestamp = tags.get("t"); String expiration = tags.get("x"); long now = clock.instant().getEpochSecond(); - if (timestamp != null && Long.parseLong(timestamp) > now) { + long clockSkewSeconds = acceptedClockSkew.getSeconds(); + if (timestamp != null && Long.parseLong(timestamp) > now + clockSkewSeconds) { throw new ArcException("AMS t= timestamp must not be in the future"); } if (expiration == null) { @@ -221,7 +233,7 @@ private void validateAmsTimestamp(Map tags) { if (timestamp != null && expirationEpoch <= Long.parseLong(timestamp)) { throw new ArcException("AMS x= expiration must be greater than t= timestamp"); } - if (expirationEpoch < now) { + if (expirationEpoch < now - clockSkewSeconds) { throw new ArcException("AMS signature is expired"); } } @@ -487,6 +499,7 @@ private boolean checkArcSealTags(List arcSet) { Map tags = parseTagList(field.getBody()); return hasRequiredArcSealTags(tags) && isValidArcSealCv(tags.get("cv")) + && isValidArcSealTimestamp(tags.get("t")) && DOMAIN_PATTERN.matcher(tags.get("d")).matches() && SELECTOR_PATTERN.matcher(tags.get("s")).matches() && !tags.containsKey("h"); @@ -514,6 +527,20 @@ private boolean isValidArcSealCv(String cv) { || "fail".equalsIgnoreCase(cv); } + private boolean isValidArcSealTimestamp(String timestamp) { + if (timestamp == null) { + return true; + } + if (!timestamp.matches("\\d+")) { + return false; + } + try { + return Long.parseLong(timestamp) <= clock.instant().getEpochSecond() + acceptedClockSkew.getSeconds(); + } catch (NumberFormatException e) { + return false; + } + } + private boolean checkCv(List lastArcSet, int instToVerify) { Optional arcSealHeader = lastArcSet.stream().filter(f -> f.getName().equalsIgnoreCase(ARC_SEAL)).findFirst(); if (arcSealHeader.isPresent()) { diff --git a/arc/src/test/java/org/apache/james/arc/ARCTest.java b/arc/src/test/java/org/apache/james/arc/ARCTest.java index e3aa0b7..e10b5bc 100644 --- a/arc/src/test/java/org/apache/james/arc/ARCTest.java +++ b/arc/src/test/java/org/apache/james/arc/ARCTest.java @@ -45,12 +45,14 @@ import java.nio.charset.StandardCharsets; import java.security.Signature; import java.time.Clock; +import java.time.Duration; import java.time.Instant; import java.time.ZoneOffset; import java.util.Map; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import static org.assertj.core.api.Assertions.assertThatThrownBy; public class ARCTest { @@ -700,6 +702,16 @@ public void extract_arc_set_matches_exact_instance_number() throws Exception { .allMatch(field -> "1".equals(arcVerifier.parseTagGeneric(field.getBody(), "i"))); } + @Test + public void current_instance_ignores_tag_names_containing_i_suffix() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage( + new ByteArrayInputStream("Subject: exact instance test\n\nbody".getBytes(StandardCharsets.UTF_8))); + message.getHeader().addField(new RawField(ARC_SEAL, "unrelatedi=10; i=1; cv=none; d=example.org; s=arc; b=one")); + ARCChainValidator arcChainValidator = new ARCChainValidator(keyRecordRetriever); + + assertThat(arcChainValidator.getCurrentInstance(message.getHeader())).isEqualTo(2); + } + @Test public void arc_header_grouping_rejects_zero_instance_number() throws Exception { Message message = new DefaultMessageBuilder().parseMessage( @@ -1684,13 +1696,65 @@ public void verify_ams_throws_clear_exception_when_signature_is_expired() throws String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; - Clock clockAfterExpiration = Clock.fixed(Instant.ofEpochSecond(1001), ZoneOffset.UTC); + Clock clockAfterExpiration = Clock.fixed(Instant.ofEpochSecond(1301), ZoneOffset.UTC); assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever, clockAfterExpiration).verifyAms(amsField, message, publicKeyDnsRecord)) .isInstanceOf(ArcException.class) .hasMessage("AMS signature is expired"); } + @Test + public void verify_ams_accepts_timestamp_within_default_clock_skew() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( + ("From: sender@example.org\r\n" + + "To: recipient@example.org\r\n" + + "Subject: future ams timestamp within skew\r\n").getBytes(StandardCharsets.UTF_8))); + String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " + + "t=1300; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + Clock clockBeforeTimestamp = Clock.fixed(Instant.ofEpochSecond(1000), ZoneOffset.UTC); + + assertThatCode(() -> new ARCVerifier(keyRecordRetriever, clockBeforeTimestamp).verifyAms(amsField, message, publicKeyDnsRecord)) + .doesNotThrowAnyException(); + } + + @Test + public void verify_ams_throws_clear_exception_when_timestamp_exceeds_default_clock_skew() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( + ("From: sender@example.org\r\n" + + "To: recipient@example.org\r\n" + + "Subject: future ams timestamp beyond skew\r\n").getBytes(StandardCharsets.UTF_8))); + String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " + + "t=1301; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + Clock clockBeforeTimestamp = Clock.fixed(Instant.ofEpochSecond(1000), ZoneOffset.UTC); + + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever, clockBeforeTimestamp).verifyAms(amsField, message, publicKeyDnsRecord)) + .isInstanceOf(ArcException.class) + .hasMessage("AMS t= timestamp must not be in the future"); + } + + @Test + public void verify_ams_uses_configured_clock_skew() throws Exception { + Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( + ("From: sender@example.org\r\n" + + "To: recipient@example.org\r\n" + + "Subject: future ams timestamp with configured skew\r\n").getBytes(StandardCharsets.UTF_8))); + String amsWithoutSignature = "i=1; a=rsa-sha256; c=relaxed/relaxed; d=dmarc.example; s=arc; " + + "t=1060; h=from:to:subject; bh=KWSe46TZKCcDbH4klJPo+tjk5LWJnVRlP5pvjXFZYLQ=; b="; + String signature = signRelaxedAmsForNoBodyMessage(message, amsWithoutSignature); + Field amsField = new RawField(ARC_MESSAGE_SIGNATURE, amsWithoutSignature + signature); + String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; + Clock clockBeforeTimestamp = Clock.fixed(Instant.ofEpochSecond(1000), ZoneOffset.UTC); + + assertThatCode(() -> new ARCVerifier(keyRecordRetriever, clockBeforeTimestamp, Duration.ofMinutes(1)).verifyAms(amsField, message, publicKeyDnsRecord)) + .doesNotThrowAnyException(); + } + @Test public void verify_ams_throws_clear_exception_when_timestamp_is_in_the_future_without_expiration() throws Exception { Message message = new DefaultMessageBuilder().parseMessage(new ByteArrayInputStream( @@ -1704,7 +1768,7 @@ public void verify_ams_throws_clear_exception_when_timestamp_is_in_the_future_wi String publicKeyDnsRecord = "k=rsa; p=" + Base64.getEncoder().encodeToString(ArcTestKeys.publicKeyArc.getEncoded()) + ";"; Clock clockBeforeTimestamp = Clock.fixed(Instant.ofEpochSecond(1000), ZoneOffset.UTC); - assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever, clockBeforeTimestamp).verifyAms(amsField, message, publicKeyDnsRecord)) + assertThatThrownBy(() -> new ARCVerifier(keyRecordRetriever, clockBeforeTimestamp, Duration.ZERO).verifyAms(amsField, message, publicKeyDnsRecord)) .isInstanceOf(ArcException.class) .hasMessage("AMS t= timestamp must not be in the future"); } @@ -2819,6 +2883,45 @@ public void validate_arc_chain_fails_when_arc_seal_timestamp_tag_is_invalid() th assertThat(cv.getResult().toString().toLowerCase()).isEqualTo("fail"); } + @Test + public void validate_arc_set_structure_passes_when_arc_seal_timestamp_is_within_default_clock_skew() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "t=1300"), true, false); + ARCVerifier arcVerifier = new ARCVerifier( + keyRecordRetriever, + Clock.fixed(Instant.ofEpochSecond(1000), ZoneOffset.UTC)); + + Map> arcHeadersByI = arcVerifier.getArcHeadersByI(message.getHeader().getFields()); + + assertThat(arcVerifier.validateArcSetStructure(arcHeadersByI)).isTrue(); + } + + @Test + public void validate_arc_set_structure_fails_when_arc_seal_timestamp_exceeds_default_clock_skew() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "t=1301"), true, false); + ARCVerifier arcVerifier = new ARCVerifier( + keyRecordRetriever, + Clock.fixed(Instant.ofEpochSecond(1000), ZoneOffset.UTC)); + + Map> arcHeadersByI = arcVerifier.getArcHeadersByI(message.getHeader().getFields()); + + assertThatThrownBy(() -> arcVerifier.validateArcSetStructure(arcHeadersByI)) + .isInstanceOf(ArcException.class) + .hasMessage("ARC Chain validation fails due to invalid ARC-Seal tags at instance [1]."); + } + + @Test + public void validate_arc_set_structure_uses_configured_arc_seal_clock_skew() throws Exception { + Message message = buildOneHopChainWithSeal(seal -> seal.replace("t=1755918846", "t=1060"), true, false); + ARCVerifier arcVerifier = new ARCVerifier( + keyRecordRetriever, + Clock.fixed(Instant.ofEpochSecond(1000), ZoneOffset.UTC), + Duration.ofMinutes(1)); + + Map> arcHeadersByI = arcVerifier.getArcHeadersByI(message.getHeader().getFields()); + + assertThat(arcVerifier.validateArcSetStructure(arcHeadersByI)).isTrue(); + } + // Builds a valid two-hop ARC chain: applies i=1 to the base message, then applies i=2 on top. private Message buildTwoHopChain() throws Exception { return buildNHopChain(2);