Log user IP addresses.

This commit is contained in:
Greg Edwards
2022-02-08 02:53:50 -05:00
parent e4f7511abe
commit db1ff08b42
10 changed files with 74 additions and 24 deletions

View File

@@ -12,6 +12,10 @@
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
<appSettings>
<add key="AllowedProxies" value="::1,127.0.0.1,178.62.43.212,195.201.236.139,172.104.88.237" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<!--

View File

@@ -122,6 +122,7 @@
</Compile>
<Compile Include="src\AppStateHelper.cs" />
<Compile Include="src\FakeOpponentGenerator4.cs" />
<Compile Include="src\IpAddressHelper.cs" />
<Compile Include="syachi2ds.ashx.cs">
<DependentUpon>syachi2ds.ashx</DependentUpon>
</Compile>

View File

@@ -56,7 +56,7 @@ namespace PkmnFoundations.GTS
#endif
byte[] profileBinary = new byte[100];
Array.Copy(data, 0, profileBinary, 0, 100);
TrainerProfile4 profile = new TrainerProfile4(pid, profileBinary);
TrainerProfile4 profile = new TrainerProfile4(pid, profileBinary, IpAddressHelper.GetIpAddress(context.Request));
Database.Instance.GamestatsSetProfile4(profile);
#if !DEBUG
}
@@ -124,7 +124,7 @@ namespace PkmnFoundations.GTS
// todo: find out the meaning of this request.
// is it simply done to check whether the GTS is online?
Database.Instance.GamestatsBumpProfile4(pid);
Database.Instance.GamestatsBumpProfile4(pid, IpAddressHelper.GetIpAddress(context.Request));
response.Write(new byte[] { 0x01, 0x00 }, 0, 2);
break;
@@ -510,7 +510,7 @@ namespace PkmnFoundations.GTS
SessionManager.Remove(session);
// Probably an availability/status code.
Database.Instance.GamestatsBumpProfile4(pid);
Database.Instance.GamestatsBumpProfile4(pid, IpAddressHelper.GetIpAddress(context.Request));
// Response codes:
// 0x00: BSOD

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
namespace PkmnFoundations.GTS
{
public static class IpAddressHelper
{
public static string GetIpAddress(HttpRequest request)
{
var allowedProxies = ConfigurationManager.AppSettings["AllowedProxies"].Split(',').Select(s => s.Trim());
string hostAddress = RemovePort(request.UserHostAddress.Trim());
if (!allowedProxies.Contains(hostAddress)) return hostAddress; // return real IP if not a blessed proxy
var xForwardedFor = request.Headers["X-Forwarded-For"].Split(',').Select(s => RemovePort(s.Trim()));
foreach (string s in xForwardedFor.Reverse())
{
if (!allowedProxies.Contains(s)) return s; // return LAST IP in the proxy chain that's not trusted. (everything coming earlier could be spoofed)
}
// these conditions can only happen if the real user is at a blessed proxy IP address. (probably localhost)
return xForwardedFor.FirstOrDefault() ?? hostAddress;
}
private static string RemovePort(string ip)
{
if (ip.Contains(':') && ip.Contains('.'))
return ip.Substring(0, ip.IndexOf(':'));
else
return ip;
}
}
}

View File

@@ -56,7 +56,7 @@ namespace PkmnFoundations.GTS
// Specifically, email, notification status, and the two secrets appear to always be 0.
byte[] profileBinary = new byte[100];
Array.Copy(request, 0, profileBinary, 0, 100);
TrainerProfile5 profile = new TrainerProfile5(pid, profileBinary);
TrainerProfile5 profile = new TrainerProfile5(pid, profileBinary, IpAddressHelper.GetIpAddress(context.Request));
Database.Instance.GamestatsSetProfile5(profile);
#if !DEBUG
}

View File

@@ -1056,12 +1056,12 @@ namespace PkmnFoundations.Data
#endregion
#region Other Gamestats 4
public override bool GamestatsBumpProfile4(int pid)
public override bool GamestatsBumpProfile4(int pid, string ip_address)
{
return WithTransaction(tran => GamestatsBumpProfile4(tran, pid));
return WithTransaction(tran => GamestatsBumpProfile4(tran, pid, ip_address));
}
public bool GamestatsBumpProfile4(MySqlTransaction tran, int pid)
public bool GamestatsBumpProfile4(MySqlTransaction tran, int pid, string ip_address)
{
bool exists = Convert.ToSByte(tran.ExecuteScalar("SELECT EXISTS(SELECT * FROM GtsProfiles4 WHERE pid = @pid)",
new MySqlParameter("@pid", pid))) != 0;
@@ -1069,13 +1069,18 @@ namespace PkmnFoundations.Data
if (exists)
{
return tran.ExecuteNonQuery("UPDATE GtsProfiles4 SET " +
"TimeUpdated = UTC_TIMESTAMP() WHERE pid = @pid", new MySqlParameter("@pid", pid)) > 0;
"TimeUpdated = UTC_TIMESTAMP(), IpAddress = @ip_address " +
"WHERE pid = @pid",
new MySqlParameter("@ip_address", ip_address),
new MySqlParameter("@pid", pid)) > 0;
}
else
{
return tran.ExecuteNonQuery("INSERT INTO GtsProfiles4 " +
"(pid, TimeAdded, TimeUpdated) VALUES (@pid, UTC_TIMESTAMP(), " +
"UTC_TIMESTAMP())", new MySqlParameter("@pid", pid)) > 0;
"(pid, TimeAdded, TimeUpdated, IpAddress) VALUES (@pid, UTC_TIMESTAMP(), " +
"UTC_TIMESTAMP(), @ip_address)",
new MySqlParameter("@pid", pid),
new MySqlParameter("@ip_address", ip_address)) > 0;
}
}
@@ -1104,7 +1109,8 @@ namespace PkmnFoundations.Data
new MySqlParameter("@email", profile.Email),
new MySqlParameter("@has_notifications", profile.HasNotifications),
new MySqlParameter("@client_secret", profile.ClientSecret),
new MySqlParameter("@mail_secret", profile.MailSecret)
new MySqlParameter("@mail_secret", profile.MailSecret),
new MySqlParameter("@ip_address", profile.IpAddress)
};
if (exists)
@@ -1114,7 +1120,7 @@ namespace PkmnFoundations.Data
"Region = @region, OT = @ot, Name = @name, MacAddress = @mac_address, " +
"Email = @email, HasNotifications = @has_notifications, " +
"ClientSecret = @client_secret, MailSecret = @mail_secret, " +
"ParseVersion = 2, TimeUpdated = UTC_TIMESTAMP() " +
"IpAddress = @ip_address, ParseVersion = 2, TimeUpdated = UTC_TIMESTAMP() " +
"WHERE pid = @pid", _params) > 0;
}
else
@@ -1122,10 +1128,10 @@ namespace PkmnFoundations.Data
return tran.ExecuteNonQuery("INSERT INTO GtsProfiles4 " +
"(pid, Data, Version, Language, Country, Region, OT, Name, " +
"MacAddress, Email, HasNotifications, ClientSecret, MailSecret, " +
"ParseVersion, TimeAdded, TimeUpdated) VALUES " +
"IpAddress, ParseVersion, TimeAdded, TimeUpdated) VALUES " +
"(@pid, @data, @version, @language, @country, @region, @ot, " +
"@name, @mac_address, @email, @has_notifications, " +
"@client_secret, @mail_secret, 2, UTC_TIMESTAMP(), UTC_TIMESTAMP())", _params) > 0;
"@client_secret, @mail_secret, @ip_address, 2, UTC_TIMESTAMP(), UTC_TIMESTAMP())", _params) > 0;
}
}
#endregion
@@ -2025,7 +2031,8 @@ namespace PkmnFoundations.Data
new MySqlParameter("@email", profile.Email),
new MySqlParameter("@has_notifications", profile.HasNotifications),
new MySqlParameter("@client_secret", profile.ClientSecret),
new MySqlParameter("@mail_secret", profile.MailSecret)
new MySqlParameter("@mail_secret", profile.MailSecret),
new MySqlParameter("@ip_address", profile.IpAddress)
};
if (exists)
@@ -2035,7 +2042,7 @@ namespace PkmnFoundations.Data
"Region = @region, OT = @ot, Name = @name, MacAddress = @mac_address, " +
"Email = @email, HasNotifications = @has_notifications, " +
"ClientSecret = @client_secret, MailSecret = @mail_secret, " +
"ParseVersion = 2, TimeUpdated = UTC_TIMESTAMP() " +
"IpAddress = @ip_address, ParseVersion = 2, TimeUpdated = UTC_TIMESTAMP() " +
"WHERE pid = @pid", _params) > 0;
}
else
@@ -2043,10 +2050,10 @@ namespace PkmnFoundations.Data
return tran.ExecuteNonQuery("INSERT INTO GtsProfiles5 " +
"(pid, Data, Version, Language, Country, Region, OT, Name, " +
"MacAddress, Email, HasNotifications, ClientSecret, MailSecret, " +
"ParseVersion, TimeAdded, TimeUpdated) VALUES " +
"IpAddress, ParseVersion, TimeAdded, TimeUpdated) VALUES " +
"(@pid, @data, @version, @language, @country, @region, @ot, " +
"@name, @mac_address, @email, @has_notifications, " +
"@client_secret, @mail_secret, 2, UTC_TIMESTAMP(), UTC_TIMESTAMP())", _params) > 0;
"@client_secret, @mail_secret, @ip_address, 2, UTC_TIMESTAMP(), UTC_TIMESTAMP())", _params) > 0;
}
}
#endregion

View File

@@ -93,7 +93,7 @@ namespace PkmnFoundations.Data
#endregion
#region Other Gamestats 4
public abstract bool GamestatsBumpProfile4(int pid);
public abstract bool GamestatsBumpProfile4(int pid, string ip_address);
public abstract bool GamestatsSetProfile4(TrainerProfile4 profile);
#endregion

View File

@@ -11,7 +11,7 @@ namespace PkmnFoundations.Structures
{
}
public TrainerProfile4(int pid, byte[] data) : base(pid, data)
public TrainerProfile4(int pid, byte[] data, string ip_address) : base(pid, data, ip_address)
{
}
@@ -25,7 +25,7 @@ namespace PkmnFoundations.Structures
public TrainerProfile4 Clone()
{
return new TrainerProfile4(PID, Data.ToArray());
return new TrainerProfile4(PID, Data.ToArray(), IpAddress);
}
}
}

View File

@@ -11,7 +11,7 @@ namespace PkmnFoundations.Structures
{
}
public TrainerProfile5(int pid, byte[] data) : base(pid, data)
public TrainerProfile5(int pid, byte[] data, string ip_address) : base(pid, data, ip_address)
{
}
@@ -25,7 +25,7 @@ namespace PkmnFoundations.Structures
public TrainerProfile5 Clone()
{
return new TrainerProfile5(PID, Data.ToArray());
return new TrainerProfile5(PID, Data.ToArray(), IpAddress);
}
}
}

View File

@@ -13,17 +13,19 @@ namespace PkmnFoundations.Structures
}
protected TrainerProfileBase(int pid, byte[] data)
protected TrainerProfileBase(int pid, byte[] data, string ip_address)
{
if (data.Length != 100) throw new ArgumentException("Profile data must be 100 bytes.");
PID = pid;
Data = data;
IpAddress = ip_address;
}
// todo: encapsulate these so calculated fields are always correct
public int PID;
public byte[] Data; // 100 bytes
public string IpAddress;
public Versions Version
{