001: // Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
002:
003: package org.xbill.DNS;
004:
005: import java.io.*;
006: import java.net.*;
007: import java.util.*;
008: import org.xbill.DNS.utils.*;
009:
010: /**
011: * APL - Address Prefix List. See RFC 3123.
012: *
013: * @author Brian Wellington
014: */
015:
016: /*
017: * Note: this currently uses the same constants as the Address class;
018: * this could change if more constants are defined for APL records.
019: */
020:
021: public class APLRecord extends Record {
022:
023: public static class Element {
024: public final int family;
025: public final boolean negative;
026: public final int prefixLength;
027: public final Object address;
028:
029: private Element(int family, boolean negative, Object address,
030: int prefixLength) {
031: this .family = family;
032: this .negative = negative;
033: this .address = address;
034: this .prefixLength = prefixLength;
035: if (!validatePrefixLength(family, prefixLength)) {
036: throw new IllegalArgumentException("invalid prefix "
037: + "length");
038: }
039: }
040:
041: /**
042: * Creates an APL element corresponding to an IPv4 or IPv6 prefix.
043: * @param negative Indicates if this prefix is a negation.
044: * @param address The IPv4 or IPv6 address.
045: * @param prefixLength The length of this prefix, in bits.
046: * @throws IllegalArgumentException The prefix length is invalid.
047: */
048: public Element(boolean negative, InetAddress address,
049: int prefixLength) {
050: this (Address.familyOf(address), negative, address,
051: prefixLength);
052: }
053:
054: public String toString() {
055: StringBuffer sb = new StringBuffer();
056: if (negative)
057: sb.append("!");
058: sb.append(family);
059: sb.append(":");
060: if (family == Address.IPv4 || family == Address.IPv6)
061: sb.append(((InetAddress) address).getHostAddress());
062: else
063: sb.append(base16.toString((byte[]) address));
064: sb.append("/");
065: sb.append(prefixLength);
066: return sb.toString();
067: }
068:
069: public boolean equals(Object arg) {
070: if (arg == null || !(arg instanceof Element))
071: return false;
072: Element elt = (Element) arg;
073: return (family == elt.family && negative == elt.negative
074: && prefixLength == elt.prefixLength && address
075: .equals(elt.address));
076: }
077: }
078:
079: private List elements;
080:
081: APLRecord() {
082: }
083:
084: Record getObject() {
085: return new APLRecord();
086: }
087:
088: private static boolean validatePrefixLength(int family,
089: int prefixLength) {
090: if (prefixLength < 0 || prefixLength >= 256)
091: return false;
092: if ((family == Address.IPv4 && prefixLength > 32)
093: || (family == Address.IPv6 && prefixLength > 128))
094: return false;
095: return true;
096: }
097:
098: /**
099: * Creates an APL Record from the given data.
100: * @param elements The list of APL elements.
101: */
102: public APLRecord(Name name, int dclass, long ttl, List elements) {
103: super (name, Type.APL, dclass, ttl);
104: this .elements = new ArrayList(elements.size());
105: for (Iterator it = elements.iterator(); it.hasNext();) {
106: Object o = it.next();
107: if (!(o instanceof Element)) {
108: throw new IllegalArgumentException("illegal element");
109: }
110: Element element = (Element) o;
111: if (element.family != Address.IPv4
112: && element.family != Address.IPv6) {
113: throw new IllegalArgumentException("unknown family");
114: }
115: this .elements.add(element);
116:
117: }
118: }
119:
120: private static byte[] parseAddress(byte[] in, int length)
121: throws WireParseException {
122: if (in.length > length)
123: throw new WireParseException("invalid address length");
124: if (in.length == length)
125: return in;
126: byte[] out = new byte[length];
127: System.arraycopy(in, 0, out, 0, in.length);
128: return out;
129: }
130:
131: void rrFromWire(DNSInput in) throws IOException {
132: elements = new ArrayList(1);
133: while (in.remaining() != 0) {
134: int family = in.readU16();
135: int prefix = in.readU8();
136: int length = in.readU8();
137: boolean negative = (length & 0x80) != 0;
138: length &= ~0x80;
139:
140: byte[] data = in.readByteArray(length);
141: Element element;
142: if (!validatePrefixLength(family, prefix)) {
143: throw new WireParseException("invalid prefix length");
144: }
145:
146: if (family == Address.IPv4 || family == Address.IPv6) {
147: data = parseAddress(data, Address.addressLength(family));
148: InetAddress addr = InetAddress.getByAddress(data);
149: element = new Element(negative, addr, prefix);
150: } else {
151: element = new Element(family, negative, data, prefix);
152: }
153: elements.add(element);
154:
155: }
156: }
157:
158: void rdataFromString(Tokenizer st, Name origin) throws IOException {
159: elements = new ArrayList(1);
160: while (true) {
161: Tokenizer.Token t = st.get();
162: if (!t.isString())
163: break;
164:
165: boolean negative = false;
166: int family = 0;
167: int prefix = 0;
168:
169: String s = t.value;
170: int start = 0;
171: if (s.startsWith("!")) {
172: negative = true;
173: start = 1;
174: }
175: int colon = s.indexOf(':', start);
176: if (colon < 0)
177: throw st.exception("invalid address prefix element");
178: int slash = s.indexOf('/', colon);
179: if (slash < 0)
180: throw st.exception("invalid address prefix element");
181:
182: String familyString = s.substring(start, colon);
183: String addressString = s.substring(colon + 1, slash);
184: String prefixString = s.substring(slash + 1);
185:
186: try {
187: family = Integer.parseInt(familyString);
188: } catch (NumberFormatException e) {
189: throw st.exception("invalid family");
190: }
191: if (family != Address.IPv4 && family != Address.IPv6)
192: throw st.exception("unknown family");
193:
194: try {
195: prefix = Integer.parseInt(prefixString);
196: } catch (NumberFormatException e) {
197: throw st.exception("invalid prefix length");
198: }
199:
200: if (!validatePrefixLength(family, prefix)) {
201: throw st.exception("invalid prefix length");
202: }
203:
204: byte[] bytes = Address.toByteArray(addressString, family);
205: if (bytes == null)
206: throw st.exception("invalid IP address "
207: + addressString);
208:
209: InetAddress address = InetAddress.getByAddress(bytes);
210: elements.add(new Element(negative, address, prefix));
211: }
212: st.unget();
213: }
214:
215: String rrToString() {
216: StringBuffer sb = new StringBuffer();
217: for (Iterator it = elements.iterator(); it.hasNext();) {
218: Element element = (Element) it.next();
219: sb.append(element);
220: if (it.hasNext())
221: sb.append(" ");
222: }
223: return sb.toString();
224: }
225:
226: /** Returns the list of APL elements. */
227: public List getElements() {
228: return elements;
229: }
230:
231: private static int addressLength(byte[] addr) {
232: for (int i = addr.length - 1; i >= 0; i--) {
233: if (addr[i] != 0)
234: return i + 1;
235: }
236: return 0;
237: }
238:
239: void rrToWire(DNSOutput out, Compression c, boolean canonical) {
240: for (Iterator it = elements.iterator(); it.hasNext();) {
241: Element element = (Element) it.next();
242: int length = 0;
243: byte[] data;
244: if (element.family == Address.IPv4
245: || element.family == Address.IPv6) {
246: InetAddress addr = (InetAddress) element.address;
247: data = addr.getAddress();
248: length = addressLength(data);
249: } else {
250: data = (byte[]) element.address;
251: length = data.length;
252: }
253: int wlength = length;
254: if (element.negative) {
255: wlength |= 0x80;
256: }
257: out.writeU16(element.family);
258: out.writeU8(element.prefixLength);
259: out.writeU8(wlength);
260: out.writeByteArray(data, 0, length);
261: }
262: }
263:
264: }
|