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