213 lines
5.1 KiB
C
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;
|
||
|
}
|