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