EDNSOption.java revision d7955ce24d294fb2014c59d11fca184471056f44
1// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
2package org.xbill.DNS;
3
4import java.io.*;
5import 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@bnivideo.com>, Beaumaris Networks
13 */
14public abstract class EDNSOption {
15
16public 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
57private final int code;
58
59/**
60 *
61 * Creates an option with the given option code and data.
62 */
63public
64EDNSOption(int code) {
65	this.code = Record.checkU16("code", code);
66}
67
68public String
69toString() {
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 */
86public int
87getCode() {
88	return code;
89}
90
91/**
92 * Returns the EDNS Option's data, as a byte array.
93 *
94 * @return the option data
95 */
96byte []
97getData() {
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 */
108abstract void
109optionFromWire(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 */
116static EDNSOption
117fromWire(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 */
149public static EDNSOption
150fromWire(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 */
158abstract void
159optionToWire(DNSOutput out);
160
161/**
162 * Converts an EDNS Option (including code and length) into wire format.
163 * @param out The output stream.
164 */
165void
166toWire(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 */
179public byte []
180toWire() 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 */
191public boolean
192equals(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 */
204public int
205hashCode() {
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
213abstract String optionToString();
214
215}
216