1 /**
2 * @file src/net.c Networking code
3 *
4 * Copyright (C) 2010 - 2016 Creytiv.com
5 */
6 #include <re.h>
7 #include <baresip.h>
8 #include "core.h"
9
10
11 struct network {
12 struct config_net cfg;
13 struct sa laddr;
14 char ifname[16];
15 #ifdef HAVE_INET6
16 struct sa laddr6;
17 char ifname6[16];
18 #endif
19 struct tmr tmr;
20 struct dnsc *dnsc;
21 struct sa nsv[NET_MAX_NS];/**< Configured name servers */
22 uint32_t nsn; /**< Number of configured name servers */
23 uint32_t interval;
24 int af; /**< Preferred address family */
25 char domain[64]; /**< DNS domain from network */
26 net_change_h *ch;
27 void *arg;
28 };
29
30
net_dnssrv_add(struct network * net,const struct sa * sa)31 static int net_dnssrv_add(struct network *net, const struct sa *sa)
32 {
33 if (!net)
34 return EINVAL;
35
36 if (net->nsn >= ARRAY_SIZE(net->nsv))
37 return E2BIG;
38
39 sa_cpy(&net->nsv[net->nsn++], sa);
40
41 return 0;
42 }
43
44
net_dns_srv_get(const struct network * net,struct sa * srvv,uint32_t * n,bool * from_sys)45 static int net_dns_srv_get(const struct network *net,
46 struct sa *srvv, uint32_t *n, bool *from_sys)
47 {
48 struct sa nsv[NET_MAX_NS];
49 uint32_t i, nsn = ARRAY_SIZE(nsv);
50 int err;
51
52 err = dns_srv_get(NULL, 0, nsv, &nsn);
53 if (err) {
54 nsn = 0;
55 }
56
57 if (net->nsn) {
58
59 if (net->nsn > *n)
60 return E2BIG;
61
62 /* Use any configured nameservers */
63 for (i=0; i<net->nsn; i++) {
64 srvv[i] = net->nsv[i];
65 }
66
67 *n = net->nsn;
68
69 if (from_sys)
70 *from_sys = false;
71 }
72 else {
73 if (nsn > *n)
74 return E2BIG;
75
76 for (i=0; i<nsn; i++)
77 srvv[i] = nsv[i];
78
79 *n = nsn;
80
81 if (from_sys)
82 *from_sys = true;
83 }
84
85 return 0;
86 }
87
88
89 /**
90 * Check for DNS Server updates
91 */
dns_refresh(struct network * net)92 static void dns_refresh(struct network *net)
93 {
94 struct sa nsv[NET_MAX_NS];
95 uint32_t nsn;
96 int err;
97
98 nsn = ARRAY_SIZE(nsv);
99
100 err = net_dns_srv_get(net, nsv, &nsn, NULL);
101 if (err)
102 return;
103
104 (void)dnsc_srv_set(net->dnsc, nsv, nsn);
105 }
106
107
108 /**
109 * Detect changes in IP address(es)
110 */
ipchange_handler(void * arg)111 static void ipchange_handler(void *arg)
112 {
113 struct network *net = arg;
114 bool change;
115
116 tmr_start(&net->tmr, net->interval * 1000, ipchange_handler, net);
117
118 dns_refresh(net);
119
120 change = net_check(net);
121 if (change && net->ch) {
122 net->ch(net->arg);
123 }
124 }
125
126
127 /**
128 * Check if local IP address(es) changed
129 *
130 * @param net Network instance
131 *
132 * @return True if changed, otherwise false
133 */
net_check(struct network * net)134 bool net_check(struct network *net)
135 {
136 struct sa laddr = net->laddr;
137 #ifdef HAVE_INET6
138 struct sa laddr6 = net->laddr6;
139 #endif
140 bool change = false;
141
142 if (!net)
143 return false;
144
145 if (str_isset(net->cfg.ifname)) {
146
147 (void)net_if_getaddr(net->cfg.ifname, AF_INET, &net->laddr);
148
149 #ifdef HAVE_INET6
150 (void)net_if_getaddr(net->cfg.ifname, AF_INET6, &net->laddr6);
151 #endif
152 }
153 else {
154 (void)net_default_source_addr_get(AF_INET, &net->laddr);
155 (void)net_rt_default_get(AF_INET, net->ifname,
156 sizeof(net->ifname));
157
158 #ifdef HAVE_INET6
159 (void)net_default_source_addr_get(AF_INET6, &net->laddr6);
160 (void)net_rt_default_get(AF_INET6, net->ifname6,
161 sizeof(net->ifname6));
162 #endif
163 }
164
165 if (sa_isset(&net->laddr, SA_ADDR) &&
166 !sa_cmp(&laddr, &net->laddr, SA_ADDR)) {
167 change = true;
168 info("net: local IPv4 address changed: %j -> %j\n",
169 &laddr, &net->laddr);
170 }
171
172 #ifdef HAVE_INET6
173 if (sa_isset(&net->laddr6, SA_ADDR) &&
174 !sa_cmp(&laddr6, &net->laddr6, SA_ADDR)) {
175 change = true;
176 info("net: local IPv6 address changed: %j -> %j\n",
177 &laddr6, &net->laddr6);
178 }
179 #endif
180
181 return change;
182 }
183
184
dns_init(struct network * net)185 static int dns_init(struct network *net)
186 {
187 struct sa nsv[NET_MAX_NS];
188 uint32_t nsn = ARRAY_SIZE(nsv);
189 int err;
190
191 err = net_dns_srv_get(net, nsv, &nsn, NULL);
192 if (err)
193 return err;
194
195 return dnsc_alloc(&net->dnsc, NULL, nsv, nsn);
196 }
197
198
199 /**
200 * Return TRUE if libre supports IPv6
201 */
check_ipv6(void)202 static bool check_ipv6(void)
203 {
204 struct sa sa;
205
206 return 0 == sa_set_str(&sa, "::1", 2000);
207 }
208
209
net_destructor(void * data)210 static void net_destructor(void *data)
211 {
212 struct network *net = data;
213
214 tmr_cancel(&net->tmr);
215 mem_deref(net->dnsc);
216 }
217
218
219 /**
220 * Initialise networking
221 *
222 * @param netp Pointer to allocated network instance
223 * @param cfg Network configuration
224 * @param af Preferred address family
225 *
226 * @return 0 if success, otherwise errorcode
227 */
net_alloc(struct network ** netp,const struct config_net * cfg,int af)228 int net_alloc(struct network **netp, const struct config_net *cfg, int af)
229 {
230 struct network *net;
231 struct sa nsv[NET_MAX_NS];
232 uint32_t nsn = ARRAY_SIZE(nsv);
233 char buf4[128] = "", buf6[128] = "";
234 int err;
235
236 if (!netp || !cfg)
237 return EINVAL;
238
239 /*
240 * baresip/libre must be built with matching HAVE_INET6 value.
241 * if different the size of `struct sa' will not match and the
242 * application is very likely to crash.
243 */
244 #ifdef HAVE_INET6
245 if (!check_ipv6()) {
246 error_msg("libre was compiled without IPv6-support"
247 ", but baresip was compiled with\n");
248 return EAFNOSUPPORT;
249 }
250 #else
251 if (check_ipv6()) {
252 error_msg("libre was compiled with IPv6-support"
253 ", but baresip was compiled without\n");
254 return EAFNOSUPPORT;
255 }
256 #endif
257
258 net = mem_zalloc(sizeof(*net), net_destructor);
259 if (!net)
260 return ENOMEM;
261
262 net->cfg = *cfg;
263 net->af = af;
264
265 tmr_init(&net->tmr);
266
267 if (cfg->nsc) {
268 size_t i;
269
270 for (i=0; i<cfg->nsc; i++) {
271
272 const char *ns = cfg->nsv[i].addr;
273 struct sa sa;
274
275 err = sa_decode(&sa, ns, str_len(ns));
276 if (err) {
277 warning("net: dns_server:"
278 " could not decode `%s' (%m)\n",
279 ns, err);
280 goto out;
281 }
282
283 err = net_dnssrv_add(net, &sa);
284 if (err) {
285 warning("net: failed to add nameserver: %m\n",
286 err);
287 goto out;
288 }
289 }
290 }
291
292 /* Initialise DNS resolver */
293 err = dns_init(net);
294 if (err) {
295 warning("net: dns_init: %m\n", err);
296 goto out;
297 }
298
299 sa_init(&net->laddr, AF_INET);
300 (void)sa_set_str(&net->laddr, "127.0.0.1", 0);
301
302 if (str_isset(cfg->ifname)) {
303
304 bool got_it = false;
305
306 info("Binding to interface '%s'\n", cfg->ifname);
307
308 str_ncpy(net->ifname, cfg->ifname, sizeof(net->ifname));
309
310 err = net_if_getaddr(cfg->ifname,
311 AF_INET, &net->laddr);
312 if (err) {
313 info("net: %s: could not get IPv4 address (%m)\n",
314 cfg->ifname, err);
315 }
316 else
317 got_it = true;
318
319 #ifdef HAVE_INET6
320 str_ncpy(net->ifname6, cfg->ifname,
321 sizeof(net->ifname6));
322
323 err = net_if_getaddr(cfg->ifname,
324 AF_INET6, &net->laddr6);
325 if (err) {
326 info("net: %s: could not get IPv6 address (%m)\n",
327 cfg->ifname, err);
328 }
329 else
330 got_it = true;
331 #endif
332 if (got_it)
333 err = 0;
334 else {
335 warning("net: %s: could not get network address\n",
336 cfg->ifname);
337 err = EADDRNOTAVAIL;
338 goto out;
339 }
340 }
341 else {
342 (void)net_default_source_addr_get(AF_INET, &net->laddr);
343 (void)net_rt_default_get(AF_INET, net->ifname,
344 sizeof(net->ifname));
345
346 #ifdef HAVE_INET6
347 sa_init(&net->laddr6, AF_INET6);
348
349 (void)net_default_source_addr_get(AF_INET6, &net->laddr6);
350 (void)net_rt_default_get(AF_INET6, net->ifname6,
351 sizeof(net->ifname6));
352 #endif
353 }
354
355 if (sa_isset(&net->laddr, SA_ADDR)) {
356 re_snprintf(buf4, sizeof(buf4), " IPv4=%s:%j",
357 net->ifname, &net->laddr);
358 }
359 #ifdef HAVE_INET6
360 if (sa_isset(&net->laddr6, SA_ADDR)) {
361 re_snprintf(buf6, sizeof(buf6), " IPv6=%s:%j",
362 net->ifname6, &net->laddr6);
363 }
364 #endif
365
366 (void)dns_srv_get(net->domain, sizeof(net->domain), nsv, &nsn);
367
368 info("Local network address: %s %s\n",
369 buf4, buf6);
370
371 out:
372 if (err)
373 mem_deref(net);
374 else
375 *netp = net;
376
377 return err;
378 }
379
380
381 /**
382 * Use a specific DNS server
383 *
384 * @param net Network instance
385 * @param ns DNS Server IP address and port
386 *
387 * @return 0 if success, otherwise errorcode
388 */
net_use_nameserver(struct network * net,const struct sa * ns)389 int net_use_nameserver(struct network *net, const struct sa *ns)
390 {
391 struct dnsc *dnsc;
392 int err;
393
394 if (!net || !ns)
395 return EINVAL;
396
397 err = dnsc_alloc(&dnsc, NULL, ns, 1);
398 if (err)
399 return err;
400
401 mem_deref(net->dnsc);
402 net->dnsc = dnsc;
403
404 return 0;
405 }
406
407
408 /**
409 * Check for networking changes with a regular interval
410 *
411 * @param net Network instance
412 * @param interval Interval in seconds
413 * @param ch Handler called when a change was detected
414 * @param arg Handler argument
415 */
net_change(struct network * net,uint32_t interval,net_change_h * ch,void * arg)416 void net_change(struct network *net, uint32_t interval,
417 net_change_h *ch, void *arg)
418 {
419 if (!net)
420 return;
421
422 net->interval = interval;
423 net->ch = ch;
424 net->arg = arg;
425
426 if (interval)
427 tmr_start(&net->tmr, interval * 1000, ipchange_handler, net);
428 else
429 tmr_cancel(&net->tmr);
430 }
431
432
net_force_change(struct network * net)433 void net_force_change(struct network *net)
434 {
435 if (net && net->ch) {
436 net->ch(net->arg);
437 }
438 }
439
440
dns_debug(struct re_printf * pf,const struct network * net)441 static int dns_debug(struct re_printf *pf, const struct network *net)
442 {
443 struct sa nsv[NET_MAX_NS];
444 uint32_t i, nsn = ARRAY_SIZE(nsv);
445 bool from_sys = false;
446 int err;
447
448 if (!net)
449 return 0;
450
451 err = net_dns_srv_get(net, nsv, &nsn, &from_sys);
452 if (err)
453 nsn = 0;
454
455 err = re_hprintf(pf, " DNS Servers from %s: (%u)\n",
456 from_sys ? "System" : "Config", nsn);
457 for (i=0; i<nsn; i++)
458 err |= re_hprintf(pf, " %u: %J\n", i, &nsv[i]);
459
460 return err;
461 }
462
463
net_af(const struct network * net)464 int net_af(const struct network *net)
465 {
466 if (!net)
467 return AF_UNSPEC;
468
469 return net->af;
470 }
471
472
473 /**
474 * Print networking debug information
475 *
476 * @param pf Print handler for debug output
477 * @param net Network instance
478 *
479 * @return 0 if success, otherwise errorcode
480 */
net_debug(struct re_printf * pf,const struct network * net)481 int net_debug(struct re_printf *pf, const struct network *net)
482 {
483 int err;
484
485 if (!net)
486 return 0;
487
488 err = re_hprintf(pf, "--- Network debug ---\n");
489 err |= re_hprintf(pf, " Preferred AF: %s\n", net_af2name(net->af));
490 err |= re_hprintf(pf, " Local IPv4: %9s - %j\n",
491 net->ifname, &net->laddr);
492 #ifdef HAVE_INET6
493 err |= re_hprintf(pf, " Local IPv6: %9s - %j\n",
494 net->ifname6, &net->laddr6);
495 #endif
496 err |= re_hprintf(pf, " Domain: %s\n", net->domain);
497
498 err |= net_if_debug(pf, NULL);
499
500 err |= net_rt_debug(pf, NULL);
501
502 err |= dns_debug(pf, net);
503
504 return err;
505 }
506
507
508 /**
509 * Get the local IP Address for a specific Address Family (AF)
510 *
511 * @param net Network instance
512 * @param af Address Family
513 *
514 * @return Local IP Address
515 */
net_laddr_af(const struct network * net,int af)516 const struct sa *net_laddr_af(const struct network *net, int af)
517 {
518 if (!net)
519 return NULL;
520
521 switch (af) {
522
523 case AF_INET: return &net->laddr;
524 #ifdef HAVE_INET6
525 case AF_INET6: return &net->laddr6;
526 #endif
527 default: return NULL;
528 }
529 }
530
531
532 /**
533 * Get the DNS Client
534 *
535 * @param net Network instance
536 *
537 * @return DNS Client
538 */
net_dnsc(const struct network * net)539 struct dnsc *net_dnsc(const struct network *net)
540 {
541 if (!net)
542 return NULL;
543
544 return net->dnsc;
545 }
546
547
548 /**
549 * Get the network domain name
550 *
551 * @param net Network instance
552 *
553 * @return Network domain
554 */
net_domain(const struct network * net)555 const char *net_domain(const struct network *net)
556 {
557 if (!net)
558 return NULL;
559
560 return net->domain[0] ? net->domain : NULL;
561 }
562