]> git.proxmox.com Git - pve-network.git/blob - PVE/Network/SDN/Dns/PowerdnsPlugin.pm
move dns options from subnets to zone
[pve-network.git] / PVE / Network / SDN / Dns / PowerdnsPlugin.pm
1 package PVE::Network::SDN::Dns::PowerdnsPlugin;
2
3 use strict;
4 use warnings;
5 use PVE::INotify;
6 use PVE::Cluster;
7 use PVE::Tools;
8 use JSON;
9 use Net::IP;
10 use NetAddr::IP;
11
12 use base('PVE::Network::SDN::Dns::Plugin');
13
14 sub type {
15 return 'powerdns';
16 }
17
18 sub properties {
19 return {
20 url => {
21 type => 'string',
22 },
23 key => {
24 type => 'string',
25 },
26 reversemaskv6 => {
27 type => 'integer'
28 },
29 };
30 }
31
32 sub options {
33
34 return {
35 url => { optional => 0},
36 key => { optional => 0 },
37 ttl => { optional => 1 },
38 reversemaskv6 => { optional => 1, description => "force a different netmask for the ipv6 reverse zone name." },
39
40 };
41 }
42
43 # Plugin implementation
44
45 sub add_a_record {
46 my ($class, $plugin_config, $zone, $hostname, $ip) = @_;
47
48 my $url = $plugin_config->{url};
49 my $key = $plugin_config->{key};
50 my $ttl = $plugin_config->{ttl} ? $plugin_config->{ttl} : 14400;
51 my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
52
53 my $type = Net::IP::ip_is_ipv6($ip) ? "AAAA" : "A";
54 my $fqdn = $hostname.".".$zone.".";
55
56
57 my $record = { content => $ip,
58 disabled => JSON::false,
59 name => $fqdn,
60 type => $type,
61 priority => 0 };
62
63 my $rrset = { name => $fqdn,
64 type => $type,
65 ttl => $ttl,
66 changetype => "REPLACE",
67 records => [ $record ] };
68
69
70 my $params = { rrsets => [ $rrset ] };
71
72 eval {
73 PVE::Network::SDN::Dns::Plugin::api_request("PATCH", "$url/zones/$zone", $headers, $params);
74 };
75
76 if ($@) {
77 die "error add $fqdn to zone $zone: $@";
78 }
79 }
80
81 sub add_ptr_record {
82 my ($class, $plugin_config, $zone, $hostname, $ip) = @_;
83
84 my $url = $plugin_config->{url};
85 my $key = $plugin_config->{key};
86 my $ttl = $plugin_config->{ttl} ? $plugin_config->{ttl} : 14400;
87 my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
88 $hostname .= ".";
89
90 my $reverseip = Net::IP->new($ip)->reverse_ip();
91
92 my $type = "PTR";
93
94 my $record = { content => $hostname,
95 disabled => JSON::false,
96 name => $reverseip,
97 type => $type,
98 priority => 0 };
99
100 my $rrset = { name => $reverseip,
101 type => $type,
102 ttl => $ttl,
103 changetype => "REPLACE",
104 records => [ $record ] };
105
106
107 my $params = { rrsets => [ $rrset ] };
108
109 eval {
110 PVE::Network::SDN::Dns::Plugin::api_request("PATCH", "$url/zones/$zone", $headers, $params);
111 };
112
113 if ($@) {
114 die "error add $reverseip to zone $zone: $@";
115 }
116 }
117
118 sub del_a_record {
119 my ($class, $plugin_config, $zone, $hostname, $ip) = @_;
120
121 my $url = $plugin_config->{url};
122 my $key = $plugin_config->{key};
123 my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
124 my $fqdn = $hostname.".".$zone.".";
125 my $type = Net::IP::ip_is_ipv6($ip) ? "AAAA" : "A";
126
127 my $rrset = { name => $fqdn,
128 type => $type,
129 changetype => "DELETE",
130 records => [] };
131
132 my $params = { rrsets => [ $rrset ] };
133
134 eval {
135 PVE::Network::SDN::Dns::Plugin::api_request("PATCH", "$url/zones/$zone", $headers, $params);
136 };
137
138 if ($@) {
139 die "error delete $fqdn from zone $zone: $@";
140 }
141 }
142
143 sub del_ptr_record {
144 my ($class, $plugin_config, $zone, $ip) = @_;
145
146 my $url = $plugin_config->{url};
147 my $key = $plugin_config->{key};
148 my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
149
150 my $reverseip = Net::IP->new($ip)->reverse_ip();
151
152 my $type = "PTR";
153
154 my $rrset = { name => $reverseip,
155 type => $type,
156 changetype => "DELETE",
157 records => [] };
158
159 my $params = { rrsets => [ $rrset ] };
160
161 eval {
162 PVE::Network::SDN::Dns::Plugin::api_request("PATCH", "$url/zones/$zone", $headers, $params);
163 };
164
165 if ($@) {
166 die "error delete $reverseip from zone $zone: $@";
167 }
168 }
169
170 sub verify_zone {
171 my ($class, $plugin_config, $zone) = @_;
172
173 #verify that api is working
174
175 my $url = $plugin_config->{url};
176 my $key = $plugin_config->{key};
177 my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
178
179 eval {
180 PVE::Network::SDN::Dns::Plugin::api_request("GET", "$url/zones/$zone", $headers);
181 };
182
183 if ($@) {
184 die "can't read zone $zone: $@";
185 }
186 }
187
188 sub get_reversedns_zone {
189 my ($class, $plugin_config, $subnetid, $ip) = @_;
190
191 my ($network, $mask) = split(/-/, $subnetid);
192
193 my $cidr = "$ip/$mask";
194 my $zone = "";
195
196 if (Net::IP::ip_is_ipv4($ip)) {
197 my ($ipblock1, $ipblock2, $ipblock3, $ipblock4) = split(/\./, $ip);
198
199 my $ipv4 = new NetAddr::IP($cidr);
200 #private addresse #powerdns built-in private zone : serve-rfc1918
201 if($ipv4->is_rfc1918()) {
202 if ($ipblock1 == 192) {
203 $zone = "168.192.in-addr.arpa.";
204 } elsif ($ipblock1 == 172) {
205 $zone = "16-31.172.in-addr.arpa.";
206 } elsif ($ipblock1 == 10) {
207 $zone = "10.in-addr.arpa.";
208 }
209
210 } else {
211 #public ipv4 : RIPE,ARIN,AFRNIC
212 #. Delegations can be managed in IPv4 on bit boundaries (/8, /16 or /24s), and IPv6 networks can be managed on nibble boundaries (every 4 bits of the IPv6 address)
213 #One or more /24 type zones need to be created if your address space has a prefix length between /17 and /24.
214 # If your prefix length is between /16 and /9 you will have to request one or more delegations for /16 type zones.
215
216 if ($mask <= 24) {
217 $zone = "$ipblock3.$ipblock2.$ipblock1.in-addr.arpa.";
218 } elsif ($mask <= 16) {
219 $zone = "$ipblock2.$ipblock1.in-addr.arpa.";
220 } elsif ($mask <= 8) {
221 $zone = "$ipblock1.in-addr.arpa.";
222 }
223 }
224 } else {
225 $mask = $plugin_config->{reversemaskv6} if $plugin_config->{reversemaskv6};
226 die "reverse dns zone mask need to be a multiple of 4" if ($mask % 4);
227 my $networkv6 = NetAddr::IP->new($cidr)->network();
228 $zone = Net::IP->new($networkv6)->reverse_ip();
229 }
230
231 return $zone;
232 }
233
234
235 sub on_update_hook {
236 my ($class, $plugin_config) = @_;
237
238 #verify that api is working
239
240 my $url = $plugin_config->{url};
241 my $key = $plugin_config->{key};
242 my $headers = ['Content-Type' => 'application/json; charset=UTF-8', 'X-API-Key' => $key];
243
244 eval {
245 PVE::Network::SDN::Dns::Plugin::api_request("GET", "$url", $headers);
246 };
247
248 if ($@) {
249 die "dns api error: $@";
250 }
251 }
252
253 1;
254
255