Commits

overlord  committed 6448134

Remote uptime boaster

  • Participants

Comments (0)

Files changed (7)

+#
+# Makefile for building:
+#
+# ruptimed daemom (for running on all hosts)
+# ruptime_agent daemon (for running on the publically accessable gateway)
+# ruptime tool (for manually querying daemons)
+# The CGI component does not have to be built because it is Perl
+#
+# (C) Copyright 2003 Daybo Logic, all rights reserved.
+# Written by David Duncan Ross Palmer of Daybo Logic.
+# Contact: http://www.daybologic.co.uk/mailddrp/
+#
+
+ERASE=rm
+
+all : ruptimed ruptime
+
+# Build primary daemon
+ruptimed : ruptimed.c ruptime.h
+	cc -o ruptimed ruptimed.c
+
+# Build command line checking tool
+ruptime : ruptime.c ruptime.h
+	cc -o ruptime ruptime.c
+
+clean:
+	-$(ERASE) ruptimed ruptimed.core core
+	-$(ERASE) ruptime ruptime.core

File ruptime-boasterd.pl

+#!/usr/bin/perl -w
+# This is the remote "boaster" uptime super-server.
+# It listens on the gateway of the Daybo Logic network and accepts
+# connections... one at a time.  It accepts a single string as an
+# argument from it's clients.  This is the hostname of the host running
+# ruptimed.pl which it should query.  The string that service returns
+# is then passed on to our client.  It is done in this way to avoid having
+# to open a port per host on the gateway and set up a complex mapping
+# of port to port mappings to get the correct machine's reading.  All
+# connections are handled with TCP.  ruptime-boasterd was written by
+# David Duncan Ross Palmer on 20060101.  Copyright Daybo Logic.
+# All rights reserved.
+
+use strict;
+use IO::Socket;
+
+# Constants
+
+# MAXMSGLEN defines the absolute maximum length of any strings received
+# from the hosts and given to our client.  Uptime strings aren't generally
+# very long, so this is not usually a concern.
+use constant MAXMSGLEN => 1024;
+
+# RUPTIMED_PORTNO defines the port number (on TCP) on which the various
+# hosts' ruptimed.pl daemons are listening.  We will have to connect to
+# this port on the various hosts in order to read their uptime information.
+use constant RUPTIMED_PORTNO => 30669;
+
+# BOASTERD_PORTNO is the port we should open to the outside world.  This
+# port will be used by the various CGI scripts on the websites to query
+# uptimes of the hosts.
+use constant BOASTERD_PORTNO => 30670;
+
+# DOMAIN is the only domain name in which we are allowed to resolve hosts.
+# Hosts must be supplied from the client _without_ a domain name and we
+# append this domain name before resolving the host.
+use constant DOMAIN => 'daybologic.com';
+
+# Global variables in script
+my $shutdown;
+# Sockets
+my $serversock;      # Socket which listens on port
+my $clientsock;      # Our client (generally a web site script)
+my $hostsock;        # Host we are querying (should be running ruptimed.pl)
+
+# Variable copies of constants
+my $maxmsglen;
+my $ruptimed_portno;
+my $boasterd_portno;
+my $domain;
+
+# Functions
+sub main();
+sub TermHandler();
+sub Title();
+sub ClientRequest($);
+sub IsKnownHost($);
+
+# Initialise globals
+$maxmsglen = MAXMSGLEN;
+$ruptimed_portno = RUPTIMED_PORTNO;
+$boasterd_portno = BOASTERD_PORTNO;
+$domain = DOMAIN;
+$shutdown = 0;
+
+# Code
+exit main(); # Run main routine and quit
+
+sub TermHandler()
+{
+  $shutdown = 1;
+}
+
+sub Title()
+{
+  my $localhostname = `hostname`;
+  chomp $localhostname;
+  printf "Daybo Logic ruptime-boasterd starting on host $localhostname\n";
+  printf "Super-server for ruptimed.pl daemons on all hosts.\n";
+  printf "Version 20060101 by <http://www.daybologic.co.uk/mailddrp/>\n";
+  return;
+}
+
+sub main()
+{
+  # Set up signal handlers
+  $SIG{INT} = \&TermHandler;
+  $SIG{TERM} = \&TermHandler;
+
+  Title();
+
+  # Let's open a port and start listening for the web server
+  $serversock = IO::Socket::INET->new(
+    LocalPort => $boasterd_portno,
+    Proto => 'tcp',
+    Listen => SOMAXCONN,
+    Reuse => 0
+  );
+  if ( !$serversock ) {
+    printf "Cannot listen on port $boasterd_portno: $!";
+    return 1;
+  }
+
+  print "Super-server listening on port TCP/$boasterd_portno\n";
+
+  do {
+    $clientsock = $serversock->accept();
+    if ( $clientsock ) {
+      ClientRequest($clientsock);
+      $clientsock->close();
+    }
+  } while ( !$shutdown );
+
+  print "Closing port TCP/$boasterd_portno and shutting down\n";
+  close $serversock;
+  return 0;
+}
+
+sub ClientRequest($)
+{
+  my $sock = $_[0];
+  my $host;
+  print "In ClientRequest()\n";
+
+  $sock->recv($host, $maxmsglen);
+  $host = $host . '.' . $domain;
+  print "$host\n";
+}
+
+sub IsAllowedHost($)
+{
+  # This is is called to ensure we don't go resolving hosts which we aren't allowed to
+  # probe.  For security, this program is restricted to a very tight subset of allowed
+  # hosts.  All hosts must be in the domain .daybologic.com anyway but also, list _all_
+  # hosts which you will allow to be probed.  Do not add the domain name here.
+
+  my $host = $_[0];
+  my @allowed = (
+    'hauge',
+    'heath',
+    'smith',
+    'cameron',
+    'pavilion',
+    'major'
+  );
+
+  foreach ( @allowed ) {
+    return 1 if ( $_ eq $host );
+  }
+  return 0;
+}
+
+#$portsock = IO::Socket::INET->new(
+#  LocalPort => $portno,
+#  Proto => 'tcp',
+#  Reuse => 1,
+#  Listen => SOMAXCONN
+#) or die "socket: $@";
+#print "Awaiting queries on TCP/" . $portsock->sockport . "\n";
+
+#while ( $clientsock = $portsock->accept() ) {
+#  my $uptime;
+#  my $reply;
+#  my($port, $ipaddr) = sockaddr_in($clientsock->peername);
+#  $hishost = gethostbyaddr($ipaddr, AF_INET);
+#  print "ruptimed: Uptime requested by $hishost [" . $clientsock->peerhost . "] OK.\n";
+#  $uptime = `uptime`;
+#  chomp $uptime;
+#  $reply = $localhostname . ':' . $uptime;
+#  print $clientsock $reply;
+#  $clientsock->close();
+#} 
+
+/*
+  This simple tool queries a ruptimed running on any host specified.
+  Copyright 2003 Daybo Logic, all rights reserved.
+  Created by David Duncan Ross Palmer.
+  Contact: http://www.daybologic.co.uk/mailddrp/
+  20030810
+*/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h> /* memset() */
+#include <sys/time.h> /* select() */ 
+#include <stdlib.h>
+#ifdef HDRSTOP
+# praga mdrstop
+#endif /*HDRSTOP*/
+
+#include "ruptime.h"
+
+int main(int argc, char *argv[]) {
+  
+  int sd, rc, i;
+  struct sockaddr_in cliAddr, remoteServAddr;
+  struct hostent *h;
+
+  /* check command line args */
+  if( argc < 2 ) {
+    printf(
+      "usage : %s <server>\n\n"
+      "If you only have one computer, use \'localhost\'\n\n",
+      argv[0]
+    );
+    return EXIT_FAILURE;
+  }
+
+  /* get server IP address (no check if input is IP address or DNS name) */
+  printf("Looking up %s\n", argv[1]);
+  h = gethostbyname(argv[1]);
+  if(h==NULL) {
+    printf("%s: unknown host \'%s\' \n", argv[0], argv[1]);
+    return EXIT_FAILURE;
+  }
+
+  printf("%s: sending command to '%s' (IP : %s) \n", argv[0], h->h_name,
+	 inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));
+
+  remoteServAddr.sin_family = h->h_addrtype;
+  memcpy((char *) &remoteServAddr.sin_addr.s_addr, 
+	 h->h_addr_list[0], h->h_length);
+  remoteServAddr.sin_port = htons(RUPTIMED_PORT);
+
+  /* socket creation */
+  sd = socket(AF_INET, SOCK_DGRAM, 0);
+  if( sd < 0 ) {
+    printf("%s: cannot open socket \n", argv[0]);
+    exit(1);
+  }
+  
+  /* bind any port */
+  cliAddr.sin_family = AF_INET;
+  cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+  cliAddr.sin_port = htons(0);
+  
+  rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
+  if(rc < 0) {
+    printf("%s: cannot bind port\n", argv[0]);
+    exit(1);
+  }
+
+
+  /* send data */
+  {
+    char uptime_cmd[] = RUPTIME_CMD_UPTIME;
+    rc = sendto(sd, uptime_cmd, strlen(uptime_cmd)+1, 0, 
+		(struct sockaddr *) &remoteServAddr, 
+		sizeof(remoteServAddr));
+
+    if( rc < 0 ) {
+      fprintf(stderr, "%s: cannot send command\n", argv[0]);
+      close(sd);
+      return EXIT_FAILURE;
+    }
+  }
+
+  printf("Sent command\n");
+  close(sd);
+  return EXIT_SUCCESS;
+}
+/*
+  This header lists the things that the project shares between all it's
+  global aspects.
+*/
+
+#ifndef __INC_RUPTIME_H
+#define __INC_RUPTIME_H
+
+#define RUPTIMED_PORT (53003) /* Port used by daemons on various hosts */
+#define RUPTIME_AGENT_PORT (53004) /* Port used on the gateway agent */
+#define RUPTIME_MAXMSG (1024) /* Maximum size of messages */
+
+/* Commands accepted by the primary daemon */
+#define RUPTIME_CMD_UPTIME ("UPTIME")
+
+#endif /*!__INC_RUPTIME_H*/
+#!/usr/bin/perl
+
+# Demonstration client for obtaining uptime from Daybo Logic ruptimed
+# servers.  Type ruptime [hostname]
+# Written 20051230 by David Duncan Ross Palmer
+
+use IO::Socket;
+use strict;
+
+my($sock, $server_host, $msg, $port, $ipaddr, $hishost, 
+   $MAXLEN, $PORTNO, $TIMEOUT);
+
+$MAXLEN  = 1024;
+$PORTNO  = 30669;
+
+$server_host = shift; # From command line
+
+$sock = IO::Socket::INET->new(
+  Proto => 'tcp',
+  PeerPort  => $PORTNO,
+  PeerAddr  => $server_host
+) or die "Creating socket: $!\n";
+
+$sock->recv($msg, $MAXLEN);
+($port, $ipaddr) = sockaddr_in($sock->peername);
+$sock->close();
+# $hishost = gethostbyaddr($ipaddr, AF_INET);
+print "$msg\n";
+/*
+  This program is used internally by Daybo Logic and runs on port 53003/UDP
+  on all computers on the network who wish to participate in the online
+  uptime project.  Please compile and run this code on your computer!
+  The idea is that it hosts run this daemon and then when they receive
+  the message on port 53003/UDP, they return a message to the computer they
+  received the request from giving them a simple text string which specifies
+  the uptime of the system in seconds.
+  The message that must be sent to the daemon to get a response is
+  "UPTIME".
+
+  (C) Copyright Daybo Logic, all rights reserved.
+  Written by David Duncan Ross Palmer <daybologic.co.uk/mailddrp>
+  20030810
+*/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h> /* close() */
+#include <string.h>
+#include <stdlib.h>
+#ifdef HDRSTOP
+# pragma hdrstop
+#endif /*HDRSTOP*/
+
+#include "ruptime.h" /* Information shared through the whole project */
+
+static uint32_t Uptime(uint32_t* PUptimeOut);
+
+int main(const int argc, const char* argv[])
+{
+  int sd, rc, n, cliLen;
+  struct sockaddr_in cliAddr, servAddr;
+  char msg[RUPTIME_MAXMSG];
+
+  /* Socket creation */
+  sd = socket(AF_INET, SOCK_DGRAM, 0);
+  if ( sd < 0 ) {
+    fprintf(stderr, "%s: Cannot open socket\n", argv[0]);
+    return EXIT_FAILURE;
+  }
+
+  /* Bind local server port */
+  servAddr.sin_family = AF_INET;
+  servAddr.sin_addr.s_addr = htons(INADDR_ANY);
+  servAddr.sin_port = htons(RUPTIMED_PORT);
+  rc = bind(sd, (struct sockaddr*)&servAddr, sizeof(servAddr));
+  if ( rc < 0 ) {
+    fprintf(stderr, "%s: Cannot bind port number: %d\n", argv[0], RUPTIMED_PORT);
+    return EXIT_FAILURE;
+  }
+
+  printf("%s: Waiting for data on port UDP: %u\n", argv[0], RUPTIMED_PORT);
+
+  /* Infinite server loop */
+  while ( 1 ) {
+    memset(msg, 0, RUPTIME_MAXMSG); /* Init buffer */
+    /* Receive message (if/when it arrives) */
+    cliLen = sizeof(cliAddr);
+    n = recvfrom(sd, msg, RUPTIME_MAXMSG, 0, (struct sockaddr*)&cliAddr, &cliLen);
+    if ( n < 0 ) {
+      fprintf(stderr, "%s: Cannot receive data\n", argv[0]);
+      continue;
+    }
+    /* Data has been received, check it's what we're looking for */
+    if ( strcmp(msg, RUPTIME_CMD_UPTIME) == 0 ) {
+      /* It's what we're looking for! */
+      uint32_t uptime;
+      Uptime(&uptime);
+      printf("Received UPTIME command, giving the uptime as %lu\n", uptime);
+    }
+    else {
+      printf("Received unknown command: %s\n", msg);
+    }
+  }
+  return EXIT_SUCCESS;
+}
+
+static uint32_t Uptime(uint32_t* PUptimeOut)
+{
+  uint32_t uptime;
+
+  uptime = 0U; /* FIXME */
+
+  if ( PUptimeOut )
+    *PUptimeOut = uptime;
+  return uptime;
+}
+#!/usr/bin/perl -w
+# This is the remote uptime server which runs on all Daybo Logic
+# machines.
+# You should ensure all hosts are running it because it is the only
+# way the website will show information about the load and uptime of
+# our servers to our customers.  This server runs on TCP, unfortunately.
+# The old version ran on TCP but the connection-less protocol didn't
+# work properly with portfwd.
+
+use strict;
+use IO::Socket;
+use constant MAXLEN => 1024;
+use constant PORTNO => 30669;
+
+my($localhostname, $clientsock, $portsock, $hisaddr, $hishost, $maxlen, $portno);
+
+$maxlen = MAXLEN;
+$portno = PORTNO;
+$localhostname = `hostname`;
+chomp $localhostname;
+
+printf "Daybo Logic ruptimed starting on host $localhostname\n";
+printf "Version 20060215 by <http://www.daybologic.co.uk/mailddrp/>\n";
+
+$portsock = IO::Socket::INET->new(
+  LocalPort => $portno,
+  Proto => 'tcp',
+  Reuse => 1,
+  Listen => SOMAXCONN
+) or die "socket: $@";
+print "Awaiting queries on TCP/" . $portsock->sockport . "\n";
+
+while ( $clientsock = $portsock->accept() ) {
+  my $uptime;
+  my $reply;
+  my($port, $ipaddr) = sockaddr_in($clientsock->peername);
+  $hishost = gethostbyaddr($ipaddr, AF_INET);
+  $hishost = '(unknown)' if ( !($hishost) );
+  print "ruptimed: Uptime requested by $hishost [" . $clientsock->peerhost . "] OK.\n";
+  $uptime = `uptime`;
+  chomp $uptime;
+  $reply = $localhostname . ':' . $uptime;
+  print $clientsock $reply;
+  $clientsock->close();
+} 
+