9

Does anyone have a good (preferably tested) regex for accepting only a valid DNS hostname, IPv4, or IPv6 address?

Saikat
  • 14,222
  • 20
  • 104
  • 125
ljbade
  • 4,576
  • 4
  • 30
  • 35

5 Answers5

25

I understand that you may be forced to use a regex. However, if possible it is better to avoid using regexes for this task and use a Java library class to do the validation instead.

If you want to do validation and DNS lookup together, then InetAddress.getByName(String) is a good choice. This will cope with DNS, IPv4 and IPv6 in one go, and it returns you a neatly wrapped InetAddress instance that contains both the DNS name (if provided) and the IPv4 or IPv6 address.

If you just want to do a syntactic validation, then Apache commons has a couple of classes that should do the job: DomainValidator and InetAddressValidator.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Sadly it throws an exception merely because a host does not exist, not just when the host is invalid. – Hakanai Mar 27 '15 at 04:34
  • @Trejkaz - what "it" are you talking about? Did you try the alternative approach too? – Stephen C Mar 27 '15 at 07:34
  • @StephenC yeah, my bad, I meant getByName() in particular. For DomainValidator, you can immediately see from the Javadoc that it won't work in general, because they're restricting the list of top-level domains, which is something people surely realised was a bad idea back when .eu, .asia and so forth were added and all their validation stopped working. – Hakanai Mar 29 '15 at 07:17
  • Well, yes, any TLD validator (like Apache `DomainValidator`) that uses a static table of TLDs is liable to get out of date. However, that API does allow you to supply a more up to date table; see the `updateTLDOverride` method. – Stephen C Aug 06 '20 at 10:30
5

Guava has a new class HostSpecifier. It will even validate that the host name (if it is a host name) ends in a valid "public suffix" (e.g., ".com", ".co.uk", etc.), based on the latest mozilla public suffix list. That's something you would NOT want to attempt with a hand-crafted regex!

Kevin Bourrillion
  • 40,336
  • 12
  • 74
  • 87
  • 1
    I wouldn't want to trust code which has taken a snapshot of the "latest" public suffix list either, because a couple of months later it won't be the latest one. – Hakanai Mar 29 '15 at 07:19
4

As others have said, doing this with a regex is quite a challenge and not advisable. But it is easy to do with the IPAddress Java library which can parse host names, IPv4 and IPv6 addresses, without triggering DNS lookup. Disclaimer: I am the project manager of that library.

Sample code:

check("1.2.3.4");
check("::1");
check("a.b.com");

static void check(String hostStr) {
    HostName host = new HostName(hostStr);
    try {
        host.validate(); // triggers exception for invalid
        if(host.isAddress()) {
            IPAddress address = host.asAddress();
            System.out.println(address.getIPVersion() + " address: " + address);
        } else {
            System.out.println("host name: " + host);
        }
    } catch(HostNameException e) {
        System.out.println(e.getMessage());
    }
}

Output:

IPv4 address: 1.2.3.4
IPv6 address: ::1
host name: a.b.com
Sean F
  • 4,344
  • 16
  • 30
  • what if the hostname is not reachable from current network / protected by firewall etc? Would it throw HostNameException? – andrestascon Feb 10 '23 at 14:35
  • No, it doesn't check if a host name is reachable, or if it is used, it checks whether the string could potentially be a host name, whether it has a valid host name format. It checks whether it is a valid host name. – Sean F Feb 12 '23 at 04:02
1

Inspired by the code I found in this post, I created the following validator method that seems to suit simple validation needs quite nicely. By reading the JavaDoc of URI I removed some false positives such as "host:80" and "hostname/page", but I cannot guarantee there are some false positives left.

public static boolean isValidHostNameSyntax(String candidateHost) {
    if (candidateHost.contains("/")) {
        return false;
    }
    try {
        // WORKAROUND: add any scheme and port to make the resulting URI valid
        return new URI("my://userinfo@" + candidateHost + ":80").getHost() != null;
    } catch (URISyntaxException e) {
        return false;
    }
}
Community
  • 1
  • 1
Henno Vermeulen
  • 1,495
  • 2
  • 15
  • 25
0

You can also do this. Let's say:

public boolean isHostnameValid(String hostname) {
    try {
        InetAddress.getAllByName(hostname); // throws an error when the hostnme could not be found, if so, then return false
        return true;
    } catch(Exception exc) {
        return false;
    }
}