IP Adress Change Notifications

I’ve always had some sort of server at my house, for various reasons, but one thing that I never have to go along with those servers is a static IP address. Either they are way too expensive and not worth it for something that I am not making any money from, or they are completely unavailable. One day, hopefully my ISP will provide them for something other than a huge monthly business package, but that is probably wishful thinking.

Because I have servers, and this dynamic IP address, every once in a while my IP address changes. It’s much less frequent than I thought it would be, but it still happens from time to time. And since it doesn’t happen often, it’s usually one of those things I don’t notice until I am away from home and trying to access something on one of my servers, with no way to check the new IP address. I also try to keep some DNS records updated with the address, for easy reference.

So, my solution was to make a simple WebAPI service that simply returns the clients IP address, and then to have a simple application that consumes that service and keeps track of the addresses that are returned. Once a change is found, it will shoot out an e-mail to me with the new address and a reference to the old address. Then I can update my DNS, etc… No more unknown address changes. And if it changes while I’m out of the house, I will still be able to get access to my systems.

The WebAPI is very simple, just a Get() method with some very simple IP logic in it.

public class IpPingController : ApiController
{
	public string Get()
	{
		string ipAddr = HttpContext.Current.Request.UserHostAddress;
		if(string.IsNullOrEmpty(ipAddr)) {
			object property;
			Request.Properties.TryGetValue(typeof(RemoteEndpointMessageProperty).FullName, out property);
			RemoteEndpointMessageProperty remoteProperty = property as RemoteEndpointMessageProperty;
			if (remoteProperty != null) {
				ipAddr = remoteProperty.Address;
			}
		}
		return ipAddr;
	}
}

You can test this service by hitting this address in your browser, http://www.santsys.com/api/ipping/.

The application is a very simple console application that I run using windows scheduled tasks. I have it setup to run every 2 hours.

private static Configuration _cfg = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
public static Configuration Config { get { return _cfg; } }
public static string ApiAddress { get { return ConfigurationManager.AppSettings["IpPingAddress"]; } }
public static string PreviousIpAddress
{
	get { return ConfigurationManager.AppSettings["PreviousIpAddress"]; }
	set { _cfg.AppSettings.Settings["PreviousIpAddress"].Value = value; }
}
public static string LastUpdate
{
	get { return ConfigurationManager.AppSettings["LastCheck"]; }
	set { _cfg.AppSettings.Settings["LastCheck"].Value = value; }
}
public static string SmtpHost { get { return ConfigurationManager.AppSettings["SmtpHost"]; } }
public static int SmtpPort
{
	get
	{
		string port = ConfigurationManager.AppSettings["SmtpPort"];
		int iPort;
		if (int.TryParse(port, out iPort)) {
			return iPort;
		}
		return 25;
	}
}
public static string SmtpUser { get { return ConfigurationManager.AppSettings["SmtpUser"]; } }
public static string SmtpPassword { get { return ConfigurationManager.AppSettings["SmtpPassword"]; } }
public static string SmtpFrom { get { return ConfigurationManager.AppSettings["SmtpFrom"]; } }
public static string SmtpTo { get { return ConfigurationManager.AppSettings["SmtpTo"]; } }

static void Main(string[] args)
{
	try {
		DoWork();

#if DEBUG
		Console.Write("\r\nPress any key to exit.");
		Console.ReadKey();
#endif
	}
	catch (Exception ex) {
		Console.WriteLine("{0}\r\n\r\n{1}", ex.Message, ex.StackTrace);
	}
}

public static void DoWork()
{
	Version ver = Assembly.GetAssembly(typeof(Program)).GetName().Version;
	Console.WriteLine("IpPing v{0}.{1} build {2}", ver.Major, ver.Minor, ver.Revision);
	Console.WriteLine("\r\nLast Run: {0} @ {1}", PreviousIpAddress, LastUpdate);
	Console.Write("\r\n");

	if (string.IsNullOrEmpty(ApiAddress)) {
		Console.WriteLine("Error: No Api Address found in configuration. (IpPingAddress)");
		return;
	}

	HttpClient client = new HttpClient();
	client.BaseAddress = new Uri(ApiAddress);

	// Add an Accept header for JSON format.
	client.DefaultRequestHeaders.Accept.Add(
			new MediaTypeWithQualityHeaderValue("application/json"));

	HttpResponseMessage response = client.GetAsync("api/IpPing/").Result;
	if (response.IsSuccessStatusCode) {
		var ipAddrInfo = response.Content.ReadAsAsync<string>().Result;

		Task emailUpdate = null;

		// if the IP Address has not changed
		if (PreviousIpAddress != ipAddrInfo) {
			Console.WriteLine("New IP address detected.\r\n\tOld Address:{0}\r\n\tNew Address:{1}\r\n\r\nSending notification.", PreviousIpAddress, ipAddrInfo);
			emailUpdate = SendUpdateEmail(ipAddrInfo, PreviousIpAddress);
			PreviousIpAddress = ipAddrInfo;
		}

		LastUpdate = DateTime.Now.ToString();
		Config.Save(ConfigurationSaveMode.Modified);
		ConfigurationManager.RefreshSection("appSettings");
		
		// wait for the email to send, if one is being sent
		if (emailUpdate != null) {
			emailUpdate.Wait();
		}
	}
	else {
		Console.WriteLine("Error: {0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
	}
}

public static Task SendUpdateEmail(string newIp, string oldIp)
{
	return Task.Factory.StartNew(() => {
		try {
			SmtpClient smtpClient = new SmtpClient(SmtpHost, SmtpPort);
			if (!string.IsNullOrEmpty(SmtpUser) && !string.IsNullOrEmpty(SmtpPassword)) {
				smtpClient.UseDefaultCredentials = false;
				smtpClient.Credentials = new NetworkCredential(SmtpUser, SmtpPassword);
			}
			MailMessage msg = new MailMessage(SmtpFrom, SmtpTo);
			msg.IsBodyHtml = true;
			msg.Priority = MailPriority.High;
			msg.Headers.Add("X-IP-PING", "Automated message from IP PING");
			msg.Headers.Add("X-IP-PING-ADDRESS", newIp);
			msg.Subject = "Ip Address Changed!";
			msg.Body =
					"<style type=\"text/css\">body, p { color: #555; font-size: 12px; font-family: Arial; } a, a:link, a:visited { color: #486db5; text-decoration:none;}</style>"
				+ "<p style=\"color: #555;font-size: 12px; font-family: Arial;\">This is a notification from Ip Ping. Your IP Address has changed.</p>"
				+ "<p style=\"color: #555;font-size: 12px; font-family: Arial;\">Your new IP Address is <b style=\"font-size: 14px; color: #000;\">" + newIp + "</b></p>"
				+ "<p style=\"color: #555;font-size: 12px; font-family: Arial;\">Your old IP Address was " + (string.IsNullOrEmpty(oldIp) ? "(blank)" : oldIp) + "</p>"
				+ "<br /><br /><p style=\"color: #666;font-size: 10px; font-family: Arial;\">© " + DateTime.Now.Year.ToString() + " Santomieri Systems - <a href=\"http://www.santsys.com/\">www.santsys.com</a></p>";

			smtpClient.Send(msg);
		}
		catch (Exception ex) {
			Console.WriteLine("{0}\r\n\r\n{1}", ex.Message, ex.StackTrace);
		}
	});
}

That’s pretty much it. Feel free to use this if it will help you out. I know it solved a lot of issues for me.

Leave a Reply

Your email address will not be published. Required fields are marked *