Don't require a configured network interface to start up, and add network interface monitoring support on Linux.
This commit is contained in:
258
getifaddr.c
258
getifaddr.c
@ -53,35 +53,18 @@
|
||||
#include <net/if_dl.h>
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_NETLINK
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/netlink.h>
|
||||
#endif
|
||||
#include "upnpglobalvars.h"
|
||||
#include "getifaddr.h"
|
||||
#include "minissdp.h"
|
||||
#include "log.h"
|
||||
|
||||
static uint32_t
|
||||
get_netmask(struct sockaddr_in *netmask)
|
||||
static int
|
||||
getifaddr(const char *ifname)
|
||||
{
|
||||
uint32_t mask;
|
||||
int i;
|
||||
|
||||
if (!netmask)
|
||||
return 0;
|
||||
mask = ntohl(netmask->sin_addr.s_addr);
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
if ((mask >> i) & 1)
|
||||
break;
|
||||
}
|
||||
mask = 32 - i;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
int
|
||||
getifaddr(const char * ifname, char * buf, int len)
|
||||
{
|
||||
/* SIOCGIFADDR struct ifreq * */
|
||||
uint32_t mask = 0;
|
||||
int i;
|
||||
#if HAVE_GETIFADDRS
|
||||
struct ifaddrs *ifap, *p;
|
||||
struct sockaddr_in *addr_in;
|
||||
@ -91,106 +74,40 @@ getifaddr(const char * ifname, char * buf, int len)
|
||||
DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (p = ifap; p != NULL; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET)
|
||||
if (!p->ifa_addr || p->ifa_addr->sa_family != AF_INET)
|
||||
continue;
|
||||
if (ifname && strcmp(p->ifa_name, ifname) != 0)
|
||||
continue;
|
||||
addr_in = (struct sockaddr_in *)p->ifa_addr;
|
||||
if (!ifname && (p->ifa_flags & (IFF_LOOPBACK | IFF_SLAVE)))
|
||||
continue;
|
||||
memcpy(&lan_addr[n_lan_addr].addr, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].addr));
|
||||
if (!inet_ntop(AF_INET, &addr_in->sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)) )
|
||||
{
|
||||
if (strcmp(p->ifa_name, ifname) != 0)
|
||||
continue;
|
||||
addr_in = (struct sockaddr_in *)p->ifa_addr;
|
||||
if (!inet_ntop(AF_INET, &addr_in->sin_addr, buf, len))
|
||||
{
|
||||
DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
addr_in = (struct sockaddr_in *)p->ifa_netmask;
|
||||
mask = get_netmask(addr_in);
|
||||
break;
|
||||
DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
addr_in = (struct sockaddr_in *)p->ifa_netmask;
|
||||
memcpy(&lan_addr[n_lan_addr].mask, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].mask));
|
||||
lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(lan_addr[n_lan_addr].addr.s_addr);
|
||||
if (lan_addr[n_lan_addr].snotify >= 0)
|
||||
{
|
||||
SendSSDPNotifies(lan_addr[n_lan_addr].snotify, lan_addr[n_lan_addr].str,
|
||||
runtime_vars.port, runtime_vars.notify_interval);
|
||||
n_lan_addr++;
|
||||
}
|
||||
if (ifname || n_lan_addr >= MAX_LAN_ADDR)
|
||||
break;
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
if (!p)
|
||||
if (ifname && !p)
|
||||
{
|
||||
DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
int s;
|
||||
struct ifreq ifr;
|
||||
int ifrlen;
|
||||
struct sockaddr_in * addr;
|
||||
|
||||
ifrlen = sizeof(ifr);
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s < 0)
|
||||
{
|
||||
DPRINTF(E_ERROR, L_GENERAL, "socket(PF_INET, SOCK_DGRAM): %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
|
||||
if (ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
|
||||
{
|
||||
DPRINTF(E_ERROR, L_GENERAL, "ioctl(s, SIOCGIFADDR, ...): %s\n", strerror(errno));
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
addr = (struct sockaddr_in *)&ifr.ifr_addr;
|
||||
if (!inet_ntop(AF_INET, &addr->sin_addr, buf, len))
|
||||
{
|
||||
DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(s, SIOCGIFNETMASK, &ifr, &ifrlen) == 0)
|
||||
{
|
||||
addr = (struct sockaddr_in *)&ifr.ifr_netmask;
|
||||
mask = get_netmask(addr);
|
||||
}
|
||||
else
|
||||
DPRINTF(E_ERROR, L_GENERAL, "ioctl(s, SIOCGIFNETMASK, ...): %s\n", strerror(errno));
|
||||
close(s);
|
||||
#endif
|
||||
if (mask)
|
||||
{
|
||||
i = strlen(buf);
|
||||
snprintf(buf+i, len-i, "/%u", mask);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
getsysaddrs(void)
|
||||
{
|
||||
#if HAVE_GETIFADDRS
|
||||
struct ifaddrs *ifap, *p;
|
||||
struct sockaddr_in *addr_in;
|
||||
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
{
|
||||
DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
for (p = ifap; p != NULL; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET)
|
||||
{
|
||||
addr_in = (struct sockaddr_in *)p->ifa_addr;
|
||||
if (p->ifa_flags & (IFF_LOOPBACK | IFF_SLAVE))
|
||||
continue;
|
||||
memcpy(&lan_addr[n_lan_addr].addr, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].addr));
|
||||
if (!inet_ntop(AF_INET, &addr_in->sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)) )
|
||||
{
|
||||
DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
addr_in = (struct sockaddr_in *)p->ifa_netmask;
|
||||
memcpy(&lan_addr[n_lan_addr].mask, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].mask));
|
||||
n_lan_addr++;
|
||||
if (n_lan_addr >= MAX_LAN_ADDR)
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
#else
|
||||
int s = socket(PF_INET, SOCK_STREAM, 0);
|
||||
struct sockaddr_in addr;
|
||||
@ -211,11 +128,13 @@ getsysaddrs(void)
|
||||
}
|
||||
|
||||
n = ifc.ifc_len / sizeof(struct ifreq);
|
||||
for (i=0; i < n; i++)
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
ifr = &ifc.ifc_req[i];
|
||||
if (ioctl(s, SIOCGIFFLAGS, ifr) < 0 ||
|
||||
ifr->ifr_ifru.ifru_flags & IFF_LOOPBACK)
|
||||
if (ifname && strcmp(ifr->ifr_name, ifname) != 0)
|
||||
continue;
|
||||
if (!ifname &&
|
||||
(ioctl(s, SIOCGIFFLAGS, ifr) < 0 || ifr->ifr_ifru.ifru_flags & IFF_LOOPBACK))
|
||||
continue;
|
||||
if (ioctl(s, SIOCGIFADDR, ifr) < 0)
|
||||
continue;
|
||||
@ -231,11 +150,22 @@ getsysaddrs(void)
|
||||
continue;
|
||||
memcpy(&addr, &(ifr->ifr_addr), sizeof(addr));
|
||||
memcpy(&lan_addr[n_lan_addr].mask, &addr.sin_addr, sizeof(addr));
|
||||
n_lan_addr++;
|
||||
if (n_lan_addr >= MAX_LAN_ADDR)
|
||||
lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(lan_addr[i].addr.s_addr);
|
||||
if (lan_addr[n_lan_addr].snotify >= 0)
|
||||
{
|
||||
SendSSDPNotifies(lan_addr[n_lan_addr].snotify, lan_addr[n_lan_addr].str,
|
||||
runtime_vars.port, runtime_vars.notify_interval);
|
||||
n_lan_addr++;
|
||||
}
|
||||
if (ifname || n_lan_addr >= MAX_LAN_ADDR)
|
||||
break;
|
||||
}
|
||||
close(s);
|
||||
if (ifname && i == n)
|
||||
{
|
||||
DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return n_lan_addr;
|
||||
}
|
||||
@ -245,7 +175,7 @@ getsyshwaddr(char *buf, int len)
|
||||
{
|
||||
unsigned char mac[6];
|
||||
int ret = -1;
|
||||
#if HAVE_GETIFADDRS
|
||||
#if defined(HAVE_GETIFADDRS) && !defined (__linux__)
|
||||
struct ifaddrs *ifap, *p;
|
||||
struct sockaddr_in *addr_in;
|
||||
uint8_t a;
|
||||
@ -367,3 +297,91 @@ get_remote_mac(struct in_addr ip_addr, unsigned char *mac)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
reload_ifaces(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_lan_addr; i++)
|
||||
{
|
||||
close(lan_addr[i].snotify);
|
||||
}
|
||||
n_lan_addr = 0;
|
||||
|
||||
if (runtime_vars.ifaces[0])
|
||||
{
|
||||
for (i = 0; runtime_vars.ifaces[i]; i++)
|
||||
{
|
||||
getifaddr(runtime_vars.ifaces[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
getifaddr(NULL);
|
||||
|
||||
for (i = 0; i < n_lan_addr; i++)
|
||||
{
|
||||
DPRINTF(E_INFO, L_GENERAL, "Enabled interface %s/%s\n",
|
||||
lan_addr[i].str, inet_ntoa(lan_addr[i].mask));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
OpenAndConfMonitorSocket(void)
|
||||
{
|
||||
#ifdef HAVE_NETLINK
|
||||
struct sockaddr_nl addr;
|
||||
int s;
|
||||
int ret;
|
||||
|
||||
s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (s < 0)
|
||||
{
|
||||
perror("couldn't open NETLINK_ROUTE socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.nl_family = AF_NETLINK;
|
||||
addr.nl_groups = RTMGRP_IPV4_IFADDR;
|
||||
|
||||
ret = bind(s, (struct sockaddr*)&addr, sizeof(addr));
|
||||
if (ret < 0)
|
||||
{
|
||||
perror("couldn't bind");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ProcessMonitorEvent(int s)
|
||||
{
|
||||
#ifdef HAVE_NETLINK
|
||||
int len;
|
||||
char buf[4096];
|
||||
struct nlmsghdr *nlh;
|
||||
int changed = 0;
|
||||
|
||||
nlh = (struct nlmsghdr*)buf;
|
||||
|
||||
len = recv(s, nlh, sizeof(buf), 0);
|
||||
if (len <= 0)
|
||||
return;
|
||||
while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE))
|
||||
{
|
||||
if (nlh->nlmsg_type == RTM_NEWADDR ||
|
||||
nlh->nlmsg_type == RTM_DELADDR)
|
||||
{
|
||||
changed = 1;
|
||||
}
|
||||
nlh = NLMSG_NEXT(nlh, len);
|
||||
}
|
||||
if (changed)
|
||||
reload_ifaces();
|
||||
#endif
|
||||
}
|
||||
|
Reference in New Issue
Block a user