DWORD InterfaceUtils::InterfaceGetIndexInternetAccessed(const char* testAddrString, PDWORD interfaceIndex) { //BEGIN --find main interface DWORD ret; struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(testAddrString);//try for google if ((ret = GetBestInterfaceEx((struct sockaddr*)&sa, interfaceIndex)) == NO_ERROR) { return NO_ERROR; } else { switch (ret) { case ERROR_CAN_NOT_COMPLETE: printf(" (ERROR_CAN_NOT_COMPLETE)\n"); break; case ERROR_INVALID_PARAMETER: printf(" (ERROR_INVALID_PARAMETER)\n"); break; case ERROR_NOT_SUPPORTED: printf(" (ERROR_NOT_SUPPORTED)\n"); break; default: printf("\n"); break; } } return -1; //END --find main interface }
int ip_route_get(const char* destination, char ip[40]) { DWORD index = ~(-1); struct sockaddr_in addrin; MIB_IPADDRTABLE *table = NULL; ULONG dwSize = 0; DWORD errcode = 0; DWORD i = 0; addrin.sin_family = AF_INET; addrin.sin_port = htons(0); inet_pton(AF_INET, destination, &addrin.sin_addr); if(NO_ERROR != GetBestInterfaceEx((struct sockaddr*)&addrin, &index)) return -1; errcode = GetIpAddrTable( table, &dwSize, 0 ); assert(ERROR_INSUFFICIENT_BUFFER == errcode); table = (MIB_IPADDRTABLE*)malloc(dwSize); errcode = GetIpAddrTable( table, &dwSize, 0 ); if(!table || NO_ERROR != errcode) { free(table); return -1; } ip[0] = '\0'; for(i = 0; i < table->dwNumEntries; i++) { if(table->table[i].dwIndex == index) { sprintf(ip, "%d.%d.%d.%d", (table->table[i].dwAddr >> 0) & 0xFF, (table->table[i].dwAddr >> 8) & 0xFF, (table->table[i].dwAddr >> 16) & 0xFF, (table->table[i].dwAddr >> 24) & 0xFF); break; } }
/* ssdpDiscoverDevices() : * return a chained list of all devices found or NULL if * no devices was found. * It is up to the caller to free the chained list * delay is in millisecond (poll). * UDA v1.1 says : * The TTL for the IP packet SHOULD default to 2 and * SHOULD be configurable. */ struct UPNPDev * ssdpDiscoverDevices(const char * const deviceTypes[], int delay, const char * multicastif, int localport, int ipv6, unsigned char ttl, int * error, int searchalltypes) { struct UPNPDev * tmp; struct UPNPDev * devlist = 0; unsigned int scope_id = 0; int opt = 1; static const char MSearchMsgFmt[] = "M-SEARCH * HTTP/1.1\r\n" "HOST: %s:" XSTR(SSDP_PORT) "\r\n" "ST: %s\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: %u\r\n" "\r\n"; int deviceIndex; char bufr[1536]; /* reception and emission buffer */ SOCKET sudp; int n; struct sockaddr_storage sockudp_r; unsigned int mx; #ifdef NO_GETADDRINFO struct sockaddr_storage sockudp_w; #else int rv; struct addrinfo hints, *servinfo, *p; #endif #ifdef _WIN32 unsigned long _ttl = (unsigned long)ttl; #endif int linklocal = 1; int sentok; if(error) *error = MINISSDPC_UNKNOWN_ERROR; if(localport==UPNP_LOCAL_PORT_SAME) localport = SSDP_PORT; #ifdef _WIN32 sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP); #else sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); #endif if(ISINVALID(sudp)) { if(error) *error = MINISSDPC_SOCKET_ERROR; PRINT_SOCKET_ERROR("socket"); return NULL; } /* reception */ memset(&sockudp_r, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; p->sin6_family = AF_INET6; if(localport > 0 && localport < 65536) p->sin6_port = htons((unsigned short)localport); p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; p->sin_family = AF_INET; if(localport > 0 && localport < 65536) p->sin_port = htons((unsigned short)localport); p->sin_addr.s_addr = INADDR_ANY; } #ifdef _WIN32 /* This code could help us to use the right Network interface for * SSDP multicast traffic */ /* Get IP associated with the index given in the ip_forward struct * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ if(!ipv6) { DWORD ifbestidx; SOCKADDR_IN destAddr; memset(&destAddr, 0, sizeof(destAddr)); destAddr.sin_family = AF_INET; destAddr.sin_addr.s_addr = inet_addr("223.255.255.255"); destAddr.sin_port = 0; if (GetBestInterfaceEx((struct sockaddr *)&destAddr, &ifbestidx) == NO_ERROR) { DWORD dwRetVal = 0; PIP_ADAPTER_ADDRESSES pAddresses = NULL; ULONG outBufLen = 0; ULONG Iterations = 0; PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL; PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL; outBufLen = 15360; do { pAddresses = (IP_ADAPTER_ADDRESSES *) HeapAlloc(GetProcessHeap(), 0, outBufLen); if (pAddresses == NULL) { break; } dwRetVal = GetAdaptersAddresses(AF_INET, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddresses, &outBufLen); if (dwRetVal == ERROR_BUFFER_OVERFLOW) { HeapFree(GetProcessHeap(), 0, pAddresses); pAddresses = NULL; } else { break; } Iterations++; } while ((dwRetVal == ERROR_BUFFER_OVERFLOW) && (Iterations < 3)); if (dwRetVal == NO_ERROR) { pCurrAddresses = pAddresses; while (pCurrAddresses) { #ifdef DEBUG int i; PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL; PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL; printf("\tIfIndex (IPv4 interface): %u\n", pCurrAddresses->IfIndex); printf("\tAdapter name: %s\n", pCurrAddresses->AdapterName); pUnicast = pCurrAddresses->FirstUnicastAddress; if (pUnicast != NULL) { for (i = 0; pUnicast != NULL; i++) { IPAddr.S_un.S_addr = (u_long) pUnicast->Address; printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); pUnicast = pUnicast->Next; } printf("\tNumber of Unicast Addresses: %d\n", i); } pAnycast = pCurrAddresses->FirstAnycastAddress; if (pAnycast) { for (i = 0; pAnycast != NULL; i++) { IPAddr.S_un.S_addr = (u_long) pAnyCast->Address; printf("\tAnycast Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); pAnycast = pAnycast->Next; } printf("\tNumber of Anycast Addresses: %d\n", i); } pMulticast = pCurrAddresses->FirstMulticastAddress; if (pMulticast) { for (i = 0; pMulticast != NULL; i++) { IPAddr.S_un.S_addr = (u_long) pMultiCast->Address; printf("\tMulticast Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); } } printf("\n"); #endif pUnicast = pCurrAddresses->FirstUnicastAddress; if (pCurrAddresses->IfIndex == ifbestidx && pUnicast != NULL) { SOCKADDR_IN *ipv4 = (SOCKADDR_IN *)(pUnicast->Address.lpSockaddr); /* Set the address of this interface to be used */ struct in_addr mc_if; memset(&mc_if, 0, sizeof(mc_if)); mc_if.s_addr = ipv4->sin_addr.s_addr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt"); } ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = ipv4->sin_addr.s_addr; #ifndef DEBUG break; #endif } pCurrAddresses = pCurrAddresses->Next; } } if (pAddresses != NULL) { HeapFree(GetProcessHeap(), 0, pAddresses); pAddresses = NULL; } } } #endif /* _WIN32 */ #ifdef _WIN32 if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) #else if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) #endif { if(error) *error = MINISSDPC_SOCKET_ERROR; PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)"); return NULL; } if(ipv6) { #ifdef _WIN32 DWORD mcastHops = ttl; if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char *)&mcastHops, sizeof(mcastHops)) < 0) #else /* _WIN32 */ int mcastHops = ttl; if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastHops, sizeof(mcastHops)) < 0) #endif /* _WIN32 */ { PRINT_SOCKET_ERROR("setsockopt(IPV6_MULTICAST_HOPS,...)"); } } else { #ifdef _WIN32 if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0) #else /* _WIN32 */ if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) #endif /* _WIN32 */ { /* not a fatal error */ PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)"); } } if(multicastif) { if(ipv6) { #if !defined(_WIN32) /* according to MSDN, if_nametoindex() is supported since * MS Windows Vista and MS Windows Server 2008. * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) { PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF"); } #else #ifdef DEBUG printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); #endif #endif } else { struct in_addr mc_if; #if defined(_WIN32) && (_WIN32_WINNT >= _WIN32_WINNT_VISTA) InetPtonA(AF_INET, multicastif, &mc_if); #else mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ #endif if(mc_if.s_addr != INADDR_NONE) { ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); } } else { #ifdef HAS_IP_MREQN /* was not an ip address, try with an interface name */ struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ memset(&reqn, 0, sizeof(struct ip_mreqn)); reqn.imr_ifindex = if_nametoindex(multicastif); if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) { PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); } #elif !defined(_WIN32) struct ifreq ifr; int ifrlen = sizeof(ifr); strncpy(ifr.ifr_name, multicastif, IFNAMSIZ); ifr.ifr_name[IFNAMSIZ-1] = '\0'; if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0) { PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)"); } mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); } #else /* _WIN32 */ #ifdef DEBUG printf("Setting of multicast interface not supported with interface name.\n"); #endif #endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */ } } } /* Before sending the packed, we first "bind" in order to be able * to receive the response */ if (bind(sudp, (const struct sockaddr *)&sockudp_r, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) { if(error) *error = MINISSDPC_SOCKET_ERROR; PRINT_SOCKET_ERROR("bind"); closesocket(sudp); return NULL; } if(error) *error = MINISSDPC_SUCCESS; /* Calculating maximum response time in seconds */ mx = ((unsigned int)delay) / 1000u; if(mx == 0) { mx = 1; delay = 1000; } /* receiving SSDP response packet */ for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { sentok = 0; /* sending the SSDP M-SEARCH packet */ n = snprintf(bufr, sizeof(bufr), MSearchMsgFmt, ipv6 ? (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") : UPNP_MCAST_ADDR, deviceTypes[deviceIndex], mx); if ((unsigned int)n >= sizeof(bufr)) { if(error) *error = MINISSDPC_MEMORY_ERROR; goto error; } #ifdef DEBUG /*printf("Sending %s", bufr);*/ printf("Sending M-SEARCH request to %s with ST: %s\n", ipv6 ? (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") : UPNP_MCAST_ADDR, deviceTypes[deviceIndex]); #endif #ifdef NO_GETADDRINFO /* the following code is not using getaddrinfo */ /* emission */ memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); if(ipv6) { struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; p->sin6_family = AF_INET6; p->sin6_port = htons(SSDP_PORT); inet_pton(AF_INET6, linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, &(p->sin6_addr)); } else { struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; p->sin_family = AF_INET; p->sin_port = htons(SSDP_PORT); p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); } n = sendto(sudp, bufr, n, 0, &sockudp_w, ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); if (n < 0) { if(error) *error = MINISSDPC_SOCKET_ERROR; PRINT_SOCKET_ERROR("sendto"); } else { sentok = 1; } #else /* #ifdef NO_GETADDRINFO */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ hints.ai_socktype = SOCK_DGRAM; /*hints.ai_flags = */ if ((rv = getaddrinfo(ipv6 ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) : UPNP_MCAST_ADDR, XSTR(SSDP_PORT), &hints, &servinfo)) != 0) { if(error) *error = MINISSDPC_SOCKET_ERROR; #ifdef _WIN32 fprintf(stderr, "getaddrinfo() failed: %d\n", rv); #else fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); #endif break; } for(p = servinfo; p; p = p->ai_next) { n = sendto(sudp, bufr, n, 0, p->ai_addr, MSC_CAST_INT p->ai_addrlen); if (n < 0) { #ifdef DEBUG char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); } #endif PRINT_SOCKET_ERROR("sendto"); continue; } else { sentok = 1; } } freeaddrinfo(servinfo); if(!sentok) { if(error) *error = MINISSDPC_SOCKET_ERROR; } #endif /* #ifdef NO_GETADDRINFO */ /* Waiting for SSDP REPLY packet to M-SEARCH * if searchalltypes is set, enter the loop only * when the last deviceType is reached */ if((sentok && !searchalltypes) || !deviceTypes[deviceIndex + 1]) do { n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); if (n < 0) { /* error */ if(error) *error = MINISSDPC_SOCKET_ERROR; goto error; } else if (n == 0) { /* no data or Time Out */ #ifdef DEBUG printf("NODATA or TIMEOUT\n"); #endif /* DEBUG */ if (devlist && !searchalltypes) { /* found some devices, stop now*/ if(error) *error = MINISSDPC_SUCCESS; goto error; } } else { const char * descURL=NULL; int urlsize=0; const char * st=NULL; int stsize=0; const char * usn=NULL; int usnsize=0; parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize); if(st&&descURL) { #ifdef DEBUG printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n", stsize, st, usnsize, (usn?usn:""), urlsize, descURL); #endif /* DEBUG */ for(tmp=devlist; tmp; tmp = tmp->pNext) { if(memcmp(tmp->descURL, descURL, urlsize) == 0 && tmp->descURL[urlsize] == '\0' && memcmp(tmp->st, st, stsize) == 0 && tmp->st[stsize] == '\0' && (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) && tmp->usn[usnsize] == '\0') break; } /* at the exit of the loop above, tmp is null if * no duplicate device was found */ if(tmp) continue; tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); if(!tmp) { /* memory allocation error */ if(error) *error = MINISSDPC_MEMORY_ERROR; goto error; } tmp->pNext = devlist; tmp->descURL = tmp->buffer; tmp->st = tmp->buffer + 1 + urlsize; tmp->usn = tmp->st + 1 + stsize; memcpy(tmp->buffer, descURL, urlsize); tmp->buffer[urlsize] = '\0'; memcpy(tmp->st, st, stsize); tmp->buffer[urlsize+1+stsize] = '\0'; if(usn != NULL) memcpy(tmp->usn, usn, usnsize); tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; tmp->scope_id = scope_id; devlist = tmp; } } } while(n > 0); if(ipv6) { /* switch linklocal flag */ if(linklocal) { linklocal = 0; --deviceIndex; } else { linklocal = 1; } } } error: closesocket(sudp); return devlist; }
/** * \brief Get interface for a destination route. * \param addr destination address * \param src source address, this parameter will be filled in function succeed * \return 0 if success, -1 otherwise */ static int get_source_for_destination(struct sockaddr* dst, struct sockaddr_storage* src) { DWORD ifindex = 0; IP_ADAPTER_ADDRESSES* allAdapters = NULL; IP_ADAPTER_ADDRESSES* adapter = NULL; ULONG size = ADAPTERS_DEFAULT_SIZE; ULONG ret = 0; BOOL found = FALSE; /* need a valid pointer */ if(!src || !dst) { return -1; } /* get output interface index for specific destination address */ if(GetBestInterfaceEx(dst, &ifindex) != NO_ERROR) { return -1; } do { /* we should loop only if host has more than * (ADAPTERS_DEFAULT_SIZE / sizeof(IP_ADAPTER_ADDRESSES)) interfaces */ allAdapters = malloc(size); if(!allAdapters) { /* out of memory */ return -1; } /* get the list of host addresses and try to find * the index */ ret = GetAdaptersAddresses(dst->sa_family, /* return same address family as destination */ GAA_FLAG_INCLUDE_ALL_INTERFACES | GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST, NULL, /* reserved */ allAdapters, &size); if(ret == ERROR_BUFFER_OVERFLOW) { /* free memory as the loop will allocate again with * proper size */ free(allAdapters); } }while(ret == ERROR_BUFFER_OVERFLOW); if(ret != ERROR_SUCCESS) { free(allAdapters); return -1; } adapter = allAdapters; while(adapter) { /* find the right adapter for interface index return by GetBestInterface */ if(dst->sa_family == AF_INET && (adapter->IfIndex == ifindex)) { IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; if(unicast != NULL) { struct sockaddr_in* addr = (struct sockaddr_in*)unicast->Address.lpSockaddr; memcpy(src, addr, sizeof(struct sockaddr_in)); found = TRUE; /* found source address, break the loop */ break; } } else if(dst->sa_family == AF_INET6 && (adapter->Ipv6IfIndex == ifindex)) { /* XXX multihoming on IPv6 interfaces, they can have * multiple global addresses (+ link-local address), handle this case */ IP_ADAPTER_UNICAST_ADDRESS* unicast = adapter->FirstUnicastAddress; if(unicast != NULL) { struct sockaddr_in6* addr = (struct sockaddr_in6*)unicast->Address.lpSockaddr; memcpy(src, addr, sizeof(struct sockaddr_in6)); found = TRUE; /* found source address, break the loop */ break; } } adapter = adapter->Next; } /* cleanup */ free(allAdapters); return found ? 0 : -1; }