1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.example.dns.tcp;
17
18 import io.netty.bootstrap.Bootstrap;
19 import io.netty.bootstrap.ServerBootstrap;
20 import io.netty.buffer.ByteBufUtil;
21 import io.netty.buffer.Unpooled;
22 import io.netty.channel.Channel;
23 import io.netty.channel.ChannelHandlerContext;
24 import io.netty.channel.ChannelInitializer;
25 import io.netty.channel.EventLoopGroup;
26 import io.netty.channel.MultiThreadIoEventLoopGroup;
27 import io.netty.channel.SimpleChannelInboundHandler;
28 import io.netty.channel.nio.NioIoHandler;
29 import io.netty.channel.socket.SocketChannel;
30 import io.netty.channel.socket.nio.NioServerSocketChannel;
31 import io.netty.channel.socket.nio.NioSocketChannel;
32 import io.netty.handler.codec.dns.DefaultDnsQuery;
33 import io.netty.handler.codec.dns.DefaultDnsQuestion;
34 import io.netty.handler.codec.dns.DefaultDnsRawRecord;
35 import io.netty.handler.codec.dns.DefaultDnsResponse;
36 import io.netty.handler.codec.dns.DnsOpCode;
37 import io.netty.handler.codec.dns.DnsQuery;
38 import io.netty.handler.codec.dns.DnsQuestion;
39 import io.netty.handler.codec.dns.DnsRawRecord;
40 import io.netty.handler.codec.dns.DnsRecord;
41 import io.netty.handler.codec.dns.DnsRecordType;
42 import io.netty.handler.codec.dns.DnsSection;
43 import io.netty.handler.codec.dns.TcpDnsQueryDecoder;
44 import io.netty.handler.codec.dns.TcpDnsQueryEncoder;
45 import io.netty.handler.codec.dns.TcpDnsResponseDecoder;
46 import io.netty.handler.codec.dns.TcpDnsResponseEncoder;
47 import io.netty.handler.logging.LogLevel;
48 import io.netty.handler.logging.LoggingHandler;
49 import io.netty.util.NetUtil;
50
51 import java.util.Random;
52 import java.util.concurrent.Executors;
53 import java.util.concurrent.TimeUnit;
54
55 public final class TcpDnsServer {
56 private static final String QUERY_DOMAIN = "www.example.com";
57 private static final int DNS_SERVER_PORT = 53;
58 private static final String DNS_SERVER_HOST = "127.0.0.1";
59 private static final byte[] QUERY_RESULT = new byte[]{(byte) 192, (byte) 168, 1, 1};
60
61 public static void main(String[] args) throws Exception {
62 ServerBootstrap bootstrap = new ServerBootstrap().group(
63 new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory()))
64 .channel(NioServerSocketChannel.class)
65 .handler(new LoggingHandler(LogLevel.INFO))
66 .childHandler(new ChannelInitializer<Channel>() {
67 @Override
68 protected void initChannel(Channel ch) throws Exception {
69 ch.pipeline().addLast(new TcpDnsQueryDecoder(), new TcpDnsResponseEncoder(),
70 new SimpleChannelInboundHandler<DnsQuery>() {
71 @Override
72 protected void channelRead0(ChannelHandlerContext ctx,
73 DnsQuery msg) throws Exception {
74 DnsQuestion question = msg.recordAt(DnsSection.QUESTION);
75 System.out.println("Query domain: " + question);
76
77
78 ctx.writeAndFlush(newResponse(msg, question, 600, QUERY_RESULT));
79 }
80
81 private DefaultDnsResponse newResponse(DnsQuery query,
82 DnsQuestion question,
83 long ttl, byte[]... addresses) {
84 DefaultDnsResponse response = new DefaultDnsResponse(query.id());
85 response.addRecord(DnsSection.QUESTION, question);
86
87 for (byte[] address : addresses) {
88 DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord(
89 question.name(),
90 DnsRecordType.A, ttl, Unpooled.wrappedBuffer(address));
91 response.addRecord(DnsSection.ANSWER, queryAnswer);
92 }
93 return response;
94 }
95 });
96 }
97 });
98 final Channel channel = bootstrap.bind(DNS_SERVER_PORT).channel();
99 Executors.newSingleThreadScheduledExecutor().schedule(new Runnable() {
100 @Override
101 public void run() {
102 try {
103 clientQuery();
104 channel.close();
105 } catch (Exception e) {
106 e.printStackTrace();
107 }
108 }
109 }, 1000, TimeUnit.MILLISECONDS);
110 channel.closeFuture().sync();
111 }
112
113
114 private static void clientQuery() throws Exception {
115 EventLoopGroup group = new MultiThreadIoEventLoopGroup(NioIoHandler.newFactory());
116 try {
117 Bootstrap b = new Bootstrap();
118 b.group(group)
119 .channel(NioSocketChannel.class)
120 .handler(new ChannelInitializer<SocketChannel>() {
121 @Override
122 protected void initChannel(SocketChannel ch) {
123 ch.pipeline().addLast(new TcpDnsQueryEncoder())
124 .addLast(new TcpDnsResponseDecoder())
125 .addLast(new SimpleChannelInboundHandler<DefaultDnsResponse>() {
126 @Override
127 protected void channelRead0(ChannelHandlerContext ctx, DefaultDnsResponse msg) {
128 try {
129 handleQueryResp(msg);
130 } finally {
131 ctx.close();
132 }
133 }
134 });
135 }
136 });
137
138 final Channel ch = b.connect(DNS_SERVER_HOST, DNS_SERVER_PORT).sync().channel();
139
140 int randomID = new Random().nextInt(60000 - 1000) + 1000;
141 DnsQuery query = new DefaultDnsQuery(randomID, DnsOpCode.QUERY)
142 .setRecord(DnsSection.QUESTION, new DefaultDnsQuestion(QUERY_DOMAIN, DnsRecordType.A));
143 ch.writeAndFlush(query).sync();
144 boolean success = ch.closeFuture().await(10, TimeUnit.SECONDS);
145 if (!success) {
146 System.err.println("dns query timeout!");
147 ch.close().sync();
148 }
149 } finally {
150 group.shutdownGracefully();
151 }
152 }
153
154 private static void handleQueryResp(DefaultDnsResponse msg) {
155 if (msg.count(DnsSection.QUESTION) > 0) {
156 DnsQuestion question = msg.recordAt(DnsSection.QUESTION, 0);
157 System.out.printf("name: %s%n", question.name());
158 }
159 for (int i = 0, count = msg.count(DnsSection.ANSWER); i < count; i++) {
160 DnsRecord record = msg.recordAt(DnsSection.ANSWER, i);
161 if (record.type() == DnsRecordType.A) {
162
163 DnsRawRecord raw = (DnsRawRecord) record;
164 System.out.println(NetUtil.bytesToIpAddress(ByteBufUtil.getBytes(raw.content())));
165 }
166 }
167 }
168 }