![]() |
Prüfen, ob String eine gültige IPv6-Adresse ist
Gibt es eine fertige Funktion, die prüfen kann, ob ein String eine gültige IPv6 Adresse ist?
Also für eine Verwendung wie:
Delphi-Quellcode:
Habe leider nur Prüfungen für IPv4-Adressen gefunden...
if IsIPv6('2001:db8:85a3:8d3:1319:8a2e:370:7344') then ...
|
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Möchtest du prüfen, ob der String prinzipiell eine gültige Adresse enthält oder ob die IP existiert?
Für die Existenz sollte getnameinfo helfen, diese ist ab Windows XP verfügbar: ![]() Ab Vista kannst du auch einen solchen String in die Binärdarstellung umwandeln versuchen mit RtlIpv6StringToAddress: ![]() Je nachdem ob nur Vista und Windows 7 oder auch XP unterstützt werden sollen, musst du schauen was du benutzt. Für XP gibt es wohl keine direkte Umwandlungsfunktion. Grundsätzlich ist das zwar nicht ganz so einfach wie bei IPv4, aber so schwer ist die manuelle Prüfung auch nicht, dann wärst du nicht vom benutzten System abhängig. |
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Man müsste doch nur prüfen, ob die Teile der IP-Adresse im gültigen Wertebereich sind. Bei IPv4 darf zum Beispiel in der Dezimaldarstellung kein Oktett größer als 255 sein. Ähnliches sollte für IPv6 auch gelten.
|
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Die Überprüfung an sich ist nicht so schwer, das habe ich ja schon geschrieben.
Aber es gibt z.B. für ein und die selbe Adresse mehrere Schreibweisen. Dies wäre alles äquivalent...
Code:
Und diese Adressen gibt es nicht...
ff00:0:ff::ff
ff00:0000:ff::ff ff00:0:ff:0:0:0:0:ff ff00:0000:ff:0000:0000:0000:0000:ff00
Code:
Als Internetadresse gibts die IP dann noch in eckigen Klammern und ggf. mit Port dahinter.
ff00::ff:0:0::ff
ff00::ff::ff ff00:0:ff:0:0:0:0:0:ff Und ich weiß nicht, ob es da noch mehr gibt, was ich selbst bisher noch nicht weiß. Ich habe hier das lokale Netzwerk auf IPv6 umgestellt (zum Ausprobieren), das war nicht so lustig teilweise. |
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Zitat:
Zitat:
Zitat:
|
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Zitat:
![]() ![]() Aber wie fast immer bei Regular Expressions gilt: Optimal ists vermutlich nicht ;) |
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Ok, als ich das mit den Regechsen eben gelesen habe, habe ich mir mal überlegt wie das einfacher geht. Dabei ist mir ein endlicher Automat eingefallen. :idea:
Und dann habe ich das einmal schnell umgesetzt. Ich weiß im Moment nicht ob :: am Anfang oder Ende erlaubt sind, bin aber davon ausgegangen, dass beides möglich ist. Die neue Schreibweise für localhost ist ja ::1, insofern kommt sowas ja vor. Auch wenn Nullblocks wohl ansonsten kaum am Anfang vorkommen werden, sind es wohl gültige IPs, deshalb akzeptiere ich diese normal.
Delphi-Quellcode:
// EDIT:
// Autor: Sebastian Jänicke (jaenicke @ delphipraxis.net)
// [url]http://www.delphipraxis.net/post1011159.html#1011159[/url] function SJCheckIPv6(Value: String): Boolean; type CheckIPState = (cisNone, cisDelim, cisDelimStart, cisDoubleDelim, cisHex1, cisHex2, cisHex3, cisHex4); var DoubleDelim: Boolean; i, CurBlock: Integer; CurState: CheckIPState; begin Result := False; DoubleDelim := False; CurState := cisNone; CurBlock := 0; for i := 1 to Length(Value) do case Value[i] of 'a'..'f', '0'..'9': case CurState of cisNone, cisDelim: begin CurState := cisHex1; Inc(CurBlock); if CurBlock > 8 then Exit; // :: steht für mind. 2 Blöcke, mehr als 8 geht nicht end; cisDelimStart: Exit; // ein einzelnes : am Anfang geht nicht cisDoubleDelim: begin CurState := cisHex1; Inc(CurBlock, 3); if CurBlock > 8 then Exit; // :: steht für mind. 2 Blöcke, mehr als 8 geht nicht DoubleDelim := True; end; cisHex1: CurState := cisHex2; cisHex2: CurState := cisHex3; cisHex3: CurState := cisHex4; cisHex4: Exit; // Mehr als 4 hexadezimale Zeichen hintereinander geht nicht end; ':': case CurState of cisNone: CurState := cisDelimStart; cisDelim: if DoubleDelim or (CurBlock > 6) then Exit // zweimal :: geht nicht, // außerdem steht :: für mind. 2 Blöcke, mehr als 8 geht nicht else CurState := cisDoubleDelim; cisDelimStart: CurState := cisDoubleDelim; cisDoubleDelim: Exit; // drittes : hintereinander ist nicht erlaubt cisHex1, cisHex2, cisHex3, cisHex4: CurState := cisDelim; end; else Exit; // ungültiges Zeichen end; Result := CurState <> cisDelim; end; Ein paar Kommentare eingestreut. ;-) // EDIT2: Eine eingebettete IPv4 Adresse kannte ich bis eben gar nicht, das ist nicht drin. Allerdings sollte das auf diese Art auch ggf. einfach zu ergänzen sein. ;-) |
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Sieht gut aus. :)
Allerdings bin ich mir nicht so sicher, ob da wirklich alle Regeln miteinbezogen sind. Die Funktion liefert auch für leere und falsch verkürzte Strings true. ('' oder '0000:fff') Ich hatte in der Zwischenzeit auch angefangen, eine eigene Funktion zu schreiben. Die ist definitiv nicht so kurz und schnell wie Deine, weil ich quasi für jede Regel auf eine eigene Prüfung zurückgreife, aber letztlich hängt es bei mir gerade auch an der vollständigen Regeldefinition. Damit habe ich u.A. das gleiche Problem, was ich gerade bei dir angemerkt habe.
Delphi-Quellcode:
Der Übersicht halber erspare ich mir hier den Inhalt der einzelnen Funktionen (bei Interesse kann ich sie natürlich auch noch posten).
if //nicht länger als 39 Stellen 8*4+7
(length(myIPv6) <= 39) and // max. ein Mal :: (CountPos('::', myIPv6) <= 1) and // nur 0-F und : (ValidCharsInString(myIPv6, ['0'..'9', 'A'..'F', 'a'..'f', ':'])) and // zwischen : und : max. 4 Stellen (MaxSubStringLength(myIPv6, ':') <=4) then Da ich den String nicht wie in Deiner SJCheckIPv6 in einem Durchgang Zeichen für Zeichen überprüfe, könnte ich weitere Prüfungen im Ganzen anhängen. Dafür fehlt es mir momentan aber an der Regel-Definition: - Kürzest-mögliche Adresse (von localhost abgesehen)? - Eventuell nur bestimmter Anfang der Adresse gültig (je nach Einer-Bitfolge) wie 2000, fc00, fe80, ff00? - Sofern kein :: vorkommt, müssten es wohl 8 Blöcke bzw. 7 : sein - ... Ich befürchte einfach, dass das alles keine 100%ige Prüfung darstellt. Etwas besseres fällt mir aber auch nicht ein... |
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Ok, die Result Zuweisung am Ende muss dann so aussehen, das berücksichtigt beide Fälle:
Delphi-Quellcode:
Result := (CurState <> cisDelim) and ((CurBlock = 8) or DoubleDelim);
Zitat:
|
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Zitat:
|
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Ach, :: kann auch nur ein Block mit 0 sein. :wall:
Ok, dann so, sind nur zwei Zahlen anders, aber ich poste es mal trotzdem komplett nochmal:
Delphi-Quellcode:
// EDIT:
// Autor: Sebastian Jänicke (jaenicke @ delphipraxis.net)
// [url]http://www.delphipraxis.net/post1011159.html#1011273[/url] function SJCheckIPv6(Value: String): Boolean; type CheckIPState = (cisNone, cisDelim, cisDelimStart, cisDoubleDelim, cisHex1, cisHex2, cisHex3, cisHex4); var DoubleDelim: Boolean; i, CurBlock: Integer; CurState: CheckIPState; begin Result := False; DoubleDelim := False; CurState := cisNone; CurBlock := 0; for i := 1 to Length(Value) do case Value[i] of 'a'..'f', '0'..'9': case CurState of cisNone, cisDelim: begin CurState := cisHex1; Inc(CurBlock); if CurBlock > 8 then Exit; // mehr als 8 Blöcke geht nicht end; cisDelimStart: Exit; // ein einzelnes : am Anfang geht nicht cisDoubleDelim: begin CurState := cisHex1; Inc(CurBlock, 2); if CurBlock > 8 then Exit; // :: steht für mind. 1 Block, mehr als 8 geht nicht DoubleDelim := True; end; cisHex1: CurState := cisHex2; cisHex2: CurState := cisHex3; cisHex3: CurState := cisHex4; cisHex4: Exit; // Mehr als 4 hexadezimale Zeichen hintereinander geht nicht end; ':': case CurState of cisNone: CurState := cisDelimStart; cisDelim: if DoubleDelim or (CurBlock > 7) then Exit // zweimal :: geht nicht, // außerdem steht :: für mind. 1 Block, mehr als 8 geht nicht else CurState := cisDoubleDelim; cisDelimStart: CurState := cisDoubleDelim; cisDoubleDelim: Exit; // drittes : hintereinander ist nicht erlaubt cisHex1, cisHex2, cisHex3, cisHex4: CurState := cisDelim; end; else Exit; // ungültiges Zeichen end; Result := (CurState <> cisDelim) and ((CurBlock = 8) or DoubleDelim); end; Kommentare aktualisiert // EDIT2: Jedenfalls siehst du, dass das auf diese Weise nicht nur schnell geschrieben war (vorhin 10 Minuten oder so), sondern auch sehr einfach angepasst werden kann. :mrgreen: |
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Sieht gut aus. Hab mal alle möglichen Test-Fälle durchgespielt und es scheint alles zu klappen. :)
Wäre imho was für die Library. |
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
Wie gesagt: Es fehlt z.B. noch die Behandlung einer IPv4 in einer IPv6 Adresse.
Ich checke das noch mit dem entsprechenden Standard RFC 2373 (26 DIN A4 Seiten, aber bin gleich durch^^), integriere vielleicht noch eine Unterscheidung zwischen Adresstypen und die Integration einer IPv6 Adresse in eine URL nach RFC 2732, und dann stelle ich es in die Library. ;-) |
Re: Prüfen, ob String eine gültige IPv6-Adresse ist
So, für die IP sollten jetzt alle Fälle des Standards erkannt werden.
Der aktuelle Quelltext befindet sich auch hier als Vorschlag für die Library: :zwinker: ![]()
Delphi-Quellcode:
// Autor: Sebastian Jänicke (jaenicke @ delphipraxis.net)
// [url]http://www.delphipraxis.net/post1011159.html#1011159[/url] function SJCheckIPv6(Value: AnsiString): Boolean; 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 > 255) or CurDot or (i = Start) then Exit else begin CurValue := 0; CurDot := True; Inc(DotCount); end; else Exit; end; Result := (DotCount = 3) and (CurValue <= 255) and 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 > 7) then 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 > 0) and (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 = 8) or DoubleColon); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:12 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz