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