Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

some dns fixes.

  • Loading branch information...
commit 5e6680108c0b8a7541e0871a99c9d76b346a4d3f 1 parent 53fc754
Neil authored
View
2  clc/modules/core/src/main/java/com/eucalyptus/util/WalrusProperties.java
@@ -49,7 +49,7 @@
public static final String SERVICE_NAME = "Walrus";
public static final String VIRTUAL_SUBDOMAIN = "I_R_Bukkit";
- public static String WALRUS_DOMAIN = "walrus.darkness";
+ public static String WALRUS_DOMAIN = "walrus.localhost";
public static String WALRUS_IP = "127.0.0.1";
public static final long G = 1024*1024*1024;
public static final long M = 1024*1024;
View
26 clc/modules/dns/src/main/java/com/eucalyptus/cloud/ws/ConnectionHandler.java
@@ -39,8 +39,6 @@
package com.eucalyptus.cloud.ws;
-import org.xbill.DNS.*;
-
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
@@ -48,6 +46,30 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import org.xbill.DNS.CNAMERecord;
+import org.xbill.DNS.Credibility;
+import org.xbill.DNS.DClass;
+import org.xbill.DNS.DNAMERecord;
+import org.xbill.DNS.ExtendedFlags;
+import org.xbill.DNS.Flags;
+import org.xbill.DNS.Header;
+import org.xbill.DNS.Message;
+import org.xbill.DNS.Name;
+import org.xbill.DNS.NameTooLongException;
+import org.xbill.DNS.OPTRecord;
+import org.xbill.DNS.Opcode;
+import org.xbill.DNS.RRset;
+import org.xbill.DNS.Rcode;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.Section;
+import org.xbill.DNS.TSIG;
+import org.xbill.DNS.TSIGRecord;
+import org.xbill.DNS.Type;
+
+import com.eucalyptus.dns.SetResponse;
+import com.eucalyptus.dns.Zone;
+import com.eucalyptus.dns.Cache;
+
public class ConnectionHandler extends Thread {
static final int FLAG_DNSSECOK = 1;
View
28 clc/modules/dns/src/main/java/com/eucalyptus/cloud/ws/ZoneManager.java
@@ -39,8 +39,17 @@
import edu.ucsb.eucalyptus.cloud.entities.*;
import org.apache.log4j.Logger;
-import org.xbill.DNS.*;
+import com.eucalyptus.dns.Zone;
import org.xbill.DNS.Address;
+import org.xbill.DNS.CNAMERecord;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.RRset;
+import org.xbill.DNS.DClass;
+import org.xbill.DNS.SOARecord;
+import org.xbill.DNS.ARecord;
+import org.xbill.DNS.Name;
+import org.xbill.DNS.NSRecord;
+import org.xbill.DNS.Type;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
@@ -163,12 +172,15 @@ public static void updateARecord(String zoneName, ARecord record) {
Zone zone = getZone(zoneName);
RRset rrSet = zone.findExactMatch(record.getName(), record.getDClass());
Iterator<Record> rrIterator = rrSet.rrs();
+ Record recordToRemove = null;
while(rrIterator.hasNext()) {
Record rec = rrIterator.next();
if(rec.getName().equals(record.getName())) {
- zone.removeRecord(rec);
+ recordToRemove = rec;
}
}
+ if(recordToRemove != null)
+ zone.removeRecord(recordToRemove);
zone.addRecord(record);
//now change the persistent store
EntityWrapper<ARecordInfo> db = new EntityWrapper<ARecordInfo>();
@@ -192,12 +204,15 @@ public static void updateCNAMERecord(String zoneName, CNAMERecord record) {
Zone zone = getZone(zoneName);
RRset rrSet = zone.findExactMatch(record.getName(), record.getDClass());
Iterator<Record> rrIterator = rrSet.rrs();
+ Record recordToRemove = null;
while(rrIterator.hasNext()) {
Record rec = rrIterator.next();
if(rec.getName().equals(record.getName())) {
- zone.removeRecord(rec);
+ recordToRemove = rec;
}
}
+ if(recordToRemove != null)
+ zone.removeRecord(recordToRemove);
zone.addRecord(record);
//now change the persistent store
EntityWrapper<CNAMERecordInfo> db = new EntityWrapper<CNAMERecordInfo>();
@@ -220,12 +235,15 @@ public static void deleteRecord(String zoneName, Record record) {
Zone zone = getZone(zoneName);
RRset rrSet = zone.findExactMatch(record.getName(), record.getDClass());
Iterator<Record> rrIterator = rrSet.rrs();
+ Record recordToRemove = null;
while(rrIterator.hasNext()) {
Record rec = rrIterator.next();
if(rec.getName().equals(record.getName())) {
- zone.removeRecord(rec);
+ recordToRemove = rec;
}
}
+ if(recordToRemove != null)
+ zone.removeRecord(recordToRemove);
} catch(Exception ex) {
LOG.error(ex);
}
@@ -235,4 +253,4 @@ public static void deleteZone(String zoneName) {
zones.remove(zoneName);
}
-}
+}
View
865 clc/modules/dns/src/main/java/com/eucalyptus/dns/Cache.java
@@ -0,0 +1,865 @@
+// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
+
+package com.eucalyptus.dns;
+
+import java.io.*;
+import java.util.*;
+
+import org.xbill.DNS.CNAMERecord;
+import org.xbill.DNS.Credibility;
+import org.xbill.DNS.DClass;
+import org.xbill.DNS.DNAMERecord;
+import org.xbill.DNS.Flags;
+import org.xbill.DNS.Master;
+import org.xbill.DNS.Message;
+import org.xbill.DNS.Name;
+import org.xbill.DNS.NameTooLongException;
+import org.xbill.DNS.Options;
+import org.xbill.DNS.RRset;
+import org.xbill.DNS.Rcode;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.SOARecord;
+import org.xbill.DNS.Section;
+import org.xbill.DNS.Type;
+
+/**
+ * A cache of DNS records. The cache obeys TTLs, so items are purged after
+ * their validity period is complete. Negative answers are cached, to
+ * avoid repeated failed DNS queries. The credibility of each RRset is
+ * maintained, so that more credible records replace less credible records,
+ * and lookups can specify the minimum credibility of data they are requesting.
+ * @see RRset
+ * @see Credibility
+ *
+ * @author Brian Wellington
+ */
+
+public class Cache {
+
+private interface Element {
+ public boolean expired();
+ public int compareCredibility(int cred);
+ public int getType();
+}
+
+private static int
+limitExpire(long ttl, long maxttl) {
+ if (maxttl >= 0 && maxttl < ttl)
+ ttl = maxttl;
+ int expire = (int)((System.currentTimeMillis() / 1000) + ttl);
+ if (expire < 0 || expire > Integer.MAX_VALUE)
+ return Integer.MAX_VALUE;
+ return expire;
+}
+
+private static class CacheRRset extends RRset implements Element {
+ int credibility;
+ int expire;
+
+ public
+ CacheRRset(Record rec, int cred, long maxttl) {
+ super();
+ this.credibility = cred;
+ this.expire = limitExpire(rec.getTTL(), maxttl);
+ addRR(rec);
+ }
+
+ public
+ CacheRRset(RRset rrset, int cred, long maxttl) {
+ super(rrset);
+ this.credibility = cred;
+ this.expire = limitExpire(rrset.getTTL(), maxttl);
+ }
+
+ public final boolean
+ expired() {
+ int now = (int)(System.currentTimeMillis() / 1000);
+ return (now >= expire);
+ }
+
+ public final int
+ compareCredibility(int cred) {
+ return credibility - cred;
+ }
+
+ public String
+ toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append(super.toString());
+ sb.append(" cl = ");
+ sb.append(credibility);
+ return sb.toString();
+ }
+}
+
+private static class NegativeElement implements Element {
+ int type;
+ Name name;
+ SOARecord soa;
+ int credibility;
+ int expire;
+
+ public
+ NegativeElement(Name name, int type, SOARecord soa, int cred,
+ long maxttl)
+ {
+ this.name = name;
+ this.type = type;
+ this.soa = soa;
+ long cttl = 0;
+ if (soa != null)
+ cttl = soa.getMinimum();
+ this.credibility = cred;
+ this.expire = limitExpire(cttl, maxttl);
+ }
+
+ public int
+ getType() {
+ return type;
+ }
+
+ public final boolean
+ expired() {
+ int now = (int)(System.currentTimeMillis() / 1000);
+ return (now >= expire);
+ }
+
+ public final int
+ compareCredibility(int cred) {
+ return credibility - cred;
+ }
+
+ public String
+ toString() {
+ StringBuffer sb = new StringBuffer();
+ if (type == 0)
+ sb.append("NXDOMAIN " + name);
+ else
+ sb.append("NXRRSET " + name + " " + Type.string(type));
+ sb.append(" cl = ");
+ sb.append(credibility);
+ return sb.toString();
+ }
+}
+
+private static class CacheMap extends LinkedHashMap {
+ private int maxsize = -1;
+
+ CacheMap(int maxsize) {
+ super(16, (float) 0.75, true);
+ this.maxsize = maxsize;
+ }
+
+ int
+ getMaxSize() {
+ return maxsize;
+ }
+
+ void
+ setMaxSize(int maxsize) {
+ /*
+ * Note that this doesn't shrink the size of the map if
+ * the maximum size is lowered, but it should shrink as
+ * entries expire.
+ */
+ this.maxsize = maxsize;
+ }
+
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return maxsize >= 0 && size() > maxsize;
+ }
+}
+
+private CacheMap data;
+private int maxncache = -1;
+private int maxcache = -1;
+private int dclass;
+
+private static final int defaultMaxEntries = 50000;
+
+/**
+ * Creates an empty Cache
+ *
+ * @param dclass The DNS class of this cache
+ * @see DClass
+ */
+public
+Cache(int dclass) {
+ this.dclass = dclass;
+ data = new CacheMap(defaultMaxEntries);
+}
+
+/**
+ * Creates an empty Cache for class IN.
+ * @see DClass
+ */
+public
+Cache() {
+ this(DClass.IN);
+}
+
+/**
+ * Creates a Cache which initially contains all records in the specified file.
+ */
+public
+Cache(String file) throws IOException {
+ data = new CacheMap(defaultMaxEntries);
+ Master m = new Master(file);
+ Record record;
+ while ((record = m.nextRecord()) != null)
+ addRecord(record, Credibility.HINT, m);
+}
+
+private synchronized Object
+exactName(Name name) {
+ return data.get(name);
+}
+
+private synchronized void
+removeName(Name name) {
+ data.remove(name);
+}
+
+private synchronized Element []
+allElements(Object types) {
+ if (types instanceof List) {
+ List typelist = (List) types;
+ int size = typelist.size();
+ return (Element []) typelist.toArray(new Element[size]);
+ } else {
+ Element set = (Element) types;
+ return new Element[] {set};
+ }
+}
+
+private synchronized Element
+oneElement(Name name, Object types, int type, int minCred) {
+ Element found = null;
+
+ if (type == Type.ANY)
+ throw new IllegalArgumentException("oneElement(ANY)");
+ if (types instanceof List) {
+ List list = (List) types;
+ for (int i = 0; i < list.size(); i++) {
+ Element set = (Element) list.get(i);
+ if (set.getType() == type) {
+ found = set;
+ break;
+ }
+ }
+ } else {
+ Element set = (Element) types;
+ if (set.getType() == type)
+ found = set;
+ }
+ if (found == null)
+ return null;
+ if (found.expired()) {
+ removeElement(name, type);
+ return null;
+ }
+ if (found.compareCredibility(minCred) < 0)
+ return null;
+ return found;
+}
+
+private synchronized Element
+findElement(Name name, int type, int minCred) {
+ Object types = exactName(name);
+ if (types == null)
+ return null;
+ return oneElement(name, types, type, minCred);
+}
+
+private synchronized void
+addElement(Name name, Element element) {
+ Object types = data.get(name);
+ if (types == null) {
+ data.put(name, element);
+ return;
+ }
+ int type = element.getType();
+ if (types instanceof List) {
+ List list = (List) types;
+ for (int i = 0; i < list.size(); i++) {
+ Element elt = (Element) list.get(i);
+ if (elt.getType() == type) {
+ list.set(i, element);
+ return;
+ }
+ }
+ list.add(element);
+ } else {
+ Element elt = (Element) types;
+ if (elt.getType() == type)
+ data.put(name, element);
+ else {
+ LinkedList list = new LinkedList();
+ list.add(elt);
+ list.add(element);
+ data.put(name, list);
+ }
+ }
+}
+
+private synchronized void
+removeElement(Name name, int type) {
+ Object types = data.get(name);
+ if (types == null) {
+ return;
+ }
+ if (types instanceof List) {
+ List list = (List) types;
+ for (int i = 0; i < list.size(); i++) {
+ Element elt = (Element) list.get(i);
+ if (elt.getType() == type) {
+ list.remove(i);
+ if (list.size() == 0)
+ data.remove(name);
+ return;
+ }
+ }
+ } else {
+ Element elt = (Element) types;
+ if (elt.getType() != type)
+ return;
+ data.remove(name);
+ }
+}
+
+/** Empties the Cache. */
+public synchronized void
+clearCache() {
+ data.clear();
+}
+
+/**
+ * Adds a record to the Cache.
+ * @param r The record to be added
+ * @param cred The credibility of the record
+ * @param o The source of the record (this could be a Message, for example)
+ * @see Record
+ */
+public synchronized void
+addRecord(Record r, int cred, Object o) {
+ Name name = r.getName();
+ int type = r.getRRsetType();
+ if (!Type.isRR(type))
+ return;
+ Element element = findElement(name, type, cred);
+ if (element == null) {
+ CacheRRset crrset = new CacheRRset(r, cred, maxcache);
+ addRRset(crrset, cred);
+ } else if (element.compareCredibility(cred) == 0) {
+ if (element instanceof CacheRRset) {
+ CacheRRset crrset = (CacheRRset) element;
+ crrset.addRR(r);
+ }
+ }
+}
+
+/**
+ * Adds an RRset to the Cache.
+ * @param rrset The RRset to be added
+ * @param cred The credibility of these records
+ * @see RRset
+ */
+public synchronized void
+addRRset(RRset rrset, int cred) {
+ long ttl = rrset.getTTL();
+ Name name = rrset.getName();
+ int type = rrset.getType();
+ Element element = findElement(name, type, 0);
+ if (ttl == 0) {
+ if (element != null && element.compareCredibility(cred) <= 0)
+ removeElement(name, type);
+ } else {
+ if (element != null && element.compareCredibility(cred) <= 0)
+ element = null;
+ if (element == null) {
+ CacheRRset crrset;
+ if (rrset instanceof CacheRRset)
+ crrset = (CacheRRset) rrset;
+ else
+ crrset = new CacheRRset(rrset, cred, maxcache);
+ addElement(name, crrset);
+ }
+ }
+}
+
+/**
+ * Adds a negative entry to the Cache.
+ * @param name The name of the negative entry
+ * @param type The type of the negative entry
+ * @param soa The SOA record to add to the negative cache entry, or null.
+ * The negative cache ttl is derived from the SOA.
+ * @param cred The credibility of the negative entry
+ */
+public synchronized void
+addNegative(Name name, int type, SOARecord soa, int cred) {
+ long ttl = 0;
+ if (soa != null)
+ ttl = soa.getTTL();
+ Element element = findElement(name, type, 0);
+ if (ttl == 0) {
+ if (element != null && element.compareCredibility(cred) <= 0)
+ removeElement(name, type);
+ } else {
+ if (element != null && element.compareCredibility(cred) <= 0)
+ element = null;
+ if (element == null)
+ addElement(name, new NegativeElement(name, type,
+ soa, cred,
+ maxncache));
+ }
+}
+
+/**
+ * Finds all matching sets or something that causes the lookup to stop.
+ */
+protected synchronized SetResponse
+lookup(Name name, int type, int minCred) {
+ int labels;
+ int tlabels;
+ Element element;
+ Name tname;
+ Object types;
+ SetResponse sr;
+
+ labels = name.labels();
+
+ for (tlabels = labels; tlabels >= 1; tlabels--) {
+ boolean isRoot = (tlabels == 1);
+ boolean isExact = (tlabels == labels);
+
+ if (isRoot)
+ tname = Name.root;
+ else if (isExact)
+ tname = name;
+ else
+ tname = new Name(name, labels - tlabels);
+
+ types = data.get(tname);
+ if (types == null)
+ continue;
+
+ /* If this is an ANY lookup, return everything. */
+ if (isExact && type == Type.ANY) {
+ sr = new SetResponse(SetResponse.SUCCESSFUL);
+ Element [] elements = allElements(types);
+ int added = 0;
+ for (int i = 0; i < elements.length; i++) {
+ element = elements[i];
+ if (element.expired()) {
+ removeElement(tname, element.getType());
+ continue;
+ }
+ if (!(element instanceof CacheRRset))
+ continue;
+ if (element.compareCredibility(minCred) < 0)
+ continue;
+ sr.addRRset((CacheRRset)element);
+ added++;
+ }
+ /* There were positive entries */
+ if (added > 0)
+ return sr;
+ }
+
+ /*
+ * If this is the name, look for the actual type or a CNAME.
+ * Otherwise, look for a DNAME.
+ */
+ if (isExact) {
+ element = oneElement(tname, types, type, minCred);
+ if (element != null &&
+ element instanceof CacheRRset)
+ {
+ sr = new SetResponse(SetResponse.SUCCESSFUL);
+ sr.addRRset((CacheRRset) element);
+ return sr;
+ } else if (element != null) {
+ sr = new SetResponse(SetResponse.NXRRSET);
+ return sr;
+ }
+
+ element = oneElement(tname, types, Type.CNAME, minCred);
+ if (element != null &&
+ element instanceof CacheRRset)
+ {
+ return new SetResponse(SetResponse.CNAME,
+ (CacheRRset) element);
+ }
+ } else {
+ element = oneElement(tname, types, Type.DNAME, minCred);
+ if (element != null &&
+ element instanceof CacheRRset)
+ {
+ return new SetResponse(SetResponse.DNAME,
+ (CacheRRset) element);
+ }
+ }
+
+ /* Look for an NS */
+ element = oneElement(tname, types, Type.NS, minCred);
+ if (element != null && element instanceof CacheRRset)
+ return new SetResponse(SetResponse.DELEGATION,
+ (CacheRRset) element);
+
+ /* Check for the special NXDOMAIN element. */
+ if (isExact) {
+ element = oneElement(tname, types, 0, minCred);
+ if (element != null)
+ return SetResponse.ofType(SetResponse.NXDOMAIN);
+ }
+
+ }
+ return SetResponse.ofType(SetResponse.UNKNOWN);
+}
+
+/**
+ * Looks up Records in the Cache. This follows CNAMEs and handles negatively
+ * cached data.
+ * @param name The name to look up
+ * @param type The type to look up
+ * @param minCred The minimum acceptable credibility
+ * @return A SetResponse object
+ * @see SetResponse
+ * @see Credibility
+ */
+public SetResponse
+lookupRecords(Name name, int type, int minCred) {
+ return lookup(name, type, minCred);
+}
+
+private RRset []
+findRecords(Name name, int type, int minCred) {
+ SetResponse cr = lookupRecords(name, type, minCred);
+ if (cr.isSuccessful())
+ return cr.answers();
+ else
+ return null;
+}
+
+/**
+ * Looks up credible Records in the Cache (a wrapper around lookupRecords).
+ * Unlike lookupRecords, this given no indication of why failure occurred.
+ * @param name The name to look up
+ * @param type The type to look up
+ * @return An array of RRsets, or null
+ * @see Credibility
+ */
+public RRset []
+findRecords(Name name, int type) {
+ return findRecords(name, type, Credibility.NORMAL);
+}
+
+/**
+ * Looks up Records in the Cache (a wrapper around lookupRecords). Unlike
+ * lookupRecords, this given no indication of why failure occurred.
+ * @param name The name to look up
+ * @param type The type to look up
+ * @return An array of RRsets, or null
+ * @see Credibility
+ */
+public RRset []
+findAnyRecords(Name name, int type) {
+ return findRecords(name, type, Credibility.GLUE);
+}
+
+private final int
+getCred(int section, boolean isAuth) {
+ if (section == Section.ANSWER) {
+ if (isAuth)
+ return Credibility.AUTH_ANSWER;
+ else
+ return Credibility.NONAUTH_ANSWER;
+ } else if (section == Section.AUTHORITY) {
+ if (isAuth)
+ return Credibility.AUTH_AUTHORITY;
+ else
+ return Credibility.NONAUTH_AUTHORITY;
+ } else if (section == Section.ADDITIONAL) {
+ return Credibility.ADDITIONAL;
+ } else
+ throw new IllegalArgumentException("getCred: invalid section");
+}
+
+private static void
+markAdditional(RRset rrset, Set names) {
+ Record first = rrset.first();
+ if (first.getAdditionalName() == null)
+ return;
+
+ Iterator it = rrset.rrs();
+ while (it.hasNext()) {
+ Record r = (Record) it.next();
+ Name name = r.getAdditionalName();
+ if (name != null)
+ names.add(name);
+ }
+}
+
+/**
+ * Adds all data from a Message into the Cache. Each record is added with
+ * the appropriate credibility, and negative answers are cached as such.
+ * @param in The Message to be added
+ * @return A SetResponse that reflects what would be returned from a cache
+ * lookup, or null if nothing useful could be cached from the message.
+ * @see Message
+ */
+public SetResponse
+addMessage(Message in) {
+ boolean isAuth = in.getHeader().getFlag(Flags.AA);
+ Record question = in.getQuestion();
+ Name qname;
+ Name curname;
+ int qtype;
+ int qclass;
+ int cred;
+ int rcode = in.getHeader().getRcode();
+ boolean completed = false;
+ RRset [] answers, auth, addl;
+ SetResponse response = null;
+ boolean verbose = Options.check("verbosecache");
+ HashSet additionalNames;
+
+ if ((rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN) ||
+ question == null)
+ return null;
+
+ qname = question.getName();
+ qtype = question.getType();
+ qclass = question.getDClass();
+
+ curname = qname;
+
+ additionalNames = new HashSet();
+
+ answers = in.getSectionRRsets(Section.ANSWER);
+ for (int i = 0; i < answers.length; i++) {
+ if (answers[i].getDClass() != qclass)
+ continue;
+ int type = answers[i].getType();
+ Name name = answers[i].getName();
+ cred = getCred(Section.ANSWER, isAuth);
+ if ((type == qtype || qtype == Type.ANY) &&
+ name.equals(curname))
+ {
+ addRRset(answers[i], cred);
+ completed = true;
+ if (curname == qname) {
+ if (response == null)
+ response = new SetResponse(
+ SetResponse.SUCCESSFUL);
+ response.addRRset(answers[i]);
+ }
+ markAdditional(answers[i], additionalNames);
+ } else if (type == Type.CNAME && name.equals(curname)) {
+ CNAMERecord cname;
+ addRRset(answers[i], cred);
+ if (curname == qname)
+ response = new SetResponse(SetResponse.CNAME,
+ answers[i]);
+ cname = (CNAMERecord) answers[i].first();
+ curname = cname.getTarget();
+ } else if (type == Type.DNAME && curname.subdomain(name)) {
+ DNAMERecord dname;
+ addRRset(answers[i], cred);
+ if (curname == qname)
+ response = new SetResponse(SetResponse.DNAME,
+ answers[i]);
+ dname = (DNAMERecord) answers[i].first();
+ try {
+ curname = curname.fromDNAME(dname);
+ }
+ catch (NameTooLongException e) {
+ break;
+ }
+ }
+ }
+
+ auth = in.getSectionRRsets(Section.AUTHORITY);
+ RRset soa = null, ns = null;
+ for (int i = 0; i < auth.length; i++) {
+ if (auth[i].getType() == Type.SOA &&
+ curname.subdomain(auth[i].getName()))
+ soa = auth[i];
+ else if (auth[i].getType() == Type.NS &&
+ curname.subdomain(auth[i].getName()))
+ ns = auth[i];
+ }
+ if (!completed) {
+ /* This is a negative response or a referral. */
+ int cachetype = (rcode == Rcode.NXDOMAIN) ? 0 : qtype;
+ if (rcode == Rcode.NXDOMAIN || soa != null || ns == null) {
+ /* Negative response */
+ cred = getCred(Section.AUTHORITY, isAuth);
+ SOARecord soarec = null;
+ if (soa != null)
+ soarec = (SOARecord) soa.first();
+ addNegative(curname, cachetype, soarec, cred);
+ if (response == null) {
+ int responseType;
+ if (rcode == Rcode.NXDOMAIN)
+ responseType = SetResponse.NXDOMAIN;
+ else
+ responseType = SetResponse.NXRRSET;
+ response = SetResponse.ofType(responseType);
+ }
+ /* DNSSEC records are not cached. */
+ } else {
+ /* Referral response */
+ cred = getCred(Section.AUTHORITY, isAuth);
+ addRRset(ns, cred);
+ markAdditional(ns, additionalNames);
+ if (response == null)
+ response = new SetResponse(
+ SetResponse.DELEGATION,
+ ns);
+ }
+ } else if (rcode == Rcode.NOERROR && ns != null) {
+ /* Cache the NS set from a positive response. */
+ cred = getCred(Section.AUTHORITY, isAuth);
+ addRRset(ns, cred);
+ markAdditional(ns, additionalNames);
+ }
+
+ addl = in.getSectionRRsets(Section.ADDITIONAL);
+ for (int i = 0; i < addl.length; i++) {
+ int type = addl[i].getType();
+ if (type != Type.A && type != Type.AAAA && type != Type.A6)
+ continue;
+ Name name = addl[i].getName();
+ if (!additionalNames.contains(name))
+ continue;
+ cred = getCred(Section.ADDITIONAL, isAuth);
+ addRRset(addl[i], cred);
+ }
+ if (verbose)
+ System.out.println("addMessage: " + response);
+ return (response);
+}
+
+/**
+ * Flushes an RRset from the cache
+ * @param name The name of the records to be flushed
+ * @param type The type of the records to be flushed
+ * @see RRset
+ */
+public void
+flushSet(Name name, int type) {
+ removeElement(name, type);
+}
+
+/**
+ * Flushes all RRsets with a given name from the cache
+ * @param name The name of the records to be flushed
+ * @see RRset
+ */
+public void
+flushName(Name name) {
+ removeName(name);
+}
+
+/**
+ * Sets the maximum length of time that a negative response will be stored
+ * in this Cache. A negative value disables this feature (that is, sets
+ * no limit).
+ */
+public void
+setMaxNCache(int seconds) {
+ maxncache = seconds;
+}
+
+/**
+ * Gets the maximum length of time that a negative response will be stored
+ * in this Cache. A negative value indicates no limit.
+ */
+public int
+getMaxNCache() {
+ return maxncache;
+}
+
+/**
+ * Sets the maximum length of time that records will be stored in this
+ * Cache. A negative value disables this feature (that is, sets no limit).
+ */
+public void
+setMaxCache(int seconds) {
+ maxcache = seconds;
+}
+
+/**
+ * Gets the maximum length of time that records will be stored
+ * in this Cache. A negative value indicates no limit.
+ */
+public int
+getMaxCache() {
+ return maxcache;
+}
+
+/**
+ * Gets the current number of entries in the Cache, where an entry consists
+ * of all records with a specific Name.
+ */
+public int
+getSize() {
+ return data.size();
+}
+
+/**
+ * Gets the maximum number of entries in the Cache, where an entry consists
+ * of all records with a specific Name. A negative value is treated as an
+ * infinite limit.
+ */
+public int
+getMaxEntries() {
+ return data.getMaxSize();
+}
+
+/**
+ * Sets the maximum number of entries in the Cache, where an entry consists
+ * of all records with a specific Name. A negative value is treated as an
+ * infinite limit.
+ *
+ * Note that setting this to a value lower than the current number
+ * of entries will not cause the Cache to shrink immediately.
+ *
+ * The default maximum number of entries is 50000.
+ *
+ * @param entries The maximum number of entries in the Cache.
+ */
+public void
+setMaxEntries(int entries) {
+ data.setMaxSize(entries);
+}
+
+/**
+ * Returns the DNS class of this cache.
+ */
+public int
+getDClass() {
+ return dclass;
+}
+
+/**
+ * Returns the contents of the Cache as a string.
+ */
+public String
+toString() {
+ StringBuffer sb = new StringBuffer();
+ synchronized (this) {
+ Iterator it = data.values().iterator();
+ while (it.hasNext()) {
+ Element [] elements = allElements(it.next());
+ for (int i = 0; i < elements.length; i++) {
+ sb.append(elements[i]);
+ sb.append("\n");
+ }
+ }
+ }
+ return sb.toString();
+}
+
+}
View
216 clc/modules/dns/src/main/java/com/eucalyptus/dns/SetResponse.java
@@ -0,0 +1,216 @@
+// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
+
+package com.eucalyptus.dns;
+
+import java.util.*;
+
+import org.xbill.DNS.CNAMERecord;
+import org.xbill.DNS.DNAMERecord;
+import org.xbill.DNS.Master;
+import org.xbill.DNS.RRset;
+import org.xbill.DNS.DClass;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.SOARecord;
+import org.xbill.DNS.ARecord;
+import org.xbill.DNS.Name;
+import org.xbill.DNS.NSRecord;
+import org.xbill.DNS.Type;
+import org.xbill.DNS.ZoneTransferException;
+import org.xbill.DNS.ZoneTransferIn;
+
+/**
+ * The Response from a query to Cache.lookupRecords() or Zone.findRecords()
+ * @see Cache
+ * @see Zone
+ *
+ * @author Brian Wellington
+ */
+
+public class SetResponse {
+
+/**
+ * The Cache contains no information about the requested name/type
+ */
+static final int UNKNOWN = 0;
+
+/**
+ * The Zone does not contain the requested name, or the Cache has
+ * determined that the name does not exist.
+ */
+static final int NXDOMAIN = 1;
+
+/**
+ * The Zone contains the name, but no data of the requested type,
+ * or the Cache has determined that the name exists and has no data
+ * of the requested type.
+ */
+static final int NXRRSET = 2;
+
+/**
+ * A delegation enclosing the requested name was found.
+ */
+static final int DELEGATION = 3;
+
+/**
+ * The Cache/Zone found a CNAME when looking for the name.
+ * @see CNAMERecord
+ */
+static final int CNAME = 4;
+
+/**
+ * The Cache/Zone found a DNAME when looking for the name.
+ * @see DNAMERecord
+ */
+static final int DNAME = 5;
+
+/**
+ * The Cache/Zone has successfully answered the question for the
+ * requested name/type/class.
+ */
+static final int SUCCESSFUL = 6;
+
+private static final SetResponse unknown = new SetResponse(UNKNOWN);
+private static final SetResponse nxdomain = new SetResponse(NXDOMAIN);
+private static final SetResponse nxrrset = new SetResponse(NXRRSET);
+
+private int type;
+private Object data;
+
+private
+SetResponse() {}
+
+SetResponse(int type, RRset rrset) {
+ if (type < 0 || type > 6)
+ throw new IllegalArgumentException("invalid type");
+ this.type = type;
+ this.data = rrset;
+}
+
+SetResponse(int type) {
+ if (type < 0 || type > 6)
+ throw new IllegalArgumentException("invalid type");
+ this.type = type;
+ this.data = null;
+}
+
+static SetResponse
+ofType(int type) {
+ switch (type) {
+ case UNKNOWN:
+ return unknown;
+ case NXDOMAIN:
+ return nxdomain;
+ case NXRRSET:
+ return nxrrset;
+ case DELEGATION:
+ case CNAME:
+ case DNAME:
+ case SUCCESSFUL:
+ SetResponse sr = new SetResponse();
+ sr.type = type;
+ sr.data = null;
+ return sr;
+ default:
+ throw new IllegalArgumentException("invalid type");
+ }
+}
+
+void
+addRRset(RRset rrset) {
+ if (data == null)
+ data = new ArrayList();
+ List l = (List) data;
+ l.add(rrset);
+}
+
+/** Is the answer to the query unknown? */
+public boolean
+isUnknown() {
+ return (type == UNKNOWN);
+}
+
+/** Is the answer to the query that the name does not exist? */
+public boolean
+isNXDOMAIN() {
+ return (type == NXDOMAIN);
+}
+
+/** Is the answer to the query that the name exists, but the type does not? */
+public boolean
+isNXRRSET() {
+ return (type == NXRRSET);
+}
+
+/** Is the result of the lookup that the name is below a delegation? */
+public boolean
+isDelegation() {
+ return (type == DELEGATION);
+}
+
+/** Is the result of the lookup a CNAME? */
+public boolean
+isCNAME() {
+ return (type == CNAME);
+}
+
+/** Is the result of the lookup a DNAME? */
+public boolean
+isDNAME() {
+ return (type == DNAME);
+}
+
+/** Was the query successful? */
+public boolean
+isSuccessful() {
+ return (type == SUCCESSFUL);
+}
+
+/** If the query was successful, return the answers */
+public RRset []
+answers() {
+ if (type != SUCCESSFUL)
+ return null;
+ List l = (List) data;
+ return (RRset []) l.toArray(new RRset[l.size()]);
+}
+
+/**
+ * If the query encountered a CNAME, return it.
+ */
+public CNAMERecord
+getCNAME() {
+ return (CNAMERecord)((RRset)data).first();
+}
+
+/**
+ * If the query encountered a DNAME, return it.
+ */
+public DNAMERecord
+getDNAME() {
+ return (DNAMERecord)((RRset)data).first();
+}
+
+/**
+ * If the query hit a delegation point, return the NS set.
+ */
+public RRset
+getNS() {
+ return (RRset)data;
+}
+
+/** Prints the value of the SetResponse */
+public String
+toString() {
+ switch (type) {
+ case UNKNOWN: return "unknown";
+ case NXDOMAIN: return "NXDOMAIN";
+ case NXRRSET: return "NXRRSET";
+ case DELEGATION: return "delegation: " + data;
+ case CNAME: return "CNAME: " + data;
+ case DNAME: return "DNAME: " + data;
+ case SUCCESSFUL: return "successful";
+ default: return null;
+ }
+}
+
+}
View
567 clc/modules/dns/src/main/java/com/eucalyptus/dns/Zone.java
@@ -0,0 +1,567 @@
+// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
+
+package com.eucalyptus.dns;
+
+import java.io.*;
+import java.util.*;
+
+import org.xbill.DNS.Master;
+import org.xbill.DNS.RRset;
+import org.xbill.DNS.DClass;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.SOARecord;
+import org.xbill.DNS.ARecord;
+import org.xbill.DNS.Name;
+import org.xbill.DNS.NSRecord;
+import org.xbill.DNS.Type;
+import org.xbill.DNS.ZoneTransferException;
+import org.xbill.DNS.ZoneTransferIn;
+
+/**
+ * A DNS Zone. This encapsulates all data related to a Zone, and provides
+ * convenient lookup methods.
+ *
+ * @author Brian Wellington
+ */
+
+public class Zone {
+
+/** A primary zone */
+public static final int PRIMARY = 1;
+
+/** A secondary zone */
+public static final int SECONDARY = 2;
+
+private Map data;
+private Name origin;
+private Object originNode;
+private int dclass = DClass.IN;
+private RRset NS;
+private SOARecord SOA;
+private boolean hasWild;
+
+class ZoneIterator implements Iterator {
+ private Iterator zentries;
+ private RRset [] current;
+ private int count;
+ private boolean wantLastSOA;
+
+ ZoneIterator(boolean axfr) {
+ zentries = data.entrySet().iterator();
+ wantLastSOA = axfr;
+ RRset [] sets = allRRsets(originNode);
+ current = new RRset[sets.length];
+ for (int i = 0, j = 2; i < sets.length; i++) {
+ int type = sets[i].getType();
+ if (type == Type.SOA)
+ current[0] = sets[i];
+ else if (type == Type.NS)
+ current[1] = sets[i];
+ else
+ current[j++] = sets[i];
+ }
+ }
+
+ public boolean
+ hasNext() {
+ return (current != null || wantLastSOA);
+ }
+
+ public Object
+ next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ if (current == null && wantLastSOA) {
+ wantLastSOA = false;
+ return oneRRset(originNode, Type.SOA);
+ }
+ Object set = current[count++];
+ if (count == current.length) {
+ current = null;
+ while (zentries.hasNext()) {
+ Map.Entry entry = (Map.Entry) zentries.next();
+ if (entry.getKey().equals(origin))
+ continue;
+ RRset [] sets = allRRsets(entry.getValue());
+ if (sets.length == 0)
+ continue;
+ current = sets;
+ count = 0;
+ break;
+ }
+ }
+ return set;
+ }
+
+ public void
+ remove() {
+ throw new UnsupportedOperationException();
+ }
+}
+
+private void
+validate() throws IOException {
+ originNode = exactName(origin);
+ if (originNode == null)
+ throw new IOException(origin + ": no data specified");
+
+ RRset rrset = oneRRset(originNode, Type.SOA);
+ if (rrset == null || rrset.size() != 1)
+ throw new IOException(origin +
+ ": exactly 1 SOA must be specified");
+ Iterator it = rrset.rrs();
+ SOA = (SOARecord) it.next();
+
+ NS = oneRRset(originNode, Type.NS);
+ if (NS == null)
+ throw new IOException(origin + ": no NS set specified");
+}
+
+private final void
+maybeAddRecord(Record record) throws IOException {
+ int rtype = record.getType();
+ Name name = record.getName();
+
+ if (rtype == Type.SOA && !name.equals(origin)) {
+ throw new IOException("SOA owner " + name +
+ " does not match zone origin " +
+ origin);
+ }
+ if (name.subdomain(origin))
+ addRecord(record);
+}
+
+/**
+ * Creates a Zone from the records in the specified master file.
+ * @param zone The name of the zone.
+ * @param file The master file to read from.
+ * @see Master
+ */
+public
+Zone(Name zone, String file) throws IOException {
+ data = new HashMap();
+
+ if (zone == null)
+ throw new IllegalArgumentException("no zone name specified");
+ Master m = new Master(file, zone);
+ Record record;
+
+ origin = zone;
+ while ((record = m.nextRecord()) != null)
+ maybeAddRecord(record);
+ validate();
+}
+
+/**
+ * Creates a Zone from an array of records.
+ * @param zone The name of the zone.
+ * @param records The records to add to the zone.
+ * @see Master
+ */
+public
+Zone(Name zone, Record [] records) throws IOException {
+ data = new HashMap();
+
+ if (zone == null)
+ throw new IllegalArgumentException("no zone name specified");
+ origin = zone;
+ for (int i = 0; i < records.length; i++)
+ maybeAddRecord(records[i]);
+ validate();
+}
+
+private void
+fromXFR(ZoneTransferIn xfrin) throws IOException, ZoneTransferException {
+ data = new HashMap();
+
+ origin = xfrin.getName();
+ List records = xfrin.run();
+ for (Iterator it = records.iterator(); it.hasNext(); ) {
+ Record record = (Record) it.next();
+ maybeAddRecord(record);
+ }
+ if (!xfrin.isAXFR())
+ throw new IllegalArgumentException("zones can only be " +
+ "created from AXFRs");
+ validate();
+}
+
+/**
+ * Creates a Zone by doing the specified zone transfer.
+ * @param xfrin The incoming zone transfer to execute.
+ * @see ZoneTransferIn
+ */
+public
+Zone(ZoneTransferIn xfrin) throws IOException, ZoneTransferException {
+ fromXFR(xfrin);
+}
+
+/**
+ * Creates a Zone by performing a zone transfer to the specified host.
+ * @see ZoneTransferIn
+ */
+public
+Zone(Name zone, int dclass, String remote)
+throws IOException, ZoneTransferException
+{
+ ZoneTransferIn xfrin = ZoneTransferIn.newAXFR(zone, remote, null);
+ xfrin.setDClass(dclass);
+ fromXFR(xfrin);
+}
+
+/** Returns the Zone's origin */
+public Name
+getOrigin() {
+ return origin;
+}
+
+/** Returns the Zone origin's NS records */
+public RRset
+getNS() {
+ return NS;
+}
+
+/** Returns the Zone's SOA record */
+public SOARecord
+getSOA() {
+ return SOA;
+}
+
+/** Returns the Zone's class */
+public int
+getDClass() {
+ return dclass;
+}
+
+private synchronized Object
+exactName(Name name) {
+ return data.get(name);
+}
+
+private synchronized RRset []
+allRRsets(Object types) {
+ if (types instanceof List) {
+ List typelist = (List) types;
+ return (RRset []) typelist.toArray(new RRset[typelist.size()]);
+ } else {
+ RRset set = (RRset) types;
+ return new RRset [] {set};
+ }
+}
+
+private synchronized RRset
+oneRRset(Object types, int type) {
+ if (type == Type.ANY)
+ throw new IllegalArgumentException("oneRRset(ANY)");
+ if (types instanceof List) {
+ List list = (List) types;
+ for (int i = 0; i < list.size(); i++) {
+ RRset set = (RRset) list.get(i);
+ if (set.getType() == type)
+ return set;
+ }
+ } else {
+ RRset set = (RRset) types;
+ if (set.getType() == type)
+ return set;
+ }
+ return null;
+}
+
+private synchronized RRset
+findRRset(Name name, int type) {
+ Object types = exactName(name);
+ if (types == null)
+ return null;
+ return oneRRset(types, type);
+}
+
+private synchronized void
+addRRset(Name name, RRset rrset) {
+ if (!hasWild && name.isWild())
+ hasWild = true;
+ Object types = data.get(name);
+ if (types == null) {
+ data.put(name, rrset);
+ return;
+ }
+ int rtype = rrset.getType();
+ if (types instanceof List) {
+ List list = (List) types;
+ for (int i = 0; i < list.size(); i++) {
+ RRset set = (RRset) list.get(i);
+ if (set.getType() == rtype) {
+ list.set(i, rrset);
+ return;
+ }
+ }
+ list.add(rrset);
+ } else {
+ RRset set = (RRset) types;
+ if (set.getType() == rtype)
+ data.put(name, rrset);
+ else {
+ LinkedList list = new LinkedList();
+ list.add(set);
+ list.add(rrset);
+ data.put(name, list);
+ }
+ }
+}
+
+private synchronized void
+removeRRset(Name name, int type) {
+ Object types = data.get(name);
+ if (types == null) {
+ return;
+ }
+ if (types instanceof List) {
+ List list = (List) types;
+ for (int i = 0; i < list.size(); i++) {
+ RRset set = (RRset) list.get(i);
+ if (set.getType() == type) {
+ list.remove(i);
+ if (list.size() == 0)
+ data.remove(name);
+ return;
+ }
+ }
+ } else {
+ RRset set = (RRset) types;
+ if (set.getType() != type)
+ return;
+ data.remove(name);
+ }
+}
+
+private synchronized SetResponse
+lookup(Name name, int type) {
+ int labels;
+ int olabels;
+ int tlabels;
+ RRset rrset;
+ Name tname;
+ Object types;
+ SetResponse sr;
+
+ if (!name.subdomain(origin))
+ return SetResponse.ofType(SetResponse.NXDOMAIN);
+
+ labels = name.labels();
+ olabels = origin.labels();
+
+ for (tlabels = olabels; tlabels <= labels; tlabels++) {
+ boolean isOrigin = (tlabels == olabels);
+ boolean isExact = (tlabels == labels);
+
+ if (isOrigin)
+ tname = origin;
+ else if (isExact)
+ tname = name;
+ else
+ tname = new Name(name, labels - tlabels);
+
+ types = exactName(tname);
+ if (types == null)
+ continue;
+
+ /* If this is a delegation, return that. */
+ if (!isOrigin) {
+ RRset ns = oneRRset(types, Type.NS);
+ if (ns != null)
+ return new SetResponse(SetResponse.DELEGATION,
+ ns);
+ }
+
+ /* If this is an ANY lookup, return everything. */
+ if (isExact && type == Type.ANY) {
+ sr = new SetResponse(SetResponse.SUCCESSFUL);
+ RRset [] sets = allRRsets(types);
+ for (int i = 0; i < sets.length; i++)
+ sr.addRRset(sets[i]);
+ return sr;
+ }
+
+ /*
+ * If this is the name, look for the actual type or a CNAME.
+ * Otherwise, look for a DNAME.
+ */
+ if (isExact) {
+ rrset = oneRRset(types, type);
+ if (rrset != null) {
+ sr = new SetResponse(SetResponse.SUCCESSFUL);
+ sr.addRRset(rrset);
+ return sr;
+ }
+ rrset = oneRRset(types, Type.CNAME);
+ if (rrset != null)
+ return new SetResponse(SetResponse.CNAME,
+ rrset);
+ } else {
+ rrset = oneRRset(types, Type.DNAME);
+ if (rrset != null)
+ return new SetResponse(SetResponse.DNAME,
+ rrset);
+ }
+
+ /* We found the name, but not the type. */
+ if (isExact)
+ return SetResponse.ofType(SetResponse.NXRRSET);
+ }
+
+ if (hasWild) {
+ for (int i = 0; i < labels - olabels; i++) {
+ tname = name.wild(i + 1);
+
+ types = exactName(tname);
+ if (types == null)
+ continue;
+
+ rrset = oneRRset(types, type);
+ if (rrset != null) {
+ sr = new SetResponse(SetResponse.SUCCESSFUL);
+ sr.addRRset(rrset);
+ return sr;
+ }
+ }
+ }
+
+ return SetResponse.ofType(SetResponse.NXDOMAIN);
+}
+
+/**
+ * Looks up Records in the Zone. This follows CNAMEs and wildcards.
+ * @param name The name to look up
+ * @param type The type to look up
+ * @return A SetResponse object
+ * @see SetResponse
+ */
+public SetResponse
+findRecords(Name name, int type) {
+ return lookup(name, type);
+}
+
+/**
+ * Looks up Records in the zone, finding exact matches only.
+ * @param name The name to look up
+ * @param type The type to look up
+ * @return The matching RRset
+ * @see RRset
+ */
+public RRset
+findExactMatch(Name name, int type) {
+ Object types = exactName(name);
+ if (types == null)
+ return null;
+ return oneRRset(types, type);
+}
+
+/**
+ * Adds an RRset to the Zone
+ * @param rrset The RRset to be added
+ * @see RRset
+ */
+public void
+addRRset(RRset rrset) {
+ Name name = rrset.getName();
+ addRRset(name, rrset);
+}
+
+/**
+ * Adds a Record to the Zone
+ * @param r The record to be added
+ * @see Record
+ */
+public void
+addRecord(Record r) {
+ Name name = r.getName();
+ int rtype = r.getRRsetType();
+ synchronized (this) {
+ RRset rrset = findRRset(name, rtype);
+ if (rrset == null) {
+ rrset = new RRset(r);
+ addRRset(name, rrset);
+ } else {
+ rrset.addRR(r);
+ }
+ }
+}
+
+/**
+ * Removes a record from the Zone
+ * @param r The record to be removed
+ * @see Record
+ */
+public void
+removeRecord(Record r) {
+ Name name = r.getName();
+ int rtype = r.getRRsetType();
+ synchronized (this) {
+ RRset rrset = findRRset(name, rtype);
+ if (rrset == null)
+ return;
+ if (rrset.size() == 1 && rrset.first().equals(r))
+ removeRRset(name, rtype);
+ else
+ rrset.deleteRR(r);
+ }
+}
+
+/**
+ * Returns an Iterator over the RRsets in the zone.
+ */
+public Iterator
+iterator() {
+ return new ZoneIterator(false);
+}
+
+/**
+ * Returns an Iterator over the RRsets in the zone that can be used to
+ * construct an AXFR response. This is identical to {@link #iterator} except
+ * that the SOA is returned at the end as well as the beginning.
+ */
+public Iterator
+AXFR() {
+ return new ZoneIterator(true);
+}
+
+private void
+nodeToString(StringBuffer sb, Object node) {
+ RRset [] sets = allRRsets(node);
+ for (int i = 0; i < sets.length; i++) {
+ RRset rrset = sets[i];
+ Iterator it = rrset.rrs();
+ while (it.hasNext())
+ sb.append(it.next() + "\n");
+ it = rrset.sigs();
+ while (it.hasNext())
+ sb.append(it.next() + "\n");
+ }
+}
+
+/**
+ * Returns the contents of the Zone in master file format.
+ */
+public String
+toMasterFile() {
+ Iterator zentries = data.entrySet().iterator();
+ StringBuffer sb = new StringBuffer();
+ nodeToString(sb, originNode);
+ while (zentries.hasNext()) {
+ Map.Entry entry = (Map.Entry) zentries.next();
+ if (!origin.equals(entry.getKey()))
+ nodeToString(sb, entry.getValue());
+ }
+ return sb.toString();
+}
+
+/**
+ * Returns the contents of the Zone as a string (in master file format).
+ */
+public String
+toString() {
+ return toMasterFile();
+}
+
+}
View
2  clc/modules/msgs/src/main/java/com/eucalyptus/bootstrap/SystemBootstrapper.java
@@ -36,7 +36,7 @@ public static SystemBootstrapper getInstance( ) {
private MuleContext context;
- private SystemBootstrapper( ) {}
+ public SystemBootstrapper( ) {}
public boolean destroy( ) {
return true;
View
2  clc/modules/www/src/main/java/edu/ucsb/eucalyptus/admin/client/EucalyptusWebInterface.java
@@ -1482,7 +1482,7 @@ public void onClick(Widget sender) {
cloud_panel.add( new HTML (cloud_registration_text) );
Grid g1 = new Grid (2, 2);
g1.setWidget (0, 0, new HTML ("<b><font size=\"2\">Cloud URL:</font></b>"));
- final HTML cloudUrl = new HTML ("<font color=#666666 size=\"1\">http://"
+ final HTML cloudUrl = new HTML ("<font color=#666666 size=\"1\">https://"
+ cloudInfo.getInternalHostPort()
+ cloudInfo.getServicePath()
+ "</font>");
Please sign in to comment.
Something went wrong with that request. Please try again.