/* * MinIO .NET Library for Amazon S3 Compatible Cloud Storage, (C) 2020 MinIO, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System.Globalization; using System.Net; namespace Minio.Helper; public static class BuilderUtil { public static bool IsAwsDualStackEndpoint(string endpoint) { if (string.IsNullOrEmpty(endpoint)) throw new ArgumentException($"'{nameof(endpoint)}' cannot be null or empty.", nameof(endpoint)); return endpoint.Contains(".dualstack.", StringComparison.OrdinalIgnoreCase); } public static bool IsAwsAccelerateEndpoint(string endpoint) { if (string.IsNullOrEmpty(endpoint)) throw new ArgumentException($"'{nameof(endpoint)}' cannot be null or empty.", nameof(endpoint)); return endpoint.StartsWith("s3-accelerate.", StringComparison.OrdinalIgnoreCase); } public static bool IsAwsEndpoint(string endpoint) { if (string.IsNullOrEmpty(endpoint)) throw new ArgumentException($"'{nameof(endpoint)}' cannot be null or empty.", nameof(endpoint)); return (endpoint.StartsWith("s3.", StringComparison.OrdinalIgnoreCase) || IsAwsAccelerateEndpoint(endpoint)) && (endpoint.EndsWith(".amazonaws.com", StringComparison.OrdinalIgnoreCase) || endpoint.EndsWith(".amazonaws.com.cn", StringComparison.OrdinalIgnoreCase)); } public static bool IsChineseDomain(string host) { if (string.IsNullOrEmpty(host)) throw new ArgumentException($"'{nameof(host)}' cannot be null or empty.", nameof(host)); return host.EndsWith(".cn", StringComparison.OrdinalIgnoreCase); } public static string ExtractRegion(string endpoint) { if (string.IsNullOrEmpty(endpoint)) throw new ArgumentException($"'{nameof(endpoint)}' cannot be null or empty.", nameof(endpoint)); var tokens = endpoint.Split('.'); if (tokens.Length < 2) return null; var token = tokens[1]; // If token is "dualstack", then region might be in next token. if (token.Equals("dualstack", StringComparison.OrdinalIgnoreCase) && tokens.Length >= 3) token = tokens[2]; // If token is equal to "amazonaws", region is not passed in the endpoint. if (token.Equals("amazonaws", StringComparison.OrdinalIgnoreCase)) return null; // Return token as region. return token; } private static bool IsValidSmallInt(string val) { return byte.TryParse(val, out _); } private static bool IsValidOctetVal(string val) { const byte uLimit = 255; return byte.Parse(val, NumberStyles.Integer, CultureInfo.InvariantCulture) <= uLimit; } private static bool IsValidIPv4(string ip) { var posColon = ip.LastIndexOf(':'); if (posColon != -1) ip = ip[..posColon]; var octetsStr = ip.Split('.'); if (octetsStr.Length != 4) return false; var isValidSmallInt = Array.TrueForAll(octetsStr, IsValidSmallInt); if (!isValidSmallInt) return false; return Array.TrueForAll(octetsStr, IsValidOctetVal); } private static bool IsValidIP(string host) { return IPAddress.TryParse(host, out _); } public static bool IsValidHostnameOrIPAddress(string host) { // Let's do IP address check first. if (string.IsNullOrWhiteSpace(host)) return false; // IPv4 first if (IsValidIPv4(host)) return true; // IPv6 or other IP address format if (IsValidIP(host)) return true; // Remove any port in endpoint, in such a case. var posColon = host.LastIndexOf(':'); if (posColon != -1) { try { var port = int.Parse(host.Substring(posColon + 1, host.Length - posColon - 1), CultureInfo.InvariantCulture); } catch (FormatException) { return false; } host = host[..posColon]; } // Check host if it is a hostname. return Uri.CheckHostName(host).ToString().Equals("dns", StringComparison.OrdinalIgnoreCase); } }