blob: 5940da238bc244f05af48dc80ff6365773c3a138 [file] [log] [blame]
Shuyi Chend7955ce2013-05-22 14:51:55 -07001// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
2
3package org.xbill.DNS;
4
5import java.io.*;
6import java.net.*;
7import java.util.*;
8import org.xbill.DNS.utils.*;
9
10/**
11 * APL - Address Prefix List. See RFC 3123.
12 *
13 * @author Brian Wellington
14 */
15
16/*
17 * Note: this currently uses the same constants as the Address class;
18 * this could change if more constants are defined for APL records.
19 */
20
21public class APLRecord extends Record {
22
23public static class Element {
24 public final int family;
25 public final boolean negative;
26 public final int prefixLength;
27 public final Object address;
28
29 private
30 Element(int family, boolean negative, Object address, int prefixLength)
31 {
32 this.family = family;
33 this.negative = negative;
34 this.address = address;
35 this.prefixLength = prefixLength;
36 if (!validatePrefixLength(family, prefixLength)) {
37 throw new IllegalArgumentException("invalid prefix " +
38 "length");
39 }
40 }
41
42 /**
43 * Creates an APL element corresponding to an IPv4 or IPv6 prefix.
44 * @param negative Indicates if this prefix is a negation.
45 * @param address The IPv4 or IPv6 address.
46 * @param prefixLength The length of this prefix, in bits.
47 * @throws IllegalArgumentException The prefix length is invalid.
48 */
49 public
50 Element(boolean negative, InetAddress address, int prefixLength) {
51 this(Address.familyOf(address), negative, address,
52 prefixLength);
53 }
54
55 public String
56 toString() {
57 StringBuffer sb = new StringBuffer();
58 if (negative)
59 sb.append("!");
60 sb.append(family);
61 sb.append(":");
62 if (family == Address.IPv4 || family == Address.IPv6)
63 sb.append(((InetAddress) address).getHostAddress());
64 else
65 sb.append(base16.toString((byte []) address));
66 sb.append("/");
67 sb.append(prefixLength);
68 return sb.toString();
69 }
70
71 public boolean
72 equals(Object arg) {
73 if (arg == null || !(arg instanceof Element))
74 return false;
75 Element elt = (Element) arg;
76 return (family == elt.family &&
77 negative == elt.negative &&
78 prefixLength == elt.prefixLength &&
79 address.equals(elt.address));
80 }
81
82 public int
83 hashCode() {
84 return address.hashCode() + prefixLength + (negative ? 1 : 0);
85 }
86}
87
88private static final long serialVersionUID = -1348173791712935864L;
89
90private List elements;
91
92APLRecord() {}
93
94Record
95getObject() {
96 return new APLRecord();
97}
98
99private static boolean
100validatePrefixLength(int family, int prefixLength) {
101 if (prefixLength < 0 || prefixLength >= 256)
102 return false;
103 if ((family == Address.IPv4 && prefixLength > 32) ||
104 (family == Address.IPv6 && prefixLength > 128))
105 return false;
106 return true;
107}
108
109/**
110 * Creates an APL Record from the given data.
111 * @param elements The list of APL elements.
112 */
113public
114APLRecord(Name name, int dclass, long ttl, List elements) {
115 super(name, Type.APL, dclass, ttl);
116 this.elements = new ArrayList(elements.size());
117 for (Iterator it = elements.iterator(); it.hasNext(); ) {
118 Object o = it.next();
119 if (!(o instanceof Element)) {
120 throw new IllegalArgumentException("illegal element");
121 }
122 Element element = (Element) o;
123 if (element.family != Address.IPv4 &&
124 element.family != Address.IPv6)
125 {
126 throw new IllegalArgumentException("unknown family");
127 }
128 this.elements.add(element);
129
130 }
131}
132
133private static byte []
134parseAddress(byte [] in, int length) throws WireParseException {
135 if (in.length > length)
136 throw new WireParseException("invalid address length");
137 if (in.length == length)
138 return in;
139 byte [] out = new byte[length];
140 System.arraycopy(in, 0, out, 0, in.length);
141 return out;
142}
143
144void
145rrFromWire(DNSInput in) throws IOException {
146 elements = new ArrayList(1);
147 while (in.remaining() != 0) {
148 int family = in.readU16();
149 int prefix = in.readU8();
150 int length = in.readU8();
151 boolean negative = (length & 0x80) != 0;
152 length &= ~0x80;
153
154 byte [] data = in.readByteArray(length);
155 Element element;
156 if (!validatePrefixLength(family, prefix)) {
157 throw new WireParseException("invalid prefix length");
158 }
159
160 if (family == Address.IPv4 || family == Address.IPv6) {
161 data = parseAddress(data,
162 Address.addressLength(family));
163 InetAddress addr = InetAddress.getByAddress(data);
164 element = new Element(negative, addr, prefix);
165 } else {
166 element = new Element(family, negative, data, prefix);
167 }
168 elements.add(element);
169
170 }
171}
172
173void
174rdataFromString(Tokenizer st, Name origin) throws IOException {
175 elements = new ArrayList(1);
176 while (true) {
177 Tokenizer.Token t = st.get();
178 if (!t.isString())
179 break;
180
181 boolean negative = false;
182 int family = 0;
183 int prefix = 0;
184
185 String s = t.value;
186 int start = 0;
187 if (s.startsWith("!")) {
188 negative = true;
189 start = 1;
190 }
191 int colon = s.indexOf(':', start);
192 if (colon < 0)
193 throw st.exception("invalid address prefix element");
194 int slash = s.indexOf('/', colon);
195 if (slash < 0)
196 throw st.exception("invalid address prefix element");
197
198 String familyString = s.substring(start, colon);
199 String addressString = s.substring(colon + 1, slash);
200 String prefixString = s.substring(slash + 1);
201
202 try {
203 family = Integer.parseInt(familyString);
204 }
205 catch (NumberFormatException e) {
206 throw st.exception("invalid family");
207 }
208 if (family != Address.IPv4 && family != Address.IPv6)
209 throw st.exception("unknown family");
210
211 try {
212 prefix = Integer.parseInt(prefixString);
213 }
214 catch (NumberFormatException e) {
215 throw st.exception("invalid prefix length");
216 }
217
218 if (!validatePrefixLength(family, prefix)) {
219 throw st.exception("invalid prefix length");
220 }
221
222 byte [] bytes = Address.toByteArray(addressString, family);
223 if (bytes == null)
224 throw st.exception("invalid IP address " +
225 addressString);
226
227 InetAddress address = InetAddress.getByAddress(bytes);
228 elements.add(new Element(negative, address, prefix));
229 }
230 st.unget();
231}
232
233String
234rrToString() {
235 StringBuffer sb = new StringBuffer();
236 for (Iterator it = elements.iterator(); it.hasNext(); ) {
237 Element element = (Element) it.next();
238 sb.append(element);
239 if (it.hasNext())
240 sb.append(" ");
241 }
242 return sb.toString();
243}
244
245/** Returns the list of APL elements. */
246public List
247getElements() {
248 return elements;
249}
250
251private static int
252addressLength(byte [] addr) {
253 for (int i = addr.length - 1; i >= 0; i--) {
254 if (addr[i] != 0)
255 return i + 1;
256 }
257 return 0;
258}
259
260void
261rrToWire(DNSOutput out, Compression c, boolean canonical) {
262 for (Iterator it = elements.iterator(); it.hasNext(); ) {
263 Element element = (Element) it.next();
264 int length = 0;
265 byte [] data;
266 if (element.family == Address.IPv4 ||
267 element.family == Address.IPv6)
268 {
269 InetAddress addr = (InetAddress) element.address;
270 data = addr.getAddress();
271 length = addressLength(data);
272 } else {
273 data = (byte []) element.address;
274 length = data.length;
275 }
276 int wlength = length;
277 if (element.negative) {
278 wlength |= 0x80;
279 }
280 out.writeU16(element.family);
281 out.writeU8(element.prefixLength);
282 out.writeU8(wlength);
283 out.writeByteArray(data, 0, length);
284 }
285}
286
287}