/** * @file net.c Networking code * * Copyright (C) 2010 Creytiv.com */ #include #include #include "core.h" static struct { struct config_net cfg; struct sa laddr; char ifname[16]; #ifdef HAVE_INET6 struct sa laddr6; char ifname6[16]; #endif struct tmr tmr; struct dnsc *dnsc; struct sa nsv[4]; /**< Configured name servers */ uint32_t nsn; /**< Number of configured name servers */ uint32_t interval; int af; /**< Preferred address family */ char domain[64]; /**< DNS domain from network */ net_change_h *ch; void *arg; } net; /** * Check for DNS Server updates */ static void dns_refresh(void) { struct sa nsv[8]; uint32_t i, nsn; int err; nsn = ARRAY_SIZE(nsv); err = dns_srv_get(NULL, 0, nsv, &nsn); if (err) return; for (i=0; i %j\n", &laddr, &net.laddr); } #ifdef HAVE_INET6 if (sa_isset(&net.laddr6, SA_ADDR) && !sa_cmp(&laddr6, &net.laddr6, SA_ADDR)) { change = true; info("net: local IPv6 address changed: %j -> %j\n", &laddr6, &net.laddr6); } #endif return change; } static int dns_init(void) { struct sa nsv[8]; uint32_t i, nsn; int err; nsn = ARRAY_SIZE(nsv); err = dns_srv_get(net.domain, sizeof(net.domain), nsv, &nsn); if (err) { nsn = 0; } /* Add any configured nameservers */ for (i=0; iifname)) { bool got_it = false; info("Binding to interface '%s'\n", cfg->ifname); str_ncpy(net.ifname, cfg->ifname, sizeof(net.ifname)); err = net_if_getaddr(cfg->ifname, AF_INET, &net.laddr); if (err) { info("net: %s: could not get IPv4 address (%m)\n", cfg->ifname, err); } else got_it = true; #ifdef HAVE_INET6 str_ncpy(net.ifname6, cfg->ifname, sizeof(net.ifname6)); err = net_if_getaddr(cfg->ifname, AF_INET6, &net.laddr6); if (err) { info("net: %s: could not get IPv6 address (%m)\n", cfg->ifname, err); } else got_it = true; #endif if (got_it) err = 0; else { warning("net: %s: could not get network address\n", cfg->ifname); return EADDRNOTAVAIL; } } else { (void)net_default_source_addr_get(AF_INET, &net.laddr); (void)net_rt_default_get(AF_INET, net.ifname, sizeof(net.ifname)); #ifdef HAVE_INET6 sa_init(&net.laddr6, AF_INET6); (void)net_default_source_addr_get(AF_INET6, &net.laddr6); (void)net_rt_default_get(AF_INET6, net.ifname6, sizeof(net.ifname6)); #endif } (void)re_fprintf(stderr, "Local network address:"); if (sa_isset(&net.laddr, SA_ADDR)) { (void)re_fprintf(stderr, " IPv4=%s:%j", net.ifname, &net.laddr); } #ifdef HAVE_INET6 if (sa_isset(&net.laddr6, SA_ADDR)) { (void)re_fprintf(stderr, " IPv6=%s:%j", net.ifname6, &net.laddr6); } #endif (void)re_fprintf(stderr, "\n"); return err; } /** * Reset the DNS resolver * * @return 0 if success, otherwise errorcode */ int net_reset(void) { net.dnsc = mem_deref(net.dnsc); return dns_init(); } /** * Close networking */ void net_close(void) { net.dnsc = mem_deref(net.dnsc); tmr_cancel(&net.tmr); } /** * Add a DNS server * * @param sa DNS Server IP address and port * * @return 0 if success, otherwise errorcode */ int net_dnssrv_add(const struct sa *sa) { if (net.nsn >= ARRAY_SIZE(net.nsv)) return E2BIG; sa_cpy(&net.nsv[net.nsn++], sa); return 0; } /** * Check for networking changes with a regular interval * * @param interval Interval in seconds * @param ch Handler called when a change was detected * @param arg Handler argument */ void net_change(uint32_t interval, net_change_h *ch, void *arg) { net.interval = interval; net.ch = ch; net.arg = arg; if (interval) tmr_start(&net.tmr, interval * 1000, ipchange_handler, NULL); else tmr_cancel(&net.tmr); } static int dns_debug(struct re_printf *pf, void *unused) { struct sa nsv[4]; uint32_t i, nsn; int err; (void)unused; nsn = ARRAY_SIZE(nsv); err = dns_srv_get(NULL, 0, nsv, &nsn); if (err) nsn = 0; err = re_hprintf(pf, " DNS Servers: (%u)\n", nsn); for (i=0; i