| // Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org) |
| package org.xbill.DNS; |
| |
| import java.io.*; |
| import java.util.Arrays; |
| |
| /** |
| * DNS extension options, as described in RFC 2671. The rdata of an OPT record |
| * is defined as a list of options; this represents a single option. |
| * |
| * @author Brian Wellington |
| * @author Ming Zhou <mizhou@bnivideo.com>, Beaumaris Networks |
| */ |
| public abstract class EDNSOption { |
| |
| public static class Code { |
| private Code() {} |
| |
| /** Name Server Identifier, RFC 5001 */ |
| public final static int NSID = 3; |
| |
| /** Client Subnet, defined in draft-vandergaast-edns-client-subnet-00 */ |
| public final static int CLIENT_SUBNET = 20730; |
| |
| private static Mnemonic codes = new Mnemonic("EDNS Option Codes", |
| Mnemonic.CASE_UPPER); |
| |
| static { |
| codes.setMaximum(0xFFFF); |
| codes.setPrefix("CODE"); |
| codes.setNumericAllowed(true); |
| |
| codes.add(NSID, "NSID"); |
| codes.add(CLIENT_SUBNET, "CLIENT_SUBNET"); |
| } |
| |
| /** |
| * Converts an EDNS Option Code into its textual representation |
| */ |
| public static String |
| string(int code) { |
| return codes.getText(code); |
| } |
| |
| /** |
| * Converts a textual representation of an EDNS Option Code into its |
| * numeric value. |
| * @param s The textual representation of the option code |
| * @return The option code, or -1 on error. |
| */ |
| public static int |
| value(String s) { |
| return codes.getValue(s); |
| } |
| } |
| |
| private final int code; |
| |
| /** |
| * |
| * Creates an option with the given option code and data. |
| */ |
| public |
| EDNSOption(int code) { |
| this.code = Record.checkU16("code", code); |
| } |
| |
| public String |
| toString() { |
| StringBuffer sb = new StringBuffer(); |
| |
| sb.append("{"); |
| sb.append(EDNSOption.Code.string(code)); |
| sb.append(": "); |
| sb.append(optionToString()); |
| sb.append("}"); |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * Returns the EDNS Option's code. |
| * |
| * @return the option code |
| */ |
| public int |
| getCode() { |
| return code; |
| } |
| |
| /** |
| * Returns the EDNS Option's data, as a byte array. |
| * |
| * @return the option data |
| */ |
| byte [] |
| getData() { |
| DNSOutput out = new DNSOutput(); |
| optionToWire(out); |
| return out.toByteArray(); |
| } |
| |
| /** |
| * Converts the wire format of an EDNS Option (the option data only) into the |
| * type-specific format. |
| * @param in The input Stream. |
| */ |
| abstract void |
| optionFromWire(DNSInput in) throws IOException; |
| |
| /** |
| * Converts the wire format of an EDNS Option (including code and length) into |
| * the type-specific format. |
| * @param out The input stream. |
| */ |
| static EDNSOption |
| fromWire(DNSInput in) throws IOException { |
| int code, length; |
| |
| code = in.readU16(); |
| length = in.readU16(); |
| if (in.remaining() < length) |
| throw new WireParseException("truncated option"); |
| int save = in.saveActive(); |
| in.setActive(length); |
| EDNSOption option; |
| switch (code) { |
| case Code.NSID: |
| option = new NSIDOption(); |
| break; |
| case Code.CLIENT_SUBNET: |
| option = new ClientSubnetOption(); |
| break; |
| default: |
| option = new GenericEDNSOption(code); |
| break; |
| } |
| option.optionFromWire(in); |
| in.restoreActive(save); |
| |
| return option; |
| } |
| |
| /** |
| * Converts the wire format of an EDNS Option (including code and length) into |
| * the type-specific format. |
| * @return The option, in wire format. |
| */ |
| public static EDNSOption |
| fromWire(byte [] b) throws IOException { |
| return fromWire(new DNSInput(b)); |
| } |
| |
| /** |
| * Converts an EDNS Option (the type-specific option data only) into wire format. |
| * @param out The output stream. |
| */ |
| abstract void |
| optionToWire(DNSOutput out); |
| |
| /** |
| * Converts an EDNS Option (including code and length) into wire format. |
| * @param out The output stream. |
| */ |
| void |
| toWire(DNSOutput out) { |
| out.writeU16(code); |
| int lengthPosition = out.current(); |
| out.writeU16(0); /* until we know better */ |
| optionToWire(out); |
| int length = out.current() - lengthPosition - 2; |
| out.writeU16At(length, lengthPosition); |
| } |
| |
| /** |
| * Converts an EDNS Option (including code and length) into wire format. |
| * @return The option, in wire format. |
| */ |
| public byte [] |
| toWire() throws IOException { |
| DNSOutput out = new DNSOutput(); |
| toWire(out); |
| return out.toByteArray(); |
| } |
| |
| /** |
| * Determines if two EDNS Options are identical. |
| * @param arg The option to compare to |
| * @return true if the options are equal, false otherwise. |
| */ |
| public boolean |
| equals(Object arg) { |
| if (arg == null || !(arg instanceof EDNSOption)) |
| return false; |
| EDNSOption opt = (EDNSOption) arg; |
| if (code != opt.code) |
| return false; |
| return Arrays.equals(getData(), opt.getData()); |
| } |
| |
| /** |
| * Generates a hash code based on the EDNS Option's data. |
| */ |
| public int |
| hashCode() { |
| byte [] array = getData(); |
| int hashval = 0; |
| for (int i = 0; i < array.length; i++) |
| hashval += ((hashval << 3) + (array[i] & 0xFF)); |
| return hashval; |
| } |
| |
| abstract String optionToString(); |
| |
| } |