【问题标题】:How to check an IP address is within a range of two IPs in Delphi?如何检查一个IP地址是否在Delphi中的两个IP范围内?
【发布时间】:2013-07-27 21:18:00
【问题描述】:

我想检查一个 IP 地址是否在最小和最大 IP 地址的范围内。我如何在 Delphi 中做到这一点?

例如我想做这样的事情:

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 地址。

【问题讨论】:

  • @TLama 我编辑了问题
  • 您能指定您要使用的顺序吗?
  • @DavidHeffernan 我不明白你在问什么
  • 我的意思是,你对 a
  • @DavidHeffernan 我编辑了问题。现在清楚了吗?

标签: delphi ip delphi-7 ipv4


【解决方案1】:

对于 IPv4 地址,您可以简单地将它们转换为整数形式,然后对它们执行标准的序数比较。

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

【讨论】:

    【解决方案2】:

    我将假设您的地址是以主机字节顺序存储在 32 位整数中的 IPv4 地址。而且我还假设您想要一个字典顺序,以便:

     a.b.c.d < p.q.r.s 
    

    首先比较ap,如果相等则比较bq,以此类推。

    在这种情况下,自然无符号整数排序(使用&lt;&gt; 运算符)将产生您想要的排序。

    如果地址是网络字节序,那么你需要在比较之前转换为主机字节序。

    在您的问题中,您将地址作为字符串。因此,您需要使用inet_addr 将它们转换为网络字节顺序32 位无符号整数,然后使用ntohl 将它们转换为主机字节顺序。然后你就可以比较了。

    【讨论】:

    • @Sertac 我错了。我认为我的回答现在是准确的。如果使用 inet_addr 以网络字节顺序返回输出,则字节顺序是相关的。
    • 是的。 AAMOF OP 的上一个问题的答案涉及相同的转换,以便能够添加 IP 地址,转换正是您所提议的。
    • @Sertac 啊,我记得那个问题。你的答案是正确的!我投了赞成票。
    • @JerryDodge:自毁失败? :-)
    【解决方案3】:

    我之前在这里向a slightly similar question 询问过IP 地址的一般字符串例程。基于the answer by NGLN,我实现了一组比较函数和一个演示应用程序。函数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.
    

    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
    

    我已经测试过 IPv4,但没有测试过 IPv6,虽然它应该可以工作。我对 IPv6 不够熟悉,甚至不知道不同的测试场景。

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


    编辑

    我修复了确定 v4 与 v6 的逻辑,因为 IPv6 地址中也可能包含.,我不得不将检查顺序从 v4-v6 切换到 v6-v4。

    【讨论】:

    • if (IsV4) and (IsV4) and (IsV4) then begin ... 您需要检查多少次才能确信它是 V4?
    • 使用相同的TIPv4 结构以及Math 单元中的InRange 函数,您可以简单地编写一个code like this。这就是为这些结构使用变体记录的重点......
    • @SertacAkyuz 哦,快照,该子程序应该检查三个中的每一个,但我错过了添加参数的主要部分......已修复并感谢您指出。我有这些参数,但出于某种原因我决定删除它,但当然我不能让它神奇地检测到我要检查哪个参数
    • @Jeryy - 不客气 :)。恕我直言,您可以完全跳过检查,AFAICS 'test.bmp' 将有资格调用 StrToIPv4 无论如何都会引发异常。如果要判断一个地址是V4还是V6,V4映射的V6地址的一些符号也有点。
    • @SertacAkyuz 所以我假设这意味着我需要在. 之前检查: 对吗?
    猜你喜欢
    • 2012-06-22
    • 2021-09-08
    • 2013-04-27
    • 2013-08-22
    • 2017-05-21
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    相关资源
    最近更新 更多