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