1 /* $Id: ifacewatcher.c,v 1.10 2019/10/02 22:02:02 nanard Exp $ */
2 /* MiniUPnP project
3  * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
4  * (c) 2006-2020 Thomas Bernard
5  *
6  * ifacewatcher.c
7  *
8  * This file implements dynamic serving of new network interfaces
9  * which weren't available during daemon start. It also takes care
10  * of interfaces which become unavailable.
11  *
12  * Copyright (c) 2011, Alexey Osipov <simba@lerlan.ru>
13  * All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions are met:
17  *
18  *    * Redistributions of source code must retain the above copyright notice,
19  *      this list of conditions and the following disclaimer.
20  *    * Redistributions in binary form must reproduce the above copyright notice,
21  *      this list of conditions and the following disclaimer in the documentation
22  *      and/or other materials provided with the distribution.
23  *    * The name of the author may not be used to endorse or promote products
24  *      derived from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE. */
37 
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <linux/netlink.h>
42 #include <linux/rtnetlink.h>
43 #include <arpa/inet.h>
44 #include <net/if.h>
45 #include <syslog.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <signal.h>
50 
51 #include "config.h"
52 #include "../macros.h"
53 
54 #ifdef USE_IFACEWATCHER
55 
56 #include "../ifacewatcher.h"
57 #include "../minissdp.h"
58 #include "../getifaddr.h"
59 #include "../upnpglobalvars.h"
60 #include "../natpmp.h"
61 
62 extern volatile sig_atomic_t should_send_public_address_change_notif;
63 
64 
65 int
OpenAndConfInterfaceWatchSocket(void)66 OpenAndConfInterfaceWatchSocket(void)
67 {
68 	int s;
69 	struct sockaddr_nl addr;
70 
71 	s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
72 	if (s == -1)
73 	{
74 		syslog(LOG_ERR, "socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE): %m");
75 		return -1;
76 	}
77 
78 	memset(&addr, 0, sizeof(addr));
79 	addr.nl_family = AF_NETLINK;
80 	addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
81 	/*addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;*/
82 
83 	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
84 	{
85 		syslog(LOG_ERR, "bind(netlink): %m");
86 		close(s);
87 		return -1;
88 	}
89 
90 	return s;
91 }
92 
93 #if 0
94 /* disabled at the moment */
95 int
96 ProcessInterfaceUp(struct ifinfomsg *ifi)
97 {
98 	struct lan_iface_s * lan_iface;
99 	struct lan_iface_s * lan_iface2;
100 	struct lan_addr_s * lan_addr;
101 	char ifname[IFNAMSIZ];
102 	char ifstraddr[16];
103 	struct in_addr ifaddr;
104 
105 	/* check if we already have this iface */
106 	for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
107 		if (lan_iface->iface.index == ifi->ifi_index)
108 			break;
109 
110 	if (lan_iface != NULL)
111 		return 0;
112 
113 	if (if_indextoname(ifi->ifi_index, ifname) == NULL)
114 	{
115 		syslog(LOG_ERR, "if_indextoname(%d, ifname) failed", ifi->ifi_index);
116 		return -1;
117 	}
118 
119 	if (getifaddr(ifname, ifstraddr, 16) < 0)
120 	{
121 		syslog(LOG_DEBUG, "getifaddr(%s, ifaddr, 16) failed", ifname);
122 		return 1;
123 	}
124 
125 	if (inet_pton(AF_INET, ifstraddr, &ifaddr) != 1)
126 	{
127 		syslog(LOG_ERR, "inet_pton(AF_INET, \"%s\", &ifaddr) failed", ifstraddr);
128 		return -1;
129 	}
130 
131 	/* check if this new interface has address which we need to listen to */
132 	for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
133 	{
134 		if (lan_addr->addr.s_addr != ifaddr.s_addr)
135 			continue;
136 
137 		syslog(LOG_INFO, "Interface up: %s (%s)", ifname, ifstraddr);
138 
139 		/* adding new lan_iface entry */
140 		lan_iface = (struct lan_iface_s *) malloc(sizeof(struct lan_iface_s));
141 		if (lan_iface == NULL)
142 		{
143 			syslog(LOG_ERR, "malloc(sizeof(struct lan_iface_s): %m");
144 			continue;
145 		}
146 
147 		lan_iface->lan_addr = lan_addr;
148 		strncpy(lan_iface->iface.name, ifname, IFNAMSIZ);
149 		lan_iface->iface.index = ifi->ifi_index;
150 		lan_iface->iface.addr = ifaddr;
151 		lan_iface->snotify = -1;
152 #ifdef ENABLE_NATPMP
153 		lan_iface->snatpmp = -1;
154 #endif
155 
156 		LIST_INSERT_HEAD(&lan_ifaces, lan_iface, list);
157 
158 		/* adding multicast membership for SSDP */
159 		if(AddMulticastMembership(sudp, ifaddr.s_addr, ifi->ifi_index) < 0)
160 			syslog(LOG_WARNING, "Failed to add multicast membership for interface %s (%s)", ifname, ifstraddr);
161 		else
162 			syslog(LOG_INFO, "Multicast membership added for %s (%s)", ifname, ifstraddr);
163 
164 		/* create SSDP notify socket */
165 		if (OpenAndConfSSDPNotifySocket(lan_iface) < 0)
166 			syslog(LOG_WARNING, "Failed to open SSDP notify socket for interface %s (%s)", ifname, ifstraddr);
167 
168 #ifdef ENABLE_NATPMP
169 		/* create NAT-PMP socket */
170 		for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
171 			if (lan_iface2->lan_addr->addr.s_addr == lan_iface->lan_addr->addr.s_addr &&
172 			    lan_iface2->snatpmp >= 0)
173 				lan_iface->snatpmp = lan_iface2->snatpmp;
174 
175 		if (lan_iface->snatpmp < 0)
176 		{
177 			lan_iface->snatpmp = OpenAndConfNATPMPSocket(ifaddr.s_addr);
178 			if (lan_iface->snatpmp < 0)
179 				syslog(LOG_ERR, "OpenAndConfNATPMPSocket(ifaddr.s_addr) failed for %s (%s)", ifname, ifstraddr);
180 			else
181 				syslog(LOG_INFO, "Listening for NAT-PMP connection on %s:%d", ifstraddr, NATPMP_PORT);
182 		}
183 #endif
184 	}
185 
186 	return 0;
187 }
188 
189 int
190 ProcessInterfaceDown(struct ifinfomsg *ifi)
191 {
192 	struct lan_iface_s * lan_iface;
193 	struct lan_iface_s * lan_iface2;
194 
195 	/* check if we have this iface */
196 	for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
197 		if (lan_iface->iface.index == ifi->ifi_index)
198 			break;
199 
200 	if (lan_iface == NULL)
201 		return 0;
202 
203 	/* one of our interfaces is going down, clean up */
204 	syslog(LOG_INFO, "Interface down: %s", lan_iface->iface.name);
205 
206 	/* remove multicast membership for SSDP */
207 	if(DropMulticastMembership(sudp, lan_iface->lan_addr->addr.s_addr, lan_iface->iface.index) < 0)
208 		syslog(LOG_WARNING, "Failed to drop multicast membership for interface %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
209 	else
210 		syslog(LOG_INFO, "Multicast membership dropped for %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
211 
212 	/* closing SSDP notify socket */
213 	close(lan_iface->snotify);
214 
215 #ifdef ENABLE_NATPMP
216 	/* closing NAT-PMP socket if it's not used anymore */
217 	for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
218 		if (lan_iface2 != lan_iface && lan_iface2->snatpmp == lan_iface->snatpmp)
219 			break;
220 
221 	if (lan_iface2 == NULL)
222 		close(lan_iface->snatpmp);
223 #endif
224 
225 	/* del corresponding lan_iface entry */
226 	LIST_REMOVE(lan_iface, list);
227 	free(lan_iface);
228 
229 	return 0;
230 }
231 #endif
232 
233 void
ProcessInterfaceWatchNotify(int s)234 ProcessInterfaceWatchNotify(int s)
235 {
236 	char buffer[4096];
237 	struct iovec iov;
238 	struct msghdr hdr;
239 	struct nlmsghdr *nlhdr;
240 #if 0
241 /* disabled at the moment */
242 	struct ifinfomsg *ifi;
243 #endif
244 	struct ifaddrmsg *ifa;
245 	int len;
246 
247 	struct rtattr *rth;
248 	int rtl;
249 
250 	unsigned int ext_if_name_index = 0;
251 
252 	iov.iov_base = buffer;
253 	iov.iov_len = sizeof(buffer);
254 
255 	memset(&hdr, 0, sizeof(hdr));
256 	hdr.msg_iov = &iov;
257 	hdr.msg_iovlen = 1;
258 
259 	len = recvmsg(s, &hdr, 0);
260 	if (len < 0)
261 	{
262 		syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
263 		return;
264 	}
265 
266 	if(ext_if_name) {
267 		ext_if_name_index = if_nametoindex(ext_if_name);
268 	}
269 
270 	for (nlhdr = (struct nlmsghdr *) buffer;
271 	     NLMSG_OK (nlhdr, (unsigned int)len);
272 	     nlhdr = NLMSG_NEXT (nlhdr, len))
273 	{
274 		int is_del = 0;
275 		char address[48];
276 		char ifname[IFNAMSIZ];
277 		address[0] = '\0';
278 		ifname[0] = '\0';
279 		if (nlhdr->nlmsg_type == NLMSG_DONE)
280 			break;
281 		switch(nlhdr->nlmsg_type) {
282 		case RTM_DELLINK:
283 			is_del = 1;
284 			FALL_THROUGH;
285 		case RTM_NEWLINK:
286 #if 0
287 /* disabled at the moment */
288 			ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
289 			if(is_del) {
290 				if(ProcessInterfaceDown(ifi) < 0)
291 					syslog(LOG_ERR, "ProcessInterfaceDown(ifi) failed");
292 			} else {
293 				if(ProcessInterfaceUp(ifi) < 0)
294 					syslog(LOG_ERR, "ProcessInterfaceUp(ifi) failed");
295 			}
296 #endif
297 			break;
298 		case RTM_DELADDR:
299 			is_del = 1;
300 			FALL_THROUGH;
301 		case RTM_NEWADDR:
302 			/* see /usr/include/linux/netlink.h
303 			 * and /usr/include/linux/rtnetlink.h */
304 			ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
305 			syslog(LOG_DEBUG, "%s %s index=%d fam=%d", "ProcessInterfaceWatchNotify",
306 			       is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
307 			       ifa->ifa_index, ifa->ifa_family);
308 			for(rth = IFA_RTA(ifa), rtl = IFA_PAYLOAD(nlhdr);
309 			    rtl && RTA_OK(rth, rtl);
310 			    rth = RTA_NEXT(rth, rtl)) {
311 				char tmp[128];
312 				memset(tmp, 0, sizeof(tmp));
313 				switch(rth->rta_type) {
314 				case IFA_ADDRESS:
315 				case IFA_LOCAL:
316 				case IFA_BROADCAST:
317 				case IFA_ANYCAST:
318 					inet_ntop(ifa->ifa_family, RTA_DATA(rth), tmp, sizeof(tmp));
319 					if(rth->rta_type == IFA_ADDRESS)
320 						strncpy(address, tmp, sizeof(address));
321 					break;
322 				case IFA_LABEL:
323 					strncpy(tmp, RTA_DATA(rth), sizeof(tmp));
324 					strncpy(ifname, tmp, sizeof(ifname));
325 					break;
326 				case IFA_CACHEINFO:
327 					{
328 						struct ifa_cacheinfo *cache_info;
329 						cache_info = RTA_DATA(rth);
330 						snprintf(tmp, sizeof(tmp), "valid=%u preferred=%u",
331 						         cache_info->ifa_valid, cache_info->ifa_prefered);
332 					}
333 					break;
334 				default:
335 					strncpy(tmp, "*unknown*", sizeof(tmp));
336 				}
337 				syslog(LOG_DEBUG, " - %u - %s type=%d",
338 				       ifa->ifa_index, tmp,
339 				       rth->rta_type);
340 			}
341 			if(ifa->ifa_index == ext_if_name_index) {
342 				should_send_public_address_change_notif = 1;
343 			}
344 			break;
345 		default:
346 			syslog(LOG_DEBUG, "%s type %d ignored",
347 			       "ProcessInterfaceWatchNotify", nlhdr->nlmsg_type);
348 		}
349 	}
350 
351 }
352 
353 #endif
354