Annotation of embedaddon/miniupnpd/linux/ifacewatcher.c, revision 1.1.1.2
1.1.1.2 ! misho 1: /* $Id: ifacewatcher.c,v 1.7 2012/05/27 22:16:10 nanard Exp $ */
1.1 misho 2: /* MiniUPnP project
3: * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
1.1.1.2 ! misho 4: * (c) 2006-2012 Thomas Bernard
1.1 misho 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: *
1.1.1.2 ! misho 12: * Copyright (c) 2011, Alexey Osipov <simba@lerlan.ru>
1.1 misho 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:
1.1.1.2 ! misho 38: #include <stdio.h>
1.1 misho 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>
1.1.1.2 ! misho 49: #include <signal.h>
1.1 misho 50:
51: #include "../config.h"
52:
53: #ifdef USE_IFACEWATCHER
54:
55: #include "../ifacewatcher.h"
56: #include "../minissdp.h"
57: #include "../getifaddr.h"
58: #include "../upnpglobalvars.h"
59: #include "../natpmp.h"
60:
1.1.1.2 ! misho 61: extern volatile sig_atomic_t should_send_public_address_change_notif;
1.1 misho 62:
63:
64: int
65: OpenAndConfInterfaceWatchSocket(void)
66: {
67: int s;
68: struct sockaddr_nl addr;
69:
70: s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
71: if (s == -1)
72: {
73: syslog(LOG_ERR, "socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE): %m");
74: return -1;
75: }
76:
77: memset(&addr, 0, sizeof(addr));
78: addr.nl_family = AF_NETLINK;
79: addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
1.1.1.2 ! misho 80: /*addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;*/
1.1 misho 81:
82: if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
83: {
84: syslog(LOG_ERR, "bind(netlink): %m");
85: close(s);
86: return -1;
87: }
88:
89: return s;
90: }
91:
92: #if 0
93: /* disabled at the moment */
94: int
95: ProcessInterfaceUp(struct ifinfomsg *ifi)
96: {
97: struct lan_iface_s * lan_iface;
98: struct lan_iface_s * lan_iface2;
99: struct lan_addr_s * lan_addr;
100: char ifname[IFNAMSIZ];
101: char ifstraddr[16];
102: struct in_addr ifaddr;
103:
104: /* check if we already have this iface */
105: for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
106: if (lan_iface->iface.index == ifi->ifi_index)
107: break;
108:
109: if (lan_iface != NULL)
110: return 0;
111:
112: if (if_indextoname(ifi->ifi_index, ifname) == NULL)
113: {
114: syslog(LOG_ERR, "if_indextoname(%d, ifname) failed", ifi->ifi_index);
115: return -1;
116: }
117:
118: if (getifaddr(ifname, ifstraddr, 16) < 0)
119: {
120: syslog(LOG_DEBUG, "getifaddr(%s, ifaddr, 16) failed", ifname);
121: return 1;
122: }
123:
124: if (inet_pton(AF_INET, ifstraddr, &ifaddr) != 1)
125: {
126: syslog(LOG_ERR, "inet_pton(AF_INET, \"%s\", &ifaddr) failed", ifstraddr);
127: return -1;
128: }
129:
130: /* check if this new interface has address which we need to listen to */
131: for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
132: {
133: if (lan_addr->addr.s_addr != ifaddr.s_addr)
134: continue;
135:
136: syslog(LOG_INFO, "Interface up: %s (%s)", ifname, ifstraddr);
137:
138: /* adding new lan_iface entry */
139: lan_iface = (struct lan_iface_s *) malloc(sizeof(struct lan_iface_s));
140: if (lan_iface == NULL)
141: {
142: syslog(LOG_ERR, "malloc(sizeof(struct lan_iface_s): %m");
143: continue;
144: }
145:
146: lan_iface->lan_addr = lan_addr;
147: strncpy(lan_iface->iface.name, ifname, IFNAMSIZ);
148: lan_iface->iface.index = ifi->ifi_index;
149: lan_iface->iface.addr = ifaddr;
150: lan_iface->snotify = -1;
151: #ifdef ENABLE_NATPMP
152: lan_iface->snatpmp = -1;
153: #endif
154:
155: LIST_INSERT_HEAD(&lan_ifaces, lan_iface, list);
156:
157: /* adding multicast membership for SSDP */
158: if(AddMulticastMembership(sudp, ifaddr.s_addr, ifi->ifi_index) < 0)
159: syslog(LOG_WARNING, "Failed to add multicast membership for interface %s (%s)", ifname, ifstraddr);
160: else
161: syslog(LOG_INFO, "Multicast membership added for %s (%s)", ifname, ifstraddr);
162:
163: /* create SSDP notify socket */
164: if (OpenAndConfSSDPNotifySocket(lan_iface) < 0)
165: syslog(LOG_WARNING, "Failed to open SSDP notify socket for interface %s (%s)", ifname, ifstraddr);
166:
167: #ifdef ENABLE_NATPMP
168: /* create NAT-PMP socket */
169: for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
170: if (lan_iface2->lan_addr->addr.s_addr == lan_iface->lan_addr->addr.s_addr &&
171: lan_iface2->snatpmp >= 0)
172: lan_iface->snatpmp = lan_iface2->snatpmp;
173:
174: if (lan_iface->snatpmp < 0)
175: {
176: lan_iface->snatpmp = OpenAndConfNATPMPSocket(ifaddr.s_addr);
177: if (lan_iface->snatpmp < 0)
178: syslog(LOG_ERR, "OpenAndConfNATPMPSocket(ifaddr.s_addr) failed for %s (%s)", ifname, ifstraddr);
179: else
180: syslog(LOG_INFO, "Listening for NAT-PMP connection on %s:%d", ifstraddr, NATPMP_PORT);
181: }
182: #endif
183: }
184:
185: return 0;
186: }
187:
188: int
189: ProcessInterfaceDown(struct ifinfomsg *ifi)
190: {
191: struct lan_iface_s * lan_iface;
192: struct lan_iface_s * lan_iface2;
193:
194: /* check if we have this iface */
195: for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next)
196: if (lan_iface->iface.index == ifi->ifi_index)
197: break;
198:
199: if (lan_iface == NULL)
200: return 0;
201:
202: /* one of our interfaces is going down, clean up */
203: syslog(LOG_INFO, "Interface down: %s", lan_iface->iface.name);
204:
205: /* remove multicast membership for SSDP */
206: if(DropMulticastMembership(sudp, lan_iface->lan_addr->addr.s_addr, lan_iface->iface.index) < 0)
207: syslog(LOG_WARNING, "Failed to drop multicast membership for interface %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
208: else
209: syslog(LOG_INFO, "Multicast membership dropped for %s (%s)", lan_iface->iface.name, lan_iface->lan_addr->str);
210:
211: /* closing SSDP notify socket */
212: close(lan_iface->snotify);
213:
214: #ifdef ENABLE_NATPMP
215: /* closing NAT-PMP socket if it's not used anymore */
216: for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next)
217: if (lan_iface2 != lan_iface && lan_iface2->snatpmp == lan_iface->snatpmp)
218: break;
219:
220: if (lan_iface2 == NULL)
221: close(lan_iface->snatpmp);
222: #endif
223:
224: /* del corresponding lan_iface entry */
225: LIST_REMOVE(lan_iface, list);
226: free(lan_iface);
227:
228: return 0;
229: }
230: #endif
231:
232: void
233: ProcessInterfaceWatchNotify(int s)
234: {
235: char buffer[4096];
236: struct iovec iov;
237: struct msghdr hdr;
238: struct nlmsghdr *nlhdr;
239: struct ifinfomsg *ifi;
240: struct ifaddrmsg *ifa;
241: int len;
242:
1.1.1.2 ! misho 243: struct rtattr *rth;
1.1 misho 244: int rtl;
245:
246: unsigned int ext_if_name_index = 0;
247:
248: iov.iov_base = buffer;
249: iov.iov_len = sizeof(buffer);
250:
251: memset(&hdr, 0, sizeof(hdr));
252: hdr.msg_iov = &iov;
253: hdr.msg_iovlen = 1;
254:
255: len = recvmsg(s, &hdr, 0);
256: if (len < 0)
257: {
258: syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m");
259: return;
260: }
261:
262: if(ext_if_name) {
263: ext_if_name_index = if_nametoindex(ext_if_name);
264: }
265:
266: for (nlhdr = (struct nlmsghdr *) buffer;
1.1.1.2 ! misho 267: NLMSG_OK (nlhdr, (unsigned int)len);
1.1 misho 268: nlhdr = NLMSG_NEXT (nlhdr, len))
269: {
1.1.1.2 ! misho 270: int is_del = 0;
! 271: char address[48];
! 272: char ifname[IFNAMSIZ];
! 273: address[0] = '\0';
! 274: ifname[0] = '\0';
1.1 misho 275: if (nlhdr->nlmsg_type == NLMSG_DONE)
276: break;
277: switch(nlhdr->nlmsg_type) {
278: case RTM_DELLINK:
1.1.1.2 ! misho 279: is_del = 1;
1.1 misho 280: case RTM_NEWLINK:
281: ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
1.1.1.2 ! misho 282: #if 0
! 283: if(is_del) {
! 284: if(ProcessInterfaceDown(ifi) < 0)
! 285: syslog(LOG_ERR, "ProcessInterfaceDown(ifi) failed");
! 286: } else {
! 287: if(ProcessInterfaceUp(ifi) < 0)
! 288: syslog(LOG_ERR, "ProcessInterfaceUp(ifi) failed");
! 289: }
! 290: #endif
1.1 misho 291: break;
1.1.1.2 ! misho 292: case RTM_DELADDR:
! 293: is_del = 1;
1.1 misho 294: case RTM_NEWADDR:
295: /* see /usr/include/linux/netlink.h
296: * and /usr/include/linux/rtnetlink.h */
297: ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
1.1.1.2 ! misho 298: syslog(LOG_DEBUG, "%s %s index=%d fam=%d", "ProcessInterfaceWatchNotify",
! 299: is_del ? "RTM_DELADDR" : "RTM_NEWADDR",
! 300: ifa->ifa_index, ifa->ifa_family);
1.1 misho 301: for(rth = IFA_RTA(ifa), rtl = IFA_PAYLOAD(nlhdr);
302: rtl && RTA_OK(rth, rtl);
303: rth = RTA_NEXT(rth, rtl)) {
1.1.1.2 ! misho 304: char tmp[128];
! 305: memset(tmp, 0, sizeof(tmp));
! 306: switch(rth->rta_type) {
! 307: case IFA_ADDRESS:
! 308: case IFA_LOCAL:
! 309: case IFA_BROADCAST:
! 310: case IFA_ANYCAST:
! 311: inet_ntop(ifa->ifa_family, RTA_DATA(rth), tmp, sizeof(tmp));
! 312: if(rth->rta_type == IFA_ADDRESS)
! 313: strncpy(address, tmp, sizeof(address));
! 314: break;
! 315: case IFA_LABEL:
! 316: strncpy(tmp, RTA_DATA(rth), sizeof(tmp));
! 317: strncpy(ifname, tmp, sizeof(ifname));
! 318: break;
! 319: case IFA_CACHEINFO:
! 320: {
! 321: struct ifa_cacheinfo *cache_info;
! 322: cache_info = RTA_DATA(rth);
! 323: snprintf(tmp, sizeof(tmp), "valid=%u prefered=%u",
! 324: cache_info->ifa_valid, cache_info->ifa_prefered);
! 325: }
! 326: break;
! 327: default:
! 328: strncpy(tmp, "*unknown*", sizeof(tmp));
! 329: }
1.1 misho 330: syslog(LOG_DEBUG, " - %u - %s type=%d",
1.1.1.2 ! misho 331: ifa->ifa_index, tmp,
1.1 misho 332: rth->rta_type);
333: }
334: if(ifa->ifa_index == ext_if_name_index) {
335: should_send_public_address_change_notif = 1;
336: }
337: break;
338: default:
1.1.1.2 ! misho 339: syslog(LOG_DEBUG, "%s type %d ignored",
! 340: "ProcessInterfaceWatchNotify", nlhdr->nlmsg_type);
1.1 misho 341: }
342: }
343:
344: }
345:
346: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>