diff options
| author | flu0r1ne <flu0r1ne@flu0r1ne.net> | 2023-08-25 19:05:30 -0500 | 
|---|---|---|
| committer | flu0r1ne <flu0r1ne@flu0r1ne.net> | 2023-08-25 19:05:30 -0500 | 
| commit | 84ba3607bf4b87e2f872e960c957d7d860acd83d (patch) | |
| tree | a4d5e92b2b88edd9c325ada62bf6d60948459529 | |
| parent | 2f0a9c87bd5acd8fc0852f599599d031cde44bbe (diff) | |
| download | wg2nd-84ba3607bf4b87e2f872e960c957d7d860acd83d.tar.xz wg2nd-84ba3607bf4b87e2f872e960c957d7d860acd83d.zip | |
Rename project wg2sd -> wg2nd, new CLI + generate
1. Renamed the project from wg2sd to wg2nd
2. Modified the _gen_netdev_cfg() function to handle the MTUBytes field.
3. Add new CLI with `generate` and `install` commands
4. Modified the gen_systemd_config() function to accept keyfile_or_output_path and filename parameters.
   - user can choose the name of the keyfile on the CLI
   - user can choose alternative output filename (instead of just using
     the  interface name)
| -rw-r--r-- | makefile | 6 | ||||
| -rw-r--r-- | src/main.cpp | 327 | ||||
| -rw-r--r-- | src/wg2nd.cpp (renamed from src/wg2sd.cpp) | 114 | ||||
| -rw-r--r-- | src/wg2nd.hpp (renamed from src/wg2sd.hpp) | 12 | ||||
| -rw-r--r-- | test/wg2nd_test.cpp (renamed from test/wg2sd_test.cpp) | 10 | 
5 files changed, 367 insertions, 102 deletions
| @@ -24,7 +24,7 @@ DEBUGFLAGS = -ggdb -O0  LDFLAGS = -largon2  # Object files -OBJECTS := wg2sd.o +OBJECTS := wg2nd.o  OBJECTS += main.o  # Source directory @@ -41,7 +41,7 @@ OBJ_DIR = obj  DEBUG_OBJ_DIR = obj/debug  # Target executable -CMD = wg2sd +CMD = wg2nd  # Build rules  all: CXXFLAGS += $(RELEASE_CXXFLAGS) @@ -62,7 +62,7 @@ $(CMD): $(addprefix $(OBJ_DIR)/, $(OBJECTS))  $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)  	$(CXX) $(CXXFLAGS) -c $< -o $@ -$(TEST_DIR)/%: $(TEST_DIR)/%.cpp $(addprefix $(OBJ_DIR)/, wg2sd.o) | $(OBJ_DIR) +$(TEST_DIR)/%: $(TEST_DIR)/%.cpp $(addprefix $(OBJ_DIR)/, wg2nd.o) | $(OBJ_DIR)  	$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@  $(OBJ_DIR) $(DEBUG_OBJ_DIR): diff --git a/src/main.cpp b/src/main.cpp index 19b5ced..b8c8ec6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,14 @@ +#include <iostream> +#include <string> +#include <vector> +#include <filesystem> +#include <cstdlib> +#include <cstring> +#include <cstdio> +#include <getopt.h> +  // ===================================== -//   ERROR HANDING - FROM FCUTILS +//	 ERROR HANDING - FROM FCUTILS  // =====================================  #include <stdio.h> @@ -69,35 +78,122 @@ void err(char const * format, ...) {  }  // ============================================= -//   COMMAND LINE UTILITY +//	 COMMAND LINE UTILITY  // ============================================= +constexpr char const * DEFAULT_OUTPUT_PATH = "/etc/systemd/network/"; -#include "wg2sd.hpp" +/* + * HELP AND USAGE + */ -#include <filesystem> -#include <fstream> -#include <iostream> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <grp.h> +void die_usage(const char *prog) { +	err("Usage: %s { install, generate } [ OPTIONS ] { -h, CONFIG_FILE }", prog); +	die("Use -h for help"); +} + +void print_help(const char *prog) { +	err("Usage: %s { install, generate } [ OPTIONS ] { -h, CONFIG_FILE }\n", prog); +	err("  CONFIG_FILE is the complete path to a WireGuard configuration file, used by"); +	err("  `wg-quick`. `wg2nd` will convert the WireGuard configuration to networkd"); +	err("  files.\n"); +	err("  The generated configurations are functionally equivalent to `wg-quick(8)`"); +	err("  with the following exceptions:\n"); +	err("  1. When unspecified, `wg-quick` determines whether `FwMark` and `Table` are available dynamically,"); +	err("     ensuring that the routing table and `fwmark` are not already in use. `wg2nd` sets"); +	err("     the `fwmark` to a random number (deterministically generated from the interface"); +	err("     name). If more than 500 `fwmarks` are in use, there is a non-negligible chance of a"); +	err("     collision. This would occur when there are more than 500 active WireGuard interfaces.\n"); +	err("  2. The PreUp, PostUp, PreDown, and PostDown script snippets are ignored.\n"); +	err("  3. `wg-quick(8)` installs a firewall when a default route is specified (i.e., when `0.0.0.0/0`"); +	err("     or `::/0` are specified in `AllowedIPs`). This is not installed by"); +	err("     default with `wg2nd install`. The equivalent firewall can be generated with"); +	err("     `wg2nd generate -t nft CONFIG_FILE`. Refer to `nft(8)` for details.\n"); +	err("  Actions:"); +	err("    install   Generate and install the configuration with restricted permissions"); +	err("    generate  Generate specific configuration files and write the results to stdout\n"); +	err("  Options:"); +	err("    -h        Print this help"); +	exit(EXIT_SUCCESS); +} -[[noreturn]] void die_usage(char const * prog) { -	err("Usage: %s [ -o OUTPUT_PATH ] CONFIG_FILE", prog); +void die_usage_generate(const char *prog) { +	err("Usage: %s generate [ -h ] [ -k KEYPATH ] [ -t { network, netdev, keyfile, nft } ] CONFIG_FILE", prog);  	die("Use -h for help");  } -void print_help(char const * prog) { -	err("Usage: %s [ -h | -f | -o OUTPUT_PATH ] CONFIG_FILE", prog); +void print_help_generate(const char *prog) { +	err("Usage: %s generate [ -h ] [ -k KEYPATH ] [ -t { network, netdev, keyfile, nft } ] CONFIG_FILE\n", prog);  	err("Options:"); -	err("-o OUTPUT_PATH\tSet the output path (default is /etc/systemd/network)"); -	err("-f            \tOutput firewall rules"); -	err("-h            \tDisplay this help message"); +	err("  -t FILE_TYPE"); +	err("     network  Generate a Network Configuration File (see systemd.network(8))"); +	err("     netdev   Generate a Virtual Device File (see systemd.netdev(8))"); +	err("     keyfile  Print the interface's private key"); +	err("     nft      Print the netfilter table `nft(8)` installed by `wg-quick(8)`\n"); +	err("  -k KEYPATH  Full path to the keyfile (a path relative to /etc/systemd/network is generated"); +	err("              if unspecified)\n"); +	err("  -h        Print this help");  	exit(EXIT_SUCCESS);  } -using namespace wg2sd; +void die_usage_install(const char *prog) { +	err("Usage: %s install [ -h ] [ -f FILE_NAME ] [ -k KEYFILE ] [ -o OUTPUT_PATH ] CONFIG_FILE", prog); +	die("Use -h for help"); +} + +void print_help_install(const char *prog) { +	err("Usage: %s install [ -h ] [ -f FILE_NAME ] [ -o OUTPUT_PATH ] CONFIG_FILE\n", prog); +	err("  `wg2nd install` translates `wg-quick(8)` configuration into corresponding"); +	err("  `networkd` configuration and installs the resulting files in `OUTPUT_PATH`.\n"); +	err("  `wg2nd install` generates a `netdev`, `network`, and `keyfile` for each"); +	err("  CONFIG_FILE. Links will be installed with a `manual` `ActivationPolicy`."); +	err("  The interface can be brought up with `networkctl up INTERFACE` and down"); +	err("  with `networkctl down INTERFACE`.\n"); +	err("  `wg-quick(8)` installs a firewall when a default route (i.e., when `0.0.0.0/0`"); +	err("  or `::/0` is specified in `AllowedIPs`). This is not installed by default"); +	err("  with `wg2nd install`. The equivalent firewall can be generated with"); +	err("  `wg2nd generate -t nft CONFIG_FILE`.\n"); +	err("Options:"); +	err("  -o OUTPUT_PATH  The installation path (default is /etc/systemd/network)\n"); +	err("  -f FILE_NAME    The base name for the installed configuration files. The"); +	err("                  networkd-specific configuration suffix will be added"); +	err("                  (FILE_NAME.netdev for systemd-netdev(8) files,"); +	err("                  FILE_NAME.network for systemd-network(8) files,"); +	err("                  and FILE_NAME.keyfile for keyfiles)\n"); +	err("  -k KEYFILE       The name of the private keyfile\n"); +	err("  -h              Print this help"); +	exit(EXIT_SUCCESS); +} + + +/* + * PARSING + */ + +enum class FileType { +	NONE = 0, +	NETWORK, +	NETDEV, +	KEYFILE, +	NFT +}; + + +/* + * INTERNAL LOGIC + */ + +#include "wg2nd.hpp" + +#include <iostream> +#include <fstream> +#include <optional> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <grp.h> + +using namespace wg2nd;  void write_systemd_file(SystemdFilespec const & filespec, std::string output_path, bool secure) {  	std::string full_path = output_path + "/" + filespec.name; @@ -142,44 +238,23 @@ void write_systemd_file(SystemdFilespec const & filespec, std::string output_pat  	}  } -int main(int argc, char ** argv) { -	int opt; -	std::filesystem::path output_path = "/etc/systemd/network"; -	bool print_firewall_rules = false; - -	while ((opt = getopt(argc, argv, "o:fh")) != -1) { -		switch (opt) { -			case 'o': -				output_path = optarg; -				break; -			case 'f': -				print_firewall_rules = true; -				break; -			case 'h': -				print_help(argv[0]); -				break; -			default: /* '?' */ -				die_usage(argv[0]); -		} -	} - -	if (optind >= argc) { -		die_usage(argv[0]); -	} - -	std::filesystem::path config_path = argv[optind]; +SystemdConfig generate_cfg_or_die( +	std::filesystem::path && config_path, +	std::filesystem::path const & keyfile_or_output_path, +	std::optional<std::string> const & filename +	) {  	std::fstream cfg_stream { config_path };  	if(!cfg_stream.is_open()) {  		die("Failed to open config file %s", config_path.string().c_str());  	} -	std::string interface_name = interface_name_from_filename(config_path); -  	SystemdConfig cfg; +	std::string interface_name = interface_name_from_filename(config_path); +  	try { -		cfg = wg2sd::wg2sd(interface_name, cfg_stream, output_path); +		cfg = wg2nd::wg2nd(interface_name, cfg_stream, keyfile_or_output_path, filename);  	} catch(ConfigurationException const & cex) {  		const ParsingException * pex = dynamic_cast<const ParsingException *>(&cex); @@ -191,16 +266,25 @@ int main(int argc, char ** argv) {  	} -	if(print_firewall_rules) { -		fprintf(stdout, "%s", cfg.firewall.c_str()); +	return cfg; +} -		return 0; -	} + +void wg2nd_install_internal(std::optional<std::string> && filename, std::string && keyfile_name, +	std::filesystem::path && output_path, std::filesystem::path && config_path) {  	if(!std::filesystem::path(output_path).is_absolute()) {  		output_path = std::filesystem::absolute(output_path);  	} +	std::filesystem::path keyfile_or_output_path = output_path; + +	if(!keyfile_name.empty()) { +		keyfile_or_output_path /= keyfile_name; +	} + +	SystemdConfig cfg = generate_cfg_or_die(std::move(config_path), keyfile_or_output_path, std::move(filename)); +  	for(std::string const & warning : cfg.warnings) {  		err("warning: %s", warning.c_str());  	} @@ -212,6 +296,147 @@ int main(int argc, char ** argv) {  	for(SystemdFilespec const & spec : cfg.symmetric_keyfiles) {  		write_systemd_file(spec, output_path, true);  	} +} + +void wg2nd_generate_internal(FileType type, std::string && config_file, +	std::optional<std::filesystem::path> && keyfile_path) { + +	SystemdConfig cfg = generate_cfg_or_die( +		std::move(config_file), std::move(keyfile_path.value_or(DEFAULT_OUTPUT_PATH)), {} +	); + +	switch(type) { +		case FileType::NFT: +			printf("%s", cfg.firewall.c_str()); +			break; +		case FileType::NETWORK: +			printf("%s", cfg.network.contents.c_str()); +			break; +		case FileType::NETDEV: +			printf("%s", cfg.netdev.contents.c_str()); +			break; +		case FileType::KEYFILE: +			printf("%s", cfg.private_keyfile.contents.c_str()); +			break; +		default: +			break; +	} +} + + +static int wg2nd_generate(char const * prog, int argc, char **argv) { +	std::filesystem::path config_path = ""; + +	FileType type = FileType::NONE; +	std::optional<std::filesystem::path> keyfile_path = {}; + +	int opt; +	while ((opt = getopt(argc, argv, "ht:k:")) != -1) { +		switch (opt) { +			case 't': +				if (strcmp(optarg, "network") == 0) { +					type = FileType::NETWORK; +				} else if (strcmp(optarg, "netdev") == 0) { +					type = FileType::NETDEV; +				} else if (strcmp(optarg, "keyfile") == 0) { +					type = FileType::KEYFILE; +				} else if (strcmp(optarg, "nft") == 0) { +					type = FileType::NFT; +				} else { +					die("Unknown file type: %s", optarg); +				} +				break; +			case 'k': +				keyfile_path = optarg; +				break; +			case 'h': +				print_help_generate(prog); +				break; +			default: +				die_usage_generate(prog); +		} +	} + +	if (optind >= argc) { +		die_usage_generate(prog); +	} + +	config_path = argv[optind]; + +	wg2nd_generate_internal(type, std::move(config_path), std::move(keyfile_path)); + +	return 0; +} + +static int wg2nd_install(char const * prog, int argc, char **argv) { +	std::filesystem::path config_path = ""; + +	std::optional<std::string> filename = {}; +	std::filesystem::path output_path = DEFAULT_OUTPUT_PATH; +	std::string keyfile_name = ""; + +	int opt; +	while ((opt = getopt(argc, argv, "o:f:k:h")) != -1) { +		switch (opt) { +			case 'o': { +				std::string path = optarg; +				if(path[path.size() - 1] != '/') { +					path.push_back('/'); +				} +				output_path = std::move(path); +				break; +			} +			case 'f': +				filename = optarg; +				break; +			case 'h': +				print_help_install(prog); +				break; +			case 'k': +				keyfile_name = optarg; +				break; +			default: +				die_usage_install(prog); +		} +	} + +	if (optind >= argc) { +		die_usage_install(prog); +	} + +	config_path = argv[optind]; + +	wg2nd_install_internal(std::move(filename), std::move(keyfile_name), std::move(output_path), std::move(config_path)); + +	return 0; +} + +// The main function remains the same as before + + +int main(int argc, char **argv) { +	char const * prog = "wg2nd"; + +	if(argc > 0) { +		prog = argv[0]; +	} + +	if (argc < 2) { +		die_usage(prog); +	} + +	std::string action = argv[1]; + +	if (action == "generate") { +		return wg2nd_generate(prog, argc - 1, argv + 1); +	} else if (action == "install") { +		return wg2nd_install(prog, argc - 1, argv + 1); +	} else if (action == "-h" || action == "--help") { +		print_help(prog); +	} else { +		err("Unknown action: %s", action.c_str()); +		die_usage(prog); +	}  	return 0;  } diff --git a/src/wg2sd.cpp b/src/wg2nd.cpp index 4c39a03..c53df04 100644 --- a/src/wg2sd.cpp +++ b/src/wg2nd.cpp @@ -1,4 +1,4 @@ -#include "wg2sd.hpp" +#include "wg2nd.hpp"  #include <exception>  #include <sstream> @@ -27,7 +27,7 @@ std::string hashed_keyfile_name(std::string const & priv_key) {  	uint8_t hash[HASHLEN]; -	argon2i_hash_raw(t_cost, m_cost, parallelism, key, keylen, SALT, sizeof(SALT), hash, HASHLEN); +	argon2id_hash_raw(t_cost, m_cost, parallelism, key, keylen, SALT, sizeof(SALT), hash, HASHLEN);  	constexpr char KEYFILE_EXT[] = ".keyfile"; @@ -47,8 +47,29 @@ std::string hashed_keyfile_name(std::string const & priv_key) {  	return std::string { filename } ;  } +uint32_t deterministic_fwmark(std::string const & interface_name) { +	constexpr uint8_t const SALT[] = { +		0x90, 0x08, 0x82, 0xd7, 0x75, 0x68, 0xf4, 0x8e, +		0x90, 0x74, 0x0c, 0x74, 0x0d, 0xf4, 0xfb, 0x91, +		0xe5, 0x44, 0x87, 0x7e, 0xce, 0x48, 0xcf, 0x01, +	}; + +	uint8_t const * key = reinterpret_cast<uint8_t const *>(interface_name.c_str()); +	uint32_t keylen = interface_name.size(); + +	uint32_t mark; + +	uint8_t t_cost = 2; +	uint32_t m_cost = 1 << 10; +	uint32_t parallelism = 1; + +	argon2id_hash_raw(t_cost, m_cost, parallelism, key, keylen, SALT, sizeof(SALT), &mark, sizeof(mark)); + +	return mark; +} + -namespace wg2sd { +namespace wg2nd {  	std::string interface_name_from_filename(std::filesystem::path config_path) {  		std::string interface_name = config_path.filename().string(); @@ -219,6 +240,8 @@ namespace wg2sd {  					}  					cfg.intf.listen_port = port; +				} else if (key == "MTU") { +					cfg.intf.mtu = value;  				} else if (key == "PreUp") {  					cfg.intf.preup = value;  				} else if (key == "PostUp") { @@ -303,7 +326,7 @@ namespace wg2sd {  		return cfg;  	} -	static void _write_table(std::stringstream & firewall, Config const & cfg, std::vector<std::string_view> addrs, bool ipv4) { +	static void _write_table(std::stringstream & firewall, Config const & cfg, std::vector<std::string_view> addrs, bool ipv4, uint32_t fwd_table) {  		char const * ip = ipv4 ? "ip" : "ip6";  		firewall << "table " << ip << " " << cfg.intf.name << " {\n" @@ -323,13 +346,13 @@ namespace wg2sd {  		         << "\n"  		         << "  chain postmangle {\n"  		         << "    type filter hook postrouting priority mangle; policy accept;\n" -		         << "    meta l4proto udp meta mark " << std::hex << cfg.intf.table << std::dec << "ct mark set meta mark;\n" +		         << "    meta l4proto udp meta mark 0x" << std::hex << fwd_table << std::dec << " ct mark set meta mark;\n"  		         << "  }\n"  		         << "}\n";  	} -	std::string _gen_nftables_firewall(Config const & cfg) { +	std::string _gen_nftables_firewall(Config const & cfg, uint32_t fwd_table) {  		std::stringstream firewall;  		std::vector<std::string_view> ipv4_addrs; @@ -343,39 +366,31 @@ namespace wg2sd {  			}  		} -		_write_table(firewall, cfg, ipv4_addrs, true); - -		firewall << "\n"; +		if(ipv4_addrs.size() > 0) { +			_write_table(firewall, cfg, ipv4_addrs, true, fwd_table); +			firewall << "\n"; +		} -		_write_table(firewall, cfg, ipv6_addrs, false); +		if(ipv6_addrs.size() > 0) { +			_write_table(firewall, cfg, ipv6_addrs, false, fwd_table); +		}  		return firewall.str();  	} -	static std::string _gen_netdev_cfg(Config const & cfg, uint32_t fwd_table, std::string const & private_keyfile, -			std::vector<SystemdFilespec> & symmetric_keyfiles, std::string const & output_path) { +	static std::string _gen_netdev_cfg(Config const & cfg, uint32_t fwd_table, std::filesystem::path const & private_keyfile, +			std::vector<SystemdFilespec> & symmetric_keyfiles) {  		std::stringstream netdev; -		netdev << "# Autogenerated by wg2sd\n"; +		netdev << "# Autogenerated by wg2nd\n";  		netdev << "[NetDev]\n";  		netdev << "Name = " << cfg.intf.name << "\n";  		netdev << "Kind = wireguard\n";  		netdev << "Description = " << cfg.intf.name << " - wireguard tunnel\n"; - -		if(!cfg.intf.mtu.empty()) { -			netdev << "MTUBytes = " << cfg.intf.mtu << "\n"; -		} -  		netdev << "\n";  		netdev << "[WireGuard]\n"; -		netdev << "PrivateKeyFile = " << output_path; - -		if(output_path.back() != '/') { -			netdev << "/"; -		} - -		netdev << private_keyfile << "\n"; +		netdev << "PrivateKeyFile = " << private_keyfile.string() << "\n";  		if(cfg.intf.listen_port.has_value()) {  			netdev << "ListenPort = " << cfg.intf.listen_port.value() << "\n"; @@ -441,11 +456,18 @@ namespace wg2sd {  	static std::string _gen_network_cfg(Config const & cfg, uint32_t fwd_table) {  		std::stringstream network; -		network << "# Autogenerated by wg2sd\n"; +		network << "# Autogenerated by wg2nd\n";  		network << "[Match]\n";  		network << "Name = " << cfg.intf.name << "\n";  		network << "\n"; +		network << "[Link]" << "\n"; +		network << "ActivationPolicy = manual\n"; +		if(!cfg.intf.mtu.empty()) { +			network << "MTUBytes = " << cfg.intf.mtu << "\n"; +		} +		network << "\n"; +  		network << "[Network]\n";  		for(std::string const & addr : cfg.intf.addresses) {  			network << "Address = " << addr << "\n"; @@ -523,19 +545,21 @@ namespace wg2sd {  		return network.str();  	} -	static uint32_t _random_table() { -		std::random_device rd; -		std::mt19937 rng { rd() }; +	static uint32_t _deterministic_random_table(std::string const & interface_name) {  		uint32_t table = 0;  		while(table == 0 or table == MAIN_TABLE or table == LOCAL_TABLE) { -			table = rng() % UINT32_MAX; +			table = deterministic_fwmark(interface_name);  		}  		return table;  	} -	SystemdConfig gen_systemd_config(Config const & cfg, std::string const & output_path) { +	SystemdConfig gen_systemd_config( +		Config const & cfg, +		std::filesystem::path const & keyfile_or_output_path, +		std::optional<std::string> const & filename +	) {  		// If the table is explicitly specified with Table=<number>,  		// all routes are added to this table. @@ -549,11 +573,18 @@ namespace wg2sd {  		// table.  		//  		// If Table=off, no routes are added. -		uint32_t fwd_table = _random_table(); +		uint32_t fwd_table = _deterministic_random_table(cfg.intf.name);  		std::vector<SystemdFilespec> symmetric_keyfiles; -		std::string private_keyfile = hashed_keyfile_name(cfg.intf.private_key); +		std::filesystem::path keyfile_path; + +		if(keyfile_or_output_path.has_filename()) { +			keyfile_path = keyfile_or_output_path; +		} else { +			std::string private_keyfile = hashed_keyfile_name(cfg.intf.private_key); +			keyfile_path = keyfile_or_output_path / private_keyfile; +		}  		std::vector<std::string> warnings; @@ -572,27 +603,30 @@ if(!cfg.intf.field_.empty()) { \  			warnings.push_back("[Interface] section contains a field \"PreUp\" which does not have a systemd-networkd analog");  		} +		std::string const & basename = filename.value_or(cfg.intf.name); +  		return SystemdConfig {  			.netdev = { -				.name = cfg.intf.name + ".netdev", -				.contents = _gen_netdev_cfg(cfg, fwd_table, private_keyfile, symmetric_keyfiles, output_path), +				.name = basename + ".netdev", +				.contents = _gen_netdev_cfg(cfg, fwd_table, keyfile_path, symmetric_keyfiles),  			},  			.network = { -				.name = cfg.intf.name + ".network", +				.name = basename + ".network",  				.contents = _gen_network_cfg(cfg, fwd_table)  			},  			.private_keyfile = { -				.name = private_keyfile, +				.name = keyfile_path.filename(),  				.contents = cfg.intf.private_key + "\n",  			},  			.symmetric_keyfiles = std::move(symmetric_keyfiles),  			.warnings = std::move(warnings), -			.firewall = _gen_nftables_firewall(cfg), +			.firewall = _gen_nftables_firewall(cfg, fwd_table),  		};  	} -	SystemdConfig wg2sd(std::string const & interface_name, std::istream & stream, std::string const & output_path) { -		return gen_systemd_config(parse_config(interface_name, stream), output_path); +	SystemdConfig wg2nd(std::string const & interface_name, std::istream & stream, +			std::filesystem::path const & keyfile_or_output_path, std::optional<std::string> const & filename) { +		return gen_systemd_config(parse_config(interface_name, stream), keyfile_or_output_path, filename);  	}  } diff --git a/src/wg2sd.hpp b/src/wg2nd.hpp index e80a284..7bf7f54 100644 --- a/src/wg2sd.hpp +++ b/src/wg2nd.hpp @@ -9,7 +9,7 @@  #include <cstdint> -namespace wg2sd { +namespace wg2nd {  	struct Interface {  		// File name, or defaults to "wg" @@ -134,8 +134,14 @@ namespace wg2sd {  	Config parse_config(std::string const & interface_name, std::istream & stream); -	SystemdConfig gen_systemd_config(Config const & cfg, std::string const & output_path); +	SystemdConfig gen_systemd_config( +		Config const & cfg, +		std::filesystem::path const & keyfile_or_output_path, +		std::optional<std::string> const & filename +	); -	SystemdConfig wg2sd(std::string const & interface_name, std::istream & stream, std::string const & output_path); +	SystemdConfig wg2nd(std::string const & interface_name, std::istream & stream, +		std::filesystem::path const & keyfile_or_output_path, +		std::optional<std::string> const & filename);  }; diff --git a/test/wg2sd_test.cpp b/test/wg2nd_test.cpp index 5d57ac9..39b0766 100644 --- a/test/wg2sd_test.cpp +++ b/test/wg2nd_test.cpp @@ -1,17 +1,17 @@  #include "utest.h" -#include "wg2sd.hpp" +#include "wg2nd.hpp"  #include <sstream>  #include <array> -namespace wg2sd { +namespace wg2nd {  	extern bool _is_default_route(std::string const & cidr);  	extern bool _is_ipv4_route(std::string const & cidr);  }; -using namespace wg2sd; +using namespace wg2nd; -UTEST(wg2sd, ip_helpers) { +UTEST(wg2nd, ip_helpers) {  	std::array<std::string, 8> default_routes = {  		"0/0", @@ -121,7 +121,7 @@ const char * INVALID_CONFIG = (  ); -UTEST(wg2sd, parses_config) { +UTEST(wg2nd, parses_config) {  	// CONFIG1  	std::istringstream ss { CONFIG1 }; | 
