How InetAddress.getLocalHost() works? - java

I'm trying to get how InetAddress.getLocalHost() works. Javadoc says that it retrieves the name of the host from the system and then resolves it into an InetAddress. What exactly does "resolve into InetAddess" mean? Does it simply ask DNS to resolve a hostname?

From InetAddress.java source:
private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
throws UnknownHostException
{
InetAddress[] addresses = null;
boolean success = false;
UnknownHostException ex = null;
// Check whether the host is in the lookupTable.
// 1) If the host isn't in the lookupTable when
// checkLookupTable() is called, checkLookupTable()
// would add the host in the lookupTable and
// return null. So we will do the lookup.
// 2) If the host is in the lookupTable when
// checkLookupTable() is called, the current thread
// would be blocked until the host is removed
// from the lookupTable. Then this thread
// should try to look up the addressCache.
// i) if it found the addresses in the
// addressCache, checkLookupTable() would
// return the addresses.
// ii) if it didn't find the addresses in the
// addressCache for any reason,
// it should add the host in the
// lookupTable and return null so the
// following code would do a lookup itself.
...
if (host.equalsIgnoreCase("localhost")) {
InetAddress[] local = new InetAddress[] { impl.loopbackAddress() }; // {0x7f,0x00,0x00,0x01}
addresses = local;
success = true;
break;
}
To recap:
both InetAddress.getAllByName() and InetAddress.getLocalHost() resolve the address by calling getAddressesFromNameService()
The JVM maintains its own cache of hostname -> IP address mapping.
If the address is not in the cache (lookupTable or addressCache) it will call the operating system's DNS (exact behavior may vary per JVM implementation).
For localhost sepcificly - there is a specific case inside getAddressesFromNameService()

Related

How to implement ping like functionality using pcap4j library

I want to implement basic network check functionality to test if the provided url is responding or not (eg. ping www.google.com).It must provide operational information indicating, for example, that a requested service is not available or that a host could not be reached. I am able to achive it using icmp4j library. But i want to achieve the same using pcap4j library. I want to put the url in text box and click on connect button which will call pcap4j api to check whether the host is responding or not.
You can create ICMPv4 Echo (ping) on Ethernet packets using the Builders of IcmpV4EchoPacket, IcmpV4CommonPacket, IpV4Packet, and EthernetPacket and send them by PcapHandle.sendPacket(). Please refer to org.pcap4j.sample.SendFragmentedEcho in pcap4j-sample project.
You will need to implement ARP to resolve IP addresses to MAC addresses like org.pcap4j.sample.SendArpRequest in pcap4j-sample project.
And you will also need to implement a feature to find the next hop (default gateway or so) from the given IP address somehow. Pcap4J doesn't provide API to support this implementation. (Java doesn't provide API to get routing table...)
You'd maybe better use java.net.InetAddress#isReachable() instead.
It took me more than a year to figure this out, as I wanted to make a traceroute with pcap4j, so here is what I did:
Get your IPv4 Address and Mac Address, this can be easily achieved by querying the PcapNetworkInterface
Get target IP Address, if you have a DNS Name you need to resolve it beforehand.
Get target Mac Address.
Target is in the same subnet: send an ARP Request to resolve the mac (alternatively, a mac broadcast will likely work fine too).
Target is in different subnet: you need to get the mac of your gateway server then, this is not as easy. Assuming you have other network traffic going on, you could listen for incoming packets and get the source mac, where the source IP address is from a different subnet, this is likely the mac address of your gateway server.
Create IcmpV4EchoPacket and sent it
Listen for incoming ICMP traffic, you will get one of these three:
A IcmpV4EchoReplyPacket which is likely to be an answer to your request (check identifier and sequence number to be sure)
A IcmpV4TimeExceededPacket if the target could not be reached with the time-to-live you specified
Nothing, routers and pinged targets are free to ignore and not answer your request
Variables that need to be filled:
short IDENTIFIER; // identifer may be any 16 bit interger
short SEQUENCE; // sequence may be any 16 bit integer
byte TTL; // time to live (1-255)
Inet4Address IP_TARGET; // ip address of your ping target
Inet4Address IP_ORIGIN; // your own ip address
MacAddress MAC_TARGET; // target or gateway mac address
MacAddress MAC_SOURCE; // your own mac address
PcapNetworkInterface PCAP4J_NETWORK_INTERFACE; // network interface used to execute the ping
How to make a ICMP Echo Request Packet (as payload of IcmpV4CommonPacket of IpV4Packet of EthernetPacket):
public Packet buildPacket() {
IcmpV4EchoPacket.Builder icmpV4Echo = new IcmpV4EchoPacket.Builder()
.identifier(IDENTIFIER) // optional, default zero
.sequenceNumber(SEQUENCE); // optional, default zero
IcmpV4CommonPacket.Builder icmpV4Common = new IcmpV4CommonPacket.Builder()
.type(IcmpV4Type.ECHO) // type is echo
.code(IcmpV4Code.NO_CODE) // echo request doesn't need this
.payloadBuilder(icmpV4Echo)
.correctChecksumAtBuild(true);
IpV4Packet.Builder ipv4Builder = new IpV4Packet.Builder()
.correctChecksumAtBuild(true)
.correctLengthAtBuild(true)
.dstAddr(IP_TARGET) // IPv4 Address where tp send the request
.payloadBuilder(icmpV4Common)
.protocol(IpNumber.ICMPV4) // payload is ICMPV4
.srcAddr(IP_ORIGIN) // Your own IPv4 Address
.tos(IpV4Rfc1349Tos.newInstance((byte) 0))
.ttl(TTL) // time to live (1-255)
.version(IpVersion.IPV4); // IP Version is IPv4
EthernetPacket.Builder etherBuilder = new EthernetPacket.Builder()
.dstAddr(MAC_TARGET) // the targets mac address
.srcAddr(MAC_SOURCE) // your own mac address
.type(EtherType.IPV4) // payload protocl is IPv4
.payloadBuilder(ipv4Builder)
.paddingAtBuild(true);
return etherBuilder.build(); // build your packet
}
Listener for ICMP Echo Answers or timeouts:
public PacketListener buildListener() {
return new PacketListener() {
#Override
public void gotPacket(Packet packet) {
if (!(packet instanceof EthernetPacket))
return;
EthernetPacket ethernetPacket = (EthernetPacket) packet;
packet = ethernetPacket.getPayload();
if (!(packet instanceof IpV4Packet))
return;
IpV4Packet ipV4Packet = (IpV4Packet) packet;
IpV4Header ipV4Header = ipV4Packet.getHeader();
packet = ipV4Packet.getPayload();
if (!(packet instanceof IcmpV4CommonPacket))
return;
IcmpV4CommonPacket icmpPacket = (IcmpV4CommonPacket) packet;
packet = icmpPacket.getPayload();
// successful reply just measure time and done
if (packet instanceof IcmpV4EchoReplyPacket) {
IcmpV4EchoReplyPacket icmpV4EchoReplyPacket = (IcmpV4EchoReplyPacket) packet;
IcmpV4EchoReplyHeader icmpV4EchoReplyHeader = icmpV4EchoReplyPacket.getHeader();
if (icmpV4EchoReplyHeader.getIdentifier() != identifier)
return;
if (icmpV4EchoReplyHeader.getSequenceNumber() != sequence)
return;
// here you got an echo reply
System.out.println(packet);
return;
}
// try handle time to live exceeded messages
if (packet instanceof IcmpV4TimeExceededPacket) {
packet = packet.getPayload(); // original IPv4
if (!(packet instanceof IpV4Packet))
return;
packet = packet.getPayload(); // original ICMP common
if (!(packet instanceof IcmpV4CommonPacket))
return;
packet = packet.getPayload(); // original ICMP echo
if (!(packet instanceof IcmpV4EchoPacket))
return;
IcmpV4EchoHeader icmpV4EchoHeader = ((IcmpV4EchoPacket)packet).getHeader();
if (icmpV4EchoHeader.getIdentifier() != IDENTIFIER)
return;
if(icmpV4EchoHeader.getSequenceNumber() != SEQUENCE)
return;
// HERE you got an answer, that the time to live has been used up
System.out.println(packet);
return;
}
};
}
Combining it togther:
public static void main(String[] args) throws IOException, PcapNativeException, NotOpenException, InterruptedException {
try (PcapHandle handle = PCAP4J_NETWORK_INTERFACE.openLive(1024, PromiscuousMode.PROMISCUOUS, 1000)) {
// set filter to only get incoming ICMP traffic
handle.setFilter("icmp and dst host " + Pcaps.toBpfString(IP_ORIGIN), BpfCompileMode.OPTIMIZE);
// send ARP request
Packet p = buildPacket();
handle.sendPacket(p);
// wait (forever) for ARP answer
PacketListener listener = buildListener();
handle.loop(-1, listener);
}
}

RMI and JMX Socket Factories

I'm trying to start an embedded JMX server in my java app. I want to use the same port for the RMI Registry and for the actual RMI traffic (or JMX traffic if you like). Apparently this is possible since the RMI Registry is merely a Remote Object itself.
The added difficulty is that I need to use Socket Factories because I need to bind to a specific NIC.
I start off by:
int registryPort = 3012;
int jmxPort = 3012; // use the same port
and here's my server socket factory. Pretty straight-forward stuff:
public class MyRMIServerSocketFactory implements RMIServerSocketFactory {
private final InetAddress inetAddress;
public MyRMIServerSocketFactory(InetAddress inetAddress) {
this.inetAddress = inetAddress;
}
#Override
public ServerSocket createServerSocket(int port) throws IOException {
return new ServerSocket(port, 0, inetAddress);
}
#Override
public int hashCode() {
int hash = 5;
hash = 97 * hash + (this.inetAddress != null ? this.inetAddress.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final FlexibleRMIServerSocketFactory other = (FlexibleRMIServerSocketFactory) obj;
if (this.inetAddress != other.inetAddress && (this.inetAddress == null || !this.inetAddress.equals(other.inetAddress))) {
return false;
}
return true;
}
}
(the equals() and hashCode() are auto-generated by my IDE, don't get stuck on them)
I create the RMI Registry like this:
serverSocketFactory = new MyRMIServerSocketFactory(inetAddressBind);
LocateRegistry.createRegistry(
registryPort,
RMISocketFactory.getDefaultSocketFactory(), // client socket factory
serverSocketFactory // server socket factory
);
and then on to creating the JMXConnectorServer:
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi://localhost:" + jmxPort +
"/jndi/rmi://:" + registryPort + "/jmxrmi");
Map env = new HashMap();
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverSocketFactory);
connector = JMXConnectorServerFactory.newJMXConnectorServer(
url,
env,
ManagementFactory.getPlatformMBeanServer());
connector.start();
This results in a bind error on the connector.start() saying that the address is already in use.
If I skip using Socket Factories altogether:
LocateRegistry.createRegistry(registryPort);
and
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi://localhost:" + jmxPort +
"/jndi/rmi://:" + registryPort + "/jmxrmi");
connector = JMXConnectorServerFactory.newJMXConnectorServer(
url,
null,
ManagementFactory.getPlatformMBeanServer());
connector.start();
it works as expected, i.e. only a single port will be opened and no errors.
Question: How to make the 'single-listening-port-scenario' work with Socket Factories ?
UPDATE - FINAL SOLUTION
It works if you create the Registry with a null client socket factory, i.e.
LocateRegistry.createRegistry(
registryPort,
null, // client socket factory (let it default to whatever RMI lib wants)
serverSocketFactory // server socket factory
);
I also had to set the java.rmi.server.hostname System Property which I guess will often be the case in a scenario like mine.
This should work: you have a correct-looking equals() method in your ServerSocketFactory, which is the important bit. RMI does call that. However the same doesn't apply currently to your client socket factory. You need to pass null as the client socket factory, not RMISocketFactory.getDefaultSocketFactory(), as that gives you a sun.rmi.transport.proxy.RMIMasterSocketFactory, which doesn't implement equals() for some reason. Or else your own implementation of RMIClientSocketFactory with a plausible equals() method.
So what is happening here is that RMI is comparing the CSFs first, and they are coming out unequal, so it doesn't even bother comparing the SSFs:
csf1.equals(csf2) && ssf1.equals(ssf2)
so it tries to create a new ServerSocket on the port you specifed, which is the same as the first port, so it fails.
You could add a shortcut at the beginning of equals that returns true if this == that.
You should search for the JMXMP protocol, and for the jmxremote_optional.jar that contains it. This is a more controllable, more efficient protocol for JMX.

How to learn system (Windows) non-proxy hosts in Java

I'm writting a Java (1.7) application to be running on Windows. The application is accessing additional services running on the same host and other ones running in the Internet. The application can be run in two environments where in one, proxy settings must be specified (there is proxy when accessing the Internet); while in the other environment, the proxy settings must not be specified (there is no proxy).
I want the application to be simple and don't want its users bother with specification of the proxy settings on cmd-line (-Dhttp.proxyHost, etc.) - the application should learn the proxy settings from Windows system settings (IE / Tools / Internet Properties / Connections / LAN Settings).
I have written a piece of code that is supposed to learn that settings, see below. The trouble is that this piece of code does not identify localhost, 127.0.0.1 and my-computer-name (where my-computer-name is the name of my computer) as URLs where proxy should be by-passed when being accessed (yes, I do have 'Bypass proxy server for local addresses' checked). As a result, the application tries to access local services through the proxy which is wrong.
So far I've found out that one way to teach JVM not to use proxy for 'local addresses' is to list the strings (localhost, 127.0.0.1, my-computer-name) in Proxy Settings / Exceptions (Do not use proxy server for addresses beginning with). Obviously, this is not a good solution as usually no one is listing these strings there (the first check-box is enough for non-Java applications).
Second (trivial) solution would be just to count with these strings in my piece of code and do not use proxy settings for them even when JVM thinks otherwise. I don't think this is a good solution and if this is the only solution, IMHO, there is a defect in JVM.
I've found many resources in the Internet how to learn System proxy settings. But how to learn the non-proxy settings?
Thanks,
PP
public static final String HTTP_PROXY_HOST_KEY = "http.proxyHost";
public static final String HTTPS_PROXY_HOST_KEY = "https.proxyHost";
public static final String HTTP_PROXY_PORT_KEY = "http.proxyPort";
public static final String HTTPS_PROXY_PORT_KEY = "https.proxyPort";
public static final String NO_PROXY_HOSTS_KEY = "http.nonProxyHosts";
// provide list of urls which are to be accessed by this application and return proxy and non-proxy settings
private Properties getSystemProxyConfiguration(String[] urls) {
log.debug("Getting system proxy");
Properties properties = new Properties();
SortedSet<String> nonProxyHosts = new TreeSet<>();
for (String url : urls) {
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new IllegalStateException(e);
}
InetSocketAddress address = getSystemProxy(uri);
if (address != null) {
if (url.toLowerCase().startsWith("https")) {
properties.put(HTTPS_PROXY_HOST_KEY, address.getHostString());
properties.put(HTTPS_PROXY_PORT_KEY, ""+address.getPort());
//todo verify that all previous URLs in this array are using the same proxy
log.debug("HTTPS proxy: " + address.getHostString() + ":" + address.getPort());
} else {
properties.put(HTTP_PROXY_HOST_KEY, address.getHostString());
properties.put(HTTP_PROXY_PORT_KEY, ""+address.getPort());
//todo verify that all previous URLs in this array are using the same proxy
log.debug("HTTP proxy: " + address.getHostString() + ":" + address.getPort());
}
} else { //todo DEFECT -> this does not find the non-proxy hosts (even though specified in IE Internet settings)
nonProxyHosts.add(uri.getHost());
}
}
if (nonProxyHosts.size() > 0) {
String nonProxyHostsString = nonProxyHosts.first();
nonProxyHosts.remove(nonProxyHostsString);
for (String nonProxyHost : nonProxyHosts) {
nonProxyHostsString = nonProxyHostsString + "|" + nonProxyHost;
}
properties.put(NO_PROXY_HOSTS_KEY, nonProxyHostsString);
log.debug("Non HTTP(S) proxy hosts: "+nonProxyHostsString);
} else {
log.debug("No non HTTP(S) proxy hosts set");
}
return properties;
}
private InetSocketAddress getSystemProxy(URI uri) {
List<Proxy> proxyList;
proxyList = ProxySelector.getDefault().select(uri);
if (proxyList != null && proxyList.size() > 0) { //todo DEFECT - this never returns DIRECT proxy for localhost, 127.0.0.1, my-computer-name strings
Proxy proxy = proxyList.get(0);
if (proxyList.size() > 1) {
log.warn("There is more " + proxy.type() + " proxies available. Use "+PROXY_PROPERTIES_FILE_NAME+" to set the right one.");
}
InetSocketAddress address = (InetSocketAddress) proxy.address();
return address;
}
return null;
}

Identify server on Tomcat (HttpServletRequest.getLocalAddr() fails)

With Tomcat setup behind Apache, how can an id (IP address ideally) of the server be easily determined?
The specific situation is that multiple servers are setup behind a load balancer, thus the incoming request host name is non-unique and insufficient to identify a particular server for logging purposes. Using HttpServletRequest.getLocalAddr() is unfortunately returning the same hostname instead of the IP address as would be expected (I am assuming this is related to this very old issue here: https://issues.apache.org/bugzilla/show_bug.cgi?id=46082).
Is there a way to make getLocalAddr() perform as documented, or are other methods required to query the IP address of the server?
On our project, we use JMX to get all the config information.
It takes a few steps, because it is like navigating down the server.xml file
This link has some info: http://oss.wxnet.org/mbeans.html
It is probably overkill if all you want is the IP, but I thought I'd throw it out there.
MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> theConnectors = mbeanServer.queryNames(
new ObjectName("Catalina:type=Connector,*"),
null);
if (theConnectors != null)
{
for (ObjectName nextConnectorName : theConnectors)
{
InetAddress theInetAddress = (InetAddress) mbeanServer.getAttribute(
nextConnectorName,
"address");
if (theInetAddress != null)
{
ipAddress = theInetAddress.getHostAddress();
}
if (!StringUtil.isEmpty(ipAddress))
{
// found the IP address
break;
}
}
}
For my situation, the solution was to get the IP address of the server directly instead of attempting to get the local address via HttpServleRequest.
I cached the IP for use in my filter via:
private static final String serverIp;
static {
String addressString = null;
try
{
InetAddress address = InetAddress.getLocalHost();
addressString = address.getHostAddress();
} catch (Exception e)
{
logger.error("Exception while attempting to determine local ip address",e);
}
if (addressString != null) serverIp = addressString;
else serverIp = "unknown";
}
I had a similar issue recently (a few years after the original question) and found this question and answers. The issue in my case was that the ServletRequest#getLocalAddr() implementation was returning the remote address instead of the local address. The issue was caused by a regression in Tomcat v9.0.22. It was fixed in v9.0.23. See the question and answer here:
https://stackoverflow.com/a/57725039/9602527

Java: Common way to validate and convert "host:port" to InetSocketAddress?

What is the common way in Java to validate and convert a string of the form host:port into an instance of InetSocketAddress?
It would be nice if following criteria were met:
No address lookups;
Working for IPv4, IPv6, and "string" hostnames;
(For IPv4 it's ip:port, for IPv6 it's [ip]:port, right? Is there some RFC which defines all these schemes?)
Preferable without parsing the string by hand.
(I'm thinking about all those special cases, when someone think he knows all valid forms of socket addresses, but forgets about "that special case" which leads to unexpected results.)
I myself propose one possible workaround solution.
Convert a string into URI (this would validate it automatically) and then query the URI's host and port components.
Sadly, an URI with a host component MUST have a scheme. This is why this solution is "not perfect".
String string = ... // some string which has to be validated
try {
// WORKAROUND: add any scheme to make the resulting URI valid.
URI uri = new URI("my://" + string); // may throw URISyntaxException
String host = uri.getHost();
int port = uri.getPort();
if (uri.getHost() == null || uri.getPort() == -1) {
throw new URISyntaxException(uri.toString(),
"URI must have host and port parts");
}
// here, additional checks can be performed, such as
// presence of path, query, fragment, ...
// validation succeeded
return new InetSocketAddress (host, port);
} catch (URISyntaxException ex) {
// validation failed
}
This solution needs no custom string parsing, works with IPv4 (1.1.1.1:123), IPv6 ([::0]:123) and host names (my.host.com:123).
Accidentally, this solution is well suited for my scenario. I was going to use URI schemes anyway.
A regex will do this quite neatly:
Pattern p = Pattern.compile("^\\s*(.*?):(\\d+)\\s*$");
Matcher m = p.matcher("127.0.0.1:8080");
if (m.matches()) {
String host = m.group(1);
int port = Integer.parseInt(m.group(2));
}
You can this in many ways such as making the port optional or doing some validation on the host.
It doesn't answer the question exactly, but this answer could still be useful others like me who just want to parse a host and port, but not necessarily a full InetAddress. Guava has a HostAndPort class with a parseString method.
Another person has given a regex answer which is what I was doing to do when originally asking the question about hosts. I will still do because it's an example of a regex that is slightly more advanced and can help determine what kind of address you are dealing with.
String ipPattern = "(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}):(\\d+)";
String ipV6Pattern = "\\[([a-zA-Z0-9:]+)\\]:(\\d+)";
String hostPattern = "([\\w\\.\\-]+):(\\d+)"; // note will allow _ in host name
Pattern p = Pattern.compile( ipPattern + "|" + ipV6Pattern + "|" + hostPattern );
Matcher m = p.matcher( someString );
if( m.matches() ) {
if( m.group(1) != null ) {
// group(1) IP address, group(2) is port
} else if( m.group(3) != null ) {
// group(3) is IPv6 address, group(4) is port
} else if( m.group(5) != null ) {
// group(5) is hostname, group(6) is port
} else {
// Not a valid address
}
}
Modifying so that port is optional is pretty straight forward. Wrap the ":(\d+)" as "(?::(\d+))?" and then check for null for group(2), etc.
Edit: I'll note that there's no "common way" way that I'm aware of but the above is how I'd do it if I had to.
Also note: the IPv4 case can be removed if the host and IPv4 cases will actually be handled the same. I split them out because sometimes you can avoid an ultimate host look-up if you know you have the IP address.
new InetSocketAddress(
addressString.substring(0, addressString.lastIndexOf(":")),
Integer.parseInt(addressString.substring(addressString.lastIndexOf(":")+1, addressString.length));
? I probably made some little silly mistake. and I'm assuming you just wanted a new InetSocketAddress object out of the String in only that format. host:port
All kind of peculiar hackery, and elegant but unsafe solutions provided elsewhere. Sometimes the inelegant brute-force solution is the way.
public static InetSocketAddress parseInetSocketAddress(String addressAndPort) throws IllegalArgumentException {
int portPosition = addressAndPort.length();
int portNumber = 0;
while (portPosition > 1 && Character.isDigit(addressAndPort.charAt(portPosition-1)))
{
--portPosition;
}
String address;
if (portPosition > 1 && addressAndPort.charAt(portPosition-1) == ':')
{
try {
portNumber = Integer.parseInt(addressAndPort.substring(portPosition));
} catch (NumberFormatException ignored)
{
throw new IllegalArgumentException("Invalid port number.");
}
address = addressAndPort.substring(0,portPosition-1);
} else {
portNumber = 0;
address = addressAndPort;
}
return new InetSocketAddress(address,portNumber);
}
The open-source IPAddress Java library has a HostName class which will do the required parsing. Disclaimer: I am the project manager of the IPAddress library.
It will parse IPv4, IPv6 and string host names with or without ports. It will handle all the various formats of hosts and addresses. BTW, there is no single RFC for this, there are a number of RFCs that apply in different ways.
String hostName = "[a:b:c:d:e:f:a:b]:8080";
String hostName2 = "1.2.3.4:8080";
String hostName3 = "a.com:8080";
try {
HostName host = new HostName(hostName);
host.validate();
InetSocketAddress address = host.asInetSocketAddress();
HostName host2 = new HostName(hostName2);
host2.validate();
InetSocketAddress address2 = host2.asInetSocketAddress();
HostName host3 = new HostName(hostName3);
host3.validate();
InetSocketAddress address3 = host3.asInetSocketAddress();
// use socket address
} catch (HostNameException e) {
String msg = e.getMessage();
// handle improperly formatted host name or address string
}
URI can accomplish this:
URI uri = new URI(null, "example.com:80", null, null, null);
Unfortunately, there's a bug in current OpenJDK (or in the documentation) where the authority isn't properly validated. The documentation states:
The resulting URI string is then parsed as if by invoking the URI(String) constructor and then invoking the parseServerAuthority() method upon the result
That call to parseServerAuthority just doesn't happen unfortunately so the real solution here that properly validates is:
URI uri = new URI(null, "example.com:80", null, null, null).parseServerAuthority();
then
InetSocketAddress address = new InetSocketAddress(uri.getHost(), uri.getPort());

Categories

Resources