unet-cli: strip initial newline in usage message
[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 if (asprintf(&tmpfile, "%s.XXXXXXXX", hosts_file) < 0)
52 return;
53
54 fd = mkstemp(tmpfile);
55 if (fd < 0) {
56 perror("mkstemp");
57 goto out;
58 }
59
60 chmod(tmpfile, 0644);
61 f = fdopen(fd, "w");
62 if (!f) {
63 close(fd);
64 goto out;
65 }
66
67 avl_for_each_element(&networks, net, node)
68 network_write_hosts(net, f);
69
70 fclose(f);
71
72 if (rename(tmpfile, hosts_file))
73 unlink(tmpfile);
74
75 out:
76 free(tmpfile);
77 }
78
79 static void add_networks(void)
80 {
81 struct cmdline_network *net;
82 static struct blob_buf b;
83 struct blob_attr *name;
84
85 for (net = cmd_nets; net; net = net->next) {
86 blob_buf_init(&b, 0);
87 if (!blobmsg_add_json_from_string(&b, net->data))
88 continue;
89
90 blobmsg_parse(&network_policy[NETWORK_ATTR_NAME], 1, &name,
91 blobmsg_data(b.head), blobmsg_len(b.head));
92 if (!name)
93 continue;
94
95 unetd_network_add(blobmsg_get_string(name), b.head);
96 }
97
98 blob_buf_free(&b);
99 }
100
101 int main(int argc, char **argv)
102 {
103 struct cmdline_network *net;
104 const char *unix_socket = NULL;
105 int ch;
106
107 while ((ch = getopt(argc, argv, "D:dh:u:M:N:P:")) != -1) {
108 switch (ch) {
109 case 'D':
110 data_dir = optarg;
111 break;
112 case 'd':
113 debug = true;
114 break;
115 case 'h':
116 hosts_file = optarg;
117 break;
118 case 'N':
119 net = calloc(1, sizeof(*net));
120 net->next = cmd_nets;
121 net->data = optarg;
122 cmd_nets = net;
123 break;
124 case 'M':
125 mssfix_path = optarg;
126 break;
127 case 'P':
128 global_pex_port = atoi(optarg);
129 break;
130 case 'u':
131 unix_socket = optarg;
132 break;
133 }
134 }
135
136 uloop_init();
137 unetd_ubus_init();
138 unetd_write_hosts();
139 global_pex_open(unix_socket);
140 add_networks();
141 uloop_run();
142 pex_close();
143 network_free_all();
144 uloop_done();
145
146 return 0;
147 }