View Javadoc
1   /*
2    * Copyright 2015 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.codec.dns;
17  
18  import io.netty.channel.AddressedEnvelope;
19  import io.netty.util.internal.StringUtil;
20  
21  import java.net.SocketAddress;
22  
23  /**
24   * Provides some utility methods for DNS message implementations.
25   */
26  final class DnsMessageUtil {
27  
28      static StringBuilder appendQuery(StringBuilder buf, DnsQuery query) {
29          appendQueryHeader(buf, query);
30          appendAllRecords(buf, query);
31          return buf;
32      }
33  
34      static StringBuilder appendResponse(StringBuilder buf, DnsResponse response) {
35          appendResponseHeader(buf, response);
36          appendAllRecords(buf, response);
37          return buf;
38      }
39  
40      static StringBuilder appendRecordClass(StringBuilder buf, int dnsClass) {
41          final String name;
42          switch (dnsClass &= 0xFFFF) {
43          case DnsRecord.CLASS_IN:
44              name = "IN";
45              break;
46          case DnsRecord.CLASS_CSNET:
47              name = "CSNET";
48              break;
49          case DnsRecord.CLASS_CHAOS:
50              name = "CHAOS";
51              break;
52          case DnsRecord.CLASS_HESIOD:
53              name = "HESIOD";
54              break;
55          case DnsRecord.CLASS_NONE:
56              name = "NONE";
57              break;
58          case DnsRecord.CLASS_ANY:
59              name = "ANY";
60              break;
61          default:
62              name = null;
63              break;
64          }
65  
66          if (name != null) {
67              buf.append(name);
68          } else {
69              buf.append("UNKNOWN(").append(dnsClass).append(')');
70          }
71  
72          return buf;
73      }
74  
75      private static void appendQueryHeader(StringBuilder buf, DnsQuery msg) {
76          buf.append(StringUtil.simpleClassName(msg))
77             .append('(');
78  
79          appendAddresses(buf, msg)
80             .append(msg.id())
81             .append(", ")
82             .append(msg.opCode());
83  
84          if (msg.isRecursionDesired()) {
85              buf.append(", RD");
86          }
87          if (msg.z() != 0) {
88              buf.append(", Z: ")
89                 .append(msg.z());
90          }
91          buf.append(')');
92      }
93  
94      private static void appendResponseHeader(StringBuilder buf, DnsResponse msg) {
95          buf.append(StringUtil.simpleClassName(msg))
96             .append('(');
97  
98          appendAddresses(buf, msg)
99             .append(msg.id())
100            .append(", ")
101            .append(msg.opCode())
102            .append(", ")
103            .append(msg.code())
104            .append(',');
105 
106         boolean hasComma = true;
107         if (msg.isRecursionDesired()) {
108             hasComma = false;
109             buf.append(" RD");
110         }
111         if (msg.isAuthoritativeAnswer()) {
112             hasComma = false;
113             buf.append(" AA");
114         }
115         if (msg.isTruncated()) {
116             hasComma = false;
117             buf.append(" TC");
118         }
119         if (msg.isRecursionAvailable()) {
120             hasComma = false;
121             buf.append(" RA");
122         }
123         if (msg.z() != 0) {
124             if (!hasComma) {
125                 buf.append(',');
126             }
127             buf.append(" Z: ")
128                .append(msg.z());
129         }
130 
131         if (hasComma) {
132             buf.setCharAt(buf.length() - 1, ')');
133         } else {
134             buf.append(')');
135         }
136     }
137 
138     private static StringBuilder appendAddresses(StringBuilder buf, DnsMessage msg) {
139 
140         if (!(msg instanceof AddressedEnvelope)) {
141             return buf;
142         }
143 
144         @SuppressWarnings("unchecked")
145         AddressedEnvelope<?, SocketAddress> envelope = (AddressedEnvelope<?, SocketAddress>) msg;
146 
147         SocketAddress addr = envelope.sender();
148         if (addr != null) {
149             buf.append("from: ")
150                .append(addr)
151                .append(", ");
152         }
153 
154         addr = envelope.recipient();
155         if (addr != null) {
156             buf.append("to: ")
157                .append(addr)
158                .append(", ");
159         }
160 
161         return buf;
162     }
163 
164     private static void appendAllRecords(StringBuilder buf, DnsMessage msg) {
165         appendRecords(buf, msg, DnsSection.QUESTION);
166         appendRecords(buf, msg, DnsSection.ANSWER);
167         appendRecords(buf, msg, DnsSection.AUTHORITY);
168         appendRecords(buf, msg, DnsSection.ADDITIONAL);
169     }
170 
171     private static void appendRecords(StringBuilder buf, DnsMessage message, DnsSection section) {
172         final int count = message.count(section);
173         for (int i = 0; i < count; i ++) {
174             buf.append(StringUtil.NEWLINE)
175                .append(StringUtil.TAB)
176                .append(message.<DnsRecord>recordAt(section, i));
177         }
178     }
179 
180     private DnsMessageUtil() { }
181 }