udp_address.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #include "stdafx.h"
  2. #include "udp_address.h"
  3. #include <util/system/mutex.h>
  4. #include <util/system/spinlock.h>
  5. #ifdef _win_
  6. #include <iphlpapi.h>
  7. #pragma comment(lib, "Iphlpapi.lib")
  8. #else
  9. #include <errno.h>
  10. #include <ifaddrs.h>
  11. #endif
  12. namespace NNetliba {
  13. static bool IsValidIPv6(const char* sz) {
  14. enum {
  15. S1,
  16. SEMICOLON,
  17. SCOPE
  18. };
  19. int state = S1, scCount = 0, digitCount = 0, hasDoubleSemicolon = false;
  20. while (*sz) {
  21. if (state == S1) {
  22. switch (*sz) {
  23. case '0':
  24. case '1':
  25. case '2':
  26. case '3':
  27. case '4':
  28. case '5':
  29. case '6':
  30. case '7':
  31. case '8':
  32. case '9':
  33. case 'A':
  34. case 'B':
  35. case 'C':
  36. case 'D':
  37. case 'E':
  38. case 'F':
  39. case 'a':
  40. case 'b':
  41. case 'c':
  42. case 'd':
  43. case 'e':
  44. case 'f':
  45. ++digitCount;
  46. if (digitCount > 4)
  47. return false;
  48. break;
  49. case ':':
  50. state = SEMICOLON;
  51. ++scCount;
  52. break;
  53. case '%':
  54. state = SCOPE;
  55. break;
  56. default:
  57. return false;
  58. }
  59. ++sz;
  60. } else if (state == SEMICOLON) {
  61. if (*sz == ':') {
  62. if (hasDoubleSemicolon)
  63. return false;
  64. hasDoubleSemicolon = true;
  65. ++scCount;
  66. digitCount = 0;
  67. state = S1;
  68. ++sz;
  69. } else {
  70. digitCount = 0;
  71. state = S1;
  72. }
  73. } else if (state == SCOPE) {
  74. // arbitrary string is allowed as scope id
  75. ++sz;
  76. }
  77. }
  78. if (!hasDoubleSemicolon && scCount != 7)
  79. return false;
  80. return scCount <= 7;
  81. }
  82. static bool ParseInetName(TUdpAddress* pRes, const char* name, int nDefaultPort, EUdpAddressType addressType) {
  83. int nPort = nDefaultPort;
  84. TString host;
  85. if (name[0] == '[') {
  86. ++name;
  87. const char* nameFin = name;
  88. for (; *nameFin; ++nameFin) {
  89. if (nameFin[0] == ']')
  90. break;
  91. }
  92. host.assign(name, nameFin);
  93. Y_ASSERT(IsValidIPv6(host.c_str()));
  94. name = *nameFin ? nameFin + 1 : nameFin;
  95. if (name[0] == ':') {
  96. char* endPtr = nullptr;
  97. nPort = strtol(name + 1, &endPtr, 10);
  98. if (!endPtr || *endPtr != '\0')
  99. return false;
  100. }
  101. } else {
  102. host = name;
  103. if (!IsValidIPv6(name)) {
  104. size_t nIdx = host.find(':');
  105. if (nIdx != (size_t)TString::npos) {
  106. const char* pszPort = host.c_str() + nIdx + 1;
  107. char* endPtr = nullptr;
  108. nPort = strtol(pszPort, &endPtr, 10);
  109. if (!endPtr || *endPtr != '\0')
  110. return false;
  111. host.resize(nIdx);
  112. }
  113. }
  114. }
  115. addrinfo aiHints;
  116. Zero(aiHints);
  117. aiHints.ai_family = AF_UNSPEC;
  118. aiHints.ai_socktype = SOCK_DGRAM;
  119. aiHints.ai_protocol = IPPROTO_UDP;
  120. // Do not use TMutex here: it has a non-trivial destructor which will be called before
  121. // destruction of current thread, if its TThread declared as global/static variable.
  122. static TAdaptiveLock cs;
  123. TGuard lock(cs);
  124. addrinfo* aiList = nullptr;
  125. for (int attempt = 0; attempt < 1000; ++attempt) {
  126. int rv = getaddrinfo(host.c_str(), "1313", &aiHints, &aiList);
  127. if (rv == 0)
  128. break;
  129. if (aiList) {
  130. freeaddrinfo(aiList);
  131. }
  132. if (rv != EAI_AGAIN) {
  133. return false;
  134. }
  135. usleep(100 * 1000);
  136. }
  137. for (addrinfo* ptr = aiList; ptr; ptr = ptr->ai_next) {
  138. sockaddr* addr = ptr->ai_addr;
  139. if (addr == nullptr)
  140. continue;
  141. switch (addressType) {
  142. case UAT_ANY: {
  143. if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)
  144. continue;
  145. break;
  146. }
  147. case UAT_IPV4: {
  148. if (addr->sa_family != AF_INET)
  149. continue;
  150. break;
  151. }
  152. case UAT_IPV6: {
  153. if (addr->sa_family != AF_INET6)
  154. continue;
  155. break;
  156. }
  157. }
  158. GetUdpAddress(pRes, *(sockaddr_in6*)addr);
  159. pRes->Port = nPort;
  160. freeaddrinfo(aiList);
  161. return true;
  162. }
  163. freeaddrinfo(aiList);
  164. return false;
  165. }
  166. bool GetLocalAddresses(TVector<TUdpAddress>* addrs) {
  167. #ifdef _win_
  168. TVector<char> buf;
  169. buf.resize(1000000);
  170. PIP_ADAPTER_ADDRESSES adapterBuf = (PIP_ADAPTER_ADDRESSES)&buf[0];
  171. ULONG bufSize = buf.ysize();
  172. ULONG rv = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, adapterBuf, &bufSize);
  173. if (rv != ERROR_SUCCESS)
  174. return false;
  175. for (PIP_ADAPTER_ADDRESSES ptr = adapterBuf; ptr; ptr = ptr->Next) {
  176. if ((ptr->Flags & (IP_ADAPTER_IPV4_ENABLED | IP_ADAPTER_IPV6_ENABLED)) == 0) {
  177. continue;
  178. }
  179. if (ptr->IfType == IF_TYPE_TUNNEL) {
  180. // ignore tunnels
  181. continue;
  182. }
  183. if (ptr->OperStatus != IfOperStatusUp) {
  184. // ignore disable adapters
  185. continue;
  186. }
  187. if (ptr->Mtu < 1280) {
  188. fprintf(stderr, "WARNING: MTU %d is less then ipv6 minimum", ptr->Mtu);
  189. }
  190. for (IP_ADAPTER_UNICAST_ADDRESS* addr = ptr->FirstUnicastAddress; addr; addr = addr->Next) {
  191. sockaddr* x = (sockaddr*)addr->Address.lpSockaddr;
  192. if (x == 0)
  193. continue;
  194. if (x->sa_family == AF_INET || x->sa_family == AF_INET6) {
  195. TUdpAddress address;
  196. sockaddr_in6* xx = (sockaddr_in6*)x;
  197. GetUdpAddress(&address, *xx);
  198. addrs->push_back(address);
  199. }
  200. }
  201. }
  202. return true;
  203. #else
  204. ifaddrs* ifap;
  205. if (getifaddrs(&ifap) != -1) {
  206. for (ifaddrs* ifa = ifap; ifa; ifa = ifa->ifa_next) {
  207. sockaddr* sa = (sockaddr*)ifa->ifa_addr;
  208. if (sa == nullptr)
  209. continue;
  210. if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) {
  211. TUdpAddress address;
  212. sockaddr_in6* xx = (sockaddr_in6*)sa;
  213. GetUdpAddress(&address, *xx);
  214. addrs->push_back(address);
  215. }
  216. }
  217. freeifaddrs(ifap);
  218. return true;
  219. }
  220. return false;
  221. #endif
  222. }
  223. void GetUdpAddress(TUdpAddress* res, const sockaddr_in6& addr) {
  224. if (addr.sin6_family == AF_INET) {
  225. const sockaddr_in& addr4 = *(const sockaddr_in*)&addr;
  226. res->Network = 0;
  227. res->Interface = 0xffff0000ll + (((ui64)(ui32)addr4.sin_addr.s_addr) << 32);
  228. res->Scope = 0;
  229. res->Port = ntohs(addr4.sin_port);
  230. } else if (addr.sin6_family == AF_INET6) {
  231. res->Network = *BreakAliasing<ui64>(addr.sin6_addr.s6_addr + 0);
  232. res->Interface = *BreakAliasing<ui64>(addr.sin6_addr.s6_addr + 8);
  233. res->Scope = addr.sin6_scope_id;
  234. res->Port = ntohs(addr.sin6_port);
  235. }
  236. }
  237. void GetWinsockAddr(sockaddr_in6* res, const TUdpAddress& addr) {
  238. if (0) { //addr.IsIPv4()) {
  239. // use ipv4 to ipv6 mapping
  240. //// ipv4
  241. //sockaddr_in &toAddress = *(sockaddr_in*)res;
  242. //Zero(toAddress);
  243. //toAddress.sin_family = AF_INET;
  244. //toAddress.sin_addr.s_addr = addr.GetIPv4();
  245. //toAddress.sin_port = htons((u_short)addr.Port);
  246. } else {
  247. // ipv6
  248. sockaddr_in6& toAddress = *(sockaddr_in6*)res;
  249. Zero(toAddress);
  250. toAddress.sin6_family = AF_INET6;
  251. *BreakAliasing<ui64>(toAddress.sin6_addr.s6_addr + 0) = addr.Network;
  252. *BreakAliasing<ui64>(toAddress.sin6_addr.s6_addr + 8) = addr.Interface;
  253. toAddress.sin6_scope_id = addr.Scope;
  254. toAddress.sin6_port = htons((u_short)addr.Port);
  255. }
  256. }
  257. TUdpAddress CreateAddress(const TString& server, int defaultPort, EUdpAddressType addressType) {
  258. TUdpAddress res;
  259. ParseInetName(&res, server.c_str(), defaultPort, addressType);
  260. return res;
  261. }
  262. TString GetAddressAsString(const TUdpAddress& addr) {
  263. char buf[1000];
  264. if (addr.IsIPv4()) {
  265. int ip = addr.GetIPv4();
  266. snprintf(buf, sizeof(buf), "%d.%d.%d.%d:%d",
  267. (ip >> 0) & 0xff, (ip >> 8) & 0xff,
  268. (ip >> 16) & 0xff, (ip >> 24) & 0xff,
  269. addr.Port);
  270. } else {
  271. ui16 ipv6[8];
  272. *BreakAliasing<ui64>(ipv6) = addr.Network;
  273. *BreakAliasing<ui64>(ipv6 + 4) = addr.Interface;
  274. char suffix[100] = "";
  275. if (addr.Scope != 0) {
  276. snprintf(suffix, sizeof(suffix), "%%%d", addr.Scope);
  277. }
  278. snprintf(buf, sizeof(buf), "[%x:%x:%x:%x:%x:%x:%x:%x%s]:%d",
  279. ntohs(ipv6[0]), ntohs(ipv6[1]), ntohs(ipv6[2]), ntohs(ipv6[3]),
  280. ntohs(ipv6[4]), ntohs(ipv6[5]), ntohs(ipv6[6]), ntohs(ipv6[7]),
  281. suffix, addr.Port);
  282. }
  283. return buf;
  284. }
  285. }