vpn
changeset 0 6f74002230f0
child 1 a5a1e5f284d2
equal deleted inserted replaced
-1:000000000000 0:6f74002230f0
       
     1 #! /usr/bin/perl
       
     2 
       
     3 # based on a version Uwe Werler downloaded from f5networks developer
       
     4 # area
       
     5 
       
     6 use 5.8.8;
       
     7 use strict;
       
     8 use warnings;
       
     9 use Getopt::Long qw(:config no_ignore_case bundling);
       
    10 use Pod::Usage;
       
    11 use File::Basename;
       
    12 
       
    13 use constant ME => basename $0;
       
    14 
       
    15 ###
       
    16 ### STEP 0 :: Verify that we have the necessary requirements.
       
    17 ###
       
    18 ### This script requires recent versions of Perl, OpenSSL and PPPD (including
       
    19 ### the 'chat' program), and that they all be in our PATH.  This script was
       
    20 ### written and tested with the following versions:
       
    21 ###	FirePass:	5.5 and 6.0
       
    22 ###	Perl:		5.8.8
       
    23 ###	OpenSSL:	0.9.8b
       
    24 ###	PPPD:		2.4.4
       
    25 
       
    26 ###
       
    27 ### STEP 1 :: Set up variables with the proper information to log in.
       
    28 ###
       
    29 
       
    30 # Default values for the FQDN or IP of the FirePass we wish to connect to, the
       
    31 # name of our Network Access favorite, and our username/pasword.  All of these
       
    32 # can be passed as arguments, if desired.
       
    33 
       
    34 my $user;
       
    35 my $passcode;
       
    36 my $host     = 'connectwdf.sap.com';
       
    37 my $name     = 'SAP Network Access';
       
    38 my $opt_help = 0;
       
    39 my $opt_man  = 0;
       
    40 my $debug;
       
    41 my $ppp_opts = [];
       
    42 my $opt_script;
       
    43 
       
    44 MAIN: {
       
    45 
       
    46     GetOptions(
       
    47         "u|user=s"      => \$user,
       
    48         "p|passcode=s"  => \$passcode,
       
    49         "H|host=s"      => \$host,
       
    50         "n|favorite=s" => \$name,
       
    51         "d|debug"       => \$debug,
       
    52         "o|opts=s"      => $ppp_opts,
       
    53         "h|help"        => \$opt_help,
       
    54         "m|man"         => \$opt_man,
       
    55 	"s|script"	=> \$opt_script,
       
    56     ) or pod2usage();
       
    57 
       
    58     die ME . ": need to run with root permissions!\n" if $> != 0;
       
    59 
       
    60     pod2usage(-verbose => 1, -exitval => 0) if $opt_help;
       
    61     pod2usage(-verbose => 2, -exitval => 0) if $opt_man;
       
    62     pod2usage(-verbose => 0, -exitval => 0) if not defined $user;
       
    63 
       
    64     if (not defined $passcode) {
       
    65 	chomp(my $settings = qx{stty "-g"});
       
    66 	open(IN, "/dev/tty") or die "Can't open /dev/tty: $!\n";
       
    67 	print "Passcode: ";
       
    68 	system stty => "-echo";
       
    69 	chomp($passcode = <IN>);
       
    70 	system stty => $settings;
       
    71 	print "\n";
       
    72     }
       
    73 
       
    74     pod2usage(-verbose => 0, -exitval => 0) if not defined $passcode;
       
    75 
       
    76     push @$ppp_opts, "nodetach" if !@$ppp_opts;
       
    77     push @$ppp_opts, $debug ? "debug" : "nolog";
       
    78     push @$ppp_opts, "nodefaultroute" if not grep /^defaultroute$/, @$ppp_opts;
       
    79     $ppp_opts = join(" ", @$ppp_opts);
       
    80     print "\nPPP-Options: $ppp_opts\n" if $debug;
       
    81 
       
    82     # Declare variables used throughout the rest of the script.
       
    83     my ($request, $response, $sessionid, $favorite);
       
    84 
       
    85     # Store the OpenSSL command in a variable for convienence.
       
    86     my $openssl =
       
    87         "openssl s_client"
       
    88       . (-d "/etc/ssl/certs" ? " -CApath /etc/ssl/certs" : "")
       
    89       . " -ign_eof -quiet -connect ${host}:443";
       
    90 
       
    91     # Make initial request to get client_data
       
    92     $request =
       
    93         "GET /my.logon.php3?check=1 HTTP/1.0\r\n"
       
    94       . "Content-Type: application/x-www-form-urlencoded\r\n"
       
    95       . "Connection: close\r\n" . "\r\n";
       
    96 
       
    97     $response = qx(echo "${request}" | ${openssl} 2>/dev/null)
       
    98       or die "Invalid Host spezified or not reachable: $host\n";
       
    99 
       
   100     $response =~ s/<INPUT type="hidden" name="client_data" value="(.*)">/$1/;
       
   101     my $client_data = $1;
       
   102 
       
   103 ###
       
   104 ### STEP 2 :: Log in to FirePass.
       
   105 ###
       
   106 
       
   107   # This is the bare minimum required in order to successfully log in.  A normal
       
   108   # browser will make many more requests than this to complete the log in
       
   109   # sequence, but all that is required is this POST with our credentails.  This
       
   110   # may fail if the FirePass has End-Point Security Policies configured.
       
   111     $request =
       
   112 "check=1&username=${user}&password=${passcode}&mrhlogonform=1&client_data=${client_data}";
       
   113     $request =
       
   114         "POST /my.activation.php3 HTTP/1.0\r\n"
       
   115       . "Host: ${host}\r\n"
       
   116       . "Content-Type: application/x-www-form-urlencoded\r\n"
       
   117       . "Content-Length: "
       
   118       . length($request) . "\r\n"
       
   119       . "Connection: close\r\n" . "\r\n"
       
   120       . "${request}\r\n";
       
   121     $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
       
   122 
       
   123   # We can then parse the response for the MRHSession Cookie, which contains our
       
   124   # SessionID.  In this example, we print out the SessionID in order to verify
       
   125   # that our log in attempt worked.
       
   126     $response =~ /MRHSession=(\w+);/;
       
   127     $sessionid = $1;
       
   128     print "SessionID: ${sessionid}\n" if $debug;
       
   129 
       
   130 ###
       
   131 ### STEP 3 :: Create the SSL VPN tunnel.
       
   132 ###
       
   133 
       
   134    # Now that we are authenticated and have a valid SessionID, we must request
       
   135    # specific pages/objects in order to initiate a SSL VPN tunnel.  Before we do
       
   136    # this, let's determine the resource locator for our Network Access favorite.
       
   137     $request = "GET /vdesk/vpn/index.php3?outform=xml HTTP/1.0\r\n"
       
   138       . "Cookie: MRHSession=${sessionid}\r\n\r\n";
       
   139     $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
       
   140 
       
   141  # The response is XML, so we can safely grab what we are looking for using some
       
   142  # regular expression magic.  Same with the SessionID, we're printing out the
       
   143  # final value to make sure we're on the right track.
       
   144     $response =~ /${name}[^\n]+\n[^Z]+Z=\d+,(\d+)/;
       
   145     $favorite = $1;
       
   146     print "Favorite: ${favorite}\n" if $debug;
       
   147 
       
   148     # We're all set!  Let's visit the necessary pages/objects to notify FirePass
       
   149     # that we wish to open a SSL VPN tunnel.
       
   150     foreach my $uri ("/vdesk/", "/vdesk/vpn/connect.php3?Z=0,${favorite}",) {
       
   151         $request = "GET ${uri} HTTP/1.0\r\n"
       
   152           . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n";
       
   153         system("echo \"${request}\" | ${openssl} >/dev/null 2>&1");
       
   154     }
       
   155 
       
   156 # We are now authenticated, and have requested the necessary pre-tunnel
       
   157 # pages/objects.  It's time to start our SSL VPN connection.  To do this, we are
       
   158 # simply calling PPPD, and having it use OpenSSL as a psuedo terminal device.
       
   159     $request = "GET /myvpn?sess=${sessionid} HTTP/1.0\r\n"
       
   160       . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n";
       
   161     $request = "chat -v '' '${request}'";
       
   162     system(
       
   163 "pppd ${ppp_opts} noauth crtscts passive noproxyarp local pty \"${openssl}\" connect \"${request}\""
       
   164     );
       
   165 
       
   166     # Voila!  We should now have a PPP connection running over SSL.  We can exit
       
   167     # from this script cleanly, and move on to setting up routes to the remote
       
   168     # network using our favorite networking tools.  Happy hacking!
       
   169 
       
   170     exit(0);
       
   171 
       
   172 }
       
   173 
       
   174 __END__
       
   175 
       
   176 =head1 SYNOPSIS
       
   177 
       
   178  vpn [-d|--debug] [-H|--host <host>] [-o|--opt <ppp option>]...
       
   179      [-s|--script <script>]
       
   180      [-u|--user <user>] [-p|--passcode <passcode>]
       
   181 
       
   182  vpn [-h|--help]
       
   183  vpn [-m|--man]
       
   184 
       
   185 =head1 DESCRIPTION
       
   186 
       
   187 Ths script establishes a VPN connecttion to a FirePass server.
       
   188 B<Note:> This script requires root privileges and should be run via sudo.
       
   189 
       
   190 =head1 OPTIONS
       
   191 
       
   192 
       
   193 =over
       
   194 
       
   195 =item B<-u>|B<--user> I<user>
       
   196 
       
   197 Your D|C|I user, not really optional. (no default)
       
   198 
       
   199 =item B<-p>|B<--passcode> I<passcode>
       
   200 
       
   201 Your passcode, if not supplied, F</dev/tty> is opened for reading
       
   202 the passcode. (no default)
       
   203 
       
   204 =item B<-H>|B<--host> I<host>
       
   205 
       
   206 Host to connect to. (defaults to C<connectwdf.sap.corp>)
       
   207 
       
   208 =item B<-n>|B<--name> I<name>
       
   209 
       
   210 Name of the service(?). (default: to 'SAP Network Access')
       
   211 
       
   212 =item B<-d>
       
   213 
       
   214 Print debug output from pppd. (default: 0)
       
   215 
       
   216 =item B<-o>|B<--opts> I<ppp options>
       
   217 
       
   218 Additional options for ppp. Can be specified multiple times. (default: nodetach)
       
   219 Good choices are C<detach>, or C<updetach>.
       
   220 B<Note:> The C<nodefaultroute> is set automatically.
       
   221 
       
   222 =back
       
   223 
       
   224 =cut
       
   225 
       
   226 ###
       
   227 ### End of file.
       
   228 ###