Подпрограммы строк IP-адреса в Delphi? - PullRequest
2 голосов
/ 15 декабря 2011

Я ищу способ в Delphi проверять и управлять IP-адресами. Некоторые вещи, которые он должен уметь делать ...

  • Убедитесь, что строка является действительным IP-адресом
  • Убедитесь, что строка является допустимой маской подсети
  • Убедитесь, что IP-адрес находится в данной подсети
  • Некоторый тип (запись или строка или что-то еще), который предназначен для хранения IP-адреса
  • Базовое преобразование типов IP-адресов, таких как String или Array[0..3] of Byte
  • Любые другие подпрограммы IP-адреса, которые могут упростить манипулирование IP-адресом

Основная причина в том, что я хочу посмотреть, уже существуют ли эти вещи, прежде чем я продолжу их изобретать.

Ответы [ 2 ]

8 голосов
/ 16 декабря 2011

Я также однажды написал модуль преобразования IPv4 и IPv6 , включающий пользовательский тип варианта для обоих типов IP-адресов. Этот ответ показывает несколько примеров его возможностей. Первоначально он был разработан для визуализации значений различных типов в масштабе на некоторых ползунках 1) . Тогда требования были такими, что существующих библиотек по умолчанию было недостаточно, но я согласен с комментариями, что вам, вероятно, помогут только Indy (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 вы должны сами выводить некоторые подпрограммы, но это не должно не представлять никаких проблем.

1) Для интересующихся, это этот ползунок и эта тема послужила инициацией для данного устройства.

3 голосов
/ 15 декабря 2011

Я уже написал все функции, которые вам нужны, но, боюсь, я не в состоянии поделиться кодом.

Однако библиотека 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.

Если вы хотите свернуть свои собственные,Вот несколько указателей:

  • Управление адресами IPv4 довольно просто, поскольку они состоят только из 32 битов, которые могут храниться в стандартном целочисленном типе.IPv6-адреса сложнее, так как им нужно 128 бит, и ни у одного собственного типа нет такого количества битов.
  • Прежде чем пытаться манипулировать IP-адресом, сначала преобразуйте его в целое число (конечно, только для IPv4, для IPv6 потребуется другое хранилище).метод).Для этого разделите IP-адрес с помощью «.»в качестве разделителя.Убедитесь, что каждое отдельное значение содержит только цифры и находится в диапазоне от 0 до 255. Затем используйте эти значения для генерации окончательного целого числа.
  • После того, как IP-адрес был преобразован в целое число, вы можете манипулировать им по своему усмотрению.Например, учитывая IP-адрес и маску подсети, вы можете найти подсеть, которой принадлежит IP-адрес, например, IPtoInt (IPAddress) AND NOT (IPToInt (SubnetMask)) = Целое число подсети.Теперь вы можете получить целочисленный IP-адрес для целочисленной подсети, чтобы узнать, попадает ли IP в подсеть.
  • Наконец, преобразовать целочисленный IP-адрес обратно в строку.

Если у вас есть какие-то конкретные вопросы, я могу попытаться ответить и на них.

...