This is an automated email from the ASF dual-hosted git repository.
cgivre pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/drill.git
The following commit(s) were added to refs/heads/master by this push:
new c1d699571e DRILL-8413: Add DNS Lookup Functions (#2778)
c1d699571e is described below
commit c1d699571e305e86614a35bc3716f6b38227c01c
Author: Charles S. Givre <[email protected]>
AuthorDate: Sun Mar 19 09:53:22 2023 -0400
DRILL-8413: Add DNS Lookup Functions (#2778)
---
contrib/udfs/README.md | 8 +
contrib/udfs/pom.xml | 18 ++
.../org/apache/drill/exec/udfs/DNSFunctions.java | 258 +++++++++++++++++++++
.../java/org/apache/drill/exec/udfs/DNSUtils.java | 234 +++++++++++++++++++
.../apache/drill/exec/udfs/TestDNSFunctions.java | 79 +++++++
pom.xml | 28 +++
6 files changed, 625 insertions(+)
diff --git a/contrib/udfs/README.md b/contrib/udfs/README.md
index 38046f9fc6..23ece7df6b 100644
--- a/contrib/udfs/README.md
+++ b/contrib/udfs/README.md
@@ -436,3 +436,11 @@ The functions are:
[1]: https://github.com/target/huntlib
+
+# DNS Functions
+These functions enable DNS research using Drill.
+
+* `getHostName(<IP address>)`: Returns the host name associated with an IP
address.
+* `getHostAddress(<host>)`: Returns an IP address associated with a host name.
+* `dnsLookup(<host>, [<Resolver>])`: Performs a DNS lookup on a given host.
You can optionally provide a resolver. Possible resolver values are:
`cloudflare`, `cloudflare_secondary`, `google`, `google_secondary`,
`verisign`, `verisign_secondary`, `yandex`, `yandex_secondary`.
+* `whois(<host>, [<Resolver>])`: Performs a whois lookup on the given host
name. You can optionally provide a resolver URL. Note that not all providers
allow bulk automated whois lookups, so please follow the terms fo service for
your provider.
\ No newline at end of file
diff --git a/contrib/udfs/pom.xml b/contrib/udfs/pom.xml
index 8ab5ac1e0a..63187978ca 100644
--- a/contrib/udfs/pom.xml
+++ b/contrib/udfs/pom.xml
@@ -31,10 +31,22 @@
<name>Drill : Contrib : UDFs</name>
<dependencies>
+ <dependency>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ <version>3.5.2</version>
+ </dependency>
+
<dependency>
<groupId>org.apache.drill.exec</groupId>
<artifactId>drill-java-exec</artifactId>
<version>${project.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
@@ -83,6 +95,12 @@
<classifier>tests</classifier>
<version>${project.version}</version>
<scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
+ </exclusions>
</dependency>
<dependency>
diff --git
a/contrib/udfs/src/main/java/org/apache/drill/exec/udfs/DNSFunctions.java
b/contrib/udfs/src/main/java/org/apache/drill/exec/udfs/DNSFunctions.java
new file mode 100644
index 0000000000..6a9e04841d
--- /dev/null
+++ b/contrib/udfs/src/main/java/org/apache/drill/exec/udfs/DNSFunctions.java
@@ -0,0 +1,258 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.drill.exec.udfs;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.drill.exec.expr.DrillSimpleFunc;
+import org.apache.drill.exec.expr.annotations.FunctionTemplate;
+import org.apache.drill.exec.expr.annotations.Output;
+import org.apache.drill.exec.expr.annotations.Param;
+import org.apache.drill.exec.expr.annotations.Workspace;
+import org.apache.drill.exec.expr.holders.NullableVarCharHolder;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+import org.apache.drill.exec.vector.complex.writer.BaseWriter;
+
+import javax.inject.Inject;
+
+public class DNSFunctions {
+
+ private DNSFunctions() {
+ }
+
+ /* This function gets the host name associated with an IP address */
+ @FunctionTemplate(names = {"get_host_name", "getHostName",
"reverse_ip_lookup"},
+ scope = FunctionTemplate.FunctionScope.SIMPLE,
+ nulls = FunctionTemplate.NullHandling.NULL_IF_NULL)
+ public static class ReverseIPLookup implements DrillSimpleFunc {
+
+ @Param
+ VarCharHolder ipaddress;
+
+ @Output
+ VarCharHolder out;
+
+ @Inject
+ DrillBuf buffer;
+
+ @Override
+ public void setup() {
+
+ }
+
+ @Override
+ public void eval() {
+ String ipString =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(ipaddress.start,
ipaddress.end, ipaddress.buffer);
+ String hostname = "";
+
+ try {
+ java.net.InetAddress address =
java.net.InetAddress.getByName(ipString);
+ hostname = address.getHostName();
+
+ } catch (java.net.UnknownHostException e) {
+ hostname = "Unknown host";
+ }
+ out.buffer = buffer;
+ out.start = 0;
+ out.end = hostname.getBytes().length;
+ buffer.setBytes(0, hostname.getBytes());
+ }
+ }
+
+ /* This function takes a host name and returns the IP address associated
with that host, and "Unknown if there is an error */
+ @FunctionTemplate(names = {"get_host_address", "getHostAddress",
"host_lookup", "hostLookup"},
+ scope = FunctionTemplate.FunctionScope.SIMPLE,
+ nulls = FunctionTemplate.NullHandling.NULL_IF_NULL)
+ public static class HostLookup implements DrillSimpleFunc {
+
+ @Param
+ VarCharHolder hostname;
+
+ @Output
+ VarCharHolder out;
+
+ @Inject
+ DrillBuf buffer;
+
+ @Override
+ public void setup() {
+
+ }
+
+ @Override
+ public void eval() {
+ String host =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(hostname.start,
hostname.end, hostname.buffer);
+ String result = "";
+ try {
+ java.net.Inet4Address ip = (java.net.Inet4Address)
java.net.Inet4Address.getByName(host);
+ result = ip.getHostAddress();
+ } catch (Exception e) {
+ result = "Unknown";
+ }
+
+ out.buffer = buffer;
+ out.start = 0;
+ out.end = result.getBytes().length;
+ buffer.setBytes(0, result.getBytes());
+ }
+ }
+
+ /* This function performs a complete DNS lookup */
+ @FunctionTemplate(names = {"dns_lookup", "dnsLookup", "dns"}, scope =
FunctionTemplate.FunctionScope.SIMPLE)
+ public static class DNSLookupFunctionWithNull implements DrillSimpleFunc {
+
+ @Param
+ NullableVarCharHolder rawDomainName;
+
+ @Output
+ BaseWriter.ComplexWriter out;
+
+ @Inject
+ DrillBuf buffer;
+
+ @Override
+ public void setup() {
+ // no op
+ }
+
+ @Override
+ public void eval() {
+ if (rawDomainName.isSet == 0) {
+ org.apache.drill.exec.vector.complex.writer.BaseWriter.ListWriter
listWriter = out.rootAsList();
+ org.apache.drill.exec.vector.complex.writer.BaseWriter.MapWriter
rowMapWriter = listWriter.map();
+ listWriter.startList();
+ rowMapWriter.start();
+ rowMapWriter.end();
+ listWriter.endList();
+ return;
+ }
+
+ try {
+ String domainName =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawDomainName.start,
rawDomainName.end, rawDomainName.buffer);
+ org.apache.drill.exec.udfs.DNSUtils.getDNS(domainName, out, buffer);
+ } catch (Exception e) {
+ org.apache.drill.exec.vector.complex.writer.BaseWriter.ListWriter
listWriter = out.rootAsList();
+ org.apache.drill.exec.vector.complex.writer.BaseWriter.MapWriter
rowMapWriter = listWriter.map();
+ listWriter.startList();
+ rowMapWriter.start();
+ rowMapWriter.end();
+ listWriter.endList();
+ }
+ }
+ }
+
+ @FunctionTemplate(names = {"dns_lookup", "dnsLookup", "dns"}, scope =
FunctionTemplate.FunctionScope.SIMPLE)
+ public static class DNSLookupFunctionWithResolver implements DrillSimpleFunc
{
+
+ @Param
+ NullableVarCharHolder rawDomainName;
+
+ @Param(constant = true)
+ VarCharHolder resolverHolder;
+
+ @Output
+ BaseWriter.ComplexWriter out;
+
+ @Workspace
+ String resolver;
+
+ @Inject
+ DrillBuf buffer;
+
+ @Override
+ public void setup() {
+ resolver =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(resolverHolder.start,
resolverHolder.end, resolverHolder.buffer);
+ }
+
+ @Override
+ public void eval() {
+ if (rawDomainName.isSet == 0) {
+ org.apache.drill.exec.vector.complex.writer.BaseWriter.ListWriter
listWriter = out.rootAsList();
+ org.apache.drill.exec.vector.complex.writer.BaseWriter.MapWriter
rowMapWriter = listWriter.map();
+ listWriter.startList();
+ rowMapWriter.start();
+ rowMapWriter.end();
+ listWriter.endList();
+ return;
+ }
+
+ try {
+ String domainName =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawDomainName.start,
rawDomainName.end, rawDomainName.buffer);
+ org.apache.drill.exec.udfs.DNSUtils.getDNS(domainName, resolver, out,
buffer);
+ } catch (Exception e) {
+ org.apache.drill.exec.vector.complex.writer.BaseWriter.ListWriter
listWriter = out.rootAsList();
+ org.apache.drill.exec.vector.complex.writer.BaseWriter.MapWriter
rowMapWriter = listWriter.map();
+ listWriter.startList();
+ rowMapWriter.start();
+ rowMapWriter.end();
+ listWriter.endList();
+ }
+ }
+ }
+
+ @FunctionTemplate(names = {"whois"},
+ scope = FunctionTemplate.FunctionScope.SIMPLE)
+ public static class WhoIsFunction implements DrillSimpleFunc {
+
+ @Param
+ NullableVarCharHolder rawDomainName;
+
+ @Output
+ BaseWriter.ComplexWriter out;
+
+ @Inject
+ DrillBuf buffer;
+ @Override
+ public void setup() {
+ // No op
+ }
+
+ @Override
+ public void eval() {
+ String domain =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawDomainName.start,
rawDomainName.end, rawDomainName.buffer);
+ org.apache.drill.exec.udfs.DNSUtils.whois(domain, out, buffer);
+ }
+ }
+
+ @FunctionTemplate(names = {"whois"}, scope =
FunctionTemplate.FunctionScope.SIMPLE)
+ public static class WhoIsFunctionWithNonDefaultServer implements
DrillSimpleFunc {
+
+ @Param
+ NullableVarCharHolder rawDomainName;
+
+ @Param(constant = true)
+ VarCharHolder serverHolder;
+
+ @Output
+ BaseWriter.ComplexWriter out;
+
+ @Inject
+ DrillBuf buffer;
+ @Override
+ public void setup() {
+ // No op
+ }
+
+ @Override
+ public void eval() {
+ String domain =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(rawDomainName.start,
rawDomainName.end, rawDomainName.buffer);
+ String server =
org.apache.drill.exec.expr.fn.impl.StringFunctionHelpers.toStringFromUTF8(serverHolder.start,
serverHolder.end, serverHolder.buffer);
+ org.apache.drill.exec.udfs.DNSUtils.whois(domain, server, out, buffer);
+ }
+ }
+}
diff --git
a/contrib/udfs/src/main/java/org/apache/drill/exec/udfs/DNSUtils.java
b/contrib/udfs/src/main/java/org/apache/drill/exec/udfs/DNSUtils.java
new file mode 100644
index 0000000000..08890350fd
--- /dev/null
+++ b/contrib/udfs/src/main/java/org/apache/drill/exec/udfs/DNSUtils.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.drill.exec.udfs;
+
+import io.netty.buffer.DrillBuf;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.net.whois.WhoisClient;
+import org.apache.drill.common.exceptions.UserException;
+import org.apache.drill.exec.expr.holders.VarCharHolder;
+import org.apache.drill.exec.vector.complex.writer.BaseWriter.ComplexWriter;
+import org.apache.drill.exec.vector.complex.writer.BaseWriter.ListWriter;
+import org.apache.drill.exec.vector.complex.writer.BaseWriter.MapWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xbill.DNS.Lookup;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.SimpleResolver;
+import org.xbill.DNS.TextParseException;
+import org.xbill.DNS.Type;
+
+import java.io.IOException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utility class which contains various methods for performing DNS resolution
and WHOIS lookups in Drill UDFs.
+ */
+public class DNSUtils {
+
+ private static final Logger logger = LoggerFactory.getLogger(DNSUtils.class);
+ /**
+ * A list of known DNS resolvers.
+ */
+ private static final Map<String, String> KNOWN_RESOLVERS = new HashMap<>();
+ static {
+ KNOWN_RESOLVERS.put("cloudflare", "1.1.1.1");
+ KNOWN_RESOLVERS.put("cloudflare_secondary", "1.0.0.1");
+ KNOWN_RESOLVERS.put("google", "8.8.8.8");
+ KNOWN_RESOLVERS.put("google_secondary", "8.8.4.4");
+ KNOWN_RESOLVERS.put("verisign", "64.6.64.6");
+ KNOWN_RESOLVERS.put("verisign_secondary", "64.6.65.6");
+ KNOWN_RESOLVERS.put("yandex", "77.88.8.8");
+ KNOWN_RESOLVERS.put("yandex_secondary", "77.88.8.1");
+ }
+
+ private static final Pattern WHOIS_REGEX = Pattern.compile("([a-zA-Z0-9_
]+):\\s(.+)");
+
+ /**
+ * Performs the actual DNS lookup and returns the results in a {@link
ComplexWriter}. If the resolver
+ * is not null, we will use the provided resolver. If a resolver is not
provided, we'll use the local cache.
+ * <p>
+ * Relating to the resolver, you can specify an IP or host, or you can use
a name of a known resolver. Known resolvers are:
+ * <ul>
+ * <li>cloudflare</li>
+ * <li>cloudflare_secondary</li>
+ * <li>google</li>
+ * <li>google_secondary</li>
+ * <li>verisign</li>
+ * <li>verisign_secondary</li>
+ * <li>yandex</li>
+ * <li>yandex_secondary</li>
+ * </ul>
+ *
+ * </p>
+ * @param domainName A {@link String} of a domain for which you want to look
up.
+ * @param resolverName A {@link String} containing the resolver name.
+ * @param out The {@link ComplexWriter} to which the DNS results will be
written.
+ * @param buffer The {@link DrillBuf} to which the data will be written.
+ * @throws TextParseException If the resolver is unparsable, throw an
exception.
+ */
+ public static void getDNS(String domainName, String resolverName,
ComplexWriter out, DrillBuf buffer) throws TextParseException {
+
+ Lookup look = new Lookup(domainName, Type.ANY);
+ String resolverIP;
+ // Add the resolver if it is provided.
+ if (StringUtils.isNotEmpty(resolverName)) {
+ // Create a resolver
+ resolverIP = KNOWN_RESOLVERS.getOrDefault(resolverName.toLowerCase(),
resolverName);
+ try {
+ SimpleResolver resolver = new SimpleResolver(resolverIP);
+ look.setResolver(resolver);
+ } catch (UnknownHostException e) {
+ throw UserException.connectionError(e)
+ .message("Cannot find resolver: " + resolverName)
+ .build(logger);
+ }
+ }
+
+ Record[] records = look.run();
+
+ // Initialize writers
+ ListWriter listWriter = out.rootAsList();
+ MapWriter rowMapWriter = listWriter.map();
+ // If there are no records, return an empty list.
+ if (records == null) {
+ listWriter.startList();
+ rowMapWriter.start();
+ rowMapWriter.end();
+ listWriter.endList();
+ return;
+ }
+
+ for (Record record : records) {
+ VarCharHolder fieldHolder = new VarCharHolder();
+
+ rowMapWriter.start();
+ byte[] name = record.getName().toString().getBytes();
+ buffer = buffer.reallocIfNeeded(name.length);
+ buffer.setBytes(0, name);
+ rowMapWriter.varChar("name").writeVarChar(0, name.length, buffer);
+
+ byte[] completeRecord = record.toString().getBytes();
+ buffer = buffer.reallocIfNeeded(completeRecord.length);
+ buffer.setBytes(0, completeRecord);
+ fieldHolder.start = 0;
+ fieldHolder.end = completeRecord.length;
+ fieldHolder.buffer = buffer;
+ rowMapWriter.varChar("record").write(fieldHolder);
+
+ rowMapWriter.bigInt("ttl").writeBigInt(record.getTTL());
+
+ byte[] type = Type.string(record.getType()).getBytes();
+ buffer = buffer.reallocIfNeeded(type.length);
+ buffer.setBytes(0, type);
+ rowMapWriter.varChar("type").writeVarChar(0, type.length, buffer);
+
+ byte[] rdata = record.rdataToString().getBytes();
+ buffer.reallocIfNeeded(rdata.length);
+ buffer.setBytes(0, rdata);
+ rowMapWriter.varChar("rdata").writeVarChar(0, rdata.length, buffer);
+ rowMapWriter.end();
+ }
+ }
+
+ /**
+ * Performs the actual DNS lookup and returns the results in a {@link
ComplexWriter}. Uses the local cache as the
+ * DNS resolver.
+ * @param domainName A {@link String} of a domain for which you want to look
up.
+ * @param out The {@link ComplexWriter} to which the DNS results will be
written.
+ * @param buffer The {@link DrillBuf} to which the data will be written.
+ * @throws TextParseException If the domain is unparsable, throw an
exception.
+ */
+ public static void getDNS(String domainName, ComplexWriter out, DrillBuf
buffer) throws TextParseException {
+ getDNS(domainName, null, out, buffer);
+ }
+
+ /**
+ * Performs a WHOIS lookup and populates the results into a Drill map. This
method uses a default server.
+ * @param domainName The input domain name.
+ * @param out A {@link ComplexWriter} to which the results will be written
+ * @param buffer A {@link DrillBuf} which contains the output
+ */
+ public static void whois(String domainName, ComplexWriter out, DrillBuf
buffer) {
+ whois(domainName, WhoisClient.DEFAULT_HOST, out, buffer);
+ }
+
+ /**
+ * Performs a WHOIS lookup and populates the results into a Drill map. This
method uses a default server.
+ * @param domainName The input domain name.
+ * @param whoisServer A {@link String} containing the whois server
+ * @param out A {@link ComplexWriter} to which the results will be written
+ * @param buffer A {@link DrillBuf} which contains the output
+ */
+ public static void whois(String domainName, String whoisServer,
ComplexWriter out, DrillBuf buffer) {
+ WhoisClient whois = new WhoisClient();
+ MapWriter mapWriter = out.rootAsMap();
+
+ try {
+ whois.connect(whoisServer);
+ String whoisData = whois.query(domainName);
+ whois.disconnect();
+
+ // Split the result line by line
+ String[] lines = whoisData.split("\\R");
+
+ // Now iterate over those lines
+ mapWriter.start();
+ for (String line : lines) {
+ Matcher matcher = WHOIS_REGEX.matcher(line);
+ boolean matchFound = matcher.find();
+
+ // Map to output
+ if (matchFound) {
+ String key = matcher.group(1);
+ String value = matcher.group(2);
+
+ // Skip useless keys
+ if (key.contentEquals("NOTICE") ||
+ key.contentEquals("by the following terms of use") ||
+ key.contentEquals("TERMS OF USE") ||
+ key.contentEquals("to")
+ ) {
+ continue;
+ }
+
+ // Write to output map
+ byte[] valueBytes = value.getBytes();
+ buffer = buffer.reallocIfNeeded(valueBytes.length);
+ buffer.setBytes(0, valueBytes);
+ mapWriter.varChar(key.trim()).writeVarChar(0, valueBytes.length,
buffer);
+ }
+ }
+ mapWriter.end();
+ } catch (SocketException e) {
+ throw UserException.connectionError(e)
+ .message("Error connecting to WHOIS server: " + e.getMessage())
+ .build(logger);
+ } catch (IOException e) {
+ throw UserException.connectionError(e)
+ .message("Error retrieving WHOIS results: " + e.getMessage())
+ .build(logger);
+ }
+ }
+}
diff --git
a/contrib/udfs/src/test/java/org/apache/drill/exec/udfs/TestDNSFunctions.java
b/contrib/udfs/src/test/java/org/apache/drill/exec/udfs/TestDNSFunctions.java
new file mode 100644
index 0000000000..8ffd907924
--- /dev/null
+++
b/contrib/udfs/src/test/java/org/apache/drill/exec/udfs/TestDNSFunctions.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.drill.exec.udfs;
+
+import org.apache.drill.categories.SqlFunctionTest;
+import org.apache.drill.categories.UnlikelyTest;
+import org.apache.drill.test.ClusterFixture;
+import org.apache.drill.test.ClusterFixtureBuilder;
+import org.apache.drill.test.ClusterTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category({UnlikelyTest.class, SqlFunctionTest.class})
+public class TestDNSFunctions extends ClusterTest {
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ ClusterFixtureBuilder builder = ClusterFixture.builder(dirTestWatcher);
+ startCluster(builder);
+ }
+
+ @Test
+ public void testGetHostAddress() throws Exception {
+ String query = "select get_host_address('apache.org') as hostname from
(values(1))";
+
testBuilder().sqlQuery(query).ordered().baselineColumns("hostname").baselineValues("151.101.2.132").go();
+
+ query = "select get_host_address('google') as hostname from (values(1))";
+
testBuilder().sqlQuery(query).ordered().baselineColumns("hostname").baselineValues("Unknown").go();
+
+ query = "select get_host_address('') as hostname from (values(1))";
+
testBuilder().sqlQuery(query).ordered().baselineColumns("hostname").baselineValues("127.0.0.1").go();
+
+ query = "select get_host_address(cast(null as varchar)) as hostname from
(values(1))";
+
testBuilder().sqlQuery(query).ordered().baselineColumns("hostname").baselineValues((String)null).go();
+ }
+
+ @Test
+ public void testGetHostName() throws Exception {
+ String query = "select get_host_name('142.251.16.102') as hostname from
(values(1))";
+
testBuilder().sqlQuery(query).ordered().baselineColumns("hostname").baselineValues("bl-in-f102.1e100.net").go();
+
+ query = "select get_host_name('sdfsdfafsdfadfdsf') as hostname from
(values(1))";
+
testBuilder().sqlQuery(query).ordered().baselineColumns("hostname").baselineValues("Unknown
host").go();
+
+ query = "select get_host_name('') as hostname from (values(1))";
+
testBuilder().sqlQuery(query).ordered().baselineColumns("hostname").baselineValues("localhost").go();
+
+ query = "select get_host_name(cast(null as varchar)) as hostname from
(values(1))";
+
testBuilder().sqlQuery(query).ordered().baselineColumns("hostname").baselineValues((String)null).go();
+ }
+
+ @Test
+ public void testDNSLookup() throws Exception {
+ String sql = "SELECT dns_lookup('google.com') AS dns_info FROM
(VALUES(1))";
+ testBuilder().sqlQuery(sql).ordered().baselineColumns("dns_info").go();
+ }
+
+ @Test
+ public void testWhois() throws Exception {
+ String sql = "SELECT whois('google.com') AS whois FROM (VALUES(1))";
+ testBuilder().sqlQuery(sql).ordered().baselineColumns("whois").go();
+ }
+}
diff --git a/pom.xml b/pom.xml
index bc8f927ba4..4d2075e23b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2207,6 +2207,10 @@
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
@@ -2374,6 +2378,10 @@
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
@@ -3034,6 +3042,10 @@
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
@@ -3541,6 +3553,10 @@
<groupId>org.mortbay.jetty</groupId>
<artifactId>servlet-api-2.5</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
@@ -3661,6 +3677,10 @@
<groupId>org.mortbay.jetty</groupId>
<artifactId>servlet-api-2.5</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
@@ -3991,6 +4011,10 @@
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>
@@ -4240,6 +4264,10 @@
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
+ <exclusion>
+ <groupId>dnsjava</groupId>
+ <artifactId>dnsjava</artifactId>
+ </exclusion>
</exclusions>
</dependency>
<dependency>