我正在寻找一种在 Delphi 中验证和操作 IP 地址的方法。它应该能够做的一些事情是......
String
或 Array[0..3] of Byte
基本原因是,我想在继续重新发明它们之前看看这些东西是否已经存在。
我还曾经编写过一个IPv4 和 IPv6 转换单元,其中包括针对这两种类型的 IP 地址的自定义变体类型。 这个答案展示了其功能的一些示例。最初,它的设计目的是在某些滑块控件1)上按比例可视化各种类型的值。当时的要求是默认的现有库是不够的,但我同意这里的评论,你可能会得到印地(10!)或类似的帮助。
用该单元的一些代码片段回答您的问题列表:
Q4:IP 类型的存储类型:
const
IPv4BitSize = SizeOf(Byte) * 4 * 8;
IPv6BitSize = SizeOf(Word) * 8 * 8;
type
T4 = 0..3;
T8 = 0..7;
TIPv4ByteArray = array[T4] of Byte;
TIPv6WordArray = array[T8] of Word;
TIPv4 = packed record
case Integer of
0: (D, C, B, A: Byte);
1: (Groups: TIPv4ByteArray);
2: (Value: Cardinal);
end;
TIPv6 = packed record
case Integer of
0: (H, G, F, E, D, C, B, A: Word);
1: (Groups: TIPv6WordArray);
end;
Q5:将 IP 地址字符串转换为这些记录或数组类型:
function StrToIPv4(const S: String): TIPv4;
var
SIP: String;
Start: Integer;
I: T4;
Index: Integer;
Count: Integer;
SGroup: String;
G: Integer;
begin
SIP := S + '.';
Start := 1;
for I := High(T4) downto Low(T4) do
begin
Index := PosEx('.', SIP, Start);
if Index = 0 then
IPv4ErrorFmt(SInvalidIPv4Value, S);
Count := Index - Start + 1;
SGroup := Copy(SIP, Start, Count - 1);
if TryStrToInt(SGroup, G) and (G >= Low(Word)) and (G <= High(Word)) then
Result.Groups[I] := G
else
Result.Groups[I] := 0;
Inc(Start, Count);
end;
end;
function StrToIPv6(const S: String): TIPv6;
{ Valid examples for S:
2001:0db8:85a3:0000:0000:8a2e:0370:7334
2001:db8:85a3:0:0:8a2e:370:7334
2001:db8:85a3::8a2e:370:7334
::8a2e:370:7334
2001:db8:85a3::
::1
::
::ffff:c000:280
::ffff:192.0.2.128 }
var
ZeroPos: Integer;
DotPos: Integer;
SIP: String;
Start: Integer;
Index: Integer;
Count: Integer;
SGroup: String;
G: Integer;
procedure NormalNotation;
var
I: T8;
begin
SIP := S + ':';
Start := 1;
for I := High(T8) downto Low(T8) do
begin
Index := PosEx(':', SIP, Start);
if Index = 0 then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Count := Index - Start + 1;
SGroup := '$' + Copy(SIP, Start, Count - 1);
if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Result.Groups[I] := G;
Inc(Start, Count);
end;
end;
procedure CompressedNotation;
var
I: T8;
A: array of Word;
begin
SIP := S + ':';
Start := 1;
I := High(T8);
while Start < ZeroPos do
begin
Index := PosEx(':', SIP, Start);
if Index = 0 then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Count := Index - Start + 1;
SGroup := '$' + Copy(SIP, Start, Count - 1);
if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Result.Groups[I] := G;
Inc(Start, Count);
Dec(I);
end;
FillChar(Result.H, (I + 1) * SizeOf(Word), 0);
if ZeroPos < (Length(S) - 1) then
begin
SetLength(A, I + 1);
Start := ZeroPos + 2;
repeat
Index := PosEx(':', SIP, Start);
if Index > 0 then
begin
Count := Index - Start + 1;
SGroup := '$' + Copy(SIP, Start, Count - 1);
if not TryStrToInt(SGroup, G) or (G > High(Word)) or (G < 0) then
IPv6ErrorFmt(SInvalidIPv6Value, S);
A[I] := G;
Inc(Start, Count);
Dec(I);
end;
until Index = 0;
Inc(I);
Count := Length(A) - I;
Move(A[I], Result.H, Count * SizeOf(Word));
end;
end;
procedure DottedQuadNotation;
var
I: T4;
begin
if UpperCase(Copy(S, ZeroPos + 2, 4)) <> 'FFFF' then
IPv6ErrorFmt(SInvalidIPv6Value, S);
FillChar(Result.E, 5 * SizeOf(Word), 0);
Result.F := $FFFF;
SIP := S + '.';
Start := ZeroPos + 7;
for I := Low(T4) to High(T4) do
begin
Index := PosEx('.', SIP, Start);
if Index = 0 then
IPv6ErrorFmt(SInvalidIPv6Value, S);
Count := Index - Start + 1;
SGroup := Copy(SIP, Start, Count - 1);
if not TryStrToInt(SGroup, G) or (G > High(Byte)) or (G < 0) then
IPv6ErrorFmt(SInvalidIPv6Value, S);
case I of
0: Result.G := G shl 8;
1: Inc(Result.G, G);
2: Result.H := G shl 8;
3: Inc(Result.H, G);
end;
Inc(Start, Count);
end;
end;
begin
ZeroPos := Pos('::', S);
if ZeroPos = 0 then
NormalNotation
else
begin
DotPos := Pos('.', S);
if DotPos = 0 then
CompressedNotation
else
DottedQuadNotation;
end;
end;
对于 Q1 到 Q3,你必须自己导出一些例程,但这应该没有任何问题。
我已经编写了您需要的所有功能,但恐怕我无法分享代码。
但是,Synapse库在synaip单元中包含相当多的函数。例如
function IsIP(const Value: string): Boolean;
function IsIP6(const Value: string): Boolean;
function IPToID(Host: string): Ansistring;
function StrToIp6(value: string): TIp6Bytes;
function Ip6ToStr(value: TIp6Bytes): string;
function StrToIp(value: string): integer;
function IpToStr(value: integer): string;
function ReverseIP(Value: AnsiString): AnsiString;
function ReverseIP6(Value: AnsiString): AnsiString;
几年前我尝试这些功能时,IPv6 功能有点错误,尤其是在处理压缩的 IPv6 地址时。
如果你想自己动手,这里有一些建议:
如果您有任何具体问题,我也可以尝试回答。
{*************************************************************************** }
{
{ Outils pour les adresses IPv6 et IPv4 (2024)
{
{ *************************************************************************** }
unit MyIPUtils;
interface
uses
Types;
type
TIPVersion = (_IPv4, _IPv6);
TIPData = record
case Integer of
0 : (B : packed array[0..3] of Byte); // Lo - > Hi
1 : (W : packed array[0..7] of Word);
2 : (Value: Cardinal); // IPv4
end;
TIP = record
private
FIPVersion: TIPVersion;
Data : TIPData;
FErr : Word;
function Get(Index: Integer): Word;
procedure Put(Index: Integer; Value: Word);
public
class operator Implicit(const a : UInt64) : TIP;
class operator Implicit(const a : String) : TIP;
class operator Implicit(const a : TIP) : String;
class operator Explicit(const a : TIP) : String;
class operator Equal(const a, b: TIP): Boolean;
class operator NotEqual(const a, b: TIP): Boolean;
class operator LogicalNot(const a: TIP): TIP;
class operator GreaterThan(const a, b: TIP): Boolean;
class operator GreaterThanOrEqual(const a, b: TIP): Boolean;
class operator LessThan(const a, b: TIP): Boolean;
class operator LessThanOrEqual(const a, b: TIP): Boolean;
class operator LeftShift(a: TIP; b: LongWord): TIP;
class operator RightShift(a: TIP; b: LongWord): TIP;
class operator LogicalAnd(a, b: TIP): TIP;
class operator LogicalOr(a, b: TIP): TIP;
class operator LogicalXor(a, b: TIP): TIP;
class operator BitwiseAnd(a, b: TIP): TIP;
class operator BitwiseOr(a, b: TIP): TIP;
class operator BitwiseXor(a, b: TIP): TIP;
procedure Clear(aErr: Word = 0);
procedure CheckMask(BitsCount: Word);
procedure SetIPVersion(IPv: TIPVersion);
property Err: Word read FErr;
property Items[Index: Integer]: Word read Get write Put; default;
property IPVersion: TIPVersion read FIPVersion write FIPVersion;
end;
function MakeMask(BitsCount: Word; IPVersion: TIPVersion): TIP; overload;
function IsBetween(const Lo, Hi, Val: TIP): Boolean;
function CmpVersion(const a, b: TIP): TValueRelationship;
function IPCmp(a, b: TIP): TValueRelationship;
function IsIPCIDR(AddrStr, MaskStr: WideString): Boolean;
function IsValidIP(const IP: TIP): Boolean;
function StrToIPv4(AIP: String): TIP;
function StrToIPv6(AIP: String): TIP;
function IpV4StrToInt(MyIP: PAnsiChar): LongWord;
implementation
uses
SysUtils,
MyWideStr;
const
LenIPs : array[TIPVersion] of integer = (4, 8); // 4 octets ou 8 word
SeparIP : array[TIPVersion] of Char = ('.', ':');
resourcestring
SInvalidIPv4Value = 'IPV4 conversion not possible.';
SInvalidIPv6Value = 'IPV6 conversion not possible.';
type
EIPError = class(Exception);
procedure IPErrorFmt(ResString: string; const Arg: String); local;
begin
raise EIPError.CreateFmt(ResString, [Arg]);
end;
function CmpWord(a, b: Word): TValueRelationship;
begin
if (a <= b) then
if (a < b) then Result := LessThanValue
else Result := EqualsValue
else Result := GreaterThanValue;
end;
function CmpVersion(const a, b: TIP): TValueRelationship;
begin
if (a.IPVersion <= b.IPVersion) then
if (a.IPVersion < b.IPVersion) then Result := LessThanValue
else Result := EqualsValue
else Result := GreaterThanValue;
end;
function IPCmp(a, b: TIP): TValueRelationship;
var
i : integer;
begin
if (a.IPVersion <> b.IPVersion) then begin
a.IPVersion := _IPv6;
b.IPVersion := _IPv6;
end;
for i := LenIPs[a.IPVersion] - 1 downto 0 do begin
Result := CmpWord(a[i], b[i]);
if (Result <> EqualsValue) then // On ne compare pas tout
Break;
end;
end;
function IsBetween(const Lo, Hi, Val: TIP): Boolean;
begin
Result := (Lo <= Val) and (Val <= Hi);
end;
// https://www.it-connect.fr/adresses-ipv4-et-le-calcul-des-masques-de-sous-reseaux/
// https://www.formip.com/pages/blog/type-dadresse-ipv6-et-eui-64
function IsIPCIDR(AddrStr, MaskStr: WideString): Boolean;
var
LeftStr, S : String;
BitsCount: Word;
Err: Integer;
Addr,
Left,
Mask : TIP;
begin
// L'adresse est de ce style 192.168.5.3/24
S := MaskStr; BitsCount := 0; Err := 0;
LeftStr := Fetch(S, '/');
if (Length(S) > 0)then begin
Val(S, BitsCount, Err); // Si erreur de syntaxe dans le Masque
// L'erreur de bitcount sera vérifié dans MakeMask
end;
Addr := AddrStr;
Left := LeftStr;
if (BitsCount = 0) then // Pas de masque
Result := (Addr = Left) and (Err = 0)
else begin
Mask := MakeMask(BitsCount, Left.IPVersion); // IPv4 ou IPv6
Result := IsBetween(Left and Mask, Left or not Mask, Addr) and (Mask.FErr = 0) and (Err = 0);
end;
end;
procedure TIP.Clear(aErr: Word = 0);
begin
FErr := aErr;
FillChar(Data.W, SizeOf(Data.W), 0);
end;
function IsValidIP(const IP: TIP): Boolean;
begin
Result := IP.FErr = 0;
end;
function TIP.Get(Index: Integer): Word;
begin
case IPVersion of
_IPv4 : Result := Data.B[Index];
_IPv6 : Result := Data.W[Index];
end;
end;
procedure TIP.Put(Index: Integer; Value: Word);
begin
case IPVersion of
_IPv4 : Data.B[Index] := Value;
_IPv6 : Data.W[Index] := Value;
end;
end;
{ // Version poids faibles (pas la norme)
function MakeMask(a: Word; IPVersion: TIPVersion): TIP;
var
b : TIP;
i : integer;
begin
b.IPVersion := IPVersion;
Clear(b); Result := b;
for i := 0 to a - 1 do
Result := (Result shl 1) or 1;
end;
}
{
// https://www.it-connect.fr/adresses-ipv4-et-le-calcul-des-masques-de-sous-reseaux/
Le masque est sur les poids. Exemple IPV4
Classe A : 255.0.0.0 soit /8
Classe B : 255.255.0.0 soit /16
Classe C : 255.255.255.0 soit /24
}
function MakeMask(BitsCount: Word; IPVersion: TIPVersion): TIP;
var
b : TIP;
i, LenBits : integer;
begin
b.Clear;
b.IPVersion := IPVersion;
Result := b; Result.CheckMask(BitsCount);
i := LenIPs[IPVersion] -1;
LenBits := LenIPs[IPVersion] * 2; // Nombre de bits par élément
while (BitsCount >= LenBits) and (i >= 0) do
begin
Result[i] := Word(-1); // Par paquet de 8 ou 16 bits
Dec(i);
Dec(BitsCount, LenBits);
end;
if (BitsCount > 0) and (i >= 0) then // Le reste
begin
Result[i] := Word(-1) shl (LenBits-BitsCount); // Nombre de 0 en poids faible
end;
end;
function MaxVersion(const a, b: TIP): TIPVersion;
begin
if a.IPVersion > b.IPVersion then
Result := a.IPVersion
else
Result := b.IPVersion;
end;
procedure TIP.CheckMask(BitsCount: Word);
begin
case IPVersion of
_IPv4 : if (BitsCount > SizeOf(Data.B) * 8) then Inc(FErr); // Dépasse le nombre de bits total
_IPv6 : if (BitsCount > SizeOf(Data.W) * 8) then Inc(FErr);
end;
end;
procedure TIP.SetIPVersion(IPv: TIPVersion);
begin
if (IPv <> IPVersion) then begin
case IPv of
_IPv4: FillChar(Data.W[2], 6 * SizeOf(Word), 0);
_IPv6: begin Data.W[2] := $FFFF; FillChar(Data.W[3], 5 * SizeOf(Word), 0); end;
end;
FIPVersion := IPv;
end;
end;
function StrToIPv4(AIP: String): TIP;
var
i: Integer;
S : String;
W : Integer;
BitsCount: Word;
Err: Integer;
begin
Result.Clear;
Result.IPVersion := _IPv4;
S := AIP;
AIP := Fetch(S, '/'); // Découpe le masque
if (Length(S) > 0)then begin
Val(S, BitsCount, Err);
if (Err > 0) or (BitsCount > (LenIPs[_IPv4] * 8)) then Inc(Result.FErr); // Erreur dans le Masque Syntaxe ou trop grand
end;
for i := LenIPs[_IPv4] - 1 downto 0 do begin
S := Fetch(AIP, '.');
if (S = '') then Inc(Result.FErr) // Pas de veleur
else begin
Val(S, W, Err);
if (Err <> 0) or (W > 255) or (W < 0) then
Inc(Result.FErr) // Valeur erronnée
else
Result[i] := W;
end;
end;
if (Length(AIP) > 0) or (i >= 0) then Inc(Result.FErr); // Syntaxe incorrecte, Il reste des truc dans la chaine
end;
function StrToIPv6(AIP: String): TIP;
var
S : String;
A : array of Word;
i, Count, ZeroPos : integer;
L : Integer;
Err : Integer;
BitsCount : Word;
IPv4 : Boolean;
begin
Result.Clear;
Result.IPVersion := _IPv6;
S := AIP; AIP := Fetch(S, '/'); // Découpe le masque
if (Length(S) > 0)then begin
Val(S, BitsCount, Err);
if (Err > 0) or (BitsCount > (LenIPs[_IPv6] * 16)) then Inc(Result.FErr); // Erreur dans le Masque Syntaxe ou trop grand
end;
i := LenIPs[_IPv6]; ZeroPos := -1;
if (AIP[1] = ':') then Delete(AIP, 1, 1); // '::' Deux à la suite
while (Length(AIP) > 0) do begin
IPv4 := FindFirstWChar(PWideChar(AIP), ':.') = '.';
if IPv4 then Break;
S := Fetch(AIP, ':');
if (S = '') then // '::'
if (ZeroPos = -1) then
ZeroPos := i
else
ZeroPos := -1 // '::' plusieurs fois signifie une Erreur
else begin
Dec(i);
if (i >= 0) then begin
Val('$'+S, L, Err);
if (Err <> 0) or (L > $FFFF) or (L < 0) then
Inc(Result.FErr) // Le nombre Hexa exprimé n'est pas syntaxiquement correct
else
Result[i] := L;
end
else
Inc(Result.FErr) // Trop de block dans le numéro IP V6
end;
end;
// i est le dernier remplis
if (ZeroPos >= 0) and (i >= 0) then begin // '::'
Count := ZeroPos - i; // Nombre déjà dans la partie droite (Lo)
if IPv4 then L := 2 else L := 0;
Move(Result.Data.W[i], Result.Data.W[L], Count * SizeOf(Word));
FillChar(Result.Data.W[Count+L], (i-L) * SizeOf(Word), 0);
end
else // Si on passe en IPv4, il doit rester 2 word, sinon 0
if IPv4 then
if (i <> 2) then Inc(Result.FErr) else // Pas de place pour l'IPV4 finale
else
if (i <> 0) then Inc(Result.FErr); // On a pas rempli les 8 word
if IPv4 then begin
Result := StrToIPv4(AIP) or Result;
end;
end;
class operator TIP.Implicit(const a : UInt64) : TIP;
begin
Result.Clear;
Move(a, Result.Data.W, SizeOf(a));
Result.IPVersion := _IPv6;
end;
class operator TIP.Implicit(const a : String) : TIP;
begin
if (Pos(':', a) > 0) then
Result := StrToIPv6(a)
else
Result := StrToIPv4(a);
end;
class operator TIP.Implicit(const a : TIP) : String;
var
i : Integer;
begin
Result := '';;
for i := LenIPs[a.IPVersion] - 1 downto 0 do begin
if (Length(Result) > 0) then
Result := Result + SeparIP[a.IPVersion];
case a.IPVersion of
_IPv4: Result := Result + IntToStr(a[i]);
_IPv6: Result := Result + IntToHex(a[i], 4);
end;
end;
end;
class operator TIP.Explicit(const a : TIP) : String;
begin
Result := a; // -> Implicit
end;
class operator TIP.Equal(const a, b: TIP): Boolean;
begin
Result := IPCmp(a, b) = EqualsValue;
end;
class operator TIP.NotEqual(const a, b: TIP): Boolean;
begin
Result := IPCmp(a, b) <> EqualsValue;
end;
class operator TIP.GreaterThan(const a, b: TIP): Boolean;
begin
Result := IPCmp(a, b) = GreaterThanValue;
end;
class operator TIP.GreaterThanOrEqual(const a, b: TIP): Boolean;
begin
Result := IPCmp(a, b) >= EqualsValue;
end;
class operator TIP.LessThan(const a, b: TIP): Boolean;
begin
Result := IPCmp(a, b) = LessThanValue;
end;
class operator TIP.LessThanOrEqual(const a, b: TIP): Boolean;
begin
Result := IPCmp(a, b) <= EqualsValue;
end;
class operator TIP.LeftShift(a: TIP; b: LongWord): TIP;
var
i, d : integer;
c : LongWord;
e : Integer;
begin
Result.Clear(a.FErr);
Result.IPVersion := a.IPVersion;
if (b > 0) then begin
e := LenIPs[a.IPVersion] * 2;
repeat
if (b >= e) then begin
Result := a;
d := b div e;
for i:= LenIPs[a.IPVersion] - 1 - d downto 0 do
Result[i + d] := Result[i];
for i:= 0 to d-1 do
Result[i] := 0;
Dec(b, d * e);
a := Result;
end
else begin
c := 0;
for i:= 0 to LenIPs[a.IPVersion] - 1 do begin
c := (LongWord(a[i]) shl b) or c;
Result[i] := c;
c := c shr e;
end;
if (c > 0) then
Result[i] := c;
b := 0;
end;
until (b = 0);
end
else
Result := a;
end;
class operator TIP.RightShift(a: TIP; b: LongWord): TIP;
var
i : integer;
c : LongWord;
d : LongWord;
e : Integer;
begin
Result.Clear(a.FErr);
Result.IPVersion := a.IPVersion;
if (b > 0) then begin
e := LenIPs[a.IPVersion] * 2; // Un élément = 8 ou 16 bits
repeat
if (b >= e) then begin
Result := a;
d := b div e; // Nombre d'éléments 0..N-1
if (d < (LenIPs[a.IPVersion])) then begin
for i:= d to LenIPs[a.IPVersion] - 1 do begin
Result[i-d] := Result[i];
Result[i] := 0;
end;
end
else begin
Result.Clear;
exit;
end;
Dec(b, d * e);
a := Result;
end
else begin
c := 0;
for i:= LenIPs[a.IPVersion] - 1 downto 0 do begin
d := a[i];
Result[i] := (d shr b) or c;
c := d shl (e-b); // Les bits à reporter
end;
b := 0;
end;
until (b = 0);
end
else
Result := a;
end;
class operator TIP.LogicalNot(const a: TIP): TIP;
var
i : integer;
begin
Result.FErr := a.FErr;
Result.IPVersion := a.IPVersion;
for i := 0 to LenIPs[Result.IPVersion] - 1 do
Result[i] := not a[i];
end;
class operator TIP.LogicalAnd(a, b: TIP): TIP;
var
i : integer;
begin
Result.FErr := a.FErr + b.FErr;
Result.IPVersion := MaxVersion(a, b);
for i := 0 to LenIPs[_IPv6] - 1 do
Result.Data.W[i] := a.Data.W[i] and b.Data.W[i];
end;
class operator TIP.LogicalOr(a, b: TIP): TIP;
var
i : integer;
begin
Result.FErr := a.FErr + b.FErr;
Result.IPVersion := MaxVersion(a, b);
for i := 0 to LenIPs[_IPv6] - 1 do
Result.Data.W[i] := a.Data.W[i] or b.Data.W[i];
end;
class operator TIP.LogicalXor(a, b: TIP): TIP;
var
i : integer;
begin
Result.FErr := a.FErr + b.FErr;
Result.IPVersion := MaxVersion(a, b);
for i := 0 to LenIPs[_IPv6] - 1 do
Result.Data.W[i] := a.Data.W[i] xor b.Data.W[i];
end;
class operator TIP.BitwiseAnd(a, b: TIP): TIP;
var
i : integer;
begin
Result.FErr := a.FErr + b.FErr;
Result.IPVersion := MaxVersion(a, b);
for i := 0 to LenIPs[_IPv6] - 1 do
Result.Data.W[i] := a.Data.W[i] and b.Data.W[i];
end;
class operator TIP.BitwiseOr(a, b: TIP): TIP;
var
i : integer;
begin
Result.FErr := a.FErr + b.FErr;
Result.IPVersion := MaxVersion(a, b);
for i := 0 to LenIPs[_IPv6] - 1 do
Result.Data.W[i] := a.Data.W[i] or b.Data.W[i];
end;
class operator TIP.BitwiseXor(a, b: TIP): TIP;
var
i : integer;
begin
Result.FErr := a.FErr + b.FErr;
Result.IPVersion := MaxVersion(a, b);
for i := 0 to LenIPs[_IPv6] - 1 do
Result.Data.W[i] := a.Data.W[i] xor b.Data.W[i];
end;
function IpV4StrToInt(MyIP: PAnsiChar): LongWord;
var
IP : TIP;
begin
IP := MyIP;
Result := IP.Data.Value;
end;
function Tests: Boolean;
var
a, b, c : TIP;
S : String;
procedure TestA(St: String); begin a := St; if a.Err = 0 then Beep; end;
procedure TestB(St: String); begin a := St; if a.Err > 0 then Beep; end;
begin
a := 1;
b := a shl 127;
a := b shr 10;
if b > a then ;
if b >= a then ;
if a < b then ;
if a <= b then ;
if a <> b then ;
c := not b;
c := a and b;
c := a or b;
c := a xor b;
a := '192.168.1.3'; b := MakeMask(24, _IPv4); c := '192.168.1.5';
Result := IsBetween(c and b, c or (not b), a);
a := '192.168.1.3'; b := MakeMask(96+24, _IPv6); c := '192.168.1.5';
a.SetIPVersion(_IPv6);
S := b; // Implicit
S := String(b) + ' ' + String(a); // Explicit
Result := IsBetween(c and b, c or (not b), a);
{ Erreurs }
TestA('2001:0db8:85a3:1234:4567:0000:0000:8a2e:0370');
TestA('2001:0db8:85a3::1234:4567:0000:0000:8a2e:0370');
TestA('2001:0db8:85a3::1234:4567:0000:0000:8a2e:0370:192.168.1.8');
TestA('2001:0db8:85k3:0000:0000:8a2e:0370:7334');
TestA('2001:0db8:85a3:0000:0000:8a2e:0370'); // Pas assez de nombre
TestA('2001:192.168.1.1:0000:0000:8a2e:0370');
TestA('2001:0db8:192.0.2.128');
TestA('2001:0db8:192.0.2.');
TestA('2001:db8::85a3::ac1f:8001');
Result := IsIPCIDR('192.168.50.5', '192.168.50.0/264');
Result := IsIPCIDR('192.168.50.5', '192.168.50.0/64');
Result := IsIPCIDR('192.168.50.5', '192.168.50.0/4a');
TestA('2001:0db8');
TestA('192.168b.1.5.24');
TestA('192.168.1b.5.24');
TestA('192.168.1.5.24');
TestA('192.168.1.5/2b');
TestA('192.168.1.5\24');
TestA('192.168.1/24');
TestA('192.168.1b.24');
TestA('192.168.24');
TestA('2001');
{ Correct}
TestB('::192.168.1.4');
TestB('2001::192.168.1.4');
TestB('2001::0db8/94');
TestB('::8888:192.168.1.4/95');
TestB('2001:db8:85a3::8a2e:370:7334');
TestB('::8a2e:370:7334');
TestB('::1');
TestB('::');
TestB('::ffff:c000:280');
TestB('::ffff:192.0.2.128');
TestB('2001:db8:85a3::');
TestB('2001:db8:85a3::/24');
TestB('2001:0db8:85a3:0000:0000::0370:7334');
TestB('2001:0db8:85a3:0000:0000:8a2e:0370:7334');
TestB('0:0:0:0:0:ffff:192.168.1.3');
TestB('2001:db8:85a3:0:0:8a2e:370:7334');
TestB('ffff::');
TestB('0:0:0:0:0:ffff:c0a8:103');
TestB('192.168.1.4/24');
Result := IsIPCIDR('192.168.50.5', '192.168.50.5');
Result := IsIPCIDR('192.168.50.5', '192.168.50.0/24');
Result := IsIPCIDR('2001:db8:85a3::8a2e:370:4324', '2001:db8:85a3::8a2e:370:7334/65');
TestB('::ffff/95');
S := String(a); // Explicit
if S = '' then;
a.IPVersion := _IPv4;
S := String(a);
if S = '' then;
end;
initialization
begin
Tests;
end;
end.