Autor Beitrag
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Di 10.03.09 03:10 
Hallo!

Es wurde in der DP die Frage gestellt, wie man überprüfen kann, ob eine IPv6 Adresse gültig ist. Da die entsprechenden Funktionen in älteren Windowsversionen noch nicht vorhanden sind, habe ich daraufhin nach der RFC 2373 die Vorgaben an eine solche Adresse umgesetzt.

Bei der Umsetzung habe ich mich am Prinzip eines endlichen Automaten orientiert, denn so ließ sich das ganze sehr schnell und erweiterbar implementieren.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
// Prüft, ob der angegebene String einer IPv6 Adresse laut RFC 2373
// entspricht.
// Autor: Sebastian Jänicke (jaenicke @ delphi-forum.de)
// Getestet mit Delphi 3 bis 2009.
function SJCheckIPv6(Value: AnsiString): Boolean; 

  // Prüft ob Value ab Index Start eine IPv4 Adresse enthält
  function CheckIPv4(Start: Integer): Boolean; 
  var 
    i, CurValue, DotCount: Integer; 
    CurDot: Boolean; 
  begin 
    Result := False; 
    CurValue := 0
    DotCount := 0
    CurDot := False; 
    for i := Start to Length(Value) do 
      case Value[i] of 
        '0'..'9'
          begin 
            CurValue := CurValue * 10 + Ord(Value[i]) - 48
            CurDot := False; 
          end
        '.'
          if (CurValue > 255or CurDot or (i = Start) then 
            Exit 
          else 
          begin 
            CurValue := 0
            CurDot := True; 
            Inc(DotCount); 
          end
      else 
        Exit; 
      end
    Result := (DotCount = 3and (CurValue <= 255and not CurDot; 
  end

type 
  TCheckIP6State = (cisNone, cisColon, cisColonStart, cisDoubleColon, 
    cisHex1, cisHex2, cisHex3, cisHex4); 
var 
  DoubleColon: Boolean; 
  i, CurBlock: Integer; 
  CurState: TCheckIP6State; 

  function CheckHexChars: Boolean; 
  begin 
    Result := True; 
    case CurState of 
      cisNone, cisColon: 
        begin 
          CurState := cisHex1; 
          Inc(CurBlock); 
          if CurBlock > 8 then 
            Result := False; // mehr als 8 Blöcke geht nicht 
        end
      cisColonStart: 
        Result := False; // ein einzelnes : am Anfang geht nicht 
      cisDoubleColon: 
        begin 
          CurState := cisHex1; 
          Inc(CurBlock, 2); 
          if CurBlock > 8 then 
            Result := False; // :: steht für mind. 1 Block, mehr als 8 geht nicht 
        end
      cisHex1: 
        CurState := cisHex2; 
      cisHex2: 
        CurState := cisHex3; 
      cisHex3: 
        CurState := cisHex4; 
      cisHex4: 
        Result := False; // Mehr als 4 hexadezimale Zeichen hintereinander geht nicht 
    end
  end

  function CheckColon: Boolean; 
  begin 
    Result := True; 
    case CurState of 
      cisNone: 
        CurState := cisColonStart; 
      cisColon: 
        if DoubleColon or (CurBlock > 7then 
          Result := False // zweimal :: geht nicht, 
               // außerdem steht :: für mind. 1 Block, mehr als 8 geht nicht 
        else 
        begin 
          CurState := cisDoubleColon; 
          DoubleColon := True; 
        end
      cisColonStart: 
        begin 
          CurState := cisDoubleColon; 
          DoubleColon := True; 
        end
      cisDoubleColon: 
        Result := False; // drittes : hintereinander ist nicht erlaubt 
      cisHex1, cisHex2, cisHex3, cisHex4: 
        CurState := cisColon; 
    end
  end

  // Überprüfung ob IPv4 Adresse eingebettet ist 
  function CheckDot: Boolean; 
  type 
    TCheckIP4State = (cis4Colon, cis4DoubleColon, cis4Zero, cis4F1, cis4F2, cis4F3, cis4F4); 
  var 
    j, Start: Integer; 
    IP4State: TCheckIP4State; 
  begin 
    Result := False; 
    Start := i - 1
    while (Start > 0and (Value[Start] <> ':'do 
      Dec(Start); 
    if Start = 0 then 
      Exit; 
    IP4State := cis4Colon; 
    for j := Start - 1 downto 1 do 
      case Value[j] of 
        'f''F'
          case IP4State of 
            cis4Colon: 
              IP4State := cis4F1; 
            cis4Zero: 
              Exit; 
            cis4F1: 
              IP4State := cis4F2; 
            cis4F2: 
              IP4State := cis4F3; 
            cis4F3: 
              IP4State := cis4F4; 
            cis4F4: 
              Exit; 
          end
        '0'
          case IP4State of 
            cis4Colon, cis4DoubleColon, cis4Zero: 
              IP4State := cis4Zero; 
          else 
            Exit; 
          end
        '1'..'9'
          Exit; 
        ':'
          case IP4State of 
            cis4Colon: 
              IP4State := cis4DoubleColon; 
            cis4DoubleColon: 
              Exit; 
          else 
            IP4State := cis4Colon; 
          end
      else 
        Exit; // ungültiges Zeichen für IPv4 Einbettung 
      end
    if IP4State in [cis4DoubleColon, cis4Zero] then 
      Result := CheckIPv4(Start + 1); 
  end

begin 
  Result := False; 
  DoubleColon := False; 
  CurState := cisNone; 
  CurBlock := 0
  for i := 1 to Length(Value) do 
    case Value[i] of 
      'a'..'f''0'..'9''A'..'F'
        if not CheckHexChars then 
          Exit; 
      ':'
        if not CheckColon then 
          Exit; 
      '.'// Überprüfung ob IPv4 Adresse eingebettet ist 
        begin 
          if CurBlock <= 7 then 
            Result := CheckDot; 
          Exit; 
        end
    else 
      Exit; // ungültiges Zeichen 
    end
  Result := (CurState <> cisColon) and ((CurBlock = 8or DoubleColon); 
end;
Hier geht es nur um die IPv6 Adresse selbst, nicht um die Einbettung in eine URI oder Präfixe nach CIDR Notation, die wie bei IPv4 auch möglich sind.
Dies ließe sich natürlich ergänzen.

Schönen Gruß,
Sebastian