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