blob: 2a44d085af46cda8e550a01a691ae7da62dc3ee0 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS;
4
5import java.io.*;
6import java.util.*;
7
8/**
9 * A DNS message header
10 * @see Message
11 *
12 * @author Brian Wellington
13 */
14
15public class Header implements Cloneable {
16
17private int id;
18private int flags;
19private int [] counts;
20
21private static Random random = new Random();
22
23/** The length of a DNS Header in wire format. */
24public static final int LENGTH = 12;
25
26private void
27init() {
28 counts = new int[4];
29 flags = 0;
30 id = -1;
31}
32
33/**
34 * Create a new empty header.
35 * @param id The message id
36 */
37public
38Header(int id) {
39 init();
40 setID(id);
41}
42
43/**
44 * Create a new empty header with a random message id
45 */
46public
47Header() {
48 init();
49}
50
51/**
52 * Parses a Header from a stream containing DNS wire format.
53 */
54Header(DNSInput in) throws IOException {
55 this(in.readU16());
56 flags = in.readU16();
57 for (int i = 0; i < counts.length; i++)
58 counts[i] = in.readU16();
59}
60
61/**
62 * Creates a new Header from its DNS wire format representation
63 * @param b A byte array containing the DNS Header.
64 */
65public
66Header(byte [] b) throws IOException {
67 this(new DNSInput(b));
68}
69
70void
71toWire(DNSOutput out) {
72 out.writeU16(getID());
73 out.writeU16(flags);
74 for (int i = 0; i < counts.length; i++)
75 out.writeU16(counts[i]);
76}
77
78public byte []
79toWire() {
80 DNSOutput out = new DNSOutput();
81 toWire(out);
82 return out.toByteArray();
83}
84
85static private boolean
86validFlag(int bit) {
87 return (bit >= 0 && bit <= 0xF && Flags.isFlag(bit));
88}
89
90static private void
91checkFlag(int bit) {
92 if (!validFlag(bit))
93 throw new IllegalArgumentException("invalid flag bit " + bit);
94}
95
96/**
97 * Sets a flag to the supplied value
98 * @see Flags
99 */
100public void
101setFlag(int bit) {
102 checkFlag(bit);
103 // bits are indexed from left to right
104 flags |= (1 << (15 - bit));
105}
106
107/**
108 * Sets a flag to the supplied value
109 * @see Flags
110 */
111public void
112unsetFlag(int bit) {
113 checkFlag(bit);
114 // bits are indexed from left to right
115 flags &= ~(1 << (15 - bit));
116}
117
118/**
119 * Retrieves a flag
120 * @see Flags
121 */
122public boolean
123getFlag(int bit) {
124 checkFlag(bit);
125 // bits are indexed from left to right
126 return (flags & (1 << (15 - bit))) != 0;
127}
128
129boolean []
130getFlags() {
131 boolean [] array = new boolean[16];
132 for (int i = 0; i < array.length; i++)
133 if (validFlag(i))
134 array[i] = getFlag(i);
135 return array;
136}
137
138/**
139 * Retrieves the message ID
140 */
141public int
142getID() {
143 if (id >= 0)
144 return id;
145 synchronized (this) {
146 if (id < 0)
147 id = random.nextInt(0xffff);
148 return id;
149 }
150}
151
152/**
153 * Sets the message ID
154 */
155public void
156setID(int id) {
157 if (id < 0 || id > 0xffff)
158 throw new IllegalArgumentException("DNS message ID " + id +
159 " is out of range");
160 this.id = id;
161}
162
163/**
164 * Sets the message's rcode
165 * @see Rcode
166 */
167public void
168setRcode(int value) {
169 if (value < 0 || value > 0xF)
170 throw new IllegalArgumentException("DNS Rcode " + value +
171 " is out of range");
172 flags &= ~0xF;
173 flags |= value;
174}
175
176/**
177 * Retrieves the mesasge's rcode
178 * @see Rcode
179 */
180public int
181getRcode() {
182 return flags & 0xF;
183}
184
185/**
186 * Sets the message's opcode
187 * @see Opcode
188 */
189public void
190setOpcode(int value) {
191 if (value < 0 || value > 0xF)
192 throw new IllegalArgumentException("DNS Opcode " + value +
193 "is out of range");
194 flags &= 0x87FF;
195 flags |= (value << 11);
196}
197
198/**
199 * Retrieves the mesasge's opcode
200 * @see Opcode
201 */
202public int
203getOpcode() {
204 return (flags >> 11) & 0xF;
205}
206
207void
208setCount(int field, int value) {
209 if (value < 0 || value > 0xFFFF)
210 throw new IllegalArgumentException("DNS section count " +
211 value + " is out of range");
212 counts[field] = value;
213}
214
215void
216incCount(int field) {
217 if (counts[field] == 0xFFFF)
218 throw new IllegalStateException("DNS section count cannot " +
219 "be incremented");
220 counts[field]++;
221}
222
223void
224decCount(int field) {
225 if (counts[field] == 0)
226 throw new IllegalStateException("DNS section count cannot " +
227 "be decremented");
228 counts[field]--;
229}
230
231/**
232 * Retrieves the record count for the given section
233 * @see Section
234 */
235public int
236getCount(int field) {
237 return counts[field];
238}
239
240/** Converts the header's flags into a String */
241public String
242printFlags() {
243 StringBuffer sb = new StringBuffer();
244
245 for (int i = 0; i < 16; i++)
246 if (validFlag(i) && getFlag(i)) {
247 sb.append(Flags.string(i));
248 sb.append(" ");
249 }
250 return sb.toString();
251}
252
253String
254toStringWithRcode(int newrcode) {
255 StringBuffer sb = new StringBuffer();
256
257 sb.append(";; ->>HEADER<<- ");
258 sb.append("opcode: " + Opcode.string(getOpcode()));
259 sb.append(", status: " + Rcode.string(newrcode));
260 sb.append(", id: " + getID());
261 sb.append("\n");
262
263 sb.append(";; flags: " + printFlags());
264 sb.append("; ");
265 for (int i = 0; i < 4; i++)
266 sb.append(Section.string(i) + ": " + getCount(i) + " ");
267 return sb.toString();
268}
269
270/** Converts the header into a String */
271public String
272toString() {
273 return toStringWithRcode(getRcode());
274}
275
276/* Creates a new Header identical to the current one */
277public Object
278clone() {
279 Header h = new Header();
280 h.id = id;
281 h.flags = flags;
282 System.arraycopy(counts, 0, h.counts, 0, counts.length);
283 return h;
284}
285
286}