Sophie

Sophie

distrib > Mageia > 1 > i586 > by-pkgid > b24f4357c8479344be16703c233650c5 > files > 73

pdns-2.9.22-9.mga1.i586.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<HTML
><HEAD
><TITLE
>Read/write slave-capable backends</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK
REL="HOME"
TITLE="PowerDNS manual"
HREF="index.html"><LINK
REL="UP"
TITLE="Backend writers' guide"
HREF="backend-writers-guide.html"><LINK
REL="PREVIOUS"
TITLE="Declaring and reading configuration details"
HREF="backend-configuration-details.html"><LINK
REL="NEXT"
TITLE="Read/write master-capable backends"
HREF="master-backends.html"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
SUMMARY="Header navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>PowerDNS manual</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="backend-configuration-details.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Appendix C. Backend writers' guide</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="master-backends.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="RW-BACKENDS"
>C.4. Read/write slave-capable backends</A
></H1
><P
>	The backends above are 'natively capable' in that they contain all data relevant for a domain and do not pull in data from other nameservers.
	To enable storage of information, a backend must be able to do more.
      </P
><P
>	Before diving into the details of the implementation some theory is in order. Slave domains are pulled from the master. PDNS needs to 
	know for which domains it is to be a slave, and for each slave domain, what the IP address of the master is.
      </P
><P
>	A slave zone is pulled from a master, after which it is 'fresh', but this is only temporary. In the SOA record of a zone there is a field
	which specifies the 'refresh' interval. After that interval has elapsed, the slave nameserver needs to check at the master ff the serial
	number there is higher than what is stored in the backend locally.
      </P
><P
>	If this is the case, PDNS dubs the domain 'stale', and schedules a transfer of data from the remote. This transfer remains scheduled
	until the serial numbers remote and locally are identical again.
      </P
><P
>	This theory is implemented by the <CODE
CLASS="FUNCTION"
>getUnfreshSlaveInfos</CODE
> method, which is called on all backends periodically. 
	This method fills a vector of <B
CLASS="COMMAND"
>SlaveDomain</B
>s with domains that are unfresh and possibly stale. 
      </P
><P
>	PDNS then retrieves the SOA of those domains remotely and locally and creates a list of stale domains. For each of these domains, PDNS
	starts a zonetransfer to resynchronise. Because zone transfers can fail, it is important that the interface to the backend allows
	for transaction semantics because a zone might otherwise be left in a halfway updated situation.
      </P
><P
>	The following excerpt from the DNSBackend shows the relevant functions:
      </P
><P
>	<PRE
CLASS="PROGRAMLISTING"
>	  class DNSBackend {
	  public:
           /* ... */
           virtual bool getDomainInfo(const string &amp;domain, DomainInfo &amp;di);
	   virtual bool isMaster(const string &amp;name, const string &amp;ip);
	   virtual bool startTransaction(const string &amp;qname, int id);
	   virtual bool commitTransaction();
	   virtual bool abortTransaction();
	   virtual bool feedRecord(const DNSResourceRecord &amp;rr);
	   virtual void getUnfreshSlaveInfos(vector&lt;DomainInfo&gt;* domains);
	   virtual void setFresh(int id);
           /* ... */
	 }
	</PRE
>
      </P
><P
>        The mentioned DomainInfo struct looks like this:
	<DIV
CLASS="TABLE"
><A
NAME="AEN5828"
></A
><P
><B
>Table C-3. DomainInfo struct</B
></P
><TABLE
BORDER="1"
CLASS="CALSTABLE"
><COL><COL><TBODY
><TR
><TD
>int id</TD
><TD
>ID of this zone within this backend</TD
></TR
><TR
><TD
>string master</TD
><TD
>IP address of the master of this domain, if any</TD
></TR
><TR
><TD
>u_int32_t serial</TD
><TD
>Serial number of this zone</TD
></TR
><TR
><TD
>u_int32_t notified_serial</TD
><TD
>Last serial number of this zone that slaves have seen</TD
></TR
><TR
><TD
>time_t last_check</TD
><TD
>Last time this zone was checked over at the master for changes</TD
></TR
><TR
><TD
>enum {Master,Slave,Native} kind</TD
><TD
>Type of zone</TD
></TR
><TR
><TD
>DNSBackend *backend</TD
><TD
>Pointer to the backend that feels authoritative for a domain and can act as a slave</TD
></TR
></TBODY
></TABLE
></DIV
>
      </P
><P
>	These functions all have a default implementation that returns false - which explains that these methods can be omitted in simple backends. 
	Furthermore, unlike with simple backends, a slave capable backend must make sure that the 'DNSBackend *db' field of the SOAData record is filled 
	out correctly - it is used to determine which backend will house this zone. 
	<P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>bool isMaster(const string &amp;name, const string &amp;ip);</DT
><DD
><P
>		If a backend considers itself a slave for the domain <B
CLASS="COMMAND"
>name</B
> and if the IP address in <B
CLASS="COMMAND"
>ip</B
>
		is indeed a master, it should return true. False otherwise. This is a first line of checks to guard against reloading a domain
		unnecessarily.
	      </P
></DD
><DT
>void getUnfreshSlaveInfos(vector&lt;DomainInfo&gt;* domains)</DT
><DD
><P
>		When called, the backend should examine its list of slave domains and add any unfresh ones to the domains vector.
	      </P
></DD
><DT
>bool getDomainInfo(const string &amp;name, DomainInfo &amp; di)</DT
><DD
><P
>                This is like getUnfreshSlaveInfos, but for a specific domain. If the backend considers itself authoritative for the named
                zone, <CODE
CLASS="FUNCTION"
>di</CODE
> should be filled out, and 'true' be returned. Otherwise return false.
	      </P
></DD
><DT
>bool startTransaction(const string &amp;qname, int id)</DT
><DD
><P
>		When called, the backend should start a transaction that can be committed or rolled back atomically later on. 
		In SQL terms, this function should <B
CLASS="COMMAND"
>BEGIN</B
> a transaction and <B
CLASS="COMMAND"
>DELETE</B
> all
		records.
	      </P
></DD
><DT
>bool feedRecord(const DNSResourceRecord &amp;rr)</DT
><DD
><P
>		Insert this record.
	      </P
></DD
><DT
>bool commitTransaction();</DT
><DD
><P
>		Make the changes effective. In SQL terms, execute <B
CLASS="COMMAND"
>COMMIT</B
>.
	      </P
></DD
><DT
>bool abortTransaction();</DT
><DD
><P
>		Abort changes. In SQL terms, execute <B
CLASS="COMMAND"
>ABORT</B
>.
	      </P
></DD
><DT
>bool setFresh()</DT
><DD
><P
>		Indicate that a domain has either been updated or refreshed without the need for a retransfer. This causes
		the domain to vanish from the vector modified by <CODE
CLASS="FUNCTION"
>getUnfreshSlaveInfos()</CODE
>.
	      </P
></DD
></DL
></DIV
>
      </P
><P
>	PDNS will always call <CODE
CLASS="FUNCTION"
>startTransaction()</CODE
> before making calls to <CODE
CLASS="FUNCTION"
>feedRecord()</CODE
>.
	Although it is likely that <CODE
CLASS="FUNCTION"
>abortTransaction()</CODE
> will be called in case of problems, backends should also
	be prepared to abort from their destructor.
      </P
><P
>	The actual code in PDNS is currently (1.99.9):
	<PRE
CLASS="PROGRAMLISTING"
>    Resolver resolver;
    resolver.axfr(remote,domain.c_str());

    db-&#62;startTransaction(domain, domain_id);
    
    L&lt;&lt;Logger::Error&lt;&lt;"AXFR started for '"&lt;&lt;domain&lt;&lt;"'"&lt;&lt;endl;
    Resolver::res_t recs;
    
    while(resolver.axfrChunk(recs)) {
      for(Resolver::res_t::const_iterator i=recs.begin();i!=recs.end();++i) {
	db-&#62;feedRecord(*i);
      }
    }
    db-&#62;commitTransaction();
    db-&#62;setFresh(domain_id);
    L&lt;&lt;Logger::Error&lt;&lt;"AXFR done for '"&lt;&lt;domain&lt;&lt;"'"&lt;&lt;endl;
	</PRE
>
      </P
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="AEN5901"
>C.4.1. Supermaster/Superslave capability</A
></H2
><P
>          A backend that wants to act as a 'superslave' for a master should implement the following method:
          <PRE
CLASS="PROGRAMLISTING"
>            class DNSBackend 
            {
               virtual bool superMasterBackend(const string &amp;ip, const string &amp;domain, const vector&lt;DNSResourceRecord&gt;&amp;nsset, string *account, DNSBackend **db)
            };
          </PRE
>
          This function gets called with the IP address of the potential supermaster, the domain it is sending a notification for and the set of NS records
          for this domain at that IP address. 
        </P
><P
>          Using the supplied data, the backend needs to determine if this is a bonafide 'supernotification' which should be honoured. If it decides that it
          should, the supplied pointer to 'account' needs to be filled with the configured name of the supermaster (if accounting is desired), and the 
          db needs to be filled with a pointer to your backend.
        </P
><P
>          Supermaster/superslave is a complicated concept, if this is all unclear see <A
HREF="slave.html#SUPERMASTER"
>Section 13.2.1</A
>.
	</P
></DIV
></DIV
><DIV
CLASS="NAVFOOTER"
><HR
ALIGN="LEFT"
WIDTH="100%"><TABLE
SUMMARY="Footer navigation table"
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
><A
HREF="backend-configuration-details.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="index.html"
ACCESSKEY="H"
>Home</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><A
HREF="master-backends.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Declaring and reading configuration details</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="backend-writers-guide.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Read/write master-capable backends</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>