// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2022 Felix Fietkau */ #define _GNU_SOURCE #include #include #include #include #include "unetd.h" struct cmdline_network { struct cmdline_network *next; char *data; }; static struct cmdline_network *cmd_nets; static const char *hosts_file; const char *mssfix_path = UNETD_MSS_BPF_PATH; const char *data_dir = UNETD_DATA_DIR; int global_pex_port = UNETD_GLOBAL_PEX_PORT; bool debug; static void network_write_hosts(struct network *net, FILE *f) { struct network_host *host; char ip[INET6_ADDRSTRLEN]; if (!net->net_config.local_host) return; avl_for_each_element(&net->hosts, host, node) { inet_ntop(AF_INET6, &host->peer.local_addr, ip, sizeof(ip)); fprintf(f, "%s\t%s%s%s\n", ip, network_host_name(host), net->config.domain ? "." : "", net->config.domain ? net->config.domain : ""); } } void unetd_write_hosts(void) { struct network *net; char *tmpfile = NULL; FILE *f; int fd; if (!hosts_file) return; if (asprintf(&tmpfile, "%s.XXXXXXXX", hosts_file) < 0) return; fd = mkstemp(tmpfile); if (fd < 0) { perror("mkstemp"); goto out; } chmod(tmpfile, 0644); f = fdopen(fd, "w"); if (!f) { close(fd); goto out; } avl_for_each_element(&networks, net, node) network_write_hosts(net, f); fclose(f); if (rename(tmpfile, hosts_file)) unlink(tmpfile); out: free(tmpfile); } static void add_networks(void) { struct cmdline_network *net; static struct blob_buf b; struct blob_attr *name; for (net = cmd_nets; net; net = net->next) { blob_buf_init(&b, 0); if (!blobmsg_add_json_from_string(&b, net->data)) continue; blobmsg_parse(&network_policy[NETWORK_ATTR_NAME], 1, &name, blobmsg_data(b.head), blobmsg_len(b.head)); if (!name) continue; unetd_network_add(blobmsg_get_string(name), b.head); } blob_buf_free(&b); } int main(int argc, char **argv) { struct cmdline_network *net; const char *unix_socket = NULL; int ch; while ((ch = getopt(argc, argv, "D:dh:u:M:N:P:")) != -1) { switch (ch) { case 'D': data_dir = optarg; break; case 'd': debug = true; break; case 'h': hosts_file = optarg; break; case 'N': net = calloc(1, sizeof(*net)); net->next = cmd_nets; net->data = optarg; cmd_nets = net; break; case 'M': mssfix_path = optarg; break; case 'P': global_pex_port = atoi(optarg); break; case 'u': unix_socket = optarg; break; } } uloop_init(); unetd_ubus_init(); unetd_write_hosts(); global_pex_open(unix_socket); add_networks(); uloop_run(); pex_close(); network_free_all(); uloop_done(); return 0; }