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