For example if I have the following SRV record defined in my DNS config
_dev._tcp IN SRV 0 0 8400 dev.server.com.
I can execute the following command
host -lt SRV server.com
And it gives me complete list of SRV records in the dns server(server.com). If I want to do the same thing using JNDI lookup
Hashtable<String, String> env = new Hashtable<String, String>();
env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
DirContext ctx = new InitialDirContext(env);
Attributes attributes = ctx.getAttributes("server.com", new String [] { "SRV" });
return attributes;
The above code is not returning any attributes. If I change the penultimate line in the above code to this,
Attributes attributes = ctx.getAttributes("_dev._tcp.server.com", new String [] { "SRV" });
it works.
But the problem is I don't know the complete domain name in prior and I have to lookup the SRV record to find the complete domain name.
Any ideas as how to do this?
The -l parameter to /usr/bin/host instructs a DNS zone transfer. Unlike a conventional DNS query, zone transfers work over TCP.
Here's what host -lt SRV server.com does:
Finds out the name servers of server.com.
Connects to the first listed name server's port 53 with TCP.
Initiates a zone transfer.
Filters out the results in accordance to its -t srv filter.
You need to initiate a zone transfer via JNDI and filter out the results for what you are looking for. The method to invoke a DNS zone transfer in DnsContext is list().
NamingEnumeration<NameClassPair> names = ctx.list("server.com");
IMHO, JNDI has a terrible interface. It is designed to be very generic to be all naming and directory services and both mechanical and technical mismatch between the interface and DNS is simply frustrating.
If you are looking for a more pragmatic, easier to use and full features DNS library, have a look at dnsjava project at http://www.dnsjava.org
Also keep in mind not every DNS server allows zone transfers from untrusted hosts. Even LAN DNS servers won't allow zone transfers by default nowadays.
Related
For an app I'm writing I want to completely avoid DNS host name resolution: I'm using numeric IPv4 and IPv6 addresses and I have no use for lookups. I've googled a bit but I can't find a class that allows me to open a connection without causing a DNS request to occur. Any hints?
TIA
If you invoke InetAddress.getByName() with a name that's not really a name, but is an IP address, Java won't perform the DNS lookup.
Another option is to use InetAddress.getByAddress() like so:
byte[] numericAddress = new byte[]{127,0,0,1};
InetAddress.getByAddress(numericAddress); //Will return an InetAddress that points to 127.0.0.1
Is there a way to listen to DNS changes using Java? I'm looking to update an external system with DNS changes as they happen.
Existing solution is to listen to bind.log for changes.
Monitoring a DNS server for changes over the internet requires that you are granted DNS zone transfer access (AXFR/IXFR). Once you have zone transfer access, you can pull a copy of the DNS data held by the server, but without such permission your options are rather limited. For instance, you can poll the server for RR changes for known names, but you can't possibly detect new names using just public DNS access.
Another alternative is to use a passive DNS data provider, but the coverage these provide may be limited and the service might be expensive. At least one of the major providers of passive DNS data works by tapping into DNS traffic, so they see new names and changes as they appear in DNS traffic.
This is similar to this question: Resolving ip-address of a hostname
To resolve a host in Java:
InetAddress address = InetAddress.getByName("www.example.com");
Now you could run this on a separate Thread and listen for the change:
public void launchThread()
{
Thread thread = new Thread(new Runnable()
{
InetAddress start = InetAddress.getByName("www.example.com");
while(start.equals(InetAddress.getByName("www.example.com")))
{
try
{
Thread.sleep(1000);
}catch(Exception e){e.printStackTrace();}
}
System.out.println("Domain resolution has changed.");
})
}
This is my first question at Stack Overflow, so feel free to tell me if I do something wrong :)
I'm working on a project involving EJB and JBoss 4.2.3.GA. In a point, we try to access every node of the cluster, locating an EJB and returning it.
This is the piece of code that does the JNDI lookup:
public static <I> I getCache(Class<I> i, String clusterNode) {
ServiceLocator serviceLocator = ServiceLocator.getInstance();
String jndi = serviceLocator.getRemoteJNDIName(i);
Properties props = new Properties();
props.setProperty(Context.PROVIDER_URL, "jnp://" + clusterNode + ":"
+ jndiPort);
props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming");
props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
Object result = null;
try {
InitialContext ctx = new InitialContext(props);
result = ctx.lookup(jndi);
} catch (NamingException e) {
return null;
}
return (I) result;
}
Here:
clusterNode is a simple string with the IP address or the dns name of the node. E.g: "192.168.2.65" or "cluster1".
getRemoteJNDIName returns an String such as this: "MyEARName/MyEJBName/remote"
The problem is that when I call this method with, for example, "127.0.0.1" it works fine. Also, if I call it with an existing and working IP address where a server is up and running, it's OK too.
However if I call the method with a non-existing or non-working address or dns name, instead of throwing the NamingException, it returns the EJB in my own machine. Therefore, I don't know wether the node is up or not.
I guess there may be better ways to do it. I'd like to hear about them, but we cannot make "big" changes to the product due to it being in production for a few years by now.
That's it. Thank you in anticipation and best regards.
However if I call the method with a non-existing or non-working
address or dns name, instead of throwing the NamingException, it
returns the EJB in my own machine
I think this behavior can be explained if you have automatic naming discovery. When the Contex.PROVIDER_URL is not specified or the nodes in the list are not reachable (which is your case) the client is allowed to search in the network for available JNDI services.
However this only works under certain conditions, some of them:all clusters node running in ALL mode, all nodes located in the same subnet.
You can disable this behavior setting the InitialContext property jnp.disableDiscovery=true.
I guess there may be better ways to do it
According to the code, you are not catching the object polled from the JNDI, this implies that every time you need to execute a service, a new lookup (wich is a time consuming operation) has to be done. The ServiceLocator pattern suggests caching the lookup result for improving performance.
Here's the method-
public static String getHostByAddr(byte[] addr) throws UnknownHostException {
Name name = ReverseMap.fromAddress(InetAddress.getByAddress(addr));
final String[] servers = new String[] {"208.67.220.220", "208.67.222.222"};
final Resolver res = new ExtendedResolver(servers);
final Lookup lookUp = new Lookup(name, Type.PTR);
lookUp.setResolver(res);
Record[] records = lookUp.run();
if (records == null) {
throw new UnknownHostException();
}
return ((PTRRecord) records[0]).getTarget().toString();
}
And here's the call to the above method-
final InetAddress ip = InetAddress.getByName("198.154.218.168");
final byte[] bytes = ip.getAddress();
final String host = getHostByAddr(bytes);
System.out.println("Host - " + host);
Works fine for most of the cases, but fails when the IP is mapped to multiple domains (???)
Here's the example-
Get IP of securonix.com from here, it is 198.154.218.168
If I pass this IP to the above method it gives error
But if I try the same IP here, it lists down the 4 domains
Is it possible to do this with DNSJava?
In general, you can't. Just as the owner of the domain securonix.com created an entry on their DNS server that translates securonix.com to 198.154.218.168, the owner of the IP address 198.154.218.168 maintains a "reverse" DNS record (usually on a separate server) that maps the IP address to a default DNS name. See the page for "Reverse DNS lookup" on wikipedia for more information on reverse DNS lookups, and note that the reverse DNS lookup -- from IP address to name -- is often maintained by a different owner than the domain name owner and it is NOT just created "automatically" by swapping the name and IP address.
Furthermore, the site you mention doesn't seem to have reverse DNS entries for that IP address, so you won't ever get an answer for 198.154.218.168 from a standard DNS query; there simply is no (reverse) DNS entry for 198.154.218.168 and the code above fails.
As an example of the difference between the forward and reverse DNS lookups, when I was first allocated my static IP address, my provider (Comcast) mapped the IP address to some generic name like 75-148-###-###-Houston.hfc.comcastbusiness.net (random IP address example) and I had ask them to modify the reverse DNS entry to map to the name of my domain instead so that a forward and reverse lookup of the IP address and domain name matched. They maintained the lookup of the IP address on their DNS servers, and I maintained the lookup of the domain name on my DNS servers.
The page at yougetsignal.com must have been doing DNS (forward) lookups of names and storing them in the huge database available for purchase, which allows the web page to find all the names with the same IP. But there is no easy way to do that for an arbitrary IP address by querying DNS servers, unless you have considerable additional information or have already done the millions of lookups like that site.
I found that there are two websites providing this functionality. However I don't know how they implement that functionality.
http://reverseip.domaintools.com/
http://ipaddress.com/reverse_ip/
update:
domaintools provide api calls. maybe you can call domaintools api to get multiple domain names for the single IP.
I am trying to learn Cassandra and have setup a 4 node Cassandra cluster. I have written a client in Java using Hector, which currently connects to a hard coded single node in the cluster. Ideally, I would like my client to connect to the "cluster" rather then a specific node....so if any of the 4 nodes are down, the client will still connect to something. From the client application perspective how does this work exactly? I can't seem to find a good explanation.
My Hector connection string currently, I need to specify a specific node here:
Cluster c = getOrCreateCluster("Test Cluster", cassandraNode1:9160);
My Cassandra nodes are all configured with my rpc_address: 0.0.0.0
If you pass a CassandraHostConfigurator to getOrCreateCluster(), you can specify multiple nodes as a comma-separated string:
public CassandraHostConfigurator(String hosts) {
this.hosts = hosts;
}
...
String[] hostVals = hosts.split(",");
CassandraHost[] cassandraHosts = new CassandraHost[hostVals.length];
...
You can also toggle CassandraHostConfigurator#setAutoDiscoverHosts and #setUseAutoDiscoverAtStartup to use your initial host(s) to automatically add all hosts found on via the Thrift API method describe_keyspaces. This makes configuration a little bit easier in that you only need to reference a single host.
Keeping autoDiscover enabled (it is off by default) makes it a bit easier to scale out as new nodes will be added as they are discovered. The ability to add nodes is also available via JMX as well so adding nodes can be done manually at any time, though you would have to do it once per Hector instance.