summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2020-07-04 08:56:03 -0500
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2020-07-04 08:56:03 -0500
commit1d9c703a8eebcf8f328e610879c7a1799258bba3 (patch)
tree5c1a84c61e4277e931effe8c2aea25b20932936a
parentb0690189d37cb96924fd52e6647f84020ba56ef6 (diff)
downloadhorizon-1d9c703a8eebcf8f328e610879c7a1799258bba3.tar.gz
horizon-1d9c703a8eebcf8f328e610879c7a1799258bba3.tar.bz2
horizon-1d9c703a8eebcf8f328e610879c7a1799258bba3.tar.xz
horizon-1d9c703a8eebcf8f328e610879c7a1799258bba3.zip
hscipt: Implement parse and validation of 'pppoe' key
-rw-r--r--hscript/network.cc114
-rw-r--r--hscript/network.hh25
-rw-r--r--hscript/script.cc3
-rw-r--r--hscript/script_e.cc9
-rw-r--r--hscript/script_i.hh17
-rw-r--r--hscript/script_v.cc4
-rw-r--r--tests/fixtures/0241-pppoe-basic.installfile6
-rw-r--r--tests/fixtures/0242-pppoe-auth.installfile6
-rw-r--r--tests/fixtures/0243-pppoe-allkeys.installfile6
-rw-r--r--tests/fixtures/0244-pppoe-invalid.installfile6
-rw-r--r--tests/fixtures/0245-pppoe-valueless.installfile6
-rw-r--r--tests/spec/validator_spec.rb35
12 files changed, 230 insertions, 7 deletions
diff --git a/hscript/network.cc b/hscript/network.cc
index 1e915b3..3d847a2 100644
--- a/hscript/network.cc
+++ b/hscript/network.cc
@@ -14,6 +14,7 @@
#include <arpa/inet.h> /* inet_pton */
#include <cstring> /* memcpy */
#include <fstream> /* ofstream for Net write */
+#include <set> /* for PPPoE valid param keys */
#ifdef HAS_INSTALL_ENV
# include <linux/wireless.h> /* struct iwreq */
# include <string.h> /* strerror */
@@ -352,9 +353,7 @@ bool execute_address_eni(const NetAddress *addr) {
return true;
}
-bool NetAddress::execute() const {
- output_info(pos, "netaddress: adding configuration for " + _iface);
-
+NetConfigType::ConfigSystem current_system(const Horizon::Script *script) {
NetConfigType::ConfigSystem system = NetConfigType::Netifrc;
const Key *key = script->getOneValue("netconfigtype");
@@ -363,7 +362,13 @@ bool NetAddress::execute() const {
system = nct->type();
}
- switch(system) {
+ return system;
+}
+
+bool NetAddress::execute() const {
+ output_info(pos, "netaddress: adding configuration for " + _iface);
+
+ switch(current_system(script)) {
case NetConfigType::Netifrc:
default:
return execute_address_netifrc(this);
@@ -373,6 +378,107 @@ bool NetAddress::execute() const {
}
+Key *PPPoE::parseFromData(const std::string &data, const ScriptLocation &pos,
+ int *errors, int *, const Script *script) {
+ std::string::size_type spos, next;
+ std::map<std::string, std::string> params;
+ std::string iface;
+
+ spos = data.find_first_of(' ');
+ iface = data.substr(0, spos);
+ if(iface.length() > IFNAMSIZ) {
+ if(errors) *errors += 1;
+ output_error(pos, "pppoe: invalid interface name '" + iface + "'",
+ "interface names must be 16 characters or less");
+ return nullptr;
+ }
+
+ while(spos != std::string::npos) {
+ std::string key, val;
+ std::string::size_type equals;
+
+ spos++;
+
+ next = data.find_first_of(' ', spos);
+ equals = data.find_first_of('=', spos);
+ if(equals != std::string::npos && equals < next) {
+ key = data.substr(spos, equals - spos);
+ if(next == std::string::npos) {
+ val = data.substr(equals + 1);
+ } else {
+ val = data.substr(equals + 1, next - equals);
+ }
+ } else {
+ if(next == std::string::npos) {
+ key = data.substr(spos);
+ } else {
+ key = data.substr(spos, next - spos);
+ }
+ }
+
+ params[key] = val;
+
+ spos = next;
+ }
+
+ return new PPPoE(script, pos, iface, params);
+}
+
+bool PPPoE::validate() const {
+ bool valid = true;
+ const std::set<std::string> valid_keys = {"mtu", "username", "password",
+ "lcp-echo-interval",
+ "lcp-echo-failure"};
+
+ for(const auto &elem : this->params()) {
+ if(valid_keys.find(elem.first) == valid_keys.end()) {
+ output_error(this->pos, "pppoe: invalid parameter", elem.first);
+ valid = false;
+ }
+ }
+
+ return valid;
+}
+
+static int ppp_link_count = 0;
+
+bool execute_pppoe_netifrc(const PPPoE *link) {
+ std::ofstream ethconfig("/tmp/horizon/netifrc/config_" + link->iface(),
+ std::ios_base::trunc);
+ if(!ethconfig) {
+ output_error(link->where(), "pppoe: couldn't write network "
+ "configuration for " + link->iface());
+ return false;
+ }
+
+ ethconfig << "null";
+
+ std::string linkiface{"ppp" + std::to_string(ppp_link_count)};
+
+ std::ofstream config("/tmp/horizon/netifrc/config_" + linkiface);
+ if(!config) {
+ output_error(link->where(), "pppoe: couldn't write network "
+ "configuration for " + linkiface);
+ return false;
+ }
+ config << "ppp";
+ return true;
+}
+
+bool PPPoE::execute() const {
+ output_info(pos, "pppoe: adding configuration for " + _iface);
+
+ switch(current_system(script)) {
+ case NetConfigType::Netifrc:
+ default:
+ return execute_pppoe_netifrc(this);
+ case NetConfigType::ENI:
+ /* eni */
+ return false;
+ }
+}
+
+
Key *Nameserver::parseFromData(const std::string &data,
const ScriptLocation &pos, int *errors, int *,
const Script *script) {
diff --git a/hscript/network.hh b/hscript/network.hh
index 18ffc34..2ed40ca 100644
--- a/hscript/network.hh
+++ b/hscript/network.hh
@@ -13,6 +13,8 @@
#ifndef __HSCRIPT_NETWORK_HH_
#define __HSCRIPT_NETWORK_HH_
+#include <map>
+
#include "key.hh"
#include "util/output.hh"
@@ -93,6 +95,29 @@ public:
bool execute() const override;
};
+class PPPoE : public Key {
+private:
+ const std::string _iface;
+ const std::map<std::string, std::string> _params;
+
+ PPPoE(const Script *_sc, const ScriptLocation &_pos, const std::string &_i,
+ const std::map<std::string, std::string> &_p) : Key(_sc, _pos),
+ _iface(_i), _params(_p) {}
+public:
+ static Key *parseFromData(const std::string &, const ScriptLocation &,
+ int*, int*, const Script *);
+
+ /*! Retrieve the interface to which this PPPoE link is associated. */
+ const std::string iface() const { return this->_iface; }
+ /*! Retrieve the parameters for this PPPoE link. */
+ const std::map<std::string, std::string> params() const {
+ return this->_params;
+ }
+
+ bool validate() const override;
+ bool execute() const override;
+};
+
class Nameserver : public StringKey {
private:
Nameserver(const Script *_s, const ScriptLocation &_pos,
diff --git a/hscript/script.cc b/hscript/script.cc
index 897d5d4..20ccbe5 100644
--- a/hscript/script.cc
+++ b/hscript/script.cc
@@ -58,6 +58,7 @@ const std::map<std::string, key_parse_fn> valid_keys = {
{"netaddress", &NetAddress::parseFromData},
{"nameserver", &Nameserver::parseFromData},
{"netssid", &NetSSID::parseFromData},
+ {"pppoe", &PPPoE::parseFromData},
{"username", &Username::parseFromData},
{"useralias", &UserAlias::parseFromData},
@@ -98,6 +99,8 @@ bool Script::ScriptPrivate::store_key(const std::string &key_name, Key *obj,
std::unique_ptr<NetSSID> ssid(dynamic_cast<NetSSID *>(obj));
this->ssids.push_back(std::move(ssid));
return true;
+ } else if(key_name == "pppoe") {
+ return store_pppoe(obj, pos, errors, warnings, opts);
} else if(key_name == "hostname") {
return store_hostname(obj, pos, errors, warnings, opts);
} else if(key_name == "pkginstall") {
diff --git a/hscript/script_e.cc b/hscript/script_e.cc
index 866a836..87ade0f 100644
--- a/hscript/script_e.cc
+++ b/hscript/script_e.cc
@@ -287,7 +287,7 @@ bool Script::execute() const {
}
bool dhcp = false;
- if(!internal->addresses.empty()) {
+ if(!internal->addresses.empty() || !internal->pppoes.empty()) {
fs::path conf_dir, targ_netconf_dir, targ_netconf_file;
switch(netconfsys) {
case NetConfigType::Netifrc:
@@ -319,6 +319,13 @@ bool Script::execute() const {
if(addr->type() == NetAddress::DHCP) dhcp = true;
}
+ int pppcnt = 0;
+ for(auto &ppp_link : internal->pppoes) {
+ EXECUTE_OR_FAIL("pppoe", ppp_link);
+ ifaces.insert(ppp_link->iface());
+ ifaces.insert("ppp" + std::to_string(pppcnt++));
+ }
+
std::ostringstream conf;
if(netconfsys == NetConfigType::ENI) {
diff --git a/hscript/script_i.hh b/hscript/script_i.hh
index abe56ec..b82b807 100644
--- a/hscript/script_i.hh
+++ b/hscript/script_i.hh
@@ -72,6 +72,8 @@ struct Script::ScriptPrivate {
std::vector< std::unique_ptr<Nameserver> > nses;
/*! Wireless networking configuration */
std::vector< std::unique_ptr<NetSSID> > ssids;
+ /*! PPPoE configuration */
+ std::vector< std::unique_ptr<PPPoE> > pppoes;
/*! APK repositories */
std::vector< std::unique_ptr<Repository> > repos;
@@ -153,6 +155,21 @@ struct Script::ScriptPrivate {
return true;
}
+ bool store_pppoe(Key *obj, const ScriptLocation &pos, int *errors,
+ int *, const ScriptOptions &) {
+ PPPoE *ppp = dynamic_cast<PPPoE *>(obj);
+ for(const auto &ppplink : pppoes) {
+ if(ppplink->iface() == ppp->iface()) {
+ DUPLICATE_ERROR(ppplink, "pppoe", ppplink->iface());
+ return false;
+ }
+ }
+
+ std::unique_ptr<PPPoE> uppp(ppp);
+ pppoes.push_back(std::move(uppp));
+ return true;
+ }
+
bool store_hostname(Key* obj, const ScriptLocation &pos, int *errors,
int *, const ScriptOptions &) {
if(hostname) {
diff --git a/hscript/script_v.cc b/hscript/script_v.cc
index 1fc3726..41f1756 100644
--- a/hscript/script_v.cc
+++ b/hscript/script_v.cc
@@ -252,6 +252,10 @@ bool Horizon::Script::validate() const {
if(!ssid->validate()) failures++;
}
+ for(auto &pppoe : internal->pppoes) {
+ if(!pppoe->validate()) failures++;
+ }
+
/* REQ: Runner.Validate.hostname */
if(!internal->hostname->validate()) failures++;
diff --git a/tests/fixtures/0241-pppoe-basic.installfile b/tests/fixtures/0241-pppoe-basic.installfile
new file mode 100644
index 0000000..9e7d4e5
--- /dev/null
+++ b/tests/fixtures/0241-pppoe-basic.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+pppoe eth0
diff --git a/tests/fixtures/0242-pppoe-auth.installfile b/tests/fixtures/0242-pppoe-auth.installfile
new file mode 100644
index 0000000..250e820
--- /dev/null
+++ b/tests/fixtures/0242-pppoe-auth.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+pppoe eth0 username=awilfox password=fuzzball
diff --git a/tests/fixtures/0243-pppoe-allkeys.installfile b/tests/fixtures/0243-pppoe-allkeys.installfile
new file mode 100644
index 0000000..6b70daa
--- /dev/null
+++ b/tests/fixtures/0243-pppoe-allkeys.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+pppoe eth0 username=awilfox password=fuzzball mtu=9001 lcp-echo-interval=10 lcp-echo-failure=5
diff --git a/tests/fixtures/0244-pppoe-invalid.installfile b/tests/fixtures/0244-pppoe-invalid.installfile
new file mode 100644
index 0000000..8fc2768
--- /dev/null
+++ b/tests/fixtures/0244-pppoe-invalid.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+pppoe eth0 cat=meow
diff --git a/tests/fixtures/0245-pppoe-valueless.installfile b/tests/fixtures/0245-pppoe-valueless.installfile
new file mode 100644
index 0000000..ee75450
--- /dev/null
+++ b/tests/fixtures/0245-pppoe-valueless.installfile
@@ -0,0 +1,6 @@
+network false
+hostname test.machine
+pkginstall adelie-base
+rootpw $6$gumtLGmHwOVIRpQR$2M9PUO24hy5mofzWWf9a.YLbzOgOlUby1g0hDj.wG67E2wrrvys59fq02PPdxBdbgkLZFtjfEx6MHZwMBamwu/
+mount /dev/sda1 /
+pppoe eth0 username password=fuzzball
diff --git a/tests/spec/validator_spec.rb b/tests/spec/validator_spec.rb
index 8fb6c95..d2d121a 100644
--- a/tests/spec/validator_spec.rb
+++ b/tests/spec/validator_spec.rb
@@ -278,6 +278,37 @@ RSpec.describe 'HorizonScript validation', :type => :aruba do
expect(last_command_started).to have_output(/error: .*nameserver.*valid IPv6/)
end
end
+ context "for 'pppoe' key" do
+ it "succeeds with only an interface" do
+ use_fixture '0241-pppoe-basic.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "succeeds with autnentication credentials" do
+ use_fixture '0242-pppoe-auth.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "succeeds with all valid keys" do
+ use_fixture '0243-pppoe-allkeys.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ it "fails with an invalid key" do
+ use_fixture '0244-pppoe-invalid.installfile'
+ run_validate
+ expect(last_command_started).to have_output(/error: .*pppoe.*invalid/)
+ end
+ it "succeeds with a value-less key" do
+ use_fixture '0245-pppoe-valueless.installfile'
+ run_validate
+ expect(last_command_started).to have_output(PARSER_SUCCESS)
+ expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
+ end
+ end
context "for 'firmware' key" do
it "always supports 'false' value" do
use_fixture '0112-firmware-false.installfile'
@@ -687,12 +718,12 @@ RSpec.describe 'HorizonScript validation', :type => :aruba do
run_validate
expect(last_command_started).to have_output(/error: .*svcenable.*invalid/)
end
- it "succeeds with a runlevel specified" do
+ it "succeeds with a runlevel specified" do
use_fixture '0239-svcenable-runlevel.installfile'
run_validate
expect(last_command_started).to have_output(PARSER_SUCCESS)
expect(last_command_started).to have_output(VALIDATOR_SUCCESS)
- end
+ end
end
context "for 'diskid' key" do
it "succeeds with basic disk identification" do