Home | History | Annotate | Download | only in DNS
      1 // Copyright (c) 2004 Brian Wellington (bwelling (at) xbill.org)
      2 
      3 package org.xbill.DNS;
      4 
      5 import java.io.*;
      6 import java.net.*;
      7 import java.util.*;
      8 import 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 
     21 public class APLRecord extends Record {
     22 
     23 public 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 
     88 private static final long serialVersionUID = -1348173791712935864L;
     89 
     90 private List elements;
     91 
     92 APLRecord() {}
     93 
     94 Record
     95 getObject() {
     96 	return new APLRecord();
     97 }
     98 
     99 private static boolean
    100 validatePrefixLength(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  */
    113 public
    114 APLRecord(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 
    133 private static byte []
    134 parseAddress(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 
    144 void
    145 rrFromWire(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 
    173 void
    174 rdataFromString(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 
    233 String
    234 rrToString() {
    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. */
    246 public List
    247 getElements() {
    248 	return elements;
    249 }
    250 
    251 private static int
    252 addressLength(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 
    260 void
    261 rrToWire(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 }
    288