]> granicus.if.org Git - pdns/commitdiff
moar docs
authorPieter Lexis <pieter@plexis.eu>
Mon, 11 Aug 2014 22:34:03 +0000 (00:34 +0200)
committerPieter Lexis <pieter@plexis.eu>
Tue, 25 Nov 2014 19:11:10 +0000 (20:11 +0100)
12 files changed:
pdns/docs/Makefile
pdns/docs/markdown/appendix/backend-writers-guide.md
pdns/docs/markdown/appendix/compiling-powerdns.md
pdns/docs/markdown/authoritative/backend-bind.md
pdns/docs/markdown/authoritative/backend-pipe.md [new file with mode: 0644]
pdns/docs/markdown/authoritative/backend-random.md
pdns/docs/markdown/authoritative/backend-tinydns.md
pdns/docs/markdown/authoritative/fancy-records.md [new file with mode: 0644]
pdns/docs/markdown/authoritative/modes-of-operation.md
pdns/docs/markdown/authoritative/settings.md
pdns/docs/markdown/authoritative/upgrading.md
pdns/docs/mkdocs.yml

index 36682d60b44ab03a88652c01d5ba342bc1c7bd3c..72346e8f3b3789ce9e91a20aa191e57fb583d706 100644 (file)
@@ -14,7 +14,7 @@ html-new:
        rm -rf html-new
        mkdir html-new
 
-html-new/index.html: html-new markdown/**
+html-new/index.html: html-new markdown/** mkdocs.yml
        mkdocs build
 
 html/index.html: pdns-expanded.xml
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a099a9c7f4b3a05db99b164dae7c7ef30931070e 100644 (file)
@@ -0,0 +1,446 @@
+# Backend writers' guide
+PDNS backends are implemented via a simple yet powerful C++ interface. If your needs are not met by the PipeBackend, you may want to write your own. Before doing any PowerDNS development, please visit [the wiki](http://wiki.powerdns.com).
+
+A backend contains zero DNS logic. It need not look for CNAMEs, it need not return NS records unless explicitly asked for, etcetera. All DNS logic is contained within PDNS itself - backends should simply return records matching the description asked for.
+
+**Warning**: However, please note that your backend can get queries in aNy CAsE! If your database is case sensitive, like most are (with the notable exception of MySQL), you must make sure that you do find answers which differ only in case.
+
+**Warning**: PowerDNS may instantiate multiple instances of your backend, or destroy existing copies and instantiate new ones. Backend code should therefore be thread-safe with respect to its static data. Additionally, it is wise if instantiation is a fast operation, with the possible exception of the first construction.
+
+## Simple read-only native backends
+Implementing a backend consists of inheriting from the DNSBackend class. For read-only backends, which do not support slave operation, only the following methods are relevant:
+
+```
+    class DNSBackend
+    {
+    public:
+
+    virtual void lookup(const QType &qtype, const string &qdomain, DNSPacket *pkt_p=0, int zoneId=-1)=0;
+    virtual bool list(const string &target, int domain_id)=0;
+    virtual bool get(DNSResourceRecord &r)=0;
+    virtual bool getSOA(const string &name, SOAData &soadata, DNSPacket *p=0);
+    };
+```
+
+Note that the first three methods must be implemented. `getSOA()` has a useful default implementation.
+
+The semantics are simple. Each instance of your class only handles one (1) query at a time. There is no need for locking as PDNS guarantees that your backend will never be called reentrantly.
+
+**Note**: Queries for wildcard names should be answered literally, without expansion. So, if a backend gets a question for "\*.powerdns.com", it should only answer with data if there is an actual "\*.powerdns.com" name
+
+Some examples, a more formal specification is down below. A normal lookup starts like this:
+
+```
+        YourBackend yb;
+    yb.lookup(QType::CNAME,"www.powerdns.com");
+```
+
+Your class should now do everything to start this query. Perform as much preparation as possible - handling errors at this stage is better for PDNS than doing so later on. A real error should be reported by throwing an exception.
+
+PDNS will then call the `get()` method to get `DNSResourceRecord`s back. The following code illustrates a typical query:
+
+```
+    yb.lookup(QType::CNAME,"www.powerdns.com");
+
+    DNSResourceRecord rr;
+    while(yb.get(rr))
+      cout<<"Found cname pointing to '"+rr.content+"'"<<endl;
+    }
+```
+
+Each zone starts with a Start of Authority (SOA) record. This record is special so many backends will choose to implement it specially. The default `getSOA()` method performs a regular lookup on your backend to figure out the SOA, so if you have no special treatment for SOA records, where is no need to implement your own `getSOA()`.
+
+Besides direct queries, PDNS also needs to be able to list a zone, to do zone transfers for example. Each zone has an id which should be unique within the backend. To list all records belonging to a zone id, the `list()` method is used. Conveniently, the domain\_id is also available in the `SOAData` structure.
+
+The following lists the contents of a zone called "powerdns.com".
+
+```
+    SOAData sd;
+    if(!yb.getSOA("powerdns.com",sd))  // are we authoritative over powerdns.com?
+      return RCode::NotAuth;           // no
+
+    yb.list(sd.domain_id);
+    while(yb.get(rr))
+      cout<<rr.qname<<"\t IN "<<rr.qtype.getName()<<"\t"<<rr.content<<endl;
+```
+
+Please note that when so called 'fancy records' (see [Fancy records](../authoritative/fancy-records.md)) are enabled, a backend can receive wildcard lookups. These have a % as the first character of the qdomain in lookup.
+
+## A sample minimal backend
+
+This backend only knows about the host "random.powerdns.com", and furthermore, only about its A record:
+
+```
+/* FIRST PART */
+class RandomBackend : public DNSBackend
+{
+public:
+  bool list(const string &target, int id)
+  {
+    return false; // we don't support AXFR
+  }
+
+  void lookup(const QType &type, const string &qdomain, DNSPacket *p, int zoneId)
+  {
+    if(type.getCode()!=QType::A || qdomain!="random.powerdns.com")  // we only know about random.powerdns.com A
+      d_answer="";                                                  // no answer
+    else {
+      ostringstream os;
+      os<<random()%256<<"."<<random()%256<<"."<<random()%256<<"."<<random()%256;
+      d_answer=os.str();                                           // our random ip address
+    }
+  }
+
+  bool get(DNSResourceRecord &rr)
+  {
+    if(!d_answer.empty()) {
+      rr.qname="random.powerdns.com";                               // fill in details
+      rr.qtype=QType::A;                                            // A record
+      rr.ttl=86400;                                                 // 1 day
+      rr.content=d_answer;
+
+      d_answer="";                                                  // this was the last answer
+
+      return true;
+    }
+    return false;                                                   // no more data
+  }
+
+private:
+  string d_answer;
+};
+
+/* SECOND PART */
+
+class RandomFactory : public BackendFactory
+{
+public:
+  RandomFactory() : BackendFactory("random") {}
+
+  DNSBackend *make(const string &suffix)
+  {
+    return new RandomBackend();
+  }
+};
+
+/* THIRD PART */
+
+class RandomLoader
+{
+public:
+  RandomLoader()
+  {
+    BackendMakers().report(new RandomFactory);
+    L << Logger::Info << "[randombackend] This is the random backend version " VERSION " reporting" << endl;
+  }
+};
+
+static RandomLoader randomloader;
+```
+
+This simple backend can be used as an 'overlay'. In other words, it only knows about a single record, another loaded backend would have to know about the SOA and NS records and such. But nothing prevents us from loading it without another backend.
+
+The first part of the code contains the actual logic and should be pretty straightforward. The second part is a boilerplate 'factory' class which PDNS calls to create randombackend instances. Note that a 'suffix' parameter is passed. Real life backends also declare parameters for the configuration file; these get the 'suffix' appended to them. Note that the "random" in the constructor denotes the name by which the backend will be known.
+
+The third part registers the RandomFactory with PDNS. This is a simple C++ trick which makes sure that this function is called on execution of the binary or when loading the dynamic module.
+
+Please note that a RandomBackend is actually in most PDNS releases. By default it lives on random.example.com, but you can change that by setting [`random-hostname`](../authoritative/backend-random.md#random-hostname).
+
+**Note**: this simple backend neglects to handle case properly!
+
+## Interface definition
+
+### Classes
+
+#### DNSResourceRecord
+| | |
+|:--|:--|
+|QType qtype|QType of this record|
+|string qname|name of this record|
+|string content|ASCII representation of right hand side|
+|uint16\_t priority| priority of an MX record.|
+|uint32\_t ttl|Time To Live of this record|
+|int domain\_id| ID of the domain this record belongs to|
+|time\_t last\_modified| If unzero, last time\_t this record was changed|
+|bool auth| Used for DNSSEC operations. See [DNSSEC](../authoritative/dnssec.md) and more specifically the [Migration](../authoritative/dnssec.md#migration) section. It is also useful to check out the `rectifyZone()` in pdnssec.cc|
+|bool disabled|If set, this record is not to be served to DNS clients. Backends should not make these records available to PowerDNS unless indicated otherwise.|
+
+#### SOAData
+| | |
+|:--|:--|
+|string nameserver|Name of the master nameserver of this zone|
+|string hostmaster|Hostmaster of this domain. May contain an @|
+|u\_int32\_t serial|Serial number of this zone|
+|u\_int32\_t refresh|How often this zone should be refreshed|
+|u\_int32\_t retry|How often a failed zone pull should be retried.|
+|u\_int32\_t expire|If zone pulls failed for this long, retire records|
+|u\_int32\_t default\_ttl|Difficult|
+|int domain\_id|The ID of the domain within this backend. Must be filled!|
+|DNSBackend \*db|Pointer to the backend that feels authoritative for a domain and can act as a slave|
+
+### Methods
+#### `void lookup(const QType &qtype, const string &qdomain, DNSPacket *pkt=0, int zoneId=-1)`
+This function is used to initiate a straight lookup for a record of name 'qdomain' and type 'qtype'. A QType can be converted into an integer by invoking its `getCode()` method and into a string with the `getCode()`.
+
+The original question may or may not be passed in the pointer p. If it is, you can retrieve (from 1.99.11 onwards) information about who asked the question with the `getRemote(DNSPacket *)` method. Alternatively, `bool getRemote(struct sockaddr *sa, socklen_t *len)` is available.
+
+Note that **qdomain** can be of any case and that your backend should make sure it is in effect case insensitive. Furthermore, the case of the original question should be retained in answers returned by `get()`!
+
+Finally, the domain\_id might also be passed indicating that only answers from the indicated zone need apply. This can both be used as a restriction or as a possible speedup, hinting your backend where the answer might be found.
+
+If initiated successfully, as indicated by returning **true**, answers should be made available over the `get()` method.
+
+Should throw an PDNSException if an error occurred accessing the database. Returning otherwise indicates that the query was started successfully. If it is known that no data is available, no exception should be thrown! An exception indicates that the backend considers itself broken - not that no answers are available for a question.
+
+It is legal to return here, and have the first call to `get()` return false. This is interpreted as 'no data'.
+
+#### `bool list(int domain_id, bool include_disabled=false)`
+Initiates a list of the indicated domain. Records should then be made available via the `get()` method. Need not include the SOA record. If it is, PDNS will not get confused. If include\_disabled is given as true, records that are configured but should not be served to DNS clients must also be made available.
+
+Should return false if the backend does not consider itself authoritative for this zone. Should throw an PDNSException if an error occurred accessing the database. Returning true indicates that data is or should be available.
+
+#### `bool get(DNSResourceRecord &rr)`
+Request a DNSResourceRecord from a query started by `get()` of `list()`. If this functions returns **true**, **rr** has been filled with data. When it returns false, no more data is available, and **rr** does not contain new data. A backend should make sure that it either fills out all fields of the DNSResourceRecord or resets them to their default values.
+
+The qname field of the DNSResourceRecord should be filled out with the exact `qdomain` passed to lookup, preserving its case. So if a query for 'CaSe.yourdomain.com' comes in and your database contains data for 'case.yourdomain.com', the qname field of rr should contain 'CaSe.yourdomain.com'!
+
+Should throw an PDNSException in case a database error occurred.
+
+#### `bool getSOA(const string &name, SOAData &soadata)`
+If the backend considers itself authoritative over domain `name`, this method should fill out the passed **SOAData** structure and return a positive number. If the backend is functioning correctly, but does not consider itself authoritative, it should return 0. In case of errors, an PDNSException should be thrown.
+
+## Reporting errors
+To report errors, the Logger class is available which works mostly like an iostream. Example usage is as shown above in the RandomBackend. Note that it is very important that each line is ended with **endl** as your message won't be visible otherwise.
+
+To indicate the importance of an error, the standard syslog errorlevels are available. They can be set by outputting `Logger::Critical`, `Logger::Error`, `Logger::Warning`, `Logger::Notice`, `Logger::Info` or `Logger::Debug` to `L`, in descending order of graveness.
+
+## Declaring and reading configuration details
+It is highly likely that a backend needs configuration details. On launch, these parameters need to be declared with PDNS so it knows it should accept them in the configuration file and on the command line. Furthermore, they will be listed in the output of `--help`.
+
+Declaring arguments is done by implementing the member function `declareArguments()` in the factory class of your backend. PDNS will call this method after launching the backend.
+
+In the `declareArguments()` method, the function `declare()` is available. The exact definitions:
+
+### `void declareArguments(const string &suffix="")`
+This method is called to allow a backend to register configurable parameters. The suffix is the sub-name of this module. There is no need to touch this suffix, just pass it on to the declare method.
+
+### `void declare(const string &suffix, const string &param, const string &explanation, const string &value)`
+The suffix is passed to your method, and can be passed on to declare. **param** is the name of your parameter. **explanation** is what will appear in the output of --help. Furthermore, a default value can be supplied in the **value** parameter.
+
+A sample implementation:
+
+```
+        void declareArguments(const string &suffix)
+        {
+          declare(suffix,"dbname","Pdns backend database name to connect to","powerdns");
+          declare(suffix,"user","Pdns backend user to connect as","powerdns");
+          declare(suffix,"host","Pdns backend host to connect to","");
+          declare(suffix,"password","Pdns backend password to connect with","");
+        }
+```
+
+After the arguments have been declared, they can be accessed from your backend using the `mustDo()`, `getArg()` and `getArgAsNum()` methods. The are defined as follows in the DNSBackend class:
+
+### `void setArgPrefix(const string &prefix)`
+Must be called before any of the other accessing functions are used. Typical usage is '`setArgPrefix("mybackend"+suffix)`' in the constructor of a backend.
+
+### `bool mustDo(const string &key)`
+Returns true if the variable `key` is set to anything but 'no'.
+
+### `const string& getArg(const string &key)`
+Returns the exact value of a parameter.
+
+### `int getArgAsNum(const string &key)`
+Returns the numerical value of a parameter. Uses `atoi()` internally
+
+Sample usage from the BindBackend, using the [`bind-example-zones`](../authoritative/backend-bind.md#bind-example-zones) and [`bind-config`](../authoritative/backend-bind.md#bind-config) parameters.
+
+```
+  if(mustDo("example-zones")) {
+    insert(0,"www.example.com","A","192.0.2.4");
+    /* ... */
+  }
+
+  if(!getArg("config").empty()) {
+    BindParser BP;
+
+    BP.parse(getArg("config"));
+  }
+
+```
+
+## Read/write slave-capable backends
+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.
+
+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.
+
+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.
+
+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.
+
+This theory is implemented by the `getUnfreshSlaveInfos` method, which is called on all backends periodically. This method fills a vector of **SlaveDomain**s with domains that are unfresh and possibly stale.
+
+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 zone transfer 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.
+
+The following excerpt from the DNSBackend shows the relevant functions:
+
+```
+      class DNSBackend {
+      public:
+           /* ... */
+           virtual bool getDomainInfo(const string &domain, DomainInfo &di);
+       virtual bool isMaster(const string &name, const string &ip);
+       virtual bool startTransaction(const string &qname, int id);
+       virtual bool commitTransaction();
+       virtual bool abortTransaction();
+       virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername=0);
+       virtual void getUnfreshSlaveInfos(vector<DomainInfo>* domains);
+       virtual void setFresh(uint32_t id);
+           /* ... */
+     }
+```
+
+The mentioned DomainInfo struct looks like this:
+
+### DomainInfo struct
+| | |
+|:--|:--|
+|uint32\_t id|ID of this zone within this backend|
+|string master|IP address of the master of this domain, if any|
+|uint32\_t serial|Serial number of this zone|
+|uint32\_t notified\_serial|Last serial number of this zone that slaves have seen|
+|time\_t last\_check|Last time this zone was checked over at the master for changes|
+|enum {Master,Slave,Native} kind|Type of zone|
+|DNSBackend \*backend|Pointer to the backend that feels authoritative for a domain and can act as a slave|
+
+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.
+
+### `bool isMaster(const string &name, const string &ip)`
+If a backend considers itself a slave for the domain **name** and if the IP address in **ip** is indeed a master, it should return true. False otherwise. This is a first line of checks to guard against reloading a domain unnecessarily.
+
+### `void getUnfreshSlaveInfos(vector\<DomainInfo\>\* domains)`
+When called, the backend should examine its list of slave domains and add any unfresh ones to the domains vector.
+
+### `bool getDomainInfo(const string &name, DomainInfo & di)`
+This is like `getUnfreshSlaveInfos`, but for a specific domain. If the backend considers itself authoritative for the named zone, `di` should be filled out, and 'true' be returned. Otherwise return false.
+
+### `bool startTransaction(const string &qname, int id)`
+When called, the backend should start a transaction that can be committed or rolled back atomically later on. In SQL terms, this function should **BEGIN** a transaction and **DELETE** all records.
+
+### `bool feedRecord(const DNSResourceRecord &rr, string *ordername)`
+Insert this record.
+
+### `bool commitTransaction()`
+Make the changes effective. In SQL terms, execute **COMMIT**.
+
+### `bool abortTransaction()`
+Abort changes. In SQL terms, execute **ABORT**.
+
+### `bool setFresh()`
+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 `getUnfreshSlaveInfos()`.
+
+PDNS will always call `startTransaction()` before making calls to `feedRecord()`. Although it is likely that `abortTransaction()` will be called in case of problems, backends should also be prepared to abort from their destructor.
+
+The actual code in PDNS is currently (1.99.9):
+
+```
+    Resolver resolver;
+    resolver.axfr(remote,domain.c_str());
+
+    db->startTransaction(domain, domain_id);
+    L<<Logger::Error<<"AXFR started for '"<<domain<<"'"<<endl;
+    Resolver::res_t recs;
+
+    while(resolver.axfrChunk(recs)) {
+      for(Resolver::res_t::const_iterator i=recs.begin();i!=recs.end();++i) {
+    db->feedRecord(*i);
+      }
+    }
+    db->commitTransaction();
+    db->setFresh(domain_id);
+    L<<Logger::Error<<"AXFR done for '"<<domain<<"'"<<endl;
+```
+
+## Supermaster/Superslave capability
+
+A backend that wants to act as a 'superslave' for a master should implement the following method:
+
+```
+            class DNSBackend 
+            {
+               virtual bool superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db)
+            };
+```
+
+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.
+
+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.
+
+Supermaster/superslave is a complicated concept, if this is all unclear see the [Supermaster and Superslave](../authoritative/modes-of-operation.md#supermaster-automatic-provisioning-of-slaves) documentation.
+
+## Read/write master-capable backends
+In order to be a useful master for a domain, notifies must be sent out whenever a domain is changed. Periodically, PDNS queries backends for domains that may have changed, and sends out notifications for slave nameservers.
+
+In order to do so, PDNS calls the `getUpdatedMasters()` method. Like the `getUnfreshSlaveInfos()` function mentioned above, this should add changed domain names to the vector passed.
+
+The following excerpt from the DNSBackend shows the relevant functions:
+
+```
+      class DNSBackend {
+      public:
+           /* ... */
+       virtual void getUpdatedMasters(vector<DomainInfo>* domains);
+       virtual void setNotified(uint32_t id, uint32_t serial);
+           /* ... */
+     }
+```
+
+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.
+
+### `void getUpdatedMasters(vector<DomainInfo>* domains)`
+When called, the backend should examine its list of master domains and add any changed ones to the DomainInfo vector
+
+### `bool setNotified(uint32_t domain_id, uint32_t serial)`
+Indicate that notifications have been queued for this domain and that it need not be considered 'updated' anymore
+
+## DNS update support
+To make your backend DNS update compatible, it needs to implement a number of new functions and functions already used for slave-operation. The new functions are not DNS update specific and might be used for other update/remove functionality at a later stage.
+
+```
+class DNSBackend {
+public:
+  /* ... */
+  virtual bool startTransaction(const string &qname, int id);
+  virtual bool commitTransaction();
+  virtual bool abortTransaction();
+  virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername);
+  virtual bool replaceRRSet(uint32_t domain_id, const string& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)
+  virtual bool listSubZone(const string &zone, int domain_id);
+  /* ... */
+}
+```
+
+### `virtual bool startTransaction(const string &qname, int id)`
+See [above](#bool-starttransactionconst-string-qname-int-id). Please note that this function now receives a negative number (-1), which indicates that the current zone data should NOT be deleted.
+
+### `virtual bool commitTransaction()`
+See [above](#bool-committransaction)
+
+### `virtual bool abortTransaction()`
+See [above](#bool-aborttransaction). Method is called when an exception is received.
+
+### `virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername)`
+See [above](#bool-feedrecordconst-dnsresourcerecord-rr-string-ordername). Please keep in mind that the zone is not empty because `startTransaction()` was called different.
+
+### `virtual bool listSubZone(const string &name, int domain\_id)`
+This method is needed for rectification of a zone after NS-records have been added. For DNSSEC, we need to know which records are below the currently added record. `listSubZone()` is used like `list()` which means PowerDNS will call `get()` after this method. The default SQL query looks something like this:
+
+```
+// First %s is 'sub.zone.com', second %s is '*.sub.zone.com'
+select content,ttl,prio,type,domain_id,name from records where (name='%s' OR name like '%s') and domain_id=%d
+```
+
+The method is not only used when adding records, but also to correct ENT-records in powerdns. Make sure it returns every record in the tree below the given record.
+
+### `virtual bool replaceRRSet(uint32_t domain_id, const string& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)`
+This method should remove all the records with `qname` of type `qt`. `qt` might also be ANY, which means all the records with that `qname` need to be removed. After removal, the records in `rrset` must be added to the zone. `rrset` can be empty in which case the method is used to remove a RRset.
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a84314833bb0df267cd06872871b697671f9dd9b 100644 (file)
@@ -0,0 +1,32 @@
+# Compiling PowerDNS
+**Note**: For now, see [the Open Source PowerDNS site](http://wiki.powerdns.com/). `./configure ; make ; make install` will do The Right Thing for most people.
+
+PowerDNS can be compiled with modules built in, or with modules designed to be loaded at runtime. All that is configured before compiling using the well known autoconf/automake system.
+
+To compile in modules, specify them as `--with-modules='mod1 mod2 mod3'`, substituting the desired module names. Each backend has a module name in the table at the beginning of its section.
+
+To compile a module for inclusion at runtime, which is great if you are a unix vendor, use `--with-dynmodules='mod1 mod2 mod3'`. These modules then end up as .so files in the compiled libdir.
+
+Starting with version 2.9.18, PowerDNS requires 'Boost' to compile, it is available for most operating systems. Otherwise, see [the Boost website](http://www.boost.org).
+
+### AIX
+Known to compile with gcc, but only since 2.9.8. AIX lacks POSIX semaphores so they need to be emulated, as with MacOS X.
+
+### FreeBSD
+Works fine, but use gmake. Pipe backend is currently broken, for reasons, see [PipeBackend](../authoritative/backend-pipe.md). Due to the threading model of FreeBSD, PowerDNS does not benefit from additional CPUs on the system.
+
+The FreeBSD Boost include files are installed in `/usr/local/include`, so prefix `CXXFLAGS=-I/usr/local/include` to your `./configure` invocation.
+
+### Linux
+Linux is probably the best supported platform as most of the main coders are Linux users. The static DEB distribution is known to have problems on Debian 'Sid', but that doesn't matter as PowerDNS is a native part of Debian 'Sid'. Just `apt-get`!
+
+### MacOS X
+Did compile at one point but maintenance has lapsed. Let us know if you can provide us with a login on MacOS X or if you want to help.
+
+### OpenBSD
+Compiles but then does not work very well. We hear that it may work with more recent versions of gcc, please let us know on `<pdns-dev@mailman.powerdns.com>`.
+
+### Solaris
+Solaris 7 is supported, but only just. AAAA records do not work on Solaris 7. Solaris 8 and 9 work fine. The 'Sunpro' compiler has not been tried but is reported to be lacking large parts of the Standard Template Library, which PowerDNS relies on heavily. Use gcc and gmake (if available). Regular Solaris make has some issues with some PowerDNS Makefile constructs.
+
+When compiling, make sure that you have `/usr/ccs/bin` in your path. Furthermore, with some versions of MySQL, you may have to add `LDFLAGS=-lz` before `./configure`.
index a1f7e8e2086e8d98ea2da1422b8755c11b852b36..9059981a170c437b3f6a3a87b67e2bc03b42a995 100644 (file)
@@ -15,7 +15,7 @@ The BindBackend started life as a demonstration of the versatility of PDNS but q
 
 The BindBackend parses a Bind-style `named.conf` and extracts information about zones from it. It makes no attempt to honour other configuration flags, which you should configure (when available) using the PDNS native configuration.
 
-## Settings
+## Configuration Parameters
 ### `--help=bind`
 Outputs all known parameters related to the bindbackend
 
diff --git a/pdns/docs/markdown/authoritative/backend-pipe.md b/pdns/docs/markdown/authoritative/backend-pipe.md
new file mode 100644 (file)
index 0000000..e69de29
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..40a63ec634bca4a8778e34f054b23670270cfc4a 100644 (file)
@@ -0,0 +1,24 @@
+# Random Backend
+
+* Native: Yes
+* Master: No
+* Slave: No
+* Superslave: No
+* Autoserial: No
+* Case: Depends
+* DNSSEC: Yes, no key storage
+* Disabled data: No
+* Comments: No
+* Module name: built in
+* Launch: random
+
+This is a very silly backend which is discussed in the [Backends writer's guide](../appendix/backend-writers-guide.md#simple-backends) as a demonstration on how to write a PowerDNS backend.
+
+This backend knows about only one hostname, and only about its IP address at that. With every query, a new random IP address is generated.
+
+It only makes sense to load the random backend in combination with a regular backend. This can be done by prepending it to the [`launch`](settings.md#launch) instruction, such as `launch=random,gmysql`.
+
+## Configuration Parameters
+### `random-hostname`
+* String
+Hostname for which to supply a random IP address.
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d9c493ec569dfa605646037d35ce91c4e64b5d54 100644 (file)
@@ -0,0 +1,59 @@
+# TinyDNS Backend
+**Warning**: The TinyDNS Backend is available since PowerDNS Authoritative Server 3.1. This backend is marked as experimental!
+
+* Native: Yes
+* Master: Yes
+* Slave: No
+* Superslave: No
+* Autoserial: No
+* DNSSEC: No
+* Multiple Instances: Yes
+* Module name: tinydns
+* Launch: tinydns
+
+The TinyDNS backend allows you to use [djbdns's](http://cr.yp.to/djbdns.html) `data.cdb` file format as the storage of your DNS records. The `data.cdb` file is created using [tinydns-data](http://cr.yp.to/djbdns/tinydns-data.html). The backend is designed to be able to use the `data.cdb` files without any changes.
+
+## Configuration Parameters
+These are the configuration file parameters that are available for the TinyDNS backend. It is recommended to set the `tinydns-dbfile`.
+
+### `tinydns-dbfile`
+* String
+* Default: data.cdb
+Specifies the name of the data file to use.
+
+### `tinydns-tai-adjust`
+* Integer
+* Default: 11
+This adjusts the [TAI](http://www.tai64.com/) value if timestamps are used. These seconds will be added to the start point (1970) and will allow you to adjust for leap seconds. The current default is 11. The last update was on [june 30th 2012](http://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat).
+
+### `tinydns-notify-on-startup`
+* Boolean
+* Default: no
+Tell the TinyDNSBackend to notify all the slave nameservers on startup. This might cause broadcast storms.
+
+### `tinydns-ignore-bogus-records`
+* Boolean
+* Default: no
+The `tinydns-data` program can create data.cdb files that have bad/corrupt RDATA. PowerDNS will crash when it tries to read that bad/corrupt data. This option (change to yes), allows you to ignore that bad RDATA to make PowerDNS operate when bad data is in your CDB file. Be aware that the records are then ignored, where tinydns would still send out the bogus data. The option is primarily useful in master mode, as that reads all the packets in the zone to find all the SOA records.
+
+### `tinydns-locations`
+* Boolean
+* Default: no
+Enable or Disable location support in the backend. Changing the value to 'no' will make the backend ignore the locations. This then returns all records. When the setting is changed to 'no' an AXFR will also return all the records. With the setting on 'yes' an AXFR will only return records without a location.
+
+## Location and Timestamp support
+Both timestamp and location are supported in the backend. Locations support can be changed using the [`tinydns-locations`](#tinydns-locations) setting. Timestamp and location only work as expected when [`cache-ttl`](settings.md#cache-ttl) and [`query-cache-ttl`](settings.md#query-cache-ttl) are set to 0 (which disables these caches). Timestamp can operate with [`cache-ttl`](settings.md#cache-ttl) if cache is needed, but the TTL returned for the timestamped racked will not be totally correct. The record will expire once the cache is expired and the backend is queried again. Please note that [`cache-ttl`](settings.md#cache-ttl) is a performance related setting. See [Performance related settings](performance.md). Location support only exists for IPv4!
+
+## Master mode
+The TinyDNSBackend supports master mode. This allows it to notify slave nameservers of updates to a zone. You simply need to rewrite the `data.cdb` file with an updated/increased serial and PowerDNS will notify the slave nameservers of that domain. The [`tinydns-notify-on-startup`](#tinydns-notify-on-startup) configuration setting tells the backend if it should notify all the slave nameservers just after startup.
+
+The CDB datafile does not allow PowerDNS to easily query for newly added domains or updated serial numbers. The CDB datafile requires us to do a full scan of all the records. When running with verbose logging, this could lead to a lot of output. The scanning of the CDB file may also take a while on systems with large files. The scan happens at an interval set by the [`slave-cycle-interval`](settings.md#slave-cycle-interval). It might be useful to raise this value to limit the amount of scans on the CDB file.
+
+The TinyDNSBackend also keeps a list of all the zones. This is needed to detect an updated serial and to give every zone a unique id. The list is updated when a zone is added, but not when a zone is removed. This leads to some memory loss.
+
+## Useful implementation Notes
+This backend might solve some issues you have with the current tinydns noted on [Jonathan de Boyne Pollard's](http://homepage.ntlworld.com/jonathan.deboynepollard/author.html) [djbdns known problems page](http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/djbdns-problems.html).
+
+The `data.cdb` file format support all types of records. They are sometimes difficult to create because you need to specify the actual content of the rdata. [Tinydns.org](http://tinydns.org/) provides a number of links to tools/cgi-scripts that allow you to create records. [Anders Brownworth](http://anders.com/) also provides a number of useful record building scripts on his [djbdnsRecordBuilder](http://anders.com/projects/sysadmin/djbdnsRecordBuilder/).
+
+Compiling the TinyDNS backend requires you to have [tinycdb](http://www.corpit.ru/mjt/tinycdb.html) version 0.77.
diff --git a/pdns/docs/markdown/authoritative/fancy-records.md b/pdns/docs/markdown/authoritative/fancy-records.md
new file mode 100644 (file)
index 0000000..e69de29
index 5b72d97d8aaacb42462a508b58a24d699eaf2837..4cc863c695bd8a85f7c644c105a29434277589c4 100644 (file)
@@ -44,7 +44,7 @@ Slave operation can also be programmed using several [`pdns_control`](../appendi
 
 Since version 2.9.21, PowerDNS supports multiple masters. For the BIND backend, the native BIND configuration language suffices to specify multiple masters, for SQL based backends, list all master servers separated by commas in the 'master' field of the domains table.
 
-## Supermaster automatic provisioning of slaves
+## Supermaster: automatic provisioning of slaves
 PDNS can recognize so called 'supermasters'. A supermaster is a host which is master for domains and for which we are to be a slave. When a master (re)loads a domain, it sends out a notification to its slaves. Normally, such a notification is only accepted if PDNS already knows that it is a slave for a domain.
 
 However, a notification from a supermaster carries more persuasion. When PDNS determines that a notification comes from a supermaster and it is bonafide, PDNS can provision the domain automatically, and configure itself as a slave for that zone.
index b477594654ec06b226f4fb13467dd334d4ea4550..80aa170243794ceaed0ebfee1a6c27bbcb3de3c0 100644 (file)
@@ -6,10 +6,16 @@ You can use `+=` syntax to set some variables incrementally, but this requires y
 For boolean settings, specifying the name of the setting without a value means `yes`.
 
 ## `allow-axfr-ips`
+* IP ranges
+* Default: 127.0.0.0/8,::1
 Behaviour pre 2.9.10: When not allowing AXFR (disable-axfr), DO allow from these IP addresses or netmasks.
 
 Behaviour post 2.9.10: If set, only these IP addresses or netmasks will be able to perform AXFR.
 
+## `allow-dns-update-from`
+* IP ranges
+From 3.4 onward. Allow DNS updates from these IP ranges.
+
 ## `allow-recursion`
 By specifying `allow-recursion`, recursion can be restricted to netmasks specified. The default is to allow recursion from everywhere. Example: `allow-recursion=192.168.0.0/24, 10.0.0.0/8, 192.0.2.4`.
 
@@ -74,7 +80,7 @@ Number of Distributor (backend) threads to start per receiver thread. See ["Auth
 Perform AAAA additional processing.
 
 ## `edns-subnet-option-number`
-If edns-subnet-processing is enabled, this option allows the user to override the option number.
+Removed in 3.4. If edns-subnet-processing is enabled, this option allows the user to override the option number.
 
 ## `edns-subnet-processing`
 Enables EDNS subnet processing, for backends that support it.
@@ -82,12 +88,26 @@ Enables EDNS subnet processing, for backends that support it.
 ## `entropy-source`
 Entropy source (like /dev/urandom).
 
+## `experimental-api-readonly`
+* Boolean
+From 3.4 onward. Disallow data modification through the json API when set.
+
 ## `experimental-dname-processing`
-Synthesise CNAME records from DNAME records as required. This approximately doubles query load. *Do not combine with DNSSEC!*
+Synthesise CNAME records from DNAME records as required. This approximately doubles query load. **Do not combine with DNSSEC!**
+
+## `experimental-dnsupdate`
+* Boolean
+* Default: no
+Enable/Disable DNS update (RFC2136) support.
 
 ## `fancy-records`
 Process URL and MBOXFW records. See ["Fancy Records"](#XXX).
 
+## `forward-dnsupdates`
+* Boolean
+* Default: no
+Forward DNS updates sent to a slave to the master.
+
 ## `guardian`
 Boolean, run within a guardian process. See ["Guardian"](#XXX).
 
@@ -101,7 +121,7 @@ Directory to scan for additional config files. All files that end with .conf are
 Which backends to launch and order to query them in. See ["Modules & Backends"](#XXX).
 
 ## `lazy-recursion`
-Boolean, on by default as of 2.1. Checks local data first before recursing. See ["Recursion"](#XXX).
+Boolean, on by default as of 2.1. Checks local data first before recursing. See ["Recursion"](#XXX). Removed in 3.2.
 
 ## `load-modules`
 Load this module - supply absolute or relative path. See ["Modules & Backends"](#XXX).
@@ -109,13 +129,25 @@ Load this module - supply absolute or relative path. See ["Modules & Backends"](
 ## `local-address`
 Local IP address to which we bind. You can specify multiple addresses separated by commas or whitespace. It is highly advised to bind to specific interfaces and not use the default 'bind to any'. This causes big problems if you have multiple IP addresses. Unix does not provide a way of figuring out what IP address a packet was sent to when binding to any.
 
+## `local-address-nonexist-fail`
+* Boolean
+* Default: no
+Fail to start if one or more of the local-address's do not exist on this server
+
 ## `local-ipv6`
 Local IPv6 address to which we bind. You can specify multiple addresses separated by commas or whitespace.
 
+## `local-ipv6-nonexist-fail`
+* Boolean
+* Default: no
+Fail to start if one or more of the local-ipv6 addresses do not exist on this server.
+
 ## `local-port`
 The port on which we listen. Only one port possible.
 
-## `log-dns-details` [,=no]
+## `log-dns-details`
+* Boolean
+* Default: no
 If set to 'no', informative-only DNS details will not even be sent to syslog, improving performance. Available from 2.5 and onwards.
 
 ## `logging-facility`
@@ -139,9 +171,18 @@ Maximum number of cache entries. 1 million will generally suffice for most insta
 ## `max-ent-entries`
 Maximum number of empty non-terminals to add to a zone. This is a protection measure to avoid database explosion due to long names.
 
+## `max-nsec3-iterations`
+* Integer
+* Default: 500
+Limit the number of NSEC3 hash iterations
+
 ## `max-queue-length`
 If this many packets are waiting for database attention, consider the situation hopeless and respawn.
 
+## `max-signature-cache-entries`
+* Integer
+Maximum number of signatures cache entries
+
 ## `max-tcp-connections`
 Allow this many incoming TCP DNS connections simultaneously.
 
@@ -184,7 +225,7 @@ Seconds to store queries with an answer in the Query Cache. See ["Query Cache"](
 ## `query-local-address`
 The IP address to use as a source address for sending queries. Useful if you have multiple IPs and pdns is not bound to the IP address your operating system uses by default for outgoing packets.
 
-## ``query-local-address6``
+## `query-local-address6`
 Source IP address for sending IPv6 queries.
 
 ## `query-logging`
@@ -271,6 +312,8 @@ Enable the Linux-only traceback handler (default on).
 IP address of incoming notification proxy
 
 ## `udp-truncation-threshold`
+* Integer
+* Default: 1680
 EDNS0 allows for large UDP response datagrams, which can potentially raise performance. Large responses however also have downsides in terms of reflection attacks. Up till PowerDNS Authoritative Server 3.3, the truncation limit was set at 1680 bytes, regardless of EDNS0 buffer size indications from the client. Beyond 3.3, this setting makes our truncation limit configurable. Maximum value is 65535, but values above 4096 should probably not be attempted.
 
 ## `urlredirector`
@@ -295,6 +338,10 @@ Start a webserver for monitoring. See ["Performance Monitoring"](logging.md#perf
 * Default: 127.0.0.1
 IP Address of webserver to listen on. See ["Performance Monitoring"](logging.md#performance-monitoring).
 
+## `webserver-allow-from`
+* IP ranges
+Webserver access is only allowed from these subnets
+
 ## `webserver-password`
 * String
 * Default: unset
index 3f0d1a34d2d5d074d850b9fb11385ad4e6a3a8cb..2430c8d94c22f4046bfe3be10632c7cbb01adea4 100644 (file)
@@ -5,12 +5,616 @@ Before proceeding, it is advised to check the release notes for your PDNS versio
 # 3.3.1 to 3.4.0
 If you are coming from any 3.x version (including 3.3.1), there is a mandatory SQL schema upgrade
 
+## Database schema
+**Warning**: The default database schema has changed. The database update below is mandatory.
+
+If custom queries are in use, they probably need an update.
+
+### gmysql backend with nodnssec schema
+
+```
+/* Uncomment next line for versions <= 3.1 */
+/* DROP INDEX rec_name_index ON records; */
+
+ALTER TABLE records ADD disabled TINYINT(1) DEFAULT 0;
+ALTER TABLE records MODIFY content VARCHAR(64000) DEFAULT NULL;
+ALTER TABLE records ADD ordername VARCHAR(255) BINARY DEFAULT NULL;
+ALTER TABLE records ADD auth TINYINT(1) DEFAULT 1;
+ALTER TABLE records MODIFY type VARCHAR(10);
+ALTER TABLE supermasters MODIFY ip VARCHAR(64) NOT NULL;
+ALTER TABLE supermasters ADD PRIMARY KEY(ip, nameserver);
+
+CREATE INDEX recordorder ON records (domain_id, ordername);
+
+
+CREATE TABLE domainmetadata (
+  id                    INT AUTO_INCREMENT,
+  domain_id             INT NOT NULL,
+  kind                  VARCHAR(32),
+  content               TEXT,
+  PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
+
+
+CREATE TABLE cryptokeys (
+  id                    INT AUTO_INCREMENT,
+  domain_id             INT NOT NULL,
+  flags                 INT NOT NULL,
+  active                TINYINT(1),
+  content               TEXT,
+  PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+  id                    INT AUTO_INCREMENT,
+  name                  VARCHAR(255),
+  algorithm             VARCHAR(50),
+  secret                VARCHAR(255),
+  PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
+
+
+CREATE TABLE comments (
+  id                    INT AUTO_INCREMENT,
+  domain_id             INT NOT NULL,
+  name                  VARCHAR(255) NOT NULL,
+  type                  VARCHAR(10) NOT NULL,
+  modified_at           INT NOT NULL,
+  account               VARCHAR(40) NOT NULL,
+  comment               VARCHAR(64000) NOT NULL,
+  PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+```
+
+### gmysql backend with dnssec schema
+
+```
+/* Uncomment next 3 lines for versions <= 3.1 */
+/* DROP INDEX rec_name_index ON records; */
+/* DROP INDEX orderindex ON records; */
+/* CREATE INDEX recordorder ON records (domain_id, ordername); */
+
+ALTER TABLE records ADD disabled TINYINT(1) DEFAULT 0 AFTER change_date;
+ALTER TABLE records MODIFY content VARCHAR(64000) DEFAULT NULL;
+ALTER TABLE records MODIFY ordername VARCHAR(255) BINARY DEFAULT NULL;
+ALTER TABLE records MODIFY auth TINYINT(1) DEFAULT 1;
+ALTER TABLE records MODIFY type VARCHAR(10);
+ALTER TABLE supermasters MODIFY ip VARCHAR(64) NOT NULL;
+ALTER TABLE supermasters ADD PRIMARY KEY(ip, nameserver);
+ALTER TABLE domainmetadata MODIFY kind VARCHAR(32);
+ALTER TABLE tsigkeys MODIFY algorithm VARCHAR(50);
+
+DROP INDEX domainmetaidindex ON domainmetadata;
+CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
+
+CREATE TABLE comments (
+  id                    INT AUTO_INCREMENT,
+  domain_id             INT NOT NULL,
+  name                  VARCHAR(255) NOT NULL,
+  type                  VARCHAR(10) NOT NULL,
+  modified_at           INT NOT NULL,
+  account               VARCHAR(40) NOT NULL,
+  comment               VARCHAR(64000) NOT NULL,
+  PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+```
+
+### gpgsql backend with nodnssec schema
+
+```
+/* Uncomment next line for versions <= 3.3 */
+/* ALTER TABLE domains ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */
+
+ALTER TABLE records ADD disabled BOOL DEFAULT 'f';
+ALTER TABLE records ALTER COLUMN content TYPE VARCHAR(65535);
+ALTER TABLE records ADD ordername VARCHAR(255);
+ALTER TABLE records ADD auth BOOL DEFAULT 't';
+ALTER TABLE records ALTER COLUMN type TYPE VARCHAR(10);
+ALTER TABLE supermasters ALTER COLUMN ip TYPE INET USING ip::INET;
+ALTER TABLE supermasters ADD CONSTRAINT supermasters_pkey PRIMARY KEY (ip, nameserver);
+
+CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);
+
+
+CREATE TABLE domainmetadata (
+ id                     SERIAL PRIMARY KEY,
+ domain_id              INT REFERENCES domains(id) ON DELETE CASCADE,
+ kind                   VARCHAR(32),
+ content                TEXT
+);
+
+CREATE INDEX domainidmetaindex ON domainmetadata(domain_id);
+
+
+CREATE TABLE cryptokeys (
+ id                     SERIAL PRIMARY KEY,
+ domain_id              INT REFERENCES domains(id) ON DELETE CASCADE,
+ flags                  INT NOT NULL,
+ active                 BOOL,
+ content                TEXT
+);
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id                     SERIAL PRIMARY KEY,
+ name                   VARCHAR(255),
+ algorithm              VARCHAR(50),
+ secret                 VARCHAR(255),
+ constraint c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
+
+
+CREATE TABLE comments (
+  id                    SERIAL PRIMARY KEY,
+  domain_id             INT NOT NULL,
+  name                  VARCHAR(255) NOT NULL,
+  type                  VARCHAR(10) NOT NULL,
+  modified_at           INT NOT NULL,
+  account               VARCHAR(40) DEFAULT NULL,
+  comment               VARCHAR(65535) NOT NULL,
+  CONSTRAINT domain_exists
+  FOREIGN KEY(domain_id) REFERENCES domains(id)
+  ON DELETE CASCADE,
+  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+```
+
+### gpgsql backend with dnssec schema:
+
+``` {.programlisting}
+/* Uncomment next 2 lines for versions <= 3.3 */
+/* ALTER TABLE domains ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */
+/* ALTER TABLE tsigkeys ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */
+
+ALTER TABLE records ADD disabled BOOL DEFAULT 'f';
+ALTER TABLE records ALTER COLUMN content TYPE VARCHAR(65535);
+ALTER TABLE records ALTER COLUMN auth SET DEFAULT 't';
+ALTER TABLE records ALTER COLUMN type TYPE VARCHAR(10);
+ALTER TABLE supermasters ALTER COLUMN ip TYPE INET USING ip::INET;
+ALTER TABLE supermasters ADD CONSTRAINT supermasters_pkey PRIMARY KEY (ip, nameserver);
+ALTER TABLE domainmetadata ALTER COLUMN kind TYPE VARCHAR(32);
+ALTER TABLE tsigkeys ALTER COLUMN algorithm TYPE VARCHAR(50);
+
+CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);
+DROP INDEX IF EXISTS orderindex;
+
+
+CREATE TABLE comments (
+  id                    SERIAL PRIMARY KEY,
+  domain_id             INT NOT NULL,
+  name                  VARCHAR(255) NOT NULL,
+  type                  VARCHAR(10) NOT NULL,
+  modified_at           INT NOT NULL,
+  account               VARCHAR(40) DEFAULT NULL,
+  comment               VARCHAR(65535) NOT NULL,
+  CONSTRAINT domain_exists
+  FOREIGN KEY(domain_id) REFERENCES domains(id)
+  ON DELETE CASCADE,
+  CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+```
+
+### gsqlite3 backend with nodnssec schema
+
+```
+ALTER TABLE records ADD disabled BOOL DEFAULT 0;
+ALTER TABLE records ADD ordername VARCHAR(255);
+ALTER TABLE records ADD auth BOOL DEFAULT 1;
+
+CREATE INDEX orderindex ON records(ordername);
+
+
+CREATE TABLE domainmetadata (
+  id                    INTEGER PRIMARY KEY,
+  domain_id             INT NOT NULL,
+  kind                  VARCHAR(32) COLLATE NOCASE,
+  content               TEXT
+);
+
+CREATE INDEX domainmetaidindex on domainmetadata(domain_id);
+
+
+CREATE TABLE cryptokeys (
+  id                    INTEGER PRIMARY KEY,
+  domain_id             INT NOT NULL,
+  flags                 INT NOT NULL,
+  active                BOOL,
+  content               TEXT
+);
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+  id                    INTEGER PRIMARY KEY,
+  name                  VARCHAR(255) COLLATE NOCASE,
+  algorithm             VARCHAR(50) COLLATE NOCASE,
+  secret                VARCHAR(255)
+);
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
+
+
+CREATE TABLE comments (
+  id                    INTEGER PRIMARY KEY,
+  domain_id             INTEGER NOT NULL,
+  name                  VARCHAR(255) NOT NULL,
+  type                  VARCHAR(10) NOT NULL,
+  modified_at           INT NOT NULL,
+  account               VARCHAR(40) DEFAULT NULL,
+  comment               VARCHAR(65535) NOT NULL
+);
+
+CREATE INDEX comments_domain_id_index ON comments (domain_id);
+CREATE INDEX comments_nametype_index ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+BEGIN TRANSACTION;
+  CREATE TEMPORARY TABLE supermasters_backup (
+    ip                  VARCHAR(64) NOT NULL,
+    nameserver          VARCHAR(255) NOT NULL COLLATE NOCASE,
+    account             VARCHAR(40) DEFAULT NULL
+  );
+
+  INSERT INTO supermasters_backup SELECT ip, nameserver, account FROM supermasters;
+  DROP TABLE supermasters;
+
+  CREATE TABLE supermasters (
+    ip                  VARCHAR(64) NOT NULL,
+    nameserver          VARCHAR(255) NOT NULL COLLATE NOCASE,
+    account             VARCHAR(40) DEFAULT NULL
+  );
+  CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver);
+
+  INSERT INTO supermasters SELECT ip, nameserver, account FROM supermasters_backup;
+  DROP TABLE supermasters_backup;
+COMMIT;
+```
+
+### gsqlite3 backend with dnssec schema:
+
+```
+CREATE TABLE comments (
+  id                    INTEGER PRIMARY KEY,
+  domain_id             INTEGER NOT NULL,
+  name                  VARCHAR(255) NOT NULL,
+  type                  VARCHAR(10) NOT NULL,
+  modified_at           INT NOT NULL,
+  account               VARCHAR(40) DEFAULT NULL,
+  comment               VARCHAR(65535) NOT NULL
+);
+
+CREATE INDEX comments_domain_id_index ON comments (domain_id);
+CREATE INDEX comments_nametype_index ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+BEGIN TRANSACTION;
+  CREATE TEMPORARY TABLE records_backup(
+    id                  INTEGER PRIMARY KEY,
+    domain_id           INTEGER DEFAULT NULL,
+    name                VARCHAR(255) DEFAULT NULL,
+    type                VARCHAR(10) DEFAULT NULL,
+    content             VARCHAR(65535) DEFAULT NULL,
+    ttl                 INTEGER DEFAULT NULL,
+    prio                INTEGER DEFAULT NULL,
+    change_date         INTEGER DEFAULT NULL,
+    ordername           VARCHAR(255),
+    auth                BOOL DEFAULT 1
+  );
+
+  INSERT INTO records_backup SELECT id,domain_id,name,type,content,ttl,prio,change_date,ordername,auth FROM records;
+  DROP TABLE records;
+
+  CREATE TABLE records (
+    id                  INTEGER PRIMARY KEY,
+    domain_id           INTEGER DEFAULT NULL,
+    name                VARCHAR(255) DEFAULT NULL,
+    type                VARCHAR(10) DEFAULT NULL,
+    content             VARCHAR(65535) DEFAULT NULL,
+    ttl                 INTEGER DEFAULT NULL,
+    prio                INTEGER DEFAULT NULL,
+    change_date         INTEGER DEFAULT NULL,
+    disabled            BOOLEAN DEFAULT 0,
+    ordername           VARCHAR(255),
+    auth                BOOL DEFAULT 1
+  );
+
+  CREATE INDEX rec_name_index ON records(name);
+  CREATE INDEX nametype_index ON records(name,type);
+  CREATE INDEX domain_id ON records(domain_id);
+  CREATE INDEX orderindex ON records(ordername);
+
+  INSERT INTO records SELECT id,domain_id,name,type,content,ttl,prio,change_date,0,ordername,auth FROM records_backup;
+  DROP TABLE records_backup;
+COMMIT;
+
+
+BEGIN TRANSACTION;
+  CREATE TEMPORARY TABLE supermasters_backup (
+    ip                  VARCHAR(64) NOT NULL,
+    nameserver          VARCHAR(255) NOT NULL COLLATE NOCASE,
+    account             VARCHAR(40) DEFAULT NULL
+  );
+
+  INSERT INTO supermasters_backup SELECT ip,nameserver,account FROM supermasters;
+  DROP TABLE supermasters;
+
+  CREATE TABLE supermasters (
+    ip                  VARCHAR(64) NOT NULL,
+    nameserver          VARCHAR(255) NOT NULL COLLATE NOCASE,
+    account             VARCHAR(40) DEFAULT NULL
+  );
+  CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver);
+
+  INSERT INTO supermasters SELECT ip,nameserver,account FROM supermasters_backup;
+  DROP TABLE supermasters_backup;
+COMMIT;
+
+
+BEGIN TRANSACTION;
+  CREATE TABLE domainmetadata__backup (
+    id INTEGER PRIMARY KEY,
+    domain_id INT NOT NULL,
+    kind VARCHAR(32) COLLATE NOCASE,
+    content TEXT
+  );
+
+  INSERT INTO domainmetadata_backup SELECT id,domain_id,kind,content FROM domainmetadata;
+  DROP TABLE domainmetadata;
+
+  CREATE TABLE domainmetadata (
+    id INTEGER PRIMARY KEY,
+    domain_id INT NOT NULL,
+    kind VARCHAR(32) COLLATE NOCASE,
+    content TEXT
+  );
+  CREATE INDEX domainmetaidindex ON domainmetadata(domain_id);
+
+  INSERT INTO domainmetadata SELECT id,domain_id,kind,content FROM domainmetadata_backup;
+  DROP TABLE domainmetadata_backup;
+COMMIT;
+```
+
+### goracle backend:
+
+```
+ALTER TABLE records ADD disabled INT DEFAULT 0;
+ALTER TABLE records MODIFY auth INT DEFAULT 1;
+
+UPDATE records SET auth=1 WHERE auth IS NULL;
+```
+
+## Configuration option changes
+
+### New options
+#### `allow-dnsupdate-from`
+A global setting to allow DNS update from these IP ranges.
+
+#### `also-notify`
+When notifying a domain, also notify these nameservers
+
+#### `carbon-interval`
+Number of seconds between carbon (graphite) updates
+
+#### `carbon-ourname`
+If set, overrides our reported hostname for carbon stats
+
+#### `carbon-server`
+If set, send metrics in carbon (graphite) format to this server
+
+#### `disable-axfr-rectify`
+Disable the rectify step during an outgoing AXFR. Only required for regression testing.
+
+#### `experimental-api-readonly`
+If the JSON API should disallow data modification
+
+#### `experimental-dname-processing`
+If we should support DNAME records
+
+#### `experimental-dnsupdate`
+Enable/Disable DNS update (RFC2136) support. Default is no.
+
+#### `forward-dnsupdate`
+A global setting to allow DNS update packages that are for a Slave domain, to be forwarded to the master.
+
+#### `max-signature-cache-entries`
+Maximum number of signatures cache entries
+
+#### `local-address-nonexist-fail`
+Fail to start if one or more of the local-address's do not exist on this server
+
+#### `local-ipv6-nonexist-fail`
+Fail to start if one or more of the local-ipv6 addresses do not exist on this server
+
+#### `max-nsec3-iterations`
+Limit the number of NSEC3 hash iterations
+
+#### `only-notify`
+Only send AXFR NOTIFY to these IP addresses or netmasks
+
+#### `reuseport`
+Enable higher performance on compliant kernels by using SO\_REUSEPORT allowing each receiver thread to open its own socket
+
+#### `udp-truncation-threshold`
+Maximum UDP response size before we truncate
+
+#### `webserver-allow-from`
+Webserver access is only allowed from these subnets
+
+### Removed options
+#### `add-superfluous-nsec3-for-old-bind`
+Add superfluous NSEC3 record to positive wildcard response
+
+#### `edns-subnet-option-number`
+EDNS option number to use
+
+#### `fancy-records`
+Process URL and MBOXFW records
+
+#### `log-failed-updates`
+If PDNS should log failed update requests
+
+#### `smtpredirector`
+Our smtpredir MX host
+
+#### `urlredirector`
+Where we send hosts to that need to be url redirected
+
+#### `wildcard-url`
+Process URL and MBOXFW records
+
+### Options with changed default values
+
+#### `allow-axfr-ips`
+Allow zonetransfers only to these subnets
+
+* old value: 0.0.0.0/0,::/0
+* new value: 127.0.0.0/8,::1
+
+#### log-dns-details
+If PDNS should log DNS non-erroneous details
+
+* old value:
+* new value: no
+
+#### module-dir
+The default location has changed from libdir to pkglibdir. pkglibdir is defined as '\$(libdir)/pdns'
+
 # 3.3 to 3.3.1
+Constraints were added to the PostgreSQL schema:
+
+```
+        alter table domains add constraint c_lowercase_name CHECK (((name)::text = lower((name)::text)));
+        alter table tsigkeys add constraint c_lowercase_name check (((name)::text = lower((name)::text)));
+```
+
+The (gmysql-)innodb-read-committed flag was added to the gmysql backend, and enabled by default. This interferes with statement replication. Please set your binlog\_format to MIXED or ROW, or disable binlog. Alternatively, disable (gmysql-)innodb-read-committed but be aware that this may cause deadlocks during AXFRs.
 
 # 3.2 to 3.3
+The 'ip' field in the supermasters table (for the various gsql backends) has been stretched to 64 characters to support IPv6. For MySQL:
+
+```
+alter table supermasters modify ip VARCHAR(64);
+```
+
+For PostgreSQL:
+```
+alter table supermasters alter column ip type VARCHAR(64);
+```
+
+`pdnssec secure-zone` now creates one KSK and one ZSK, instead of two ZSKs.
+
+The 'rec\_name\_index' index was dropped from the gmysql schema, as it was superfluous.
 
 # 3.1 to 3.2
+Previously, on Linux, if the PowerDNS Authoritative Server was configured to bind to the IPv6 address `::`, the server would answer questions that came in via IPv6 **and** IPv4.
+
+As of 3.2, binding to :: on Linux now does the same thing as binding to :: on other operating systems: perform IPv6 service. To continue the old behaviour, use [`local-address`](settings.md#local-address)`=0.0.0.0` and [`local-ipv6`](settings.md#local-ipv6)`=::`.
+
+3.2 again involves some SQL schema changes, to make sure 'ordername' is ordered correctly for NSEC generation. For MySQL:
+
+```
+alter table records modify ordername    VARCHAR(255) BINARY;
+drop index orderindex on records;
+create index recordorder on records (domain_id, ordername);
+```
+
+You can test the BINARY change with the new and experimental 'pdnssec test-schema' command. For PostgreSQL, there are no real schema changes, but our indexes turned out to be inefficient, especially given the changed ordername queries in 3.2. Changes:
+
+```
+drop index orderindex;
+create index recordorder on records (domain_id, ordername text_pattern_ops);
+```
+Additionally, with 3.2 supporting empty non-terminals (see [XXX](XXX)), your frontend may need some changes.
+
+Due to a bug, in 3.1 and earlier releases, the pipebackend would default to a 1000 second timeout for responses from scripts, instead of the intended and documented 1000 milliseconds (1 second). In 3.2, pipe-timeout is in fact in milliseconds. To avoid some surprise, the default is now 2000 (2 seconds). If you have slow pipebackend scripts, make sure to increase [`pipe-timeout`](backend-pipe.md#pipe-timeout).
+
+Some configuration settings (that did not do anything, anyway) have been removed. You need to remove them from your configuration to start pdns\_server. They are: lazy-recursion, use-logfile, logfile.
 
 # 3.0 to 3.1
+PowerDNS 3.1 introduces native SQLite3 support for storing key material for DNSSEC in the bindbackend. With this change, support for bind+gsql-setups ('hybrid mode') has been dropped. If you were using this mode, you will need to switch to bind-dnssec-db and migrate your keying material.
+
+There have been changes to the SQL schemas for the generic backends.
+
+For MySQL:
+```
+mysql> ALTER TABLE records MODIFY content VARCHAR(64000);
+mysql> ALTER TABLE tsigkeys MODIFY algorithm VARCHAR(50);
+```
+
+For PostgreSQL:
+```
+postgres=# ALTER TABLE records ALTER COLUMN content TYPE VARCHAR(65535);
+postgres=# ALTER TABLE tsigkeys alter column algorithm type VARCHAR(50);
+```
+
+The definition of 'auth' and 'ordername' in backends has changed slightly, see [XXX](XXX).
+
+PowerDNS 3.0 and 3.1 will only fetch DNSSEC metadata and key material from the first DNSSEC-capable backend in the launch line. In 3.1, the bindbackend supports DNSSEC storage. This means that setups using `launch=bind,gsqlite3` or `launch=gsqlite3,bind` may break. Please tread carefully!
 
 # 2.9.X to 3.0
+The 3.0 release of the PowerDNS Authoritative Server is significantly different from previous 2.9.x versions. This section lists important things to be aware of.
+
+**Warning**: Version 3.0 of the PowerDNS Authoritative Server is the biggest change in PowerDNS history. In some senses, this means that it behaves somewhat like a '1.0' version. We advise operators to carefully perform the upgrade process from 2.9.x, and if possible test on a copy of the database beforehand.
+
+In addition, it may also be useful to have a support agreement in place during such upgrades. For first class and rapid support, please contact powerdns-support@netherlabs.nl, or see [www.powerdns.com](www.powerdns.com). Alternatively, the [PowerDNS Community](http://wiki.powerdns.com) can be very helpful too.
+
+With similar settings, version 3.0 will most likely use a lot more memory than 2.9. This is due to the new DNSSEC key & signature caches, but also because the database query cache will now store multiple row answers, which it did not do previously. Memory use can be brought down again by tuning the cache-ttl settings.
+
+Performance may be up, or it may be down. We appreciate that this is spotty guidance, but depending on your setup, lookups may be a lot faster or a lot slower. The improved database cache may prove to be a big benefit, and improve performance dramatically. This could be offset by a near duplication of database queries needed because of more strict interpretation of DNS standards.
+
+PowerDNS Authoritative Server 3.0 contains a completely renewed implementation of the core DNS 'Algorithm', loosely specified in RFC 1034. As stated above, our new implementation is a lot closer to the original standard. This may mean that version 3.0 may interpret the contents of your database differently from how 2.9.x interpreted them. For fully standards confirming zones, there should not be a problem, but if zones were misconfigured (no SOA record, for example), things will be different.
+
+When compiling version 3.0, there are now more dependencies than there used to be. Whereas previously, only Boost header files were needed, PowerDNS now needs a number of Boost libraries to be installed (like boost-program-options, boost-serialization). In addition, for now Lua 5.1 is a dependency.
+
+PowerDNS Authoritative Server 3.0 comes with DNSSEC support, but this has required big changes to database schemas. Each backend lists the changes required. To facilitate a smooth upgrade, the old, non-DNSSEC schema is used by default. Features like per-domain metadata, TSIG and DNSSEC itself however need the new schema. Consult your backend documentation for the correct 'alter table' statements. Afterwards, set the relevant '-dnssec' setting for your backend (for example: gmysql-dnssec).
+
+In version 3.0, "Fancy Records", like URL, CURL and MBOXFW are no longer supported. Support may come back in later versions. In addition, the LDAP Backend has moved to 'unmaintained' status.
+
+## Frequently Asked Questions about 3.0
+
+Q: Can 2.9.x versions read the 3.0 DNSSEC database schema?
+A: Yes, every database can be altered to the new schema without impact on 2.9. The new fields and tables are ignored.
+
+Q: Can 3.x versions read the 2.9 pre-DNSSEC database schema?
+A: Yes, as long as the relevant '-dnssec' setting is not enabled. These settings are typically called 'gmysql-dnssec', 'gpgsql-dnssec', 'gsqlite3-dnssec'. If this setting IS enabled, 3.x expects the new schema to be in place.
+
+Q: If I run 3.0 with the new schema, and I have set '-dnssec', do I need to rectify my zones?
+A: Yes. If the '-dnssec' setting is enabled, PowerDNS expects the 'auth' field to be filled out correctly. When slaving zones this happens automatically. For other zones, run 'pdnssec rectify-zone zonename'. Even if a zone is not DNSSEC secured, as long as the new schema is in place, the zone must be rectified (or at least have the 'auth' field set correctly).
+
+Q: I want to fill out the 'auth' and 'ordername' fields directly, how do I do this?
+A: The 'auth' field should be '1' or 'true' for all records that are within your zone. For a zone without delegations, this means 'auth' should always be set. If you have delegations, both the NS records for that delegation and possible glue records for it should not have 'auth' set.
+
+For more details on 'auth' and 'ordername', please see [XXX](XXX).
+
+Q: If I don't update to the new DNSSEC schema, will 3.0 give identical answers as 2.9.x?
+A: Not always. The core DNS logic of 3.0 was changed, so even if no changes are made to the database, you may get different answers. This might happen for zones without SOA records for example, which used to (more or less) work. An upgrade from 2.9.x to 3.0 should always be monitored carefully.
index d0974f29622498287006c12ac22e72145f034a2f..72008475c0501f3b4b1a04fd9e8534f770bad398 100644 (file)
@@ -12,6 +12,7 @@ pages:
   - [authoritative/upgrading.md, 'Authoritative', 'Upgrading']
   - [authoritative/modes-of-operation.md, 'Authoritative', 'Modes of Operation']
   - [authoritative/virtual.md, 'Authoritative', 'Virtual Hosting']
+  - [authoritative/fancy-records.md, 'Authoritative', 'Fancy Records']
   - [authoritative/performance.md, 'Authoritative', 'Performance Tuning']
   - [authoritative/logging.md, 'Authoritative', 'Logging and Performance Monitoring']
   - [authoritative/security.md, 'Authoritative', 'Security settings & considerations']
@@ -21,6 +22,7 @@ pages:
   - [authoritative/backend-bind.md, 'Authoritative', 'Backend: BIND']
   - [authoritative/backend-db2.md, 'Authoritative', 'Backend: DB2']
   - [authoritative/backend-random.md, 'Authoritative', 'Backend: Random']
+  - [authoritative/backend-pipe.md, 'Authoritative', 'Backend: Pipe']
   - [authoritative/backend-oracle.md, 'Authoritative', 'Backend: Oracle']
   - [authoritative/backend-generic-mypgsql.md, 'Authoritative', 'Backend: Generic MySQL and PostGreSQL']
   - [authoritative/backend-tinydns.md, 'Authoritative', 'Backend: TinyDNS']