]>
git.proxmox.com Git - pve-network.git/blob - src/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
,
74 push @$final_records, $record ;
76 my $rrset = { name
=> $fqdn,
79 changetype
=> "REPLACE" ,
80 records
=> $final_records };
83 my $params = { rrsets
=> [ $rrset ] };
86 PVE
:: Network
:: SDN
:: api_request
( "PATCH" , " $url/zones/$zone " , $headers, $params );
90 die "error add $fqdn to zone $zone : $@ " if ! $noerr ;
95 my ( $class, $plugin_config, $zone, $hostname, $ip, $noerr ) = @_ ;
97 my $url = $plugin_config ->{ url
};
98 my $key = $plugin_config ->{ key
};
99 my $ttl = $plugin_config ->{ ttl
} ?
$plugin_config ->{ ttl
} : 14400 ;
100 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
103 my $reverseip = Net
:: IP-
> new ( $ip )-> reverse_ip ();
107 my $record = { content
=> $hostname,
108 disabled
=> JSON
:: false
,
112 my $rrset = { name
=> $reverseip,
115 changetype
=> "REPLACE" ,
116 records
=> [ $record ] };
119 my $params = { rrsets
=> [ $rrset ] };
122 PVE
:: Network
:: SDN
:: api_request
( "PATCH" , " $url/zones/$zone " , $headers, $params );
126 die "error add $reverseip to zone $zone : $@ " if ! $noerr ;
131 my ( $class, $plugin_config, $zone, $hostname, $ip, $noerr ) = @_ ;
133 my $url = $plugin_config ->{ url
};
134 my $key = $plugin_config ->{ key
};
135 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
136 my $fqdn = $hostname . "." . $zone . "." ;
137 my $type = Net
:: IP
:: ip_is_ipv6
( $ip ) ?
"AAAA" : "A" ;
139 my $zonecontent = get_zone_content
( $plugin_config, $zone );
140 my $existing_rrset = get_zone_rrset
( $zonecontent, $fqdn );
142 my $final_records = [];
143 my $foundrecord = undef ;
144 foreach my $record (@{ $existing_rrset ->{ records
}}) {
145 if ( $record ->{ content
} eq $ip ) {
149 push @$final_records, $record ;
151 return if ! $foundrecord ;
155 if ( scalar (@{ $final_records }) > 0 ) {
156 #if we still have other records, we rewrite them without removed ip
157 $rrset = { name
=> $fqdn,
159 ttl
=> $existing_rrset ->{ ttl
},
160 changetype
=> "REPLACE" ,
161 records
=> $final_records };
165 $rrset = { name
=> $fqdn,
167 changetype
=> "DELETE" ,
171 my $params = { rrsets
=> [ $rrset ] };
174 PVE
:: Network
:: SDN
:: api_request
( "PATCH" , " $url/zones/$zone " , $headers, $params );
178 die "error delete $fqdn from zone $zone : $@ " if ! $noerr ;
183 my ( $class, $plugin_config, $zone, $ip, $noerr ) = @_ ;
185 my $url = $plugin_config ->{ url
};
186 my $key = $plugin_config ->{ key
};
187 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
189 my $reverseip = Net
:: IP-
> new ( $ip )-> reverse_ip ();
193 my $rrset = { name
=> $reverseip,
195 changetype
=> "DELETE" ,
198 my $params = { rrsets
=> [ $rrset ] };
201 PVE
:: Network
:: SDN
:: api_request
( "PATCH" , " $url/zones/$zone " , $headers, $params );
205 die "error delete $reverseip from zone $zone : $@ " if ! $noerr ;
210 my ( $class, $plugin_config, $zone, $noerr ) = @_ ;
212 #verify that api is working
214 my $url = $plugin_config ->{ url
};
215 my $key = $plugin_config ->{ key
};
216 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
219 PVE
:: Network
:: SDN
:: api_request
( "GET" , " $url/zones/$zone?rrsets =false" , $headers );
223 die "can't read zone $zone : $@ " if ! $noerr ;
227 sub get_reversedns_zone
{
228 my ( $class, $plugin_config, $subnetid, $subnet, $ip ) = @_ ;
230 my $cidr = $subnet ->{ cidr
};
231 my $mask = $subnet ->{ mask
};
235 if ( Net
:: IP
:: ip_is_ipv4
( $ip )) {
236 my ( $ipblock1, $ipblock2, $ipblock3, $ipblock4 ) = split ( /\./ , $ip );
238 my $ipv4 = NetAddr
:: IP-
> new ( $cidr );
239 #private addresse #powerdns built-in private zone : serve-rfc1918
240 if ( $ipv4 -> is_rfc1918 ()) {
241 if ( $ipblock1 == 192 ) {
242 $zone = "168.192.in-addr.arpa." ;
243 } elsif ( $ipblock1 == 172 ) {
244 $zone = "16-31.172.in-addr.arpa." ;
245 } elsif ( $ipblock1 == 10 ) {
246 $zone = "10.in-addr.arpa." ;
250 #public ipv4 : RIPE,ARIN,AFRNIC
251 #. 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)
252 #One or more /24 type zones need to be created if your address space has a prefix length between /17 and /24.
253 # If your prefix length is between /16 and /9 you will have to request one or more delegations for /16 type zones.
256 $zone = " $ipblock3 . $ipblock2 . $ipblock1 .in-addr.arpa." ;
257 } elsif ( $mask <= 16 ) {
258 $zone = " $ipblock2 . $ipblock1 .in-addr.arpa." ;
259 } elsif ( $mask <= 8 ) {
260 $zone = " $ipblock1 .in-addr.arpa." ;
264 $mask = $plugin_config ->{ reversemaskv6
} if $plugin_config ->{ reversemaskv6
};
265 die "reverse dns zone mask need to be a multiple of 4" if ( $mask % 4 );
266 my $networkv6 = NetAddr
:: IP-
> new ( $cidr )-> network ();
267 $zone = Net
:: IP-
> new ( $networkv6 )-> reverse_ip ();
275 my ( $class, $plugin_config ) = @_ ;
277 #verify that api is working
279 my $url = $plugin_config ->{ url
};
280 my $key = $plugin_config ->{ key
};
281 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
284 PVE
:: Network
:: SDN
:: api_request
( "GET" , " $url " , $headers );
288 die "dns api error: $@ " ;
293 sub get_zone_content
{
294 my ( $plugin_config, $zone ) = @_ ;
296 #verify that api is working
298 my $url = $plugin_config ->{ url
};
299 my $key = $plugin_config ->{ key
};
300 my $headers = [ 'Content-Type' => 'application/json; charset=UTF-8' , 'X-API-Key' => $key ];
304 $result = PVE
:: Network
:: SDN
:: api_request
( "GET" , " $url/zones/$zone " , $headers );
308 die "can't read zone $zone : $@ " ;
314 my ( $zonecontent, $name ) = @_ ;
316 my $rrsetresult = undef ;
317 foreach my $rrset (@{ $zonecontent ->{ rrsets
}}) {
318 next if $rrset ->{ name
} ne $name ;
319 $rrsetresult = $rrset ;