Monitoring your internet connections with OpenWRT and a Telegram Bot

For the past 5 years or so, I have been using a single ISP at home and mobile data for backup when it went down. But since last few months, the ISP service became a bit unreliable – this is more related to the rainy season. Mobile data doesn’t give fiber like constant speeds I get on the wire. It’s very annoying to browse at < 10 Mbps on mobile data when you are used to 100 Mbps on the wire.

I decided to get another fiber pipe from a local ISP. One needs to be very unlucky to have both going down at the same time – I hope that never happens. Now the question is how to monitor the two connections: Why do I need monitoring? – so that I can inform the ISP when it goes down, with the fail-over happening automatically thanks to OpenWRT’s mwan3 package, I won’t ever know when I am using which ISP (unless I am checking the public IP address, of course).

The solution: A custom API and a Telegram bot. For those not aware about Telegram, it is an amazing messaging app just like Whatsapp with way more features (bots, channels), and does away with some idiosyncrasies of Whatsapp such as restricting you to always have the phone connected.

A Telegram bot is fairly simple to write, you just have to use their API. Now this bot is just going to send me messages, I am never going to send any to it, so implementing my WAN monitor bot was very easy.

My router is a TP Link WR740N which has 4 MB flash – so it is not possible to have curl with SSL support which is required by the API. I wrote a custom script which can be called over HTTP and plays well with the default wget. The script is present on a cloud server which can, obviously, do the SSL stuff.

A custom wrapper to Telegram API to send message in PHP:

The <your chat id>  part needs to be discovered once you send a /start command to your bot and use Telegram’s getUpdates method. You will get it in API’s response JSON. $key  is just a security check to prevent external attacks on the script.

And this script is called on interface events by mwan3 (/etc/mwan3.user ):

Shell script to monitor connections by cron directly from the server:

The above script uses netcat to do the link test using a TCP connection to a port number which is port forwarded to a server because I found ping was doing some false positives. I couldn’t reproduce it when I was trying it manually but I used to get DOWN messages even though the connection was working.

One must wonder though, how will the message reach me via Telegram when both ISPs go down at the same time – well I leave that job to Android and mobile data. Android switches to mobile data as soon as it finds WiFi doesn’t have internet access.

Advertisements

A networking insight into the past

Back in 2007-2008, when I was just starting out with Linux geekery I had an ISP connection which was working fine for almost a year. Previously I was a Windows user and the hardware I used to run Windows XP was a Pentium 3 with 384 MB RAM.

Now I don’t know whether it was the hardware or issues with Windows itself that caused me so much frustration sufficient to make me move to Linux. After switching to Linux, things had become smooth so it was probably not the hardware. Perhaps the hardware was insufficient to run XP although it was slightly better than the recommended hardware specification at that time.

So yeah, this ISP had installed a telephone wire into my house and provided me an ADSL modem. In those days, it was rather uncommon to have multiple devices at home at least in India, so they had a policy of allowing only one PC at a time to use the Internet. My networking knowledge was pretty limited at that time so I never thought about how or why it was like that.

Then dad’s workplace assigned him a laptop and that’s when there were two devices at home that required Internet. Again due to limited knowledge of networking and Linux, I got a long LAN cable so that dad’s laptop could be wired to the modem having a single Ethernet port. A couple of times this plugging/unplugging; we got tired of it and then bought an unmanaged switch. That helped solve the cabling issue, but still two computers couldn’t use the Internet at the same time. I used to log out when my dad wanted to use Internet and vice versa. The switch model worked because the modem provided by the ISP was in bridge mode as per the settings I found out by poking around.

Both the machines were Windows XP initially. Then I switched to Linux and configured a simple DHCP based Ethernet connection to use Internet and it worked fine. The wizards helped me and the authentication mechanism was to login to the ISP using a Web page you got redirected to once you opened some site after acquiring a lease. But one day, all of a sudden the Internet stopped working on my Linux box. A quick observation was that it worked fine in Windows. Numerous calls to the ISP’s call center and as usual a clueless response by them (this continues even today to some extent) but they eventually sent their technician who couldn’t solve the problem either. Then we switched ISP.

Over the seven years after this I have learned a lot of Linux and Networking and worked in real life scenarios. But today while chatting with my friend Nikhil about ISPs and their reviews, I recalled this issue and now I can make sense why it wasn’t working. Reason is simple, routers generally contain Embedded Linux. In DHCP there’s a field mentioning what OS or which client is it (like a Web browser sends user agent to every website). This cunning ISP wanted to make money by selling their own routers and charging more for allowing multiple computers to use Internet at the same time so they decided to block all Linux DHCP clients (probably excluding their own) because every Linux box is a potential NAT box! It is possible to use Windows as a NAT box as well, but then they had no choice. If they blocked windows nobody would use their services 😂😂

CloudFlare Dynamic DNS using OpenWRT

I use dynamic DNS for my home internet connection so that I can access the machines from anywhere on the internet. And I use OpenWRT on my router. Earlier I was using Namecheap for managing DNS but I switched to CloudFlare for performance and security reasons of the website.

Unfortunately CloudFlare doesn’t support updating IP via shell script — well, it sort of does but the JSON stuff gets very messy with quoting in shell scripts, so I wrote a Lua script to update my IP whenever my PPPoE connection starts up; I have dropped the script in /etc/ppp/ip-up.d  so it gets executed by pppd whenever my connection comes up. You can run this script via cron or put it /etc/hotplug  if you wish to. This script uses LuaSocket, LuaSec, JSON4Lua and libubus-lua libraries that are easily installable on an OpenWRT router with 4 MB flash memory.

Now I can have the benefits of CloudFlare without losing out on DDNS :D. Here’s the code:

Suggestions? Post in comments or fork on GitHub.

The Proxy ARP method of routing subnets to solve the docker networking problem

Recently I discovered something called Proxy ARP. I had seen this earlier in sysctl options but never understood it and why would someone need it, until one day I worked in a networking setup which used this to route traffic from the machine to the Internet. It’s an interesting technique and can solve a big problem when you want to use the currently popular tool, docker in your LAN subnet that has DHCP without having to do some other stuff like port forwarding when trying to give access to others.

Continue reading “The Proxy ARP method of routing subnets to solve the docker networking problem”

FreeBSD IPFW NAT and Jails

IPFW in FreeBSD has built-in support for NATing and the configuration syntax is same as that of natd. It took me quite some time to figure out how to NAT for jails while ensuring that certain jails can have public IPs.

Configure the nat on one of the IP addresses:

When using stateful firewall, the NAT rule for incoming traffic must appear before check-state:

Other rules (service ports) can be placed below this:

Then the NAT rule for outgoing traffic:

Notice above, I am NATing only traffic that comes from 10.0.0.0/8 . I allocate jails an IP on that subnet (unless I need a public IP for the jail). If the source is not mentioned in the rule, it will NAT even public IPs!

And finally, the outgoing ports:

The catch here is that we jump to the NAT rule only if the traffic comes from 10.0.0.0/8 . If the traffic is coming from somewhere else (for example, a public IP allocated to one of the jails), it will hit the second rule and directly allow it.

Make sure you have the rule to allow loX traffic if you have separate clone interfaces for each jail.

Final touches:

The firewall script ipfw.rules must to contain other rules for services, icmp, etc not mentioned here.
Everything working smoothly now – ip4 from private jails, ip4 and ip6 from others 😀