Created
September 11, 2025 15:20
-
-
Save ravnx/e8e39c70e65cc0d3bc86c131d599b0d0 to your computer and use it in GitHub Desktop.
Mojolicious Service to Check if a host has a port open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/perl -w | |
| # This mojo will just check for an open port. | |
| # I use this with nagios to alert me if a firewalled webserver is open to the public internet. | |
| # I run this in a nano cloud instance off network. I use nginx to serve it, and hypnotoad to run it. | |
| # Nagios calls it like "http://foo.app.com/check?host=1.2.3.4&port=443&key=abc123" | |
| # | |
| # You can setup a nagios command like this: | |
| # define command { | |
| # command_name check_api_port_open | |
| # command_line /usr/bin/curl -s "https://foo.app.com/check?host=$HOSTADDRESS$&port=443" | /usr/bin/grep -q '"status":"open"' && echo "Port 443 is OPEN" && exit 2 || echo "Port 443 is closed" && exit 0 | |
| #} | |
| # | |
| # Last update: 2025-09-11 19:54:20 UTC | |
| use strict; | |
| use Mojolicious::Lite -signatures; | |
| use IO::Socket::INET; | |
| # Logging setup | |
| app->log( Mojo::Log->new( path => '/var/log/canary.log', level => 'warn' ) ); | |
| # Server Setup | |
| app->config(hypnotoad => {listen => ['http://*:8090'], hypnotoad => {proxy => 1}, }); | |
| # ---------------------------------------------------------------------- # | |
| # Ping route for monitoring this service being up # | |
| # ---------------------------------------------------------------------- # | |
| # I like to use updown.io to monitor service monitors, i like to get a pong reply | |
| get '/ping' => sub { | |
| my $self = shift; | |
| $self->render(text => 'pong'); | |
| }; | |
| # If you want to save even more bandwidth, you can just render 200 ok. | |
| #head '/ping' => sub { | |
| # my $c = shift; | |
| # $c->rendered(200); | |
| #}; | |
| # ---------------------------------------------------------------------- # | |
| # render main screen # | |
| # ---------------------------------------------------------------------- # | |
| # Just a default text render for bots and stuff | |
| any '/' => sub { | |
| my $self = shift; | |
| $self->render(text => 'chirp'); | |
| }; | |
| # ---------------------------------------------------------------------- # | |
| # render main screen # | |
| # ---------------------------------------------------------------------- # | |
| # Lets keep bots from crawling this site | |
| any '/robots.txt' => sub { | |
| my $self = shift; | |
| $self->render( | |
| text => "User-agent: *\nDisallow: /", | |
| format => 'txt' | |
| ); | |
| }; | |
| # ---------------------------------------------------------------------- # | |
| # Allow GET /check?host=1.2.3.4&port=443 # | |
| # ---------------------------------------------------------------------- # | |
| get '/check' => sub ($c) { | |
| # Check for token, die if there isnt one, you can change this to a static if you dont want to mess with ENV vars. | |
| return $c->render(text => 'unauthorized', status => 403) | |
| unless $c->param('token') eq $ENV{CANARY_TOKEN}; | |
| # it might be smart to limit the hosts to a list of allowed hosts, but I've got mine firewalled to | |
| # only allow my nagios server to make requests here, so im leaving it open. | |
| my $host = $c->param('host') // return $c->render(json => { error => 'Missing host' }, status => 400); | |
| my $port = 443; # I'm forcing 443 only, but you can use any port like this: $c->param('port') // 443; | |
| my $sock = IO::Socket::INET->new( | |
| PeerAddr => $host, | |
| PeerPort => $port, | |
| Proto => 'tcp', | |
| Timeout => 2 | |
| ); | |
| if ($sock) { | |
| close($sock); | |
| return $c->render(json => { host => $host, port => $port, status => 'open' }); | |
| } else { | |
| return $c->render(json => { host => $host, port => $port, status => 'closed' }); | |
| } | |
| }; | |
| app->start; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment