io.milton.dns.record.APLRecord Maven / Gradle / Ivy
/*
* Copied from the DnsJava project
*
* Copyright (c) 1998-2011, Brian Wellington.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package io.milton.dns.record;
import io.milton.dns.Address;
import io.milton.dns.Name;
import io.milton.dns.utils.base16;
import java.io.*;
import java.net.*;
import java.util.*;
/**
* 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() {
StringBuilder sb = new StringBuilder();
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 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;
return (family != Address.IPv4 || prefixLength <= 32) &&
(family != Address.IPv6 || prefixLength <= 128);
}
/**
* 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 (Object o : elements) {
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() {
StringBuilder sb = new StringBuilder();
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 (Object o : elements) {
Element element = (Element) o;
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);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy