GithubHelp home page GithubHelp logo

powerdns-php's Introduction

Latest Version on Packagist Software License Build Status Total Downloads

powerdns-php

A PHP client to communicate with the PowerDNS API.

Install

Via Composer

$ composer require exonet/powerdns-php

Usage

Basic example how to create a new DNS zone and insert a few DNS records.

use Exonet\Powerdns\Powerdns;
use Exonet\Powerdns\RecordType;
use Exonet\Powerdns\Resources\ResourceRecord;
use Exonet\Powerdns\Resources\Record;

// Initialize the Powerdns client.
$powerdns = new Powerdns('127.0.0.1', 'powerdns_secret_string');

// Create a new zone.
$zone = $powerdns->createZone(
    'example.com',
    ['ns1.example.com.', 'ns2.example.com.']
);

// Add two DNS records to the zone.
$zone->create([
    ['type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60, 'name' => '@'],
    ['type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60, 'name' => 'www'],
]);

// OR use the Object-based way
$zone->create([
    (new ResourceRecord())->setType(RecordType::A)->setRecord('127.0.0.1')->setName('@')->setTtl(60),
    (new ResourceRecord())->setType(RecordType::A)->setRecord((new Record())->setContent('127.0.0.1'))->setName('@')->setTtl(60),
]);

See the examples directory for more.

Change log

Please see releases for more information on what has changed recently.

Testing

Testing against multiple PHP / PowerDNS versions can be done by using the provided docker-compose.yml and the run-tests.sh shell script:

$ docker-compose up -d
$ ./run-tests.sh

After running docker-compose up -d wait a few seconds so PowerDNS can be initialized. You can leave the containers running and call the test script multiple times.

To test against a specific PHP / PowerDNS combination, you can provide the PHP version as first and the PowerDNS version as second parameter:

$ ./run-tests.sh 7.4 4.3

Contributing

Please see CONTRIBUTING and CODE_OF_CONDUCT for details.

Security

If you discover any security related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.

powerdns-php's People

Contributors

akondas avatar bennetgallein avatar brianvanwessel avatar dependabot[bot] avatar frankvanhest avatar jackdpeterson avatar jeroenvermeulen avatar mkevenaar-docktera avatar mvdgeijn avatar peter279k avatar robbinjanssen avatar robinmulder avatar rsplithof avatar styxit avatar th3mouk avatar trizz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

powerdns-php's Issues

Allow nsec3params to be changed.

To edit the nsec3params, the zone needs to be updated.

Detailed description

As a feature request, it would be nice to be able to change the nsec3params. This would end-up in the zone put request.

Context

I want to build a scheduled job to set nsec3params for each DNSSEC enabled domain.

Possible implementation

I will submit a PR for this soon.

Account field is not set while createZoneFromResource

The account field is not set when using the createZoneFromResource function and setting:

$newZone->setAccount("1024");

Detailed description

Below is the object before it is send to pdns api:

  ["name":"Exonet\Powerdns\Resources\Zone":private]=>
  string(21) "example.net."
  ["kind":"Exonet\Powerdns\Resources\Zone":private]=>
  string(6) "Native"
  ["serial":"Exonet\Powerdns\Resources\Zone":private]=>
  NULL
  ["notifiedSerial":"Exonet\Powerdns\Resources\Zone":private]=>
  NULL
  ["masters":"Exonet\Powerdns\Resources\Zone":private]=>
  array(0) {
  }
  ["dnssec":"Exonet\Powerdns\Resources\Zone":private]=>
  bool(false)
  ["nsec3param":"Exonet\Powerdns\Resources\Zone":private]=>
  NULL
  ["soaEdit":"Exonet\Powerdns\Resources\Zone":private]=>
  string(5) "EPOCH"
  ["soaEditApi":"Exonet\Powerdns\Resources\Zone":private]=>
  string(5) "EPOCH"
  ["apiRectify":"Exonet\Powerdns\Resources\Zone":private]=>
  bool(true)
  ["account":"Exonet\Powerdns\Resources\Zone":private]=>
  string(2) "1024"
  ["nameservers":"Exonet\Powerdns\Resources\Zone":private]=>
  array(3) {
    [0]=>
    string(16) "ns1.example.net."
    [1]=>
    string(16) "ns2.example.eu."
    [2]=>
    string(16) "ns3.example.net."
  }
}

Lookin in the database field, it's just empty not even null.

Your environment

Include as many relevant details about the environment you experienced the bug in and how to reproduce it.

  • Version used (e.g. PHP 7.1): PHP 7.4.11
  • PDNS: 4.3
  • Operating system and version (e.g. Ubuntu 16.04, Windows 7): RHEL 8

Compatibility with psr/log 3.0

Describe the bug
This package depends on psr/log ^1.0 but current version is 3.0.
Installing will cause this error:

  Problem 1
    - Root composer.json requires exonet/powerdns-php ^4.1 -> satisfiable by exonet/powerdns-php[v4.1.0].
    - exonet/powerdns-php v4.1.0 requires psr/log ^1.0 -> found psr/log[1.0.0, ..., 1.1.4] but the package is fixed to 3.0.0 (lock file version) by a partial update and that version does not match. Make sure you list it as an argument for the update command.

To Reproduce

# Install latest psr/log or a package that depends on it.
composer require psr/log 3.0.0
composer require exonet/powerdns-php

Expected behavior
Package installs

How to create additional records for the same subdomain

I read on examples/manage_records.php the following:

/*
 * In PowerDNS there's no such thing as 'updating' a record. Instead, just create a new record with the same name and
 * type, as this is the 'unique' combination for a record. The following example will change the IP for 'test2' from
 * '127.0.0.2' (see the example above) to  '127.0.1.2'.
 */

With this in mind, what is the best practice if we have an existing subdomain foo.bar.bz 1.2.3.4 and we want to add a second A record to the same subdomain without removing the first?

How to create multiple MX records

Ho I can create multiple MX records in PowerDNS using this library ?

zone.com	MX	1		3600	ASPMX.L.GOOGLE.COM	 
zone.com	MX	5		3600	ALT1.ASPMX.L.GOOGLE.COM
zone.com	MX	5		3600	ALT2.ASPMX.L.GOOGLE.COM
zone.com	MX	10		3600	ASPMX2.GOOGLEMAIL.COM
zone.com	MX	10		3600	ASPMX3.GOOGLEMAIL.COM

listZones could be faster

According to the PowerDNS documentation the listZones could be a lot faster. https://doc.powerdns.com/authoritative/http-api/zone.html#get--servers-server_id-zones
When providing the query parameter dnssec=false performance increase is for 12000 zones is a factor of 10.

I would be happy create a PR to include an argument for the listZones method to set the dnssec flag to false in the request to PowerDNS with a default true, so there won't be any BC breaking.

What is you thought about this?

TTL values of nameservers defaulting to 3600

Detailed description

When adding an zone it seems that the TTL value of NS records is set to 3600.

Context

Would be nice if we could add an TTL value too. For us 3600 it's a little bit low for me.

How to delete a zone?

Trying to delete a zone completely.

Tried this:

$powerdns->zone($domain)->delete();

Getting:

Call to undefined method Exonet\Powerdns\Zone::delete()

Delete metadata SOA-EDIT

Short description

Every domain that is created has metadata; kind (content): API-RECTIFY (1), SOA-EDIT (NONE) and SOA-EDIT-API (DEFAULT).

The issue: my system administrator asked me to remove the SOA-EDIT records. Ofcourse i can do this using a query/mysql; but it would be nice if i could the use the API for this.

Usecase

            $newZone = new ZoneResource();
            $newZone->setName($domain . '.');
            $newZone->setKind('master');
            $newZone->setNameservers($nameservers);

Description

$newZone->setSoaEdit(); // no parameter deletes the record (?)

or just:

$newZone->delSoaEdit(); // 

[update]
The API supports this: https://doc.powerdns.com/authoritative/http-api/metadata.html

Many thanks, keep up the good work!

How to return status code in controller

Hi Guys,

I'm trying to create a function which will add a zone to the DNS server and if the zone has been added successfully I would like to add this information to the user's account, now to do that I will need to get a status code in the controller.

So when I'm for example adding a zone or a record

e.g:
$powerdns->createZone($domain, $nameServers)->create($dnsRecords);

I'm looking to get some response like $powerdns['error'] => true or false or $powerdns->getStatusCode() => Conflict.

Currently when something will fail I'm getting exception but I don't know how I can process it in the controller.

Many thanks,
Matt

More human readable output

Is it possible to obtain zone records in more human readable format? Current result set is returned is so complex to parse and understand... Example:

Current version:

foreach ($zoneResourceSets as $resourceSet) {
    $recordContents = array_map(function (Record $record) {
        return $record->getContent();
    }, $resourceSet->getRecords());

    echo sprintf(
        '| %-4s | %30s --> %-30s%s',
        $resourceSet->getType(),
        $resourceSet->getName(),
        implode(', ', $recordContents),
        PHP_EOL
    );
}

Suggestion:

foreach ($zoneResourceSets as $resourceSet) {

        echo $resourceSet->getARecords();
        echo $resourceSet->getMXRecords();
}

All that "sprintf" magic is insanely complex. I would like to see JSON output rather than array objects.

This is not a problem, rather a suggestion to improve library to be more user friendly and easy to use for non hardcore PHP users.

How to increment serial ?

Hello,
I try to increment serial.

			$zone = $powerdns->zone("test.com");

			if(substr($zone->resource()->getSerial(), 0, 8) == date("Ymd")) {
				$serial = $zone->resource()->getSerial() + 1;
			}
			else {
				$serial = date("Ymd") . '00';
			}

			$zone->resource()->setSerial($serial);

why doesn't it work?
do you have another solution?

Bulk zone create

Hello,
Is it possible to use the project to create zones in bulk?
Now I am reading a list of domains, looping through it and creating the zones one by one. But I would hope that there is a way to submit bulk zones to the PowerDNS API.

Thank you.

Return a complete zone for a domain

Thank you for providing this excellent class of PowerDns control

I'm having a hard time understanding. How can we receive and format all entries in a domain's zone?

I can get the entries with -> zone ($ domain) -> get ();
However, I can't understand how to format it in a readable form.

Create a more specified zone

The purpose is to create a zone, with more specific options.

Detailed description

To create a zone, I think it would be nice to supply the Zone resource, instead of the parameters. This way it's easier to create a zone with more specific options, like a soaEditApi value.

Context

This makes it easier to create a more specific zone.

Possible implementation

$zone = new Resources\Zone();
$zone->set...();
...
$powerDns->createZoneFromResource($zone);

What needs to be done:

  1. Create a toArray function on the resource.
  2. Create a method which passes the data to $this->connector->patch()

Filtering and paginating lists

Detailed description

As a user I would like to filter lists of zones and paginate results.

I didn't see such a feature in the API.

Context

Why is this change important to you? How would you use it?

There is no search resource currently, so it would be nice to filter within a specific resource.
If there is a large result set, the request may time out.

Possible implementation

Unknown - ideally leverage the underlying API

Your environment

Include as many relevant details about the environment you experienced the bug in and how to reproduce it.

  • Version used: PHP 7.4
  • Operating system and version: Unix Centos

Cant connect to PowerdDNS - php fatal error

Detailed description

Seems like I can't connect to PDNS api - even though everything seems correct.
Changed also api port to 8081 in /src/Powerdns.php file.

php add.php

PHP Fatal error:  Uncaught Error: Wrong parameters for Exonet\Powerdns\Exceptions\PowerdnsException([string $message [, long $code [, Throwable $previous = NULL]]]) in /root/www/vendor/exonet/powerdns-php/src/Connector.php:159
Stack trace:
#0 /root/www/vendor/exonet/powerdns-php/src/Connector.php(159): Exception->__construct(NULL)
#1 /root/www/vendor/exonet/powerdns-php/src/Connector.php(128): Exonet\Powerdns\Connector->parseResponse(Object(GuzzleHttp\Psr7\Response))
#2 /root/www/vendor/exonet/powerdns-php/src/Connector.php(63): Exonet\Powerdns\Connector->makeCall('POST', 'zones', '{"name":"exampl...')
#3 /root/www/vendor/exonet/powerdns-php/src/Powerdns.php(146): Exonet\Powerdns\Connector->post('zones', Object(Exonet\Powerdns\Transformers\CreateZoneTransformer))
#4 /root/www/vendor/exonet/powerdns-php/examples/add.php(13): Exonet\Powerdns\Powerdns->createZone('example.com.', Array)
#5 {main}
  thrown in /root/www/vendor/exonet/powerdns-php/src/Connector.php on line 159

cat add.php

<?php

require __DIR__.'/../../../../vendor/autoload.php';
require __DIR__.'/CliLogger.php';
use Exonet\Powerdns\Powerdns;
use Exonet\Powerdns\RecordType;

// Initialize the Powerdns client.
$powerdns = new Powerdns('192.168.40.175', 'redacted_key');
// Create a new zone.
$zone = $powerdns->createZone(
    'example.com',
    ['ns1.example.com.', 'ns2.example.']
);

// Add two DNS records to the zone.
$zone->create([
    ['type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60, 'name' => '@'],
    ['type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60, 'name' => 'www'],
]);

Your environment

  • Ubuntu 18.04

  • PHP 7.2.19-0ubuntu0.18.04.1 (cli)

  • powerdns-php v 1.0

  • pdns-server v 4.1.10-1pdns.xenial

Can't set nameservers for existing zone

Hi. I am able to connect to PowerDNS, and I have successfully added and deleted a zone. I am having trouble editing an existing zone. The dnssec value will change, but the nameservers value won't. Is there something wrong with my code (below)?

// Set up data
$domain = 'example.com.';
$data = [
	'dnssec' => true,
	'nameservers' => [
		'ns1.testme.net.',
		'ns2.testme.net.',
		'ns3.testme.net.',
		'ns4.testme.net.',
	],
];

// Get existing zone
$api = new Powerdns($url, $apikey, $port);
$zone = $api->zone($canonicalDomain);
$resource = $zone->resource();

// Modify it
$resource->setDnssec($data['dnssec']);
$resource->setNameservers($data['nameservers']);

// Save changes
$transformer = new CreateZoneTransformer($resource);
$result = $zone->put($transformer);

// Verify values
$updatedZone = $api->zone($canonicalDomain);
$actual = [
	'dnssec' => $updatedZone->hasDnssec(),
	'nameservers' => $updatedZone->getNameservers(),
];
$this->assertEquals($data, $actual); // Fails, with nameservers not being changed!

Question: `put` a full array of rrset changes to zone

Detailed description

I'm trying to find a way in the powerdns client (Thanks for an awesome module by the way!) to update/replace a bunch of records in one fly (different record types).

My array format is exactly the same as in the new_domain_from_zone_resource.php example:

$deletedDnsRecords = [
    ['name' => 'subdomain', 'type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60],
    ['name' => 'subdomain', 'type' => RecordType::AAAA, 'content' => '2a00:1e28:3:1629::1', 'ttl' => 60],
    ['name' => 'www', 'type' => RecordType::CNAME, 'content' => 'google.com.', 'ttl' => 60],
];
$addedDnsRecords = [
    ['name' => 'subdomain', 'type' => RecordType::A, 'content' => '10.0.0.1', 'ttl' => 60],
    ['name' => 'www', 'type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60],
    ['name' => 'www', 'type' => RecordType::AAAA, 'content' => '2a00:1e28:3:1629::1', 'ttl' => 60],
];

I have a zone editor in a webpage, where the whole zone is loaded in from PowerDNS using this package.
When I click "Save zone", I calculate the difference between the "original" zone, and the updated one (coming in via a POST request).

To do this, I use two simple array_filter functions (This is the only way I know how to "compare" multidimensional arrays).

        $addedRecords = array_filter($newDnsRecords, function($element) use ($oldDnsRecords) {
            return !in_array($element, $oldDnsRecords);
        });


        $deletedRecords = array_filter($oldDnsRecords, function($element) use ($newDnsRecords) {
            return !in_array($element, $newDnsRecords);
        });

In the above case, I have e.g. changed subdomain from IP 127.0.0.1 to 10.0.0.1, as well as changed www from a CNAME to A and AAAA records.

What I'd love to do is to make a staged change that isn't committed, that does the following:

foreach($deletedRecords as $record) {
    $zone->find($record['name'], $record['type'])->delete();
}

foreach($addedRecords as $record) {
    // Somehow if I pass $record directly, I get `Cannot access offset of type string on string`.
    $currentZone->create($record['name'], $record['type'], array_unique($record['content']), $item['ttl']);
}

// Now commit the changes!

Currently if I do the two foreach, then obviously records will disappear from PowerDNS (and return NXDOMAIN) until they're added back again (in the next loop) - so a way to do the changes locally on a Zone object, and then when I've done the changes I do, I send a single save/commit call.

Whether that's even possible in PowerDNS's own API, I don't know :(

What I do know, is that when changing from A to CNAME or CNAME to A, I cannot just do a $currentZone->create() with e.g. a change from A to CNAME, since it will give a conflict exception.

I'm curious how other people handles a case like this, where you have to change/update batches, and go from one type to another - is the solution simply to e.g. delete the CNAME and then do another call shortly after to add the A record? Is there no way one can actually "replace" the RRset when changing to a different type?

Context

To push bigger changes (e.g. loading in zone templates), replacing "replacing" all the content in a zone is desirable.

Your environment

  • PHP 8.0 on MacOS and Linux.

How to add new NS with different TTL without remove existing NS

Detailed description

I have created a new zone with the default NS. How do I add a new NS with a different TTL without deleting the existing NS.

$domain = 'dns-new-zone-test.nl';
$nameServers = ['ns1.example.com.', 'ns2.example.com.'];
$dnsRecords = [
    ['name' => '@', 'type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60],
    ['name' => 'www', 'type' => RecordType::A, 'content' => '127.0.0.1', 'ttl' => 60],
    ['name' => 'mail01', 'type' => RecordType::A, 'content' => '127.0.0.1'],
    ['name' => 'mail02', 'type' => RecordType::A, 'content' => '127.0.0.2']
];

$powerdns = new Powerdns('127.0.0.1', 'very_secret_secret');

$powerdns->createZone($domain, $nameServers)->create($dnsRecords);

with this i have two NS

Name Type Status TTL Data
@ NS Active 3600 ns1.example.com.
@ NS Active 3600 ns2.example.com.

Then can I add one NS with a different TTL without deleting the existing NS?
I did with this, but the existing NS is gone

$zone->create('@', RecordType::NS, 'ns3.example.com.', 86400);

My assumption is that there is no need to send all existing records to add new records, just enough records have just been added.

Expectation

Name Type Status TTL Data
@ NS Active 3600 ns1.example.com.
@ NS Active 3600 ns2.example.com.
@ NS Active 86400 ns3.example.com.

Can anyone provide a more detailed sample regarding adding records without deleting the existing ones. This applies not only to NS but all records.

Thank you for the help

Create new NS, MX with different TTL

Hello, thanks again for the class.

Is it possible to create NS, MX records with different TTL?
So how to update the TTL of a specific NS, MX?

Adding an NS record without overwriting old ones

Hello,

I am trying to add a third NS record to the base domain via

$zone->create("@", RecordType::NS, $hostname.".", $ttl);

However in this case, all old records get deleted, and only the new one is being added. (as it was said in the example files when modifying a record)

How I can add it as a new NS record without overwriting the old ones?

Thank you.

Hardcoded PDNS port

Latest PDNS release 4.6 have web server on 8081 by default. Your lib hardcoded this for 8001. And better documentation would be appreciated ;) , fantastic library!

Multiple A records for the same hostname

Hello,

How can I add multiple A records for the same hostname? And then update/delete them? I.e. test.example.com has IPs 1.2.3.4. I need to add same hostname, with IP 5.6.7.8. Then I need to modify 1.2.3.4 to 9.10.11.12

Is it possible?
I tried sometime ago using the examples, but ended having funny issues like deleting one record resulted in deletion of all A records with the same hostname. Now I need it again, and not sure from where to start?

Thank you.

ResourceRecord::getZone() would be helpful

The ResourceRecord class has getters and setters for all private variables except that it's missing a getter for zone. A getZone() method would be useful for me, as I'm having to pass these objects around, and in a context where I don't have immediate access to the zone. The zone record is there on the ResourceRecord class, but because it's private, I can't access it.

Exception if comments is null

I'm getting the following exception thrown when calling $resourceRecord->getComments() and the value for $resourceRecord->comments is null:

TypeError: Return value of Exonet\Powerdns\Resources\ResourceRecord::getComments() must be of the type array, null returned

Perhaps $comments should be initialized to [] in ResourceRecord.php, line 29?

Or if that's not a good idea, then perhaps we could have a hasComments() method, so we can know when to call getComments()?

As it is right now, not even a try/catch block will suppress the exception.

Guzzle PSR7 released 2.0 which breaks this package

Guzzle release a new version of PSR7 which has removed \GuzzleHttp\Psr7\stream_for from the codebase.

Detailed description

For a quick fix, lock guzzlehttp/guzzle on 7.2 in composer.json.

For a lasting fix, see what the replacement is for \GuzzleHttp\Psr7\stream_for.

Context

Currently a composer update will break an application using this package.

Your environment

Use PHP8 and run a composer update and try to make a call to PowerDNS API.

How to delete a single record?

Hi,

I was wondering how to delete a single, specific record from a zone? For example if I have multiple MX records and want to delete or update one?

The $zone->find() can be restricted to the name and record type, but not to the content, which would be the "unique identifier" for that specific record.

Thanks

Manipulation of records for the zone

Looking for the best method to edit / delete records for the zone. As I understand there is no easy way to edit/delete single record from pdns in "traditional" way by some kind of ID. Only just by type or name. But what if have this:

@ IN A 127.0.0.1
@ IN A 127.0.0.2
...

Is it sane to just recreate all records when single record is edited/deleted? Rough logic:

step 1. Pushing edit button;
step 2. PHP script gathers all old records for the zone and deletes them;
step 3. After delete, PHP script writes new records.

Same for delete.

It is pretty hard to manipulate records when there is no unique identifier :-/ very strange decision from pdns side.

Fatal error by 'unknown' response status codes

I'm getting the following fatal error when the response returns a statuscode which is not 200,201,204 or 422:

Uncaught Error: Wrong parameters for Exonet\Powerdns\Exceptions\PowerdnsException([string $message [, long $code [, Throwable $previous = NULL]]]) in xxxxxx/vendor/exonet/powerdns-php/src/Connector.php:161

In my case, I'm getting a 403 statuscode which is causing this error. Shouldn't there be a default in the switch ($response->getStatusCode()) in the parseResponse method in Connector.php ? So in case we're getting a status code other than the 4 I mentioned before?

CNAME Record

Hello, again thanks for the code and I come to ask for help.

I'm having trouble creating CNAME records.

Apparently it is not in the correct format, but I cannot find the necessary format, could you help me with that?

Exonet \ Powerdns \ Exceptions \ ValidationException: Record www.domain.net./CNAME 'domain.net': Not in expected format (parsed as 'domain.net.') in /home/public_html/vendor/exonet/powerdns-php/src/Connector.php:155\nStack

Query for records/record sets without knowing the zone (add a search resource?)

Detailed description

As a developer I would like to query records by content and retrieve a list of records

Context

I have an older app that connects to PDNS via the database, and we're looking to move to using the API.
Our app has a list page that lets the user filter all records by the record content, zone etc.

I don't see this in the PDNS api or this project - has anyone solved this problem?

Possible implementation

Make use of the search endpoint in the API?

Your environment

  • Version used: PHP 7.4
  • Operating system and version: centos

Delete only 1 record from RR Set

Detailed description

I have some examples where I have multiple A records with the same name. eg:

  • test1.zone.example. IN A 127.0.0.1
  • test1.zone.example. IN A 127.0.0.2

PDNS will see this as Resource Record Set. And thus if I delete (with find) test1 both records are gone even if I want to have one left.

I'm aware that this is mainly PDNS behaviour, but any tip to handle this sort of cases?

Ohh and +1 for this project!

Problem adding TXT record.

Detailed description

When I want to add a TXT record, the dot character added to the beginning of the domain name causes the process to terminate with an error.

Possible implementation

When adding a TXT record, the domain name must not start with a dot character.

Define interfaces for classes PowerDNS and Connector for easy integration with testsuites

Detailed description

When you are testing an application with this package included, you'll need to have PowerDNS up and running. This can be a hazard and it slows down you tests. What I'm suggestion is that two interfaces are created. One for the class Powerdns and one the class Connector.
This allows an easy integration with testsuites, especially if you use Dependency Injection. When testing the behaviour of an application I'm only interested in what happens when something goes wrong in dealing with PowerDNS, without having to somehow simulate this by making for instance a false request to the PowerDNS API.

I hope I'm clear enough, otherwise please let me know. Is this something you are willing to add to the codebase?

Context

The interface for Connector makes it easier to implement your own connector in stead of having to extend the existing one.
The interface for Powerdns is, as stated above, for testsuites.

Possible implementation

I'm more than happy to submit a PR for this.

How to delete one specific record

I see in the examples the following

// To delete a specific record from the zone, perform a search followed by a delete:
$zone->find('test3')->delete();

/*
 * The example above will delete ALL records for 'test3' (in this example both the A and AAAA). If you'd like to remove
 * only a specific type, you can pass a second argument. The example below only removes the AAAA record for 'test2',
 * leaving the A record intact.
 */
$zone->find('test2', RecordType::AAAA)->delete();

If I have the following

test-sub    A    1.1.1.1
test-sub    A    2.2.2.2
test-sub    A    3.3.3.3

How do I go about deleting only test-sub A 1.1.1.1 without deleting the other two records which I want to keep in tact

Change buildUrl behavior

With the current buildUrl behavior, some environments cannot be used (kubernetes with proxy, for example)

Detailed description

Our development environment makes use of the kubernetes proxy to access the PowerDNS API. Unfortunately, that means that to access the API our URL is somewhat 'strange'.

Example of the URL on which we can access the API:
http://127.0.0.1:8001/api/v1/namespaces/dns/services/powerdns-api:8081/proxy/

As you can see, we already need to define port 8001, as this is the kubernetes proxy port. We also need to define the kubernetes service port (8081) to proxy to the developer.

As you can see, /proxy/ needs to be added to the end of the URL as well.

This results in a scenario where the buildUrl function would try to append the port number (when null, the port "0" would be added) to a ready-to-go URL...

Context

Everybody who wants to use some kind of proxy like kubectl proxy would benefit from this change.

Possible implementation

Changing the code in Connector.php , rule 177 - 186 to:

        $host_with_port = $config['port'] === 0 ? $config['host'] : sprintf("%s:%d",$config['host'], $config['port']);
        
        return rtrim(
            sprintf(
                '%s/api/v1/servers/%s/%s',
                $host_with_port,
                $config['server'],
                $path
            ),
            '/'
        );

would resolve the issue.

Unfortunately, as is, there is a default port set in Powerdns.php ($port = 8001) and the constructor explicitly disallows "null" to be inserted here. Due to these limitations and to ensure backwards compatibility for people who rely on the default port, this would be the least invasive fix.

To remove the :port from the url, one would simply put "0" in the constructor of the Powerdns class.

A better fix would be to allow null as port and change the check I've created above to:
$host_with_port = isset($config['port']) ? sprintf("%s:%d",$config['host'], $config['port']) : $config['host']

Your environment

PHP 7.4
Windows / Linux

Any SRV record examples or test cases?

Detailed description

This is rather a feature request/enhancement on elaborative explanation.
I spent today working with this library and reading through the code, however, I could not find any examples or test cases of mechanisms that explain how RecordType::SRV would work.

I'm not sure if I should be putting the weight, port, and target in the content parameter, or if there's specific keys that I should use?

Here's some example mock code I wrote.

        $dnsPayload = [
            'name' => $request->input('name'),
            'type' => self::TYPE_RESOLVER[$request->input('type')],
            'content' => sprintf("%d %d _%s._%s.%s", $request->input("weight"), $request->input("port"), $request->input("service"), $request->input("protocol"), $request->input("name")),
            'ttl' => $request->input('ttl'),
            // What about priority, protocol, weight?
        ];

Context

I'm currently working on a system that will issue subdomains to people who want them on various domains that I own,

How can it benefit other users?

I've previously worked in the game server hosting industry, where hundreds of thousands of clients create subdomains to easily access their server rather than remembering an IP address. Having a proper way to do this could likely sway some big names in this particular industry rather than leaving Cloudflare as the only viable DNS management option via a CURL request.

eg: In the case of Minecraft, _minecraft._tcp

Your environment

I don't think is exactly relevant for this request, but...

OS: Windows 10
PHP 7.4.10 (cli) (built: Sep  1 2020 16:52:39) ( ZTS Visual C++ 2017 x64 )
Laravel 8.0
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies

Thanks in advance.

When creating a zone, remove it and recreate it again, the DNSSEC key is not found

Good morning,

Hopefully you can provide me an answer for the following case.
I'm writing integration tests and in these tests a zone with the same name is created, removed and created again, running on a local PowerDNS master instance. After it is created again the DNSSEC key is not available. Do you know perhaps what is going on and how I can resolve this?
Here is a small script which can be used to reproduce the case:

<?php

declare(strict_types=1);

use Exonet\Powerdns\Powerdns;
use Exonet\Powerdns\Resources\Zone as ZoneResource;

require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/vendor/exonet/powerdns-php/examples/CliLogger.php';

$powerdns = new Powerdns('localhost', 'some-api-key', 8081);
$powerdns->setLogger(new CliLogger());
try {
    if (!$powerdns->deleteZone('domain.com')) {
        throw new \Exception('Unable to remove the zone');
    }
} catch (ValidationException $exception) {
}

$zoneResource = new ZoneResource();
$zoneResource->setName('domain.com.');
$zoneResource->setKind('Master');
$zoneResource->setDnssec(true);
$zoneResource->setNsec3param('1 0 1 ab');

$zone = $powerdns->createZoneFromResource($zoneResource);
if (isset($zone->dnssec()->getKeys()[0])) {
    echo $zone->dnssec()->getKeys()[0]->getDnsKey() . PHP_EOL;
} else {
    echo 'No DNSSEC key found' . PHP_EOL;
}
if (!$powerdns->deleteZone('domain.com')) {
    throw new \Exception('Unable to remove the zone');
}

$zone = $powerdns->createZoneFromResource($zoneResource);
if (isset($zone->dnssec()->getKeys()[0])) {
    echo $zone->dnssec()->getKeys()[0]->getDnsKey() . PHP_EOL;
} else {
    echo 'No DNSSEC key found' . PHP_EOL;
}

This will produce the output:

[ DEBUG ]     Sending [DELETE] request
                url: localhost:8081/api/v1/servers/localhost/zones/domain.com
                headers: Array
                (
                    [X-API-Key] => some-api-key
                    [Accept] => application/json
                    [Content-Type] => application/json
                    [User-Agent] => exonet-powerdns-php/v3.1.0
                )
                
                payload: 
[ DEBUG ]     Request completed
                statusCode: 204
[ DEBUG ]     Sending [POST] request
                url: localhost:8081/api/v1/servers/localhost/zones
                headers: Array
                (
                    [X-API-Key] => some-api-key
                    [Accept] => application/json
                    [Content-Type] => application/json
                    [User-Agent] => exonet-powerdns-php/v3.1.0
                )
                
                payload: {"name":"domain.com.","kind":"Master","dnssec":true,"api_rectify":true,"soa_edit":"INCEPTION-INCREMENT","soa_edit_api":"DEFAULT","masters":[],"nameservers":[],"nsec3param":"1 0 1 ab","account":null}
[ DEBUG ]     Request completed
                statusCode: 201
[ DEBUG ]     Sending [GET] request
                url: localhost:8081/api/v1/servers/localhost/zones/domain.com./cryptokeys
                headers: Array
                (
                    [X-API-Key] => some-api-key
                    [Accept] => application/json
                    [Content-Type] => application/json
                    [User-Agent] => exonet-powerdns-php/v3.1.0
                )
                
                payload: 
[ DEBUG ]     Request completed
                statusCode: 200
[ DEBUG ]     Sending [GET] request
                url: localhost:8081/api/v1/servers/localhost/zones/domain.com./cryptokeys
                headers: Array
                (
                    [X-API-Key] => some-api-key
                    [Accept] => application/json
                    [Content-Type] => application/json
                    [User-Agent] => exonet-powerdns-php/v3.1.0
                )
                
                payload: 
[ DEBUG ]     Request completed
                statusCode: 200
257 3 13 9ZTTn3kX2znanCJKlnAVqSaaT4Rif3ykJlOiTZxIn4KFht7mtneg5zP8hrg/VheE/AwwOJtL/8j77jfRpOrNCQ==
[ DEBUG ]     Sending [DELETE] request
                url: localhost:8081/api/v1/servers/localhost/zones/domain.com
                headers: Array
                (
                    [X-API-Key] => some-api-key
                    [Accept] => application/json
                    [Content-Type] => application/json
                    [User-Agent] => exonet-powerdns-php/v3.1.0
                )
                
                payload: 
[ DEBUG ]     Request completed
                statusCode: 204
[ DEBUG ]     Sending [POST] request
                url: localhost:8081/api/v1/servers/localhost/zones
                headers: Array
                (
                    [X-API-Key] => some-api-key
                    [Accept] => application/json
                    [Content-Type] => application/json
                    [User-Agent] => exonet-powerdns-php/v3.1.0
                )
                
                payload: {"name":"domain.com.","kind":"Master","dnssec":true,"api_rectify":true,"soa_edit":"INCEPTION-INCREMENT","soa_edit_api":"DEFAULT","masters":[],"nameservers":[],"nsec3param":"1 0 1 ab","account":null}
[ DEBUG ]     Request completed
                statusCode: 201
[ DEBUG ]     Sending [GET] request
                url: localhost:8081/api/v1/servers/localhost/zones/domain.com./cryptokeys
                headers: Array
                (
                    [X-API-Key] => some-api-key
                    [Accept] => application/json
                    [Content-Type] => application/json
                    [User-Agent] => exonet-powerdns-php/v3.1.0
                )
                
                payload: 
[ DEBUG ]     Request completed
                statusCode: 200
No DNSSEC key found

Thanks in advance for your time!

Accept zone name in `find`

The find method doesn't work when searching for a record that is the same as the zone name. If this is the case, it should be 'transformed' to a canonical name: $powerdns->zone('test.nl')->find('test.nl'); doesn't work, $powerdns->zone('test.nl')->find('test.nl.'); does. However, this isn't expected behavior and should be done by the library.

Discussed in #125

Can't add two Records with same name

Describe the bug
Not sure if its a library bug, or PowerDNS limitation

To Reproduce

        $dns_records = [
            ['name' => '@', 'type' => RecordType::A, 'content' => '127.0.0.80'],
            ['name' => 'www', 'type' => RecordType::A, 'content' => '127.0.0.80'],
            ['name' => '@', 'type' => RecordType::NS, 'content' => 'ns1.example.com.'],
            ['name' => '@', 'type' => RecordType::NS, 'content' => 'ns2.example.com.'],
        ];

I can't add for example two DNS servers, I get error:
Duplicate RRset testzone1.com. IN NS with changetype: REPLACE

Maybe I missed something in PowerDNS docs?

Thanks

Why is the port 8001

Hi, Why is the default port hardcoded to be 8001 and not 8081.
As the documentation of PowerDNS states the default webserver port is 8081.
https://doc.powerdns.com/authoritative/http-api/index.html#webserver

Also there is not documentation how to change the port.
When I try the following I get the error: Conflict.

$powerdns = new Powerdns('127.0.0.1', 'powerdns_secret_string', 8081);
50: Exonet\Powerdns\Exceptions\PowerdnsException 
…/vendor/exonet/powerdns-php/src/Connector.php162
49: Exonet\Powerdns\Connector parseResponse
…/vendor/exonet/powerdns-php/src/Connector.php128
48: Exonet\Powerdns\Connector makeCall
…/vendor/exonet/powerdns-php/src/Connector.php63
47: Exonet\Powerdns\Connector post
…/vendor/exonet/powerdns-php/src/Powerdns.php146
46: Exonet\Powerdns\Powerdns createZone
…/app/Handlers/PowerDnsHandler.php26

cannot delete an MX record

Hi and thanks for a great integration tool to powerdns.

I hope you can help im a bit stuck regarding deleting a mx record. Hopefully you can help.

Description of the bug:
When trying to delete an MX record. The record is not being deleted.

How to reproduce the bug:
Create a domain with an MX record. In my case it look like below:
[{"type":"MX","name":"test.com.","content":"15 mail.test.com."},{"type":"SOA","name":"test.com.","content":"nameserver01. hostmaster.test.com. 2022121303 10800 3600 604800 3600"},{"type":"NS","name":"test.com.","content":"nameserver01"},{"type":"NS","name":"test.com.","content":"nameserver02"}]

Code I use to delete the MX record is as follow:

require DIR.'/autoload.php';
require DIR.'/vendor/exonet/powerdns-php/examples/CliLogger.php';

use Exonet\Powerdns\Powerdns;
use Exonet\Powerdns\RecordType;
use Exonet\Powerdns\Resources\ResourceRecord;

// Initialize the Powerdns client.
$powerdns = new Powerdns('nameserver', '**************');

$zone = $powerdns->zone('test.com');
$result = $zone->find('@', RecordType::MX)->delete();
print_r($result);

The return code from the code is true.

The expected behavior:
The MX record is being deleted.

Additional comment
I hope you can help

No SOA found for domain

Hey Guys

After I created a domain and some records. When I now try to delete the records, I get a message No SOA found for domain 'testmydomain.co.za.'

What might be causing this as there is an soa record for the domain in the database?

SearchResult fails on zone and comment results

Detailed description

The SearchResult class fails to interpret zone and comment results and issues warnings :

PHP Notice: Undefined index: content in /root/pdns-cli/vendor/exonet/powerdns-php/src/Resources/SearchResult.php on line 148
PHP Notice: Undefined index: disabled in /root/pdns-cli/vendor/exonet/powerdns-php/src/Resources/SearchResult.php on line 149
PHP Notice: Undefined index: ttl in /root/pdns-cli/vendor/exonet/powerdns-php/src/Resources/SearchResult.php on line 152
PHP Notice: Undefined index: type in /root/pdns-cli/vendor/exonet/powerdns-php/src/Resources/SearchResult.php on line 153
PHP Notice: Undefined index: zone in /root/pdns-cli/vendor/exonet/powerdns-php/src/Resources/SearchResult.php on line 154

during processing a zone result, and :

PHP Notice: Undefined index: disabled in /root/pdns-cli/vendor/exonet/powerdns-php/src/Resources/SearchResult.php on line 149
PHP Notice: Undefined index: ttl in /root/pdns-cli/vendor/exonet/powerdns-php/src/Resources/SearchResult.php on line 152

during processing a comment result.

This is a bug in public function setFromApiResponse(array $data) that tries to get record data that are not present on zone results or comment results.

Context

This is not well documented in the powerdns REST API documentation, but depending on the SearchResult type, depending on the returned object type the SearchResult contains theses properties :

object_type = "record", properties returned = content, disabled, name, object_type, zone_id, zone, type, ttl
object_type = "comment", properties returned = content, name, object_type, zone_id, zone, type (no disabled or ttl fields)
object_type = "zone", properties returned = name, object_type, zone_id (no content, disabled, zone, type or ttl fields)

Possible implementation

A simple change to overcome this problem is to replace :

public function setFromApiResponse(array $data): self
{
    $this->content = $data['content'];
    $this->disabled = (bool) $data['disabled'];
    $this->name = $data['name'];
    $this->objectType = $data['object_type'];
    $this->ttl = (int) $data['ttl'];
    $this->type = $data['type'];
    $this->zone = $data['zone'];
    $this->zoneId = $data['zone_id'];

    return $this;
}

with

public function setFromApiResponse(array $data): self
{
    $this->content = isset($data['content']) ? $data['content'] : null;
    $this->disabled = isset($data['disabled']) ? (bool) $data['disabled'] : null;
    $this->name = $data['name'];
    $this->objectType = $data['object_type'];
    $this->ttl = isset($data['ttl']) ? (int) $data['ttl'] : null;
    $this->type = isset($data['type']) ? $data['type'] : null;
    $this->zone = isset($data['zone']) ? $data['zone'] : null;
    $this->zoneId = $data['zone_id'];

    return $this;
}

in exonet/powerdns-php/src/Resources/SearchResult.php

Your environment

The problem was hit using linux centos-8, php 7.2.24, pdns 4.5.1.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.