minidlna: update to 1.1.5
[tomato.git] / release / src / router / minidlna / getifaddr.c
blob7aff3706d411811941d034f00680b5ea9f6f670b
1 /* MiniUPnP project
2 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * Copyright (c) 2006, Thomas Bernard
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <net/if.h>
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <netdb.h>
40 #include <errno.h>
41 #if defined(sun)
42 #include <sys/sockio.h>
43 #endif
45 #include "config.h"
46 #if HAVE_GETIFADDRS
47 # include <ifaddrs.h>
48 # ifdef __linux__
49 # ifndef AF_LINK
50 # define AF_LINK AF_INET
51 # endif
52 # else
53 # include <net/if_dl.h>
54 # endif
55 # ifndef IFF_SLAVE
56 # define IFF_SLAVE 0
57 # endif
58 #endif
59 #ifdef HAVE_NETLINK
60 # include <linux/rtnetlink.h>
61 # include <linux/netlink.h>
62 #endif
63 #include "upnpglobalvars.h"
64 #include "getifaddr.h"
65 #include "minissdp.h"
66 #include "utils.h"
67 #include "log.h"
68 #include "ifaddrs.c"
71 static int
72 getifaddr(const char *ifname)
74 #if HAVE_GETIFADDRS
75 struct ifaddrs *ifap, *p;
76 struct sockaddr_in *addr_in;
78 if (getifaddrs(&ifap) != 0)
80 DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
81 return -1;
84 for (p = ifap; p != NULL; p = p->ifa_next)
86 if (!p->ifa_addr || p->ifa_addr->sa_family != AF_INET)
87 continue;
88 if (ifname && strcmp(p->ifa_name, ifname) != 0)
89 continue;
90 addr_in = (struct sockaddr_in *)p->ifa_addr;
91 if (!ifname && (p->ifa_flags & (IFF_LOOPBACK | IFF_SLAVE)))
92 continue;
93 memcpy(&lan_addr[n_lan_addr].addr, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].addr));
94 if (!inet_ntop(AF_INET, &addr_in->sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)) )
96 DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
97 continue;
99 addr_in = (struct sockaddr_in *)p->ifa_netmask;
100 memcpy(&lan_addr[n_lan_addr].mask, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].mask));
101 lan_addr[n_lan_addr].ifindex = if_nametoindex(p->ifa_name);
102 lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(&lan_addr[n_lan_addr]);
103 if (lan_addr[n_lan_addr].snotify >= 0)
104 n_lan_addr++;
105 if (ifname || n_lan_addr >= MAX_LAN_ADDR)
106 break;
108 freeifaddrs(ifap);
109 if (ifname && !p)
111 DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
112 return -1;
114 #else
115 int s = socket(PF_INET, SOCK_STREAM, 0);
116 struct sockaddr_in addr;
117 struct ifconf ifc;
118 struct ifreq *ifr;
119 char buf[8192];
120 int i, n;
122 memset(&ifc, '\0', sizeof(ifc));
123 ifc.ifc_buf = buf;
124 ifc.ifc_len = sizeof(buf);
126 if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
128 DPRINTF(E_ERROR, L_GENERAL, "SIOCGIFCONF: %s\n", strerror(errno));
129 close(s);
130 return -1;
133 n = ifc.ifc_len / sizeof(struct ifreq);
134 for (i = 0; i < n; i++)
136 ifr = &ifc.ifc_req[i];
137 if (ifname && strcmp(ifr->ifr_name, ifname) != 0)
138 continue;
139 if (!ifname &&
140 (ioctl(s, SIOCGIFFLAGS, ifr) < 0 || ifr->ifr_ifru.ifru_flags & IFF_LOOPBACK))
141 continue;
142 if (ioctl(s, SIOCGIFADDR, ifr) < 0)
143 continue;
144 memcpy(&addr, &(ifr->ifr_addr), sizeof(addr));
145 memcpy(&lan_addr[n_lan_addr].addr, &addr.sin_addr, sizeof(lan_addr[n_lan_addr].addr));
146 if (!inet_ntop(AF_INET, &addr.sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)))
148 DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
149 close(s);
150 continue;
152 if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
153 continue;
154 memcpy(&addr, &(ifr->ifr_addr), sizeof(addr));
155 memcpy(&lan_addr[n_lan_addr].mask, &addr.sin_addr, sizeof(addr));
156 lan_addr[n_lan_addr].ifindex = if_nametoindex(ifr->ifr_name);
157 lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(&lan_addr[n_lan_addr]);
158 if (lan_addr[n_lan_addr].snotify >= 0)
159 n_lan_addr++;
160 if (ifname || n_lan_addr >= MAX_LAN_ADDR)
161 break;
163 close(s);
164 if (ifname && i == n)
166 DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
167 return -1;
169 #endif
170 return n_lan_addr;
174 getsyshwaddr(char *buf, int len)
176 unsigned char mac[6];
177 int ret = -1;
178 #if defined(HAVE_GETIFADDRS) && !defined (__linux__) && !defined (__sun__)
179 struct ifaddrs *ifap, *p;
180 struct sockaddr_in *addr_in;
181 uint8_t a;
183 if (getifaddrs(&ifap) != 0)
185 DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
186 return -1;
188 for (p = ifap; p != NULL; p = p->ifa_next)
190 if (p->ifa_addr && p->ifa_addr->sa_family == AF_LINK)
192 addr_in = (struct sockaddr_in *)p->ifa_addr;
193 a = (htonl(addr_in->sin_addr.s_addr) >> 0x18) & 0xFF;
194 if (a == 127)
195 continue;
196 #if defined(__linux__)
197 struct ifreq ifr;
198 int fd;
199 fd = socket(AF_INET, SOCK_DGRAM, 0);
200 if (fd < 0)
201 continue;
202 strncpy(ifr.ifr_name, p->ifa_name, IFNAMSIZ);
203 ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
204 close(fd);
205 if (ret < 0)
206 continue;
207 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
208 #else
209 struct sockaddr_dl *sdl;
210 sdl = (struct sockaddr_dl*)p->ifa_addr;
211 memcpy(mac, LLADDR(sdl), sdl->sdl_alen);
212 #endif
213 if (MACADDR_IS_ZERO(mac))
214 continue;
215 ret = 0;
216 break;
219 freeifaddrs(ifap);
220 #else
221 struct if_nameindex *ifaces, *if_idx;
222 struct ifreq ifr;
223 int fd;
225 memset(&mac, '\0', sizeof(mac));
226 /* Get the spatially unique node identifier */
227 fd = socket(AF_INET, SOCK_DGRAM, 0);
228 if (fd < 0)
229 return ret;
231 ifaces = if_nameindex();
232 if (!ifaces)
234 close(fd);
235 return ret;
238 for (if_idx = ifaces; if_idx->if_index; if_idx++)
240 strncpyt(ifr.ifr_name, if_idx->if_name, IFNAMSIZ);
241 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
242 continue;
243 if (ifr.ifr_ifru.ifru_flags & IFF_LOOPBACK)
244 continue;
245 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
246 continue;
247 #ifdef __sun__
248 if (MACADDR_IS_ZERO(ifr.ifr_addr.sa_data))
249 continue;
250 memcpy(mac, ifr.ifr_addr.sa_data, 6);
251 #else
252 if (MACADDR_IS_ZERO(ifr.ifr_hwaddr.sa_data))
253 continue;
254 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
255 #endif
256 ret = 0;
257 break;
259 if_freenameindex(ifaces);
260 close(fd);
261 #endif
262 if (ret == 0)
264 if (len > 12)
265 sprintf(buf, "%02x%02x%02x%02x%02x%02x",
266 mac[0]&0xFF, mac[1]&0xFF, mac[2]&0xFF,
267 mac[3]&0xFF, mac[4]&0xFF, mac[5]&0xFF);
268 else if (len == 6)
269 memmove(buf, mac, 6);
271 return ret;
275 get_remote_mac(struct in_addr ip_addr, unsigned char *mac)
277 struct in_addr arp_ent;
278 FILE * arp;
279 char remote_ip[16];
280 int matches, hwtype, flags;
281 memset(mac, 0xFF, 6);
283 arp = fopen("/proc/net/arp", "r");
284 if (!arp)
285 return 1;
286 while (!feof(arp))
288 matches = fscanf(arp, "%15s 0x%8X 0x%8X %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
289 remote_ip, &hwtype, &flags,
290 &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
291 if (matches != 9)
292 continue;
293 inet_pton(AF_INET, remote_ip, &arp_ent);
294 if (ip_addr.s_addr == arp_ent.s_addr)
295 break;
296 mac[0] = 0xFF;
298 fclose(arp);
300 if (mac[0] == 0xFF)
302 memset(mac, 0xFF, 6);
303 return 1;
306 return 0;
309 void
310 reload_ifaces(int force_notify)
312 struct in_addr old_addr[MAX_LAN_ADDR];
313 int i, j;
315 memset(&old_addr, 0xFF, sizeof(old_addr));
316 for (i = 0; i < n_lan_addr; i++)
318 memcpy(&old_addr[i], &lan_addr[i].addr, sizeof(struct in_addr));
319 close(lan_addr[i].snotify);
321 n_lan_addr = 0;
323 i = 0;
324 do {
325 getifaddr(runtime_vars.ifaces[i]);
326 i++;
327 } while (i < MAX_LAN_ADDR && runtime_vars.ifaces[i]);
329 for (i = 0; i < n_lan_addr; i++)
331 for (j = 0; j < MAX_LAN_ADDR; j++)
333 if (memcmp(&lan_addr[i].addr, &old_addr[j], sizeof(struct in_addr)) == 0)
334 break;
336 /* Send out startup notifies if it's a new interface, or on SIGHUP */
337 if (force_notify || j == MAX_LAN_ADDR)
339 DPRINTF(E_INFO, L_GENERAL, "Enabling interface %s/%s\n",
340 lan_addr[i].str, inet_ntoa(lan_addr[i].mask));
341 SendSSDPGoodbyes(lan_addr[i].snotify);
342 SendSSDPNotifies(lan_addr[i].snotify, lan_addr[i].str,
343 runtime_vars.port, runtime_vars.notify_interval);
349 OpenAndConfMonitorSocket(void)
351 #ifdef HAVE_NETLINK
352 struct sockaddr_nl addr;
353 int s;
354 int ret;
356 s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
357 if (s < 0)
359 perror("couldn't open NETLINK_ROUTE socket");
360 return -1;
363 memset(&addr, 0, sizeof(addr));
364 addr.nl_family = AF_NETLINK;
365 addr.nl_groups = RTMGRP_IPV4_IFADDR;
367 ret = bind(s, (struct sockaddr*)&addr, sizeof(addr));
368 if (ret < 0)
370 perror("couldn't bind");
371 close(s);
372 return -1;
375 return s;
376 #else
377 return -1;
378 #endif
381 void
382 ProcessMonitorEvent(int s)
384 #ifdef HAVE_NETLINK
385 int len;
386 char buf[4096];
387 struct nlmsghdr *nlh;
388 int changed = 0;
390 nlh = (struct nlmsghdr*)buf;
392 len = recv(s, nlh, sizeof(buf), 0);
393 if (len <= 0)
394 return;
395 while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE))
397 if (nlh->nlmsg_type == RTM_NEWADDR ||
398 nlh->nlmsg_type == RTM_DELADDR)
400 changed = 1;
402 nlh = NLMSG_NEXT(nlh, len);
404 if (changed)
405 reload_ifaces(0);
406 #endif