IP::addr and IPv6

Did you know that all address internal to tmm are kept in IPv6 format?  If you’ve written external monitors, I’m guessing you knew this.  In the external monitors, for IPv4 networks the IPv6 “header” is removed with the line:

IP=`echo $1 | sed 's/::ffff://'`

IPv4 address are stored in what’s called “IPv4-mapped” format. An IPv4-mapped address has its first 80 bits set to zero and the next 16 set to one, followed by the 32 bits of the IPv4 address.  The prefix looks like this:

0000:0000:0000:0000:0000:ffff: (abbreviated as ::ffff:, which looks strickingly simliar—ok, identical—to the pattern stripped above)

Notation of the IPv4 section of the IPv4-formatted address vary in implementations between ::ffff:192.168.1.1 and ::ffff:c0a8:c8c8, but only the latter notation (in hex) is supported.  If you need the decimal version, you can extract it like so:

% puts $x
::ffff:c0a8:c8c8
% if { [string range $x 0 6] == "::ffff:" } {
scan [string range $x 7 end] "%2x%2x:%2x%2x" ip1 ip2 ip3 ip4
set ipv4addr "$ip1.$ip2.$ip3.$ip4"
}
192.168.200.200

Address Comparisons

The text format is not what controls whether the IP::addr command (nor the class command) does an IPv4 or IPv6 comparison. Whether or not the IP address is IPv4-mapped is what controls the comparison. The text format merely controls how the text is then translated into the internal IPv6 format (ie: whether it becomes a IPv4-mapped address or not). Normally, this is not an issue, however, if you are trying to compare an IPv6 address against an IPv4 address, then you really need to understand this mapping business.  Also, it is not recommended to use 0.0.0.0/0.0.0.0 for testing whether something is IPv4 versus IPv6 as that is not really valid a IP address—using the 0.0.0.0 mask (technically the same as /0) is a loophole and ultimately, what you are doing is loading the equivalent form of a IPv4-mapped mask. Rather, you should just use the following to test whether it is an IPv4-mapped address:

if { [IP::addr $IP1 equals ::ffff:0000:0000/96] } {  log local0. “Yep, that’s an IPv4 address” }

These notes are covered in the IP::addr wiki entry.  Any updates to the command and/or supporting notes will exist there, so keep the links handy.

 

Related Articles
Published Mar 23, 2011
Version 1.0
  • % set ip "10.10.11.70"

     

    10.10.11.70

     

    % scan $ip {%d.%d.%d.%d} a b c d

     

    4

     

    % set srcsnat "2001:111:111:22:[format %02x $a][format %02x $b]:[format %02x $c][format %02x $d]::"

     

    2001:111:111:22:0a0a:0b46::

     

     

    The leading 0's are in there, which isn't exactly what you wanted, but best to leave for IP octets that don't fit nicely in a single character.