I want to check if an IP address is within a range of a minimum and maximum IP address. How can I do that in Delphi?
For example I want to do something like this:
if CheckIp("127.0.0.15","127.0.0.1","127.0.0.255") then ShowMessage('ok');
127.0.0.1 is start value of range, 127.0.0.255 is end value of range and 127.0.0.15 is IP address that will be checked.
For IPv4 addresses, you can simply convert them to their integer forms and then perform standard ordinal comparisons on them.
IPv6 address are too big to convert to integers (unless you use a third party BigInt library), so you would have to convert them to their binary form and compare them byte-by-byte instead.
I'm going to assume that your addresses are IPv4 addresses stored in a 32 bit integer in host byte order. And I'm also assuming that you want a lexicographic ordering so that:
a.b.c.d < p.q.r.s
is compared by first comparing a
and p
, and if equal then comparing b
and q
, and so on.
In which case, the natural unsigned integer ordering (using the <
or >
operators) will produce the ordering that you desire.
If the addresses are in network byte order, then you need to convert to host byte order before comparing.
In your question, you have addresses as strings. So you'd need to convert them to network byte order 32 bit unsigned integers with inet_addr
, and then to host byte order with ntohl
. And then you could compare.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.