Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

790 lines
22 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. str2addt.h
  5. Abstract:
  6. Code file for IP string-to-address translation routines.
  7. Author:
  8. Dave Thaler (dthaler) 3-28-2001
  9. Revision History:
  10. IPv4 conversion code originally from old winsock code
  11. IPv6 conversion code originally by Rich Draves (richdr)
  12. --*/
  13. struct in6_addr {
  14. union {
  15. UCHAR Byte[16];
  16. USHORT Word[8];
  17. } u;
  18. };
  19. #define s6_bytes u.Byte
  20. #define s6_words u.Word
  21. struct in_addr {
  22. union {
  23. struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
  24. struct { USHORT s_w1,s_w2; } S_un_w;
  25. ULONG S_addr;
  26. } S_un;
  27. };
  28. #define s_addr S_un.S_addr
  29. //
  30. // Define some versions of crt functions which are not affected by locale.
  31. //
  32. #define ISDIGIT(c) (_istascii(c) && _istdigit(c))
  33. #define ISLOWER(c) (_istascii(c) && _istlower(c))
  34. #define ISXDIGIT(c) (_istascii(c) && _istxdigit(c))
  35. #define INADDR_NONE 0xffffffff
  36. NTSTATUS
  37. RtlIpv6StringToAddressT(
  38. IN LPCTSTR S,
  39. OUT LPCTSTR *Terminator,
  40. OUT struct in6_addr *Addr
  41. )
  42. /*++
  43. Routine Description:
  44. Parses the string S as an IPv6 address. See RFC 1884.
  45. The basic string representation consists of 8 hex numbers
  46. separated by colons, with a couple embellishments:
  47. - a string of zero numbers (at most one) may be replaced
  48. with a double-colon. Double-colons are allowed at beginning/end
  49. of the string.
  50. - the last 32 bits may be represented in IPv4-style dotted-octet notation.
  51. For example,
  52. ::
  53. ::1
  54. ::157.56.138.30
  55. ::ffff:156.56.136.75
  56. ff01::
  57. ff02::2
  58. 0:1:2:3:4:5:6:7
  59. Arguments:
  60. S - RFC 1884 string representation of an IPv6 address.
  61. Terminator - Receives a pointer to the character that terminated
  62. the conversion.
  63. Addr - Receives the IPv6 address.
  64. Return Value:
  65. TRUE if parsing was successful. FALSE otherwise.
  66. --*/
  67. {
  68. enum { Start, InNumber, AfterDoubleColon } state = Start;
  69. const TCHAR *number = NULL;
  70. BOOLEAN sawHex;
  71. ULONG numColons = 0, numDots = 0, numDigits = 0;
  72. ULONG sawDoubleColon = 0;
  73. ULONG i = 0;
  74. TCHAR c;
  75. // There are a several difficulties here. For one, we don't know
  76. // when we see a double-colon how many zeroes it represents.
  77. // So we just remember where we saw it and insert the zeroes
  78. // at the end. For another, when we see the first digits
  79. // of a number we don't know if it is hex or decimal. So we
  80. // remember a pointer to the first character of the number
  81. // and convert it after we see the following character.
  82. while (c = *S) {
  83. switch (state) {
  84. case Start:
  85. if (c == _T(':')) {
  86. // this case only handles double-colon at the beginning
  87. if (numDots > 0)
  88. goto Finish;
  89. if (numColons > 0)
  90. goto Finish;
  91. if (S[1] != _T(':'))
  92. goto Finish;
  93. sawDoubleColon = 1;
  94. numColons = 2;
  95. Addr->s6_words[i++] = 0; // pretend it was 0::
  96. S++;
  97. state = AfterDoubleColon;
  98. } else
  99. case AfterDoubleColon:
  100. if (ISDIGIT(c)) {
  101. sawHex = FALSE;
  102. number = S;
  103. state = InNumber;
  104. numDigits = 1;
  105. } else if (ISXDIGIT(c)) {
  106. if (numDots > 0)
  107. goto Finish;
  108. sawHex = TRUE;
  109. number = S;
  110. state = InNumber;
  111. numDigits = 1;
  112. } else
  113. goto Finish;
  114. break;
  115. case InNumber:
  116. if (ISDIGIT(c)) {
  117. numDigits++;
  118. // remain in InNumber state
  119. } else if (ISXDIGIT(c)) {
  120. numDigits++;
  121. if (numDots > 0)
  122. goto Finish;
  123. sawHex = TRUE;
  124. // remain in InNumber state;
  125. } else if (c == _T(':')) {
  126. if (numDots > 0)
  127. goto Finish;
  128. if (numColons > 6)
  129. goto Finish;
  130. if (S[1] == _T(':')) {
  131. if (sawDoubleColon)
  132. goto Finish;
  133. if (numColons > 5)
  134. goto Finish;
  135. sawDoubleColon = numColons+1;
  136. numColons += 2;
  137. S++;
  138. state = AfterDoubleColon;
  139. } else {
  140. numColons++;
  141. state = Start;
  142. }
  143. } else if (c == _T('.')) {
  144. if (sawHex)
  145. goto Finish;
  146. if (numDots > 2)
  147. goto Finish;
  148. if (numColons > 6)
  149. goto Finish;
  150. numDots++;
  151. state = Start;
  152. } else
  153. goto Finish;
  154. break;
  155. }
  156. // If we finished a number, parse it.
  157. if ((state != InNumber) && (number != NULL)) {
  158. // Note either numDots > 0 or numColons > 0,
  159. // because something terminated the number.
  160. if (numDots == 0) {
  161. if (numDigits > 4)
  162. return STATUS_INVALID_PARAMETER;
  163. Addr->s6_words[i++] =
  164. RtlUshortByteSwap((USHORT) _tcstol(number, NULL, 16));
  165. } else {
  166. ULONG Temp;
  167. if (numDigits > 3)
  168. return STATUS_INVALID_PARAMETER;
  169. Temp = _tcstol(number, NULL, 10);
  170. if (Temp > 255)
  171. return STATUS_INVALID_PARAMETER;
  172. Addr->s6_bytes[2*i + numDots-1] = (UCHAR) Temp;
  173. }
  174. }
  175. S++;
  176. }
  177. Finish:
  178. *Terminator = S;
  179. // Check that we have a complete address.
  180. if (numDots == 0)
  181. ;
  182. else if (numDots == 3)
  183. numColons++;
  184. else
  185. return STATUS_INVALID_PARAMETER;
  186. if (sawDoubleColon)
  187. ;
  188. else if (numColons == 7)
  189. ;
  190. else
  191. return STATUS_INVALID_PARAMETER;
  192. // Parse the last number, if necessary.
  193. if (state == InNumber) {
  194. if (numDots == 0) {
  195. if (numDigits > 4)
  196. return STATUS_INVALID_PARAMETER;
  197. Addr->s6_words[i] =
  198. RtlUshortByteSwap((USHORT) _tcstol(number, NULL, 16));
  199. } else {
  200. ULONG Temp;
  201. if (numDigits > 3)
  202. return STATUS_INVALID_PARAMETER;
  203. Temp = _tcstol(number, NULL, 10);
  204. if (Temp > 255)
  205. return STATUS_INVALID_PARAMETER;
  206. Addr->s6_bytes[2*i + numDots] = (UCHAR) Temp;
  207. }
  208. } else if (state == AfterDoubleColon) {
  209. Addr->s6_words[i] = 0; // pretend it was ::0
  210. } else
  211. return STATUS_INVALID_PARAMETER;
  212. // Insert zeroes for the double-colon, if necessary.
  213. if (sawDoubleColon) {
  214. RtlMoveMemory(&Addr->s6_words[sawDoubleColon + 8 - numColons],
  215. &Addr->s6_words[sawDoubleColon],
  216. (numColons - sawDoubleColon) * sizeof(USHORT));
  217. RtlZeroMemory(&Addr->s6_words[sawDoubleColon],
  218. (8 - numColons) * sizeof(USHORT));
  219. }
  220. return STATUS_SUCCESS;
  221. }
  222. NTSTATUS
  223. RtlIpv6StringToAddressExT (
  224. IN LPCTSTR AddressString,
  225. OUT struct in6_addr *Address,
  226. OUT PULONG ScopeId,
  227. OUT PUSHORT Port
  228. )
  229. /*++
  230. Routine Description:
  231. Parsing a human-readable string to Address, port number and scope id.
  232. The syntax is address%scope-id or [address%scope-id]:port, where
  233. the scope-id and port are optional.
  234. Note that since the IPv6 address format uses a varying number
  235. of ':' characters, the IPv4 convention of address:port cannot
  236. be supported without the braces.
  237. Arguments:
  238. AddressString - Points to the zero-terminated human-readable string.
  239. Address - Receive address part (in6_addr) of this address.
  240. ScopeId - Receive scopeid of this address. If there is no scope id in
  241. the address string, 0 is returned.
  242. Port - Receive port number of this address. If there is no port number
  243. in the string, 0 is returned. Port is returned in network byte order.
  244. Return Value:
  245. NT_STATUS - STATUS_SUCCESS if successful, NT error code if not.
  246. --*/
  247. {
  248. LPTSTR Terminator;
  249. ULONG TempScopeId;
  250. USHORT TempPort;
  251. TCHAR Ch;
  252. BOOLEAN ExpectBrace;
  253. //
  254. // Quick sanity checks.
  255. //
  256. if ((AddressString == NULL) ||
  257. (Address == NULL) ||
  258. (ScopeId == NULL) ||
  259. (Port == NULL)) {
  260. return STATUS_INVALID_PARAMETER;
  261. }
  262. TempPort = 0;
  263. TempScopeId = 0;
  264. ExpectBrace = FALSE;
  265. if (*AddressString == _T('[')) {
  266. ExpectBrace = TRUE;
  267. AddressString++;
  268. }
  269. if (!NT_SUCCESS(RtlIpv6StringToAddressT(AddressString,
  270. &Terminator,
  271. Address))) {
  272. return STATUS_INVALID_PARAMETER;
  273. }
  274. //
  275. // We have parsed the address, check for a scope-id.
  276. //
  277. if (*Terminator == _T('%')) {
  278. Terminator++;
  279. Ch = *Terminator;
  280. if (!ISDIGIT(Ch)) {
  281. return STATUS_INVALID_PARAMETER;
  282. }
  283. while ((Ch != 0) && (Ch != _T(']'))) {
  284. if (!ISDIGIT(Ch)) {
  285. return STATUS_INVALID_PARAMETER;
  286. }
  287. //
  288. // first check the possibility of overflow
  289. //
  290. if (((ULONGLONG)TempScopeId * 10 + Ch - _T('0')) >
  291. 0xFFFFFFFF) {
  292. return STATUS_INVALID_PARAMETER;
  293. }
  294. TempScopeId = 10 * TempScopeId + (Ch - _T('0'));
  295. Terminator++;
  296. Ch = *Terminator;
  297. }
  298. }
  299. //
  300. // When we come here, the current char should either be the
  301. // end of the string or ']' if expectbrace is true.
  302. //
  303. if (*Terminator == _T(']')) {
  304. if (!ExpectBrace) {
  305. return STATUS_INVALID_PARAMETER;
  306. }
  307. ExpectBrace = FALSE;
  308. Terminator++;
  309. //
  310. // See if we have a port to parse.
  311. //
  312. if (*Terminator == _T(':')) {
  313. USHORT Base;
  314. Terminator++;
  315. Base = 10;
  316. if (*Terminator == _T('0')) {
  317. Base = 8;
  318. Terminator++;
  319. if ((*Terminator == _T('x')) ||
  320. (*Terminator == _T('X'))) {
  321. Base = 16;
  322. Terminator++;
  323. }
  324. }
  325. Ch = *Terminator;
  326. while (Ch != 0) {
  327. if (ISDIGIT(Ch) && (Ch - _T('0')) < Base) {
  328. //
  329. // check the possibility for overflow first
  330. //
  331. if (((ULONG)TempPort * Base + Ch - _T('0')) >
  332. 0xFFFF) {
  333. return STATUS_INVALID_PARAMETER;
  334. }
  335. TempPort = (TempPort * Base) + (Ch - _T('0'));
  336. } else if (Base == 16 && ISXDIGIT(Ch)) {
  337. //
  338. // check the possibility for overflow
  339. //
  340. if ((((ULONG)TempPort << 4) + Ch + 10 -
  341. (ISLOWER(Ch)? _T('a') : _T('A'))) > 0xFFFF) {
  342. return STATUS_INVALID_PARAMETER;
  343. }
  344. TempPort = (TempPort << 4);
  345. TempPort += Ch + 10 - (ISLOWER(Ch)? _T('a') : _T('A'));
  346. } else {
  347. return STATUS_INVALID_PARAMETER;
  348. }
  349. Terminator++;
  350. Ch = *Terminator;
  351. }
  352. }
  353. }
  354. //
  355. // We finished parsing address, scope id and port number. We are expecting the
  356. // end of the string.
  357. //
  358. if ((*Terminator != 0) || ExpectBrace) {
  359. return STATUS_INVALID_PARAMETER;
  360. }
  361. //
  362. // Now construct the address.
  363. //
  364. *Port = RtlUshortByteSwap(TempPort);
  365. *ScopeId = TempScopeId;
  366. return STATUS_SUCCESS;
  367. }
  368. NTSTATUS
  369. RtlIpv4StringToAddressT(
  370. IN LPCTSTR String,
  371. IN BOOLEAN Strict,
  372. OUT LPCTSTR *Terminator,
  373. OUT struct in_addr *Addr
  374. )
  375. /*++
  376. Routine Description:
  377. This function interprets the character string specified by the cp
  378. parameter. This string represents a numeric Internet address
  379. expressed in the Internet standard ".'' notation. The value
  380. returned is a number suitable for use as an Internet address. All
  381. Internet addresses are returned in network order (bytes ordered from
  382. left to right).
  383. Internet Addresses
  384. Values specified using the "." notation take one of the following
  385. forms:
  386. a.b.c.d a.b.c a.b a
  387. When four parts are specified, each is interpreted as a byte of data
  388. and assigned, from left to right, to the four bytes of an Internet
  389. address. Note that when an Internet address is viewed as a 32-bit
  390. integer quantity on the Intel architecture, the bytes referred to
  391. above appear as "d.c.b.a''. That is, the bytes on an Intel
  392. processor are ordered from right to left.
  393. Note: The following notations are only used by Berkeley, and nowhere
  394. else on the Internet. In the interests of compatibility with their
  395. software, they are supported as specified.
  396. When a three part address is specified, the last part is interpreted
  397. as a 16-bit quantity and placed in the right most two bytes of the
  398. network address. This makes the three part address format
  399. convenient for specifying Class B network addresses as
  400. "128.net.host''.
  401. When a two part address is specified, the last part is interpreted
  402. as a 24-bit quantity and placed in the right most three bytes of the
  403. network address. This makes the two part address format convenient
  404. for specifying Class A network addresses as "net.host''.
  405. When only one part is given, the value is stored directly in the
  406. network address without any byte rearrangement.
  407. Arguments:
  408. String - A character string representing a number expressed in the
  409. Internet standard "." notation.
  410. Strict - If TRUE, the string must be dotted-decimal with 4 parts.
  411. Otherwise, any of the four forms are allowed, with decimal,
  412. octal, or hex.
  413. Terminator - Receives a pointer to the character that terminated
  414. the conversion.
  415. Addr - Receives a pointer to the structure to fill in with
  416. a suitable binary representation of the Internet address given.
  417. Return Value:
  418. TRUE if parsing was successful. FALSE otherwise.
  419. --*/
  420. {
  421. ULONG val, n;
  422. LONG base;
  423. TCHAR c;
  424. ULONG parts[4], *pp = parts;
  425. BOOLEAN sawDigit;
  426. again:
  427. //
  428. // We must see at least one digit for address to be valid.
  429. //
  430. sawDigit=FALSE;
  431. //
  432. // Collect number up to ``.''.
  433. // Values are specified as for C:
  434. // 0x=hex, 0=octal, other=decimal.
  435. //
  436. val = 0;
  437. base = 10;
  438. if (*String == _T('0')) {
  439. String++;
  440. if (ISDIGIT(*String)) {
  441. base = 8;
  442. } else if (*String == _T('x') || *String == _T('X')) {
  443. base = 16;
  444. String++;
  445. } else {
  446. //
  447. // It is still decimal but we saw the digit
  448. // and it was 0.
  449. //
  450. sawDigit = TRUE;
  451. }
  452. }
  453. if (Strict && (base != 10)) {
  454. *Terminator = String;
  455. return STATUS_INVALID_PARAMETER;
  456. }
  457. while ((c = *String)!= 0) {
  458. ULONG newVal;
  459. if (ISDIGIT(c) && ((c - _T('0')) < base)) {
  460. newVal = (val * base) + (c - _T('0'));
  461. } else if ((base == 16) && ISXDIGIT(c)) {
  462. newVal = (val << 4) + (c + 10 - (ISLOWER(c) ? _T('a') : _T('A')));
  463. } else {
  464. break;
  465. }
  466. //
  467. // Protect from overflow
  468. //
  469. if (newVal < val) {
  470. *Terminator = String;
  471. return STATUS_INVALID_PARAMETER;
  472. }
  473. String++;
  474. sawDigit = TRUE;
  475. val = newVal;
  476. }
  477. if (*String == _T('.')) {
  478. //
  479. // Internet format:
  480. // a.b.c.d
  481. // a.b.c (with c treated as 16-bits)
  482. // a.b (with b treated as 24 bits)
  483. //
  484. if (pp >= parts + 3) {
  485. *Terminator = String;
  486. return STATUS_INVALID_PARAMETER;
  487. }
  488. *pp++ = val, String++;
  489. //
  490. // Check if we saw at least one digit.
  491. //
  492. if (!sawDigit) {
  493. *Terminator = String;
  494. return STATUS_INVALID_PARAMETER;
  495. }
  496. goto again;
  497. }
  498. //
  499. // Check if we saw at least one digit.
  500. //
  501. if (!sawDigit) {
  502. *Terminator = String;
  503. return STATUS_INVALID_PARAMETER;
  504. }
  505. *pp++ = val;
  506. //
  507. // Concoct the address according to
  508. // the number of parts specified.
  509. //
  510. n = (ULONG)(pp - parts);
  511. if (Strict && (n != 4)) {
  512. *Terminator = String;
  513. return STATUS_INVALID_PARAMETER;
  514. }
  515. switch ((int) n) {
  516. case 1: /* a -- 32 bits */
  517. val = parts[0];
  518. break;
  519. case 2: /* a.b -- 8.24 bits */
  520. if ((parts[0] > 0xff) || (parts[1] > 0xffffff)) {
  521. *Terminator = String;
  522. return STATUS_INVALID_PARAMETER;
  523. }
  524. val = (parts[0] << 24) | (parts[1] & 0xffffff);
  525. break;
  526. case 3: /* a.b.c -- 8.8.16 bits */
  527. if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
  528. (parts[2] > 0xffff)) {
  529. *Terminator = String;
  530. return STATUS_INVALID_PARAMETER;
  531. }
  532. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  533. (parts[2] & 0xffff);
  534. break;
  535. case 4: /* a.b.c.d -- 8.8.8.8 bits */
  536. if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
  537. (parts[2] > 0xff) || (parts[3] > 0xff)) {
  538. *Terminator = String;
  539. return STATUS_INVALID_PARAMETER;
  540. }
  541. val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
  542. ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
  543. break;
  544. default:
  545. *Terminator = String;
  546. return STATUS_INVALID_PARAMETER;
  547. }
  548. val = RtlUlongByteSwap(val);
  549. *Terminator = String;
  550. Addr->s_addr = val;
  551. return STATUS_SUCCESS;
  552. }
  553. NTSTATUS
  554. RtlIpv4StringToAddressExT (
  555. IN LPCTSTR AddressString,
  556. IN BOOLEAN Strict,
  557. OUT struct in_addr *Address,
  558. OUT PUSHORT Port
  559. )
  560. /*++
  561. Routine Description:
  562. Parsing a human-readable string to in_addr and port number.
  563. Arguments:
  564. AddressString - Points to the zero-terminated human-readable string.
  565. Strict - If TRUE, the address portion must be dotted-decimal with 4 parts.
  566. Otherwise, any of the four forms are allowed, with decimal,
  567. octal, or hex.
  568. Address - Receives the address (in_addr) itself.
  569. Port - Receives port number. 0 is returned if there is no port number.
  570. Port is returned in network byte order.
  571. Return Value:
  572. NTSTATUS - STATUS_SUCCESS if successful, error code if not.
  573. --*/
  574. {
  575. LPTSTR Terminator;
  576. USHORT TempPort;
  577. if ((AddressString == NULL) ||
  578. (Address == NULL) ||
  579. (Port == NULL)) {
  580. return STATUS_INVALID_PARAMETER;
  581. }
  582. if (!NT_SUCCESS(RtlIpv4StringToAddressT(AddressString,
  583. Strict,
  584. &Terminator,
  585. Address))) {
  586. return STATUS_INVALID_PARAMETER;
  587. }
  588. if (*Terminator == _T(':')) {
  589. TCHAR Ch;
  590. USHORT Base;
  591. BOOLEAN ExpectPort = TRUE;
  592. Terminator++;
  593. TempPort = 0;
  594. Base = 10;
  595. if (*Terminator == _T('0')) {
  596. Base = 8;
  597. Terminator++;
  598. if ((*Terminator == _T('x')) || (*Terminator == _T('X'))) {
  599. Base = 16;
  600. Terminator++;
  601. }
  602. }
  603. if (Ch = *Terminator) {
  604. ExpectPort = FALSE;
  605. }
  606. while (Ch = *Terminator++) {
  607. if (ISDIGIT(Ch) && (USHORT)(Ch-_T('0')) < Base) {
  608. //
  609. // Check the possibility for overflow
  610. //
  611. if (((ULONG)TempPort * Base + Ch - _T('0')) > 0xFFFF) {
  612. return STATUS_INVALID_PARAMETER;
  613. }
  614. TempPort = (TempPort * Base) + (Ch - _T('0'));
  615. } else if (Base == 16 && ISXDIGIT(Ch)) {
  616. //
  617. // Check the possibility for overflow first
  618. //
  619. if ((((ULONG)TempPort << 4) + Ch + 10 -
  620. (ISLOWER(Ch) ? _T('a') : _T('A')))
  621. > 0xFFFF) {
  622. return STATUS_INVALID_PARAMETER;
  623. }
  624. TempPort = TempPort << 4;
  625. TempPort += Ch + 10 - (ISLOWER(Ch) ? _T('a') : _T('A'));
  626. } else {
  627. return STATUS_INVALID_PARAMETER;
  628. }
  629. }
  630. if (ExpectPort) {
  631. return STATUS_INVALID_PARAMETER;
  632. }
  633. } else if (*Terminator == 0) {
  634. TempPort = 0;
  635. } else {
  636. return STATUS_INVALID_PARAMETER;
  637. }
  638. *Port = RtlUshortByteSwap(TempPort);
  639. return STATUS_SUCCESS;
  640. }