1/* MiniUPnP project
2 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
3 *
4 * Copyright (c) 2006, Thomas Bernard
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *     * Redistributions of source code must retain the above copyright
10 *       notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above copyright
12 *       notice, this list of conditions and the following disclaimer in the
13 *       documentation and/or other materials provided with the distribution.
14 *     * The name of the author may not be used to endorse or promote products
15 *       derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <unistd.h>
33#include <sys/ioctl.h>
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <net/if.h>
37#include <arpa/inet.h>
38#include <netinet/in.h>
39#include <netdb.h>
40#include <errno.h>
41#if defined(sun)
42#include <sys/sockio.h>
43#endif
44
45#include "config.h"
46#if HAVE_GETIFADDRS
47# include <ifaddrs.h>
48# ifdef __linux__
49#  ifndef AF_LINK
50#   define AF_LINK AF_INET
51#  endif
52# else
53#  include <net/if_dl.h>
54# endif
55# ifndef IFF_SLAVE
56#  define IFF_SLAVE 0
57# endif
58#endif
59#ifdef HAVE_NETLINK
60# include <linux/rtnetlink.h>
61# include <linux/netlink.h>
62#endif
63#include "upnpglobalvars.h"
64#include "getifaddr.h"
65#include "minissdp.h"
66#include "utils.h"
67#include "log.h"
68
69static int
70getifaddr(const char *ifname)
71{
72#if HAVE_GETIFADDRS
73	struct ifaddrs *ifap, *p;
74	struct sockaddr_in *addr_in;
75
76	if (getifaddrs(&ifap) != 0)
77	{
78		DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
79		return -1;
80	}
81
82	for (p = ifap; p != NULL; p = p->ifa_next)
83	{
84		if (!p->ifa_addr || p->ifa_addr->sa_family != AF_INET)
85			continue;
86		if (ifname && strcmp(p->ifa_name, ifname) != 0)
87			continue;
88		addr_in = (struct sockaddr_in *)p->ifa_addr;
89		if (!ifname && (p->ifa_flags & (IFF_LOOPBACK | IFF_SLAVE)))
90			continue;
91			/* Foxconn added start Bernie 06/01/2016 */
92			if (strcmp(p->ifa_name, "br0") != 0)
93				continue;
94			/* Foxconn added end Bernie 06/01/2016 */
95		memcpy(&lan_addr[n_lan_addr].addr, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].addr));
96		if (!inet_ntop(AF_INET, &addr_in->sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)) )
97		{
98			DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
99			continue;
100		}
101		addr_in = (struct sockaddr_in *)p->ifa_netmask;
102		memcpy(&lan_addr[n_lan_addr].mask, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].mask));
103		lan_addr[n_lan_addr].ifindex = if_nametoindex(p->ifa_name);
104		lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(&lan_addr[n_lan_addr]);
105		if (lan_addr[n_lan_addr].snotify >= 0)
106			n_lan_addr++;
107		if (ifname || n_lan_addr >= MAX_LAN_ADDR)
108			break;
109	}
110	freeifaddrs(ifap);
111	if (ifname && !p)
112	{
113		DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
114		return -1;
115	}
116#else
117	int s = socket(PF_INET, SOCK_STREAM, 0);
118	struct sockaddr_in addr;
119	struct ifconf ifc;
120	struct ifreq *ifr;
121	char buf[8192];
122	int i, n;
123
124	memset(&ifc, '\0', sizeof(ifc));
125	ifc.ifc_buf = buf;
126	ifc.ifc_len = sizeof(buf);
127
128	if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
129	{
130		DPRINTF(E_ERROR, L_GENERAL, "SIOCGIFCONF: %s\n", strerror(errno));
131		close(s);
132		return -1;
133	}
134
135	n = ifc.ifc_len / sizeof(struct ifreq);
136	for (i = 0; i < n; i++)
137	{
138		ifr = &ifc.ifc_req[i];
139		if (ifname && strcmp(ifr->ifr_name, ifname) != 0)
140			continue;
141		if(strcmp(ifr->ifr_name,"br0")!=0)
142			continue;
143		if (!ifname &&
144		    (ioctl(s, SIOCGIFFLAGS, ifr) < 0 || ifr->ifr_ifru.ifru_flags & IFF_LOOPBACK))
145			continue;
146		if (ioctl(s, SIOCGIFADDR, ifr) < 0)
147			continue;
148		memcpy(&addr, &(ifr->ifr_addr), sizeof(addr));
149		memcpy(&lan_addr[n_lan_addr].addr, &addr.sin_addr, sizeof(lan_addr[n_lan_addr].addr));
150		if (!inet_ntop(AF_INET, &addr.sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)))
151		{
152			DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
153			close(s);
154			continue;
155		}
156		if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
157			continue;
158		memcpy(&addr, &(ifr->ifr_addr), sizeof(addr));
159		memcpy(&lan_addr[n_lan_addr].mask, &addr.sin_addr, sizeof(addr));
160		lan_addr[n_lan_addr].ifindex = if_nametoindex(ifr->ifr_name);
161		lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(&lan_addr[n_lan_addr]);
162		if (lan_addr[n_lan_addr].snotify >= 0)
163			n_lan_addr++;
164		if (ifname || n_lan_addr >= MAX_LAN_ADDR)
165			break;
166	}
167	close(s);
168	if (ifname && i == n)
169	{
170		DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
171		return -1;
172	}
173#endif
174	return n_lan_addr;
175}
176
177int
178getsyshwaddr(char *buf, int len)
179{
180	unsigned char mac[6];
181	int ret = -1;
182#if defined(HAVE_GETIFADDRS) && !defined (__linux__) && !defined (__sun__)
183	struct ifaddrs *ifap, *p;
184	struct sockaddr_in *addr_in;
185	uint8_t a;
186
187	if (getifaddrs(&ifap) != 0)
188	{
189		DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
190		return -1;
191	}
192	for (p = ifap; p != NULL; p = p->ifa_next)
193	{
194		if (p->ifa_addr && p->ifa_addr->sa_family == AF_LINK)
195		{
196			addr_in = (struct sockaddr_in *)p->ifa_addr;
197			a = (htonl(addr_in->sin_addr.s_addr) >> 0x18) & 0xFF;
198			if (a == 127)
199				continue;
200#if defined(__linux__)
201			struct ifreq ifr;
202			int fd;
203			fd = socket(AF_INET, SOCK_DGRAM, 0);
204			if (fd < 0)
205				continue;
206			/* Foxconn added start Bernie 06/01/2016 */
207			/* DLNA should only work on br0 interface...*/
208			if (strcmp(p->ifa_name, "br0") != 0)
209				continue;
210			/* Foxconn added end Bernie 06/01/2016 */
211
212			strncpy(ifr.ifr_name, p->ifa_name, IFNAMSIZ);
213			ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
214			close(fd);
215			if (ret < 0)
216				continue;
217			memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
218#else
219			struct sockaddr_dl *sdl;
220			sdl = (struct sockaddr_dl*)p->ifa_addr;
221			memcpy(mac, LLADDR(sdl), sdl->sdl_alen);
222#endif
223			if (MACADDR_IS_ZERO(mac))
224				continue;
225			ret = 0;
226			break;
227		}
228	}
229	freeifaddrs(ifap);
230#else
231	struct if_nameindex *ifaces, *if_idx;
232	struct ifreq ifr;
233	int fd;
234
235	memset(&mac, '\0', sizeof(mac));
236	/* Get the spatially unique node identifier */
237	fd = socket(AF_INET, SOCK_DGRAM, 0);
238	if (fd < 0)
239		return ret;
240
241	ifaces = if_nameindex();
242	if (!ifaces)
243	{
244		close(fd);
245		return ret;
246	}
247
248	for (if_idx = ifaces; if_idx->if_index; if_idx++)
249	{
250		/* Foxconn added start pling 09/30/2013 */
251		/* DLNA should only work on br0 interface...*/
252		if (strcmp(if_idx->if_name, "br0") != 0)
253			continue;
254		/* Foxconn added end pling 09/30/2013 */
255
256		strncpyt(ifr.ifr_name, if_idx->if_name, IFNAMSIZ);
257		if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
258			continue;
259		if (ifr.ifr_ifru.ifru_flags & IFF_LOOPBACK)
260			continue;
261		if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
262			continue;
263#ifdef __sun__
264		if (MACADDR_IS_ZERO(ifr.ifr_addr.sa_data))
265			continue;
266		memcpy(mac, ifr.ifr_addr.sa_data, 6);
267#else
268		if (MACADDR_IS_ZERO(ifr.ifr_hwaddr.sa_data))
269			continue;
270		memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
271#endif
272		ret = 0;
273		break;
274	}
275	if_freenameindex(ifaces);
276	close(fd);
277#endif
278	if (ret == 0)
279	{
280		if (len > 12)
281			sprintf(buf, "%02x%02x%02x%02x%02x%02x",
282			        mac[0]&0xFF, mac[1]&0xFF, mac[2]&0xFF,
283			        mac[3]&0xFF, mac[4]&0xFF, mac[5]&0xFF);
284		else if (len == 6)
285			memmove(buf, mac, 6);
286	}
287	return ret;
288}
289
290int
291get_remote_mac(struct in_addr ip_addr, unsigned char *mac)
292{
293	struct in_addr arp_ent;
294	FILE * arp;
295	char remote_ip[16];
296	int matches, hwtype, flags;
297	memset(mac, 0xFF, 6);
298
299	arp = fopen("/proc/net/arp", "r");
300	if (!arp)
301		return 1;
302	while (!feof(arp))
303	{
304		matches = fscanf(arp, "%15s 0x%8X 0x%8X %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
305		                      remote_ip, &hwtype, &flags,
306		                      &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
307		if (matches != 9)
308			continue;
309		inet_pton(AF_INET, remote_ip, &arp_ent);
310		if (ip_addr.s_addr == arp_ent.s_addr)
311			break;
312		mac[0] = 0xFF;
313	}
314	fclose(arp);
315
316	if (mac[0] == 0xFF)
317	{
318		memset(mac, 0xFF, 6);
319		return 1;
320	}
321
322	return 0;
323}
324
325void
326reload_ifaces(int force_notify)
327{
328	struct in_addr old_addr[MAX_LAN_ADDR];
329	int i, j;
330
331	memset(&old_addr, 0xFF, sizeof(old_addr));
332	for (i = 0; i < n_lan_addr; i++)
333	{
334		memcpy(&old_addr[i], &lan_addr[i].addr, sizeof(struct in_addr));
335		close(lan_addr[i].snotify);
336	}
337	n_lan_addr = 0;
338
339	i = 0;
340	do {
341		getifaddr(runtime_vars.ifaces[i]);
342		i++;
343	} while (i < MAX_LAN_ADDR && runtime_vars.ifaces[i]);
344
345	for (i = 0; i < n_lan_addr; i++)
346	{
347		for (j = 0; j < MAX_LAN_ADDR; j++)
348		{
349			if (memcmp(&lan_addr[i].addr, &old_addr[j], sizeof(struct in_addr)) == 0)
350				break;
351		}
352		/* Send out startup notifies if it's a new interface, or on SIGHUP */
353		if (force_notify || j == MAX_LAN_ADDR)
354		{
355			DPRINTF(E_INFO, L_GENERAL, "Enabling interface %s/%s\n",
356				lan_addr[i].str, inet_ntoa(lan_addr[i].mask));
357			SendSSDPGoodbyes(lan_addr[i].snotify);
358			SendSSDPNotifies(lan_addr[i].snotify, lan_addr[i].str,
359					runtime_vars.port, runtime_vars.notify_interval);
360		}
361	}
362}
363
364int
365OpenAndConfMonitorSocket(void)
366{
367#ifdef HAVE_NETLINK
368	struct sockaddr_nl addr;
369	int s;
370	int ret;
371
372	s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
373	if (s < 0)
374	{
375		perror("couldn't open NETLINK_ROUTE socket");
376		return -1;
377	}
378
379	memset(&addr, 0, sizeof(addr));
380	addr.nl_family = AF_NETLINK;
381	addr.nl_groups = RTMGRP_IPV4_IFADDR;
382
383	ret = bind(s, (struct sockaddr*)&addr, sizeof(addr));
384	if (ret < 0)
385	{
386		perror("couldn't bind");
387		close(s);
388		return -1;
389	}
390
391	return s;
392#else
393	return -1;
394#endif
395}
396
397void
398ProcessMonitorEvent(int s)
399{
400#ifdef HAVE_NETLINK
401	int len;
402	char buf[4096];
403	struct nlmsghdr *nlh;
404	int changed = 0;
405
406	nlh = (struct nlmsghdr*)buf;
407
408	len = recv(s, nlh, sizeof(buf), 0);
409	if (len <= 0)
410		return;
411	while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE))
412	{
413		if (nlh->nlmsg_type == RTM_NEWADDR ||
414		    nlh->nlmsg_type == RTM_DELADDR)
415		{
416			changed = 1;
417		}
418		nlh = NLMSG_NEXT(nlh, len);
419	}
420	if (changed)
421		reload_ifaces(0);
422#endif
423}
424