Moving things forward

This commit is contained in:
James Gilliland 2022-03-10 19:56:41 -06:00
parent 0083bddfca
commit 0569b34086
9 changed files with 293 additions and 88 deletions

View file

@ -40,12 +40,13 @@ final class GenDuid extends Command
$manufacturer = '001E46';
}
$question = new Question('Serial number?');
$question = new Question('Serial number: ');
/** @var string $serial */
$serial = $helper->ask($input, $output, $question);
$output->writeln('Identifier: ' . $this->ascii2hex($manufacturer . ':' . $serial));
$output->write($this->getInstructions());
$id = $this->ascii2hex($manufacturer . ':' . $serial);
$output->writeln('Identifier: ' . $id);
$output->write($this->getInstructions($id));
return Command::SUCCESS;
}
@ -60,7 +61,7 @@ final class GenDuid extends Command
return implode(':', $bytes);
}
private function getInstructions(): string
private function getInstructions($id): string
{
return <<<EOF
@ -70,7 +71,7 @@ IPv6 Options
DHCP6 DUID: DUID-EN
DUID-EN
Enterprise Number: 3561
Identifier: As shown above
Identifier: $id
Click Save.
@ -82,7 +83,7 @@ General Configuration
Other options are probably needed, so set those too.
Click Save. This will finally save dhcp6c's DUID file and start the client.
Click Save. This will finally save DHCP6's DUID file and start the client.
Step 4) Finished, hopefully.

View file

@ -5,7 +5,8 @@ declare(strict_types=1);
namespace Pfatt\Commands;
use Pfatt\Service\Config;
use Pfatt\Service\NgController;
use Pfatt\Service\IfConfig;
use Pfatt\Service\NgCtl;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
@ -18,17 +19,20 @@ final class Monitor extends Command
protected static $defaultDescription = 'Monitor connection to trigger 5268AC updates';
protected Config $config;
protected LoggerInterface $logger;
protected NgController $ngControl;
protected NgCtl $ngControl;
private IfConfig $ifConfig;
public function __construct(
Config $config,
LoggerInterface $logger,
NgController $ngControl
NgCtl $ngControl,
IfConfig $ifConfig
) {
parent::__construct('monitor');
$this->config = $config;
$this->logger = $logger;
$this->ngControl = $ngControl;
$this->ifConfig = $ifConfig;
}
/**
@ -43,6 +47,7 @@ final class Monitor extends Command
$this->logger->info('Stopping 5268AC ping monitor ...');
});
$failures = 0;
while ($input->isInteractive()) {
if (!$this->ping()) {
if ($this->ngControl->ngIsConnected()) {
@ -52,12 +57,38 @@ final class Monitor extends Command
else {
$this->logger->info('Everything is going well.');
}
$failures = 0;
} elseif (!$this->ngControl->ngIsConnected()) {
$this->logger->warning('Connection to ' . $this->config->getPingHost() . ' is down, but EAP is not being bridged!');
$this->ngControl->ngConnect();
}
else {
$this->logger->error('Connection to ' . $this->config->getPingHost() . ' is down, and EAP is not being bridged! We are stuck!');
$failures++;
if ($failures > 10 ){
$this->logger->error('Connection to ' . $this->config->getPingHost() . ' is down, and EAP is bridged! We are stuck!');
}
elseif ($failures > 3) {
$this->logger->error('Things are stuck. Lets trying restarting things.');
$this->ifConfig->stop(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
$this->ngControl->removeNodes(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
sleep(2);
$this->logger->error('Bringing things back up.');
$this->ngControl->createNodes(
$this->config->getOntInterface(),
$this->config->getRgInterface(),
$this->config->getRgEthernetMac()
);
$this->ifConfig->start(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
}
}
sleep(5);
}

34
src/Commands/Restart.php Normal file
View file

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace Pfatt\Commands;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
final class Restart extends Command
{
protected static $defaultName = 'restart';
protected static $defaultDescription = 'Fully restart the netgraph connections';
/**
* {@inheritDoc}
*/
protected function execute(
InputInterface $input,
OutputInterface $output
): int {
$application = $this->getApplication();
if (!$application) {
return Command::FAILURE;
}
$application->find('shutdown')
->run(new ArrayInput([]), $output);
$application->find('startup')
->run(new ArrayInput([]), $output);
return Command::SUCCESS;
}
}

48
src/Commands/Shutdown.php Normal file
View file

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Pfatt\Commands;
use Pfatt\Service\Config;
use Pfatt\Service\KldLoad;
use Pfatt\Service\NgCtl;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
final class Shutdown extends Command
{
protected static $defaultName = 'shutdown';
protected static $defaultDescription = 'Shutdown netgraph connections';
protected Config $config;
protected LoggerInterface $logger;
protected NgCtl $ngControl;
public function __construct(
Config $config,
LoggerInterface $logger,
NgCtl $ngControl
) {
parent::__construct('startup');
$this->config = $config;
$this->logger = $logger;
$this->ngControl = $ngControl;
}
/**
* {@inheritDoc}
*/
protected function execute(
InputInterface $input,
OutputInterface $output
): int {
$this->ngControl->removeNodes(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
return Command::SUCCESS;
}
}

View file

@ -5,7 +5,9 @@ declare(strict_types=1);
namespace Pfatt\Commands;
use Pfatt\Service\Config;
use Pfatt\Service\NgController;
use Pfatt\Service\IfConfig;
use Pfatt\Service\KldLoad;
use Pfatt\Service\NgCtl;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
@ -15,20 +17,26 @@ use Symfony\Component\Process\Process;
final class Startup extends Command
{
protected static $defaultName = 'startup';
protected static $defaultDescription = 'Setup initial connection';
protected static $defaultDescription = 'Start netgraph connetion';
protected Config $config;
protected LoggerInterface $logger;
protected NgController $ngControl;
protected NgCtl $ngControl;
private IfConfig $ifConfig;
private KldLoad $kldLoad;
public function __construct(
Config $config,
LoggerInterface $logger,
NgController $ngControl
NgCtl $ngControl,
IfConfig $ifConfig,
KldLoad $kldLoad
) {
parent::__construct('startup');
$this->config = $config;
$this->logger = $logger;
$this->ngControl = $ngControl;
$this->ifConfig = $ifConfig;
$this->kldLoad = $kldLoad;
}
/**
@ -38,19 +46,15 @@ final class Startup extends Command
InputInterface $input,
OutputInterface $output
): int {
switch ($this->getVeriant()) {
switch ($this->getVariant()) {
case 'opnsense':
$kldload = function (string $mod): Process {
return new Process(['/sbin/kldload', '-nq', $mod]);
};
$this->logger->info('loading netgraph kernel modules...');
$kldload('netgraph')->mustRun();
$kldload('ng_ether')->mustRun();
$kldload('ng_etf')->mustRun();
$kldload('ng_vlan')->mustRun();
$kldload('ng_eiface')->mustRun();
$kldload('ng_one2many')->mustRun();
$this->kldLoad->execute('netgraph');
$this->kldLoad->execute('ng_ether');
$this->kldLoad->execute('ng_etf');
$this->kldLoad->execute('ng_vlan');
$this->kldLoad->execute('ng_eiface');
$this->kldLoad->execute('ng_one2many');
$this->logger->info('OK!');
break;
@ -60,7 +64,7 @@ final class Startup extends Command
return new Process([
'/usr/local/bin/php',
'-r',
'"pfSense_ngctl_attach(\'.\', \'' . $interface . '\';"'
'"pfSense_ngctl_attach(\'.\', \'' . $interface . '\');"'
]);
};
@ -75,13 +79,19 @@ final class Startup extends Command
$this->config->getRgInterface(),
$this->config->getRgEthernetMac()
);
$this->ifConfig->start(
$this->config->getOntInterface(),
$this->config->getRgInterface()
);
$this->logger->info("ngeth0 should now be available to configure as your pfSense WAN");
$this->logger->info("Done");
return Command::SUCCESS;
}
/**
* @return string
*/
private function getVeriant(): string
private function getVariant(): string
{
// @todo detect the variant to trigger different behaviors.
return 'opnsense';

View file

@ -9,9 +9,13 @@ use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Pfatt\Commands\GenDuid;
use Pfatt\Commands\Monitor;
use Pfatt\Commands\Restart;
use Pfatt\Commands\Shutdown;
use Pfatt\Commands\Startup;
use Pfatt\Service\Config;
use Pfatt\Service\NgController;
use Pfatt\Service\IfConfig;
use Pfatt\Service\KldLoad;
use Pfatt\Service\NgCtl;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\CommandLoader\ContainerCommandLoader;
@ -46,26 +50,27 @@ final class PfattKernel
if (!file_exists($file)) {
$containerBuilder = new ContainerBuilder();
$containerBuilder->register(Config::class, Config::class)
->setPublic(true);
$containerBuilder->register(Config::class, Config::class);
// Setup various logging handlers.
$containerBuilder->register('syslogger', SyslogHandler::class)
->setArguments(['pfatt'])
->setPublic(true);
->setArguments(['pfatt']);
$containerBuilder->register(LoggerInterface::class, Logger::class)
->setArguments(['pfatt', [new Reference('syslogger')]])
->setPublic(true);
->setArguments(['pfatt', [new Reference('syslogger')]]);
$containerBuilder->setAlias(Logger::class, LoggerInterface::class);
// Utilities.
$containerBuilder->autowire(NgController::class, NgController::class)
->setPublic(true);
$containerBuilder->autowire(NgCtl::class, NgCtl::class);
$containerBuilder->autowire(KldLoad::class, KldLoad::class);
$containerBuilder->autowire(IfConfig::class, IfConfig::class);
// Register commands.
$containerBuilder->autowire(Startup::class, Startup::class)
->setPublic(true);
$containerBuilder->autowire(Shutdown::class, Shutdown::class)
->setPublic(true);
$containerBuilder->autowire(Restart::class, Restart::class)
->setPublic(true);
$containerBuilder->autowire(GenDuid::class, GenDuid::class)
->setPublic(true);
$containerBuilder->autowire(Monitor::class, Monitor::class)
@ -76,8 +81,7 @@ final class PfattKernel
->setArguments([
new Reference('service_container'),
$this->commands
])
->setPublic(true);
]);
$containerBuilder->autowire(PfattApplication::class, PfattApplication::class)
->addMethodCall('setCommandLoader', [new Reference(ContainerCommandLoader::class)])
->setPublic(true);

57
src/Service/IfConfig.php Normal file
View file

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace Pfatt\Service;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
class IfConfig
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function start(string $ont, string $rg): void
{
$this->logger->info(" enabling $rg interface...");
$this->exec([$rg, 'up']);
$this->logger->info('OK!');
$this->logger->info(" enabling $ont interface...");
$this->exec([$ont, 'up"']);
$this->logger->info('OK!');
$this->logger->info(" enabling promiscuous mode on $rg...");
$this->exec([$rg, 'promisc']);
$this->logger->info('OK!');
$this->logger->info(" enabling promiscuous mode on $ont...");
$this->exec([$ont, 'promisc']);
$this->logger->info('OK!');
}
public function stop(string $ont, string $rg): void
{
//
}
/**
* Run a ifconfig command.
*
* @param array<int, string> $args
* Additional arguments to pass to ifconfig.
*
* @return bool
* True on success, false on failure.
*/
private function exec(array $args): bool
{
$process = new Process(['/sbin/ifconfig', ...$args], '/tmp');
return !$process->run();
}
}

25
src/Service/KldLoad.php Normal file
View file

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Pfatt\Service;
use Symfony\Component\Process\Process;
class KldLoad
{
/**
* Load a module with kldload.
*
* @param string $module
* Additional arguments to pass to kldload.
*
* @return bool
* True on success, false on failure.
*/
public function execute(string $module): bool
{
$process = new Process(['/sbin/kldload', '-nq', $module], '/tmp');
return !$process->run();
}
}

View file

@ -8,7 +8,7 @@ use Psr\Log\LoggerAwareInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Process\Process;
class NgController implements LoggerAwareInterface
class NgCtl implements LoggerAwareInterface
{
private LoggerInterface $logger;
@ -22,7 +22,7 @@ class NgController implements LoggerAwareInterface
*/
public function ngIsConnected(): bool
{
return $this->ngCtlRun(['show', 'laneapfilter:eapout']);
return $this->exec(['show', 'laneapfilter:eapout']);
}
/**
@ -31,7 +31,7 @@ class NgController implements LoggerAwareInterface
public function ngRmHook(): void
{
$this->logger->info('Disconnecting netgraph node ...');
$this->ngCtlRun(['rmhook', 'laneapfilter: eapout']) ?
$this->exec(['rmhook', 'laneapfilter:', 'eapout']) ?
$this->logger->info('OK!') :
$this->logger->error('ERROR!');
}
@ -42,7 +42,7 @@ class NgController implements LoggerAwareInterface
public function ngConnect(): void
{
$this->logger->info('Connecting netgraph node ...');
$this->ngCtlRun(['connect', 'waneapfilter:', 'laneapfilter:', 'eapout', 'eapout']) ?
$this->exec(['connect', 'waneapfilter:', 'laneapfilter:', 'eapout', 'eapout']) ?
$this->logger->info('OK!') :
$this->logger->error('ERROR!');
}
@ -63,27 +63,26 @@ class NgController implements LoggerAwareInterface
$this->logger->info('Building netgraph nodes.');
$this->logger->info(' creating ng_one2many...');
$this->ngCtlRun(['mkpeer', $ont . ':', 'one2many', 'lower', 'one']);
$this->ngCtlRun(['name', $ont . ':lower', 'o2m']);
$this->exec(['mkpeer', $ont . ':', 'one2many', 'lower', 'one']);
$this->exec(['name', $ont . ':lower', 'o2m']);
$this->logger->info('OK!');
$this->logger->info(' creating vlan node and interface...');
$this->ngCtlRun(['mkpeer', 'o2m:', 'vlan', 'many0', ' downstream']);
$this->ngCtlRun(['name', 'o2m:many0', 'vlan0']);
$this->ngCtlRun(['mkpeer', 'vlan0:', 'eiface', 'vlan0', 'ether']);
$this->ngCtlRun([
$this->exec(['mkpeer', 'o2m:', 'vlan', 'many0', ' downstream']);
$this->exec(['name', 'o2m:many0', 'vlan0']);
$this->exec(['mkpeer', 'vlan0:', 'eiface', 'vlan0', 'ether']);
$this->exec([
'msg',
'vlan0:',
'\'addfilter { vlan=0 hook="vlan0" }\''
]);
$this->ngCtlRun(['msg', 'ngeth0:', 'set', $rgMac]);
$this->exec(['msg', 'ngeth0:', 'set', $rgMac]);
$this->logger->info('OK!');
$this->logger->info(" defining etf for $ont (ONT)...");
$this->ngCtlRun(['mkpeer', 'o2m:', 'etf', 'many1', 'downstream']);
$this->ngCtlRun(['name', 'o2m:many1', 'waneapfilter']);
$this->ngCtlRun([
$this->exec(['mkpeer', 'o2m:', 'etf', 'many1', 'downstream']);
$this->exec(['name', 'o2m:many1', 'waneapfilter']);
$this->exec([
'connect',
'waneapfilter:',
$ont . ':',
@ -93,9 +92,9 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!');
$this->logger->info(" defining etf for $rg (RG)...");
$this->ngCtlRun(['mkpeer', $rg . ':', 'etf', 'lower', 'downstream']);
$this->ngCtlRun(['name', $rg . ':', 'lower', 'laneapfilter']);
$this->ngCtlRun([
$this->exec(['mkpeer', $rg . ':', 'etf', 'lower', 'downstream']);
$this->exec(['name', $rg . ':', 'lower', 'laneapfilter']);
$this->exec([
'connect',
'laneapfilter:',
$rg . ':',
@ -105,7 +104,7 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!');
$this->logger->info(" bridging etf for $ont <-> $rg...");
$this->ngCtlRun([
$this->exec([
'connect',
'waneapfilter:',
'laneapfilter:',
@ -115,12 +114,12 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!');
$this->logger->info(" defining filters for EAP traffic...");
$this->ngCtlRun([
$this->exec([
'msg',
'waneapfilter:',
'\'setfilter { matchhook="eapout" ethertype=0x888e }\''
]);
$this->ngCtlRun([
$this->exec([
'msg',
'laneapfilter:',
'\'setfilter { matchhook="eapout" ethertype=0x888e }\''
@ -128,7 +127,7 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!');
$this->logger->info(" enabling one2many links...");
$this->ngCtlRun([
$this->exec([
'msg',
'o2m:',
'setconfig',
@ -137,23 +136,19 @@ class NgController implements LoggerAwareInterface
$this->logger->info('OK!');
$this->logger->info(" removing waneapfilter:nomatch hook...");
$this->ngCtlRun(['rmhook', 'waneapfilter:', 'nomatch']);
$this->exec(['rmhook', 'waneapfilter:', 'nomatch']);
$this->logger->info('OK!');
}
$this->logger->info(" enabling $rg interface...");
$this->ngCtlRun([$rg, 'up']);
$this->logger->info('OK!');
$this->logger->info(" enabling $ont interface...");
$this->ngCtlRun([$ont, 'up"']);
$this->logger->info('OK!');
$this->logger->info(" enabling promiscuous mode on $rg...");
$this->ngCtlRun([$rg, 'promisc']);
$this->logger->info('OK!');
$this->logger->info("ngeth0 should now be available to configure as your pfSense WAN");
$this->logger->info("Done");
public function removeNodes(string $ont, string $rg): void
{
$this->exec(['shutdown', 'waneapfilter:']);
$this->exec(['shutdown', 'laneapfilter:']);
$this->exec(['shutdown', $ont . ':']);
$this->exec(['shutdown', $rg . ':']);
$this->exec(['shutdown', 'o2m:']);
$this->exec(['shutdown', 'vlan0:']);
$this->exec(['shutdown', 'ngeth0:']);
}
/**
@ -165,7 +160,7 @@ class NgController implements LoggerAwareInterface
* @return bool
* True on success, false on failure.
*/
private function ngCtlRun(array $args): bool
private function exec(array $args): bool
{
$process = new Process(['/usr/sbin/ngctl', ...$args], '/tmp');
return !$process->run();