Moved DNS to it's own project

This commit is contained in:
nathan 2019-01-09 18:19:44 +01:00
parent 33853d44e3
commit 3f003995b6
230 changed files with 0 additions and 40001 deletions

View File

@ -1,807 +0,0 @@
/*
* Copyright 2010 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network;
import static dorkbox.network.dns.resolver.addressProvider.DnsServerAddressStreamProviders.platformDefault;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static io.netty.util.internal.ObjectUtil.intValue;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import dorkbox.network.connection.Shutdownable;
import dorkbox.network.dns.DnsQuestion;
import dorkbox.network.dns.clientHandlers.DnsResponse;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsResponseCode;
import dorkbox.network.dns.constants.DnsSection;
import dorkbox.network.dns.records.DnsRecord;
import dorkbox.network.dns.resolver.DnsNameResolver;
import dorkbox.network.dns.resolver.DnsQueryLifecycleObserverFactory;
import dorkbox.network.dns.resolver.NoopDnsQueryLifecycleObserverFactory;
import dorkbox.network.dns.resolver.addressProvider.DefaultDnsServerAddressStreamProvider;
import dorkbox.network.dns.resolver.addressProvider.DnsServerAddressStreamProvider;
import dorkbox.network.dns.resolver.addressProvider.SequentialDnsServerAddressStreamProvider;
import dorkbox.network.dns.resolver.cache.DefaultDnsCache;
import dorkbox.network.dns.resolver.cache.DnsCache;
import dorkbox.util.NamedThreadFactory;
import dorkbox.util.OS;
import dorkbox.util.Property;
import io.netty.channel.ChannelFactory;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ReflectiveChannelFactory;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.kqueue.KQueueDatagramChannel;
import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.socket.DatagramChannel;
import io.netty.channel.socket.InternetProtocolFamily;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.oio.OioDatagramChannel;
import io.netty.resolver.HostsFileEntriesResolver;
import io.netty.resolver.ResolvedAddressTypes;
import io.netty.util.concurrent.Future;
/**
* A DnsClient for resolving DNS name, with reasonably good defaults.
*/
@SuppressWarnings({"unused", "WeakerAccess"})
public
class DnsClient extends Shutdownable {
/*
* TODO: verify ResolverConfiguration works as expected!
* http://bugs.java.com/view_bug.do?bug_id=8176361
* Previous JDK releases documented how to configure `java.net.InetAddress` to use the JNDI DNS service provider as the name service.
* This mechanism, and the system properties to configure it, have been removed in JDK 9
*
* A new mechanism to configure the use of a hosts file has been introduced.
*
* A new system property `jdk.net.hosts.file` has been defined. When this system property is set, the name and address resolution calls
* of `InetAddress`, i.e `getByXXX`, retrieve the relevant mapping from the specified file. The structure of this file is equivalent to
* that of the `/etc/hosts` file.
*
* When the system property `jdk.net.hosts.file` is set, and the specified file doesn't exist, the name or address lookup will result in
* an UnknownHostException. Thus, a non existent hosts file is handled as if the file is empty.
*
* UP UNTIL java 1.8, one can use org/xbill/DNS/spi, ie: sun.net.dns.ResolverConfiguration
*
* TODO: add this functionality? https://en.wikipedia.org/wiki/Link-Local_Multicast_Name_Resolution
*/
/**
* This is a list of all of the public DNS servers to query, when submitting DNS queries
*/
// @formatter:off
@Property
public static
List<InetSocketAddress> DNS_SERVER_LIST = Arrays.asList(
new InetSocketAddress("8.8.8.8", 53), // Google Public DNS
new InetSocketAddress("8.8.4.4", 53),
new InetSocketAddress("208.67.222.222", 53), // OpenDNS
new InetSocketAddress("208.67.220.220", 53),
new InetSocketAddress("37.235.1.174", 53), // FreeDNS
new InetSocketAddress("37.235.1.177", 53)
);
// @formatter:on
/**
* This is a list of all of the BOX default DNS servers to query, when submitting DNS queries.
*/
public final static List<InetSocketAddress> DEFAULT_DNS_SERVER_LIST = DefaultDnsServerAddressStreamProvider.defaultAddressList();
public static final InetAddress[] INET_ADDRESSES = new InetAddress[0];
/**
* Gets the version number.
*/
public static
String getVersion() {
return "2.13";
}
/**
* Retrieve the public facing IP address of this system using DNS.
* <p/>
* Same command as
* <p/>
* dig +short myip.opendns.com @resolver1.opendns.com
*
* @return the public IP address if found, or null if it didn't find it
*/
public static
InetAddress getPublicIp() {
final InetSocketAddress dnsServer = new InetSocketAddress("208.67.222.222", 53); // openDNS
DnsClient dnsClient = new DnsClient(dnsServer);
List<InetAddress> resolved = null;
try {
resolved = dnsClient.resolve("myip.opendns.com");
} catch (Throwable ignored) {
}
dnsClient.stop();
if (resolved != null && resolved.size() > 0) {
return resolved.get(0);
}
return null;
}
private final Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
private Class<? extends DatagramChannel> channelType;
private DnsNameResolver resolver;
private ThreadGroup threadGroup;
private static final String THREAD_NAME = "DnsClient";
private EventLoopGroup eventLoopGroup;
private ChannelFactory<? extends DatagramChannel> channelFactory;
private DnsCache resolveCache;
private DnsCache authoritativeDnsServerCache;
private Integer minTtl;
private Integer maxTtl;
private Integer negativeTtl;
private long queryTimeoutMillis = 5000;
private ResolvedAddressTypes resolvedAddressTypes = DnsNameResolver.DEFAULT_RESOLVE_ADDRESS_TYPES;
private boolean recursionDesired = true;
private int maxQueriesPerResolve = 16;
private boolean traceEnabled;
private int maxPayloadSize = 4096;
private HostsFileEntriesResolver hostsFileEntriesResolver = HostsFileEntriesResolver.DEFAULT;
private DnsServerAddressStreamProvider dnsServerAddressStreamProvider = platformDefault();
private DnsQueryLifecycleObserverFactory dnsQueryLifecycleObserverFactory = NoopDnsQueryLifecycleObserverFactory.INSTANCE;
private String[] searchDomains;
private int ndots = -1;
private boolean decodeIdn = true;
/**
* Creates a new DNS client, with default name server addresses.
*/
public
DnsClient() {
this(DnsClient.DNS_SERVER_LIST);
}
/**
* Creates a new DNS client, using the provided server (default port 53) for DNS query resolution, with a cache that will obey the TTL of the response
*
* @param nameServerAddresses the server to receive your DNS questions.
*/
public
DnsClient(final String nameServerAddresses) {
this(nameServerAddresses, 53);
}
/**
* Creates a new DNS client, using the provided server and por tfor DNS query resolution, with a cache that will obey the TTL of the response
*
* @param nameServerAddresses the server to receive your DNS questions.
*/
public
DnsClient(final String nameServerAddresses, int port) {
this(Collections.singletonList(new InetSocketAddress(nameServerAddresses, port)));
}
/**
* Creates a new DNS client, using the provided server for DNS query resolution, with a cache that will obey the TTL of the response
*
* @param nameServerAddresses the server to receive your DNS questions.
*/
public
DnsClient(final InetSocketAddress nameServerAddresses) {
this(Collections.singletonList(nameServerAddresses));
}
/**
* Creates a new DNS client.
*
* The default TTL value is {@code 0} and {@link Integer#MAX_VALUE}, which practically tells this resolver to
* respect the TTL from the DNS server.
*
* @param nameServerAddresses the list of servers to receive your DNS questions, until it succeeds
*/
public
DnsClient(Collection<InetSocketAddress> nameServerAddresses) {
super(DnsClient.class);
if (OS.isAndroid()) {
// android ONLY supports OIO (not NIO)
eventLoopGroup = new OioEventLoopGroup(1, new NamedThreadFactory(THREAD_NAME + "-DNS", threadGroup));
channelType = OioDatagramChannel.class;
}
else if (OS.isLinux() && NativeLibrary.isAvailable()) {
// epoll network stack is MUCH faster (but only on linux)
eventLoopGroup = new EpollEventLoopGroup(1, new NamedThreadFactory(THREAD_NAME + "-DNS", threadGroup));
channelType = EpollDatagramChannel.class;
}
else if (OS.isMacOsX() && NativeLibrary.isAvailable()) {
// KQueue network stack is MUCH faster (but only on macosx)
eventLoopGroup = new KQueueEventLoopGroup(1, new NamedThreadFactory(THREAD_NAME + "-DNS", threadGroup));
channelType = KQueueDatagramChannel.class;
}
else {
eventLoopGroup = new NioEventLoopGroup(1, new NamedThreadFactory(THREAD_NAME + "-DNS", threadGroup));
channelType = NioDatagramChannel.class;
}
manageForShutdown(eventLoopGroup);
if (nameServerAddresses != null) {
this.dnsServerAddressStreamProvider = new SequentialDnsServerAddressStreamProvider(nameServerAddresses);
}
}
/**
* Sets the cache for resolution results.
*
* @param resolveCache the DNS resolution results cache
*
* @return {@code this}
*/
public
DnsClient resolveCache(DnsCache resolveCache) {
this.resolveCache = resolveCache;
return this;
}
/**
* Set the factory used to generate objects which can observe individual DNS queries.
*
* @param lifecycleObserverFactory the factory used to generate objects which can observe individual DNS queries.
*
* @return {@code this}
*/
public
DnsClient dnsQueryLifecycleObserverFactory(DnsQueryLifecycleObserverFactory lifecycleObserverFactory) {
this.dnsQueryLifecycleObserverFactory = checkNotNull(lifecycleObserverFactory, "lifecycleObserverFactory");
return this;
}
/**
* Sets the cache for authoritative NS servers
*
* @param authoritativeDnsServerCache the authoritative NS servers cache
*
* @return {@code this}
*/
public
DnsClient authoritativeDnsServerCache(DnsCache authoritativeDnsServerCache) {
this.authoritativeDnsServerCache = authoritativeDnsServerCache;
return this;
}
/**
* Sets the minimum and maximum TTL of the cached DNS resource records (in seconds). If the TTL of the DNS
* resource record returned by the DNS server is less than the minimum TTL or greater than the maximum TTL,
* this resolver will ignore the TTL from the DNS server and use the minimum TTL or the maximum TTL instead
* respectively.
* The default value is {@code 0} and {@link Integer#MAX_VALUE}, which practically tells this resolver to
* respect the TTL from the DNS server.
*
* @param minTtl the minimum TTL
* @param maxTtl the maximum TTL
*
* @return {@code this}
*/
public
DnsClient ttl(int minTtl, int maxTtl) {
this.maxTtl = maxTtl;
this.minTtl = minTtl;
return this;
}
/**
* Sets the TTL of the cache for the failed DNS queries (in seconds).
*
* @param negativeTtl the TTL for failed cached queries
*
* @return {@code this}
*/
public
DnsClient negativeTtl(int negativeTtl) {
this.negativeTtl = negativeTtl;
return this;
}
/**
* Sets the timeout of each DNS query performed by this resolver (in milliseconds).
*
* @param queryTimeoutMillis the query timeout
*
* @return {@code this}
*/
public
DnsClient queryTimeoutMillis(long queryTimeoutMillis) {
this.queryTimeoutMillis = queryTimeoutMillis;
return this;
}
/**
* Sets the list of the protocol families of the address resolved.
* You can use {@link DnsClient#computeResolvedAddressTypes(InternetProtocolFamily...)}
* to get a {@link ResolvedAddressTypes} out of some {@link InternetProtocolFamily}s.
*
* @param resolvedAddressTypes the address types
*
* @return {@code this}
*/
public
DnsClient resolvedAddressTypes(ResolvedAddressTypes resolvedAddressTypes) {
this.resolvedAddressTypes = resolvedAddressTypes;
return this;
}
/**
* Sets if this resolver has to send a DNS query with the RD (recursion desired) flag set.
*
* @param recursionDesired true if recursion is desired
*
* @return {@code this}
*/
public
DnsClient recursionDesired(boolean recursionDesired) {
this.recursionDesired = recursionDesired;
return this;
}
/**
* Sets the maximum allowed number of DNS queries to send when resolving a host name.
*
* @param maxQueriesPerResolve the max number of queries
*
* @return {@code this}
*/
public
DnsClient maxQueriesPerResolve(int maxQueriesPerResolve) {
this.maxQueriesPerResolve = maxQueriesPerResolve;
return this;
}
/**
* Sets if this resolver should generate the detailed trace information in an exception message so that
* it is easier to understand the cause of resolution failure.
*
* @param traceEnabled true if trace is enabled
*
* @return {@code this}
*/
public
DnsClient traceEnabled(boolean traceEnabled) {
this.traceEnabled = traceEnabled;
return this;
}
/**
* Sets the capacity of the datagram packet buffer (in bytes). The default value is {@code 4096} bytes.
*
* @param maxPayloadSize the capacity of the datagram packet buffer
*
* @return {@code this}
*/
public
DnsClient maxPayloadSize(int maxPayloadSize) {
this.maxPayloadSize = maxPayloadSize;
return this;
}
/**
* @param hostsFileEntriesResolver the {@link HostsFileEntriesResolver} used to first check
* if the hostname is locally aliased.
*
* @return {@code this}
*/
public
DnsClient hostsFileEntriesResolver(HostsFileEntriesResolver hostsFileEntriesResolver) {
this.hostsFileEntriesResolver = hostsFileEntriesResolver;
return this;
}
/**
* Set the {@link DnsServerAddressStreamProvider} which is used to determine which DNS server is used to resolve
* each hostname.
*
* @return {@code this}
*/
public
DnsClient nameServerProvider(DnsServerAddressStreamProvider dnsServerAddressStreamProvider) {
this.dnsServerAddressStreamProvider = checkNotNull(dnsServerAddressStreamProvider, "dnsServerAddressStreamProvider");
return this;
}
/**
* Set the list of search domains of the resolver.
*
* @param searchDomains the search domains
*
* @return {@code this}
*/
public
DnsClient searchDomains(Iterable<String> searchDomains) {
checkNotNull(searchDomains, "searchDomains");
final List<String> list = new ArrayList<String>(4);
for (String f : searchDomains) {
if (f == null) {
break;
}
// Avoid duplicate entries.
if (list.contains(f)) {
continue;
}
list.add(f);
}
this.searchDomains = list.toArray(new String[list.size()]);
return this;
}
/**
* Set the number of dots which must appear in a name before an initial absolute query is made.
* The default value is {@code 1}.
*
* @param ndots the ndots value
*
* @return {@code this}
*/
public
DnsClient ndots(int ndots) {
this.ndots = ndots;
return this;
}
private
DnsCache newCache() {
return new DefaultDnsCache(intValue(minTtl, 0), intValue(maxTtl, Integer.MAX_VALUE), intValue(negativeTtl, 0));
}
/**
* Set if domain / host names should be decoded to unicode when received.
* See <a href="https://tools.ietf.org/html/rfc3492">rfc3492</a>.
*
* @param decodeIdn if should get decoded
*
* @return {@code this}
*/
public
DnsClient decodeToUnicode(boolean decodeIdn) {
this.decodeIdn = decodeIdn;
return this;
}
/**
* Compute a {@link ResolvedAddressTypes} from some {@link InternetProtocolFamily}s.
* An empty input will return the default value, based on "java.net" System properties.
* Valid inputs are (), (IPv4), (IPv6), (Ipv4, IPv6) and (IPv6, IPv4).
*
* @param internetProtocolFamilies a valid sequence of {@link InternetProtocolFamily}s
*
* @return a {@link ResolvedAddressTypes}
*/
public static
ResolvedAddressTypes computeResolvedAddressTypes(InternetProtocolFamily... internetProtocolFamilies) {
if (internetProtocolFamilies == null || internetProtocolFamilies.length == 0) {
return DnsNameResolver.DEFAULT_RESOLVE_ADDRESS_TYPES;
}
if (internetProtocolFamilies.length > 2) {
throw new IllegalArgumentException("No more than 2 InternetProtocolFamilies");
}
switch (internetProtocolFamilies[0]) {
case IPv4:
return (internetProtocolFamilies.length >= 2 && internetProtocolFamilies[1] == InternetProtocolFamily.IPv6)
? ResolvedAddressTypes.IPV4_PREFERRED
: ResolvedAddressTypes.IPV4_ONLY;
case IPv6:
return (internetProtocolFamilies.length >= 2 && internetProtocolFamilies[1] == InternetProtocolFamily.IPv4)
? ResolvedAddressTypes.IPV6_PREFERRED
: ResolvedAddressTypes.IPV6_ONLY;
default:
throw new IllegalArgumentException("Couldn't resolve ResolvedAddressTypes from InternetProtocolFamily array");
}
}
/**
* Starts the DNS Name Resolver for the client, which will resolve DNS queries.
*/
public
DnsClient start() {
ReflectiveChannelFactory<DatagramChannel> channelFactory = new ReflectiveChannelFactory<DatagramChannel>(channelType);
// default support is IPV4
if (this.resolvedAddressTypes == null) {
this.resolvedAddressTypes = ResolvedAddressTypes.IPV4_ONLY;
}
if (resolveCache != null && (minTtl != null || maxTtl != null || negativeTtl != null)) {
throw new IllegalStateException("resolveCache and TTLs are mutually exclusive");
}
if (authoritativeDnsServerCache != null && (minTtl != null || maxTtl != null || negativeTtl != null)) {
throw new IllegalStateException("authoritativeDnsServerCache and TTLs are mutually exclusive");
}
DnsCache resolveCache = this.resolveCache != null ? this.resolveCache : newCache();
DnsCache authoritativeDnsServerCache = this.authoritativeDnsServerCache != null ? this.authoritativeDnsServerCache : newCache();
resolver = new DnsNameResolver(eventLoopGroup.next(),
channelFactory,
resolveCache,
authoritativeDnsServerCache,
dnsQueryLifecycleObserverFactory,
queryTimeoutMillis,
resolvedAddressTypes,
recursionDesired,
maxQueriesPerResolve,
traceEnabled,
maxPayloadSize,
hostsFileEntriesResolver,
dnsServerAddressStreamProvider,
searchDomains,
ndots,
decodeIdn);
return this;
}
/**
* Clears the DNS resolver cache
*/
public
void reset() {
if (resolver == null) {
start();
}
clearResolver();
}
private
void clearResolver() {
resolver.resolveCache()
.clear();
}
@Override
protected
void stopExtraActions() {
if (resolver != null) {
clearResolver();
resolver.close(); // also closes the UDP channel that DNS client uses
}
}
/**
* Resolves a specific hostname A/AAAA record with the default timeout of 5 seconds
*
* @param hostname the hostname, ie: google.com, that you want to resolve
*
* @return the list of resolved InetAddress or throws an exception if the hostname cannot be resolved
* @throws UnknownHostException if the hostname cannot be resolved
*/
public
List<InetAddress> resolve(String hostname) throws UnknownHostException {
return resolve(hostname, 5);
}
/**
* Resolves a specific hostname A/AAAA record.
*
* @param hostname the hostname, ie: google.com, that you want to resolve
* @param queryTimeoutSeconds the number of seconds to wait for host resolution
*
* @return the list of resolved InetAddress or throws an exception if the hostname cannot be resolved
* @throws UnknownHostException if the hostname cannot be resolved
*/
public
List<InetAddress> resolve(String hostname, int queryTimeoutSeconds) throws UnknownHostException {
if (hostname == null) {
throw new UnknownHostException("Cannot submit query for an unknown host");
}
if (resolver == null) {
start();
}
// use "resolve", since it handles A/AAAA records + redirects correctly
final Future<List<InetAddress>> resolve = resolver.resolveAll(hostname);
boolean finished = resolve.awaitUninterruptibly(queryTimeoutSeconds, TimeUnit.SECONDS);
// now return whatever value we had
if (finished && resolve.isSuccess() && resolve.isDone()) {
try {
List<InetAddress> now = resolve.getNow();
return now;
} catch (Exception e) {
String msg = "Could not ask question to DNS server";
logger.error(msg, e);
throw new UnknownHostException(msg);
}
}
String msg = "Could not ask question to DNS server for A/AAAA record: " + hostname;
logger.error(msg);
UnknownHostException cause = (UnknownHostException) resolve.cause();
if (cause != null) {
throw cause;
}
throw new UnknownHostException(msg);
}
/**
* @return the DNS resolver used by the client. This is for more advanced functionality
*/
public
DnsNameResolver getResolver() {
return resolver;
}
/**
* Resolves a specific hostname record, of the specified type (PTR, MX, TXT, etc) with the default timeout of 5 seconds
* <p/>
* <p/>
* Note: PTR queries absolutely MUST end in '.in-addr.arpa' in order for the DNS server to understand it.
* -- because of this, we will automatically fix this in case that clients are unaware of this requirement
* <p/>
* <p/>
* Note: A/AAAA queries absolutely MUST end in a '.' -- because of this we will automatically fix this in case that clients are
* unaware of this requirement
*
* @param hostname the hostname, ie: google.com, that you want to resolve
* @param type the DnsRecordType you want to resolve (PTR, MX, TXT, etc)
*
* @return the DnsRecords or throws an exception if the hostname cannot be resolved
*
* @throws @throws UnknownHostException if the hostname cannot be resolved
*/
@SuppressWarnings({"unchecked", "Duplicates"})
public
DnsRecord[] query(String hostname, final int type) throws UnknownHostException {
return query(hostname, type, 5);
}
/**
* Resolves a specific hostname record, of the specified type (PTR, MX, TXT, etc)
* <p/>
* <p/>
* Note: PTR queries absolutely MUST end in '.in-addr.arpa' in order for the DNS server to understand it.
* -- because of this, we will automatically fix this in case that clients are unaware of this requirement
* <p/>
* <p/>
* Note: A/AAAA queries absolutely MUST end in a '.' -- because of this we will automatically fix this in case that clients are
* unaware of this requirement
*
* @param hostname the hostname, ie: google.com, that you want to resolve
* @param type the DnsRecordType you want to resolve (PTR, MX, TXT, etc)
* @param queryTimeoutSeconds the number of seconds to wait for host resolution
*
* @return the DnsRecords or throws an exception if the hostname cannot be resolved
*
* @throws @throws UnknownHostException if the hostname cannot be resolved
*/
@SuppressWarnings({"unchecked", "Duplicates"})
public
DnsRecord[] query(String hostname, final int type, int queryTimeoutSeconds) throws UnknownHostException {
if (hostname == null) {
throw new UnknownHostException("Cannot submit query for an unknown host");
}
if (resolver == null) {
start();
}
// we use our own resolvers
DnsQuestion dnsMessage = DnsQuestion.newQuery(hostname, type, recursionDesired);
return query(dnsMessage, queryTimeoutSeconds);
}
/**
* Resolves a specific DnsQuestion
* <p/>
* <p/>
* Note: PTR queries absolutely MUST end in '.in-addr.arpa' in order for the DNS server to understand it.
* -- because of this, we will automatically fix this in case that clients are unaware of this requirement
* <p/>
* <p/>
* Note: A/AAAA queries absolutely MUST end in a '.' -- because of this we will automatically fix this in case that clients are
* unaware of this requirement
*
* @param queryTimeoutSeconds the number of seconds to wait for host resolution
*
* @return the DnsRecords or throws an exception if the hostname cannot be resolved
*
* @throws @throws UnknownHostException if the hostname cannot be resolved
*/
public
DnsRecord[] query(final DnsQuestion dnsMessage, final int queryTimeoutSeconds) throws UnknownHostException {
int questionCount = dnsMessage.getHeader()
.getCount(DnsSection.QUESTION);
if (questionCount > 1) {
throw new UnknownHostException("Cannot ask more than 1 question at a time! You tried to ask " + questionCount + " questions at once");
}
final int type = dnsMessage.getQuestion()
.getType();
final Future<DnsResponse> query = resolver.query(dnsMessage);
boolean finished = query.awaitUninterruptibly(queryTimeoutSeconds, TimeUnit.SECONDS);
// now return whatever value we had
if (finished && query.isSuccess() && query.isDone()) {
DnsResponse response = query.getNow();
try {
final int code = response.getHeader()
.getRcode();
if (code == DnsResponseCode.NOERROR) {
return response.getSectionArray(DnsSection.ANSWER);
}
String msg = "Could not ask question to DNS server: Error code " + code + " for type: " + type + " - " + DnsRecordType.string(type);
logger.error(msg);
throw new UnknownHostException(msg);
} finally {
response.release();
}
}
String msg = "Could not ask question to DNS server for type: " + DnsRecordType.string(type);
logger.error(msg);
UnknownHostException cause = (UnknownHostException) query.cause();
if (cause != null) {
throw cause;
}
throw new UnknownHostException(msg);
}
}

View File

@ -1,357 +0,0 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network;
import java.util.ArrayList;
import org.slf4j.Logger;
import dorkbox.network.connection.EndPoint;
import dorkbox.network.connection.Shutdownable;
import dorkbox.network.dns.DnsQuestion;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsClass;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.records.ARecord;
import dorkbox.network.dns.serverHandlers.DnsServerHandler;
import dorkbox.util.NamedThreadFactory;
import dorkbox.util.OS;
import dorkbox.util.Property;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.WriteBufferWaterMark;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.kqueue.KQueueDatagramChannel;
import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.kqueue.KQueueServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.oio.OioDatagramChannel;
import io.netty.channel.socket.oio.OioServerSocketChannel;
import io.netty.util.NetUtil;
/**
* from: https://blog.cloudflare.com/how-the-consumer-product-safety-commission-is-inadvertently-behind-the-internets-largest-ddos-attacks/
*
* NOTE: CloudFlare has anti-DNS reflection protections in place. Specifically, we automatically upgrade from UDP to TCP when a DNS response
* is particularly large (generally, over 512 bytes). Since TCP requires a handshake, it prevents source IP address spoofing which is
* necessary for a DNS amplification attack.
*
* In addition, we rate limit unknown resolvers. Again, this helps ensure that our infrastructure can't be abused to amplify attacks.
*
* Finally, across our DNS infrastructure we have deprecated ANY queries and have proposed to the IETF to restrict ANY queries to only
* authorized parties. By neutering ANY, we've significantly reduced the maximum size of responses even for zone files that need to be
* large due to a large number of records.
*
*
*
* ALSO: see LINK-LOCAL MULTICAST NAME RESOLUTION
* https://en.wikipedia.org/wiki/Link-Local_Multicast_Name_Resolution
*
* In responding to queries, responders listen on UDP port 5355 on the following link-scope Multicast address:
*
* IPv4 - 224.0.0.252, MAC address of 01-00-5E-00-00-FC
* IPv6 - FF02:0:0:0:0:0:1:3 (this notation can be abbreviated as FF02::1:3), MAC address of 33-33-00-01-00-03
* The responders also listen on TCP port 5355 on the unicast address that the host uses to respond to queries.
*/
public
class DnsServer extends Shutdownable {
/**
* The maximum queue length for incoming connection indications (a request to connect). If a connection indication arrives when the
* queue is full, the connection is refused.
*/
@Property
public static int backlogConnectionCount = 50;
private final ServerBootstrap tcpBootstrap;
private final Bootstrap udpBootstrap;
private final int tcpPort;
private final int udpPort;
private final String hostName;
public static
void main(String[] args) {
DnsServer server = new DnsServer("localhost", 2053);
// MasterZone zone = new MasterZone();
server.aRecord("google.com", DnsClass.IN, 10, "127.0.0.1");
// server.bind(false);
server.bind();
// DnsClient client = new DnsClient("localhost", 2053);
// List<InetAddress> resolve = null;
// try {
// resolve = client.resolve("google.com");
// } catch (UnknownHostException e) {
// e.printStackTrace();
// }
// System.err.println("RESOLVED: " + resolve);
// client.stop();
// server.stop();
}
private final DnsServerHandler dnsServerHandler;
public
DnsServer(String host, int port) {
super(DnsServer.class);
tcpPort = port;
udpPort = port;
if (host == null) {
hostName = "0.0.0.0";
}
else {
hostName = host;
}
dnsServerHandler = new DnsServerHandler(logger);
String threadName = DnsServer.class.getSimpleName();
final EventLoopGroup boss;
final EventLoopGroup work;
if (OS.isAndroid()) {
// android ONLY supports OIO (not NIO)
boss = new OioEventLoopGroup(1, new NamedThreadFactory(threadName + "-boss", threadGroup));
work = new OioEventLoopGroup(WORKER_THREAD_POOL_SIZE, new NamedThreadFactory(threadName, threadGroup));
}
else if (OS.isLinux() && NativeLibrary.isAvailable()) {
// epoll network stack is MUCH faster (but only on linux)
boss = new EpollEventLoopGroup(1, new NamedThreadFactory(threadName + "-boss", threadGroup));
work = new EpollEventLoopGroup(WORKER_THREAD_POOL_SIZE, new NamedThreadFactory(threadName, threadGroup));
}
else if (OS.isMacOsX() && NativeLibrary.isAvailable()) {
// KQueue network stack is MUCH faster (but only on macosx)
boss = new KQueueEventLoopGroup(1, new NamedThreadFactory(threadName + "-boss", threadGroup));
work = new KQueueEventLoopGroup(WORKER_THREAD_POOL_SIZE, new NamedThreadFactory(threadName, threadGroup));
}
else {
// sometimes the native libraries cannot be loaded, so fall back to NIO
boss = new NioEventLoopGroup(1, new NamedThreadFactory(threadName + "-boss", threadGroup));
work = new NioEventLoopGroup(WORKER_THREAD_POOL_SIZE, new NamedThreadFactory(threadName, threadGroup));
}
manageForShutdown(boss);
manageForShutdown(work);
tcpBootstrap = new ServerBootstrap();
udpBootstrap = new Bootstrap();
if (OS.isAndroid()) {
// android ONLY supports OIO (not NIO)
tcpBootstrap.channel(OioServerSocketChannel.class);
}
else if (OS.isLinux() && NativeLibrary.isAvailable()) {
// epoll network stack is MUCH faster (but only on linux)
tcpBootstrap.channel(EpollServerSocketChannel.class);
}
else if (OS.isMacOsX() && NativeLibrary.isAvailable()) {
// KQueue network stack is MUCH faster (but only on macosx)
tcpBootstrap.channel(KQueueServerSocketChannel.class);
}
else {
tcpBootstrap.channel(NioServerSocketChannel.class);
}
// TODO: If we use netty for an HTTP server,
// Beside the usual ChannelOptions the Native Transport allows to enable TCP_CORK which may come in handy if you implement a HTTP Server.
tcpBootstrap.group(boss, work)
.option(ChannelOption.SO_BACKLOG, backlogConnectionCount)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(EndPoint.WRITE_BUFF_LOW, EndPoint.WRITE_BUFF_HIGH))
.childHandler(dnsServerHandler);
// have to check options.host for "0.0.0.0". we don't bind to "0.0.0.0", we bind to "null" to get the "any" address!
if (hostName.equals("0.0.0.0")) {
tcpBootstrap.localAddress(tcpPort);
}
else {
tcpBootstrap.localAddress(hostName, tcpPort);
}
// android screws up on this!!
tcpBootstrap.option(ChannelOption.TCP_NODELAY, !OS.isAndroid())
.childOption(ChannelOption.TCP_NODELAY, !OS.isAndroid());
if (OS.isAndroid()) {
// android ONLY supports OIO (not NIO)
udpBootstrap.channel(OioDatagramChannel.class);
}
else if (OS.isLinux() && NativeLibrary.isAvailable()) {
// epoll network stack is MUCH faster (but only on linux)
udpBootstrap.channel(EpollDatagramChannel.class);
}
else if (OS.isMacOsX() && NativeLibrary.isAvailable()) {
// KQueue network stack is MUCH faster (but only on macosx)
udpBootstrap.channel(KQueueDatagramChannel.class);
}
else {
udpBootstrap.channel(NioDatagramChannel.class);
}
udpBootstrap.group(work)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(EndPoint.WRITE_BUFF_LOW, EndPoint.WRITE_BUFF_HIGH))
// not binding to specific address, since it's driven by TCP, and that can be bound to a specific address
.localAddress(udpPort) // if you bind to a specific interface, Linux will be unable to receive broadcast packets!
.handler(dnsServerHandler);
}
@Override
protected
void stopExtraActions() {
dnsServerHandler.stop();
}
/**
* Binds the server to the configured, underlying protocols.
* <p/>
* This method will also BLOCK until the stop method is called, and if you want to continue running code after this method invocation,
* bind should be called in a separate, non-daemon thread.
*/
public
void bind() {
bind(true);
}
/**
* Binds the server to the configured, underlying protocols.
* <p/>
* This is a more advanced method, and you should consider calling <code>bind()</code> instead.
*
* @param blockUntilTerminate will BLOCK until the server stop method is called, and if you want to continue running code after this method
* invocation, bind should be called in a separate, non-daemon thread - or with false as the parameter.
*/
@SuppressWarnings("AutoBoxing")
public
void bind(boolean blockUntilTerminate) {
// make sure we are not trying to connect during a close or stop event.
// This will wait until we have finished starting up/shutting down.
synchronized (shutdownInProgress) {
}
// The bootstraps will be accessed ONE AT A TIME, in this order!
ChannelFuture future;
Logger logger2 = logger;
// TCP
// Wait until the connection attempt succeeds or fails.
// try {
// future = tcpBootstrap.bind();
// future.await();
// } catch (Exception e) {
// // String errorMessage = stopWithErrorMessage(logger2,
// // "Could not bind to address " + hostName + " TCP port " + tcpPort +
// // " on the server.",
// // e);
// // throw new IllegalArgumentException(errorMessage);
// throw new RuntimeException();
// }
//
// if (!future.isSuccess()) {
// // String errorMessage = stopWithErrorMessage(logger2,
// // "Could not bind to address " + hostName + " TCP port " + tcpPort +
// // " on the server.",
// // future.cause());
// // throw new IllegalArgumentException(errorMessage);
// throw new RuntimeException();
// }
//
// // logger2.info("Listening on address {} at TCP port: {}", hostName, tcpPort);
//
// manageForShutdown(future);
// UDP
// Wait until the connection attempt succeeds or fails.
try {
future = udpBootstrap.bind();
future.await();
} catch (Exception e) {
String errorMessage = stopWithErrorMessage(logger2,
"Could not bind to address " + hostName + " UDP port " + udpPort +
" on the server.",
e);
throw new IllegalArgumentException(errorMessage);
}
if (!future.isSuccess()) {
String errorMessage = stopWithErrorMessage(logger2,
"Could not bind to address " + hostName + " UDP port " + udpPort +
" on the server.",
future.cause());
throw new IllegalArgumentException(errorMessage);
}
// logger2.info("Listening on address {} at UDP port: {}", hostName, udpPort);
manageForShutdown(future);
// we now BLOCK until the stop method is called.
// if we want to continue running code in the server, bind should be called in a separate, non-daemon thread.
if (blockUntilTerminate) {
waitForShutdown();
}
}
/**
* Adds a domain name query result, so clients that request the domain name will get the ipAddress
*
* @param domainName the domain name to have results for
* @param ipAddresses the ip addresses (can be multiple) to return for the requested domain name
*/
public
void aRecord(final String domainName, final int dClass, final int ttl, final String... ipAddresses) {
Name name = DnsQuestion.createName(domainName, DnsRecordType.A);
int length = ipAddresses.length;
ArrayList<ARecord> records = new ArrayList<ARecord>(length);
for (int i = 0; i < length; i++) {
byte[] address = NetUtil.createByteArrayFromIpAddressString(ipAddresses[i]);
records.add(new ARecord(name, dClass, ttl, address));
}
dnsServerHandler.addARecord(name, records);
}
}

View File

@ -1,85 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns;
import dorkbox.network.dns.records.DnsMessage;
import dorkbox.network.dns.utils.Options;
/**
* DNS Name Compression object.
*
* @author Brian Wellington
* @see DnsMessage
* @see Name
*/
public
class Compression {
private static final int TABLE_SIZE = 17;
private static final int MAX_POINTER = 0x3FFF;
private Entry[] table;
private boolean verbose = Options.check("verbosecompression");
private static
class Entry {
Name name;
int pos;
Entry next;
}
/**
* Creates a new Compression object.
*/
public
Compression() {
table = new Entry[TABLE_SIZE];
}
/**
* Adds a compression entry mapping a name to a position in a message.
*
* @param pos The position at which the name is added.
* @param name The name being added to the message.
*/
public
void add(int pos, Name name) {
if (pos > MAX_POINTER) {
return;
}
int row = (name.hashCode() & 0x7FFFFFFF) % TABLE_SIZE;
Entry entry = new Entry();
entry.name = name;
entry.pos = pos;
entry.next = table[row];
table[row] = entry;
if (verbose) {
System.err.println("Adding " + name + " at " + pos);
}
}
/**
* Retrieves the position of the given name, if it has been previously
* included in the message.
*
* @param name The name to find in the compression table.
*
* @return The position of the name, or -1 if not found.
*/
public
int get(Name name) {
int row = (name.hashCode() & 0x7FFFFFFF) % TABLE_SIZE;
int pos = -1;
for (Entry entry = table[row]; entry != null; entry = entry.next) {
if (entry.name.equals(name)) {
pos = entry.pos;
}
}
if (verbose) {
System.err.println("Looking for " + name + ", found " + pos);
}
return pos;
}
}

View File

@ -1,118 +0,0 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.dns;
import java.io.IOException;
import java.net.InetSocketAddress;
import dorkbox.network.dns.records.DnsMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.AddressedEnvelope;
/**
*
*/
public
class DnsEnvelope extends DnsMessage implements AddressedEnvelope<DnsEnvelope, InetSocketAddress> {
private InetSocketAddress localAddress;
private InetSocketAddress remoteAddress;
public
DnsEnvelope() {
super();
}
public
DnsEnvelope(final int id, final InetSocketAddress localAddress, final InetSocketAddress remoteAddress) {
super(id);
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
}
public
DnsEnvelope(final ByteBuf buffer, final InetSocketAddress localAddress, final InetSocketAddress remoteAddress) throws IOException {
super(buffer);
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
}
public
DnsEnvelope(final DnsInput input, final InetSocketAddress localAddress, final InetSocketAddress remoteAddress) throws IOException {
super(input);
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
}
public
void setLocalAddress(final InetSocketAddress localAddress) {
this.localAddress = localAddress;
}
public
void setRemoteAddress(final InetSocketAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
@Override
public
DnsEnvelope content() {
return this;
}
@Override
public final
InetSocketAddress sender() {
return localAddress;
}
@Override
public final
InetSocketAddress recipient() {
return remoteAddress;
}
@Override
public
DnsEnvelope touch() {
return (DnsEnvelope) super.touch();
}
@Override
public
DnsEnvelope touch(Object hint) {
return (DnsEnvelope) super.touch(hint);
}
@Override
public
DnsEnvelope retain() {
return (DnsEnvelope) super.retain();
}
@Override
public
DnsEnvelope retain(int increment) {
return (DnsEnvelope) super.retain(increment);
}
}

View File

@ -1,237 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns;
import dorkbox.network.dns.exceptions.WireParseException;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
* An class for parsing DNS messages.
*
* @author Brian Wellington
*/
public
class DnsInput {
private ByteBuf byteBuf;
private int savedActiveIndex = -1;
private boolean marked = false;
/**
* Creates a new DnsInput
*
* @param input The byte array to read from
*/
public
DnsInput(byte[] input) {
byteBuf = Unpooled.wrappedBuffer(input);
}
/**
* Creates a new DnsInput from the given {@link ByteBuf}
*
* @param byteBuf The ByteBuf
*/
public
DnsInput(ByteBuf byteBuf) {
this.byteBuf = byteBuf;
}
/**
* Returns the current position, for reading only
*/
public
int readIndex() {
return byteBuf.readerIndex();
}
/**
* NOTE: "Active" restricts operations to a specific part of the buffer, defined by the current position + length. Operations that
* extend BEYOND this section are denied by virtue that we set the max readable length in the underlying ByteBuf.
*
* Marks the following bytes in the stream as active, and saves it's state (so it can be restored later)
*
* @param len The number of bytes in the active region.
*
* @throws IllegalArgumentException The number of bytes in the active region
* is longer than the remainder of the input.
*/
public
void setActive(int len) {
savedActiveIndex = byteBuf.writerIndex();
if (len > byteBuf.readableBytes()) {
throw new IllegalArgumentException("cannot set active " + "region past end of input");
}
byteBuf.writerIndex(byteBuf.readerIndex() + len);
}
/**
* Restores the previously set active region.
*/
public
void restoreActive() {
if (savedActiveIndex > -1) {
byteBuf.writerIndex(savedActiveIndex);
savedActiveIndex = -1;
}
}
/**
* Resets the current position of the input stream to the specified index,
* and clears the active region.
*
* @param index The position to continue parsing at.
*
* @throws IllegalArgumentException The index is not within the input.
*/
public
void jump(int index) {
if (index >= byteBuf.capacity()) {
throw new IllegalArgumentException("cannot jump past " + "end of input");
}
byteBuf.readerIndex(index);
restoreActive();
}
/**
* Saves the current state of the input stream. Both the current position and
* the end of the active region are saved.
*
* @throws IllegalArgumentException The index is not within the input.
*/
public
void save() {
marked = true;
byteBuf.markReaderIndex();
}
/**
* Restores the input stream to its state before the call to {@link #save}.
*/
public
void restore() {
if (!marked) {
throw new IllegalStateException("Not marked first");
}
byteBuf.resetReaderIndex();
}
private
void require(int n) throws WireParseException {
if (n > remaining()) {
throw new WireParseException("end of input");
}
}
/**
* Returns the number of bytes that can be read from this stream before
* reaching the end.
*/
public
int remaining() {
return byteBuf.readableBytes();
}
/**
* Reads an unsigned 8 bit value from the stream, as an int.
*
* @return An unsigned 8 bit value.
*
* @throws WireParseException The end of the stream was reached.
*/
public
int readU8() throws WireParseException {
require(1);
return byteBuf.readUnsignedByte();
}
/**
* Reads an unsigned 16 bit value from the stream, as an int.
*
* @return An unsigned 16 bit value.
*
* @throws WireParseException The end of the stream was reached.
*/
public
int readU16() throws WireParseException {
require(2);
return byteBuf.readUnsignedShort();
}
/**
* Reads an unsigned 32 bit value from the stream, as a long.
*
* @return An unsigned 32 bit value.
*
* @throws WireParseException The end of the stream was reached.
*/
public
long readU32() throws WireParseException {
require(4);
return byteBuf.readUnsignedInt();
}
/**
* Reads a byte array of a specified length from the stream into an existing
* array.
*
* @param b The array to read into.
* @param off The offset of the array to start copying data into.
* @param len The number of bytes to copy.
*
* @throws WireParseException The end of the stream was reached.
*/
public
void readByteArray(byte[] b, int off, int len) throws WireParseException {
require(len);
byteBuf.readBytes(b, off, len);
}
/**
* Reads a byte array of a specified length from the stream.
*
* @return The byte array.
*
* @throws WireParseException The end of the stream was reached.
*/
public
byte[] readByteArray(int len) throws WireParseException {
require(len);
byte[] out = new byte[len];
byteBuf.readBytes(out, 0, len);
return out;
}
/**
* Reads a byte array consisting of the remainder of the stream (or the
* active region, if one is set.
*
* @return The byte array.
*/
public
byte[] readByteArray() {
int len = remaining();
byte[] out = new byte[len];
byteBuf.readBytes(out, 0, len);
return out;
}
/**
* Reads a counted string from the stream. A counted string is a one byte
* value indicating string length, followed by bytes of data.
*
* @return A byte array containing the string.
*
* @throws WireParseException The end of the stream was reached.
*/
public
byte[] readCountedString() throws WireParseException {
int len = readU8();
return readByteArray(len);
}
}

View File

@ -1,222 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
* A class for rendering DNS messages.
*
* @author Brian Wellington
*/
public
class DnsOutput {
private ByteBuf byteBuf;
private boolean marked = false;
/**
* Create a new DnsOutput
*/
public
DnsOutput() {
this(32);
}
/**
* Create a new DnsOutput with a specified size.
*
* @param size The initial size
*/
public
DnsOutput(int size) {
this(Unpooled.buffer(size));
}
/**
* Create a new DnsOutput with a specified ByteBuf.
*
* @param byteBuf The ByteBuf to use
*/
public
DnsOutput(ByteBuf byteBuf) {
this.byteBuf = byteBuf;
}
/**
* Returns the current position.
*/
public
int current() {
return byteBuf.writerIndex();
}
/**
* Resets the current position of the output stream to the specified index.
*
* @param index The new current position.
*
* @throws IllegalArgumentException The index is not within the output.
*/
public
void jump(int index) {
if (index >= byteBuf.writerIndex()) {
// we haven't written data to this point yet, and the contract for jump() is that it can only jump to a PREVIOUSLY written spot
throw new IllegalArgumentException("Unable to jump to invalid position " + index + ". Max is " + byteBuf.writerIndex());
}
byteBuf.writerIndex(index);
}
/**
* Saves the current state of the output stream.
*
* @throws IllegalArgumentException The index is not within the output.
*/
public
void save() {
marked = true;
byteBuf.markWriterIndex();
}
/**
* Restores the input stream to its state before the call to {@link #save}.
*/
public
void restore() {
if (!marked) {
throw new IllegalStateException("Not marked first");
}
byteBuf.resetWriterIndex();
marked = false;
}
/**
* Writes an unsigned 8 bit value to the stream.
*
* @param val The value to be written
*/
public
void writeU8(int val) {
check(val, 8);
byteBuf.ensureWritable(1);
byteBuf.writeByte(val);
}
private
void check(long val, int bits) {
long max = 1;
max <<= bits;
if (val < 0 || val > max) {
throw new IllegalArgumentException(val + " out of range for " + bits + " bit value");
}
}
/**
* Writes an unsigned 16 bit value to the stream.
*
* @param val The value to be written
*/
public
void writeU16(int val) {
check(val, 16);
byteBuf.ensureWritable(2);
byteBuf.writeShort(val);
}
/**
* Writes an unsigned 16 bit value to the specified position in the stream.
*
* @param val The value to be written
* @param where The position to write the value.
*/
public
void writeU16At(int val, int where) {
check(val, 16);
// save and set both the read/write index, otherwise if the read index is > write index, errors happen.
int saved = byteBuf.writerIndex();
int readSaved = byteBuf.readerIndex();
byteBuf.setIndex(where, where);
byteBuf.ensureWritable(2);
byteBuf.writeShort(val);
// put the read/write back to where it was (since this was an operation to write a value at a specific position)
byteBuf.writerIndex(saved);
byteBuf.readerIndex(readSaved);
}
/**
* Writes an unsigned 32 bit value to the stream.
*
* @param val The value to be written
*/
public
void writeU32(long val) {
check(val, 32);
byteBuf.ensureWritable(4);
byteBuf.writeInt((int) val);
}
/**
* Writes a byte array to the stream.
*
* @param b The array to write.
*/
public
void writeByteArray(byte[] b) {
writeByteArray(b, 0, b.length);
}
/**
* Writes a byte array to the stream.
*
* @param b The array to write.
* @param off The offset of the array to start copying data from.
* @param len The number of bytes to write.
*/
public
void writeByteArray(byte[] b, int off, int len) {
byteBuf.ensureWritable(len);
byteBuf.writeBytes(b, off, len);
}
/**
* Writes a counted string from the stream. A counted string is a one byte
* value indicating string length, followed by bytes of data.
*
* @param s The string to write.
*/
public
void writeCountedString(byte[] s) {
if (s.length > 0xFF) {
throw new IllegalArgumentException("Invalid counted string");
}
byteBuf.ensureWritable(1 + s.length);
byteBuf.writeByte(s.length);
byteBuf.writeBytes(s, 0, s.length);
}
/**
* Returns a byte array containing the current contents of the stream.
*/
public
byte[] toByteArray() {
byte[] out = new byte[byteBuf.writerIndex()];
byteBuf.readBytes(out, 0, out.length);
return out;
}
public
ByteBuf getByteBuf() {
return byteBuf;
}
}

View File

@ -1,187 +0,0 @@
package dorkbox.network.dns;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Locale;
import dorkbox.network.dns.constants.DnsClass;
import dorkbox.network.dns.constants.DnsOpCode;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsSection;
import dorkbox.network.dns.constants.Flags;
import dorkbox.network.dns.records.DnsRecord;
import io.netty.channel.AddressedEnvelope;
import io.netty.util.internal.StringUtil;
/**
*
*/
public
class DnsQuestion extends DnsEnvelope {
public static
DnsQuestion newResolveQuestion(final String inetHost, final int type, final boolean isRecursionDesired) {
return newQuestion(inetHost, type, isRecursionDesired, true);
}
public static
DnsQuestion newQuery(final String inetHost, final int type, final boolean isRecursionDesired) {
return newQuestion(inetHost, type, isRecursionDesired, false);
}
public static
Name createName(String hostName, final int type) {
// Convert to ASCII which will also check that the length is not too big. Throws null pointer if null.
// See:
// - https://github.com/netty/netty/issues/4937
// - https://github.com/netty/netty/issues/4935
hostName = hostNameAsciiFix(checkNotNull(hostName, "hostname"));
if (hostName == null) {
// hostNameAsciiFix can throw a TextParseException if it fails to parse
return null;
}
hostName = hostName.toLowerCase(Locale.US);
// NOTE: have to make sure that the hostname is a FQDN name
hostName = DnsRecordType.ensureFQDN(type, hostName);
try {
return Name.fromString(hostName);
} catch (Exception e) {
// Name.fromString may throw a TextParseException if it fails to parse
return null;
}
}
private static
DnsQuestion newQuestion(final String inetHost, final int type, final boolean isRecursionDesired, boolean isResolveQuestion) {
Name name = createName(inetHost, type);
try {
DnsRecord questionRecord = DnsRecord.newRecord(name, type, DnsClass.IN);
DnsQuestion question = new DnsQuestion(isResolveQuestion);
question.getHeader()
.setOpcode(DnsOpCode.QUERY);
if (isRecursionDesired) {
question.getHeader()
.setFlag(Flags.RD);
}
question.addRecord(questionRecord, DnsSection.QUESTION);
// keep the question around so we can compare the response to it.
question.retain();
return question;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static
String hostNameAsciiFix(String inetHost) {
try {
String hostName = java.net.IDN.toASCII(inetHost); // can throw IllegalArgumentException
// Check for http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6894622
if (StringUtil.endsWith(inetHost, '.') && !StringUtil.endsWith(hostName, '.')) {
return hostName + '.';
}
return hostName;
} catch (Exception e) {
// java.net.IDN.toASCII(...) may throw an IllegalArgumentException if it fails to parse the hostname
}
return null;
}
private final boolean isResolveQuestion;
/**
* Creates a new instance.
*
* @param isResolveQuestion true if it's a resolve question, which means we ALSO are going to keep resolving names until we get an IP
* address.
*/
private
DnsQuestion(final boolean isResolveQuestion) {
super();
this.isResolveQuestion = isResolveQuestion;
}
public
boolean isResolveQuestion() {
return isResolveQuestion;
}
public
void init(int id, InetSocketAddress recipient) {
getHeader().setID(id);
setRemoteAddress(recipient);
}
@Override
public
int hashCode() {
int hashCode = super.hashCode();
if (sender() != null) {
hashCode = hashCode * 31 + sender().hashCode();
}
if (recipient() != null) {
hashCode = hashCode * 31 + recipient().hashCode();
}
return hashCode;
}
@Override
public
boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof AddressedEnvelope)) {
return false;
}
@SuppressWarnings("unchecked")
final AddressedEnvelope<?, SocketAddress> that = (AddressedEnvelope<?, SocketAddress>) obj;
if (sender() == null) {
if (that.sender() != null) {
return false;
}
}
else if (!sender().equals(that.sender())) {
return false;
}
if (recipient() == null) {
if (that.recipient() != null) {
return false;
}
}
else if (!recipient().equals(that.recipient())) {
return false;
}
return true;
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.dns;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import dorkbox.network.dns.records.DnsMessage;
import io.netty.channel.AddressedEnvelope;
import io.netty.util.internal.UnstableApi;
/**
* A {@link DnsServerResponse} implementation for UDP/IP.
*/
@UnstableApi
public
class DnsServerResponse extends DnsEnvelope {
/**
* Creates a new instance.
*
* @param localAddress the address of the sender
* @param remoteAddress the address of the recipient
*/
public
DnsServerResponse(final DnsMessage dnsQuestion, InetSocketAddress localAddress, InetSocketAddress remoteAddress) {
super(dnsQuestion.getHeader()
.getID(), localAddress, remoteAddress);
if (remoteAddress == null && localAddress == null) {
throw new NullPointerException("localAddress and remoteAddress");
}
}
@Override
public
int hashCode() {
int hashCode = super.hashCode();
if (sender() != null) {
hashCode = hashCode * 31 + sender().hashCode();
}
if (recipient() != null) {
hashCode = hashCode * 31 + recipient().hashCode();
}
return hashCode;
}
@Override
public
boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof AddressedEnvelope)) {
return false;
}
@SuppressWarnings("unchecked")
final AddressedEnvelope<?, SocketAddress> that = (AddressedEnvelope<?, SocketAddress>) obj;
if (sender() == null) {
if (that.sender() != null) {
return false;
}
}
else if (!sender().equals(that.sender())) {
return false;
}
if (recipient() == null) {
if (that.recipient() != null) {
return false;
}
}
else if (!recipient().equals(that.recipient())) {
return false;
}
return true;
}
}

View File

@ -1,212 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns;
import com.esotericsoftware.kryo.util.IntMap;
import dorkbox.util.collections.ObjectIntMap;
/**
* A utility class for converting between numeric codes and mnemonics
* for those codes. Mnemonics are case insensitive.
*
* @author Brian Wellington
*/
public
class Mnemonic {
/** Strings are case-sensitive. */
public static final int CASE_SENSITIVE = 1;
/** Strings will be stored/searched for in uppercase. */
public static final int CASE_UPPER = 2;
/** Strings will be stored/searched for in lowercase. */
public static final int CASE_LOWER = 3;
private static final int INVALID_VALUE = -1;
private ObjectIntMap<String> strings;
private IntMap<String> values;
private String description;
private int wordcase;
private String prefix;
private int max;
private boolean numericok;
/**
* Creates a new Mnemonic table.
*
* @param description A short description of the mnemonic to use when
* @param wordcase Whether to convert strings into uppercase, lowercase,
* or leave them unchanged.
* throwing exceptions.
*/
public
Mnemonic(String description, int wordcase) {
this.description = description;
this.wordcase = wordcase;
strings = new ObjectIntMap<String>();
values = new IntMap<String>();
max = Integer.MAX_VALUE;
}
/**
* Sets the maximum numeric value
*/
public
void setMaximum(int max) {
this.max = max;
}
/**
* Sets the prefix to use when converting to and from values that don't
* have mnemonics.
*/
public
void setPrefix(String prefix) {
this.prefix = sanitize(prefix);
}
/* Converts a String to the correct case. */
private
String sanitize(String str) {
if (wordcase == CASE_UPPER) {
return str.toUpperCase();
}
else if (wordcase == CASE_LOWER) {
return str.toLowerCase();
}
return str;
}
/**
* Sets whether numeric values stored in strings are acceptable.
*/
public
void setNumericAllowed(boolean numeric) {
this.numericok = numeric;
}
/**
* Defines the text representation of a numeric value.
*
* @param value The numeric value
* @param string The text string
*/
public
void add(int value, String string) {
check(value);
string = sanitize(string);
strings.put(string, value);
values.put(value, string);
}
/**
* Checks that a numeric value is within the range [0..max]
*/
public
void check(int val) {
if (val < 0 || val > max) {
throw new IllegalArgumentException(description + " " + val + "is out of range");
}
}
/**
* Defines an additional text representation of a numeric value. This will
* be used by getValue(), but not getText().
*
* @param value The numeric value
* @param string The text string
*/
public
void addAlias(int value, String string) {
check(value);
string = sanitize(string);
strings.put(string, value);
}
/**
* Copies all mnemonics from one table into another.
*
* @param source The Mnemonic source to add from
*
* @throws IllegalArgumentException The wordcases of the Mnemonics do not
* match.
*/
public
void addAll(Mnemonic source) {
if (wordcase != source.wordcase) {
throw new IllegalArgumentException(source.description + ": wordcases do not match");
}
strings.putAll(source.strings);
values.putAll(source.values);
}
/**
* Gets the text mnemonic corresponding to a numeric value.
*
* @param value The numeric value
*
* @return The corresponding text mnemonic.
*/
public
String getText(int value) {
check(value);
String str = values.get(value);
if (str != null) {
return str;
}
str = Integer.toString(value);
if (prefix != null) {
return prefix + str;
}
return str;
}
/**
* Gets the numeric value corresponding to a text mnemonic.
*
* @param str The text mnemonic
*
* @return The corresponding numeric value, or -1 if there is none
*/
public
int getValue(String str) {
str = sanitize(str);
int value = strings.get(str, INVALID_VALUE);
if (value != INVALID_VALUE) {
return value;
}
if (prefix != null) {
if (str.startsWith(prefix)) {
int val = parseNumeric(str.substring(prefix.length()));
if (val >= 0) {
return val;
}
}
}
if (numericok) {
return parseNumeric(str);
}
return INVALID_VALUE;
}
private
int parseNumeric(String s) {
try {
int val = Integer.parseInt(s);
if (val >= 0 && val <= max) {
return val;
}
} catch (NumberFormatException ignored) {
}
return INVALID_VALUE;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +0,0 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.dns.clientHandlers;
import java.net.InetSocketAddress;
import java.util.List;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.DnsQuestion;
import dorkbox.network.dns.records.DnsMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.AddressedEnvelope;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageEncoder;
import io.netty.util.internal.UnstableApi;
/**
* Encodes an {@link AddressedEnvelope} of {@link DnsQuestion}} into a {@link DatagramPacket}.
*/
@UnstableApi
@ChannelHandler.Sharable
public
class DatagramDnsQueryEncoder extends MessageToMessageEncoder<AddressedEnvelope<DnsQuestion, InetSocketAddress>> {
private final int maxPayloadSize;
/**
* Creates a new encoder
*/
public
DatagramDnsQueryEncoder(int maxPayloadSize) {
this.maxPayloadSize = maxPayloadSize;
}
@Override
protected
void encode(ChannelHandlerContext ctx, AddressedEnvelope<DnsQuestion, InetSocketAddress> in, List<Object> out) throws Exception {
final InetSocketAddress recipient = in.recipient();
final DnsMessage query = in.content();
final ByteBuf buf = ctx.alloc()
.ioBuffer(maxPayloadSize);
boolean success = false;
try {
DnsOutput dnsOutput = new DnsOutput(buf);
query.toWire(dnsOutput);
success = true;
} finally {
if (!success) {
buf.release();
}
}
out.add(new DatagramPacket(buf, recipient, null));
}
@Override
public
void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
cause.printStackTrace();
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.dns.clientHandlers;
import java.util.List;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.records.Header;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.internal.UnstableApi;
/**
* Decodes a {@link DatagramPacket} into a {@link DnsResponse}.
*/
@UnstableApi
@ChannelHandler.Sharable
public
class DatagramDnsResponseDecoder extends MessageToMessageDecoder<DatagramPacket> {
/**
* Creates a new DNS Response decoder
*/
public
DatagramDnsResponseDecoder() {
}
@Override
protected
void decode(ChannelHandlerContext ctx, DatagramPacket packet, List<Object> out) throws Exception {
final ByteBuf buf = packet.content();
// Check that the response is long enough.
if (buf.readableBytes() < Header.LENGTH) {
throw new WireParseException("invalid DNS header - " + "too short");
}
DnsInput dnsInput = new DnsInput(buf);
DnsResponse dnsMessage = new DnsResponse(dnsInput, packet.sender(), packet.recipient());
out.add(dnsMessage);
}
}

View File

@ -1,99 +0,0 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.dns.clientHandlers;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import dorkbox.network.dns.DnsEnvelope;
import dorkbox.network.dns.DnsInput;
import io.netty.channel.AddressedEnvelope;
import io.netty.util.internal.UnstableApi;
/**
* A {@link DnsResponse} implementation for UDP/IP.
*/
@UnstableApi
public
class DnsResponse extends DnsEnvelope {
/**
* Creates a new instance.
*
* @param localAddress the address of the sender
* @param remoteAddress the address of the recipient
*/
public
DnsResponse(final DnsInput dnsInput, InetSocketAddress localAddress, InetSocketAddress remoteAddress) throws IOException {
super(dnsInput, localAddress, remoteAddress);
if (remoteAddress == null && localAddress == null) {
throw new NullPointerException("localAddress and remoteAddress");
}
}
@Override
public
int hashCode() {
int hashCode = super.hashCode();
if (sender() != null) {
hashCode = hashCode * 31 + sender().hashCode();
}
if (recipient() != null) {
hashCode = hashCode * 31 + recipient().hashCode();
}
return hashCode;
}
@Override
public
boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof AddressedEnvelope)) {
return false;
}
@SuppressWarnings("unchecked")
final AddressedEnvelope<?, SocketAddress> that = (AddressedEnvelope<?, SocketAddress>) obj;
if (sender() == null) {
if (that.sender() != null) {
return false;
}
}
else if (!sender().equals(that.sender())) {
return false;
}
if (recipient() == null) {
if (that.recipient() != null) {
return false;
}
}
else if (!recipient().equals(that.recipient())) {
return false;
}
return true;
}
}

View File

@ -1,132 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.constants;
import dorkbox.network.dns.Mnemonic;
import dorkbox.network.dns.exceptions.InvalidDClassException;
/**
* Constants and functions relating to DNS classes. This is called DnsClass to avoid confusion with Class.
*
* @author Brian Wellington
*/
public final
class DnsClass {
/**
* Internet DNS resource record class: {@code IN}
*/
public static final int IN = 1;
/**
* Computer Science Network network DNS resource record class: {@code CSNET}. It was never installed as a top-level domain
* in the Domain Name System, but parsed in the message routing logic of mail transport agents (MTA). It was introduced in 1985.
*/
public static final int CS = 2;
/**
* Computer Science Network network DNS resource record class: {@code CSNET}. It was never installed as a top-level domain
* in the Domain Name System, but parsed in the message routing logic of mail transport agents (MTA). It was introduced in 1985.
*/
public static final int CSNET = 2;
/**
* Chaos network DNS resource record class: {@code CH} (MIT)
*/
public static final int CH = 3;
/**
* Chaos network DNS resource record class: {@code CHAOS} (MIT, alternate name)
*/
public static final int CHAOS = 3;
/**
* Hesiod DNS resource record class: {@code HS} (MIT)
*/
public static final int HS = 4;
/**
* Hesiod DNS resource record class: {@code HESIOD} (MIT, alternate name)
*/
public static final int HESIOD = 4;
/**
* Special value used in dynamic update messages
*/
public static final int NONE = 254;
/**
* Matches any class
*/
public static final int ANY = 255;
private static Mnemonic classes = new DClassMnemonic();
private static
class DClassMnemonic extends Mnemonic {
DClassMnemonic() {
super("DnsClass", CASE_UPPER);
setPrefix("CLASS");
}
@Override
public
void check(int val) {
DnsClass.check(val);
}
}
static {
classes.add(IN, "IN");
classes.add(CS, "CS");
classes.addAlias(CSNET, "CSNET");
classes.add(CH, "CH");
classes.addAlias(CH, "CHAOS");
classes.add(HS, "HS");
classes.addAlias(HS, "HESIOD");
classes.add(NONE, "NONE");
classes.add(ANY, "ANY");
}
private
DnsClass() {}
/**
* Checks that a numeric DnsClass is valid.
*
* @throws InvalidDClassException The class is out of range.
*/
public static
void check(int i) {
if (i < 0 || i > 0xFFFF) {
throw new InvalidDClassException(i);
}
}
/**
* Converts a numeric DnsClass into a String
*
* @return The canonical string representation of the class
*
* @throws InvalidDClassException The class is out of range.
*/
public static
String string(int i) {
return classes.getText(i);
}
/**
* Converts a String representation of a DnsClass into its numeric value
*
* @return The class code, or -1 on error.
*/
public static
int value(String s) {
return classes.getValue(s);
}
}

View File

@ -1,73 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.constants;
import dorkbox.network.dns.Mnemonic;
/**
* Constants and functions relating to DNS opcodes
*
* @author Brian Wellington
*/
public final
class DnsOpCode {
/**
* A standard query
*/
public static final int QUERY = 0;
/**
* An inverse query (deprecated)
*/
public static final int IQUERY = 1;
/**
* A server status request (not used)
*/
public static final int STATUS = 2;
/**
* A message from a primary to a secondary server to initiate a zone transfer
*/
public static final int NOTIFY = 4;
/**
* A dynamic update message
*/
public static final int UPDATE = 5;
private static Mnemonic opcodes = new Mnemonic("DNS DnsOpCode", Mnemonic.CASE_UPPER);
static {
opcodes.setMaximum(0xF);
opcodes.setPrefix("RESERVED");
opcodes.setNumericAllowed(true);
opcodes.add(QUERY, "QUERY");
opcodes.add(IQUERY, "IQUERY");
opcodes.add(STATUS, "STATUS");
opcodes.add(NOTIFY, "NOTIFY");
opcodes.add(UPDATE, "UPDATE");
}
private
DnsOpCode() {}
/**
* Converts a numeric DnsOpCode into a String
*/
public static
String string(int i) {
return opcodes.getText(i);
}
/**
* Converts a String representation of an DnsOpCode into its numeric value
*/
public static
int value(String s) {
return opcodes.getValue(s);
}
}

View File

@ -1,610 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.constants;
import dorkbox.network.dns.Mnemonic;
import dorkbox.network.dns.exceptions.InvalidTypeException;
import dorkbox.network.dns.records.DnsRecord;
import dorkbox.network.dns.records.DnsTypeProtoAssignment;
import dorkbox.util.collections.IntMap;
import io.netty.util.internal.StringUtil;
/**
* Constants and functions relating to DNS Types
*
* @author Brian Wellington
*/
public final
class DnsRecordType {
/**
* Address record RFC 1035 Returns a 32-bit IPv4 address, most commonly used
* to map hostnames to an IP address of the host, but also used for DNSBLs,
* storing subnet masks in RFC 1101, etc.
*/
public static final int A = 1;
/**
* Name server record RFC 1035 Delegates a DNS zone to use the given
* authoritative name servers
*/
public static final int NS = 2;
/**
* Mail destination. MD specifies the final destination to which a message addressed to a given domain name should be delivered
* (Obsolete, as it's behavior has been replaced by MX)
*/
@Deprecated
public static final int MD = 3;
/**
* Mail forwarder. MF specifies a host that would forward mail on to the eventual destination, should that destination be unreachable.
* (Obsolete, as it's behavior has been replaced by MX)
*/
@Deprecated
public static final int MF = 4;
/**
* Canonical name (alias) record RFC 1035 Alias of one name to another: the DNS
* lookup will continue by retrying the lookup with the new name.
*/
public static final int CNAME = 5;
/**
* Start of [a zone of] authority record RFC 1035 and RFC 2308 Specifies
* authoritative information about a DNS zone, including the primary name
* server, the email of the domain administrator, the domain serial number,
* and several timers relating to refreshing the zone.
*/
public static final int SOA = 6;
/**
* Mailbox domain name RFC 1035. EXPERIMENTAL. A <domain-name> which specifies a host which has the
* specified mailbox.
*/
public static final int MB = 7;
/**
* Mail group member RFC 1035. EXPERIMENTAL. A <domain-name> which specifies a mailbox which is a
* member of the mail group specified by the domain name. MG records cause no additional section processing.
*/
public static final int MG = 8;
/**
* Mail rename name RFC 1035. EXPERIMENTAL. A <domain-name> which specifies a mailbox which is the
* proper rename of the specified mailbox.
*/
public static final int MR = 9;
/**
* Null record RFC 1035. EXPERIMENTAL. Anything at all may be in the RDATA field so long as it is 65535 octets
* or less
*/
public static final int NULL = 10;
/**
* The WKS record RFC 1035 is used to describe the well known services supported by
* a particular protocol on a particular internet address.
*/
public static final int WKS = 11;
/**
* Pointer record RFC 1035 Pointer to a canonical name. Unlike a CNAME, DNS
* processing does NOT proceed, just the name is returned. The most common
* use is for implementing reverse DNS lookups, but other uses include such
* things as DNS-SD.
*/
public static final int PTR = 12;
/**
* Host information HINFO RFC 1035. records are used to acquire general information about a host. The
* main use is for protocols such as FTP that can use special procedures when talking between machines
* or operating systems of the same type.
*/
public static final int HINFO = 13;
/**
* Mailbox or mail list information RFC 1035. EXPERIMENTAL. MINFO records cause no additional section processing. Although these
* records can be associated with a simple mailbox, they are usually used with a mailing list.
*/
public static final int MINFO = 14;
/**
* Mail exchange (routing) record RFC 1035 Maps a domain name to a list of message transfer agents for that domain.
*/
public static final int MX = 15;
/**
* Text record RFC 1035 Originally for arbitrary human-readable text in a
* DNS record. Since the early 1990s, however, this record more often
* carries machine-readable data, such as specified by RFC 1464,
* opportunistic encryption, Sender Policy Framework, DKIM, DMARC DNS-SD,
* etc.
*/
public static final int TXT = 16;
/**
* Responsible person record RFC 1183 Information about the responsible
* person(s) for the domain. Usually an email address with the @ replaced by
* a .
*/
public static final int RP = 17;
/**
* AFS cell database record RFC 1183 Location of database servers of an AFS cell.
* This record is commonly used by AFS clients to contact AFS cells outside
* their local domain. A subtype of this record is used by the obsolete
* DCE/DFS file system.
*/
public static final int AFSDB = 18;
/**
* X.25 calling address
*/
public static final int X25 = 19;
/**
* ISDN calling address
*/
public static final int ISDN = 20;
/**
* Router
*/
public static final int RT = 21;
/**
* NSAP address
*/
public static final int NSAP = 22;
/**
* Reverse NSAP address (deprecated)
*/
@Deprecated
public static final int NSAP_PTR = 23;
/**
* Signature record RFC 2535 Signature record used in SIG(0) (RFC 2931) and
* TKEY (RFC 2930). RFC 3755 designated RRSIG as the replacement for SIG for
* use within DNSSEC.
*/
public static final int SIG = 24;
/**
* key record RFC 2535 and RFC 2930 Used only for SIG(0) (RFC 2931) and TKEY
* (RFC 2930). RFC 3445 eliminated their use for application keys and
* limited their use to DNSSEC. RFC 3755 designates DNSKEY as the
* replacement within DNSSEC. RFC 4025 designates IPSECKEY as the
* replacement for use with IPsec.
*/
public static final int KEY = 25;
/**
* X.400 mail mapping
*/
public static final int PX = 26;
/**
* Geographical position (withdrawn)
*/
@Deprecated
public static final int GPOS = 27;
/**
* IPv6 address record RFC 3596 Returns a 128-bit IPv6 address, most
* commonly used to map hostnames to an IP address of the host.
*/
public static final int AAAA = 28;
/**
* Location record RFC 1876 Specifies a geographical location associated
* with a domain name.
*/
public static final int LOC = 29;
/**
* Next valid name in zone
*/
public static final int NXT = 30;
/**
* Endpoint identifier
*/
public static final int EID = 31;
/**
* Nimrod locator
*/
public static final int NIMLOC = 32;
/**
* Service selection locator RFC 2782 Generalized service location record, used for
* newer protocols instead of creating protocol-specific records such as MX.
*/
public static final int SRV = 33;
/**
* ATM address
*/
public static final int ATMA = 34;
/**
* Naming Authority Pointer record RFC 3403 Allows regular expression based
* rewriting of domain names which can then be used as URIs, further domain
* names to lookups, etc.
*/
public static final int NAPTR = 35;
/**
* Key eXchanger record RFC 2230 Used with some cryptographic systems (not
* including DNSSEC) to identify a key management agent for the associated
* domain-name. Note that this has nothing to do with DNS Security. It is
* Informational status, rather than being on the IETF standards-track. It
* has always had limited deployment, but is still in use.
*/
public static final int KX = 36;
/**
* Certificate record RFC 4398 Stores PKIX, SPKI, PGP, etc.
*/
public static final int CERT = 37;
/**
* IPv6 address (experimental)
*/
public static final int A6 = 38;
/**
* Delegation name record RFC 2672 DNAME creates an alias for a name and all
* its subnames, unlike CNAME, which aliases only the exact name in its
* label. Like the CNAME record, the DNS lookup will continue by retrying
* the lookup with the new name. This is also known as Non-terminal name redirection
*/
public static final int DNAME = 39;
/**
* Options - contains EDNS metadata. Option record RFC 2671 This is a pseudo DNS
* record type needed to support EDNS.
*/
public static final int OPT = 41;
/**
* Address Prefix List record RFC 3123 Specify lists of address ranges, e.g.
* in CIDR format, for various address families. Experimental.
*/
public static final int APL = 42;
/**
* Delegation signer record RFC 4034 The record used to identify the DNSSEC
* signing key of a delegated zone.
*/
public static final int DS = 43;
/**
* SSH Public Key Fingerprint record RFC 4255 Resource record for publishing
* SSH public host key fingerprints in the DNS System, in order to aid in
* verifying the authenticity of the host. RFC 6594 defines ECC SSH keys and
* SHA-256 hashes. See the IANA SSHFP RR parameters registry for details.
*/
public static final int SSHFP = 44;
/**
* IPsec Key record RFC 4025 Key record that can be used with IPsec.
*/
public static final int IPSECKEY = 45;
/**
* Resource Record Signature. DNSSEC signature record RFC 4034 Signature for a DNSSEC-secured record
* set. Uses the same format as the SIG record.
*/
public static final int RRSIG = 46;
/**
* Next Secure Name. Next-Secure record RFC 4034 Part of DNSSEC, used to prove a name does not
* exist. Uses the same format as the (obsolete) NXT record.
*/
public static final int NSEC = 47;
/**
* DNSSEC Key record RFC 4034 The key record used in DNSSEC. Uses the same
* format as the KEY record.
*/
public static final int DNSKEY = 48;
/**
* Dynamic Host Configuration Protocol (DHCP) ID. DHCP identifier record RFC 4701
* Used in conjunction with the FQDN option to DHCP.
*/
public static final int DHCID = 49;
/**
* Next SECure, 3rd edition, RFC 5155. An extension to DNSSEC that allows proof
* of nonexistence for a name without permitting zonewalking.
*/
public static final int NSEC3 = 50;
/**
* NSEC3 parameters record RFC 5155 Parameter record for use with NSEC3.
*/
public static final int NSEC3PARAM = 51;
/**
* Transport Layer Security Authentication, draft-ietf-dane-protocol-23.
* TLSA certificate association record RFC 6698 A record for DNS-based
* Authentication of Named Entities (DANE). RFC 6698 defines The TLSA DNS
* resource record is used to associate a TLS server certificate or public
* key with the domain name where the record is found, thus forming a 'TLSA
* certificate association'.
*/
public static final int TLSA = 52;
/**
* S/MIME cert association, draft-ietf-dane-smime
*/
public static final int SMIMEA = 53;
/**
* Host Identity Protocol record RFC 5205 Method of separating the end-point
* identifier and locator roles of IP addresses.
*/
public static final int HIP = 55;
/**
* OpenPGP Key, RFC 7929
*/
public static final int OPENPGPKEY = 61;
/**
* Sender Policy Framework (experimental) record RFC 4408 Specified as part of the SPF
* protocol as an alternative to of storing SPF data in TXT records. Uses
* the same format as the earlier TXT record.
*/
public static final int SPF = 99;
/**
* Transaction key - used to compute a shared secret or exchange a key.
* Secret key record RFC 2930 A method of providing keying material to be
* used with TSIG that is encrypted under the public key in an accompanying
* KEY RR..
*/
public static final int TKEY = 249;
/**
* Transaction Signature record RFC 2845 Can be used to authenticate dynamic
* updates as coming from an approved client, or to authenticate responses
* as coming from an approved recursive name server similar to DNSSEC.
*/
public static final int TSIG = 250;
/**
* Incremental Zone Transfer record RFC 1996 Requests a zone transfer of the
* given zone but only differences from a previous serial number. This
* request may be ignored and a full (AXFR) sent in response if the
* authoritative server is unable to fulfill the request due to
* configuration or lack of required deltas.
*/
public static final int IXFR = 251;
/**
* Authoritative Zone Transfer record RFC 1035 Transfer entire zone file
* from the master name server to secondary name servers.
*/
public static final int AXFR = 252;
/**
* Transfer mailbox records
*/
public static final int MAILB = 253;
/**
* Transfer mail agent records
*/
public static final int MAILA = 254;
/**
* Matches any type
*
* All cached records RFC 1035 Returns all records of all types known to the
* name server. If the name server does not have any information on the
* name, the request will be forwarded on. The records returned may not be
* complete. For example, if there is both an A and an MX for a name, but
* the name server has only the A record cached, only the A record will be
* returned. Sometimes referred to as ANY, for example in Windows nslookup
* and Wireshark.
*/
public static final int ANY = 255;
/**
* URI
*
* @see <a href="http://tools.ietf.org/html/draft-faltstrom-uri-14">draft-faltstrom-uri-14</a>
*/
public static final int URI = 256;
/**
* Certification Authority Authorization, RFC 6844. CA pinning,
* constraining acceptable CAs for a host/domain.
*/
public static final int CAA = 257;
/**
* DNSSEC Trust Authorities record N/A Part of a deployment proposal for
* DNSSEC without a signed DNS root. See the IANA database and Weiler Spec
* for details. Uses the same format as the DS record.
*/
public static final int TA = 32768;
/**
* DNSSEC Lookaside Validation, RFC 4431. For publishing DNSSEC trust
* anchors outside of the DNS delegation chain. Uses the same format as the
* DS record. RFC 5074 describes a way of using these records.
*/
public static final int DLV = 32769;
private static TypeMnemonic types = new TypeMnemonic();
public static
class TypeMnemonic extends Mnemonic {
private IntMap<DnsRecord> objects;
public
TypeMnemonic() {
super("DnsRecordType", CASE_UPPER);
setPrefix("TYPE");
objects = new IntMap<DnsRecord>();
}
public
void add(int value, String str, DnsRecord proto) {
super.add(value, str);
objects.put(value, proto);
}
@SuppressWarnings("unchecked")
public
<T extends DnsRecord> T getProto(int value) {
check(value);
return (T) objects.get(value);
}
@Override
public
void check(int val) {
DnsRecordType.check(val);
}
}
static {
// this is so we don't have to make each type constructor public
DnsTypeProtoAssignment.assign(types);
}
private
DnsRecordType() {
}
/**
* Checks that a numeric DnsRecordType is valid.
*
* @throws InvalidTypeException The type is out of range.
*/
public static
void check(int val) {
if (val < 0 || val > 0xFFFF) {
throw new InvalidTypeException(val);
}
}
/**
* Converts a numeric DnsRecordType into a String
*
* @param val The type value.
*
* @return The canonical string representation of the type
*
* @throws InvalidTypeException The type is out of range.
*/
public static
String string(int val) {
return types.getText(val);
}
/**
* Converts a String representation of an DnsRecordType into its numeric value
*
* @return The type code, or -1 on error.
*/
public static
int value(String s) {
return value(s, false);
}
/**
* Converts a String representation of an DnsRecordType into its numeric value.
*
* @param s The string representation of the type
* @param numberok Whether a number will be accepted or not.
*
* @return The type code, or -1 on error.
*/
public static
int value(String s, boolean numberok) {
int val = types.getValue(s);
if (val == -1 && numberok) {
val = types.getValue("TYPE" + s);
}
return val;
}
public static
<T extends DnsRecord> T getProto(int val) {
return types.getProto(val);
}
/**
* Is this type valid for a record (a non-meta type)?
*/
public static
boolean isRR(int type) {
switch (type) {
case OPT:
case TKEY:
case TSIG:
case IXFR:
case AXFR:
case MAILB:
case MAILA:
case ANY:
return false;
default:
return true;
}
}
private static final String ptrSuffix = ".in-addr.arpa";
/**
* Guarantees that the specified host name is a FQND. This depends on it's type, which must also be specified.
*
* @param type the resource record type
* @param hostName the hostname
*
* @return the Fully Qualified Domain Name for this hostname, depending on it's type
*/
public static
String ensureFQDN(int type, String hostName) {
// list of RecordTypes from: https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html
switch (type) {
case PTR:
if (!hostName.endsWith(ptrSuffix)) {
// PTR absolutely MUST end in '.in-addr.arpa' in order for the DNS server to understand it.
// in this case, hostname is an ip address
return hostName + ptrSuffix;
}
case A:
case AAAA:
case CAA:
case CNAME:
case MX:
case NAPTR:
case NS:
case SOA:
case SPF:
case SRV:
case TXT:
// resolving a hostname -> ip address, the hostname MUST end in a dot
if (!StringUtil.endsWith(hostName, '.')) {
return hostName + '.';
} else {
return hostName;
}
default:
return hostName;
}
}
}

View File

@ -1,180 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.constants;
import dorkbox.network.dns.Mnemonic;
/**
* Constants and functions relating to DNS rcodes (error values)
*
* @author Brian Wellington
*/
public final
class DnsResponseCode {
private static Mnemonic rcodes = new Mnemonic("DNS DnsResponseCode", Mnemonic.CASE_UPPER);
private static Mnemonic tsigrcodes = new Mnemonic("TSIG rcode", Mnemonic.CASE_UPPER);
/**
* No error
*/
public static final int NOERROR = 0;
/**
* Format error
*/
public static final int FORMERR = 1;
/**
* Server failure
*/
public static final int SERVFAIL = 2;
/**
* The name does not exist
*/
public static final int NXDOMAIN = 3;
/**
* The operation requested is not implemented
*/
public static final int NOTIMP = 4;
/**
* Deprecated synonym for NOTIMP.
*/
public static final int NOTIMPL = 4;
/**
* The operation was refused by the server
*/
public static final int REFUSED = 5;
/**
* The name exists
*/
public static final int YXDOMAIN = 6;
/**
* The RRset (name, type) exists
*/
public static final int YXRRSET = 7;
/**
* The RRset (name, type) does not exist
*/
public static final int NXRRSET = 8;
/**
* The requestor is not authorized to perform this operation
*/
public static final int NOTAUTH = 9;
/**
* The zone specified is not a zone
*/
public static final int NOTZONE = 10;
/* EDNS extended rcodes */
/**
* Unsupported EDNS level
*/
public static final int BADVERS = 16;
/* TSIG/TKEY only rcodes */
/**
* The signature is invalid (TSIG/TKEY extended error)
*/
public static final int BADSIG = 16;
/**
* The key is invalid (TSIG/TKEY extended error)
*/
public static final int BADKEY = 17;
/**
* The time is out of range (TSIG/TKEY extended error)
*/
public static final int BADTIME = 18;
/**
* The mode is invalid (TKEY extended error)
*/
public static final int BADMODE = 19;
/**
* The 'BADNAME' DNS RCODE (20), as defined in <a href="https://tools.ietf.org/html/rfc2930">RFC2930</a>.
*/
public static final int BADNAME = 20;
/**
* The 'BADALG' DNS RCODE (21), as defined in <a href="https://tools.ietf.org/html/rfc2930">RFC2930</a>.
*/
public static final int BADALG = 21;
static {
rcodes.setMaximum(0xFFF);
rcodes.setPrefix("RESERVED");
rcodes.setNumericAllowed(true);
rcodes.add(NOERROR, "NOERROR");
rcodes.add(FORMERR, "FORMERR");
rcodes.add(SERVFAIL, "SERVFAIL");
rcodes.add(NXDOMAIN, "NXDOMAIN");
rcodes.add(NOTIMP, "NOTIMP");
rcodes.addAlias(NOTIMP, "NOTIMPL");
rcodes.add(REFUSED, "REFUSED");
rcodes.add(YXDOMAIN, "YXDOMAIN");
rcodes.add(YXRRSET, "YXRRSET");
rcodes.add(NXRRSET, "NXRRSET");
rcodes.add(NOTAUTH, "NOTAUTH");
rcodes.add(NOTZONE, "NOTZONE");
rcodes.add(BADVERS, "BADVERS");
tsigrcodes.setMaximum(0xFFFF);
tsigrcodes.setPrefix("RESERVED");
tsigrcodes.setNumericAllowed(true);
tsigrcodes.addAll(rcodes);
tsigrcodes.add(BADSIG, "BADSIG");
tsigrcodes.add(BADKEY, "BADKEY");
tsigrcodes.add(BADTIME, "BADTIME");
tsigrcodes.add(BADMODE, "BADMODE");
tsigrcodes.add(BADNAME, "BADNAME");
tsigrcodes.add(BADALG, "BADALG");
}
private
DnsResponseCode() {}
/**
* Converts a numeric DnsResponseCode into a String
*/
public static
String string(int i) {
return rcodes.getText(i);
}
/**
* Converts a numeric TSIG extended DnsResponseCode into a String
*/
public static
String TSIGstring(int i) {
return tsigrcodes.getText(i);
}
/**
* Converts a String representation of an DnsResponseCode into its numeric value
*/
public static
int value(String s) {
return rcodes.getValue(s);
}
}

View File

@ -1,115 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.constants;
import dorkbox.network.dns.Mnemonic;
/**
* Constants and functions relating to DNS message sections
*
* @author Brian Wellington
*/
public final
class DnsSection {
public static final int TOTAL_SECTION_COUNT = 4;
/**
* The question (first) section
*/
public static final int QUESTION = 0;
/**
* The answer (second) section
*/
public static final int ANSWER = 1;
/**
* The authority (third) section
*/
public static final int AUTHORITY = 2;
/**
* The additional (fourth) section
*/
public static final int ADDITIONAL = 3;
/* Aliases for dynamic update */
/**
* The zone (first) section of a dynamic update message
*/
public static final int ZONE = 0;
/**
* The prerequisite (second) section of a dynamic update message
*/
public static final int PREREQ = 1;
/**
* The update (third) section of a dynamic update message
*/
public static final int UPDATE = 2;
private static Mnemonic sections = new Mnemonic("DnsMessage DnsSection", Mnemonic.CASE_LOWER);
private static String[] longSections = new String[4];
private static String[] updateSections = new String[4];
static {
sections.setMaximum(3);
sections.setNumericAllowed(true);
sections.add(QUESTION, "qd");
sections.add(ANSWER, "an");
sections.add(AUTHORITY, "au");
sections.add(ADDITIONAL, "ad");
longSections[QUESTION] = "QUESTIONS";
longSections[ANSWER] = "ANSWERS";
longSections[AUTHORITY] = "AUTHORITY RECORDS";
longSections[ADDITIONAL] = "ADDITIONAL RECORDS";
updateSections[ZONE] = "ZONE";
updateSections[PREREQ] = "PREREQUISITES";
updateSections[UPDATE] = "UPDATE RECORDS";
updateSections[ADDITIONAL] = "ADDITIONAL RECORDS";
}
private
DnsSection() {}
/**
* Converts a numeric DnsSection into an abbreviation String
*/
public static
String string(int i) {
return sections.getText(i);
}
/**
* Converts a numeric DnsSection into a full description String
*/
public static
String longString(int i) {
sections.check(i);
return longSections[i];
}
/**
* Converts a numeric DnsSection into a full description String for an update
* DnsMessage.
*/
public static
String updString(int i) {
sections.check(i);
return updateSections[i];
}
/**
* Converts a String representation of a DnsSection into its numeric value
*/
public static
int value(String s) {
return sections.getValue(s);
}
}

View File

@ -1,81 +0,0 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.network.dns.constants;
import dorkbox.network.dns.Mnemonic;
/**
* Constants and functions relating to EDNS flags.
*
* @author Brian Wellington
*/
public
enum ExtendedFlags {
/**
* dnssec ok
*/
DO(0x8000, "do");
private static Mnemonic extflags = new Mnemonic("EDNS Flag", Mnemonic.CASE_LOWER);
static {
extflags.setMaximum(0xFFFF);
extflags.setPrefix("FLAG");
extflags.setNumericAllowed(true);
extflags.add(DO.flagValue, "do");
}
private final byte flagValue;
private final String textValue;
ExtendedFlags(final int flagValue, final String textValue) {
this.flagValue = (byte) flagValue;
this.textValue = textValue;
}
public
byte value() {
return flagValue;
}
public
String string() {
return textValue;
}
/**
* Converts a numeric extended flag into a String
*/
public static
String string(int i) {
return extflags.getText(i);
}
/**
* Converts a textual representation of an extended flag into its numeric
* value
*/
public static
int value(String s) {
return extflags.getValue(s);
}
}

View File

@ -1,149 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.constants;
import dorkbox.network.dns.Mnemonic;
/**
* Constants and functions relating to flags in the DNS header.
*
* In DNS query header there is a flag field in the second 16 bit word in query from bit 5 through bit 11 ([RFC1035] section 4.1.1)
*
* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-12
*/
public
enum Flags {
/**
* query/response
*/
QR(0, "qr"),
/**
* authoritative answer
*/
AA(5, "aa"),
/**
* truncated
*/
TC(6, "tc"),
/**
* recursion desired
*/
RD(7, "rd"),
/**
* recursion available
*/
RA(8, "ra"),
/**
* RESERVED
*/
RESERVED(9, "__"),
/**
* authenticated data
*/
AD(10, "ad"),
/**
* (security) checking disabled
*/
CD(11, "cd"),
/**
* dnssec ok (extended)
*/
DO(ExtendedFlags.DO.value(), ExtendedFlags.DO.string());
private static Mnemonic flags = new Mnemonic("DNS Header Flag", Mnemonic.CASE_LOWER);
static {
flags.setMaximum(0xF);
flags.setPrefix("FLAG");
flags.setNumericAllowed(true);
flags.add(QR.flagValue, "qr");
flags.add(AA.flagValue, "aa");
flags.add(TC.flagValue, "tc");
flags.add(RD.flagValue, "rd");
flags.add(RA.flagValue, "ra");
flags.add(AD.flagValue, "ad");
flags.add(CD.flagValue, "cd");
}
private final byte flagValue;
private final String textValue;
Flags(final int flagValue, final String textValue) {
this.flagValue = (byte) flagValue;
this.textValue = textValue;
}
public
byte value() {
return flagValue;
}
public
String string() {
return textValue;
}
public static
Flags toFlag(final int flagBit) {
for (Flags flag : values()) {
if (flag.value() == flagBit) {
return flag;
}
}
throw new IllegalArgumentException("Invalid flag " + flagBit);
}
public static
Flags toFlag(final String flagName) {
for (Flags flag : values()) {
if (flag.string().equals(flagName)) {
return flag;
}
}
throw new IllegalArgumentException("Invalid flag " + flagName);
}
// /**
// * Converts a numeric Flag into a String
// */
// public static
// String string(int i) {
// return flags.getText(i);
// }
//
// /**
// * Converts a String representation of an Flag into its numeric value
// */
// public static
// int value(String s) {
// return flags.getValue(s);
// }
/**
* Indicates if a bit in the flags field is a flag or not. If it's part of the rcode or opcode, it's not.
*/
public static
boolean isFlag(int index) {
// Checks that a numeric value is within the range
if (index < 0 || index > 0xF || (index >= 1 && index <= 4) || (index >= 12)) {
return false;
}
return true;
}
}

View File

@ -1,19 +0,0 @@
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.exceptions;
/**
* An exception thrown when an invalid dclass code is specified.
*
* @author Brian Wellington
*/
public
class InvalidDClassException extends IllegalArgumentException {
public
InvalidDClassException(int dclass) {
super("Invalid DNS class: " + dclass);
}
}

View File

@ -1,19 +0,0 @@
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.exceptions;
/**
* An exception thrown when an invalid TTL is specified.
*
* @author Brian Wellington
*/
public
class InvalidTTLException extends IllegalArgumentException {
public
InvalidTTLException(long ttl) {
super("Invalid DNS TTL: " + ttl);
}
}

View File

@ -1,19 +0,0 @@
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.exceptions;
/**
* An exception thrown when an invalid type code is specified.
*
* @author Brian Wellington
*/
public
class InvalidTypeException extends IllegalArgumentException {
public
InvalidTypeException(int type) {
super("Invalid DNS type: " + type);
}
}

View File

@ -1,25 +0,0 @@
// Copyright (c) 2002-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.exceptions;
/**
* An exception thrown when a name is longer than the maximum length of a DNS
* name.
*
* @author Brian Wellington
*/
public
class NameTooLongException extends WireParseException {
public
NameTooLongException() {
super();
}
public
NameTooLongException(String s) {
super(s);
}
}

View File

@ -1,27 +0,0 @@
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.exceptions;
import dorkbox.network.dns.Name;
/**
* An exception thrown when a relative name is passed as an argument to
* a method requiring an absolute name.
*
* @author Brian Wellington
*/
public
class RelativeNameException extends IllegalArgumentException {
public
RelativeNameException(Name name) {
super("'" + name + "' is not an absolute name");
}
public
RelativeNameException(String s) {
super(s);
}
}

View File

@ -1,26 +0,0 @@
// Copyright (c) 2002-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.exceptions;
import java.io.IOException;
/**
* An exception thrown when unable to parse text.
*
* @author Brian Wellington
*/
public
class TextParseException extends IOException {
public
TextParseException() {
super();
}
public
TextParseException(String s) {
super(s);
}
}

View File

@ -1,32 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.exceptions;
import java.io.IOException;
/**
* An exception thrown when a DNS message is invalid.
*
* @author Brian Wellington
*/
public
class WireParseException extends IOException {
public
WireParseException() {
super();
}
public
WireParseException(String s) {
super(s);
}
public
WireParseException(String s, Throwable cause) {
super(s);
initCause(cause);
}
}

View File

@ -1,24 +0,0 @@
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.exceptions;
/**
* An exception thrown when a zone transfer fails.
*
* @author Brian Wellington
*/
public
class ZoneTransferException extends Exception {
public
ZoneTransferException() {
super();
}
public
ZoneTransferException(String s) {
super(s);
}
}

View File

@ -1,147 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Address;
import dorkbox.network.dns.utils.Tokenizer;
/**
* A6 Record - maps a domain name to an IPv6 address (experimental)
*
* @author Brian Wellington
*/
public
class A6Record extends DnsRecord {
private static final long serialVersionUID = -8815026887337346789L;
private int prefixBits;
private InetAddress suffix;
private Name prefix;
A6Record() {}
@Override
DnsRecord getObject() {
return new A6Record();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
prefixBits = in.readU8();
int suffixbits = 128 - prefixBits;
int suffixbytes = (suffixbits + 7) / 8;
if (prefixBits < 128) {
byte[] bytes = new byte[16];
in.readByteArray(bytes, 16 - suffixbytes, suffixbytes);
suffix = InetAddress.getByAddress(bytes);
}
if (prefixBits > 0) {
prefix = new Name(in);
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(prefixBits);
if (suffix != null) {
int suffixbits = 128 - prefixBits;
int suffixbytes = (suffixbits + 7) / 8;
byte[] data = suffix.getAddress();
out.writeByteArray(data, 16 - suffixbytes, suffixbytes);
}
if (prefix != null) {
prefix.toWire(out, null, canonical);
}
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(prefixBits);
if (suffix != null) {
sb.append(" ");
sb.append(suffix.getHostAddress());
}
if (prefix != null) {
sb.append(" ");
sb.append(prefix);
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
prefixBits = st.getUInt8();
if (prefixBits > 128) {
throw st.exception("prefix bits must be [0..128]");
}
else if (prefixBits < 128) {
String s = st.getString();
try {
suffix = Address.getByAddress(s, Address.IPv6);
} catch (UnknownHostException e) {
throw st.exception("invalid IPv6 address: " + s);
}
}
if (prefixBits > 0) {
prefix = st.getName(origin);
}
}
/**
* Creates an A6 Record from the given data
*
* @param prefixBits The number of bits in the address prefix
* @param suffix The address suffix
* @param prefix The name of the prefix
*/
public
A6Record(Name name, int dclass, long ttl, int prefixBits, InetAddress suffix, Name prefix) {
super(name, DnsRecordType.A6, dclass, ttl);
this.prefixBits = checkU8("prefixBits", prefixBits);
if (suffix != null && Address.familyOf(suffix) != Address.IPv6) {
throw new IllegalArgumentException("invalid IPv6 address");
}
this.suffix = suffix;
if (prefix != null) {
this.prefix = checkName("prefix", prefix);
}
}
/**
* Returns the number of bits in the prefix
*/
public
int getPrefixBits() {
return prefixBits;
}
/**
* Returns the address suffix
*/
public
InetAddress getSuffix() {
return suffix;
}
/**
* Returns the address prefix
*/
public
Name getPrefix() {
return prefix;
}
}

View File

@ -1,122 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Address;
import dorkbox.network.dns.utils.Tokenizer;
/**
* IPv6 Address Record - maps a domain name to an IPv6 address
*
* @author Brian Wellington
*/
public
class AAAARecord extends DnsRecord {
private static final long serialVersionUID = -4588601512069748050L;
private byte[] address;
AAAARecord() {}
@Override
DnsRecord getObject() {
return new AAAARecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
address = in.readByteArray(16);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeByteArray(address);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
InetAddress addr;
try {
addr = InetAddress.getByAddress(null, address);
} catch (UnknownHostException e) {
return;
}
if (addr.getAddress().length == 4) {
// Deal with Java's broken handling of mapped IPv4 addresses.
sb.append("0:0:0:0:0:ffff:");
int high = ((address[12] & 0xFF) << 8) + (address[13] & 0xFF);
int low = ((address[14] & 0xFF) << 8) + (address[15] & 0xFF);
sb.append(Integer.toHexString(high));
sb.append(':');
sb.append(Integer.toHexString(low));
return;
}
sb.append(addr.getHostAddress());
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
address = st.getAddressBytes(Address.IPv6);
}
/**
* Creates an AAAA Record from the given data
*
* @param address The address that the name refers
*/
public
AAAARecord(Name name, int dclass, long ttl, InetAddress address) {
super(name, DnsRecordType.AAAA, dclass, ttl);
if (Address.familyOf(address) != Address.IPv6) {
throw new IllegalArgumentException("invalid IPv6 address");
}
this.address = address.getAddress();
}
/**
* Creates an AAAA Record from the given data
*
* @param address The address that the name refers to as a byte array. This value is NOT COPIED.
*/
public
AAAARecord(Name name, int dclass, long ttl, byte[] address) {
super(name, DnsRecordType.AAAA, dclass, ttl);
if (address.length != Address.addressLength(Address.IPv6)) {
throw new IllegalArgumentException("invalid IPv6 address");
}
this.address = address;
}
/**
* Returns the address
*/
public
InetAddress getAddress() {
try {
if (name == null) {
return InetAddress.getByAddress(address);
}
else {
return InetAddress.getByAddress(name.toString(true), address);
}
} catch (UnknownHostException e) {
return null;
}
}
}

View File

@ -1,53 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* AFS Data Base Record - maps a domain name to the name of an AFS cell
* database server.
*
* @author Brian Wellington
*/
public
class AFSDBRecord extends U16NameBase {
private static final long serialVersionUID = 3034379930729102437L;
AFSDBRecord() {}
@Override
DnsRecord getObject() {
return new AFSDBRecord();
}
/**
* Creates an AFSDB Record from the given data.
*
* @param subtype Indicates the type of service provided by the host.
* @param host The host providing the service.
*/
public
AFSDBRecord(Name name, int dclass, long ttl, int subtype, Name host) {
super(name, DnsRecordType.AFSDB, dclass, ttl, subtype, "subtype", host, "host");
}
/**
* Gets the subtype indicating the service provided by the host.
*/
public
int getSubtype() {
return getU16Field();
}
/**
* Gets the host providing service for the domain.
*/
public
Name getHost() {
return getNameField();
}
}

View File

@ -1,305 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.utils.Address;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* 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 DnsRecord {
private static final long serialVersionUID = -1348173791712935864L;
private List elements;
public static
class Element {
public final int family;
public final boolean negative;
public final int prefixLength;
public final Object address;
/**
* 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);
}
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");
}
}
public
int hashCode() {
return address.hashCode() + prefixLength + (negative ? 1 : 0);
}
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
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();
}
}
APLRecord() {}
@Override
DnsRecord getObject() {
return new APLRecord();
}
@Override
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);
}
}
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;
}
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;
}
@Override
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);
}
}
@Override
void rrToString(StringBuilder sb) {
for (Iterator it = elements.iterator(); it.hasNext(); ) {
Element element = (Element) it.next();
sb.append(element);
if (it.hasNext()) {
sb.append(" ");
}
}
}
@Override
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();
}
private static
int addressLength(byte[] addr) {
for (int i = addr.length - 1; i >= 0; i--) {
if (addr[i] != 0) {
return i + 1;
}
}
return 0;
}
/**
* 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, DnsRecordType.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);
}
}
/**
* Returns the list of APL elements.
*/
public
List getElements() {
return elements;
}
}

View File

@ -1,119 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Address;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Address Record - maps a domain name to an Internet address
*
* @author Brian Wellington
*/
public
class ARecord extends DnsRecord {
private static final long serialVersionUID = -2172609200849142323L;
private int addr;
ARecord() {}
@Override
DnsRecord getObject() {
return new ARecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
addr = fromArray(in.readByteArray(4));
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU32(((long) addr) & 0xFFFFFFFFL);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(Address.toDottedQuad(toArray(addr)));
}
private static
byte[] toArray(int addr) {
byte[] bytes = new byte[4];
bytes[0] = (byte) ((addr >>> 24) & 0xFF);
bytes[1] = (byte) ((addr >>> 16) & 0xFF);
bytes[2] = (byte) ((addr >>> 8) & 0xFF);
bytes[3] = (byte) (addr & 0xFF);
return bytes;
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
addr = fromArray(st.getAddressBytes(Address.IPv4));
}
private static
int fromArray(byte[] array) {
return (((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF));
}
/**
* Creates an A Record from the given data
*
* @param address The address that the name refers to
*/
public
ARecord(Name name, int dclass, long ttl, InetAddress address) {
super(name, DnsRecordType.A, dclass, ttl);
if (Address.familyOf(address) != Address.IPv4) {
throw new IllegalArgumentException("invalid IPv4 address");
}
addr = fromArray(address.getAddress());
}
/**
* Creates an A Record from the given data
*
* @param address The address that the name refers to as a byte array. This value is NOT COPIED.
*/
public
ARecord(Name name, int dclass, long ttl, byte[] address) {
super(name, DnsRecordType.A, dclass, ttl);
if (address.length != Address.addressLength(Address.IPv4)) {
throw new IllegalArgumentException("invalid IPv4 address");
}
addr = fromArray(address);
}
/**
* Returns the Internet address
*/
public
InetAddress getAddress() {
try {
if (name == null) {
return InetAddress.getByAddress(toArray(addr));
}
else {
return InetAddress.getByAddress(name.toString(true), toArray(addr));
}
} catch (UnknownHostException e) {
return null;
}
}
}

View File

@ -1,122 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Certification Authority Authorization
*
* @author Brian Wellington
*/
public
class CAARecord extends DnsRecord {
private static final long serialVersionUID = 8544304287274216443L;
private int flags;
private byte[] tag;
private byte[] value;
public static
class Flags {
public static final int IssuerCritical = 128;
private
Flags() {}
}
CAARecord() {}
@Override
DnsRecord getObject() {
return new CAARecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
flags = in.readU8();
tag = in.readCountedString();
value = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(flags);
out.writeCountedString(tag);
out.writeByteArray(value);
}
@Override
void rrToString(StringBuilder sb) {
sb.append(flags);
sb.append(" ");
sb.append(byteArrayToString(tag, false));
sb.append(" ");
sb.append(byteArrayToString(value, true));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
flags = st.getUInt8();
try {
tag = byteArrayFromString(st.getString());
value = byteArrayFromString(st.getString());
} catch (TextParseException e) {
throw st.exception(e.getMessage());
}
}
/**
* Creates an CAA Record from the given data.
*
* @param flags The flags.
* @param tag The tag.
* @param value The value.
*/
public
CAARecord(Name name, int dclass, long ttl, int flags, String tag, String value) {
super(name, DnsRecordType.CAA, dclass, ttl);
this.flags = checkU8("flags", flags);
try {
this.tag = byteArrayFromString(tag);
this.value = byteArrayFromString(value);
} catch (TextParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
/**
* Returns the flags.
*/
public
int getFlags() {
return flags;
}
/**
* Returns the tag.
*/
public
String getTag() {
return byteArrayToString(tag, false);
}
/**
* Returns the value
*/
public
String getValue() {
return byteArrayToString(value, false);
}
}

View File

@ -1,257 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Mnemonic;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Options;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.util.Base64Fast;
import dorkbox.util.OS;
/**
* Certificate Record - Stores a certificate associated with a name. The
* certificate might also be associated with a KEYRecord.
*
* @author Brian Wellington
* @see KEYRecord
*/
public
class CERTRecord extends DnsRecord {
/**
* PKIX (X.509v3)
*/
public static final int PKIX = CertificateType.PKIX;
/**
* Simple Public Key Infrastructure
*/
public static final int SPKI = CertificateType.SPKI;
/**
* Pretty Good Privacy
*/
public static final int PGP = CertificateType.PGP;
/**
* Certificate format defined by URI
*/
public static final int URI = CertificateType.URI;
/**
* Certificate format defined by IOD
*/
public static final int OID = CertificateType.OID;
private static final long serialVersionUID = 4763014646517016835L;
private int certType, keyTag;
private int alg;
private byte[] cert;
public static
class CertificateType {
/**
* PKIX (X.509v3)
*/
public static final int PKIX = 1;
/**
* Simple Public Key Infrastructure
*/
public static final int SPKI = 2;
/**
* Pretty Good Privacy
*/
public static final int PGP = 3;
/**
* URL of an X.509 data object
*/
public static final int IPKIX = 4;
/**
* URL of an SPKI certificate
*/
public static final int ISPKI = 5;
/**
* Fingerprint and URL of an OpenPGP packet
*/
public static final int IPGP = 6;
/**
* Attribute Certificate
*/
public static final int ACPKIX = 7;
/**
* URL of an Attribute Certificate
*/
public static final int IACPKIX = 8;
/**
* Certificate format defined by URI
*/
public static final int URI = 253;
/**
* Certificate format defined by OID
*/
public static final int OID = 254;
private static Mnemonic types = new Mnemonic("Certificate type", Mnemonic.CASE_UPPER);
/**
* Certificate type identifiers. See RFC 4398 for more detail.
*/
private
CertificateType() {}
static {
types.setMaximum(0xFFFF);
types.setNumericAllowed(true);
types.add(PKIX, "PKIX");
types.add(SPKI, "SPKI");
types.add(PGP, "PGP");
types.add(PKIX, "IPKIX");
types.add(SPKI, "ISPKI");
types.add(PGP, "IPGP");
types.add(PGP, "ACPKIX");
types.add(PGP, "IACPKIX");
types.add(URI, "URI");
types.add(OID, "OID");
}
/**
* Converts a certificate type into its textual representation
*/
public static
String string(int type) {
return types.getText(type);
}
/**
* Converts a textual representation of an certificate type into its
* numeric code. Integers in the range 0..65535 are also accepted.
*
* @param s The textual representation of the algorithm
*
* @return The algorithm code, or -1 on error.
*/
public static
int value(String s) {
return types.getValue(s);
}
}
CERTRecord() {}
@Override
DnsRecord getObject() {
return new CERTRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
certType = in.readU16();
keyTag = in.readU16();
alg = in.readU8();
cert = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(certType);
out.writeU16(keyTag);
out.writeU8(alg);
out.writeByteArray(cert);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(certType);
sb.append(" ");
sb.append(keyTag);
sb.append(" ");
sb.append(alg);
if (cert != null) {
if (Options.check("multiline")) {
sb.append(" (");
sb.append(OS.LINE_SEPARATOR);
sb.append(Base64Fast.formatString(Base64Fast.encode2(cert), 64, "\t", true));
}
else {
sb.append(" ");
sb.append(Base64Fast.encode2(cert));
}
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
String certTypeString = st.getString();
certType = CertificateType.value(certTypeString);
if (certType < 0) {
throw st.exception("Invalid certificate type: " + certTypeString);
}
keyTag = st.getUInt16();
String algString = st.getString();
alg = DNSSEC.Algorithm.value(algString);
if (alg < 0) {
throw st.exception("Invalid algorithm: " + algString);
}
cert = st.getBase64();
}
/**
* Creates a CERT Record from the given data
*
* @param certType The type of certificate (see constants)
* @param keyTag The ID of the associated KEYRecord, if present
* @param alg The algorithm of the associated KEYRecord, if present
* @param cert Binary data representing the certificate
*/
public
CERTRecord(Name name, int dclass, long ttl, int certType, int keyTag, int alg, byte[] cert) {
super(name, DnsRecordType.CERT, dclass, ttl);
this.certType = checkU16("certType", certType);
this.keyTag = checkU16("keyTag", keyTag);
this.alg = checkU8("alg", alg);
this.cert = cert;
}
/**
* Returns the type of certificate
*/
public
int getCertType() {
return certType;
}
/**
* Returns the ID of the associated KEYRecord, if present
*/
public
int getKeyTag() {
return keyTag;
}
/**
* Returns the algorithm of the associated KEYRecord, if present
*/
public
int getAlgorithm() {
return alg;
}
/**
* Returns the binary representation of the certificate
*/
public
byte[] getCert() {
return cert;
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* CNAME Record - maps an alias to its real name
*
* @author Brian Wellington
*/
public
class CNAMERecord extends SingleCompressedNameBase {
private static final long serialVersionUID = -4020373886892538580L;
CNAMERecord() {}
@Override
DnsRecord getObject() {
return new CNAMERecord();
}
/**
* Creates a new CNAMERecord with the given data
*
* @param alias The name to which the CNAME alias points
*/
public
CNAMERecord(Name name, int dclass, long ttl, Name alias) {
super(name, DnsRecordType.CNAME, dclass, ttl, alias, "alias");
}
/**
* Gets the target of the CNAME Record
*/
public
Name getTarget() {
return getSingleName();
}
/**
* Gets the alias specified by the CNAME Record
*/
public
Name getAlias() {
return getSingleName();
}
}

View File

@ -1,187 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.net.InetAddress;
import java.net.UnknownHostException;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.utils.Address;
/**
* The Client Subnet EDNS Option, defined in
* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-00
* ("Client subnet in DNS requests").
* <p>
* The option is used to convey information about the IP address of the
* originating client, so that an authoritative server can make decisions
* based on this address, rather than the address of the intermediate
* caching name server.
* <p>
* The option is transmitted as part of an OPTRecord in the additional section
* of a DNS message, as defined by RFC 2671 (EDNS0).
* <p>
* The wire format of the option contains a 2-byte length field (1 for IPv4, 2
* for IPv6), a 1-byte source netmask, a 1-byte scope netmask, and an address
* truncated to the source netmask length (where the final octet is padded with
* bits set to 0)
*
* @author Brian Wellington
* @author Ming Zhou &lt;mizhou@bnivideo.com&gt;, Beaumaris Networks
* @see OPTRecord
*/
public
class ClientSubnetOption extends EDNSOption {
private static final long serialVersionUID = -3868158449890266347L;
private int family;
private int sourceNetmask;
private int scopeNetmask;
private InetAddress address;
ClientSubnetOption() {
super(EDNSOption.Code.CLIENT_SUBNET);
}
/**
* Construct a Client Subnet option with scope netmask set to 0.
*
* @param sourceNetmask The length of the netmask pertaining to the query.
* In replies, it mirrors the same value as in the requests.
* @param address The address of the client.
*
* @see ClientSubnetOption
*/
public
ClientSubnetOption(int sourceNetmask, InetAddress address) {
this(sourceNetmask, 0, address);
}
/**
* Construct a Client Subnet option. Note that the number of significant bits
* in the address must not be greater than the supplied source netmask. There
* may also be issues related to Java's handling of mapped addresses
*
* @param sourceNetmask The length of the netmask pertaining to the query.
* In replies, it mirrors the same value as in the requests.
* @param scopeNetmask The length of the netmask pertaining to the reply.
* In requests, it MUST be set to 0. In responses, this may or may not match
* the source netmask.
* @param address The address of the client.
*/
public
ClientSubnetOption(int sourceNetmask, int scopeNetmask, InetAddress address) {
super(EDNSOption.Code.CLIENT_SUBNET);
this.family = Address.familyOf(address);
this.sourceNetmask = checkMaskLength("source netmask", this.family, sourceNetmask);
this.scopeNetmask = checkMaskLength("scope netmask", this.family, scopeNetmask);
this.address = Address.truncate(address, sourceNetmask);
if (!address.equals(this.address)) {
throw new IllegalArgumentException("source netmask is not " + "valid for address");
}
}
private static
int checkMaskLength(String field, int family, int val) {
int max = Address.addressLength(family) * 8;
if (val < 0 || val > max) {
throw new IllegalArgumentException("\"" + field + "\" " + val + " must be in the range " + "[0.." + max + "]");
}
return val;
}
/**
* Returns the family of the network address. This will be either IPv4 (1)
* or IPv6 (2).
*/
public
int getFamily() {
return family;
}
/**
* Returns the source netmask.
*/
public
int getSourceNetmask() {
return sourceNetmask;
}
/**
* Returns the scope netmask.
*/
public
int getScopeNetmask() {
return scopeNetmask;
}
/**
* Returns the IP address of the client.
*/
public
InetAddress getAddress() {
return address;
}
@Override
void optionFromWire(DnsInput in) throws WireParseException {
family = in.readU16();
if (family != Address.IPv4 && family != Address.IPv6) {
throw new WireParseException("unknown address family");
}
sourceNetmask = in.readU8();
if (sourceNetmask > Address.addressLength(family) * 8) {
throw new WireParseException("invalid source netmask");
}
scopeNetmask = in.readU8();
if (scopeNetmask > Address.addressLength(family) * 8) {
throw new WireParseException("invalid scope netmask");
}
// Read the truncated address
byte[] addr = in.readByteArray();
if (addr.length != (sourceNetmask + 7) / 8) {
throw new WireParseException("invalid address");
}
// Convert it to a full length address.
byte[] fulladdr = new byte[Address.addressLength(family)];
System.arraycopy(addr, 0, fulladdr, 0, addr.length);
try {
address = InetAddress.getByAddress(fulladdr);
} catch (UnknownHostException e) {
throw new WireParseException("invalid address", e);
}
InetAddress tmp = Address.truncate(address, sourceNetmask);
if (!tmp.equals(address)) {
throw new WireParseException("invalid padding");
}
}
@Override
void optionToWire(DnsOutput out) {
out.writeU16(family);
out.writeU8(sourceNetmask);
out.writeU8(scopeNetmask);
out.writeByteArray(address.getAddress(), 0, (sourceNetmask + 7) / 8);
}
@Override
String optionToString() {
StringBuilder sb = new StringBuilder();
sb.append(address.getHostAddress());
sb.append("/");
sb.append(sourceNetmask);
sb.append(", scope netmask ");
sb.append(scopeNetmask);
return sb.toString();
}
}

View File

@ -1,74 +0,0 @@
// Copyright (c) 2008 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.util.Base64Fast;
/**
* DHCID - Dynamic Host Configuration Protocol (DHCP) ID (RFC 4701)
*
* @author Brian Wellington
*/
public
class DHCIDRecord extends DnsRecord {
private static final long serialVersionUID = -8214820200808997707L;
private byte[] data;
DHCIDRecord() {}
@Override
DnsRecord getObject() {
return new DHCIDRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
data = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeByteArray(data);
}
@Override
void rrToString(StringBuilder sb) {
sb.append(Base64Fast.encode2(data));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
data = st.getBase64();
}
/**
* Creates an DHCID Record from the given data
*
* @param data The binary data, which is opaque to DNS.
*/
public
DHCIDRecord(Name name, int dclass, long ttl, byte[] data) {
super(name, DnsRecordType.DHCID, dclass, ttl);
this.data = data;
}
/**
* Returns the binary data.
*/
public
byte[] getData() {
return data;
}
}

View File

@ -1,136 +0,0 @@
// Copyright (c) 2002-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* DLV - contains a Delegation Lookaside Validation record, which acts
* as the equivalent of a DS record in a lookaside zone.
*
* @author David Blacka
* @author Brian Wellington
* @see DNSSEC
* @see DSRecord
*/
public
class DLVRecord extends DnsRecord {
public static final int SHA1_DIGEST_ID = DSRecord.Digest.SHA1;
public static final int SHA256_DIGEST_ID = DSRecord.Digest.SHA1;
private static final long serialVersionUID = 1960742375677534148L;
private int footprint;
private int alg;
private int digestid;
private byte[] digest;
DLVRecord() {}
@Override
DnsRecord getObject() {
return new DLVRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
footprint = in.readU16();
alg = in.readU8();
digestid = in.readU8();
digest = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(footprint);
out.writeU8(alg);
out.writeU8(digestid);
if (digest != null) {
out.writeByteArray(digest);
}
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(footprint);
sb.append(" ");
sb.append(alg);
sb.append(" ");
sb.append(digestid);
if (digest != null) {
sb.append(" ");
sb.append(base16.toString(digest));
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
footprint = st.getUInt16();
alg = st.getUInt8();
digestid = st.getUInt8();
digest = st.getHex();
}
/**
* Creates a DLV Record from the given data
*
* @param footprint The original KEY record's footprint (keyid).
* @param alg The original key algorithm.
* @param digestid The digest id code.
* @param digest A hash of the original key.
*/
public
DLVRecord(Name name, int dclass, long ttl, int footprint, int alg, int digestid, byte[] digest) {
super(name, DnsRecordType.DLV, dclass, ttl);
this.footprint = checkU16("footprint", footprint);
this.alg = checkU8("alg", alg);
this.digestid = checkU8("digestid", digestid);
this.digest = digest;
}
/**
* Returns the key's algorithm.
*/
public
int getAlgorithm() {
return alg;
}
/**
* Returns the key's Digest ID.
*/
public
int getDigestID() {
return digestid;
}
/**
* Returns the binary hash of the key.
*/
public
byte[] getDigest() {
return digest;
}
/**
* Returns the key's footprint.
*/
public
int getFootprint() {
return footprint;
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* DNAME Record - maps a nonterminal alias (subtree) to a different domain
*
* @author Brian Wellington
*/
public
class DNAMERecord extends SingleNameBase {
private static final long serialVersionUID = 2670767677200844154L;
DNAMERecord() {}
@Override
DnsRecord getObject() {
return new DNAMERecord();
}
/**
* Creates a new DNAMERecord with the given data
*
* @param alias The name to which the DNAME alias points
*/
public
DNAMERecord(Name name, int dclass, long ttl, Name alias) {
super(name, DnsRecordType.DNAME, dclass, ttl, alias, "alias");
}
/**
* Gets the target of the DNAME Record
*/
public
Name getTarget() {
return getSingleName();
}
/**
* Gets the alias specified by the DNAME Record
*/
public
Name getAlias() {
return getSingleName();
}
}

View File

@ -1,107 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.security.PublicKey;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Key - contains a cryptographic public key for use by DNS.
* The data can be converted to objects implementing
* java.security.interfaces.PublicKey
*
* @author Brian Wellington
* @see DNSSEC
*/
public
class DNSKEYRecord extends KEYBase {
private static final long serialVersionUID = -8679800040426675002L;
public static
class Protocol {
/**
* Key will be used for DNSSEC
*/
public static final int DNSSEC = 3;
private
Protocol() {}
}
public static
class Flags {
/**
* Key is a zone key
*/
public static final int ZONE_KEY = 0x100;
/**
* Key is a secure entry point key
*/
public static final int SEP_KEY = 0x1;
/**
* Key has been revoked
*/
public static final int REVOKE = 0x80;
private
Flags() {}
}
DNSKEYRecord() {}
@Override
DnsRecord getObject() {
return new DNSKEYRecord();
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
flags = st.getUInt16();
proto = st.getUInt8();
String algString = st.getString();
alg = DNSSEC.Algorithm.value(algString);
if (alg < 0) {
throw st.exception("Invalid algorithm: " + algString);
}
key = st.getBase64();
}
/**
* Creates a DNSKEY Record from the given data
*
* @param flags Flags describing the key's properties
* @param proto The protocol that the key was created for
* @param alg The key's algorithm
* @param key Binary representation of the key
*/
public
DNSKEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, byte[] key) {
super(name, DnsRecordType.DNSKEY, dclass, ttl, flags, proto, alg, key);
}
/**
* Creates a DNSKEY Record from the given data
*
* @param flags Flags describing the key's properties
* @param proto The protocol that the key was created for
* @param alg The key's algorithm
* @param key The key as a PublicKey
*
* @throws DNSSEC.DNSSECException The PublicKey could not be converted into DNS
* format.
*/
public
DNSKEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, PublicKey key) throws DNSSEC.DNSSECException {
super(name, DnsRecordType.DNSKEY, dclass, ttl, flags, proto, alg, DNSSEC.fromPublicKey(key, alg));
publicKey = key;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,170 +0,0 @@
// Copyright (c) 2002-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* DS - contains a Delegation Signer record, which acts as a
* placeholder for KEY records in the parent zone.
*
* @author David Blacka
* @author Brian Wellington
* @see DNSSEC
*/
public
class DSRecord extends DnsRecord {
public static final int SHA1_DIGEST_ID = Digest.SHA1;
public static final int SHA256_DIGEST_ID = Digest.SHA256;
public static final int GOST3411_DIGEST_ID = Digest.GOST3411;
public static final int SHA384_DIGEST_ID = Digest.SHA384;
private static final long serialVersionUID = -9001819329700081493L;
private int footprint;
private int alg;
private int digestid;
private byte[] digest;
public static
class Digest {
/**
* SHA-1
*/
public static final int SHA1 = 1;
/**
* SHA-256
*/
public static final int SHA256 = 2;
/**
* GOST R 34.11-94
*/
public static final int GOST3411 = 3;
/**
* SHA-384
*/
public static final int SHA384 = 4;
private
Digest() {}
}
DSRecord() {}
@Override
DnsRecord getObject() {
return new DSRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
footprint = in.readU16();
alg = in.readU8();
digestid = in.readU8();
digest = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(footprint);
out.writeU8(alg);
out.writeU8(digestid);
if (digest != null) {
out.writeByteArray(digest);
}
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(footprint);
sb.append(" ");
sb.append(alg);
sb.append(" ");
sb.append(digestid);
if (digest != null) {
sb.append(" ");
sb.append(base16.toString(digest));
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
footprint = st.getUInt16();
alg = st.getUInt8();
digestid = st.getUInt8();
digest = st.getHex();
}
/**
* Creates a DS Record from the given data
*
* @param digestid The digest id code.
* @param key The key to digest
*/
public
DSRecord(Name name, int dclass, long ttl, int digestid, DNSKEYRecord key) {
this(name, dclass, ttl, key.getFootprint(), key.getAlgorithm(), digestid, DNSSEC.generateDSDigest(key, digestid));
}
/**
* Creates a DS Record from the given data
*
* @param footprint The original KEY record's footprint (keyid).
* @param alg The original key algorithm.
* @param digestid The digest id code.
* @param digest A hash of the original key.
*/
public
DSRecord(Name name, int dclass, long ttl, int footprint, int alg, int digestid, byte[] digest) {
super(name, DnsRecordType.DS, dclass, ttl);
this.footprint = checkU16("footprint", footprint);
this.alg = checkU8("alg", alg);
this.digestid = checkU8("digestid", digestid);
this.digest = digest;
}
/**
* Returns the key's algorithm.
*/
public
int getAlgorithm() {
return alg;
}
/**
* Returns the key's Digest ID.
*/
public
int getDigestID() {
return digestid;
}
/**
* Returns the binary hash of the key.
*/
public
byte[] getDigest() {
return digest;
}
/**
* Returns the key's footprint.
*/
public
int getFootprint() {
return footprint;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,825 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.Arrays;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsClass;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsSection;
import dorkbox.network.dns.exceptions.RelativeNameException;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.utils.Options;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* A generic DNS resource record. The specific record types extend this class.
* A record contains a name, type, class, ttl, and rdata.
*
* @author Brian Wellington
*/
public abstract
class DnsRecord implements Cloneable, Comparable, Serializable {
private static final long serialVersionUID = 2694906050116005466L;
protected Name name;
protected int type, dclass;
protected long ttl;
private static final DecimalFormat byteFormat = new DecimalFormat();
static {
byteFormat.setMinimumIntegerDigits(3);
}
protected
DnsRecord() {}
DnsRecord(Name name, int type, int dclass, long ttl) {
if (!name.isAbsolute()) {
throw new RelativeNameException(name);
}
DnsRecordType.check(type);
DnsClass.check(dclass);
TTL.check(ttl);
this.name = name;
this.type = type;
this.dclass = dclass;
this.ttl = ttl;
}
/**
* Creates a new record, with the given parameters.
*
* @param name The owner name of the record.
* @param type The record's type.
* @param dclass The record's class.
* @param ttl The record's time to live.
* @param data The complete rdata of the record, in uncompressed DNS wire
* format.
*/
public static
DnsRecord newRecord(Name name, int type, int dclass, long ttl, byte[] data) {
return newRecord(name, type, dclass, ttl, data.length, data);
}
/**
* Creates a new record, with the given parameters.
*
* @param name The owner name of the record.
* @param type The record's type.
* @param dclass The record's class.
* @param ttl The record's time to live.
* @param length The length of the record's data.
* @param data The rdata of the record, in uncompressed DNS wire format. Only
* the first length bytes are used.
*/
public static
DnsRecord newRecord(Name name, int type, int dclass, long ttl, int length, byte[] data) {
if (!name.isAbsolute()) {
throw new RelativeNameException(name);
}
DnsRecordType.check(type);
DnsClass.check(dclass);
TTL.check(ttl);
DnsInput in;
if (data != null) {
in = new DnsInput(data);
}
else {
in = null;
}
try {
return newRecord(name, type, dclass, ttl, length, in);
} catch (IOException e) {
return null;
}
}
private static
DnsRecord newRecord(Name name, int type, int dclass, long ttl, int length, DnsInput in) throws IOException {
DnsRecord rec;
rec = getEmptyRecord(name, type, dclass, ttl, in != null);
if (in != null) {
if (in.remaining() < length) {
throw new WireParseException("truncated record");
}
in.setActive(length);
rec.rrFromWire(in);
int remaining = in.remaining();
in.restoreActive();
if (remaining > 0) {
throw new WireParseException("invalid record length");
}
}
return rec;
}
private static
DnsRecord getEmptyRecord(Name name, int type, int dclass, long ttl, boolean hasData) {
DnsRecord proto, rec;
if (hasData) {
proto = DnsRecordType.getProto(type);
if (proto != null) {
rec = proto.getObject();
}
else {
rec = new UNKRecord();
}
}
else {
rec = new EmptyRecord();
}
rec.name = name;
rec.type = type;
rec.dclass = dclass;
rec.ttl = ttl;
return rec;
}
/**
* Creates an empty record of the correct type; must be overriden
*/
abstract
DnsRecord getObject();
/**
* Converts the type-specific RR to wire format - must be overriden
*/
abstract
void rrFromWire(DnsInput in) throws IOException;
/**
* Creates a new empty record, with the given parameters.
*
* @param name The owner name of the record.
* @param type The record's type.
* @param dclass The record's class.
* @param ttl The record's time to live.
*
* @return An object of a subclass of Record
*/
public static
DnsRecord newRecord(Name name, int type, int dclass, long ttl) {
if (!name.isAbsolute()) {
throw new RelativeNameException(name);
}
DnsRecordType.check(type);
DnsClass.check(dclass);
TTL.check(ttl);
return getEmptyRecord(name, type, dclass, ttl, false);
}
/**
* Creates a new empty record, with the given parameters. This method is
* designed to create records that will be added to the QUERY section
* of a message.
*
* @param name The owner name of the record.
* @param type The record's type.
* @param dclass The record's class.
*
* @return An object of a subclass of Record
*/
public static
DnsRecord newRecord(Name name, int type, int dclass) {
return newRecord(name, type, dclass, 0);
}
static
DnsRecord fromWire(DnsInput in, int section, boolean isUpdate) throws IOException {
int type, dclass;
long ttl;
int length;
Name name;
DnsRecord rec;
name = new Name(in);
type = in.readU16();
dclass = in.readU16();
if (section == DnsSection.QUESTION) {
return newRecord(name, type, dclass);
}
ttl = in.readU32();
length = in.readU16();
if (length == 0 && isUpdate && (section == DnsSection.PREREQ || section == DnsSection.UPDATE)) {
return newRecord(name, type, dclass, ttl);
}
rec = newRecord(name, type, dclass, ttl, length, in);
return rec;
}
static
DnsRecord fromWire(DnsInput in, int section) throws IOException {
return fromWire(in, section, false);
}
/**
* Builds a Record from DNS uncompressed wire format.
*/
public static
DnsRecord fromWire(byte[] b, int section) throws IOException {
return fromWire(new DnsInput(b), section, false);
}
/**
* Converts a Record into DNS uncompressed wire format.
*/
public
byte[] toWire(int section) {
DnsOutput out = new DnsOutput();
toWire(out, section, null);
return out.toByteArray();
}
void toWire(DnsOutput out, int section, Compression c) {
name.toWire(out, c);
out.writeU16(type);
out.writeU16(dclass);
if (section == DnsSection.QUESTION) {
return;
}
out.writeU32(ttl);
int lengthPosition = out.current();
out.writeU16(0); /* until we know better */
rrToWire(out, c, false);
int rrlength = out.current() - lengthPosition - 2;
out.writeU16At(rrlength, lengthPosition);
}
/**
* Converts the type-specific RR to wire format - must be overriden
*/
abstract
void rrToWire(DnsOutput out, Compression c, boolean canonical);
/**
* Converts a Record into canonical DNS uncompressed wire format (all names are
* converted to lowercase).
*/
public
byte[] toWireCanonical() {
return toWireCanonical(false);
}
/*
* Converts a Record into canonical DNS uncompressed wire format (all names are
* converted to lowercase), optionally ignoring the TTL.
*/
private
byte[] toWireCanonical(boolean noTTL) {
DnsOutput out = new DnsOutput();
toWireCanonical(out, noTTL);
return out.toByteArray();
}
private
void toWireCanonical(DnsOutput out, boolean noTTL) {
name.toWireCanonical(out);
out.writeU16(type);
out.writeU16(dclass);
if (noTTL) {
out.writeU32(0);
}
else {
out.writeU32(ttl);
}
int lengthPosition = out.current();
out.writeU16(0); /* until we know better */
rrToWire(out, null, true);
int rrlength = out.current() - lengthPosition - 2;
out.writeU16At(rrlength, lengthPosition);
}
/**
* Converts the rdata portion of a Record into a String representation
*/
public
void rdataToString(StringBuilder sb) {
rrToString(sb);
}
/**
* Converts the type-specific RR to text format - must be overriden
*/
abstract
void rrToString(StringBuilder sb);
/**
* Converts the text format of an RR to the internal format - must be overriden
*/
abstract
void rdataFromString(Tokenizer st, Name origin) throws IOException;
/**
* Converts a String into a byte array.
*/
protected static
byte[] byteArrayFromString(String s) throws TextParseException {
byte[] array = s.getBytes();
boolean escaped = false;
boolean hasEscapes = false;
for (int i = 0; i < array.length; i++) {
if (array[i] == '\\') {
hasEscapes = true;
break;
}
}
if (!hasEscapes) {
if (array.length > 255) {
throw new TextParseException("text string too long");
}
return array;
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
int digits = 0;
int intval = 0;
for (int i = 0; i < array.length; i++) {
byte b = array[i];
if (escaped) {
if (b >= '0' && b <= '9' && digits < 3) {
digits++;
intval *= 10;
intval += (b - '0');
if (intval > 255) {
throw new TextParseException("bad escape");
}
if (digits < 3) {
continue;
}
b = (byte) intval;
}
else if (digits > 0 && digits < 3) {
throw new TextParseException("bad escape");
}
os.write(b);
escaped = false;
}
else if (array[i] == '\\') {
escaped = true;
digits = 0;
intval = 0;
}
else {
os.write(array[i]);
}
}
if (digits > 0 && digits < 3) {
throw new TextParseException("bad escape");
}
array = os.toByteArray();
if (array.length > 255) {
throw new TextParseException("text string too long");
}
return os.toByteArray();
}
/**
* Converts a byte array into a String.
*/
protected static
String byteArrayToString(byte[] array, boolean quote) {
StringBuilder sb = new StringBuilder();
if (quote) {
sb.append('"');
}
for (int i = 0; i < array.length; i++) {
int b = array[i] & 0xFF;
if (b < 0x20 || b >= 0x7f) {
sb.append('\\');
sb.append(byteFormat.format(b));
}
else if (b == '"' || b == '\\') {
sb.append('\\');
sb.append((char) b);
}
else {
sb.append((char) b);
}
}
if (quote) {
sb.append('"');
}
return sb.toString();
}
/**
* Converts a byte array into the unknown RR format.
*/
protected static
String unknownToString(byte[] data) {
StringBuilder sb = new StringBuilder();
sb.append("\\# ");
sb.append(data.length);
sb.append(" ");
sb.append(base16.toString(data));
return sb.toString();
}
/**
* Builds a new Record from its textual representation
*
* @param name The owner name of the record.
* @param type The record's type.
* @param dclass The record's class.
* @param ttl The record's time to live.
* @param st A tokenizer containing the textual representation of the rdata.
* @param origin The default origin to be appended to relative domain names.
*
* @return The new record
*
* @throws IOException The text format was invalid.
*/
public static
DnsRecord fromString(Name name, int type, int dclass, long ttl, Tokenizer st, Name origin) throws IOException {
DnsRecord rec;
if (!name.isAbsolute()) {
throw new RelativeNameException(name);
}
DnsRecordType.check(type);
DnsClass.check(dclass);
TTL.check(ttl);
Tokenizer.Token t = st.get();
if (t.type == Tokenizer.IDENTIFIER && t.value.equals("\\#")) {
int length = st.getUInt16();
byte[] data = st.getHex();
if (data == null) {
data = new byte[0];
}
if (length != data.length) {
throw st.exception("invalid unknown RR encoding: " + "length mismatch");
}
DnsInput in = new DnsInput(data);
return newRecord(name, type, dclass, ttl, length, in);
}
st.unget();
rec = getEmptyRecord(name, type, dclass, ttl, true);
rec.rdataFromString(st, origin);
t = st.get();
if (t.type != Tokenizer.EOL && t.type != Tokenizer.EOF) {
throw st.exception("unexpected tokens at end of record");
}
return rec;
}
/**
* Builds a new Record from its textual representation
*
* @param name The owner name of the record.
* @param type The record's type.
* @param dclass The record's class.
* @param ttl The record's time to live.
* @param s The textual representation of the rdata.
* @param origin The default origin to be appended to relative domain names.
*
* @return The new record
*
* @throws IOException The text format was invalid.
*/
public static
DnsRecord fromString(Name name, int type, int dclass, long ttl, String s, Name origin) throws IOException {
return fromString(name, type, dclass, ttl, new Tokenizer(s), origin);
}
/**
* Returns the record's name
*
* @see Name
*/
public
Name getName() {
return name;
}
/**
* Returns the record's type
*
* @see DnsRecordType
*/
public
int getType() {
return type;
}
/**
* Returns the record's class
*/
public
int getDClass() {
return dclass;
}
/**
* Returns the record's TTL
*/
public
long getTTL() {
return ttl;
}
/* Sets the TTL to the specified value. This is intentionally not public. EDIT: public now so we can change it if we want to */
public
void setTTL(long ttl) {
this.ttl = ttl;
}
/**
* Determines if two Records could be part of the same RRset.
* This compares the name, type, and class of the Records; the ttl and
* rdata are not compared.
*/
public
boolean sameRRset(DnsRecord rec) {
return (getRRsetType() == rec.getRRsetType() && dclass == rec.dclass && name.equals(rec.name));
}
/**
* Returns the type of RRset that this record would belong to. For all types
* except RRSIG, this is equivalent to getType().
*
* @return The type of record, if not RRSIG. If the type is RRSIG,
* the type covered is returned.
*
* @see DnsRecordType
* @see RRset
* @see SIGRecord
*/
public
int getRRsetType() {
if (type == DnsRecordType.RRSIG) {
RRSIGRecord sig = (RRSIGRecord) this;
return sig.getTypeCovered();
}
return type;
}
/**
* Generates a hash code based on the Record's data.
*/
@Override
public
int hashCode() {
byte[] array = toWireCanonical(true);
int code = 0;
for (int i = 0; i < array.length; i++) {
code += ((code << 3) + (array[i] & 0xFF));
}
return code;
}
/**
* Determines if two Records are identical. This compares the name, type,
* class, and rdata (with names canonicalized). The TTLs are not compared.
*
* @param arg The record to compare to
*
* @return true if the records are equal, false otherwise.
*/
@Override
public
boolean equals(Object arg) {
if (arg == null || !(arg instanceof DnsRecord)) {
return false;
}
DnsRecord r = (DnsRecord) arg;
if (type != r.type || dclass != r.dclass || !name.equals(r.name)) {
return false;
}
byte[] array1 = rdataToWireCanonical();
byte[] array2 = r.rdataToWireCanonical();
return Arrays.equals(array1, array2);
}
/**
* Converts the rdata in a Record into canonical DNS uncompressed wire format
* (all names are converted to lowercase).
*/
public
byte[] rdataToWireCanonical() {
DnsOutput out = new DnsOutput();
rrToWire(out, null, true);
return out.toByteArray();
}
/**
* Converts a Record into a String representation
*/
@Override
public final
String toString() {
StringBuilder sb = new StringBuilder();
toString(sb);
return sb.toString();
}
/**
* Converts a Record into a String representation in a StringBuilder
*/
public
void toString(StringBuilder sb) {
sb.append(name);
if (sb.length() < 8) {
sb.append("\t");
}
if (sb.length() < 16) {
sb.append("\t");
}
sb.append("\t");
if (Options.check("BINDTTL")) {
sb.append(TTL.format(ttl));
}
else {
sb.append(ttl);
}
sb.append("\t");
if (dclass != DnsClass.IN || !Options.check("noPrintIN")) {
sb.append(DnsClass.string(dclass));
sb.append("\t");
}
sb.append(DnsRecordType.string(type));
sb.append("\t");
int length = sb.length();
rrToString(sb);
if (length == sb.length()) {
// delete the /t since we had no record data
sb.deleteCharAt(length-1);
}
}
/**
* Creates a new record identical to the current record, but with a different
* name. This is most useful for replacing the name of a wildcard record.
*/
public
DnsRecord withName(Name name) {
if (!name.isAbsolute()) {
throw new RelativeNameException(name);
}
DnsRecord rec = cloneRecord();
rec.name = name;
return rec;
}
DnsRecord cloneRecord() {
try {
return (DnsRecord) clone();
} catch (CloneNotSupportedException e) {
throw new IllegalStateException();
}
}
/**
* Creates a new record identical to the current record, but with a different
* class and ttl. This is most useful for dynamic update.
*/
DnsRecord withDClass(int dclass, long ttl) {
DnsRecord rec = cloneRecord();
rec.dclass = dclass;
rec.ttl = ttl;
return rec;
}
/**
* Compares this Record to another Object.
*
* @param o The Object to be compared.
*
* @return The value 0 if the argument is a record equivalent to this record;
* a value less than 0 if the argument is less than this record in the
* canonical ordering, and a value greater than 0 if the argument is greater
* than this record in the canonical ordering. The canonical ordering
* is defined to compare by name, class, type, and rdata.
*
* @throws ClassCastException if the argument is not a Record.
*/
@Override
public
int compareTo(Object o) {
DnsRecord arg = (DnsRecord) o;
if (this == arg) {
return (0);
}
int n = name.compareTo(arg.name);
if (n != 0) {
return (n);
}
n = dclass - arg.dclass;
if (n != 0) {
return (n);
}
n = type - arg.type;
if (n != 0) {
return (n);
}
byte[] rdata1 = rdataToWireCanonical();
byte[] rdata2 = arg.rdataToWireCanonical();
for (int i = 0; i < rdata1.length && i < rdata2.length; i++) {
n = (rdata1[i] & 0xFF) - (rdata2[i] & 0xFF);
if (n != 0) {
return (n);
}
}
return (rdata1.length - rdata2.length);
}
/**
* Returns the name for which additional data processing should be done
* for this record. This can be used both for building responses and
* parsing responses.
*
* @return The name to used for additional data processing, or null if this
* record type does not require additional data processing.
*/
public
Name getAdditionalName() {
return null;
}
/* Checks that an int contains an unsigned 8 bit value */
static
int checkU8(String field, int val) {
if (val < 0 || val > 0xFF) {
throw new IllegalArgumentException("\"" + field + "\" " + val + " must be an unsigned 8 " + "bit value");
}
return val;
}
/* Checks that an int contains an unsigned 16 bit value */
static
int checkU16(String field, int val) {
if (val < 0 || val > 0xFFFF) {
throw new IllegalArgumentException("\"" + field + "\" " + val + " must be an unsigned 16 " + "bit value");
}
return val;
}
/* Checks that a long contains an unsigned 32 bit value */
static
long checkU32(String field, long val) {
if (val < 0 || val > 0xFFFFFFFFL) {
throw new IllegalArgumentException("\"" + field + "\" " + val + " must be an unsigned 32 " + "bit value");
}
return val;
}
/* Checks that a name is absolute */
static
Name checkName(String field, Name name) {
if (!name.isAbsolute()) {
throw new RelativeNameException(name);
}
return name;
}
static
byte[] checkByteArrayLength(String field, byte[] array, int maxLength) {
if (array.length > 0xFFFF) {
throw new IllegalArgumentException("\"" + field + "\" array " + "must have no more than " + maxLength + " elements");
}
byte[] out = new byte[array.length];
System.arraycopy(array, 0, out, 0, array.length);
return out;
}
}

View File

@ -1,78 +0,0 @@
package dorkbox.network.dns.records;
import dorkbox.network.dns.constants.DnsRecordType;
public
class DnsTypeProtoAssignment {
// this is so we don't have to make each type constructor public
public static
void assign(final DnsRecordType.TypeMnemonic types) {
types.add(DnsRecordType.A, "A", new ARecord());
types.add(DnsRecordType.NS, "NS", new NSRecord());
types.add(DnsRecordType.MD, "MD", new MDRecord());
types.add(DnsRecordType.MF, "MF", new MFRecord());
types.add(DnsRecordType.CNAME, "CNAME", new CNAMERecord());
types.add(DnsRecordType.SOA, "SOA", new SOARecord());
types.add(DnsRecordType.MB, "MB", new MBRecord());
types.add(DnsRecordType.MG, "MG", new MGRecord());
types.add(DnsRecordType.MR, "MR", new MRRecord());
types.add(DnsRecordType.NULL, "NULL", new NULLRecord());
types.add(DnsRecordType.WKS, "WKS", new WKSRecord());
types.add(DnsRecordType.PTR, "PTR", new PTRRecord());
types.add(DnsRecordType.HINFO, "HINFO", new HINFORecord());
types.add(DnsRecordType.MINFO, "MINFO", new MINFORecord());
types.add(DnsRecordType.MX, "MX", new MXRecord());
types.add(DnsRecordType.TXT, "TXT", new TXTRecord());
types.add(DnsRecordType.RP, "RP", new RPRecord());
types.add(DnsRecordType.AFSDB, "AFSDB", new AFSDBRecord());
types.add(DnsRecordType.X25, "X25", new X25Record());
types.add(DnsRecordType.ISDN, "ISDN", new ISDNRecord());
types.add(DnsRecordType.RT, "RT", new RTRecord());
types.add(DnsRecordType.NSAP, "NSAP", new NSAPRecord());
types.add(DnsRecordType.NSAP_PTR, "NSAP-PTR", new NSAP_PTRRecord());
types.add(DnsRecordType.SIG, "SIG", new SIGRecord());
types.add(DnsRecordType.KEY, "KEY", new KEYRecord());
types.add(DnsRecordType.PX, "PX", new PXRecord());
types.add(DnsRecordType.GPOS, "GPOS", new GPOSRecord());
types.add(DnsRecordType.AAAA, "AAAA", new AAAARecord());
types.add(DnsRecordType.LOC, "LOC", new LOCRecord());
types.add(DnsRecordType.NXT, "NXT", new NXTRecord());
types.add(DnsRecordType.EID, "EID");
types.add(DnsRecordType.NIMLOC, "NIMLOC");
types.add(DnsRecordType.SRV, "SRV", new SRVRecord());
types.add(DnsRecordType.ATMA, "ATMA");
types.add(DnsRecordType.NAPTR, "NAPTR", new NAPTRRecord());
types.add(DnsRecordType.KX, "KX", new KXRecord());
types.add(DnsRecordType.CERT, "CERT", new CERTRecord());
types.add(DnsRecordType.A6, "A6", new A6Record());
types.add(DnsRecordType.DNAME, "DNAME", new DNAMERecord());
types.add(DnsRecordType.OPT, "OPT", new OPTRecord());
types.add(DnsRecordType.APL, "APL", new APLRecord());
types.add(DnsRecordType.DS, "DS", new DSRecord());
types.add(DnsRecordType.SSHFP, "SSHFP", new SSHFPRecord());
types.add(DnsRecordType.IPSECKEY, "IPSECKEY", new IPSECKEYRecord());
types.add(DnsRecordType.RRSIG, "RRSIG", new RRSIGRecord());
types.add(DnsRecordType.NSEC, "NSEC", new NSECRecord());
types.add(DnsRecordType.DNSKEY, "DNSKEY", new DNSKEYRecord());
types.add(DnsRecordType.DHCID, "DHCID", new DHCIDRecord());
types.add(DnsRecordType.NSEC3, "NSEC3", new NSEC3Record());
types.add(DnsRecordType.NSEC3PARAM, "NSEC3PARAM", new NSEC3PARAMRecord());
types.add(DnsRecordType.TLSA, "TLSA", new TLSARecord());
types.add(DnsRecordType.SMIMEA, "SMIMEA", new SMIMEARecord());
types.add(DnsRecordType.SMIMEA, "HIP");
types.add(DnsRecordType.OPENPGPKEY, "OPENPGPKEY", new OPENPGPKEYRecord());
types.add(DnsRecordType.SPF, "SPF", new SPFRecord());
types.add(DnsRecordType.TKEY, "TKEY", new TKEYRecord());
types.add(DnsRecordType.TSIG, "TSIG", new TSIGRecord());
types.add(DnsRecordType.IXFR, "IXFR");
types.add(DnsRecordType.AXFR, "AXFR");
types.add(DnsRecordType.MAILB, "MAILB");
types.add(DnsRecordType.MAILA, "MAILA");
types.add(DnsRecordType.ANY, "ANY");
types.add(DnsRecordType.URI, "URI", new URIRecord());
types.add(DnsRecordType.CAA, "CAA", new CAARecord());
types.add(DnsRecordType.TA, "TA");
types.add(DnsRecordType.DLV, "DLV", new DLVRecord());
}
}

View File

@ -1,236 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.util.Arrays;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Mnemonic;
import dorkbox.network.dns.exceptions.WireParseException;
/**
* DNS extension options, as described in RFC 2671. The rdata of an OPT record
* is defined as a list of options; this represents a single option.
*
* @author Brian Wellington
* @author Ming Zhou &lt;mizhou@bnivideo.com&gt;, Beaumaris Networks
*/
public abstract
class EDNSOption {
private final int code;
public static
class Code {
/**
* Name Server Identifier, RFC 5001
*/
public final static int NSID = 3;
/**
* Client Subnet, defined in draft-vandergaast-edns-client-subnet-02
*/
public final static int CLIENT_SUBNET = 8;
private static Mnemonic codes = new Mnemonic("EDNS Option Codes", Mnemonic.CASE_UPPER);
private
Code() {}
static {
codes.setMaximum(0xFFFF);
codes.setPrefix("CODE");
codes.setNumericAllowed(true);
codes.add(NSID, "NSID");
codes.add(CLIENT_SUBNET, "CLIENT_SUBNET");
}
/**
* Converts an EDNS Option Code into its textual representation
*/
public static
String string(int code) {
return codes.getText(code);
}
/**
* Converts a textual representation of an EDNS Option Code into its
* numeric value.
*
* @param s The textual representation of the option code
*
* @return The option code, or -1 on error.
*/
public static
int value(String s) {
return codes.getValue(s);
}
}
/**
* Creates an option with the given option code and data.
*/
public
EDNSOption(int code) {
this.code = DnsRecord.checkU16("code", code);
}
/**
* Returns the EDNS Option's code.
*
* @return the option code
*/
public
int getCode() {
return code;
}
/**
* Converts the wire format of an EDNS Option (including code and length) into
* the type-specific format.
*
* @return The option, in wire format.
*/
public static
EDNSOption fromWire(byte[] b) throws IOException {
return fromWire(new DnsInput(b));
}
/**
* Converts the wire format of an EDNS Option (including code and length) into
* the type-specific format.
*
* @param in The input stream.
*/
static
EDNSOption fromWire(DnsInput in) throws IOException {
int code, length;
code = in.readU16();
length = in.readU16();
if (in.remaining() < length) {
throw new WireParseException("truncated option");
}
in.setActive(length);
EDNSOption option;
switch (code) {
case Code.NSID:
option = new NSIDOption();
break;
case Code.CLIENT_SUBNET:
option = new ClientSubnetOption();
break;
default:
option = new GenericEDNSOption(code);
break;
}
option.optionFromWire(in);
in.restoreActive();
return option;
}
/**
* Converts the wire format of an EDNS Option (the option data only) into the
* type-specific format.
*
* @param in The input Stream.
*/
abstract
void optionFromWire(DnsInput in) throws IOException;
/**
* Converts an EDNS Option (including code and length) into wire format.
*
* @return The option, in wire format.
*/
public
byte[] toWire() throws IOException {
DnsOutput out = new DnsOutput();
toWire(out);
return out.toByteArray();
}
/**
* Converts an EDNS Option (including code and length) into wire format.
*
* @param out The output stream.
*/
void toWire(DnsOutput out) {
out.writeU16(code);
int lengthPosition = out.current();
out.writeU16(0); /* until we know better */
optionToWire(out);
int length = out.current() - lengthPosition - 2;
out.writeU16At(length, lengthPosition);
}
/**
* Converts an EDNS Option (the type-specific option data only) into wire format.
*
* @param out The output stream.
*/
abstract
void optionToWire(DnsOutput out);
/**
* Generates a hash code based on the EDNS Option's data.
*/
public
int hashCode() {
byte[] array = getData();
int hashval = 0;
for (int i = 0; i < array.length; i++) {
hashval += ((hashval << 3) + (array[i] & 0xFF));
}
return hashval;
}
/**
* Determines if two EDNS Options are identical.
*
* @param arg The option to compare to
*
* @return true if the options are equal, false otherwise.
*/
public
boolean equals(Object arg) {
if (arg == null || !(arg instanceof EDNSOption)) {
return false;
}
EDNSOption opt = (EDNSOption) arg;
if (code != opt.code) {
return false;
}
return Arrays.equals(getData(), opt.getData());
}
public
String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append(EDNSOption.Code.string(code));
sb.append(": ");
sb.append(optionToString());
sb.append("}");
return sb.toString();
}
abstract
String optionToString();
/**
* Returns the EDNS Option's data, as a byte array.
*
* @return the option data
*/
byte[] getData() {
DnsOutput out = new DnsOutput();
optionToWire(out);
return out.toByteArray();
}
}

View File

@ -1,46 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.utils.Tokenizer;
/**
* A class implementing Records with no data; that is, records used in
* the question section of messages and meta-records in dynamic update.
*
* @author Brian Wellington
*/
class EmptyRecord extends DnsRecord {
private static final long serialVersionUID = 3601852050646429582L;
EmptyRecord() {}
@Override
DnsRecord getObject() {
return new EmptyRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
}
@Override
void rrToString(StringBuilder sb) {
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
}
}

View File

@ -1,191 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Geographical Location - describes the physical location of a host.
*
* @author Brian Wellington
*/
public
class GPOSRecord extends DnsRecord {
private static final long serialVersionUID = -6349714958085750705L;
private byte[] latitude, longitude, altitude;
GPOSRecord() {}
@Override
DnsRecord getObject() {
return new GPOSRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
longitude = in.readCountedString();
latitude = in.readCountedString();
altitude = in.readCountedString();
try {
validate(getLongitude(), getLatitude());
} catch (IllegalArgumentException e) {
throw new WireParseException(e.getMessage());
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeCountedString(longitude);
out.writeCountedString(latitude);
out.writeCountedString(altitude);
}
/**
* Convert to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(byteArrayToString(longitude, true));
sb.append(" ");
sb.append(byteArrayToString(latitude, true));
sb.append(" ");
sb.append(byteArrayToString(altitude, true));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
try {
longitude = byteArrayFromString(st.getString());
latitude = byteArrayFromString(st.getString());
altitude = byteArrayFromString(st.getString());
} catch (TextParseException e) {
throw st.exception(e.getMessage());
}
try {
validate(getLongitude(), getLatitude());
} catch (IllegalArgumentException e) {
throw new WireParseException(e.getMessage());
}
}
/**
* Creates an GPOS Record from the given data
*
* @param longitude The longitude component of the location.
* @param latitude The latitude component of the location.
* @param altitude The altitude component of the location (in meters above sea
* level).
*/
public
GPOSRecord(Name name, int dclass, long ttl, double longitude, double latitude, double altitude) {
super(name, DnsRecordType.GPOS, dclass, ttl);
validate(longitude, latitude);
this.longitude = Double.toString(longitude)
.getBytes();
this.latitude = Double.toString(latitude)
.getBytes();
this.altitude = Double.toString(altitude)
.getBytes();
}
private
void validate(double longitude, double latitude) throws IllegalArgumentException {
if (longitude < -90.0 || longitude > 90.0) {
throw new IllegalArgumentException("illegal longitude " + longitude);
}
if (latitude < -180.0 || latitude > 180.0) {
throw new IllegalArgumentException("illegal latitude " + latitude);
}
}
/**
* Creates an GPOS Record from the given data
*
* @param longitude The longitude component of the location.
* @param latitude The latitude component of the location.
* @param altitude The altitude component of the location (in meters above sea
* level).
*/
public
GPOSRecord(Name name, int dclass, long ttl, String longitude, String latitude, String altitude) {
super(name, DnsRecordType.GPOS, dclass, ttl);
try {
this.longitude = byteArrayFromString(longitude);
this.latitude = byteArrayFromString(latitude);
validate(getLongitude(), getLatitude());
this.altitude = byteArrayFromString(altitude);
} catch (TextParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
/**
* Returns the longitude as a double
*
* @throws NumberFormatException The string does not contain a valid numeric
* value.
*/
public
double getLongitude() {
return Double.parseDouble(getLongitudeString());
}
/**
* Returns the longitude as a string
*/
public
String getLongitudeString() {
return byteArrayToString(longitude, false);
}
/**
* Returns the latitude as a double
*
* @throws NumberFormatException The string does not contain a valid numeric
* value.
*/
public
double getLatitude() {
return Double.parseDouble(getLatitudeString());
}
/**
* Returns the latitude as a string
*/
public
String getLatitudeString() {
return byteArrayToString(latitude, false);
}
/**
* Returns the altitude as a double
*
* @throws NumberFormatException The string does not contain a valid numeric
* value.
*/
public
double getAltitude() {
return Double.parseDouble(getAltitudeString());
}
/**
* Returns the altitude as a string
*/
public
String getAltitudeString() {
return byteArrayToString(altitude, false);
}
}

View File

@ -1,51 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.utils.base16;
/**
* An EDNSOption with no internal structure.
*
* @author Ming Zhou &lt;mizhou@bnivideo.com&gt;, Beaumaris Networks
* @author Brian Wellington
*/
public
class GenericEDNSOption extends EDNSOption {
private byte[] data;
GenericEDNSOption(int code) {
super(code);
}
/**
* Construct a generic EDNS option.
*
* @param data The contents of the option.
*/
public
GenericEDNSOption(int code, byte[] data) {
super(code);
this.data = DnsRecord.checkByteArrayLength("option data", data, 0xFFFF);
}
@Override
void optionFromWire(DnsInput in) throws IOException {
data = in.readByteArray();
}
@Override
void optionToWire(DnsOutput out) {
out.writeByteArray(data);
}
@Override
String optionToString() {
return "<" + base16.toString(data) + ">";
}
}

View File

@ -1,102 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Host Information - describes the CPU and OS of a host
*
* @author Brian Wellington
*/
public
class HINFORecord extends DnsRecord {
private static final long serialVersionUID = -4732870630947452112L;
private byte[] cpu, os;
HINFORecord() {}
@Override
DnsRecord getObject() {
return new HINFORecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
cpu = in.readCountedString();
os = in.readCountedString();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeCountedString(cpu);
out.writeCountedString(os);
}
/**
* Converts to a string
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(byteArrayToString(cpu, true));
sb.append(" ");
sb.append(byteArrayToString(os, true));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
try {
cpu = byteArrayFromString(st.getString());
os = byteArrayFromString(st.getString());
} catch (TextParseException e) {
throw st.exception(e.getMessage());
}
}
/**
* Creates an HINFO Record from the given data
*
* @param cpu A string describing the host's CPU
* @param os A string describing the host's OS
*
* @throws IllegalArgumentException One of the strings has invalid escapes
*/
public
HINFORecord(Name name, int dclass, long ttl, String cpu, String os) {
super(name, DnsRecordType.HINFO, dclass, ttl);
try {
this.cpu = byteArrayFromString(cpu);
this.os = byteArrayFromString(os);
} catch (TextParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
/**
* Returns the host's CPU
*/
public
String getCPU() {
return byteArrayToString(cpu, false);
}
/**
* Returns the host's OS
*/
public
String getOS() {
return byteArrayToString(os, false);
}
}

View File

@ -1,361 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.constants.DnsOpCode;
import dorkbox.network.dns.constants.DnsResponseCode;
import dorkbox.network.dns.constants.DnsSection;
import dorkbox.network.dns.constants.Flags;
import dorkbox.util.FastThreadLocal;
import dorkbox.util.MersenneTwisterFast;
import dorkbox.util.OS;
/**
* A DNS message header
*
* @author Brian Wellington
* @see DnsMessage
*/
public
class Header implements Cloneable {
private int id;
private int flags;
private int[] counts;
private static final
FastThreadLocal<MersenneTwisterFast> random = new FastThreadLocal<MersenneTwisterFast>() {
@Override
public
MersenneTwisterFast initialValue() {
return new MersenneTwisterFast();
}
};
/**
* The length of a DNS Header in wire format.
*/
public static final int LENGTH = 12;
/**
* Create a new empty header with a random message id
*/
public
Header() {
init();
}
private
void init() {
counts = new int[4];
flags = 0;
id = -1;
}
/**
* Creates a new Header from its DNS wire format representation
*
* @param b A byte array containing the DNS Header.
*/
public
Header(byte[] b) throws IOException {
this(new DnsInput(b));
}
/**
* Parses a Header from a stream containing DNS wire format.
*/
Header(DnsInput in) throws IOException {
this(in.readU16());
flags = in.readU16();
for (int i = 0; i < counts.length; i++) {
counts[i] = in.readU16();
}
}
/**
* Create a new empty header.
*
* @param id The message id
*/
public
Header(int id) {
init();
setID(id);
}
public
byte[] toWire() {
DnsOutput out = new DnsOutput();
toWire(out);
return out.toByteArray();
}
void toWire(DnsOutput out) {
out.writeU16(getID());
out.writeU16(flags);
for (int i = 0; i < counts.length; i++) {
out.writeU16(counts[i]);
}
}
/**
* Retrieves the message ID
*/
public
int getID() {
if (id >= 0) {
return id;
}
synchronized (this) {
if (id < 0) {
id = random.get().nextInt(0xffff);
}
return id;
}
}
/**
* Sets the message ID
*/
public
void setID(int id) {
if (id < 0 || id > 0xffff) {
throw new IllegalArgumentException("DNS message ID " + id + " is out of range");
}
this.id = id;
}
/**
* Sets a flag to the supplied value
*
* @see Flags
*/
public
void setFlag(Flags flag) {
checkFlag(flag);
flags = setFlag(flags, flag, true);
}
static private
void checkFlag(int flag) {
if (!Flags.isFlag(flag)) {
throw new IllegalArgumentException("invalid flag bit " + flag);
}
}
static private
void checkFlag(Flags flag) {
if (!validFlag(flag)) {
throw new IllegalArgumentException("invalid flag bit " + flag);
}
}
static private
boolean validFlag(Flags flag) {
return flag != null && (flag.value() >= 0 && flag.value() <= 0xF && Flags.isFlag(flag.value()));
}
static
int setFlag(int flags, Flags flag, boolean value) {
checkFlag(flag);
// bits are indexed from left to right
if (value) {
return flags |= (1 << (15 - flag.value()));
}
else {
return flags &= ~(1 << (15 - flag.value()));
}
}
/**
* Sets a flag to the supplied value
*
* @see Flags
*/
public
void unsetFlag(Flags flag) {
checkFlag(flag);
flags = setFlag(flags, flag, false);
}
boolean[] getFlags() {
boolean[] array = new boolean[16];
for (int i = 0; i < array.length; i++) {
if (Flags.isFlag(i)) {
array[i] = getFlag(i);
}
}
return array;
}
/**
* Retrieves a flag
*
* @see Flags
*/
public
boolean getFlag(Flags flag) {
// bit s are indexed from left to right
return (flags & (1 << (15 - flag.value()))) != 0;
}
/**
* Retrieves a flag.
*
* @param flagValue ALWAYS checked before using, so additional checks are not necessary
* @see Flags
*/
private
boolean getFlag(int flagValue) {
// bits are indexed from left to right
return (flags & (1 << (15 - flagValue))) != 0;
}
void setCount(int field, int value) {
if (value < 0 || value > 0xFFFF) {
throw new IllegalArgumentException("DNS section count " + value + " is out of range");
}
counts[field] = value;
}
void incCount(int field) {
if (counts[field] == 0xFFFF) {
throw new IllegalStateException("DNS section count cannot " + "be incremented");
}
counts[field]++;
}
void decCount(int field) {
if (counts[field] == 0) {
throw new IllegalStateException("DNS section count cannot " + "be decremented");
}
counts[field]--;
}
int getFlagsByte() {
return flags;
}
/* Creates a new Header identical to the current one */
@Override
public
Object clone() {
Header h = new Header();
h.id = id;
h.flags = flags;
System.arraycopy(counts, 0, h.counts, 0, counts.length);
return h;
}
/**
* Converts the header into a String
*/
@Override
public
String toString() {
return toStringWithRcode(getRcode());
}
/**
* Retrieves the message's rcode
*
* @see DnsResponseCode
*/
public
int getRcode() {
return flags & 0xF;
}
/**
* Sets the message's rcode
*
* @see DnsResponseCode
*/
public
void setRcode(int value) {
if (value < 0 || value > 0xF) {
throw new IllegalArgumentException("DNS DnsResponseCode " + value + " is out of range");
}
flags &= ~0xF;
flags |= value;
}
String toStringWithRcode(int newrcode) {
StringBuilder sb = new StringBuilder();
sb.append(";; ->>HEADER<<- ");
sb.append("opcode: " + DnsOpCode.string(getOpcode()));
sb.append(", status: " + DnsResponseCode.string(newrcode));
sb.append(", id: " + getID());
sb.append(OS.LINE_SEPARATOR);
sb.append(";; flags: ")
.append(printFlags());
sb.append("; ");
for (int i = 0; i < 4; i++) {
sb.append(DnsSection.string(i))
.append(": ")
.append(getCount(i))
.append(" ");
}
return sb.toString();
}
/**
* Retrieves the mesasge's opcode
*
* @see DnsOpCode
*/
public
int getOpcode() {
return (flags >> 11) & 0xF;
}
/**
* Sets the message's opcode
*
* @see DnsOpCode
*/
public
void setOpcode(int value) {
if (value < 0 || value > 0xF) {
throw new IllegalArgumentException("DNS DnsOpCode " + value + "is out of range");
}
flags &= 0x87FF;
flags |= (value << 11);
}
/**
* Retrieves the record count for the given section
*
* @see DnsSection
*/
public
int getCount(int field) {
return counts[field];
}
/**
* Converts the header's flags into a String
*/
String printFlags() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 16; i++) {
if (Flags.isFlag(i) && getFlag(i)) {
Flags flag = Flags.toFlag(i);
sb.append(flag.string());
sb.append(" ");
}
}
return sb.toString();
}
}

View File

@ -1,253 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.utils.Address;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.util.Base64Fast;
/**
* IPsec Keying Material (RFC 4025)
*
* @author Brian Wellington
*/
public
class IPSECKEYRecord extends DnsRecord {
private static final long serialVersionUID = 3050449702765909687L;
private int precedence;
private int gatewayType;
private int algorithmType;
private Object gateway;
private byte[] key;
public static
class Algorithm {
public static final int DSA = 1;
public static final int RSA = 2;
private
Algorithm() {}
}
public static
class Gateway {
public static final int None = 0;
public static final int IPv4 = 1;
public static final int IPv6 = 2;
public static final int Name = 3;
private
Gateway() {}
}
IPSECKEYRecord() {}
@Override
DnsRecord getObject() {
return new IPSECKEYRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
precedence = in.readU8();
gatewayType = in.readU8();
algorithmType = in.readU8();
switch (gatewayType) {
case Gateway.None:
gateway = null;
break;
case Gateway.IPv4:
gateway = InetAddress.getByAddress(in.readByteArray(4));
break;
case Gateway.IPv6:
gateway = InetAddress.getByAddress(in.readByteArray(16));
break;
case Gateway.Name:
gateway = new Name(in);
break;
default:
throw new WireParseException("invalid gateway type");
}
if (in.remaining() > 0) {
key = in.readByteArray();
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(precedence);
out.writeU8(gatewayType);
out.writeU8(algorithmType);
switch (gatewayType) {
case Gateway.None:
break;
case Gateway.IPv4:
case Gateway.IPv6:
InetAddress gatewayAddr = (InetAddress) gateway;
out.writeByteArray(gatewayAddr.getAddress());
break;
case Gateway.Name:
Name gatewayName = (Name) gateway;
gatewayName.toWire(out, null, canonical);
break;
}
if (key != null) {
out.writeByteArray(key);
}
}
@Override
void rrToString(StringBuilder sb) {
sb.append(precedence);
sb.append(" ");
sb.append(gatewayType);
sb.append(" ");
sb.append(algorithmType);
sb.append(" ");
switch (gatewayType) {
case Gateway.None:
sb.append(".");
break;
case Gateway.IPv4:
case Gateway.IPv6:
InetAddress gatewayAddr = (InetAddress) gateway;
sb.append(gatewayAddr.getHostAddress());
break;
case Gateway.Name:
sb.append(gateway);
break;
}
if (key != null) {
sb.append(" ");
sb.append(Base64Fast.encode2(key));
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
precedence = st.getUInt8();
gatewayType = st.getUInt8();
algorithmType = st.getUInt8();
switch (gatewayType) {
case Gateway.None:
String s = st.getString();
if (!s.equals(".")) {
throw new TextParseException("invalid gateway format");
}
gateway = null;
break;
case Gateway.IPv4:
gateway = st.getAddress(Address.IPv4);
break;
case Gateway.IPv6:
gateway = st.getAddress(Address.IPv6);
break;
case Gateway.Name:
gateway = st.getName(origin);
break;
default:
throw new WireParseException("invalid gateway type");
}
key = st.getBase64(false);
}
/**
* Creates an IPSECKEY Record from the given data.
*
* @param precedence The record's precedence.
* @param gatewayType The record's gateway type.
* @param algorithmType The record's algorithm type.
* @param gateway The record's gateway.
* @param key The record's public key.
*/
public
IPSECKEYRecord(Name name, int dclass, long ttl, int precedence, int gatewayType, int algorithmType, Object gateway, byte[] key) {
super(name, DnsRecordType.IPSECKEY, dclass, ttl);
this.precedence = checkU8("precedence", precedence);
this.gatewayType = checkU8("gatewayType", gatewayType);
this.algorithmType = checkU8("algorithmType", algorithmType);
switch (gatewayType) {
case Gateway.None:
this.gateway = null;
break;
case Gateway.IPv4:
if (!(gateway instanceof InetAddress)) {
throw new IllegalArgumentException("\"gateway\" " + "must be an IPv4 " + "address");
}
this.gateway = gateway;
break;
case Gateway.IPv6:
if (!(gateway instanceof Inet6Address)) {
throw new IllegalArgumentException("\"gateway\" " + "must be an IPv6 " + "address");
}
this.gateway = gateway;
break;
case Gateway.Name:
if (!(gateway instanceof Name)) {
throw new IllegalArgumentException("\"gateway\" " + "must be a DNS " + "name");
}
this.gateway = checkName("gateway", (Name) gateway);
break;
default:
throw new IllegalArgumentException("\"gatewayType\" " + "must be between 0 and 3");
}
this.key = key;
}
/**
* Returns the record's precedence.
*/
public
int getPrecedence() {
return precedence;
}
/**
* Returns the record's gateway type.
*/
public
int getGatewayType() {
return gatewayType;
}
/**
* Returns the record's algorithm type.
*/
public
int getAlgorithmType() {
return algorithmType;
}
/**
* Returns the record's gateway.
*/
public
Object getGateway() {
return gateway;
}
/**
* Returns the record's public key
*/
public
byte[] getKey() {
return key;
}
}

View File

@ -1,118 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.utils.Tokenizer;
/**
* ISDN - identifies the ISDN number and subaddress associated with a name.
*
* @author Brian Wellington
*/
public
class ISDNRecord extends DnsRecord {
private static final long serialVersionUID = -8730801385178968798L;
private byte[] address;
private byte[] subAddress;
ISDNRecord() {}
@Override
DnsRecord getObject() {
return new ISDNRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
address = in.readCountedString();
if (in.remaining() > 0) {
subAddress = in.readCountedString();
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeCountedString(address);
if (subAddress != null) {
out.writeCountedString(subAddress);
}
}
@Override
void rrToString(StringBuilder sb) {
sb.append(byteArrayToString(address, true));
if (subAddress != null) {
sb.append(" ");
sb.append(byteArrayToString(subAddress, true));
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
try {
address = byteArrayFromString(st.getString());
Tokenizer.Token t = st.get();
if (t.isString()) {
subAddress = byteArrayFromString(t.value);
}
else {
st.unget();
}
} catch (TextParseException e) {
throw st.exception(e.getMessage());
}
}
/**
* Creates an ISDN Record from the given data
*
* @param address The ISDN number associated with the domain.
* @param subAddress The subaddress, if any.
*
* @throws IllegalArgumentException One of the strings is invalid.
*/
public
ISDNRecord(Name name, int dclass, long ttl, String address, String subAddress) {
super(name, DnsRecordType.ISDN, dclass, ttl);
try {
this.address = byteArrayFromString(address);
if (subAddress != null) {
this.subAddress = byteArrayFromString(subAddress);
}
} catch (TextParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
/**
* Returns the ISDN number associated with the domain.
*/
public
String getAddress() {
return byteArrayToString(address, false);
}
/**
* Returns the ISDN subaddress, or null if there is none.
*/
public
String getSubAddress() {
if (subAddress == null) {
return null;
}
return byteArrayToString(subAddress, false);
}
}

View File

@ -1,175 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.security.PublicKey;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.utils.Options;
import dorkbox.util.Base64Fast;
import dorkbox.util.OS;
/**
* The base class for KEY/DNSKEY records, which have identical formats
*
* @author Brian Wellington
*/
abstract
class KEYBase extends DnsRecord {
private static final long serialVersionUID = 3469321722693285454L;
protected int flags, proto, alg;
protected byte[] key;
protected int footprint = -1;
protected PublicKey publicKey = null;
protected
KEYBase() {}
public
KEYBase(Name name, int type, int dclass, long ttl, int flags, int proto, int alg, byte[] key) {
super(name, type, dclass, ttl);
this.flags = checkU16("flags", flags);
this.proto = checkU8("proto", proto);
this.alg = checkU8("alg", alg);
this.key = key;
}
@Override
void rrFromWire(DnsInput in) throws IOException {
flags = in.readU16();
proto = in.readU8();
alg = in.readU8();
if (in.remaining() > 0) {
key = in.readByteArray();
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(flags);
out.writeU8(proto);
out.writeU8(alg);
if (key != null) {
out.writeByteArray(key);
}
}
/**
* Converts the DNSKEY/KEY Record to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(flags);
sb.append(" ");
sb.append(proto);
sb.append(" ");
sb.append(alg);
if (key != null) {
if (Options.check("multiline")) {
sb.append(" (")
.append(OS.LINE_SEPARATOR);
sb.append(Base64Fast.formatString(Base64Fast.encode2(key), 64, "\t", true));
sb.append(" ; key_tag = ");
sb.append(getFootprint());
}
else {
sb.append(" ");
sb.append(Base64Fast.encode2(key));
}
}
}
/**
* Returns the key's footprint (after computing it)
*/
public
int getFootprint() {
if (footprint >= 0) {
return footprint;
}
int foot = 0;
DnsOutput out = new DnsOutput();
rrToWire(out, null, false);
byte[] rdata = out.toByteArray();
if (alg == DNSSEC.Algorithm.RSAMD5) {
int d1 = rdata[rdata.length - 3] & 0xFF;
int d2 = rdata[rdata.length - 2] & 0xFF;
foot = (d1 << 8) + d2;
}
else {
int i;
for (i = 0; i < rdata.length - 1; i += 2) {
int d1 = rdata[i] & 0xFF;
int d2 = rdata[i + 1] & 0xFF;
foot += ((d1 << 8) + d2);
}
if (i < rdata.length) {
int d1 = rdata[i] & 0xFF;
foot += (d1 << 8);
}
foot += ((foot >> 16) & 0xFFFF);
}
footprint = (foot & 0xFFFF);
return footprint;
}
/**
* Returns the flags describing the key's properties
*/
public
int getFlags() {
return flags;
}
/**
* Returns the protocol that the key was created for
*/
public
int getProtocol() {
return proto;
}
/**
* Returns the key's algorithm
*/
public
int getAlgorithm() {
return alg;
}
/**
* Returns the binary data representing the key
*/
public
byte[] getKey() {
return key;
}
/**
* Returns a PublicKey corresponding to the data in this key.
*
* @throws DNSSEC.DNSSECException The key could not be converted.
*/
public
PublicKey getPublicKey() throws DNSSEC.DNSSECException {
if (publicKey != null) {
return publicKey;
}
publicKey = DNSSEC.toPublicKey(this);
return publicKey;
}
}

View File

@ -1,421 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.security.PublicKey;
import java.util.StringTokenizer;
import dorkbox.network.dns.Mnemonic;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Key - contains a cryptographic public key. The data can be converted
* to objects implementing java.security.interfaces.PublicKey
*
* @author Brian Wellington
* @see DNSSEC
*/
public
class KEYRecord extends KEYBase {
private static final long serialVersionUID = 6385613447571488906L;
/**
* This key cannot be used for confidentiality (encryption)
*/
public static final int FLAG_NOCONF = Flags.NOCONF;
/**
* This key cannot be used for authentication
*/
public static final int FLAG_NOAUTH = Flags.NOAUTH;
/* flags */
/**
* This key cannot be used for authentication or confidentiality
*/
public static final int FLAG_NOKEY = Flags.NOKEY;
/**
* A zone key
*/
public static final int OWNER_ZONE = Flags.ZONE;
/**
* A host/end entity key
*/
public static final int OWNER_HOST = Flags.HOST;
/**
* A user key
*/
public static final int OWNER_USER = Flags.USER;
/**
* Key was created for use with transaction level security
*/
public static final int PROTOCOL_TLS = Protocol.TLS;
/**
* Key was created for use with email
*/
public static final int PROTOCOL_EMAIL = Protocol.EMAIL;
/* protocols */
/**
* Key was created for use with DNSSEC
*/
public static final int PROTOCOL_DNSSEC = Protocol.DNSSEC;
/**
* Key was created for use with IPSEC
*/
public static final int PROTOCOL_IPSEC = Protocol.IPSEC;
/**
* Key was created for use with any protocol
*/
public static final int PROTOCOL_ANY = Protocol.ANY;
public static
class Protocol {
/**
* No defined protocol.
*/
public static final int NONE = 0;
/**
* Transaction Level Security
*/
public static final int TLS = 1;
/**
* Email
*/
public static final int EMAIL = 2;
/**
* DNSSEC
*/
public static final int DNSSEC = 3;
/**
* IPSEC Control
*/
public static final int IPSEC = 4;
/**
* Any protocol
*/
public static final int ANY = 255;
private static Mnemonic protocols = new Mnemonic("KEY protocol", Mnemonic.CASE_UPPER);
/**
* KEY protocol identifiers.
*/
private
Protocol() {}
static {
protocols.setMaximum(0xFF);
protocols.setNumericAllowed(true);
protocols.add(NONE, "NONE");
protocols.add(TLS, "TLS");
protocols.add(EMAIL, "EMAIL");
protocols.add(DNSSEC, "DNSSEC");
protocols.add(IPSEC, "IPSEC");
protocols.add(ANY, "ANY");
}
/**
* Converts an KEY protocol value into its textual representation
*/
public static
String string(int type) {
return protocols.getText(type);
}
/**
* Converts a textual representation of a KEY protocol into its
* numeric code. Integers in the range 0..255 are also accepted.
*
* @param s The textual representation of the protocol
*
* @return The protocol code, or -1 on error.
*/
public static
int value(String s) {
return protocols.getValue(s);
}
}
public static
class Flags {
/**
* KEY cannot be used for confidentiality
*/
public static final int NOCONF = 0x4000;
/**
* KEY cannot be used for authentication
*/
public static final int NOAUTH = 0x8000;
/**
* No key present
*/
public static final int NOKEY = 0xC000;
/**
* Bitmask of the use fields
*/
public static final int USE_MASK = 0xC000;
/**
* Flag 2 (unused)
*/
public static final int FLAG2 = 0x2000;
/**
* Flags extension
*/
public static final int EXTEND = 0x1000;
/**
* Flag 4 (unused)
*/
public static final int FLAG4 = 0x0800;
/**
* Flag 5 (unused)
*/
public static final int FLAG5 = 0x0400;
/**
* Key is owned by a user.
*/
public static final int USER = 0x0000;
/**
* Key is owned by a zone.
*/
public static final int ZONE = 0x0100;
/**
* Key is owned by a host.
*/
public static final int HOST = 0x0200;
/**
* Key owner type 3 (reserved).
*/
public static final int NTYP3 = 0x0300;
/**
* Key owner bitmask.
*/
public static final int OWNER_MASK = 0x0300;
/**
* Flag 8 (unused)
*/
public static final int FLAG8 = 0x0080;
/**
* Flag 9 (unused)
*/
public static final int FLAG9 = 0x0040;
/**
* Flag 10 (unused)
*/
public static final int FLAG10 = 0x0020;
/**
* Flag 11 (unused)
*/
public static final int FLAG11 = 0x0010;
/**
* Signatory value 0
*/
public static final int SIG0 = 0;
/**
* Signatory value 1
*/
public static final int SIG1 = 1;
/**
* Signatory value 2
*/
public static final int SIG2 = 2;
/**
* Signatory value 3
*/
public static final int SIG3 = 3;
/**
* Signatory value 4
*/
public static final int SIG4 = 4;
/**
* Signatory value 5
*/
public static final int SIG5 = 5;
/**
* Signatory value 6
*/
public static final int SIG6 = 6;
/**
* Signatory value 7
*/
public static final int SIG7 = 7;
/**
* Signatory value 8
*/
public static final int SIG8 = 8;
/**
* Signatory value 9
*/
public static final int SIG9 = 9;
/**
* Signatory value 10
*/
public static final int SIG10 = 10;
/**
* Signatory value 11
*/
public static final int SIG11 = 11;
/**
* Signatory value 12
*/
public static final int SIG12 = 12;
/**
* Signatory value 13
*/
public static final int SIG13 = 13;
/**
* Signatory value 14
*/
public static final int SIG14 = 14;
/**
* Signatory value 15
*/
public static final int SIG15 = 15;
private static Mnemonic flags = new Mnemonic("KEY flags", Mnemonic.CASE_UPPER);
/**
* KEY flags identifiers.
*/
private
Flags() {}
static {
flags.setMaximum(0xFFFF);
flags.setNumericAllowed(false);
flags.add(NOCONF, "NOCONF");
flags.add(NOAUTH, "NOAUTH");
flags.add(NOKEY, "NOKEY");
flags.add(FLAG2, "FLAG2");
flags.add(EXTEND, "EXTEND");
flags.add(FLAG4, "FLAG4");
flags.add(FLAG5, "FLAG5");
flags.add(USER, "USER");
flags.add(ZONE, "ZONE");
flags.add(HOST, "HOST");
flags.add(NTYP3, "NTYP3");
flags.add(FLAG8, "FLAG8");
flags.add(FLAG9, "FLAG9");
flags.add(FLAG10, "FLAG10");
flags.add(FLAG11, "FLAG11");
flags.add(SIG0, "SIG0");
flags.add(SIG1, "SIG1");
flags.add(SIG2, "SIG2");
flags.add(SIG3, "SIG3");
flags.add(SIG4, "SIG4");
flags.add(SIG5, "SIG5");
flags.add(SIG6, "SIG6");
flags.add(SIG7, "SIG7");
flags.add(SIG8, "SIG8");
flags.add(SIG9, "SIG9");
flags.add(SIG10, "SIG10");
flags.add(SIG11, "SIG11");
flags.add(SIG12, "SIG12");
flags.add(SIG13, "SIG13");
flags.add(SIG14, "SIG14");
flags.add(SIG15, "SIG15");
}
/**
* Converts a textual representation of KEY flags into its
* numeric code. Integers in the range 0..65535 are also accepted.
*
* @param s The textual representation of the protocol
*
* @return The protocol code, or -1 on error.
*/
public static
int value(String s) {
int value;
try {
value = Integer.parseInt(s);
if (value >= 0 && value <= 0xFFFF) {
return value;
}
return -1;
} catch (NumberFormatException e) {
}
StringTokenizer st = new StringTokenizer(s, "|");
value = 0;
while (st.hasMoreTokens()) {
int val = flags.getValue(st.nextToken());
if (val < 0) {
return -1;
}
value |= val;
}
return value;
}
}
KEYRecord() {}
@Override
DnsRecord getObject() {
return new KEYRecord();
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
String flagString = st.getIdentifier();
flags = Flags.value(flagString);
if (flags < 0) {
throw st.exception("Invalid flags: " + flagString);
}
String protoString = st.getIdentifier();
proto = Protocol.value(protoString);
if (proto < 0) {
throw st.exception("Invalid protocol: " + protoString);
}
String algString = st.getIdentifier();
alg = DNSSEC.Algorithm.value(algString);
if (alg < 0) {
throw st.exception("Invalid algorithm: " + algString);
}
/* If this is a null KEY, there's no key data */
if ((flags & Flags.USE_MASK) == Flags.NOKEY) {
key = null;
}
else {
key = st.getBase64();
}
}
/**
* Creates a KEY Record from the given data
*
* @param flags Flags describing the key's properties
* @param proto The protocol that the key was created for
* @param alg The key's algorithm
* @param key Binary data representing the key
*/
public
KEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, byte[] key) {
super(name, DnsRecordType.KEY, dclass, ttl, flags, proto, alg, key);
}
/**
* Creates a KEY Record from the given data
*
* @param flags Flags describing the key's properties
* @param proto The protocol that the key was created for
* @param alg The key's algorithm
* @param key The key as a PublicKey
*
* @throws DNSSEC.DNSSECException The PublicKey could not be converted into DNS
* format.
*/
public
KEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, PublicKey key) throws DNSSEC.DNSSECException {
super(name, DnsRecordType.KEY, dclass, ttl, flags, proto, alg, DNSSEC.fromPublicKey(key, alg));
publicKey = key;
}
}

View File

@ -1,60 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Key Exchange - delegation of authority
*
* @author Brian Wellington
*/
public
class KXRecord extends U16NameBase {
private static final long serialVersionUID = 7448568832769757809L;
KXRecord() {}
@Override
DnsRecord getObject() {
return new KXRecord();
}
@Override
public
Name getAdditionalName() {
return getNameField();
}
/**
* Creates a KX Record from the given data
*
* @param preference The preference of this KX. Records with lower priority
* are preferred.
* @param target The host that authority is delegated to
*/
public
KXRecord(Name name, int dclass, long ttl, int preference, Name target) {
super(name, DnsRecordType.KX, dclass, ttl, preference, "preference", target, "target");
}
/**
* Returns the target of the KX record
*/
public
Name getTarget() {
return getNameField();
}
/**
* Returns the preference of this KX record
*/
public
int getPreference() {
return getU16Field();
}
}

View File

@ -1,349 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Location - describes the physical location of hosts, networks, subnets.
*
* @author Brian Wellington
*/
public
class LOCRecord extends DnsRecord {
private static final long serialVersionUID = 9058224788126750409L;
private static NumberFormat w2, w3;
private long size, hPrecision, vPrecision;
private long latitude, longitude, altitude;
static {
w2 = new DecimalFormat();
w2.setMinimumIntegerDigits(2);
w3 = new DecimalFormat();
w3.setMinimumIntegerDigits(3);
}
LOCRecord() {}
@Override
DnsRecord getObject() {
return new LOCRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
int version;
version = in.readU8();
if (version != 0) {
throw new WireParseException("Invalid LOC version");
}
size = parseLOCformat(in.readU8());
hPrecision = parseLOCformat(in.readU8());
vPrecision = parseLOCformat(in.readU8());
latitude = in.readU32();
longitude = in.readU32();
altitude = in.readU32();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(0); /* version */
out.writeU8(toLOCformat(size));
out.writeU8(toLOCformat(hPrecision));
out.writeU8(toLOCformat(vPrecision));
out.writeU32(latitude);
out.writeU32(longitude);
out.writeU32(altitude);
}
/**
* Convert to a String
*/
@Override
void rrToString(StringBuilder sb) {
/* Latitude */
sb.append(positionToString(latitude, 'N', 'S'));
sb.append(" ");
/* Latitude */
sb.append(positionToString(longitude, 'E', 'W'));
sb.append(" ");
/* Altitude */
renderFixedPoint(sb, w2, altitude - 10000000, 100);
sb.append("m ");
/* Size */
renderFixedPoint(sb, w2, size, 100);
sb.append("m ");
/* Horizontal precision */
renderFixedPoint(sb, w2, hPrecision, 100);
sb.append("m ");
/* Vertical precision */
renderFixedPoint(sb, w2, vPrecision, 100);
sb.append("m");
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
latitude = parsePosition(st, "latitude");
longitude = parsePosition(st, "longitude");
altitude = parseDouble(st, "altitude", true, -10000000, 4284967295L, 0) + 10000000;
size = parseDouble(st, "size", false, 0, 9000000000L, 100);
hPrecision = parseDouble(st, "horizontal precision", false, 0, 9000000000L, 1000000);
vPrecision = parseDouble(st, "vertical precision", false, 0, 9000000000L, 1000);
}
private
long parsePosition(Tokenizer st, String type) throws IOException {
boolean isLatitude = type.equals("latitude");
int deg = 0, min = 0;
double sec = 0;
long value;
String s;
deg = st.getUInt16();
if (deg > 180 || (deg > 90 && isLatitude)) {
throw st.exception("Invalid LOC " + type + " degrees");
}
s = st.getString();
try {
min = Integer.parseInt(s);
if (min < 0 || min > 59) {
throw st.exception("Invalid LOC " + type + " minutes");
}
s = st.getString();
sec = parseFixedPoint(s);
if (sec < 0 || sec >= 60) {
throw st.exception("Invalid LOC " + type + " seconds");
}
s = st.getString();
} catch (NumberFormatException e) {
}
if (s.length() != 1) {
throw st.exception("Invalid LOC " + type);
}
value = (long) (1000 * (sec + 60L * (min + 60L * deg)));
char c = Character.toUpperCase(s.charAt(0));
if ((isLatitude && c == 'S') || (!isLatitude && c == 'W')) {
value = -value;
}
else if ((isLatitude && c != 'N') || (!isLatitude && c != 'E')) {
throw st.exception("Invalid LOC " + type);
}
value += (1L << 31);
return value;
}
private
double parseFixedPoint(String s) {
if (s.matches("^-?\\d+$")) {
return Integer.parseInt(s);
}
else if (s.matches("^-?\\d+\\.\\d*$")) {
String[] parts = s.split("\\.");
double value = Integer.parseInt(parts[0]);
double fraction = Integer.parseInt(parts[1]);
if (value < 0) {
fraction *= -1;
}
int digits = parts[1].length();
return value + (fraction / Math.pow(10, digits));
}
else {
throw new NumberFormatException();
}
}
private
long parseDouble(Tokenizer st, String type, boolean required, long min, long max, long defaultValue) throws IOException {
Tokenizer.Token token = st.get();
if (token.isEOL()) {
if (required) {
throw st.exception("Invalid LOC " + type);
}
st.unget();
return defaultValue;
}
String s = token.value;
if (s.length() > 1 && s.charAt(s.length() - 1) == 'm') {
s = s.substring(0, s.length() - 1);
}
try {
long value = (long) (100 * parseFixedPoint(s));
if (value < min || value > max) {
throw st.exception("Invalid LOC " + type);
}
return value;
} catch (NumberFormatException e) {
throw st.exception("Invalid LOC " + type);
}
}
private
String positionToString(long value, char pos, char neg) {
StringBuilder sb = new StringBuilder();
char direction;
long temp = value - (1L << 31);
if (temp < 0) {
temp = -temp;
direction = neg;
}
else {
direction = pos;
}
sb.append(temp / (3600 * 1000)); /* degrees */
temp = temp % (3600 * 1000);
sb.append(" ");
sb.append(temp / (60 * 1000)); /* minutes */
temp = temp % (60 * 1000);
sb.append(" ");
renderFixedPoint(sb, w3, temp, 1000); /* seconds */
sb.append(" ");
sb.append(direction);
return sb.toString();
}
private
void renderFixedPoint(StringBuilder sb, NumberFormat formatter, long value, long divisor) {
sb.append(value / divisor);
value %= divisor;
if (value != 0) {
sb.append(".");
sb.append(formatter.format(value));
}
}
private
int toLOCformat(long l) {
byte exp = 0;
while (l > 9) {
exp++;
l /= 10;
}
return (int) ((l << 4) + exp);
}
private static
long parseLOCformat(int b) throws WireParseException {
long out = b >> 4;
int exp = b & 0xF;
if (out > 9 || exp > 9) {
throw new WireParseException("Invalid LOC Encoding");
}
while (exp-- > 0) {
out *= 10;
}
return (out);
}
/**
* Creates an LOC Record from the given data
*
* @param latitude The latitude of the center of the sphere
* @param longitude The longitude of the center of the sphere
* @param altitude The altitude of the center of the sphere, in m
* @param size The diameter of a sphere enclosing the described entity, in m.
* @param hPrecision The horizontal precision of the data, in m.
* @param vPrecision The vertical precision of the data, in m.
*/
public
LOCRecord(Name name,
int dclass,
long ttl,
double latitude,
double longitude,
double altitude,
double size,
double hPrecision,
double vPrecision) {
super(name, DnsRecordType.LOC, dclass, ttl);
this.latitude = (long) (latitude * 3600 * 1000 + (1L << 31));
this.longitude = (long) (longitude * 3600 * 1000 + (1L << 31));
this.altitude = (long) ((altitude + 100000) * 100);
this.size = (long) (size * 100);
this.hPrecision = (long) (hPrecision * 100);
this.vPrecision = (long) (vPrecision * 100);
}
/**
* Returns the latitude
*/
public
double getLatitude() {
return ((double) (latitude - (1L << 31))) / (3600 * 1000);
}
/**
* Returns the longitude
*/
public
double getLongitude() {
return ((double) (longitude - (1L << 31))) / (3600 * 1000);
}
/**
* Returns the altitude
*/
public
double getAltitude() {
return ((double) (altitude - 10000000)) / 100;
}
/**
* Returns the diameter of the enclosing sphere
*/
public
double getSize() {
return ((double) size) / 100;
}
/**
* Returns the horizontal precision
*/
public
double getHPrecision() {
return ((double) hPrecision) / 100;
}
/**
* Returns the horizontal precision
*/
public
double getVPrecision() {
return ((double) vPrecision) / 100;
}
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Mailbox Record - specifies a host containing a mailbox.
*
* @author Brian Wellington
*/
public
class MBRecord extends SingleNameBase {
private static final long serialVersionUID = 532349543479150419L;
MBRecord() {}
@Override
DnsRecord getObject() {
return new MBRecord();
}
@Override
public
Name getAdditionalName() {
return getSingleName();
}
/**
* Creates a new MB Record with the given data
*
* @param mailbox The host containing the mailbox for the domain.
*/
public
MBRecord(Name name, int dclass, long ttl, Name mailbox) {
super(name, DnsRecordType.MB, dclass, ttl, mailbox, "mailbox");
}
/**
* Gets the mailbox for the domain
*/
public
Name getMailbox() {
return getSingleName();
}
}

View File

@ -1,51 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Mail Destination Record - specifies a mail agent which delivers mail
* for a domain (obsolete)
*
* @author Brian Wellington
*/
public
class MDRecord extends SingleNameBase {
private static final long serialVersionUID = 5268878603762942202L;
MDRecord() {}
@Override
DnsRecord getObject() {
return new MDRecord();
}
@Override
public
Name getAdditionalName() {
return getSingleName();
}
/**
* Creates a new MD Record with the given data
*
* @param mailAgent The mail agent that delivers mail for the domain.
*/
public
MDRecord(Name name, int dclass, long ttl, Name mailAgent) {
super(name, DnsRecordType.MD, dclass, ttl, mailAgent, "mail agent");
}
/**
* Gets the mail agent for the domain
*/
public
Name getMailAgent() {
return getSingleName();
}
}

View File

@ -1,51 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Mail Forwarder Record - specifies a mail agent which forwards mail
* for a domain (obsolete)
*
* @author Brian Wellington
*/
public
class MFRecord extends SingleNameBase {
private static final long serialVersionUID = -6670449036843028169L;
MFRecord() {}
@Override
DnsRecord getObject() {
return new MFRecord();
}
@Override
public
Name getAdditionalName() {
return getSingleName();
}
/**
* Creates a new MF Record with the given data
*
* @param mailAgent The mail agent that forwards mail for the domain.
*/
public
MFRecord(Name name, int dclass, long ttl, Name mailAgent) {
super(name, DnsRecordType.MF, dclass, ttl, mailAgent, "mail agent");
}
/**
* Gets the mail agent for the domain
*/
public
Name getMailAgent() {
return getSingleName();
}
}

View File

@ -1,45 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Mail Group Record - specifies a mailbox which is a member of a mail group.
*
* @author Brian Wellington
*/
public
class MGRecord extends SingleNameBase {
private static final long serialVersionUID = -3980055550863644582L;
MGRecord() {}
@Override
DnsRecord getObject() {
return new MGRecord();
}
/**
* Creates a new MG Record with the given data
*
* @param mailbox The mailbox that is a member of the group specified by the
* domain.
*/
public
MGRecord(Name name, int dclass, long ttl, Name mailbox) {
super(name, DnsRecordType.MG, dclass, ttl, mailbox, "mailbox");
}
/**
* Gets the mailbox in the mail group specified by the domain
*/
public
Name getMailbox() {
return getSingleName();
}
}

View File

@ -1,98 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Mailbox information Record - lists the address responsible for a mailing
* list/mailbox and the address to receive error messages relating to the
* mailing list/mailbox.
*
* @author Brian Wellington
*/
public
class MINFORecord extends DnsRecord {
private static final long serialVersionUID = -3962147172340353796L;
private Name responsibleAddress;
private Name errorAddress;
MINFORecord() {}
@Override
DnsRecord getObject() {
return new MINFORecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
responsibleAddress = new Name(in);
errorAddress = new Name(in);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
responsibleAddress.toWire(out, null, canonical);
errorAddress.toWire(out, null, canonical);
}
/**
* Converts the MINFO Record to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(responsibleAddress);
sb.append(" ");
sb.append(errorAddress);
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
responsibleAddress = st.getName(origin);
errorAddress = st.getName(origin);
}
/**
* Creates an MINFO Record from the given data
*
* @param responsibleAddress The address responsible for the
* mailing list/mailbox.
* @param errorAddress The address to receive error messages relating to the
* mailing list/mailbox.
*/
public
MINFORecord(Name name, int dclass, long ttl, Name responsibleAddress, Name errorAddress) {
super(name, DnsRecordType.MINFO, dclass, ttl);
this.responsibleAddress = checkName("responsibleAddress", responsibleAddress);
this.errorAddress = checkName("errorAddress", errorAddress);
}
/**
* Gets the address responsible for the mailing list/mailbox.
*/
public
Name getResponsibleAddress() {
return responsibleAddress;
}
/**
* Gets the address to receive error messages relating to the mailing
* list/mailbox.
*/
public
Name getErrorAddress() {
return errorAddress;
}
}

View File

@ -1,45 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Mailbox Rename Record - specifies a rename of a mailbox.
*
* @author Brian Wellington
*/
public
class MRRecord extends SingleNameBase {
private static final long serialVersionUID = -5617939094209927533L;
MRRecord() {}
@Override
DnsRecord getObject() {
return new MRRecord();
}
/**
* Creates a new MR Record with the given data
*
* @param newName The new name of the mailbox specified by the domain.
* domain.
*/
public
MRRecord(Name name, int dclass, long ttl, Name newName) {
super(name, DnsRecordType.MR, dclass, ttl, newName, "new name");
}
/**
* Gets the new name of the mailbox specified by the domain
*/
public
Name getNewName() {
return getSingleName();
}
}

View File

@ -1,68 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Mail Exchange - specifies where mail to a domain is sent
*
* @author Brian Wellington
*/
public
class MXRecord extends U16NameBase {
private static final long serialVersionUID = 2914841027584208546L;
MXRecord() {}
@Override
DnsRecord getObject() {
return new MXRecord();
}
@Override
public
Name getAdditionalName() {
return getNameField();
}
/**
* Creates an MX Record from the given data
*
* @param priority The priority of this MX. Records with lower priority
* are preferred.
* @param target The host that mail is sent to
*/
public
MXRecord(Name name, int dclass, long ttl, int priority, Name target) {
super(name, DnsRecordType.MX, dclass, ttl, priority, "priority", target, "target");
}
/**
* Returns the target of the MX record
*/
public
Name getTarget() {
return getNameField();
}
/**
* Returns the priority of this MX record
*/
public
int getPriority() {
return getU16Field();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(u16Field);
nameField.toWire(out, c, canonical);
}
}

View File

@ -1,174 +0,0 @@
// Copyright (c) 2000-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Name Authority Pointer Record - specifies rewrite rule, that when applied
* to an existing string will produce a new domain.
*
* @author Chuck Santos
*/
public
class NAPTRRecord extends DnsRecord {
private static final long serialVersionUID = 5191232392044947002L;
private int order, preference;
private byte[] flags, service, regexp;
private Name replacement;
NAPTRRecord() {}
@Override
DnsRecord getObject() {
return new NAPTRRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
order = in.readU16();
preference = in.readU16();
flags = in.readCountedString();
service = in.readCountedString();
regexp = in.readCountedString();
replacement = new Name(in);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(order);
out.writeU16(preference);
out.writeCountedString(flags);
out.writeCountedString(service);
out.writeCountedString(regexp);
replacement.toWire(out, null, canonical);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(order);
sb.append(" ");
sb.append(preference);
sb.append(" ");
sb.append(byteArrayToString(flags, true));
sb.append(" ");
sb.append(byteArrayToString(service, true));
sb.append(" ");
sb.append(byteArrayToString(regexp, true));
sb.append(" ");
sb.append(replacement);
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
order = st.getUInt16();
preference = st.getUInt16();
try {
flags = byteArrayFromString(st.getString());
service = byteArrayFromString(st.getString());
regexp = byteArrayFromString(st.getString());
} catch (TextParseException e) {
throw st.exception(e.getMessage());
}
replacement = st.getName(origin);
}
@Override
public
Name getAdditionalName() {
return replacement;
}
/**
* Creates an NAPTR Record from the given data
*
* @param order The order of this NAPTR. Records with lower order are
* preferred.
* @param preference The preference, used to select between records at the
* same order.
* @param flags The control aspects of the NAPTRRecord.
* @param service The service or protocol available down the rewrite path.
* @param regexp The regular/substitution expression.
* @param replacement The domain-name to query for the next DNS resource
* record, depending on the value of the flags field.
*
* @throws IllegalArgumentException One of the strings has invalid escapes
*/
public
NAPTRRecord(Name name, int dclass, long ttl, int order, int preference, String flags, String service, String regexp, Name replacement) {
super(name, DnsRecordType.NAPTR, dclass, ttl);
this.order = checkU16("order", order);
this.preference = checkU16("preference", preference);
try {
this.flags = byteArrayFromString(flags);
this.service = byteArrayFromString(service);
this.regexp = byteArrayFromString(regexp);
} catch (TextParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
this.replacement = checkName("replacement", replacement);
}
/**
* Returns the order
*/
public
int getOrder() {
return order;
}
/**
* Returns the preference
*/
public
int getPreference() {
return preference;
}
/**
* Returns flags
*/
public
String getFlags() {
return byteArrayToString(flags, false);
}
/**
* Returns service
*/
public
String getService() {
return byteArrayToString(service, false);
}
/**
* Returns regexp
*/
public
String getRegexp() {
return byteArrayToString(regexp, false);
}
/**
* Returns the replacement domain-name
*/
public
Name getReplacement() {
return replacement;
}
}

View File

@ -1,120 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* NSAP Address Record.
*
* @author Brian Wellington
*/
public
class NSAPRecord extends DnsRecord {
private static final long serialVersionUID = -1037209403185658593L;
private byte[] address;
NSAPRecord() {}
@Override
DnsRecord getObject() {
return new NSAPRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
address = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeByteArray(address);
}
@Override
void rrToString(StringBuilder sb) {
sb.append("0x")
.append(base16.toString(address));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
String addr = st.getString();
this.address = checkAndConvertAddress(addr);
if (this.address == null) {
throw st.exception("invalid NSAP address " + addr);
}
}
/**
* Creates an NSAP Record from the given data
*
* @param address The NSAP address.
*
* @throws IllegalArgumentException The address is not a valid NSAP address.
*/
public
NSAPRecord(Name name, int dclass, long ttl, String address) {
super(name, DnsRecordType.NSAP, dclass, ttl);
this.address = checkAndConvertAddress(address);
if (this.address == null) {
throw new IllegalArgumentException("invalid NSAP address " + address);
}
}
private static
byte[] checkAndConvertAddress(String address) {
if (!address.substring(0, 2)
.equalsIgnoreCase("0x")) {
return null;
}
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
boolean partial = false;
int current = 0;
for (int i = 2; i < address.length(); i++) {
char c = address.charAt(i);
if (c == '.') {
continue;
}
int value = Character.digit(c, 16);
if (value == -1) {
return null;
}
if (partial) {
current += value;
bytes.write(current);
partial = false;
}
else {
current = value << 4;
partial = true;
}
}
if (partial) {
return null;
}
return bytes.toByteArray();
}
/**
* Returns the NSAP address.
*/
public
String getAddress() {
return byteArrayToString(address, false);
}
}

View File

@ -1,45 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* NSAP Pointer Record - maps a domain name representing an NSAP Address to
* a hostname.
*
* @author Brian Wellington
*/
public
class NSAP_PTRRecord extends SingleNameBase {
private static final long serialVersionUID = 2386284746382064904L;
NSAP_PTRRecord() {}
@Override
DnsRecord getObject() {
return new NSAP_PTRRecord();
}
/**
* Creates a new NSAP_PTR Record with the given data
*
* @param target The name of the host with this address
*/
public
NSAP_PTRRecord(Name name, int dclass, long ttl, Name target) {
super(name, DnsRecordType.NSAP_PTR, dclass, ttl, target, "target");
}
/**
* Gets the target of the NSAP_PTR Record
*/
public
Name getTarget() {
return getSingleName();
}
}

View File

@ -1,188 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* Next SECure name 3 Parameters - this record contains the parameters (hash
* algorithm, salt, iterations) used for a valid, complete NSEC3 chain present
* in a zone. Zones signed using NSEC3 must include this record at the zone apex
* to inform authoritative servers that NSEC3 is being used with the given
* parameters.
*
* @author Brian Wellington
* @author David Blacka
*/
public
class NSEC3PARAMRecord extends DnsRecord {
private static final long serialVersionUID = -8689038598776316533L;
private int hashAlg;
private int flags;
private int iterations;
private byte salt[];
NSEC3PARAMRecord() {}
@Override
DnsRecord getObject() {
return new NSEC3PARAMRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
hashAlg = in.readU8();
flags = in.readU8();
iterations = in.readU16();
int salt_length = in.readU8();
if (salt_length > 0) {
salt = in.readByteArray(salt_length);
}
else {
salt = null;
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(hashAlg);
out.writeU8(flags);
out.writeU16(iterations);
if (salt != null) {
out.writeU8(salt.length);
out.writeByteArray(salt);
}
else {
out.writeU8(0);
}
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(hashAlg);
sb.append(' ');
sb.append(flags);
sb.append(' ');
sb.append(iterations);
sb.append(' ');
if (salt == null) {
sb.append('-');
}
else {
sb.append(base16.toString(salt));
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
hashAlg = st.getUInt8();
flags = st.getUInt8();
iterations = st.getUInt16();
String s = st.getString();
if (s.equals("-")) {
salt = null;
}
else {
st.unget();
salt = st.getHexString();
if (salt.length > 255) {
throw st.exception("salt value too long");
}
}
}
/**
* Creates an NSEC3PARAM record from the given data.
*
* @param name The ownername of the NSEC3PARAM record (generally the zone name).
* @param dclass The class.
* @param ttl The TTL.
* @param hashAlg The hash algorithm.
* @param flags The value of the flags field.
* @param iterations The number of hash iterations.
* @param salt The salt to use (may be null).
*/
public
NSEC3PARAMRecord(Name name, int dclass, long ttl, int hashAlg, int flags, int iterations, byte[] salt) {
super(name, DnsRecordType.NSEC3PARAM, dclass, ttl);
this.hashAlg = checkU8("hashAlg", hashAlg);
this.flags = checkU8("flags", flags);
this.iterations = checkU16("iterations", iterations);
if (salt != null) {
if (salt.length > 255) {
throw new IllegalArgumentException("Invalid salt " + "length");
}
if (salt.length > 0) {
this.salt = new byte[salt.length];
System.arraycopy(salt, 0, this.salt, 0, salt.length);
}
}
}
/**
* Returns the hash algorithm
*/
public
int getHashAlgorithm() {
return hashAlg;
}
/**
* Returns the flags
*/
public
int getFlags() {
return flags;
}
/**
* Returns the number of iterations
*/
public
int getIterations() {
return iterations;
}
/**
* Returns the salt
*/
public
byte[] getSalt() {
return salt;
}
/**
* Hashes a name with the parameters of this NSEC3PARAM record.
*
* @param name The name to hash
*
* @return The hashed version of the name
*
* @throws NoSuchAlgorithmException The hash algorithm is unknown.
*/
public
byte[] hashName(Name name) throws NoSuchAlgorithmException {
return NSEC3Record.hashName(name, hashAlg, iterations, salt);
}
}

View File

@ -1,301 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
import dorkbox.network.dns.utils.base32;
/**
* Next SECure name 3 - this record contains the next hashed name in an
* ordered list of hashed names in the zone, and a set of types for which
* records exist for this name. The presence of this record in a response
* signifies a negative response from a DNSSEC-signed zone.
* <p>
* This replaces the NSEC and NXT records, when used.
*
* @author Brian Wellington
* @author David Blacka
*/
public
class NSEC3Record extends DnsRecord {
public static final int SHA1_DIGEST_ID = Digest.SHA1;
private static final long serialVersionUID = -7123504635968932855L;
private int hashAlg;
private int flags;
private int iterations;
private byte[] salt;
private byte[] next;
private TypeBitmap types;
private static final base32 b32 = new base32(base32.Alphabet.BASE32HEX, false, false);
public static
class Flags {
/**
* Unsigned delegation are not included in the NSEC3 chain.
*/
public static final int OPT_OUT = 0x01;
/**
* NSEC3 flags identifiers.
*/
private
Flags() {}
}
public static
class Digest {
/**
* SHA-1
*/
public static final int SHA1 = 1;
private
Digest() {}
}
NSEC3Record() {}
@Override
DnsRecord getObject() {
return new NSEC3Record();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
hashAlg = in.readU8();
flags = in.readU8();
iterations = in.readU16();
int salt_length = in.readU8();
if (salt_length > 0) {
salt = in.readByteArray(salt_length);
}
else {
salt = null;
}
int next_length = in.readU8();
next = in.readByteArray(next_length);
types = new TypeBitmap(in);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(hashAlg);
out.writeU8(flags);
out.writeU16(iterations);
if (salt != null) {
out.writeU8(salt.length);
out.writeByteArray(salt);
}
else {
out.writeU8(0);
}
out.writeU8(next.length);
out.writeByteArray(next);
types.toWire(out);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(hashAlg);
sb.append(' ');
sb.append(flags);
sb.append(' ');
sb.append(iterations);
sb.append(' ');
if (salt == null) {
sb.append('-');
}
else {
sb.append(base16.toString(salt));
}
sb.append(' ');
sb.append(b32.toString(next));
if (!types.empty()) {
sb.append(' ');
sb.append(types.toString());
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
hashAlg = st.getUInt8();
flags = st.getUInt8();
iterations = st.getUInt16();
String s = st.getString();
if (s.equals("-")) {
salt = null;
}
else {
st.unget();
salt = st.getHexString();
if (salt.length > 255) {
throw st.exception("salt value too long");
}
}
next = st.getBase32String(b32);
types = new TypeBitmap(st);
}
/**
* Creates an NSEC3 record from the given data.
*
* @param name The ownername of the NSEC3 record (base32'd hash plus zonename).
* @param dclass The class.
* @param ttl The TTL.
* @param hashAlg The hash algorithm.
* @param flags The value of the flags field.
* @param iterations The number of hash iterations.
* @param salt The salt to use (may be null).
* @param next The next hash (may not be null).
* @param types The types present at the original ownername.
*/
public
NSEC3Record(Name name, int dclass, long ttl, int hashAlg, int flags, int iterations, byte[] salt, byte[] next, int[] types) {
super(name, DnsRecordType.NSEC3, dclass, ttl);
this.hashAlg = checkU8("hashAlg", hashAlg);
this.flags = checkU8("flags", flags);
this.iterations = checkU16("iterations", iterations);
if (salt != null) {
if (salt.length > 255) {
throw new IllegalArgumentException("Invalid salt");
}
if (salt.length > 0) {
this.salt = new byte[salt.length];
System.arraycopy(salt, 0, this.salt, 0, salt.length);
}
}
if (next.length > 255) {
throw new IllegalArgumentException("Invalid next hash");
}
this.next = new byte[next.length];
System.arraycopy(next, 0, this.next, 0, next.length);
this.types = new TypeBitmap(types);
}
/**
* Returns the hash algorithm
*/
public
int getHashAlgorithm() {
return hashAlg;
}
/**
* Returns the flags
*/
public
int getFlags() {
return flags;
}
/**
* Returns the number of iterations
*/
public
int getIterations() {
return iterations;
}
/**
* Returns the salt
*/
public
byte[] getSalt() {
return salt;
}
/**
* Returns the next hash
*/
public
byte[] getNext() {
return next;
}
/**
* Returns the set of types defined for this name
*/
public
int[] getTypes() {
return types.toArray();
}
/**
* Returns whether a specific type is in the set of types.
*/
public
boolean hasType(int type) {
return types.contains(type);
}
/**
* Hashes a name with the parameters of this NSEC3 record.
*
* @param name The name to hash
*
* @return The hashed version of the name
*
* @throws NoSuchAlgorithmException The hash algorithm is unknown.
*/
public
byte[] hashName(Name name) throws NoSuchAlgorithmException {
return hashName(name, hashAlg, iterations, salt);
}
static
byte[] hashName(Name name, int hashAlg, int iterations, byte[] salt) throws NoSuchAlgorithmException {
MessageDigest digest;
switch (hashAlg) {
case Digest.SHA1:
digest = MessageDigest.getInstance("sha-1");
break;
default:
throw new NoSuchAlgorithmException("Unknown NSEC3 algorithm" + "identifier: " + hashAlg);
}
byte[] hash = null;
for (int i = 0; i <= iterations; i++) {
digest.reset();
if (i == 0) {
digest.update(name.toWireCanonical());
}
else {
digest.update(hash);
}
if (salt != null) {
digest.update(salt);
}
hash = digest.digest();
}
return hash;
}
}

View File

@ -1,113 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Next SECure name - this record contains the following name in an
* ordered list of names in the zone, and a set of types for which
* records exist for this name. The presence of this record in a response
* signifies a negative response from a DNSSEC-signed zone.
* <p>
* This replaces the NXT record.
*
* @author Brian Wellington
* @author David Blacka
*/
public
class NSECRecord extends DnsRecord {
private static final long serialVersionUID = -5165065768816265385L;
private Name next;
private TypeBitmap types;
NSECRecord() {}
@Override
DnsRecord getObject() {
return new NSECRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
next = new Name(in);
types = new TypeBitmap(in);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
// Note: The next name is not lowercased.
next.toWire(out, null, false);
types.toWire(out);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(next);
if (!types.empty()) {
sb.append(' ');
sb.append(types.toString());
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
next = st.getName(origin);
types = new TypeBitmap(st);
}
/**
* Creates an NSEC Record from the given data.
*
* @param next The following name in an ordered list of the zone
* @param types An array containing the types present.
*/
public
NSECRecord(Name name, int dclass, long ttl, Name next, int[] types) {
super(name, DnsRecordType.NSEC, dclass, ttl);
this.next = checkName("next", next);
for (int i = 0; i < types.length; i++) {
DnsRecordType.check(types[i]);
}
this.types = new TypeBitmap(types);
}
/**
* Returns the next name
*/
public
Name getNext() {
return next;
}
/**
* Returns the set of types defined for this name
*/
public
int[] getTypes() {
return types.toArray();
}
/**
* Returns whether a specific type is in the set of types.
*/
public
boolean hasType(int type) {
return types.contains(type);
}
}

View File

@ -1,30 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
/**
* The Name Server Identifier Option, define in RFC 5001.
*
* @author Brian Wellington
* @see OPTRecord
*/
public
class NSIDOption extends GenericEDNSOption {
private static final long serialVersionUID = 74739759292589056L;
NSIDOption() {
super(EDNSOption.Code.NSID);
}
/**
* Construct an NSID option.
*
* @param data The contents of the option.
*/
public
NSIDOption(byte[] data) {
super(EDNSOption.Code.NSID, data);
}
}

View File

@ -1,50 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Name Server Record - contains the name server serving the named zone
*
* @author Brian Wellington
*/
public
class NSRecord extends SingleCompressedNameBase {
private static final long serialVersionUID = 487170758138268838L;
NSRecord() {}
@Override
DnsRecord getObject() {
return new NSRecord();
}
@Override
public
Name getAdditionalName() {
return getSingleName();
}
/**
* Creates a new NS Record with the given data
*
* @param target The name server for the given domain
*/
public
NSRecord(Name name, int dclass, long ttl, Name target) {
super(name, DnsRecordType.NS, dclass, ttl, target, "target");
}
/**
* Gets the target of the NS Record
*/
public
Name getTarget() {
return getSingleName();
}
}

View File

@ -1,78 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* The NULL Record. This has no defined purpose, but can be used to
* hold arbitrary data.
*
* @author Brian Wellington
*/
public
class NULLRecord extends DnsRecord {
private static final long serialVersionUID = -5796493183235216538L;
private byte[] data;
NULLRecord() {}
@Override
DnsRecord getObject() {
return new NULLRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
data = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeByteArray(data);
}
@Override
void rrToString(StringBuilder sb) {
sb.append(unknownToString(data));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
throw st.exception("no defined text format for NULL records");
}
/**
* Creates a NULL record from the given data.
*
* @param data The contents of the record.
*/
public
NULLRecord(Name name, int dclass, long ttl, byte[] data) {
super(name, DnsRecordType.NULL, dclass, ttl);
if (data.length > 0xFFFF) {
throw new IllegalArgumentException("data must be <65536 bytes");
}
this.data = data;
}
/**
* Returns the contents of this record.
*/
public
byte[] getData() {
return data;
}
}

View File

@ -1,129 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.util.BitSet;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Next name - this record contains the following name in an ordered list
* of names in the zone, and a set of types for which records exist for
* this name. The presence of this record in a response signifies a
* failed query for data in a DNSSEC-signed zone.
*
* @author Brian Wellington
*/
public
class NXTRecord extends DnsRecord {
private static final long serialVersionUID = -8851454400765507520L;
private Name next;
private BitSet bitmap;
NXTRecord() {}
@Override
DnsRecord getObject() {
return new NXTRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
next = new Name(in);
bitmap = new BitSet();
int bitmapLength = in.remaining();
for (int i = 0; i < bitmapLength; i++) {
int t = in.readU8();
for (int j = 0; j < 8; j++) {
if ((t & (1 << (7 - j))) != 0) {
bitmap.set(i * 8 + j);
}
}
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
next.toWire(out, null, canonical);
int length = bitmap.length();
for (int i = 0, t = 0; i < length; i++) {
t |= (bitmap.get(i) ? (1 << (7 - i % 8)) : 0);
if (i % 8 == 7 || i == length - 1) {
out.writeU8(t);
t = 0;
}
}
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(next);
int length = bitmap.length();
for (short i = 0; i < length; i++) {
if (bitmap.get(i)) {
sb.append(" ");
sb.append(DnsRecordType.string(i));
}
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
next = st.getName(origin);
bitmap = new BitSet();
while (true) {
Tokenizer.Token t = st.get();
if (!t.isString()) {
break;
}
int typecode = DnsRecordType.value(t.value, true);
if (typecode <= 0 || typecode > 128) {
throw st.exception("Invalid type: " + t.value);
}
bitmap.set(typecode);
}
st.unget();
}
/**
* Creates an NXT Record from the given data
*
* @param next The following name in an ordered list of the zone
* @param bitmap The set of type for which records exist at this name
*/
public
NXTRecord(Name name, int dclass, long ttl, Name next, BitSet bitmap) {
super(name, DnsRecordType.NXT, dclass, ttl);
this.next = checkName("next", next);
this.bitmap = bitmap;
}
/**
* Returns the next name
*/
public
Name getNext() {
return next;
}
/**
* Returns the set of types defined for this name
*/
public
BitSet getBitmap() {
return bitmap;
}
}

View File

@ -1,88 +0,0 @@
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Options;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.util.Base64Fast;
import dorkbox.util.OS;
/**
* OPENPGPKEY Record - Stores an OpenPGP certificate associated with a name.
* RFC 7929.
*
* @author Brian Wellington
* @author Valentin Hauner
*/
public
class OPENPGPKEYRecord extends DnsRecord {
private static final long serialVersionUID = -1277262990243423062L;
private byte[] cert;
OPENPGPKEYRecord() {}
@Override
DnsRecord getObject() {
return new OPENPGPKEYRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
cert = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeByteArray(cert);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
if (cert != null) {
if (Options.check("multiline")) {
sb.append("(")
.append(OS.LINE_SEPARATOR);
sb.append(Base64Fast.formatString(Base64Fast.encode2(cert), 64, "\t", true));
}
else {
sb.append("\t");
sb.append(Base64Fast.encode2(cert));
}
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
cert = st.getBase64();
}
/**
* Creates an OPENPGPKEY Record from the given data
*
* @param cert Binary data representing the certificate
*/
public
OPENPGPKEYRecord(Name name, int dclass, long ttl, byte[] cert) {
super(name, DnsRecordType.OPENPGPKEY, dclass, ttl);
this.cert = cert;
}
/**
* Returns the binary representation of the certificate
*/
public
byte[] getCert() {
return cert;
}
}

View File

@ -1,234 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsResponseCode;
import dorkbox.network.dns.constants.ExtendedFlags;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Options - describes Extended DNS (EDNS) properties of a DnsMessage.
* No specific options are defined other than those specified in the
* header. An OPT should be generated by Resolver.
* <p>
* EDNS is a method to extend the DNS protocol while providing backwards
* compatibility and not significantly changing the protocol. This
* implementation of EDNS is mostly complete at level 0.
*
* @author Brian Wellington
* @see DnsMessage
*/
public
class OPTRecord extends DnsRecord {
private static final long serialVersionUID = -6254521894809367938L;
private List options;
OPTRecord() {}
@Override
DnsRecord getObject() {
return new OPTRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
if (in.remaining() > 0) {
options = new ArrayList();
}
while (in.remaining() > 0) {
EDNSOption option = EDNSOption.fromWire(in);
options.add(option);
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
if (options == null) {
return;
}
Iterator it = options.iterator();
while (it.hasNext()) {
EDNSOption option = (EDNSOption) it.next();
option.toWire(out);
}
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
if (options != null) {
sb.append(options);
sb.append(" ");
}
sb.append(" ; payload ");
sb.append(getPayloadSize());
sb.append(", xrcode ");
sb.append(getExtendedRcode());
sb.append(", version ");
sb.append(getVersion());
sb.append(", flags ");
sb.append(getFlags());
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
throw st.exception("no text format defined for OPT");
}
/**
* Determines if two OPTRecords are identical. This compares the name, type,
* class, and rdata (with names canonicalized). Additionally, because TTLs
* are relevant for OPT records, the TTLs are compared.
*
* @param arg The record to compare to
*
* @return true if the records are equal, false otherwise.
*/
@Override
public
boolean equals(final Object arg) {
return super.equals(arg) && ttl == ((OPTRecord) arg).ttl;
}
/**
* Returns the maximum allowed payload size.
*/
public
int getPayloadSize() {
return dclass;
}
/**
* Returns the extended DnsResponseCode
*
* @see DnsResponseCode
*/
public
int getExtendedRcode() {
return (int) (ttl >>> 24);
}
/**
* Returns the highest supported EDNS version
*/
public
int getVersion() {
return (int) ((ttl >>> 16) & 0xFF);
}
/**
* Returns the EDNS flags
*/
public
int getFlags() {
return (int) (ttl & 0xFFFF);
}
/**
* Creates an OPT Record with no data. This is normally called by
* SimpleResolver, but can also be called by a server.
*
* @param payloadSize The size of a packet that can be reassembled on the
* sending host.
* @param xrcode The value of the extended rcode field. This is the upper
* 16 bits of the full rcode.
* @param flags Additional message flags.
* @param version The EDNS version that this DNS implementation supports.
* This should be 0 for dnsjava.
*
* @see ExtendedFlags
*/
public
OPTRecord(int payloadSize, int xrcode, int version, int flags) {
this(payloadSize, xrcode, version, flags, null);
}
/**
* Creates an OPT Record. This is normally called by SimpleResolver, but can
* also be called by a server.
*
* @param payloadSize The size of a packet that can be reassembled on the
* sending host.
* @param xrcode The value of the extended rcode field. This is the upper
* 16 bits of the full rcode.
* @param flags Additional message flags.
* @param version The EDNS version that this DNS implementation supports.
* This should be 0 for dnsjava.
* @param options The list of options that comprise the data field. There
* are currently no defined options.
*
* @see ExtendedFlags
*/
public
OPTRecord(int payloadSize, int xrcode, int version, int flags, List options) {
super(Name.root, DnsRecordType.OPT, payloadSize, 0);
checkU16("payloadSize", payloadSize);
checkU8("xrcode", xrcode);
checkU8("version", version);
checkU16("flags", flags);
ttl = ((long) xrcode << 24) + ((long) version << 16) + flags;
if (options != null) {
this.options = new ArrayList(options);
}
}
/**
* Creates an OPT Record with no data. This is normally called by
* SimpleResolver, but can also be called by a server.
*/
public
OPTRecord(int payloadSize, int xrcode, int version) {
this(payloadSize, xrcode, version, 0, null);
}
/**
* Gets all options in the OPTRecord. This returns a list of EDNSOptions.
*/
public
List getOptions() {
if (options == null) {
return Collections.EMPTY_LIST;
}
return Collections.unmodifiableList(options);
}
/**
* Gets all options in the OPTRecord with a specific code. This returns a list
* of EDNSOptions.
*/
public
List getOptions(int code) {
if (options == null) {
return Collections.EMPTY_LIST;
}
List list = Collections.EMPTY_LIST;
for (Iterator it = options.iterator(); it.hasNext(); ) {
EDNSOption opt = (EDNSOption) it.next();
if (opt.getCode() == code) {
if (list == Collections.EMPTY_LIST) {
list = new ArrayList();
}
list.add(opt);
}
}
return list;
}
}

View File

@ -1,45 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Pointer Record - maps a domain name representing an Internet Address to
* a hostname.
*
* @author Brian Wellington
*/
public
class PTRRecord extends SingleCompressedNameBase {
private static final long serialVersionUID = -8321636610425434192L;
PTRRecord() {}
@Override
DnsRecord getObject() {
return new PTRRecord();
}
/**
* Creates a new PTR Record with the given data
*
* @param target The name of the machine with this address
*/
public
PTRRecord(Name name, int dclass, long ttl, Name target) {
super(name, DnsRecordType.PTR, dclass, ttl, target, "target");
}
/**
* Gets the target of the PTR Record
*/
public
Name getTarget() {
return getSingleName();
}
}

View File

@ -1,109 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* X.400 mail mapping record.
*
* @author Brian Wellington
*/
public
class PXRecord extends DnsRecord {
private static final long serialVersionUID = 1811540008806660667L;
private int preference;
private Name map822;
private Name mapX400;
PXRecord() {}
@Override
DnsRecord getObject() {
return new PXRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
preference = in.readU16();
map822 = new Name(in);
mapX400 = new Name(in);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(preference);
map822.toWire(out, null, canonical);
mapX400.toWire(out, null, canonical);
}
/**
* Converts the PX Record to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(preference);
sb.append(" ");
sb.append(map822);
sb.append(" ");
sb.append(mapX400);
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
preference = st.getUInt16();
map822 = st.getName(origin);
mapX400 = st.getName(origin);
}
/**
* Creates an PX Record from the given data
*
* @param preference The preference of this mail address.
* @param map822 The RFC 822 component of the mail address.
* @param mapX400 The X.400 component of the mail address.
*/
public
PXRecord(Name name, int dclass, long ttl, int preference, Name map822, Name mapX400) {
super(name, DnsRecordType.PX, dclass, ttl);
this.preference = checkU16("preference", preference);
this.map822 = checkName("map822", map822);
this.mapX400 = checkName("mapX400", mapX400);
}
/**
* Gets the preference of the route.
*/
public
int getPreference() {
return preference;
}
/**
* Gets the RFC 822 component of the mail address.
*/
public
Name getMap822() {
return map822;
}
/**
* Gets the X.400 component of the mail address.
*/
public
Name getMapX400() {
return mapX400;
}
}

View File

@ -1,95 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Responsible Person Record - lists the mail address of a responsible person
* and a domain where TXT records are available.
*
* @author Tom Scola (tscola@research.att.com)
* @author Brian Wellington
*/
public
class RPRecord extends DnsRecord {
private static final long serialVersionUID = 8124584364211337460L;
private Name mailbox;
private Name textDomain;
RPRecord() {}
@Override
DnsRecord getObject() {
return new RPRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
mailbox = new Name(in);
textDomain = new Name(in);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
mailbox.toWire(out, null, canonical);
textDomain.toWire(out, null, canonical);
}
/**
* Converts the RP Record to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(mailbox);
sb.append(" ");
sb.append(textDomain);
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
mailbox = st.getName(origin);
textDomain = st.getName(origin);
}
/**
* Creates an RP Record from the given data
*
* @param mailbox The responsible person
* @param textDomain The address where TXT records can be found
*/
public
RPRecord(Name name, int dclass, long ttl, Name mailbox, Name textDomain) {
super(name, DnsRecordType.RP, dclass, ttl);
this.mailbox = checkName("mailbox", mailbox);
this.textDomain = checkName("textDomain", textDomain);
}
/**
* Gets the mailbox address of the RP Record
*/
public
Name getMailbox() {
return mailbox;
}
/**
* Gets the text domain info of the RP Record
*/
public
Name getTextDomain() {
return textDomain;
}
}

View File

@ -1,61 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.util.Date;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Recource Record Signature - An RRSIG provides the digital signature of an
* RRset, so that the data can be authenticated by a DNSSEC-capable resolver.
* The signature is generated by a key contained in a DNSKEY Record.
*
* @author Brian Wellington
* @see RRset
* @see DNSSEC
* @see KEYRecord
*/
public
class RRSIGRecord extends SIGBase {
private static final long serialVersionUID = -2609150673537226317L;
RRSIGRecord() {}
@Override
DnsRecord getObject() {
return new RRSIGRecord();
}
/**
* Creates an RRSIG Record from the given data
*
* @param covered The RRset type covered by this signature
* @param alg The cryptographic algorithm of the key that generated the
* signature
* @param origttl The original TTL of the RRset
* @param expire The time at which the signature expires
* @param timeSigned The time at which this signature was generated
* @param footprint The footprint/key id of the signing key.
* @param signer The owner of the signing key
* @param signature Binary data representing the signature
*/
public
RRSIGRecord(Name name,
int dclass,
long ttl,
int covered,
int alg,
long origttl,
Date expire,
Date timeSigned,
int footprint,
Name signer,
byte[] signature) {
super(name, DnsRecordType.RRSIG, dclass, ttl, covered, alg, origttl, expire, timeSigned, footprint, signer, signature);
}
}

View File

@ -1,309 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsClass;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* A set of Records with the same name, type, and class. Also included
* are all RRSIG records signing the data records.
*
* @author Brian Wellington
* @see DnsRecord
* @see RRSIGRecord
*/
public
class RRset implements Serializable {
private static final long serialVersionUID = -3270249290171239695L;
/*
* rrs contains both normal and RRSIG records, with the RRSIG records
* at the end.
*/
private List resourceRecords;
private short nsigs;
private short position;
/**
* Creates an RRset and sets its contents to the specified record
*/
public
RRset(DnsRecord record) {
this();
safeAddRR(record);
}
/**
* Creates an empty RRset
*/
public
RRset() {
resourceRecords = new ArrayList(1);
nsigs = 0;
position = 0;
}
private
void safeAddRR(DnsRecord r) {
if (!(r instanceof RRSIGRecord)) {
if (nsigs == 0) {
resourceRecords.add(r);
}
else {
resourceRecords.add(resourceRecords.size() - nsigs, r);
}
}
else {
resourceRecords.add(r);
nsigs++;
}
}
/**
* Creates an RRset with the contents of an existing RRset
*/
public
RRset(RRset rrset) {
synchronized (rrset) {
resourceRecords = (List) ((ArrayList) rrset.resourceRecords).clone();
nsigs = rrset.nsigs;
position = rrset.position;
}
}
/**
* Adds a Record to an RRset
*/
public synchronized
void addRR(DnsRecord r) {
if (resourceRecords.size() == 0) {
safeAddRR(r);
return;
}
DnsRecord first = first();
if (!r.sameRRset(first)) {
throw new IllegalArgumentException("record does not match " + "rrset");
}
if (r.getTTL() != first.getTTL()) {
if (r.getTTL() > first.getTTL()) {
r = r.cloneRecord();
r.setTTL(first.getTTL());
}
else {
for (int i = 0; i < resourceRecords.size(); i++) {
DnsRecord tmp = (DnsRecord) resourceRecords.get(i);
tmp = tmp.cloneRecord();
tmp.setTTL(r.getTTL());
resourceRecords.set(i, tmp);
}
}
}
if (!resourceRecords.contains(r)) {
safeAddRR(r);
}
}
/**
* Returns the first record
*
* @throws IllegalStateException if the rrset is empty
*/
public synchronized
DnsRecord first() {
if (resourceRecords.size() == 0) {
throw new IllegalStateException("rrset is empty");
}
return (DnsRecord) resourceRecords.get(0);
}
/**
* Deletes a Record from an RRset
*/
public synchronized
void deleteRR(DnsRecord r) {
if (resourceRecords.remove(r) && (r instanceof RRSIGRecord)) {
nsigs--;
}
}
/**
* Deletes all Records from an RRset
*/
public synchronized
void clear() {
resourceRecords.clear();
position = 0;
nsigs = 0;
}
/**
* Returns an Iterator listing all (data) records.
*
* @param cycle If true, cycle through the records so that each Iterator will
* start with a different record.
*/
public synchronized
Iterator rrs(boolean cycle) {
return iterator(true, cycle);
}
private synchronized
Iterator iterator(boolean data, boolean cycle) {
int size, start, total;
total = resourceRecords.size();
if (data) {
size = total - nsigs;
}
else {
size = nsigs;
}
if (size == 0) {
return Collections.EMPTY_LIST.iterator();
}
if (data) {
if (!cycle) {
start = 0;
}
else {
if (position >= size) {
position = 0;
}
start = position++;
}
}
else {
start = total - nsigs;
}
List list = new ArrayList(size);
if (data) {
list.addAll(resourceRecords.subList(start, size));
if (start != 0) {
list.addAll(resourceRecords.subList(0, start));
}
}
else {
list.addAll(resourceRecords.subList(start, total));
}
return list.iterator();
}
/**
* Returns an Iterator listing all (data) records. This cycles through
* the records, so each Iterator will start with a different record.
*/
public synchronized
Iterator rrs() {
return iterator(true, true);
}
/**
* Returns an Iterator listing all signature records
*/
public synchronized
Iterator sigs() {
return iterator(false, false);
}
/**
* Returns the number of (data) records
*/
public synchronized
int size() {
return resourceRecords.size() - nsigs;
}
/**
* Converts the RRset to a String
*/
@Override
public
String toString() {
if (resourceRecords.size() == 0) {
return ("{empty}");
}
StringBuilder sb = new StringBuilder();
sb.append("{ ");
sb.append(getName() + " ");
sb.append(getTTL() + " ");
sb.append(DnsClass.string(getDClass()) + " ");
sb.append(DnsRecordType.string(getType()) + " ");
sb.append(iteratorToString(iterator(true, false)));
if (nsigs > 0) {
sb.append(" sigs: ");
sb.append(iteratorToString(iterator(false, false)));
}
sb.append(" }");
return sb.toString();
}
/**
* Returns the name of the records
*
* @see Name
*/
public
Name getName() {
return first().getName();
}
/**
* Returns the type of the records
*
* @see DnsRecordType
*/
public
int getType() {
return first().getRRsetType();
}
/**
* Returns the class of the records
*
* @see DnsClass
*/
public
int getDClass() {
return first().getDClass();
}
/**
* Returns the ttl of the records
*/
public synchronized
long getTTL() {
return first().getTTL();
}
private
String iteratorToString(Iterator it) {
StringBuilder sb = new StringBuilder();
while (it.hasNext()) {
DnsRecord rr = (DnsRecord) it.next();
sb.append("[");
rr.rdataToString(sb);
sb.append("]");
if (it.hasNext()) {
sb.append(" ");
}
}
return sb.toString();
}
}

View File

@ -1,54 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Route Through Record - lists a route preference and intermediate host.
*
* @author Brian Wellington
*/
public
class RTRecord extends U16NameBase {
private static final long serialVersionUID = -3206215651648278098L;
RTRecord() {}
@Override
DnsRecord getObject() {
return new RTRecord();
}
/**
* Creates an RT Record from the given data
*
* @param preference The preference of the route. Smaller numbers indicate
* more preferred routes.
* @param intermediateHost The domain name of the host to use as a router.
*/
public
RTRecord(Name name, int dclass, long ttl, int preference, Name intermediateHost) {
super(name, DnsRecordType.RT, dclass, ttl, preference, "preference", intermediateHost, "intermediateHost");
}
/**
* Gets the preference of the route.
*/
public
int getPreference() {
return getU16Field();
}
/**
* Gets the host to use as a router.
*/
public
Name getIntermediateHost() {
return getNameField();
}
}

View File

@ -1,84 +0,0 @@
// Copyright (c) 2001-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.security.PrivateKey;
import java.util.Date;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsSection;
import dorkbox.network.dns.utils.Options;
/**
* Creates SIG(0) transaction signatures.
*
* @author Pasi Eronen
* @author Brian Wellington
*/
public
class SIG0 {
/**
* The default validity period for outgoing SIG(0) signed messages.
* Can be overriden by the sig0validity option.
*/
private static final short VALIDITY = 300;
private
SIG0() { }
/**
* Sign a dnsMessage with SIG(0). The DNS key and private key must refer to the
* same underlying cryptographic key.
*
* @param dnsMessage The dnsMessage to be signed
* @param key The DNSKEY record to use as part of signing
* @param privkey The PrivateKey to use when signing
* @param previous If this dnsMessage is a response, the SIG(0) from the query
*/
public static
void signMessage(DnsMessage dnsMessage, KEYRecord key, PrivateKey privkey, SIGRecord previous) throws DNSSEC.DNSSECException {
int validity = Options.intValue("sig0validity");
if (validity < 0) {
validity = VALIDITY;
}
long now = System.currentTimeMillis();
Date timeSigned = new Date(now);
Date timeExpires = new Date(now + validity * 1000);
SIGRecord sig = DNSSEC.signMessage(dnsMessage, previous, key, privkey, timeSigned, timeExpires);
dnsMessage.addRecord(sig, DnsSection.ADDITIONAL);
}
/**
* Verify a dnsMessage using SIG(0).
*
* @param dnsMessage The dnsMessage to be signed
* @param b An array containing the dnsMessage in unparsed form. This is
* necessary since SIG(0) signs the dnsMessage in wire format, and we can't
* recreate the exact wire format (with the same name compression).
* @param key The KEY record to verify the signature with.
* @param previous If this dnsMessage is a response, the SIG(0) from the query
*/
public static
void verifyMessage(DnsMessage dnsMessage, byte[] b, KEYRecord key, SIGRecord previous) throws DNSSEC.DNSSECException {
SIGRecord sig = null;
DnsRecord[] additional = dnsMessage.getSectionArray(DnsSection.ADDITIONAL);
for (int i = 0; i < additional.length; i++) {
if (additional[i].getType() != DnsRecordType.SIG) {
continue;
}
if (((SIGRecord) additional[i]).getTypeCovered() != 0) {
continue;
}
sig = (SIGRecord) additional[i];
break;
}
DNSSEC.verifyMessage(dnsMessage, b, sig, previous, key);
}
}

View File

@ -1,229 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.util.Date;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.FormattedTime;
import dorkbox.network.dns.utils.Options;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.util.Base64Fast;
import dorkbox.util.OS;
/**
* The base class for SIG/RRSIG records, which have identical formats
*
* @author Brian Wellington
*/
abstract
class SIGBase extends DnsRecord {
private static final long serialVersionUID = -3738444391533812369L;
protected int covered;
protected int alg, labels;
protected long origttl;
protected Date expire, timeSigned;
protected int footprint;
protected Name signer;
protected byte[] signature;
protected
SIGBase() {}
public
SIGBase(Name name,
int type,
int dclass,
long ttl,
int covered,
int alg,
long origttl,
Date expire,
Date timeSigned,
int footprint,
Name signer,
byte[] signature) {
super(name, type, dclass, ttl);
DnsRecordType.check(covered);
TTL.check(origttl);
this.covered = covered;
this.alg = checkU8("alg", alg);
this.labels = name.labels() - 1;
if (name.isWild()) {
this.labels--;
}
this.origttl = origttl;
this.expire = expire;
this.timeSigned = timeSigned;
this.footprint = checkU16("footprint", footprint);
this.signer = checkName("signer", signer);
this.signature = signature;
}
@Override
void rrFromWire(DnsInput in) throws IOException {
covered = in.readU16();
alg = in.readU8();
labels = in.readU8();
origttl = in.readU32();
expire = new Date(1000 * in.readU32());
timeSigned = new Date(1000 * in.readU32());
footprint = in.readU16();
signer = new Name(in);
signature = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(covered);
out.writeU8(alg);
out.writeU8(labels);
out.writeU32(origttl);
out.writeU32(expire.getTime() / 1000);
out.writeU32(timeSigned.getTime() / 1000);
out.writeU16(footprint);
signer.toWire(out, null, canonical);
out.writeByteArray(signature);
}
/**
* Converts the RRSIG/SIG Record to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(DnsRecordType.string(covered));
sb.append(" ");
sb.append(alg);
sb.append(" ");
sb.append(labels);
sb.append(" ");
sb.append(origttl);
sb.append(" ");
if (Options.check("multiline")) {
sb.append("(\n\t");
}
sb.append(FormattedTime.format(expire));
sb.append(" ");
sb.append(FormattedTime.format(timeSigned));
sb.append(" ");
sb.append(footprint);
sb.append(" ");
sb.append(signer);
if (Options.check("multiline")) {
sb.append(OS.LINE_SEPARATOR);
sb.append(Base64Fast.formatString(Base64Fast.encode2(signature), 64, "\t", true));
}
else {
sb.append(" ");
sb.append(Base64Fast.encode2(signature));
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
String typeString = st.getString();
covered = DnsRecordType.value(typeString);
if (covered < 0) {
throw st.exception("Invalid type: " + typeString);
}
String algString = st.getString();
alg = DNSSEC.Algorithm.value(algString);
if (alg < 0) {
throw st.exception("Invalid algorithm: " + algString);
}
labels = st.getUInt8();
origttl = st.getTTL();
expire = FormattedTime.parse(st.getString());
timeSigned = FormattedTime.parse(st.getString());
footprint = st.getUInt16();
signer = st.getName(origin);
signature = st.getBase64();
}
/**
* Returns the RRset type covered by this signature
*/
public
int getTypeCovered() {
return covered;
}
/**
* Returns the cryptographic algorithm of the key that generated the signature
*/
public
int getAlgorithm() {
return alg;
}
/**
* Returns the number of labels in the signed domain name. This may be
* different than the record's domain name if the record is a wildcard
* record.
*/
public
int getLabels() {
return labels;
}
/**
* Returns the original TTL of the RRset
*/
public
long getOrigTTL() {
return origttl;
}
/**
* Returns the time at which the signature expires
*/
public
Date getExpire() {
return expire;
}
/**
* Returns the time at which this signature was generated
*/
public
Date getTimeSigned() {
return timeSigned;
}
/**
* Returns The footprint/key id of the signing key.
*/
public
int getFootprint() {
return footprint;
}
/**
* Returns the owner of the signing key
*/
public
Name getSigner() {
return signer;
}
/**
* Returns the binary data representing the signature
*/
public
byte[] getSignature() {
return signature;
}
void setSignature(byte[] signature) {
this.signature = signature;
}
}

View File

@ -1,61 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.util.Date;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Signature - A SIG provides the digital signature of an RRset, so that
* the data can be authenticated by a DNSSEC-capable resolver. The
* signature is usually generated by a key contained in a KEYRecord
*
* @author Brian Wellington
* @see RRset
* @see DNSSEC
* @see KEYRecord
*/
public
class SIGRecord extends SIGBase {
private static final long serialVersionUID = 4963556060953589058L;
SIGRecord() {}
@Override
DnsRecord getObject() {
return new SIGRecord();
}
/**
* Creates an SIG Record from the given data
*
* @param covered The RRset type covered by this signature
* @param alg The cryptographic algorithm of the key that generated the
* signature
* @param origttl The original TTL of the RRset
* @param expire The time at which the signature expires
* @param timeSigned The time at which this signature was generated
* @param footprint The footprint/key id of the signing key.
* @param signer The owner of the signing key
* @param signature Binary data representing the signature
*/
public
SIGRecord(Name name,
int dclass,
long ttl,
int covered,
int alg,
long origttl,
Date expire,
Date timeSigned,
int footprint,
Name signer,
byte[] signature) {
super(name, DnsRecordType.SIG, dclass, ttl, covered, alg, origttl, expire, timeSigned, footprint, signer, signature);
}
}

View File

@ -1,178 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* S/MIME cert association, draft-ietf-dane-smime.
*
* @author Brian Wellington
*/
public
class SMIMEARecord extends DnsRecord {
private static final long serialVersionUID = 1640247915216425235L;
// Note; these are copied from the TLSA type.
private int certificateUsage;
private int selector;
private int matchingType;
private byte[] certificateAssociationData;
public static
class CertificateUsage {
public static final int CA_CONSTRAINT = 0;
public static final int SERVICE_CERTIFICATE_CONSTRAINT = 1;
public static final int TRUST_ANCHOR_ASSERTION = 2;
public static final int DOMAIN_ISSUED_CERTIFICATE = 3;
private
CertificateUsage() {}
}
public static
class Selector {
/**
* Full certificate; the Certificate binary structure defined in
* [RFC5280]
*/
public static final int FULL_CERTIFICATE = 0;
/**
* SubjectPublicKeyInfo; DER-encoded binary structure defined in
* [RFC5280]
*/
public static final int SUBJECT_PUBLIC_KEY_INFO = 1;
private
Selector() {}
}
public static
class MatchingType {
/**
* Exact match on selected content
*/
public static final int EXACT = 0;
/**
* SHA-256 hash of selected content [RFC6234]
*/
public static final int SHA256 = 1;
/**
* SHA-512 hash of selected content [RFC6234]
*/
public static final int SHA512 = 2;
private
MatchingType() {}
}
SMIMEARecord() {}
@Override
DnsRecord getObject() {
return new SMIMEARecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
certificateUsage = in.readU8();
selector = in.readU8();
matchingType = in.readU8();
certificateAssociationData = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(certificateUsage);
out.writeU8(selector);
out.writeU8(matchingType);
out.writeByteArray(certificateAssociationData);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(certificateUsage);
sb.append(" ");
sb.append(selector);
sb.append(" ");
sb.append(matchingType);
sb.append(" ");
sb.append(base16.toString(certificateAssociationData));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
certificateUsage = st.getUInt8();
selector = st.getUInt8();
matchingType = st.getUInt8();
certificateAssociationData = st.getHex();
}
/**
* Creates an SMIMEA Record from the given data
*
* @param certificateUsage The provided association that will be used to
* match the certificate presented in the S/MIME handshake.
* @param selector The part of the S/MIME certificate presented by the server
* that will be matched against the association data.
* @param matchingType How the certificate association is presented.
* @param certificateAssociationData The "certificate association data" to be
* matched.
*/
public
SMIMEARecord(Name name, int dclass, long ttl, int certificateUsage, int selector, int matchingType, byte[] certificateAssociationData) {
super(name, DnsRecordType.SMIMEA, dclass, ttl);
this.certificateUsage = checkU8("certificateUsage", certificateUsage);
this.selector = checkU8("selector", selector);
this.matchingType = checkU8("matchingType", matchingType);
this.certificateAssociationData = checkByteArrayLength("certificateAssociationData", certificateAssociationData, 0xFFFF);
}
/**
* Returns the certificate usage of the SMIMEA record
*/
public
int getCertificateUsage() {
return certificateUsage;
}
/**
* Returns the selector of the SMIMEA record
*/
public
int getSelector() {
return selector;
}
/**
* Returns the matching type of the SMIMEA record
*/
public
int getMatchingType() {
return matchingType;
}
/**
* Returns the certificate associate data of this SMIMEA record
*/
public final
byte[] getCertificateAssociationData() {
return certificateAssociationData;
}
}

View File

@ -1,186 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Options;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Start of Authority - describes properties of a zone.
*
* @author Brian Wellington
*/
public
class SOARecord extends DnsRecord {
private static final long serialVersionUID = 1049740098229303931L;
private Name host, admin;
private long serial, refresh, retry, expire, minimum;
SOARecord() {}
@Override
DnsRecord getObject() {
return new SOARecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
host = new Name(in);
admin = new Name(in);
serial = in.readU32();
refresh = in.readU32();
retry = in.readU32();
expire = in.readU32();
minimum = in.readU32();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
host.toWire(out, c, canonical);
admin.toWire(out, c, canonical);
out.writeU32(serial);
out.writeU32(refresh);
out.writeU32(retry);
out.writeU32(expire);
out.writeU32(minimum);
}
/**
* Convert to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(host);
sb.append(" ");
sb.append(admin);
if (Options.check("multiline")) {
sb.append(" (\n\t\t\t\t\t");
sb.append(serial);
sb.append("\t; serial\n\t\t\t\t\t");
sb.append(refresh);
sb.append("\t; refresh\n\t\t\t\t\t");
sb.append(retry);
sb.append("\t; retry\n\t\t\t\t\t");
sb.append(expire);
sb.append("\t; expire\n\t\t\t\t\t");
sb.append(minimum);
sb.append(" )\t; minimum");
}
else {
sb.append(" ");
sb.append(serial);
sb.append(" ");
sb.append(refresh);
sb.append(" ");
sb.append(retry);
sb.append(" ");
sb.append(expire);
sb.append(" ");
sb.append(minimum);
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
host = st.getName(origin);
admin = st.getName(origin);
serial = st.getUInt32();
refresh = st.getTTLLike();
retry = st.getTTLLike();
expire = st.getTTLLike();
minimum = st.getTTLLike();
}
/**
* Creates an SOA Record from the given data
*
* @param host The primary name server for the zone
* @param admin The zone administrator's address
* @param serial The zone's serial number
* @param refresh The amount of time until a secondary checks for a new serial
* number
* @param retry The amount of time between a secondary's checks for a new
* serial number
* @param expire The amount of time until a secondary expires a zone
* @param minimum The minimum TTL for records in the zone
*/
public
SOARecord(Name name, int dclass, long ttl, Name host, Name admin, long serial, long refresh, long retry, long expire, long minimum) {
super(name, DnsRecordType.SOA, dclass, ttl);
this.host = checkName("host", host);
this.admin = checkName("admin", admin);
this.serial = checkU32("serial", serial);
this.refresh = checkU32("refresh", refresh);
this.retry = checkU32("retry", retry);
this.expire = checkU32("expire", expire);
this.minimum = checkU32("minimum", minimum);
}
/**
* Returns the primary name server
*/
public
Name getHost() {
return host;
}
/**
* Returns the zone administrator's address
*/
public
Name getAdmin() {
return admin;
}
/**
* Returns the zone's serial number
*/
public
long getSerial() {
return serial;
}
/**
* Returns the zone refresh interval
*/
public
long getRefresh() {
return refresh;
}
/**
* Returns the zone retry interval
*/
public
long getRetry() {
return retry;
}
/**
* Returns the time until a secondary expires a zone
*/
public
long getExpire() {
return expire;
}
/**
* Returns the minimum TTL for records in the zone
*/
public
long getMinimum() {
return minimum;
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.util.List;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Sender Policy Framework (RFC 4408, experimental)
*
* @author Brian Wellington
*/
public
class SPFRecord extends TXTBase {
private static final long serialVersionUID = -2100754352801658722L;
SPFRecord() {}
@Override
DnsRecord getObject() {
return new SPFRecord();
}
/**
* Creates a SPF Record from the given data
*
* @param strings The text strings
*
* @throws IllegalArgumentException One of the strings has invalid escapes
*/
public
SPFRecord(Name name, int dclass, long ttl, List strings) {
super(name, DnsRecordType.SPF, dclass, ttl, strings);
}
/**
* Creates a SPF Record from the given data
*
* @param string One text string
*
* @throws IllegalArgumentException The string has invalid escapes
*/
public
SPFRecord(Name name, int dclass, long ttl, String string) {
super(name, DnsRecordType.SPF, dclass, ttl, string);
}
}

View File

@ -1,130 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Server Selection Record - finds hosts running services in a domain. An
* SRV record will normally be named _&lt;service&gt;._&lt;protocol&gt;.domain
* - examples would be _sips._tcp.example.org (for the secure SIP protocol) and
* _http._tcp.example.com (if HTTP used SRV records)
*
* @author Brian Wellington
*/
public
class SRVRecord extends DnsRecord {
private static final long serialVersionUID = -3886460132387522052L;
private int priority, weight, port;
private Name target;
SRVRecord() {}
@Override
DnsRecord getObject() {
return new SRVRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
priority = in.readU16();
weight = in.readU16();
port = in.readU16();
target = new Name(in);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU16(priority);
out.writeU16(weight);
out.writeU16(port);
target.toWire(out, null, canonical);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(priority + " ");
sb.append(weight + " ");
sb.append(port + " ");
sb.append(target);
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
priority = st.getUInt16();
weight = st.getUInt16();
port = st.getUInt16();
target = st.getName(origin);
}
@Override
public
Name getAdditionalName() {
return target;
}
/**
* Creates an SRV Record from the given data
*
* @param priority The priority of this SRV. Records with lower priority
* are preferred.
* @param weight The weight, used to select between records at the same
* priority.
* @param port The TCP/UDP port that the service uses
* @param target The host running the service
*/
public
SRVRecord(Name name, int dclass, long ttl, int priority, int weight, int port, Name target) {
super(name, DnsRecordType.SRV, dclass, ttl);
this.priority = checkU16("priority", priority);
this.weight = checkU16("weight", weight);
this.port = checkU16("port", port);
this.target = checkName("target", target);
}
/**
* Returns the priority
*/
public
int getPriority() {
return priority;
}
/**
* Returns the weight
*/
public
int getWeight() {
return weight;
}
/**
* Returns the port that the service runs on
*/
public
int getPort() {
return port;
}
/**
* Returns the host running that the service
*/
public
Name getTarget() {
return target;
}
}

View File

@ -1,123 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* SSH Fingerprint - stores the fingerprint of an SSH host key.
*
* @author Brian Wellington
*/
public
class SSHFPRecord extends DnsRecord {
private static final long serialVersionUID = -8104701402654687025L;
private int alg;
private int digestType;
private byte[] fingerprint;
public static
class Algorithm {
public static final int RSA = 1;
public static final int DSS = 2;
private
Algorithm() {}
}
public static
class Digest {
public static final int SHA1 = 1;
private
Digest() {}
}
SSHFPRecord() {}
@Override
DnsRecord getObject() {
return new SSHFPRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
alg = in.readU8();
digestType = in.readU8();
fingerprint = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(alg);
out.writeU8(digestType);
out.writeByteArray(fingerprint);
}
@Override
void rrToString(StringBuilder sb) {
sb.append(alg);
sb.append(" ");
sb.append(digestType);
sb.append(" ");
sb.append(base16.toString(fingerprint));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
alg = st.getUInt8();
digestType = st.getUInt8();
fingerprint = st.getHex(true);
}
/**
* Creates an SSHFP Record from the given data.
*
* @param alg The public key's algorithm.
* @param digestType The public key's digest type.
* @param fingerprint The public key's fingerprint.
*/
public
SSHFPRecord(Name name, int dclass, long ttl, int alg, int digestType, byte[] fingerprint) {
super(name, DnsRecordType.SSHFP, dclass, ttl);
this.alg = checkU8("alg", alg);
this.digestType = checkU8("digestType", digestType);
this.fingerprint = fingerprint;
}
/**
* Returns the public key's algorithm.
*/
public
int getAlgorithm() {
return alg;
}
/**
* Returns the public key's digest type.
*/
public
int getDigestType() {
return digestType;
}
/**
* Returns the fingerprint
*/
public
byte[] getFingerPrint() {
return fingerprint;
}
}

View File

@ -1,34 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
/**
* Implements common functionality for the many record types whose format
* is a single compressed name.
*
* @author Brian Wellington
*/
abstract
class SingleCompressedNameBase extends SingleNameBase {
private static final long serialVersionUID = -236435396815460677L;
protected
SingleCompressedNameBase() {}
protected
SingleCompressedNameBase(Name name, int type, int dclass, long ttl, Name singleName, String description) {
super(name, type, dclass, ttl, singleName, description);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
singleName.toWire(out, c, canonical);
}
}

View File

@ -1,66 +0,0 @@
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Implements common functionality for the many record types whose format
* is a single name.
*
* @author Brian Wellington
*/
abstract
class SingleNameBase extends DnsRecord {
private static final long serialVersionUID = -18595042501413L;
protected Name singleName;
protected
SingleNameBase() {}
protected
SingleNameBase(Name name, int type, int dclass, long ttl) {
super(name, type, dclass, ttl);
}
protected
SingleNameBase(Name name, int type, int dclass, long ttl, Name singleName, String description) {
super(name, type, dclass, ttl);
this.singleName = checkName(description, singleName);
}
@Override
void rrFromWire(DnsInput in) throws IOException {
singleName = new Name(in);
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
singleName.toWire(out, null, canonical);
}
@Override
void rrToString(StringBuilder sb) {
sb.append(singleName.toString());
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
singleName = st.getName(origin);
}
protected
Name getSingleName() {
return singleName;
}
}

View File

@ -1,285 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.util.Date;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsResponseCode;
import dorkbox.network.dns.utils.FormattedTime;
import dorkbox.network.dns.utils.Options;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.util.Base64Fast;
import dorkbox.util.OS;
/**
* Transaction Key - used to compute and/or securely transport a shared
* secret to be used with TSIG.
*
* @author Brian Wellington
* @see TSIG
*/
public
class TKEYRecord extends DnsRecord {
private static final long serialVersionUID = 8828458121926391756L;
private Name alg;
private Date timeInception;
private Date timeExpire;
private int mode, error;
private byte[] key;
private byte[] other;
/**
* The key is assigned by the server (unimplemented)
*/
public static final int SERVERASSIGNED = 1;
/**
* The key is computed using a Diffie-Hellman key exchange
*/
public static final int DIFFIEHELLMAN = 2;
/**
* The key is computed using GSS_API (unimplemented)
*/
public static final int GSSAPI = 3;
/**
* The key is assigned by the resolver (unimplemented)
*/
public static final int RESOLVERASSIGNED = 4;
/**
* The key should be deleted
*/
public static final int DELETE = 5;
TKEYRecord() {}
@Override
DnsRecord getObject() {
return new TKEYRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
alg = new Name(in);
timeInception = new Date(1000 * in.readU32());
timeExpire = new Date(1000 * in.readU32());
mode = in.readU16();
error = in.readU16();
int keylen = in.readU16();
if (keylen > 0) {
key = in.readByteArray(keylen);
}
else {
key = null;
}
int otherlen = in.readU16();
if (otherlen > 0) {
other = in.readByteArray(otherlen);
}
else {
other = null;
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
alg.toWire(out, null, canonical);
out.writeU32(timeInception.getTime() / 1000);
out.writeU32(timeExpire.getTime() / 1000);
out.writeU16(mode);
out.writeU16(error);
if (key != null) {
out.writeU16(key.length);
out.writeByteArray(key);
}
else {
out.writeU16(0);
}
if (other != null) {
out.writeU16(other.length);
out.writeByteArray(other);
}
else {
out.writeU16(0);
}
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(alg);
sb.append(" ");
if (Options.check("multiline")) {
sb.append("(")
.append(OS.LINE_SEPARATOR)
.append("\t");
}
sb.append(FormattedTime.format(timeInception));
sb.append(" ");
sb.append(FormattedTime.format(timeExpire));
sb.append(" ");
sb.append(modeString());
sb.append(" ");
sb.append(DnsResponseCode.TSIGstring(error));
if (Options.check("multiline")) {
sb.append(OS.LINE_SEPARATOR);
if (key != null) {
sb.append(Base64Fast.formatString(Base64Fast.encode2(key), 64, "\t", true));
sb.append(OS.LINE_SEPARATOR);
}
if (other != null) {
sb.append(Base64Fast.formatString(Base64Fast.encode2(other), 64, "\t", true));
}
sb.append(" )");
}
else {
sb.append(" ");
if (key != null) {
sb.append("\t");
sb.append(Base64Fast.encode2(key));
sb.append(" ");
}
if (other != null) {
sb.append("\t");
sb.append(Base64Fast.encode2(other));
}
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
throw st.exception("no text format defined for TKEY");
}
protected
String modeString() {
switch (mode) {
case SERVERASSIGNED:
return "SERVERASSIGNED";
case DIFFIEHELLMAN:
return "DIFFIEHELLMAN";
case GSSAPI:
return "GSSAPI";
case RESOLVERASSIGNED:
return "RESOLVERASSIGNED";
case DELETE:
return "DELETE";
default:
return Integer.toString(mode);
}
}
/**
* Creates a TKEY Record from the given data.
*
* @param alg The shared key's algorithm
* @param timeInception The beginning of the validity period of the shared
* secret or keying material
* @param timeExpire The end of the validity period of the shared
* secret or keying material
* @param mode The mode of key agreement
* @param error The extended error field. Should be 0 in queries
* @param key The shared secret
* @param other The other data field. Currently unused
* responses.
*/
public
TKEYRecord(Name name,
int dclass,
long ttl,
Name alg,
Date timeInception,
Date timeExpire,
int mode,
int error,
byte[] key,
byte other[]) {
super(name, DnsRecordType.TKEY, dclass, ttl);
this.alg = checkName("alg", alg);
this.timeInception = timeInception;
this.timeExpire = timeExpire;
this.mode = checkU16("mode", mode);
this.error = checkU16("error", error);
this.key = key;
this.other = other;
}
/**
* Returns the shared key's algorithm
*/
public
Name getAlgorithm() {
return alg;
}
/**
* Returns the beginning of the validity period of the shared secret or
* keying material
*/
public
Date getTimeInception() {
return timeInception;
}
/**
* Returns the end of the validity period of the shared secret or
* keying material
*/
public
Date getTimeExpire() {
return timeExpire;
}
/**
* Returns the key agreement mode
*/
public
int getMode() {
return mode;
}
/**
* Returns the extended error
*/
public
int getError() {
return error;
}
/**
* Returns the shared secret or keying material
*/
public
byte[] getKey() {
return key;
}
/**
* Returns the other data
*/
public
byte[] getOther() {
return other;
}
}

View File

@ -1,176 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.network.dns.utils.base16;
/**
* Transport Layer Security Authentication
*
* @author Brian Wellington
*/
public
class TLSARecord extends DnsRecord {
private static final long serialVersionUID = 356494267028580169L;
private int certificateUsage;
private int selector;
private int matchingType;
private byte[] certificateAssociationData;
public static
class CertificateUsage {
public static final int CA_CONSTRAINT = 0;
public static final int SERVICE_CERTIFICATE_CONSTRAINT = 1;
public static final int TRUST_ANCHOR_ASSERTION = 2;
public static final int DOMAIN_ISSUED_CERTIFICATE = 3;
private
CertificateUsage() {}
}
public static
class Selector {
/**
* Full certificate; the Certificate binary structure defined in
* [RFC5280]
*/
public static final int FULL_CERTIFICATE = 0;
/**
* SubjectPublicKeyInfo; DER-encoded binary structure defined in
* [RFC5280]
*/
public static final int SUBJECT_PUBLIC_KEY_INFO = 1;
private
Selector() {}
}
public static
class MatchingType {
/**
* Exact match on selected content
*/
public static final int EXACT = 0;
/**
* SHA-256 hash of selected content [RFC6234]
*/
public static final int SHA256 = 1;
/**
* SHA-512 hash of selected content [RFC6234]
*/
public static final int SHA512 = 2;
private
MatchingType() {}
}
TLSARecord() {}
@Override
DnsRecord getObject() {
return new TLSARecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
certificateUsage = in.readU8();
selector = in.readU8();
matchingType = in.readU8();
certificateAssociationData = in.readByteArray();
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
out.writeU8(certificateUsage);
out.writeU8(selector);
out.writeU8(matchingType);
out.writeByteArray(certificateAssociationData);
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(certificateUsage);
sb.append(" ");
sb.append(selector);
sb.append(" ");
sb.append(matchingType);
sb.append(" ");
sb.append(base16.toString(certificateAssociationData));
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
certificateUsage = st.getUInt8();
selector = st.getUInt8();
matchingType = st.getUInt8();
certificateAssociationData = st.getHex();
}
/**
* Creates an TLSA Record from the given data
*
* @param certificateUsage The provided association that will be used to
* match the certificate presented in the TLS handshake.
* @param selector The part of the TLS certificate presented by the server
* that will be matched against the association data.
* @param matchingType How the certificate association is presented.
* @param certificateAssociationData The "certificate association data" to be
* matched.
*/
public
TLSARecord(Name name, int dclass, long ttl, int certificateUsage, int selector, int matchingType, byte[] certificateAssociationData) {
super(name, DnsRecordType.TLSA, dclass, ttl);
this.certificateUsage = checkU8("certificateUsage", certificateUsage);
this.selector = checkU8("selector", selector);
this.matchingType = checkU8("matchingType", matchingType);
this.certificateAssociationData = checkByteArrayLength("certificateAssociationData", certificateAssociationData, 0xFFFF);
}
/**
* Returns the certificate usage of the TLSA record
*/
public
int getCertificateUsage() {
return certificateUsage;
}
/**
* Returns the selector of the TLSA record
*/
public
int getSelector() {
return selector;
}
/**
* Returns the matching type of the TLSA record
*/
public
int getMatchingType() {
return matchingType;
}
/**
* Returns the certificate associate data of this TLSA record
*/
public final
byte[] getCertificateAssociationData() {
return certificateAssociationData;
}
}

View File

@ -1,777 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Date;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import com.esotericsoftware.kryo.util.ObjectMap;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsClass;
import dorkbox.network.dns.constants.DnsResponseCode;
import dorkbox.network.dns.constants.DnsSection;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.utils.Options;
import dorkbox.util.Base64Fast;
/**
* Transaction signature handling. This class generates and verifies
* TSIG records on messages, which provide transaction security.
*
* @author Brian Wellington
* @see TSIGRecord
*/
@SuppressWarnings("WeakerAccess")
public
class TSIG {
/**
* The domain name representing the HMAC-MD5 algorithm.
*/
public static final Name HMAC_MD5 = Name.fromConstantString("HMAC-MD5.SIG-ALG.REG.INT.");
/**
* The domain name representing the HMAC-MD5 algorithm (deprecated).
*/
public static final Name HMAC = HMAC_MD5;
/**
* The domain name representing the HMAC-SHA1 algorithm.
*/
public static final Name HMAC_SHA1 = Name.fromConstantString("hmac-sha1.");
/**
* The domain name representing the HMAC-SHA224 algorithm.
* Note that SHA224 is not supported by Java out-of-the-box, this requires use
* of a third party provider like BouncyCastle.org.
*/
public static final Name HMAC_SHA224 = Name.fromConstantString("hmac-sha224.");
/**
* The domain name representing the HMAC-SHA256 algorithm.
*/
public static final Name HMAC_SHA256 = Name.fromConstantString("hmac-sha256.");
/**
* The domain name representing the HMAC-SHA384 algorithm.
*/
public static final Name HMAC_SHA384 = Name.fromConstantString("hmac-sha384.");
/**
* The domain name representing the HMAC-SHA512 algorithm.
*/
public static final Name HMAC_SHA512 = Name.fromConstantString("hmac-sha512.");
private static final ObjectMap<Name, String> algMap = new ObjectMap<Name, String>();
/**
* The default fudge value for outgoing packets. Can be overridden by the
* tsigfudge option.
*/
public static final short FUDGE = 300;
private Name name, alg;
private Mac hmac;
static {
algMap.put(HMAC_MD5, "HmacMD5");
algMap.put(HMAC_SHA1, "HmacSHA1");
algMap.put(HMAC_SHA224, "HmacSHA224");
algMap.put(HMAC_SHA256, "HmacSHA256");
algMap.put(HMAC_SHA384, "HmacSHA384");
algMap.put(HMAC_SHA512, "HmacSHA512");
}
/**
* Verifies the data (computes the secure hash and compares it to the input)
*
* @param mac The HMAC generator
* @param signature The signature to compare against
*
* @return true if the signature matches, false otherwise
*/
private static
boolean verify(Mac mac, byte[] signature) {
return verify(mac, signature, false);
}
/**
* Verifies the data (computes the secure hash and compares it to the input)
*
* @param mac The HMAC generator
* @param signature The signature to compare against
* @param truncation_ok If true, the signature may be truncated; only the
* number of bytes in the provided signature are compared.
*
* @return true if the signature matches, false otherwise
*/
private static
boolean verify(Mac mac, byte[] signature, boolean truncation_ok) {
byte[] expected = mac.doFinal();
if (truncation_ok && signature.length < expected.length) {
byte[] truncated = new byte[signature.length];
System.arraycopy(expected, 0, truncated, 0, truncated.length);
expected = truncated;
}
return Arrays.equals(signature, expected);
}
/**
* Creates a new TSIG key, which can be used to sign or verify a message.
*
* @param algorithm The algorithm of the shared key.
* @param name The name of the shared key.
* @param key The shared key.
*/
public
TSIG(Name algorithm, Name name, SecretKey key) {
this.name = name;
this.alg = algorithm;
String macAlgorithm = nameToAlgorithm(algorithm);
init_hmac(macAlgorithm, key);
}
public static
String nameToAlgorithm(Name name) {
String alg = algMap.get(name);
if (alg != null) {
return alg;
}
throw new IllegalArgumentException("Unknown algorithm");
}
private
void init_hmac(String macAlgorithm, SecretKey key) {
try {
hmac = Mac.getInstance(macAlgorithm);
hmac.init(key);
} catch (GeneralSecurityException ex) {
throw new IllegalArgumentException("Caught security " + "exception setting up " + "HMAC.");
}
}
/**
* Creates a new TSIG key from a pre-initialized Mac instance.
* This assumes that init() has already been called on the mac
* to set up the key.
*
* @param mac The JCE HMAC object
* @param name The name of the key
*/
public
TSIG(Mac mac, Name name) {
this.name = name;
this.hmac = mac;
this.alg = algorithmToName(mac.getAlgorithm());
}
public static
Name algorithmToName(String alg) {
// false identity check because it's string comparisons.
Name foundKey = algMap.findKey(alg, false);
if (foundKey != null) {
return foundKey;
}
throw new IllegalArgumentException("Unknown algorithm");
}
/**
* Creates a new TSIG key with the hmac-md5 algorithm, which can be used to
* sign or verify a message.
*
* @param name The name of the shared key.
* @param key The shared key's data.
*/
public
TSIG(Name name, byte[] key) {
this(HMAC_MD5, name, key);
}
/**
* Creates a new TSIG key, which can be used to sign or verify a message.
*
* @param algorithm The algorithm of the shared key.
* @param name The name of the shared key.
* @param keyBytes The shared key's data.
*/
public
TSIG(Name algorithm, Name name, byte[] keyBytes) {
this.name = name;
this.alg = algorithm;
String macAlgorithm = nameToAlgorithm(algorithm);
SecretKey key = new SecretKeySpec(keyBytes, macAlgorithm);
init_hmac(macAlgorithm, key);
}
/**
* Creates a new TSIG object, which can be used to sign or verify a message.
*
* @param name The name of the shared key.
* @param algorithm The algorithm of the shared key. The legal values are
* "hmac-md5", "hmac-sha1", "hmac-sha224", "hmac-sha256", "hmac-sha384", and
* "hmac-sha512".
* @param key The shared key's data represented as a base64 encoded string.
*
* @throws IllegalArgumentException The key name is an invalid name
* @throws IllegalArgumentException The key data is improperly encoded
*/
public
TSIG(String algorithm, String name, String key) {
this(algorithmToName(algorithm), name, key);
}
/**
* Creates a new TSIG object, which can be used to sign or verify a message.
*
* @param name The name of the shared key.
* @param key The shared key's data represented as a base64 encoded string.
*
* @throws IllegalArgumentException The key name is an invalid name
* @throws IllegalArgumentException The key data is improperly encoded
*/
public
TSIG(Name algorithm, String name, String key) {
byte[] keyBytes;
try {
keyBytes = Base64Fast.decode2(key);
} catch (IOException e) {
throw new IllegalArgumentException("Invalid TSIG key string");
}
if (keyBytes == null) {
throw new IllegalArgumentException("Invalid TSIG key string");
}
try {
this.name = Name.fromString(name, Name.root);
} catch (TextParseException e) {
throw new IllegalArgumentException("Invalid TSIG key name");
}
this.alg = algorithm;
String macAlgorithm = nameToAlgorithm(this.alg);
init_hmac(macAlgorithm, new SecretKeySpec(keyBytes, macAlgorithm));
}
/**
* Creates a new TSIG object with the hmac-md5 algorithm, which can be used to
* sign or verify a message.
*
* @param name The name of the shared key
* @param key The shared key's data, represented as a base64 encoded string.
*
* @throws IllegalArgumentException The key name is an invalid name
* @throws IllegalArgumentException The key data is improperly encoded
*/
public
TSIG(String name, String key) {
this(HMAC_MD5, name, key);
}
/**
* Creates a new TSIG object, which can be used to sign or verify a message.
*
* @param str The TSIG key, in the form name:secret, name/secret,
* alg:name:secret, or alg/name/secret. If an algorithm is specified, it must
* be "hmac-md5", "hmac-sha1", or "hmac-sha256".
*
* @throws IllegalArgumentException The string does not contain both a name
* and secret.
* @throws IllegalArgumentException The key name is an invalid name
* @throws IllegalArgumentException The key data is improperly encoded
*/
static public
TSIG fromString(String str) {
String[] parts = str.split("[:/]", 3);
if (parts.length < 2) {
throw new IllegalArgumentException("Invalid TSIG key " + "specification");
}
if (parts.length == 3) {
try {
return new TSIG(parts[0], parts[1], parts[2]);
} catch (IllegalArgumentException e) {
parts = str.split("[:/]", 2);
}
}
return new TSIG(HMAC_MD5, parts[0], parts[1]);
}
/**
* Generates a TSIG record for a message and adds it to the message
*
* @param m The message
* @param old If this message is a response, the TSIG from the request
*/
public
void applyStream(DnsMessage m, TSIGRecord old, boolean first) {
if (first) {
apply(m, old);
return;
}
Date timeSigned = new Date();
int fudge;
hmac.reset();
fudge = Options.intValue("tsigfudge");
if (fudge < 0 || fudge > 0x7FFF) {
fudge = FUDGE;
}
DnsOutput out = new DnsOutput();
out.writeU16(old.getSignature().length);
hmac.update(out.toByteArray());
hmac.update(old.getSignature());
/* Digest the message */
hmac.update(m.toWire());
out = new DnsOutput();
long time = timeSigned.getTime() / 1000;
int timeHigh = (int) (time >> 32);
long timeLow = (time & 0xFFFFFFFFL);
out.writeU16(timeHigh);
out.writeU32(timeLow);
out.writeU16(fudge);
hmac.update(out.toByteArray());
byte[] signature = hmac.doFinal();
byte[] other = null;
DnsRecord r = new TSIGRecord(name,
DnsClass.ANY,
0,
alg,
timeSigned,
fudge,
signature,
m.getHeader()
.getID(),
DnsResponseCode.NOERROR,
other);
m.addRecord(r, DnsSection.ADDITIONAL);
m.tsigState = DnsMessage.TSIG_SIGNED;
}
/**
* Generates a TSIG record for a message and adds it to the message
*
* @param m The message
* @param old If this message is a response, the TSIG from the request
*/
public
void apply(DnsMessage m, TSIGRecord old) {
apply(m, DnsResponseCode.NOERROR, old);
}
/**
* Generates a TSIG record with a specific error for a message and adds it
* to the message.
*
* @param m The message
* @param error The error
* @param old If this message is a response, the TSIG from the request
*/
public
void apply(DnsMessage m, int error, TSIGRecord old) {
DnsRecord r = generate(m, m.toWire(), error, old);
m.addRecord(r, DnsSection.ADDITIONAL);
m.tsigState = DnsMessage.TSIG_SIGNED;
}
/**
* Generates a TSIG record with a specific error for a message that has
* been rendered.
*
* @param m The message
* @param b The rendered message
* @param error The error
* @param old If this message is a response, the TSIG from the request
*
* @return The TSIG record to be added to the message
*/
public
TSIGRecord generate(DnsMessage m, byte[] b, int error, TSIGRecord old) {
Date timeSigned;
if (error != DnsResponseCode.BADTIME) {
timeSigned = new Date();
}
else {
timeSigned = old.getTimeSigned();
}
int fudge;
boolean signing = false;
if (error == DnsResponseCode.NOERROR || error == DnsResponseCode.BADTIME) {
signing = true;
hmac.reset();
}
fudge = Options.intValue("tsigfudge");
if (fudge < 0 || fudge > 0x7FFF) {
fudge = FUDGE;
}
if (old != null) {
DnsOutput out = new DnsOutput();
out.writeU16(old.getSignature().length);
if (signing) {
hmac.update(out.toByteArray());
hmac.update(old.getSignature());
}
}
/* Digest the message */
if (signing) {
hmac.update(b);
}
DnsOutput out = new DnsOutput();
name.toWireCanonical(out);
out.writeU16(DnsClass.ANY); /* class */
out.writeU32(0); /* ttl */
alg.toWireCanonical(out);
long time = timeSigned.getTime() / 1000;
int timeHigh = (int) (time >> 32);
long timeLow = (time & 0xFFFFFFFFL);
out.writeU16(timeHigh);
out.writeU32(timeLow);
out.writeU16(fudge);
out.writeU16(error);
out.writeU16(0); /* No other data */
if (signing) {
hmac.update(out.toByteArray());
}
byte[] signature;
if (signing) {
signature = hmac.doFinal();
}
else {
signature = new byte[0];
}
byte[] other = null;
if (error == DnsResponseCode.BADTIME) {
out = new DnsOutput();
time = new Date().getTime() / 1000;
timeHigh = (int) (time >> 32);
timeLow = (time & 0xFFFFFFFFL);
out.writeU16(timeHigh);
out.writeU32(timeLow);
other = out.toByteArray();
}
return (new TSIGRecord(name,
DnsClass.ANY,
0,
alg,
timeSigned,
fudge,
signature,
m.getHeader()
.getID(),
error,
other));
}
/**
* Verifies a TSIG record on an incoming message. Since this is only called
* in the context where a TSIG is expected to be present, it is an error
* if one is not present. After calling this routine, DnsMessage.isVerified() may
* be called on this message.
*
* @param m The message
* @param b The message in unparsed form. This is necessary since TSIG
* signs the message in wire format, and we can't recreate the exact wire
* format (with the same name compression).
* @param old If this message is a response, the TSIG from the request
*
* @return The result of the verification (as an DnsResponseCode)
*
* @see DnsResponseCode
*/
public
int verify(DnsMessage m, byte[] b, TSIGRecord old) {
return verify(m, b, b.length, old);
}
/**
* Verifies a TSIG record on an incoming message. Since this is only called
* in the context where a TSIG is expected to be present, it is an error
* if one is not present. After calling this routine, DnsMessage.isVerified() may
* be called on this message.
*
* @param m The message
* @param b An array containing the message in unparsed form. This is
* necessary since TSIG signs the message in wire format, and we can't
* recreate the exact wire format (with the same name compression).
* @param length The length of the message in the array.
* @param old If this message is a response, the TSIG from the request
*
* @return The result of the verification (as an DnsResponseCode)
*
* @see DnsResponseCode
*/
public
byte verify(DnsMessage m, byte[] b, int length, TSIGRecord old) {
m.tsigState = DnsMessage.TSIG_FAILED;
TSIGRecord tsig = m.getTSIG();
hmac.reset();
if (tsig == null) {
return DnsResponseCode.FORMERR;
}
if (!tsig.getName()
.equals(name) || !tsig.getAlgorithm()
.equals(alg)) {
if (Options.check("verbose")) {
System.err.println("BADKEY failure");
}
return DnsResponseCode.BADKEY;
}
long now = System.currentTimeMillis();
long then = tsig.getTimeSigned()
.getTime();
long fudge = tsig.getFudge();
if (Math.abs(now - then) > fudge * 1000) {
if (Options.check("verbose")) {
System.err.println("BADTIME failure");
}
return DnsResponseCode.BADTIME;
}
if (old != null && tsig.getError() != DnsResponseCode.BADKEY && tsig.getError() != DnsResponseCode.BADSIG) {
DnsOutput out = new DnsOutput();
out.writeU16(old.getSignature().length);
hmac.update(out.toByteArray());
hmac.update(old.getSignature());
}
m.getHeader()
.decCount(DnsSection.ADDITIONAL);
byte[] header = m.getHeader()
.toWire();
m.getHeader()
.incCount(DnsSection.ADDITIONAL);
hmac.update(header);
int len = m.tsigstart - header.length;
hmac.update(b, header.length, len);
DnsOutput out = new DnsOutput();
tsig.getName()
.toWireCanonical(out);
out.writeU16(tsig.dclass);
out.writeU32(tsig.ttl);
tsig.getAlgorithm()
.toWireCanonical(out);
long time = tsig.getTimeSigned()
.getTime() / 1000;
int timeHigh = (int) (time >> 32);
long timeLow = (time & 0xFFFFFFFFL);
out.writeU16(timeHigh);
out.writeU32(timeLow);
out.writeU16(tsig.getFudge());
out.writeU16(tsig.getError());
if (tsig.getOther() != null) {
out.writeU16(tsig.getOther().length);
out.writeByteArray(tsig.getOther());
}
else {
out.writeU16(0);
}
hmac.update(out.toByteArray());
byte[] signature = tsig.getSignature();
int digestLength = hmac.getMacLength();
int minDigestLength;
if (hmac.getAlgorithm()
.toLowerCase()
.contains("md5")) {
minDigestLength = 10;
}
else {
minDigestLength = digestLength / 2;
}
if (signature.length > digestLength) {
if (Options.check("verbose")) {
System.err.println("BADSIG: signature too long");
}
return DnsResponseCode.BADSIG;
}
else if (signature.length < minDigestLength) {
if (Options.check("verbose")) {
System.err.println("BADSIG: signature too short");
}
return DnsResponseCode.BADSIG;
}
else if (!verify(hmac, signature, true)) {
if (Options.check("verbose")) {
System.err.println("BADSIG: signature verification");
}
return DnsResponseCode.BADSIG;
}
m.tsigState = DnsMessage.TSIG_VERIFIED;
return DnsResponseCode.NOERROR;
}
/**
* Returns the maximum length of a TSIG record generated by this key.
*
* @see TSIGRecord
*/
public
int recordLength() {
return (name.length() + 10 + alg.length() + 8 + // time signed, fudge
18 + // 2 byte MAC length, 16 byte MAC
4 + // original id, error
8); // 2 byte error length, 6 byte max error field.
}
public static
class StreamVerifier {
/**
* A helper class for verifying multiple message responses.
*/
private TSIG key;
private Mac verifier;
private int nresponses;
private int lastsigned;
private TSIGRecord lastTSIG;
/**
* Creates an object to verify a multiple message response
*/
public
StreamVerifier(TSIG tsig, TSIGRecord old) {
key = tsig;
verifier = tsig.hmac;
nresponses = 0;
lastTSIG = old;
}
/**
* Verifies a TSIG record on an incoming message that is part of a
* multiple message response.
* TSIG records must be present on the first and last messages, and
* at least every 100 records in between.
* After calling this routine, DnsMessage.isVerified() may be called on
* this message.
*
* @param m The message
* @param b The message in unparsed form
*
* @return The result of the verification (as an DnsResponseCode)
*
* @see DnsResponseCode
*/
public
int verify(DnsMessage m, byte[] b) {
TSIGRecord tsig = m.getTSIG();
nresponses++;
if (nresponses == 1) {
int result = key.verify(m, b, lastTSIG);
if (result == DnsResponseCode.NOERROR) {
byte[] signature = tsig.getSignature();
DnsOutput out = new DnsOutput();
out.writeU16(signature.length);
verifier.update(out.toByteArray());
verifier.update(signature);
}
lastTSIG = tsig;
return result;
}
if (tsig != null) {
m.getHeader()
.decCount(DnsSection.ADDITIONAL);
}
byte[] header = m.getHeader()
.toWire();
if (tsig != null) {
m.getHeader()
.incCount(DnsSection.ADDITIONAL);
}
verifier.update(header);
int len;
if (tsig == null) {
len = b.length - header.length;
}
else {
len = m.tsigstart - header.length;
}
verifier.update(b, header.length, len);
if (tsig != null) {
lastsigned = nresponses;
lastTSIG = tsig;
}
else {
boolean required = (nresponses - lastsigned >= 100);
if (required) {
m.tsigState = DnsMessage.TSIG_FAILED;
return DnsResponseCode.FORMERR;
}
else {
m.tsigState = DnsMessage.TSIG_INTERMEDIATE;
return DnsResponseCode.NOERROR;
}
}
if (!tsig.getName()
.equals(key.name) || !tsig.getAlgorithm()
.equals(key.alg)) {
if (Options.check("verbose")) {
System.err.println("BADKEY failure");
}
m.tsigState = DnsMessage.TSIG_FAILED;
return DnsResponseCode.BADKEY;
}
DnsOutput out = new DnsOutput();
long time = tsig.getTimeSigned()
.getTime() / 1000;
int timeHigh = (int) (time >> 32);
long timeLow = (time & 0xFFFFFFFFL);
out.writeU16(timeHigh);
out.writeU32(timeLow);
out.writeU16(tsig.getFudge());
verifier.update(out.toByteArray());
if (TSIG.verify(verifier, tsig.getSignature()) == false) {
if (Options.check("verbose")) {
System.err.println("BADSIG failure");
}
m.tsigState = DnsMessage.TSIG_FAILED;
return DnsResponseCode.BADSIG;
}
verifier.reset();
out = new DnsOutput();
out.writeU16(tsig.getSignature().length);
verifier.update(out.toByteArray());
verifier.update(tsig.getSignature());
m.tsigState = DnsMessage.TSIG_VERIFIED;
return DnsResponseCode.NOERROR;
}
}
}

View File

@ -1,264 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.util.Date;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsResponseCode;
import dorkbox.network.dns.utils.Options;
import dorkbox.network.dns.utils.Tokenizer;
import dorkbox.util.Base64Fast;
import dorkbox.util.OS;
/**
* Transaction Signature - this record is automatically generated by the
* resolver. TSIG records provide transaction security between the
* sender and receiver of a message, using a shared key.
*
* @author Brian Wellington
* @see TSIG
*/
public
class TSIGRecord extends DnsRecord {
private static final long serialVersionUID = -88820909016649306L;
private Name alg;
private Date timeSigned;
private int fudge;
private byte[] signature;
private int originalID;
private int error;
private byte[] other;
TSIGRecord() {}
@Override
DnsRecord getObject() {
return new TSIGRecord();
}
@Override
void rrFromWire(DnsInput in) throws IOException {
alg = new Name(in);
long timeHigh = in.readU16();
long timeLow = in.readU32();
long time = (timeHigh << 32) + timeLow;
timeSigned = new Date(time * 1000);
fudge = in.readU16();
int sigLen = in.readU16();
signature = in.readByteArray(sigLen);
originalID = in.readU16();
error = in.readU16();
int otherLen = in.readU16();
if (otherLen > 0) {
other = in.readByteArray(otherLen);
}
else {
other = null;
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
alg.toWire(out, null, canonical);
long time = timeSigned.getTime() / 1000;
int timeHigh = (int) (time >> 32);
long timeLow = (time & 0xFFFFFFFFL);
out.writeU16(timeHigh);
out.writeU32(timeLow);
out.writeU16(fudge);
out.writeU16(signature.length);
out.writeByteArray(signature);
out.writeU16(originalID);
out.writeU16(error);
if (other != null) {
out.writeU16(other.length);
out.writeByteArray(other);
}
else {
out.writeU16(0);
}
}
/**
* Converts rdata to a String
*/
@Override
void rrToString(StringBuilder sb) {
sb.append(alg);
sb.append(" ");
if (Options.check("multiline")) {
sb.append("(")
.append(OS.LINE_SEPARATOR)
.append("\t");
}
sb.append(timeSigned.getTime() / 1000);
sb.append(" ");
sb.append(fudge);
sb.append(" ");
sb.append(signature.length);
if (Options.check("multiline")) {
sb.append(OS.LINE_SEPARATOR);
sb.append(Base64Fast.formatString(Base64Fast.encode2(signature), 64, "\t", true));
}
else {
sb.append(" ");
sb.append(Base64Fast.encode2(signature));
}
sb.append(" ");
sb.append(DnsResponseCode.TSIGstring(error));
sb.append(" ");
if (other == null) {
sb.append(0);
}
else {
sb.append(other.length);
if (Options.check("multiline")) {
sb.append(OS.LINE_SEPARATOR)
.append(OS.LINE_SEPARATOR)
.append(OS.LINE_SEPARATOR)
.append("\t");
}
else {
sb.append(" ");
}
if (error == DnsResponseCode.BADTIME) {
if (other.length != 6) {
sb.append("<invalid BADTIME other data>");
}
else {
long time = ((long) (other[0] & 0xFF) << 40) + ((long) (other[1] & 0xFF) << 32) + ((other[2] & 0xFF) << 24) +
((other[3] & 0xFF) << 16) + ((other[4] & 0xFF) << 8) + ((other[5] & 0xFF));
sb.append("<server time: ");
sb.append(new Date(time * 1000));
sb.append(">");
}
}
else {
sb.append("<");
sb.append(Base64Fast.encode2(other));
sb.append(">");
}
}
if (Options.check("multiline")) {
sb.append(" )");
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
throw st.exception("no text format defined for TSIG");
}
/**
* Creates a TSIG Record from the given data. This is normally called by
* the TSIG class
*
* @param alg The shared key's algorithm
* @param timeSigned The time that this record was generated
* @param fudge The fudge factor for time - if the time that the message is
* received is not in the range [now - fudge, now + fudge], the signature
* fails
* @param signature The signature
* @param originalID The message ID at the time of its generation
* @param error The extended error field. Should be 0 in queries.
* @param other The other data field. Currently used only in BADTIME
* responses.
*
* @see TSIG
*/
public
TSIGRecord(Name name,
int dclass,
long ttl,
Name alg,
Date timeSigned,
int fudge,
byte[] signature,
int originalID,
int error,
byte other[]) {
super(name, DnsRecordType.TSIG, dclass, ttl);
this.alg = checkName("alg", alg);
this.timeSigned = timeSigned;
this.fudge = checkU16("fudge", fudge);
this.signature = signature;
this.originalID = checkU16("originalID", originalID);
this.error = checkU16("error", error);
this.other = other;
}
/**
* Returns the shared key's algorithm
*/
public
Name getAlgorithm() {
return alg;
}
/**
* Returns the time that this record was generated
*/
public
Date getTimeSigned() {
return timeSigned;
}
/**
* Returns the time fudge factor
*/
public
int getFudge() {
return fudge;
}
/**
* Returns the signature
*/
public
byte[] getSignature() {
return signature;
}
/**
* Returns the original message ID
*/
public
int getOriginalID() {
return originalID;
}
/**
* Returns the extended error
*/
public
int getError() {
return error;
}
/**
* Returns the other data
*/
public
byte[] getOther() {
return other;
}
}

View File

@ -1,146 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import dorkbox.network.dns.exceptions.InvalidTTLException;
/**
* Routines for parsing BIND-style TTL values. These values consist of
* numbers followed by 1 letter units of time (W - week, D - day, H - hour,
* M - minute, S - second).
*
* @author Brian Wellington
*/
public final
class TTL {
public static final long MAX_VALUE = 0x7FFFFFFFL;
private
TTL() {}
/**
* Parses a TTL, which can either be expressed as a number or a BIND-style
* string with numbers and units.
*
* @param s The string representing the TTL
*
* @return The TTL as a number of seconds
*
* @throws NumberFormatException The string was not in a valid TTL format.
*/
public static
long parseTTL(String s) {
return parse(s, true);
}
/**
* Parses a TTL-like value, which can either be expressed as a number or a
* BIND-style string with numbers and units.
*
* @param s The string representing the numeric value.
* @param clamp Whether to clamp values in the range [MAX_VALUE + 1, 2^32 -1]
* to MAX_VALUE. This should be donw for TTLs, but not other values which
* can be expressed in this format.
*
* @return The value as a number of seconds
*
* @throws NumberFormatException The string was not in a valid TTL format.
*/
public static
long parse(String s, boolean clamp) {
if (s == null || s.length() == 0 || !Character.isDigit(s.charAt(0))) {
throw new NumberFormatException();
}
long value = 0;
long ttl = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
long oldvalue = value;
if (Character.isDigit(c)) {
value = (value * 10) + Character.getNumericValue(c);
if (value < oldvalue) {
throw new NumberFormatException();
}
}
else {
switch (Character.toUpperCase(c)) {
case 'W':
value *= 7;
case 'D':
value *= 24;
case 'H':
value *= 60;
case 'M':
value *= 60;
case 'S':
break;
default:
throw new NumberFormatException();
}
ttl += value;
value = 0;
if (ttl > 0xFFFFFFFFL) {
throw new NumberFormatException();
}
}
}
if (ttl == 0) {
ttl = value;
}
if (ttl > 0xFFFFFFFFL) {
throw new NumberFormatException();
}
else if (ttl > MAX_VALUE && clamp) {
ttl = MAX_VALUE;
}
return ttl;
}
public static
String format(long ttl) {
TTL.check(ttl);
StringBuilder sb = new StringBuilder();
long secs, mins, hours, days, weeks;
secs = ttl % 60;
ttl /= 60;
mins = ttl % 60;
ttl /= 60;
hours = ttl % 24;
ttl /= 24;
days = ttl % 7;
ttl /= 7;
weeks = ttl;
if (weeks > 0) {
sb.append(weeks)
.append("W");
}
if (days > 0) {
sb.append(days)
.append("D");
}
if (hours > 0) {
sb.append(hours)
.append("H");
}
if (mins > 0) {
sb.append(mins)
.append("M");
}
if (secs > 0 || (weeks == 0 && days == 0 && hours == 0 && mins == 0)) {
sb.append(secs)
.append("S");
}
return sb.toString();
}
static
void check(long i) {
if (i < 0 || i > MAX_VALUE) {
throw new InvalidTTLException(i);
}
}
}

View File

@ -1,138 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.utils.Tokenizer;
/**
* Implements common functionality for the many record types whose format
* is a list of strings.
*
* @author Brian Wellington
*/
abstract
class TXTBase extends DnsRecord {
private static final long serialVersionUID = -4319510507246305931L;
protected List strings;
protected
TXTBase() {}
protected
TXTBase(Name name, int type, int dclass, long ttl) {
super(name, type, dclass, ttl);
}
protected
TXTBase(Name name, int type, int dclass, long ttl, String string) {
this(name, type, dclass, ttl, Collections.singletonList(string));
}
protected
TXTBase(Name name, int type, int dclass, long ttl, List strings) {
super(name, type, dclass, ttl);
if (strings == null) {
throw new IllegalArgumentException("strings must not be null");
}
this.strings = new ArrayList(strings.size());
Iterator it = strings.iterator();
try {
while (it.hasNext()) {
String s = (String) it.next();
this.strings.add(byteArrayFromString(s));
}
} catch (TextParseException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
@Override
void rrFromWire(DnsInput in) throws IOException {
strings = new ArrayList(2);
while (in.remaining() > 0) {
byte[] b = in.readCountedString();
strings.add(b);
}
}
@Override
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
Iterator it = strings.iterator();
while (it.hasNext()) {
byte[] b = (byte[]) it.next();
out.writeCountedString(b);
}
}
/**
* converts to a String
*/
@Override
void rrToString(StringBuilder sb) {
Iterator it = strings.iterator();
while (it.hasNext()) {
byte[] array = (byte[]) it.next();
sb.append(byteArrayToString(array, true));
if (it.hasNext()) {
sb.append(" ");
}
}
}
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
strings = new ArrayList(2);
while (true) {
Tokenizer.Token t = st.get();
if (!t.isString()) {
break;
}
try {
strings.add(byteArrayFromString(t.value));
} catch (TextParseException e) {
throw st.exception(e.getMessage());
}
}
st.unget();
}
/**
* Returns the text strings
*
* @return A list of Strings corresponding to the text strings.
*/
public
List getStrings() {
List list = new ArrayList(strings.size());
for (int i = 0; i < strings.size(); i++) {
list.add(byteArrayToString((byte[]) strings.get(i), false));
}
return list;
}
/**
* Returns the text strings
*
* @return A list of byte arrays corresponding to the text strings.
*/
public
List getStringsAsByteArrays() {
return strings;
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
package dorkbox.network.dns.records;
import java.util.List;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsRecordType;
/**
* Text - stores text strings
*
* @author Brian Wellington
*/
public
class TXTRecord extends TXTBase {
private static final long serialVersionUID = -5780785764284221342L;
TXTRecord() {}
@Override
DnsRecord getObject() {
return new TXTRecord();
}
/**
* Creates a TXT Record from the given data
*
* @param strings The text strings
*
* @throws IllegalArgumentException One of the strings has invalid escapes
*/
public
TXTRecord(Name name, int dclass, long ttl, List strings) {
super(name, DnsRecordType.TXT, dclass, ttl, strings);
}
/**
* Creates a TXT Record from the given data
*
* @param string One text string
*
* @throws IllegalArgumentException The string has invalid escapes
*/
public
TXTRecord(Name name, int dclass, long ttl, String string) {
super(name, DnsRecordType.TXT, dclass, ttl, string);
}
}

Some files were not shown because too many files have changed in this diff Show More