]>
git.proxmox.com Git - pve-network.git/blob - PVE/Network/SDN/Dns/PowerdnsPlugin.pm
1 package PVE
:: Network
:: SDN
:: Dns
:: PowerdnsPlugin
;
10 use NetAddr
:: IP
qw(:lower) ;
11 use base
( 'PVE::Network::SDN::Dns::Plugin' );
34 url
=> { optional
=> 0 },
35 key
=> { optional
=> 0 },
36 ttl
=> { optional
=> 1 },
37 reversemaskv6
=> { optional
=> 1 , description
=> "force a different netmask for the ipv6 reverse zone name." },
42 # Plugin implementation
45 my ( $class, $plugin_config, $zone, $hostname, $ip, $noerr ) = @_ ;
47 my $url = $plugin_config ->{ url
};
48 my $key = $plugin_config ->{ key
};
49 my $ttl = $plugin_config ->{ ttl
} ?
$plugin_config ->{ ttl
} : 14400 ;
50 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
52 my $type = Net
:: IP
:: ip_is_ipv6
( $ip ) ?
"AAAA" : "A" ;
53 my $fqdn = $hostname . "." . $zone . "." ;
55 my $zonecontent = get_zone_content
( $plugin_config, $zone );
56 my $existing_rrset = get_zone_rrset
( $zonecontent, $fqdn );
58 my $final_records = [];
59 my $foundrecord = undef ;
60 foreach my $record (@{ $existing_rrset ->{ records
}}) {
61 if ( $record ->{ content
} eq $ip ) {
65 push @$final_records, $record ;
67 return if $foundrecord ;
69 my $record = { content
=> $ip,
70 disabled
=> JSON
:: false
,
75 push @$final_records, $record ;
77 my $rrset = { name
=> $fqdn,
80 changetype
=> "REPLACE" ,
81 records
=> $final_records };
84 my $params = { rrsets
=> [ $rrset ] };
87 PVE
:: Network
:: SDN
:: api_request
( "PATCH" , " $url/zones/$zone " , $headers, $params );
91 die "error add $fqdn to zone $zone : $@ " if ! $noerr ;
96 my ( $class, $plugin_config, $zone, $hostname, $ip, $noerr ) = @_ ;
98 my $url = $plugin_config ->{ url
};
99 my $key = $plugin_config ->{ key
};
100 my $ttl = $plugin_config ->{ ttl
} ?
$plugin_config ->{ ttl
} : 14400 ;
101 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
104 my $reverseip = Net
:: IP-
> new ( $ip )-> reverse_ip ();
108 my $record = { content
=> $hostname,
109 disabled
=> JSON
:: false
,
114 my $rrset = { name
=> $reverseip,
117 changetype
=> "REPLACE" ,
118 records
=> [ $record ] };
121 my $params = { rrsets
=> [ $rrset ] };
124 PVE
:: Network
:: SDN
:: api_request
( "PATCH" , " $url/zones/$zone " , $headers, $params );
128 die "error add $reverseip to zone $zone : $@ " if ! $noerr ;
133 my ( $class, $plugin_config, $zone, $hostname, $ip, $noerr ) = @_ ;
135 my $url = $plugin_config ->{ url
};
136 my $key = $plugin_config ->{ key
};
137 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
138 my $fqdn = $hostname . "." . $zone . "." ;
139 my $type = Net
:: IP
:: ip_is_ipv6
( $ip ) ?
"AAAA" : "A" ;
141 my $zonecontent = get_zone_content
( $plugin_config, $zone );
142 my $existing_rrset = get_zone_rrset
( $zonecontent, $fqdn );
144 my $final_records = [];
145 my $foundrecord = undef ;
146 foreach my $record (@{ $existing_rrset ->{ records
}}) {
147 if ( $record ->{ content
} eq $ip ) {
151 push @$final_records, $record ;
153 return if ! $foundrecord ;
157 if ( scalar (@{ $final_records }) > 0 ) {
158 #if we still have other records, we rewrite them without removed ip
159 $rrset = { name
=> $fqdn,
161 ttl
=> $existing_rrset ->{ ttl
},
162 changetype
=> "REPLACE" ,
163 records
=> $final_records };
167 $rrset = { name
=> $fqdn,
169 changetype
=> "DELETE" ,
173 my $params = { rrsets
=> [ $rrset ] };
176 PVE
:: Network
:: SDN
:: api_request
( "PATCH" , " $url/zones/$zone " , $headers, $params );
180 die "error delete $fqdn from zone $zone : $@ " if ! $noerr ;
185 my ( $class, $plugin_config, $zone, $ip, $noerr ) = @_ ;
187 my $url = $plugin_config ->{ url
};
188 my $key = $plugin_config ->{ key
};
189 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
191 my $reverseip = Net
:: IP-
> new ( $ip )-> reverse_ip ();
195 my $rrset = { name
=> $reverseip,
197 changetype
=> "DELETE" ,
200 my $params = { rrsets
=> [ $rrset ] };
203 PVE
:: Network
:: SDN
:: api_request
( "PATCH" , " $url/zones/$zone " , $headers, $params );
207 die "error delete $reverseip from zone $zone : $@ " if ! $noerr ;
212 my ( $class, $plugin_config, $zone, $noerr ) = @_ ;
214 #verify that api is working
216 my $url = $plugin_config ->{ url
};
217 my $key = $plugin_config ->{ key
};
218 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
221 PVE
:: Network
:: SDN
:: api_request
( "GET" , " $url/zones/$zone?rrsets =false" , $headers );
225 die "can't read zone $zone : $@ " if ! $noerr ;
229 sub get_reversedns_zone
{
230 my ( $class, $plugin_config, $subnetid, $subnet, $ip ) = @_ ;
232 my $cidr = $subnet ->{ cidr
};
233 my $mask = $subnet ->{ mask
};
237 if ( Net
:: IP
:: ip_is_ipv4
( $ip )) {
238 my ( $ipblock1, $ipblock2, $ipblock3, $ipblock4 ) = split ( /\./ , $ip );
240 my $ipv4 = new NetAddr
:: IP
( $cidr );
241 #private addresse #powerdns built-in private zone : serve-rfc1918
242 if ( $ipv4 -> is_rfc1918 ()) {
243 if ( $ipblock1 == 192 ) {
244 $zone = "168.192.in-addr.arpa." ;
245 } elsif ( $ipblock1 == 172 ) {
246 $zone = "16-31.172.in-addr.arpa." ;
247 } elsif ( $ipblock1 == 10 ) {
248 $zone = "10.in-addr.arpa." ;
252 #public ipv4 : RIPE,ARIN,AFRNIC
253 #. 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)
254 #One or more /24 type zones need to be created if your address space has a prefix length between /17 and /24.
255 # If your prefix length is between /16 and /9 you will have to request one or more delegations for /16 type zones.
258 $zone = " $ipblock3 . $ipblock2 . $ipblock1 .in-addr.arpa." ;
259 } elsif ( $mask <= 16 ) {
260 $zone = " $ipblock2 . $ipblock1 .in-addr.arpa." ;
261 } elsif ( $mask <= 8 ) {
262 $zone = " $ipblock1 .in-addr.arpa." ;
266 $mask = $plugin_config ->{ reversemaskv6
} if $plugin_config ->{ reversemaskv6
};
267 die "reverse dns zone mask need to be a multiple of 4" if ( $mask % 4 );
268 my $networkv6 = NetAddr
:: IP-
> new ( $cidr )-> network ();
269 $zone = Net
:: IP-
> new ( $networkv6 )-> reverse_ip ();
277 my ( $class, $plugin_config ) = @_ ;
279 #verify that api is working
281 my $url = $plugin_config ->{ url
};
282 my $key = $plugin_config ->{ key
};
283 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
286 PVE
:: Network
:: SDN
:: api_request
( "GET" , " $url " , $headers );
290 die "dns api error: $@ " ;
295 sub get_zone_content
{
296 my ( $plugin_config, $zone ) = @_ ;
298 #verify that api is working
300 my $url = $plugin_config ->{ url
};
301 my $key = $plugin_config ->{ key
};
302 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
306 $result = PVE
:: Network
:: SDN
:: api_request
( "GET" , " $url/zones/$zone " , $headers );
310 die "can't read zone $zone : $@ " ;
316 my ( $zonecontent, $name ) = @_ ;
318 my $rrsetresult = undef ;
319 foreach my $rrset (@{ $zonecontent ->{ rrsets
}}) {
320 next if $rrset ->{ name
} ne $name ;
321 $rrsetresult = $rrset ;