A Simple Dynamic IP Service

I thought it would be interesting to see how I could get this site (which is currently running on shared hosting) to interact with a service on another network, the caveat being that the other network is only accessible over a dynamic IP address.

But, Why?

There may be times that I want to go beyond the capabilities of shared hosting, perhaps serve some computationally complex task or maybe test some API. In such rare cases, it would be handy to outsource these capabilities to a device running on my network.

Just use a DDNS

Yes, I could have used a Dynamic Domain Name Service (DDNS), it would be the ideal solution in most cases. Then again, an even better solution would be to use cloud-based services, where I could not only run virtual machines to host my site but also my very own DDNS. However, sometimes it becomes far more rewarding to gain results when working within a set of constraints, than going with the ideal, and at times more costly, solution.

Going down the third-party DDNS route has its own possible set of shortcomings too. For instance, extra and or hidden costs, the provider may accidentally deactivate the account, or the provider may suddenly go out of business.

In any case, my solution seeks to be an acceptable alternative when there is a need to utilise a service running on a Dynamic IP address.

If the reader is familiar with dynamic IP addresses, DDNSs, and their clients, they can skip ahead to “Enabling a Dynamic IP service”. However, if they are not familiar with these topics, continue reading as I provide some high-level understanding on these topics.

The problem with dynamic IPs is that they’re dynamic!

We encounter a ubiquitous piece of technology every day - the humble internet router. For the average person, it’s just a device that provides other devices internet access. However, to understand why there is a need for a DDNS, we must first understand how the router gets an IP address.

Before the router is allowed to provide internet access to devices, it must first make a connection with an ISP (internet service provider). In doing the ISP provides the router with a WAN (Wide Area Network) IP address. The WAN IP address serves as the public-facing address for the router’s local network. The WAN IP address functions in many ways as a postal address given to commercial or residential properties, in that it is an identifiable location where things can be sent from and to. Whenever data leaves the router, the destination address and the router’s IP address are packaged along with the data. When a server receives the package it extracts the information and knows where to send the response to.

Diagram showing how the a router connects the internet via a ISP

The WAN IP addresses assigned to routers are often dynamic, they will change over time. Normally after x amount of days. This is due to there being a limited pool of IP addresses available to any given ISP. To ensure an optimal service the ISP must reallocate IP addresses that are not currently used and those whose maximum allocated time has expired. The change of IP address on a router is unlikely to affect the average internet user, but it will present a challenge for those wanting to host internet-accessible services from their networks. Consider that to host any web-based service reliably, it is important that there is a long-lasting connection available to the service. This is why instead of dynamic IP addresses, web-based services and private networks would ideally like to have a static IP (an address that does not change) address, but this is not always an option.

The reason why DDNS exist

ISP providers are reluctant to give out static IPs to their non-business customers, this is because of limited availability. There may be other reasons as to why a static address cannot be used, but at the very least I have identified one such case. So there does exist the problem of needing to reliably connect to a service that utilises a dynamic IP address.

The most accepted solution to this problem is the DDNS. The job of a DDNS is simply to automatically link a static domain (example.com) or subdomain (foo.example.com) name to a dynamic IP address. A program called a DDNS client will notify the DDNS provider of any change to the router’s IP address. These DDNS clients are often pre-installed on routers or they can be installed to run on the networks server or device.

Diagram depicting a DDNS provider and client

Enabling a Dynamic IP service

I am creating this solution just for the fun of it, and because I believe it has the potential to be useful under certain circumstances.

Limitations

Any solution will have its own set of benefits and limitations. Because I am slightly pessimistic by nature when it comes to the benefits of technology, I tend to focus on the perceived limitations first.

Delayed Update

My solution requires a client, whose function is to check in with the web hosting server. A DDNS client fulfils this type of functionality. So it would have been ideal if I could have used some pre-installed DDNS client running on the router. The reason is that such DDNS clients operate on the firmware level and will automatically make a request to the target server if some change takes place on the router’s IP. This would result in the minimum disruption to the service. I cannot use this type of client, because there is no generic standard DDNS client installed on most routers.

A DDNS client can also run within the LAN, which entails running it on a machine 24/7. This type of client functions by periodically checking in with the DDNS provider. In theory, if we are dealing with a check-in interval of 15 min, and then a change takes place on the router just after the last check-in, then the service will be unavailable for 15 minutes, minus the reconnection time. So there will always exist the possibility of encountering the maximum amount of downtime with this type of client. Yet, this downtime is not as bad as it appears. If the IP address changes after a period of days. I will use 14 days as an example, which equates to 20160 minutes, and the estimated average downtime is around 7 minutes. That service has an uptime of around 99.97%. Which can be considered perfectly acceptable and in line with the uptime promised by many cloud and hosting providers.

My solution will be using a bespoke client, but there are also tried and tested DDNS clients that could have been used as clients. One such client is ddclient. All I want my client to do is send a request to some remote resource every now and again.

IP addresses and Secure Connections

If the service does not use a DDNS then the service is only accessible through an IP address and not a domain name. The repercussions of this are twofold.

First, it makes it harder to seamlessly integrate the service into a web domain. I have to accept that in this respect I am limited in my options, and will have to hide the IP from end users somehow. For now, I can think up three possible ways of getting around this issue, none of which I have fully tested. The first is via a proxy script, where a user makes a request and the script queries the service for data, and then passes it back to the user. This would be ideal for content that is limited in size. The other options would be to provide direct access to data on the service using an iframe or fetching data with JavaScript.

The second repercussion of not using a DDNS is that it makes securing connections more problematic. There are ways and means of securing connections, but they are beyond the scope of this post. On this site, I will mostly be dealing with non-sensitive data, so I am happy with using HTTP for the solutions provided.

The solution

I have two solutions which I have implemented. True to form I tend to over-engineer my first attempt. The main characteristic that distinguishes the two solutions is that the first uses what I call a passive client while the second uses an active one. Both solutions comprise of three main elements. Two are common to both; the client and the IP logger. It is only the third element where there is any major difference.

The passive client solution (first attempt)

Diagram of the first Dynamic IO solution

Client

The client script is located on the same server as the service. It has two modes of operation, the first will send an initial broadcast to the logger script on shared hosting. If an OK response is received, the Client script with transition to listening mode. This mode waits and listens for the target server to periodically contact it. If for whatever reason a response is not received from the target after a given time, then the IP address has likely changed and the client changes back to broadcast mode.

IP Logger

The logger will receive a response from the client, in doing so the logger will extract the sender’s IP, the dynamic IP address. PHP provides a way to acquire the client’s IP address using the $_SERVER['REMOTE_ADDR'] value. If the target server was behind a proxy then $_SERVER['HTTP_X_FORWARDED_FOR'] would be used to get the IP address instead.

When the IP is retrieved, the logger must somehow validate the service. This prevents unwanted parties from hijacking the service and redirecting users to malicious IPs. In the prototype I used a simple key for prototyping purposes, however a proper authentication method would be used in production. When the service is validated the IP address is stored on a database.

Check-in

My hosting provider provides access to running cron jobs (scheduled script execution), the check-in script is assigned to a job that fires every 15 minutes. As it runs it retrieves the IP record from the database, checks the status of the service, and sends a request to the router’s IP. If something goes wrong such as the request timing out, or the service is not found. The script will update the database by changing the status of the service to inactive.

The problem with this solution is that it requires some optional functionality on behalf of the hosting provider and an overly complex client. The next solution is much simpler and can be implemented from scratch within a short amount of time.

The active client solutions

Diagram of the second Dynamic IP solution

The client

Consists of a simple script that sends a request to the logger script on the web host every 15 minutes. This simple script can be run as a cron job on a server.

The Logger

Is almost identical to the first attempt, but instead of recording an active value, a date-time value is stored.

Service Status script

Provides the means for other scripts to check if the service is still active. All it does is look up the recorded IP record and compare the difference between the datetime value recorded and the current time. If enough time has elapsed, it’s assumed that the service is inactive. An active status will return the connection details for the dynamic ip service (IP, port, resource), else the script will return false.

Click on the following links to see the code files first and second solution.

Some considerations

The code links in the post, are that of the first iteration of the solution, a working proof of concept. Little consideration was given to security. So I have not thoroughly tested the scripts to safeguard against the likes of SQL injection, nor have I tested ways of securing connections. These concerns are fairly straightforward to address in further iterations.

Thought should also be given to how such a service may impact the resources provided by the shared hosting provider. My shared hosting places daily limits on resource use. Carelessly moving around large chunks of data over HTTP requests might end up being costly if due consideration is not given.

The user experience of interacting with the service should also be as seamless as possible. There is nothing more jarring than a link or request, suddenly triggering a redirect to some random IP address.

The limitations of the hosting provider should also be taken into account. My hosting provider allows for cron jobs and allows for an extensive number of PHP modules to be enabled. Some hosting providers may not do so. One module which I have used is PHP’s cURL module. CURL (client for URL) allows machines, to send network requests and also supports various internet protocols. Without this module, a developer would be further restricted and would have to rely mainly on redirects.