uncrustify as demanded.
[oweals/gnunet.git] / src / gns / w32nsp-resolve.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file gns/w32nsp-resolve.c
22  * @brief W32 integration for GNS
23  * @author LRN
24  */
25 /* Instead of including gnunet_common.h */
26 #define GNUNET_memcpy(dst, src, n) do { if (0 != n) { (void)memcpy(dst, src, n); } } while (0)
27
28 #include <ws2tcpip.h>
29 #include <windows.h>
30 #include <nspapi.h>
31 #include <ws2spi.h>
32 #include <nspapi.h>
33 #include <initguid.h>
34 #include "gnunet_w32nsp_lib.h"
35 #include <stdio.h>
36
37 typedef int (WSPAPI *LPNSPSTARTUP)(LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines);
38
39 GUID host = { 0x0002a800, 0, 0, { 0xC0, 0, 0, 0, 0, 0, 0, 0x46 } };
40 GUID ip4 = { 0x00090035, 0, 1, { 0xc0, 0, 0, 0, 0, 0, 0, 0x046 } };
41 GUID ip6 = { 0x00090035, 0, 0x001c, { 0xc0, 0, 0, 0, 0, 0, 0, 0x046 } };
42
43 DEFINE_GUID(W32_DNS, 0x22059D40, 0x7E9E, 0x11CF, 0xAE, 0x5A, 0x00, 0xAA, 0x00, 0xA7, 0x11, 0x2B);
44
45 #define DEFINE_DNS_GUID(a, x) DEFINE_GUID(a, 0x00090035, 0x0000, x, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)
46 DEFINE_DNS_GUID(SVCID_DNS_TYPE_A, 0x0001);
47 DEFINE_DNS_GUID(SVCID_DNS_TYPE_NS, 0x0002);
48 DEFINE_DNS_GUID(SVCID_DNS_TYPE_CNAME, 0x0005);
49 DEFINE_DNS_GUID(SVCID_DNS_TYPE_SOA, 0x0006);
50 DEFINE_DNS_GUID(SVCID_DNS_TYPE_PTR, 0x000c);
51 DEFINE_DNS_GUID(SVCID_DNS_TYPE_MX, 0x000f);
52 DEFINE_DNS_GUID(SVCID_DNS_TYPE_TEXT, 0x0010);
53 DEFINE_DNS_GUID(SVCID_DNS_TYPE_AAAA, 0x001c);
54 DEFINE_DNS_GUID(SVCID_DNS_TYPE_SRV, 0x0021);
55 DEFINE_GUID(SVCID_HOSTNAME, 0x0002a800, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
56 DEFINE_GUID(SVCID_INET_HOSTADDRBYNAME, 0x0002a803, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
57
58 //
59 // Utility to turn a list of offsets into a list of addresses. Used
60 // to convert structures returned as BLOBs.
61 //
62
63 VOID
64 FixList(PCHAR ** List, PCHAR Base)
65 {
66   if (*List)
67     {
68       PCHAR * Addr;
69
70       Addr = *List = (PCHAR *)(((DWORD)*List + Base));
71       while (*Addr)
72         {
73           *Addr = (PCHAR)(((DWORD)*Addr + Base));
74           Addr++;
75         }
76     }
77 }
78
79
80 //
81 // Routine to convert a hostent returned in a BLOB to one with
82 // usable pointers. The structure is converted in-place.
83 //
84 VOID
85 UnpackHostEnt(struct hostent * hostent)
86 {
87   PCHAR pch;
88
89   pch = (PCHAR)hostent;
90
91   if (hostent->h_name)
92     {
93       hostent->h_name = (PCHAR)((DWORD)hostent->h_name + pch);
94     }
95   FixList(&hostent->h_aliases, pch);
96   FixList(&hostent->h_addr_list, pch);
97 }
98
99
100 static void
101 print_hostent(struct hostent *he)
102 {
103   int i;
104   char **pAlias;
105
106   printf("\tOfficial name: %s\n", he->h_name);
107   for (i = 0, pAlias = he->h_aliases; *pAlias != 0; pAlias++)
108     {
109       printf("\tAlternate name #%d: %s\n", ++i, *pAlias);
110     }
111   printf("\tAddress type: ");
112   switch (he->h_addrtype)
113     {
114     case AF_INET:
115       printf("AF_INET\n");
116       break;
117
118     case AF_INET6:
119       printf("AF_INET6\n");
120       break;
121
122     case AF_NETBIOS:
123       printf("AF_NETBIOS\n");
124       break;
125
126     default:
127       printf(" %d\n", he->h_addrtype);
128       break;
129     }
130   printf("\tAddress length: %d\n", he->h_length);
131
132   if (he->h_addrtype == AF_INET)
133     {
134       struct sockaddr_in addr;
135       memset(&addr, 0, sizeof(addr));
136       addr.sin_family = AF_INET;
137       addr.sin_port = 0;
138       i = 0;
139       while (he->h_addr_list[i] != 0)
140         {
141           char buf[1024];
142           DWORD buflen = 1024;
143           addr.sin_addr = *(struct in_addr *)he->h_addr_list[i++];
144           if (NO_ERROR == WSAAddressToStringA((LPSOCKADDR)&addr, sizeof(addr), NULL, buf, &buflen))
145             printf("\tIPv4 Address #%d: %s\n", i, buf);
146           else
147             printf("\tIPv4 Address #%d: Can't convert: %lu\n", i, GetLastError());
148         }
149     }
150   else if (he->h_addrtype == AF_INET6)
151     {
152       struct sockaddr_in6 addr;
153       memset(&addr, 0, sizeof(addr));
154       addr.sin6_family = AF_INET6;
155       addr.sin6_port = 0;
156       i = 0;
157       while (he->h_addr_list[i] != 0)
158         {
159           char buf[1024];
160           DWORD buflen = 1024;
161           addr.sin6_addr = *(struct in6_addr *)he->h_addr_list[i++];
162           if (NO_ERROR == WSAAddressToStringA((LPSOCKADDR)&addr, sizeof(addr), NULL, buf, &buflen))
163             printf("\tIPv6 Address #%d: %s\n", i, buf);
164           else
165             printf("\tIPv6 Address #%d: Can't convert: %lu\n", i, GetLastError());
166         }
167     }
168 }
169
170
171 int
172 main(int argc, char **argv)
173 {
174   int ret;
175   int r = 1;
176   WSADATA wsd;
177   GUID prov;
178   GUID sc;
179   wchar_t *cmdl;
180   int wargc;
181   wchar_t **wargv;
182
183   if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
184     {
185       fprintf(stderr, "WSAStartup() failed: %lu\n", GetLastError());
186       return 5;
187     }
188
189   cmdl = GetCommandLineW();
190   if (cmdl == NULL)
191     {
192       WSACleanup();
193       return 2;
194     }
195   wargv = CommandLineToArgvW(cmdl, &wargc);
196   if (wargv == NULL)
197     {
198       WSACleanup();
199       return 3;
200     }
201   r = 4;
202
203   if (wargc == 5)
204     {
205       if (wcscmp(wargv[1], L"A") == 0)
206         sc = SVCID_DNS_TYPE_A;
207       else if (wcscmp(wargv[1], L"AAAA") == 0)
208         sc = SVCID_DNS_TYPE_AAAA;
209       else if (wcscmp(wargv[1], L"name") == 0)
210         sc = SVCID_HOSTNAME;
211       else if (wcscmp(wargv[1], L"addr") == 0)
212         sc = SVCID_INET_HOSTADDRBYNAME;
213       else
214         wargc -= 1;
215       if (wcscmp(wargv[4], L"mswdns") == 0)
216         prov = W32_DNS;
217       else if (wcscmp(wargv[4], L"gnunetdns") == 0)
218         prov = GNUNET_NAMESPACE_PROVIDER_DNS;
219       else
220         wargc -= 1;
221     }
222   else if (wargc == 3)
223     {
224     }
225   else
226     {
227       fprintf(stderr, "Usage: %S <record type> <service name> <NSP library path> <NSP id>\n"
228               "record type      - one of the following: A | AAAA | name | addr\n"
229               "service name     - a string to resolve; \" \" (a space) means 'blank'\n"
230               "NSP library path - path to libw32nsp\n"
231               "NSP id           - one of the following: mswdns | gnunetdns\n",
232               wargv[0]);
233     }
234
235   if (wargc == 5)
236     {
237       HMODULE nsp;
238
239       nsp = LoadLibraryW(wargv[3]);
240       if (nsp == NULL)
241         {
242           fprintf(stderr, "Failed to load library `%S'\n", wargv[3]);
243         }
244       else
245         {
246           LPNSPSTARTUP startup = (LPNSPSTARTUP)GetProcAddress(nsp, "NSPStartup");
247           if (startup == NULL)
248             startup = (LPNSPSTARTUP)GetProcAddress(nsp, "NSPStartup@8");
249           if (startup != NULL)
250             {
251               NSP_ROUTINE api;
252               api.cbSize = sizeof(api);
253               ret = startup(&prov, &api);
254               if (NO_ERROR != ret)
255                 fprintf(stderr, "startup failed: %lu\n", GetLastError());
256               else
257                 {
258                   HANDLE lookup;
259                   WSAQUERYSETW search;
260                   char buf[4096];
261                   WSAQUERYSETW *result = (WSAQUERYSETW *)buf;
262                   DWORD resultsize;
263                   DWORD err;
264                   memset(&search, 0, sizeof(search));
265                   search.dwSize = sizeof(search);
266                   search.lpszServiceInstanceName = (wcscmp(wargv[2], L" ") == 0) ? NULL : wargv[2];
267                   search.lpServiceClassId = &sc;
268                   search.lpNSProviderId = &prov;
269                   search.dwNameSpace = NS_ALL;
270                   ret = api.NSPLookupServiceBegin(&prov, &search, NULL, LUP_RETURN_ALL, &lookup);
271                   if (ret != NO_ERROR)
272                     {
273                       fprintf(stderr, "lookup start failed\n");
274                     }
275                   else
276                     {
277                       resultsize = 4096;
278                       ret = api.NSPLookupServiceNext(lookup, LUP_RETURN_ALL, &resultsize, result);
279                       err = GetLastError();
280                       if (ret != NO_ERROR)
281                         {
282                           fprintf(stderr, "lookup next failed: %lu\n", err);
283                         }
284                       else
285                         {
286                           int i;
287                           printf("Got result:\n");
288                           printf("  lpszServiceInstanceName: %S\n", result->lpszServiceInstanceName ? result->lpszServiceInstanceName : L"NULL");
289                           if (result->lpServiceClassId)
290                             printf("  lpServiceClassId:        { 0x%08lX,0x%04X,0x%04X, { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X } }\n",
291                                    result->lpServiceClassId->Data1, result->lpServiceClassId->Data2, result->lpServiceClassId->Data3, result->lpServiceClassId->Data4[0],
292                                    result->lpServiceClassId->Data4[1], result->lpServiceClassId->Data4[2], result->lpServiceClassId->Data4[3], result->lpServiceClassId->Data4[4],
293                                    result->lpServiceClassId->Data4[5], result->lpServiceClassId->Data4[6], result->lpServiceClassId->Data4[7]);
294                           else
295                             printf("  lpServiceClassId:        NULL\n");
296                           if (result->lpVersion)
297                             printf("  lpVersion:               0x%08lX, %d\n", result->lpVersion->dwVersion, result->lpVersion->ecHow);
298                           else
299                             printf("  lpVersion:               NULL\n");
300                           printf("  lpszComment:             %S\n", result->lpszComment ? result->lpszComment : L"NULL");
301                           printf("  dwNameSpace:             %lu\n", result->dwNameSpace);
302                           if (result->lpNSProviderId)
303                             printf("  lpNSProviderId:          { 0x%08lX,0x%04X,0x%04X, { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X } }\n",
304                                    result->lpNSProviderId->Data1, result->lpNSProviderId->Data2, result->lpNSProviderId->Data3, result->lpNSProviderId->Data4[0],
305                                    result->lpNSProviderId->Data4[1], result->lpNSProviderId->Data4[2], result->lpNSProviderId->Data4[3], result->lpNSProviderId->Data4[4],
306                                    result->lpNSProviderId->Data4[5], result->lpNSProviderId->Data4[6], result->lpNSProviderId->Data4[7]);
307                           else
308                             printf("  lpNSProviderId:          NULL\n");
309                           printf("  lpszContext:             %S\n", result->lpszContext ? result->lpszContext : L"NULL");
310                           printf("  dwNumberOfProtocols:     %lu\n", result->dwNumberOfProtocols);
311                           printf("  lpszQueryString:         %S\n", result->lpszQueryString ? result->lpszQueryString : L"NULL");
312                           printf("  dwNumberOfCsAddrs:       %lu\n", result->dwNumberOfCsAddrs);
313                           for (i = 0; i < result->dwNumberOfCsAddrs; i++)
314                             {
315                               switch (result->lpcsaBuffer[i].iSocketType)
316                                 {
317                                 case SOCK_STREAM:
318                                   printf("    %d: iSocketType = SOCK_STREAM\n", i);
319                                   break;
320
321                                 case SOCK_DGRAM:
322                                   printf("    %d: iSocketType = SOCK_DGRAM\n", i);
323                                   break;
324
325                                 default:
326                                   printf("    %d: iSocketType = %d\n", i, result->lpcsaBuffer[i].iSocketType);
327                                 }
328                               switch (result->lpcsaBuffer[i].iProtocol)
329                                 {
330                                 case IPPROTO_TCP:
331                                   printf("    %d: iProtocol   = IPPROTO_TCP\n", i);
332                                   break;
333
334                                 case IPPROTO_UDP:
335                                   printf("    %d: iProtocol   = IPPROTO_UDP\n", i);
336                                   break;
337
338                                 default:
339                                   printf("    %d: iProtocol   = %d\n", i, result->lpcsaBuffer[i].iProtocol);
340                                 }
341                               switch (result->lpcsaBuffer[i].LocalAddr.lpSockaddr->sa_family)
342                                 {
343                                 case AF_INET:
344                                   printf("    %d: loc family  = AF_INET\n", i);
345                                   break;
346
347                                 case AF_INET6:
348                                   printf("    %d: loc family  = AF_INET6\n", i);
349                                   break;
350
351                                 default:
352                                   printf("    %d: loc family  = %hu\n", i, result->lpcsaBuffer[i].LocalAddr.lpSockaddr->sa_family);
353                                 }
354                               switch (result->lpcsaBuffer[i].RemoteAddr.lpSockaddr->sa_family)
355                                 {
356                                 case AF_INET:
357                                   printf("    %d: rem family  = AF_INET\n", i);
358                                   break;
359
360                                 case AF_INET6:
361                                   printf("    %d: rem family  = AF_INET6\n", i);
362                                   break;
363
364                                 default:
365                                   printf("    %d: rem family = %hu\n", i, result->lpcsaBuffer[i].RemoteAddr.lpSockaddr->sa_family);
366                                 }
367                               char buf[1024];
368                               DWORD buflen = 1024;
369                               if (NO_ERROR == WSAAddressToStringA(result->lpcsaBuffer[i].LocalAddr.lpSockaddr, result->lpcsaBuffer[i].LocalAddr.iSockaddrLength, NULL, buf, &buflen))
370                                 printf("\tLocal Address #%d: %s\n", i, buf);
371                               else
372                                 printf("\tLocal Address #%d: Can't convert: %lu\n", i, GetLastError());
373                               buflen = 1024;
374                               if (NO_ERROR == WSAAddressToStringA(result->lpcsaBuffer[i].RemoteAddr.lpSockaddr, result->lpcsaBuffer[i].RemoteAddr.iSockaddrLength, NULL, buf, &buflen))
375                                 printf("\tRemote Address #%d: %s\n", i, buf);
376                               else
377                                 printf("\tRemote Address #%d: Can't convert: %lu\n", i, GetLastError());
378                             }
379                           printf("  dwOutputFlags:           0x%08lX\n", result->dwOutputFlags);
380                           printf("  lpBlob:                  0x%p\n", result->lpBlob);
381                           if (result->lpBlob)
382                             {
383                               struct hostent *he = malloc(result->lpBlob->cbSize);
384                               if (he != NULL)
385                                 {
386                                   GNUNET_memcpy(he, result->lpBlob->pBlobData, result->lpBlob->cbSize);
387                                   UnpackHostEnt(he);
388                                   print_hostent(he);
389                                   free(he);
390                                 }
391                             }
392                         }
393                       ret = api.NSPLookupServiceEnd(lookup);
394                       if (ret != NO_ERROR)
395                         printf("NSPLookupServiceEnd() failed: %lu\n", GetLastError());
396                     }
397                   api.NSPCleanup(&prov);
398                 }
399             }
400           FreeLibrary(nsp);
401         }
402     }
403   else if (wargc == 3)
404     {
405       int s;
406       ADDRINFOW hints;
407       ADDRINFOW *result;
408       ADDRINFOW *pos;
409
410       memset(&hints, 0, sizeof(struct addrinfo));
411       hints.ai_family = AF_UNSPEC;
412       hints.ai_socktype = SOCK_STREAM;
413
414       if (0 != (s = GetAddrInfoW(wargv[2], NULL, &hints, &result)))
415         {
416           fprintf(stderr, "Cound not resolve `%S' using GetAddrInfoW: %lu\n",
417                   wargv[2], GetLastError());
418         }
419       else
420         {
421           for (pos = result; pos != NULL; pos = pos->ai_next)
422             {
423               wchar_t tmpbuf[1024];
424               DWORD buflen = 1024;
425               if (0 == WSAAddressToStringW(pos->ai_addr, pos->ai_addrlen, NULL, tmpbuf, &buflen))
426                 fprintf(stderr, "Result:\n"
427                         "  flags: 0x%X\n"
428                         "  family: 0x%X\n"
429                         "  socktype: 0x%X\n"
430                         "  protocol: 0x%X\n"
431                         "  addrlen: %u\n"
432                         "  addr: %S\n"
433                         "  canonname: %S\n",
434                         pos->ai_flags,
435                         pos->ai_family,
436                         pos->ai_socktype,
437                         pos->ai_protocol,
438                         pos->ai_addrlen,
439                         tmpbuf,
440                         pos->ai_canonname);
441               else
442                 fprintf(stderr, "Result:\n"
443                         "  flags: 0x%X\n"
444                         "  family: 0x%X\n"
445                         "  socktype: 0x%X\n"
446                         "  protocol: 0x%X\n"
447                         "  addrlen: %u\n"
448                         "  addr: %S\n"
449                         "  canonname: %S\n",
450                         pos->ai_flags,
451                         pos->ai_family,
452                         pos->ai_socktype,
453                         pos->ai_protocol,
454                         pos->ai_addrlen,
455                         L"<can't stringify>",
456                         pos->ai_canonname);
457             }
458           if (NULL != result)
459             FreeAddrInfoW(result);
460         }
461     }
462   WSACleanup();
463   return r;
464 }