Skip to content

Commit

Permalink
feat: add AvailableInterface model, endpoint and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jaredhendrickson13 committed May 21, 2024
1 parent ecfaace commit 6a4f0de
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace RESTAPI\Endpoints;

require_once 'RESTAPI/autoloader.inc';

use RESTAPI\Core\Endpoint;

/**
* Defines an Endpoint for interacting with many AvailableInterface Model objects at
* /api/v2/interface/available_interfaces
*/
class InterfaceAvailableInterfacesEndpoint extends Endpoint {
public function __construct() {
# Set Endpoint attributes
$this->url = '/api/v2/interface/available_interfaces';
$this->model_name = 'AvailableInterface';
$this->many = true;
$this->request_method_options = ['GET'];

# Construct the parent Endpoint object
parent::__construct();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php

namespace RESTAPI\Models;

use RESTAPI\Core\Model;
use RESTAPI\Fields\StringField;

class AvailableInterface extends Model
{
public StringField $if;
public StringField $mac;
public StringField $dmesg;
public StringField $in_use_by;

public function __construct(mixed $id = null, mixed $parent_id = null, mixed $data = [], ...$options)
{
# Set model attributes
$this->internal_callable = 'get_all_avail_interfaces';
$this->many = true;

# Set model fields
$this->if = new StringField(
default: "",
allow_empty: true,
allow_null: true,
help_text: 'The name of the interface.',
);
$this->mac = new StringField(
default: "",
allow_empty: true,
allow_null: true,
help_text: 'The MAC address of the interface.',
);
$this->dmesg = new StringField(
default: "",
allow_empty: true,
allow_null: true,
help_text: 'The description of the interface.',
);
$this->in_use_by = new StringField(
default: null,
allow_null: true,
help_text: 'The pfSense interface ID that is using this interface.',
);

parent::__construct($id, $parent_id, $data, ...$options);
}

/**
* Obtains all available interfaces on the system
* @return array Returns all available interfaces on the system
*/
protected function get_all_avail_interfaces(): array {
// Local variables
global $ipsec_descrs;
$base_ifs = get_interface_list();

# Include wireless clone interfaces
if (config_get_path('wireless/clone') && is_array(config_get_path('wireless/clone')) && count(config_get_path('wireless/clone'))) {
foreach (config_get_path('wireless/clone', []) as $clone) {
$base_ifs[$clone['cloneif']] = $clone;
$base_ifs[$clone['cloneif']]['iswlclone'] = true;
}
}

# Include VLAN interfaces
if (config_get_path('vlans/vlan') && is_array(config_get_path('vlans/vlan')) && count(config_get_path('vlans/vlan'))) {
foreach (config_get_path('vlans/vlan', []) as $vlan) {
$base_ifs[$vlan['vlanif']] = $vlan;
$base_ifs[$vlan['vlanif']]['isvlan'] = true;
}
}

# Include Bridge interfaces
if (config_get_path('bridges/bridged') && is_array(config_get_path('bridges/bridged')) && count(config_get_path('bridges/bridged'))) {
foreach (config_get_path('bridges/bridged', []) as $bridge) {
$base_ifs[$bridge['bridgeif']] = $bridge;
$base_ifs[$bridge['bridgeif']]['isbridge'] = true;
}
}

# Include GIF interfaces
if (config_get_path('gifs/gif') && is_array(config_get_path('gifs/gif')) && count(config_get_path('gifs/gif'))) {
foreach (config_get_path('gifs/gif', []) as $gif) {
$base_ifs[$gif['gifif']] = $gif;
$base_ifs[$gif['gifif']]['isgif'] = true;
}
}

# Include GRE interfaces
if (config_get_path('gres/gre') && is_array(config_get_path('gres/gre')) && count(config_get_path('gres/gre'))) {
foreach (config_get_path('gres/gre', []) as $gre) {
$base_ifs[$gre['greif']] = $gre;
$base_ifs[$gre['greif']]['isgre'] = true;
}
}

# Include LAGG interfaces
if (config_get_path('laggs/lagg') && is_array(config_get_path('laggs/lagg')) && count(config_get_path('laggs/lagg'))) {
foreach (config_get_path('laggs/lagg', []) as $lagg) {
$base_ifs[$lagg['laggif']] = $lagg;
$base_ifs[$lagg['laggif']]['islagg'] = true;
# LAGG members cannot be assigned
$lagifs = explode(',', $lagg['members']);
foreach ($lagifs as $lagif) {
if (isset($base_ifs[$lagif])) {
unset($base_ifs[$lagif]);
}
}
}
}

# Include QinQ interfaces
if (config_get_path('qinqs/qinqentry') && is_array(config_get_path('qinqs/qinqentry')) && count(config_get_path('qinqs/qinqentry'))) {
foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
$base_ifs["{$qinq['vlanif']}"]['descr'] = "VLAN {$qinq['tag']} on {$qinq['if']}";
$base_ifs["{$qinq['vlanif']}"]['isqinq'] = true;
# QinQ members
$qinqifs = explode(' ', $qinq['members']);
foreach ($qinqifs as $qinqif) {
$base_ifs["{$qinq['vlanif']}.{$qinqif}"]['descr'] = "QinQ {$qinqif} on VLAN {$qinq['tag']} on {$qinq['if']}";
$base_ifs["{$qinq['vlanif']}.{$qinqif}"]['isqinq'] = true;
}
}
}

# Include PPP interfaces
if (config_get_path('ppps/ppp') && is_array(config_get_path('ppps/ppp')) && count(config_get_path('ppps/ppp'))) {
foreach (config_get_path('ppps/ppp', []) as $pppid => $ppp) {
$portname = $ppp['if'];
$base_ifs[$portname] = $ppp;
$base_ifs[$portname]['isppp'] = true;
$ports_base = basename($ppp['ports']);
if (isset($ppp['descr'])) {
$base_ifs[$portname]['descr'] = strtoupper($ppp['if']). "({$ports_base}) - {$ppp['descr']}";
} else if (isset($ppp['username'])) {
$base_ifs[$portname]['descr'] = strtoupper($ppp['if']). "({$ports_base}) - {$ppp['username']}";
} else {
$base_ifs[$portname]['descr'] = strtoupper($ppp['if']). "({$ports_base})";
}
}
}

# Include OpenVPN interfaces
$ovpn_descrs = array();
if (config_get_path('openvpn') && is_array(config_get_path('openvpn'))) {
if (config_get_path('openvpn/openvpn-server') && is_array(config_get_path('openvpn/openvpn-server'))) {
foreach (config_get_path('openvpn/openvpn-server', []) as $s) {
$portname = "ovpns{$s['vpnid']}";
$base_ifs[$portname] = $s;
$ovpn_descrs[$s['vpnid']] = $s['description'];
}
}
if (config_get_path('openvpn/openvpn-client') && is_array(config_get_path('openvpn/openvpn-client'))) {
foreach (config_get_path('openvpn/openvpn-client', []) as $c) {
$portname = "ovpnc{$c['vpnid']}";
$base_ifs[$portname] = $c;
$ovpn_descrs[$c['vpnid']] = $c['description'];
}
}
}

# Include IPsec interfaces
$ipsec_descrs = interface_ipsec_vti_list_all();
foreach ($ipsec_descrs as $ifname => $ifdescr) {
$base_ifs[$ifname] = array('descr' => $ifdescr);
}

# Loop through our array and check if interface is in use
foreach ($base_ifs as $pid => $conf) {
# Add the physical interface ID to the configuration
$base_ifs[$pid]["if"] = $pid;

# Check if there is a configuration for this interface
$pf_id = NetworkInterface::query(if: $pid);

# Check if the pfSense interface ID was found
if ($pf_id->exists()) {
$base_ifs[$pid]["in_use_by"] = $pf_id->first()->id;;
}
}

return $base_ifs;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace RESTAPI\Tests;

use RESTAPI\Core\TestCase;
use RESTAPI\Models\AvailableInterface;

class APIModelsAvailableInterfaceTestCase extends TestCase
{
/**
* Checks that we can correctly read AvailableInterface objects
*/
public function test_read(): void
{
# Create a AvailableInterface to populate an interface
$available_interface = AvailableInterface::read_all();
$this->assert_is_true($available_interface->exists());
$this->assert_is_not_empty($available_interface->first()->if->value);
$this->assert_is_not_empty($available_interface->first()->mac->value);
$this->assert_is_not_empty($available_interface->first()->in_use_by->value);
}
}

0 comments on commit 6a4f0de

Please sign in to comment.