[Regex] Wert/Range zwischen 0-255 < 0-255 für IP-Adressen

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    [Regex] Wert/Range zwischen 0-255 < 0-255 für IP-Adressen

    Hallo Community,

    ich möchte für meinen NETworkManager/IPScanner eine Funktion einbauen, um Gateways zu scannen. Dazu würde ich gerne die Eingabe von Benutzern wie folgt auflösen:

    192.168.[0-100].1

    zu

    192.168.0.1, 192.168.1.1, 192.168.2.1, ...


    Bis jetz prüfe ich IP-Adressen so:

    ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$

    Um [10-200] abzubilden hab ich folgendes:

    ​\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\]

    Hier würden aber auch falsche Eingaben wie [200-30] als Richtig erkannt werden.

    Gibt es in Regex die Möglichkeit zu vergleichen, dass die erste Zahl der Range kleiner sein muss als die zweite Zahl!?

    Grüße
    BornToBeRoot
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!
    @BornToBeRoot Wenn der String das richtige Format hat, splitte ihn nach "." und konvertiere die Teile nach Byte, da kannst Du mit den Werten direkt arbeiten.
    Wenn der User was eingeben soll, bau Dir ein geeignetes UserControl, das nur erlaubte Eingaben zulässt.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    BornToBeRoot schrieb:

    Hier würden aber auch falsche Eingaben wie [200-30] als Richtig erkannt werden.

    Gibt es in Regex die Möglichkeit zu vergleichen, dass die erste Zahl der Range kleiner sein muss als die zweite Zahl!?
    ähnlich wie Rod: Versuch nicht alles mit einem einzigen Regex zu lösen.
    Regex kann viel, wird aber dann auch schnell extrem unverständlich - und kann vieles eben auch nicht.
    zB dass die erste kleiner ist als die zweite kanner nicht.
    Und auch Einschränkung des Zahlbereiches auf 0 - 255 dürfte irre umständlich werden - da fährste viel besser mit wie Rod sagt: Byte.TryParse().

    Ist eiglich auch sowas zulässig? 192.[100-150].168.12
    oder sowas? 192.[100-150].168.[10-15]

    jdfs. ich würd den String einfach ohne Regex bei "." splitten, und im weiteren Regex nur nutzen, um grob gültige Gruppen zu suchen:
    (d{1,3})|(\[(d{1,3})-(d{1,3})\])
    matcht die erste gruppe, so ist deren Inhalt nach Byte zu parsen, matcht die 2. Gruppe, so kann man deren beide Untergruppen parsen - und dann erst gugge, ob die 2. größer ist als die erste.
    Aber wenn das starr ist (also nur die 3. Gruppe ist immer ein Range), dann ganz nach Rod: ein UserControl, wo man mit Tab-Taste von einer Gruppe zur nächsten hopft

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @RodFromGermany sowas in der Art hab ich mir auch schon gedacht... Ich hab bereits eine ValidationRule für die Eingabe und werde die entsprechend erweitern.

    Mein derzeitiger Regex sieht jetzt so aus:

    (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])\.){3}((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])

    + 192.168.0.[200-150]
    + 192.168.0.0
    + 192.[0-5].0.0
    - 255.265.2.0
    - 192.168.[300-400].0
    + [25-99].2.5.6
    + [9-10].[9-10].[9-10].[9-10]

    ErfinderDesRades schrieb:

    Ist eiglich auch sowas zulässig? 192.[100-150].168.12
    oder sowas? 192.[100-150].168.[10-15]


    Ja natürlich, wenn man z.B. Class A/B Netze scannt sollte man alle Oktetts entsprechend anpassen können und auch sowas 172.[16-31].0.[1-2] kann man schön auflösen: 172.16.0.1, 172.16.0.2, 172.17.0.1, ...


    Edit: Gerade kam mir die Idee, dass man das ganze ja noch erweitern kann: 192.168.[2,4,6].1 --> 192.168.2.1, 192.168.4.1
    (?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(-|,)(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])\.){3}((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(-|,)(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])

    Kann man den Regex noch vereinfachen?! Hier blickt ja keiner mehr durch...
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!

    BornToBeRoot schrieb:

    Ich hab bereits eine ValidationRule für die Eingabe und werde die entsprechend erweitern.
    Wie ganz genau seehen denn Deine möglichen Eingaben aus?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    BornToBeRoot schrieb:

    Ja natürlich, wenn man z.B. Class A/B Netze scannt sollte man alle Oktetts entsprechend anpassen können und auch sowas 172.[16-31].0.[1-2] kann man schön auflösen: 172.16.0.1, 172.16.0.2, 172.17.0.1, ...
    Also das wird ziemlich knackig, und das Hauptproblem hat dann mit Regex auch garnix mehr zu tun.
    Intuitiv erscheint dir das einfach, aber ums zu coden musst du die Algorithmus-Beschreibung verstehen:
    Die 4 Segmente deiner Eingabe werden jeweils als Zahlenbereiche aufgefasst - wenn ein Segment nur Ziffern enthält ists eben ein Zahlenbereich der Länge 1.
    Und dann die 4 Zahlenbereiche gegeneinander durch-permutieren, und jede Permutation als Ip-Addresse ausgeben.
    Naja - Letzteres ist auch nicht soo schwierig, ich glaub dein Knackpunkt wird sein, Eingaben nach deiner Grammatik (es ist nämlich eine eigene Grammatik, die du da definierst) korrekt in ein 2-dimensionales Byte-Array zu parsen - in ein Byte(3,1), um genau zu sein.

    Habs hinbekommen, hier der Commit: github.com/BornToBeRoot/NETwor…520adb086b5df8570a57ab0d6

    Der Regex:
    Spoiler anzeigen

    C#-Quellcode

    1. // Match a range like [0-255]
    2. public const string SpecialRangeRegex = @"\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)-(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\]";
    3. // Match a IPv4-Address like 192.168.[50-100].1
    4. public const string IPv4AddressSpecialRangeRegex = @"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|" + SpecialRangeRegex + @")\.){3}((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|" + SpecialRangeRegex + @")$";


    ValidationRule (Ab Zeile 36)
    Spoiler anzeigen

    C#-Quellcode

    1. namespace NETworkManager.Validators
    2. {
    3. public class IPScanRangeValidator : ValidationRule
    4. {
    5. public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    6. {
    7. bool isValid = true;
    8. foreach (string ipOrRange in (value as string).Replace(" ", "").Split(';'))
    9. {
    10. // like 192.168.0.1
    11. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressRegex))
    12. continue;
    13. // like 192.168.0.0/24
    14. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressCidrRegex))
    15. continue;
    16. // like 192.168.0.0/255.255.255.0
    17. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressSubnetmaskRegex))
    18. continue;
    19. // like 192.168.0.0 - 192.168.0.100
    20. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressRangeRegex))
    21. {
    22. string[] range = ipOrRange.Split('-');
    23. if (IPv4AddressHelper.ConvertToInt32(IPAddress.Parse(range[0])) >= IPv4AddressHelper.ConvertToInt32(IPAddress.Parse(range[1])))
    24. isValid = false;
    25. continue;
    26. }
    27. // like 192.168.[50-100].1
    28. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressSpecialRangeRegex))
    29. {
    30. string[] octets = ipOrRange.Split('.');
    31. foreach (string octet in octets)
    32. {
    33. // Match [50-100]
    34. if (Regex.IsMatch(octet, RegexHelper.SpecialRangeRegex))
    35. {
    36. // [50-100] --> {"50","100"}
    37. string[] rangeNumber = octet.Substring(1, octet.Length - 2).Split('-');
    38. if (int.Parse(rangeNumber[0]) > int.Parse(rangeNumber[1]))
    39. isValid = false;
    40. }
    41. }
    42. continue;
    43. }
    44. isValid = false;
    45. }
    46. if (isValid)
    47. return ValidationResult.ValidResult;
    48. else
    49. return new ValidationResult(false, Application.Current.Resources["String_ValidateError_EnterValidIPScanRange"] as string);
    50. }
    51. }
    52. }



    Zur Auflösung der Range in IP-Adressen... (Ab Zeile 58)
    Spoiler anzeigen

    C#-Quellcode

    1. namespace NETworkManager.Helpers
    2. {
    3. public static class IPScanRangeHelper
    4. {
    5. public static Task<IPAddress[]> ConvertIPRangeToIPAddressesAsync(string ipRange, CancellationToken cancellationToken)
    6. {
    7. return Task.Run(() => ConvertIPRangeToIPAddresses(ipRange, cancellationToken), cancellationToken);
    8. }
    9. public static IPAddress[] ConvertIPRangeToIPAddresses(string ipRange, CancellationToken cancellationToken)
    10. {
    11. ConcurrentBag<IPAddress> bag = new ConcurrentBag<IPAddress>();
    12. ParallelOptions parallelOptions = new ParallelOptions()
    13. {
    14. CancellationToken = cancellationToken
    15. };
    16. foreach (string ipOrRange in ipRange.Replace(" ", "").Split(';'))
    17. {
    18. // Match 192.168.0.1
    19. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressRegex))
    20. bag.Add(IPAddress.Parse(ipOrRange));
    21. // Match 192.168.0.0/24
    22. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressCidrRegex) || Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressSubnetmaskRegex))
    23. {
    24. string[] subnet = ipOrRange.Split('/');
    25. IPAddress ip = IPAddress.Parse(subnet[0]);
    26. IPAddress subnetmask = int.TryParse(subnet[1], out int cidr) ? IPAddress.Parse(SubnetmaskHelper.ConvertCidrToSubnetmask(cidr)) : IPAddress.Parse(subnet[1]);
    27. IPAddress networkAddress = SubnetHelper.GetIPv4NetworkAddress(ip, subnetmask);
    28. IPAddress broadcast = SubnetHelper.GetIPv4Broadcast(ip, subnetmask);
    29. Parallel.For(IPv4AddressHelper.ConvertToInt32(networkAddress), IPv4AddressHelper.ConvertToInt32(broadcast) + 1, parallelOptions, i =>
    30. {
    31. bag.Add(IPv4AddressHelper.ConvertFromInt32(i));
    32. parallelOptions.CancellationToken.ThrowIfCancellationRequested();
    33. });
    34. }
    35. // Match 192.168.0.0 - 192.168.0.100
    36. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressRangeRegex))
    37. {
    38. string[] range = ipOrRange.Split('-');
    39. Parallel.For(IPv4AddressHelper.ConvertToInt32(IPAddress.Parse(range[0])), IPv4AddressHelper.ConvertToInt32(IPAddress.Parse(range[1])) + 1, parallelOptions, i =>
    40. {
    41. bag.Add(IPv4AddressHelper.ConvertFromInt32(i));
    42. parallelOptions.CancellationToken.ThrowIfCancellationRequested();
    43. });
    44. }
    45. // Convert 192.168.[50-100].1 to 192.168.50.1, 192.168.51.1, 192.168.52.1, etc.
    46. if (Regex.IsMatch(ipOrRange, RegexHelper.IPv4AddressSpecialRangeRegex))
    47. {
    48. string[] octets = ipOrRange.Split('.');
    49. List<List<int>> list = new List<List<int>>();
    50. // Go through each octet...
    51. for (int i = 0; i < octets.Length; i++)
    52. {
    53. List<int> innerList = new List<int>();
    54. // Create a range for each octet
    55. if (Regex.IsMatch(octets[i], RegexHelper.SpecialRangeRegex))
    56. {
    57. string[] rangeNumbers = octets[i].Substring(1, octets[i].Length - 2).Split('-');
    58. for (int j = int.Parse(rangeNumbers[0]); j < (int.Parse(rangeNumbers[1]) + 1); j++)
    59. {
    60. innerList.Add(j);
    61. }
    62. }
    63. else
    64. {
    65. innerList.Add(int.Parse(octets[i]));
    66. }
    67. list.Add(innerList);
    68. }
    69. // Build the new ipv4
    70. foreach (int i in list[0])
    71. {
    72. foreach (int j in list[1])
    73. {
    74. foreach (int k in list[2])
    75. {
    76. foreach (int h in list[3])
    77. {
    78. bag.Add(IPAddress.Parse(string.Format("{0}.{1}.{2}.{3}", i, j, k, h)));
    79. }
    80. }
    81. }
    82. }
    83. }
    84. }
    85. return bag.ToArray();
    86. }
    87. }
    88. }
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!
    @BornToBeRoot Wenn Du jetzt noch meine Frage beantwortest:

    RodFromGermany schrieb:

    Wie ganz genau sehen denn Deine möglichen Eingaben aus?
    kann jemand, der ein vergleichbares Problem hat und von Frau Google hier her geleitet wird, sein Problem ebenfalls lösen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    tja, und mit dem Github-Link kann ich auch nix anfangen
    Error 1 The name 'RegexHelper' does not exist in the current context C:\Programming\VS13\FormsCs\IpRangeParser\IpRangeParser\IPScanRangeHelper.cs 23 30 IpRangeParser
    Error 9 The name 'SubnetmaskHelper' does not exist in the current context C:\Programming\VS13\FormsCs\IpRangeParser\IpRangeParser\IPScanRangeHelper.cs 30 80 IpRangeParser
    Error 11 The name 'SubnetHelper' does not exist in the current context C:\Programming\VS13\FormsCs\IpRangeParser\IpRangeParser\IPScanRangeHelper.cs 31 28 IpRangeParserError 13 The name 'IPv4AddressHelper' does not exist in the current context C:\Programming\VS13\FormsCs\IpRangeParser\IpRangeParser\IPScanRangeHelper.cs 33 14 IpRangeParser
    @RodFromGermany

    Als Eingabe gibt es:

    192.168.0.1 (normale IP)
    192.168.0.0/24 und 192.168.0.0/255.255.255.0(Subnetze)
    192.168.0.0 - 192.168.0.100 (IP range)
    192.168.[0-100].1 (z.B. Gateways)

    Mehrere Eingaben mit ; getrennt, also 192.168.0.0/24; 172.16.0.10




    Daraus wird dann eine Liste von IPs generiert und anschließend diese gescannt.

    @ErfinderDesRades

    Was soll nicht funktionieren? Womit öffnest du denn den Link?
    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!
    ich hab den code aus dem Browser kopiert in eine c#-klasse: Fehlermeldungen sieh post#10

    ich hab auch das ganze projekt von github gezogen, kompiliert aber auch nicht. Fehlen vmtl. endlos Bibliotheken.
    Aber ich will mir auch nicht meine Festplatte voll-installieren nur um deine Ip-Spezial-Grammatik testen zu können.

    aber auch sowas:

    C#-Quellcode

    1. IPAddress subnetmask = int.TryParse(subnet[1], out int cidr) ? IPAddress.Parse(SubnetmaskHelper.ConvertCidrToSubnetmask(cidr)) : IPAddress.Parse(subnet[1]);
    also auf meim System geht das nicht: int.TryParse(subnet[1], out int cidr)

    ErfinderDesRades schrieb:

    ich hab den code aus dem Browser kopiert in eine c#-klasse: Fehlermeldungen sieh post#10


    Ist ja klar... da sind noch andere Klassen als abhängigkeit im meinem Projekt (Regex, Helper, usw.)...



    Das Projekt kompiliert ohne Probleme (zumindest der Master), du musst halt die Packete (MahApps.Metro, + Iconpacks, Dragablz) via Nuget installieren (Rechtklick auf das Projekt im Projektexplorer: "Restore Nuget Packeges")

    ErfinderDesRades schrieb:

    also auf meim System geht das nicht: int.TryParse(subnet[1], out int cidr)


    C# 7

    docs.microsoft.com/de-de/dotne…ds/out-parameter-modifier
    dotnetperls.com/out

    NETworkManager - A powerful tool for managing networks and troubleshoot network problems!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „BornToBeRoot“ ()

    so, habich jetzt die nötigen Dateien in ein eigenes Projekt kopiert, und geht.
    und geht auch richtig!
    müssteste halt noch drankommentieren, iwie eine Grammatik-Definition, und v.a., dass es im Fail-Fall keine Exception, sondern nur eine leere IpAddressen-Liste.

    Und das mit dem Threading bringt an dieser Stelle sicher keinen messbaren Zeitgewinn.