-fix for #688590: allow user to specify how to install nsslibs
[oweals/gnunet.git] / src / gns / w32nsp-resolve.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file gns/w32nsp-resolve.c
22  * @brief W32 integration for GNS
23  * @author LRN
24  */
25 #define INITGUID
26 #include <windows.h>
27 #include <nspapi.h>
28 #include <ws2spi.h>
29 #include <nspapi.h>
30 #include <ws2tcpip.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 FixList(PCHAR ** List, PCHAR Base)
61 {
62     if(*List)
63     {
64         PCHAR * Addr;
65
66         Addr = *List = (PCHAR *)( ((DWORD)*List + Base) );
67         while(*Addr)
68         {
69             *Addr = (PCHAR)(((DWORD)*Addr + Base));
70             Addr++;
71         }
72     }
73 }
74
75
76 //
77 // Routine to convert a hostent returned in a BLOB to one with
78 // usable pointers. The structure is converted in-place.
79 //
80 VOID 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 void
95 print_hostent (struct hostent *he)
96 {
97   int i;
98   char **pAlias;
99   printf("\tOfficial name: %s\n", he->h_name);
100   for (pAlias = he->h_aliases; *pAlias != 0; pAlias++) {
101       printf("\tAlternate name #%d: %s\n", ++i, *pAlias);
102   }
103   printf("\tAddress type: ");
104   switch (he->h_addrtype) {
105   case AF_INET:
106       printf("AF_INET\n");
107       break;
108   case AF_INET6:
109       printf("AF_INET6\n");
110       break;
111   case AF_NETBIOS:
112       printf("AF_NETBIOS\n");
113       break;
114   default:
115       printf(" %d\n", he->h_addrtype);
116       break;
117   }
118   printf("\tAddress length: %d\n", he->h_length);
119
120   if (he->h_addrtype == AF_INET) {
121     struct sockaddr_in addr;
122     memset (&addr, 0, sizeof (addr));
123     addr.sin_family = AF_INET;
124     addr.sin_port = 0;
125     i = 0;
126     while (he->h_addr_list[i] != 0) {
127       char buf[1024];
128       DWORD buflen = 1024;
129       addr.sin_addr = *(struct in_addr *) he->h_addr_list[i++];
130       if (NO_ERROR == WSAAddressToStringA ((LPSOCKADDR) &addr, sizeof (addr), NULL, buf, &buflen))
131         printf("\tIPv4 Address #%d: %s\n", i, buf);
132       else
133         printf("\tIPv4 Address #%d: Can't convert: %lu\n", i, GetLastError ());
134     }
135   } else if (he->h_addrtype == AF_INET6) {
136     struct sockaddr_in6 addr;
137     memset (&addr, 0, sizeof (addr));
138     addr.sin6_family = AF_INET6;
139     addr.sin6_port = 0;
140     i = 0;
141     while (he->h_addr_list[i] != 0) {
142       char buf[1024];
143       DWORD buflen = 1024;
144       addr.sin6_addr = *(struct in6_addr *) he->h_addr_list[i++];
145       if (NO_ERROR == WSAAddressToStringA ((LPSOCKADDR) &addr, sizeof (addr), NULL, buf, &buflen))
146         printf("\tIPv6 Address #%d: %s\n", i, buf);
147       else
148         printf("\tIPv6 Address #%d: Can't convert: %lu\n", i, GetLastError ());
149     }
150   }
151 }
152
153 int
154 main (int argc, char **argv)
155 {
156   int ret;
157   int r = 1;
158   WSADATA wsd;
159   GUID *prov = NULL;
160   GUID *sc = NULL;
161   wchar_t *cmdl;
162   int wargc;
163   wchar_t **wargv;
164
165   if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
166   {
167     fprintf (stderr, "WSAStartup() failed: %lu\n", GetLastError());
168     return 5;
169   }
170
171   cmdl = GetCommandLineW ();
172   if (cmdl == NULL)
173   {
174     WSACleanup();
175     return 2;
176   }
177   wargv = CommandLineToArgvW (cmdl, &wargc);
178   if (wargv == NULL)
179   {
180     WSACleanup();
181     return 3;
182   }
183   r = 4;
184
185   if (wargc == 5)
186   {
187     if (wcscmp (wargv[1], L"A") == 0)
188       sc = &SVCID_DNS_TYPE_A;
189     else if (wcscmp (wargv[1], L"AAAA") == 0)
190       sc = &SVCID_DNS_TYPE_AAAA;
191     else if (wcscmp (wargv[1], L"name") == 0)
192       sc = &SVCID_HOSTNAME;
193     else if (wcscmp (wargv[1], L"addr") == 0)
194       sc = &SVCID_INET_HOSTADDRBYNAME;
195     else
196       wargc -= 1;
197     if (wcscmp (wargv[4], L"mswdns") == 0)
198       prov = &W32_DNS;
199     else if (wcscmp (wargv[4], L"gnunetdns") == 0)
200       prov = &GNUNET_NAMESPACE_PROVIDER_DNS;
201     else
202       wargc -= 1;
203   }
204
205   if (wargc == 5)
206   {
207     HMODULE nsp;
208    
209     nsp = LoadLibraryW (wargv[3]);
210     if (nsp == NULL)
211     {
212       fprintf (stderr, "Failed to load library `%S'\n", wargv[3]);
213     }
214     else
215     {
216       LPNSPSTARTUP startup = (LPNSPSTARTUP) GetProcAddress (nsp, "NSPStartup");
217       if (startup != NULL)
218       {
219         NSP_ROUTINE api;
220         ret = startup (prov, &api);
221         if (NO_ERROR != ret)
222           fprintf (stderr, "startup failed\n");
223         else
224         {
225           HANDLE lookup;
226           WSAQUERYSETW search;
227           char buf[4096];
228           WSAQUERYSETW *result = (WSAQUERYSETW *) buf;
229           DWORD resultsize;
230           DWORD err;
231           memset (&search, 0, sizeof (search));
232           search.dwSize = sizeof (search);
233           search.lpszServiceInstanceName = (wcscmp (wargv[2], L" ") == 0) ? NULL : wargv[2];
234           search.lpServiceClassId = sc;
235           search.lpNSProviderId = prov;
236           search.dwNameSpace = NS_ALL;
237           ret = api.NSPLookupServiceBegin (prov, &search, NULL, LUP_RETURN_ALL, &lookup);
238           if (ret != NO_ERROR)
239           {
240             fprintf (stderr, "lookup start failed\n");
241           }
242           else
243           {
244             resultsize = 4096;
245             ret = api.NSPLookupServiceNext (lookup, LUP_RETURN_ALL, &resultsize, result);
246             err = GetLastError ();
247             if (ret != NO_ERROR)
248             {
249               fprintf (stderr, "lookup next failed\n");
250             }
251             else
252             {
253               int i;
254               printf ("Got result:\n");
255               printf ("  lpszServiceInstanceName: %S\n", result->lpszServiceInstanceName ? result->lpszServiceInstanceName : L"NULL");
256               if (result->lpServiceClassId)
257                 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",
258                     result->lpServiceClassId->Data1, result->lpServiceClassId->Data2, result->lpServiceClassId->Data3, result->lpServiceClassId->Data4[0],
259                     result->lpServiceClassId->Data4[1], result->lpServiceClassId->Data4[2], result->lpServiceClassId->Data4[3], result->lpServiceClassId->Data4[4],
260                     result->lpServiceClassId->Data4[5], result->lpServiceClassId->Data4[6], result->lpServiceClassId->Data4[7]);
261               else
262                 printf ("  lpServiceClassId:        NULL\n");
263               if (result->lpVersion)
264                 printf ("  lpVersion:               0x%08lX, %d\n", result->lpVersion->dwVersion, result->lpVersion->ecHow);
265               else
266                 printf ("  lpVersion:               NULL\n");
267               printf ("  lpszComment:             %S\n", result->lpszComment ? result->lpszComment : L"NULL");
268               printf ("  dwNameSpace:             %lu\n", result->dwNameSpace);
269               if (result->lpNSProviderId)
270                 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",
271                     result->lpNSProviderId->Data1, result->lpNSProviderId->Data2, result->lpNSProviderId->Data3, result->lpNSProviderId->Data4[0],
272                     result->lpNSProviderId->Data4[1], result->lpNSProviderId->Data4[2], result->lpNSProviderId->Data4[3], result->lpNSProviderId->Data4[4],
273                     result->lpNSProviderId->Data4[5], result->lpNSProviderId->Data4[6], result->lpNSProviderId->Data4[7]);
274               else
275                 printf ("  lpNSProviderId:          NULL\n");
276               printf ("  lpszContext:             %S\n", result->lpszContext ? result->lpszContext : L"NULL");
277               printf ("  dwNumberOfProtocols:     %lu\n", result->dwNumberOfProtocols);
278               printf ("  lpszQueryString:         %S\n", result->lpszQueryString ? result->lpszQueryString : L"NULL");
279               printf ("  dwNumberOfCsAddrs:       %lu\n", result->dwNumberOfCsAddrs);
280               for (i = 0; i < result->dwNumberOfCsAddrs; i++)
281               {
282                 switch (result->lpcsaBuffer[i].iSocketType)
283                 {
284                 case SOCK_STREAM:
285                   printf ("    %d: iSocketType = SOCK_STREAM\n", i);
286                   break;
287                 case SOCK_DGRAM:
288                   printf ("    %d: iSocketType = SOCK_DGRAM\n", i);
289                   break;
290                 default:
291                   printf ("    %d: iSocketType = %d\n", i, result->lpcsaBuffer[i].iSocketType);
292                 }
293                 switch (result->lpcsaBuffer[i].iProtocol)
294                 {
295                 case IPPROTO_TCP:
296                   printf ("    %d: iProtocol   = IPPROTO_TCP\n", i);
297                   break;
298                 case IPPROTO_UDP:
299                   printf ("    %d: iProtocol   = IPPROTO_UDP\n", i);
300                   break;
301                 default:
302                   printf ("    %d: iProtocol   = %d\n", i, result->lpcsaBuffer[i].iProtocol);
303                 }
304                 switch (result->lpcsaBuffer[i].LocalAddr.lpSockaddr->sa_family)
305                 {
306                 case AF_INET:
307                   printf ("    %d: loc family  = AF_INET\n", i);
308                   break;
309                 case AF_INET6:
310                   printf ("    %d: loc family  = AF_INET6\n", i);
311                   break;
312                 default:
313                   printf ("    %d: loc family  = %hu\n", i, result->lpcsaBuffer[i].LocalAddr.lpSockaddr->sa_family);
314                 }
315                 switch (result->lpcsaBuffer[i].RemoteAddr.lpSockaddr->sa_family)
316                 {
317                 case AF_INET:
318                   printf ("    %d: rem family  = AF_INET\n", i);
319                   break;
320                 case AF_INET6:
321                   printf ("    %d: rem family  = AF_INET6\n", i);
322                   break;
323                 default:
324                   printf ("    %d: rem family = %hu\n", i, result->lpcsaBuffer[i].RemoteAddr.lpSockaddr->sa_family);
325                 }
326                 char buf[1024];
327                 DWORD buflen = 1024;
328                 if (NO_ERROR == WSAAddressToStringA (result->lpcsaBuffer[i].LocalAddr.lpSockaddr, result->lpcsaBuffer[i].LocalAddr.iSockaddrLength, NULL, buf, &buflen))
329                   printf("\tLocal Address #%d: %s\n", i, buf);
330                 else
331                   printf("\tLocal Address #%d: Can't convert: %lu\n", i, GetLastError ());
332                 buflen = 1024;
333                 if (NO_ERROR == WSAAddressToStringA (result->lpcsaBuffer[i].RemoteAddr.lpSockaddr, result->lpcsaBuffer[i].RemoteAddr.iSockaddrLength, NULL, buf, &buflen))
334                   printf("\tRemote Address #%d: %s\n", i, buf);
335                 else
336                   printf("\tRemote Address #%d: Can't convert: %lu\n", i, GetLastError ());
337               }
338               printf ("  dwOutputFlags:           0x%08lX\n", result->dwOutputFlags);
339               printf ("  lpBlob:                  0x%p\n", result->lpBlob);
340               if (result->lpBlob)
341               {
342                 struct hostent *he = malloc (result->lpBlob->cbSize);
343                 if (he != NULL)
344                 {
345                   memcpy (he, result->lpBlob->pBlobData, result->lpBlob->cbSize);
346                   UnpackHostEnt (he);
347                   print_hostent (he);
348                   free (he);
349                 }
350               }
351             }
352             ret = api.NSPLookupServiceEnd (lookup);
353             if (ret != NO_ERROR)
354               printf ("NSPLookupServiceEnd() failed: %lu\n", GetLastError ());
355           }
356           api.NSPCleanup (prov);
357         }
358       }
359       FreeLibrary (nsp);
360     }
361   }
362   WSACleanup();
363   return r;
364 }