1
0

netaddr.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. netaddr.c
  9. Abstract:
  10. This module implements support for network address and name translation.
  11. Author:
  12. Evan Green 5-Dec-2013
  13. Environment:
  14. User Mode C Library
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "libcp.h"
  20. #include <arpa/inet.h>
  21. #include <assert.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <netdb.h>
  25. #include <stdlib.h>
  26. //
  27. // ---------------------------------------------------------------- Definitions
  28. //
  29. //
  30. // Define the maximum lengths for a network address.
  31. //
  32. #define IP4_ADDRESS_STRING_SIZE sizeof("255.255.255.255")
  33. #define IP6_ADDRESS_STRING_SIZE \
  34. sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
  35. //
  36. // Define the number of 16-bit words in an IPv6 address.
  37. //
  38. #define IP6_WORD_COUNT 8
  39. //
  40. // ------------------------------------------------------ Data Type Definitions
  41. //
  42. //
  43. // ----------------------------------------------- Internal Function Prototypes
  44. //
  45. const char *
  46. ClpConvertIp4AddressToString (
  47. const unsigned char *Source,
  48. char *Destination,
  49. socklen_t Size
  50. );
  51. const char *
  52. ClpConvertIp6AddressToString (
  53. const char *Source,
  54. char *Destination,
  55. socklen_t Size
  56. );
  57. int
  58. ClpConvertIp4AddressFromString (
  59. const char *Source,
  60. struct in_addr *Destination
  61. );
  62. int
  63. ClpConvertIp6AddressFromString (
  64. const char *Source,
  65. struct in6_addr *Destination
  66. );
  67. //
  68. // -------------------------------------------------------------------- Globals
  69. //
  70. //
  71. // Define an area for the static IP4 address string buffer.
  72. //
  73. CHAR ClIp4StringBuffer[IP4_ADDRESS_STRING_SIZE];
  74. //
  75. // Define the "any" address for IPv6.
  76. //
  77. LIBC_API const struct in6_addr in6addr_any = IN6_ANY_INIT;
  78. //
  79. // Define the IPv6 loopback address.
  80. //
  81. LIBC_API const struct in6_addr in6addr_loopback = IN6_LOOPBACK_INIT;
  82. //
  83. // ------------------------------------------------------------------ Functions
  84. //
  85. LIBC_API
  86. const char *
  87. inet_ntop (
  88. int AddressFamily,
  89. const void *Source,
  90. char *Destination,
  91. socklen_t Size
  92. )
  93. /*++
  94. Routine Description:
  95. This routine converts a numeric address into a text string suitable for
  96. presentation. IPv4 addresses will be printed in standard dotted decimal
  97. form: ddd.ddd.ddd.ddd, where d is a one to three digit decimal number
  98. between 0 and 255. IPv6 addresses are represented in the form
  99. x:x:x:x:x:x:x:x, where x is the hexadecimal 16-bit piece of the address.
  100. Leading zeros may be omitted, but there shall be at least one numeral in
  101. each field. Alternatively, a string of contiguous zeros can be shown as
  102. "::". The "::" string can only appear once in an address. Unspecified
  103. addresses ("0:0:0:0:0:0:0:0") may be represented simply as "::".
  104. Arguments:
  105. AddressFamily - Supplies the address family of the source argument. Valid
  106. values are AF_INET for IPv4 and AF_INET6 for IPv6.
  107. Source - Supplies a pointer to the address structure, whose type depends
  108. on the address family parameter. For IPv4 addresses this should be a
  109. pointer to a struct in_addr, and for IPv6 addresses this should be a
  110. pointer to a struct in6_addr (not a sockaddr* structure).
  111. Destination - Supplies a pointer to a buffer where the resulting string
  112. will be written on success. This must not be NULL.
  113. Size - Supplies the size in bytes of the supplied destination buffer.
  114. Return Value:
  115. Returns the destination pointer on success.
  116. NULL on failure, and errno will be set to contain more information.
  117. --*/
  118. {
  119. const char *Result;
  120. Result = NULL;
  121. switch (AddressFamily) {
  122. case AF_INET:
  123. Result = ClpConvertIp4AddressToString(Source, Destination, Size);
  124. break;
  125. case AF_INET6:
  126. Result = ClpConvertIp6AddressToString(Source, Destination, Size);
  127. break;
  128. default:
  129. errno = EAFNOSUPPORT;
  130. break;
  131. }
  132. return Result;
  133. }
  134. LIBC_API
  135. int
  136. inet_pton (
  137. int AddressFamily,
  138. const char *Source,
  139. void *Destination
  140. )
  141. /*++
  142. Routine Description:
  143. This routine converts an address represented in text form into its
  144. corresponding binary address form. For IPv4 addresses, the text should be
  145. in the standard form ddd.ddd.ddd.ddd, where d is a one to three digit
  146. decimal number between 0 and 255. For IPv6 addresses, the text should be
  147. in the form "x:x:x:x:x:x:x:x", where x is a hexadecimal 16-bit piece
  148. of the address. Leading zeros may be omitted, but there shall be at least
  149. one numeral in each field. Alternatively, a string of contiguous zeros can
  150. be replaced with "::". The string "::" can appear only once in an address.
  151. The string "::" by itself translates to the address 0:0:0:0:0:0:0:0. As a
  152. third alternative, the address can be represented as "x:x:x:x:x:x:d.d.d.d",
  153. where x is the 16-bit hexadecimal portion of the address, and d is the
  154. decimal values of the four low-order 8-bit pieces of the address (standard
  155. IPv4 representation).
  156. Arguments:
  157. AddressFamily - Supplies the address family of the source argument. Valid
  158. values are AF_INET for IPv4 and AF_INET6 for IPv6.
  159. Source - Supplies a pointer to the null-terminated string to convert into
  160. an address.
  161. Destination - Supplies a pointer to the address structure (whose type
  162. depends on the address family parameter) where the binary form of the
  163. address will be returned on success. This should be something like a
  164. pointer to an in_addr or in6_addr, not a sockaddr structure.
  165. Return Value:
  166. 1 if the conversion succeeds.
  167. 0 if the conversion failed.
  168. -1 with errno set to EAFNOSUPPORT if the address family parameter is
  169. unrecognized.
  170. --*/
  171. {
  172. int Result;
  173. Result = -1;
  174. switch (AddressFamily) {
  175. case AF_INET:
  176. Result = ClpConvertIp4AddressFromString(Source, Destination);
  177. break;
  178. case AF_INET6:
  179. Result = ClpConvertIp6AddressFromString(Source, Destination);
  180. break;
  181. default:
  182. errno = EAFNOSUPPORT;
  183. break;
  184. }
  185. return Result;
  186. }
  187. LIBC_API
  188. in_addr_t
  189. inet_addr (
  190. const char *String
  191. )
  192. /*++
  193. Routine Description:
  194. This routine converts the given string to an integer value suitable for use
  195. as an integer address.
  196. Arguments:
  197. String - Supplies a pointer to the string to convert.
  198. Return Value:
  199. returns the IPv4 internet address associated with the string.
  200. (in_addr_t)(-1) on failure.
  201. --*/
  202. {
  203. struct in_addr IpAddress;
  204. int Result;
  205. Result = ClpConvertIp4AddressFromString(String, &IpAddress);
  206. //
  207. // Return -1 if the conversion failed.
  208. //
  209. if (Result == 0) {
  210. return (in_addr_t)-1;
  211. }
  212. return IpAddress.s_addr;
  213. }
  214. LIBC_API
  215. char *
  216. inet_ntoa (
  217. struct in_addr Address
  218. )
  219. /*++
  220. Routine Description:
  221. This routine converts the given IPv4 address into an internet standard
  222. dot notation string. This function is neither thread-safe nor reentrant.
  223. Arguments:
  224. Address - Supplies the address to convert.
  225. Return Value:
  226. Returns a pointer to the address string on success. This buffer will be
  227. overwritten on subsequent calls to this function.
  228. --*/
  229. {
  230. const char *Result;
  231. Result = ClpConvertIp4AddressToString(
  232. (const unsigned char *)&(Address.s_addr),
  233. ClIp4StringBuffer,
  234. sizeof(ClIp4StringBuffer));
  235. return (char *)Result;
  236. }
  237. LIBC_API
  238. int
  239. inet_aton (
  240. const char *String,
  241. struct in_addr *Address
  242. )
  243. /*++
  244. Routine Description:
  245. This routine converts the given string to an interger value suitable for
  246. use as an IPv4 address.
  247. Arguments:
  248. String - Supplies a pointer to the string to convert.
  249. Address - Supplies a pointer that receives the converted IPv4 address.
  250. Return Value:
  251. Returns non-zero if the address string is valid.
  252. 0 if the address string is invalid.
  253. --*/
  254. {
  255. return ClpConvertIp4AddressFromString(String, Address);
  256. }
  257. //
  258. // --------------------------------------------------------- Internal Functions
  259. //
  260. const char *
  261. ClpConvertIp4AddressToString (
  262. const unsigned char *Source,
  263. char *Destination,
  264. socklen_t Size
  265. )
  266. /*++
  267. Routine Description:
  268. This routine converts an IPv4 address to a string, which will be printed in
  269. standard dotted decimal form: ddd.ddd.ddd.ddd, where d is a one to three
  270. digit decimal number between 0 and 255.
  271. Arguments:
  272. Source - Supplies a pointer to the source IPv4 address.
  273. Destination - Supplies a pointer to a buffer where the resulting string
  274. will be written on success. This must not be NULL.
  275. Size - Supplies the size in bytes of the supplied destination buffer.
  276. Return Value:
  277. Returns the destination pointer on success.
  278. NULL on failure, and errno will be set to contain more information.
  279. --*/
  280. {
  281. size_t Length;
  282. CHAR WorkingBuffer[IP4_ADDRESS_STRING_SIZE];
  283. snprintf(WorkingBuffer,
  284. IP4_ADDRESS_STRING_SIZE,
  285. "%d.%d.%d.%d",
  286. Source[0],
  287. Source[1],
  288. Source[2],
  289. Source[3]);
  290. Length = strlen(WorkingBuffer);
  291. if (Length >= Size) {
  292. errno = ENOSPC;
  293. return NULL;
  294. }
  295. strcpy(Destination, WorkingBuffer);
  296. return Destination;
  297. }
  298. const char *
  299. ClpConvertIp6AddressToString (
  300. const char *Source,
  301. char *Destination,
  302. socklen_t Size
  303. )
  304. /*++
  305. Routine Description:
  306. This routine converts a numeric IPv6 address into a text string suitable for
  307. for presentation. IPv6 addresses are represented in the form
  308. x:x:x:x:x:x:x:x, where x is the hexadecimal 16-bit piece of the address.
  309. Leading zeros may be omitted, but there shall be at least one numeral in
  310. each field. Alternatively, a string of contiguous zeros can be shown as
  311. "::". The "::" string can only appear once in an address. Unspecified
  312. addresses ("0:0:0:0:0:0:0:0") may be represented simply as "::".
  313. Arguments:
  314. AddressFamily - Supplies the address family of the source argument. Valid
  315. values are AF_INET for IPv4 and AF_INET6 for IPv6.
  316. Source - Supplies a pointer to the IPv6 address.
  317. Destination - Supplies a pointer to a buffer where the resulting string
  318. will be written on success. This must not be NULL.
  319. Size - Supplies the size in bytes of the supplied destination buffer.
  320. Return Value:
  321. Returns the destination pointer on success.
  322. NULL on failure, and errno will be set to contain more information.
  323. --*/
  324. {
  325. LONG CurrentRun;
  326. LONG CurrentRunSize;
  327. PSTR String;
  328. UINTN StringSize;
  329. LONG WinnerRun;
  330. LONG WinnerRunSize;
  331. ULONG WordIndex;
  332. USHORT Words[IP6_WORD_COUNT];
  333. CHAR WorkingString[IP6_ADDRESS_STRING_SIZE];
  334. //
  335. // Copy the address into its word array.
  336. //
  337. for (WordIndex = 0; WordIndex < IP6_WORD_COUNT; WordIndex += 1) {
  338. Words[WordIndex] = (((UCHAR)Source[WordIndex * 2]) << 8) |
  339. (UCHAR)Source[(WordIndex * 2) + 1];
  340. }
  341. //
  342. // Find the longest run of zeroes in the array. This makes for a nice
  343. // interview question.
  344. //
  345. WinnerRun = -1;
  346. WinnerRunSize = 0;
  347. CurrentRun = -1;
  348. CurrentRunSize = 0;
  349. for (WordIndex = 0; WordIndex < IP6_WORD_COUNT; WordIndex += 1) {
  350. //
  351. // If a zero is found, start or update the current run.
  352. //
  353. if (Words[WordIndex] == 0) {
  354. if (CurrentRun == -1) {
  355. CurrentRun = WordIndex;
  356. CurrentRunSize = 1;
  357. } else {
  358. CurrentRunSize += 1;
  359. }
  360. //
  361. // Keep the max up to date as well.
  362. //
  363. if (CurrentRunSize > WinnerRunSize) {
  364. WinnerRun = CurrentRun;
  365. WinnerRunSize = CurrentRunSize;
  366. }
  367. //
  368. // The run is broken.
  369. //
  370. } else {
  371. CurrentRun = -1;
  372. CurrentRunSize = 0;
  373. }
  374. }
  375. //
  376. // Print the formatted string.
  377. //
  378. String = WorkingString;
  379. for (WordIndex = 0; WordIndex < IP6_WORD_COUNT; WordIndex += 1) {
  380. //
  381. // Represent the run of zeros with a single extra colon (so it looks
  382. // like "::").
  383. //
  384. if ((WinnerRun != -1) && (WordIndex >= WinnerRun) &&
  385. (WordIndex < (WinnerRun + WinnerRunSize))) {
  386. if (WordIndex == WinnerRun) {
  387. *String = ':';
  388. String += 1;
  389. }
  390. continue;
  391. }
  392. //
  393. // Every number is preceded by a colon except the first.
  394. //
  395. if (WordIndex != 0) {
  396. *String = ':';
  397. String += 1;
  398. }
  399. //
  400. // Potentially print an encapsulated IPv4 address.
  401. //
  402. if ((WordIndex == 6) && (WinnerRun == 0) &&
  403. ((WinnerRunSize == 6) ||
  404. ((WinnerRunSize == 5) && (Words[5] == 0xFFFF)))) {
  405. ClpConvertIp4AddressToString((const unsigned char *)(Source + 12),
  406. String,
  407. IP4_ADDRESS_STRING_SIZE);
  408. String += strlen(String);
  409. break;
  410. }
  411. String += snprintf(String, 5, "%x", Words[WordIndex]);
  412. }
  413. //
  414. // If the winning run of zeros goes to the end, then a final extra colon
  415. // is needed since the lower half of the preceding loop never got a chance
  416. // to run.
  417. //
  418. if ((WinnerRun != -1) && ((WinnerRun + WinnerRunSize) == IP6_WORD_COUNT)) {
  419. *String = ':';
  420. String += 1;
  421. }
  422. //
  423. // Null terminate the string.
  424. //
  425. *String = '\0';
  426. String += 1;
  427. StringSize = (UINTN)String - (UINTN)WorkingString;
  428. assert(StringSize <= IP6_ADDRESS_STRING_SIZE);
  429. if (Size < StringSize) {
  430. errno = ENOSPC;
  431. return NULL;
  432. }
  433. strcpy(Destination, WorkingString);
  434. return Destination;
  435. }
  436. int
  437. ClpConvertIp4AddressFromString (
  438. const char *Source,
  439. struct in_addr *Destination
  440. )
  441. /*++
  442. Routine Description:
  443. This routine converts an address represented in text form into its
  444. corresponding binary address form. For IPv4 addresses, the text should be
  445. in the standard form ddd.ddd.ddd.ddd, where d is a one to three digit
  446. decimal number between 0 and 255.
  447. Arguments:
  448. Source - Supplies a pointer to the null-terminated string to convert into
  449. an address.
  450. Destination - Supplies a pointer to the address structure where the binary
  451. form of the address will be returned on success.
  452. Return Value:
  453. 1 if the conversion succeeds.
  454. 0 if the conversion failed.
  455. --*/
  456. {
  457. PSTR AfterScan;
  458. PSTR CurrentString;
  459. ULONG Integer;
  460. ULONG IpAddress;
  461. ULONG Shift;
  462. CurrentString = (PSTR)Source;
  463. IpAddress = 0;
  464. Shift = 24;
  465. while (TRUE) {
  466. Integer = strtoul(CurrentString, &AfterScan, 0);
  467. if (AfterScan == CurrentString) {
  468. return 0;
  469. }
  470. CurrentString = AfterScan;
  471. if (*CurrentString == '\0') {
  472. IpAddress |= Integer;
  473. break;
  474. }
  475. if (*CurrentString == '.') {
  476. if (Integer > 255) {
  477. return 0;
  478. }
  479. IpAddress |= Integer << Shift;
  480. if (Shift >= BITS_PER_BYTE) {
  481. Shift -= BITS_PER_BYTE;
  482. }
  483. CurrentString += 1;
  484. //
  485. // Some funky character up in here.
  486. //
  487. } else {
  488. return 0;
  489. }
  490. }
  491. Destination->s_addr = htonl(IpAddress);
  492. return 1;
  493. }
  494. int
  495. ClpConvertIp6AddressFromString (
  496. const char *Source,
  497. struct in6_addr *Destination
  498. )
  499. /*++
  500. Routine Description:
  501. This routine converts an address represented in text form into its
  502. corresponding binary address form. For IPv6 addresses, the text should be
  503. in the form "x:x:x:x:x:x:x:x:x", where x is a hexadecimal 16-bit piece
  504. of the address. Leading zeros may be omitted, but there shall be at least
  505. one numeral in each field. Alternatively, a string of contiguous zeros can
  506. be replaced with "::". The string "::" can appear only once in an address.
  507. The string "::" by itself translates to the address 0:0:0:0:0:0:0:0. As a
  508. third alternative, the address can be represented as "x:x:x:x:x:x:d.d.d.d",
  509. where x is the 16-bit hexadecimal portion of the address, and d is the
  510. decimal values of the four low-order 8-bit pieces of the address (standard
  511. IPv4 representation).
  512. Arguments:
  513. Source - Supplies a pointer to the null-terminated string to convert into
  514. an address.
  515. Destination - Supplies a pointer to the address structure where the binary
  516. form of the address will be returned on success.
  517. Return Value:
  518. 1 if the conversion succeeds.
  519. 0 if the conversion failed.
  520. --*/
  521. {
  522. PSTR AfterScan;
  523. ULONG DestinationIndex;
  524. ULONG Integer;
  525. struct in_addr *Ip4Address;
  526. ULONG PrefixLength;
  527. int Result;
  528. const char *String;
  529. CHAR Suffix[16];
  530. ULONG SuffixIndex;
  531. ULONG SuffixLength;
  532. PrefixLength = 0;
  533. String = Source;
  534. SuffixLength = 0;
  535. memset(Destination, 0, sizeof(struct in6_addr));
  536. memset(Suffix, 0, sizeof(Suffix));
  537. //
  538. // Scan things in directly as long as a double colon was not found.
  539. //
  540. while (TRUE) {
  541. if (*String == ':') {
  542. String += 1;
  543. //
  544. // Break out of this loop if a double colon was found.
  545. //
  546. if (*String == ':') {
  547. String += 1;
  548. break;
  549. }
  550. }
  551. Integer = strtoul(String, &AfterScan, 16);
  552. if (AfterScan == String) {
  553. return 0;
  554. }
  555. //
  556. // The last 4 bytes may be written as an IPv4 address.
  557. //
  558. if ((PrefixLength == 12) && (*AfterScan == '.')) {
  559. Ip4Address = (struct in_addr *)&(Destination->s6_addr[12]);
  560. Result = ClpConvertIp4AddressFromString(String, Ip4Address);
  561. String += strlen(String);
  562. goto ConvertIp6AddressFromStringEnd;
  563. }
  564. Destination->s6_addr[PrefixLength] = Integer >> BITS_PER_BYTE;
  565. PrefixLength += 1;
  566. Destination->s6_addr[PrefixLength] = Integer & 0xFF;
  567. PrefixLength += 1;
  568. String = AfterScan;
  569. if (PrefixLength == 16) {
  570. goto ConvertIp6AddressFromStringEnd;
  571. }
  572. }
  573. //
  574. // Scan in the remainder after a double colon.
  575. //
  576. while (TRUE) {
  577. if (*String == ':') {
  578. if (SuffixLength == 0) {
  579. break;
  580. }
  581. String += 1;
  582. } else if (SuffixLength != 0) {
  583. break;
  584. }
  585. Integer = strtoul(String, &AfterScan, 16);
  586. if (AfterScan == String) {
  587. break;
  588. }
  589. if (((SuffixLength + PrefixLength) <= 12) && (*AfterScan == '.')) {
  590. Ip4Address = (struct in_addr *)&(Suffix[SuffixLength]);
  591. Result = ClpConvertIp4AddressFromString(String, Ip4Address);
  592. if (Result == 0) {
  593. return 0;
  594. }
  595. SuffixLength += 4;
  596. String += strlen(String);
  597. break;
  598. }
  599. Suffix[SuffixLength] = Integer >> BITS_PER_BYTE;
  600. SuffixLength += 1;
  601. Suffix[SuffixLength] = Integer & 0xFF;
  602. SuffixLength += 1;
  603. String = AfterScan;
  604. if (PrefixLength + SuffixLength >= 16) {
  605. break;
  606. }
  607. }
  608. //
  609. // Now that the suffix length is known, copy it into the destination.
  610. //
  611. for (SuffixIndex = 0; SuffixIndex < SuffixLength; SuffixIndex += 1) {
  612. DestinationIndex = 16 - SuffixLength + SuffixIndex;
  613. Destination->s6_addr[DestinationIndex] = Suffix[SuffixIndex];
  614. }
  615. ConvertIp6AddressFromStringEnd:
  616. //
  617. // Allow a % at the end, but otherwise it's an error for the string not to
  618. // be completely used up.
  619. //
  620. if (*String != '\0') {
  621. if (*String != '%') {
  622. return 0;
  623. }
  624. }
  625. return 1;
  626. }