diff options
Diffstat (limited to 'src/org/xbill/DNS/APLRecord.java')
-rw-r--r-- | src/org/xbill/DNS/APLRecord.java | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/src/org/xbill/DNS/APLRecord.java b/src/org/xbill/DNS/APLRecord.java new file mode 100644 index 0000000..5940da2 --- /dev/null +++ b/src/org/xbill/DNS/APLRecord.java @@ -0,0 +1,287 @@ +// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org) + +package org.xbill.DNS; + +import java.io.*; +import java.net.*; +import java.util.*; +import org.xbill.DNS.utils.*; + +/** + * APL - Address Prefix List. See RFC 3123. + * + * @author Brian Wellington + */ + +/* + * Note: this currently uses the same constants as the Address class; + * this could change if more constants are defined for APL records. + */ + +public class APLRecord extends Record { + +public static class Element { + public final int family; + public final boolean negative; + public final int prefixLength; + public final Object address; + + private + Element(int family, boolean negative, Object address, int prefixLength) + { + this.family = family; + this.negative = negative; + this.address = address; + this.prefixLength = prefixLength; + if (!validatePrefixLength(family, prefixLength)) { + throw new IllegalArgumentException("invalid prefix " + + "length"); + } + } + + /** + * Creates an APL element corresponding to an IPv4 or IPv6 prefix. + * @param negative Indicates if this prefix is a negation. + * @param address The IPv4 or IPv6 address. + * @param prefixLength The length of this prefix, in bits. + * @throws IllegalArgumentException The prefix length is invalid. + */ + public + Element(boolean negative, InetAddress address, int prefixLength) { + this(Address.familyOf(address), negative, address, + prefixLength); + } + + public String + toString() { + StringBuffer sb = new StringBuffer(); + if (negative) + sb.append("!"); + sb.append(family); + sb.append(":"); + if (family == Address.IPv4 || family == Address.IPv6) + sb.append(((InetAddress) address).getHostAddress()); + else + sb.append(base16.toString((byte []) address)); + sb.append("/"); + sb.append(prefixLength); + return sb.toString(); + } + + public boolean + equals(Object arg) { + if (arg == null || !(arg instanceof Element)) + return false; + Element elt = (Element) arg; + return (family == elt.family && + negative == elt.negative && + prefixLength == elt.prefixLength && + address.equals(elt.address)); + } + + public int + hashCode() { + return address.hashCode() + prefixLength + (negative ? 1 : 0); + } +} + +private static final long serialVersionUID = -1348173791712935864L; + +private List elements; + +APLRecord() {} + +Record +getObject() { + return new APLRecord(); +} + +private static boolean +validatePrefixLength(int family, int prefixLength) { + if (prefixLength < 0 || prefixLength >= 256) + return false; + if ((family == Address.IPv4 && prefixLength > 32) || + (family == Address.IPv6 && prefixLength > 128)) + return false; + return true; +} + +/** + * Creates an APL Record from the given data. + * @param elements The list of APL elements. + */ +public +APLRecord(Name name, int dclass, long ttl, List elements) { + super(name, Type.APL, dclass, ttl); + this.elements = new ArrayList(elements.size()); + for (Iterator it = elements.iterator(); it.hasNext(); ) { + Object o = it.next(); + if (!(o instanceof Element)) { + throw new IllegalArgumentException("illegal element"); + } + Element element = (Element) o; + if (element.family != Address.IPv4 && + element.family != Address.IPv6) + { + throw new IllegalArgumentException("unknown family"); + } + this.elements.add(element); + + } +} + +private static byte [] +parseAddress(byte [] in, int length) throws WireParseException { + if (in.length > length) + throw new WireParseException("invalid address length"); + if (in.length == length) + return in; + byte [] out = new byte[length]; + System.arraycopy(in, 0, out, 0, in.length); + return out; +} + +void +rrFromWire(DNSInput in) throws IOException { + elements = new ArrayList(1); + while (in.remaining() != 0) { + int family = in.readU16(); + int prefix = in.readU8(); + int length = in.readU8(); + boolean negative = (length & 0x80) != 0; + length &= ~0x80; + + byte [] data = in.readByteArray(length); + Element element; + if (!validatePrefixLength(family, prefix)) { + throw new WireParseException("invalid prefix length"); + } + + if (family == Address.IPv4 || family == Address.IPv6) { + data = parseAddress(data, + Address.addressLength(family)); + InetAddress addr = InetAddress.getByAddress(data); + element = new Element(negative, addr, prefix); + } else { + element = new Element(family, negative, data, prefix); + } + elements.add(element); + + } +} + +void +rdataFromString(Tokenizer st, Name origin) throws IOException { + elements = new ArrayList(1); + while (true) { + Tokenizer.Token t = st.get(); + if (!t.isString()) + break; + + boolean negative = false; + int family = 0; + int prefix = 0; + + String s = t.value; + int start = 0; + if (s.startsWith("!")) { + negative = true; + start = 1; + } + int colon = s.indexOf(':', start); + if (colon < 0) + throw st.exception("invalid address prefix element"); + int slash = s.indexOf('/', colon); + if (slash < 0) + throw st.exception("invalid address prefix element"); + + String familyString = s.substring(start, colon); + String addressString = s.substring(colon + 1, slash); + String prefixString = s.substring(slash + 1); + + try { + family = Integer.parseInt(familyString); + } + catch (NumberFormatException e) { + throw st.exception("invalid family"); + } + if (family != Address.IPv4 && family != Address.IPv6) + throw st.exception("unknown family"); + + try { + prefix = Integer.parseInt(prefixString); + } + catch (NumberFormatException e) { + throw st.exception("invalid prefix length"); + } + + if (!validatePrefixLength(family, prefix)) { + throw st.exception("invalid prefix length"); + } + + byte [] bytes = Address.toByteArray(addressString, family); + if (bytes == null) + throw st.exception("invalid IP address " + + addressString); + + InetAddress address = InetAddress.getByAddress(bytes); + elements.add(new Element(negative, address, prefix)); + } + st.unget(); +} + +String +rrToString() { + StringBuffer sb = new StringBuffer(); + for (Iterator it = elements.iterator(); it.hasNext(); ) { + Element element = (Element) it.next(); + sb.append(element); + if (it.hasNext()) + sb.append(" "); + } + return sb.toString(); +} + +/** Returns the list of APL elements. */ +public List +getElements() { + return elements; +} + +private static int +addressLength(byte [] addr) { + for (int i = addr.length - 1; i >= 0; i--) { + if (addr[i] != 0) + return i + 1; + } + return 0; +} + +void +rrToWire(DNSOutput out, Compression c, boolean canonical) { + for (Iterator it = elements.iterator(); it.hasNext(); ) { + Element element = (Element) it.next(); + int length = 0; + byte [] data; + if (element.family == Address.IPv4 || + element.family == Address.IPv6) + { + InetAddress addr = (InetAddress) element.address; + data = addr.getAddress(); + length = addressLength(data); + } else { + data = (byte []) element.address; + length = data.length; + } + int wlength = length; + if (element.negative) { + wlength |= 0x80; + } + out.writeU16(element.family); + out.writeU8(element.prefixLength); + out.writeU8(wlength); + out.writeByteArray(data, 0, length); + } +} + +} |