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 encodeName(record.hostname(), out);
72 }
73
74 private void encodeOptPseudoRecord(DnsOptPseudoRecord record, ByteBuf out) throws Exception {
75 encodeRecord0(record, out);
76 out.writeShort(0);
77 }
78
79 private void encodeOptEcsRecord(DnsOptEcsRecord record, ByteBuf out) throws Exception {
80 encodeRecord0(record, out);
81
82 int sourcePrefixLength = record.sourcePrefixLength();
83 int scopePrefixLength = record.scopePrefixLength();
84 int lowOrderBitsToPreserve = sourcePrefixLength & PREFIX_MASK;
85
86 byte[] bytes = record.address();
87 int addressBits = bytes.length << 3;
88 if (addressBits < sourcePrefixLength || sourcePrefixLength < 0) {
89 throw new IllegalArgumentException(sourcePrefixLength + ": " +
90 sourcePrefixLength + " (expected: 0 >= " + addressBits + ')');
91 }
92
93
94 final short addressNumber = (short) (bytes.length == 4 ? 1 : 2);
95 int payloadLength = calculateEcsAddressLength(sourcePrefixLength, lowOrderBitsToPreserve);
96
97 int fullPayloadLength = 2 +
98 2 +
99 2 +
100 1 +
101 1 +
102 payloadLength;
103
104 out.writeShort(fullPayloadLength);
105 out.writeShort(8);
106
107 out.writeShort(fullPayloadLength - 4);
108 out.writeShort(addressNumber);
109 out.writeByte(sourcePrefixLength);
110 out.writeByte(scopePrefixLength);
111
112 if (lowOrderBitsToPreserve > 0) {
113 int bytesLength = payloadLength - 1;
114 out.writeBytes(bytes, 0, bytesLength);
115
116
117 out.writeByte(padWithZeros(bytes[bytesLength], lowOrderBitsToPreserve));
118 } else {
119
120 out.writeBytes(bytes, 0, payloadLength);
121 }
122 }
123
124
125 static int calculateEcsAddressLength(int sourcePrefixLength, int lowOrderBitsToPreserve) {
126 return (sourcePrefixLength >>> 3) + (lowOrderBitsToPreserve != 0 ? 1 : 0);
127 }
128
129 private void encodeRawRecord(DnsRawRecord record, ByteBuf out) throws Exception {
130 encodeRecord0(record, out);
131
132 ByteBuf content = record.content();
133 int contentLen = content.readableBytes();
134
135 out.writeShort(contentLen);
136 out.writeBytes(content, content.readerIndex(), contentLen);
137 }
138
139 protected void encodeName(String name, ByteBuf buf) throws Exception {
140 DnsCodecUtil.encodeDomainName(name, buf);
141 }
142
143 private static byte padWithZeros(byte b, int lowOrderBitsToPreserve) {
144 switch (lowOrderBitsToPreserve) {
145 case 0:
146 return 0;
147 case 1:
148 return (byte) (0x80 & b);
149 case 2:
150 return (byte) (0xC0 & b);
151 case 3:
152 return (byte) (0xE0 & b);
153 case 4:
154 return (byte) (0xF0 & b);
155 case 5:
156 return (byte) (0xF8 & b);
157 case 6:
158 return (byte) (0xFC & b);
159 case 7:
160 return (byte) (0xFE & b);
161 case 8:
162 return b;
163 default:
164 throw new IllegalArgumentException("lowOrderBitsToPreserve: " + lowOrderBitsToPreserve);
165 }
166 }
167 }