1+ <?php
2+
3+ /*
4+ Copyright (c) 2009, Falko Timme, Till Brehm, projektfarm Gmbh
5+ All rights reserved.
6+
7+ Redistribution and use in source and binary forms, with or without modification,
8+ are permitted provided that the following conditions are met:
9+
10+ * Redistributions of source code must retain the above copyright notice,
11+ this list of conditions and the following disclaimer.
12+ * Redistributions in binary form must reproduce the above copyright notice,
13+ this list of conditions and the following disclaimer in the documentation
14+ and/or other materials provided with the distribution.
15+ * Neither the name of ISPConfig nor the names of its contributors
16+ may be used to endorse or promote products derived from this software without
17+ specific prior written permission.
18+
19+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+ IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+ */
30+
31+ /*
32+ The powerdns database name has to be "powerdns" and it must be accessible
33+ by the "ispconfig" database user
34+
35+ TABLE STRUCTURE of the "powerdns" database:
36+
37+ CREATE TABLE `domains` (
38+ `id` int(11) NOT NULL auto_increment,
39+ `name` varchar(255) NOT NULL,
40+ `master` varchar(128) default NULL,
41+ `last_check` int(11) default NULL,
42+ `type` varchar(6) NOT NULL,
43+ `notified_serial` int(11) default NULL,
44+ `account` varchar(40) default NULL,
45+ `ispconfig_id` int(11) NOT NULL,
46+ PRIMARY KEY (`id`),
47+ UNIQUE KEY `name_index` (`name`)
48+ ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
49+
50+ CREATE TABLE `records` (
51+ `id` int(11) NOT NULL auto_increment,
52+ `domain_id` int(11) default NULL,
53+ `name` varchar(255) default NULL,
54+ `type` varchar(6) default NULL,
55+ `content` varchar(255) default NULL,
56+ `ttl` int(11) default NULL,
57+ `prio` int(11) default NULL,
58+ `change_date` int(11) default NULL,
59+ `ispconfig_id` int(11) NOT NULL,
60+ PRIMARY KEY (`id`),
61+ KEY `rec_name_index` (`name`),
62+ KEY `nametype_index` (`name`,`type`),
63+ KEY `domain_id` (`domain_id`)
64+ ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
65+
66+ CREATE TABLE `supermasters` (
67+ `ip` varchar(25) NOT NULL,
68+ `nameserver` varchar(255) NOT NULL,
69+ `account` varchar(40) default NULL
70+ ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
71+
72+
73+ IMPORTANT:
74+ - This plugin does not support ALIAS records (supported only by MyDNS).
75+
76+ TODO:
77+ - introduce a variable for the PowerDNS database
78+ */
79+
80+ class powerdns_plugin {
81+
82+ var $ plugin_name = 'powerdns_plugin ' ;
83+ var $ class_name = 'powerdns_plugin ' ;
84+
85+ //* This function is called during ispconfig installation to determine
86+ // if a symlink shall be created for this plugin.
87+ function onInstall () {
88+ global $ conf ;
89+
90+ if (isset ($ conf ['powerdns ' ]['installed ' ]) && $ conf ['powerdns ' ]['installed ' ] == true ) {
91+ return true ;
92+ } else {
93+ return false ;
94+ }
95+
96+ }
97+
98+
99+ /*
100+ This function is called when the plugin is loaded
101+ */
102+
103+ function onLoad () {
104+ global $ app ;
105+
106+ /*
107+ Register for the events
108+ */
109+
110+ //* SOA
111+ $ app ->plugins ->registerEvent ('dns_soa_insert ' ,$ this ->plugin_name ,'soa_insert ' );
112+ $ app ->plugins ->registerEvent ('dns_soa_update ' ,$ this ->plugin_name ,'soa_update ' );
113+ $ app ->plugins ->registerEvent ('dns_soa_delete ' ,$ this ->plugin_name ,'soa_delete ' );
114+
115+ //* RR
116+ $ app ->plugins ->registerEvent ('dns_rr_insert ' ,$ this ->plugin_name ,'rr_insert ' );
117+ $ app ->plugins ->registerEvent ('dns_rr_update ' ,$ this ->plugin_name ,'rr_update ' );
118+ $ app ->plugins ->registerEvent ('dns_rr_delete ' ,$ this ->plugin_name ,'rr_delete ' );
119+
120+ }
121+
122+
123+ function soa_insert ($ event_name ,$ data ) {
124+ global $ app , $ conf ;
125+
126+ if ($ data ["new " ]["active " ] != 'Y ' ) return ;
127+
128+ $ origin = substr ($ data ["new " ]["origin " ], 0 , -1 );
129+ $ ispconfig_id = $ data ["new " ]["id " ];
130+ $ app ->db ->query ("INSERT INTO powerdns.domains (name, type, ispconfig_id) VALUES (' $ origin', 'NATIVE', $ ispconfig_id) " );
131+ $ zone_id = mysql_insert_id ();
132+ if (substr ($ data ["new " ]["ns " ], -1 ) == '. ' ){
133+ $ ns = substr ($ data ["new " ]["ns " ], 0 , -1 );
134+ } else {
135+ $ ns = $ data ["new " ]["ns " ].'. ' .$ origin ;
136+ }
137+ if ($ ns == '' ) $ ns = $ origin ;
138+
139+ $ hostmaster = substr ($ data ["new " ]["mbox " ], 0 , -1 );
140+ $ content = $ ns .' ' .$ hostmaster .' 0 ' ;
141+ $ ttl = $ data ["new " ]["ttl " ];
142+
143+ $ app ->db ->query ("INSERT INTO powerdns.records (domain_id, name, type, content, ttl, prio, change_date, ispconfig_id) VALUES ( $ zone_id, ' $ origin', 'SOA', ' $ content', $ ttl, 0, " .time ().", $ ispconfig_id) " );
144+
145+ }
146+
147+ function soa_update ($ event_name ,$ data ) {
148+ global $ app , $ conf ;
149+
150+ if ($ data ["new " ]["active " ] != 'Y ' ){
151+ if ($ data ["old " ]["active " ] != 'Y ' ) return ;
152+ $ this ->soa_delete ($ event_name ,$ data );
153+ } else {
154+ if ($ data ["old " ]["active " ] == 'Y ' ){
155+ $ origin = substr ($ data ["new " ]["origin " ], 0 , -1 );
156+ $ ispconfig_id = $ data ["new " ]["id " ];
157+ $ app ->db ->query ("UPDATE powerdns.domains SET name = ' $ origin' WHERE ispconfig_id = $ ispconfig_id " );
158+
159+ if (substr ($ data ["new " ]["ns " ], -1 ) == '. ' ){
160+ $ ns = substr ($ data ["new " ]["ns " ], 0 , -1 );
161+ } else {
162+ $ ns = $ data ["new " ]["ns " ].'. ' .$ origin ;
163+ }
164+ if ($ ns == '' ) $ ns = $ origin ;
165+
166+ $ hostmaster = substr ($ data ["new " ]["mbox " ], 0 , -1 );
167+ $ content = $ ns .' ' .$ hostmaster .' 0 ' ;
168+ $ ttl = $ data ["new " ]["ttl " ];
169+ $ app ->db ->query ("UPDATE powerdns.records SET name = ' $ origin', content = ' $ content', ttl = $ ttl, change_date = " .time ()." WHERE ispconfig_id = " .$ data ["new " ]["id " ]." AND type = 'SOA' " );
170+ } else {
171+ $ this ->soa_insert ($ event_name ,$ data );
172+ $ ispconfig_id = $ data ["new " ]["id " ];
173+ if ($ records = $ app ->db ->queryAllRecords ("SELECT * FROM dns_rr WHERE zone = $ ispconfig_id AND active = 'Y' " )){
174+ foreach ($ records as $ record ){
175+ foreach ($ record as $ key => $ val ){
176+ $ data ["new " ][$ key ] = $ val ;
177+ }
178+ $ this ->rr_insert ("dns_rr_insert " , $ data );
179+ }
180+ }
181+
182+ }
183+ }
184+
185+ }
186+
187+ function soa_delete ($ event_name ,$ data ) {
188+ global $ app , $ conf ;
189+
190+ $ zone = $ app ->db ->queryOneRecord ("SELECT * FROM powerdns.domains WHERE ispconfig_id = " .$ data ["old " ]["id " ]);
191+ $ zone_id = $ zone ["id " ];
192+ $ app ->db ->query ("DELETE FROM powerdns.records WHERE domain_id = $ zone_id " );
193+ $ app ->db ->query ("DELETE FROM powerdns.domains WHERE id = $ zone_id " );
194+
195+ }
196+
197+ function rr_insert ($ event_name ,$ data ) {
198+ global $ app , $ conf ;
199+ if ($ data ["new " ]["active " ] != 'Y ' ) return ;
200+
201+ $ zone = $ app ->db ->queryOneRecord ("SELECT * FROM dns_soa WHERE id = " .$ data ["new " ]["zone " ]);
202+ $ origin = substr ($ zone ["origin " ], 0 , -1 );
203+ $ powerdns_zone = $ app ->db ->queryOneRecord ("SELECT * FROM powerdns.domains WHERE ispconfig_id = " .$ data ["new " ]["zone " ]);
204+ $ zone_id = $ powerdns_zone ["id " ];
205+
206+ $ type = $ data ["new " ]["type " ];
207+
208+ switch ($ type ) {
209+ case "PTR " :
210+ $ name = $ data ["new " ]["name " ];
211+ break ;
212+ default :
213+ if (substr ($ data ["new " ]["name " ], -1 ) == '. ' ){
214+ $ name = substr ($ data ["new " ]["name " ], 0 , -1 );
215+ } else {
216+ if ($ data ["new " ]["name " ] == "" ){
217+ $ name = $ origin ;
218+ } else {
219+ $ name = $ data ["new " ]["name " ].'. ' .$ origin ;
220+ }
221+ }
222+ if ($ name == '' ) $ name = $ origin ;
223+ }
224+
225+ switch ($ type ) {
226+ case "CNAME " :
227+ case "MX " :
228+ case "NS " :
229+ case "ALIAS " :
230+ case "PTR " :
231+ case "SRV " :
232+ if (substr ($ data ["new " ]["data " ], -1 ) == '. ' ){
233+ $ content = substr ($ data ["new " ]["data " ], 0 , -1 );
234+ } else {
235+ $ content = $ data ["new " ]["data " ].'. ' .$ origin ;
236+ }
237+ break ;
238+ case "HINFO " :
239+ $ content = $ data ["new " ]["data " ];
240+ $ quote1 = strpos ($ content , '" ' );
241+ if ($ quote1 !== FALSE ){
242+ $ quote2 = strpos (substr ($ content , ($ quote1 + 1 )), '" ' );
243+ }
244+ if ($ quote1 !== FALSE && $ quote2 !== FALSE ){
245+ $ text_between_quotes = str_replace (' ' , '_ ' , substr ($ content , ($ quote1 + 1 ), (($ quote2 - $ quote1 ))));
246+ $ content = $ text_between_quotes .substr ($ content , ($ quote2 + 2 ));
247+ }
248+ break ;
249+ default :
250+ $ content = $ data ["new " ]["data " ];
251+ }
252+
253+ $ ttl = $ data ["new " ]["ttl " ];
254+ $ prio = $ data ["new " ]["aux " ];
255+ $ change_date = time ();
256+ $ ispconfig_id = $ data ["new " ]["id " ];
257+
258+ $ app ->db ->query ("INSERT INTO powerdns.records (domain_id, name, type, content, ttl, prio, change_date, ispconfig_id) VALUES ( $ zone_id, ' $ name', ' $ type', ' $ content', $ ttl, $ prio, $ change_date, $ ispconfig_id) " );
259+
260+ }
261+
262+ function rr_update ($ event_name ,$ data ) {
263+ global $ app , $ conf ;
264+
265+ if ($ data ["new " ]["active " ] != 'Y ' ){
266+ if ($ data ["old " ]["active " ] != 'Y ' ) return ;
267+ $ this ->rr_delete ($ event_name ,$ data );
268+ } else {
269+ if ($ data ["old " ]["active " ] == 'Y ' ){
270+ $ zone = $ app ->db ->queryOneRecord ("SELECT * FROM dns_soa WHERE id = " .$ data ["new " ]["zone " ]);
271+ $ origin = substr ($ zone ["origin " ], 0 , -1 );
272+ $ powerdns_zone = $ app ->db ->queryOneRecord ("SELECT * FROM powerdns.domains WHERE ispconfig_id = " .$ data ["new " ]["zone " ]);
273+ $ zone_id = $ powerdns_zone ["id " ];
274+
275+ $ type = $ data ["new " ]["type " ];
276+
277+ switch ($ type ) {
278+ case "PTR " :
279+ $ name = $ data ["new " ]["name " ];
280+ break ;
281+ default :
282+ if (substr ($ data ["new " ]["name " ], -1 ) == '. ' ){
283+ $ name = substr ($ data ["new " ]["name " ], 0 , -1 );
284+ } else {
285+ if ($ data ["new " ]["name " ] == "" ){
286+ $ name = $ origin ;
287+ } else {
288+ $ name = $ data ["new " ]["name " ].'. ' .$ origin ;
289+ }
290+ }
291+ if ($ name == '' ) $ name = $ origin ;
292+ }
293+
294+ switch ($ type ) {
295+ case "CNAME " :
296+ case "MX " :
297+ case "NS " :
298+ case "ALIAS " :
299+ case "PTR " :
300+ case "SRV " :
301+ if (substr ($ data ["new " ]["data " ], -1 ) == '. ' ){
302+ $ content = substr ($ data ["new " ]["data " ], 0 , -1 );
303+ } else {
304+ $ content = $ data ["new " ]["data " ].'. ' .$ origin ;
305+ }
306+ break ;
307+ case "HINFO " :
308+ $ content = $ data ["new " ]["data " ];
309+ $ quote1 = strpos ($ content , '" ' );
310+ if ($ quote1 !== FALSE ){
311+ $ quote2 = strpos (substr ($ content , ($ quote1 + 1 )), '" ' );
312+ }
313+ if ($ quote1 !== FALSE && $ quote2 !== FALSE ){
314+ $ text_between_quotes = str_replace (' ' , '_ ' , substr ($ content , ($ quote1 + 1 ), (($ quote2 - $ quote1 ))));
315+ $ content = $ text_between_quotes .substr ($ content , ($ quote2 + 2 ));
316+ }
317+ break ;
318+ default :
319+ $ content = $ data ["new " ]["data " ];
320+ }
321+
322+ $ ttl = $ data ["new " ]["ttl " ];
323+ $ prio = $ data ["new " ]["aux " ];
324+ $ change_date = time ();
325+ $ ispconfig_id = $ data ["new " ]["id " ];
326+ //echo "UPDATE powerdns.records SET name = '$name', type = '$type', content = '$content', ttl = $ttl, prio = $prio, change_date = ".time()." WHERE id = $record_id";
327+ $ app ->db ->query ("UPDATE powerdns.records SET name = ' $ name', type = ' $ type', content = ' $ content', ttl = $ ttl, prio = $ prio, change_date = " .time ()." WHERE ispconfig_id = $ ispconfig_id AND type != 'SOA' " );
328+
329+ } else {
330+ $ this ->rr_insert ($ event_name ,$ data );
331+ }
332+ }
333+
334+ }
335+
336+ function rr_delete ($ event_name ,$ data ) {
337+ global $ app , $ conf ;
338+
339+ $ ispconfig_id = $ data ["old " ]["id " ];
340+ $ app ->db ->query ("DELETE FROM powerdns.records WHERE ispconfig_id = $ ispconfig_id AND type != 'SOA' " );
341+
342+ }
343+
344+
345+
346+
347+ } // end class
348+
349+ ?>
0 commit comments