15e4ca989a
git-svn-id: https://svn.code.sf.net/p/synalist/code/trunk@123 7c85be65-684b-0410-a082-b2ed4fbef004
423 lines
12 KiB
ObjectPascal
423 lines
12 KiB
ObjectPascal
{==============================================================================|
|
|
| Project : Ararat Synapse | 001.002.001 |
|
|
|==============================================================================|
|
|
| Content: IP address support procedures and functions |
|
|
|==============================================================================|
|
|
| Copyright (c)2006-2010, Lukas Gebauer |
|
|
| All rights reserved. |
|
|
| |
|
|
| Redistribution and use in source and binary forms, with or without |
|
|
| modification, are permitted provided that the following conditions are met: |
|
|
| |
|
|
| Redistributions of source code must retain the above copyright notice, this |
|
|
| list of conditions and the following disclaimer. |
|
|
| |
|
|
| Redistributions in binary form must reproduce the above copyright notice, |
|
|
| this list of conditions and the following disclaimer in the documentation |
|
|
| and/or other materials provided with the distribution. |
|
|
| |
|
|
| Neither the name of Lukas Gebauer nor the names of its contributors may |
|
|
| be used to endorse or promote products derived from this software without |
|
|
| specific prior written permission. |
|
|
| |
|
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
|
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
|
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
|
| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
|
|
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
|
| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
|
|
| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
|
|
| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
|
| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
|
| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
|
|
| DAMAGE. |
|
|
|==============================================================================|
|
|
| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
|
|
| Portions created by Lukas Gebauer are Copyright (c) 2006-2010. |
|
|
| All Rights Reserved. |
|
|
|==============================================================================|
|
|
| Contributor(s): |
|
|
|==============================================================================|
|
|
| History: see HISTORY.HTM from distribution package |
|
|
| (Found at URL: http://www.ararat.cz/synapse/) |
|
|
|==============================================================================}
|
|
|
|
{:@abstract(IP adress support procedures and functions)}
|
|
|
|
{$IFDEF FPC}
|
|
{$MODE DELPHI}
|
|
{$ENDIF}
|
|
{$Q-}
|
|
{$R-}
|
|
{$H+}
|
|
|
|
{$IFDEF UNICODE}
|
|
{$WARN IMPLICIT_STRING_CAST OFF}
|
|
{$WARN IMPLICIT_STRING_CAST_LOSS OFF}
|
|
{$WARN SUSPICIOUS_TYPECAST OFF}
|
|
{$ENDIF}
|
|
|
|
unit synaip;
|
|
|
|
interface
|
|
|
|
uses
|
|
SysUtils, SynaUtil;
|
|
|
|
type
|
|
{:binary form of IPv6 adress (for string conversion routines)}
|
|
TIp6Bytes = array [0..15] of Byte;
|
|
{:binary form of IPv6 adress (for string conversion routines)}
|
|
TIp6Words = array [0..7] of Word;
|
|
|
|
{:Returns @TRUE, if "Value" is a valid IPv4 address. Cannot be a symbolic Name!}
|
|
function IsIP(const Value: string): Boolean;
|
|
|
|
{:Returns @TRUE, if "Value" is a valid IPv6 address. Cannot be a symbolic Name!}
|
|
function IsIP6(const Value: string): Boolean;
|
|
|
|
{:Returns a string with the "Host" ip address converted to binary form.}
|
|
function IPToID(Host: string): Ansistring;
|
|
|
|
{:Convert IPv6 address from their string form to binary byte array.}
|
|
function StrToIp6(value: string): TIp6Bytes;
|
|
|
|
{:Convert IPv6 address from binary byte array to string form.}
|
|
function Ip6ToStr(value: TIp6Bytes): string;
|
|
|
|
{:Convert IPv4 address from their string form to binary.}
|
|
function StrToIp(value: string): integer;
|
|
|
|
{:Convert IPv4 address from binary to string form.}
|
|
function IpToStr(value: integer): string;
|
|
|
|
{:Convert IPv4 address to reverse form.}
|
|
function ReverseIP(Value: AnsiString): AnsiString;
|
|
|
|
{:Convert IPv6 address to reverse form.}
|
|
function ReverseIP6(Value: AnsiString): AnsiString;
|
|
|
|
{:Expand short form of IPv6 address to long form.}
|
|
function ExpandIP6(Value: AnsiString): AnsiString;
|
|
|
|
|
|
implementation
|
|
|
|
{==============================================================================}
|
|
|
|
function IsIP(const Value: string): Boolean;
|
|
var
|
|
TempIP: string;
|
|
function ByteIsOk(const Value: string): Boolean;
|
|
var
|
|
x, n: integer;
|
|
begin
|
|
x := StrToIntDef(Value, -1);
|
|
Result := (x >= 0) and (x < 256);
|
|
// X may be in correct range, but value still may not be correct value!
|
|
// i.e. "$80"
|
|
if Result then
|
|
for n := 1 to length(Value) do
|
|
if not (AnsiChar(Value[n]) in ['0'..'9']) then
|
|
begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
end;
|
|
begin
|
|
TempIP := Value;
|
|
Result := False;
|
|
if not ByteIsOk(Fetch(TempIP, '.')) then
|
|
Exit;
|
|
if not ByteIsOk(Fetch(TempIP, '.')) then
|
|
Exit;
|
|
if not ByteIsOk(Fetch(TempIP, '.')) then
|
|
Exit;
|
|
if ByteIsOk(TempIP) then
|
|
Result := True;
|
|
end;
|
|
|
|
{==============================================================================}
|
|
|
|
function IsIP6(const Value: string): Boolean;
|
|
var
|
|
TempIP: string;
|
|
s,t: string;
|
|
x: integer;
|
|
partcount: integer;
|
|
zerocount: integer;
|
|
First: Boolean;
|
|
begin
|
|
TempIP := Value;
|
|
Result := False;
|
|
if Value = '::' then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
partcount := 0;
|
|
zerocount := 0;
|
|
First := True;
|
|
while tempIP <> '' do
|
|
begin
|
|
s := fetch(TempIP, ':');
|
|
if not(First) and (s = '') then
|
|
Inc(zerocount);
|
|
First := False;
|
|
if zerocount > 1 then
|
|
break;
|
|
Inc(partCount);
|
|
if s = '' then
|
|
Continue;
|
|
if partCount > 8 then
|
|
break;
|
|
if tempIP = '' then
|
|
begin
|
|
t := SeparateRight(s, '%');
|
|
s := SeparateLeft(s, '%');
|
|
x := StrToIntDef('$' + t, -1);
|
|
if (x < 0) or (x > $ffff) then
|
|
break;
|
|
end;
|
|
x := StrToIntDef('$' + s, -1);
|
|
if (x < 0) or (x > $ffff) then
|
|
break;
|
|
if tempIP = '' then
|
|
if not((PartCount = 1) and (ZeroCount = 0)) then
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
{==============================================================================}
|
|
function IPToID(Host: string): Ansistring;
|
|
var
|
|
s: string;
|
|
i, x: Integer;
|
|
begin
|
|
Result := '';
|
|
for x := 0 to 3 do
|
|
begin
|
|
s := Fetch(Host, '.');
|
|
i := StrToIntDef(s, 0);
|
|
Result := Result + AnsiChar(i);
|
|
end;
|
|
end;
|
|
|
|
{==============================================================================}
|
|
|
|
function StrToIp(value: string): integer;
|
|
var
|
|
s: string;
|
|
i, x: Integer;
|
|
begin
|
|
Result := 0;
|
|
for x := 0 to 3 do
|
|
begin
|
|
s := Fetch(value, '.');
|
|
i := StrToIntDef(s, 0);
|
|
Result := (256 * Result) + i;
|
|
end;
|
|
end;
|
|
|
|
{==============================================================================}
|
|
|
|
function IpToStr(value: integer): string;
|
|
var
|
|
x1, x2: word;
|
|
y1, y2: byte;
|
|
begin
|
|
Result := '';
|
|
x1 := value shr 16;
|
|
x2 := value and $FFFF;
|
|
y1 := x1 div $100;
|
|
y2 := x1 mod $100;
|
|
Result := inttostr(y1) + '.' + inttostr(y2) + '.';
|
|
y1 := x2 div $100;
|
|
y2 := x2 mod $100;
|
|
Result := Result + inttostr(y1) + '.' + inttostr(y2);
|
|
end;
|
|
|
|
{==============================================================================}
|
|
|
|
function ExpandIP6(Value: AnsiString): AnsiString;
|
|
var
|
|
n: integer;
|
|
s: ansistring;
|
|
x: integer;
|
|
begin
|
|
Result := '';
|
|
if value = '' then
|
|
exit;
|
|
x := countofchar(value, ':');
|
|
if x > 7 then
|
|
exit;
|
|
if value[1] = ':' then
|
|
value := '0' + value;
|
|
if value[length(value)] = ':' then
|
|
value := value + '0';
|
|
x := 8 - x;
|
|
s := '';
|
|
for n := 1 to x do
|
|
s := s + ':0';
|
|
s := s + ':';
|
|
Result := replacestring(value, '::', s);
|
|
end;
|
|
{==============================================================================}
|
|
|
|
function StrToIp6(Value: string): TIp6Bytes;
|
|
var
|
|
IPv6: TIp6Words;
|
|
Index: Integer;
|
|
n: integer;
|
|
b1, b2: byte;
|
|
s: string;
|
|
x: integer;
|
|
begin
|
|
for n := 0 to 15 do
|
|
Result[n] := 0;
|
|
for n := 0 to 7 do
|
|
Ipv6[n] := 0;
|
|
Index := 0;
|
|
Value := ExpandIP6(value);
|
|
if value = '' then
|
|
exit;
|
|
while Value <> '' do
|
|
begin
|
|
if Index > 7 then
|
|
Exit;
|
|
s := fetch(value, ':');
|
|
if s = '@' then
|
|
break;
|
|
if s = '' then
|
|
begin
|
|
IPv6[Index] := 0;
|
|
end
|
|
else
|
|
begin
|
|
x := StrToIntDef('$' + s, -1);
|
|
if (x > 65535) or (x < 0) then
|
|
Exit;
|
|
IPv6[Index] := x;
|
|
end;
|
|
Inc(Index);
|
|
end;
|
|
for n := 0 to 7 do
|
|
begin
|
|
b1 := ipv6[n] div 256;
|
|
b2 := ipv6[n] mod 256;
|
|
Result[n * 2] := b1;
|
|
Result[(n * 2) + 1] := b2;
|
|
end;
|
|
end;
|
|
|
|
{==============================================================================}
|
|
//based on routine by the Free Pascal development team
|
|
function Ip6ToStr(value: TIp6Bytes): string;
|
|
var
|
|
i, x: byte;
|
|
zr1,zr2: set of byte;
|
|
zc1,zc2: byte;
|
|
have_skipped: boolean;
|
|
ip6w: TIp6words;
|
|
begin
|
|
zr1 := [];
|
|
zr2 := [];
|
|
zc1 := 0;
|
|
zc2 := 0;
|
|
for i := 0 to 7 do
|
|
begin
|
|
x := i * 2;
|
|
ip6w[i] := value[x] * 256 + value[x + 1];
|
|
if ip6w[i] = 0 then
|
|
begin
|
|
include(zr2, i);
|
|
inc(zc2);
|
|
end
|
|
else
|
|
begin
|
|
if zc1 < zc2 then
|
|
begin
|
|
zc1 := zc2;
|
|
zr1 := zr2;
|
|
zc2 := 0;
|
|
zr2 := [];
|
|
end;
|
|
end;
|
|
end;
|
|
if zc1 < zc2 then
|
|
begin
|
|
zr1 := zr2;
|
|
end;
|
|
SetLength(Result, 8*5-1);
|
|
SetLength(Result, 0);
|
|
have_skipped := false;
|
|
for i := 0 to 7 do
|
|
begin
|
|
if not(i in zr1) then
|
|
begin
|
|
if have_skipped then
|
|
begin
|
|
if Result = '' then
|
|
Result := '::'
|
|
else
|
|
Result := Result + ':';
|
|
have_skipped := false;
|
|
end;
|
|
Result := Result + IntToHex(Ip6w[i], 1) + ':';
|
|
end
|
|
else
|
|
begin
|
|
have_skipped := true;
|
|
end;
|
|
end;
|
|
if have_skipped then
|
|
if Result = '' then
|
|
Result := '::0'
|
|
else
|
|
Result := Result + ':';
|
|
|
|
if Result = '' then
|
|
Result := '::0';
|
|
if not (7 in zr1) then
|
|
SetLength(Result, Length(Result)-1);
|
|
Result := LowerCase(result);
|
|
end;
|
|
|
|
{==============================================================================}
|
|
function ReverseIP(Value: AnsiString): AnsiString;
|
|
var
|
|
x: Integer;
|
|
begin
|
|
Result := '';
|
|
repeat
|
|
x := LastDelimiter('.', Value);
|
|
Result := Result + '.' + Copy(Value, x + 1, Length(Value) - x);
|
|
Delete(Value, x, Length(Value) - x + 1);
|
|
until x < 1;
|
|
if Length(Result) > 0 then
|
|
if Result[1] = '.' then
|
|
Delete(Result, 1, 1);
|
|
end;
|
|
|
|
{==============================================================================}
|
|
function ReverseIP6(Value: AnsiString): AnsiString;
|
|
var
|
|
ip6: TIp6bytes;
|
|
n: integer;
|
|
x, y: integer;
|
|
begin
|
|
ip6 := StrToIP6(Value);
|
|
x := ip6[15] div 16;
|
|
y := ip6[15] mod 16;
|
|
Result := IntToHex(y, 1) + '.' + IntToHex(x, 1);
|
|
for n := 14 downto 0 do
|
|
begin
|
|
x := ip6[n] div 16;
|
|
y := ip6[n] mod 16;
|
|
Result := Result + '.' + IntToHex(y, 1) + '.' + IntToHex(x, 1);
|
|
end;
|
|
end;
|
|
|
|
{==============================================================================}
|
|
end.
|