DomainResolver.java
// 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.doris.catalog;
import org.apache.doris.common.util.MasterDaemon;
import org.apache.doris.mysql.privilege.Auth;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Set;
/*
* DomainResolver resolve the domain name saved in user property to list of IPs,
* and refresh password entries in user priv table, periodically.
*/
public class DomainResolver extends MasterDaemon {
private static final Logger LOG = LogManager.getLogger(DomainResolver.class);
// this is only available in BAIDU, for resolving BNS
private static final String BNS_RESOLVER_TOOLS_PATH = "/usr/bin/get_instance_by_service";
private Auth auth;
public DomainResolver(Auth auth) {
super("domain resolver", 10 * 1000);
this.auth = auth;
}
// 'public' for test
@Override
public void runAfterCatalogReady() {
// domain names
Set<String> allDomains = Sets.newHashSet();
auth.getAllDomains(allDomains);
// resolve domain name
Map<String, Set<String>> resolvedIPsMap = Maps.newHashMap();
for (String domain : allDomains) {
if (LOG.isDebugEnabled()) {
LOG.debug("begin to resolve domain: {}", domain);
}
Set<String> resolvedIPs = Sets.newHashSet();
if (!resolveWithBNS(domain, resolvedIPs) && !resolveWithDNS(domain, resolvedIPs)) {
continue;
}
if (LOG.isDebugEnabled()) {
LOG.debug("get resolved ip of domain {}: {}", domain, resolvedIPs);
}
resolvedIPsMap.put(domain, resolvedIPs);
}
// refresh user priv table by resolved IPs
auth.refreshUserPrivEntriesByResovledIPs(resolvedIPsMap);
}
/**
* Check if domain name is valid
*
* @param host:
* currently is the user's whitelist bns or dns name
* @return true of false
*/
public boolean isValidDomain(String domainName) {
if (Strings.isNullOrEmpty(domainName)) {
LOG.warn("Domain name is null or empty");
return false;
}
Set<String> ipSet = Sets.newHashSet();
if (!resolveWithDNS(domainName, ipSet) && !resolveWithBNS(domainName, ipSet)) {
return false;
}
return true;
}
/**
* resolve domain name with dns
*/
public boolean resolveWithDNS(String domainName, Set<String> resolvedIPs) {
InetAddress[] address;
try {
address = InetAddress.getAllByName(domainName);
} catch (UnknownHostException e) {
LOG.warn("unknown domain name " + domainName + " with dns: " + e.getMessage());
return false;
}
for (InetAddress addr : address) {
resolvedIPs.add(addr.getHostAddress());
}
return true;
}
public boolean resolveWithBNS(String domainName, Set<String> resolvedIPs) {
File binaryFile = new File(BNS_RESOLVER_TOOLS_PATH);
if (!binaryFile.exists()) {
LOG.info("{} does not exist", BNS_RESOLVER_TOOLS_PATH);
return false;
}
final StringBuilder cmdBuilder = new StringBuilder();
cmdBuilder.append(BNS_RESOLVER_TOOLS_PATH).append(" -a ").append(domainName);
Process process = null;
BufferedReader bufferedReader = null;
String str = null;
String ip = null;
try {
process = Runtime.getRuntime().exec(cmdBuilder.toString());
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((str = bufferedReader.readLine()) != null) {
ip = str.split(" ")[1];
resolvedIPs.add(ip);
}
final int exitCode = process.waitFor();
// mean something error
if (exitCode != 0) {
LOG.warn("failed to execute cmd: {}, exit code: {}", cmdBuilder.toString(), exitCode);
resolvedIPs.clear();
return false;
}
return true;
} catch (IOException | InterruptedException e) {
LOG.warn("failed to resolve domain with BNS", e);
resolvedIPs.clear();
return false;
} finally {
if (process != null) {
process.destroy();
}
try {
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (IOException e) {
LOG.error("Close bufferedReader error! " + e);
}
}
}
}