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