/* (c) Copyright 2012 - 2018 Anton Sviridenko https://picapica.im This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "PICA_netconf.h" #include #ifdef HAVE_LIBMINIUPNPC #include #include #include #include #include #endif #ifndef WIN32 #include #include #include #endif #define PREFIX4 htonl(0xf0000000U) #define PREFIX8 htonl(0xff000000U) #define PREFIX12 htonl(0xfff00000U) #define PREFIX16 htonl(0xffff0000U) #define PREFIX24 htonl(0xffffff00U) #define MAKEIP(a, b, c, d) (htonl( (a&0xFF) << 24 | (b&0xFF) << 16 | (c&0xFF) << 8 | (d&0xFF) )) int PICA_is_reserved_addr_ipv4(in_addr_t addr) { if ((addr & PREFIX8) == 0 //0.0.0.0/8 || (addr & PREFIX8) == MAKEIP(10, 0, 0, 0) //10.0.0.0/8 || (addr & PREFIX8) == MAKEIP(127, 0, 0, 0)//127.0.0.0/8 || (addr & PREFIX16) == MAKEIP(169, 254, 0, 0) //169.254.0.0/16 || (addr & PREFIX12) == MAKEIP(172, 16, 0, 0) //172.16.0.0/12 || (addr & PREFIX16) == MAKEIP(192, 168, 0, 0) //192.168.0.0/16 || (addr & PREFIX4) == MAKEIP(224, 0, 0, 0) //224.0.0.0/4 || (addr & PREFIX4) == MAKEIP(240, 0, 0, 0) //240.0.0.0/4 || addr == INADDR_BROADCAST ) return 1; return 0; } in_addr_t PICA_guess_listening_addr_ipv4() { in_addr_t retaddr = INADDR_ANY; int found_global = 0; #ifndef WIN32 struct ifaddrs *ifaddr, *ifa; if (getifaddrs(&ifaddr) == -1) return INADDR_ANY; for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr == NULL) continue; if (ifa->ifa_addr->sa_family != AF_INET) continue; if (ifa->ifa_flags & IFF_LOOPBACK) continue; if (!((ifa->ifa_flags & IFF_RUNNING) && (ifa->ifa_flags & IFF_UP))) continue; if (!found_global) { retaddr = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr; if (!PICA_is_reserved_addr_ipv4(retaddr)) found_global = 1; } } freeifaddrs(ifaddr); #else char databuf[16384]; ULONG size = sizeof databuf; ULONG ret; PIP_ADAPTER_ADDRESSES addrs = (PIP_ADAPTER_ADDRESSES)databuf; PIP_ADAPTER_ADDRESSES ap; ret = GetAdaptersAddresses(AF_INET, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME, NULL, addrs, &size); if (ret != NO_ERROR) return INADDR_ANY; ap = addrs; while(ap) { retaddr = ((struct sockaddr_in*)ap->FirstUnicastAddress->Address.lpSockaddr)->sin_addr.s_addr; if (!PICA_is_reserved_addr_ipv4(retaddr)) break; ap = ap->Next; } #endif return retaddr; } #ifdef HAVE_LIBMINIUPNPC int PICA_upnp_autoconfigure_ipv4(int public_port, int local_port, char *public_ip) { struct UPNPDev *devlist = NULL; int error = 0; struct UPNPUrls urls; struct IGDdatas data; char lanaddr[64]; char ppstr[8]; char lpstr[8]; int ret; #if MINIUPNPC_API_VERSION < 14 devlist = upnpDiscover(2000, 0, 0, 0, 0, &error); #else devlist = upnpDiscover(2000, 0, 0, 0, 0, 2, &error); #endif ret = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); if (ret != 1) { freeUPNPDevlist(devlist); return 0; } ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, public_ip); if (ret != UPNPCOMMAND_SUCCESS) { freeUPNPDevlist(devlist); FreeUPNPUrls(&urls); return 0; } sprintf(ppstr, "%u", public_port); sprintf(lpstr, "%u", local_port); ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, ppstr, lpstr, lanaddr, "Pica Pica", "TCP", 0, "0"); if (ret != UPNPCOMMAND_SUCCESS) ret = 0; else ret = 1; freeUPNPDevlist(devlist); FreeUPNPUrls(&urls); return ret; } #endif