1 // Copyright (c) 1999-2004 Brian Wellington (bwelling (at) xbill.org) 2 package org.xbill.DNS; 3 4 import java.io.*; 5 import java.util.Arrays; 6 7 /** 8 * DNS extension options, as described in RFC 2671. The rdata of an OPT record 9 * is defined as a list of options; this represents a single option. 10 * 11 * @author Brian Wellington 12 * @author Ming Zhou <mizhou (at) bnivideo.com>, Beaumaris Networks 13 */ 14 public abstract class EDNSOption { 15 16 public static class Code { 17 private Code() {} 18 19 /** Name Server Identifier, RFC 5001 */ 20 public final static int NSID = 3; 21 22 /** Client Subnet, defined in draft-vandergaast-edns-client-subnet-00 */ 23 public final static int CLIENT_SUBNET = 20730; 24 25 private static Mnemonic codes = new Mnemonic("EDNS Option Codes", 26 Mnemonic.CASE_UPPER); 27 28 static { 29 codes.setMaximum(0xFFFF); 30 codes.setPrefix("CODE"); 31 codes.setNumericAllowed(true); 32 33 codes.add(NSID, "NSID"); 34 codes.add(CLIENT_SUBNET, "CLIENT_SUBNET"); 35 } 36 37 /** 38 * Converts an EDNS Option Code into its textual representation 39 */ 40 public static String 41 string(int code) { 42 return codes.getText(code); 43 } 44 45 /** 46 * Converts a textual representation of an EDNS Option Code into its 47 * numeric value. 48 * @param s The textual representation of the option code 49 * @return The option code, or -1 on error. 50 */ 51 public static int 52 value(String s) { 53 return codes.getValue(s); 54 } 55 } 56 57 private final int code; 58 59 /** 60 * 61 * Creates an option with the given option code and data. 62 */ 63 public 64 EDNSOption(int code) { 65 this.code = Record.checkU16("code", code); 66 } 67 68 public String 69 toString() { 70 StringBuffer sb = new StringBuffer(); 71 72 sb.append("{"); 73 sb.append(EDNSOption.Code.string(code)); 74 sb.append(": "); 75 sb.append(optionToString()); 76 sb.append("}"); 77 78 return sb.toString(); 79 } 80 81 /** 82 * Returns the EDNS Option's code. 83 * 84 * @return the option code 85 */ 86 public int 87 getCode() { 88 return code; 89 } 90 91 /** 92 * Returns the EDNS Option's data, as a byte array. 93 * 94 * @return the option data 95 */ 96 byte [] 97 getData() { 98 DNSOutput out = new DNSOutput(); 99 optionToWire(out); 100 return out.toByteArray(); 101 } 102 103 /** 104 * Converts the wire format of an EDNS Option (the option data only) into the 105 * type-specific format. 106 * @param in The input Stream. 107 */ 108 abstract void 109 optionFromWire(DNSInput in) throws IOException; 110 111 /** 112 * Converts the wire format of an EDNS Option (including code and length) into 113 * the type-specific format. 114 * @param out The input stream. 115 */ 116 static EDNSOption 117 fromWire(DNSInput in) throws IOException { 118 int code, length; 119 120 code = in.readU16(); 121 length = in.readU16(); 122 if (in.remaining() < length) 123 throw new WireParseException("truncated option"); 124 int save = in.saveActive(); 125 in.setActive(length); 126 EDNSOption option; 127 switch (code) { 128 case Code.NSID: 129 option = new NSIDOption(); 130 break; 131 case Code.CLIENT_SUBNET: 132 option = new ClientSubnetOption(); 133 break; 134 default: 135 option = new GenericEDNSOption(code); 136 break; 137 } 138 option.optionFromWire(in); 139 in.restoreActive(save); 140 141 return option; 142 } 143 144 /** 145 * Converts the wire format of an EDNS Option (including code and length) into 146 * the type-specific format. 147 * @return The option, in wire format. 148 */ 149 public static EDNSOption 150 fromWire(byte [] b) throws IOException { 151 return fromWire(new DNSInput(b)); 152 } 153 154 /** 155 * Converts an EDNS Option (the type-specific option data only) into wire format. 156 * @param out The output stream. 157 */ 158 abstract void 159 optionToWire(DNSOutput out); 160 161 /** 162 * Converts an EDNS Option (including code and length) into wire format. 163 * @param out The output stream. 164 */ 165 void 166 toWire(DNSOutput out) { 167 out.writeU16(code); 168 int lengthPosition = out.current(); 169 out.writeU16(0); /* until we know better */ 170 optionToWire(out); 171 int length = out.current() - lengthPosition - 2; 172 out.writeU16At(length, lengthPosition); 173 } 174 175 /** 176 * Converts an EDNS Option (including code and length) into wire format. 177 * @return The option, in wire format. 178 */ 179 public byte [] 180 toWire() throws IOException { 181 DNSOutput out = new DNSOutput(); 182 toWire(out); 183 return out.toByteArray(); 184 } 185 186 /** 187 * Determines if two EDNS Options are identical. 188 * @param arg The option to compare to 189 * @return true if the options are equal, false otherwise. 190 */ 191 public boolean 192 equals(Object arg) { 193 if (arg == null || !(arg instanceof EDNSOption)) 194 return false; 195 EDNSOption opt = (EDNSOption) arg; 196 if (code != opt.code) 197 return false; 198 return Arrays.equals(getData(), opt.getData()); 199 } 200 201 /** 202 * Generates a hash code based on the EDNS Option's data. 203 */ 204 public int 205 hashCode() { 206 byte [] array = getData(); 207 int hashval = 0; 208 for (int i = 0; i < array.length; i++) 209 hashval += ((hashval << 3) + (array[i] & 0xFF)); 210 return hashval; 211 } 212 213 abstract String optionToString(); 214 215 } 216