windows-nt/Source/XPSP1/NT/base/ntos/rtl/add2strt.h
2020-09-26 16:20:57 +08:00

213 lines
5.1 KiB
C

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
add2strt.h
Abstract:
Code for IP address-to-string translation routines.
Author:
Dave Thaler (dthaler) 3-28-2001
Revision History:
IPv6 conversion code originally by Rich Draves (richdr)
--*/
struct in6_addr {
union {
UCHAR Byte[16];
USHORT Word[8];
} u;
};
#define s6_bytes u.Byte
#define s6_words u.Word
struct in_addr {
union {
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { USHORT s_w1,s_w2; } S_un_w;
ULONG S_addr;
} S_un;
};
#define s_addr S_un.S_addr
LPTSTR
RtlIpv6AddressToStringT(
IN const struct in6_addr *Addr,
OUT LPTSTR S
)
/*++
Routine Description:
Generates an IPv6 string literal corresponding to the address Addr.
The shortened canonical forms are used (RFC 1884 etc).
The basic string representation consists of 8 hex numbers
separated by colons, with a couple embellishments:
- a string of zero numbers (at most one) is replaced
with a double-colon.
- the last 32 bits are represented in IPv4-style dotted-octet notation
if the address is a v4-compatible or ISATAP address.
For example,
::
::1
::157.56.138.30
::ffff:156.56.136.75
ff01::
ff02::2
0:1:2:3:4:5:6:7
Arguments:
S - Receives a pointer to the buffer in which to place the
string literal.
Addr - Receives the IPv6 address.
Return Value:
Pointer to the null byte at the end of the string inserted.
This can be used by the caller to easily append more information.
--*/
{
int maxFirst, maxLast;
int curFirst, curLast;
int i;
int endHex = 8;
// Check for IPv6-compatible, IPv4-mapped, and IPv4-translated
// addresses
if ((Addr->s6_words[0] == 0) && (Addr->s6_words[1] == 0) &&
(Addr->s6_words[2] == 0) && (Addr->s6_words[3] == 0) &&
(Addr->s6_words[6] != 0)) {
if ((Addr->s6_words[4] == 0) &&
((Addr->s6_words[5] == 0) || (Addr->s6_words[5] == 0xffff)))
{
// compatible or mapped
S += _stprintf(S, _T("::%hs%u.%u.%u.%u"),
Addr->s6_words[5] == 0 ? "" : "ffff:",
Addr->s6_bytes[12], Addr->s6_bytes[13],
Addr->s6_bytes[14], Addr->s6_bytes[15]);
return S;
}
else if ((Addr->s6_words[4] == 0xffff) && (Addr->s6_words[5] == 0)) {
// translated
S += _stprintf(S, _T("::ffff:0:%u.%u.%u.%u"),
Addr->s6_bytes[12], Addr->s6_bytes[13],
Addr->s6_bytes[14], Addr->s6_bytes[15]);
return S;
}
}
// Find largest contiguous substring of zeroes
// A substring is [First, Last), so it's empty if First == Last.
maxFirst = maxLast = 0;
curFirst = curLast = 0;
// ISATAP EUI64 starts with 00005EFE (or 02005EFE)...
if (((Addr->s6_words[4] & 0xfffd) == 0) && (Addr->s6_words[5] == 0xfe5e)) {
endHex = 6;
}
for (i = 0; i < endHex; i++) {
if (Addr->s6_words[i] == 0) {
// Extend current substring
curLast = i+1;
// Check if current is now largest
if (curLast - curFirst > maxLast - maxFirst) {
maxFirst = curFirst;
maxLast = curLast;
}
}
else {
// Start a new substring
curFirst = curLast = i+1;
}
}
// Ignore a substring of length 1.
if (maxLast - maxFirst <= 1)
maxFirst = maxLast = 0;
// Write colon-separated words.
// A double-colon takes the place of the longest string of zeroes.
// All zeroes is just "::".
for (i = 0; i < endHex; i++) {
// Skip over string of zeroes
if ((maxFirst <= i) && (i < maxLast)) {
S += _stprintf(S, _T("::"));
i = maxLast-1;
continue;
}
// Need colon separator if not at beginning
if ((i != 0) && (i != maxLast))
S += _stprintf(S, _T(":"));
S += _stprintf(S, _T("%x"), RtlUshortByteSwap(Addr->s6_words[i]));
}
if (endHex < 8) {
S += _stprintf(S, _T(":%u.%u.%u.%u"),
Addr->s6_bytes[12], Addr->s6_bytes[13],
Addr->s6_bytes[14], Addr->s6_bytes[15]);
}
return S;
}
LPTSTR
RtlIpv4AddressToStringT(
IN const struct in_addr *Addr,
OUT LPTSTR S
)
/*++
Routine Description:
Generates an IPv4 string literal corresponding to the address Addr.
Arguments:
S - Receives a pointer to the buffer in which to place the
string literal.
Addr - Receives the IPv4 address.
Return Value:
Pointer to the null byte at the end of the string inserted.
This can be used by the caller to easily append more information.
--*/
{
S += _stprintf(S, _T("%u.%u.%u.%u"),
( Addr->s_addr >> 0 ) & 0xFF,
( Addr->s_addr >> 8 ) & 0xFF,
( Addr->s_addr >> 16 ) & 0xFF,
( Addr->s_addr >> 24 ) & 0xFF );
return S;
}