1
0
Форкнуть 0

Implement WebClientIPHeader telemetry initializer

This commit is contained in:
Sergey Kanzhelev 2015-03-25 16:28:41 -07:00
Родитель f6f9c81cac
Коммит 3624ac7705
1 изменённых файлов: 118 добавлений и 9 удалений

Просмотреть файл

@ -9,15 +9,69 @@ namespace Microsoft.ApplicationInsights.AspNet.DataCollection
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Interfaces;
using Microsoft.ApplicationInsights.AspNet.Implementation;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net;
/// <summary>
/// This telemetry initializer extracts client IP address and populates telemetry.Context.Location.Ip property.
/// Lot's of code reuse from Microsoft.ApplicationInsights.Extensibility.Web.TelemetryInitializers.WebClientIpHeaderTelemetryInitializer
/// </summary>
public class WebClientIpHeaderTelemetryInitializer : ITelemetryInitializer
{
private IServiceProvider serviceProvider;
public WebClientIpHeaderTelemetryInitializer(IServiceProvider serviceProvider)
private readonly char[] HeaderValuesSeparatorDefault = new char[] { ',' };
private const string HeaderNameDefault = "X-Forwarded-For";
private char[] headerValueSeparators;
private readonly ICollection<string> headerNames;
public WebClientIpHeaderTelemetryInitializer(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}
this.headerNames = new List<string>();
this.HeaderNames.Add(HeaderNameDefault);
this.UseFirstIp = true;
this.headerValueSeparators = HeaderValuesSeparatorDefault;
}
/// <summary>
/// Gets or sets comma separated list of request header names that is used to check client id.
/// </summary>
public ICollection<string> HeaderNames
{
get
{
return this.headerNames;
}
}
/// <summary>
/// Gets or sets a header values separator.
/// </summary>
public string HeaderValueSeparators
{
get
{
return string.Concat(this.headerValueSeparators);
}
set
{
if (!string.IsNullOrEmpty(value))
{
this.headerValueSeparators = value.ToCharArray();
}
}
}
/// <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; }
public void Initialize(ITelemetry telemetry)
{
@ -30,18 +84,73 @@ namespace Microsoft.ApplicationInsights.AspNet.DataCollection
{
var context = this.serviceProvider.GetService<HttpContextHolder>().Context;
var connectionFeature = context.GetFeature<IHttpConnectionFeature>();
if (connectionFeature != null)
string resultIp = null;
foreach (var name in this.HeaderNames)
{
string ip = connectionFeature.RemoteIpAddress.ToString();
request.Context.Location.Ip = ip;
if (request != telemetry)
var headerValue = context.Request.Headers[name];
if (!string.IsNullOrEmpty(headerValue))
{
telemetry.Context.Location.Ip = ip;
var ip = GetIpFromHeader(headerValue);
ip = CutPort(ip);
if (IsCorrectIpAddress(ip))
{
resultIp = ip;
break;
}
}
}
if (string.IsNullOrEmpty(resultIp))
{
var connectionFeature = context.GetFeature<IHttpConnectionFeature>();
if (connectionFeature != null)
{
resultIp = connectionFeature.RemoteIpAddress.ToString();
}
}
request.Context.Location.Ip = resultIp;
telemetry.Context.Location.Ip = resultIp;
}
}
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();
}
}
}