Friday, December 26, 2008

Passive monitoring of ping times on incoming TCP connections

For those of hosting web applications, it is frequently convenient to have ping time information available for all incoming connections. Most networks these days block icmp ping requests, making it impossible to actively ping users. One workaround is to passively monitor events in the TCP connection which have approximately the same round trip time as a ping request. Specifically, the time between a packet from a client with SYN and ACK flags set and the next packet received with an ACK flag set are monitored and reported.

Below is a PHP script which uses tcpdump to monitor incoming connections on ports 80 and 443. Due to the fact that packet sniffing is used, root access is required for execution.

#!/usr/bin/php

/**
* This is a script which tracks the tcp handshake to attempt to passively monitor our client's ping times.
*
*/


$ip_latency = array();

$handle = popen('sudo tcpdump -n -tt "tcp[tcpflags] & (tcp-syn|tcp-ack) != 0 && (port 80 or port 443)" 2>/dev/null', 'r');

while(! feof($handle)) {
$output = fgets($handle);

if (preg_match('/^([0-9.]+).* > ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\.([0-9]+): S .* ack /', $output, $matches)) {
// it's a SYN+ACK
// record the timestamp and wait for the response
list($dummy, $timestamp, $remote_ip, $remote_port) = $matches;

$ip_latency[$remote_ip.':'.$remote_port] = array('start' => $timestamp);

// echo("SYNACK $timestamp, $remote_ip, $remote_port\n");
} elseif (preg_match('/^([0-9.]+) IP ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\.([0-9]+) > .*: \. ack 1 /', $output, $matches)) {
// it's an ACK 1
list($dummy, $timestamp, $remote_ip, $remote_port) = $matches;

if (isset($ip_latency[$remote_ip.':'.$remote_port]) && ! isset($ip_latency[$remote_ip.':'.$remote_port]['end'])) {
$ip_latency[$remote_ip.':'.$remote_port]['end'] = $timestamp;

$latency = $timestamp - $ip_latency[$remote_ip.':'.$remote_port]['start'];
// echo("ACK $timestamp, $remote_ip, $remote_port\n");
printf("%s - %s : %2.8f\n", $timestamp, $remote_ip, $latency);
unset($ip_latency[$remote_ip.':'.$remote_port]);
}

if (rand(0, 100) == 0) {
// clean up, clear out all entries older than 100s

foreach($ip_latency as $key => $timing) {
if ($timestamp - $timing['start'] > 100) {
// echo("PURGE $key\n");
unset($ip_latency[$key]);
}
}
}
}
}

Sunday, December 7, 2008

Morse code on the EZ-430/MSP430

//******************************************************************************
// Morse code blinker program
// derived from a basic blinker app
//******************************************************************************

#include "msp430.h"

const char* morse_table[] = { 
  ".-" , // A
  "-...", // B
  "-.-.", // C
  "-..", // D
  ".", // E
  "..-.", // F
  "--." , // G
  "....", // H
  ".."  , // I
  ".---", // J
  ".-.-", // K
  ".-..", // L
  "--", // M
  "-.", // N
  "---", // O
  ".--.", // P
  "--.-", // Q
  ".-.", // R
  "...", // S
  "-", // T
  "..-", // U
  "...-", // V
  ".--", // W
  "-..-", // X
  "-.--", // Y
  "--.." // Z
  
};

/**
 * Low power mode sleep
 *
 */ 

void sleep(int howlong)
{
  int i;
    for(i=2*howlong;i>0;i--) { LPM0; }
}

/**
 * Turn on pin 1
 *
 */

inline void led_on()
{
      P1OUT |= 0x01;
}

/**
 * Turn off pin 1
 *
 */

inline void led_off()
{
      P1OUT &= ~0x01;
}

/**
 * Blink a string in morse code
 *
 * Takes a string and blinks it
 */

void blink_morse(const char *s)
{
  int i,j, letter_index;
  const char *dots;
  for(i=0;s[i] != (char) 0; i++){
    letter_index = -1;
    if (s[i] >= 'A' && s[i] <= 'Z')
      letter_index = (int) s[i] - (int) 'A';
    
    if (s[i] >= 'a' && s[i] <= 'z')
      letter_index = (int) s[i] - (int) 'a';
    
    if (letter_index != -1) {
      dots = morse_table[letter_index];
     for(j=0;dots[j] != (char) 0; j++) {
       switch(dots[j]) {
        case '.':
        led_on();
        sleep(1);
        led_off();
        break;
        
       case '-':
         led_on();
         sleep(3);
         led_off();
         break;
       }
      sleep(1);
     }
    } else {
      // not a regular character
      sleep(4); // medium gap when combined with short gap below
    }
    led_off();
    sleep(3); // short gap
  }
}

int main(void)
{
  
  WDTCTL = WDTPW + WDTHOLD;
 
 // Set pin 1 for output
  P1DIR |= 0x01;
  
 
  CCTL0 = CCIE;
  // set CCR0 delay to 60,000 
  CCR0 = 60000;
  TACTL = TASSEL_2 + MC_1;
 
  _BIS_SR(LPM0_bits + GIE);
  // start with the LED off
  led_off(); 

  for(;;)
  {

 blink_morse("This message is blinking in morse code");
 blink_morse("You can fit a paragraph or two into even the smallest MSP430");

 
    sleep(10);
  }
}

#pragma vector=TIMERA0_VECTOR
__interrupt void Timer_A (void)
{
 LPM0_EXIT; 
 
}