package helpers;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.typesafe.config.ConfigFactory;
import models.Domain;
import models.Ip;
import models.ResourceRecord;
import play.Logger;
import play.libs.F.Function;
import play.libs.F.Promise;
import play.libs.ws.WS;
import play.libs.ws.WSResponse;
public class DnsInquireHelper {
private final static String AUTODNS_HOST = ConfigFactory.load().getString("autodns.host");
private final static String AUTODNS_USERNAME = ConfigFactory.load().getString("autodns.user");
private final static String AUTODNS_PASSWORD = ConfigFactory.load().getString("autodns.pass");
private final static String AUTODNS_CONTEXT = ConfigFactory.load().getString("autodns.context");
private final static String AUTODNS_NS_1 = ConfigFactory.load().getString("autodns.ns1");
private Domain domain;
public DnsInquireHelper(Domain domain) {
this.domain = domain;
}
public void inquire() {
String message = getRequest();
Logger.debug("@"+System.currentTimeMillis()+" sending Inquire for "+domain.name+":\n" + message + "\n");
performInquire(message);
}
private String getRequest() {
return ""
+ ""
+ ""
+ AUTODNS_USERNAME
+ ""
+ ""
+ AUTODNS_PASSWORD
+ ""
+ ""
+ AUTODNS_CONTEXT
+ ""
+ ""
+ ""
+ "0205
"
+ ""
+ ""
+ AUTODNS_NS_1
+ ""
+ ""
+ domain.name
+ ""
+ ""
+ ""
+ ""
+ "";
}
private void performInquire(String content) {
Promise xmlPromise = WS.url(AUTODNS_HOST)
.setHeader("Content-Type", "text/xml; charset=utf-8")
.post(content).map(new Function() {
public Document apply(WSResponse response) {
Logger.debug("response: "+response.getBody());
Document doc = response.asXml();
if (getUpdateStatus(doc)) {
Logger.info("@"+System.currentTimeMillis()+" inquire "+domain.name+" success!");
domain = updatingDomain(doc, domain);
domain.save();
} else {
Logger.error("@"+System.currentTimeMillis()+" inquire "+domain.name+" error:\n", doc.getTextContent());
}
return doc;
}
});
}
private static Domain updatingDomain(Document doc, Domain domain) {
List oldResourceRecords = domain.getResourceRecords();
List newResourceRecords = new ArrayList<>();
domain = updatingMain(doc, domain);
domain = updatingSoa(doc, domain);
domain = updatingNS(doc, domain);
NodeList rrList = doc.getElementsByTagName("rr");
for(int i = 0; i < rrList.getLength(); i++) {
Node n = rrList.item(i);
newResourceRecords.add(getRRFromNode(n, domain));
}
cleanResourceRecords(oldResourceRecords, newResourceRecords);
return domain;
}
private static void cleanResourceRecords(List oldResourceRecords, List newResourceRecords) {
for(ResourceRecord rr : oldResourceRecords) {
if(!newResourceRecords.contains(rr)) {
Logger.debug("removing RR: "+rr.name);
ResourceRecord.Find.byId(rr.id).delete();
}
}
}
private static Domain updatingMain(Document doc, Domain domain) {
NodeList zoneList = doc.getElementsByTagName("zone");
if(zoneList.getLength() == 1) {
NodeList elements = zoneList.item(0).getChildNodes();
for(int i = 0; i < elements.getLength(); i++) {
switch(elements.item(i).getNodeName().toLowerCase()) {
case "main":
Node n = elements.item(i);
for(int j = 0; j < n.getChildNodes().getLength(); j++) {
if("value".equals( n.getChildNodes().item(j).getNodeName())) {
domain.ip = n.getChildNodes().item(0).getTextContent();
}
}
break;
}
}
}
return domain;
}
private static Domain updatingSoa(Document doc, Domain domain) {
NodeList soaList = doc.getElementsByTagName("soa");
if(soaList.getLength() > 0) {
Node soa = soaList.item(0);
NodeList elements = soa.getChildNodes();
for(int j = 0; j < elements.getLength(); j++) {
switch(elements.item(j).getNodeName().toLowerCase()) {
case "refresh":
domain.soaRefresh = getInteger(elements.item(j).getTextContent());
break;
case "retry":
domain.soaRetry = getInteger(elements.item(j).getTextContent());
break;
case "expire":
domain.soaExpire = getInteger(elements.item(j).getTextContent());
break;
case "ttl":
domain.soaTtl = getInteger(elements.item(j).getTextContent());
break;
case "email":
domain.soaEmail = elements.item(j).getTextContent();
break;
case "default":
domain.soaDefault = getInteger(elements.item(j).getTextContent());
break;
}
}
}
return domain;
}
private static Domain updatingNS(Document doc, Domain domain) {
NodeList nsList = doc.getElementsByTagName("nserver");
StringBuilder sb = new StringBuilder();
for(int i = 0; i < nsList.getLength(); i++) {
Node n = nsList.item(i);
NodeList elements = n.getChildNodes();
for(int j = 0; j < elements.getLength(); j++) {
if("name".equals(elements.item(j).getNodeName().toLowerCase())) {
sb.append(elements.item(j).getTextContent().trim()).append("\n");
}
}
}
domain.nameservers = sb.toString();
return domain;
}
private static ResourceRecord getRRFromNode(Node node, Domain domain) {
String name = null;
String value = null;
String type = null;
Integer ttl = null;
Integer pref = null;
ResourceRecord rr = null;
NodeList elements = node.getChildNodes();
for(int i = 0; i < elements.getLength(); i++) {
Node n = elements.item(i);
switch(n.getNodeName().toLowerCase()) {
case "name":
name = n.getTextContent();
break;
case "value":
value = n.getTextContent();
if(Ip.valid(value)) {
Ip.getOrCrate(value);
}
break;
case "type":
type = n.getTextContent();
break;
case "ttl":
ttl = getInteger(n.getTextContent());
break;
case "pref":
pref = getInteger(n.getTextContent());
break;
}
}
if(name != null && type != null && value != null) {
rr = ResourceRecord.getOrCreate(domain, name, type);
rr.value = value;
}
rr.ttl = ttl;
rr.pref = pref;
rr.save();
return rr;
}
private static Integer getInteger(String value) {
try {
return Integer.parseInt(value);
} catch( NumberFormatException ex) {
Logger.error(ex.getLocalizedMessage(), ex);
}
return 0;
}
private boolean getUpdateStatus(Document doc) {
doc.getDocumentElement().normalize();
NodeList statusConfigList = doc.getElementsByTagName("status");
Node status = statusConfigList.getLength() > 0 ? statusConfigList.item(0) : null;
if(status == null) {
return false;
}
NodeList layerConfigList = status.getChildNodes();
for(int i = 0; i < layerConfigList.getLength(); i++) {
Node n = layerConfigList.item(i);
if( n.getTextContent().toLowerCase().equals("success") ) {
return true;
}
}
return false;
}
}