Helper in the SboxSuperuser alt-account tracking code. Normalizes an IP address string using regexes instead of System.Net, strips the port, lowercases IPv6, and returns null for loopback, invalid octets or non-address text.
using System.Text.RegularExpressions;
namespace SboxSuperuser.Core.Alts;
/// <summary>
/// Recognises the text of an IP address without System.Net, which s&box's code whitelist doesn't allow. Ports are
/// dropped and loopback addresses ignored, so the same network gives the same text.
/// </summary>
internal static class IpAddress
{
private static readonly Regex Ipv4 = new( @"^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})(:\d+)?$", RegexOptions.CultureInvariant );
private static readonly Regex Ipv6 = new( @"^\[?([0-9a-fA-F:]{2,39})\]?(:\d+)?$", RegexOptions.CultureInvariant );
/// <summary>The address without its port, lowercase; null for anything else, such as a Steam ID or loopback.</summary>
internal static string Normalize( string address )
{
if ( string.IsNullOrWhiteSpace( address ) ) return null;
if ( Ipv4.Match( address.Trim() ) is { Success: true } v4 )
{
var parts = Enumerable.Range( 1, 4 ).Select( group => int.Parse( v4.Groups[ group ].Value ) ).ToArray();
if ( parts.Any( part => part > 255 ) || parts[ 0 ] == 127 ) return null;
return string.Join( '.', parts );
}
if ( Ipv6.Match( address.Trim() ) is { Success: true } v6 && v6.Groups[ 1 ].Value.Contains( ':' ) )
{
var ip = v6.Groups[ 1 ].Value.ToLowerInvariant();
return ip is "::1" ? null : ip;
}
return null;
}
}