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