All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.mongodb.internal.dns.DefaultDnsResolver Maven / Gradle / Ivy

Go to download

The Java operations layer for the MongoDB Java Driver. Third parties can wrap this layer to provide custom higher-level APIs

There is a newer version: 5.3.0-beta0
Show newest version
/*
 * Copyright 2008-present MongoDB, Inc.
 *
 * 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 com.mongodb.internal.dns;

import com.mongodb.MongoConfigurationException;
import com.mongodb.lang.Nullable;
import com.mongodb.spi.dns.DnsClient;
import com.mongodb.spi.dns.DnsClientProvider;
import com.mongodb.spi.dns.DnsWithResponseCodeException;

import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.stream.StreamSupport;

import static java.lang.String.format;
import static java.util.Arrays.asList;

/**
 * Utility class for resolving SRV and TXT records.
 *
 * 

This class is not part of the public API and may be removed or changed at any time

*/ public final class DefaultDnsResolver implements DnsResolver { private static final DnsClient DEFAULT_DNS_CLIENT; static { DEFAULT_DNS_CLIENT = StreamSupport.stream(ServiceLoader.load(DnsClientProvider.class).spliterator(), false) .findFirst() .map(DnsClientProvider::create) .orElse(new JndiDnsClient()); } private final DnsClient dnsClient; public DefaultDnsResolver() { this(DEFAULT_DNS_CLIENT); } public DefaultDnsResolver(@Nullable final DnsClient dnsClient) { this.dnsClient = dnsClient == null ? DEFAULT_DNS_CLIENT : dnsClient; } /* The format of SRV record is priority weight port target. e.g. 0 5 5060 example.com. The priority and weight are ignored, and we just concatenate the host (after removing the ending '.') and port with a ':' in between, as expected by ServerAddress. It's required that the srvHost has at least three parts (e.g. foo.bar.baz) and that all of the resolved hosts have a parent domain equal to the domain of the srvHost. */ @Override public List resolveHostFromSrvRecords(final String srvHost, final String srvServiceName) { String srvHostDomain = srvHost.substring(srvHost.indexOf('.') + 1); List srvHostDomainParts = asList(srvHostDomain.split("\\.")); List hosts = new ArrayList<>(); String resourceName = "_" + srvServiceName + "._tcp." + srvHost; try { List srvAttributeValues = dnsClient.getResourceRecordData(resourceName, "SRV"); if (srvAttributeValues == null || srvAttributeValues.isEmpty()) { throw new MongoConfigurationException(format("No SRV records available for '%s'.", resourceName)); } for (String srvRecord : srvAttributeValues) { String[] split = srvRecord.split(" "); String resolvedHost = split[3].endsWith(".") ? split[3].substring(0, split[3].length() - 1) : split[3]; String resolvedHostDomain = resolvedHost.substring(resolvedHost.indexOf('.') + 1); if (!sameParentDomain(srvHostDomainParts, resolvedHostDomain)) { throw new MongoConfigurationException( format("The SRV host name '%s' resolved to a host '%s 'that is not in a sub-domain of the SRV host.", srvHost, resolvedHost)); } hosts.add(resolvedHost + ":" + split[2]); } } catch (Exception e) { throw new MongoConfigurationException(format("Failed looking up SRV record for '%s'.", resourceName), e); } return hosts; } private static boolean sameParentDomain(final List srvHostDomainParts, final String resolvedHostDomain) { List resolvedHostDomainParts = asList(resolvedHostDomain.split("\\.")); if (srvHostDomainParts.size() > resolvedHostDomainParts.size()) { return false; } return resolvedHostDomainParts.subList(resolvedHostDomainParts.size() - srvHostDomainParts.size(), resolvedHostDomainParts.size()) .equals(srvHostDomainParts); } /* A TXT record is just a string We require each to be one or more query parameters for a MongoDB connection string. Here we concatenate TXT records together with a '&' separator as required by connection strings */ @Override public String resolveAdditionalQueryParametersFromTxtRecords(final String host) { try { List attributeValues = dnsClient.getResourceRecordData(host, "TXT"); if (attributeValues == null || attributeValues.isEmpty()) { return ""; } if (attributeValues.size() > 1) { throw new MongoConfigurationException(format("Multiple TXT records found for host '%s'. Only one is permitted", host)); } // Remove all space characters, as the DNS resolver for TXT records inserts a space character // between each character-string in a single TXT record. That whitespace is spurious in // this context and must be removed return attributeValues.get(0).replaceAll("\\s", ""); } catch (DnsWithResponseCodeException e) { // ignore NXDomain error (error code 3, "Non-Existent Domain) if (e.getResponseCode() != 3) { throw new MongoConfigurationException("Failed looking up TXT record for host " + host, e); } return ""; } catch (Exception e) { throw new MongoConfigurationException("Failed looking up TXT record for host " + host, e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy