如何在Delphi中检查IP地址是否在两个IP的范围内?

如何在Delphi中检查IP地址是否在两个IP的范围内?,delphi,ip,delphi-7,ipv4,Delphi,Ip,Delphi 7,Ipv4,我想检查IP地址是否在最小和最大IP地址的范围内。我怎样才能在德尔福做到这一点 例如,我想做这样的事情: if CheckIp("127.0.0.15","127.0.0.1","127.0.0.255") then ShowMessage('ok'); 127.0.0.1是范围的起始值,127.0.0.255是范围的结束值,127.0.0.15是将要检查的IP地址。对于IPv4地址,您只需将其转换为整数形式,然后对其执行标准顺序比较 IPv6地址太大,无法转换为整数(除非您使用第三方BigI

我想检查IP地址是否在最小和最大IP地址的范围内。我怎样才能在德尔福做到这一点

例如,我想做这样的事情:

if CheckIp("127.0.0.15","127.0.0.1","127.0.0.255") then ShowMessage('ok');

127.0.0.1是范围的起始值,127.0.0.255是范围的结束值,127.0.0.15是将要检查的IP地址。

对于IPv4地址,您只需将其转换为整数形式,然后对其执行标准顺序比较


IPv6地址太大,无法转换为整数(除非您使用第三方BigInt库),因此您必须将其转换为二进制形式,然后逐字节比较。

我将假设您的地址是以主机字节顺序存储在32位整数中的IPv4地址。我还假设你需要一个词典排序,这样:

 a.b.c.d < p.q.r.s 
a.b.c.d
首先比较
a
p
,如果相等,则比较
b
q
,依此类推

在这种情况下,自然无符号整数排序(使用
运算符)将生成所需的排序

如果地址是按网络字节顺序排列的,则需要在比较之前转换为主机字节顺序

在您的问题中,地址是字符串。因此,您需要使用
inet\u addr
将它们转换为网络字节顺序32位无符号整数,然后使用
ntohl
将它们转换为主机字节顺序。然后您可以进行比较。

我以前在这里问过,关于IP地址的一般字符串例程。基于,我实现了一组比较函数和一个演示应用程序。功能
IPRange
检测它是v4还是v6,并进行相应的比较

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.
我已经测试了IPv4,但还没有测试IPv6,尽管它应该可以工作。我对IPv6还不够熟悉,甚至不知道不同的测试场景

您可能还需要添加一些逻辑来检查IP是否在同一子网内,因为您可能不希望包含不同的子网。这就像确保前3个数字(v4)完全相同一样简单。如果子网之间存在任何差异,您可能希望提出一个例外,但这取决于您需要如何实现它


编辑


我修正了确定v4与v6的逻辑,因为IPv6地址中可能也有一个
,我必须将检查顺序从v4-v6切换到v6-v4。

@TLama我编辑了一个问题你能指定你想要使用的顺序吗?@DavidHeffernan我不明白你askI的意思,你对这个词的定义是什么a@DavidHeffernan我编辑了这个问题。现在清楚了吗?@Sertac我完全错了。我认为我的答案现在是准确的。如果使用inet_addr返回网络字节顺序的输出,则字节顺序是相关的。AAMOF OP之前的问题有一个答案,涉及到非常相同的转换,以便能够在IP地址上进行添加,转换正是您所建议的。@Sertac啊,我记得那个问题。你的答案是正确的!我投了更高的票。@Jerrydoge:自毁失败?:-)<代码>如果(IsV4)和(IsV4)和(IsV4),则开始。。。您需要检查多少次才能确定它是V4?使用相同的
TIPv4
结构以及
Math
单元中的
InRange
函数,您可以简单地编写一个。这就是为这些结构使用变量记录的意义…@SertacAkyuz-Oh-snap,该子例程应该检查3个变量中的每一个,但我错过了添加参数的主要部分。。。修正了,谢谢你指出。我有这些参数,但无论出于什么原因,我决定删除它,但当然我不能让它神奇地检测到我想要哪一个check@Jeryy-不客气:)。我想你完全可以跳过这项检查,AFAICS的“test.bmp”将符合对strotipv4的调用,这将在那里引发异常。如果要确定地址是V4还是V6,V4映射的V6地址的一些符号也有点。@SertacAkyuz所以我假设这意味着我需要在
之前检查
,对吗?
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