001: // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS;
004:
005: import java.io.*;
006: import java.util.*;
007:
008: /**
009: * A DNS message header
010: * @see Message
011: *
012: * @author Brian Wellington
013: */
014:
015: public class Header {
016:
017: private int id;
018: private int flags;
019: private int[] counts;
020:
021: private static Random random = new Random();
022:
023: /** The length of a DNS Header in wire format. */
024: public static final int LENGTH = 12;
025:
026: private void init() {
027: counts = new int[4];
028: flags = 0;
029: id = -1;
030: }
031:
032: /**
033: * Create a new empty header.
034: * @param id The message id
035: */
036: public Header(int id) {
037: init();
038: setID(id);
039: }
040:
041: /**
042: * Create a new empty header with a random message id
043: */
044: public Header() {
045: init();
046: }
047:
048: /**
049: * Parses a Header from a stream containing DNS wire format.
050: */
051: Header(DNSInput in) throws IOException {
052: this (in.readU16());
053: flags = in.readU16();
054: for (int i = 0; i < counts.length; i++)
055: counts[i] = in.readU16();
056: }
057:
058: /**
059: * Creates a new Header from its DNS wire format representation
060: * @param b A byte array containing the DNS Header.
061: */
062: public Header(byte[] b) throws IOException {
063: this (new DNSInput(b));
064: }
065:
066: void toWire(DNSOutput out) {
067: out.writeU16(getID());
068: out.writeU16(flags);
069: for (int i = 0; i < counts.length; i++)
070: out.writeU16(counts[i]);
071: }
072:
073: public byte[] toWire() {
074: DNSOutput out = new DNSOutput();
075: toWire(out);
076: return out.toByteArray();
077: }
078:
079: static private boolean validFlag(int bit) {
080: return (bit >= 0 && bit <= 0xF && Flags.isFlag(bit));
081: }
082:
083: static private void checkFlag(int bit) {
084: if (!validFlag(bit))
085: throw new IllegalArgumentException("invalid flag bit "
086: + bit);
087: }
088:
089: /**
090: * Sets a flag to the supplied value
091: * @see Flags
092: */
093: public void setFlag(int bit) {
094: checkFlag(bit);
095: // bits are indexed from left to right
096: flags |= (1 << (15 - bit));
097: }
098:
099: /**
100: * Sets a flag to the supplied value
101: * @see Flags
102: */
103: public void unsetFlag(int bit) {
104: checkFlag(bit);
105: // bits are indexed from left to right
106: flags &= ~(1 << (15 - bit));
107: }
108:
109: /**
110: * Retrieves a flag
111: * @see Flags
112: */
113: public boolean getFlag(int bit) {
114: checkFlag(bit);
115: // bits are indexed from left to right
116: return (flags & (1 << (15 - bit))) != 0;
117: }
118:
119: boolean[] getFlags() {
120: boolean[] array = new boolean[16];
121: for (int i = 0; i < array.length; i++)
122: if (validFlag(i))
123: array[i] = getFlag(i);
124: return array;
125: }
126:
127: /**
128: * Retrieves the message ID
129: */
130: public int getID() {
131: if (id >= 0)
132: return id;
133: synchronized (this ) {
134: if (id < 0)
135: id = random.nextInt(0xffff);
136: return id;
137: }
138: }
139:
140: /**
141: * Sets the message ID
142: */
143: public void setID(int id) {
144: if (id < 0 || id > 0xffff)
145: throw new IllegalArgumentException("DNS message ID " + id
146: + " is out of range");
147: this .id = id;
148: }
149:
150: /**
151: * Sets the message's rcode
152: * @see Rcode
153: */
154: public void setRcode(int value) {
155: if (value < 0 || value > 0xF)
156: throw new IllegalArgumentException("DNS Rcode " + value
157: + " is out of range");
158: flags &= ~0xF;
159: flags |= value;
160: }
161:
162: /**
163: * Retrieves the mesasge's rcode
164: * @see Rcode
165: */
166: public int getRcode() {
167: return flags & 0xF;
168: }
169:
170: /**
171: * Sets the message's opcode
172: * @see Opcode
173: */
174: public void setOpcode(int value) {
175: if (value < 0 || value > 0xF)
176: throw new IllegalArgumentException("DNS Opcode " + value
177: + "is out of range");
178: flags &= 0x87FF;
179: flags |= (value << 11);
180: }
181:
182: /**
183: * Retrieves the mesasge's opcode
184: * @see Opcode
185: */
186: public int getOpcode() {
187: return (flags >> 11) & 0xF;
188: }
189:
190: void setCount(int field, int value) {
191: if (value < 0 || value > 0xFFFF)
192: throw new IllegalArgumentException("DNS section count "
193: + value + " is out of range");
194: counts[field] = value;
195: }
196:
197: void incCount(int field) {
198: if (counts[field] == 0xFFFF)
199: throw new IllegalStateException("DNS section count cannot "
200: + "be incremented");
201: counts[field]++;
202: }
203:
204: void decCount(int field) {
205: if (counts[field] == 0)
206: throw new IllegalStateException("DNS section count cannot "
207: + "be decremented");
208: counts[field]--;
209: }
210:
211: /**
212: * Retrieves the record count for the given section
213: * @see Section
214: */
215: public int getCount(int field) {
216: return counts[field];
217: }
218:
219: /** Converts the header's flags into a String */
220: public String printFlags() {
221: StringBuffer sb = new StringBuffer();
222:
223: for (int i = 0; i < 16; i++)
224: if (validFlag(i) && getFlag(i)) {
225: sb.append(Flags.string(i));
226: sb.append(" ");
227: }
228: return sb.toString();
229: }
230:
231: String toStringWithRcode(int newrcode) {
232: StringBuffer sb = new StringBuffer();
233:
234: sb.append(";; ->>HEADER<<- ");
235: sb.append("opcode: " + Opcode.string(getOpcode()));
236: sb.append(", status: " + Rcode.string(newrcode));
237: sb.append(", id: " + getID());
238: sb.append("\n");
239:
240: sb.append(";; flags: " + printFlags());
241: sb.append("; ");
242: for (int i = 0; i < 4; i++)
243: sb.append(Section.string(i) + ": " + getCount(i) + " ");
244: return sb.toString();
245: }
246:
247: /** Converts the header into a String */
248: public String toString() {
249: return toStringWithRcode(getRcode());
250: }
251:
252: /* Creates a new Header identical to the current one */
253: public Object clone() {
254: Header h = new Header();
255: h.id = id;
256: h.flags = flags;
257: System.arraycopy(counts, 0, h.counts, 0, counts.length);
258: return h;
259: }
260:
261: }
|