summaryrefslogtreecommitdiff
path: root/src/tailnet.c
diff options
context:
space:
mode:
authorWayne Cole <waynecole339@gmail.com>2026-04-26 16:29:30 +0000
committerWayne Cole <waynecole339@gmail.com>2026-04-26 16:29:30 +0000
commitc45c35cf85f3f10dadff964165cff3e5dba5fffc (patch)
tree06005afbdd1d63691ace663e0aacedb152f50889 /src/tailnet.c
downloadhoodsgate-main.tar.xz
hoodsgate-main.zip
chore: actually vcs this proj, working on it for monthsmain
Diffstat (limited to 'src/tailnet.c')
-rw-r--r--src/tailnet.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/tailnet.c b/src/tailnet.c
new file mode 100644
index 0000000..21a90f6
--- /dev/null
+++ b/src/tailnet.c
@@ -0,0 +1,173 @@
+#include "tailnet.h"
+#include "hoodsgate/hoodsgate.h"
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+DEFINE_PROGRAM_LIST(PROG_TAILSCALE, PROG_SYSCTL, PROG_UFW, PROG_CURL, PROG_NFT)
+
+const char *tailnetMissingProgs[MAX_PROG_COUNT];
+static int _missingProgsCount = 0;
+static char *_kernelOpts[] = {"net.ipv4.ip_forward = 1\n",
+ "net.ipv6.conf.all.forwarding = 1\n"};
+// filename needs to be 99-tailscale.conf
+static char *_sysctlConf = "/etc/sysctl.d/100-tailscale.conf";
+static char *_sysctlConfFallback = "/etc/sysctl.conf";
+static char *_ufw_file = "/etc/default/ufw";
+
+bool tailnet_is_file_executable_boolean(const char *filepath) {
+ return access(filepath, X_OK) == 0;
+}
+
+bool tailnet_is_program_installed_boolean(const char *program_name) {
+ if (!program_name || strlen(program_name) == 0) {
+ return false;
+ }
+
+ char *path_env = getenv("PATH");
+ if (!path_env) {
+ return false;
+ }
+
+ char path_copy[4096];
+ strncpy(path_copy, path_env, sizeof(path_copy) - 1);
+ path_copy[sizeof(path_copy) - 1] = '\0';
+
+ char *dir = strtok(path_copy, ":");
+ while (dir != NULL) {
+ char fullpath[1024];
+ snprintf(fullpath, sizeof(fullpath), "%s/%s", dir, program_name);
+
+ if (tailnet_is_file_executable_boolean(fullpath)) {
+ return true;
+ }
+ dir = strtok(NULL, ":");
+ }
+ return false;
+}
+
+bool tailnet_check_required_programs_boolean(void) {
+ printf("Checking required programs...\n");
+ bool res = true;
+ for (int i = 0; i < REQUIRED_PROGS_COUNT; i++) {
+ if (!tailnet_is_program_installed_boolean(REQUIRED_PROGS[i])) {
+ int pos = _missingProgsCount;
+ if (pos < MAX_PROG_COUNT) {
+ tailnetMissingProgs[pos] = REQUIRED_PROGS[i];
+ _missingProgsCount++;
+ }
+ printf(" ✗ %s (MISSING)\n", REQUIRED_PROGS[i]);
+ res = false;
+ } else {
+ printf(" ✓ %s\n", REQUIRED_PROGS[i]);
+ }
+ }
+
+ if (res) {
+ printf("All required programs found!\n");
+ } else {
+ printf("\nPlease install missing programs. \n");
+ }
+
+ return res;
+}
+
+bool tailnet_advertise_exit_node_boolean() {
+ const char *conf_file =
+ (access("/etc/sysctl.d/", F_OK) == 0) ? _sysctlConf : _sysctlConfFallback;
+
+ FILE *file = fopen(conf_file, "a");
+ if (!file) {
+ perror("Failed to open file for appending kernel opts forwarding rules");
+ return false;
+ }
+
+ for (int i = 0; i < (int)(sizeof(_kernelOpts) / sizeof(_kernelOpts[0]));
+ i++) {
+ fputs(_kernelOpts[i], file);
+ }
+
+ fclose(file);
+ printf("Wrote kernel forwarding opts to %s\n", conf_file);
+
+ if (!(access(_ufw_file, F_OK) == 0)) {
+ perror("Failed to access ufw default file for file ops");
+ return false;
+ }
+ file = fopen(_ufw_file, "r");
+ if (!file) {
+ perror("Failed to open file to look for ufw foward policy");
+ return false;
+ }
+
+ /* Following is from a comment in /etc/default/ufw
+ * 'Set the default forward policy to ACCEPT, DROP or REJECT. Please note
+ * that if you change this you will most likely want to adjust your rules
+ * DEFAULT_FORWARD_POLICY="DROP"'
+ */
+ char line[512];
+ bool found = false;
+ while (fgets(line, sizeof(line), file)) {
+ if (strstr(line, "DEFAULT_FORWARD_POLICY") && strstr(line, "DROP")) {
+ printf("Found: %s\n", line);
+ found = true;
+ break;
+ } else if (strstr(line, "DEFAULT_FORWARD_POLICY") &&
+ strstr(line, "ACCEPT")) {
+ printf("Found: %s\nChange your policy rule in /etc/default/ufw to "
+ "DEFAULT_FORWARD_POLICY='DROP'\nand adjust your ufw rules "
+ "accordingly, then rerun",
+ line);
+ exit(1);
+ } else if (strstr(line, "DEFAULT_FORWARD_POLICY") &&
+ strstr(line, "REJECT")) {
+ printf("Found: %s\nChange your policy rule in /etc/default/ufw to "
+ "DEFAULT_FORWARD_POLICY='DROP'\nand adjust your ufw rules "
+ "accordingly, then rerun",
+ line);
+ exit(1);
+ }
+ }
+
+ fclose(file);
+
+ if (found != true) {
+ return false;
+ }
+
+ // tailscaled exit node ivp4 addr
+ char *const tsGetIpv4Addr[] = {PROG_TAILSCALE, "ip", "--4", NULL};
+ char *exitNodeIpv4 =
+ hg_run_command_w_execvp_pchar(PROG_TAILSCALE, tsGetIpv4Addr, NULL);
+
+ if (exitNodeIpv4 == NULL || hg_validate_ipv4_boolean(exitNodeIpv4) == false) {
+ return false;
+ }
+
+ char *flagExitNode = "--exit-node=";
+ strcat(flagExitNode, exitNodeIpv4);
+ char *const tsSetExitNode[] = {PROG_TAILSCALE, "set", flagExitNode,
+ "--exit-node-allow-lan-access=true", NULL};
+ char *setExitNode =
+ hg_run_command_w_execvp_pchar(PROG_TAILSCALE, tsSetExitNode, NULL);
+
+ // not sure if the setExitNode returns output; will have to test
+ if (setExitNode == NULL) {
+ return false;
+ }
+
+ char *const tsRunExitNode[] = {PROG_TAILSCALE, "up", NULL};
+ char *runExitNode =
+ hg_run_command_w_execvp_pchar(PROG_TAILSCALE, tsRunExitNode, NULL);
+
+ // not sure if the runExitNode returns output; will have to test
+ if (runExitNode == NULL) {
+ return false;
+ }
+
+ return true;
+}