[Pdns-users] proof of concept: clone domains

Reinoud van Leeuwen pdns at spoetnik.xs4all.nl
Wed Mar 3 14:59:03 UTC 2010


Hi,

Every now and then I tend to maintain domains that end up to be clones of 
other domeins. The company has registered company.com, and wants the same 
DNS records for company.net or maybe even brandx.com.

So I thought up a solution for this, implemented in the postgreSQL 
backend: I replaced the table records with a view. This solution has the 
following features:
- domain.org can be a clone of domain.com
- domain.org can have extra records that do not exist in domain.com
  (hoeever: at this moment not the opposite)

at the moment it is not yet possible to 'override' a record in domain.org.

To avoid confusion, I used copcepts SOURCE and COPY, to avoid names like 
MASTER and SLAVE.

-- NOTE: this is a PROOF OF CONCEPT. Not thoroughly tested. Not suitable 
for production yet. 

The main difference is the table virtdomains, that links a set of records 
to multiple DNS zones.

This is the SQL I used.


create table supermasters (
	  ip VARCHAR(25) NOT NULL, 
	  nameserver VARCHAR(255) NOT NULL, 
	  account VARCHAR(40) DEFAULT NULL
);

GRANT SELECT ON supermasters TO pdns;
GRANT ALL ON domains_org TO pdns;
GRANT ALL ON domains_org_id_seq TO pdns;
GRANT ALL ON records_org TO pdns;
GRANT ALL ON records_org_id_seq TO pdns;



create table domains (
 id		 SERIAL PRIMARY KEY,
 name		 VARCHAR(255) NOT NULL,
 master		 VARCHAR(128) DEFAULT NULL,
 last_check	 INT DEFAULT NULL,
 type		 VARCHAR(6) NOT NULL,
 notified_serial INT DEFAULT NULL, 
 account         VARCHAR(40) DEFAULT NULL
);

CREATE UNIQUE INDEX name_index ON domains(name);


create type virttype as enum ('SOURCE', 'COPY', 'EXTENSION');

-- this is an extra table that links DNS records to multiple zones.
-- SOURCE identifies a 'normal' zone.
-- COPY identifes that a zone is a copy of another (SOURCE) zone
-- EXTENSION makes it possible to add records to a copy zone that do not 
exist in the SOURCE

create table virtdomains (
        id                 SERIAL PRIMARY KEY,
        domain_id          INT DEFAULT NULL,
        recordtype         virttype default 'SOURCE',
        copydomain_id      INT DEFAULT NULL,
        CONSTRAINT domain_exists 
        FOREIGN KEY(domain_id) REFERENCES domains(id)
        ON DELETE CASCADE
);       

-- todo: constraint to check that copydomain is not null 
-- when recordtype = 'COPY'
-- todo: constraint to check that extension points to the same domain of 
-- an existing copy zone

CREATE UNIQUE INDEX virt_domain_id  ON virtdomains (domain_id, 
recordtype);

CREATE TABLE realrecords (
        id              SERIAL PRIMARY KEY,
        virtdomain_id   INT DEFAULT NULL,
        name            VARCHAR(255) DEFAULT NULL,
        type            VARCHAR(6) DEFAULT NULL,
        content         VARCHAR(255) DEFAULT NULL,
        ttl             INT DEFAULT NULL,
        prio            INT DEFAULT NULL,
        change_date     INT DEFAULT NULL, 
        CONSTRAINT virtdomain_exists 
        FOREIGN KEY(virtdomain_id) REFERENCES virtdomains(id)
        ON DELETE CASCADE
);

CREATE INDEX rec_name_index ON realrecords(name);
CREATE INDEX nametype_index ON realrecords(name,type);
CREATE INDEX domain_id      ON realrecords(virtdomain_id);

create view records as
select d.id * 100000 + r.id                            as id,
       v.domain_id                                     as domain_id,
       trim (leading '.' from r.name || '.' || d.name) as name,
       r.type                                          as type,
       r.content                                       as content,
       r.ttl                                           as ttl,
       r.prio                                          as prio,
       r.change_date                                   as change_date
  from realrecords r,
       virtdomains v,
       domains     d
 where d.id = v.domain_id
   and (   (v.recordtype in ('SOURCE', 'EXTENSION') and r.virtdomain_id = 
v.id ) 
        OR (v.recordtype = 'COPY'                   and r.virtdomain_id = 
v.copydomain_id ));

-- todo: fix view to make sure a record in the extension zone has 
-- precedence over SOURCE records
-- todo: create a rule so it is possible to do inserts in records table




-- insert some testdata:

-- we have 3 domains:

insert into domains (name, type) 
values ('company.com', '');

insert into domains (name, type) 
values ('company.net', '');

insert into domains (name, type) 
values ('company.org', '');


-- company.com has copyzones company.net and company.org

insert into virtdomains (domain_id, recordtype)
select id, 'SOURCE' 
  from domains
 where name = 'company.com';


insert into virtdomains (domain_id, recordtype, copydomain_id)
select d1.id, 'COPY', d2.id
  from domains d1,
       domains d2
 where d1.name = 'company.net'
   and d2.name = 'company.com';


insert into virtdomains (domain_id, recordtype, copydomain_id)
select d1.id, 'COPY', d2.id
  from domains d1,
       domains d2
 where d1.name = 'company.org'
   and d2.name = 'company.com';


-- make a virtual zone that extends the COPY zone company.org to hold 
extra records only for company.org

insert into virtdomains (domain_id, recordtype)
select d1.id, 'EXTENSION'
  from domains d1
 where d1.name = 'company.org';


-- insert some DNS records for all zones:

insert into realrecords  (virtdomain_id, name, type, content)
select v.id, '', 'SOA', 'ns1.company.com hostmaster.company.com 
2010030301'
  from virtdomains v,
       domains d
 where d.name = 'company.com'
   and d.id   = v.domain_id;


insert into realrecords  (virtdomain_id, name, type, content)
select v.id, 'www', 'A', '192.168.1.1'
  from virtdomains v,
       domains d
 where d.name = 'company.com'
   and d.id   = v.domain_id;


insert into realrecords  (virtdomain_id, name, type, content)
select v.id, 'ftp', 'A', '192.168.1.2'
  from virtdomains v,
       domains d
 where d.name = 'company.com'
   and d.id   = v.domain_id;


-- insert a record that only exists in the zone company.org

insert into realrecords  (virtdomain_id, name, type, content)
select v.id, 'orgonly', 'A', '192.168.1.3'
  from virtdomains v,
       domains d
 where d.name       = 'company.org'
   and d.id         = v.domain_id
   and v.recordtype = 'EXTENSION';




-- SQL check:

# select * from domains;
 id |    name     | master | last_check | type | notified_serial | account
----+-------------+--------+------------+------+-----------------+---------
  1 | company.com |        |            |      |                 |
  2 | company.net |        |            |      |                 |
  3 | company.org |        |            |      |                 |
(3 rows)

^^ 3 domains (as expected)



# select id, domain_id, name, type, content from records ;
   id   | domain_id |        name         | type |                      
content
--------+-----------+---------------------+------+---------------------------------------------------
 100001 |         1 | company.com         | SOA  | ns1.company.com 
hostmaster.company.com 2010030301
 100002 |         1 | www.company.com     | A    | 192.168.1.1
 100003 |         1 | ftp.company.com     | A    | 192.168.1.2
 200001 |         2 | company.net         | SOA  | ns1.company.com 
hostmaster.company.com 2010030301
 200002 |         2 | www.company.net     | A    | 192.168.1.1
 200003 |         2 | ftp.company.net     | A    | 192.168.1.2
 300001 |         3 | company.org         | SOA  | ns1.company.com 
hostmaster.company.com 2010030301
 300002 |         3 | www.company.org     | A    | 192.168.1.1
 300003 |         3 | ftp.company.org     | A    | 192.168.1.2
 300004 |         3 | orgonly.company.org | A    | 192.168.1.3
(10 rows)

^^^
3 records for each domain, and 1 extra that only exists in de company.org 
zone
(note that the ID is made unique here by adding the record id to 100,000 
times the domain_id. Some tools
might rely on the fact that id is unique)



#  select id, virtdomain_id, name, type, content from realrecords;
 id | virtdomain_id |  name   | type |                      content
----+---------------+---------+------+---------------------------------------------------
  1 |             1 |         | SOA  | ns1.company.com 
hostmaster.company.com 2010030301
  2 |             1 | www     | A    | 192.168.1.1
  3 |             1 | ftp     | A    | 192.168.1.2
  4 |             4 | orgonly | A    | 192.168.1.3
(4 rows)


^^^
only 4 real records.



-- 
__________________________________________________
"Nothing is as subjective as reality"
Reinoud van Leeuwen    reinoud.v at n.leeuwen.net
http://reinoud.van.leeuwen.net kvk 27320762
__________________________________________________



More information about the Pdns-users mailing list