#!/usr/bin/perl -w
#
# mtufinder - test different sized HTTP requests to a web server, 
#             highlighting MTU size problems. Perl, Unix/Linux/Windows...
#
# 25-Jan-2006, ver 1.05
#
# USAGE:    mtufinder [-h] | [-p proxy:port] hostname
#    eg,
#           mtufinder science.nasa.gov
#           mtufinder -p proxy1:8080 science.nasa.gov
#
# Sometimes firewalls on the Internet are misconfigured to block ICMP,
# and in doing so they block the ICMP can't fragment requests that
# are returned when a too large MTU was used. This program can help
# identify the case.
#
# COPYRIGHT: Copyright (c) 2005 Brendan Gregg.
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
#  (http://www.gnu.org/copyleft/gpl.html)
#
# 24-Mar-2004   Brendan Gregg   Created this.
# 25-Jan-2006      "      "     Tweaked style.
 
use strict;
use IO::Socket;
use Getopt::Std;

#
#  Command line arguments
#
usage() if @ARGV == 0 or $ARGV[0] eq "--help";
getopts('hp:');
usage() if $main::opt_h;
$main::opt_h = 0;
my ($hostname, $proxy, $port, $website);
if (defined $main::opt_p) {
    $main::opt_p =~ s|^http://||;
    ($hostname, $port) = split /:/, $main::opt_p;
    $port = 8080 if $port eq "";    # default proxy port
    $proxy = 1;
    $website = $ARGV[0];
} else {
    $hostname = $ARGV[0];
    $hostname =~ s|^http://||;
    $port = 80;                     # default port
    $website = "/";
}

#
#  Variables
#
my $string = "Accept-Language: en\n";    # This has a length of 20 bytes,
                                         # and is used as a padding string.
my $count = 0;
my $inc = 25;                            # multiple of $string increment
$| = 1;

#
#  Main
#
if ($proxy) {
    print "website, $website via proxy, $hostname:$port\n";
}
else {
    print "website, $hostname\n";
}

while ((16 + 20 * $count) < 1600) {

    ### Connect to host
    my $remote = IO::Socket::INET->new(
        Proto    => "tcp",
        PeerAddr => "$hostname",
        PeerPort => "$port"
    );

    if ($remote) {

        ### Send test request
        my $bytes = 16 + 20 * $count;
        print "trying $bytes bytes... ";
        print $remote "GET $website HTTP/1.0\n";
        print $remote $string x $count . "\n";

        ### Read reply
        my $reply = "";
        $reply .= $_ while (<$remote>);

        ### Check reply was ok
        print length($reply) > 10 ? "connected ok\n" : "failed\n";
        close $remote;

    }
    else {
        ### Initial connection failed
        print STDERR "ERROR1: Connection to $hostname failed\n";
    }

    $count += $inc;
}

# usage - print usage message and exit
#
sub usage {
    print STDERR "USAGE: mtufinder [-h] | [-p proxy:port] hostname\n";
    print STDERR "   eg, mtufinder science.nasa.gov\n";
    print STDERR "       mtufinder -p proxy1:8080 science.nasa.gov\n";
    exit 1;
}
