I asked a slightly similar question here before, for general string routines for IP addresses. Based off of the answer by NGLN, I have implemented a set of comparison functions, and a demo application. The function IPRange
detects whether it's v4 or v6 and compares them accordingly.
uMain.pas
unit uMain;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
IPTypes;
type
TfrmCheckIPRange = class(TForm)
txtFrom: TEdit;
txtTo: TEdit;
txtIP: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
txtResult: TEdit;
Label4: TLabel;
procedure DoCheck(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmCheckIPRange: TfrmCheckIPRange;
implementation
{$R *.dfm}
function IntRange(const Val, Min, Max: Integer): Boolean;
begin
Result:= (Val >= Min) and (Val <= Max);
end;
function IPRangeV4(const IP, IPFrom, IPTo: TIPv4): Boolean;
begin
Result:= IntRange(IP.D, IPFrom.D, IPTo.D);
if Result then
Result:= IntRange(IP.C, IPFrom.C, IPTo.C);
if Result then
Result:= IntRange(IP.B, IPFrom.B, IPTo.B);
if Result then
Result:= IntRange(IP.A, IPFrom.A, IPTo.A);
end;
function IPRangeV6(const IP, IPFrom, IPTo: TIPv6): Boolean;
begin
Result:= IntRange(IP.H, IPFrom.H, IPTo.H);
if Result then
Result:= IntRange(IP.G, IPFrom.G, IPTo.G);
if Result then
Result:= IntRange(IP.F, IPFrom.F, IPTo.F);
if Result then
Result:= IntRange(IP.E, IPFrom.E, IPTo.E);
if Result then
Result:= IntRange(IP.D, IPFrom.D, IPTo.D);
if Result then
Result:= IntRange(IP.C, IPFrom.C, IPTo.C);
if Result then
Result:= IntRange(IP.B, IPFrom.B, IPTo.B);
if Result then
Result:= IntRange(IP.A, IPFrom.A, IPTo.A);
end;
function IPRange(const IP, IPFrom, IPTo: String): Boolean;
var
IP4, FR4, TO4: TIPv4;
IP6, FR6, TO6: TIPv6;
function IsV4(const S: String): Boolean;
begin
Result:= Pos('.', S) > 1;
end;
function IsV6(const S: String): Boolean;
begin
Result:= Pos(':', S) > 0;
end;
begin
Result:= False;
if (IsV6(IP)) and (IsV6(IPFrom)) and (IsV6(IPTo)) then begin
IP6:= StrToIPv6(IP);
FR6:= StrToIPv6(IPFrom);
TO6:= StrToIPv6(IPTo);
Result:= IPRangeV6(IP6, FR6, TO6);
end else
if (IsV4(IP)) and (IsV4(IPFrom)) and (IsV4(IPTo)) then begin
IP4:= StrToIPv4(IP);
FR4:= StrToIPv4(IPFrom);
TO4:= StrToIPv4(IPTo);
Result:= IPRangeV4(IP4, FR4, TO4);
end else begin
raise Exception.Create('Invalid IP Address Input');
end;
end;
{ TfrmCheckIPRange }
procedure TfrmCheckIPRange.FormCreate(Sender: TObject);
begin
DoCheck(nil);
end;
procedure TfrmCheckIPRange.DoCheck(Sender: TObject);
begin
try
if IPRange(txtIP.Text, txtFrom.Text, txtTo.Text) then begin
txtResult.Text:= 'IP is in range';
txtResult.Color:= clGreen;
end else begin
txtResult.Text:= 'IP is NOT in range';
txtResult.Color:= clRed;
end;
except
on e: exception do begin
txtResult.Text:= e.Message;
txtResult.Color:= clYellow;
end;
end;
end;
end.
uMain.dfm
object frmCheckIPRange: TfrmCheckIPRange
Left = 350
Top = 113
BorderIcons = [biSystemMenu]
BorderStyle = bsSingle
Caption = 'Check IP Range'
ClientHeight = 124
ClientWidth = 296
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
Position = poScreenCenter
OnCreate = FormCreate
DesignSize = (
296
124)
PixelsPerInch = 96
TextHeight = 13
object Label1: TLabel
Left = 11
Top = 11
Width = 71
Height = 13
Alignment = taRightJustify
Caption = 'IP To Compare'
end
object Label2: TLabel
Left = 11
Top = 38
Width = 71
Height = 13
Alignment = taRightJustify
Caption = 'IP Range From'
end
object Label3: TLabel
Left = 23
Top = 65
Width = 59
Height = 13
Alignment = taRightJustify
Caption = 'IP Range To'
end
object Label4: TLabel
Left = 52
Top = 92
Width = 30
Height = 13
Alignment = taRightJustify
Caption = 'Result'
end
object txtFrom: TEdit
Left = 88
Top = 35
Width = 196
Height = 21
Anchors = [akLeft, akTop, akRight]
TabOrder = 1
Text = '192.168.3.100'
OnChange = DoCheck
ExplicitWidth = 158
end
object txtTo: TEdit
Left = 88
Top = 62
Width = 196
Height = 21
Anchors = [akLeft, akTop, akRight]
TabOrder = 2
Text = '192.168.3.200'
OnChange = DoCheck
ExplicitWidth = 158
end
object txtIP: TEdit
Left = 88
Top = 8
Width = 196
Height = 21
Anchors = [akLeft, akTop, akRight]
TabOrder = 0
Text = '192.168.3.105'
OnChange = DoCheck
ExplicitWidth = 158
end
object txtResult: TEdit
Left = 88
Top = 89
Width = 196
Height = 21
Anchors = [akLeft, akTop, akRight]
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = [fsBold]
ParentFont = False
ReadOnly = True
TabOrder = 3
OnChange = DoCheck
ExplicitWidth = 158
end
end
I've tested IPv4, but have NOT tested IPv6, although it should work. I'm not familiar enough with IPv6 to even know different test scenarios.
You may also want to add some logic to check if an IP is within the same subnet, because you might not want to include different subnets. That's as easy as making sure the first 3 numbers (v4) are exactly the same. You may wish to raise an exception if there are any differences in subnets, but that's all up to how you need to implement this.
EDIT
I fixed the logic in determining v4 vs v6, because an IPv6 address could also possibly have a .
in it, I had to switch the order of checking from v4-v6 to v6-v4.