As part of an app I'm developing, I need to be able to resolve the correct IP that corresponds with a Bonjour hostname.
For example, I'm given jack.local and need to resolve it to 192.168.1.141 which is the IP address associated with jack.
I've been combing through the JmDNS APIs and the most I can find are methods that allow resolving a Service if the type and name are known. However, I simply cannot find anything that would allow resolving a hostname.
So am I missing something? Is there really no way to resolve a hostname using JmDNS?
If you need to find out remote hostname in LAN from IP address using JmDNS you can use the following code. If you need to map from hostname to IP then you can resolve hostnames for all your subnet IPs to build a cache. If your native name resolution supports local Bonjour names you can just use InetAddress.getByName(hostname).getHostAddress().
final JmDNSImpl jmdns = new JmDNSImpl(null, null);
final HostInfo hostInfo = HostInfo.newHostInfo(InetAddress.getByName("192.168.1.78"), jmdns, null);
System.out.println("MDNS hostname (Bonjour): " + hostInfo.getName());
System.out.println("DNS hostname: " + hostInfo.getInetAddress().getHostName());
System.out.println("IP address: " + hostInfo.getInetAddress().getHostAddress());
jmdns.close();
With jmdns you listen to services. To subscribe use the functions
jmdns = JmDNS.create();
jmdns.addServiceListener(String type, ServiceListener listener);
Once jmdns finds a service the ServiceListener gets notified. The listener has three public functions:
serviceResolved(ServiceEvent event)
serviceRemoved(ServiceEvent event)
serviceAdded(ServiceEvent event)
with everyone you get the ServiceEvent. Now call event.getInfo().getHostAddresses() to get an array of all addresses of the Host.
If you want to resolve the service you have to call
jmdns.requestServiceInfo(event.getType(), event.getName(), 1);
in the serviceAdded method.
Have a look at :Quick Tutorial
Related
I am working with JMDNS 3.5.4. My PC as well as other PCs are in multiple networks. I was wondering how to define the host-address (IP-address) which is broadcasted within the service.
I tried to select an address using "InetAddress.getAllByName(host)" and use this address in the create function. However, this address is simply ignored in the ServiceInfo object.
JmDNS jmdns = JmDNS.create(INETADDRESS);
// Register a service
ServiceInfo serviceInfo = ServiceInfo.create("_http._tcp.local.", "example", 1234, "path=index.html");
jmdns.registerService(serviceInfo);
Later, the clients which find the service will use its port and IP-address to call a REST-service.
It seems like the DNS cache was the problem - I deleted it.
I will evaluate my suspicion and update this post...
Running Wildfly as Azure App Service was possible via a custom java app [https://azure.microsoft.com/en-us/documentation/articles/web-sites-java-custom-upload/]. However, app service nodes don't know the internal IP address while registering with JGroups. They always expose 127.0.0.1. In order to make JGroups cluster members communicate, we need a well known IP address of the node.
How can Wildfly determine the internal IP address of the host that it can use to register with JGroups cluster?
Per my experience, I think you can try to use Azure SDK for Java to get the internal IP address of the host from the WebSiteManagementClient.
Here is a sample code below for getting the internal IP address.
String userName = "<user-name>";
String password = "<password>";
String resourceGroupName = "<resource-group-name>";
String name = "<webapp-name>";
ServiceClientCredentials credentials = new BasicAuthenticationCredentials(userName, password);
WebSiteManagementClient webSiteManagementClient = new WebSiteManagementClientImpl(credentials);
HostingEnvironmentsOperations hostingEnvironmentsOperations = webSiteManagementClient.getHostingEnvironmentsOperations();
ServiceResponse<AddressResponse> serviceResponse = hostingEnvironmentsOperations.getHostingEnvironmentVips(resourceGroupName, name);
AddressResponse addressResponse = (AddressResponse) serviceResponse.getBody();
String internalIp = addressResponse.getInternalIpAddress();
To run the above sample, you need to add the dependent libraries into your Maven project, please see the dependencies below.
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-svc-mgmt-websites</artifactId>
<version>0.9.2</version>
</dependency>
More details for the key classes in the above sample code, please see below.
WebSiteManagementClient & WebSiteManagementClientImpl
HostingEnvironmentsOperations
AddressResponse
You could use a special keyword for the bind_addr, see [1] for details. E.g. bind_addr=match-address:192.168.1.* to try to pick an IP address on a given subnet.
[1] http://www.jgroups.org/manual/index.html#Transport
You could use Peter's code (above) to detect the available IP addresses, then set bind_addr in JGroups, e.g. like this:
InetAddress bind_addr; // detect address by using Azure's SDK
JChannel ch=new JChannel("config.xml");
TP transport=ch.getProtocolStack().getTransport();
transport.setBindAddress(bind_addr);
ch.connect("mycluster");
The important thing is that you need to set the bind address before connecting the channel.
I have two computers plugged in the same router of a network which I know supports IPv6. Let's call them "PC-A" and "PC-B
I want "PC-A" to figure out "PC-B"s IPv6 address and vice-versa
The first thing I do is
setSystem.setProperty("java.net.preferIPv6Addresses", "true");
If I then say
InetAddress IPAddress = InetAddress.getLocalHost();
I can get my own address which will be in IpV6 format
However, neither of the following two statements gives me "PC-B"s IPv6 address:
Inet6Address IPAddress6 = (Inet6Address)InetAddress.getByName("PC-B");
InetAddress IPAddress = InetAddress.getByName("PC-B");
I also tried to import
import com.lavantech.net.dns.SimpleDNSLookup;
import com.lavantech.net.dns.DNSLookup
The first one I am using as:
SimpleDNSLookup d = new SimpleDNSLookup();
System.out.println(d.getInet6Address("PC-B"));
and the second one as:
DNSLookup dnsLookup = new DNSLookup("PC-B", DNSLookup.QTYPE_AAAA, DNSLookup.QCLASS_IN, 3000, null);
// Get all Address Records.
ResourceRecord[] ansRecords = dnsLookup.getAAAARecords();
System.out.println(ansRecords[0]);
none of which works.
I also tried to use the following
import org.xbill.DNS.*;
int type = Type.AAAA;
Name name = Name.fromString("PC-B");
Lookup lookup = new Lookup(name, type);
lookup.run();
int result = lookup.getResult();
Record[] answers = lookup.getAnswers();
System.out.println(answers[0]);
// (where, for brevity, i am skipping the parts where I check whether result == Lookup.SUCCESSFUL
Note that if I substitute "PC-B" for, say, "ipv6.google.com" I get all the desired results!
Also note that if I just use InetAddress and Type_A wherever applicable in the above approaches, my program returns "PC-B"s IPv4 address without problem.
What am I missing?
Any help is greatly appreciated!
Your question is -unfortunately- a yet unsolved network problem dealing with host discovery on a local subnet (regardless if that subnet has a router or not).
Your desired output is clearly an IPv6 address, but it is unclear what exactly your input is.
Let's focus on PC-B. How exactly do you identify PC-B? It clear that you call it "PC-B", but that name should be configured somewhere before your PC know that that's its name. Where exactly is that configured? Is that the hostname you set on PC-B itself, or is there a domain name server (DNS) where you have given that name? If it is the name in the DNS system, you can indeed query the DNS system for the AAAA record to get the IPv6 address, but you need the fully qualified domain name (FQDN). E.g. "PC-B.yourdomain.com" rather than just "PC-B".
If you know the MAC address of PC-B, you can use the neighbour discovery protocol (NDP) to find out the IP address of PC-B.
There are network protocols that allow PC-A and PC-B to announce their names themselves, once you configured them on the local machines. Such protocols are called "service discovery" protocols, and your options here are (1) multicast DNS (mDNS) and possibly DNS service discovery (DNS-SD) on top of that; or (2) Simple Service Discovery Protocol (SSDP) in UPnP on the other hand. The advantage is that some operating systems already implement this. E.g. if PC-B is a Mac OS X host, all you need to do is query DNS for "pc-b.local" to get the answer. Unfortunately, while implementations of mDNS exist for Linux (Avahi) and Windows (Bonjour), they're not installed by default. A third alternative is to write your own host discovery protocol, and have your hosts run that protocol.
Considerations are which platforms you want to support, if installing third-party software is an option, if the discovery needs to be secure (the above options are not, look into Secure Neighbour Discovery -SEND- if this is a concern), and what input you have in the first place (the hostname "PC-B", or the type of service that runs on PC-B, e.g. _http._tcp for a webserver).
I'm trying to write a simple program using Java that, given an IP in either version 4 or 6 format, will return its FQDN. The following code works fine when given an ipv4 address, but will only return the given address when an ipv6 address is entered.
InetAddress inet;
try { inet = InetAddress.getByName(theIpAddress); }
catch(UnknownHostException e) { System.out.println("Unknown Host"); return; }
System.out.println(inet.getHostAddress(););
System.out.println(inet.getHostName(););
Whenever I enter an ipv6 getHostName() will only return the same ipv6, even when I know that the ipv6 will resolve to a FQDN. Also, if I enter an ipv6 host name, such as ipv6.google.com, in place of theIpAddress, the exception will occur.
I'm new to this stuff so would appreciate any assistance. Thanks.
The problem was actually the version of Java I was running. Updating Java to 1.6.23, from 1.6.21, allowed ipv6s to resolve to their FQDN.
I've done a quick investigation of what's going on with hostname <-> ipv6 resolution in java 8, Windows 7.
Looks like 'default' NameService does not work with ipv6 at all!
But! Java comes with another, JNDI based NameService implementation called 'dns,sun'.
So, if you enable it using either
-Dsun.net.spi.nameservice.provider.1=dns,sun
or
System.setProperty("sun.net.spi.nameservice.provider.1", "dns,sun");
you will get bidirectional ip <-> hostname resolution for v4 and v6 addresses like this
InetAddress.getAllByName(...)
address.getHostName()
More info about java ipv6 you can find here http://docs.oracle.com/javase/8/docs/technotes/guides/net/ipv6_guide/
Try inet.getCanonicalHostName(); which "Gets the fully qualified domain name for this IP address."
If you construct the InetAddress using InetAddress.getByName(), getHostName() will return what you constructed it with. getCanonicalHostName() forces a reverse name lookup.
Using java.net.InetAddress it is not possible to have ipv6 and ipv4 name resolution etc. The bunch of static methods like getByName etc delegate the lookup to instance of Inet4(or 6)AddressImpl that does
public native InetAddress[] lookupAllHostAddr(String hostname) throws UnknownHostException;
Now the fun is a) all these are private/package local so there is not way to inject the impl classes to the InetAddress class b) Inet4(or 6)AddressImpl classes are themselves package local . So there is no way to say , do a ipv4 or ipv6 lookup/name resolution on the fly. I do not get the way all extension points were blocked for these classes making them of really very limited use and flexibility.
The real black-magic happens here , where InetAddress class statically initializes the impls, on what does outcome of method isIPv6Supported() dependent ?? My Linux setup supports ipv6 , i can do dns lookups for ipv6 hostnames like ipv6.google.com.
Will appreciate if anybody can point me to the direction of a good net library in java for ipv4/v6 utilities like lookup etc.
class InetAddressImplFactory {
static InetAddressImpl create() {
Object o;
if (isIPv6Supported()) {
o = InetAddress.loadImpl("Inet6AddressImpl");
} else {
o = InetAddress.loadImpl("Inet4AddressImpl");
}
return (InetAddressImpl)o;
}
static native boolean isIPv6Supported();
}
I set up a static IP and did port forwarding on my notebook, and now I have a static IP address, but it's relatively static, every time I re-start the machine, I get another address, and since I have a "static" IP I can now do Paypal IPN messaging. But how can I get this static IP from my Java program ? One way I can think of is to visit : http://portforward.com/ and on that page it tells me what my external IP is, so I can extract it with Java code, is there any other way that I can do in my Java code to get this info ?
The best solution is probably dynamic DNS. Essentially, you run a program on your computer (or router) that notifies a DNS server when your IP changes. Then, you can just tell PayPal the domain name.
There is a public service you can call with your script to retrieve your external IP address. Bear in mind they have changed the link location once. If you control your own server, you should probably write your own PHP script to simply return the address of the caller to the script.
http://www.whatismyip.com/faq/automation.asp - follow the developers link they provide
import java.net.*;
import java.io.*;
URL myExternalIP = new URL("PUT THE LINK HERE");
BufferedReader in = new BufferedReader(new InputStreamReader(
myExternalIP.openStream()));
String ip = in.readLine(); //you get the IP as a String
System.out.println(ip);
Your own server script is a simple one-liner. Create a file called whatismyip.php and here's the content.
<? echo $_SERVER['REMOTE_ADDR']?>
I see three ways of doing this:
As you discovered, querying an external server what IP you're apparently connecting from. This is simple but you require such a service to be available and, usually, that no transparent proxy messes with your results.
IGD, a sub-protocol of UPnP can give you the result very easily if your port forwarding devices supports it (many do). Google "IGD JAVA" for libraries and samples.
Register for a dynamic DNS service and then lookup your own DNS name.
You can use the NetworkInterface class:
Enumeration<NetworkInterface> ifcs = NetworkInterface.getNetworkInterfaces();
while(ifcs.hasMoreElements()){
NetworkInterface ifc = ifcs.nextElement();
System.out.println("Adresses of: "+ifc.getDisplayName());
Enumeration<InetAddress> adresses = ifc.getInetAddresses();
while(adresses.hasMoreElements()){
System.out.println(adresses.nextElement().getHostAddress());
}
}
This snippet will show you all of the interfaces and the IPs bound to them. You will need to look through the list to find the appropriate interface (see also NetworkInterface.getByName(String name)) And then look at the addresses for that interface. Once you have found the appropriate InetAdress you can use that to get the string or byte representation.