Skip to content

Instantly share code, notes, and snippets.

@lmolkova
Created August 18, 2020 16:53
Show Gist options
  • Save lmolkova/b5fe5a1a48144f0caf95addcb6f86be6 to your computer and use it in GitHub Desktop.
Save lmolkova/b5fe5a1a48144f0caf95addcb6f86be6 to your computer and use it in GitHub Desktop.
public class ClientIpHeaderTelemetryInitializerCopy : TelemetryInitializerBase
{
private const string HeaderNameDefault = "X-Forwarded-For";
private readonly char[] headerValuesSeparatorDefault = { ',' };
private char[] headerValueSeparators;
/// <summary>
/// Initializes a new instance of the <see cref="ClientIpHeaderTelemetryInitializer" /> class.
/// </summary>
/// <param name="httpContextAccessor">Accessor to provide HttpContext corresponding to telemetry items.</param>
public ClientIpHeaderTelemetryInitializerCopy(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
{
this.HeaderNames = new List<string>();
this.HeaderNames.Add(HeaderNameDefault);
this.UseFirstIp = true;
this.headerValueSeparators = this.headerValuesSeparatorDefault;
}
/// <summary>
/// Gets comma separated list of request header names that is used to check client id.
/// </summary>
public ICollection<string> HeaderNames { get; }
/// <summary>
/// Gets or sets a value indicating whether the first or the last IP should be used from the lists of IPs in the header.
/// </summary>
public bool UseFirstIp { get; set; }
/// <inheritdoc />
protected override void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry)
{
if (telemetry == null)
{
throw new ArgumentNullException(nameof(telemetry));
}
if (requestTelemetry == null)
{
throw new ArgumentNullException(nameof(requestTelemetry));
}
if (string.IsNullOrEmpty(requestTelemetry.Context.Location.Ip))
{
string resultIp = null;
if (platformContext == null)
{
throw new ArgumentNullException(nameof(platformContext));
}
if (platformContext.Request?.Headers != null)
{
foreach (var name in this.HeaderNames)
{
string headerValue = platformContext.Request.Headers[name];
if (!string.IsNullOrEmpty(headerValue))
{
var ip = this.GetIpFromHeader(headerValue);
ip = CutPort(ip);
if (IsCorrectIpAddress(ip))
{
resultIp = ip;
break;
}
}
}
}
if (string.IsNullOrEmpty(resultIp))
{
var connectionFeature = platformContext.Features.Get<IHttpConnectionFeature>();
if (connectionFeature?.RemoteIpAddress != null)
{
resultIp = connectionFeature.RemoteIpAddress.ToString();
}
}
requestTelemetry.Context.Location.Ip = resultIp;
}
telemetry.Context.Location.Ip = requestTelemetry.Context.Location.Ip;
}
private static string CutPort(string address)
{
// For Web sites in Azure header contains ip address with port e.g. 50.47.87.223:54464
int portSeparatorIndex = address.IndexOf(":", StringComparison.OrdinalIgnoreCase);
if (portSeparatorIndex > 0)
{
return address.Substring(0, portSeparatorIndex);
}
return address;
}
private static bool IsCorrectIpAddress(string address)
{
IPAddress outParameter;
address = address.Trim();
// Core SDK does not support setting Location.Ip to malformed ip address
if (IPAddress.TryParse(address, out outParameter))
{
// Also SDK supports only ipv4!
if (outParameter.AddressFamily == AddressFamily.InterNetwork)
{
return true;
}
}
return false;
}
private string GetIpFromHeader(string clientIpsFromHeader)
{
var ips = clientIpsFromHeader.Split(this.headerValueSeparators, StringSplitOptions.RemoveEmptyEntries);
return this.UseFirstIp ? ips[0].Trim() : ips[ips.Length - 1].Trim();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment