1// 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} 287