xref: /reactos/sdk/lib/dnslib/straddr.c (revision 98e8827a)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS DNS Shared Library
4  * FILE:        lib/dnslib/straddr.c
5  * PURPOSE:     Functions for address<->string conversion.
6  */
7 
8 /* INCLUDES ******************************************************************/
9 #include "precomp.h"
10 
11 /* DATA **********************************************************************/
12 
13 /* FUNCTIONS *****************************************************************/
14 
15 LPWSTR
16 WINAPI
17 Dns_Ip6AddressToReverseName_W(OUT LPWSTR Name,
18                               IN IN6_ADDR Address)
19 {
20     /* FIXME */
21     return NULL;
22 }
23 
24 LPWSTR
25 WINAPI
26 Dns_Ip4AddressToReverseName_W(OUT LPWSTR Name,
27                               IN IN_ADDR Address)
28 {
29     /* Simply append the ARPA string */
30     return Name + (wsprintfW(Name,
31                              L"%u.%u.%u.%u.in-addr.arpa.",
32                              Address.S_un.S_addr >> 24,
33                              Address.S_un.S_addr >> 10,
34                              Address.S_un.S_addr >> 8,
35                              Address.S_un.S_addr) * sizeof(WCHAR));
36 }
37 
38 BOOLEAN
39 WINAPI
40 Dns_Ip4ReverseNameToAddress_A(OUT PIN_ADDR Address,
41                               IN LPSTR Name)
42 {
43     /* FIXME */
44     return FALSE;
45 }
46 
47 BOOLEAN
48 WINAPI
49 Dns_Ip6ReverseNameToAddress_A(OUT PIN6_ADDR Address,
50                               IN LPSTR Name)
51 {
52     /* FIXME */
53     return FALSE;
54 }
55 
56 BOOLEAN
57 WINAPI
58 Dns_Ip6StringToAddress_A(OUT PIN6_ADDR Address,
59                          IN LPSTR Name)
60 {
61     PCHAR Terminator;
62     NTSTATUS Status;
63 
64     /* Let RTL Do it for us */
65     Status = RtlIpv6StringToAddressA(Name, &Terminator, Address);
66     if (NT_SUCCESS(Status)) return TRUE;
67 
68     /* We failed */
69     return FALSE;
70 }
71 
72 BOOLEAN
73 WINAPI
74 Dns_Ip6StringToAddress_W(OUT PIN6_ADDR Address,
75                          IN LPWSTR Name)
76 {
77     PCHAR Terminator;
78     NTSTATUS Status;
79 
80     /* Let RTL Do it for us */
81     Status = RtlIpv6StringToAddressW(Name, &Terminator, Address);
82     if (NT_SUCCESS(Status)) return TRUE;
83 
84     /* We failed */
85     return FALSE;
86 }
87 
88 BOOLEAN
89 WINAPI
90 Dns_Ip4StringToAddress_A(OUT PIN_ADDR Address,
91                          IN LPSTR Name)
92 {
93     ULONG Addr;
94 
95     /* Use inet_addr to convert it... */
96     Addr = inet_addr(Name);
97     if (Addr == -1)
98     {
99         /* Check if it's the wildcard (which is ok...) */
100         if (strcmp("255.255.255.255", Name)) return FALSE;
101     }
102 
103     /* If we got here, then we suceeded... return the address */
104     Address->S_un.S_addr = Addr;
105     return TRUE;
106 }
107 
108 BOOLEAN
109 WINAPI
110 Dns_Ip4StringToAddress_W(OUT PIN_ADDR Address,
111                          IN LPWSTR Name)
112 {
113     CHAR AnsiName[16];
114     ULONG Size = sizeof(AnsiName);
115     INT ErrorCode;
116 
117     /* Make a copy of the name in ANSI */
118     ErrorCode = Dns_StringCopy(&AnsiName,
119                                &Size,
120                                Name,
121                                0,
122                                UnicodeString,
123                                AnsiString);
124     if (ErrorCode)
125     {
126         /* Copy made sucesfully, now convert it */
127         ErrorCode = Dns_Ip4StringToAddress_A(Address, AnsiName);
128     }
129 
130     /* Return either 0 bytes copied (failure == false) or conversion status */
131     return ErrorCode;
132 }
133 
134 BOOLEAN
135 WINAPI
136 Dns_Ip4ReverseNameToAddress_W(OUT PIN_ADDR Address,
137                               IN LPWSTR Name)
138 {
139     CHAR AnsiName[32];
140     ULONG Size = sizeof(AnsiName);
141     INT ErrorCode;
142 
143     /* Make a copy of the name in ANSI */
144     ErrorCode = Dns_StringCopy(&AnsiName,
145                                &Size,
146                                Name,
147                                0,
148                                UnicodeString,
149                                AnsiString);
150     if (ErrorCode)
151     {
152         /* Copy made sucesfully, now convert it */
153         ErrorCode = Dns_Ip4ReverseNameToAddress_A(Address, AnsiName);
154     }
155 
156     /* Return either 0 bytes copied (failure == false) or conversion status */
157     return ErrorCode;
158 }
159 
160 BOOLEAN
161 WINAPI
162 Dns_StringToAddressEx(OUT PVOID Address,
163                       IN OUT PULONG AddressSize,
164                       IN PVOID AddressName,
165                       IN OUT PDWORD AddressFamily,
166                       IN BOOLEAN Unicode,
167                       IN BOOLEAN Reverse)
168 {
169     DWORD Af = *AddressFamily;
170     ULONG AddrSize = *AddressSize;
171     IN6_ADDR Addr;
172     BOOLEAN Return;
173     INT ErrorCode = ERROR_SUCCESS;
174     CHAR AnsiName[INET6_ADDRSTRLEN + sizeof("ip6.arpa.")];
175     ULONG Size = sizeof(AnsiName);
176 
177     /* First check if this is a reverse address string */
178     if (Reverse)
179     {
180         /* Convert it right now to ANSI as an optimization */
181         Dns_StringCopy(AnsiName,
182                        &Size,
183                        AddressName,
184                        0,
185                        UnicodeString,
186                        AnsiString);
187 
188         /* Use the ANSI Name instead */
189         AddressName = AnsiName;
190     }
191 
192     /*
193      * If the caller doesn't know what the family is, we'll assume IPv4 and
194      * check if we failed or not. If the caller told us it's IPv4, then just
195      * do IPv4...
196      */
197     if ((Af == AF_UNSPEC) || (Af == AF_INET))
198     {
199         /* Now check if the caller gave us the reverse name or not */
200         if (Reverse)
201         {
202             /* Get the Address */
203             Return = Dns_Ip4ReverseNameToAddress_A((PIN_ADDR)&Addr, AddressName);
204         }
205         else
206         {
207             /* Check if the caller gave us unicode or not */
208             if (Unicode)
209             {
210                 /* Get the Address */
211                 Return = Dns_Ip4StringToAddress_W((PIN_ADDR)&Addr, AddressName);
212             }
213             else
214             {
215                 /* Get the Address */
216                 Return = Dns_Ip4StringToAddress_A((PIN_ADDR)&Addr, AddressName);
217             }
218         }
219 
220         /* Check if we suceeded */
221         if (Return)
222         {
223             /* Save address family */
224             Af = AF_INET;
225 
226             /* Check if the address size matches */
227             if (AddrSize < sizeof(IN_ADDR))
228             {
229                 /* Invalid match, set error code */
230                 ErrorCode = ERROR_MORE_DATA;
231             }
232             else
233             {
234                 /* It matches, save the address! */
235                 *(PIN_ADDR)Address = *(PIN_ADDR)&Addr;
236             }
237         }
238     }
239 
240     /* If we are here, either AF_INET6 was specified or IPv4 failed */
241     if ((Af == AF_UNSPEC) || (Af == AF_INET6))
242     {
243         /* Now check if the caller gave us the reverse name or not */
244         if (Reverse)
245         {
246             /* Get the Address */
247             Return = Dns_Ip6ReverseNameToAddress_A(&Addr, AddressName);
248         }
249         else
250         {
251             /* Check if the caller gave us unicode or not */
252             if (Unicode)
253             {
254                 /* Get the Address */
255                 Return = Dns_Ip6StringToAddress_W(&Addr, AddressName);
256             }
257             else
258             {
259                 /* Get the Address */
260                 Return = Dns_Ip6StringToAddress_A(&Addr, AddressName);
261             }
262         }
263 
264         /* Check if we suceeded */
265         if (Return)
266         {
267             /* Save address family */
268             Af = AF_INET6;
269 
270             /* Check if the address size matches */
271             if (AddrSize < sizeof(IN6_ADDR))
272             {
273                 /* Invalid match, set error code */
274                 ErrorCode = ERROR_MORE_DATA;
275             }
276             else
277             {
278                 /* It matches, save the address! */
279                 *(PIN6_ADDR)Address = Addr;
280             }
281         }
282     }
283     else if (Af != AF_INET)
284     {
285         /* You're like.. ATM or something? Get outta here! */
286         Af = AF_UNSPEC;
287         ErrorCode = WSA_INVALID_PARAMETER;
288     }
289 
290     /* Set error if we had one */
291     if (ErrorCode) SetLastError(ErrorCode);
292 
293     /* Return the address family and size */
294     *AddressFamily = Af;
295     *AddressSize = AddrSize;
296 
297     /* Return success or failure */
298     return (ErrorCode == ERROR_SUCCESS);
299 }
300 
301 BOOLEAN
302 WINAPI
303 Dns_StringToAddressW(OUT PVOID Address,
304                      IN OUT PULONG AddressSize,
305                      IN LPWSTR AddressName,
306                      IN OUT PDWORD AddressFamily)
307 {
308     /* Call the common API */
309     return Dns_StringToAddressEx(Address,
310                                  AddressSize,
311                                  AddressName,
312                                  AddressFamily,
313                                  TRUE,
314                                  FALSE);
315 }
316 
317 BOOLEAN
318 WINAPI
319 Dns_StringToDnsAddrEx(OUT PDNS_ADDRESS DnsAddr,
320                       IN PVOID AddressName,
321                       IN DWORD AddressFamily,
322                       IN BOOLEAN Unicode,
323                       IN BOOLEAN Reverse)
324 {
325     IN6_ADDR Addr;
326     BOOLEAN Return;
327     INT ErrorCode = ERROR_SUCCESS;
328     CHAR AnsiName[INET6_ADDRSTRLEN + sizeof("ip6.arpa.")];
329     ULONG Size = sizeof(AnsiName);
330 
331     /* First check if this is a reverse address string */
332     if ((Reverse) && (Unicode))
333     {
334         /* Convert it right now to ANSI as an optimization */
335         Dns_StringCopy(AnsiName,
336                        &Size,
337                        AddressName,
338                        0,
339                        UnicodeString,
340                        AnsiString);
341 
342         /* Use the ANSI Name instead */
343         AddressName = AnsiName;
344     }
345 
346     /*
347      * If the caller doesn't know what the family is, we'll assume IPv4 and
348      * check if we failed or not. If the caller told us it's IPv4, then just
349      * do IPv4...
350      */
351     if ((AddressFamily == AF_UNSPEC) || (AddressFamily == AF_INET))
352     {
353         /* Now check if the caller gave us the reverse name or not */
354         if (Reverse)
355         {
356             /* Get the Address */
357             Return = Dns_Ip4ReverseNameToAddress_A((PIN_ADDR)&Addr, AddressName);
358         }
359         else
360         {
361             /* Check if the caller gave us unicode or not */
362             if (Unicode)
363             {
364                 /* Get the Address */
365                 Return = Dns_Ip4StringToAddress_W((PIN_ADDR)&Addr, AddressName);
366             }
367             else
368             {
369                 /* Get the Address */
370                 Return = Dns_Ip4StringToAddress_A((PIN_ADDR)&Addr, AddressName);
371             }
372         }
373 
374         /* Check if we suceeded */
375         if (Return)
376         {
377             /* Build the IPv4 Address */
378             DnsAddr_BuildFromIp4(DnsAddr, *(PIN_ADDR)&Addr, 0);
379 
380             /* So we don't go in the code below... */
381             AddressFamily = AF_INET;
382         }
383     }
384 
385     /* If we are here, either AF_INET6 was specified or IPv4 failed */
386     if ((AddressFamily == AF_UNSPEC) || (AddressFamily == AF_INET6))
387     {
388         /* Now check if the caller gave us the reverse name or not */
389         if (Reverse)
390         {
391             /* Get the Address */
392             Return = Dns_Ip6ReverseNameToAddress_A(&Addr, AddressName);
393             if (Return)
394             {
395                 /* Build the IPv6 Address */
396                 DnsAddr_BuildFromIp6(DnsAddr, &Addr, 0, 0);
397             }
398             else
399             {
400                 goto Quickie;
401             }
402         }
403         else
404         {
405             /* Check if the caller gave us unicode or not */
406             if (Unicode)
407             {
408                 /* Get the Address */
409                 if (NT_SUCCESS(RtlIpv6StringToAddressExW(AddressName,
410                                                          &DnsAddr->Ip6Address.sin6_addr,
411                                                          &DnsAddr->Ip6Address.sin6_scope_id,
412                                                          &DnsAddr->Ip6Address.sin6_port)))
413                     Return = TRUE;
414                 else
415                     Return = FALSE;
416             }
417             else
418             {
419                 /* Get the Address */
420                 if (NT_SUCCESS(RtlIpv6StringToAddressExA(AddressName,
421                                                          &DnsAddr->Ip6Address.sin6_addr,
422                                                          &DnsAddr->Ip6Address.sin6_scope_id,
423                                                          &DnsAddr->Ip6Address.sin6_port)))
424                    Return = TRUE;
425                 else
426                    Return = FALSE;
427             }
428         }
429 
430         /* Check if we suceeded */
431         if (Return)
432         {
433             /* Finish setting up the structure */
434             DnsAddr->Ip6Address.sin6_family = AF_INET6;
435             DnsAddr->AddressLength = sizeof(SOCKADDR_IN6);
436         }
437     }
438     else if (AddressFamily != AF_INET)
439     {
440         /* You're like.. ATM or something? Get outta here! */
441         RtlZeroMemory(DnsAddr, sizeof(DNS_ADDRESS));
442         SetLastError(WSA_INVALID_PARAMETER);
443     }
444 
445 Quickie:
446     /* Return success or failure */
447     return (ErrorCode == ERROR_SUCCESS);
448 }
449 
450 BOOLEAN
451 WINAPI
452 Dns_ReverseNameToDnsAddr_W(OUT PDNS_ADDRESS DnsAddr,
453                            IN LPWSTR Name)
454 {
455     /* Call the common API */
456     return Dns_StringToDnsAddrEx(DnsAddr,
457                                  Name,
458                                  AF_UNSPEC,
459                                  TRUE,
460                                  TRUE);
461 }
462 
463