diff -aur dnsjava-1.2.3/org/xbill/DNS/Zone.java dnsjava-devel/org/xbill/DNS/Zone.java --- dnsjava-1.2.3/org/xbill/DNS/Zone.java Wed Mar 14 20:49:55 2001 +++ dnsjava-devel/org/xbill/DNS/Zone.java Mon Feb 11 23:31:13 2002 @@ -15,6 +15,14 @@ public class Zone extends NameSet { + private static final int FIRSTSOA = 0; + private static final int SECONDSOA = 1; + private static final int ADD = 2; + private static final int DEL = 3; + private static final int LASTSOA = 4; + private static final int DONE = 5; + private static final int AXFR = 6; + class AXFREnumeration implements Enumeration { private Enumeration znames; private Name currentName; @@ -173,6 +181,11 @@ Record rec = Record.newRecord(zone, Type.AXFR, dclass); Message query = Message.newQuery(rec); Message response = res.send(query); + + if (response.getHeader().getRcode() != Rcode.NOERROR) { + // XXX uh, oh. we fux0red up. return an error! + } + Record [] recs = response.getSectionArray(Section.ANSWER); for (int i = 0; i < recs.length; i++) { if (!recs[i].getName().subdomain(origin)) { @@ -191,6 +204,114 @@ validate(); } + /** Perform an IXFR (if possible) to update the zone. + @return false if unsuccessful, true if updated. + non-success may be because unsupported! */ + public boolean updateZone(String remote, Cache cache) + throws IOException + { + Resolver res = new SimpleResolver(remote); + Record rec = Record.newRecord(origin, Type.IXFR, dclass); + Message query = Message.newQuery(rec); + query.addRecord(getSOA(), Section.AUTHORITY); + Message response = res.send(query); + + if (response.getHeader().getRcode() == Rcode.NOTIMPL) { + // IXFR not supported. try again as an AXFR. + rec = Record.newRecord(origin, Type.AXFR, dclass); + query = Message.newQuery(rec); + response = res.send(query); + } + + if (response.getHeader().getRcode() != Rcode.NOERROR) + return false; // uh, oh. we fux0red up. return an error! + + // XXX what about other errors? permission, etc? + + Record [] recs = response.getSectionArray(Section.ANSWER); + + // check for UDP overflow. + if ((response.getHeader().getFlag(Flags.TC) == true) || + ((recs.length == 1) && (recs[0].getType() == Type.SOA))) { + SOARecord r = (SOARecord) recs[0]; + return (r.getSerial() <= getSOA().getSerial()); + // if >, then it needs updating. otherwise we're okay. + } + + SOARecord oldSOA = getSOA(); + SOARecord newSOA = null; + + int state = FIRSTSOA; + + // we're getting a successful IXFR! + for (int i = 0; i < recs.length; i++) { + if (!recs[i].getName().subdomain(origin)) { + if (Options.check("verbose")) + System.err.println(recs[i].getName() + + "is not in zone " + origin); + continue; + } + + // now for the state machine. + switch(state) { + case FIRSTSOA: { + newSOA = (SOARecord) recs[i]; + state = SECONDSOA; + break; + } + case SECONDSOA: { + Record r = recs[i]; + if (! (r instanceof SOARecord)) { + clear(); + addRecord(r); + state = AXFR; + } else { + state = DEL; + deleteRecord(r); + } + } + case DEL: { + Record r = recs[i]; + if (r instanceof SOARecord) { + state = ADD; + addRecord(r); + } else { + deleteRecord(r); + } + } + case ADD: { + Record r = recs[i]; + if (r instanceof SOARecord) { + SOARecord x = (SOARecord) r; + if (x.getSerial() == newSOA.getSerial()) { + addRecord(r); + state = DONE; + } else { + state = DEL; + deleteRecord(r); + } + } else { + addRecord(r); + } + } + case AXFR: { + Record r = recs[i]; + addRecord(r); + } + case DONE: { + // XXX wtF? nothing should get here. + } + } // end switch + } + if (cache != null) { + recs = response.getSectionArray(Section.ADDITIONAL); + for (int i = 0; i < recs.length; i++) + cache.addRecord(recs[i], Credibility.ZONE_GLUE, recs); + } + validate(); + return true; +} + /** Returns the Zone's origin */ public Name getOrigin() { @@ -326,6 +447,22 @@ rrset.addRR(r); } +/** + * Deletes a record from the Zone + * @param r The record to be deleted + * @see Record + */ +public void +deleteRecord(Record r) { + Name name = r.getName(); + short type = r.getRRsetType(); + RRset rrset = (RRset) findExactSet (name, type); + if (rrset == null) + return; + else + rrset.deleteRR(r); +} + public Enumeration AXFR() { return new AXFREnumeration();