Moved DNS to it's own project
This commit is contained in:
parent
33853d44e3
commit
3f003995b6
|
@ -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);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 <mizhou@bnivideo.com>, 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
@ -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
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 <mizhou@bnivideo.com>, 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 <mizhou@bnivideo.com>, 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) + ">";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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 _<service>._<protocol>.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
Loading…
Reference in New Issue
Block a user