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