1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.dns;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.handler.codec.UnsupportedMessageTypeException;
20
21
22
23
24
25
26 public class DefaultDnsRecordEncoder implements DnsRecordEncoder {
27 private static final int PREFIX_MASK = Byte.SIZE - 1;
28
29
30
31
32 protected DefaultDnsRecordEncoder() { }
33
34 @Override
35 public final void encodeQuestion(DnsQuestion question, ByteBuf out) throws Exception {
36 encodeName(question.name(), out);
37 out.writeShort(question.type().intValue());
38 out.writeShort(question.dnsClass());
39 }
40
41 private static final Class<?>[] SUPPORTED_MESSAGES = new Class<?>[] {
42 DnsQuestion.class, DnsPtrRecord.class,
43 DnsOptEcsRecord.class, DnsOptPseudoRecord.class, DnsRawRecord.class };
44
45 @Override
46 public void encodeRecord(DnsRecord record, ByteBuf out) throws Exception {
47 if (record instanceof DnsQuestion) {
48 encodeQuestion((DnsQuestion) record, out);
49 } else if (record instanceof DnsPtrRecord) {
50 encodePtrRecord((DnsPtrRecord) record, out);
51 } else if (record instanceof DnsOptEcsRecord) {
52 encodeOptEcsRecord((DnsOptEcsRecord) record, out);
53 } else if (record instanceof DnsOptPseudoRecord) {
54 encodeOptPseudoRecord((DnsOptPseudoRecord) record, out);
55 } else if (record instanceof DnsRawRecord) {
56 encodeRawRecord((DnsRawRecord) record, out);
57 } else {
58 throw new UnsupportedMessageTypeException(record, SUPPORTED_MESSAGES);
59 }
60 }
61
62 private void encodeRecord0(DnsRecord record, ByteBuf out) throws Exception {
63 encodeName(record.name(), out);
64 out.writeShort(record.type().intValue());
65 out.writeShort(record.dnsClass());
66 out.writeInt((int) record.timeToLive());
67 }
68
69 private void encodePtrRecord(DnsPtrRecord record, ByteBuf out) throws Exception {
70 encodeRecord0(record, out);
71 int writerIndex = out.writerIndex();
72
73
74 out.writerIndex(writerIndex + 2);
75 encodeName(record.hostname(), out);
76 int rdLength = out.writerIndex() - (writerIndex + 2);
77 out.setShort(writerIndex, rdLength);
78 }
79
80 private void encodeOptPseudoRecord(DnsOptPseudoRecord record, ByteBuf out) throws Exception {
81 encodeRecord0(record, out);
82 out.writeShort(0);
83 }
84
85 private void encodeOptEcsRecord(DnsOptEcsRecord record, ByteBuf out) throws Exception {
86 encodeRecord0(record, out);
87
88 int sourcePrefixLength = record.sourcePrefixLength();
89 int scopePrefixLength = record.scopePrefixLength();
90 int lowOrderBitsToPreserve = sourcePrefixLength & PREFIX_MASK;
91
92 byte[] bytes = record.address();
93 int addressBits = bytes.length << 3;
94 if (addressBits < sourcePrefixLength || sourcePrefixLength < 0) {
95 throw new IllegalArgumentException(sourcePrefixLength + ": " +
96 sourcePrefixLength + " (expected: 0 >= " + addressBits + ')');
97 }
98
99
100 final short addressNumber = (short) (bytes.length == 4 ? 1 : 2);
101 int payloadLength = calculateEcsAddressLength(sourcePrefixLength, lowOrderBitsToPreserve);
102
103 int fullPayloadLength = 2 +
104 2 +
105 2 +
106 1 +
107 1 +
108 payloadLength;
109
110 out.writeShort(fullPayloadLength);
111 out.writeShort(8);
112
113 out.writeShort(fullPayloadLength - 4);
114 out.writeShort(addressNumber);
115 out.writeByte(sourcePrefixLength);
116 out.writeByte(scopePrefixLength);
117
118 if (lowOrderBitsToPreserve > 0) {
119 int bytesLength = payloadLength - 1;
120 out.writeBytes(bytes, 0, bytesLength);
121
122
123 out.writeByte(padWithZeros(bytes[bytesLength], lowOrderBitsToPreserve));
124 } else {
125
126 out.writeBytes(bytes, 0, payloadLength);
127 }
128 }
129
130
131 static int calculateEcsAddressLength(int sourcePrefixLength, int lowOrderBitsToPreserve) {
132 return (sourcePrefixLength >>> 3) + (lowOrderBitsToPreserve != 0 ? 1 : 0);
133 }
134
135 private void encodeRawRecord(DnsRawRecord record, ByteBuf out) throws Exception {
136 encodeRecord0(record, out);
137
138 ByteBuf content = record.content();
139 int contentLen = content.readableBytes();
140
141 out.writeShort(contentLen);
142 out.writeBytes(content, content.readerIndex(), contentLen);
143 }
144
145 protected void encodeName(String name, ByteBuf buf) throws Exception {
146 DnsCodecUtil.encodeDomainName(name, buf);
147 }
148
149 private static byte padWithZeros(byte b, int lowOrderBitsToPreserve) {
150 switch (lowOrderBitsToPreserve) {
151 case 0:
152 return 0;
153 case 1:
154 return (byte) (0x80 & b);
155 case 2:
156 return (byte) (0xC0 & b);
157 case 3:
158 return (byte) (0xE0 & b);
159 case 4:
160 return (byte) (0xF0 & b);
161 case 5:
162 return (byte) (0xF8 & b);
163 case 6:
164 return (byte) (0xFC & b);
165 case 7:
166 return (byte) (0xFE & b);
167 case 8:
168 return b;
169 default:
170 throw new IllegalArgumentException("lowOrderBitsToPreserve: " + lowOrderBitsToPreserve);
171 }
172 }
173 }