blob: a65bd196edca1aee1239eb58ccd252888f129c8d [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001// 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}