NetworkDNS/src-wip/org/xbill/DNS2/clients/Generator.java

311 lines
10 KiB
Java
Executable File

// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package org.xbill.DNS2.clients;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsClass;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.InvalidTypeException;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.records.DnsRecord;
import dorkbox.network.dns.utils.Options;
/**
* A representation of a $GENERATE statement in a master file.
*
* @author Brian Wellington
*/
public
class Generator {
/**
* The start of the range.
*/
public long start;
/**
* The end of the range.
*/
public long end;
/**
* The step value of the range.
*/
public long step;
/**
* The pattern to use for generating record names.
*/
public final String namePattern;
/**
* The type of the generated records.
*/
public final int type;
/**
* The class of the generated records.
*/
public final int dclass;
/**
* The ttl of the generated records.
*/
public final long ttl;
/**
* The pattern to use for generating record data.
*/
public final String rdataPattern;
/**
* The origin to append to relative names.
*/
public final Name origin;
private long current;
/**
* Creates a specification for generating records, as a $GENERATE
* statement in a master file.
*
* @param start The start of the range.
* @param end The end of the range.
* @param step The step value of the range.
* @param namePattern The pattern to use for generating record names.
* @param type The type of the generated records. The supported types are
* PTR, CNAME, DNAME, A, AAAA, and NS.
* @param dclass The class of the generated records.
* @param ttl The ttl of the generated records.
* @param rdataPattern The pattern to use for generating record data.
* @param origin The origin to append to relative names.
*
* @throws IllegalArgumentException The range is invalid.
* @throws IllegalArgumentException The type does not support generation.
* @throws IllegalArgumentException The dclass is not a valid class.
*/
public
Generator(long start, long end, long step, String namePattern, int type, int dclass, long ttl, String rdataPattern, Name origin) {
if (start < 0 || end < 0 || start > end || step <= 0) {
throw new IllegalArgumentException("invalid range specification");
}
if (!supportedType(type)) {
throw new IllegalArgumentException("unsupported type");
}
DnsClass.check(dclass);
this.start = start;
this.end = end;
this.step = step;
this.namePattern = namePattern;
this.type = type;
this.dclass = dclass;
this.ttl = ttl;
this.rdataPattern = rdataPattern;
this.origin = origin;
this.current = start;
}
/**
* Indicates whether generation is supported for this type.
*
* @throws InvalidTypeException The type is out of range.
*/
public static
boolean supportedType(int type) {
DnsRecordType.check(type);
return (type == DnsRecordType.PTR || type == DnsRecordType.CNAME || type == DnsRecordType.DNAME || type == DnsRecordType.A || type == DnsRecordType.AAAA || type == DnsRecordType.NS);
}
/**
* Constructs and returns the next record in the expansion.
*
* @throws IOException The name or rdata was invalid after substitutions were
* performed.
*/
public
DnsRecord nextRecord() throws IOException {
if (current > end) {
return null;
}
String namestr = substitute(namePattern, current);
Name name = Name.Companion.fromString(namestr, origin);
String rdata = substitute(rdataPattern, current);
current += step;
return DnsRecord.fromString(name, type, dclass, ttl, rdata, origin);
}
private
String substitute(String spec, long n) throws IOException {
boolean escaped = false;
byte[] str = spec.getBytes();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length; i++) {
char c = (char) (str[i] & 0xFF);
if (escaped) {
sb.append(c);
escaped = false;
}
else if (c == '\\') {
if (i + 1 == str.length) {
throw new TextParseException("invalid escape character");
}
escaped = true;
}
else if (c == '$') {
boolean negative = false;
long offset = 0;
long width = 0;
long base = 10;
boolean wantUpperCase = false;
if (i + 1 < str.length && str[i + 1] == '$') {
// '$$' == literal '$' for backwards
// compatibility with old versions of BIND.
c = (char) (str[++i] & 0xFF);
sb.append(c);
continue;
}
else if (i + 1 < str.length && str[i + 1] == '{') {
// It's a substitution with modifiers.
i++;
if (i + 1 < str.length && str[i + 1] == '-') {
negative = true;
i++;
}
while (i + 1 < str.length) {
c = (char) (str[++i] & 0xFF);
if (c == ',' || c == '}') {
break;
}
if (c < '0' || c > '9') {
throw new TextParseException("invalid offset");
}
c -= '0';
offset *= 10;
offset += c;
}
if (negative) {
offset = -offset;
}
if (c == ',') {
while (i + 1 < str.length) {
c = (char) (str[++i] & 0xFF);
if (c == ',' || c == '}') {
break;
}
if (c < '0' || c > '9') {
throw new TextParseException("invalid width");
}
c -= '0';
width *= 10;
width += c;
}
}
if (c == ',') {
if (i + 1 == str.length) {
throw new TextParseException("invalid base");
}
c = (char) (str[++i] & 0xFF);
if (c == 'o') {
base = 8;
}
else if (c == 'x') {
base = 16;
}
else if (c == 'X') {
base = 16;
wantUpperCase = true;
}
else if (c != 'd') {
throw new TextParseException("invalid base");
}
}
if (i + 1 == str.length || str[i + 1] != '}') {
throw new TextParseException("invalid modifiers");
}
i++;
}
long v = n + offset;
if (v < 0) {
throw new TextParseException("invalid offset expansion");
}
String number;
if (base == 8) {
number = Long.toOctalString(v);
}
else if (base == 16) {
number = Long.toHexString(v);
}
else {
number = Long.toString(v);
}
if (wantUpperCase) {
number = number.toUpperCase();
}
if (width != 0 && width > number.length()) {
int zeros = (int) width - number.length();
while (zeros-- > 0) {
sb.append('0');
}
}
sb.append(number);
}
else {
sb.append(c);
}
}
return sb.toString();
}
/**
* Constructs and returns all records in the expansion.
*
* @throws IOException The name or rdata of a record was invalid after
* substitutions were performed.
*/
public
DnsRecord[] expand() throws IOException {
List list = new ArrayList();
for (long i = start; i < end; i += step) {
String namestr = substitute(namePattern, current);
Name name = Name.Companion.fromString(namestr, origin);
String rdata = substitute(rdataPattern, current);
list.add(DnsRecord.fromString(name, type, dclass, ttl, rdata, origin));
}
return (DnsRecord[]) list.toArray(new DnsRecord[list.size()]);
}
/**
* Converts the generate specification to a string containing the corresponding
* $GENERATE statement.
*/
public
String toString() {
StringBuilder sb = new StringBuilder();
sb.append("$GENERATE ");
sb.append(start + "-" + end);
if (step > 1) {
sb.append("/" + step);
}
sb.append(" ");
sb.append(namePattern + " ");
sb.append(ttl + " ");
if (dclass != DnsClass.IN || !Options.check("noPrintIN")) {
sb.append(DnsClass.string(dclass) + " ");
}
sb.append(DnsRecordType.string(type) + " ");
sb.append(rdataPattern + " ");
return sb.toString();
}
}