1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        tcpip/address.c
5  * PURPOSE:     Routines for handling addresses
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 
11 #include "precomp.h"
12 
13 extern int sprintf( char *out, const char *fmt, ... );
14 
15 CHAR A2SStr[128];
16 
A2S(PIP_ADDRESS Address)17 PCHAR A2S(
18     PIP_ADDRESS Address)
19 /*
20  * FUNCTION: Convert an IP address to a string (for debugging)
21  * ARGUMENTS:
22  *     Address = Pointer to an IP address structure
23  * RETURNS:
24  *     Pointer to buffer with string representation of IP address
25  */
26 {
27     ULONG ip;
28     PCHAR p;
29 
30     p = A2SStr;
31 
32     if (!Address) {
33         TI_DbgPrint(MIN_TRACE, ("NULL address given.\n"));
34         strcpy(p, "(NULL)");
35         return p;
36     }
37 
38     switch (Address->Type) {
39     case IP_ADDRESS_V4:
40 	ip = DN2H(Address->Address.IPv4Address);
41 	sprintf(p, "%d.%d.%d.%d",
42 		(INT)((ip >> 24) & 0xFF),
43 		(INT)((ip >> 16) & 0xFF),
44 		(INT)((ip >> 8) & 0xFF),
45 		(INT)(ip & 0xFF));
46 	break;
47 
48     case IP_ADDRESS_V6:
49 	/* FIXME: IPv6 is not supported */
50 	strcpy(p, "(IPv6 address not supported)");
51 	break;
52     }
53     return p;
54 }
55 
IPv4NToHl(ULONG Address)56 ULONG IPv4NToHl( ULONG Address ) {
57     return
58 	((Address & 0xff) << 24) |
59 	((Address & 0xff00) << 8) |
60 	((Address >> 8) & 0xff00) |
61 	((Address >> 24) & 0xff);
62 }
63 
AddrCountPrefixBits(PIP_ADDRESS Netmask)64 UINT AddrCountPrefixBits( PIP_ADDRESS Netmask ) {
65     UINT Prefix = 0;
66     if( Netmask->Type == IP_ADDRESS_V4 ) {
67 	ULONG BitTest = 0x80000000;
68 
69 	/* The mask has been read in network order.  Put it in host order
70 	 * in order to scan it. */
71 
72 	ULONG TestMask = IPv4NToHl(Netmask->Address.IPv4Address);
73 
74 	while ((BitTest & TestMask) != 0) {
75 	    Prefix++;
76 	    BitTest >>= 1;
77 	}
78 	return Prefix;
79     } else {
80 	TI_DbgPrint(DEBUG_DATALINK, ("Don't know address type %d\n",
81 				     Netmask->Type));
82 	return 0;
83     }
84 }
85 
AddrWidenAddress(PIP_ADDRESS Network,PIP_ADDRESS Source,PIP_ADDRESS Netmask)86 VOID AddrWidenAddress( PIP_ADDRESS Network, PIP_ADDRESS Source,
87 		       PIP_ADDRESS Netmask ) {
88     if( Netmask->Type == IP_ADDRESS_V4 ) {
89         Network->Type = Netmask->Type;
90 	Network->Address.IPv4Address =
91 	    Source->Address.IPv4Address & Netmask->Address.IPv4Address;
92     } else {
93 	TI_DbgPrint(DEBUG_DATALINK, ("Don't know address type %d\n",
94 				     Netmask->Type));
95 	*Network = *Source;
96     }
97 }
98 
IPAddressFree(PVOID Object)99 VOID IPAddressFree(
100     PVOID Object)
101 /*
102  * FUNCTION: Frees an IP_ADDRESS object
103  * ARGUMENTS:
104  *     Object = Pointer to an IP address structure
105  * RETURNS:
106  *     Nothing
107  */
108 {
109     ExFreePoolWithTag(Object, IP_ADDRESS_TAG);
110 }
111 
112 
AddrIsUnspecified(PIP_ADDRESS Address)113 BOOLEAN AddrIsUnspecified(
114     PIP_ADDRESS Address)
115 /*
116  * FUNCTION: Return wether IP address is an unspecified address
117  * ARGUMENTS:
118  *     Address = Pointer to an IP address structure
119  * RETURNS:
120  *     TRUE if the IP address is an unspecified address, FALSE if not
121  */
122 {
123     switch (Address->Type) {
124         case IP_ADDRESS_V4:
125             return (Address->Address.IPv4Address == 0 ||
126                     Address->Address.IPv4Address == 0xFFFFFFFF);
127 
128         case IP_ADDRESS_V6:
129         /* FIXME: IPv6 is not supported */
130         default:
131             return FALSE;
132     }
133 }
134 
135 
136 /*
137  * FUNCTION: Extract IP address from TDI address structure
138  * ARGUMENTS:
139  *     AddrList = Pointer to transport address list to extract from
140  *     Address  = Address of a pointer to where an IP address is stored
141  *     Port     = Pointer to where port number is stored
142  *     Cache    = Address of pointer to a cached address (updated on return)
143  * RETURNS:
144  *     Status of operation
145  */
AddrGetAddress(PTRANSPORT_ADDRESS AddrList,PIP_ADDRESS Address,PUSHORT Port)146 NTSTATUS AddrGetAddress(
147     PTRANSPORT_ADDRESS AddrList,
148     PIP_ADDRESS Address,
149     PUSHORT Port)
150 {
151     PTA_ADDRESS CurAddr;
152     INT i;
153 
154     /* We can only use IP addresses. Search the list until we find one */
155     CurAddr = AddrList->Address;
156 
157     for (i = 0; i < AddrList->TAAddressCount; i++) {
158         switch (CurAddr->AddressType) {
159         case TDI_ADDRESS_TYPE_IP:
160             if (CurAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) {
161                 /* This is an IPv4 address */
162                 PTDI_ADDRESS_IP ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address;
163                 *Port = ValidAddr->sin_port;
164 		Address->Type = CurAddr->AddressType;
165 		ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address;
166 		AddrInitIPv4(Address, ValidAddr->in_addr);
167 		return STATUS_SUCCESS;
168 	    }
169 	}
170     }
171 
172     return STATUS_INVALID_ADDRESS;
173 }
174 
175 /*
176  * FUNCTION: Extract IP address from TDI address structure
177  * ARGUMENTS:
178  *     TdiAddress = Pointer to transport address list to extract from
179  *     Address    = Address of a pointer to where an IP address is stored
180  *     Port       = Pointer to where port number is stored
181  * RETURNS:
182  *     Status of operation
183  */
AddrBuildAddress(PTRANSPORT_ADDRESS TaAddress,PIP_ADDRESS Address,PUSHORT Port)184 NTSTATUS AddrBuildAddress(
185     PTRANSPORT_ADDRESS TaAddress,
186     PIP_ADDRESS Address,
187     PUSHORT Port)
188 {
189   PTDI_ADDRESS_IP ValidAddr;
190   PTA_ADDRESS TdiAddress = &TaAddress->Address[0];
191 
192   if (TdiAddress->AddressType != TDI_ADDRESS_TYPE_IP) {
193       TI_DbgPrint
194 	  (MID_TRACE,("AddressType %x, Not valid\n", TdiAddress->AddressType));
195     return STATUS_INVALID_ADDRESS;
196   }
197   if (TdiAddress->AddressLength < TDI_ADDRESS_LENGTH_IP) {
198       TI_DbgPrint
199 	  (MID_TRACE,("AddressLength %x, Not valid (expected %x)\n",
200 		      TdiAddress->AddressLength, TDI_ADDRESS_LENGTH_IP));
201       return STATUS_INVALID_ADDRESS;
202   }
203 
204 
205   ValidAddr = (PTDI_ADDRESS_IP)TdiAddress->Address;
206 
207   AddrInitIPv4(Address, ValidAddr->in_addr);
208   *Port = ValidAddr->sin_port;
209 
210   return STATUS_SUCCESS;
211 }
212 
213 /*
214  * FUNCTION: Returns wether two addresses are equal
215  * ARGUMENTS:
216  *     Address1 = Pointer to first address
217  *     Address2 = Pointer to last address
218  * RETURNS:
219  *     TRUE if Address1 = Address2, FALSE if not
220  */
AddrIsEqual(PIP_ADDRESS Address1,PIP_ADDRESS Address2)221 BOOLEAN AddrIsEqual(
222     PIP_ADDRESS Address1,
223     PIP_ADDRESS Address2)
224 {
225     if (Address1->Type != Address2->Type) {
226         DbgPrint("AddrIsEqual: Unequal Address Types\n");
227         return FALSE;
228     }
229 
230     switch (Address1->Type) {
231         case IP_ADDRESS_V4:
232             return (Address1->Address.IPv4Address == Address2->Address.IPv4Address);
233 
234         case IP_ADDRESS_V6:
235             return (RtlCompareMemory(&Address1->Address, &Address2->Address,
236                 sizeof(IPv6_RAW_ADDRESS)) == sizeof(IPv6_RAW_ADDRESS));
237             break;
238 
239         default:
240             DbgPrint("AddrIsEqual: Bad address type\n");
241             break;
242     }
243 
244     return FALSE;
245 }
246 
247 
248 /*
249  * FUNCTION: Returns wether Address1 is less than Address2
250  * ARGUMENTS:
251  *     Address1 = Pointer to first address
252  *     Address2 = Pointer to last address
253  * RETURNS:
254  *     -1 if Address1 < Address2, 1 if Address1 > Address2,
255  *     or 0 if they are equal
256  */
AddrCompare(PIP_ADDRESS Address1,PIP_ADDRESS Address2)257 INT AddrCompare(
258     PIP_ADDRESS Address1,
259     PIP_ADDRESS Address2)
260 {
261     switch (Address1->Type) {
262         case IP_ADDRESS_V4: {
263             ULONG Addr1, Addr2;
264             if (Address2->Type == IP_ADDRESS_V4) {
265                 Addr1 = DN2H(Address1->Address.IPv4Address);
266                 Addr2 = DN2H(Address2->Address.IPv4Address);
267                 if (Addr1 < Addr2)
268                     return -1;
269                 else
270                     if (Addr1 == Addr2)
271                         return 0;
272                     else
273                         return 1;
274             } else
275                 /* FIXME: Support IPv6 */
276                 return -1;
277 
278         case IP_ADDRESS_V6:
279             /* FIXME: Support IPv6 */
280         break;
281         }
282     }
283 
284     return FALSE;
285 }
286 
287 
288 /*
289  * FUNCTION: Returns wether two addresses are equal with IPv4 as input
290  * ARGUMENTS:
291  *     Address1 = Pointer to first address
292  *     Address2 = Pointer to last address
293  * RETURNS:
294  *     TRUE if Address1 = Address2, FALSE if not
295  */
AddrIsEqualIPv4(PIP_ADDRESS Address1,IPv4_RAW_ADDRESS Address2)296 BOOLEAN AddrIsEqualIPv4(
297     PIP_ADDRESS Address1,
298     IPv4_RAW_ADDRESS Address2)
299 {
300     if (Address1->Type == IP_ADDRESS_V4)
301         return (Address1->Address.IPv4Address == Address2);
302 
303     return FALSE;
304 }
305 
306 
inet_addr(const char * AddrString)307 unsigned long NTAPI inet_addr(const char *AddrString)
308 /*
309  * Convert an ansi string dotted-quad address to a ulong
310  * NOTES:
311  *     - this isn't quite like the real inet_addr() - * it doesn't
312  *       handle "10.1" and similar - but it's good enough.
313  *     - Returns in *host* byte order, unlike real inet_addr()
314  */
315 {
316 	ULONG Octets[4] = {0,0,0,0};
317 	ULONG i = 0;
318 
319 	if(!AddrString)
320 		return -1;
321 
322 	while(*AddrString)
323 		{
324 			CHAR c = *AddrString;
325 			AddrString++;
326 
327 			if(c == '.')
328 				{
329 					i++;
330 					continue;
331 				}
332 
333 			if(c < '0' || c > '9')
334 				return -1;
335 
336 			Octets[i] *= 10;
337 			Octets[i] += (c - '0');
338 
339 			if(Octets[i] > 255)
340 				return -1;
341 		}
342 
343 	return (Octets[3] << 24) + (Octets[2] << 16) + (Octets[1] << 8) + Octets[0];
344 }
345 
346 /* EOF */
347