ubus: add support for adding auth_connect hosts at runtime
[project/unetd.git] / utils.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
4 */
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/stat.h>
8 #include <arpa/inet.h>
9 #include <netdb.h>
10 #include <stdio.h>
11
12 #include <libubox/utils.h>
13
14 #include "unetd.h"
15
16 int network_get_endpoint(union network_endpoint *dest, const char *str,
17 int default_port, int idx)
18 {
19 struct addrinfo hints = {
20 .ai_flags = AI_ADDRCONFIG,
21 .ai_family = AF_UNSPEC,
22 };
23 char *buf = strdup(str);
24 char *host = buf, *port;
25 struct addrinfo *ai, *ai_cur;
26 int n_res;
27 int ret = -1;
28
29 memset(dest, 0, sizeof(*dest));
30
31 if (*host == '[') {
32 host++;
33 port = strchr(host, ']');
34 if (!port)
35 goto out;
36
37 *(port++) = 0;
38 if (!*port)
39 port = NULL;
40 else if (*port == ':')
41 port++;
42 else
43 goto out;
44 hints.ai_family = AF_INET6;
45 hints.ai_flags |= AI_NUMERICHOST;
46 } else {
47 host = buf;
48
49 port = strchr(host, ':');
50 if (port)
51 *(port++) = 0;
52 }
53
54 if (getaddrinfo(host, port, &hints, &ai) || !ai)
55 goto out;
56
57 while (1) {
58 ai_cur = ai;
59 for (n_res = 0; ai_cur; ai_cur = ai_cur->ai_next, n_res++)
60 if (!idx--)
61 goto found;
62
63 idx %= n_res;
64 }
65
66 found:
67 if (ai_cur->ai_addrlen > sizeof(*dest))
68 goto free_ai;
69
70 memcpy(dest, ai_cur->ai_addr, ai_cur->ai_addrlen);
71 if (!port)
72 dest->in.sin_port = htons(default_port);
73 ret = 0;
74
75 free_ai:
76 freeaddrinfo(ai);
77
78 out:
79 free(buf);
80 return ret;
81 }
82
83 int network_get_subnet(int af, union network_addr *addr, int *mask, const char *str)
84 {
85 char *buf = strdup(str);
86 char *sep, *end;
87 int ret = -1;
88
89 if (af == AF_INET6)
90 *mask = 128;
91 else
92 *mask = 32;
93
94 sep = strchr(buf, '/');
95 if (sep) {
96 unsigned long val;
97
98 *(sep++) = 0;
99
100 val = strtoul(sep, &end, 0);
101 if ((end && *end) || val > *mask)
102 goto out;
103
104 *mask = val;
105 }
106
107 if (inet_pton(af, buf, addr) == 1)
108 ret = 0;
109
110 out:
111 free(buf);
112 return ret;
113 }
114
115 int network_get_local_addr(void *local, const union network_endpoint *target)
116 {
117 union network_endpoint ep = {};
118 socklen_t len;
119 int ret = -1;
120 int fd;
121
122 memset(local, 0, sizeof(union network_addr));
123 if (target->sa.sa_family == AF_INET6)
124 len = sizeof(ep.in6);
125 else
126 len = sizeof(ep.in);
127
128 fd = socket(target->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
129 if (fd < 0)
130 return -1;
131
132 if (connect(fd, (const struct sockaddr *)target, len))
133 goto out;
134
135 len = sizeof(ep);
136 if (getsockname(fd, &ep.sa, &len))
137 goto out;
138
139 if (ep.sa.sa_family == AF_INET6)
140 memcpy(local, &ep.in6.sin6_addr, sizeof(ep.in6.sin6_addr));
141 else
142 memcpy(local, &ep.in.sin_addr, sizeof(ep.in.sin_addr));
143 ret = 0;
144
145 out:
146 close(fd);
147 return ret;
148 }
149
150 void *unet_read_file(const char *name, size_t *len)
151 {
152 struct stat st;
153 void *data;
154 FILE *f;
155
156 f = fopen(name, "r");
157 if (!f)
158 goto error;
159
160 if (fstat(fileno(f), &st) < 0)
161 goto close;
162
163 if (*len && st.st_size > *len)
164 goto close;
165
166 data = malloc(st.st_size);
167 if (!data)
168 goto close;
169
170 if (fread(data, 1, st.st_size, f) != st.st_size) {
171 free(data);
172 goto close;
173 }
174 fclose(f);
175
176 *len = st.st_size;
177 return data;
178
179 close:
180 fclose(f);
181 error:
182 *len = 0;
183 return NULL;
184 }
185
186 uint64_t unet_gettime(void)
187 {
188 struct timespec ts;
189
190 clock_gettime(CLOCK_MONOTONIC, &ts);
191
192 return ts.tv_sec;
193 }