Compare commits

...

7 Commits

Author SHA1 Message Date
tracer 879feb9044 added name and author
Signed-off-by: tracer <tracer@24unix.net>
2022-02-12 19:39:47 +01:00
tracer a97b8e926a added config.json.local
Signed-off-by: tracer <tracer@24unix.net>
2022-02-12 19:39:05 +01:00
tracer 5d4586aff3 adapted to /domains/name path
Signed-off-by: tracer <tracer@24unix.net>
2022-02-12 19:37:24 +01:00
tracer ac21b53bb9 removed IP addresses from DB
Signed-off-by: tracer <tracer@24unix.net>
2022-02-12 19:36:33 +01:00
tracer cf8fb56d2d removed ip added content
Signed-off-by: tracer <tracer@24unix.net>
2022-02-12 19:30:25 +01:00
tracer 05db619afd added debugging
Signed-off-by: tracer <tracer@24unix.net>
2022-02-12 19:29:42 +01:00
tracer 9271752843 added logger & /name path
Signed-off-by: tracer <tracer@24unix.net>
2022-02-12 19:27:38 +01:00
7 changed files with 384 additions and 287 deletions

View File

@ -1,4 +1,4 @@
#!/usr/local/bin/php
#!/usr/local/bin/php81
<?php declare(strict_types=1);
namespace App\Controller;
//#!/usr/bin/keyhelp-php81
@ -15,7 +15,11 @@ $version = '0.0.1';
require dirname(path: __DIR__) . '/vendor/autoload.php';
$configFile = dirname(path: __DIR__) ."/config.json.local";
if (!file_exists(filename: $configFile)) {
$configFile = dirname(path: __DIR__) ."/config.json";
}
if (!file_exists(filename: $configFile)) {
echo 'Missing config file' . PHP_EOL;
if (confirm(message: 'Should I create a new config based on config.json.sample?')) {

View File

@ -1,4 +1,11 @@
{
"name": "tracer/bindppi",
"authors": [
{
"name": "Micha Espey",
"email": "tracer@24unix.net"
}
],
"type": "project",
"license": "proprietary",
"minimum-stability": "stable",

View File

@ -162,8 +162,8 @@ class BindAPI
echo COLOR_YELLOW . "domains" . COLOR_DEFAULT . " domains this server is responsible for" . PHP_EOL;
echo COLOR_GREEN . "\t domains:list" . PHP_EOL;
echo COLOR_GREEN . "\t domains:create <name> {panel_id=<ID>} | {A=<IPv4>} {AAAA=<IPv6>}" . PHP_EOL;
echo COLOR_GREEN . "\t domains:update <ID> {name=<name>} {panel_id=<ID>} | {A=<IPv4>} {AAAA=<IPv6>}" . PHP_EOL;
echo COLOR_GREEN . "\t domains:create <name> {panel=<name>} | {A=<IPv4>} {AAAA=<IPv6>}" . PHP_EOL;
echo COLOR_GREEN . "\t domains:update <ID> {name=<name>} {panel=<name>} | {A=<IPv4>} {AAAA=<IPv6>}" . PHP_EOL;
echo COLOR_GREEN . "\t domains:delete <ID>" . PHP_EOL;
echo COLOR_YELLOW . "apikeys" . COLOR_DEFAULT . "\t API keys for other nameservers" . PHP_EOL;
@ -219,7 +219,7 @@ class BindAPI
$id = intval(value: $this->arguments[1] ?? 0);
if ($id != 0) {
if ($panel = $this->panelController->findByID(id: $id)) {
if ($panel = $this->panelRepository->findByID(id: $id)) {
$this->checkSinglePanel(panel: $panel);
} else {
echo "Unknown panel ID: $id" . PHP_EOL;
@ -367,7 +367,7 @@ class BindAPI
serverName: $nameServer->getName(),
versionIP: 6,
apiKey: $nameServer->getApikey(),
command: 'domains/' . $domainName,
command: 'domains/name/' . $domainName,
serverType: 'nameserver');
} else {
$result = $this->apiController->sendCommand(
@ -375,16 +375,19 @@ class BindAPI
serverName: $nameServer->getName(),
versionIP: 4,
apiKey: $nameServer->getApikey(),
command: 'domains',
command: 'domains/name/',
serverType: 'nameserver' . $domainName);
}
} catch (DependencyException|NotFoundException $e) {
echo $e->getMessage();
exit(1);
}
if ($result['header'] == 200) {
switch ($result['header']) {
case 200:
echo COLOR_GREEN . ' OK';
} else {
break;
case 404:
echo COLOR_RED . $result['header'] . COLOR_DEFAULT;
$arguments = $this->parseArguments();
if (!empty($arguments['fix']) && $arguments['fix'] == 'yes') {
@ -400,7 +403,7 @@ class BindAPI
serverName: $nameServer['name'],
versionIP: 6,
apiKey: $nameServer['apikey'],
command: 'domains',
command: 'domains/name',
serverType: 'nameserver',
body: $body);
} else {
@ -409,7 +412,7 @@ class BindAPI
serverName: $nameServer['name'],
versionIP: 4,
apiKey: $nameServer['apikey'],
command: 'domains',
command: 'domains/name',
serverType: 'nameserver',
body: $body);
}
@ -418,6 +421,11 @@ class BindAPI
exit(1);
}
}
break;
default:
echo 'Server error' . PHP_EOL;
print_r(value: $result);
exit(1);
}
}
echo PHP_EOL;
@ -949,16 +957,28 @@ class BindAPI
}
if (!empty($domains)) {
$table = new ConsoleTable();
$table->setHeaders(content: ['ID', 'Name', 'Panel', 'A', 'AAAA']);
$table->setHeaders(content: ['ID', 'Name', 'Content']);
/** @var Domain $domain */
foreach ($domains as $domain) {
$row = [];
try {
$row[] = $domain->getId();
$row[] = $domain->getName();
$row[] = $domain->getPanelID();
$row[] = $domain->getA();
$row[] = $domain->getAAAA();
$content = json_decode(json: $domain->getContent());
$column = '';
if (!empty($content->panel)) {
$column = 'Panel: ' . $content->panel;
}
if (!empty($content->custom)) {
$column .= 'Custom: ';
if (!empty($content->custom->a)) {
$column .= 'A: ' . $content->custom->a;
}
if (!empty($content->custom->aaaa)) {
$column .= ' AAAA: ' . $content->custom->a;
}
}
$row[] = $column;
} catch (DependencyException|NotFoundException $e) {
echo $e->getMessage();
}
@ -992,12 +1012,14 @@ class BindAPI
$arguments = $this->parseArguments();
$a = $arguments['a'] ?? "";
$aaaa = $arguments['aaaa'] ?? "";
$panelID = $arguments['panel_id'] ?? 0;
if (empty($a) && empty($aaaa) && empty($panelID)) {
echo 'At least one IP address or panel ID is required.' . PHP_EOL;
$a = $arguments['a'] ?? '';
$aaaa = $arguments['aaaa'] ?? '';
$panel = $arguments['panel'] ?? '';
print("panel: $panel");
if (empty($a) && empty($aaaa) && empty($panel)) {
echo 'At least one IP address or panel is required.' . PHP_EOL;
exit(0);
}
@ -1006,16 +1028,27 @@ class BindAPI
echo "Domain: $name already exists." . PHP_EOL;
exit(1);
} else {
if (!empty($panelID)) {
if ($panel = $this->panelController->findByID(id: $panelID)) {
$a = $panel['a'];
$aaaa = $panel['aaaa'];
if (!empty($panel)) {
if ($this->panelRepository->findByName(name: $panel)) {
$content = $this->domainController->createPanelContent(panel: $panel);
} else {
echo 'Unknown panel: ' . $panel;
exit(1);
}
} else {
$content = [];
if (!empty($a)) {
$content['a'] = $a;
}
$domain = new Domain(name: $name, id: $panelID, panelID: $a, a: $aaaa);
if (!empty($aaaa)) {
$content['aaaa'] = $aaaa;
}
$content = $this->domainController->createIPContent(ip: $content);
}
$domain = new Domain(name: $name, content: $content);
$result = $this->domainRepository->insert(domain: $domain);
echo "Domain $name has been created with id $result" . PHP_EOL;
$this->domainController->createZoneFile(domain: $domain);
$this->domainController->createSlaveZoneFile(domain: $domain);
exit(0);
}
} catch (DependencyException|NotFoundException $e) {
@ -1033,7 +1066,7 @@ class BindAPI
$id = intval(value: $this->arguments[1] ?? 0);
$name = $arguments['name'] ?? '';
$panelID = intval(value: $arguments['panel_id'] ?? 0);
$panel = $arguments['panel'] ?? '';
$a = $arguments['a'] ?? '';
$aaaa = $arguments['aaaa'] ?? '';
@ -1045,15 +1078,39 @@ class BindAPI
echo "Domain with ID : $id doesn't exist." . PHP_EOL;
exit(1);
}
if (!empty($panelID)) {
$panel = $this->panelController->findByID(id: $panelID);
$a = $panel['a'];
$aaaa = $panel['aaaa'];
$content = [];
if (!empty($panel)) {
$panel = $this->panelRepository->findByName(name: $panel);
$content = $this->domainController->createPanelContent(panel: $panel->getName());
} else {
$addresses = [];
if (!empty($a)) {
$addresses[] = [
'a' => $a
];
}
if (!empty($aaaa)) {
$addresses[] = [
'aaaa' => $aaaa
];
}
if (!empty($addresses)) {
$content = $this->domainController->createIPContent(ip: $content);
}
}
if (empty($name) && empty($content)) {
echo 'Either a new name or new content (panel or addresses) is needed.' . PHP_EOL;
exit(1);
}
if (empty($content)) {
$newDomain = new Domain(name: $name, id: $domain->getId(), content: '');
} else {
$newDomain = new Domain(name: $name, id: $domain->getId(), content: $content);
}
$newDomain = new Domain(name: $name, id: $panelID, panelID: $a, a: $aaaa);
if ($this->domainRepository->update(domain: $newDomain) !== false) {
echo 'Domain server has been updated' . PHP_EOL;
$this->domainController->createZoneFile(domain: $domain);
$this->domainController->createSlaveZoneFile(domain: $domain);
} else {
echo 'Error while updating domain server.' . PHP_EOL;
}
@ -1080,6 +1137,7 @@ class BindAPI
echo "There is no domain with ID $id." . PHP_EOL;
exit(1);
}
$this->domainRepository->delete(domain: $domain);
$this->domainController->deleteZone(domain: $domain);
echo "The domain with ID $id has been deleted." . PHP_EOL;
}

View File

@ -215,7 +215,7 @@ class DomainController
*
* @return void
*/
public function createZoneFile(Domain $domain): void
public function createSlaveZoneFile(Domain $domain): void
{
if ($this->config['debug']) {
$domainName = $domain->getName();
@ -223,15 +223,16 @@ class DomainController
}
if ($zonefile = fopen(filename: $this->localZonesDir . $domain->getName(), mode: 'w')) {
fputs(stream: $zonefile, data: 'zone \"' . $domain->getA() . '"' . ' IN {' . PHP_EOL);
// TODO fixme soon
//fputs(stream: $zonefile, data: 'zone \"' . $domain->getA() . '"' . ' IN {' . PHP_EOL);
fputs(stream: $zonefile, data: "\ttype slave;" . PHP_EOL);
fputs(stream: $zonefile, data: "\tfile \"" . $this->zoneCachePath . $domain->getName() . '.db";' . PHP_EOL);
fputs(stream: $zonefile, data: "\tmasters {" . PHP_EOL);
if (!empty($a)) {
fputs(stream: $zonefile, data: "\t\t" . $domain->getA() . ';' . PHP_EOL);
// fputs(stream: $zonefile, data: "\t\t" . $domain->getA() . ';' . PHP_EOL);
}
if (!empty($aaaa)) {
fputs(stream: $zonefile, data: "\t\t" . $domain->getAaaa() . ';' . PHP_EOL);
// fputs(stream: $zonefile, data: "\t\t" . $domain->getAaaa() . ';' . PHP_EOL);
}
fputs(stream: $zonefile, data: "\t};" . PHP_EOL);
fputs(stream: $zonefile, data: "};" . PHP_EOL);
@ -240,4 +241,39 @@ class DomainController
// TODO add on nameservers
}
/**
* @param String $panel
*
* @return String
*/
function createPanelContent(String $panel): String
{
return json_encode(value: [
'panel' => $panel
]
);
}
/**
* @param String $panel
*
* @return false|string
*/
function createIPContent(array $ip): String
{
$result = [];
if (!empty($ip['a'])) {
$result['a'] = $ip['a'];
}
if (!empty($ip['aaaa'])) {
$result['aaaa'] = $ip['aaaa'];
}
return json_encode(value: [
'custom' => $result
]
);
}
}

View File

@ -9,6 +9,9 @@ use App\Repository\ApikeyRepository;
use App\Repository\DomainRepository;
use DI\Container;
use DI\ContainerBuilder;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use OpenApi\Generator;
use UnhandledMatchError;
use function DI\autowire;
@ -45,6 +48,8 @@ use OpenApi\Attributes as OAT;
)]
class RequestController
{
private Logger $log;
//private DatabaseConnection $databaseConnection;
private DomainRepository $domainRepository;
private ApikeyRepository $apikeyRepository;
@ -65,9 +70,25 @@ class RequestController
{
$this->requestMethod = strtoupper(string: $requestMethod);
$dateFormat = "Y:m:d H:i:s";
$output = "%datetime% %channel%.%level_name% %message%\n"; // %context% %extra%
$formatter = new LineFormatter(format: $output, dateFormat: $dateFormat);
$stream = new StreamHandler(stream: dirname(path: __DIR__, levels: 2) . '/bindAPI.log');
$stream->setFormatter(formatter: $formatter);
$this->log = new Logger(name: 'bindAPI');
$this->log->pushHandler(handler: $stream);
$containerBuilder = new ContainerBuilder();
$containerBuilder->addDefinitions([
DatabaseConnection::class => autowire()->constructorParameter(parameter: 'config', value: $this->config),
DomainRepository::class => autowire()
->constructorParameter(parameter: 'config', value: $this->config)
->constructorParameter(parameter: 'log', value: $this->log),
]);
$this->container = $containerBuilder->build();
@ -114,9 +135,7 @@ class RequestController
$domain = [
'id' => $singleDomain->getId(),
'name' => $singleDomain->getName(),
'panel_id' => $singleDomain->getPanelId(),
'a' => $singleDomain->getA(),
'aaaa' => $singleDomain->getAaaa()
'content' => json_decode(json: $singleDomain->getContent())
];
$resultDomain[] = $domain;
}
@ -292,6 +311,20 @@ class RequestController
*/
public function handleDomainGetRequest(): void
{
if ($this->uri[3] == 'name') {
if ($result = $this->domainRepository->findByName(name: $this->uri[4])) {
$domain = [
'id' => $result->getId(),
'name' => $result->getName(),
'content' => json_decode(json: $result->getContent())
];
$this->result = $domain;
} else {
$this->header = "404 Not Found ";
$this->status = "404 Not Found ";
$this->message = "The specified domain was not found.";
}
} else {
if (empty($this->uri[3])) {
$this->handleAllDomainsGetRequest();
} else {
@ -299,9 +332,7 @@ class RequestController
$domain = [
'id' => $result->getId(),
'name' => $result->getName(),
'panel_id' => $result->getPanelId(),
'a' => $result->getA(),
'aaaa' => $result->getAaaa()
'content' => json_decode(json: $result->getContent())
];
$this->result = $domain;
} else {
@ -311,17 +342,18 @@ class RequestController
}
}
}
}
/**
* @return void
*/
public function handleDomainPostRequest(): void
public
function handleDomainPostRequest(): void
{
$name = $_POST['name'] ?? '';
$panelID = intval(value: $_POST['panel_id'] ?? 0);
$a = $_POST['a'] ?? '';
$aaaa = $_POST['aaaa'] ?? '';
$content = $_POST['content'] ?? '';
if (empty($name)) {
$this->header = "400 Bad Request";
$this->status = "400 Bad Request";
@ -337,7 +369,7 @@ class RequestController
$this->status = "400 Bad request";
$this->message = "Domain: $name already exists.";
} else {
$domain = new Domain(name: $name, panelID: $panelID, a: $a, aaaa: $aaaa);
$domain = new Domain(name: $name, content: $content);
$result = $this->domainRepository->insert(domain: $domain);
$this->status = "201 Created";
$this->message = $result;
@ -363,9 +395,7 @@ class RequestController
}
$id = $put['id'] ?? 0;
$name = $put['name'] ?? '';
$panelID = $put['panel_id'] ?? "";
$a = $put['a'] ?? "";
$aaaa = $put['aaaa'] ?? "";
$content = $put['content'] ?? "";
if ($id == 0) {
$this->status = "400 Bad Request";
@ -384,7 +414,7 @@ class RequestController
$this->status = "400 Bad Request";
$this->message = "At least one IP address is required.";
} else {
$domain = new Domain(name: $panelID, id: $id, panelID: $name, a: $a, aaaa: $aaaa);
$domain = new Domain(name: $name, id: $id, content: $content);
$this->domainRepository->update(domain: $domain);
$this->header = "201 Updated";
$this->status = "201 Updated";

View File

@ -2,41 +2,38 @@
namespace App\Entity;
use App\Enums\PanelType;
/**
*
*/
class Domain
{
private int $id;
private int $panelID;
private String $name;
private String $a;
private String $aaaa;
public function __construct(String $name, int $id = 0, int $panelID = 0, String $a = '', String $aaaa = '')
/**
*/
public function __construct(private string $name, private int $id = 0, private string $content = '')
{}
/**
* @return String
*/
public function getName(): string
{
return $this->name;
}
/**
* @param String $name
*/
public function setName(string $name): void
{
$this->id = $id;
$this->panelID = $panelID;
$this->name = $name;
$this->a = $a;
$this->aaaa = $aaaa;
}
/**
* @return String
*/
public function getA(): string
{
return $this->a;
}
/**
* @return String
*/
public function getAaaa(): string
{
return $this->aaaa;
}
/**
* @return int
@ -55,51 +52,20 @@ class Domain
}
/**
* @return String
* @return string
*/
public function getName(): string
public function getContent(): string
{
return $this->name;
return $this->content;
}
/**
* @return int
* @param string $content
*/
public function getPanelID(): int
public function setContent(string $content): void
{
return $this->panelID;
$this->content = $content;
}
/**
* @param int $panelID
*/
public function setPanelID(int $panelID): void
{
$this->panelID = $panelID;
}
/**
* @param String $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @param String $a
*/
public function setA(string $a): void
{
$this->a = $a;
}
/**
* @param String $aaaa
*/
public function setAaaa(string $aaaa): void
{
$this->aaaa = $aaaa;
}
}

View File

@ -14,7 +14,12 @@ use PDOException;
class DomainRepository
{
public function __construct(private DatabaseConnection $databaseConnection, private array $config, private Logger $log)
{}
{
if ($this->config['debug']) {
$this->log->debug(message: "DomainRepository::__construct()");
}
}
/**
@ -22,9 +27,13 @@ class DomainRepository
*/
public function findAll(): array
{
if ($this->config['debug']) {
$this->log->debug(message: "findAll()");
}
$domains = [];
$sql = "
SELECT id, name, panel_id, a, aaaa
SELECT id, name, content
FROM " . DatabaseConnection::TABLE_DOMAINS . "
ORDER BY name";
@ -32,7 +41,9 @@ class DomainRepository
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->execute();
while ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
$domain = new Domain(name: $result['name'], id: $result['id'], panelID: $result['panel_id'], a: $result['a'], aaaa: $result['aaaa']);
//print_r($result);
//die();
$domain = new Domain(name: $result['name'], id: $result['id'], content: $result['content']);
$domains[] = $domain;
}
return $domains;
@ -49,8 +60,12 @@ class DomainRepository
*/
public function findByID(int $id): bool|Domain
{
if ($this->config['debug']) {
$this->log->debug(message: "findById($id)");
}
$sql = "
SELECT id, name, panel_id, a, aaaa
SELECT id, name, content
FROM . " . DatabaseConnection::TABLE_DOMAINS . "
WHERE id = :id";
@ -60,7 +75,7 @@ class DomainRepository
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Domain(name: $result['name'], panelID: $result['panel_id'], a: $result['a'], aaaa: $result['aaaa']);
return new Domain(name: $result['name'], id: $result['id'], content: $result['content']);
} else {
return false;
}
@ -77,8 +92,12 @@ class DomainRepository
*/
public function findByName(string $name): Domain|bool
{
if ($this->config['debug']) {
$this->log->debug(message: "findByName($name)");
}
print("xxx: $name");
$sql = "
SELECT id, name, panel_id, a, aaaa
SELECT id, name, content
FROM " . DatabaseConnection::TABLE_DOMAINS . "
WHERE name = :name";
@ -87,12 +106,10 @@ class DomainRepository
$statement->bindParam(param: ':name', var: $name);
$statement->execute();
if ($result = $statement->fetch(mode: PDO::FETCH_ASSOC)) {
return new Domain(name: $result['name'], id: $result['id'], panelID: $result['panel_id'], a: $result['a'], aaaa: $result['aaaa']);
return new Domain(name: $result['name'], id: $result['id'], content: $result['content']);
} else {
return false;
}
} catch (PDOException $e) {
exit($e->getMessage());
}
@ -112,20 +129,15 @@ class DomainRepository
}
$sql = "
INSERT INTO " . DatabaseConnection::TABLE_DOMAINS . " (name, panel_id, a, aaaa)
VALUES (:name, :panel_id, :a, :aaaa)";
INSERT INTO " . DatabaseConnection::TABLE_DOMAINS . " (name, content)
VALUES (:name, :content)";
try {
$name = $domain->getName();
$panelID = $domain->getPanelID();
$a = $domain->getA();
$aaaa = $domain->getAaaa();
$content = $domain->getContent();
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: ':name', var: $name);
$statement->bindParam(param: ':panel_id', var: $panelID);
$statement->bindParam(param: ':a', var: $a);
$statement->bindParam(param: ':aaaa', var: $aaaa);
$statement->bindParam(param: ':content', var: $content);
$statement->execute();
return $this->databaseConnection->getConnection()->lastInsertId();
@ -147,47 +159,31 @@ class DomainRepository
$this->log->debug(message: "update($domainName)");
}
$current = $this->findByID(id: $domain->getId());
/* doesn't work
$statement = "
INSERT INTO domains(id, name, a, aaaa)
VALUES(:id, :name, :a, :aaaa)
ON DUPLICATE KEY UPDATE
name=COALESCE(VALUES(name), :name),
a=COALESCE(:a, a),
aaaa=COALESCE(:aaaa, aaaa)";
*/
$id = $domain->getId();
$current = $this->findByID(id: $id);
if (empty($domain->getName())) {
$name = $current['name'];
$name = $current->getName();
} else {
$name = $domain->getName();
}
if (empty($domain->getPanelID())) {
$panelID = $current['panel_id'];
}
$panelID = intval(value: $panelID);
if (empty($a)) {
$a = $current['a'];
}
if (empty($aaaa)) {
$aaaa = $current['aaaa'];
if (empty($domain->getContent())) {
$content = $current->getContent();
} else {
$content = $domain->getContent();
}
$sql = "
UPDATE " . DatabaseConnection::TABLE_DOMAINS . " SET
name = :name,
panel_id = :panel_id,
a = :a,
aaaa = :aaaa
content = :content
WHERE id = :id";
try {
$statement = $this->databaseConnection->getConnection()->prepare(query: $sql);
$statement->bindParam(param: 'id', var: $id);
$statement->bindParam(param: 'name', var: $name);
$statement->bindParam(param: 'panel_id', var: $panelID);
$statement->bindParam(param: 'a', var: $a);
$statement->bindParam(param: 'aaaa', var: $aaaa);
$statement->bindParam(param: 'content', var: $content);
$statement->execute();
return $statement->rowCount();