├── README.md ├── client.pl └── lang.txt /README.md: -------------------------------------------------------------------------------- 1 | Source code for the cryptostorm client (we refer to it as the 'widget'). 2 | 3 | The latest version is available at: 4 | https://cryptostorm.is/cryptostorm_setup.exe 5 | or if you're connected to the VPN, you can also retrieve it from: 6 | http://10.31.33.7/cryptostorm_setup.exe 7 | 8 | Instructions are at https://cryptostorm.is/windows 9 | -------------------------------------------------------------------------------- /client.pl: -------------------------------------------------------------------------------- 1 | our $VERSION; 2 | BEGIN { 3 | $VERSION = "3.65"; 4 | $ENV{PAR_GLOBAL_TEMP} = 1 unless defined $ENV{PAR_GLOBAL_TEMP}; 5 | $ENV{PAR_CACHE_ID} = "cswidget_v${VERSION}" unless defined $ENV{PAR_CACHE_ID}; 6 | 7 | my $par_user = sprintf("%x", 0x61636f726e + $$); 8 | $ENV{MYAPP_PAR_PATH} = "$ENV{TEMP}/par-$par_user/cache-$ENV{PAR_CACHE_ID}"; 9 | mkdir $ENV{MYAPP_PAR_PATH} unless -d $ENV{MYAPP_PAR_PATH}; 10 | 11 | # Force preload before PAR loader 12 | $ENV{PAR_TEMP} = $ENV{MYAPP_PAR_PATH}; 13 | $ENV{PAR_CLEAN} = 1; 14 | } 15 | use PAR; 16 | use lib "$ENV{MYAPP_PAR_PATH}/inc/lib"; 17 | use lib "$ENV{MYAPP_PAR_PATH}/inc"; 18 | my $bit = 64; 19 | if (-d "\\Program Files\\Cryptostorm Client\\bin") { 20 | chdir("\\Program Files\\Cryptostorm Client\\bin\\"); 21 | $bit = 32; 22 | } 23 | if (-d "\\Program Files (x86)\\Cryptostorm Client\\bin") { 24 | chdir("\\Program Files (x86)\\Cryptostorm Client\\bin\\"); 25 | } 26 | use strict; 27 | use warnings; 28 | use threads; 29 | use threads::shared; 30 | use Tkx; 31 | Tkx::encoding("system", "utf-8"); 32 | use Tkx::SplashScreen; 33 | use Win32::GUI; 34 | # https://msdn.microsoft.com/en-us/library/windows/desktop/aa373247%28v=vs.85%29.aspx 35 | use constant WM_POWERBROADCAST => 0x218; 36 | use constant PBT_APMSUSPEND => 0x4; 37 | use constant PBT_APMRESUMEAUTOMATIC => 0x12; 38 | use constant PBT_APMRESUMECRITICAL => 0x6; 39 | if (defined &Win32::SetChildShowWindow) { 40 | Win32::SetChildShowWindow(0); 41 | } 42 | use Digest::SHA qw(sha512_hex); 43 | use File::Copy qw(copy); 44 | use IO::Socket; 45 | use IO::Socket::SSL; 46 | use LWP::UserAgent; 47 | use Socket; 48 | use Socket6; 49 | use Win32::AbsPath; 50 | use Win32::File::VersionInfo; 51 | use Win32::Process; 52 | use Win32::Process::List; 53 | use Win32::Event; 54 | use Win32::Clipboard; 55 | use Win32::Service; 56 | # for updating the nodelist, so it doesn't require DNS 57 | my @csnu_ips = ( 58 | { ip => '2a00:c98:2030:a005:c0ff:eeee:eeee:eeee', family => AF_INET6 }, 59 | { ip => '46.165.221.67', family => AF_INET }, 60 | ); 61 | my $wintunexe = Win32::GetFullPathName("cswintun.exe"); 62 | my $clip = Win32::Clipboard(); 63 | use Win32::TieRegistry qw(REG_DWORD REG_MULTI_SZ REG_SZ),(Delimiter => "/"); 64 | $Registry->{'HKEY_CURRENT_USER/Software/Cryptostorm/'} = {}; 65 | my $regkey = $Registry->{'HKEY_CURRENT_USER/Software/Cryptostorm/'}; 66 | use Win32::IPHelper; 67 | our $self = Win32::AbsPath::Fix "$0"; 68 | our $BUILDVERSION; 69 | our ($ovpnver, $osslver, $verstuff, $final_data, $counter, $doupgrade, $total_size, $fh, $dnsleak_var); 70 | my $manport; 71 | our ($fixdns_btn); 72 | our @animation = qw( \ | / -- ); 73 | our @output; 74 | our @resolved_ips; 75 | our @addresses; 76 | our @remote_random = (); 77 | our $rt; 78 | our $manpass; 79 | our $update_err : shared; 80 | our $logfile; 81 | our $chosen_ip; 82 | our $ipv6_ip_i_was_connected_to; 83 | my $lang; 84 | my $sel_lang; 85 | my $localip; 86 | my $localip6; 87 | if (defined($ARGV[0]) && ($ARGV[0] eq "/LANG")) { 88 | if (defined($ARGV[1])) { 89 | $lang = $ARGV[1]; 90 | $sel_lang = $ARGV[1]; 91 | } 92 | } 93 | if (!$lang) { 94 | $lang = "English"; 95 | $sel_lang = "English"; 96 | } 97 | my $foo = GetFileVersionInfo ( "$self" ); 98 | if ($foo) { 99 | $BUILDVERSION = $foo->{FileVersion}; 100 | } 101 | else { 102 | $BUILDVERSION = "3.64.0.0"; 103 | } 104 | our $iwasconnected = 0; 105 | my $masterpid; 106 | my %stupidstrictrefs; 107 | my @log_lines: shared; 108 | my $stop: shared = 0; 109 | my $done : shared = 0; 110 | my $nodebuf : shared; 111 | my $status : shared; 112 | my $pid : shared; 113 | my $o_version_buf : shared; 114 | my $o_done3 : shared; 115 | my $latest : shared; 116 | my $amsg : shared; 117 | our @recover; 118 | my $authfile = '..\user\config.ini'; 119 | my $hashfile = '..\user\client.dat'; 120 | my $cacertfile = '..\user\ca.crt'; 121 | my $cclientfile = '..\user\client.crt'; 122 | my $clientkey = '..\user\client.key'; 123 | my $nodelistfile = '..\user\nodelist.txt'; 124 | my $c = 0; 125 | my $server = ""; 126 | my $widget_update_var; 127 | our $VPNfh; 128 | our $updatethread; 129 | our $o_thread3; 130 | my ( $ovpnline, $vpnexe, $osslexe, $dnscexe, $h); 131 | my ($frame1, $frame2, $frame3, $frame4, $saveoption, $password, $userlbl, $passlbl, $connect, $cancel, $pass, 132 | $save, $progress, $pbar, $pbarval, $statuslbl, $statusvar, $token_textbox, $token, $worldimage, $logbox, $logbox_index, 133 | $scroll, $errorimage, $server_textbox, $disp_server, $tripimage, $server_host, $update, $menu, $send, $options); 134 | my ($autocon, $autocon_var, $autorun, $autorun_var, $o_frame1, $o_worldimage, $back, $o_tabs, $o_innerframe1, 135 | $o_innerframe2, $o_innerframe3, $o_innerframe4, $derp); 136 | my $kcxt=0; 137 | my $autosplash_var = ""; 138 | my $dnscrypt_var = "on"; 139 | my $killswitch_var = "off"; 140 | my $ts_var = "on"; 141 | our ($TrayIcon,$TrayWinHidden,$TrayNotify,$TrayMenu); 142 | my $showtiponce = 0; 143 | my ($x, $y, $width, $height); 144 | our (@servers, @disp_servers); 145 | my $upgrade = 0; 146 | my $balloon_msg; 147 | my $idle = 0; 148 | my $update_var = "on"; 149 | my $randomize_it = "off"; 150 | my $tokillornot; 151 | our @msgs; 152 | our $thread; 153 | my @tmparray; 154 | my $tmpline = ""; 155 | my $vpn_args = ""; 156 | $SIG{'TERM'} = 'TERM_handler'; 157 | $SIG{'ABRT'} = 'TERM_handler'; 158 | $SIG{'INT'} = 'TERM_handler'; 159 | $SIG{'KILL'} = 'TERM_handler'; 160 | $SIG{'HUP'} = 'TERM_handler'; 161 | if (-e $ENV{'TEMP'} . '\client.dat') { 162 | copy($ENV{'TEMP'} . '\client.dat',$hashfile); 163 | unlink($ENV{'TEMP'} . '\client.dat'); 164 | } 165 | if (-e $ENV{'TEMP'} . '\config.ini') { 166 | copy($ENV{'TEMP'} . '\config.ini',$authfile); 167 | unlink($ENV{'TEMP'} . '\config.ini'); 168 | } 169 | my $noipv6_var = "off"; 170 | my $tmp_noipv6_var; 171 | my $tmp_dnscrypt_var; 172 | my $tmp_killswitch_var; 173 | our $port_var = "443"; 174 | my $proto_var = "UDP"; 175 | my @protos = ('UDP', 'TCP'); 176 | my @tlses = ('secp521r1','Ed25519','Ed448','ML-DSA-87'); 177 | my $tls_sel = 'secp521r1'; 178 | my $cipher_sel = 'AES-256-GCM'; 179 | my $selected_adv_opt2 = "1400"; 180 | my $selected_adv_opt3 = "adaptive"; 181 | my $selected_adv_opt4 = "Any address"; 182 | my $adv_socks_opt = "off"; 183 | my $adv_ssh_opt = "off"; 184 | my $adv_https_opt = "off"; 185 | my $selected_tunnel_opt; 186 | my $local_tunnel_port; 187 | my $tunnel_check_counter = 0; 188 | my $adv_socks_ip = "127.0.0.1"; 189 | my $adv_socks_port = 9150; 190 | my $adv_socks_noauth_opt = "on"; 191 | my $adv_socks_user_var = ""; 192 | my $adv_socks_pass_var = ""; 193 | my $timeout_var = 60; 194 | if (-e "$authfile") { 195 | open(CREDS,"$authfile"); 196 | while () { 197 | if ((/^([a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5})$/) || 198 | (/^([a-f0-9]{128})$/)) { 199 | $token = $1; 200 | } 201 | if (/^timeout=([0-9]+)$/) { 202 | $timeout_var = $1; 203 | } 204 | if (/^noipv6=(.*)$/) { 205 | $noipv6_var = $1; 206 | } 207 | if (/^dnsleak=(.*)$/) { 208 | $dnsleak_var = $1; 209 | } 210 | if (/^port=(.*)$/) { 211 | $port_var = $1; 212 | } 213 | if (/^proto=(.*)$/) { 214 | $proto_var = $1; 215 | } 216 | if (/^node=(.*)$/) { 217 | $disp_server = $1; 218 | } 219 | if (/^autocon=(.*)$/) { 220 | $autocon_var = $1; 221 | } 222 | if (/^autosplash=(.*)$/) { 223 | $autosplash_var = $1; 224 | } 225 | if (/^autorun=(.*)$/) { 226 | $autorun_var = $1; 227 | } 228 | if (/^checkforupdate=(.*)$/) { 229 | $update_var = $1; 230 | } 231 | if (/^dnscrypt=(.*)$/) { 232 | $dnscrypt_var = $1; 233 | } 234 | if (/^killswitch=(.*)$/) { 235 | $killswitch_var = $1; 236 | } 237 | if (/^ts=(.*)$/) { 238 | $ts_var = $1; 239 | } 240 | if (/^tls_sel=(.*)$/) { 241 | $tls_sel = $1; 242 | } 243 | if (/^widget_update_var=(.*)$/) { 244 | $widget_update_var = $1; 245 | } 246 | if (/^randomport=(.*)$/) { 247 | $randomize_it = $1; 248 | } 249 | if ((/^lang=(.*)$/) && (defined $ARGV[0] && $ARGV[0] ne "/LANG")) { 250 | $lang = $1; 251 | $sel_lang = $1; 252 | } 253 | if (/^mssfix=(.*)$/) { 254 | $selected_adv_opt2 = $1; 255 | } 256 | if (/^route-method=(.*)$/) { 257 | $selected_adv_opt3 = $1; 258 | } 259 | if (/^bind=(.*)$/) { 260 | $selected_adv_opt4 = $1; 261 | } 262 | if (/^socks=on$/) { 263 | $adv_socks_opt = "on"; 264 | } 265 | if (/^socks_ip=(.*)$/) { 266 | $adv_socks_ip = $1; 267 | } 268 | if (/^socks_port=(.*)$/) { 269 | $adv_socks_port = $1; 270 | } 271 | if (/^socks_noauth=(.*)$/) { 272 | if ($1 eq "off") { 273 | $adv_socks_noauth_opt = "off"; 274 | $adv_socks_user_var = $regkey->{'SOCKS_USER'}; 275 | $adv_socks_pass_var = $regkey->{'SOCKS_PASS'}; 276 | } 277 | } 278 | if (/^tunnel_ssh=(.*)$/) { 279 | $adv_ssh_opt = $1; 280 | } 281 | if (/^tunnel_https=(.*)$/) { 282 | $adv_https_opt = $1; 283 | } 284 | if (/^tunnel_host=(.*)$/) { 285 | $selected_tunnel_opt = $1; 286 | } 287 | } 288 | } 289 | use utf8; 290 | use Encode; 291 | binmode(STDOUT, ":utf8"); 292 | sub load_lang_compat { 293 | my $file = shift; 294 | open my $fh, "<:encoding(UTF-8)", $file or die $!; 295 | my %lang; 296 | my $key; 297 | while (<$fh>) { 298 | chomp; 299 | next if /^\s*$/ || /^\s*#/; 300 | if (/^\S+/ && !/=/) { 301 | ($key) = split; 302 | } elsif (/^\s*(\w+)\s*=\s*(.+)$/ && defined $key) { 303 | my ($langcode, $val) = ($1, $2); 304 | $lang{$langcode}{$key} = $val; 305 | } 306 | } 307 | close $fh; 308 | return \%lang; 309 | } 310 | my $L = load_lang_compat('..\user\lang.txt'); 311 | my @langs; 312 | my $earlymw = Tkx::widget->new("."); 313 | $earlymw->g_wm_withdraw(); 314 | unless (defined $L->{$lang}{ERR_AUTH_FAIL}) { 315 | &do_error("Invalid language \"$lang\", reverting to English"); 316 | $lang = "English"; 317 | } 318 | my @missing; 319 | foreach my $msg_key (sort keys %{$L->{'English'}}) { 320 | foreach my $lang_name (keys %$L) { 321 | push @langs, $lang_name unless grep { $_ eq $lang_name } @langs; 322 | } 323 | unless (defined $L->{$lang}{$msg_key}) { 324 | push @missing, $msg_key; 325 | } 326 | } 327 | if (@missing) { 328 | my $missed = join(", ", @missing); 329 | &do_error("Some entries are missing for '$lang': $missed"); 330 | } 331 | Tkx::update(); 332 | $disp_server = $L->{$lang}{TXT_DEFAULT_SERVER} unless defined($disp_server); 333 | our $hiddenornot : shared = "Hide"; 334 | Tkx::package_require("style"); 335 | Tkx::package_require('tooltip'); 336 | Tkx::style__use("as", -priority => 70); 337 | Tkx::font_create("logo_font", -family => "Helvetica", -size => 10, -weight => "bold"); 338 | Tkx::font_create("token_font", -family => "Arial", -size => 10); 339 | Tkx::image_create_photo("mainicon", -file => "..\\res\\greyworld.png"); 340 | Tkx::image_create_photo("mainicon2", -file => "..\\res\\world2.png"); 341 | Tkx::image_create_photo("opticon", -file => "..\\res\\world3.png"); 342 | Tkx::image_create_photo("opticon2", -file => "..\\res\\world4.png"); 343 | Tkx::image_create_photo("erroricon", -file => "..\\res\\gears.png"); 344 | Tkx::image_create_photo("b1", -file => "..\\res\\b1.png"); 345 | Tkx::image_create_photo("b2", -file => "..\\res\\b2.png"); 346 | Tkx::image_create_photo("b3", -file => "..\\res\\b3.png"); 347 | Tkx::image_create_photo("b4", -file => "..\\res\\b4.png"); 348 | Tkx::image_create_photo("b5", -file => "..\\res\\b5.png"); 349 | Tkx::image_create_photo("b6", -file => "..\\res\\b6.png"); 350 | Tkx::image_create_photo("g1", -file => "..\\res\\g1.png"); 351 | Tkx::image_create_photo("g2", -file => "..\\res\\g2.png"); 352 | Tkx::image_create_photo("g3", -file => "..\\res\\g3.png"); 353 | Tkx::image_create_photo("g4", -file => "..\\res\\g4.png"); 354 | Tkx::image_create_photo("g5", -file => "..\\res\\g5.png"); 355 | Tkx::image_create_photo("g6", -file => "..\\res\\g6.png"); 356 | Tkx::image_create_photo("r1", -file => "..\\res\\r1.png"); 357 | Tkx::image_create_photo("r2", -file => "..\\res\\r2.png"); 358 | Tkx::image_create_photo("r3", -file => "..\\res\\r3.png"); 359 | Tkx::image_create_photo("r4", -file => "..\\res\\r4.png"); 360 | Tkx::image_create_photo("r5", -file => "..\\res\\r5.png"); 361 | Tkx::image_create_photo("r6", -file => "..\\res\\r6.png"); 362 | Tkx::namespace_import("::tooltip::tooltip"); 363 | my $mw = Tkx::widget->new("."); 364 | $mw->g_wm_withdraw(); 365 | if (Win32::IsAdminUser() != 1) { 366 | &do_error($L->{$lang}{ERR_NEED_ADMIN}); 367 | exit; 368 | } 369 | my ($STRING, $MAJOR, $MINOR, $BUILD, $ID) = Win32::GetOSVersion(); 370 | if ($MAJOR < 6) { 371 | &do_error($L->{$lang}{ERR_OLD_WIN}); 372 | &do_exit; 373 | } 374 | sub TERM_handler { 375 | if (defined($mw)) { 376 | $mw->g_wm_attributes('-topmost', 1); 377 | $mw->g_wm_attributes('-topmost', 0); 378 | $mw->g_wm_deiconify(); 379 | $mw->g_raise(); 380 | $mw->g_focus(); 381 | } 382 | $tokillornot = Tkx::tk___messageBox(-parent => $mw, -type => "yesno", 383 | -message => $L->{$lang}{QUESTION_ANOTHERPROG1} . "\n" . 384 | $L->{$lang}{QUESTION_ANOTHERPROG2} . "\n" . 385 | $L->{$lang}{QUESTION_ANOTHERPROG3} . "\n", 386 | -icon => "question", -title => "cryptostorm.is client"); 387 | if ($tokillornot eq "yes") { 388 | if ($token) { 389 | copy($hashfile,$ENV{'TEMP'} . "\\client.dat"); 390 | copy($authfile,$ENV{'TEMP'} . "\\config.ini"); 391 | } 392 | &do_exit; 393 | } 394 | } 395 | my $cw = $mw->new_toplevel; 396 | $cw->g_wm_withdraw(); 397 | Tkx::tk(appname => "cryptostorm.is client"); 398 | Tkx::wm_iconphoto($mw, "mainicon"); 399 | $vpnexe = "csvpn.exe"; 400 | $osslexe = "ossl.exe"; 401 | $dnscexe = "cs-dnsc-p.exe"; 402 | my $pi = Win32::Process::List->new(); 403 | $masterpid = $$; 404 | my %procs = $pi->GetProcesses(); 405 | my $proccount = 0; 406 | foreach my $pids ( keys %procs ) { 407 | next if $pids == $masterpid; 408 | if ($procs{$pids} =~ /csvpn/) { 409 | system(1,"TASKKILL /F /T /PID $pids"); 410 | } 411 | if ($procs{$pids} =~ /^client.exe$/) { 412 | $proccount++; 413 | if ($proccount == 2) { 414 | $tokillornot = Tkx::tk___messageBox(-parent => $mw, -type => "yesno", 415 | -message => $L->{$lang}{QUESTION_ONLYONE1} . "\n" . 416 | $L->{$lang}{QUESTION_ONLYONE2} . "\n", 417 | -icon => "question", -title => "cryptostorm.is client"); 418 | if ($tokillornot eq "yes") { 419 | system(1,"TASKKILL /F /T /PID $pids"); 420 | } 421 | if ($tokillornot eq "no") { 422 | system(1,"TASKKILL /F /T /PID $masterpid"); 423 | } 424 | } 425 | } 426 | } 427 | 428 | if (-e "..\\user\\mydns.txt") { 429 | open my $handle, '<', "..\\user\\mydns.txt"; 430 | chomp(@recover = <$handle>); 431 | close $handle; 432 | unlink("..\\user\\mydns.txt"); 433 | &restore_dns; 434 | } 435 | 436 | &get_current_dns; 437 | $verstuff = `$vpnexe --version 2>&1`; 438 | if ($verstuff =~ /OpenVPN ([0-9\.]+)/) { 439 | $ovpnver = $1; 440 | } 441 | if ($verstuff =~ /OpenSSL ([0-9\.a-z]+)/) { 442 | $osslver = $1; 443 | } 444 | 445 | if ($autosplash_var ne "on") { 446 | my $sr = $mw->new_tkx_SplashScreen( 447 | -image => Tkx::image_create_photo(-file => "..\\res\\splash.png"), 448 | -width => '480', 449 | -height => '272', 450 | -show => 1, 451 | -topmost => 1, 452 | ); 453 | Tkx::after(500 => sub { 454 | $sr->g_destroy(); 455 | $mw->g_wm_deiconify(); 456 | $mw->g_raise(); 457 | $mw->g_focus(); 458 | }); 459 | } 460 | $mw->g_wm_protocol('WM_DELETE_WINDOW', sub { 461 | if (&isoncs > 0) { 462 | &hidewin; 463 | } 464 | else { 465 | &do_exit; 466 | } 467 | }); 468 | $mw->g_wm_resizable(0,0); 469 | Tkx::wm_title($mw, "cryptostorm widget v$VERSION"); 470 | $pbarval = 0; 471 | 472 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 473 | Tkx::wm_attributes($mw, -toolwindow => 0, -topmost => 0); 474 | 475 | $cw->g_wm_protocol('WM_DELETE_WINDOW', sub { 476 | &backtomain; 477 | }); 478 | $cw->g_wm_resizable(0,0); 479 | Tkx::wm_attributes($cw, -toolwindow => 0, -topmost => 0); 480 | Tkx::wm_title($cw, $L->{$lang}{TXT_OPTIONS}); 481 | Tkx::wm_iconphoto($cw, "mainicon"); 482 | $o_frame1 = $cw->new_ttk__frame(-relief => "flat"); 483 | $o_worldimage = $o_frame1->new_ttk__label(-anchor => "nw", -justify => "center", -image => 'opticon', -compound => 'top', -text => "Widget v$VERSION\nBuild: $BUILDVERSION\nOpenVPN: $ovpnver\nOpenSSL: $osslver"); 484 | $back = $o_frame1->new_ttk__button(-text => $L->{$lang}{TXT_BACK}, -command => \&backtomain); 485 | $cw->g_bind("", sub { $back->invoke(); }); 486 | Tkx::update('idletasks'); 487 | 488 | $o_tabs = $cw->new_ttk__notebook(-height => 0, -width => 0); 489 | $o_innerframe1 = $o_tabs->new_ttk__frame(); 490 | $o_innerframe2 = $o_tabs->new_ttk__frame(); 491 | $o_innerframe3 = $o_tabs->new_ttk__frame(); 492 | $o_innerframe4 = $o_tabs->new_ttk__frame(); 493 | 494 | my $powerw = Win32::GUI::Window->new(); 495 | $powerw->Hook(WM_POWERBROADCAST, \&power_event); 496 | $powerw->Hide(); 497 | 498 | my $lbl_blank = $o_innerframe1->new_ttk__label(-text => " \n \n"); 499 | my $lbl_lang; 500 | my $lang_update; 501 | if ($#langs > 0) { 502 | $lbl_lang = $o_innerframe1->new_ttk__label(-text => "\n" . $L->{$lang}{TXT_LANGUAGE} . ":\n"); 503 | $lang_update = $o_innerframe1->new_ttk__combobox(-textvariable => \$sel_lang, -values => \@langs, -state=>"readonly"); 504 | $lang_update->g_bind("<>", sub { 505 | Tkx::tk___messageBox(-icon => "info", -message => "Restart the widget to switch the language to $sel_lang"); 506 | }); 507 | } 508 | my $chk_splash = $o_innerframe1->new_ttk__checkbutton(-text => $L->{$lang}{TXT_NO_SPLASH}, -variable => \$autosplash_var, -onvalue => "on", -offvalue => "off"); 509 | my $chk_autocon = $o_innerframe1->new_ttk__checkbutton(-text => $L->{$lang}{TXT_AUTO_CONNECT}, -variable => \$autocon_var, -onvalue => "on", -offvalue => "off"); 510 | my $chk_autorun = $o_innerframe1->new_ttk__checkbutton(-text => $L->{$lang}{TXT_AUTO_START}, -variable => \$autorun_var, -onvalue => "on", -offvalue => "off"); 511 | 512 | $lbl_blank->g_grid(-column => 0, -row => 0, -sticky => "nw"); 513 | $chk_splash->g_grid(-column => 0, -row => 1, -sticky => "w"); 514 | $chk_autocon->g_grid(-column => 0, -row => 2, -sticky => "w"); 515 | $chk_autorun->g_grid(-column => 0, -row => 3, -sticky => "w"); 516 | if ($#langs > 0) { 517 | $lbl_lang->g_grid(-column => 0, -row => 6, -sticky => "w"); 518 | $lang_update->g_grid(-column => 0, -row => 6, -sticky => "e"); 519 | } 520 | my $port_textbox_state; 521 | my $random_port_check_state; 522 | sub port_random { 523 | if (($randomize_it eq "on") && ($tls_sel eq 'secp521r1')) { 524 | $port_var = int(rand(29998) + 1); 525 | if (($port_var == 5061) || ($port_var == 5062) || ($port_var == 5063) || ($port_var == 8443)) { 526 | $port_var = $port_var + int(rand(1000 - 5)); 527 | } 528 | } 529 | if (($randomize_it eq "off") && ($tls_sel eq 'secp521r1')) { 530 | $port_var = 443; 531 | } 532 | if ($tls_sel =~ /(Ed25519|Ed448|ML-DSA-87)/) { 533 | if ($1 eq "Ed25519") { $port_var = 5061; } 534 | if ($1 eq "Ed448") { $port_var = 5062; } 535 | if ($1 eq "ML-DSA-87") { $port_var = 5063; } 536 | $port_textbox_state = "disabled"; 537 | $random_port_check_state = "disabled"; 538 | } 539 | else { 540 | $port_textbox_state = "normal"; 541 | $random_port_check_state = "normal"; 542 | } 543 | } 544 | &port_random; 545 | $o_innerframe2->new_ttk__label(-text => $L->{$lang}{TXT_CONNECT_PORT})->g_pack(); 546 | my $port_textbox = $o_innerframe2->new_ttk__entry(-textvariable => \$port_var, -width => 6, -state => $port_textbox_state)->g_pack(); 547 | $o_innerframe2->new_ttk__label(-text => $L->{$lang}{TXT_CONNECT_PROTOCOL})->g_pack(); 548 | my $proto_textbox = $o_innerframe2->new_ttk__combobox(-textvariable => \$proto_var, -values => \@protos, -width => 4, -state=> (($adv_ssh_opt eq "on") || ($adv_https_opt eq "on") || ($adv_socks_opt eq "on")) ? "disabled" : "readonly")->g_pack(); 549 | $o_innerframe2->new_ttk__label(-text => $L->{$lang}{TXT_TIMEOUT})->g_pack(); 550 | my @timeouts = (60, 120, 180, 240); 551 | my $timeout_textbox = $o_innerframe2->new_ttk__combobox(-textvariable => \$timeout_var, -values => \@timeouts, -width => 4, -state=>"readonly")->g_pack(); 552 | # .t.n.f2.c3 553 | $o_innerframe2->new_ttk__checkbutton(-text => $L->{$lang}{TXT_RANDOM_PORT}, -variable => \$randomize_it, -onvalue => "on", -offvalue => "off", -command => sub { 554 | &port_random; 555 | }, -state => $random_port_check_state)->g_pack(qw/-anchor n/); 556 | my $lbl_top = $o_innerframe4->new_ttk__label(-text => $L->{$lang}{TXT_ADVANCED_OPTIONS} . "\n"); 557 | my @adv_opts2 = ('disabled','1300','1400','1500','1600'); 558 | my $adv_label2 = $o_innerframe4->new_ttk__label(-text => "--mssfix: "); 559 | my $adv_combo2 = $o_innerframe4->new_ttk__combobox(-textvariable => \$selected_adv_opt2, -values => \@adv_opts2, -width => 14, -state => "readonly"); 560 | my @adv_opts3 = ('adaptive','ipapi','exe'); 561 | $selected_adv_opt3 = $adv_opts3[0]; 562 | my $adv_label3 = $o_innerframe4->new_ttk__label(-text => "--route-method: "); 563 | my $adv_combo3 = $o_innerframe4->new_ttk__combobox(-textvariable => \$selected_adv_opt3, -values => \@adv_opts3, -width => 14, -state => "readonly"); 564 | my @adv_opts4 = $selected_adv_opt4 eq "Any address" ? ($selected_adv_opt4) : ($selected_adv_opt4, "Any address"); 565 | foreach (`ipconfig /all|findstr "IPv. add"|findstr /v Link`) { 566 | if (/.*:\s+([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/) { 567 | if ($1 !~ /^169\.254\./) { 568 | push(@adv_opts4,"$1") unless "$1" eq $adv_opts4[0]; 569 | } 570 | } 571 | if (/.*:\s([a-f0-9:]+)\(Pre/) { 572 | push(@adv_opts4,"$1") unless "$1" eq $adv_opts4[0]; 573 | } 574 | } 575 | $selected_adv_opt4 = $adv_opts4[0]; 576 | my $adv_label4 = $o_innerframe4->new_ttk__label(-text => "Bind to IP: "); 577 | my $adv_combo4 = $o_innerframe4->new_ttk__combobox(-textvariable => \$selected_adv_opt4, -values => \@adv_opts4, -width => 14, -state => "readonly"); 578 | 579 | sub is_valid_ip { 580 | my $ip = shift; 581 | # Try IPv4 582 | return 1 if $ip =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ && 583 | !grep { $_ > 255 } ($1, $2, $3, $4); 584 | # Try IPv6 (colon-separated, at least one colon required) 585 | return 1 if $ip =~ /:/ && Socket::inet_pton(AF_INET6, $ip); 586 | return 0; 587 | } 588 | 589 | # Most of these align based on the width of the text, so hardcoding English here (except for errors). 590 | my $adv_socks_ip_lbl = $o_innerframe4->new_ttk__label(-text => "IP", -state => (($adv_socks_opt eq "on") ? "normal" : "disabled")); 591 | $adv_socks_ip = "127.0.0.1"; 592 | my $adv_socks_ip_txt = $o_innerframe4->new_ttk__entry(-textvariable => \$adv_socks_ip, -width => 14, -state => (($adv_socks_opt eq "on") ? "normal" : "disabled"), -validate => "focusout", -validatecommand => sub { 593 | unless (is_valid_ip($adv_socks_ip)) { 594 | &do_error($L->{$lang}{ERR_INVALID_SOCKS_IP} . "\n"); 595 | return 1; 596 | } 597 | }); 598 | my $adv_socks_port_lbl = $o_innerframe4->new_ttk__label(-text => "Port", -state => (($adv_socks_opt eq "on") ? "normal" : "disabled")); 599 | my $adv_socks_port_txt = $o_innerframe4->new_ttk__entry(-textvariable => \$adv_socks_port, -width => 6, -state => (($adv_socks_opt eq "on") ? "normal" : "disabled")); 600 | my $adv_socks_user_lbl = $o_innerframe4->new_ttk__label(-text => "Username", -state => (($adv_socks_opt eq "on") && ($adv_socks_noauth_opt eq "off")) ? "normal" : "disabled"); 601 | my $adv_socks_user_txt = $o_innerframe4->new_ttk__entry(-text => "", -textvariable => \$adv_socks_user_var, -state => (($adv_socks_opt eq "on") && ($adv_socks_noauth_opt eq "off")) ? "normal" : "disabled"); 602 | my $adv_socks_pass_lbl = $o_innerframe4->new_ttk__label(-text => "Password", -state => (($adv_socks_opt eq "on") && ($adv_socks_noauth_opt eq "off")) ? "normal" : "disabled"); 603 | my $adv_socks_pass_txt = $o_innerframe4->new_ttk__entry(-text => "", -textvariable => \$adv_socks_pass_var, -state => (($adv_socks_opt eq "on") && ($adv_socks_noauth_opt eq "off")) ? "normal" : "disabled", -show => '*'); 604 | my $adv_socks_noauth_check = $o_innerframe4->new_ttk__checkbutton(-state => (($adv_socks_opt eq "on") ? "normal" : "disabled"), -text => "No username/password needed", -variable => \$adv_socks_noauth_opt, -onvalue => "on", -offvalue => "off", -command => sub { 605 | if ($adv_socks_noauth_opt eq "on") { 606 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e3_configure"} ); 607 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 608 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e4_configure"} ); 609 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 610 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l7_configure"} ); 611 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 612 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l8_configure"} ); 613 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 614 | } 615 | if ($adv_socks_noauth_opt eq "off") { 616 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e3_configure"} ); 617 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 618 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e4_configure"} ); 619 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 620 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l7_configure"} ); 621 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 622 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l8_configure"} ); 623 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 624 | } 625 | }); 626 | my $adv_socks_check = $o_innerframe4->new_ttk__checkbutton(-text => "Use SOCKS proxy", -variable => \$adv_socks_opt, -onvalue => "on", -offvalue => "off", -command => sub { 627 | if ($adv_socks_opt eq "on") { 628 | $adv_https_opt = "off"; 629 | $adv_ssh_opt = "off"; 630 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c7_configure"} ); 631 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 632 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c6_configure"} ); 633 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 634 | $proto_var = 'TCP'; 635 | @protos = ('TCP'); 636 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c_configure"} ); 637 | &{ $stupidstrictrefs{'Tkx'} }(-textvariable => \$proto_var, -values => \@protos, -width => 4, -state=>"disabled"); 638 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e_configure"} ); 639 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 640 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e2_configure"} ); 641 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 642 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l5_configure"} ); 643 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 644 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l6_configure"} ); 645 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 646 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c4_configure"} ); 647 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 648 | if ($adv_socks_noauth_opt ne "on") { 649 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e3_configure"} ); 650 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 651 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e4_configure"} ); 652 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 653 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l7_configure"} ); 654 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 655 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l8_configure"} ); 656 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 657 | } 658 | } 659 | if ($adv_socks_opt eq "off") { 660 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c7_configure"} ); 661 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 662 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c6_configure"} ); 663 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 664 | $proto_var = 'UDP'; 665 | @protos = ('UDP','TCP'); 666 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c_configure"} ); 667 | &{ $stupidstrictrefs{'Tkx'} }(-textvariable => \$proto_var, -values => \@protos, -width => 4, -state=>"readonly"); 668 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e_configure"} ); 669 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 670 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e2_configure"} ); 671 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 672 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e3_configure"} ); 673 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 674 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e4_configure"} ); 675 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 676 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l5_configure"} ); 677 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 678 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l6_configure"} ); 679 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 680 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l7_configure"} ); 681 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 682 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l8_configure"} ); 683 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 684 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c4_configure"} ); 685 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 686 | } 687 | }, -state => ((($adv_ssh_opt eq "on") || ($adv_https_opt eq "on")) ? "disabled" : "normal")); 688 | my $adv_ssh_check = $o_innerframe4->new_ttk__checkbutton(-text => "Use SSH tunneling", -variable => \$adv_ssh_opt, -onvalue => "on", -offvalue => "off", -command => sub { 689 | if ($adv_ssh_opt eq "on") { 690 | $adv_https_opt = "off"; 691 | $adv_socks_opt = "off"; 692 | $proto_var = 'TCP'; 693 | @protos = ('TCP'); 694 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c_configure"} ); 695 | &{ $stupidstrictrefs{'Tkx'} }(-textvariable => \$proto_var, -values => \@protos, -width => 4, -state=>"disabled"); 696 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c7_configure"} ); 697 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 698 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c5_configure"} ); 699 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 700 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e_configure"} ); 701 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 702 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e2_configure"} ); 703 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 704 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e3_configure"} ); 705 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 706 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e4_configure"} ); 707 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 708 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l5_configure"} ); 709 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 710 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l6_configure"} ); 711 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 712 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l7_configure"} ); 713 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 714 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l8_configure"} ); 715 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 716 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c4_configure"} ); 717 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 718 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c8_configure"} ); 719 | &{ $stupidstrictrefs{'Tkx'} }(-state => "readonly"); 720 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l9_configure"} ); 721 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 722 | } 723 | if ($adv_ssh_opt eq "off") { 724 | $proto_var = 'UDP'; 725 | @protos = ('UDP','TCP'); 726 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c_configure"} ); 727 | &{ $stupidstrictrefs{'Tkx'} }(-textvariable => \$proto_var, -values => \@protos, -width => 4, -state=>"readonly"); 728 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e_configure"} ); 729 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 730 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c7_configure"} ); 731 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 732 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c5_configure"} ); 733 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 734 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c8_configure"} ); 735 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 736 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l9_configure"} ); 737 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 738 | } 739 | }, -state => ((($adv_https_opt eq "on") || ($adv_socks_opt eq "on")) ? "disabled" : "normal")); 740 | my $adv_https_check = $o_innerframe4->new_ttk__checkbutton(-text => "Use HTTPS tunneling", -variable => \$adv_https_opt, -onvalue => "on", -offvalue => "off", -command => sub { 741 | if ($adv_https_opt eq "on") { 742 | $adv_ssh_opt = "off"; 743 | $adv_socks_opt = "off"; 744 | $proto_var = 'TCP'; 745 | @protos = ('TCP'); 746 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c_configure"} ); 747 | &{ $stupidstrictrefs{'Tkx'} }(-textvariable => \$proto_var, -values => \@protos, -width => 4, -state=>"disabled"); 748 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c6_configure"} ); 749 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 750 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c5_configure"} ); 751 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 752 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e_configure"} ); 753 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 754 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e2_configure"} ); 755 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 756 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e3_configure"} ); 757 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 758 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e4_configure"} ); 759 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 760 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l5_configure"} ); 761 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 762 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l6_configure"} ); 763 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 764 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l7_configure"} ); 765 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 766 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l8_configure"} ); 767 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 768 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c4_configure"} ); 769 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 770 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c8_configure"} ); 771 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 772 | # remove the combobox 773 | %stupidstrictrefs = ( Tkx => \&{"Tkx::grid_remove"} ); 774 | &{ $stupidstrictrefs{'Tkx'} }(".t.n.f4.c8"); 775 | # add the entry box 776 | %stupidstrictrefs = ( Tkx => \&{"Tkx::grid"} ); 777 | &{ $stupidstrictrefs{'Tkx'} }(".t.n.f4.e5", -column => 1, -row => 9); 778 | # change the label to 'SNI host:' 779 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l9_configure"} ); 780 | &{ $stupidstrictrefs{'Tkx'} }(-state => 'normal', -text => "SNI host:"); 781 | } 782 | if ($adv_https_opt eq "off") { 783 | $proto_var = 'UDP'; 784 | @protos = ('UDP','TCP'); 785 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c_configure"} ); 786 | &{ $stupidstrictrefs{'Tkx'} }(-textvariable => \$proto_var, -values => \@protos, -width => 4, -state=>"readonly"); 787 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.e_configure"} ); 788 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 789 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c6_configure"} ); 790 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 791 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c5_configure"} ); 792 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 793 | # remove the entry box 794 | %stupidstrictrefs = ( Tkx => \&{"Tkx::grid_remove"} ); 795 | &{ $stupidstrictrefs{'Tkx'} }(".t.n.f4.e5"); 796 | # add the combo box 797 | %stupidstrictrefs = ( Tkx => \&{"Tkx::grid"} ); 798 | &{ $stupidstrictrefs{'Tkx'} }(".t.n.f4.c8", -column => 1, -row => 9); 799 | # reset combo state to default 'disabled' 800 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.c8_configure"} ); 801 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 802 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l9_configure"} ); 803 | &{ $stupidstrictrefs{'Tkx'} }(-state => 'disabled', -text => "Tunnel host:"); 804 | } 805 | }, -state => ((($adv_ssh_opt eq "on") || ($adv_socks_opt eq "on")) ? "disabled" : "normal")); 806 | my @tunnel_nodes; 807 | open(NODELIST, "$nodelistfile") || &do_error($L->{$lang}{ERR_OPEN} . " $nodelistfile"); 808 | for () { 809 | my $tmp = $_; 810 | chomp($tmp); 811 | if (($disp_server !~ /$tmp/) && ($disp_server !~ /^\n+$/)) { 812 | if ($tmp =~ /windows/) { 813 | /^(.*):(.*):(.*):(.*)$/; 814 | push(@tunnel_nodes,"$4"); 815 | } 816 | } 817 | } 818 | close(NODELIST); 819 | $selected_tunnel_opt = $tunnel_nodes[0] unless $selected_tunnel_opt; 820 | my $adv_tunnel_combo = $o_innerframe4->new_ttk__combobox(-textvariable => \$selected_tunnel_opt, -values => \@tunnel_nodes, -width => 23, -state => ($adv_ssh_opt eq "on") ? "readonly" : "disabled"); 821 | my $sni_input_val = "www.speedtest.net"; 822 | my $sni_input = $o_innerframe4->new_ttk__entry (-textvariable => \$sni_input_val, -width => 23); 823 | $lbl_top->g_grid(-column => 0, -row => 0); # .t.n.f4.l 824 | $adv_label2->g_grid(-column => 0, -row => 1); # .t.n.f4.l2 825 | $adv_combo2->g_grid(-column => 1, -row => 1); # .t.n.f4.c 826 | $adv_label3->g_grid(-column => 0, -row => 2); # .t.n.f4.l3 827 | $adv_combo3->g_grid(-column => 1, -row => 2); # .t.n.f4.c2 828 | $adv_label4->g_grid(-column => 0, -row => 3); # .t.n.f4.l4 829 | $adv_combo4->g_grid(-column => 1, -row => 3); # .t.n.f4.c3 830 | $adv_socks_check->g_grid(-column => 0, -row => 4); # .t.n.f4.c5 831 | $adv_socks_ip_lbl->g_grid(-column => 0, -row => 5); # .t.n.f4.l5 832 | $adv_socks_ip_txt->g_grid(-column => 1, -row => 5); # .t.n.f4.e 833 | $adv_socks_port_lbl->g_grid(-column => 2, -row => 5); # .t.n.f4.l6 834 | $adv_socks_port_txt->g_grid(-column => 3, -row => 5); # .t.n.f4.e2 835 | $adv_socks_user_lbl->g_grid(-column => 0, -row => 6); # .t.n.f4.l7 836 | $adv_socks_user_txt->g_grid(-column => 1, -row => 6); # .t.n.f4.e3 837 | $adv_socks_pass_lbl->g_grid(-column => 2, -row => 6); # .t.n.f4.l8 838 | $adv_socks_pass_txt->g_grid(-column => 3, -row => 6); # .t.n.f4.e4 839 | $adv_socks_noauth_check->g_grid(-column => 0, -row => 7, -columnspan => 2); # .t.n.f4.c4 840 | 841 | $fixdns_btn = $o_innerframe4->new_ttk__button(-text => "Reset DNS to DHCP", -command => \&fix_dns )->g_grid(-column => 2, -row => 1, -rowspan => 4, -columnspan => 2, -stick => "nswe"); 842 | 843 | my $adv_tunnel_lbl = $o_innerframe4->new_ttk__label(-text => "Tunnel host:", -state => "disabled"); 844 | $adv_ssh_check->g_grid(-column => 0, -row => 8); # .t.n.f4.c6 845 | $adv_https_check->g_grid(-column => 1, -row => 8); # .t.n.f4.c7 846 | $adv_tunnel_lbl->g_grid(-column => 0, -row => 9); # .t.n.f4.l9 847 | $adv_tunnel_combo->g_grid(-column => 1, -row => 9); # .t.n.f4.c8 848 | $sni_input->g_grid(-column => 1, -row => 9); # should be t.n.f.e5, create+remove it, may be readded later 849 | if ($adv_https_opt eq "off") { 850 | Tkx::grid_remove(".t.n.f4.e5"); 851 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l9_configure"} ); 852 | &{ $stupidstrictrefs{'Tkx'} }(-state => 'disabled', -text => "Tunnel host:"); 853 | } 854 | if ($adv_https_opt eq "on") { 855 | Tkx::grid_remove(".t.n.f4.c8"); 856 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.l9_configure"} ); 857 | &{ $stupidstrictrefs{'Tkx'} }(-state => 'normal', -text => "SNI host:"); 858 | } 859 | 860 | $o_tabs->add($o_innerframe1, -text => $L->{$lang}{TXT_STARTUP}); 861 | $o_tabs->add($o_innerframe2, -text => $L->{$lang}{TXT_CONNECTING}); 862 | $o_tabs->add($o_innerframe3, -text => $L->{$lang}{TXT_SECURITY}); 863 | $o_tabs->add($o_innerframe4, -text => $L->{$lang}{TXT_ADVANCED}); 864 | 865 | sub sel_tls { 866 | if ($tls_sel eq 'Ed25519') { 867 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.e_configure"} ); 868 | &{ $stupidstrictrefs{'Tkx'} }(-state=>"disabled"); 869 | $port_var = 5061; 870 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c3_configure"} ); 871 | &{ $stupidstrictrefs{'Tkx'} }(-state=>"disabled"); 872 | } 873 | if ($tls_sel eq 'Ed448') { 874 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.e_configure"} ); 875 | &{ $stupidstrictrefs{'Tkx'} }(-state=>"disabled"); 876 | $port_var = 5062; 877 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c3_configure"} ); 878 | &{ $stupidstrictrefs{'Tkx'} }(-state=>"disabled"); 879 | } 880 | if ($tls_sel eq 'ML-DSA-87') { 881 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.e_configure"} ); 882 | &{ $stupidstrictrefs{'Tkx'} }(-state=>"disabled"); 883 | $port_var = 5063; 884 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c3_configure"} ); 885 | &{ $stupidstrictrefs{'Tkx'} }(-state=>"disabled"); 886 | } 887 | if ($tls_sel eq 'secp521r1') { 888 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.e_configure"} ); 889 | &{ $stupidstrictrefs{'Tkx'} }(-state=>"normal"); 890 | &port_random; 891 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f2.c3_configure"} ); 892 | &{ $stupidstrictrefs{'Tkx'} }(-state=>"normal"); 893 | } 894 | return 0; 895 | } 896 | my $i3_blank_lbl = $o_innerframe3->new_ttk__label(-text => "\n"); 897 | my $tls_lbl = $o_innerframe3->new_ttk__label(-text => "TLS cipher:"); 898 | # .t.n.f3.c 899 | my $tls_sel_opt = $o_innerframe3->new_ttk__combobox(-textvariable => \$tls_sel, -values => \@tlses, -width => 11, 900 | -state=> 'readonly', -validate => "focusout", -validatecommand => sub { 901 | &sel_tls; 902 | }); 903 | my $cipher_lbl = $o_innerframe3->new_ttk__label(-text => "data cipher: "); 904 | my $cipher_sel_opt = $o_innerframe3->new_ttk__combobox(-textvariable => \$cipher_sel, -values => ['AES-256-GCM','CHACHA20-POLY1305'], -width => 20, -state=> 'readonly'); 905 | my $seperator_lbl = $o_innerframe3->new_ttk__label(-text => " "); 906 | my $ipv6_disable_opt = $o_innerframe3->new_ttk__checkbutton(-text => $L->{$lang}{TXT_DISABLE_IPV6}, -variable => \$noipv6_var, -onvalue => "on", -offvalue => "off"); 907 | my $dnsleak_opt = $o_innerframe3->new_ttk__checkbutton(-text => $L->{$lang}{TXT_DNS_LEAK}, -variable => \$dnsleak_var, -onvalue => "on", -offvalue => "off"); 908 | my $dnscrypt_opt = $o_innerframe3->new_ttk__checkbutton(-text => $L->{$lang}{TXT_DNSCRYPT_ENABLE}, -variable => \$dnscrypt_var, -onvalue => "on", -offvalue => "off", -state => "normal"); 909 | my $killswitch_opt = $o_innerframe3->new_ttk__checkbutton(-text => $L->{$lang}{TXT_KILLSWITCH_ENABLE}, -variable => \$killswitch_var, -onvalue => "on", -offvalue => "off"); 910 | my $adblock_opt = $o_innerframe3->new_ttk__checkbutton(-text => $L->{$lang}{TXT_ENABLE_ADBLOCK}, -variable => \$ts_var, -onvalue => "on", -offvalue => "off"); 911 | 912 | $i3_blank_lbl->g_grid(-column => 0, -row => 0); 913 | $tls_lbl->g_grid(-column => 0, -row => 1, -sticky => "e"); 914 | $tls_sel_opt->g_grid(-column => 1, -row => 1, -sticky => "w"); 915 | $cipher_lbl->g_grid(-column => 2, -row => 1, -sticky => "e"); 916 | $cipher_sel_opt->g_grid(-column => 3, -row => 1, -sticky => "w"); 917 | $seperator_lbl->g_grid(-column => 0, -row => 2, -columnspan => 4); 918 | $ipv6_disable_opt->g_grid(-column => 0, -row => 3, -columnspan => 4, -sticky => "w"); 919 | $dnsleak_opt->g_grid(-column => 0, -row => 4, -columnspan => 4, -sticky => "w"); 920 | $dnscrypt_opt->g_grid(-column => 0, -row => 5, -columnspan => 4, -sticky => "w"); 921 | $killswitch_opt->g_grid(-column => 0, -row => 6, -columnspan => 4, -sticky => "w"); 922 | $adblock_opt->g_grid(-column => 0, -row => 7, -columnspan => 4, -sticky => "w"); 923 | 924 | $o_frame1->g_grid(-column => 0, -row => 0, -sticky => "nswe"); 925 | $o_worldimage->g_grid(-column => 0, -row => 0); 926 | $back->g_grid(-column => 0, -row => 2, -sticky => "nswe"); 927 | $o_tabs->g_grid(-column => 1, -row => 0, -sticky => "nswe"); 928 | 929 | Tkx::update('idletasks'); 930 | 931 | $frame1 = $mw->new_ttk__frame(-relief => "flat"); 932 | $worldimage = $frame1->new_ttk__label(-anchor => "center", -justify => "center", -image => 'mainicon', -compound => 'top', -text => "\n\nToken:", -font => "logo_font"); 933 | $errorimage = $frame1->new_ttk__label(-anchor => "center", -justify => "center", -image => 'erroricon', -compound => 'top', -text => "\n\nToken:", -font => "logo_font"); 934 | $userlbl = $frame1->new_tk__text; 935 | $userlbl->tag(qw/configure link1 -foreground blue -underline 1/); 936 | $userlbl->tag(qw/configure link2 -foreground blue -underline 1/); 937 | $userlbl->tag(qw/configure link3 -foreground blue -underline 1/); 938 | $userlbl->tag_bind("link1", "", sub { system 1, "start https://cryptostorm.is/#section5"; $userlbl->tag(qw/configure link1 -foreground purple -underline 1/);}); 939 | $userlbl->tag_bind("link1", "", sub { }); 940 | $userlbl->tag_bind("link1", "", sub { $userlbl->configure(-cursor => 'hand2'); }); 941 | $userlbl->tag_bind("link1", "", sub { $userlbl->configure(-cursor => 'arrow'); }); 942 | $userlbl->tag_bind("link3", "", sub { system 1, "start https://cryptostorm.nu/"; $userlbl->tag(qw/configure link3 -foreground purple -underline 1/); }); 943 | $userlbl->tag_bind("link3", "", sub { }); 944 | $userlbl->tag_bind("link3", "", sub { $userlbl->configure(-cursor => 'hand2'); }); 945 | $userlbl->tag_bind("link3", "", sub { $userlbl->configure(-cursor => 'arrow'); }); 946 | $userlbl->insert("1.0", "\n" . $L->{$lang}{TXT_MAINWINDOW1} . "\n" . $L->{$lang}{TXT_MAINWINDOW2} . " "); 947 | $userlbl->insert('insert', $L->{$lang}{TXT_HERE}, 'link1'); 948 | $userlbl->insert('insert', "\n \n"); 949 | $userlbl->insert('insert', $L->{$lang}{TXT_MAINWINDOW5} . " "); 950 | $userlbl->insert('insert', $L->{$lang}{TXT_HERE}, 'link3'); 951 | $userlbl->insert('insert', ".\n"); 952 | $userlbl->configure(-width => 55, -height => 10, -borderwidth => 0, -state=> 'disabled', -font => "TkTextFont", -cursor => 'arrow', -wrap => 'none', -background => 'SystemButtonFace'); 953 | $frame2 = $mw->new_ttk__frame(-relief => "flat"); 954 | $token_textbox = $frame2->new_ttk__entry(-textvariable => \$token, -width => 27, -font => "token_font", -state => "normal"); 955 | $server_textbox = $frame2->new_ttk__combobox(-textvariable => \$disp_server, -width => 29, -state => "readonly"); 956 | @disp_servers = ($L->{$lang}{TXT_DEFAULT_SERVER}); 957 | open(NODELIST, "$nodelistfile") || &do_error($L->{$lang}{ERR_OPEN} . " $nodelistfile"); 958 | my @nodes = ; 959 | close(NODELIST); 960 | for (@nodes) { 961 | my $tmp = $_; 962 | chomp($tmp); 963 | if (($disp_server !~ /$tmp/) && ($disp_server !~ /^\n+$/)) { 964 | if ($tmp =~ /windows/) { 965 | /^(.*):(.*):(.*):(.*)$/; 966 | my $country = $1; 967 | if ($disp_server !~ /$country/) { 968 | push(@disp_servers,"$country"); 969 | } 970 | push(@servers,"$tmp"); 971 | } 972 | } 973 | } 974 | if (!grep /$disp_server/, @nodes) { 975 | $disp_server = $L->{$lang}{TXT_DEFAULT_SERVER}; 976 | } 977 | if ($disp_server ne $L->{$lang}{TXT_DEFAULT_SERVER}) { 978 | unshift(@disp_servers, "$disp_server"); 979 | } 980 | $server_textbox->configure(-values => \@disp_servers); 981 | Tkx::tooltip($token_textbox, $L->{$lang}{TXT_TOOLTIP_TOKEN}); 982 | $frame3 = $mw->new_ttk__frame(-relief => "flat"); 983 | $connect = $frame3->new_ttk__button(-text => "\n" . $L->{$lang}{TXT_CONNECT} . "\n", -command => \&connectt); 984 | $options = $frame3->new_ttk__button(-text => $L->{$lang}{TXT_OPTIONS}, -command => \&do_options); 985 | $cancel = $mw->new_ttk__button(-text => $L->{$lang}{TXT_EXIT}, -command => \&do_exit); 986 | $save = $frame2->new_ttk__checkbutton(-text => $L->{$lang}{TXT_SAVE}, -variable => \$saveoption, -onvalue => "on", -offvalue => "off"); 987 | $update = $frame2->new_ttk__button(-text => $L->{$lang}{TXT_UPDATE}, -command => sub { 988 | $statusvar = $L->{$lang}{TXT_UPDATE_NODELIST} . "..."; 989 | $update->configure(-state => "disabled"); 990 | $options->configure(-state => "disabled"); 991 | $server_textbox->configure(-state => "disabled"); 992 | $connect->configure(-state => "disabled"); 993 | Tkx::update(); 994 | &blue_derp; 995 | $done = 0; 996 | $update_err = 0; 997 | $nodebuf = ""; 998 | $updatethread = threads->new( \&update_node_list ); 999 | &blue_derp; 1000 | my $max_wait_ms = 5000; 1001 | my $elapsed = 0; 1002 | while (!$done && $elapsed < $max_wait_ms) { 1003 | Tkx::update(); 1004 | select(undef, undef, undef, 0.05); 1005 | $elapsed += 50; 1006 | Tkx::update(); 1007 | if (defined $nodebuf and length $nodebuf) { 1008 | &blue_derp; 1009 | if ($status eq "text/plain") { 1010 | &blue_derp; 1011 | my $tmpnodebuf = $nodebuf; 1012 | $nodebuf = ''; 1013 | @disp_servers = ($L->{$lang}{TXT_DEFAULT_SERVER}); 1014 | my @data=split(/\n/, $tmpnodebuf); 1015 | open(NODELIST,">$nodelistfile") || &do_error($L->{$lang}{ERR_WRITE} . " $nodelistfile"); 1016 | foreach my $sline (uniq(@data)) { 1017 | if ($sline =~ /windows/) { 1018 | print NODELIST "$sline\n"; 1019 | $sline =~ /^(.*):(.*):(.*):(.*)$/; 1020 | push(@disp_servers,"$1"); 1021 | push(@servers,"$sline"); 1022 | } 1023 | } 1024 | close(NODELIST); 1025 | &green_derp; 1026 | $server_textbox->configure(-values => \@disp_servers, -state => "readonly"); 1027 | $statusvar = $L->{$lang}{TXT_UPDATE_NODELIST_DONE}; 1028 | Tkx::update(); 1029 | $done = 1; 1030 | $updatethread->kill('KILL'); 1031 | } 1032 | else { 1033 | &red_derp; 1034 | $statusvar = $L->{$lang}{ERR_UPDATE_NODELIST}; 1035 | Tkx::update(); 1036 | $done = 1; 1037 | $updatethread->kill('KILL'); 1038 | } 1039 | $update->configure(-state => "normal"); 1040 | $options->configure(-state => "normal"); 1041 | $connect->configure(-state => "normal"); 1042 | $server_textbox->configure(-state => "readonly"); 1043 | Tkx::update(); 1044 | } 1045 | last if $done; 1046 | } 1047 | if (!$done) { 1048 | $update_err = "ERROR: Node list update timed out."; 1049 | &do_error("$update_err"); 1050 | $statusvar = $L->{$lang}{ERR_UPDATE_NODELIST}; 1051 | $update->configure(-state => "normal"); 1052 | $options->configure(-state => "normal"); 1053 | $connect->configure(-state => "normal"); 1054 | $server_textbox->configure(-state => "readonly"); 1055 | Tkx::update(); 1056 | } 1057 | $done = 1; 1058 | $updatethread->kill('KILL'); 1059 | Tkx::update(); 1060 | }); 1061 | if ($token) { 1062 | $saveoption = "on"; 1063 | } 1064 | $server_textbox->g_bind("<>", sub { 1065 | $server_textbox->configure(-state => "readonly"); 1066 | Tkx::tooltip($token_textbox, $L->{$lang}{TXT_TOOLTIP_TOKEN}); 1067 | $token_textbox->configure(-state => "normal", -textvariable => \$token); 1068 | $save->configure(-state => "normal"); 1069 | $saveoption = "on"; 1070 | }); 1071 | $progress = $mw->new_ttk__frame(-padding => "3 0 0 0", -relief => "flat"); 1072 | my $pbarlen = 0; 1073 | $pbar = $progress->new_ttk__progressbar(-orient => "horizontal", -length => $pbarlen, -mode => "determinate", -variable => \$pbarval)->g_grid (-column => 0, -row => 0, -sticky => "we"); 1074 | $statuslbl = $mw->new_ttk__label(-textvariable => \$statusvar, -padding => "0 0 0 0", -relief => "sunken", -width => 5); 1075 | $frame4 = $mw->new_ttk__frame(-relief => "flat"); 1076 | $logbox = $frame4->new_tk__text(-width => 40, -height => 14, -undo => 1, -state => "disabled", -bg => "black", -fg => "lightgrey"); 1077 | $logbox->tag_configure("goodline", -background => "green", -font => "helvetica 14 bold", -relief => "raised"); 1078 | $logbox->tag_configure("badline", -background => "red", -font => "helvetica 14 bold", -relief => "raised"); 1079 | $logbox->tag_configure("warnline", -foreground => "black", -font => "helvetica 14 bold", -background => "yellow", -relief => "raised"); 1080 | $scroll = $frame4->new_ttk__scrollbar(-command => [$logbox, "yview"], -orient => "vertical"); 1081 | $logbox->configure(-yscrollcommand => [$scroll, "set"]); 1082 | Tkx::bind($mw,"", [ sub { 1083 | my($x,$y) = @_; 1084 | my $current_window = Tkx::winfo('containing',$x,$y); 1085 | my $pop_menu = $logbox->new_menu; 1086 | my $popup_menu = $pop_menu->new_menu(-tearoff => 0,); 1087 | $popup_menu->add_command(-label => $L->{$lang}{TXT_COPY},-underline => 1, -command => [ sub { 1088 | Tkx::clipboard("clear"); 1089 | Tkx::clipboard("append",$logbox->get('1.0','end-1c')); 1090 | }]); 1091 | $popup_menu->g_tk___popup($x,$y) 1092 | } 1093 | ,Tkx::Ev('%X','%Y') ] ); 1094 | $frame4->g_grid_columnconfigure(0, -weight => 1); 1095 | $frame4->g_grid_rowconfigure(0, -weight => 1); 1096 | $mw->g_bind("", sub { $connect->invoke(); }); 1097 | $frame1->g_grid(-column => 0, -row => 0); 1098 | $worldimage->g_grid(-column => 0, -row => 0); 1099 | $userlbl->g_grid(-column => 1, -row => 0); 1100 | $frame2->g_grid(-column => 0, -row => 0, -sticky => "s"); 1101 | $token_textbox->g_grid(-column => 0, -row => 3); 1102 | $save->g_grid(-column => 4, -row => 3, -sticky => "w"); 1103 | $server_textbox->g_grid(-column => 0, -row => 2, -sticky => "nw"); 1104 | $update->g_grid(-column => 4, -row => 2, -sticky => "w"); 1105 | $frame3->g_grid(-column => 0, -row => 0, -sticky => "se"); 1106 | $progress->g_grid(-column => 0, -row => 2, -sticky => "we"); 1107 | $statuslbl->g_grid(-column => 0, -row => 1, -sticky => "w"); 1108 | $options->g_grid(-column => 1, -row => 1, -sticky => "e"); 1109 | $connect->g_grid(-column => 1, -row => 2, -sticky => "nswe"); 1110 | $cancel->g_grid(-column => 0, -row => 1, -sticky => "e"); 1111 | $password = "93b66e7059176bbfa418061c5cba87dd"; 1112 | Tkx::update('idletasks'); 1113 | $width = Tkx::winfo('reqwidth', $mw); 1114 | $height = Tkx::winfo('reqheight', $mw); 1115 | my $fullheight = $height * 2; 1116 | %stupidstrictrefs = ( 1117 | Tkx_pbar => \&{"Tkx::.f4.p_configure"}, 1118 | Tkx_sbar => \&{"Tkx::.l_configure"}, 1119 | Tkx_notb => \&{"Tkx::.t.n_configure"}, 1120 | Tkx_logb => \&{"Tkx::.f5.t_configure"} 1121 | ); 1122 | &{ $stupidstrictrefs{'Tkx_pbar'} }(-length => $width); 1123 | &{ $stupidstrictrefs{'Tkx_sbar'} }(-width => ($width / 60)); 1124 | &{ $stupidstrictrefs{'Tkx_notb'} }(-width => $width, -height => $height); 1125 | $x = int((Tkx::winfo('screenwidth', $mw) - $width ) / 2); 1126 | $y = int((Tkx::winfo('screenheight', $mw) - $height ) / 2); 1127 | $mw->g_wm_geometry("+$x+$y"); 1128 | Tkx::update('idletasks'); 1129 | 1130 | Tkx::bind($token_textbox,"<3>", [ sub { 1131 | my($x,$y) = @_; 1132 | my $current_window = Tkx::winfo('containing',$x,$y); 1133 | my $pop_menu = $token_textbox->new_menu; 1134 | my $popup_menu = $pop_menu->new_menu(-tearoff => 0,); 1135 | $popup_menu->add_command(-label => $L->{$lang}{TXT_COPY}, -state => ((($token =~ /^([a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5})$/) || 1136 | ($token =~ /^([a-f0-9]{128})$/)) ? "normal" : "disabled"), -underline => 1, -command => [ sub { 1137 | Tkx::clipboard("clear"); 1138 | Tkx::clipboard("append",$token); 1139 | }]); 1140 | my $clipboard = $clip->Get(); 1141 | $popup_menu->add_command(-label => $L->{$lang}{TXT_PASTE}, -state => ((($clipboard =~ /^([a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5})$/) || ($clipboard =~ /^([a-f0-9]{128})$/)) ? "normal" : "disabled"), -underline => 1, -command => [ sub { 1142 | $token = $clipboard; 1143 | }]); 1144 | $popup_menu->g_tk___popup($x,$y) 1145 | } 1146 | ,Tkx::Ev('%X','%Y') ] ); 1147 | 1148 | if (($killswitch_var eq "on") && ($adv_socks_opt eq "on")) { 1149 | Tkx::tk___messageBox(-icon => "info", -message => $L->{$lang}{TXT_SOCKS_NO_KILLSWITCH}); 1150 | $killswitch_var = "off"; 1151 | } 1152 | if ((-e "..\\user\\all.wfw") || ($killswitch_var eq "on") && ($autorun_var ne "on")) { 1153 | $rt = `netsh advfirewall firewall show rule name="cryptostorm - Allow DHCP"`; 1154 | if ($rt =~ /cryptostorm/) { 1155 | $tokillornot = Tkx::tk___messageBox(-parent => $mw, -type => "yesno", 1156 | -message => $L->{$lang}{QUESTION_KILLSWITCH1} . "\n" . 1157 | $L->{$lang}{QUESTION_KILLSWITCH2}, 1158 | -icon => "question", -title => "cryptostorm.is client"); 1159 | if ($tokillornot eq "yes") { 1160 | &killswitch_off; 1161 | $killswitch_var = "off"; 1162 | } 1163 | } 1164 | else { 1165 | unlink("..\\user\\all.wfw"); 1166 | &killswitch_on; 1167 | } 1168 | } 1169 | if ($dnscrypt_var eq "on") { 1170 | &dnscrypt(1); 1171 | } 1172 | $statusvar = $L->{$lang}{TXT_WINTUN_STARTING} . "..."; 1173 | Tkx::update(); 1174 | Win32::Process::Create(my $process,$wintunexe,"$wintunexe background",0,Win32::Process::DETACHED_PROCESS(),".") or 1175 | &do_error($L->{$lang}{TXT_FAILED_TO_START} . " $wintunexe: $^E\n"); 1176 | $statusvar = $L->{$lang}{TXT_WINTUN_RESTORING_DEFAULTS}; 1177 | Tkx::update(); 1178 | &restore_wintun(0); 1179 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1180 | Tkx::update(); 1181 | if ($autocon_var eq "on") { 1182 | $mw->g_wm_deiconify(); 1183 | $mw->g_raise(); 1184 | $mw->g_focus(); 1185 | &connectt; 1186 | } 1187 | if ($upgrade) { 1188 | sleep 3; 1189 | my $upgrade_or_not; 1190 | $upgrade_or_not = Tkx::tk___messageBox(-parent => $mw, -type => "yesno", 1191 | -message => $L->{$lang}{QUESTION_NEWVER1} . "\n" . 1192 | $L->{$lang}{QUESTION_NEWVER2} . "\n", 1193 | -icon => "question", -title => "cryptostorm.is client"); 1194 | if ($upgrade_or_not eq "yes") { 1195 | if ($token) { 1196 | copy($hashfile,$ENV{'TEMP'} . "\\client.dat"); 1197 | copy($authfile,$ENV{'TEMP'} . "\\config.ini"); 1198 | } 1199 | system("start https://cryptostorm.is/cryptostorm_setup.exe"); 1200 | exit; 1201 | } 1202 | } 1203 | if (defined($amsg)) { 1204 | Tkx::tk___messageBox(-parent => $mw, -type => "ok", 1205 | -message => "$amsg", 1206 | -icon => "info", -title => "cryptostorm.is client"); 1207 | 1208 | } 1209 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1210 | $TrayIcon = new Win32::GUI::Icon("..\\res\\world1.ico"); 1211 | $TrayWinHidden = Win32::GUI::Window->new( 1212 | -name => 'TrayWindow', 1213 | -text => 'TrayWindow', 1214 | -width => 1, 1215 | -height => 1, 1216 | -visible => 0, 1217 | ); 1218 | $TrayNotify = $TrayWinHidden->AddNotifyIcon( 1219 | -onRightClick => \&TrackTrayMenu, 1220 | -onClick => \&showwin, 1221 | -name => "Open", 1222 | -icon => $TrayIcon, 1223 | -tip => "cryptostorm.is client", 1224 | -balloon_icon => "info"); 1225 | Tkx::update(); 1226 | Tkx::MainLoop(); 1227 | exit; 1228 | 1229 | sub hidewin { 1230 | if (($mw->g_wm_state eq "normal") || ($mw->g_wm_state eq "iconic")) { 1231 | $idle = 1; 1232 | $hiddenornot = "Show"; 1233 | $mw->g_wm_deiconify(); 1234 | $mw->g_wm_withdraw(); 1235 | &do_menu(1); 1236 | } 1237 | } 1238 | 1239 | sub showwin { 1240 | if (($mw->g_wm_state eq "iconic") || ($mw->g_wm_state eq "normal")) { 1241 | $mw->g_wm_deiconify(); 1242 | $mw->g_focus(); 1243 | } 1244 | if ($mw->g_wm_state eq "withdrawn") { 1245 | $hiddenornot = "Hide"; 1246 | $idle = 0; 1247 | if (defined($mw)) { 1248 | $mw->g_wm_deiconify(); 1249 | $mw->g_raise(); 1250 | $mw->g_focus(); 1251 | &do_menu(0); 1252 | } 1253 | &logbox_loop; 1254 | } 1255 | } 1256 | 1257 | sub do_menu { 1258 | my $balloon = (($_[0]) && (!$showtiponce)) ? 1 : 0; 1259 | Win32::GUI::NotifyIcon::Change($TrayNotify, 1260 | -balloon => $balloon, 1261 | -balloon_tip => $balloon_msg, 1262 | -tip => "Cryptostorm Client", 1263 | -balloon_timeout => 10, 1264 | ); 1265 | if ($hiddenornot eq "Show") { 1266 | $TrayMenu = Win32::GUI::Menu->new( 1267 | "Options" => "Options", 1268 | ">$hiddenornot client" => {-name => "Toggle", -onClick => \&showwin}, 1269 | ">-" => {-name => "LS"}, 1270 | ">" . "Exit" => {-name => "Exit",-onClick => \&do_exit } 1271 | ) or &do_error($L->{$lang}{ERR_MENU}); 1272 | } 1273 | if ($hiddenornot eq "Hide") { 1274 | $TrayMenu = Win32::GUI::Menu->new( 1275 | "Options" => "Options", 1276 | ">$hiddenornot client" => {-name => "Toggle", -onClick => \&hidewin, -default => 0}, 1277 | ">-" => {-name => "LS"}, 1278 | ">" . "Exit" => {-name => "Exit", -onClick => \&do_exit } 1279 | ) or &do_error($L->{$lang}{ERR_MENU}); 1280 | } 1281 | if ($balloon) { 1282 | $showtiponce = 1; 1283 | } 1284 | } 1285 | 1286 | sub TrackTrayMenu { 1287 | if (defined($TrayNotify) && defined($TrayMenu)) { 1288 | $TrayNotify->Win32::GUI::TrackPopupMenu($TrayMenu->{"Options"}); 1289 | } 1290 | return 0; 1291 | } 1292 | 1293 | sub savelogin { 1294 | open(CREDS,">$authfile"); 1295 | if ($token =~ /^([a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5})$/) { 1296 | print CREDS sha512_hex("$token") . "\n"; 1297 | } 1298 | if ($token =~ /^([a-f0-9]{128})$/) { 1299 | print CREDS "$token\n"; 1300 | } 1301 | print CREDS "$password\n"; 1302 | if ($disp_server ne $L->{$lang}{TXT_DEFAULT_SERVER}) { 1303 | print CREDS "node=$disp_server\n"; 1304 | } 1305 | if ($autocon_var =~ /(on|off)/) { 1306 | print CREDS "autocon=$1\n"; 1307 | } 1308 | if ($autosplash_var =~ /(on|off)/) { 1309 | print CREDS "autosplash=$1\n"; 1310 | } 1311 | if ($autorun_var =~ /(on|off)/) { 1312 | print CREDS "autorun=$1\n"; 1313 | } 1314 | if ($dnscrypt_var =~ /(on|off)/) { 1315 | print CREDS "dnscrypt=$1\n"; 1316 | } 1317 | if ($killswitch_var =~ /(.*)/) { 1318 | print CREDS "killswitch=$1\n"; 1319 | } 1320 | if ($ts_var =~ /(.*)/) { 1321 | print CREDS "ts=$1\n"; 1322 | } 1323 | if ($tls_sel =~ /(.*)/) { 1324 | print CREDS "tls_sel=$1\n"; 1325 | } 1326 | if ($update_var =~ /(on|off)/) { 1327 | print CREDS "checkforupdate=$1\n"; 1328 | } 1329 | if ($dnsleak_var =~ /(on|off)/) { 1330 | print CREDS "dnsleak=$1\n"; 1331 | } 1332 | if ($timeout_var =~ /([0-9]+)/) { 1333 | print CREDS "timeout=$1\n"; 1334 | } 1335 | if ($noipv6_var =~ /(on|off)/) { 1336 | print CREDS "noipv6=$1\n"; 1337 | } 1338 | if ($port_var =~ /([0-9]+)/) { 1339 | print CREDS "port=$1\n"; 1340 | } 1341 | if ($randomize_it =~ /(on|off)/) { 1342 | print CREDS "randomport=$1\n"; 1343 | } 1344 | if ($sel_lang =~ /(.*)/) { 1345 | print CREDS "lang=$1\n"; 1346 | } 1347 | if ($proto_var =~ /(UDP|TCP)/) { 1348 | print CREDS "proto=$1\n"; 1349 | } 1350 | print CREDS "mssfix=$selected_adv_opt2\n"; 1351 | if ($selected_adv_opt3 ne "adaptive") { 1352 | print CREDS "route-method=$selected_adv_opt3\n"; 1353 | } 1354 | if ($selected_adv_opt4 ne "Any address") { 1355 | print CREDS "bind=$selected_adv_opt4\n"; 1356 | } 1357 | if ($adv_socks_opt eq "on") { 1358 | print CREDS "socks=on\n"; 1359 | } 1360 | if ($adv_socks_ip) { 1361 | print CREDS "socks_ip=$adv_socks_ip\n"; 1362 | } 1363 | if ($adv_socks_port) { 1364 | print CREDS "socks_port=$adv_socks_port\n"; 1365 | } 1366 | if ($adv_socks_noauth_opt eq "off") { 1367 | print CREDS "socks_noauth=off\n"; 1368 | if ($adv_socks_user_var) { 1369 | $regkey->{'SOCKS_USER'} = $adv_socks_user_var; 1370 | } 1371 | if ($adv_socks_pass_var) { 1372 | $regkey->{'SOCKS_PASS'} = $adv_socks_pass_var; 1373 | } 1374 | } 1375 | if ($adv_socks_noauth_opt eq "on") { 1376 | if ($regkey->{'SOCKS_USER'}) { 1377 | delete $regkey->{'SOCKS_USER'}; 1378 | } 1379 | if ($regkey->{'SOCKS_PASS'}) { 1380 | delete $regkey->{'SOCKS_PASS'}; 1381 | } 1382 | delete $Registry->{'HKEY_CURRENT_USER/Software/Cryptostorm/'}; 1383 | } 1384 | if ($adv_ssh_opt eq "on") { 1385 | print CREDS "tunnel_ssh=on\n"; 1386 | print CREDS "tunnel_host=$selected_tunnel_opt\n"; 1387 | } 1388 | if ($adv_https_opt eq "on") { 1389 | print CREDS "tunnel_https=on\n"; 1390 | } 1391 | close(CREDS); 1392 | } 1393 | 1394 | sub step_pbar { 1395 | &blue_derp unless $statusvar eq $L->{$lang}{TXT_CONNECTED}; 1396 | Tkx::update(); 1397 | return if $stop; 1398 | if (!$pbarval) { 1399 | for ($c=0;$c<=10;$c++) { 1400 | $pbarval = $c; 1401 | select(undef, undef, undef, 0.04); 1402 | Tkx::update(); 1403 | } 1404 | } 1405 | else { 1406 | my $b = $pbarval + 10; 1407 | my $a = $pbarval; 1408 | for ($c=$a;$c<=$b;$c++) { 1409 | $pbarval = $c; 1410 | select(undef, undef, undef, 0.04); 1411 | Tkx::update(); 1412 | } 1413 | } 1414 | } 1415 | 1416 | sub recon { 1417 | $logbox->insert_end("$_[0]", "warnline"); 1418 | $logbox->see('end'); 1419 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1420 | $pbarval = 0; 1421 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1422 | $connect->configure(-state => "normal"); 1423 | $options->configure(-state => "normal"); 1424 | $update->configure(-state => "normal"); 1425 | $server_textbox->configure(-state => "readonly"); 1426 | $stop = 1; 1427 | $o_done3 = 1; 1428 | $showtiponce = 0; 1429 | &shutdown_openvpn(); 1430 | alarm 0; 1431 | select(undef,undef,undef,0.05); 1432 | &connectt; 1433 | } 1434 | 1435 | sub connectt { 1436 | if ($adv_ssh_opt eq "on") { 1437 | if ($disp_server ne "Global random") { 1438 | my ($index) = grep { $servers[$_] =~ /$disp_server/} (0 .. @servers-1); 1439 | my $tmpnode = $servers[$index]; 1440 | $tmpnode =~ s/.*://; 1441 | if ($tmpnode eq $selected_tunnel_opt) { 1442 | &do_error($L->{$lang}{ERR_TUNNEL_DIFFERENT_HOST} . " ($disp_server)"); 1443 | return; 1444 | } 1445 | } 1446 | } 1447 | $stop = 0; 1448 | $idle = 0; 1449 | $SIG{ALRM} = sub { &recon($L->{$lang}{TXT_CONNECT_TIMEOUT});return; }; 1450 | alarm $timeout_var; 1451 | if (!$token) { 1452 | $worldimage->configure(-image => "mainicon"); 1453 | &do_error($L->{$lang}{ERR_NO_TOKEN}); 1454 | alarm 0; 1455 | return; 1456 | } 1457 | $connect->configure(-state => "disabled"); 1458 | $options->configure(-state => "disabled"); 1459 | $update->configure(-state => "disabled"); 1460 | $server_textbox->configure(-state => "disabled"); 1461 | $statusvar = $L->{$lang}{TXT_CHECKING_TOKEN}; 1462 | $token =~ s/[^a-zA-Z0-9\-\+\/]//g; 1463 | if (($token !~ /^[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}$/) && 1464 | ($token !~ /^[a-f0-9]{128}$/) && 1465 | ($token !~ /^AAAAC3NzaC1lZDI1NTE5AAAAI/)) { 1466 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1467 | $pbarval = 0; 1468 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1469 | $connect->configure(-state => "normal"); 1470 | $update->configure(-state => "normal"); 1471 | $options->configure(-state => "normal"); 1472 | $server_textbox->configure(-state => "readonly"); 1473 | $worldimage->configure(-image => "mainicon"); 1474 | if ($token =~ /^([a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}){2,}/) { 1475 | &do_error($L->{$lang}{ERR_TOO_MANY_TOKENS1} . "\n" . $L->{$lang}{ERR_TOO_MANY_TOKENS2}); 1476 | alarm 0; 1477 | return; 1478 | } 1479 | &do_error($L->{$lang}{ERR_INVALID_TOKEN1} . "\n" . $L->{$lang}{ERR_INVALID_TOKEN2}); 1480 | alarm 0; 1481 | return; 1482 | } 1483 | if (($autocon_var eq "on") && ($saveoption eq "off") || (!$saveoption)) { 1484 | $autocon_var = "off"; 1485 | } 1486 | Tkx::update(); 1487 | $frame4->g_grid(-column => 0, -row => 3, -sticky => "nswe"); 1488 | $logbox->g_grid(-column => 0, -row => 4, -sticky => "nwes"); 1489 | $scroll->g_grid(-column => 1, -row => 4, -sticky => "ns"); 1490 | Tkx::update('idletasks'); 1491 | my $x = int((Tkx::winfo('screenwidth', $mw) / 2) - (Tkx::winfo('reqwidth', $mw) / 2)); 1492 | my $y = int((Tkx::winfo('screenheight', $mw) / 2) - (Tkx::winfo('reqheight', $mw) / 2)); 1493 | $mw->g_wm_geometry(Tkx::winfo('reqwidth', $mw) . "x" . Tkx::winfo('reqheight', $mw) . "+" . $x . "+" . $y); 1494 | Tkx::update(); 1495 | $statusvar = $L->{$lang}{TXT_LOGGING_IN} . "..."; 1496 | Tkx::update(); 1497 | open(TMP,">..\\user\\$hashfile") || &do_error($L->{$lang}{ERR_WRITE} . " .\\user\\"); 1498 | if (length($token)) { 1499 | if ($token =~ /^([a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5}\-[a-zA-Z0-9]{5})$/) { 1500 | print TMP sha512_hex("$token") . "\n"; 1501 | } 1502 | if (($token =~ /^([a-f0-9]{128})$/) || ($token =~ /^AAAAC3NzaC1lZDI1NTE5AAAAI/)) { 1503 | print TMP "$token\n"; 1504 | } 1505 | } 1506 | else { 1507 | print TMP sha512_hex("$token") . "\n"; 1508 | } 1509 | print TMP "$password\n"; 1510 | close(TMP); 1511 | Tkx::update(); 1512 | $logbox->configure(-state => "normal"); 1513 | Tkx::update(); 1514 | $logbox_index = $logbox->search(-regexp, '^' . $L->{$lang}{TXT_DISCONNECTED} . '$',"insert"); 1515 | if (defined($logbox_index)) { 1516 | if ($logbox_index =~ /[0-9\.]+/) { 1517 | $logbox->delete($logbox_index,sprintf("%.1f", ($logbox_index+1))); 1518 | } 1519 | } 1520 | $logbox->see('end'); 1521 | Tkx::update(); 1522 | if ($randomize_it eq "on") { 1523 | $port_var = int(rand(29998) + 1); 1524 | if (($port_var == 5061) || ($port_var == 5062) || ($port_var == 5063) || ($port_var == 8443)) { 1525 | $port_var = $port_var + int(rand(1000 - 5)); 1526 | } 1527 | } 1528 | undef @tmparray; 1529 | undef $tmpline; 1530 | undef $vpn_args; 1531 | Tkx::update(); 1532 | &confgen; 1533 | Tkx::update(); 1534 | my $chosen_node = $vpn_args; 1535 | $chosen_node =~ s/.*remote ([a-zA-Z0-9\-\.]+) .*/$1/; 1536 | Tkx::update(); 1537 | my $dnsret; 1538 | if ($adv_https_opt eq "on") { 1539 | @resolved_ips = ('127.0.0.1'); 1540 | } 1541 | $statusvar = $L->{$lang}{TXT_CONNECTING} . "..."; 1542 | Tkx::update(); 1543 | @remote_random = (); 1544 | $stop = 0; 1545 | system(1,"netsh interface ipv6 set privacy state=disabled"); 1546 | $pid = open $VPNfh, "-|", "$vpnexe $vpn_args"; 1547 | $VPNfh->autoflush(1); 1548 | $thread = threads->new(\&tail_openvpn_log); 1549 | step_pbar(); 1550 | Tkx::update(); 1551 | @msgs = ('cryptostorm', 1552 | 'PUSH_REQUEST', 1553 | 'device .* opened', 1554 | 'Route addition via .* succeeded', 1555 | 'TLS: Initial packet from'); 1556 | $localip = ''; 1557 | $localip6 = ''; 1558 | $ipv6_ip_i_was_connected_to = ''; 1559 | &logbox_loop; 1560 | alarm 0; 1561 | } 1562 | 1563 | sub logbox_loop { 1564 | while (!$idle) { 1565 | select(undef,undef,undef,0.05); 1566 | Tkx::update(); 1567 | &watch_logbox; 1568 | } 1569 | } 1570 | 1571 | sub watch_logbox { 1572 | select(undef,undef,undef,0.01); 1573 | while (@log_lines) { 1574 | my $ovpnline = shift @log_lines; 1575 | $logbox->insert('end', $ovpnline); 1576 | $logbox->see('end'); 1577 | Tkx::update() unless $idle; 1578 | for (@msgs) { 1579 | if ($ovpnline =~ /$_/) { 1580 | &step_pbar(); 1581 | } 1582 | } 1583 | $logbox->see('end'); 1584 | if ($ovpnline =~ /\b(10\.(?:66|67|70|71)\.\d{1,3}\.(?:25[0-5]|2[0-4]\d|1\d\d|\d\d|[2-9]))\b/) { 1585 | $localip = $1; 1586 | } 1587 | if ($ovpnline =~ /(fd00:10:60:[a-f0-9]{1,4}:[a-f0-9]{1,4}:[a-f0-9]{1,4}:[a-f0-9]{1,4}:[a-f0-9]{1,4})/i) { 1588 | $localip6 = $1; 1589 | } 1590 | if ($ovpnline =~ /GDG6: remote_host_ipv6=([a-f0-9:]+)/) { 1591 | $ipv6_ip_i_was_connected_to = $1; 1592 | } 1593 | if ($ovpnline =~ /received, process restarting/) { 1594 | $logbox_index = $logbox->search(-regexp, '^' . $L->{$lang}{TXT_CONNECTED} . '$',"insert"); 1595 | if (defined($logbox_index)) { 1596 | if ($logbox_index =~ /[0-9\.]+/) { 1597 | $logbox->delete($logbox_index,sprintf("%.1f", ($logbox_index+1))); 1598 | } 1599 | } 1600 | $logbox->see('end'); 1601 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1602 | $pbarval = 0; 1603 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1604 | $connect->configure(-state => "normal"); 1605 | $options->configure(-state => "normal"); 1606 | $update->configure(-state => "normal"); 1607 | $server_textbox->configure(-state => "readonly"); 1608 | } 1609 | if ($ovpnline =~ /Failed to open/) { 1610 | $logbox->insert_end("\n", "badline"); 1611 | $logbox->see('end'); 1612 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1613 | $pbarval = 0; 1614 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1615 | $connect->configure(-state => "normal"); 1616 | $options->configure(-state => "normal"); 1617 | $update->configure(-state => "normal"); 1618 | $server_textbox->configure(-state => "readonly"); 1619 | &do_error($ovpnline); 1620 | &shutdown_openvpn(); 1621 | alarm 0; 1622 | close($VPNfh); 1623 | $stop = 1; 1624 | return -1; 1625 | } 1626 | if ($ovpnline =~ /Options error:/) { 1627 | $logbox->insert_end("\n", "badline"); 1628 | $logbox->see('end'); 1629 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1630 | $pbarval = 0; 1631 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1632 | $connect->configure(-state => "normal"); 1633 | $options->configure(-state => "normal"); 1634 | $update->configure(-state => "normal"); 1635 | $server_textbox->configure(-state => "readonly"); 1636 | &do_error($ovpnline); 1637 | &shutdown_openvpn(); 1638 | alarm 0; 1639 | close($VPNfh); 1640 | $stop = 1; 1641 | return -1; 1642 | } 1643 | if ($ovpnline =~ /Exiting due to fatal error/) { 1644 | # ignoring, closes things down faster on disconnect 1645 | $logbox_index = $logbox->search(-regexp, 'Assertion failed at win32\.c.*socket_defined',"insert"); 1646 | if (defined($logbox_index)) { 1647 | if ($logbox_index =~ /[0-9\.]+/) { 1648 | $logbox->delete($logbox_index,sprintf("%.1f", ($logbox_index+1))); 1649 | $logbox->delete($logbox_index,sprintf("%.1f", ($logbox_index+2))); 1650 | $logbox->see('end'); 1651 | } 1652 | } 1653 | else { 1654 | $logbox->insert_end("\n", "badline"); 1655 | $logbox->see('end'); 1656 | my @lines = split /\n/, $ovpnline; 1657 | $ovpnline = @lines[($#lines - 1 )]; 1658 | &do_error($ovpnline); 1659 | &shutdown_openvpn(); 1660 | } 1661 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1662 | $pbarval = 0; 1663 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1664 | $connect->configure(-state => "normal"); 1665 | $options->configure(-state => "normal"); 1666 | $update->configure(-state => "normal"); 1667 | $server_textbox->configure(-state => "readonly"); 1668 | alarm 0; 1669 | close($VPNfh); 1670 | $stop = 1; 1671 | return -1; 1672 | } 1673 | if ($ovpnline =~ /AUTH: Received control message: AUTH_FAILED/) { 1674 | $logbox->insert_end($L->{$lang}{ERR_AUTH_FAIL} . "\n", "badline"); 1675 | $logbox->see('end'); 1676 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1677 | $pbarval = 0; 1678 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1679 | $connect->configure(-state => "normal"); 1680 | $options->configure(-state => "normal"); 1681 | $update->configure(-state => "normal"); 1682 | $server_textbox->configure(-state => "readonly"); 1683 | &do_error($L->{$lang}{ERR_AUTH_FAIL}); 1684 | &shutdown_openvpn(); 1685 | alarm 0; 1686 | close($VPNfh); 1687 | $stop = 1; 1688 | return -1; 1689 | } 1690 | if ($ovpnline =~ /Cannot resolve host address: (.*)/) { 1691 | $logbox->insert_end($L->{$lang}{ERR_RESOLVE} . " $1\n", "badline"); 1692 | $logbox->see('end'); 1693 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1694 | $pbarval = 0; 1695 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1696 | $connect->configure(-state => "normal"); 1697 | $options->configure(-state => "normal"); 1698 | $update->configure(-state => "normal"); 1699 | $server_textbox->configure(-state => "readonly"); 1700 | &do_error($L->{$lang}{ERR_RESOLVE} . " $1"); 1701 | if ((&isoncs > 0) && ($dnscrypt_var eq "on")) { 1702 | $worldimage->configure(-image => "mainicon"); 1703 | $statusvar = $L->{$lang}{TXT_SET_DNS_DNSCRYPT} . "..."; 1704 | Tkx::update(); 1705 | &dnscrypt(0); 1706 | } 1707 | &shutdown_openvpn(); 1708 | alarm 0; 1709 | close($VPNfh); 1710 | $stop = 1; 1711 | return -1; 1712 | } 1713 | if ($ovpnline =~ /Initialization Sequence Completed/) { 1714 | delete $Registry->{"HKEY_LOCAL_MACHINE/SYSTEM/ControlSet001/Control/Network/NewNetworkWindowOff/"}; 1715 | if ($killswitch_var eq "on") { 1716 | if ($dnscrypt_var eq "off") { 1717 | # Disable temporary pre-connect DNS rule 1718 | toggle_fw_rule("cryptostorm - Allow pre-connect DNS", "no"); 1719 | } 1720 | # Enable DNS leak protection rule 1721 | toggle_fw_rule("cryptostorm - Allow internal VPN DNS", "yes"); 1722 | if ($localip) { 1723 | # Enable inbound/outbound rules for internal IPv4 1724 | toggle_fw_rule("cryptostorm - Allow internal IPv4 in", "yes localip=$localip remoteip=any"); 1725 | toggle_fw_rule("cryptostorm - Allow internal IPv4 out", "yes localip=any remoteip=$localip"); 1726 | # Allow traffic to the gateway 1727 | my $gw4 = $localip; 1728 | $gw4 =~ s/\.\d+$/.1/; 1729 | toggle_fw_rule("cryptostorm - Allow internal IPv4 gateway in", "yes localip=any remoteip=$gw4"); 1730 | toggle_fw_rule("cryptostorm - Allow internal IPv4 gateway out", "yes localip=$gw4 remoteip=any"); 1731 | } 1732 | if ($localip6) { 1733 | # Enable inbound/outbound rules for internal IPv6 1734 | toggle_fw_rule("cryptostorm - Allow internal IPv6 in", "yes localip=$localip6 remoteip=any"); 1735 | toggle_fw_rule("cryptostorm - Allow internal IPv6 out", "yes localip=any remoteip=$localip6"); 1736 | # Allow traffic to the IPv6 gateway 1737 | my $gw6 = 'fe80::1'; 1738 | toggle_fw_rule("cryptostorm - Allow internal IPv6 gateway in", "yes localip=any remoteip=$gw6"); 1739 | toggle_fw_rule("cryptostorm - Allow internal IPv6 gateway out", "yes localip=$gw6"); 1740 | } 1741 | if ($MAJOR >= 10) { 1742 | # Without this, traffic doesn't flow for the first 20-40 seconds on the initial connect, 1743 | # but only on Windows 10 and 11 for some reason. 1744 | system(1,"ipconfig /renew"); 1745 | } 1746 | } 1747 | if ($ovpnline =~ /Initialization Sequence Completed With Errors/) { 1748 | $logbox->insert_end($L->{$lang}{ERR_CONNECT_GENERIC} . "\n", "badline"); 1749 | $logbox->see('end'); 1750 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 1751 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 1752 | $connect->configure(-state => "normal"); 1753 | $options->configure(-state => "normal"); 1754 | $update->configure(-state => "normal"); 1755 | $server_textbox->configure(-state => "readonly"); 1756 | $worldimage->configure(-image => "mainicon"); 1757 | Tkx::update(); 1758 | &do_error($L->{$lang}{ERR_CONNECT_GENERIC}); 1759 | &shutdown_openvpn(); 1760 | alarm 0; 1761 | close($VPNfh); 1762 | $stop = 1; 1763 | return -1; 1764 | } 1765 | else { 1766 | step_pbar(); 1767 | if ($saveoption eq "on") { 1768 | &savelogin; 1769 | } 1770 | $worldimage->configure(-image => "g3"); 1771 | $logbox->insert_end($L->{$lang}{TXT_CONNECTED} . "\n", "goodline"); 1772 | system(1,"netsh interface ipv6 set privacy state=enabled"); 1773 | $logbox_index = $logbox->search(-regexp, '^' . $L->{$lang}{TXT_DISCONNECTED} . '$',"insert"); 1774 | if (defined($logbox_index)) { 1775 | if ($logbox_index =~ /[0-9\.]+/) { 1776 | $logbox->delete($logbox_index,sprintf("%.1f", ($logbox_index+1))); 1777 | } 1778 | } 1779 | $logbox->see('end'); 1780 | $statusvar = $L->{$lang}{TXT_CONNECTED}; 1781 | Tkx::update(); 1782 | # No $L->{$lang} for $balloon_msg because Win32::GUI::NotifyIcon can't do Unicode 1783 | $balloon_msg = "Connected to cryptostorm."; 1784 | $cancel->configure(-text => $L->{$lang}{TXT_DISCONNECT}); 1785 | Tkx::update(); 1786 | alarm 0; 1787 | if ($dnscrypt_var eq "on") { 1788 | &dnscrypt(0); 1789 | Tkx::update(); 1790 | } 1791 | $statusvar = $L->{$lang}{TXT_UPDATE_CHECKING} . "..."; 1792 | Tkx::update(); 1793 | &check_version_thread(1); 1794 | if ($VERSION < $o_version_buf) { 1795 | $upgrade = 1; 1796 | } 1797 | if ($upgrade) { 1798 | my $upgrade_or_not; 1799 | $upgrade_or_not = Tkx::tk___messageBox(-parent => $mw, -type => "yesno", 1800 | -message => $L->{$lang}{QUESTION_NEWVER1} . "\n" . 1801 | $L->{$lang}{QUESTION_NEWVER2} . "\n", 1802 | -icon => "question", -title => "cryptostorm.is client"); 1803 | if ($upgrade_or_not eq "yes") { 1804 | if ($token) { 1805 | copy($hashfile,$ENV{'TEMP'} . "\\client.dat"); 1806 | copy($authfile,$ENV{'TEMP'} . "\\config.ini"); 1807 | } 1808 | $statusvar = $L->{$lang}{TXT_DOWNLOADING_LATEST} . "..."; 1809 | Tkx::update(); 1810 | &grabnverify("../cryptostorm_setup.exe"); 1811 | copy("tmp\\cryptostorm_setup.exe","..\\"); 1812 | unlink "tmp\\cryptostorm_setup.exe" if (-e "tmp\\cryptostorm_setup.exe"); 1813 | unlink "tmp\\cryptostorm_setup.exe.hash" if (-e "tmp\\cryptostorm_setup.exe.hash"); 1814 | rmdir("tmp") unless &isEmpty("tmp") > 0; 1815 | $statusvar = $L->{$lang}{TXT_DONE}; 1816 | Tkx::update(); 1817 | $doupgrade = 1; 1818 | Tkx::tk___messageBox(-parent => $mw, -type => "ok", 1819 | -message => $L->{$lang}{TXT_UPGRADING1} . "\n" . 1820 | $L->{$lang}{TXT_UPGRADING2}, 1821 | -icon => "info", -title => "cryptostorm.is client"); 1822 | } 1823 | } 1824 | if (defined($amsg)) { 1825 | Tkx::tk___messageBox(-parent => $mw, -type => "ok", 1826 | -message => "$amsg", 1827 | -icon => "info", -title => "cryptostorm.is client"); 1828 | 1829 | } 1830 | $statusvar = $L->{$lang}{TXT_CONNECTED}; 1831 | Tkx::update(); 1832 | if (!$doupgrade) { 1833 | &hidewin; 1834 | } 1835 | Tkx::update(); 1836 | } 1837 | } 1838 | } 1839 | } 1840 | 1841 | sub tail_openvpn_log { 1842 | my $logfile = "..\\bin\\openvpn.log"; 1843 | my $lastpos = 0; 1844 | while (!$stop) { 1845 | if (open my $logfh, '<', $logfile) { 1846 | seek($logfh, $lastpos, 0); 1847 | while (my $line = <$logfh>) { 1848 | last if $stop; 1849 | $lastpos = tell($logfh); 1850 | $line =~ s/^[0-9\.]+ [0-9a-f]+ //; 1851 | next if ($line =~ /UDPv[46]\s+(READ|WRITE)/); 1852 | next if ($line =~ /TUN\s+(READ|WRITE)/); 1853 | next if ($line =~ /windows-driver/); 1854 | next if ($line =~ /edirect-gateway and redirect-private/); 1855 | next if ($line =~ /PID_ERR replay/); 1856 | next if ($line =~ /CreateFile failed/); 1857 | next if ($line =~ /sending exit notification to peer/); 1858 | next if ($line =~ /\-\-mute/); 1859 | next if ($line =~ /mode = /); 1860 | next if ($line =~ /config =/); 1861 | next if ($line =~ /Current Parameter Settings/); 1862 | next if ($line =~ /MTU parms/); 1863 | next if ($line =~ /MANAGEMENT/); 1864 | next if ($line =~ /msg_channel=/); 1865 | # If passed all filters, queue for logbox 1866 | push @log_lines, $line; 1867 | } 1868 | close $logfh; 1869 | } 1870 | select undef, undef, undef, 0.1; 1871 | } 1872 | } 1873 | 1874 | sub remove_ipv6_routes { 1875 | system(1,"route delete 128.0.0.0 MASK 128.0.0.0 & route delete 2000::/3 & route delete ::/3 & route delete 2000::/4 & route delete 3000::/4 & route delete fc00::/7"); 1876 | } 1877 | 1878 | sub do_exit { 1879 | my $idunno; 1880 | if (defined($mw)) { 1881 | $mw->g_wm_deiconify(); 1882 | $mw->g_raise(); 1883 | $mw->g_focus(); 1884 | } 1885 | Tkx::update(); 1886 | my $oncs = &isoncs; 1887 | if ($oncs > 0) { 1888 | Tkx::update(); 1889 | $idunno = Tkx::tk___messageBox(-type => "yesno", 1890 | -message => $L->{$lang}{QUESTION_DISCONNECT1} . "\n" . 1891 | $L->{$lang}{QUESTION_DISCONNECT2} . "\n" . 1892 | $L->{$lang}{QUESTION_DISCONNECT3}, 1893 | -icon => "question", -title => "cryptostorm.is client"); 1894 | if ($idunno eq "no") { 1895 | return; 1896 | } 1897 | } 1898 | if ($oncs == 0 || $idunno eq "yes") { 1899 | if (defined $idunno && $idunno eq "yes") { 1900 | $idle = 1; 1901 | $statusvar .= "."; 1902 | Tkx::update(); 1903 | &remove_ipv6_routes; 1904 | $statusvar .= "."; 1905 | Tkx::update(); 1906 | &restore_wintun(1); 1907 | } 1908 | $statusvar .= "."; 1909 | Tkx::update(); 1910 | $pbarval = 0; 1911 | # User clicked the Exit button 1912 | if ($cancel->cget(-text) eq $L->{$lang}{TXT_EXIT}) { 1913 | $TrayWinHidden->Open->Remove() if defined $TrayWinHidden; 1914 | $statusvar .= "."; 1915 | Tkx::update(); 1916 | &savelogin; 1917 | $statusvar .= "."; 1918 | Tkx::update(); 1919 | $cancel->configure(-state => "disabled"); 1920 | Tkx::update(); 1921 | if ($adv_ssh_opt eq "on") { 1922 | system(1,"taskkill /IM cs-ssh-tun.exe /F"); 1923 | } 1924 | if ($adv_https_opt eq "on") { 1925 | system(1,"taskkill /IM cs-https-tun.exe /F"); 1926 | } 1927 | if ($dnscrypt_var eq "on") { 1928 | $statusvar = $L->{$lang}{TXT_DNS_RESTORE} . "..."; 1929 | Tkx::update(); 1930 | &dnscrypt(0, 1); # 1 = also uninstall 1931 | Tkx::update(); 1932 | } 1933 | if (-e "..\\bin\\openvpn.log") { 1934 | unlink("..\\bin\\openvpn.log"); 1935 | } 1936 | if (-e "..\\user\\manpass.txt") { 1937 | unlink("..\\user\\manpass.txt"); 1938 | } 1939 | if (-e "..\\user\\mydns.txt") { 1940 | $statusvar = $L->{$lang}{TXT_DNS_RESTORE} . "..."; 1941 | Tkx::update(); 1942 | &restore_dns; 1943 | unlink "..\\user\\mydns.txt"; 1944 | } 1945 | if ((-e "..\\user\\all.wfw") || ($killswitch_var eq "on")) { 1946 | $rt = `netsh advfirewall firewall show rule name="cryptostorm - Allow CS programs"`; 1947 | if ($rt =~ /cryptostorm/) { 1948 | $tokillornot = Tkx::tk___messageBox(-parent => $mw, -type => "yesno", 1949 | -message => $L->{$lang}{QUESTION_KILLSWITCH1} . "\n" . 1950 | $L->{$lang}{QUESTION_KILLSWITCH2}, 1951 | -icon => "question", -title => "cryptostorm.is client"); 1952 | if ($tokillornot eq "yes") { 1953 | Tkx::update(); 1954 | &killswitch_off; 1955 | $killswitch_var = "off"; 1956 | &savelogin; 1957 | Tkx::update(); 1958 | } 1959 | } 1960 | } 1961 | $statusvar = $L->{$lang}{TXT_WINTUN_CLEANUP}; 1962 | Tkx::update(); 1963 | system("cswintun.exe stop"); 1964 | $statusvar = $L->{$lang}{TXT_WINTUN_STOPPED}; 1965 | Tkx::update(); 1966 | if ($MAJOR >= 10) { 1967 | # Windows 10 or newer 1968 | system("cswintun.exe uninstall"); 1969 | $statusvar = $L->{$lang}{TXT_WINTUN_STOPPED_AND_UNINSTALLED}; 1970 | Tkx::update(); 1971 | } 1972 | system(1,"ipconfig /registerdns"); 1973 | Tkx::update(); 1974 | $statusvar = $L->{$lang}{TXT_EXITING}; 1975 | Tkx::update(); 1976 | undef $TrayWinHidden if defined $TrayWinHidden; 1977 | if ($killswitch_var eq "on") { 1978 | system(1,"ipconfig /renew"); 1979 | } 1980 | $statusvar .= "."; 1981 | Tkx::update(); 1982 | if (defined $thread) { 1983 | $stop = 1; 1984 | for (1..10) { 1985 | last if !$thread->is_running(); 1986 | select undef, undef, undef, 0.1; 1987 | } 1988 | undef $thread; 1989 | } 1990 | $statusvar .= "."; 1991 | Tkx::update(); 1992 | $done = 1; 1993 | $o_done3 = 1; 1994 | if (-e "..\\user\\mydns.txt") { 1995 | unlink("..\\user\\mydns.txt"); 1996 | } 1997 | $statusvar .= "."; 1998 | Tkx::update(); 1999 | if (-e "..\\user\\socks.dat") { 2000 | unlink("..\\user\\socks.dat"); 2001 | } 2002 | &shutdown_openvpn(); 2003 | $statusvar .= "."; 2004 | Tkx::update(); 2005 | $o_thread3->join() if defined($o_thread3) && $o_thread3->is_joinable(); 2006 | $mw->g_destroy() if defined $mw; 2007 | if ($doupgrade) { 2008 | system(1,"start cryptostorm_setup.exe"); 2009 | } 2010 | Tkx::exit(0); 2011 | } 2012 | Tkx::update(); 2013 | # User clicked the Disconnect button 2014 | if ($cancel->cget(-text) eq $L->{$lang}{TXT_DISCONNECT}) { 2015 | $statusvar = $L->{$lang}{TXT_DISCONNECTING}; 2016 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 2017 | $cancel->configure(-state => "disabled"); 2018 | $connect->configure(-state => "disabled"); 2019 | $update->configure(-state => "disabled"); 2020 | $options->configure(-state => "disabled"); 2021 | Tkx::update(); 2022 | # Remove the green "Connected" text 2023 | $logbox_index = $logbox->search(-regexp, '^' . $L->{$lang}{TXT_CONNECTED} . '$',"insert"); 2024 | if (defined($logbox_index)) { 2025 | if ($logbox_index =~ /[0-9\.]+/) { 2026 | $logbox->delete($logbox_index,sprintf("%.1f", ($logbox_index+1))); 2027 | } 2028 | } 2029 | # Then put the red "Disconnected" text in the logbox 2030 | $logbox->insert_end($L->{$lang}{TXT_DISCONNECTED} . "\n", "badline"); 2031 | $logbox->see('end'); 2032 | Tkx::update(); 2033 | if ($noipv6_var eq "off") { 2034 | $statusvar .= "."; 2035 | Tkx::update(); 2036 | &remove_ipv6_routes; 2037 | $statusvar .= "."; 2038 | Tkx::update(); 2039 | if ($ipv6_ip_i_was_connected_to) { 2040 | system(1, "route delete ${ipv6_ip_i_was_connected_to}/128"); 2041 | $statusvar .= "."; 2042 | Tkx::update(); 2043 | } 2044 | } 2045 | if ($killswitch_var eq "on") { 2046 | $localip6 = ""; 2047 | $localip = ""; 2048 | if ($dnscrypt_var eq "off") { 2049 | # Re-enable temporary pre-connect DNS for reconnections 2050 | toggle_fw_rule("cryptostorm - Allow pre-connect DNS", "yes"); 2051 | $statusvar .= "."; 2052 | Tkx::update(); 2053 | } 2054 | # Disable internal DNS VPN rule 2055 | toggle_fw_rule("cryptostorm - Allow internal VPN DNS", "no"); 2056 | # Disable internal IPv4/6 rules 2057 | toggle_fw_rule("cryptostorm - Allow internal IPv4 in", "no"); 2058 | toggle_fw_rule("cryptostorm - Allow internal IPv4 out", "no"); 2059 | toggle_fw_rule("cryptostorm - Allow internal IPv6 in", "no"); 2060 | toggle_fw_rule("cryptostorm - Allow internal IPv6 out", "no"); 2061 | toggle_fw_rule("cryptostorm - Allow internal IPv4 gateway in", "no"); 2062 | toggle_fw_rule("cryptostorm - Allow internal IPv4 gateway out", "no"); 2063 | toggle_fw_rule("cryptostorm - Allow internal IPv6 gateway in", "no"); 2064 | toggle_fw_rule("cryptostorm - Allow internal IPv6 gateway out", "no"); 2065 | $statusvar .= "."; 2066 | Tkx::update(); 2067 | } 2068 | &savelogin; 2069 | if ($adv_ssh_opt eq "on") { 2070 | system(1,"taskkill /IM cs-ssh-tun.exe /F"); 2071 | } 2072 | if ($adv_https_opt eq "on") { 2073 | system(1,"taskkill /IM cs-https-tun.exe /F"); 2074 | } 2075 | if (-e "..\\user\\socks.dat") { 2076 | unlink("..\\user\\socks.dat"); 2077 | } 2078 | Tkx::update(); 2079 | $worldimage->configure(-image => "mainicon"); 2080 | if (defined $thread) { 2081 | $stop = 1; 2082 | for (1..20) { 2083 | last if !$thread->is_running(); 2084 | select undef, undef, undef, 0.1; 2085 | } 2086 | undef $thread; 2087 | } 2088 | $o_done3 = 1; 2089 | $pbarval = 0; 2090 | $showtiponce = 0; 2091 | &shutdown_openvpn(); 2092 | if ($dnscrypt_var eq "on") { 2093 | $statusvar = $L->{$lang}{TXT_SET_DNS_DNSCRYPT} . "..."; 2094 | Tkx::update(); 2095 | &dnscrypt(1); 2096 | $statusvar .= "."; 2097 | Tkx::update(); 2098 | } 2099 | system(1,"ipconfig /renew"); 2100 | $cancel->configure(-state => "normal"); 2101 | $update->configure(-state => "normal"); 2102 | $options->configure(-state => "normal"); 2103 | $connect->configure(-state => "normal"); 2104 | $server_textbox->configure(-state => "readonly"); 2105 | $statusvar = $L->{$lang}{TXT_DISCONNECTED}; 2106 | $pbarval = 0; 2107 | Tkx::update(); 2108 | } 2109 | } 2110 | } 2111 | 2112 | sub shutdown_openvpn { 2113 | return unless $manport && $manpass; 2114 | my $sock = IO::Socket::INET->new(PeerHost => '127.0.0.1', 2115 | PeerPort => $manport, 2116 | Proto => 'tcp', 2117 | Timeout => 1); 2118 | if ($sock) { 2119 | print $sock "$manpass\r\n"; 2120 | my $authorized = 0; 2121 | while (my $line = <$sock>) { 2122 | if ($line =~ /INFO:OpenVPN Management Interface Version/) { 2123 | $authorized = 1; 2124 | last; 2125 | } 2126 | } 2127 | if ($authorized) { 2128 | print $sock "signal SIGTERM\r\n"; 2129 | while (my $line = <$sock>) { 2130 | last if $line =~ /SUCCESS: signal SIGTERM thrown/; 2131 | } 2132 | # Wait for OpenVPN to close the connection 2133 | eval { 2134 | local $SIG{ALRM} = sub { die "timeout\n" }; 2135 | alarm(0.3); 2136 | <$sock>; # This should hit EOF if OpenVPN exits 2137 | alarm(0); 2138 | }; 2139 | print $sock "exit\r\n" unless $@ =~ /timeout/; 2140 | } 2141 | close($sock); 2142 | } 2143 | # fallback to taskkill 2144 | if (&isoncs()) { 2145 | system(1, "TASKKILL /F /T /IM $vpnexe"); 2146 | } 2147 | } 2148 | 2149 | sub restore_wintun { 2150 | my $disconnecting = $_[0]; 2151 | my $tmpstatusvar = $statusvar; 2152 | $statusvar = $L->{$lang}{TXT_WINTUN_RESTORING_DEFAULTS}; 2153 | Tkx::update(); 2154 | for (`netsh interface ipv6 show addresses interface="cryptostorm VPN" | findstr fd00:10:60:`) { 2155 | if (/Address (fd00:10:60:[a-f0-9:]+) Parameters/) { 2156 | my $ip_to_del = $1; 2157 | if ($MAJOR > 6 || ($MAJOR == 6 && $MINOR >= 2)) { 2158 | # Use PowerShell cmdlet Remove-NetIPAddress for Windows 8 and above 2159 | system(qq(powershell -Command "Get-NetIPAddress -IPAddress $ip_to_del | Remove-NetIPAddress -Confirm:\$false")); 2160 | $statusvar .= "."; 2161 | Tkx::update(); 2162 | } 2163 | else { 2164 | # Use netsh for < Windows 8 2165 | system(qq(netsh interface ipv6 delete address "cryptostorm VPN" "$ip_to_del")); 2166 | $statusvar .= "."; 2167 | Tkx::update(); 2168 | } 2169 | } 2170 | } 2171 | system(qq(netsh interface ipv6 set dnsservers name="cryptostorm VPN" source=dhcp)); 2172 | $statusvar .= "."; 2173 | Tkx::update(); 2174 | system(qq(netsh interface ip set address name="cryptostorm VPN" source=dhcp)); 2175 | $statusvar .= "."; 2176 | Tkx::update(); 2177 | system(qq(netsh interface ipv4 set dnsservers name="cryptostorm VPN" source=dhcp)); 2178 | $statusvar = $tmpstatusvar; 2179 | Tkx::update(); 2180 | } 2181 | 2182 | sub uniq { 2183 | my %seen; 2184 | grep !$seen{$_}++, @_; 2185 | } 2186 | 2187 | sub update_node_list { 2188 | my $socket; 2189 | my $host = "cryptostorm.nu"; 2190 | my $port = 443; 2191 | my $path = "/nodelist4.txt"; 2192 | foreach my $entry (@csnu_ips) { 2193 | my ($ip, $family) = @$entry{qw(ip family)}; 2194 | next unless inet_pton($family, $ip); # Skip unsupported families 2195 | eval { 2196 | local $SIG{ALRM} = sub { die "timeout\n" }; 2197 | alarm(7); # Total timeout per attempt 2198 | $socket = IO::Socket::SSL->new( 2199 | PeerAddr => $ip, 2200 | PeerPort => $port, 2201 | SSL_hostname => $host, 2202 | SSL_verify_mode => SSL_VERIFY_PEER, 2203 | Timeout => 5, 2204 | Domain => $family, 2205 | ); 2206 | alarm(0); 2207 | }; 2208 | if ($@) { 2209 | $socket = undef; 2210 | next; 2211 | } 2212 | last if $socket; 2213 | } 2214 | unless ($socket) { 2215 | $update_err = "ERROR: Couldn't connect to $host via any IP"; 2216 | return; 2217 | } 2218 | # Send HTTPS GET request manually 2219 | print $socket "GET $path HTTP/1.1\r\n"; 2220 | print $socket "Host: $host\r\n"; 2221 | print $socket "User-Agent: Cryptostorm client\r\n"; 2222 | print $socket "Connection: close\r\n\r\n"; 2223 | my $headers = 1; 2224 | my $body = ''; 2225 | my $timeout = 7; 2226 | eval { 2227 | local $SIG{ALRM} = sub { die "timeout\n" }; 2228 | alarm($timeout); 2229 | while (my $line = <$socket>) { 2230 | if ($headers && $line =~ /^Content-Type:\s*([a-z\/]+)/i) { 2231 | $status = $1; 2232 | } 2233 | if ($line =~ /^\r?$/) { 2234 | $headers = 0; 2235 | next; 2236 | } 2237 | $body .= $line unless $headers; 2238 | } 2239 | alarm(0); 2240 | }; 2241 | if ($@) { 2242 | $update_err = "ERROR: Download from $host failed: $@"; 2243 | return; 2244 | } 2245 | close $socket; 2246 | $nodebuf = $body; 2247 | } 2248 | 2249 | sub do_options { 2250 | if ($saveoption eq "off") { 2251 | $autocon_var = "off"; 2252 | } 2253 | $tmp_noipv6_var = $noipv6_var; 2254 | $tmp_dnscrypt_var = $dnscrypt_var; 2255 | $tmp_killswitch_var = $killswitch_var; 2256 | $mw->g_wm_deiconify(); 2257 | $mw->g_wm_withdraw(); 2258 | my $width ||= Tkx::winfo('reqwidth', $cw); 2259 | my $height ||= Tkx::winfo('reqheight', $cw); 2260 | my $x = int((Tkx::winfo('screenwidth', $cw) / 2) - ($width / 2)); 2261 | my $y = int((Tkx::winfo('screenheight', $cw) / 2) - ($height / 2)); 2262 | $cw->g_wm_geometry($width . "x" . $height . "+" . $x . "+" . $y); 2263 | $cw->g_raise(); 2264 | $cw->g_wm_deiconify(); 2265 | $cw->g_focus(); 2266 | Tkx::update(); 2267 | } 2268 | 2269 | sub backtomain { 2270 | if ($adv_socks_opt eq "on") { 2271 | if ($adv_socks_port =~ /^([0-9]+)$/) { 2272 | if (($1 < 1) || ($1 > 65535)) { 2273 | &do_error($L->{$lang}{ERR_INVALID_SOCKS_PORT}); 2274 | return; 2275 | } 2276 | } 2277 | else { 2278 | &do_error($L->{$lang}{ERR_INVALID_SOCKS_PORT}); 2279 | return; 2280 | } 2281 | } 2282 | if ($adv_ssh_opt eq "on") { 2283 | if ($disp_server ne "Global random") { 2284 | my ($index) = grep { $servers[$_] =~ /$disp_server/} (0 .. @servers-1); 2285 | my $tmpnode = $servers[$index]; 2286 | $tmpnode =~ s/.*://; 2287 | if ($tmpnode eq $selected_tunnel_opt) { 2288 | &do_error($L->{$lang}{ERR_TUNNEL_DIFFERENT_HOST} . " ($disp_server)"); 2289 | return; 2290 | } 2291 | } 2292 | } 2293 | my $tmpvar = $statusvar; 2294 | $port_var =~ s/[^0-9]//g; 2295 | if ($port_var =~ /^([0-9]+)$/) { 2296 | if (($1 < 1) || ($1 > 29999)) { 2297 | &do_error($L->{$lang}{ERR_INVALID_PORT}); 2298 | return; 2299 | } 2300 | if ($1 == 8443) { 2301 | &do_error($L->{$lang}{ERR_PORT_8443_RESERVED}); 2302 | return; 2303 | } 2304 | } 2305 | else { 2306 | &do_error($L->{$lang}{ERR_INVALID_PORT}); 2307 | return; 2308 | } 2309 | $cw->g_wm_deiconify(); 2310 | $cw->g_wm_withdraw(); 2311 | $mw->g_raise(); 2312 | $mw->g_wm_deiconify(); 2313 | $mw->g_focus(); 2314 | Tkx::update(); 2315 | if ($dnscrypt_var ne $tmp_dnscrypt_var) { 2316 | if ($dnscrypt_var eq "on") { 2317 | Tkx::update(); 2318 | &dnscrypt(1); 2319 | Tkx::update(); 2320 | } 2321 | if ($dnscrypt_var eq "off") { 2322 | Tkx::update(); 2323 | &dnscrypt(0); 2324 | Tkx::update(); 2325 | } 2326 | } 2327 | if ($autorun_var eq "on") { 2328 | $Registry->{'HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Run/Cryptostorm client'}="$self"; 2329 | } 2330 | if ($autorun_var eq "off") { 2331 | delete $Registry->{"HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Run/Cryptostorm client"}; 2332 | } 2333 | if (($autocon_var eq "on") && (!$saveoption) || ($saveoption eq "off")) { 2334 | $saveoption = "on"; 2335 | } 2336 | Tkx::update(); 2337 | if (($killswitch_var eq "on") && ($adv_socks_opt eq "on")) { 2338 | Tkx::tk___messageBox(-icon => "info", -message => "The killswitch will be disabled since a SOCKS proxy is being used"); 2339 | $killswitch_var = "off"; 2340 | } 2341 | &savelogin; 2342 | Tkx::update(); 2343 | if ($killswitch_var ne $tmp_killswitch_var) { 2344 | if ($killswitch_var eq "off") { 2345 | Tkx::update(); 2346 | &killswitch_off; 2347 | Tkx::update(); 2348 | } 2349 | if ($killswitch_var eq "on") { 2350 | my $winfirecheck = `net start|findstr "Windows.*Firewall"`; 2351 | Tkx::update(); 2352 | if ($winfirecheck =~ /Windows.*Firewall/) { 2353 | &killswitch_on; 2354 | Tkx::update(); 2355 | } 2356 | else { 2357 | my $winfire = Tkx::tk___messageBox(-parent => $mw, -type => "yesno", 2358 | -message => $L->{$lang}{QUESTION_WINFIRE1} . " " . $L->{$lang}{QUESTION_WINFIRE2}, 2359 | -icon => "question", -title => "cryptostorm.is client"); 2360 | if ($winfire eq "yes") { 2361 | system("net start MpsSvc"); 2362 | &killswitch_on; 2363 | } 2364 | if ($winfire eq "no") { 2365 | $killswitch_var = "off"; 2366 | &killswitch_off; 2367 | } 2368 | } 2369 | } 2370 | } 2371 | $statusvar = $tmpvar; 2372 | Tkx::update(); 2373 | } 2374 | 2375 | sub check_version { 2376 | $o_done3 = 0; 2377 | if (defined($o_thread3)) { 2378 | $o_thread3->join() if $o_thread3->is_joinable(); 2379 | } 2380 | my $arg = $_[0] // undef; 2381 | $o_thread3 = defined($arg) ? threads->new(\&check_version_thread, $arg) : threads->new(\&check_version_thread); 2382 | $o_thread3->detach(); 2383 | while (!$o_done3) { 2384 | Tkx::update(); 2385 | select(undef,undef,undef,0.001); 2386 | } 2387 | } 2388 | 2389 | sub check_version_thread { 2390 | my $oncs = $_[0]; 2391 | my ($ua,$response); 2392 | my @headers = ('User-Agent' => "Cryptostorm client"); 2393 | $ua = LWP::UserAgent->new(agent => "Cryptostorm client"); 2394 | $ua->timeout(3); 2395 | $response = $ua->get("http://10.31.33.7/latest.txt", @headers); 2396 | if ($response->is_success()) { 2397 | if ($response->content() =~ /LATEST:([0-9\.]+)/) { 2398 | $o_version_buf = $1; 2399 | } 2400 | if ($response->content() =~ /MSG:ON:(.*)/) { 2401 | if ($response->content() !~ /31MSG:ON:(.*)/) { 2402 | $amsg = $1; 2403 | } 2404 | } 2405 | my $upgradeornot; 2406 | if ((!$o_version_buf) && (!$amsg)) { 2407 | $o_version_buf = -1; 2408 | } 2409 | } 2410 | else { 2411 | $o_version_buf = -1; 2412 | } 2413 | } 2414 | 2415 | sub callback { 2416 | my ($data, $response, $protocol) = @_; 2417 | print $fh $data; 2418 | $final_data .= $data; 2419 | $statusvar =~ s/ \[.*//; 2420 | $statusvar = "$statusvar [" . progress_bar( length($final_data), $total_size ) . "]"; 2421 | Tkx::update(); 2422 | chop($statusvar); chop($statusvar); 2423 | chop($statusvar); chop($statusvar); 2424 | } 2425 | 2426 | sub grabnverify { 2427 | $cancel->configure(-state => "disabled"); 2428 | $final_data = undef; 2429 | my $file_to_grab; 2430 | if ($_[0] =~ /\/(.*)$/) { 2431 | $file_to_grab = $1; 2432 | } 2433 | if (!-d "tmp") { mkdir "tmp"; } 2434 | my $ua = LWP::UserAgent->new( ); 2435 | my $url = "http://10.31.33.7/" . $file_to_grab; 2436 | my $response = $ua->head($url); 2437 | my $remote_headers = $response->headers; 2438 | $total_size = $remote_headers->content_length; 2439 | $ua = LWP::UserAgent->new; 2440 | binmode STDOUT,':raw'; 2441 | open $fh, '>', "tmp\\$file_to_grab" or &do_error("\n" . $L->{$lang}{ERR_CREATE} . " tmp\\$file_to_grab: $!\n"); 2442 | binmode $fh; 2443 | $response = $ua->get($url, ':content_cb' => \&callback ); 2444 | if ($total_size == length($final_data)) { 2445 | $statusvar = $L->{$lang}{TXT_DOWNLOADED} . " $file_to_grab"; 2446 | Tkx::update(); 2447 | close $fh; 2448 | } 2449 | else { 2450 | &do_error($L->{$lang}{ERR_DOWNLOAD} . " http://10.31.33.7/$file_to_grab: " . $response->status_line . "\n"); 2451 | $cancel->configure(-state => "normal"); 2452 | return; 2453 | } 2454 | undef $ua; 2455 | undef $response; 2456 | undef $fh; 2457 | undef $final_data; 2458 | $ua = LWP::UserAgent->new; 2459 | binmode STDOUT,':raw'; 2460 | open $fh, '>', "tmp\\$file_to_grab.hash" or &do_error("\n" . $L->{$lang}{ERR_CREATE} . " tmp\\$file_to_grab: $!\n"); 2461 | binmode $fh; 2462 | $response = $ua->get($url . ".hash", ':content_cb' => \&callback ); 2463 | if ($response->is_success) { 2464 | $statusvar = $L->{$lang}{TXT_DOWNLOADED} . " $file_to_grab"; 2465 | Tkx::update(); 2466 | close $fh; 2467 | } 2468 | else { 2469 | &do_error($L->{$lang}{ERR_DOWNLOAD} . " http://10.31.33.7/$file_to_grab.hash: " . $response->status_line . "\n"); 2470 | $cancel->configure(-state => "normal"); 2471 | return; 2472 | } 2473 | my $yayornay = `$osslexe dgst -sha512 -verify widget.pub -signature tmp\\$file_to_grab.hash tmp\\$file_to_grab 2>&1`; 2474 | if ($yayornay =~ /Verified OK/) { 2475 | $statusvar = $L->{$lang}{TXT_DOWNLOAD_VERIFIED}; 2476 | Tkx::update(); 2477 | } 2478 | else { 2479 | $statusvar = $L->{$lang}{ERR_VERIFY} . " - $file_to_grab"; 2480 | Tkx::update(); 2481 | &do_error($L->{$lang}{ERR_VERIFY} . " - $file_to_grab: $yayornay\n$osslexe dgst -sha512 -verify widget.pub -signature tmp\\$file_to_grab.hash tmp\\$file_to_grab"); 2482 | unlink("tmp\\$file_to_grab"); 2483 | } 2484 | $cancel->configure(-state => "normal"); 2485 | } 2486 | 2487 | sub dnscrypt { 2488 | my ($mode, $uninstall) = @_; # mode: 0 = stop, 1 = start 2489 | $uninstall ||= 0; 2490 | my $tmpstatusvar = $statusvar; 2491 | if ($mode == 0) { 2492 | $statusvar = $L->{$lang}{TXT_DNSCRYPT_STOPPING}; 2493 | Tkx::update(); 2494 | &dnscrypt_action('stop'); 2495 | if ($uninstall) { 2496 | $statusvar = $L->{$lang}{TXT_DNSCRYPT_UNINSTALLING}; 2497 | Tkx::update(); 2498 | &dnscrypt_action('uninstall'); 2499 | } 2500 | $statusvar = $L->{$lang}{TXT_DNS_RESTORE}; 2501 | Tkx::update(); 2502 | &restore_dns; 2503 | } 2504 | elsif ($mode == 1) { 2505 | unless (&dnscrypt_installed()) { 2506 | $statusvar = $L->{$lang}{TXT_DNSCRYPT_INSTALLING}; 2507 | Tkx::update(); 2508 | unless (&dnscrypt_action('install')) { 2509 | return; 2510 | } 2511 | } 2512 | $statusvar = $L->{$lang}{TXT_DNSCRYPT_STARTING}; 2513 | Tkx::update(); 2514 | unless (&dnscrypt_action('start')) { 2515 | return; 2516 | } 2517 | $statusvar = $L->{$lang}{TXT_SET_DNS_DNSCRYPT}; 2518 | Tkx::update(); 2519 | &set_dns_to_dnscrypt; 2520 | } 2521 | system(1, "ipconfig /registerdns"); 2522 | $statusvar = $tmpstatusvar; 2523 | Tkx::update(); 2524 | } 2525 | 2526 | sub dnscrypt_action { 2527 | my ($action) = @_; 2528 | my $cmd = "\"$dnscexe\" -service $action"; 2529 | my $output = `$cmd 2>&1`; 2530 | if (($action eq "stop") || ($action eq "uninstall")) { 2531 | return 1; 2532 | } 2533 | if ($output =~ /\[FATAL\]/i) { 2534 | if ($output !~ /already running/) { 2535 | &do_error("dnscrypt '$action' failed:\n$output"); 2536 | $dnscrypt_var = "off"; 2537 | return 0; 2538 | } 2539 | else { 2540 | return 1; 2541 | } 2542 | } 2543 | if ($output =~ /\[NOTICE\]/i) { 2544 | return 1; 2545 | } 2546 | # Default fallback if we can't determine outcome 2547 | &do_error("dnscrypt '$action' returned unknown output:\n$output"); 2548 | $dnscrypt_var = "off"; 2549 | return 0; 2550 | } 2551 | 2552 | sub dnscrypt_installed { 2553 | my %services; 2554 | Win32::Service::GetServices('', \%services); 2555 | return grep { $_ =~ /dnscrypt/i } values %services; 2556 | } 2557 | 2558 | sub power_event { 2559 | my ($win, @args) = @_; 2560 | if ($args[0] eq PBT_APMSUSPEND) { 2561 | # suspending, so disconnect if connected 2562 | if ($cancel->cget(-text) eq $L->{$lang}{TXT_DISCONNECT}) { 2563 | &restore_dns; 2564 | $iwasconnected = 1; 2565 | $stop = 1; 2566 | $o_done3 = 1; 2567 | $pbarval = 0; 2568 | $showtiponce = 0; 2569 | $statusvar = $L->{$lang}{TXT_DISCONNECTED}; 2570 | $cancel->configure(-text => $L->{$lang}{TXT_EXIT}); 2571 | $update->configure(-state => "normal"); 2572 | $options->configure(-state => "normal"); 2573 | $connect->configure(-state => "normal"); 2574 | $server_textbox->configure(-state => "readonly"); 2575 | $logbox->insert_end("\n\n\n\n\n\n\n\n\n\n\n"); 2576 | $logbox->insert_end($L->{$lang}{TXT_SUSPENDING} . "...\n"); 2577 | $logbox->insert_end($L->{$lang}{TXT_DISCONNECTED} . "\n", "badline"); 2578 | $logbox_index = $logbox->search(-regexp, '^' . $L->{$lang}{TXT_CONNECTED} . '$',"insert"); 2579 | if (defined($logbox_index)) { 2580 | if ($logbox_index =~ /[0-9\.]+/) { 2581 | $logbox->delete($logbox_index,sprintf("%.1f", ($logbox_index+1))); 2582 | } 2583 | } 2584 | $logbox->see('end'); 2585 | &shutdown_openvpn(); 2586 | $cancel->configure(-state => "normal"); 2587 | } 2588 | } 2589 | if (($args[0] eq PBT_APMRESUMEAUTOMATIC) || ($args[0] eq PBT_APMRESUMECRITICAL)) { 2590 | # resuming from suspend, so reconnect if client was connected before suspend 2591 | if ($iwasconnected) { 2592 | $worldimage->configure(-image => "mainicon"); 2593 | if ($dnscrypt_var eq "on") { 2594 | &dnscrypt(1); 2595 | } 2596 | $connect->invoke(); 2597 | $iwasconnected = 0; 2598 | } 2599 | } 2600 | } 2601 | 2602 | sub restore_dns { 2603 | my $tmpstatusvarblah = $statusvar; 2604 | Tkx::update(); 2605 | for (@recover) { 2606 | Tkx::update(); 2607 | if (/^(.*):DHCP:/) { 2608 | if ($1 !~ /NameServer/) { 2609 | $Registry->{"HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/$1/NameServer"} = ""; 2610 | $statusvar = $L->{$lang}{TXT_DNS_RESTORE}; 2611 | Tkx::update(); 2612 | } 2613 | } 2614 | if (/^(.*):Static:(.*)$/) { 2615 | if ($2 !~ /127\.0\.0\.1/) { 2616 | if ($1 !~ /NameServer/) { 2617 | $Registry->{"HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/$1/NameServer"} = "$2"; 2618 | $statusvar = $L->{$lang}{TXT_DNS_RESTORE} . " ($2)"; 2619 | Tkx::update(); 2620 | } 2621 | } 2622 | else { 2623 | if ($1 !~ /NameServer/) { 2624 | $Registry->{"HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/$1/NameServer"} = ""; 2625 | $statusvar = $L->{$lang}{TXT_DNS_RESTORE} . " (DHCP)"; 2626 | Tkx::update(); 2627 | } 2628 | } 2629 | } 2630 | } 2631 | Tkx::update(); 2632 | if (-e "..\\user\\mydns.txt") { 2633 | unlink("..\\user\\mydns.txt"); 2634 | } 2635 | $statusvar = $tmpstatusvarblah; 2636 | Tkx::update(); 2637 | } 2638 | 2639 | sub is_dnscrypt_running { 2640 | my $output = `sc query "dnscrypt-proxy"`; 2641 | if ($output =~ /STATE\s*:\s*\d+\s+(RUNNING|START_PENDING)/i) { 2642 | return 1; 2643 | } else { 2644 | return 0; 2645 | } 2646 | } 2647 | 2648 | sub set_dns_to_dnscrypt { 2649 | my $tmpstatusvar = $statusvar; 2650 | my $makesurednscryptisrunning = 0; 2651 | if (&is_dnscrypt_running()) { 2652 | my $interfaces = $Registry->{'HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/'}; 2653 | foreach (keys %$interfaces) { 2654 | my $GUID = $_; 2655 | next if $GUID =~ /NameServer/; 2656 | $GUID =~ s/\/$//; 2657 | my $key = "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/$GUID/NameServer"; 2658 | $Registry->{$key} = "127.0.0.1"; 2659 | $statusvar = $L->{$lang}{TXT_SET_DNS_DNSCRYPT}; 2660 | Tkx::update(); 2661 | } 2662 | } 2663 | $statusvar = $tmpstatusvar; 2664 | Tkx::update(); 2665 | } 2666 | 2667 | sub get_current_dns { 2668 | my $interfaces = $Registry->{'HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/'}; 2669 | 2670 | foreach (keys %$interfaces) { 2671 | Tkx::update(); 2672 | my $GUID = $_; 2673 | next if $GUID =~ /NameServer/; 2674 | 2675 | $GUID =~ s/\/$//; 2676 | my $key = "HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/$GUID/NameServer"; 2677 | my $intdns = $Registry->{$key}; 2678 | 2679 | if (defined $intdns) { 2680 | if ($intdns =~ /127\.0\.0\.1/) { 2681 | if ($dnscrypt_var eq "off") { 2682 | $Registry->{$key} = ""; 2683 | system(1, "ipconfig /registerdns"); 2684 | Tkx::update(); 2685 | } 2686 | push(@recover, "$GUID:DHCP:\n"); 2687 | } else { 2688 | push(@recover, "$GUID:Static:$intdns\n"); 2689 | } 2690 | } else { 2691 | push(@recover, "$GUID:DHCP:\n"); 2692 | } 2693 | } 2694 | 2695 | if (@recover) { 2696 | if (open my $fh, '>', "..\\user\\mydns.txt") { 2697 | print $fh @recover; 2698 | close $fh; 2699 | } 2700 | } 2701 | } 2702 | 2703 | sub wait4thekill { 2704 | Tkx::update(); 2705 | my $runthis = system 1, qq($_[0]); 2706 | my $last_update = time; 2707 | while (kill(0, $runthis) == 1) { 2708 | Tkx::update(); 2709 | select(undef, undef, undef, 0.01); 2710 | if (time - $last_update >= 0.5) { 2711 | $statusvar .= "." if $statusvar =~ /\.\.$/; 2712 | Tkx::update(); 2713 | $last_update = time; 2714 | } 2715 | Tkx::update(); 2716 | } 2717 | Tkx::update(); 2718 | } 2719 | 2720 | sub blue_derp { 2721 | $worldimage->configure(-image => "mainicon"); 2722 | $derp = 0; 2723 | for ($derp=1;$derp<=6;$derp++) { 2724 | $worldimage->configure(-image => "b$derp"); 2725 | Tkx::update(); 2726 | select(undef,undef,undef,0.049); 2727 | } 2728 | for ($derp=6;$derp>=1;$derp--) { 2729 | $worldimage->configure(-image => "b$derp"); 2730 | Tkx::update(); 2731 | select(undef,undef,undef,0.049); 2732 | } 2733 | $worldimage->configure(-image => "mainicon"); 2734 | } 2735 | 2736 | sub green_derp { 2737 | $worldimage->configure(-image => "mainicon"); 2738 | for ($derp=1;$derp<=6;$derp++) { 2739 | $worldimage->configure(-image => "g$derp"); 2740 | Tkx::update(); 2741 | select(undef,undef,undef,0.049); 2742 | } 2743 | for ($derp=6;$derp>=1;$derp--) { 2744 | $worldimage->configure(-image => "g$derp"); 2745 | Tkx::update(); 2746 | select(undef,undef,undef,0.049); 2747 | } 2748 | $worldimage->configure(-image => "mainicon"); 2749 | } 2750 | 2751 | sub red_derp { 2752 | $worldimage->configure(-image => "mainicon"); 2753 | for ($derp=1;$derp<=6;$derp++) { 2754 | $worldimage->configure(-image => "r$derp"); 2755 | Tkx::update(); 2756 | select(undef,undef,undef,0.049); 2757 | } 2758 | for ($derp=6;$derp>=1;$derp--) { 2759 | $worldimage->configure(-image => "r$derp"); 2760 | Tkx::update(); 2761 | select(undef,undef,undef,0.049); 2762 | } 2763 | $worldimage->configure(-image => "mainicon"); 2764 | } 2765 | 2766 | sub do_error { 2767 | my $error = $_[0]; 2768 | $worldimage->g_grid_remove() unless !defined($worldimage); 2769 | $errorimage->g_grid(-column => 0, -row => 0) unless !defined($errorimage); 2770 | Tkx::tk___messageBox(-icon => "error", -message => "Error: $error"); 2771 | $errorimage->g_grid_remove() unless !defined($errorimage); 2772 | $worldimage->g_grid(-column => 0, -row => 0) unless !defined($worldimage); 2773 | $options->configure(-state => "normal") unless !defined($options); 2774 | if (defined($autocon_var) && ($autocon_var eq "on")) { 2775 | $statusvar = $L->{$lang}{ERR_AUTO_CONNECT}; 2776 | $autocon_var = "off"; 2777 | &savelogin; 2778 | } 2779 | return; 2780 | } 2781 | 2782 | sub isEmpty { 2783 | return undef unless -d $_[0]; 2784 | opendir my $dh, $_[0] or print $!; 2785 | my $count = grep { ! /^\.{1,2}/ } readdir $dh; 2786 | return $count; 2787 | } 2788 | 2789 | sub local_port_is_free { 2790 | my ($portnumber) = @_; 2791 | my $proto = getprotobyname('tcp'); 2792 | my $iaddr = inet_aton('127.0.0.1'); 2793 | my $timeout = 5; 2794 | my $freeport = 0; 2795 | my $paddr = sockaddr_in($portnumber, $iaddr); 2796 | Tkx::update(); 2797 | socket(SOCKET, PF_INET, SOCK_STREAM, $proto); 2798 | Tkx::update(); 2799 | eval { 2800 | local $SIG{ALRM} = sub { &do_error($L->{$lang}{TXT_TIMEOUT}); }; 2801 | alarm($timeout); 2802 | Tkx::update(); 2803 | connect(SOCKET, $paddr) || error(); 2804 | Tkx::update(); 2805 | }; 2806 | if ($@) { 2807 | eval {close SOCKET; }; 2808 | $freeport = $portnumber; 2809 | } 2810 | else { 2811 | eval {close SOCKET; }; 2812 | } 2813 | alarm(0); 2814 | return $freeport; 2815 | } 2816 | 2817 | sub get_next_free_local_port { 2818 | my ($startport) = @_; 2819 | my $freeport = 0; 2820 | my $tryport = $startport; 2821 | while(not $freeport = &local_port_is_free($tryport) ) { 2822 | $tryport++; 2823 | &do_error($L->{$lang}{ERR_NO_FREE_PORT}) if $tryport > ($startport + 100); 2824 | } 2825 | return $freeport; 2826 | } 2827 | 2828 | sub progress_bar { 2829 | my ($got, $total) = @_; 2830 | sprintf "%.2f%%", 100*$got/+$total; 2831 | } 2832 | 2833 | sub killswitch_on { 2834 | $update->configure(-state => "disabled"); 2835 | $options->configure(-state => "disabled"); 2836 | $connect->configure(-state => "disabled"); 2837 | $cancel->configure(-state => "disabled"); 2838 | Tkx::update(); 2839 | 2840 | my $tmpbar = $statusvar; 2841 | # Backup current rules 2842 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_EXPORTING_RULES}; 2843 | Tkx::update(); 2844 | if ( ! -f "..\\user\\all.wfw") { 2845 | $rt = `netsh advfirewall export "..\\user\\all.wfw" 2>&1`; 2846 | if ($rt !~ /Ok./i) { 2847 | &do_error($L->{$lang}{ERR_KILLSWITCH_EXPORT} . ": $rt"); 2848 | } 2849 | } 2850 | 2851 | # Clear existing rules 2852 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_CLEARING_EXISTING_RULES}; 2853 | Tkx::update(); 2854 | &del_fw_rule("all"); 2855 | 2856 | # Set all profiles to block everything in and out 2857 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_BLOCKING_EVERYTHING}; 2858 | Tkx::update(); 2859 | $rt = `netsh advfirewall set privateprofile firewallpolicy blockinbound,blockoutbound`; 2860 | $rt = `netsh advfirewall set domainprofile firewallpolicy blockinbound,blockoutbound`; 2861 | $rt = `netsh advfirewall set publicprofile firewallpolicy blockinbound,blockoutbound`; 2862 | # Disable notifications 2863 | $rt = `netsh advfirewall set allprofiles settings inboundusernotification disable`; 2864 | 2865 | # Allow DHCP 2866 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_WHITELISTING_DHCP}; 2867 | Tkx::update(); 2868 | &add_fw_rule( 2869 | "cryptostorm - Allow DHCP", 2870 | "out", 2871 | q{program="%SystemRoot%\\system32\\svchost.exe" localip=0.0.0.0 localport=68 remoteip=255.255.255.255 remoteport=67 protocol=UDP} 2872 | ); 2873 | 2874 | # Allow Local Network Access 2875 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_ALLOWING_LAN}; 2876 | Tkx::update(); 2877 | &add_fw_rule("cryptostorm - Allow LAN", "in", "remoteip=LocalSubnet"); 2878 | &add_fw_rule("cryptostorm - Allow LAN", "out", "remoteip=LocalSubnet"); 2879 | 2880 | # Allow programs this client uses 2881 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_WHITELISTING_PROGRAMS}; 2882 | Tkx::update(); 2883 | my @whitelisted_programs; 2884 | if ($bit == 32) { 2885 | @whitelisted_programs = ( 2886 | 'C:\\Program Files\\Cryptostorm Client\\bin\\csvpn.exe', 2887 | 'C:\\Program Files\\Cryptostorm Client\\bin\\cs-dnsc-p.exe', 2888 | 'C:\\Program Files\\Cryptostorm Client\\bin\\cs-https-tun.exe', 2889 | 'C:\\Program Files\\Cryptostorm Client\\bin\\cs-ssh-tun.exe' 2890 | ); 2891 | } 2892 | else { 2893 | @whitelisted_programs = ( 2894 | 'C:\\Program Files (x86)\\Cryptostorm Client\\bin\\csvpn.exe', 2895 | 'C:\\Program Files (x86)\\Cryptostorm Client\\bin\\cs-dnsc-p.exe', 2896 | 'C:\\Program Files (x86)\\Cryptostorm Client\\bin\\cs-https-tun.exe', 2897 | 'C:\\Program Files (x86)\\Cryptostorm Client\\bin\\cs-ssh-tun.exe' 2898 | ); 2899 | } 2900 | 2901 | foreach my $program (@whitelisted_programs) { 2902 | &add_fw_rule("cryptostorm - Allow CS programs", "out", qq{program="$program" service=any}); 2903 | &add_fw_rule("cryptostorm - Allow CS programs", "in", qq{program="$program" service=any}); 2904 | } 2905 | 2906 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_ALLOWING_PRECONNECT_DNS}; 2907 | Tkx::update(); 2908 | &add_fw_rule("cryptostorm - Allow pre-connect DNS", "out", "protocol=UDP remoteport=53"); 2909 | &add_fw_rule("cryptostorm - Allow pre-connect DNS", "out", "protocol=TCP remoteport=53"); 2910 | 2911 | # Resolve VPN endpoints 2912 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_RESOLVING_ENDPOINTS}; 2913 | Tkx::update(); 2914 | &preresolve("balancer.cstorm.is"); 2915 | 2916 | if ($#resolved_ips < 1) { 2917 | $statusvar = $L->{$lang}{TXT_NOT_CONNECTED}; 2918 | $pbarval = 0; 2919 | $cancel->configure(-state => "normal", -text => $L->{$lang}{TXT_EXIT}); 2920 | $connect->configure(-state => "normal"); 2921 | $update->configure(-state => "normal"); 2922 | $options->configure(-state => "normal"); 2923 | $server_textbox->configure(-state => "readonly"); 2924 | $worldimage->configure(-image => "mainicon"); 2925 | alarm 0; 2926 | return; 2927 | } 2928 | 2929 | # Allow VPN server IPs 2930 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_WHITELISTING_VPN_IPS}; 2931 | Tkx::update(); 2932 | my @ip_batches; 2933 | my $batch_size = 20; 2934 | while (@resolved_ips) { 2935 | my @batch = splice(@resolved_ips, 0, $batch_size); 2936 | push @ip_batches, join(",", @batch); 2937 | } 2938 | 2939 | foreach my $batch (@ip_batches) { 2940 | add_fw_rule("cryptostorm - Allow VPN IPs", "out", "remoteip=$batch"); 2941 | } 2942 | 2943 | # Allow cryptostorm.is / .nu 2944 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_WHITELISTING_STATIC_IPS}; 2945 | Tkx::update(); 2946 | my $csis_ipv4 = "46.165.221.100"; 2947 | my $csis_ipv6 = "2a00:c98:2030:a005:feed:df:c0ff:eeee"; 2948 | my $csnu_ipv4 = "46.165.221.67"; 2949 | my $csnu_ipv6 = "2a00:c98:2030:a005:c0ff:eeee:eeee:eeee"; 2950 | 2951 | add_fw_rule("cryptostorm - Allow cryptostorm.is and .nu", "out", "remoteip=$csnu_ipv4,$csnu_ipv6,$csis_ipv4,$csis_ipv6"); 2952 | 2953 | # Allow VPN server's internal DNS servers (disabled initially) 2954 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_ADDING_VPN_DNS_RULES}; 2955 | Tkx::update(); 2956 | add_fw_rule("cryptostorm - Allow internal VPN DNS", "out", "remoteip=10.31.33.7,10.31.33.8,2001:db8::7,2001:db8::8 enable=no"); 2957 | 2958 | # Allow internal VPN IPs (disabled initially, assigned later) 2959 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_ADDING_INTERNAL_VPN_IP_RULES}; 2960 | Tkx::update(); 2961 | add_fw_rule("cryptostorm - Allow internal IPv4 in", "out", "remoteip=any enable=no"); 2962 | add_fw_rule("cryptostorm - Allow internal IPv4 out", "out", "remoteip=any enable=no"); 2963 | add_fw_rule("cryptostorm - Allow internal IPv6 in", "out", "remoteip=any enable=no"); 2964 | add_fw_rule("cryptostorm - Allow internal IPv6 out", "out", "remoteip=any enable=no"); 2965 | add_fw_rule("cryptostorm - Allow internal IPv4 gateway in", "out", "remoteip=any enable=no"); 2966 | add_fw_rule("cryptostorm - Allow internal IPv4 gateway out", "out", "remoteip=any enable=no"); 2967 | add_fw_rule("cryptostorm - Allow internal IPv6 gateway in", "out", "remoteip=any enable=no"); 2968 | add_fw_rule("cryptostorm - Allow internal IPv6 gateway out", "out", "remoteip=any enable=no"); 2969 | 2970 | # Restore UI 2971 | $statusvar = $tmpbar; 2972 | $update->configure(-state => "normal"); 2973 | $options->configure(-state => "normal"); 2974 | $connect->configure(-state => "normal"); 2975 | $cancel->configure(-state => "normal"); 2976 | Tkx::update(); 2977 | } 2978 | 2979 | sub toggle_fw_rule { 2980 | my ($rule_name,$toggle) = @_; 2981 | $toggle = $toggle eq "on" ? "yes" : $toggle eq "off" ? "no" : $toggle; 2982 | my $cmd = qq{netsh advfirewall firewall set rule name="$rule_name" new enable=$toggle 2>&1}; 2983 | my $status = system($cmd); 2984 | if ($status != 0) { 2985 | &do_error($L->{$lang}{ERR_KILLSWITCH_FW_TOGGLE} . ": $rule_name\nCommand: $cmd\nExit code: $status"); 2986 | } 2987 | } 2988 | 2989 | sub add_fw_rule { 2990 | my ($rule_name, $dir, $extra_args) = @_; 2991 | my $cmd = qq{netsh advfirewall firewall add rule name="$rule_name" dir=$dir action=allow $extra_args 2>&1}; 2992 | my $rt = `$cmd`; 2993 | if ($rt !~ /Ok./i) { 2994 | &do_error($L->{$lang}{ERR_KILLSWITCH_FW_ADD} . ": $rule_name (dir=$dir)\nCommand: $cmd\nError: $rt"); 2995 | } 2996 | } 2997 | 2998 | sub del_fw_rule { 2999 | my ($rule_name) = @_; 3000 | my $cmd = qq{netsh advfirewall firewall del rule name="$rule_name" 2>&1}; 3001 | my $rt = `$cmd`; 3002 | if ($rt !~ /Ok./i) { 3003 | &do_error($L->{$lang}{ERR_KILLSWITCH_FW_DEL} . ": $rule_name\nCommand: $cmd\nError: $rt"); 3004 | } 3005 | } 3006 | 3007 | sub killswitch_off { 3008 | my $tmpbar = $statusvar; 3009 | $update->configure(-state => "disabled"); 3010 | $options->configure(-state => "disabled"); 3011 | $connect->configure(-state => "disabled"); 3012 | $cancel->configure(-state => "disabled"); 3013 | Tkx::update(); 3014 | if ((-e "..\\user\\all.wfw") || ($killswitch_var eq "on")) { 3015 | $rt = `netsh advfirewall import "..\\user\\all.wfw"`; 3016 | if ($rt =~ /Ok./) { 3017 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_IMPORTED_PREVIOUS_RULES}; 3018 | Tkx::update(); 3019 | } 3020 | $rt = `netsh advfirewall firewall show rule name="cryptostorm - Allow DHCP"`; 3021 | if ($rt =~ /cryptostorm/) { 3022 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_IS_ENABLED_DISABLING}; 3023 | Tkx::update(); 3024 | &del_fw_rule("cryptostorm - Allow cryptostorm.is and .nu"); 3025 | &del_fw_rule("cryptostorm - Allow CS programs"); 3026 | &del_fw_rule("cryptostorm - Allow DHCP"); 3027 | &del_fw_rule("cryptostorm - Allow internal IPv4 in"); 3028 | &del_fw_rule("cryptostorm - Allow internal IPv4 out"); 3029 | &del_fw_rule("cryptostorm - Allow internal IPv6 in"); 3030 | &del_fw_rule("cryptostorm - Allow internal IPv6 out"); 3031 | &del_fw_rule("cryptostorm - Allow internal IPv4 gateway in"); 3032 | &del_fw_rule("cryptostorm - Allow internal IPv4 gateway out"); 3033 | &del_fw_rule("cryptostorm - Allow internal IPv6 gateway in"); 3034 | &del_fw_rule("cryptostorm - Allow internal IPv6 gateway out"); 3035 | &del_fw_rule("cryptostorm - Allow internal VPN DNS"); 3036 | &del_fw_rule("cryptostorm - Allow LAN"); 3037 | &del_fw_rule("cryptostorm - Allow pre-connect DNS"); 3038 | &del_fw_rule("cryptostorm - Allow VPN IPs"); 3039 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_RULES_DELETED}; 3040 | Tkx::update(); 3041 | $rt = `netsh advfirewall set allprofiles settings inboundusernotification enable`; 3042 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_FW_NOTIFICATIONS_ENABLED}; 3043 | Tkx::update(); 3044 | $rt = `netsh advfirewall set allprofiles firewallpolicy BlockInbound,BlockOutbound`; 3045 | $statusvar = $L->{$lang}{TXT_KILLSWITCH_FW_PROFILE_POLICIES_RESTORED}; 3046 | Tkx::update(); 3047 | } 3048 | unlink("..\\user\\all.wfw"); 3049 | } 3050 | $statusvar = $tmpbar; 3051 | $update->configure(-state => "normal"); 3052 | $options->configure(-state => "normal"); 3053 | $connect->configure(-state => "normal"); 3054 | $cancel->configure(-state => "normal"); 3055 | Tkx::update(); 3056 | } 3057 | 3058 | sub isoncs { 3059 | return 0 unless defined $manport && defined $manpass; 3060 | return 0 if ($cancel->cget(-text) eq $L->{$lang}{TXT_EXIT}); 3061 | my $sock = IO::Socket::INET->new(PeerHost => '127.0.0.1', 3062 | PeerPort => $manport, 3063 | Proto => 'tcp', 3064 | Timeout => 2) or return 0; 3065 | print $sock "$manpass\r\n"; 3066 | my $is_connected = 0; 3067 | while (my $line = <$sock>) { 3068 | if ($line =~ /INFO:OpenVPN Management Interface Version/) { 3069 | print $sock "state\r\n"; 3070 | while (my $resp = <$sock>) { 3071 | if ($resp =~ /CONNECTED,SUCCESS/) { 3072 | $is_connected = 1; 3073 | last; 3074 | } 3075 | last if $resp =~ /^END/; 3076 | } 3077 | last; 3078 | } 3079 | } 3080 | eval { 3081 | local $SIG{ALRM} = sub { die "timeout\n" }; 3082 | alarm(0.3); 3083 | <$sock>; # This should hit EOF if OpenVPN exits 3084 | alarm(0); 3085 | }; 3086 | print $sock "exit\r\n" unless $@ =~ /timeout/; 3087 | close($sock); 3088 | return $is_connected; 3089 | } 3090 | 3091 | 3092 | sub genpass { 3093 | # generate a random password for the management interface 3094 | my @chars = ('a' .. 'z', '0' ..'9', 'A' .. 'Z'); 3095 | return join '' => map $chars[rand @chars], 0 .. int(rand(100))+20; 3096 | } 3097 | 3098 | sub preresolve { 3099 | my ($host) = @_; 3100 | our @resolved_ips; 3101 | 3102 | my $max_tries = 3; 3103 | my $attempt = 0; 3104 | 3105 | ATTEMPT: 3106 | while ($attempt++ < $max_tries) { 3107 | Tkx::update(); 3108 | @resolved_ips = (); 3109 | 3110 | my $pipe; 3111 | if (open($pipe, "-|", "nslookup $host 2>&1")) { 3112 | my $collect = 0; 3113 | my $last_update = time; 3114 | 3115 | while (my $line = <$pipe>) { 3116 | chomp $line; 3117 | Tkx::update(); 3118 | if (time - $last_update >= 0.5) { 3119 | $statusvar .= "."; 3120 | Tkx::update(); 3121 | $last_update = time; 3122 | } 3123 | 3124 | if ($line =~ /^\s*Addresses?:\s*/) { 3125 | $collect = 1; 3126 | if ($line =~ /:\s*([0-9a-fA-F:.]+)/) { 3127 | push @resolved_ips, $1; 3128 | } 3129 | next; 3130 | } 3131 | 3132 | next unless $collect; 3133 | 3134 | if ($line =~ /^\s*([0-9a-fA-F:.]+)\s*$/) { 3135 | push @resolved_ips, $1; 3136 | } 3137 | 3138 | Tkx::update(); 3139 | } 3140 | close $pipe; 3141 | } 3142 | 3143 | last ATTEMPT if @resolved_ips; 3144 | 3145 | $statusvar = "Error: failed to resolve $host, retrying"; 3146 | Tkx::update(); 3147 | 3148 | my $wait_time = 2; 3149 | my $start = time; 3150 | my $dot_time = time; 3151 | 3152 | while (time - $start < $wait_time) { 3153 | if (time - $dot_time >= 0.5) { 3154 | $statusvar .= "."; 3155 | Tkx::update(); 3156 | $dot_time = time; 3157 | } 3158 | select(undef, undef, undef, 0.05); # 50ms sleep 3159 | } 3160 | } 3161 | 3162 | if (@resolved_ips < 1) { 3163 | &do_error("nslookup failed to resolve $host"); 3164 | } 3165 | } 3166 | 3167 | sub confgen { 3168 | if ($disp_server ne $L->{$lang}{TXT_DEFAULT_SERVER}) { 3169 | my @actual_server = grep(/$disp_server/,@servers); 3170 | $server = $actual_server[0]; 3171 | $server = "" unless defined($actual_server[0]); 3172 | $server =~ s/.*://; 3173 | } 3174 | if (!$server) { 3175 | $server = $disp_server; 3176 | } 3177 | my @tmparray = grep(/$server/,@servers); 3178 | if (defined($tmparray[0])) { 3179 | my $tmpline = $tmparray[0]; 3180 | $tmpline =~ s/.*://; 3181 | $tmpline =~ s/\.cstorm\.is//; 3182 | @remote_random = ("$tmpline.cstorm.is", "$tmpline.cstorm.net", "$tmpline.cryptostorm.pw"); 3183 | } 3184 | if (($disp_server eq $L->{$lang}{TXT_DEFAULT_SERVER}) || ($server eq $L->{$lang}{TXT_DEFAULT_SERVER})) { 3185 | @remote_random = ("balancer.cstorm.is", "balancer.cstorm.net", "balancer.cryptostorm.pw"); 3186 | } 3187 | if (($tls_sel ne "secp521r1") && ($adv_https_opt eq "on")) { 3188 | $tls_sel = "secp521r1"; 3189 | } 3190 | my $tlscrypt = "--tls-crypt ..\\user\\tc.key"; 3191 | if (-e "..\\user\tcv2.key") { 3192 | $tlscrypt = "--tls-crypt-v2 ..\\user\\tcv2.key"; 3193 | } 3194 | if ($tls_sel eq 'secp521r1') { 3195 | $vpn_args = "$port_var --client --auth-nocache --auth-user-pass ..\\user\\client.dat --dev tun --resolv-retry 16 --remote-cert-tls server --down-pre --verb 6 --mute 3 --data-ciphers $cipher_sel --cipher $cipher_sel --tls-version-min 1.2 --tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384 --tls-cipher TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 --tls-client --ca ..\\user\\ca_secp521r1.crt $tlscrypt"; 3196 | } 3197 | if ($tls_sel eq 'Ed25519') { 3198 | $vpn_args = "5061 --client --auth-nocache --auth-user-pass ..\\user\\client.dat --dev tun --resolv-retry 16 --remote-cert-tls server --down-pre --verb 6 --mute 3 --data-ciphers $cipher_sel --cipher $cipher_sel --tls-version-min 1.2 --tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384 --tls-cipher TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 --tls-client --ca ..\\user\\ca_ed25519.crt $tlscrypt"; 3199 | } 3200 | if ($tls_sel eq 'Ed448') { 3201 | $vpn_args = "5062 --client --auth-nocache --auth-user-pass ..\\user\\client.dat --dev tun --resolv-retry 16 --remote-cert-tls server --down-pre --verb 6 --mute 3 --data-ciphers $cipher_sel --cipher $cipher_sel --tls-version-min 1.2 --tls-ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384 --tls-cipher TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 --tls-client --ca ..\\user\\ca_ed448.crt $tlscrypt"; 3202 | } 3203 | if ($tls_sel eq 'ML-DSA-87') { 3204 | $vpn_args = "5063 --client --auth-nocache --auth-user-pass ..\\user\\client.dat --dev tun --resolv-retry 16 --remote-cert-tls server --down-pre --verb 6 --mute 3 --data-ciphers AES-256-GCM --cipher AES-256-GCM --tls-version-min 1.2 --tls-ciphersuites TLS_AES_256_GCM_SHA384 --tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384 --tls-client --ca ..\\user\\ca_mldsa87.crt $tlscrypt"; 3205 | } 3206 | if ($proto_var eq 'UDP') { 3207 | if ($noipv6_var eq 'on') { 3208 | $vpn_args .= " --proto udp4 --explicit-exit-notify 3 "; 3209 | } 3210 | else { 3211 | $vpn_args .= " --proto udp --explicit-exit-notify 3 "; 3212 | } 3213 | } 3214 | if ($proto_var eq 'TCP') { 3215 | if ($noipv6_var eq 'on') { 3216 | $vpn_args .= " --proto tcp4 "; 3217 | } 3218 | else { 3219 | $vpn_args .= " --proto tcp "; 3220 | } 3221 | } 3222 | if ($dnsleak_var eq "on") { 3223 | $vpn_args .= " --block-outside-dns "; 3224 | } 3225 | if ($dnsleak_var eq "off") { 3226 | $vpn_args .= " --pull-filter ignore \"block-outside-dns\" "; 3227 | } 3228 | if ($killswitch_var eq "on") { 3229 | $vpn_args .= " --pull-filter ignore \"redirect-gateway def1\" "; 3230 | $vpn_args .= " --redirect-gateway "; 3231 | } 3232 | if ($noipv6_var eq "on") { 3233 | $vpn_args .= ' --block-ipv6 '; 3234 | } 3235 | if ($ts_var eq "on") { 3236 | $vpn_args .= " --pull-filter ignore \"dhcp-option DNS 10.31.33.8\" "; 3237 | $vpn_args .= " --pull-filter ignore \"dhcp-option DNS 2001:db8::8\" "; 3238 | $vpn_args .= ' --dhcp-option DNS 10.31.33.7 '; 3239 | if ($noipv6_var eq "off") { 3240 | $vpn_args .= ' --dhcp-option DNS 2001:db8::7 '; 3241 | } 3242 | } 3243 | $vpn_args .= ' --machine-readable-output '; 3244 | $vpn_args .= ' --windows-driver wintun'; 3245 | $vpn_args .= ' --dev-node "cryptostorm VPN" '; 3246 | if ($selected_adv_opt2 ne 'disabled') { 3247 | $vpn_args .= " --mssfix $selected_adv_opt2 "; 3248 | } 3249 | if ($selected_adv_opt3 ne 'adaptive') { 3250 | $vpn_args .= " --route-method $selected_adv_opt3 "; 3251 | } 3252 | if ($selected_adv_opt4 ne 'Any address') { 3253 | $vpn_args .= " --local $selected_adv_opt4 "; 3254 | } 3255 | if ($adv_socks_opt eq "on") { 3256 | if (($adv_socks_noauth_opt eq "on") || (($adv_socks_user_var eq "") && ($adv_socks_pass_var eq ""))) { 3257 | $vpn_args .= " --socks-proxy $adv_socks_ip $adv_socks_port "; 3258 | } 3259 | else { 3260 | open(SOCKS,">..\\user\\socks.dat"); 3261 | print SOCKS "$adv_socks_user_var\n"; 3262 | print SOCKS "$adv_socks_pass_var\n"; 3263 | close(SOCKS); 3264 | $vpn_args .= " --socks-proxy $adv_socks_ip $adv_socks_port ..\\user\\socks.dat "; 3265 | } 3266 | } 3267 | if ($adv_ssh_opt eq "on") { 3268 | my $oldstatus = $statusvar; 3269 | $statusvar = "Starting SSH tunnel..."; 3270 | Tkx::update(); 3271 | $local_tunnel_port = get_next_free_local_port(31337); 3272 | system(1,"echo n|cs-ssh-tun -pw sshtunnel -N -D $local_tunnel_port -l sshtunnel $selected_tunnel_opt"); 3273 | if (is_tunnel_up($local_tunnel_port) < 0) { 3274 | &do_error($L->{$lang}{ERR_TUNNEL}); 3275 | $adv_ssh_opt = "off"; 3276 | system(1,"taskkill /IM cs-ssh-tun.exe /F"); 3277 | } 3278 | else { 3279 | $vpn_args .= " --socks-proxy 127.0.0.1 $local_tunnel_port "; 3280 | } 3281 | $statusvar = $oldstatus; 3282 | Tkx::update(); 3283 | } 3284 | $manport = get_next_free_local_port(5000); 3285 | $manpass = &genpass; 3286 | open(MANPASS,">..\\user\\manpass.txt"); 3287 | print MANPASS "$manpass\n"; 3288 | close(MANPASS); 3289 | $vpn_args .= " --management 127.0.0.1 $manport ..\\user\\manpass.txt "; 3290 | my $random_node = $remote_random[rand @remote_random]; 3291 | if ($random_node !~ /balancer/) { 3292 | my $cn_host = $random_node; 3293 | $cn_host =~ s/\..*//; 3294 | $vpn_args .= qq( --verify-x509-name "cryptostorm $cn_host server" name ); 3295 | } 3296 | if ($adv_https_opt eq "on") { 3297 | my $oldstatus = $statusvar; 3298 | $statusvar = "Starting HTTPS tunnel..."; 3299 | Tkx::update(); 3300 | $local_tunnel_port = get_next_free_local_port(31337); 3301 | open(STUNNEL,">stunnel.conf"); 3302 | print STUNNEL "[openvpn]\n" . 3303 | "client = yes\n" . 3304 | "accept = 127.0.0.1:$local_tunnel_port\n" . 3305 | "connect = $random_node:443\n" . 3306 | "sni = $sni_input_val"; 3307 | close(STUNNEL); 3308 | my $confloc; 3309 | if (-d "\\Program Files\\Cryptostorm Client\\bin") { 3310 | $confloc = "\\Program Files\\Cryptostorm Client\\bin\\stunnel.conf"; 3311 | } 3312 | if (-d "\\Program Files (x86)\\Cryptostorm Client\\bin") { 3313 | $confloc = "\\Program Files (x86)\\Cryptostorm Client\\bin\\stunnel.conf"; 3314 | } 3315 | system(1,qq(cs-https-tun.exe "$confloc")); 3316 | if (is_tunnel_up($local_tunnel_port) < 0) { 3317 | &do_error($L->{$lang}{ERR_TUNNEL}); 3318 | $adv_https_opt = "off"; 3319 | system(1,"taskkill /IM cs-https-tun.exe /F"); 3320 | } 3321 | else { 3322 | $vpn_args =~ s/^[0-9]+/--remote 127.0.0.1 $local_tunnel_port /; 3323 | } 3324 | $statusvar = $oldstatus; 3325 | Tkx::update(); 3326 | } 3327 | else { 3328 | $vpn_args =~ s/^/--remote $random_node /; 3329 | } 3330 | $logfile = '..\\bin\\openvpn.log'; 3331 | unlink $logfile if -e $logfile; 3332 | $vpn_args .= " --log $logfile"; 3333 | } 3334 | 3335 | sub fix_dns { 3336 | %stupidstrictrefs = ( Tkx => \&{"Tkx::.t.n.f4.b_configure"} ); 3337 | &{ $stupidstrictrefs{'Tkx'} }(-state => "disabled"); 3338 | $dnscrypt_var = "off"; 3339 | my $interfaces = $Registry->{'HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/'}; 3340 | foreach (keys %$interfaces) { 3341 | my $GUID = $_; 3342 | if ($GUID !~ /NameServer/) { 3343 | $GUID =~ s/\/$//; 3344 | $Registry->{"HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/services/Tcpip/Parameters/Interfaces/$GUID/NameServer"} = ""; 3345 | } 3346 | } 3347 | system(1,"ipconfig /registerdns"); 3348 | Tkx::update(); 3349 | if (-e "..\\user\\mydns.txt") { 3350 | unlink("..\\user\\mydns.txt"); 3351 | } 3352 | @recover = (); 3353 | &{ $stupidstrictrefs{'Tkx'} }(-state => "normal"); 3354 | Tkx::update(); 3355 | Tkx::tk___messageBox(-parent => $cw, -type => "ok", 3356 | -message => "DNS for all network adapters has been set to DHCP\nand DNSCrypt has been disabled", 3357 | -icon => "info", -title => "cryptostorm.is client"); 3358 | } 3359 | 3360 | sub is_tunnel_up { 3361 | Tkx::update(); 3362 | if ($tunnel_check_counter == 100) { 3363 | return -1; 3364 | } 3365 | my ($portnumber) = @_; 3366 | my $proto = getprotobyname('tcp'); 3367 | my $iaddr = inet_aton('127.0.0.1'); 3368 | my $paddr = sockaddr_in($portnumber, $iaddr); 3369 | socket(SOCKET, PF_INET, SOCK_STREAM, $proto); 3370 | eval { 3371 | connect(SOCKET, $paddr) || die "connect"; 3372 | close(SOCKET); 3373 | }; 3374 | if ($@) { 3375 | $tunnel_check_counter++; 3376 | is_tunnel_up($portnumber); 3377 | } 3378 | else { 3379 | $tunnel_check_counter = 0; 3380 | return 1; 3381 | } 3382 | } 3383 | -------------------------------------------------------------------------------- /lang.txt: -------------------------------------------------------------------------------- 1 | ;To add another language, Russian for example, you would add a Russian = line to each entry: 2 | ;ERR_AUTH_FAIL 3 | ; English = Authorization failed 4 | ; Japanese = 認証失敗 5 | ; Swedish = Auktorisering misslyckades 6 | ; Russian = Авторизация не удалась 7 | ;Then continue to do the same for all the remaining text strings. There must be two spaces before the language name. 8 | ;You can also use the native script for the language name, such as 'Русский' instead of 'Russian'. 9 | ;New languages should be detected automatically, as long as every entry from ERR_AUTH_FAIL to TXT_WINTUN_STOPPED_AND_UNINSTALLED 10 | ;has translations for the new language. 11 | 12 | ERR_AUTH_FAIL 13 | English = Authorization failed 14 | Japanese = 認証失敗 15 | Swedish = Auktorisering misslyckades 16 | 17 | ERR_AUTO_CONNECT 18 | English = Autoconnect disabled due to error. Re-enable it in Options. 19 | Japanese = エラーによって自動接続機能は無効になりました。 「オプション」からリセットして下さい。 20 | Swedish = Auto-anslutning inaktiverad på grund av ett fel. Aktivera det i alternativ. 21 | 22 | ERR_RESOLVE 23 | English = Cannot resolve hostname 24 | Japanese = ホスト名を解決できません 25 | Swedish = Kan inte lösa värdnamnet 26 | 27 | ERR_OPEN 28 | English = Can't open 29 | Japanese = 開くことができません 30 | Swedish = Kan inte öppna 31 | 32 | ERR_WRITE 33 | English = Can't write to 34 | Japanese = ここに書き込むことができません: 35 | Swedish = Kan inte skriva till 36 | 37 | ERR_CONNECT_GENERIC 38 | English = Connected with errors 39 | Japanese = 接続できましたが、エラーが発生しました 40 | Swedish = Ansluten med fel 41 | 42 | ERR_CREATE 43 | English = Cannot create file 44 | Japanese = ファイル作成できません 45 | Swedish = Kan inte skapa fil 46 | 47 | ERR_DOWNLOAD 48 | English = Could not download 49 | Japanese = ダウンロードできませんでした 50 | Swedish = Kunde inte ladda ner 51 | 52 | ERR_NO_FREE_PORT 53 | English = Cannot find free port 54 | Japanese = 空いてるポートが見つかりませんでした 55 | Swedish = Kan inte hitta ledig port 56 | 57 | ERR_INVALID_SOCKS_IP 58 | English = Invalid IP specified for SOCKS proxy 59 | Japanese = SOCKSプロキシに無効なIPが指定されました 60 | Swedish = Ogiltig IP angiven för SOCKS-proxy 61 | 62 | ERR_INVALID_SOCKS_PORT 63 | English = Invalid SOCKS port 64 | Japanese = 無効なSOCKSポート 65 | Swedish = Ogiltig SOCKS-port 66 | 67 | ERR_INVALID_TOKEN1 68 | English = Token does not appear to be valid 69 | Japanese = このトークンは有効ではないように見えます 70 | Swedish = Token verkar inte vara giltigt 71 | 72 | ERR_INVALID_TOKEN2 73 | English = (Note that tokens include the dashes) 74 | Japanese = (ハイフンを省略しないようにご注意ください) 75 | Swedish = (Observera att tokens inkluderar bindestrecken) 76 | 77 | ERR_KILLSWITCH_EXPORT 78 | English = Failed to export rules: 79 | Japanese = ルールのエクスポートに失敗しました: 80 | Swedish = Misslyckades med att exportera regler: 81 | 82 | ERR_KILLSWITCH_FW_TOGGLE 83 | English = Failed to toggle firewall rule 84 | Japanese = ファイアウォールルールの切り替えに失敗しました 85 | Swedish = Misslyckades med att aktivera och växla brandväggsregel 86 | 87 | ERR_KILLSWITCH_FW_ADD 88 | English = Failed to add firewall rule 89 | Japanese = ファイアウォールルールの追加に失敗しました 90 | Swedish = Misslyckades med att lägga till brandväggsregel 91 | 92 | ERR_KILLSWITCH_FW_DEL 93 | English = Failed to delete firewall rule 94 | Japanese = ファイアウォールルールの削除に失敗しました 95 | Swedish = Misslyckades med att ta bort brandväggsregel 96 | 97 | ERR_MENU 98 | English = Creating Menu failed 99 | Japanese = メニュー初期化失敗 100 | Swedish = Skapa meny misslyckades 101 | 102 | ERR_NEED_ADMIN 103 | English = This program requires Administrator privileges 104 | Japanese = このプログラムは管理者特権が必要です 105 | Swedish = Det här programmet kräver administratörsbehörighet 106 | 107 | ERR_NO_TOKEN 108 | English = You didn't enter a token 109 | Japanese = トークンは入力されていません 110 | Swedish = Du skrev inte in ett token 111 | 112 | ERR_OLD_WIN 113 | English = This program only supports Windows Vista and later 114 | Japanese = このプログラムはWindows Vista以降のみをサポートします 115 | Swedish = Detta program stödjer endast Windows Vista och senare versioner 116 | 117 | ERR_INVALID_PORT 118 | English = Port needs to be a number between 1 and 29999. Ports 30000 and above are now reserved for port forwarding. 119 | Japanese = ポート番号は1から655334の間で選んで下さい。 120 | Swedish = Port-numret måste vara ett tal mellan 1 och 655334 121 | 122 | ERR_PORT_8443_RESERVED 123 | English = Error: port 8443 is reserved 124 | Japanese = エラー: ポート8443は予約されています 125 | Swedish = Fel: Port 8443 är reserverad 126 | 127 | ERR_TUNNEL 128 | English = Cannot start tunnel 129 | Japanese = トンネルを開始できません 130 | Swedish = Det gick inte att starta tunneln 131 | 132 | ERR_TUNNEL_DIFFERENT_HOST 133 | English = Tunnel host must be different from the selected VPN node 134 | Japanese = トンネルホストは選択したVPNノードとは異なる必要があります 135 | Swedish = Tunnelvärden måste vara en annan än den valda VPN-noden 136 | 137 | ERR_UPDATE_NODELIST 138 | English = Error downloading list from https://cryptostorm.nu/nodelist4.txt 139 | Japanese = https://cryptostorm.nu/nodelist4.txt からのダウンロード失敗 140 | Swedish = Fel vid nedladdning av lista från https://cryptostorm.nu/nodelist4.txt 141 | 142 | ERR_VERIFY 143 | English = File verification failed 144 | Japanese = ファイルの認証に失敗しました 145 | Swedish = Filverifiering misslyckades 146 | 147 | QUESTION_ANOTHERPROG1 148 | English = Another program is attempting to close the cryptostorm client. 149 | Japanese = 他のプログラムがcryptostormクライアントを終了させようとしています 150 | Swedish = Ett annat program försöker stänga cryptostorm-klienten. 151 | 152 | QUESTION_ANOTHERPROG2 153 | English = Do you want to allow this? 154 | Japanese = 許可しますか? 155 | Swedish = Vill du tillåta detta? 156 | 157 | QUESTION_ANOTHERPROG3 158 | English = (If you are upgrading using setup.exe, choose "Yes" here) 159 | Japanese = (setup.exeを実行してアップグレードするなら、ここに「はい」を選択して下さい) 160 | Swedish = (Om du uppgraderar genom setup.exe, välj "Ja" här) 161 | 162 | QUESTION_DISCONNECT1 163 | English = You are connected to Cryptostorm. 164 | Japanese = Cryptostormに接続されました 165 | Swedish = Du är ansluten till Cryptostorm. 166 | 167 | QUESTION_DISCONNECT2 168 | English = If you disconnect you will no longer be secured. 169 | Japanese = 切断すると通信は保護されなくなります 170 | Swedish = Om du kopplar ner kommer du inte längre vara säker. 171 | 172 | QUESTION_DISCONNECT3 173 | English = Are you sure you want to disconnect? 174 | Japanese = 本当に切断しますか? 175 | Swedish = Är du säker på att du vill koppla ner? 176 | 177 | QUESTION_KILLSWITCH1 178 | English = The kill switch is still enabled. 179 | Japanese = キルスウィッチはまだ有効しています 180 | Swedish = Killswitchen är fortfarande aktiverad. 181 | 182 | QUESTION_KILLSWITCH2 183 | English = Do you want to disable it? 184 | Japanese = 無効にしてもよろしい? 185 | Swedish = Vill du inaktivera detta? 186 | 187 | QUESTION_NEWVER1 188 | English = There is a new version available. 189 | Japanese = 新バージョンがあります 190 | Swedish = Det finns en ny version tillgänglig. 191 | 192 | QUESTION_NEWVER2 193 | English = Would you like to upgrade now? 194 | Japanese = アップグレードしますか? 195 | Swedish = Vill du uppgradera nu? 196 | 197 | QUESTION_ONLYONE1 198 | English = Only one instance of this program can be ran at a time. 199 | Japanese = このプログラムは一度に1つのインスタンスのみを実行できます。 200 | Swedish = Endast en instans av detta program kan köras åt gången. 201 | 202 | QUESTION_ONLYONE2 203 | English = Would you like to close the other instance? 204 | Japanese = 他のインスタンスを閉じてもよろしい? 205 | Swedish = Vill du avsluta den andra instansen? 206 | 207 | QUESTION_WINFIRE1 208 | English = The Windows Firewall service is turned off, and this killswitch requires it to be on. 209 | Japanese = キルスウィッチの操作がWindowsファイアウォールはオンに設定する必要ですが、今はオフです。 210 | Swedish = Windows-brandväggen är avstängd, och killswitchen kräver att den är på. 211 | 212 | QUESTION_WINFIRE2 213 | English = Would you like to turn on the Windows Firewall? Choosing No will disable the killswitch. 214 | Japanese = Windowsファイアウォールをオンにしますか?オンにしないと、キルスウィッチは無効になります。 215 | Swedish = Vill du aktivera Windows-brandväggen? Om du väljer Nej, stänger du av killswitchen. 216 | 217 | TXT_ADVANCED 218 | English = Advanced 219 | Japanese = 高度な 220 | Swedish = Avancerade 221 | 222 | TXT_ADVANCED_OPTIONS 223 | English = Advanced options 224 | Japanese = 詳細オプション 225 | Swedish = Avancerade alternativ 226 | 227 | TXT_AUTO_CONNECT 228 | English = Automatically connect 229 | Japanese = 自動的に接続 230 | Swedish = Anslut automatiskt 231 | 232 | TXT_AUTO_START 233 | English = Automatically start with Windows 234 | Japanese = 起動時にクライアントを開始する 235 | Swedish = Autostarta med Windows 236 | 237 | TXT_BACK 238 | English = Back 239 | Japanese = 戻る 240 | Swedish = Tillbaka 241 | 242 | TXT_CHECKING_TOKEN 243 | English = Checking token syntax 244 | Japanese = トークン構文を確認中... 245 | Swedish = Kontrollerar token syntax 246 | 247 | TXT_CONNECT 248 | English = Connect 249 | Japanese = 接続 250 | Swedish = Anslut 251 | 252 | TXT_CONNECTED 253 | English = Connected 254 | Japanese = 接続されました 255 | Swedish = Ansluten 256 | 257 | TXT_CONNECTING 258 | English = Connecting 259 | Japanese = 接続中 260 | Swedish = Ansluter 261 | 262 | TXT_CONNECT_PORT 263 | English = Connect to port 264 | Japanese = 接続しているポート番号 265 | Swedish = Ansluter till port 266 | 267 | TXT_CONNECT_PROTOCOL 268 | English = Connect with protocol 269 | Japanese = 接続するプロトコル 270 | Swedish = Anslut med protokoll 271 | 272 | TXT_CONNECT_TIMEOUT 273 | English = Connection timed out 274 | Japanese = 接続がタイムアウトしました 275 | Swedish = Anslutningen har nått sin tidsgräns 276 | 277 | TXT_COPY 278 | English = Copy 279 | Japanese = コピー 280 | Swedish = Kopiera 281 | 282 | TXT_DEFAULT_SERVER 283 | English = Global random 284 | Japanese = グローバル・ランダム 285 | Swedish = Global slumpad 286 | 287 | TXT_DISABLE_IPV6 288 | English = Disable IPv6 289 | Japanese = IPv6を無効にする 290 | Swedish = Inaktivera IPv6 291 | 292 | TXT_DISABLING_IPV6 293 | English = Disabling IPv6 294 | Japanese = IPv6を無効にする 295 | Swedish = Inaktiverar IPv6 296 | 297 | TXT_DISCONNECT 298 | English = Disconnect 299 | Japanese = 切断する 300 | Swedish = Avbryt anslutning 301 | 302 | TXT_DISCONNECTED 303 | English = Disconnected. 304 | Japanese = 切断されました 305 | Swedish = Ej ansluten. 306 | 307 | TXT_DISCONNECTING 308 | English = Disconnecting 309 | Japanese = 切断しています 310 | Swedish = Kopplar från 311 | 312 | TXT_DNS_LEAK 313 | English = Enable DNS leak prevention 314 | Japanese = DNS漏れ防止を有効にする 315 | Swedish = Aktivera DNS läckage skydd 316 | 317 | TXT_DNS_RESTORE 318 | English = Restoring DNS 319 | Japanese = DNSを戻します 320 | Swedish = Återställer DNS 321 | 322 | TXT_DONE 323 | English = Done. 324 | Japanese = 完了しました 325 | Swedish = Färdig. 326 | 327 | TXT_DOWNLOADED 328 | English = Downloaded 329 | Japanese = ダウンロードされました 330 | Swedish = Laddade ner 331 | 332 | TXT_DOWNLOADING 333 | English = Downloading 334 | Japanese = ダウンロード中 335 | Swedish = Laddar ner 336 | 337 | TXT_DOWNLOADING_LATEST 338 | English = Downloading latest widget installer 339 | Japanese = 最新のウィジェットインストーラーをダウンロード中 340 | Swedish = Hämtar senaste widget-installatören 341 | 342 | TXT_DOWNLOAD_VERIFIED 343 | English = Downloaded file verified correctly. 344 | Japanese = ダウンロードされたファイルが正しく認証されました 345 | Swedish = Nedladdad fil verifierad korrekt. 346 | 347 | TXT_ENABLE_ADBLOCK 348 | English = Block intrusive ads/trackers 349 | Japanese = 押し付けがましいオンライン広告やトラッカーをブロックする 350 | Swedish = Blockera påträngande annonser/spårare 351 | 352 | TXT_DNSCRYPT_ENABLE 353 | English = Enable DNSCrypt 354 | Japanese = DNSCryptを有効にする 355 | Swedish = Aktivera DNSCrypt 356 | 357 | TXT_DNSCRYPT_STARTING 358 | English = Starting DNSCrypt service 359 | Japanese = DNSCryptサービスを開始しています 360 | Swedish = Startar DNSCrypt-tjänsten 361 | 362 | TXT_DNSCRYPT_STOPPING 363 | English = Stopping DNSCrypt service 364 | Japanese = DNSCryptサービスを停止しています 365 | Swedish = Stoppar DNSCrypt-tjänst 366 | 367 | TXT_DNSCRYPT_INSTALLING 368 | English = Installing DNSCrypt service 369 | Japanese = DNSCryptサービスのインストール 370 | Swedish = Installerar tjänsten DNSCrypt 371 | 372 | TXT_DNSCRYPT_UNINSTALLING 373 | English = Uninstalling DNSCrypt service 374 | Japanese = DNSCryptサービスのアンインストール 375 | Swedish = Avinstallerar DNSCrypt-tjänsten 376 | 377 | TXT_EXIT 378 | English = Exit 379 | Japanese = 終了 380 | Swedish = Avsluta 381 | 382 | TXT_EXITING 383 | English = Exiting 384 | Japanese = 退出中 385 | Swedish = Avslutar 386 | 387 | TXT_FAILED_TO_START 388 | English = Failed to start 389 | Japanese = 起動に失敗しました 390 | Swedish = Misslyckades med att starta 391 | 392 | TXT_HERE 393 | English = here 394 | Japanese = ここで 395 | Swedish = här 396 | 397 | TXT_KILLSWITCH_ENABLE 398 | English = Enable killswitch 399 | Japanese = キルスイッチを有効にする 400 | Swedish = Aktivera killswitch 401 | 402 | TXT_KILLSWITCH_EXPORTING_RULES 403 | English = Kill switch - Exporting rules 404 | Japanese = キルスイッチ - ルールのエクスポート中 405 | Swedish = Kill switch - Exportera regler 406 | 407 | TXT_KILLSWITCH_CLEARING_EXISTING_RULES 408 | English = Kill switch - Clearing existing rules 409 | Japanese = キルスイッチ - 既存のルールをクリアしています 410 | Swedish = Kill switch - Rensa befintliga regler 411 | 412 | TXT_KILLSWITCH_BLOCKING_EVERYTHING 413 | English = Kill switch - Blocking everything by default 414 | Japanese = キルスイッチ - デフォルトですべてをブロックしています 415 | Swedish = Kill switch - Blockera allt som standard 416 | 417 | TXT_KILLSWITCH_WHITELISTING_DHCP 418 | English = Kill switch - Whitelisting DHCP 419 | Japanese = キルスイッチ - DHCP をホワイトリストに登録しています 420 | Swedish = Kill switch - Vitlista DHCP 421 | 422 | TXT_KILLSWITCH_ALLOWING_LAN 423 | English = Kill switch - Allowing local network 424 | Japanese = キルスイッチ - ローカルネットワークを許可しています 425 | Swedish = Kill switch - Tillåta lokalt nätverk 426 | 427 | TXT_KILLSWITCH_WHITELISTING_PROGRAMS 428 | English = Kill switch - Whitelisting programs 429 | Japanese = キルスイッチ - プログラムをホワイトリストに登録しています 430 | Swedish = Kill switch - Vitlista program 431 | 432 | TXT_KILLSWITCH_ALLOWING_PRECONNECT_DNS 433 | English = Kill switch - Allowing pre-connection DNS 434 | Japanese = キルスイッチ - 接続前 DNS を許可しています 435 | Swedish = Kill switch - Tillåta DNS före anslutning 436 | 437 | TXT_KILLSWITCH_RESOLVING_ENDPOINTS 438 | English = Kill switch - Resolving endpoints 439 | Japanese = キルスイッチ - エンドポイントを解決しています 440 | Swedish = Kill switch - Lösa slutpunkter 441 | 442 | TXT_KILLSWITCH_WHITELISTING_VPN_IPS 443 | English = Kill switch - Whitelisting VPN IPs 444 | Japanese = キルスイッチ - VPN IP をホワイトリストに登録しています 445 | Swedish = Kill switch - Vitlista VPN-IP:er 446 | 447 | TXT_KILLSWITCH_WHITELISTING_STATIC_IPS 448 | English = Kill switch - Whitelisting static IPs 449 | Japanese = キルスイッチ - 静的 IP をホワイトリストに登録しています 450 | Swedish = Kill switch - Vitlista statiska IP:er 451 | 452 | TXT_KILLSWITCH_ADDING_VPN_DNS_RULES 453 | English = Kill switch - Adding VPN DNS rules 454 | Japanese = キルスイッチ - VPN DNS ルールを追加しています 455 | Swedish = Kill switch - Lägga till VPN DNS-regler 456 | 457 | TXT_KILLSWITCH_ADDING_INTERNAL_VPN_IP_RULES 458 | English = Kill switch - Adding internal VPN IP rules 459 | Japanese = キルスイッチ - 内部 VPN IP ルールを追加しています 460 | Swedish = Kill switch - Lägga till interna VPN IP-regler 461 | 462 | TXT_KILLSWITCH_IMPORTED_PREVIOUS_RULES 463 | English = Imported previous firewall rules 464 | Japanese = 以前のファイアウォールルールをインポートしました 465 | Swedish = Importerade tidigare brandväggsregler 466 | 467 | TXT_KILLSWITCH_IS_ENABLED_DISABLING 468 | English = Kill switch is enabled, disabling... 469 | Japanese = キルスイッチが有効です。無効にしています… 470 | Swedish = Kill switch är aktiverad, inaktiverar... 471 | 472 | TXT_KILLSWITCH_RULES_DELETED 473 | English = Kill switch firewall rules deleted 474 | Japanese = キルスイッチのファイアウォールルールを削除しました 475 | Swedish = Kill switch brandväggsregler raderade 476 | 477 | TXT_KILLSWITCH_FW_NOTIFICATIONS_ENABLED 478 | English = Firewall notifications enabled 479 | Japanese = ファイアウォール通知が有効です 480 | Swedish = Brandväggsmeddelanden aktiverade 481 | 482 | TXT_KILLSWITCH_FW_PROFILE_POLICIES_RESTORED 483 | English = Firewall profile policies restored 484 | Japanese = ファイアウォールプロファイルポリシーを復元しました 485 | Swedish = Brandväggsprofilpolicyer återställda 486 | 487 | TXT_LANGUAGE 488 | English = Language 489 | Japanese = 言語 490 | Swedish = Språk 491 | 492 | TXT_LOGGING_IN 493 | English = Logging into cryptostorm 494 | Japanese = cryptostormにログインしています 495 | Swedish = Loggar in på cryptostorm 496 | 497 | TXT_MAINWINDOW1 498 | English = To connect to cryptostorm, provide an access token below. 499 | Japanese = cryptostormに接続するために、下にアクセストークンを入力してください 500 | Swedish = För att ansluta till cryptostorm, uppge ett åtkomst-token nedan. 501 | 502 | TXT_MAINWINDOW2 503 | English = If you don't have one, you can get one 504 | Japanese = アクセストークンを入手したい場合、 505 | Swedish = Om du inte har ett, kan du få ett 506 | 507 | TXT_MAINWINDOW5 508 | English = If you need to verify your token, go 509 | Japanese = トークンを検証するには、 510 | Swedish = Om du behöver verifiera ditt token, gå 511 | 512 | TXT_NO_SPLASH 513 | English = Disable splash image on startup. 514 | Japanese = スタートアップ時にスプラッシュスクリーンを無効にする 515 | Swedish = Inaktivera splash bild vid start. 516 | 517 | TXT_NOT_CONNECTED 518 | English = Not connected 519 | Japanese = 接続されていません 520 | Swedish = Ej ansluten 521 | 522 | TXT_OPTIONS 523 | English = Options 524 | Japanese = オプション 525 | Swedish = Alternativ 526 | 527 | TXT_PASTE 528 | English = Paste 529 | Japanese = 貼り付け 530 | Swedish = Klistra in 531 | 532 | TXT_RANDOM_PORT 533 | English = Random port 534 | Japanese = ランダムポート 535 | Swedish = Slumpmässig port 536 | 537 | TXT_SAVE 538 | English = Save? 539 | Japanese = セーブしますか? 540 | Swedish = Spara? 541 | 542 | TXT_SECURITY 543 | English = Security 544 | Japanese = セキュリティー 545 | Swedish = Säkerhet 546 | 547 | TXT_SET_DNS_DNSCRYPT 548 | English = Setting DNS to DNSCrypt 549 | Japanese = DNS を DNSCrypt に設定しています 550 | Swedish = Ställer in DNS till DNSCrypt 551 | 552 | TXT_SOCKS_NO_KILLSWITCH 553 | English = The killswitch will be disabled since a SOCKS proxy is being used 554 | Japanese = SOCKSプロキシが使用されているため、キルスイッチは無効になります 555 | Swedish = Kill-switchen är inaktiverad eftersom en SOCKS-proxy används 556 | 557 | TXT_STARTUP 558 | English = Startup 559 | Japanese = スタートアップ 560 | Swedish = Uppstart 561 | 562 | TXT_SUSPENDING 563 | English = System entering suspended state 564 | Japanese = システムは中断状態に入ります 565 | Swedish = Systemet går in i suspenderat tillstånd 566 | 567 | TXT_TIMEOUT 568 | English = Timeout 569 | Japanese = タイムアウト 570 | Swedish = Avbrott 571 | 572 | TXT_TOOLTIP_TOKEN 573 | English = Token format: xxxx-xxxx-xxxx-xxxx (including dashes) 574 | Japanese = トークン書式: xxxx-xxxx-xxxx-xxxx(ハイフンを省略しないで下さい) 575 | Swedish = Token format: xxxx-xxxx-xxxx-xxxx (inkludera bindestreck) 576 | 577 | TXT_UPDATE 578 | English = Update 579 | Japanese = アップデート 580 | Swedish = Uppdatera 581 | 582 | TXT_UPDATE_CHECKING 583 | English = Checking for updates 584 | Japanese = アップデートをチェックしています 585 | Swedish = Söker efter uppdateringar 586 | 587 | TXT_UPDATE_NODELIST 588 | English = Updating node list 589 | Japanese = ノードリストを更新中 590 | Swedish = Uppdaterar nod-lista 591 | 592 | TXT_UPDATE_NODELIST_DONE 593 | English = Node list update complete. 594 | Japanese = ノードリスト更新完了 595 | Swedish = Nod-listan uppdaterades. 596 | 597 | TXT_UPGRADING1 598 | English = Now disconnect and exit this program. 599 | Japanese = 切断してこのプログラムを終了して下さい。 600 | Swedish = Koppla nu ner och avsluta det här programmet. 601 | 602 | TXT_UPGRADING2 603 | English = When the widget closes, the installer for the latest version will start. 604 | Japanese = ウィジェットが閉じると、最新バージョンへのアップグレードが起動します。 605 | Swedish = När widgeten stängs, startar installationsprogrammet för den senaste versionen. 606 | 607 | TXT_WINTUN_CLEANUP 608 | English = Cleaning up wintun adapter 609 | Japanese = wintun アダプタのクリーンアップ 610 | Swedish = Rengöring av Wintun-adaptern 611 | 612 | TXT_WINTUN_RESTORING_DEFAULTS 613 | English = Restoring the adapter to its default settings 614 | Japanese = アダプタをデフォルト設定に復元する 615 | Swedish = Återställa adaptern till standardinställningarna 616 | 617 | TXT_WINTUN_STARTING 618 | English = Starting Wintun adapter 619 | Japanese = Wintunアダプタの起動 620 | Swedish = Startar Wintun-adaptern 621 | 622 | TXT_WINTUN_STOPPED 623 | English = Wintun adapter stopped 624 | Japanese = Wintunアダプタを停止しました 625 | Swedish = Stoppad Wintun-adapter 626 | 627 | TXT_WINTUN_STOPPED_AND_UNINSTALLED 628 | English = Wintun adapter stopped and uninstalled 629 | Japanese = Wintunアダプタが停止しアンインストールされました 630 | Swedish = Wintun-adaptern stoppades och avinstallerades 631 | --------------------------------------------------------------------------------