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