Home | History | Annotate | Download | only in DNS
      1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) xbill.org)
      2 
      3 package org.xbill.DNS;
      4 
      5 import java.io.*;
      6 import java.util.*;
      7 
      8 /**
      9  * A DNS message header
     10  * @see Message
     11  *
     12  * @author Brian Wellington
     13  */
     14 
     15 public class Header implements Cloneable {
     16 
     17 private int id;
     18 private int flags;
     19 private int [] counts;
     20 
     21 private static Random random = new Random();
     22 
     23 /** The length of a DNS Header in wire format. */
     24 public static final int LENGTH = 12;
     25 
     26 private void
     27 init() {
     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  */
     37 public
     38 Header(int id) {
     39 	init();
     40 	setID(id);
     41 }
     42 
     43 /**
     44  * Create a new empty header with a random message id
     45  */
     46 public
     47 Header() {
     48 	init();
     49 }
     50 
     51 /**
     52  * Parses a Header from a stream containing DNS wire format.
     53  */
     54 Header(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  */
     65 public
     66 Header(byte [] b) throws IOException {
     67 	this(new DNSInput(b));
     68 }
     69 
     70 void
     71 toWire(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 
     78 public byte []
     79 toWire() {
     80 	DNSOutput out = new DNSOutput();
     81 	toWire(out);
     82 	return out.toByteArray();
     83 }
     84 
     85 static private boolean
     86 validFlag(int bit) {
     87 	return (bit >= 0 && bit <= 0xF && Flags.isFlag(bit));
     88 }
     89 
     90 static private void
     91 checkFlag(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  */
    100 public void
    101 setFlag(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  */
    111 public void
    112 unsetFlag(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  */
    122 public boolean
    123 getFlag(int bit) {
    124 	checkFlag(bit);
    125 	// bits are indexed from left to right
    126 	return (flags & (1 << (15 - bit))) != 0;
    127 }
    128 
    129 boolean []
    130 getFlags() {
    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  */
    141 public int
    142 getID() {
    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  */
    155 public void
    156 setID(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  */
    167 public void
    168 setRcode(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  */
    180 public int
    181 getRcode() {
    182 	return flags & 0xF;
    183 }
    184 
    185 /**
    186  * Sets the message's opcode
    187  * @see Opcode
    188  */
    189 public void
    190 setOpcode(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  */
    202 public int
    203 getOpcode() {
    204 	return (flags >> 11) & 0xF;
    205 }
    206 
    207 void
    208 setCount(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 
    215 void
    216 incCount(int field) {
    217 	if (counts[field] == 0xFFFF)
    218 		throw new IllegalStateException("DNS section count cannot " +
    219 						"be incremented");
    220 	counts[field]++;
    221 }
    222 
    223 void
    224 decCount(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  */
    235 public int
    236 getCount(int field) {
    237 	return counts[field];
    238 }
    239 
    240 /** Converts the header's flags into a String */
    241 public String
    242 printFlags() {
    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 
    253 String
    254 toStringWithRcode(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 */
    271 public String
    272 toString() {
    273 	return toStringWithRcode(getRcode());
    274 }
    275 
    276 /* Creates a new Header identical to the current one */
    277 public Object
    278 clone() {
    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 }
    287