1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.example.dns.tcp;
17
18 import io.netty5.bootstrap.Bootstrap;
19 import io.netty5.bootstrap.ServerBootstrap;
20 import io.netty5.buffer.BufferUtil;
21 import io.netty5.channel.Channel;
22 import io.netty5.channel.ChannelHandlerContext;
23 import io.netty5.channel.ChannelInitializer;
24 import io.netty5.channel.IoHandlerFactory;
25 import io.netty5.channel.MultithreadEventLoopGroup;
26 import io.netty5.channel.SimpleChannelInboundHandler;
27 import io.netty5.channel.nio.NioHandler;
28 import io.netty5.channel.socket.SocketChannel;
29 import io.netty5.channel.socket.nio.NioServerSocketChannel;
30 import io.netty5.channel.socket.nio.NioSocketChannel;
31 import io.netty5.handler.codec.dns.DefaultDnsQuery;
32 import io.netty5.handler.codec.dns.DefaultDnsQuestion;
33 import io.netty5.handler.codec.dns.DefaultDnsRawRecord;
34 import io.netty5.handler.codec.dns.DefaultDnsResponse;
35 import io.netty5.handler.codec.dns.DnsOpCode;
36 import io.netty5.handler.codec.dns.DnsQuery;
37 import io.netty5.handler.codec.dns.DnsQuestion;
38 import io.netty5.handler.codec.dns.DnsRawRecord;
39 import io.netty5.handler.codec.dns.DnsRecord;
40 import io.netty5.handler.codec.dns.DnsRecordType;
41 import io.netty5.handler.codec.dns.DnsSection;
42 import io.netty5.handler.codec.dns.TcpDnsQueryDecoder;
43 import io.netty5.handler.codec.dns.TcpDnsQueryEncoder;
44 import io.netty5.handler.codec.dns.TcpDnsResponseDecoder;
45 import io.netty5.handler.codec.dns.TcpDnsResponseEncoder;
46 import io.netty5.handler.logging.LogLevel;
47 import io.netty5.handler.logging.LoggingHandler;
48 import io.netty5.util.NetUtil;
49
50 import java.util.Random;
51 import java.util.concurrent.Executors;
52 import java.util.concurrent.TimeUnit;
53
54 public final class TcpDnsServer {
55 private static final String QUERY_DOMAIN = "www.example.com";
56 private static final int DNS_SERVER_PORT = 53;
57 private static final String DNS_SERVER_HOST = "127.0.0.1";
58 private static final byte[] QUERY_RESULT = {(byte) 192, (byte) 168, 1, 1};
59
60 public static void main(String[] args) throws Exception {
61 IoHandlerFactory ioHandlerFactory = NioHandler.newFactory();
62 ServerBootstrap bootstrap = new ServerBootstrap()
63 .group(new MultithreadEventLoopGroup(1, ioHandlerFactory),
64 new MultithreadEventLoopGroup(ioHandlerFactory))
65 .channel(NioServerSocketChannel.class)
66 .handler(new LoggingHandler(LogLevel.INFO))
67 .childHandler(new ChannelInitializer<>() {
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 messageReceived(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(ctx, msg, question, 600, QUERY_RESULT));
80 }
81
82 private DefaultDnsResponse newResponse(ChannelHandlerContext ctx,
83 DnsQuery query,
84 DnsQuestion question,
85 long ttl, byte[]... addresses) {
86 DefaultDnsResponse response = new DefaultDnsResponse(query.id());
87 response.addRecord(DnsSection.QUESTION, question);
88
89 for (byte[] address : addresses) {
90 DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord(
91 question.name(),
92 DnsRecordType.A, ttl, ctx.bufferAllocator().copyOf(address));
93 response.addRecord(DnsSection.ANSWER, queryAnswer);
94 }
95 return response;
96 }
97 });
98 }
99 });
100 final Channel channel = bootstrap.bind(DNS_SERVER_PORT).asStage().get();
101 Executors.newSingleThreadScheduledExecutor().schedule(() -> {
102 try {
103 clientQuery();
104 channel.close();
105 } catch (Exception e) {
106 e.printStackTrace();
107 }
108 }, 1000, TimeUnit.MILLISECONDS);
109 channel.closeFuture().asStage().sync();
110 }
111
112
113 private static void clientQuery() throws Exception {
114 MultithreadEventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory());
115 try {
116 Bootstrap b = new Bootstrap();
117 b.group(group)
118 .channel(NioSocketChannel.class)
119 .handler(new ChannelInitializer<SocketChannel>() {
120 @Override
121 protected void initChannel(SocketChannel ch) {
122 ch.pipeline().addLast(new TcpDnsQueryEncoder())
123 .addLast(new TcpDnsResponseDecoder())
124 .addLast(new SimpleChannelInboundHandler<DefaultDnsResponse>() {
125 @Override
126 protected void messageReceived(
127 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).asStage().get();
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).asStage().sync();
144 boolean success = ch.closeFuture().asStage().await(10, TimeUnit.SECONDS);
145 if (!success) {
146 System.err.println("dns query timeout!");
147 ch.close().asStage().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(BufferUtil.getBytes(raw.content())));
165 }
166 }
167 }
168 }