286 lines
8.3 KiB
Java
Executable File
286 lines
8.3 KiB
Java
Executable File
package org.handwerkszeug.dns.aaaa;
|
|
|
|
import java.net.InetAddress;
|
|
import java.net.InetSocketAddress;
|
|
import java.text.DateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.regex.Pattern;
|
|
|
|
import org.handwerkszeug.dns.Constants;
|
|
import org.handwerkszeug.dns.DNSClass;
|
|
import org.handwerkszeug.dns.DNSMessage;
|
|
import org.handwerkszeug.dns.Header;
|
|
import org.handwerkszeug.dns.Name;
|
|
import org.handwerkszeug.dns.NameServerContainer;
|
|
import org.handwerkszeug.dns.NameServerContainerProvider;
|
|
import org.handwerkszeug.dns.OpCode;
|
|
import org.handwerkszeug.dns.RRType;
|
|
import org.handwerkszeug.dns.ResourceRecord;
|
|
import org.handwerkszeug.dns.client.WKPortNumbers;
|
|
import org.handwerkszeug.dns.client.WKProtocols;
|
|
import org.handwerkszeug.dns.nls.Messages;
|
|
import org.handwerkszeug.dns.record.WKSRecord;
|
|
import org.handwerkszeug.util.EnumUtil;
|
|
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
|
|
import org.jboss.netty.buffer.ChannelBuffer;
|
|
import org.jboss.netty.buffer.ChannelBuffers;
|
|
import org.jboss.netty.channel.ChannelFactory;
|
|
import org.jboss.netty.channel.ChannelFuture;
|
|
import org.jboss.netty.channel.ChannelHandlerContext;
|
|
import org.jboss.netty.channel.ChannelStateEvent;
|
|
import org.jboss.netty.channel.ExceptionEvent;
|
|
import org.jboss.netty.channel.MessageEvent;
|
|
import org.jboss.netty.channel.SimpleChannelHandler;
|
|
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
|
|
|
|
import werkzeugkasten.common.util.StringUtil;
|
|
|
|
public class DNSClient extends SimpleChannelHandler {
|
|
|
|
protected static final String LINE_SEP = System.getProperty("line.separator");
|
|
protected NameServerContainer container;
|
|
protected WKProtocols wkProtocols = new WKProtocols();
|
|
protected WKPortNumbers wkPortNumbers = new WKPortNumbers();
|
|
|
|
protected List<String> names = new ArrayList<String>();
|
|
|
|
protected DNSClass dnsclass = DNSClass.IN;
|
|
|
|
protected RRType type = RRType.A;
|
|
|
|
protected OpCode opCode = OpCode.QUERY;
|
|
|
|
protected InetSocketAddress serverAddress;
|
|
|
|
protected int serverPort = Constants.DEFAULT_PORT; // default DNS port.
|
|
|
|
protected DNSMessage request;
|
|
|
|
protected long time;
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
DNSClient client = new DNSClient();
|
|
client.initialize();
|
|
client.process(args);
|
|
}
|
|
|
|
protected void initialize() {
|
|
NameServerContainerProvider provider = new NameServerContainerProvider();
|
|
provider.initialize();
|
|
this.container = provider.getContainer();
|
|
this.container.initialize();
|
|
this.wkProtocols.load();
|
|
this.wkPortNumbers.load();
|
|
}
|
|
|
|
protected void process(String[] args) throws Exception {
|
|
parseArgs(args);
|
|
setUpRequest();
|
|
sendRequest();
|
|
}
|
|
|
|
protected void parseArgs(String[] args) throws Exception {
|
|
InetAddress address = null;
|
|
for (int i = 0, length = args.length; i < length; i++) {
|
|
String current = args[i];
|
|
if (current.startsWith("@")) {
|
|
String s = current.substring(1);
|
|
address = InetAddress.getByName(s);
|
|
} else if (current.startsWith("-") && (1 < current.length())) {
|
|
switch (current.charAt(1)) {
|
|
case 'x': {
|
|
this.opCode = OpCode.IQUERY;
|
|
break;
|
|
}
|
|
case 'p': {
|
|
String next = args[++i];
|
|
if (Pattern.matches("\\p{Digit}+", next)) {
|
|
int num = Integer.parseInt(next);
|
|
if ((0 < num) && (num < 0xFFFF)) {
|
|
this.serverPort = num;
|
|
} else {
|
|
System.err.printf(Messages.InvalidPortNumber, num);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
String s = current.toUpperCase();
|
|
DNSClass dc = EnumUtil.find(DNSClass.values(), s, null);
|
|
if (dc != null) {
|
|
this.dnsclass = dc;
|
|
continue;
|
|
}
|
|
RRType t = EnumUtil.find(RRType.values(), s, null);
|
|
if (t != null) {
|
|
this.type = t;
|
|
continue;
|
|
}
|
|
this.names.add(current);
|
|
}
|
|
}
|
|
if (address == null) {
|
|
address = findDNSServer();
|
|
}
|
|
|
|
this.serverAddress = new InetSocketAddress(address, this.serverPort);
|
|
}
|
|
|
|
protected InetAddress findDNSServer() throws Exception {
|
|
List<String> list = this.container.nameservers();
|
|
if (0 < list.size()) {
|
|
String host = list.get(0).toString();
|
|
return InetAddress.getByName(host);
|
|
}
|
|
return InetAddress.getLocalHost();
|
|
}
|
|
|
|
protected void setUpRequest() {
|
|
this.request = new DNSMessage(new Header());
|
|
this.request.header().opcode(this.opCode);
|
|
this.request.header().rd(true);
|
|
for (String s : this.names) {
|
|
String name = s;
|
|
if ((OpCode.IQUERY.equals(this.opCode) == false)
|
|
&& (s.endsWith(".") == false)) {
|
|
name += ".";
|
|
}
|
|
ResourceRecord rr = this.type.newRecord();
|
|
rr.name(new Name(name));
|
|
this.request.question().add(rr);
|
|
}
|
|
}
|
|
|
|
protected void sendRequest() {
|
|
// use UDP/IP
|
|
ChannelFactory factory = new NioDatagramChannelFactory(Executors.newSingleThreadExecutor());
|
|
|
|
try {
|
|
ConnectionlessBootstrap bootstrap = new ConnectionlessBootstrap(factory);
|
|
|
|
bootstrap.getPipeline().addLast("handler", DNSClient.this);
|
|
|
|
bootstrap.setOption("broadcast", "false");
|
|
// bootstrap.setOption("sendBufferSize", 512);
|
|
// bootstrap.setOption("receiveBufferSize", 512);
|
|
|
|
ChannelFuture future = bootstrap.connect(this.serverAddress);
|
|
future.awaitUninterruptibly(30, TimeUnit.SECONDS);
|
|
if (future.isSuccess() == false) {
|
|
future.getCause().printStackTrace();
|
|
}
|
|
future.getChannel().getCloseFuture().awaitUninterruptibly();
|
|
} finally {
|
|
factory.releaseExternalResources();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
|
|
System.out.println("DNSClient#channelConnected");
|
|
System.out.printf("Local %s | Remote %s\n", e.getChannel()
|
|
.getLocalAddress(), e.getChannel().getRemoteAddress());
|
|
ChannelBuffer buffer = ChannelBuffers.buffer(512);
|
|
this.request.write(buffer);
|
|
this.time = System.currentTimeMillis();
|
|
e.getChannel().write(buffer);
|
|
}
|
|
|
|
@Override
|
|
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
|
System.out.println("DNSClient#messageReceived");
|
|
System.out.println(e.getChannel().getLocalAddress() + " | "
|
|
+ e.getChannel().getRemoteAddress());
|
|
this.time = System.currentTimeMillis() - this.time;
|
|
ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
|
|
DNSMessage msg = new DNSMessage(buffer);
|
|
printResult(this.time, msg);
|
|
e.getChannel().close();
|
|
}
|
|
|
|
@Override
|
|
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
|
|
e.getCause().printStackTrace();
|
|
e.getChannel().close();
|
|
}
|
|
|
|
protected String formatMessage(long time, DNSMessage msg) {
|
|
StringBuilder stb = new StringBuilder();
|
|
stb.append(msg.header());
|
|
stb.append(LINE_SEP);
|
|
stb.append(LINE_SEP);
|
|
stb.append(";; QUESTION SECTION:");
|
|
stb.append(LINE_SEP);
|
|
for (ResourceRecord rr : msg.question()) {
|
|
stb.append(';');
|
|
int i = stb.length();
|
|
stb.append(rr.name().toString());
|
|
StringUtil.padRight(stb, ' ', i + 30);
|
|
stb.append(' ');
|
|
stb.append(rr.dnsClass().name());
|
|
stb.append(' ');
|
|
stb.append(rr.type().name());
|
|
stb.append(LINE_SEP);
|
|
}
|
|
|
|
stb.append(LINE_SEP);
|
|
append(stb, ";; ANSWER SECTION:", msg.answer());
|
|
stb.append(LINE_SEP);
|
|
append(stb, ";; AUTHORITY SECTION:", msg.authority());
|
|
stb.append(LINE_SEP);
|
|
append(stb, ";; ADDITIONAL SECTION:", msg.additional());
|
|
stb.append(LINE_SEP);
|
|
|
|
stb.append(";; Query time: ");
|
|
stb.append(time);
|
|
stb.append(" msec");
|
|
stb.append(LINE_SEP);
|
|
stb.append(";; Server: ");
|
|
stb.append(this.serverAddress);
|
|
stb.append(LINE_SEP);
|
|
stb.append(";; When: ");
|
|
stb.append(DateFormat.getDateTimeInstance().format(new Date()));
|
|
stb.append(LINE_SEP);
|
|
stb.append(";; Message size: ");
|
|
stb.append(msg.messageSize());
|
|
stb.append(" bytes");
|
|
stb.append(LINE_SEP);
|
|
return stb.toString();
|
|
}
|
|
|
|
protected void append(StringBuilder stb, String name, List<ResourceRecord> list) {
|
|
stb.append(name);
|
|
stb.append(LINE_SEP);
|
|
if (list != null) {
|
|
for (ResourceRecord rr : list) {
|
|
stb.append(rr.toString());
|
|
if (rr.type().equals(RRType.WKS)) {
|
|
append(stb, (WKSRecord) rr);
|
|
}
|
|
stb.append(LINE_SEP);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void append(StringBuilder stb, WKSRecord record) {
|
|
stb.append(' ');
|
|
stb.append(this.wkProtocols.find(record.protocol()));
|
|
stb.append(' ');
|
|
this.wkPortNumbers.appendServices(record, stb);
|
|
}
|
|
|
|
protected void printResult(long time, DNSMessage msg) {
|
|
System.out.println(formatMessage(time, msg));
|
|
}
|
|
|
|
protected void printHelp() {
|
|
// TODO print help message.
|
|
}
|
|
}
|