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.