#!/usr/bin/perl use Data::Dumper; use Config::General qw(ParseConfig SaveConfig); use Digest::MD5 qw(md5 md5_hex md5_base64); use DB_File; use LWP::UserAgent; no locale; my $listuri = "http://www.vpngate.net/en/"; my $cache = "$ENV{HOME}/.vpngate-cache"; my $vpnconfig = "$ENV{HOME}/.vpngate"; my %vpn; my @untrusted = qw(iran china russia arab japan indonesia hong viet); if (-e $cache) { my $mtime = (stat ($cache))[9]; if (time - $mtime < 600) { # young cache %vpn = ParseConfig($cache); } else { %vpn = &fetchvpns; } } else { %vpn = &fetchvpns; } my %showed; my $id = 1; my $format = "%2s %20s %6s %-40s %s\n"; printf $format, qw(id country score stats connectivity); print "-" x 140; print "\n"; foreach my $host (sort { $vpn{$b}->{score} <=> $vpn{$a}->{score} } keys %vpn) { last unless $id < 21; next if grep { $vpn{$host}->{country} =~ /$_/i } @untrusted; $showed{$id} = $vpn{$host}; printf $format, $id, $vpn{$host}->{country}, $vpn{$host}->{score}, $vpn{$host}->{stats}, $vpn{$host}->{connection}; $id++; } print "Select ID: "; while () { chomp; if (/^\d\d*$/) { if (exists $showed{$_}) { &connect($showed{$_}); last; } } print "Select ID: "; } sub connect { my $vpn = shift; # first, dissect the details uri and use the items to construct the openvpn cfg uri my $uri = $vpn->{uri}; $uri =~ s#/en/do_openvpn#/common/openvpn_download#; $uri =~ s/&tcp=\d+//; $uri =~ s/fqdn=[^&]*&//; $uri =~ s/udp=/port=/; $uri =~ s/ip=/host=/; my ($port) = $uri =~ /port=(\d+)/; $uri .= "&udp=1&vpngate_$vpn->{ip}_udp_$port.ovpn"; # next, fetch the config print "Fetching OpenVPN Config..."; my ($status, $cfg) = &httpget($uri); if ($status) { open VPN, ">$vpnconfig" or die "Could not write OpenVPN Config to $vpnconfig: $!\n"; print VPN $cfg; close VPN; # and finally, if everything went ok, run it system ("sudo openvpn --config $vpnconfig"); } else { die "Could not fetch OpenVPN Config from VPNGATE: $status!\n"; } } sub httpget { my $url = shift; my $ua = LWP::UserAgent->new; $ua->agent("Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924 Feedextrator/Version (Ubuntu)"); my $req = HTTP::Request->new(GET => $url); $req->header(Accept => "text/html, */*;q=0.1"); $req->header("Accept-Charset" => "utf-8"); $req->header("Accept-Language" => "de-DE"); $req->protocol('HTTP/1.0'); if($cookie) { $req->header(Cookie => $cookie); } my $res = $ua->request($req); if ($res->is_success) { return (1, $res->content); } else { return (0, $res->status_line); } } sub fetchvpns { my ($status, $content) = &httpget($listuri); if ($status) { if ($content =~ /vg_table_row/) { my @raw; foreach (split /[\r\n]/, $content) { if (/do_openvpn/) { push @raw, $_; } } if (@raw) { my %vpn; foreach my $one (@raw) { my @columns = split /<\/td/, $one; my @cleaned; foreach my $item (@columns) { if ($item =~ /(do_openvpn[^\']*)/) { $item = $1; } else { $item =~ s/(
|)/, /gi; $item =~ s/<[^>]*>//g; $item =~ s/[<>]//g; $item =~ s/^,\s\s*//; $item =~ s/,\s\s*$//; $item =~ s/, , /, /g; } push @cleaned, $item; } my ($alias, $ip, $hostname) = split /\s*,\s*/, $cleaned[1]; $hostname =~ s/[\(\)]//g; my $score = $cleaned[9]; $score =~ s/,//g; if ($cleaned[4] =~ /UDP: Supported/i) { $vpn{$alias} = { country => $cleaned[0], host => $hostname, alias => $alias, ip => $ip, stats => $cleaned[2], connection => $cleaned[3], features => $cleaned[4], uri => $listuri . $cleaned[6], runby => $cleaned[8], score => $score }; } } SaveConfig($cache, \%vpn); return %vpn; } else { die "Failed to extract the VPN list, regex failure, maybe site has changed!\n"; } } else { die "Didn't find the VPN List in $listuri!\n"; } } else { die "Failed to connect to $listuri: $status!\n"; } }