Skip to content

Commit

Permalink
Added support for BIND server
Browse files Browse the repository at this point in the history
  • Loading branch information
getpinga committed Jan 30, 2024
1 parent 5e29d33 commit de3b35d
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 5 deletions.
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ This module is designed for use with the following DNS providers:

- [Vultr](https://www.vultr.com/)

- [BIND](https://www.isc.org/bind/)

## FOSSBilling Module Installation instructions

### 1. Download and Install FOSSBilling:
Expand All @@ -21,13 +23,19 @@ First, download this repository. After successfully downloading the repository,

Go to `[FOSSBilling]/modules/Servicedns/Providers` directory and run the `composer install` command.

### 3. Addition of Synchronization Scripts:
### (BIND Module only) 3. Addition of Synchronization Scripts:

The BIND provider has an additional synchronization script which can be found at `[FOSSBilling]/modules/Servicedns/Crons/Bind.php`. It needs to be configured with your BIND installation parameters, so it can generate the zones regularly.

### (BIND Module only) 4. Setting Up the Cron Job:

You need to set up a hourly cron job that runs the sync module. Open crontab using the command `crontab -e` in your terminal.

**not yet implemented**
Add the following cron job:

### 4. Setting Up the Cron Job:
`0 * * * * php [FOSSBilling]/modules/Servicedns/Crons/Bind.php`

**not yet implemented**
This command schedules the synchronization script to run hourly.

### 5. Activate the DNS hosting module:

Expand Down
117 changes: 117 additions & 0 deletions Servicedns/Crons/Bind.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php
require_once __DIR__ . '/../Providers/vendor/autoload.php';

$config = include __DIR__ . '/../../../config.php';
$c = $config["db"];

use Badcow\DNS\Zone;
use Badcow\DNS\Rdata\Factory;
use Badcow\DNS\ResourceRecord;
use Badcow\DNS\Classes;
use Badcow\DNS\AlignedBuilder;

try {
$dsn = $c["type"] . ":host=" . $c["host"] . ";port=" . $c["port"] . ";dbname=" . $c["name"];
$pdo = new PDO($dsn, $c["user"], $c["password"]);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Fetch domain names and IDs from service_dns table
$domainsStmt = $pdo->query("SELECT id, domain_name FROM service_dns");
$domains = $domainsStmt->fetchAll(PDO::FETCH_ASSOC);
$timestamp = time();

foreach ($domains as $domain) {
$domainName = $domain['domain_name'];
$domainId = $domain['id'];

$stmt = $pdo->prepare("SELECT * FROM service_dns_records WHERE domain_id = :domainId");
$stmt->execute(['domainId' => $domainId]);

$zone = new Zone($domainName.'.');
$zone->setDefaultTtl(3600);

$soa = new ResourceRecord;
$soa->setName('@');
$soa->setClass(Classes::INTERNET);
$soa->setRdata(Factory::Soa(
'example.com.',
'post.example.com.',
$timestamp,
3600,
14400,
604800,
3600
));
$zone->addResourceRecord($soa);

$ns1 = new ResourceRecord;
$ns1->setName('@');
$ns1->setClass(Classes::INTERNET);
$ns1->setRdata(Factory::Ns('ns1.nameserver.com.'));
$zone->addResourceRecord($ns1);

$ns2 = new ResourceRecord;
$ns2->setName('@');
$ns2->setClass(Classes::INTERNET);
$ns2->setRdata(Factory::Ns('ns2.nameserver.com.'));
$zone->addResourceRecord($ns2);

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$recordType = $row['type'];
$host = $row['host'];
$value = $row['value'];
$ttl = $row['ttl'] ?? 3600; // Default TTL

$record = new ResourceRecord();
$record->setName($host);
$record->setTtl($ttl);

switch ($recordType) {
case 'A':
$record->setRdata(Factory::A($value));
break;
case 'AAAA':
$record->setRdata(Factory::Aaaa($value));
break;
case 'MX':
$priority = $row['priority'] ?? 0;
$record->setRdata(Factory::Mx($priority, $value));
break;
case 'CNAME':
$record->setRdata(Factory::Cname($value));
break;
case 'TXT':
$formattedValue = trim($value, '"');
$record->setRdata(Factory::Txt($formattedValue));
break;
case 'SPF':
$formattedValue = trim($value, '"');
$record->setRdata(Factory::Spf($formattedValue));
break;
case 'DS':
// DS record typically requires key tag, algorithm, digest type, and digest
// Assuming these are provided in a formatted string or individual columns
// $value format should be "keyTag algorithm digestType digest"
list($keyTag, $algorithm, $digestType, $digest) = explode(' ', $value);
$record->setRdata(Factory::Ds($keyTag, $algorithm, $digestType, $digest));
break;
// ... Other record types
}

$zone->addResourceRecord($record);
}

// Generate zone file content for each domain
$builder = new AlignedBuilder();
$zoneFileContent = $builder->build($zone);

// Generate zone for each domain and reload BIND
file_put_contents("/var/lib/bind/db.$domainName", $zoneFileContent);

exec("rndc reload {$domainName}.", $output, $return_var);
exec("rndc notify {$domainName}.", $output, $return_var);
}

} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
86 changes: 86 additions & 0 deletions Servicedns/Providers/Bind.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Box\Mod\Servicedns\Providers;

class Bind implements DnsHostingProviderInterface {

public function __construct() {
}

public function createDomain($domainName) {
if (empty($domainName)) {
throw new \FOSSBilling\Exception("Domain name cannot be empty");
}

return json_decode($domainName, true);
}

public function listDomains() {
throw new \FOSSBilling\Exception("Not yet implemented");
}

public function getDomain($domainName) {
throw new \FOSSBilling\Exception("Not yet implemented");
}

public function getResponsibleDomain($qname) {
throw new \FOSSBilling\Exception("Not yet implemented");
}

public function exportDomainAsZonefile($domainName) {
throw new \FOSSBilling\Exception("Not yet implemented");
}

public function deleteDomain($domainName) {
if (empty($domainName)) {
throw new \FOSSBilling\Exception("Domain name cannot be empty");
}

return json_decode($domainName, true);
}

public function createRRset($domainName, $rrsetData) {
if (empty($domainName)) {
throw new \FOSSBilling\Exception("Domain name cannot be empty");
}

return json_decode($domainName, true);
}

public function createBulkRRsets($domainName, $rrsetDataArray) {
throw new \FOSSBilling\Exception("Not yet implemented");
}

public function retrieveAllRRsets($domainName) {
throw new \FOSSBilling\Exception("Not yet implemented");
}

public function retrieveSpecificRRset($domainName, $subname, $type) {
throw new \FOSSBilling\Exception("Not yet implemented");
}

public function modifyRRset($domainName, $subname, $type, $rrsetData) {
if (empty($domainName)) {
throw new \FOSSBilling\Exception("Domain name cannot be empty");
}

return json_decode($domainName, true);
}

public function modifyBulkRRsets($domainName, $rrsetDataArray) {
throw new \FOSSBilling\Exception("Not yet implemented");
}

public function deleteRRset($domainName, $subname, $type, $value) {
if (empty($domainName)) {
throw new \FOSSBilling\Exception("Domain name cannot be empty");
}

return json_decode($domainName, true);
}

public function deleteBulkRRsets($domainName, $rrsetDataArray) {
throw new \FOSSBilling\Exception("Not yet implemented");
}

}
3 changes: 2 additions & 1 deletion Servicedns/Providers/composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"require": {
"guzzlehttp/guzzle": "^7.8",
"vultr/vultr-php": "^1.0"
"vultr/vultr-php": "^1.0",
"badcow/dns": "^4.2"
},
"config": {
"allow-plugins": {
Expand Down
3 changes: 3 additions & 0 deletions Servicedns/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ private function chooseDnsProvider($config) {
case 'Vultr':
$this->dnsProvider = new Providers\Vultr($apiToken);
break;
case 'Bind':
$this->dnsProvider = new Providers\Bind();
break;
// Add more cases for additional providers
default:
throw new \FOSSBilling\Exception("Unknown DNS provider: {$providerName}");
Expand Down
1 change: 1 addition & 0 deletions Servicedns/html_admin/mod_servicedns_config.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<option value="" disabled {% if not product.config.provider %}selected{% endif %}>Select Provider</option>
<option value="Desec" {% if product.config.provider == 'Desec' %}selected{% endif %}>Desec</option>
<option value="Vultr" {% if product.config.provider == 'Vultr' %}selected{% endif %}>Vultr</option>
<option value="Bind" {% if product.config.provider == 'Bind' %}selected{% endif %}>Bind</option>
</select>
</div>
</div>
Expand Down

0 comments on commit de3b35d

Please sign in to comment.