1/* MiniUPnP project 2 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ 3 * 4 * Copyright (c) 2006, Thomas Bernard 5 * All rights reserved. 6 * 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. 16 * 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. 28 */ 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 44 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 69static int 70getifaddr(const char *ifname) 71{ 72#if HAVE_GETIFADDRS 73 struct ifaddrs *ifap, *p; 74 struct sockaddr_in *addr_in; 75 76 if (getifaddrs(&ifap) != 0) 77 { 78 DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno)); 79 return -1; 80 } 81 82 for (p = ifap; p != NULL; p = p->ifa_next) 83 { 84 if (!p->ifa_addr || p->ifa_addr->sa_family != AF_INET) 85 continue; 86 if (ifname && strcmp(p->ifa_name, ifname) != 0) 87 continue; 88 addr_in = (struct sockaddr_in *)p->ifa_addr; 89 if (!ifname && (p->ifa_flags & (IFF_LOOPBACK | IFF_SLAVE))) 90 continue; 91 /* Foxconn added start Bernie 06/01/2016 */ 92 if (strcmp(p->ifa_name, "br0") != 0) 93 continue; 94 /* Foxconn added end Bernie 06/01/2016 */ 95 memcpy(&lan_addr[n_lan_addr].addr, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].addr)); 96 if (!inet_ntop(AF_INET, &addr_in->sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)) ) 97 { 98 DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno)); 99 continue; 100 } 101 addr_in = (struct sockaddr_in *)p->ifa_netmask; 102 memcpy(&lan_addr[n_lan_addr].mask, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].mask)); 103 lan_addr[n_lan_addr].ifindex = if_nametoindex(p->ifa_name); 104 lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(&lan_addr[n_lan_addr]); 105 if (lan_addr[n_lan_addr].snotify >= 0) 106 n_lan_addr++; 107 if (ifname || n_lan_addr >= MAX_LAN_ADDR) 108 break; 109 } 110 freeifaddrs(ifap); 111 if (ifname && !p) 112 { 113 DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname); 114 return -1; 115 } 116#else 117 int s = socket(PF_INET, SOCK_STREAM, 0); 118 struct sockaddr_in addr; 119 struct ifconf ifc; 120 struct ifreq *ifr; 121 char buf[8192]; 122 int i, n; 123 124 memset(&ifc, '\0', sizeof(ifc)); 125 ifc.ifc_buf = buf; 126 ifc.ifc_len = sizeof(buf); 127 128 if (ioctl(s, SIOCGIFCONF, &ifc) < 0) 129 { 130 DPRINTF(E_ERROR, L_GENERAL, "SIOCGIFCONF: %s\n", strerror(errno)); 131 close(s); 132 return -1; 133 } 134 135 n = ifc.ifc_len / sizeof(struct ifreq); 136 for (i = 0; i < n; i++) 137 { 138 ifr = &ifc.ifc_req[i]; 139 if (ifname && strcmp(ifr->ifr_name, ifname) != 0) 140 continue; 141 if(strcmp(ifr->ifr_name,"br0")!=0) 142 continue; 143 if (!ifname && 144 (ioctl(s, SIOCGIFFLAGS, ifr) < 0 || ifr->ifr_ifru.ifru_flags & IFF_LOOPBACK)) 145 continue; 146 if (ioctl(s, SIOCGIFADDR, ifr) < 0) 147 continue; 148 memcpy(&addr, &(ifr->ifr_addr), sizeof(addr)); 149 memcpy(&lan_addr[n_lan_addr].addr, &addr.sin_addr, sizeof(lan_addr[n_lan_addr].addr)); 150 if (!inet_ntop(AF_INET, &addr.sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str))) 151 { 152 DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno)); 153 close(s); 154 continue; 155 } 156 if (ioctl(s, SIOCGIFNETMASK, ifr) < 0) 157 continue; 158 memcpy(&addr, &(ifr->ifr_addr), sizeof(addr)); 159 memcpy(&lan_addr[n_lan_addr].mask, &addr.sin_addr, sizeof(addr)); 160 lan_addr[n_lan_addr].ifindex = if_nametoindex(ifr->ifr_name); 161 lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(&lan_addr[n_lan_addr]); 162 if (lan_addr[n_lan_addr].snotify >= 0) 163 n_lan_addr++; 164 if (ifname || n_lan_addr >= MAX_LAN_ADDR) 165 break; 166 } 167 close(s); 168 if (ifname && i == n) 169 { 170 DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname); 171 return -1; 172 } 173#endif 174 return n_lan_addr; 175} 176 177int 178getsyshwaddr(char *buf, int len) 179{ 180 unsigned char mac[6]; 181 int ret = -1; 182#if defined(HAVE_GETIFADDRS) && !defined (__linux__) && !defined (__sun__) 183 struct ifaddrs *ifap, *p; 184 struct sockaddr_in *addr_in; 185 uint8_t a; 186 187 if (getifaddrs(&ifap) != 0) 188 { 189 DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno)); 190 return -1; 191 } 192 for (p = ifap; p != NULL; p = p->ifa_next) 193 { 194 if (p->ifa_addr && p->ifa_addr->sa_family == AF_LINK) 195 { 196 addr_in = (struct sockaddr_in *)p->ifa_addr; 197 a = (htonl(addr_in->sin_addr.s_addr) >> 0x18) & 0xFF; 198 if (a == 127) 199 continue; 200#if defined(__linux__) 201 struct ifreq ifr; 202 int fd; 203 fd = socket(AF_INET, SOCK_DGRAM, 0); 204 if (fd < 0) 205 continue; 206 /* Foxconn added start Bernie 06/01/2016 */ 207 /* DLNA should only work on br0 interface...*/ 208 if (strcmp(p->ifa_name, "br0") != 0) 209 continue; 210 /* Foxconn added end Bernie 06/01/2016 */ 211 212 strncpy(ifr.ifr_name, p->ifa_name, IFNAMSIZ); 213 ret = ioctl(fd, SIOCGIFHWADDR, &ifr); 214 close(fd); 215 if (ret < 0) 216 continue; 217 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); 218#else 219 struct sockaddr_dl *sdl; 220 sdl = (struct sockaddr_dl*)p->ifa_addr; 221 memcpy(mac, LLADDR(sdl), sdl->sdl_alen); 222#endif 223 if (MACADDR_IS_ZERO(mac)) 224 continue; 225 ret = 0; 226 break; 227 } 228 } 229 freeifaddrs(ifap); 230#else 231 struct if_nameindex *ifaces, *if_idx; 232 struct ifreq ifr; 233 int fd; 234 235 memset(&mac, '\0', sizeof(mac)); 236 /* Get the spatially unique node identifier */ 237 fd = socket(AF_INET, SOCK_DGRAM, 0); 238 if (fd < 0) 239 return ret; 240 241 ifaces = if_nameindex(); 242 if (!ifaces) 243 { 244 close(fd); 245 return ret; 246 } 247 248 for (if_idx = ifaces; if_idx->if_index; if_idx++) 249 { 250 /* Foxconn added start pling 09/30/2013 */ 251 /* DLNA should only work on br0 interface...*/ 252 if (strcmp(if_idx->if_name, "br0") != 0) 253 continue; 254 /* Foxconn added end pling 09/30/2013 */ 255 256 strncpyt(ifr.ifr_name, if_idx->if_name, IFNAMSIZ); 257 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) 258 continue; 259 if (ifr.ifr_ifru.ifru_flags & IFF_LOOPBACK) 260 continue; 261 if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) 262 continue; 263#ifdef __sun__ 264 if (MACADDR_IS_ZERO(ifr.ifr_addr.sa_data)) 265 continue; 266 memcpy(mac, ifr.ifr_addr.sa_data, 6); 267#else 268 if (MACADDR_IS_ZERO(ifr.ifr_hwaddr.sa_data)) 269 continue; 270 memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); 271#endif 272 ret = 0; 273 break; 274 } 275 if_freenameindex(ifaces); 276 close(fd); 277#endif 278 if (ret == 0) 279 { 280 if (len > 12) 281 sprintf(buf, "%02x%02x%02x%02x%02x%02x", 282 mac[0]&0xFF, mac[1]&0xFF, mac[2]&0xFF, 283 mac[3]&0xFF, mac[4]&0xFF, mac[5]&0xFF); 284 else if (len == 6) 285 memmove(buf, mac, 6); 286 } 287 return ret; 288} 289 290int 291get_remote_mac(struct in_addr ip_addr, unsigned char *mac) 292{ 293 struct in_addr arp_ent; 294 FILE * arp; 295 char remote_ip[16]; 296 int matches, hwtype, flags; 297 memset(mac, 0xFF, 6); 298 299 arp = fopen("/proc/net/arp", "r"); 300 if (!arp) 301 return 1; 302 while (!feof(arp)) 303 { 304 matches = fscanf(arp, "%15s 0x%8X 0x%8X %2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", 305 remote_ip, &hwtype, &flags, 306 &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); 307 if (matches != 9) 308 continue; 309 inet_pton(AF_INET, remote_ip, &arp_ent); 310 if (ip_addr.s_addr == arp_ent.s_addr) 311 break; 312 mac[0] = 0xFF; 313 } 314 fclose(arp); 315 316 if (mac[0] == 0xFF) 317 { 318 memset(mac, 0xFF, 6); 319 return 1; 320 } 321 322 return 0; 323} 324 325void 326reload_ifaces(int force_notify) 327{ 328 struct in_addr old_addr[MAX_LAN_ADDR]; 329 int i, j; 330 331 memset(&old_addr, 0xFF, sizeof(old_addr)); 332 for (i = 0; i < n_lan_addr; i++) 333 { 334 memcpy(&old_addr[i], &lan_addr[i].addr, sizeof(struct in_addr)); 335 close(lan_addr[i].snotify); 336 } 337 n_lan_addr = 0; 338 339 i = 0; 340 do { 341 getifaddr(runtime_vars.ifaces[i]); 342 i++; 343 } while (i < MAX_LAN_ADDR && runtime_vars.ifaces[i]); 344 345 for (i = 0; i < n_lan_addr; i++) 346 { 347 for (j = 0; j < MAX_LAN_ADDR; j++) 348 { 349 if (memcmp(&lan_addr[i].addr, &old_addr[j], sizeof(struct in_addr)) == 0) 350 break; 351 } 352 /* Send out startup notifies if it's a new interface, or on SIGHUP */ 353 if (force_notify || j == MAX_LAN_ADDR) 354 { 355 DPRINTF(E_INFO, L_GENERAL, "Enabling interface %s/%s\n", 356 lan_addr[i].str, inet_ntoa(lan_addr[i].mask)); 357 SendSSDPGoodbyes(lan_addr[i].snotify); 358 SendSSDPNotifies(lan_addr[i].snotify, lan_addr[i].str, 359 runtime_vars.port, runtime_vars.notify_interval); 360 } 361 } 362} 363 364int 365OpenAndConfMonitorSocket(void) 366{ 367#ifdef HAVE_NETLINK 368 struct sockaddr_nl addr; 369 int s; 370 int ret; 371 372 s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 373 if (s < 0) 374 { 375 perror("couldn't open NETLINK_ROUTE socket"); 376 return -1; 377 } 378 379 memset(&addr, 0, sizeof(addr)); 380 addr.nl_family = AF_NETLINK; 381 addr.nl_groups = RTMGRP_IPV4_IFADDR; 382 383 ret = bind(s, (struct sockaddr*)&addr, sizeof(addr)); 384 if (ret < 0) 385 { 386 perror("couldn't bind"); 387 close(s); 388 return -1; 389 } 390 391 return s; 392#else 393 return -1; 394#endif 395} 396 397void 398ProcessMonitorEvent(int s) 399{ 400#ifdef HAVE_NETLINK 401 int len; 402 char buf[4096]; 403 struct nlmsghdr *nlh; 404 int changed = 0; 405 406 nlh = (struct nlmsghdr*)buf; 407 408 len = recv(s, nlh, sizeof(buf), 0); 409 if (len <= 0) 410 return; 411 while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) 412 { 413 if (nlh->nlmsg_type == RTM_NEWADDR || 414 nlh->nlmsg_type == RTM_DELADDR) 415 { 416 changed = 1; 417 } 418 nlh = NLMSG_NEXT(nlh, len); 419 } 420 if (changed) 421 reload_ifaces(0); 422#endif 423} 424