working with numeric IP addresses in IPv6 and IPv4 forms

Giganews Newsgroups
Subject: working with numeric IP addresses in IPv6 and IPv4 forms
Posted by:  jvlad (dm…@yandex.ru)
Date: Wed, 9 Feb 2011

I've got some questions regarding IPv6 support in Indy and have one issue to
report:

1) it looks like IsIP is an ipv4-only function, shouldn't it be updated to
support IPv6 too?
or be renamed to reflect the fact that it supports ipv4 only?
In latter case, what's the best way to check whether given string contains
an IP address in numeric form?

2) In my ipconfig /all output I see the following lines:

Tunnel adapter Automatic Tunneling Pseudo-Interface:

        Connection-specific DNS Suffix  . :
        Description . . . . . . . . . . . : Automatic Tunneling
Pseudo-Interface
        Dhcp Enabled. . . . . . . . . . . : No
        IP Address. . . . . . . . . . . . : fe80::5efe:192.168.2.1%2

I tried ping6 fe80::5efe:192.168.2.1%2 and it worked fine, so it is a
correct IPv6 address,
It looks like MakeCanonicalIPv6Address considers the scope (%2 in the case)
as an invalid input and returns empty string in this case (even without a
scope the returning value is wrong -- see p4 below).

3) What's the most correct way to parse an address in the user input? For
example one may enter an IPv4, IPv6 or a hostname. I'm not sure how to
distinguish the tree cases in Indy.

4) MakeCanonicalIPv6Address('fe80::5efe:192.168.2.1') returns
'FE80:0:0:0:5EFE:C0A8:0201' while in fact correct address would be
'FE80:0:0:0:0:5EFE:C0A8:0201'
(see one more zero in the middle)
I'd suggest to use the following code to parse given IPv6:
var
    hints: TAddrInfoW;
    res: PAddrInfoW;
    psa: ^TSockAddrIn6;
    hostname: array[0..NI_MAXHOST] of WideChar;
    i: integer;
    w: Word;
begin
Result := '';
fillchar(hints, sizeof(hints), 0);
hints.ai_flags := AI_NUMERICHOST or AI_NUMERICSERV;
hints.ai_family := AF_UNSPEC;
rv := getaddrinfo(PWideChar(IP), nil, @hints, @res);
if rv = 0 then begin
  if res.ai_addrlen = sizeof(TSockAddrIn6) then begin
    psa := pointer(res.ai_addr);
    s := '';
    for i := 0 to High(psa.sin6_addr.word) do begin
      w := psa.sin6_addr.word[i];
      if w = 0 then
        s := s + '0:'
      else
        s := s + Format('%0.2x%0.2x:', [Lo(w), Hi(w)]);
    end;
    delete(s, Length(s), 1); // remove last colon
    Result := s;
  end;
  freeaddrinfo(res);
end;

btw, with very little changes you can parse IPv4 too.

5) regarding the scope in the address -- I think it's an important part and
may improve performance.

Replies