9926ecdc3e47e821632dd00e49b93ddc69e1256d
[project/unetd.git] / main.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 */
5 #define _GNU_SOURCE
6 #include <unistd.h>
7 #include <arpa/inet.h>
8 #include <libubox/uloop.h>
9 #include <libubox/blobmsg_json.h>
10 #include "unetd.h"
11
12 struct cmdline_network {
13 struct cmdline_network *next;
14 char *data;
15 };
16
17 static struct cmdline_network *cmd_nets;
18 static const char *hosts_file;
19 const char *mssfix_path = UNETD_MSS_BPF_PATH;
20 const char *data_dir = UNETD_DATA_DIR;
21 int global_pex_port = UNETD_GLOBAL_PEX_PORT;
22 bool debug;
23
24 static void
25 network_write_hosts(struct network *net, FILE *f)
26 {
27 struct network_host *host;
28 char ip[INET6_ADDRSTRLEN];
29
30 if (!net->net_config.local_host)
31 return;
32
33 avl_for_each_element(&net->hosts, host, node) {
34 inet_ntop(AF_INET6, &host->peer.local_addr, ip, sizeof(ip));
35 fprintf(f, "%s\t%s%s%s\n", ip, network_host_name(host),
36 net->config.domain ? "." : "",
37 net->config.domain ? net->config.domain : "");
38 }
39 }
40
41 void unetd_write_hosts(void)
42 {
43 struct network *net;
44 char *tmpfile = NULL;
45 FILE *f;
46 int fd;
47
48 if (!hosts_file)
49 return;
50
51 asprintf(&tmpfile, "%s.XXXXXXXX", hosts_file);
52 fd = mkstemp(tmpfile);
53 if (fd < 0) {
54 perror("mkstemp");
55 goto out;
56 }
57
58 chmod(tmpfile, 0644);
59 f = fdopen(fd, "w");
60 if (!f) {
61 close(fd);
62 goto out;
63 }
64
65 avl_for_each_element(&networks, net, node)
66 network_write_hosts(net, f);
67
68 fclose(f);
69
70 if (rename(tmpfile, hosts_file))
71 unlink(tmpfile);
72
73 out:
74 free(tmpfile);
75 }
76
77 static void add_networks(void)
78 {
79 struct cmdline_network *net;
80 static struct blob_buf b;
81 struct blob_attr *name;
82
83 for (net = cmd_nets; net; net = net->next) {
84 blob_buf_init(&b, 0);
85 if (!blobmsg_add_json_from_string(&b, net->data))
86 continue;
87
88 blobmsg_parse(&network_policy[NETWORK_ATTR_NAME], 1, &name,
89 blobmsg_data(b.head), blobmsg_len(b.head));
90 if (!name)
91 continue;
92
93 unetd_network_add(blobmsg_get_string(name), b.head);
94 }
95
96 blob_buf_free(&b);
97 }
98
99 int main(int argc, char **argv)
100 {
101 struct cmdline_network *net;
102 int ch;
103
104 while ((ch = getopt(argc, argv, "D:dh:M:N:P:")) != -1) {
105 switch (ch) {
106 case 'D':
107 data_dir = optarg;
108 break;
109 case 'd':
110 debug = true;
111 break;
112 case 'h':
113 hosts_file = optarg;
114 break;
115 case 'N':
116 net = calloc(1, sizeof(*net));
117 net->next = cmd_nets;
118 net->data = optarg;
119 cmd_nets = net;
120 break;
121 case 'M':
122 mssfix_path = optarg;
123 break;
124 case 'P':
125 global_pex_port = atoi(optarg);
126 break;
127 }
128 }
129
130 uloop_init();
131 unetd_ubus_init();
132 unetd_write_hosts();
133 global_pex_open();
134 add_networks();
135 uloop_run();
136 pex_close();
137 network_free_all();
138 uloop_done();
139
140 return 0;
141 }