1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty5.handler.codec.dns;
18
19 import io.netty5.buffer.api.Buffer;
20 import io.netty5.buffer.api.BufferAllocator;
21 import io.netty5.channel.socket.SocketProtocolFamily;
22 import io.netty5.handler.codec.CorruptedFrameException;
23
24 import java.nio.charset.StandardCharsets;
25
26 import static io.netty5.handler.codec.dns.DefaultDnsRecordDecoder.ROOT;
27
28 final class DnsCodecUtil {
29 private DnsCodecUtil() {
30
31 }
32
33 static void encodeDomainName(String name, Buffer buf) {
34 if (ROOT.equals(name)) {
35
36 buf.ensureWritable(1);
37 buf.writeByte((byte) 0);
38 return;
39 }
40
41
42 buf.ensureWritable(name.length() + 1);
43
44 final String[] labels = name.split("\\.");
45 for (String label : labels) {
46 final int labelLen = label.length();
47 if (labelLen == 0) {
48
49 break;
50 }
51 buf.writeByte((byte) labelLen);
52 buf.writeBytes(label.getBytes(StandardCharsets.US_ASCII));
53 }
54
55 buf.writeByte((byte) 0);
56 }
57
58 static String decodeDomainName(Buffer in) {
59 int position = -1;
60 int checked = 0;
61 final int end = in.writerOffset();
62 final int readable = in.readableBytes();
63
64
65
66
67
68
69
70
71 if (readable == 0) {
72 return ROOT;
73 }
74
75 final StringBuilder name = new StringBuilder(readable << 1);
76 while (in.readableBytes() > 0) {
77 final int len = in.readUnsignedByte();
78 final boolean pointer = (len & 0xc0) == 0xc0;
79 if (pointer) {
80 if (position == -1) {
81 position = in.readerOffset() + 1;
82 }
83
84 if (in.readableBytes() == 0) {
85 throw new CorruptedFrameException("truncated pointer in a name");
86 }
87
88 final int next = (len & 0x3f) << 8 | in.readUnsignedByte();
89 if (next >= end) {
90 throw new CorruptedFrameException("name has an out-of-range pointer");
91 }
92 in.readerOffset(next);
93
94
95 checked += 2;
96 if (checked >= end) {
97 throw new CorruptedFrameException("name contains a loop.");
98 }
99 } else if (len != 0) {
100 if (in.readableBytes() < len) {
101 throw new CorruptedFrameException("truncated label in a name");
102 }
103 name.append(in.readCharSequence(len, StandardCharsets.UTF_8)).append('.');
104 } else {
105 break;
106 }
107 }
108
109 if (position != -1) {
110 in.readerOffset(position);
111 }
112
113 if (name.length() == 0) {
114 return ROOT;
115 }
116
117 if (name.charAt(name.length() - 1) != '.') {
118 name.append('.');
119 }
120
121 return name.toString();
122 }
123
124
125
126
127
128
129 static Buffer decompressDomainName(BufferAllocator allocator, Buffer compression) {
130 String domainName = decodeDomainName(compression);
131 Buffer result = allocator.allocate(domainName.length() << 1);
132 encodeDomainName(domainName, result);
133 return result;
134 }
135
136
137
138
139
140
141 static int addressNumber(SocketProtocolFamily family) {
142 switch (family) {
143 case INET:
144 return 1;
145 case INET6:
146 return 2;
147 default:
148 throw new UnsupportedOperationException();
149 }
150 }
151 }