libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / miniupnpd / linux / ifacewatcher.c
blobbb4f9106dc036ff9f5cc99d5afa21773714bf34a
1 /* $Id: ifacewatcher.c,v 1.7 2012/05/27 22:16:10 nanard Exp $ */
2 /* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006-2012 Thomas Bernard
6 * ifacewatcher.c
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.
12 * Copyright (c) 2011, Alexey Osipov <simba@lerlan.ru>
13 * All rights reserved.
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are met:
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.
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. */
39 #include "../config.h"
41 #ifdef USE_IFACEWATCHER
43 #include <stdio.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <linux/netlink.h>
47 #include <linux/rtnetlink.h>
48 #include <arpa/inet.h>
49 #include <net/if.h>
50 #include <syslog.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include <stdlib.h>
54 #include <signal.h>
56 #include "../ifacewatcher.h"
57 #include "../minissdp.h"
58 #include "../getifaddr.h"
59 #include "../upnpglobalvars.h"
60 #include "../natpmp.h"
62 extern volatile sig_atomic_t should_send_public_address_change_notif;
65 int
66 OpenAndConfInterfaceWatchSocket(void)
68 int s;
69 struct sockaddr_nl addr;
71 s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
72 if (s == -1)
74 syslog(LOG_ERR, "socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE): %m");
75 return -1;
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;*/
83 if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
85 syslog(LOG_ERR, "bind(netlink): %m");
86 close(s);
87 return -1;
90 return s;
93 #if 0
94 /* disabled at the moment */
95 int
96 ProcessInterfaceUp(struct ifinfomsg *ifi)
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;
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;
110 if (lan_iface != NULL)
111 return 0;
113 if (if_indextoname(ifi->ifi_index, ifname) == NULL)
115 syslog(LOG_ERR, "if_indextoname(%d, ifname) failed", ifi->ifi_index);
116 return -1;
119 if (getifaddr(ifname, ifstraddr, 16) < 0)
121 syslog(LOG_DEBUG, "getifaddr(%s, ifaddr, 16) failed", ifname);
122 return 1;
125 if (inet_pton(AF_INET, ifstraddr, &ifaddr) != 1)
127 syslog(LOG_ERR, "inet_pton(AF_INET, \"%s\", &ifaddr) failed", ifstraddr);
128 return -1;
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)
134 if (lan_addr->addr.s_addr != ifaddr.s_addr)
135 continue;
137 syslog(LOG_INFO, "Interface up: %s (%s)", ifname, ifstraddr);
139 /* adding new lan_iface entry */
140 lan_iface = (struct lan_iface_s *) malloc(sizeof(struct lan_iface_s));
141 if (lan_iface == NULL)
143 syslog(LOG_ERR, "malloc(sizeof(struct lan_iface_s): %m");
144 continue;
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
156 LIST_INSERT_HEAD(&lan_ifaces, lan_iface, list);
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);
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);
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;
175 if (lan_iface->snatpmp < 0)
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);
183 #endif
186 return 0;
190 ProcessInterfaceDown(struct ifinfomsg *ifi)
192 struct lan_iface_s * lan_iface;
193 struct lan_iface_s * lan_iface2;
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;
200 if (lan_iface == NULL)
201 return 0;
203 /* one of our interfaces is going down, clean up */
204 syslog(LOG_INFO, "Interface down: %s", lan_iface->iface.name);
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);
212 /* closing SSDP notify socket */
213 close(lan_iface->snotify);
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;
221 if (lan_iface2 == NULL)
222 close(lan_iface->snatpmp);
223 #endif
225 /* del corresponding lan_iface entry */
226 LIST_REMOVE(lan_iface, list);
227 free(lan_iface);
229 return 0;
231 #endif
233 void
234 ProcessInterfaceWatchNotify(int s)
236 char buffer[4096];
237 struct iovec iov;
238 struct msghdr hdr;
239 struct nlmsghdr *nlhdr;
240 struct ifinfomsg *ifi;
241 struct ifaddrmsg *ifa;
242 int len;
244 struct rtattr *rth;
245 int rtl;
247 unsigned int ext_if_name_index = 0;
249 iov.iov_base = buffer;
250 iov.iov_len = sizeof(buffer);
252 memset(&hdr, 0, sizeof(hdr));
253 hdr.msg_iov = &iov;
254 hdr.msg_iovlen = 1;
256 len = recvmsg(s, &hdr, 0);
257 if (len < 0)
259 syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
260 return;
263 if(ext_if_name) {
264 ext_if_name_index = if_nametoindex(ext_if_name);
267 for (nlhdr = (struct nlmsghdr *) buffer;
268 NLMSG_OK (nlhdr, (unsigned int)len);
269 nlhdr = NLMSG_NEXT (nlhdr, len))
271 int is_del = 0;
272 char address[48];
273 char ifname[IFNAMSIZ];
274 address[0] = '\0';
275 ifname[0] = '\0';
276 if (nlhdr->nlmsg_type == NLMSG_DONE)
277 break;
278 switch(nlhdr->nlmsg_type) {
279 case RTM_DELLINK:
280 is_del = 1;
281 case RTM_NEWLINK:
282 ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
283 #if 0
284 if(is_del) {
285 if(ProcessInterfaceDown(ifi) < 0)
286 syslog(LOG_ERR, "ProcessInterfaceDown(ifi) failed");
287 } else {
288 if(ProcessInterfaceUp(ifi) < 0)
289 syslog(LOG_ERR, "ProcessInterfaceUp(ifi) failed");
291 #endif
292 break;
293 case RTM_DELADDR:
294 is_del = 1;
295 case RTM_NEWADDR:
296 /* see /usr/include/linux/netlink.h
297 * and /usr/include/linux/rtnetlink.h */
298 ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
299 syslog(LOG_DEBUG, "%s %s index=%d fam=%d", "ProcessInterfaceWatchNotify",
300 is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
301 ifa->ifa_index, ifa->ifa_family);
302 for(rth = IFA_RTA(ifa), rtl = IFA_PAYLOAD(nlhdr);
303 rtl && RTA_OK(rth, rtl);
304 rth = RTA_NEXT(rth, rtl)) {
305 char tmp[128];
306 memset(tmp, 0, sizeof(tmp));
307 switch(rth->rta_type) {
308 case IFA_ADDRESS:
309 case IFA_LOCAL:
310 case IFA_BROADCAST:
311 case IFA_ANYCAST:
312 inet_ntop(ifa->ifa_family, RTA_DATA(rth), tmp, sizeof(tmp));
313 if(rth->rta_type == IFA_ADDRESS)
314 strncpy(address, tmp, sizeof(address));
315 break;
316 case IFA_LABEL:
317 strncpy(tmp, RTA_DATA(rth), sizeof(tmp));
318 strncpy(ifname, tmp, sizeof(ifname));
319 break;
320 case IFA_CACHEINFO:
322 struct ifa_cacheinfo *cache_info;
323 cache_info = RTA_DATA(rth);
324 snprintf(tmp, sizeof(tmp), "valid=%u prefered=%u",
325 cache_info->ifa_valid, cache_info->ifa_prefered);
327 break;
328 default:
329 strncpy(tmp, "*unknown*", sizeof(tmp));
331 syslog(LOG_DEBUG, " - %u - %s type=%d",
332 ifa->ifa_index, tmp,
333 rth->rta_type);
335 if(ifa->ifa_index == ext_if_name_index) {
336 should_send_public_address_change_notif = 1;
338 break;
339 default:
340 syslog(LOG_DEBUG, "%s type %d ignored",
341 "ProcessInterfaceWatchNotify", nlhdr->nlmsg_type);
347 #endif