vpn
changeset 1 a5a1e5f284d2
parent 0 6f74002230f0
child 2 5f08067bc677
equal deleted inserted replaced
0:6f74002230f0 1:a5a1e5f284d2
     1 #! /usr/bin/perl
     1 #! /usr/bin/perl
     2 
     2 # $Id$
       
     3 # $URL$
     3 # based on a version Uwe Werler downloaded from f5networks developer
     4 # based on a version Uwe Werler downloaded from f5networks developer
     4 # area
     5 # area http://devcentral.f5.com/SDK/sslvpn.public.pl.txt
     5 
     6 
     6 use 5.8.8;
     7 use 5.8.8;
     7 use strict;
     8 use strict;
     8 use warnings;
     9 use warnings;
     9 use Getopt::Long qw(:config no_ignore_case bundling);
    10 use Getopt::Long qw(:config no_ignore_case bundling);
    31 # name of our Network Access favorite, and our username/pasword.  All of these
    32 # name of our Network Access favorite, and our username/pasword.  All of these
    32 # can be passed as arguments, if desired.
    33 # can be passed as arguments, if desired.
    33 
    34 
    34 my $user;
    35 my $user;
    35 my $passcode;
    36 my $passcode;
    36 my $host     = 'connectwdf.sap.com';
    37 my $opt_host = 'connectwdf.sap.com';
    37 my $name     = 'SAP Network Access';
    38 my $opt_name = 'SAP Network Access';
    38 my $opt_help = 0;
    39 my $opt_help = 0;
    39 my $opt_man  = 0;
    40 my $opt_man  = 0;
    40 my $debug;
    41 my @ppp_opts = ();
    41 my $ppp_opts = [];
    42 my $opt_debug;
    42 my $opt_script;
    43 my $opt_script;
    43 
    44 
    44 MAIN: {
    45 MAIN: {
    45 
    46 
    46     GetOptions(
    47     GetOptions(
    47         "u|user=s"      => \$user,
    48         "u|user=s"     => \$user,
    48         "p|passcode=s"  => \$passcode,
    49         "p|passcode=s" => \$passcode,
    49         "H|host=s"      => \$host,
    50         "H|host=s"     => \$opt_host,
    50         "n|favorite=s" => \$name,
    51         "n|favorite=s" => \$opt_name,
    51         "d|debug"       => \$debug,
    52         "d|debug"      => \$opt_debug,
    52         "o|opts=s"      => $ppp_opts,
    53         "o|opts=s"     => \@ppp_opts,
    53         "h|help"        => \$opt_help,
    54         "h|help"       => \$opt_help,
    54         "m|man"         => \$opt_man,
    55         "m|man"        => \$opt_man,
    55 	"s|script"	=> \$opt_script,
    56         "s|script"     => \$opt_script,
    56     ) or pod2usage();
    57     ) or pod2usage();
    57 
    58 
    58     die ME . ": need to run with root permissions!\n" if $> != 0;
    59     die ME . ": need to run with root permissions!\n" if $> != 0;
    59 
    60 
    60     pod2usage(-verbose => 1, -exitval => 0) if $opt_help;
    61     pod2usage(-verbose => 1, -exitval => 0) if $opt_help;
    61     pod2usage(-verbose => 2, -exitval => 0) if $opt_man;
    62     pod2usage(-verbose => 2, -exitval => 0) if $opt_man;
    62     pod2usage(-verbose => 0, -exitval => 0) if not defined $user;
    63     pod2usage(-verbose => 0, -exitval => 0) if not defined $user;
    63 
    64 
    64     if (not defined $passcode) {
    65     if (not defined $passcode) {
    65 	chomp(my $settings = qx{stty "-g"});
    66         chomp(my $settings = qx{stty "-g"});
    66 	open(IN, "/dev/tty") or die "Can't open /dev/tty: $!\n";
    67         open(IN, "/dev/tty") or die ME . ": Can't open /dev/tty: $!\n";
    67 	print "Passcode: ";
    68         print "Passcode: ";
    68 	system stty => "-echo";
    69         system stty => "-echo";
    69 	chomp($passcode = <IN>);
    70         chomp($passcode = <IN>);
    70 	system stty => $settings;
    71         system stty => $settings;
    71 	print "\n";
    72         print "\n";
    72     }
    73     }
    73 
    74 
    74     pod2usage(-verbose => 0, -exitval => 0) if not defined $passcode;
    75     pod2usage(-verbose => 0, -exitval => 0) if not defined $passcode;
    75 
    76     -x $opt_script
    76     push @$ppp_opts, "nodetach" if !@$ppp_opts;
    77       or die ME . ": Script $opt_script is not executable: $!\n"
    77     push @$ppp_opts, $debug ? "debug" : "nolog";
    78       if defined $opt_script;
    78     push @$ppp_opts, "nodefaultroute" if not grep /^defaultroute$/, @$ppp_opts;
    79 
    79     $ppp_opts = join(" ", @$ppp_opts);
    80     push @ppp_opts, "nodetach" if $opt_debug;
    80     print "\nPPP-Options: $ppp_opts\n" if $debug;
    81     push @ppp_opts, $opt_debug ? "debug" : "nolog";
       
    82     push @ppp_opts, "nodefaultroute" if not grep /^defaultroute$/, @ppp_opts;
       
    83     print "\nPPP-Options: @ppp_opts\n" if $opt_debug;
    81 
    84 
    82     # Declare variables used throughout the rest of the script.
    85     # Declare variables used throughout the rest of the script.
    83     my ($request, $response, $sessionid, $favorite);
    86     my ($request, $response, $sessionid, $favorite);
    84 
    87 
    85     # Store the OpenSSL command in a variable for convienence.
    88     # Store the OpenSSL command in a variable for convienence.
    86     my $openssl =
    89     my $openssl =
    87         "openssl s_client"
    90         "openssl s_client"
    88       . (-d "/etc/ssl/certs" ? " -CApath /etc/ssl/certs" : "")
    91       . (-d "/etc/ssl/certs" ? " -CApath /etc/ssl/certs" : "")
    89       . " -ign_eof -quiet -connect ${host}:443";
    92       . " -ign_eof -quiet -connect ${opt_host}:443";
    90 
    93 
    91     # Make initial request to get client_data
    94     # Make initial request to get client_data
    92     $request =
    95     $request =
    93         "GET /my.logon.php3?check=1 HTTP/1.0\r\n"
    96         "GET /my.logon.php3?check=1 HTTP/1.0\r\n"
    94       . "Content-Type: application/x-www-form-urlencoded\r\n"
    97       . "Content-Type: application/x-www-form-urlencoded\r\n"
    95       . "Connection: close\r\n" . "\r\n";
    98       . "Connection: close\r\n" . "\r\n";
    96 
    99 
    97     $response = qx(echo "${request}" | ${openssl} 2>/dev/null)
   100     $response = qx(echo "${request}" | ${openssl} 2>/dev/null)
    98       or die "Invalid Host spezified or not reachable: $host\n";
   101       or die ME . ": Invalid Host specified or not reachable: $opt_host\n";
    99 
   102 
   100     $response =~ s/<INPUT type="hidden" name="client_data" value="(.*)">/$1/;
   103     $response =~ s/<INPUT type="hidden" name="client_data" value="(.*)">/$1/;
   101     my $client_data = $1;
   104     my $client_data = $1;
   102 
   105 
   103 ###
   106 ###
   108   # browser will make many more requests than this to complete the log in
   111   # 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
   112   # 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.
   113   # may fail if the FirePass has End-Point Security Policies configured.
   111     $request =
   114     $request =
   112 "check=1&username=${user}&password=${passcode}&mrhlogonform=1&client_data=${client_data}";
   115 "check=1&username=${user}&password=${passcode}&mrhlogonform=1&client_data=${client_data}";
       
   116 
   113     $request =
   117     $request =
   114         "POST /my.activation.php3 HTTP/1.0\r\n"
   118         "POST /my.activation.php3 HTTP/1.0\r\n"
   115       . "Host: ${host}\r\n"
   119       . "Host: ${opt_host}\r\n"
   116       . "Content-Type: application/x-www-form-urlencoded\r\n"
   120       . "Content-Type: application/x-www-form-urlencoded\r\n"
   117       . "Content-Length: "
   121       . "Content-Length: "
   118       . length($request) . "\r\n"
   122       . length($request) . "\r\n"
   119       . "Connection: close\r\n" . "\r\n"
   123       . "Connection: close\r\n" . "\r\n"
   120       . "${request}\r\n";
   124       . "${request}\r\n";
       
   125 
   121     $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
   126     $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
   122 
   127 
   123   # We can then parse the response for the MRHSession Cookie, which contains our
   128   # 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
   129   # SessionID.  In this example, we print out the SessionID in order to verify
   125   # that our log in attempt worked.
   130   # that our log in attempt worked.
   126     $response =~ /MRHSession=(\w+);/;
   131     $response =~ /MRHSession=(\w+);/;
   127     $sessionid = $1;
   132     $sessionid = $1;
   128     print "SessionID: ${sessionid}\n" if $debug;
   133     print "SessionID: ${sessionid}\n" if $opt_debug;
   129 
   134 
   130 ###
   135 ###
   131 ### STEP 3 :: Create the SSL VPN tunnel.
   136 ### STEP 3 :: Create the SSL VPN tunnel.
   132 ###
   137 ###
   133 
   138 
   134    # Now that we are authenticated and have a valid SessionID, we must request
   139    # 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
   140    # 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.
   141    # 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"
   142     $request = "GET /vdesk/vpn/index.php3?outform=xml HTTP/1.0\r\n"
   138       . "Cookie: MRHSession=${sessionid}\r\n\r\n";
   143       . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n";
   139     $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
   144     $response = qx(echo "${request}" | ${openssl} 2>/dev/null);
   140 
   145 
   141  # The response is XML, so we can safely grab what we are looking for using some
   146  # 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
   147  # regular expression magic.  Same with the SessionID, we're printing out the
   143  # final value to make sure we're on the right track.
   148  # final value to make sure we're on the right track.
   144     $response =~ /${name}[^\n]+\n[^Z]+Z=\d+,(\d+)/;
   149     $response =~ /${opt_name}[^\n]+\n[^Z]+Z=\d+,(\d+)/;
   145     $favorite = $1;
   150     $favorite = $1;
   146     print "Favorite: ${favorite}\n" if $debug;
   151     print "Favorite: ${favorite}\n" if $opt_debug;
   147 
   152 
   148     # We're all set!  Let's visit the necessary pages/objects to notify FirePass
   153     # We're all set!  Let's visit the necessary pages/objects to notify FirePass
   149     # that we wish to open a SSL VPN tunnel.
   154     # that we wish to open a SSL VPN tunnel.
   150     foreach my $uri ("/vdesk/", "/vdesk/vpn/connect.php3?Z=0,${favorite}",) {
   155     foreach my $uri ("/vdesk/", "/vdesk/vpn/connect.php3?Z=0,${favorite}",) {
   151         $request = "GET ${uri} HTTP/1.0\r\n"
   156         $request = "GET ${uri} HTTP/1.0\r\n"
   158 # simply calling PPPD, and having it use OpenSSL as a psuedo terminal device.
   163 # simply calling PPPD, and having it use OpenSSL as a psuedo terminal device.
   159     $request = "GET /myvpn?sess=${sessionid} HTTP/1.0\r\n"
   164     $request = "GET /myvpn?sess=${sessionid} HTTP/1.0\r\n"
   160       . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n";
   165       . "Cookie: MRHSession=${sessionid}\r\n" . "\r\n";
   161     $request = "chat -v '' '${request}'";
   166     $request = "chat -v '' '${request}'";
   162     system(
   167     system(
   163 "pppd ${ppp_opts} noauth crtscts passive noproxyarp local pty \"${openssl}\" connect \"${request}\""
   168         pppd     => @ppp_opts,
       
   169         pty      => ${openssl},
       
   170         connect  => ${request},
       
   171         linkname => "sap-vpn",
       
   172         qw(noauth crtscts passive noproxyarp
       
   173           local),
   164     );
   174     );
   165 
   175 
   166     # Voila!  We should now have a PPP connection running over SSL.  We can exit
   176     # 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
   177     # from this script cleanly, and move on to setting up routes to the remote
   168     # network using our favorite networking tools.  Happy hacking!
   178     # network using our favorite networking tools.  Happy hacking!
   183  vpn [-m|--man]
   193  vpn [-m|--man]
   184 
   194 
   185 =head1 DESCRIPTION
   195 =head1 DESCRIPTION
   186 
   196 
   187 Ths script establishes a VPN connecttion to a FirePass server.
   197 Ths script establishes a VPN connecttion to a FirePass server.
   188 B<Note:> This script requires root privileges and should be run via sudo.
   198 B<Note:> This script requires root privileges and should be run via sudo
       
   199 or some other approbiate mechanism.
   189 
   200 
   190 =head1 OPTIONS
   201 =head1 OPTIONS
   191 
   202 
   192 
       
   193 =over
   203 =over
   194 
   204 
   195 =item B<-u>|B<--user> I<user>
   205 =item B<-d>
   196 
   206 
   197 Your D|C|I user, not really optional. (no default)
   207 Print debug output from pppd. In this mode the script (and the pppd)
   198 
   208 will not detach from your terminal and the script code will not be
   199 =item B<-p>|B<--passcode> I<passcode>
   209 executed.  (default: 0)
   200 
   210 
   201 Your passcode, if not supplied, F</dev/tty> is opened for reading
   211 =item B<-h>|B<--help>
   202 the passcode. (no default)
   212 
       
   213 A short help. (defualt: off)
   203 
   214 
   204 =item B<-H>|B<--host> I<host>
   215 =item B<-H>|B<--host> I<host>
   205 
   216 
   206 Host to connect to. (defaults to C<connectwdf.sap.corp>)
   217 Host to connect to. (defaults to C<connectwdf.sap.corp>)
   207 
   218 
       
   219 =item B<-m>|B<--man>
       
   220 
       
   221 This man page. (default: off)
       
   222 
   208 =item B<-n>|B<--name> I<name>
   223 =item B<-n>|B<--name> I<name>
   209 
   224 
   210 Name of the service(?). (default: to 'SAP Network Access')
   225 Name of the service(?). (default: to 'SAP Network Access')
   211 
       
   212 =item B<-d>
       
   213 
       
   214 Print debug output from pppd. (default: 0)
       
   215 
   226 
   216 =item B<-o>|B<--opts> I<ppp options>
   227 =item B<-o>|B<--opts> I<ppp options>
   217 
   228 
   218 Additional options for ppp. Can be specified multiple times. (default: nodetach)
   229 Additional options for ppp. Can be specified multiple times. (default: nodetach)
   219 Good choices are C<detach>, or C<updetach>.
   230 Good choices are C<detach>, or C<updetach>.
   220 B<Note:> The C<nodefaultroute> is set automatically.
   231 B<Note:> The C<nodefaultroute> is set automatically.
   221 
   232 
       
   233 =item B<-p>|B<--passcode> I<passcode>
       
   234 
       
   235 Your passcode, if not supplied, F</dev/tty> is opened for reading
       
   236 the passcode. (no default)
       
   237 
       
   238 =item B<-s>|B<--script> I<script>
       
   239 
       
   240 Script to execute after establishing the IP link. (See the B<-d> option
       
   241 above!). (no default)
       
   242 
       
   243 B<Note:> You should consider using the F</etc/ppp/ip-up.d/> scripts.
       
   244 (see below)
       
   245 
       
   246 B<Note2:> NOT IMPLEMENTED YET!
       
   247 
       
   248 
       
   249 =item B<-u>|B<--user> I<user>
       
   250 
       
   251 Your D|C|I user, not really optional. (no default)
       
   252 
   222 =back
   253 =back
   223 
   254 
   224 =cut
   255 =cut
   225 
   256 
   226 ###
   257 ###