2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2007-2023 IPFire Team <info@ipfire.org> #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
23 use Archive
::Zip
qw(:ERROR_CODES :CONSTANTS);
25 use CGI qw
/:standard/;
28 use File
::Temp qw
/ tempfile tempdir /;
36 use URI
::Encode
qw(uri_encode uri_decode);;
38 require '/var/ipfire/general-functions.pl';
39 require "${General::swroot}/header.pl";
40 require "${General::swroot}/countries.pl";
41 require "${General::swroot}/location-functions.pl";
43 # enable only the following on debugging purpose
45 #use CGI::Carp 'fatalsToBrowser';
47 my %mainsettings = ();
48 &General
::readhash
("${General::swroot}/main/settings", \
%mainsettings);
50 # Supported ciphers for NCP
51 my @SUPPORTED_CIPHERS = (
59 my @LEGACY_CIPHERS = (
71 # Translations for the cipher selection
74 "AES-256-GCM" => $Lang::tr
{'AES-256-GCM'},
75 "AES-128-GCM" => $Lang::tr
{'AES-128-GCM'},
76 "AES-256-CBC" => $Lang::tr
{'AES-256-CBC'},
77 "AES-128-CBC" => $Lang::tr
{'AES-128-CBC'},
80 "CHACHA20-POLY1305" => $Lang::tr
{'CHACHA20-POLY1305'},
83 # Use the precomputed DH paramter from RFC7919
84 my $DHPARAM = "/etc/ssl/ffdhe4096.pem";
86 my $RW_PID = "/var/run/openvpn-rw.pid";
87 my $RW_STATUS = "/var/run/openvpn-rw.log";
90 ### Initialize variables
101 my $warnmessage = '';
102 my $errormessage = '';
104 my $routes_push_file = "${General::swroot}/ovpn/routes_push";
105 my $confighost="${General::swroot}/fwhosts/customhosts";
106 my $configgrp="${General::swroot}/fwhosts/customgroups";
107 my $customnet="${General::swroot}/fwhosts/customnetworks";
111 # Load the configuration (once)
112 &General
::readhash
("${General::swroot}/ovpn/settings", \
%vpnsettings);
113 &read_routepushfile
(\
%vpnsettings);
116 # Configure any defaults
117 &General
::set_defaults
(\
%vpnsettings, {
118 # The RW Server is disabled by default
120 "VPN_IP" => "$mainsettings{'HOSTNAME'}.$mainsettings{'DOMAINNAME'}",
121 "DOVPN_SUBNET" => sprintf("10.%d.%d.0/24", rand(256), rand(256)),
123 # Cryptographic Settings
124 "DATACIPHERS" => "AES-256-GCM|AES-128-GCM|CHACHA20-POLY1305",
126 "DCIPHER" => "", # no fallback cipher
129 "DPROTOCOL" => "udp",
130 "DDEST_PORT" => 1194,
132 "MAX_CLIENTS" => 100,
135 }) unless (%vpnsettings);
137 # Load CGI parameters
138 &Header
::getcgihash
(\
%cgiparams, {'wantfile' => 1, 'filevar' => 'FH'});
146 my @certinfo = &General
::system_output
("/usr/bin/openssl", "pkcs12", "-info", "-nodes",
147 "-in", "$file.p12", "-noout", "-passin", "pass:''");
148 if (index ($certinfo[0], "MAC: sha1") != -1) {
154 sub is_cert_rfc3280_compliant
($) {
157 my @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", $path);
159 return grep(/TLS Web Server Authentication/, @output);
162 sub is_legacy_cipher
($) {
165 foreach my $c (@LEGACY_CIPHERS) {
166 return 1 if ($cipher eq $c);
172 sub is_legacy_auth
($) {
175 foreach my $a (@LEGACY_AUTHS) {
176 return 1 if ($auth eq $a);
182 sub cleanssldatabase
() {
183 if (open(FILE
, ">${General::swroot}/ovpn/certs/serial")) {
188 if (open(FILE
, ">${General::swroot}/ovpn/certs/index.txt")) {
193 if (open(FILE
, ">${General::swroot}/ovpn/certs/index.txt.attr")) {
198 unlink("${General::swroot}/ovpn/certs/index.txt.old");
199 unlink("${General::swroot}/ovpn/certs/index.txt.attr.old");
200 unlink("${General::swroot}/ovpn/certs/serial.old");
201 unlink("${General::swroot}/ovpn/certs/01.pem");
206 if (open(FILE
, "${General::swroot}/ovpn/certs/serial.old")) {
207 my $hexvalue = <FILE
>;
210 unlink ("${General::swroot}/ovpn/certs/$hexvalue.pem");
214 sub writeserverconf
{
215 # Do we require the OpenSSL Legacy Provider?
216 my $requires_legacy_provider = 0;
218 open(CONF
, ">${General::swroot}/ovpn/server.conf") or die "Unable to open ${General::swroot}/ovpn/server.conf: $!";
220 print CONF
"#OpenVPN Server conf\n";
222 print CONF
"daemon openvpnserver\n";
223 print CONF
"writepid $RW_PID\n";
224 print CONF
"#DAN prepare OpenVPN for listening on blue and orange\n";
225 print CONF
";local $vpnsettings{'VPN_IP'}\n";
226 print CONF
"dev tun\n";
227 print CONF
"proto $vpnsettings{'DPROTOCOL'}\n";
228 print CONF
"port $vpnsettings{'DDEST_PORT'}\n";
229 print CONF
"script-security 3\n";
230 print CONF
"ifconfig-pool-persist /var/ipfire/ovpn/ovpn-leases.db 3600\n";
231 print CONF
"client-config-dir /var/ipfire/ovpn/ccd\n";
232 print CONF
"tls-server\n";
233 print CONF
"ca ${General::swroot}/ovpn/ca/cacert.pem\n";
234 print CONF
"cert ${General::swroot}/ovpn/certs/servercert.pem\n";
235 print CONF
"key ${General::swroot}/ovpn/certs/serverkey.pem\n";
236 print CONF
"dh $DHPARAM\n";
238 # Enable subnet topology
239 print CONF
"# Topology\n";
240 print CONF
"topology subnet\n\n";
242 my $netaddress = &Network
::get_netaddress
($vpnsettings{'DOVPN_SUBNET'});
243 my $subnetmask = &Network
::get_netmask
($vpnsettings{'DOVPN_SUBNET'});
245 print CONF
"server $netaddress $subnetmask\n";
246 print CONF
"tun-mtu $vpnsettings{'DMTU'}\n";
248 # Write custom routes
249 if ($vpnsettings{'ROUTES_PUSH'} ne '') {
250 my @routes = split(/\|/, $vpnsettings{'ROUTES_PUSH'});
252 foreach my $route (@routes) {
253 my $netaddr = &Network
::get_netaddress
($route);
254 my $netmask = &Network
::get_netmask
($route);
256 if (defined($netaddr) && defined($netmask)) {
257 print CONF
"push \"route ${netaddr} ${netmask}\"\n";
263 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
264 foreach my $key (keys %ccdconfhash) {
265 my $a=$ccdconfhash{$key}[1];
266 my ($b,$c) = split (/\//, $a);
267 print CONF
"route $b ".&General
::cidrtosub
($c)."\n";
270 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
271 foreach my $key (keys %ccdroutehash) {
272 foreach my $i ( 1 .. $#{$ccdroutehash{$key}}){
273 my ($a,$b)=split (/\//,$ccdroutehash{$key}[$i]);
274 print CONF
"route $a $b\n";
278 if ($vpnsettings{MSSFIX
} eq 'on') {
279 print CONF
"mssfix\n";
281 print CONF
"mssfix 0\n";
283 if ($vpnsettings{FRAGMENT
} ne '' && $vpnsettings{'DPROTOCOL'} ne 'tcp') {
284 print CONF
"fragment $vpnsettings{'FRAGMENT'}\n";
287 # Regularly send keep-alive packets
288 print CONF
"keepalive 10 60\n";
290 print CONF
"status-version 1\n";
291 print CONF
"status $RW_STATUS 30\n";
294 if ($vpnsettings{'DATACIPHERS'} eq '') {
295 print CONF
"ncp-disable\n";
297 print CONF
"data-ciphers " . $vpnsettings{'DATACIPHERS'} =~ s/\|/:/gr . "\n";
300 # Enable fallback cipher?
301 if ($vpnsettings{'DCIPHER'} ne '') {
302 if (&is_legacy_cipher
($vpnsettings{'DCIPHER'})) {
303 $requires_legacy_provider++;
306 print CONF
"data-ciphers-fallback $vpnsettings{'DCIPHER'}\n";
309 print CONF
"auth $vpnsettings{'DAUTH'}\n";
311 if (&is_legacy_auth
($vpnsettings{'DAUTH'})) {
312 $requires_legacy_provider++;
315 # Set TLSv2 as minimum
316 print CONF
"tls-version-min 1.2\n";
318 if ($vpnsettings{'TLSAUTH'} eq 'on') {
319 print CONF
"tls-auth ${General::swroot}/ovpn/certs/ta.key\n";
323 # Use migration to support clients that have compression enabled, but disable
324 # compression for everybody else.
325 print CONF
"compress migrate\n";
327 if ($vpnsettings{REDIRECT_GW_DEF1
} eq 'on') {
328 print CONF
"push \"redirect-gateway def1\"\n";
330 if ($vpnsettings{DHCP_DOMAIN
} ne '') {
331 print CONF
"push \"dhcp-option DOMAIN $vpnsettings{DHCP_DOMAIN}\"\n";
334 if ($vpnsettings{DHCP_DNS
} ne '') {
335 print CONF
"push \"dhcp-option DNS $vpnsettings{DHCP_DNS}\"\n";
338 if ($vpnsettings{DHCP_WINS
} ne '') {
339 print CONF
"push \"dhcp-option WINS $vpnsettings{DHCP_WINS}\"\n";
342 if ($vpnsettings{MAX_CLIENTS
} eq '') {
343 print CONF
"max-clients 100\n";
345 if ($vpnsettings{MAX_CLIENTS
} ne '') {
346 print CONF
"max-clients $vpnsettings{MAX_CLIENTS}\n";
348 print CONF
"tls-verify /usr/lib/openvpn/verify\n";
349 print CONF
"crl-verify /var/ipfire/ovpn/crls/cacrl.pem\n";
350 print CONF
"auth-user-pass-optional\n";
351 print CONF
"reneg-sec 86400\n";
352 print CONF
"user nobody\n";
353 print CONF
"group nobody\n";
354 print CONF
"persist-key\n";
355 print CONF
"persist-tun\n";
356 print CONF
"verb 3\n";
358 print CONF
"# Log clients connecting/disconnecting\n";
359 print CONF
"client-connect \"/usr/sbin/openvpn-metrics client-connect\"\n";
360 print CONF
"client-disconnect \"/usr/sbin/openvpn-metrics client-disconnect\"\n";
363 print CONF
"# Enable Management Socket\n";
364 print CONF
"management /var/run/openvpn.sock unix\n";
365 print CONF
"management-client-auth\n";
367 # Enable the legacy provider
368 if ($requires_legacy_provider > 0) {
369 print CONF
"providers legacy default\n";
372 # Send clients a message when the server is being shut down
373 print CONF
"explicit-exit-notify\n";
377 # Rewrite all CCD configurations
378 &write_ccd_configs
();
385 # Checks a ccdname for letters, numbers and spaces
386 sub validccdname
($) {
389 # name should be at least one character in length
390 # but no more than 63 characters
391 if (length ($name) < 1 || length ($name) > 63) {
395 # Only valid characters are a-z, A-Z, 0-9, space and -
396 if ($name !~ /^[a-zA-Z0-9 -]*$/) {
409 # Load all connections
410 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
412 # Check if the subnet is in use
413 foreach my $key (keys %conns) {
414 if ($conns{$key}[32] eq $name) {
415 return $Lang::tr
{'ccd err hostinnet'};
420 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
423 foreach my $key (keys %subnets) {
424 if ($subnets{$key}[0] eq $name){
425 delete $subnets{$key};
429 # Write the subnets back
430 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
432 # Update the server configuration to remove routes
436 # Returns the network with the matching name
437 sub get_cdd_network
($) {
442 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
444 # Find the matching subnet
445 foreach my $key (keys %subnets) {
446 if ($subnets{$key}[0] eq $name) {
447 return $subnets{$key}[1];
458 my %ccdconfhash = ();
460 # Check if the name is valid
461 unless (&validccdname
($name)) {
462 return $Lang::tr
{'ccd err invalidname'};
465 # Fetch the network address & prefix
466 my $address = &Network
::get_netaddress
($network);
467 my $prefix = &Network
::get_prefix
($network);
469 # If we could not decode the subnet, it must be invalid
470 if (!defined $address || !defined $prefix) {
471 return $Lang::tr
{'ccd err invalidnet'};
473 # If the network is smaller than /30, there is no point in using it
474 } elsif ($prefix > 30) {
475 return $Lang::tr
{'ccd err invalidnet'};
478 # Read the configuration
479 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
482 my $key = &General
::findhasharraykey
(\
%ccdconfhash);
485 $ccdconfhash{$key}[0] = $name;
486 $ccdconfhash{$key}[1] = "$address/$prefix";
488 # Write the hash back
489 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
491 # Update the server configuration to add routes
503 # Check if the new name is valid
504 unless (&validccdname
($newname)) {
505 $errormessage = $Lang::tr
{'ccd err invalidname'};
510 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
512 # Check if the name already exists
513 foreach my $key (keys %ccdconfhash) {
514 if ($ccdconfhash{$key}[0] eq $newname) {
515 return $Lang::tr
{'ccd err netadrexist'};
520 foreach my $key (keys %ccdconfhash) {
521 if ($ccdconfhash{$key}[1] eq $subnet) {
522 $oldname = $ccdconfhash{$key}[0];
523 $ccdconfhash{$key}[0] = $newname;
528 # Load all configurations
529 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
531 # Update all matching connections
532 foreach my $key (keys %conns) {
533 if ($conns{$key}[32] eq $oldname) {
534 $conns{$key}[32] = $newname;
538 # Write back the configuration
539 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
540 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
543 sub get_ccd_client_routes
($) {
546 my %client_routes = ();
549 # Load all client routes
550 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%client_routes);
552 foreach my $key (keys %client_routes) {
553 if ($client_routes{$key}[0] eq $name) {
554 push(@routes, $client_routes{$key}[1]);
561 sub get_ccd_server_routes
($) {
564 my %server_routes = ();
567 # Load all server routes
568 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%server_routes);
570 foreach my $key (keys %server_routes) {
571 if ($server_routes{$key}[0] eq $name) {
574 while (my $route = $server_routes{$key}[$i++]) {
575 push(@routes, $route);
583 # This function rewrites all CCD configuration files upon change
584 sub write_ccd_configs
() {
587 # Load all configurations
588 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
590 foreach my $key (keys %conns) {
591 my $name = $conns{$key}[1];
592 my $type = $conns{$key}[3];
594 # Skip anything that isn't a host connection
595 next unless ($type eq "host");
597 my $filename = "${General::swroot}/ovpn/ccd/$conns{$key}[2]";
599 # Open the configuration file
600 open(CONF
, ">${filename}") or die "Unable to open ${filename} for writing: $!";
603 print CONF
"# OpenVPN Client Configuration File\n\n";
605 # Fetch the allocated IP address (if any)
606 my $pool = $conns{$key}[32];
607 my $address = $conns{$key}[33];
609 # If the client has a dynamically allocated IP address, there is nothing to do
610 if ($pool eq "dynamic") {
611 print CONF
"# This client uses the dynamic pool\n\n";
613 # Otherwise we need to push the selected IP address
615 $address = &convert_top30_ccd_allocation
($address);
617 # Fetch the network of the pool
618 my $network = &get_cdd_network
($pool);
619 my $netmask = &Network
::get_netmask
($network);
621 if (defined $address && defined $network && defined $netmask) {
622 print CONF
"# Allocated IP address from $pool\n";
623 print CONF
"ifconfig-push ${address} ${netmask}\n\n";
628 my $redirect = $conns{$key}[34];
630 if ($redirect eq "on") {
631 print CONF
"# Redirect all traffic to us\n";
632 print CONF
"push redirect-gateway\n\n";
647 print CONF
"# DHCP Options";
649 foreach my $option (keys %options) {
650 foreach (@options{$option}) {
654 print CONF
"push \"dhcp-option $option $_\"\n";
661 # Networks routed to client
662 my @client_routes = &get_ccd_client_routes
($name);
664 if (scalar @client_routes) {
665 print CONF
"# Networks routed to the client\n";
667 foreach my $route (@client_routes) {
668 my $netaddress = &Network
::get_netaddress
($route);
669 my $netmask = &Network
::get_netmask
($route);
671 if (!defined $netaddress || !defined $netmask) {
675 print CONF
"iroute $netaddress $netmask\n";
682 # Networks routed to server
683 my @server_routes = &get_ccd_server_routes
($name);
685 if (scalar @server_routes) {
686 print CONF
"# Networks routed to the server\n";
688 foreach my $route (@server_routes) {
689 my $netaddress = &Network
::get_netaddress
($route);
690 my $netmask = &Network
::get_netmask
($route);
692 if (!defined $netaddress || !defined $netmask) {
696 print CONF
"push \"route $netaddress $netmask\"\n";
707 sub ccdmaxclients
($) {
711 my $prefix = &Network
::get_prefix
($network);
713 # Return undef on invalid input
714 if (!defined $prefix) {
718 # We take three addresses away: the network base address, the gateway, and broadcast
719 return (1 << (32 - $prefix)) - 3;
722 # Lists all selectable CCD addresses for the given network
723 sub getccdadresses
($) {
726 # Collect all available addresses
729 # Convert the network into binary
730 my ($start, $netmask) = &Network
::network2bin
($network);
732 # Fetch the broadcast address
733 my $broadcast = &Network
::get_broadcast
($network);
734 $broadcast = &Network
::ip2bin
($broadcast);
736 # Fail if we could not parse the network
737 if (!defined $start || !defined $netmask || !defined $broadcast) {
741 # Skip the base address and gateway
744 while ($start < $broadcast) {
745 push(@addresses, &Network
::bin2ip
($start++));
751 sub convert_top30_ccd_allocation
($) {
754 # Do nothing if the address does not end on /30
755 return $address unless ($address =~ m/\/30$/);
757 # Fetch the network base address
758 my $netaddress = &Network
::get_netaddress
($address);
760 # Break on invalid input
761 return undef if (!defined $netaddress);
763 # The client IP address was the second address of the subnet
764 return &Network
::find_next_ip_address
($netaddress, 2);
767 sub get_addresses_in_use
($) {
772 # Load all connections
773 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
777 # Check if the address is in use
778 foreach my $key (keys %conns) {
779 my $address = &convert_top30_ccd_allocation
($conns{$key}[33]);
781 # Skip on invalid inputs
782 next if (!defined $address);
784 # If the first address is part of the network, we have a match
785 if (&Network
::ip_address_in_network
($address, $network)) {
786 push(@addresses, $address);
793 sub fillselectbox
($$) {
796 my @selected = shift;
798 # Fetch all available addresses for this network
799 my @addresses = &getccdadresses
($network);
801 # Fetch all addresses in use
802 my @addresses_in_use = &get_addresses_in_use
($network);
804 print "<select name='$boxname'>";
806 foreach my $address (@addresses) {
807 print "<option value='$address'";
809 # Select any requested addresses
810 foreach (@selected) {
811 if ($address eq $_) {
817 # Disable any addresses that are not free
818 foreach (@addresses_in_use) {
819 if ($address eq $_) {
826 print ">$address</option>";
832 # XXX THIS WILL NO LONGER WORK
833 sub check_routes_push
836 my ($ip,$cidr) = split (/\//, $val);
837 ##check for existing routes in routes_push
838 if (-e
"${General::swroot}/ovpn/routes_push") {
839 open(FILE
,"${General::swroot}/ovpn/routes_push");
843 my ($ip2,$cidr2) = split (/\//,"$_");
844 my $val2=$ip2."/".&General
::iporsubtodec
($cidr2);
850 if (&General
::IpInSubnet
($ip,$ip2,&General
::iporsubtodec
($cidr2))){
863 my ($ip,$cidr) = split (/\//, $val);
864 #check for existing routes in ccdroute
865 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
866 foreach my $key (keys %ccdroutehash) {
867 foreach my $i (1 .. $#{$ccdroutehash{$key}}) {
868 if (&General
::iporsubtodec
($val) eq $ccdroutehash{$key}[$i] && $ccdroutehash{$key}[0] ne $cgiparams{'NAME'}){
871 my ($ip2,$cidr2) = split (/\//,$ccdroutehash{$key}[$i]);
873 if (&General
::IpInSubnet
($ip,$ip2,$cidr2)&& $ccdroutehash{$key}[0] ne $cgiparams{'NAME'} ){
884 my ($ip,$cidr) = split (/\//, $val);
885 #check for existing routes in ccdroute
886 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
887 foreach my $key (keys %ccdconfhash) {
888 if (&General
::iporsubtocidr
($val) eq $ccdconfhash{$key}[1]){
891 my ($ip2,$cidr2) = split (/\//,$ccdconfhash{$key}[1]);
893 if (&General
::IpInSubnet
($ip,$ip2,&General
::cidrtosub
($cidr2))){
901 # -------------------------------------------------------------------
903 sub read_routepushfile
($) {
906 # Don't read the legacy file if we already have a value
907 if ($hash->{'ROUTES_PUSH'} ne "") {
908 unlink($routes_push_file);
910 # This is some legacy code that reads the routes file if it is still present
911 } elsif (-e
"$routes_push_file") {
912 delete $hash->{'ROUTES_PUSH'};
916 open(FILE
,"$routes_push_file");
922 $hash->{'ROUTES_PUSH'} = join("|", @routes);
926 sub writecollectdconf
{
930 open(COLLECTDVPN
, ">${General::swroot}/ovpn/collectd.vpn") or die "Unable to open collectd.vpn: $!";
931 print COLLECTDVPN
"Loadplugin openvpn\n";
932 print COLLECTDVPN
"\n";
933 print COLLECTDVPN
"<Plugin openvpn>\n";
934 print COLLECTDVPN
"Statusfile \"${RW_STATUS}\"\n";
936 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%ccdhash);
937 foreach my $key (keys %ccdhash) {
938 if ($ccdhash{$key}[0] eq 'on' && $ccdhash{$key}[3] eq 'net') {
939 print COLLECTDVPN
"Statusfile \"/var/run/openvpn/$ccdhash{$key}[1]-n2n\"\n";
943 print COLLECTDVPN
"</Plugin>\n";
946 # Reload collectd afterwards
947 &General
::system("/usr/local/bin/collectdctrl", "restart");
950 sub openvpn_status
($) {
953 # Create a new Telnet session
954 my $telnet = new Net
::Telnet
(
961 $telnet->open("127.0.0.1");
964 my @output = $telnet->cmd(
966 Prompt
=> "/(END.*\n|ERROR:.*\n)/"
969 my ($time, $status) = split(/\,/, $output[1]);
972 #CONNECTING -- OpenVPN's initial state.
973 #WAIT -- (Client only) Waiting for initial response from server.
974 #AUTH -- (Client only) Authenticating with server.
975 #GET_CONFIG -- (Client only) Downloading configuration options from server.
976 #ASSIGN_IP -- Assigning IP address to virtual network interface.
977 #ADD_ROUTES -- Adding routes to system.
978 #CONNECTED -- Initialization Sequence Completed.
979 #RECONNECTING -- A restart has occurred.
980 #EXITING -- A graceful exit is in progress.
983 if ($status eq "CONNECTING") {
984 return "DISCONNECTED";
985 } elsif ($status eq "WAIT") {
986 return "DISCONNECTED";
987 } elsif ($status eq "AUTH") {
988 return "DISCONNECTED";
989 } elsif ($status eq "GET_CONFIG") {
990 return "DISCONNECTED";
991 } elsif ($status eq "ASSIGN_IP") {
992 return "DISCONNECTED";
993 } elsif ($status eq "ADD_ROUTES") {
994 return "DISCONNECTED";
995 } elsif ($status eq "RECONNECTING") {
997 } elsif ($status eq "EXITING") {
998 return "DISCONNECTED";
1004 # Hook to regenerate the configuration files
1005 if ($ENV{"REMOTE_ADDR"} eq "") {
1011 ### Save Advanced options
1014 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save-adv-options'}) {
1015 $vpnsettings{'DPROTOCOL'} = $cgiparams{'DPROTOCOL'};
1016 $vpnsettings{'DDEST_PORT'} = $cgiparams{'DDEST_PORT'};
1017 $vpnsettings{'DMTU'} = $cgiparams{'DMTU'};
1018 $vpnsettings{'MAX_CLIENTS'} = $cgiparams{'MAX_CLIENTS'};
1019 $vpnsettings{'REDIRECT_GW_DEF1'} = $cgiparams{'REDIRECT_GW_DEF1'};
1020 $vpnsettings{'DHCP_DOMAIN'} = $cgiparams{'DHCP_DOMAIN'};
1021 $vpnsettings{'DHCP_DNS'} = $cgiparams{'DHCP_DNS'};
1022 $vpnsettings{'DHCP_WINS'} = $cgiparams{'DHCP_WINS'};
1023 $vpnsettings{'ROUTES_PUSH'} = $cgiparams{'ROUTES_PUSH'};
1024 $vpnsettings{'DATACIPHERS'} = $cgiparams{'DATACIPHERS'};
1025 $vpnsettings{'DCIPHER'} = $cgiparams{'DCIPHER'};
1026 $vpnsettings{'DAUTH'} = $cgiparams{'DAUTH'};
1027 $vpnsettings{'TLSAUTH'} = $cgiparams{'TLSAUTH'};
1029 # We must have at least one cipher selected
1030 if ($cgiparams{'DATACIPHERS'} eq '') {
1031 $errormessage = $Lang::tr
{'ovpn no cipher selected'};
1035 # Split data ciphers
1036 my @dataciphers = split(/\|/, $cgiparams{'DATACIPHERS'});
1038 # Check if all ciphers are supported
1039 foreach my $cipher (@dataciphers) {
1040 if (!grep(/^$cipher$/, @SUPPORTED_CIPHERS)) {
1041 $errormessage = $Lang::tr
{'ovpn unsupported cipher selected'};
1047 unless (&General
::validport
($cgiparams{'DDEST_PORT'})) {
1048 $errormessage = $Lang::tr
{'invalid port'};
1053 if (($cgiparams{'DMTU'} eq "") || (($cgiparams{'DMTU'}) < 1280 )) {
1054 $errormessage = $Lang::tr
{'invalid mtu input'};
1058 if ($cgiparams{'FRAGMENT'} eq '') {
1059 delete $vpnsettings{'FRAGMENT'};
1061 if ($cgiparams{'FRAGMENT'} !~ /^[0-9]+$/) {
1062 $errormessage = "Incorrect value, please insert only numbers.";
1065 $vpnsettings{'FRAGMENT'} = $cgiparams{'FRAGMENT'};
1069 if ($cgiparams{'MSSFIX'} ne 'on') {
1070 delete $vpnsettings{'MSSFIX'};
1072 $vpnsettings{'MSSFIX'} = $cgiparams{'MSSFIX'};
1075 if ($cgiparams{'DHCP_DOMAIN'} ne ''){
1076 unless (&General
::validdomainname
($cgiparams{'DHCP_DOMAIN'}) || &General
::validip
($cgiparams{'DHCP_DOMAIN'})) {
1077 $errormessage = $Lang::tr
{'invalid input for dhcp domain'};
1081 if ($cgiparams{'DHCP_DNS'} ne ''){
1082 unless (&General
::validfqdn
($cgiparams{'DHCP_DNS'}) || &General
::validip
($cgiparams{'DHCP_DNS'})) {
1083 $errormessage = $Lang::tr
{'invalid input for dhcp dns'};
1087 if ($cgiparams{'DHCP_WINS'} ne ''){
1088 unless (&General
::validfqdn
($cgiparams{'DHCP_WINS'}) || &General
::validip
($cgiparams{'DHCP_WINS'})) {
1089 $errormessage = $Lang::tr
{'invalid input for dhcp wins'};
1094 # Validate pushed routes
1095 if ($cgiparams{'ROUTES_PUSH'} ne ''){
1096 my @temp = split(/\n/, $cgiparams{'ROUTES_PUSH'});
1100 foreach my $route (@temp) {
1103 # Remove any excess whitespace
1104 $route =~ s/^\s+//g;
1105 $route =~ s/\s+$//g;
1108 next if ($route eq "");
1110 unless (&Network
::check_subnet
($route)) {
1111 $errormessage = "$Lang::tr{'ovpn errmsg invalid route'}: $route";
1115 push(@routes, $route);
1118 $vpnsettings{'ROUTES_PUSH'} = join("|", @routes);
1121 if ((length($cgiparams{'MAX_CLIENTS'}) == 0) || (($cgiparams{'MAX_CLIENTS'}) < 1 ) || (($cgiparams{'MAX_CLIENTS'}) > 1024 )) {
1122 $errormessage = $Lang::tr
{'invalid input for max clients'};
1126 # Store our configuration
1127 &General
::writehash
("${General::swroot}/ovpn/settings", \
%vpnsettings);
1129 # Write the server configuration
1132 # Restart the server if it is enabled
1133 if ($vpnsettings{'ENABLED'} eq "on") {
1134 &General
::system("/usr/local/bin/openvpnctrl", "rw", "restart");
1138 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq 'net' && $cgiparams{'SIDE'} eq 'server')
1141 my @remsubnet = split(/\//,$cgiparams{'REMOTE_SUBNET'});
1142 my @ovsubnettemp = split(/\./,$cgiparams{'OVPN_SUBNET'});
1143 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
1146 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
1147 unless(-d
"${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}"){mkdir "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}", 0770 or die "Unable to create dir $!";}
1149 open(SERVERCONF
, ">${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Unable to open ${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf: $!";
1151 flock SERVERCONF
, 2;
1152 print SERVERCONF
"# IPFire n2n Open VPN Server Config by ummeegge und m.a.d\n";
1153 print SERVERCONF
"\n";
1154 print SERVERCONF
"# User Security\n";
1155 print SERVERCONF
"user nobody\n";
1156 print SERVERCONF
"group nobody\n";
1157 print SERVERCONF
"persist-tun\n";
1158 print SERVERCONF
"persist-key\n";
1159 print SERVERCONF
"script-security 2\n";
1160 print SERVERCONF
"# IP/DNS for remote Server Gateway\n";
1162 if ($cgiparams{'REMOTE'} ne '') {
1163 print SERVERCONF
"remote $cgiparams{'REMOTE'}\n";
1166 print SERVERCONF
"float\n";
1167 print SERVERCONF
"# IP adresses of the VPN Subnet\n";
1168 print SERVERCONF
"ifconfig $ovsubnet.1 $ovsubnet.2\n";
1169 print SERVERCONF
"# Client Gateway Network\n";
1170 print SERVERCONF
"route $remsubnet[0] $remsubnet[1]\n";
1171 print SERVERCONF
"up \"/etc/init.d/static-routes start\"\n";
1172 print SERVERCONF
"# tun Device\n";
1173 print SERVERCONF
"dev tun\n";
1174 print SERVERCONF
"#Logfile for statistics\n";
1175 print SERVERCONF
"status-version 1\n";
1176 print SERVERCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
1177 print SERVERCONF
"# Port and Protokol\n";
1178 print SERVERCONF
"port $cgiparams{'DEST_PORT'}\n";
1180 if ($cgiparams{'PROTOCOL'} eq 'tcp') {
1181 print SERVERCONF
"proto tcp4-server\n";
1182 print SERVERCONF
"# Packet size\n";
1183 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1400'} else {$tunmtu = $cgiparams{'MTU'}};
1184 print SERVERCONF
"tun-mtu $tunmtu\n";
1187 if ($cgiparams{'PROTOCOL'} eq 'udp') {
1188 print SERVERCONF
"proto udp4\n";
1189 print SERVERCONF
"# Paketsize\n";
1190 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1500'} else {$tunmtu = $cgiparams{'MTU'}};
1191 print SERVERCONF
"tun-mtu $tunmtu\n";
1192 if ($cgiparams{'FRAGMENT'} ne '') {print SERVERCONF
"fragment $cgiparams{'FRAGMENT'}\n";}
1193 if ($cgiparams{'MSSFIX'} eq 'on') {print SERVERCONF
"mssfix\n"; } else { print SERVERCONF
"mssfix 0\n" };
1196 print SERVERCONF
"# Auth. Server\n";
1197 print SERVERCONF
"tls-server\n";
1198 print SERVERCONF
"ca ${General::swroot}/ovpn/ca/cacert.pem\n";
1199 print SERVERCONF
"cert ${General::swroot}/ovpn/certs/servercert.pem\n";
1200 print SERVERCONF
"key ${General::swroot}/ovpn/certs/serverkey.pem\n";
1201 print SERVERCONF
"dh $DHPARAM\n";
1202 print SERVERCONF
"# Cipher\n";
1203 print SERVERCONF
"cipher $cgiparams{'DCIPHER'}\n";
1205 # If GCM cipher is used, do not use --auth
1206 if (($cgiparams{'DCIPHER'} eq 'AES-256-GCM') ||
1207 ($cgiparams{'DCIPHER'} eq 'AES-192-GCM') ||
1208 ($cgiparams{'DCIPHER'} eq 'AES-128-GCM')) {
1209 print SERVERCONF
unless "# HMAC algorithm\n";
1210 print SERVERCONF
unless "auth $cgiparams{'DAUTH'}\n";
1212 print SERVERCONF
"# HMAC algorithm\n";
1213 print SERVERCONF
"auth $cgiparams{'DAUTH'}\n";
1216 # Set TLSv1.2 as minimum
1217 print SERVERCONF
"tls-version-min 1.2\n";
1219 if ($cgiparams{'COMPLZO'} eq 'on') {
1220 print SERVERCONF
"# Enable Compression\n";
1221 print SERVERCONF
"comp-lzo\n";
1223 print SERVERCONF
"# Debug Level\n";
1224 print SERVERCONF
"verb 3\n";
1225 print SERVERCONF
"# Tunnel check\n";
1226 print SERVERCONF
"keepalive 10 60\n";
1227 print SERVERCONF
"# Start as daemon\n";
1228 print SERVERCONF
"daemon $cgiparams{'NAME'}n2n\n";
1229 print SERVERCONF
"writepid /var/run/$cgiparams{'NAME'}n2n.pid\n";
1230 print SERVERCONF
"# Activate Management Interface and Port\n";
1231 if ($cgiparams{'OVPN_MGMT'} eq '') {print SERVERCONF
"management localhost $cgiparams{'DEST_PORT'}\n"}
1232 else {print SERVERCONF
"management localhost $cgiparams{'OVPN_MGMT'}\n"};
1237 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq 'net' && $cgiparams{'SIDE'} eq 'client')
1240 my @ovsubnettemp = split(/\./,$cgiparams{'OVPN_SUBNET'});
1241 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
1242 my @remsubnet = split(/\//,$cgiparams{'REMOTE_SUBNET'});
1245 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
1246 unless(-d
"${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}"){mkdir "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}", 0770 or die "Unable to create dir $!";}
1248 open(CLIENTCONF
, ">${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Unable to open ${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf: $!";
1250 flock CLIENTCONF
, 2;
1251 print CLIENTCONF
"# IPFire rewritten n2n Open VPN Client Config by ummeegge und m.a.d\n";
1252 print CLIENTCONF
"#\n";
1253 print CLIENTCONF
"# User Security\n";
1254 print CLIENTCONF
"user nobody\n";
1255 print CLIENTCONF
"group nobody\n";
1256 print CLIENTCONF
"persist-tun\n";
1257 print CLIENTCONF
"persist-key\n";
1258 print CLIENTCONF
"script-security 2\n";
1259 print CLIENTCONF
"# IP/DNS for remote Server Gateway\n";
1260 print CLIENTCONF
"remote $cgiparams{'REMOTE'}\n";
1261 print CLIENTCONF
"float\n";
1262 print CLIENTCONF
"# IP adresses of the VPN Subnet\n";
1263 print CLIENTCONF
"ifconfig $ovsubnet.2 $ovsubnet.1\n";
1264 print CLIENTCONF
"# Server Gateway Network\n";
1265 print CLIENTCONF
"route $remsubnet[0] $remsubnet[1]\n";
1266 print CLIENTCONF
"up \"/etc/init.d/static-routes start\"\n";
1267 print CLIENTCONF
"# tun Device\n";
1268 print CLIENTCONF
"dev tun\n";
1269 print CLIENTCONF
"#Logfile for statistics\n";
1270 print CLIENTCONF
"status-version 1\n";
1271 print CLIENTCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
1272 print CLIENTCONF
"# Port and Protokol\n";
1273 print CLIENTCONF
"port $cgiparams{'DEST_PORT'}\n";
1275 if ($cgiparams{'PROTOCOL'} eq 'tcp') {
1276 print CLIENTCONF
"proto tcp4-client\n";
1277 print CLIENTCONF
"# Packet size\n";
1278 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1400'} else {$tunmtu = $cgiparams{'MTU'}};
1279 print CLIENTCONF
"tun-mtu $tunmtu\n";
1282 if ($cgiparams{'PROTOCOL'} eq 'udp') {
1283 print CLIENTCONF
"proto udp4\n";
1284 print CLIENTCONF
"# Paketsize\n";
1285 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1500'} else {$tunmtu = $cgiparams{'MTU'}};
1286 print CLIENTCONF
"tun-mtu $tunmtu\n";
1287 if ($cgiparams{'FRAGMENT'} ne '') {print CLIENTCONF
"fragment $cgiparams{'FRAGMENT'}\n";}
1288 if ($cgiparams{'MSSFIX'} eq 'on') {print CLIENTCONF
"mssfix\n"; } else { print CLIENTCONF
"mssfix 0\n" };
1291 # Check host certificate if X509 is RFC3280 compliant.
1292 # If not, old --ns-cert-type directive will be used.
1293 # If appropriate key usage extension exists, new --remote-cert-tls directive will be used.
1294 my @hostcert = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1295 if ( ! grep(/TLS Web Server Authentication/, @hostcert)) {
1296 print CLIENTCONF
"ns-cert-type server\n";
1298 print CLIENTCONF
"remote-cert-tls server\n";
1300 print CLIENTCONF
"# Auth. Client\n";
1301 print CLIENTCONF
"tls-client\n";
1302 print CLIENTCONF
"# Cipher\n";
1303 print CLIENTCONF
"cipher $cgiparams{'DCIPHER'}\n";
1304 print CLIENTCONF
"pkcs12 ${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12\r\n";
1306 # If GCM cipher is used, do not use --auth
1307 if (($cgiparams{'DCIPHER'} eq 'AES-256-GCM') ||
1308 ($cgiparams{'DCIPHER'} eq 'AES-192-GCM') ||
1309 ($cgiparams{'DCIPHER'} eq 'AES-128-GCM')) {
1310 print CLIENTCONF
unless "# HMAC algorithm\n";
1311 print CLIENTCONF
unless "auth $cgiparams{'DAUTH'}\n";
1313 print CLIENTCONF
"# HMAC algorithm\n";
1314 print CLIENTCONF
"auth $cgiparams{'DAUTH'}\n";
1317 # Set TLSv1.2 as minimum
1318 print CLIENTCONF
"tls-version-min 1.2\n";
1320 if ($cgiparams{'COMPLZO'} eq 'on') {
1321 print CLIENTCONF
"# Enable Compression\n";
1322 print CLIENTCONF
"comp-lzo\n";
1324 print CLIENTCONF
"# Debug Level\n";
1325 print CLIENTCONF
"verb 3\n";
1326 print CLIENTCONF
"# Tunnel check\n";
1327 print CLIENTCONF
"keepalive 10 60\n";
1328 print CLIENTCONF
"# Start as daemon\n";
1329 print CLIENTCONF
"daemon $cgiparams{'NAME'}n2n\n";
1330 print CLIENTCONF
"writepid /var/run/$cgiparams{'NAME'}n2n.pid\n";
1331 print CLIENTCONF
"# Activate Management Interface and Port\n";
1332 if ($cgiparams{'OVPN_MGMT'} eq '') {print CLIENTCONF
"management localhost $cgiparams{'DEST_PORT'}\n"}
1333 else {print CLIENTCONF
"management localhost $cgiparams{'OVPN_MGMT'}\n"};
1334 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}")) {
1335 print CLIENTCONF
"providers legacy default\n";
1342 ### Save main settings
1345 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq '' && $cgiparams{'KEY'} eq '') {
1346 #DAN do we really need (to to check) this value? Besides if we listen on blue and orange too,
1347 #DAN this value has to leave.
1348 if ($cgiparams{'ENABLED'} eq 'on'){
1349 unless (&General
::validfqdn
($cgiparams{'VPN_IP'}) || &General
::validip
($cgiparams{'VPN_IP'})) {
1350 $errormessage = $Lang::tr
{'invalid input for hostname'};
1351 goto SETTINGS_ERROR
;
1355 if (! &General
::validipandmask
($cgiparams{'DOVPN_SUBNET'})) {
1356 $errormessage = $Lang::tr
{'ovpn subnet is invalid'};
1357 goto SETTINGS_ERROR
;
1359 my @tmpovpnsubnet = split("\/",$cgiparams{'DOVPN_SUBNET'});
1361 if (&General
::IpInSubnet
( $Network::ethernet
{'RED_ADDRESS'},
1362 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1363 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire RED Network $Network::ethernet{'RED_ADDRESS'}";
1364 goto SETTINGS_ERROR
;
1367 if (&General
::IpInSubnet
( $Network::ethernet
{'GREEN_ADDRESS'},
1368 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1369 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Green Network $Network::ethernet{'GREEN_ADDRESS'}";
1370 goto SETTINGS_ERROR
;
1373 if (&General
::IpInSubnet
( $Network::ethernet
{'BLUE_ADDRESS'},
1374 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1375 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Blue Network $Network::ethernet{'BLUE_ADDRESS'}";
1376 goto SETTINGS_ERROR
;
1379 if (&General
::IpInSubnet
( $Network::ethernet
{'ORANGE_ADDRESS'},
1380 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1381 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Orange Network $Network::ethernet{'ORANGE_ADDRESS'}";
1382 goto SETTINGS_ERROR
;
1384 open(ALIASES
, "${General::swroot}/ethernet/aliases") or die 'Unable to open aliases file.';
1388 my @tempalias = split(/\,/,$_);
1389 if ($tempalias[1] eq 'on') {
1390 if (&General
::IpInSubnet
($tempalias[0] ,
1391 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1392 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire alias entry $tempalias[0]";
1397 if ($errormessage ne ''){
1398 goto SETTINGS_ERROR
;
1400 if ($cgiparams{'ENABLED'} !~ /^(on|off|)$/) {
1401 $errormessage = $Lang::tr
{'invalid input'};
1402 goto SETTINGS_ERROR
;
1405 # Create ta.key for tls-auth if not presant
1406 if ($cgiparams{'TLSAUTH'} eq 'on') {
1407 if ( ! -e
"${General::swroot}/ovpn/certs/ta.key") {
1408 # This system call is safe, because all arguements are passed as an array.
1409 system("/usr/sbin/openvpn", "--genkey", "secret", "${General::swroot}/ovpn/certs/ta.key");
1411 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1412 goto SETTINGS_ERROR
;
1417 $vpnsettings{'ENABLED'} = $cgiparams{'ENABLED'};
1418 $vpnsettings{'VPN_IP'} = $cgiparams{'VPN_IP'};
1419 $vpnsettings{'DOVPN_SUBNET'} = $cgiparams{'DOVPN_SUBNET'};
1421 # Store our configuration
1422 &General
::writehash
("${General::swroot}/ovpn/settings", \
%vpnsettings);
1424 # Write the OpenVPN server configuration
1427 # Start/Stop the server
1428 if ($vpnsettings{'ENABLED'} eq "on") {
1429 &General
::system("/usr/local/bin/openvpnctrl", "rw", "restart");
1431 &General
::system("/usr/local/bin/openvpnctrl", "rw", "stop");
1436 ### Reset all step 2
1438 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove x509'} && $cgiparams{'AREUSURE'} eq 'yes') {
1440 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1442 # Stop all N2N connections
1443 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop");
1445 foreach my $key (keys %confighash) {
1446 my $name = $confighash{$cgiparams{'$key'}}[1];
1448 if ($confighash{$key}[4] eq 'cert') {
1449 delete $confighash{$cgiparams{'$key'}};
1452 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "delete", "$name");
1454 while ($file = glob("${General::swroot}/ovpn/ca/*")) {
1457 while ($file = glob("${General::swroot}/ovpn/certs/*")) {
1460 while ($file = glob("${General::swroot}/ovpn/crls/*")) {
1463 &cleanssldatabase
();
1464 if (open(FILE
, ">${General::swroot}/ovpn/caconfig")) {
1468 if (open(FILE
, ">${General::swroot}/ovpn/ccdroute")) {
1472 if (open(FILE
, ">${General::swroot}/ovpn/ccdroute2")) {
1476 while ($file = glob("${General::swroot}/ovpn/ccd/*")) {
1479 while ($file = glob("${General::swroot}/ovpn/ccd/*")) {
1482 if (open(FILE
, ">${General::swroot}/ovpn/ovpn-leases.db")) {
1486 if (open(FILE
, ">${General::swroot}/ovpn/ovpnconfig")) {
1490 while ($file = glob("${General::swroot}/ovpn/n2nconf/*")) {
1494 # Remove everything from the collectd configuration
1495 &writecollectdconf
();
1497 #&writeserverconf();
1499 ### Reset all step 1
1501 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove x509'}) {
1502 &Header
::showhttpheaders
();
1503 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1504 &Header
::openbigbox
('100%', 'left', '', '');
1505 &Header
::openbox
('100%', 'left', $Lang::tr
{'are you sure'});
1507 <form method='post'>
1508 <table width='100%'>
1511 <input type='hidden' name='AREUSURE' value='yes' />
1512 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>:
1513 $Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'}</td>
1516 <td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' />
1517 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td>
1523 &Header
::closebox
();
1524 &Header
::closebigbox
();
1525 &Header
::closepage
();
1529 ### Upload CA Certificate
1531 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'upload ca certificate'}) {
1532 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1534 if ($cgiparams{'CA_NAME'} !~ /^[a-zA-Z0-9]+$/) {
1535 $errormessage = $Lang::tr
{'name must only contain characters'};
1536 goto UPLOADCA_ERROR
;
1539 if (length($cgiparams{'CA_NAME'}) >60) {
1540 $errormessage = $Lang::tr
{'name too long'};
1544 if ($cgiparams{'CA_NAME'} eq 'ca') {
1545 $errormessage = $Lang::tr
{'name is invalid'};
1546 goto UPLOADCA_ERROR
;
1549 # Check if there is no other entry with this name
1550 foreach my $key (keys %cahash) {
1551 if ($cahash{$key}[0] eq $cgiparams{'CA_NAME'}) {
1552 $errormessage = $Lang::tr
{'a ca certificate with this name already exists'};
1553 goto UPLOADCA_ERROR
;
1557 unless (ref ($cgiparams{'FH'})) {
1558 $errormessage = $Lang::tr
{'there was no file upload'};
1559 goto UPLOADCA_ERROR
;
1561 # Move uploaded ca to a temporary file
1562 (my $fh, my $filename) = tempfile
( );
1563 if (copy
($cgiparams{'FH'}, $fh) != 1) {
1565 goto UPLOADCA_ERROR
;
1567 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "$filename");
1568 if ( ! grep(/CA:TRUE/i, @temp )) {
1569 $errormessage = $Lang::tr
{'not a valid ca certificate'};
1571 goto UPLOADCA_ERROR
;
1573 unless(move
($filename, "${General::swroot}/ovpn/ca/$cgiparams{'CA_NAME'}cert.pem")) {
1574 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1576 goto UPLOADCA_ERROR
;
1580 my @casubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/$cgiparams{'CA_NAME'}cert.pem");
1583 foreach my $line (@casubject) {
1584 if ($line =~ /Subject: (.*)[\n]/) {
1586 $casubject =~ s
+/Email
+, E
+;
1587 $casubject =~ s/ ST=/ S=/;
1593 $casubject = &Header
::cleanhtml
($casubject);
1595 my $key = &General
::findhasharraykey
(\
%cahash);
1596 $cahash{$key}[0] = $cgiparams{'CA_NAME'};
1597 $cahash{$key}[1] = $casubject;
1598 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1599 # system('/usr/local/bin/ipsecctrl', 'R');
1604 ### Display ca certificate
1606 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show ca certificate'}) {
1607 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1609 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem") {
1610 &Header
::showhttpheaders
();
1611 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1612 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
1613 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ca certificate'}:");
1614 my @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1615 my $output = &Header
::cleanhtml
(join("", @output),"y");
1616 print "<pre>$output</pre>\n";
1617 &Header
::closebox
();
1618 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1619 &Header
::closebigbox
();
1620 &Header
::closepage
();
1623 $errormessage = $Lang::tr
{'invalid key'};
1627 ### Download ca certificate
1629 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download ca certificate'}) {
1630 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1632 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1633 print "Content-Type: application/octet-stream\r\n";
1634 print "Content-Disposition: filename=$cahash{$cgiparams{'KEY'}}[0]cert.pem\r\n\r\n";
1636 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1641 $errormessage = $Lang::tr
{'invalid key'};
1645 ### Remove ca certificate (step 2)
1647 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove ca certificate'} && $cgiparams{'AREUSURE'} eq 'yes') {
1648 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1649 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1651 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1652 foreach my $key (keys %confighash) {
1653 my @test = &General
::system_output
("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
1654 if (grep(/: OK/, @test)) {
1656 # if ($vpnsettings{'ENABLED'} eq 'on' ||
1657 # $vpnsettings{'ENABLED_BLUE'} eq 'on') {
1658 # system('/usr/local/bin/ipsecctrl', 'D', $key);
1660 unlink ("${General::swroot}/ovpn//certs/$confighash{$key}[1]cert.pem");
1661 unlink ("${General::swroot}/ovpn/certs/$confighash{$key}[1].p12");
1662 delete $confighash{$key};
1663 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1664 # &writeipsecfiles();
1667 unlink ("${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1668 delete $cahash{$cgiparams{'KEY'}};
1669 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1670 # system('/usr/local/bin/ipsecctrl', 'R');
1672 $errormessage = $Lang::tr
{'invalid key'};
1675 ### Remove ca certificate (step 1)
1677 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove ca certificate'}) {
1678 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1679 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1681 my $assignedcerts = 0;
1682 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1683 foreach my $key (keys %confighash) {
1684 my @test = &General
::system_output
("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
1685 if (grep(/: OK/, @test)) {
1689 if ($assignedcerts) {
1690 &Header
::showhttpheaders
();
1691 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1692 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
1693 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'are you sure'});
1695 <table><form method='post'><input type='hidden' name='AREUSURE' value='yes' />
1696 <input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />
1697 <tr><td align='center'>
1698 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>: $assignedcerts
1699 $Lang::tr{'connections are associated with this ca. deleting the ca will delete these connections as well.'}
1700 <tr><td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
1701 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td></tr>
1705 &Header
::closebox
();
1706 &Header
::closebigbox
();
1707 &Header
::closepage
();
1710 unlink ("${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1711 delete $cahash{$cgiparams{'KEY'}};
1712 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1713 # system('/usr/local/bin/ipsecctrl', 'R');
1716 $errormessage = $Lang::tr
{'invalid key'};
1720 ### Display root certificate
1722 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show root certificate'} ||
1723 $cgiparams{'ACTION'} eq $Lang::tr
{'show host certificate'}) {
1725 &Header
::showhttpheaders
();
1726 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1727 &Header
::openbigbox
('100%', 'LEFT', '', '');
1728 if ($cgiparams{'ACTION'} eq $Lang::tr
{'show root certificate'}) {
1729 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'root certificate'}:");
1730 @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
1732 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'host certificate'}:");
1733 @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1735 my $output = &Header
::cleanhtml
(join("", @output), "y");
1736 print "<pre>$output</pre>\n";
1737 &Header
::closebox
();
1738 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1739 &Header
::closebigbox
();
1740 &Header
::closepage
();
1744 ### Download root certificate
1746 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download root certificate'}) {
1747 if ( -f
"${General::swroot}/ovpn/ca/cacert.pem" ) {
1748 print "Content-Type: application/octet-stream\r\n";
1749 print "Content-Disposition: filename=cacert.pem\r\n\r\n";
1751 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
1758 ### Download host certificate
1760 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download host certificate'}) {
1761 if ( -f
"${General::swroot}/ovpn/certs/servercert.pem" ) {
1762 print "Content-Type: application/octet-stream\r\n";
1763 print "Content-Disposition: filename=servercert.pem\r\n\r\n";
1765 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1772 ### Download tls-auth key
1774 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download tls-auth key'}) {
1775 if ( -f
"${General::swroot}/ovpn/certs/ta.key" ) {
1776 print "Content-Type: application/octet-stream\r\n";
1777 print "Content-Disposition: filename=ta.key\r\n\r\n";
1779 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
1789 ### Form for generating a root certificate
1791 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'generate root/host certificates'} ||
1792 $cgiparams{'ACTION'} eq $Lang::tr
{'upload p12 file'}) {
1794 if (-f
"${General::swroot}/ovpn/ca/cacert.pem") {
1795 $errormessage = $Lang::tr
{'valid root certificate already exists'};
1796 $cgiparams{'ACTION'} = '';
1797 goto ROOTCERT_ERROR
;
1800 if (($cgiparams{'ROOTCERT_HOSTNAME'} eq '') && -e
"${General::swroot}/red/active") {
1801 if (open(IPADDR
, "${General::swroot}/red/local-ipaddress")) {
1802 my $ipaddr = <IPADDR
>;
1805 $cgiparams{'ROOTCERT_HOSTNAME'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0];
1806 if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') {
1807 $cgiparams{'ROOTCERT_HOSTNAME'} = $ipaddr;
1810 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'upload p12 file'}) {
1811 unless (ref ($cgiparams{'FH'})) {
1812 $errormessage = $Lang::tr
{'there was no file upload'};
1813 goto ROOTCERT_ERROR
;
1816 # Move uploaded certificate request to a temporary file
1817 (my $fh, my $filename) = tempfile
( );
1818 if (copy
($cgiparams{'FH'}, $fh) != 1) {
1820 goto ROOTCERT_ERROR
;
1823 # Create a temporary dirctory
1824 my $tempdir = tempdir
( CLEANUP
=> 1 );
1826 # Extract the CA certificate from the file
1827 my $pid = open(OPENSSL
, "|-");
1828 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
1829 if ($pid) { # parent
1830 if ($cgiparams{'P12_PASS'} ne '') {
1831 print OPENSSL
"$cgiparams{'P12_PASS'}\n";
1835 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1837 goto ROOTCERT_ERROR
;
1840 unless (exec ('/usr/bin/openssl', 'pkcs12', '-cacerts', '-nokeys',
1842 '-out', "$tempdir/cacert.pem")) {
1843 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1845 goto ROOTCERT_ERROR
;
1849 # Extract the Host certificate from the file
1850 $pid = open(OPENSSL
, "|-");
1851 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
1852 if ($pid) { # parent
1853 if ($cgiparams{'P12_PASS'} ne '') {
1854 print OPENSSL
"$cgiparams{'P12_PASS'}\n";
1858 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1860 goto ROOTCERT_ERROR
;
1863 unless (exec ('/usr/bin/openssl', 'pkcs12', '-clcerts', '-nokeys',
1865 '-out', "$tempdir/hostcert.pem")) {
1866 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1868 goto ROOTCERT_ERROR
;
1872 # Extract the Host key from the file
1873 $pid = open(OPENSSL
, "|-");
1874 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
1875 if ($pid) { # parent
1876 if ($cgiparams{'P12_PASS'} ne '') {
1877 print OPENSSL
"$cgiparams{'P12_PASS'}\n";
1881 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1883 goto ROOTCERT_ERROR
;
1886 unless (exec ('/usr/bin/openssl', 'pkcs12', '-nocerts',
1889 '-out', "$tempdir/serverkey.pem")) {
1890 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1892 goto ROOTCERT_ERROR
;
1896 unless(move
("$tempdir/cacert.pem", "${General::swroot}/ovpn/ca/cacert.pem")) {
1897 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1899 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1900 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1901 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1902 goto ROOTCERT_ERROR
;
1905 unless(move
("$tempdir/hostcert.pem", "${General::swroot}/ovpn/certs/servercert.pem")) {
1906 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1908 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1909 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1910 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1911 goto ROOTCERT_ERROR
;
1914 unless(move
("$tempdir/serverkey.pem", "${General::swroot}/ovpn/certs/serverkey.pem")) {
1915 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1917 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1918 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1919 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1920 goto ROOTCERT_ERROR
;
1923 goto ROOTCERT_SUCCESS
;
1925 } elsif ($cgiparams{'ROOTCERT_COUNTRY'} ne '') {
1927 # Validate input since the form was submitted
1928 if ($cgiparams{'ROOTCERT_ORGANIZATION'} eq ''){
1929 $errormessage = $Lang::tr
{'organization cant be empty'};
1930 goto ROOTCERT_ERROR
;
1932 if (length($cgiparams{'ROOTCERT_ORGANIZATION'}) >60) {
1933 $errormessage = $Lang::tr
{'organization too long'};
1934 goto ROOTCERT_ERROR
;
1936 if ($cgiparams{'ROOTCERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1937 $errormessage = $Lang::tr
{'invalid input for organization'};
1938 goto ROOTCERT_ERROR
;
1940 if ($cgiparams{'ROOTCERT_HOSTNAME'} eq ''){
1941 $errormessage = $Lang::tr
{'hostname cant be empty'};
1942 goto ROOTCERT_ERROR
;
1944 unless (&General
::validfqdn
($cgiparams{'ROOTCERT_HOSTNAME'}) || &General
::validip
($cgiparams{'ROOTCERT_HOSTNAME'})) {
1945 $errormessage = $Lang::tr
{'invalid input for hostname'};
1946 goto ROOTCERT_ERROR
;
1948 if ($cgiparams{'ROOTCERT_EMAIL'} ne '' && (! &General
::validemail
($cgiparams{'ROOTCERT_EMAIL'}))) {
1949 $errormessage = $Lang::tr
{'invalid input for e-mail address'};
1950 goto ROOTCERT_ERROR
;
1952 if (length($cgiparams{'ROOTCERT_EMAIL'}) > 40) {
1953 $errormessage = $Lang::tr
{'e-mail address too long'};
1954 goto ROOTCERT_ERROR
;
1956 if ($cgiparams{'ROOTCERT_OU'} ne '' && $cgiparams{'ROOTCERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1957 $errormessage = $Lang::tr
{'invalid input for department'};
1958 goto ROOTCERT_ERROR
;
1960 if ($cgiparams{'ROOTCERT_CITY'} ne '' && $cgiparams{'ROOTCERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1961 $errormessage = $Lang::tr
{'invalid input for city'};
1962 goto ROOTCERT_ERROR
;
1964 if ($cgiparams{'ROOTCERT_STATE'} ne '' && $cgiparams{'ROOTCERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1965 $errormessage = $Lang::tr
{'invalid input for state or province'};
1966 goto ROOTCERT_ERROR
;
1968 if ($cgiparams{'ROOTCERT_COUNTRY'} !~ /^[A-Z]*$/) {
1969 $errormessage = $Lang::tr
{'invalid input for country'};
1970 goto ROOTCERT_ERROR
;
1973 # Copy the cgisettings to vpnsettings and save the configfile
1974 $vpnsettings{'ROOTCERT_ORGANIZATION'} = $cgiparams{'ROOTCERT_ORGANIZATION'};
1975 $vpnsettings{'ROOTCERT_HOSTNAME'} = $cgiparams{'ROOTCERT_HOSTNAME'};
1976 $vpnsettings{'ROOTCERT_EMAIL'} = $cgiparams{'ROOTCERT_EMAIL'};
1977 $vpnsettings{'ROOTCERT_OU'} = $cgiparams{'ROOTCERT_OU'};
1978 $vpnsettings{'ROOTCERT_CITY'} = $cgiparams{'ROOTCERT_CITY'};
1979 $vpnsettings{'ROOTCERT_STATE'} = $cgiparams{'ROOTCERT_STATE'};
1980 $vpnsettings{'ROOTCERT_COUNTRY'} = $cgiparams{'ROOTCERT_COUNTRY'};
1981 &General
::writehash
("${General::swroot}/ovpn/settings", \
%vpnsettings);
1983 # Replace empty strings with a .
1984 (my $ou = $cgiparams{'ROOTCERT_OU'}) =~ s/^\s*$/\./;
1985 (my $city = $cgiparams{'ROOTCERT_CITY'}) =~ s/^\s*$/\./;
1986 (my $state = $cgiparams{'ROOTCERT_STATE'}) =~ s/^\s*$/\./;
1988 # Create the CA certificate
1989 my $pid = open(OPENSSL
, "|-");
1990 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
1991 if ($pid) { # parent
1992 print OPENSSL
"$cgiparams{'ROOTCERT_COUNTRY'}\n";
1993 print OPENSSL
"$state\n";
1994 print OPENSSL
"$city\n";
1995 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
1996 print OPENSSL
"$ou\n";
1997 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'} CA\n";
1998 print OPENSSL
"$cgiparams{'ROOTCERT_EMAIL'}\n";
2001 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2002 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2003 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2004 goto ROOTCERT_ERROR
;
2007 unless (exec ('/usr/bin/openssl', 'req', '-x509', '-nodes',
2008 '-days', '999999', '-newkey', 'rsa:4096', '-sha512',
2009 '-keyout', "${General::swroot}/ovpn/ca/cakey.pem",
2010 '-out', "${General::swroot}/ovpn/ca/cacert.pem",
2011 '-config', "/usr/share/openvpn/ovpn.cnf")) {
2012 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
2013 goto ROOTCERT_ERROR
;
2017 # Create the Host certificate request
2018 $pid = open(OPENSSL
, "|-");
2019 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
2020 if ($pid) { # parent
2021 print OPENSSL
"$cgiparams{'ROOTCERT_COUNTRY'}\n";
2022 print OPENSSL
"$state\n";
2023 print OPENSSL
"$city\n";
2024 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
2025 print OPENSSL
"$ou\n";
2026 print OPENSSL
"$cgiparams{'ROOTCERT_HOSTNAME'}\n";
2027 print OPENSSL
"$cgiparams{'ROOTCERT_EMAIL'}\n";
2028 print OPENSSL
".\n";
2029 print OPENSSL
".\n";
2032 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2033 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2034 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2035 goto ROOTCERT_ERROR
;
2038 unless (exec ('/usr/bin/openssl', 'req', '-nodes',
2039 '-newkey', 'rsa:4096',
2040 '-keyout', "${General::swroot}/ovpn/certs/serverkey.pem",
2041 '-out', "${General::swroot}/ovpn/certs/serverreq.pem",
2042 '-extensions', 'server',
2043 '-config', "/usr/share/openvpn/ovpn.cnf" )) {
2044 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
2045 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2046 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2047 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2048 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2049 goto ROOTCERT_ERROR
;
2053 # Sign the host certificate request
2054 # This system call is safe, because all argeuments are passed as an array.
2055 system('/usr/bin/openssl', 'ca', '-days', '999999',
2056 '-batch', '-notext',
2057 '-in', "${General::swroot}/ovpn/certs/serverreq.pem",
2058 '-out', "${General::swroot}/ovpn/certs/servercert.pem",
2059 '-extensions', 'server',
2060 '-config', "/usr/share/openvpn/ovpn.cnf");
2062 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2063 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2064 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2065 unlink ("${General::swroot}/ovpn/serverkey.pem");
2066 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2067 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
2068 &cleanssldatabase
();
2069 goto ROOTCERT_ERROR
;
2071 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2072 &deletebackupcert
();
2075 # Create an empty CRL
2076 # System call is safe, because all arguments are passed as array.
2077 system('/usr/bin/openssl', 'ca', '-gencrl',
2078 '-out', "${General::swroot}/ovpn/crls/cacrl.pem",
2079 '-config', "/usr/share/openvpn/ovpn.cnf" );
2081 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2082 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2083 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
2084 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2085 unlink ("${General::swroot}/ovpn/crls/cacrl.pem");
2086 &cleanssldatabase
();
2087 goto ROOTCERT_ERROR
;
2089 # &cleanssldatabase();
2091 # Create ta.key for tls-auth
2092 # This system call is safe, because all arguments are passed as an array.
2093 system('/usr/sbin/openvpn', '--genkey', 'secret', "${General::swroot}/ovpn/certs/ta.key");
2095 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2096 &cleanssldatabase
();
2097 goto ROOTCERT_ERROR
;
2099 goto ROOTCERT_SUCCESS
;
2102 if ($cgiparams{'ACTION'} ne '') {
2103 &Header
::showhttpheaders
();
2104 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2105 &Header
::openbigbox
('100%', 'LEFT', '', '');
2108 &Header
::errorbox
($errormessage);
2110 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'generate root/host certificates'}:");
2112 <form method='post' enctype='multipart/form-data'>
2113 <table width='100%' border='0' cellspacing='1' cellpadding='0'>
2114 <tr><td width='30%' class='base'>$Lang::tr{'organization name'}: <img src='/blob.gif' alt='*' /></td>
2115 <td width='35%' class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_ORGANIZATION' value='$cgiparams{'ROOTCERT_ORGANIZATION'}' size='32' /></td>
2116 <td width='35%' colspan='2'> </td></tr>
2117 <tr><td class='base'>$Lang::tr{'ipfires hostname'}: <img src='/blob.gif' alt='*' /></td>
2118 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_HOSTNAME' value='$cgiparams{'ROOTCERT_HOSTNAME'}' size='32' /></td>
2119 <td colspan='2'> </td></tr>
2120 <tr><td class='base'>$Lang::tr{'your e-mail'}:</td>
2121 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_EMAIL' value='$cgiparams{'ROOTCERT_EMAIL'}' size='32' /></td>
2122 <td colspan='2'> </td></tr>
2123 <tr><td class='base'>$Lang::tr{'your department'}:</td>
2124 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_OU' value='$cgiparams{'ROOTCERT_OU'}' size='32' /></td>
2125 <td colspan='2'> </td></tr>
2126 <tr><td class='base'>$Lang::tr{'city'}:</td>
2127 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_CITY' value='$cgiparams{'ROOTCERT_CITY'}' size='32' /></td>
2128 <td colspan='2'> </td></tr>
2129 <tr><td class='base'>$Lang::tr{'state or province'}:</td>
2130 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_STATE' value='$cgiparams{'ROOTCERT_STATE'}' size='32' /></td>
2131 <td colspan='2'> </td></tr>
2132 <tr><td class='base'>$Lang::tr{'country'}:</td>
2133 <td class='base'><select name='ROOTCERT_COUNTRY'>
2137 foreach my $country (sort keys %{Countries
::countries
}) {
2138 print "<option value='$Countries::countries{$country}'";
2139 if ( $Countries::countries
{$country} eq $cgiparams{'ROOTCERT_COUNTRY'} ) {
2140 print " selected='selected'";
2142 print ">$country</option>";
2148 <td><input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' /></td>
2149 <td> </td><td> </td></tr>
2150 <tr><td class='base' colspan='4' align='left'>
2151 <img src='/blob.gif' valign='top' alt='*' /> $Lang::tr{'required field'}</td></tr>
2152 <tr><td colspan='2'><br></td></tr>
2155 <table width='100%'>
2156 <tr><td colspan='4'><hr></td></tr>
2157 <tr><td class='base' nowrap='nowrap'>$Lang::tr{'upload p12 file'}: <img src='/blob.gif' alt='*' /></td>
2158 <td nowrap='nowrap'><input type='file' name='FH' size='32'></td>
2159 <td colspan='2'> </td></tr>
2160 <tr><td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
2161 <td class='base' nowrap='nowrap'><input type='password' name='P12_PASS' value='$cgiparams{'P12_PASS'}' size='32' /></td>
2162 <td colspan='2'> </td></tr>
2164 <td><input type='submit' name='ACTION' value='$Lang::tr{'upload p12 file'}' /></td>
2165 <td colspan='2'> </td></tr>
2166 <tr><td class='base' colspan='4' align='left'>
2167 <img src='/blob.gif' valign='top' alt='*' > $Lang::tr{'required field'}</td>
2172 &Header
::closebox
();
2173 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2174 &Header
::closebigbox
();
2175 &Header
::closepage
();
2180 &General
::system("chmod", "600", "${General::swroot}/ovpn/certs/serverkey.pem");
2181 # if ($vpnsettings{'ENABLED'} eq 'on' ||
2182 # $vpnsettings{'ENABLE_BLUE'} eq 'on') {
2183 # system('/usr/local/bin/ipsecctrl', 'S');
2187 ### Enable/Disable connection
2190 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'toggle enable disable'}) {
2191 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2193 my @ps = &General
::system_output
("/bin/ps", "ax");
2195 if(grep(/$confighash{$cgiparams{'KEY'}}[1]/, @ps)) {
2199 if ($confighash{$cgiparams{'KEY'}}) {
2200 if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
2201 $confighash{$cgiparams{'KEY'}}[0] = 'on';
2202 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2204 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2205 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "start", "$confighash{$cgiparams{'KEY'}}[1]");
2206 &writecollectdconf
();
2210 $confighash{$cgiparams{'KEY'}}[0] = 'off';
2211 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2213 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2214 if ($n2nactive ne '') {
2215 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
2216 &writecollectdconf
();
2223 ### Download OpenVPN client package
2226 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'dl client arch'}) {
2227 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2229 my $clientovpn = '';
2231 my $tempdir = tempdir
( CLEANUP
=> 1 );
2232 my $zippath = "$tempdir/";
2235 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2236 my $zipname = "$confighash{$cgiparams{'KEY'}}[1]-Client.zip";
2237 my $zippathname = "$zippath$zipname";
2238 $clientovpn = "$confighash{$cgiparams{'KEY'}}[1].conf";
2239 my @ovsubnettemp = split(/\./,$confighash{$cgiparams{'KEY'}}[27]);
2240 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
2242 my @remsubnet = split(/\//,$confighash{$cgiparams{'KEY'}}[8]);
2243 my $n2nfragment = '';
2245 open(CLIENTCONF
, ">$tempdir/$clientovpn") or die "Unable to open tempfile: $!";
2246 flock CLIENTCONF
, 2;
2248 my $zip = Archive
::Zip-
>new();
2249 print CLIENTCONF
"# IPFire n2n Open VPN Client Config by ummeegge und m.a.d\n";
2250 print CLIENTCONF
"# \n";
2251 print CLIENTCONF
"# User Security\n";
2252 print CLIENTCONF
"user nobody\n";
2253 print CLIENTCONF
"group nobody\n";
2254 print CLIENTCONF
"persist-tun\n";
2255 print CLIENTCONF
"persist-key\n";
2256 print CLIENTCONF
"script-security 2\n";
2257 print CLIENTCONF
"# IP/DNS for remote Server Gateway\n";
2258 print CLIENTCONF
"remote $vpnsettings{'VPN_IP'}\n";
2259 print CLIENTCONF
"float\n";
2260 print CLIENTCONF
"# IP adresses of the VPN Subnet\n";
2261 print CLIENTCONF
"ifconfig $ovsubnet.2 $ovsubnet.1\n";
2262 print CLIENTCONF
"# Server Gateway Network\n";
2263 print CLIENTCONF
"route $remsubnet[0] $remsubnet[1]\n";
2264 print CLIENTCONF
"# tun Device\n";
2265 print CLIENTCONF
"dev tun\n";
2266 print CLIENTCONF
"#Logfile for statistics\n";
2267 print CLIENTCONF
"status-version 1\n";
2268 print CLIENTCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
2269 print CLIENTCONF
"# Port and Protokoll\n";
2270 print CLIENTCONF
"port $confighash{$cgiparams{'KEY'}}[29]\n";
2272 if ($confighash{$cgiparams{'KEY'}}[28] eq 'tcp') {
2273 print CLIENTCONF
"proto tcp4-client\n";
2274 print CLIENTCONF
"# Packet size\n";
2275 if ($confighash{$cgiparams{'KEY'}}[31] eq '') {
2278 $tunmtu = $confighash{$cgiparams{'KEY'}}[31];
2280 print CLIENTCONF
"tun-mtu $tunmtu\n";
2283 if ($confighash{$cgiparams{'KEY'}}[28] eq 'udp') {
2284 print CLIENTCONF
"proto udp4\n";
2285 print CLIENTCONF
"# Paketsize\n";
2286 if ($confighash{$cgiparams{'KEY'}}[31] eq '') {
2289 $tunmtu = $confighash{$cgiparams{'KEY'}}[31];
2291 print CLIENTCONF
"tun-mtu $tunmtu\n";
2292 if ($confighash{$cgiparams{'KEY'}}[24] ne '') {
2293 print CLIENTCONF
"fragment $confighash{$cgiparams{'KEY'}}[24]\n";
2295 if ($confighash{$cgiparams{'KEY'}}[23] eq 'on') {
2296 print CLIENTCONF
"mssfix\n";
2298 print CLIENTCONF
"mssfix 0\n";
2302 # Check host certificate if X509 is RFC3280 compliant.
2303 # If not, old --ns-cert-type directive will be used.
2304 # If appropriate key usage extension exists, new --remote-cert-tls directive will be used.
2305 my @hostcert = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
2306 if (! grep(/TLS Web Server Authentication/, @hostcert)) {
2307 print CLIENTCONF
"ns-cert-type server\n";
2309 print CLIENTCONF
"remote-cert-tls server\n";
2311 print CLIENTCONF
"# Auth. Client\n";
2312 print CLIENTCONF
"tls-client\n";
2313 print CLIENTCONF
"# Cipher\n";
2314 print CLIENTCONF
"cipher $confighash{$cgiparams{'KEY'}}[40]\n";
2316 if ($confighash{$cgiparams{'KEY'}}[4] eq 'cert' && -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12") {
2317 print CLIENTCONF
"pkcs12 ${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12\r\n";
2318 $zip->addFile( "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12", "$confighash{$cgiparams{'KEY'}}[1].p12") or die "Can't add file $confighash{$cgiparams{'KEY'}}[1].p12\n";
2321 # If GCM cipher is used, do not use --auth
2322 if (($confighash{$cgiparams{'KEY'}}[40] eq 'AES-256-GCM') ||
2323 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-192-GCM') ||
2324 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-128-GCM')) {
2325 print CLIENTCONF
unless "# HMAC algorithm\n";
2326 print CLIENTCONF
unless "auth $confighash{$cgiparams{'KEY'}}[39]\n";
2328 print CLIENTCONF
"# HMAC algorithm\n";
2329 print CLIENTCONF
"auth $confighash{$cgiparams{'KEY'}}[39]\n";
2332 if ($confighash{$cgiparams{'KEY'}}[30] eq 'on') {
2333 print CLIENTCONF
"# Enable Compression\n";
2334 print CLIENTCONF
"comp-lzo\n";
2336 print CLIENTCONF
"# Debug Level\n";
2337 print CLIENTCONF
"verb 3\n";
2338 print CLIENTCONF
"# Tunnel check\n";
2339 print CLIENTCONF
"keepalive 10 60\n";
2340 print CLIENTCONF
"# Start as daemon\n";
2341 print CLIENTCONF
"daemon $confighash{$cgiparams{'KEY'}}[1]n2n\n";
2342 print CLIENTCONF
"writepid /var/run/$confighash{$cgiparams{'KEY'}}[1]n2n.pid\n";
2343 print CLIENTCONF
"# Activate Management Interface and Port\n";
2344 if ($confighash{$cgiparams{'KEY'}}[22] eq '') {
2345 print CLIENTCONF
"management localhost $confighash{$cgiparams{'KEY'}}[29]\n"
2347 print CLIENTCONF
"management localhost $confighash{$cgiparams{'KEY'}}[22]\n"
2349 print CLIENTCONF
"# remsub $confighash{$cgiparams{'KEY'}}[11]\n";
2350 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
2351 print CLIENTCONF
"providers legacy default\n";
2355 $zip->addFile( "$tempdir/$clientovpn", $clientovpn) or die "Can't add file $clientovpn\n";
2356 my $status = $zip->writeToFileNamed($zippathname);
2358 open(DLFILE
, "<$zippathname") or die "Unable to open $zippathname: $!";
2359 @fileholder = <DLFILE
>;
2360 print "Content-Type:application/x-download\n";
2361 print "Content-Disposition:attachment;filename=$zipname\n\n";
2366 my $name = $confighash{$cgiparams{'KEY'}}[1];
2369 &Header
::showhttpheaders
({
2370 "Content-Type" => "application/x-openvpn-profile",
2371 "Content-Disposition" => "attachment; filename=${name}.ovpn",
2374 print "########################################################################\n";
2375 print "# IPFire OpenVPN Client Configuration for \"${name}\"\n";
2376 print "########################################################################\n";
2381 # This is a layer 3 VPN
2384 # Point the client to this server
2385 print "remote $vpnsettings{'VPN_IP'} $vpnsettings{'DDEST_PORT'}\n";
2386 print "proto $vpnsettings{'DPROTOCOL'}\n";
2388 # Configure the MTU of the tunnel interface
2389 print "tun-mtu $vpnsettings{'DMTU'}\n";
2391 # Ask the client to verify the server certificate
2392 if (&is_cert_rfc3280_compliant
("${General::swroot}/ovpn/certs/servercert.pem")) {
2393 print "remote-cert-tls server\n";
2395 print "verify-x509-name $vpnsettings{'ROOTCERT_HOSTNAME'} name\n";
2397 if ($vpnsettings{'MSSFIX'} eq 'on') {
2402 if ($vpnsettings{'FRAGMENT'} ne '' && $vpnsettings{'DPROTOCOL'} ne 'tcp' ) {
2403 print "fragment $vpnsettings{'FRAGMENT'}\n";
2406 # We no longer send any cryptographic configuration since 2.6.
2407 # That way, we will be able to push this from the server.
2408 # Therefore we always mandate NCP for new clients.
2410 if ($vpnsettings{'DAUTH'} ne "") {
2411 print "auth $vpnsettings{'DAUTH'}\n";
2414 # Disable storing any credentials in memory
2415 print "auth-nocache\n";
2417 # Set a fake user name for authentication
2418 print "auth-token-user USER\n";
2419 print "auth-token TOTP\n";
2421 # If the server is asking for TOTP this needs to happen interactively
2422 print "auth-retry interact\n";
2424 # Add provider line if certificate is legacy type
2425 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
2426 print "providers legacy default\n";
2430 open(FILE
, "<${General::swroot}/ovpn/ca/cacert.pem");
2440 open(FILE
, "<${General::swroot}/ovpn/certs/${name}.p12");
2441 print "\n<pkcs12>\n";
2442 print &MIME
::Base64
::encode_base64
(do { local $/; <FILE
> });
2443 print "</pkcs12>\n";
2447 if ($vpnsettings{'TLSAUTH'} eq 'on') {
2448 open(FILE
, "<${General::swroot}/ovpn/certs/ta.key");
2449 print "\n<tls-auth>\n";
2454 print "</tls-auth>\n";
2461 ### Remove connection
2465 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove'}) {
2466 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2468 if ($confighash{$cgiparams{'KEY'}}) {
2469 # Revoke certificate if certificate was deleted and rewrite the CRL
2470 &General
::system("/usr/bin/openssl", "ca", "-revoke", "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2471 &General
::system("/usr/bin/openssl", "ca", "-gencrl", "-out", "${General::swroot}/ovpn/crls/cacrl.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2473 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net') {
2474 # Stop the N2N connection before it is removed
2475 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
2477 my $conffile = glob("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]/$confighash{$cgiparams{'KEY'}}[1].conf");
2478 my $certfile = glob("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2482 if (-e
"${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") {
2483 rmdir ("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") || die "Kann Verzeichnis nicht loeschen: $!";
2487 unlink ("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
2488 unlink ("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2490 # Delete CCD files and routes
2492 if (-f
"${General::swroot}/ovpn/ccd/$confighash{$cgiparams{'KEY'}}[2]")
2494 unlink "${General::swroot}/ovpn/ccd/$confighash{$cgiparams{'KEY'}}[2]";
2497 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
2498 foreach my $key (keys %ccdroutehash) {
2499 if ($ccdroutehash{$key}[0] eq $confighash{$cgiparams{'KEY'}}[1]){
2500 delete $ccdroutehash{$key};
2503 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
2505 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
2506 foreach my $key (keys %ccdroute2hash) {
2507 if ($ccdroute2hash{$key}[0] eq $confighash{$cgiparams{'KEY'}}[1]){
2508 delete $ccdroute2hash{$key};
2511 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
2514 # Update collectd configuration and delete all RRD files of the removed connection
2515 &writecollectdconf
();
2516 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "delete", "$confighash{$cgiparams{'KEY'}}[1]");
2518 delete $confighash{$cgiparams{'KEY'}};
2519 &General
::system("/usr/bin/openssl", "ca", "-gencrl", "-out", "${General::swroot}/ovpn/crls/cacrl.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2520 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2523 $errormessage = $Lang::tr
{'invalid key'};
2525 &General
::firewall_reload
();
2528 ### Download PKCS12 file
2530 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download pkcs12 file'}) {
2531 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2533 print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . ".p12\r\n";
2534 print "Content-Type: application/octet-stream\r\n\r\n";
2536 open(FILE
, "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2544 ### Display certificate
2546 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show certificate'}) {
2547 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2549 if ( -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
2550 &Header
::showhttpheaders
();
2551 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2552 &Header
::openbigbox
('100%', 'LEFT', '', '');
2553 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'certificate'}:");
2554 my @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
2555 my $output = &Header
::cleanhtml
(join("", @output), "y");
2556 print "<pre>$output</pre>\n";
2557 &Header
::closebox
();
2558 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2559 &Header
::closebigbox
();
2560 &Header
::closepage
();
2565 ### Display OTP QRCode
2567 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show otp qrcode'}) {
2568 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2570 my $qrcode = Imager
::QRCode-
>new(
2577 lightcolor
=> Imager
::Color-
>new(255, 255, 255),
2578 darkcolor
=> Imager
::Color-
>new(0, 0, 0),
2580 my $cn = uri_encode
($confighash{$cgiparams{'KEY'}}[2]);
2581 my $secret = encode_base32
(pack('H*', $confighash{$cgiparams{'KEY'}}[44]));
2582 my $issuer = uri_encode
("$mainsettings{'HOSTNAME'}.$mainsettings{'DOMAINNAME'}");
2583 my $qrcodeimg = $qrcode->plot("otpauth://totp/$cn?secret=$secret&issuer=$issuer");
2585 $qrcodeimg->write(data
=> \
$qrcodeimgdata, type
=> 'png')
2586 or die $qrcodeimg->errstr;
2587 $qrcodeimgdata = encode_base64
($qrcodeimgdata, '');
2589 &Header
::showhttpheaders
();
2590 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2591 &Header
::openbigbox
('100%', 'LEFT', '', '');
2592 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'otp qrcode'}:");
2594 $Lang::tr{'secret'}: $secret</br></br>
2595 <img alt="$Lang::tr{'otp qrcode'}" src="data:image/png;base64,$qrcodeimgdata">
2597 &Header
::closebox
();
2598 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2599 &Header
::closebigbox
();
2600 &Header
::closepage
();
2604 ### Display tls-auth key
2606 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show tls-auth key'}) {
2608 if (! -e
"${General::swroot}/ovpn/certs/ta.key") {
2609 $errormessage = $Lang::tr
{'not present'};
2611 &Header
::showhttpheaders
();
2612 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2613 &Header
::openbigbox
('100%', 'LEFT', '', '');
2614 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ta key'}:");
2616 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
2617 my @output = <FILE
>;
2620 my $output = &Header
::cleanhtml
(join("", @output),"y");
2621 print "<pre>$output</pre>\n";
2622 &Header
::closebox
();
2623 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2624 &Header
::closebigbox
();
2625 &Header
::closepage
();
2630 ### Display Certificate Revoke List
2632 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show crl'}) {
2633 # &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2635 if (! -e
"${General::swroot}/ovpn/crls/cacrl.pem") {
2636 $errormessage = $Lang::tr
{'not present'};
2638 &Header
::showhttpheaders
();
2639 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2640 &Header
::openbigbox
('100%', 'LEFT', '', '');
2641 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'crl'}:");
2642 my @output = &General
::system_output
("/usr/bin/openssl", "crl", "-text", "-noout", "-in", "${General::swroot}/ovpn/crls/cacrl.pem");
2643 my $output = &Header
::cleanhtml
(join("", @output), "y");
2644 print "<pre>$output</pre>\n";
2645 &Header
::closebox
();
2646 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2647 &Header
::closebigbox
();
2648 &Header
::closepage
();
2653 ### Advanced Server Settings
2656 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'advanced server'}) {
2658 $selected{'DPROTOCOL'}{'udp'} = '';
2659 $selected{'DPROTOCOL'}{'tcp'} = '';
2660 $selected{'DPROTOCOL'}{$vpnsettings{'DPROTOCOL'}} = 'SELECTED';
2662 $checked{'REDIRECT_GW_DEF1'}{'off'} = '';
2663 $checked{'REDIRECT_GW_DEF1'}{'on'} = '';
2664 $checked{'REDIRECT_GW_DEF1'}{$vpnsettings{'REDIRECT_GW_DEF1'}} = 'CHECKED';
2665 $checked{'MSSFIX'}{'off'} = '';
2666 $checked{'MSSFIX'}{'on'} = '';
2667 $checked{'MSSFIX'}{$vpnsettings{'MSSFIX'}} = 'CHECKED';
2669 # Split data ciphers
2670 my @data_ciphers = split(/\|/, $vpnsettings{'DATACIPHERS'});
2672 # Select the correct ones
2673 $selected{'DATACIPHERS'} = ();
2674 foreach my $cipher (@SUPPORTED_CIPHERS) {
2675 $selected{'DATACIPHERS'}{$cipher} = grep(/^$cipher$/, @data_ciphers) ? "selected" : "";
2679 $vpnsettings{'ROUTES_PUSH'} =~ s/\|/\n/g;
2681 $selected{'DCIPHER'}{'AES-256-GCM'} = '';
2682 $selected{'DCIPHER'}{'AES-192-GCM'} = '';
2683 $selected{'DCIPHER'}{'AES-128-GCM'} = '';
2684 $selected{'DCIPHER'}{'CAMELLIA-256-CBC'} = '';
2685 $selected{'DCIPHER'}{'CAMELLIA-192-CBC'} = '';
2686 $selected{'DCIPHER'}{'CAMELLIA-128-CBC'} = '';
2687 $selected{'DCIPHER'}{'AES-256-CBC'} = '';
2688 $selected{'DCIPHER'}{'AES-192-CBC'} = '';
2689 $selected{'DCIPHER'}{'AES-128-CBC'} = '';
2690 $selected{'DCIPHER'}{'DES-EDE3-CBC'} = '';
2691 $selected{'DCIPHER'}{'DESX-CBC'} = '';
2692 $selected{'DCIPHER'}{'SEED-CBC'} = '';
2693 $selected{'DCIPHER'}{'DES-EDE-CBC'} = '';
2694 $selected{'DCIPHER'}{'CAST5-CBC'} = '';
2695 $selected{'DCIPHER'}{'BF-CBC'} = '';
2696 $selected{'DCIPHER'}{'DES-CBC'} = '';
2697 $selected{'DCIPHER'}{$vpnsettings{'DCIPHER'}} = 'SELECTED';
2699 $selected{'DAUTH'}{'whirlpool'} = '';
2700 $selected{'DAUTH'}{'SHA512'} = '';
2701 $selected{'DAUTH'}{'SHA384'} = '';
2702 $selected{'DAUTH'}{'SHA256'} = '';
2703 $selected{'DAUTH'}{'SHA1'} = '';
2704 $selected{'DAUTH'}{$vpnsettings{'DAUTH'}} = 'SELECTED';
2706 $checked{'TLSAUTH'}{'off'} = '';
2707 $checked{'TLSAUTH'}{'on'} = '';
2708 $checked{'TLSAUTH'}{$vpnsettings{'TLSAUTH'}} = 'CHECKED';
2710 &Header
::showhttpheaders
();
2711 &Header
::openpage
($Lang::tr
{'status ovpn'}, 1, '');
2712 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
2715 &Header
::errorbox
($errormessage);
2717 &Header
::opensection
();
2720 <form method='POST' enctype='multipart/form-data'>
2721 <h6>$Lang::tr{'ovpn protocol settings'}</h6>
2723 <table class="form">
2725 <td>$Lang::tr{'ovpn transport protocol'}</td>
2727 <select name='DPROTOCOL'>
2728 <option value='udp' $selected{'DPROTOCOL'}{'udp'}>UDP</option>
2729 <option value='tcp' $selected{'DPROTOCOL'}{'tcp'}>TCP</option>
2735 <td>$Lang::tr{'destination port'}</td>
2737 <input type='number' name='DDEST_PORT' value='$vpnsettings{'DDEST_PORT'}' />
2742 <td>$Lang::tr{'mtu'}</td>
2744 <input type='number' name='DMTU' value='$vpnsettings{'DMTU'}' min="1280" max="9000" />
2751 <input type='checkbox' name='MSSFIX' $checked{'MSSFIX'}{'on'} />
2758 <input type='TEXT' name='FRAGMENT' value='$vpnsettings{'FRAGMENT'}' />
2763 <h6>$Lang::tr{'ovpn crypto settings'}</h6>
2765 <table class="form">
2768 $Lang::tr{'ovpn ciphers'}
2772 <select name='DATACIPHERS' multiple required>
2775 foreach my $cipher (@SUPPORTED_CIPHERS) {
2776 my $name = $CIPHERS{$cipher} // $cipher;
2779 <option value='$cipher' $selected{'DATACIPHERS'}{$cipher}>
2792 $Lang::tr{'ovpn ha'}
2796 <select name='DAUTH'>
2797 <option value='whirlpool' $selected{'DAUTH'}{'whirlpool'}>Whirlpool (512 $Lang::tr{'bit'})</option>
2798 <option value='SHA512' $selected{'DAUTH'}{'SHA512'}>SHA2 (512 $Lang::tr{'bit'})</option>
2799 <option value='SHA384' $selected{'DAUTH'}{'SHA384'}>SHA2 (384 $Lang::tr{'bit'})</option>
2800 <option value='SHA256' $selected{'DAUTH'}{'SHA256'}>SHA2 (256 $Lang::tr{'bit'})</option>
2801 <option value='SHA1' $selected{'DAUTH'}{'SHA1'}>SHA1 (160 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2808 $Lang::tr{'ovpn tls auth'}
2812 <input type='checkbox' name='TLSAUTH' $checked{'TLSAUTH'}{'on'} />
2818 $Lang::tr{'ovpn fallback cipher'}
2822 <select name='DCIPHER'>
2823 <option value='' $selected{'DCIPHER'}{''}>- $Lang::tr{'Disabled'} -</option>
2824 <option value='AES-256-GCM' $selected{'DCIPHER'}{'AES-256-GCM'}>AES-GCM (256 $Lang::tr{'bit'})</option>
2825 <option value='AES-192-GCM' $selected{'DCIPHER'}{'AES-192-GCM'}>AES-GCM (192 $Lang::tr{'bit'})</option>
2826 <option value='AES-128-GCM' $selected{'DCIPHER'}{'AES-128-GCM'}>AES-GCM (128 $Lang::tr{'bit'})</option>
2827 <option value='CAMELLIA-256-CBC' $selected{'DCIPHER'}{'CAMELLIA-256-CBC'}>CAMELLIA-CBC (256 $Lang::tr{'bit'})</option>
2828 <option value='CAMELLIA-192-CBC' $selected{'DCIPHER'}{'CAMELLIA-192-CBC'}>CAMELLIA-CBC (192 $Lang::tr{'bit'})</option>
2829 <option value='CAMELLIA-128-CBC' $selected{'DCIPHER'}{'CAMELLIA-128-CBC'}>CAMELLIA-CBC (128 $Lang::tr{'bit'})</option>
2830 <option value='AES-256-CBC' $selected{'DCIPHER'}{'AES-256-CBC'}>AES-CBC (256 $Lang::tr{'bit'})</option>
2831 <option value='AES-192-CBC' $selected{'DCIPHER'}{'AES-192-CBC'}>AES-CBC (192 $Lang::tr{'bit'})</option>
2832 <option value='AES-128-CBC' $selected{'DCIPHER'}{'AES-128-CBC'}>AES-CBC (128 $Lang::tr{'bit'})</option>
2833 <option value='SEED-CBC' $selected{'DCIPHER'}{'SEED-CBC'}>SEED-CBC (128 $Lang::tr{'bit'})</option>
2834 <option value='DES-EDE3-CBC' $selected{'DCIPHER'}{'DES-EDE3-CBC'}>DES-EDE3-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2835 <option value='DESX-CBC' $selected{'DCIPHER'}{'DESX-CBC'}>DESX-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2836 <option value='DES-EDE-CBC' $selected{'DCIPHER'}{'DES-EDE-CBC'}>DES-EDE-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2837 <option value='BF-CBC' $selected{'DCIPHER'}{'BF-CBC'}>BF-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2838 <option value='CAST5-CBC' $selected{'DCIPHER'}{'CAST5-CBC'}>CAST5-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2846 $Lang::tr{'ovpn fallback cipher help'}
2851 <h6>$Lang::tr{'ovpn dhcp settings'}</h6>
2853 <table class="form">
2857 <input type='TEXT' name='DHCP_DOMAIN' value='$vpnsettings{'DHCP_DOMAIN'}' size='30' />
2863 <input type='TEXT' name='DHCP_DNS' value='$vpnsettings{'DHCP_DNS'}' size='30' />
2869 <input type='TEXT' name='DHCP_WINS' value='$vpnsettings{'DHCP_WINS'}' size='30' />
2874 <h6>$Lang::tr{'ovpn routing settings'}</h6>
2876 <table class="form">
2878 <td>$Lang::tr{'ovpn push default route'}</td>
2880 <input type='checkbox' name='REDIRECT_GW_DEF1' $checked{'REDIRECT_GW_DEF1'}{'on'} />
2885 <td>$Lang::tr{'ovpn routes push'}</td>
2887 <textarea name='ROUTES_PUSH' cols='26' rows='6' wrap='off'>$vpnsettings{'ROUTES_PUSH'}</textarea>
2892 <h6>$Lang::tr{'ovpn misc settings'}</h6>
2894 <table class="form">
2896 <td>Max-Clients</td>
2898 <input type='text' name='MAX_CLIENTS' value='$vpnsettings{'MAX_CLIENTS'}' />
2904 <input type='submit' name='ACTION' value='$Lang::tr{'save-adv-options'}' />
2905 <input type='submit' name='ACTION' value='$Lang::tr{'cancel-adv-options'}' />
2911 &Header
::closesection
();
2912 &Header
::closebigbox
();
2914 &Header
::closepage
();
2918 # Add, delete or edit CCD net
2920 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'ccd net'} ||
2921 $cgiparams{'ACTION'} eq "ccd-add" ||
2922 $cgiparams{'ACTION'} eq "ccd-delete" ||
2923 $cgiparams{'ACTION'} eq "ccd-edit" ||
2924 $cgiparams{'ACTION'} eq 'ccd-edit-save'){
2925 &Header
::showhttpheaders
();
2927 &Header
::openpage
($Lang::tr
{'ccd net'}, 1, '');
2929 &Header
::openbigbox
('100%', 'LEFT', '', '');
2932 if ($cgiparams{'ACTION'} eq "ccd-delete") {
2933 $errormessage = &delccdnet
($cgiparams{'name'});
2936 } elsif ($cgiparams{'ACTION'} eq 'ccd-edit-save') {
2937 $errormessage = &modccdnet
($cgiparams{'subnet'}, $cgiparams{'name'});
2940 if ($errormessage eq "") {
2941 $cgiparams{"name"} = "";
2942 $cgiparams{"subnet"} = "";
2946 } elsif ($cgiparams{'ACTION'} eq "ccd-add") {
2947 $errormessage = &addccdnet
($cgiparams{'name'}, $cgiparams{'subnet'});
2950 if ($errormessage eq "") {
2951 $cgiparams{"name"} = "";
2952 $cgiparams{"subnet"} = "";
2956 &Header
::errorbox
($errormessage);
2958 my %ccdconfhash = ();
2959 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
2961 &Header
::opensection
();
2966 $Lang::tr{'ccd name'}
2970 $Lang::tr{'network'}
2974 $Lang::tr{'ccd used'}
2977 <th colspan="2"></th>
2981 foreach my $key (sort { uc($ccdconfhash{$a}[0]) cmp uc($ccdconfhash{$b}[0]) } keys %ccdconfhash) {
2982 my $name = $ccdconfhash{$key}[0];
2983 my $subnet = $ccdconfhash{$key}[1];
2985 my $ccdhosts = scalar &get_addresses_in_use
($subnet);
2986 my $maxhosts = &ccdmaxclients
($subnet);
2994 <td class="text-center">
2998 <td class="text-center">
2999 ${ccdhosts}/${maxhosts}
3002 <td class="text-center">
3003 <form method='post' />
3004 <input type='image' src='/images/edit.gif' align='middle'
3005 alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
3006 <input type='hidden' name='ACTION' value='ccd-edit'/>
3007 <input type='hidden' name='name' value='$name' />
3008 <input type='hidden' name='subnet' value='$subnet' />
3012 <td class="text-center">
3013 <form method='post' />
3014 <input type='hidden' name='ACTION' value='ccd-delete'/>
3015 <input type='hidden' name='name' value='$name' />
3016 <input type='image' src='/images/delete.gif' align='middle'
3017 alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
3024 &Header
::closesection
();
3026 &Header
::openbox
('100%', 'LEFT',
3027 ($cgiparams{'ACTION'} eq "ccd-edit") ? $Lang::tr
{'ccd modify'} : $Lang::tr
{'ccd add'});
3029 # The subnet cannot be edited
3030 my $readonly = ($cgiparams{'ACTION'} eq "ccd-edit") ? "readonly" : "";
3031 my $action = ($cgiparams{'ACTION'} eq "ccd-edit") ? "ccd-edit-save" : "ccd-add";
3034 <form method='post'>
3035 <table class="form">
3037 <td>$Lang::tr{'ccd name'}</td>
3039 <input type='TEXT' name='name' value='$cgiparams{'name'}' />
3044 <td>$Lang::tr{'ccd subnet'}</td>
3046 <input type='TEXT' name='subnet' value='$cgiparams{'subnet'}'
3053 <input type='hidden' name='ACTION' value='$action' />
3054 <input type='submit' value='$Lang::tr{'save'}' />
3060 &Header
::closebox
();
3063 <div class="text-center">
3064 <a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a>
3068 &Header
::closebigbox
();
3069 &Header
::closepage
();
3074 ### Openvpn Connections Statistics
3076 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'ovpn con stat'}) {
3077 &Header
::showhttpheaders
();
3078 &Header
::openpage
($Lang::tr
{'ovpn con stat'}, 1, '');
3079 &Header
::openbigbox
('100%', 'LEFT', '', '');
3081 &Header
::opensection
();
3086 <th>$Lang::tr{'common name'}</th>
3087 <th>$Lang::tr{'real address'}</th>
3088 <th>$Lang::tr{'country'}</th>
3089 <th>$Lang::tr{'virtual address'}</th>
3090 <th>$Lang::tr{'loged in at'}</th>
3091 <th>$Lang::tr{'bytes sent'}</th>
3092 <th>$Lang::tr{'bytes received'}</th>
3093 <th>$Lang::tr{'last activity'}</th>
3097 open(FILE
, "/usr/local/bin/openvpnctrl rw log |") or die "Unable to open $RW_STATUS: $!";
3098 my @current = <FILE
>;
3105 my %userlookup = ();
3107 foreach my $line (@current) {
3110 if ($line =~ /^Updated,(.+)/) {
3111 @match = split(/^Updated,(.+)/, $line);
3112 $status = $match[1];
3114 } elsif ( $line =~ /^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/) {
3115 @match = split(m/^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/, $line);
3118 next if ($match[1] eq "Common Name");
3120 $userlookup{$match[2]} = $uid;
3121 $users[$uid]{'CommonName'} = $match[1];
3122 $users[$uid]{'RealAddress'} = $match[2];
3123 $users[$uid]{'BytesReceived'} = &General
::formatBytes
($match[3]);
3124 $users[$uid]{'BytesSent'} = &General
::formatBytes
($match[4]);
3125 $users[$uid]{'Since'} = $match[5];
3127 my $address = (split ':', $users[$uid]{'RealAddress'})[0];
3128 $users[$uid]{'Country'} = &Location
::Functions
::lookup_country_code
($address);
3131 } elsif ($line =~ /^(\d+\.\d+\.\d+\.\d+),(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(.+)/) {
3132 @match = split(m/^(\d+\.\d+\.\d+\.\d+),(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(.+)/, $line);
3135 next if ($match[1] eq "Virtual Address");
3137 my $address = $match[3];
3138 #find the uid in the lookup table
3139 $uid = $userlookup{$address};
3140 $users[$uid]{'VirtualAddress'} = $match[1];
3141 $users[$uid]{'LastRef'} = $match[4];
3145 foreach my $id (keys @users) {
3146 my $user = $users[$id];
3148 my $flag_icon = &Location
::Functions
::get_flag_icon
($user->{"Country"});
3153 $user->{"CommonName"}
3156 <td class="text-center">
3157 $user->{"RealAddress"}
3160 <td class="text-center">
3161 <a href="country.cgi#$user->{"Country"}">
3162 <img src="$flag_icon" border='0' align='absmiddle'
3163 alt='$user->{"Country"}' title='$user->{"Country"}' />
3167 <td class="text-center">
3168 $user->{"VirtualAddress"}
3171 <td class="text-center">
3175 <td class="text-right">
3176 $user->{"BytesSent"}
3179 <td class="text-right">
3180 $user->{"BytesReceived"}
3183 <td class="text-right">
3193 <p class="text-center">
3194 $Lang::tr{'the statistics were last updated at'} <b>$status</b>
3199 &Header
::closesection
();
3202 <p class="text-center">
3203 <a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a>
3207 &Header
::closebigbox
();
3208 &Header
::closepage
();
3213 ### Download Certificate
3215 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download certificate'}) {
3216 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3218 if ( -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
3219 print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . "cert.pem\r\n";
3220 print "Content-Type: application/octet-stream\r\n\r\n";
3222 open(FILE
, "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
3231 ### Enable/Disable connection
3234 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'toggle enable disable'}) {
3235 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3237 if ($confighash{$cgiparams{'KEY'}}) {
3238 if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
3239 $confighash{$cgiparams{'KEY'}}[0] = 'on';
3240 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3241 #&writeserverconf();
3242 # if ($vpnsettings{'ENABLED'} eq 'on' ||
3243 # $vpnsettings{'ENABLED_BLUE'} eq 'on') {
3244 # system('/usr/local/bin/ipsecctrl', 'S', $cgiparams{'KEY'});
3247 $confighash{$cgiparams{'KEY'}}[0] = 'off';
3248 # if ($vpnsettings{'ENABLED'} eq 'on' ||
3249 # $vpnsettings{'ENABLED_BLUE'} eq 'on') {
3250 # system('/usr/local/bin/ipsecctrl', 'D', $cgiparams{'KEY'});
3252 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3253 #&writeserverconf();
3256 $errormessage = $Lang::tr
{'invalid key'};
3259 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'add'} && $cgiparams{'TYPE'} eq '') {
3260 &Header
::showhttpheaders
();
3261 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
3262 &Header
::openbigbox
('100%', 'LEFT', '', '');
3263 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'connection type'});
3265 if ( -s
"${General::swroot}/ovpn/settings") {
3268 <b>$Lang::tr{'connection type'}:</b><br />
3269 <table border='0' width='100%'><form method='post' ENCTYPE="multipart/form-data">
3270 <tr><td><input type='radio' name='TYPE' value='host' checked /></td>
3271 <td class='base'>$Lang::tr{'host to net vpn'}</td></tr>
3272 <tr><td><input type='radio' name='TYPE' value='net' /></td>
3273 <td class='base'>$Lang::tr{'net to net vpn'}</td></tr>
3274 <tr><td><input type='radio' name='TYPE' value='net2net' /></td>
3275 <td class='base'>$Lang::tr{'net to net vpn'} (Upload Client Package)</td></tr>
3276 <tr><td> </td><td class='base'><input type='file' name='FH' size='30'></td></tr>
3277 <tr><td> </td><td>Import Connection Name</td></tr>
3278 <tr><td> </td><td class='base'><input type='text' name='n2nname' size='30'>$Lang::tr{'openvpn default'}: Client Packagename</td></tr>
3279 <tr><td colspan='3'><hr /></td></tr>
3280 <tr><td align='right' colspan='3'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td></tr>
3288 <b>$Lang::tr{'connection type'}:</b><br />
3289 <table border='0' width='100%'><form method='post' ENCTYPE="multipart/form-data">
3290 <tr><td><input type='radio' name='TYPE' value='host' checked /></td> <td class='base'>$Lang::tr{'host to net vpn'}</td></tr>
3291 <tr><td align='right' colspan'3'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td></tr>
3298 &Header
::closebox
();
3299 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
3300 &Header
::closebigbox
();
3301 &Header
::closepage
();
3304 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) && ($cgiparams{'TYPE'} eq 'net2net')){
3308 my $uplconffilename ='';
3309 my $uplconffilename2 ='';
3310 my $uplp12name = '';
3311 my $uplp12name2 = '';
3318 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3320 # Check if a file is uploaded
3321 unless (ref ($cgiparams{'FH'})) {
3322 $errormessage = $Lang::tr
{'there was no file upload'};
3326 # Move uploaded IPfire n2n package to temporary file
3328 (my $fh, my $filename) = tempfile
( );
3329 if (copy
($cgiparams{'FH'}, $fh) != 1) {
3334 my $zip = Archive
::Zip-
>new();
3335 my $zipName = $filename;
3336 my $status = $zip->read( $zipName );
3337 if ($status != AZ_OK
) {
3338 $errormessage = "Read of $zipName failed\n";
3342 my $tempdir = tempdir
( CLEANUP
=> 1 );
3343 my @files = $zip->memberNames();
3345 $zip->extractMemberWithoutPaths($_,"$tempdir/$_");
3347 my $countfiles = @files;
3349 # Check if we have not more then 2 files
3351 if ( $countfiles == 2){
3353 if ( $_ =~ /.conf$/){
3354 $uplconffilename = $_;
3356 if ( $_ =~ /.p12$/){
3360 if (($uplconffilename eq '') || ($uplp12name eq '')){
3361 $errormessage = "Either no *.conf or no *.p12 file found\n";
3365 open(FILE
, "$tempdir/$uplconffilename") or die 'Unable to open*.conf file';
3366 @firen2nconf = <FILE
>;
3368 chomp(@firen2nconf);
3371 $errormessage = "Filecount does not match only 2 files are allowed\n";
3375 if ($cgiparams{'n2nname'} ne ''){
3377 $uplconffilename2 = "$cgiparams{'n2nname'}.conf";
3378 $uplp12name2 = "$cgiparams{'n2nname'}.p12";
3379 $n2nname[0] = $cgiparams{'n2nname'};
3380 my @n2nname2 = split(/\./,$uplconffilename);
3381 $n2nname2[0] =~ s/\n|\r//g;
3382 my $input1 = "${General::swroot}/ovpn/certs/$uplp12name";
3383 my $output1 = "${General::swroot}/ovpn/certs/$uplp12name2";
3384 my $input2 = "$n2nname2[0]n2n";
3385 my $output2 = "$n2nname[0]n2n";
3386 my $filename = "$tempdir/$uplconffilename";
3387 open(FILE
, "< $filename") or die 'Unable to open config file.';
3388 my @current = <FILE
>;
3390 foreach (@current) {s/$input1/$output1/g;}
3391 foreach (@current) {s/$input2/$output2/g;}
3392 open (OUT
, "> $filename") || die 'Unable to open config file.';
3397 $uplconffilename2 = $uplconffilename;
3398 $uplp12name2 = $uplp12name;
3399 @n2nname = split(/\./,$uplconffilename);
3400 $n2nname[0] =~ s/\n|\r//g;
3402 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
3403 unless(-d
"${General::swroot}/ovpn/n2nconf/$n2nname[0]"){mkdir "${General::swroot}/ovpn/n2nconf/$n2nname[0]", 0770 or die "Unable to create dir $!";}
3405 #Add collectd settings to configfile
3406 open(FILE
, ">> $tempdir/$uplconffilename") or die 'Unable to open config file.';
3407 print FILE
"# Logfile\n";
3408 print FILE
"status-version 1\n";
3409 print FILE
"status /var/run/openvpn/$n2nname[0]-n2n 10\n";
3410 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$cgiparams{'n2nname'}")) {
3411 print CLIENTCONF
"providers legacy default\n";
3416 unless(move
("$tempdir/$uplconffilename", "${General::swroot}/ovpn/n2nconf/$n2nname[0]/$uplconffilename2")) {
3417 $errormessage = "*.conf move failed: $!";
3422 unless(move
("$tempdir/$uplp12name", "${General::swroot}/ovpn/certs/$uplp12name2")) {
3423 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
3428 chmod 0600, "${General::swroot}/ovpn/certs/$uplp12name";
3434 my @n2nproto2 = split(/ /, (grep { /^proto/ } @firen2nconf)[0]);
3435 my @n2nproto = split(/-/, $n2nproto2[1]);
3436 my @n2nport = split(/ /, (grep { /^port/ } @firen2nconf)[0]);
3437 my @n2ntunmtu = split(/ /, (grep { /^tun-mtu/ } @firen2nconf)[0]);
3438 my @n2ncomplzo = grep { /^comp-lzo/ } @firen2nconf;
3439 if ($n2ncomplzo[0] =~ /comp-lzo/){$complzoactive = "on";} else {$complzoactive = "off";}
3440 my @n2nmssfix = grep { /^mssfix/ } @firen2nconf;
3441 if ($n2nmssfix[0] =~ /mssfix/){$mssfixactive = "on";} else {$mssfixactive = "off";}
3442 #my @n2nmssfix = split(/ /, (grep { /^mssfix/ } @firen2nconf)[0]);
3443 my @n2nfragment = split(/ /, (grep { /^fragment/ } @firen2nconf)[0]);
3444 my @n2nremote = split(/ /, (grep { /^remote/ } @firen2nconf)[0]);
3445 my @n2novpnsuball = split(/ /, (grep { /^ifconfig/ } @firen2nconf)[0]);
3446 my @n2novpnsub = split(/\./,$n2novpnsuball[1]);
3447 my @n2nremsub = split(/ /, (grep { /^route/ } @firen2nconf)[0]);
3448 my @n2nmgmt = split(/ /, (grep { /^management/ } @firen2nconf)[0]);
3449 my @n2nlocalsub = split(/ /, (grep { /^# remsub/ } @firen2nconf)[0]);
3450 my @n2ncipher = split(/ /, (grep { /^cipher/ } @firen2nconf)[0]);
3451 my @n2nauth = split(/ /, (grep { /^auth/ } @firen2nconf)[0]);;
3454 # m.a.d delete CR and LF from arrays for this chomp doesnt work
3457 $n2nremote[1] =~ s/\n|\r//g;
3458 $n2novpnsub[0] =~ s/\n|\r//g;
3459 $n2novpnsub[1] =~ s/\n|\r//g;
3460 $n2novpnsub[2] =~ s/\n|\r//g;
3461 $n2nproto[0] =~ s/\n|\r//g;
3462 $n2nport[1] =~ s/\n|\r//g;
3463 $n2ntunmtu[1] =~ s/\n|\r//g;
3464 $n2nremsub[1] =~ s/\n|\r//g;
3465 $n2nremsub[2] =~ s/\n|\r//g;
3466 $n2nlocalsub[2] =~ s/\n|\r//g;
3467 $n2nfragment[1] =~ s/\n|\r//g;
3468 $n2nmgmt[2] =~ s/\n|\r//g;
3469 $n2ncipher[1] =~ s/\n|\r//g;
3470 $n2nauth[1] =~ s/\n|\r//g;
3471 chomp ($complzoactive);
3472 chomp ($mssfixactive);
3475 # Check if there is no other entry with this name
3478 foreach my $dkey (keys %confighash) {
3479 if ($confighash{$dkey}[1] eq $n2nname[0]) {
3480 $errormessage = $Lang::tr
{'a connection with this name already exists'};
3481 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3482 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3483 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3489 # Check if OpenVPN Subnet is valid
3492 foreach my $dkey (keys %confighash) {
3493 if ($confighash{$dkey}[27] eq "$n2novpnsub[0].$n2novpnsub[1].$n2novpnsub[2].0/255.255.255.0") {
3494 $errormessage = 'The OpenVPN Subnet is already in use';
3495 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3496 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3497 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3503 # Check if Dest Port is vaild
3506 foreach my $dkey (keys %confighash) {
3507 if ($confighash{$dkey}[29] eq $n2nport[1] ) {
3508 $errormessage = 'The OpenVPN Port is already in use';
3509 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3510 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3511 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3518 $key = &General
::findhasharraykey
(\
%confighash);
3520 foreach my $i (0 .. 42) { $confighash{$key}[$i] = "";}
3522 $confighash{$key}[0] = 'off';
3523 $confighash{$key}[1] = $n2nname[0];
3524 $confighash{$key}[2] = $n2nname[0];
3525 $confighash{$key}[3] = 'net';
3526 $confighash{$key}[4] = 'cert';
3527 $confighash{$key}[6] = 'client';
3528 $confighash{$key}[8] = $n2nlocalsub[2];
3529 $confighash{$key}[10] = $n2nremote[1];
3530 $confighash{$key}[11] = "$n2nremsub[1]/$n2nremsub[2]";
3531 $confighash{$key}[22] = $n2nmgmt[2];
3532 $confighash{$key}[23] = $mssfixactive;
3533 $confighash{$key}[24] = $n2nfragment[1];
3534 $confighash{$key}[25] = 'IPFire n2n Client';
3535 $confighash{$key}[26] = 'red';
3536 $confighash{$key}[27] = "$n2novpnsub[0].$n2novpnsub[1].$n2novpnsub[2].0/255.255.255.0";
3537 $confighash{$key}[28] = $n2nproto[0];
3538 $confighash{$key}[29] = $n2nport[1];
3539 $confighash{$key}[30] = $complzoactive;
3540 $confighash{$key}[31] = $n2ntunmtu[1];
3541 $confighash{$key}[39] = $n2nauth[1];
3542 $confighash{$key}[40] = $n2ncipher[1];
3543 $confighash{$key}[41] = 'no-pass';
3545 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3549 &Header
::showhttpheaders
();
3550 &Header
::openpage
('Validate imported configuration', 1, '');
3551 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
3552 if ($errormessage) {
3553 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'error messages'});
3554 print "<class name='base'>$errormessage";
3555 print " </class>";
3556 &Header
::closebox
();
3560 &Header
::openbox
('100%', 'LEFT', 'import ipfire net2net config');
3562 if ($errormessage eq ''){
3564 <!-- ipfire net2net config gui -->
3565 <table width='100%'>
3566 <tr><td width='25%'> </td><td width='25%'> </td></tr>
3567 <tr><td class='boldbase'>$Lang::tr{'name'}:</td><td><b>$n2nname[0]</b></td></tr>
3568 <tr><td> </td><td> </td></tr>
3569 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'Act as'}</td><td><b>$confighash{$key}[6]</b></td></tr>
3570 <tr><td class='boldbase' nowrap='nowrap'>Remote Host </td><td><b>$confighash{$key}[10]</b></td></tr>
3571 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'local subnet'}</td><td><b>$confighash{$key}[8]</b></td></tr>
3572 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'remote subnet'}:</td><td><b>$confighash{$key}[11]</b></td></tr>
3573 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'ovpn subnet'}</td><td><b>$confighash{$key}[27]</b></td></tr>
3574 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'protocol'}</td><td><b>$confighash{$key}[28]</b></td></tr>
3575 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'destination port'}:</td><td><b>$confighash{$key}[29]</b></td></tr>
3576 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'comp-lzo'}</td><td><b>$confighash{$key}[30]</b></td></tr>
3577 <tr><td class='boldbase' nowrap='nowrap'>MSSFIX:</td><td><b>$confighash{$key}[23]</b></td></tr>
3578 <tr><td class='boldbase' nowrap='nowrap'>Fragment:</td><td><b>$confighash{$key}[24]</b></td></tr>
3579 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'MTU'}</td><td><b>$confighash{$key}[31]</b></td></tr>
3580 <tr><td class='boldbase' nowrap='nowrap'>Management Port </td><td><b>$confighash{$key}[22]</b></td></tr>
3581 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'ovpn tls auth'}:</td><td><b>$confighash{$key}[39]</b></td></tr>
3582 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'cipher'}</td><td><b>$confighash{$key}[40]</b></td></tr>
3583 <tr><td> </td><td> </td></tr>
3587 &Header
::closebox
();
3590 if ($errormessage) {
3591 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
3593 print "<div align='center'><form method='post' ENCTYPE='multipart/form-data'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' />";
3594 print "<input type='hidden' name='TYPE' value='net2netakn' />";
3595 print "<input type='hidden' name='KEY' value='$key' />";
3596 print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
3598 &Header
::closebigbox
();
3599 &Header
::closepage
();
3604 ### Accept IPFire n2n Package Settings
3607 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) && ($cgiparams{'TYPE'} eq 'net2netakn')){
3610 ### Discard and Rollback IPFire n2n Package Settings
3613 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'cancel'}) && ($cgiparams{'TYPE'} eq 'net2netakn')){
3615 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3617 if ($confighash{$cgiparams{'KEY'}}) {
3619 my $conffile = glob("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]/$confighash{$cgiparams{'KEY'}}[1].conf");
3620 my $certfile = glob("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
3621 unlink ($certfile) or die "Removing $certfile fail: $!";
3622 unlink ($conffile) or die "Removing $conffile fail: $!";
3623 rmdir ("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") || die "Kann Verzeichnis nicht loeschen: $!";
3624 delete $confighash{$cgiparams{'KEY'}};
3625 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3628 $errormessage = $Lang::tr
{'invalid key'};
3632 ### Adding a new connection
3634 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) ||
3635 ($cgiparams{'ACTION'} eq $Lang::tr
{'edit'}) ||
3636 ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'ADVANCED'} eq '')) {
3637 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
3638 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3640 if ($cgiparams{'ACTION'} eq $Lang::tr
{'edit'}) {
3641 if (! $confighash{$cgiparams{'KEY'}}[0]) {
3642 $errormessage = $Lang::tr
{'invalid key'};
3645 $cgiparams{'ENABLED'} = $confighash{$cgiparams{'KEY'}}[0];
3646 $cgiparams{'NAME'} = $confighash{$cgiparams{'KEY'}}[1];
3647 $cgiparams{'TYPE'} = $confighash{$cgiparams{'KEY'}}[3];
3648 $cgiparams{'AUTH'} = $confighash{$cgiparams{'KEY'}}[4];
3649 $cgiparams{'PSK'} = $confighash{$cgiparams{'KEY'}}[5];
3650 $cgiparams{'SIDE'} = $confighash{$cgiparams{'KEY'}}[6];
3651 $cgiparams{'LOCAL_SUBNET'} = $confighash{$cgiparams{'KEY'}}[8];
3652 $cgiparams{'REMOTE'} = $confighash{$cgiparams{'KEY'}}[10];
3653 $cgiparams{'REMOTE_SUBNET'} = $confighash{$cgiparams{'KEY'}}[11];
3654 $cgiparams{'OVPN_MGMT'} = $confighash{$cgiparams{'KEY'}}[22];
3655 $cgiparams{'MSSFIX'} = $confighash{$cgiparams{'KEY'}}[23];
3656 $cgiparams{'FRAGMENT'} = $confighash{$cgiparams{'KEY'}}[24];
3657 $cgiparams{'REMARK'} = $confighash{$cgiparams{'KEY'}}[25];
3658 $cgiparams{'INTERFACE'} = $confighash{$cgiparams{'KEY'}}[26];
3659 $cgiparams{'OVPN_SUBNET'} = $confighash{$cgiparams{'KEY'}}[27];
3660 $cgiparams{'PROTOCOL'} = $confighash{$cgiparams{'KEY'}}[28];
3661 $cgiparams{'DEST_PORT'} = $confighash{$cgiparams{'KEY'}}[29];
3662 $cgiparams{'COMPLZO'} = $confighash{$cgiparams{'KEY'}}[30];
3663 $cgiparams{'MTU'} = $confighash{$cgiparams{'KEY'}}[31];
3664 $cgiparams{'CHECK1'} = $confighash{$cgiparams{'KEY'}}[32];
3665 $name=$cgiparams{'CHECK1'} ;
3666 $cgiparams{$name} = $confighash{$cgiparams{'KEY'}}[33];
3667 $cgiparams{'RG'} = $confighash{$cgiparams{'KEY'}}[34];
3668 $cgiparams{'CCD_DNS1'} = $confighash{$cgiparams{'KEY'}}[35];
3669 $cgiparams{'CCD_DNS2'} = $confighash{$cgiparams{'KEY'}}[36];
3670 $cgiparams{'CCD_WINS'} = $confighash{$cgiparams{'KEY'}}[37];
3671 $cgiparams{'DAUTH'} = $confighash{$cgiparams{'KEY'}}[39];
3672 $cgiparams{'DCIPHER'} = $confighash{$cgiparams{'KEY'}}[40];
3673 $cgiparams{'TLSAUTH'} = $confighash{$cgiparams{'KEY'}}[41];
3674 $cgiparams{'OTP_STATE'} = $confighash{$cgiparams{'KEY'}}[43];
3675 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'save'}) {
3676 $cgiparams{'REMARK'} = &Header
::cleanhtml
($cgiparams{'REMARK'});
3678 # CCD check iroute field and convert it to decimal
3679 if ($cgiparams{'TYPE'} eq 'host') {
3681 my %ccdroutehash=();
3685 if ($cgiparams{'IR'} ne ''){
3686 @temp = split("\n",$cgiparams{'IR'});
3687 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3689 foreach my $key (keys %ccdroutehash) {
3690 if ($ccdroutehash{$key}[0] eq $cgiparams{'NAME'}) {
3692 delete $ccdroutehash{$key};
3694 $keypoint = &General
::findhasharraykey
(\
%ccdroutehash);
3697 $ccdroutehash{$keypoint}[0]=$cgiparams{'NAME'};
3700 foreach $val (@temp){
3703 #check if iroute exists in ccdroute or if new iroute is part of an existing one
3704 foreach my $key (keys %ccdroutehash) {
3705 foreach my $oldiroute ( 1 .. $#{$ccdroutehash{$key}}){
3706 if ($ccdroutehash{$key}[$oldiroute] eq "$val") {
3707 $errormessage=$errormessage.$Lang::tr
{'ccd err irouteexist'};
3710 my ($ip1,$cidr1) = split (/\//, $val);
3711 $ip1 = &General
::getnetworkip
($ip1,&General
::iporsubtocidr
($cidr1));
3712 my ($ip2,$cidr2) = split (/\//, $ccdroutehash{$key}[$oldiroute]);
3713 if (&General
::IpInSubnet
($ip1,$ip2,$cidr2)){
3714 $errormessage=$errormessage.$Lang::tr
{'ccd err irouteexist'};
3720 if (!&General
::validipandmask
($val)){
3721 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($val)";
3724 ($ip,$cidr) = split(/\//,$val);
3725 $ip=&General
::getnetworkip
($ip,&General
::iporsubtocidr
($cidr));
3726 $cidr=&General
::iporsubtodec
($cidr);
3727 $ccdroutehash{$keypoint}[$i] = $ip."/".$cidr;
3731 #check for existing network IP's
3732 if (&General
::IpInSubnet
($ip,$Network::ethernet
{GREEN_NETADDRESS
},$Network::ethernet
{GREEN_NETMASK
}) && $Network::ethernet
{GREEN_NETADDRESS
} ne '0.0.0.0')
3734 $errormessage=$Lang::tr
{'ccd err green'};
3736 }elsif(&General
::IpInSubnet
($ip,$Network::ethernet
{RED_NETADDRESS
},$Network::ethernet
{RED_NETMASK
}) && $Network::ethernet
{RED_NETADDRESS
} ne '0.0.0.0')
3738 $errormessage=$Lang::tr
{'ccd err red'};
3740 }elsif(&General
::IpInSubnet
($ip,$Network::ethernet
{BLUE_NETADDRESS
},$Network::ethernet
{BLUE_NETMASK
}) && $Network::ethernet
{BLUE_NETADDRESS
} ne '0.0.0.0' && $Network::ethernet
{BLUE_NETADDRESS
} gt '')
3742 $errormessage=$Lang::tr
{'ccd err blue'};
3744 }elsif(&General
::IpInSubnet
($ip,$Network::ethernet
{ORANGE_NETADDRESS
},$Network::ethernet
{ORANGE_NETMASK
}) && $Network::ethernet
{ORANGE_NETADDRESS
} ne '0.0.0.0' && $Network::ethernet
{ORANGE_NETADDRESS
} gt '' )
3746 $errormessage=$Lang::tr
{'ccd err orange'};
3750 if (&General
::validipandmask
($val)){
3751 $ccdroutehash{$keypoint}[$i] = $ip."/".$cidr;
3753 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($ip/$cidr)";
3758 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3761 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3762 foreach my $key (keys %ccdroutehash) {
3763 if ($ccdroutehash{$key}[0] eq $cgiparams{'NAME'}) {
3764 delete $ccdroutehash{$key};
3765 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3771 #check route field and convert it to decimal
3774 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
3776 foreach my $key (keys %ccdroute2hash) {
3777 if ($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}) {
3779 delete $ccdroute2hash{$key};
3781 $keypoint = &General
::findhasharraykey
(\
%ccdroute2hash);
3782 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3786 $ccdroute2hash{$keypoint}[0]=$cgiparams{'NAME'};
3787 if ($cgiparams{'IFROUTE'} eq ''){$cgiparams{'IFROUTE'} = $Lang::tr
{'ccd none'};}
3788 @temp = split(/\|/,$cgiparams{'IFROUTE'});
3789 foreach $val (@temp){
3792 if ($val eq $Lang::tr
{'green'})
3794 $val=$Network::ethernet
{GREEN_NETADDRESS
}."/".$Network::ethernet
{GREEN_NETMASK
};
3796 if ($val eq $Lang::tr
{'blue'})
3798 $val=$Network::ethernet
{BLUE_NETADDRESS
}."/".$Network::ethernet
{BLUE_NETMASK
};
3800 if ($val eq $Lang::tr
{'orange'})
3802 $val=$Network::ethernet
{ORANGE_NETADDRESS
}."/".$Network::ethernet
{ORANGE_NETMASK
};
3804 my ($ip,$cidr) = split (/\//, $val);
3806 if ($val ne $Lang::tr
{'ccd none'})
3808 if (! &check_routes_push
($val)){$errormessage=$errormessage."Route $val ".$Lang::tr
{'ccd err routeovpn2'}." ($val)";goto VPNCONF_ERROR
;}
3809 if (! &check_ccdroute
($val)){$errormessage=$errormessage."<br>Route $val ".$Lang::tr
{'ccd err inuse'}." ($val)" ;goto VPNCONF_ERROR
;}
3810 if (! &check_ccdconf
($val)){$errormessage=$errormessage."<br>Route $val ".$Lang::tr
{'ccd err routeovpn'}." ($val)";goto VPNCONF_ERROR
;}
3811 if (&General
::validipandmask
($val)){
3812 $val=$ip."/".&General
::iporsubtodec
($cidr);
3813 $ccdroute2hash{$keypoint}[$i] = $val;
3815 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($val)";
3819 $ccdroute2hash{$keypoint}[$i]='';
3823 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
3826 if ($cgiparams{'CCD_DNS1'} ne '' && ! &General
::validip
($cgiparams{'CCD_DNS1'})) {
3827 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp dns'}." 1";
3831 if ($cgiparams{'CCD_DNS2'} ne '' && ! &General
::validip
($cgiparams{'CCD_DNS2'})) {
3832 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp dns'}." 2";
3836 if ($cgiparams{'CCD_WINS'} ne '' && ! &General
::validip
($cgiparams{'CCD_WINS'})) {
3837 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp wins'};
3842 if ($cgiparams{'TYPE'} !~ /^(host|net)$/) {
3843 $errormessage = $Lang::tr
{'connection type is invalid'};
3844 if ($cgiparams{'TYPE'} eq 'net') {
3845 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3846 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3852 if ($cgiparams{'NAME'} !~ /^[a-zA-Z0-9]+$/) {
3853 $errormessage = $Lang::tr
{'name must only contain characters'};
3854 if ($cgiparams{'TYPE'} eq 'net') {
3860 if ($cgiparams{'NAME'} =~ /^(host|01|block|private|clear|packetdefault)$/) {
3861 $errormessage = $Lang::tr
{'name is invalid'};
3862 if ($cgiparams{'TYPE'} eq 'net') {
3863 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3864 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3870 if (length($cgiparams{'NAME'}) >60) {
3871 $errormessage = $Lang::tr
{'name too long'};
3872 if ($cgiparams{'TYPE'} eq 'net') {
3873 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3874 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3880 if ($cgiparams{'TYPE'} eq 'net') {
3881 if ($cgiparams{'DEST_PORT'} eq $vpnsettings{'DDEST_PORT'}) {
3882 $errormessage = $Lang::tr
{'openvpn destination port used'};
3883 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3884 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3888 foreach my $key (sort keys %confighash){
3889 if ( ($confighash{$key}[22] eq $cgiparams{'DEST_PORT'} && $cgiparams{'NAME'} ne $confighash{$key}[1]) || ($confighash{$key}[29] eq $cgiparams{'DEST_PORT'} && $cgiparams{'NAME'} ne $confighash{$key}[1])){
3890 $errormessage = $Lang::tr
{'openvpn destination port used'};
3891 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3892 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3896 if ($cgiparams{'DEST_PORT'} eq '') {
3897 $errormessage = $Lang::tr
{'invalid port'};
3898 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3899 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3903 # Check if the input for the transfer net is valid.
3904 if (!&General
::validipandmask
($cgiparams{'OVPN_SUBNET'})){
3905 $errormessage = $Lang::tr
{'ccd err invalidnet'};
3906 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3907 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3911 if ($cgiparams{'OVPN_SUBNET'} eq $vpnsettings{'DOVPN_SUBNET'}) {
3912 $errormessage = $Lang::tr
{'openvpn subnet is used'};
3913 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3914 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3918 if (($cgiparams{'PROTOCOL'} eq 'tcp') && ($cgiparams{'MSSFIX'} eq 'on')) {
3919 $errormessage = $Lang::tr
{'openvpn mssfix allowed with udp'};
3920 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3921 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3925 if (($cgiparams{'PROTOCOL'} eq 'tcp') && ($cgiparams{'FRAGMENT'} ne '')) {
3926 $errormessage = $Lang::tr
{'openvpn fragment allowed with udp'};
3927 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3928 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3932 if (!&Network
::check_subnet
($cgiparams{'LOCAL_SUBNET'})) {
3933 $errormessage = $Lang::tr
{'openvpn prefix local subnet'};
3934 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3935 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3939 if (!&Network
::check_subnet
($cgiparams{'OVPN_SUBNET'})) {
3940 $errormessage = $Lang::tr
{'openvpn prefix openvpn subnet'};
3941 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3942 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3946 if (!&Network
::check_subnet
($cgiparams{'REMOTE_SUBNET'})) {
3947 $errormessage = $Lang::tr
{'openvpn prefix remote subnet'};
3948 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3949 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3953 if ($cgiparams{'DEST_PORT'} <= 1023) {
3954 $errormessage = $Lang::tr
{'ovpn port in root range'};
3955 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3956 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3960 if ($cgiparams{'OVPN_MGMT'} eq '') {
3961 $cgiparams{'OVPN_MGMT'} = $cgiparams{'DEST_PORT'};
3964 if ($cgiparams{'OVPN_MGMT'} <= 1023) {
3965 $errormessage = $Lang::tr
{'ovpn mgmt in root range'};
3966 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3967 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3970 #Check if remote subnet is used elsewhere
3971 my ($n2nip,$n2nsub)=split("/",$cgiparams{'REMOTE_SUBNET'});
3972 $warnmessage=&General
::checksubnets
('',$n2nip,'ovpn');
3974 $warnmessage=$Lang::tr
{'remote subnet'}." ($cgiparams{'REMOTE_SUBNET'}) <br>".$warnmessage;
3978 # Check if there is no other entry with this name
3979 if (! $cgiparams{'KEY'}) {
3980 foreach my $key (keys %confighash) {
3981 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
3982 $errormessage = $Lang::tr
{'a connection with this name already exists'};
3983 if ($cgiparams{'TYPE'} eq 'net') {
3984 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3985 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3992 # Check if a remote host/IP has been set for the client.
3993 if ($cgiparams{'TYPE'} eq 'net') {
3994 if ($cgiparams{'SIDE'} ne 'server' && $cgiparams{'REMOTE'} eq '') {
3995 $errormessage = $Lang::tr
{'invalid input for remote host/ip'};
3997 # Check if this is a N2N connection and drop temporary config.
3998 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3999 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4004 # Check if a remote host/IP has been configured - the field can be empty on the server side.
4005 if ($cgiparams{'REMOTE'} ne '') {
4006 # Check if the given IP is valid - otherwise check if it is a valid domain.
4007 if (! &General
::validip
($cgiparams{'REMOTE'})) {
4008 # Check for a valid domain.
4009 if (! &General
::validfqdn
($cgiparams{'REMOTE'})) {
4010 $errormessage = $Lang::tr
{'invalid input for remote host/ip'};
4012 # Check if this is a N2N connection and drop temporary config.
4013 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4014 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4022 if ($cgiparams{'TYPE'} ne 'host') {
4023 unless (&General
::validipandmask
($cgiparams{'LOCAL_SUBNET'})) {
4024 $errormessage = $Lang::tr
{'local subnet is invalid'};
4025 if ($cgiparams{'TYPE'} eq 'net') {
4026 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4027 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4029 goto VPNCONF_ERROR
;}
4031 # Check if there is no other entry without IP-address and PSK
4032 if ($cgiparams{'REMOTE'} eq '') {
4033 foreach my $key (keys %confighash) {
4034 if(($cgiparams{'KEY'} ne $key) &&
4035 ($confighash{$key}[4] eq 'psk' || $cgiparams{'AUTH'} eq 'psk') &&
4036 $confighash{$key}[10] eq '') {
4037 $errormessage = $Lang::tr
{'you can only define one roadwarrior connection when using pre-shared key authentication'};
4042 if (($cgiparams{'TYPE'} eq 'net') && (! &General
::validipandmask
($cgiparams{'REMOTE_SUBNET'}))) {
4043 $errormessage = $Lang::tr
{'remote subnet is invalid'};
4044 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4045 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4049 # Check for N2N that OpenSSL maximum of valid days will not be exceeded
4050 if ($cgiparams{'TYPE'} eq 'net') {
4051 if ($cgiparams{'DAYS_VALID'} >= '999999') {
4052 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4053 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4054 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4059 if ($cgiparams{'ENABLED'} !~ /^(on|off|)$/) {
4060 $errormessage = $Lang::tr
{'invalid input'};
4064 if ($cgiparams{'AUTH'} eq 'certreq') {
4065 if ($cgiparams{'KEY'}) {
4066 $errormessage = $Lang::tr
{'cant change certificates'};
4069 unless (ref ($cgiparams{'FH'})) {
4070 $errormessage = $Lang::tr
{'there was no file upload'};
4074 # Move uploaded certificate request to a temporary file
4075 (my $fh, my $filename) = tempfile
( );
4076 if (copy
($cgiparams{'FH'}, $fh) != 1) {
4081 # Sign the certificate request and move it
4082 # Sign the host certificate request
4083 # The system call is safe, because all arguments are passed as an array.
4084 system('/usr/bin/openssl', 'ca', '-days', "$cgiparams{'DAYS_VALID'}",
4085 '-batch', '-notext',
4087 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4088 '-config', "/usr/share/openvpn/ovpn.cnf");
4090 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4092 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4093 &cleanssldatabase
();
4097 &deletebackupcert
();
4100 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4103 foreach my $line (@temp) {
4104 if ($line =~ /Subject:.*CN\s?=\s?(.*)[\n]/) {
4106 $temp =~ s
+/Email
+, E
+;
4107 $temp =~ s/ ST=/ S=/;
4113 $cgiparams{'CERT_NAME'} = $temp;
4114 $cgiparams{'CERT_NAME'} =~ s/,//g;
4115 $cgiparams{'CERT_NAME'} =~ s/\'//g;
4116 if ($cgiparams{'CERT_NAME'} eq '') {
4117 $errormessage = $Lang::tr
{'could not retrieve common name from certificate'};
4120 } elsif ($cgiparams{'AUTH'} eq 'certfile') {
4121 if ($cgiparams{'KEY'}) {
4122 $errormessage = $Lang::tr
{'cant change certificates'};
4125 unless (ref ($cgiparams{'FH'})) {
4126 $errormessage = $Lang::tr
{'there was no file upload'};
4129 # Move uploaded certificate to a temporary file
4130 (my $fh, my $filename) = tempfile
( );
4131 if (copy
($cgiparams{'FH'}, $fh) != 1) {
4136 # Verify the certificate has a valid CA and move it
4138 my @test = &General
::system_output
("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/cacert.pem", "$filename");
4139 if (grep(/: OK/, @test)) {
4142 foreach my $key (keys %cahash) {
4143 @test = &General
::system_output
("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/$cahash{$key}[0]cert.pem", "$filename");
4144 if (grep(/: OK/, @test)) {
4150 $errormessage = $Lang::tr
{'certificate does not have a valid ca associated with it'};
4154 unless(move
($filename, "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem")) {
4155 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
4161 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4164 foreach my $line (@temp) {
4165 if ($line =~ /Subject:.*CN\s?=\s?(.*)[\n]/) {
4167 $temp =~ s
+/Email
+, E
+;
4168 $temp =~ s/ ST=/ S=/;
4174 $cgiparams{'CERT_NAME'} = $temp;
4175 $cgiparams{'CERT_NAME'} =~ s/,//g;
4176 $cgiparams{'CERT_NAME'} =~ s/\'//g;
4177 if ($cgiparams{'CERT_NAME'} eq '') {
4178 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4179 $errormessage = $Lang::tr
{'could not retrieve common name from certificate'};
4182 } elsif ($cgiparams{'AUTH'} eq 'certgen') {
4183 if ($cgiparams{'KEY'}) {
4184 $errormessage = $Lang::tr
{'cant change certificates'};
4187 # Validate input since the form was submitted
4188 if (length($cgiparams{'CERT_NAME'}) >60) {
4189 $errormessage = $Lang::tr
{'name too long'};
4192 if ($cgiparams{'CERT_NAME'} eq '' || $cgiparams{'CERT_NAME'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
4193 $errormessage = $Lang::tr
{'invalid input for name'};
4196 if ($cgiparams{'CERT_EMAIL'} ne '' && (! &General
::validemail
($cgiparams{'CERT_EMAIL'}))) {
4197 $errormessage = $Lang::tr
{'invalid input for e-mail address'};
4200 if (length($cgiparams{'CERT_EMAIL'}) > 40) {
4201 $errormessage = $Lang::tr
{'e-mail address too long'};
4204 if ($cgiparams{'CERT_OU'} ne '' && $cgiparams{'CERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4205 $errormessage = $Lang::tr
{'invalid input for department'};
4208 if (length($cgiparams{'CERT_ORGANIZATION'}) >60) {
4209 $errormessage = $Lang::tr
{'organization too long'};
4212 if ($cgiparams{'CERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
4213 $errormessage = $Lang::tr
{'invalid input for organization'};
4216 if ($cgiparams{'CERT_CITY'} ne '' && $cgiparams{'CERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4217 $errormessage = $Lang::tr
{'invalid input for city'};
4220 if ($cgiparams{'CERT_STATE'} ne '' && $cgiparams{'CERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4221 $errormessage = $Lang::tr
{'invalid input for state or province'};
4224 if ($cgiparams{'CERT_COUNTRY'} !~ /^[A-Z]*$/) {
4225 $errormessage = $Lang::tr
{'invalid input for country'};
4228 if ($cgiparams{'CERT_PASS1'} ne '' && $cgiparams{'CERT_PASS2'} ne ''){
4229 if (length($cgiparams{'CERT_PASS1'}) < 5) {
4230 $errormessage = $Lang::tr
{'password too short'};
4234 if ($cgiparams{'CERT_PASS1'} ne $cgiparams{'CERT_PASS2'}) {
4235 $errormessage = $Lang::tr
{'passwords do not match'};
4238 if ($cgiparams{'DAYS_VALID'} eq '' && $cgiparams{'DAYS_VALID'} !~ /^[0-9]+$/) {
4239 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4243 # Check for RW that OpenSSL maximum of valid days will not be exceeded
4244 if ($cgiparams{'TYPE'} eq 'host') {
4245 if ($cgiparams{'DAYS_VALID'} >= '999999') {
4246 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4251 # Check for RW if client name is already set
4252 if ($cgiparams{'TYPE'} eq 'host') {
4253 foreach my $key (keys %confighash) {
4254 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
4255 $errormessage = $Lang::tr
{'a connection with this name already exists'};
4261 # Check if there is no other entry with this common name
4262 if ((! $cgiparams{'KEY'}) && ($cgiparams{'AUTH'} ne 'psk')) {
4263 foreach my $key (keys %confighash) {
4264 if ($confighash{$key}[2] eq $cgiparams{'CERT_NAME'}) {
4265 $errormessage = $Lang::tr
{'a connection with this common name already exists'};
4271 # Replace empty strings with a .
4272 (my $ou = $cgiparams{'CERT_OU'}) =~ s/^\s*$/\./;
4273 (my $city = $cgiparams{'CERT_CITY'}) =~ s/^\s*$/\./;
4274 (my $state = $cgiparams{'CERT_STATE'}) =~ s/^\s*$/\./;
4276 # Create the Host certificate request client
4277 my $pid = open(OPENSSL
, "|-");
4278 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto VPNCONF_ERROR
;};
4279 if ($pid) { # parent
4280 print OPENSSL
"$cgiparams{'CERT_COUNTRY'}\n";
4281 print OPENSSL
"$state\n";
4282 print OPENSSL
"$city\n";
4283 print OPENSSL
"$cgiparams{'CERT_ORGANIZATION'}\n";
4284 print OPENSSL
"$ou\n";
4285 print OPENSSL
"$cgiparams{'CERT_NAME'}\n";
4286 print OPENSSL
"$cgiparams{'CERT_EMAIL'}\n";
4287 print OPENSSL
".\n";
4288 print OPENSSL
".\n";
4291 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4292 unlink ("${General::swroot}ovpn/certs/$cgiparams{'NAME'}key.pem");
4293 unlink ("${General::swroot}ovpn/certs/$cgiparams{'NAME'}req.pem");
4297 unless (exec ('/usr/bin/openssl', 'req', '-nodes',
4298 '-newkey', 'rsa:4096',
4299 '-keyout', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem",
4300 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem",
4301 '-config', "/usr/share/openvpn/ovpn.cnf")) {
4302 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
4303 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4304 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4309 # Sign the host certificate request
4310 # The system call is safe, because all arguments are passed as an array.
4311 system('/usr/bin/openssl', 'ca', '-days', "$cgiparams{'DAYS_VALID'}",
4312 '-batch', '-notext',
4313 '-in', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem",
4314 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4315 '-config', "/usr/share/openvpn/ovpn.cnf");
4317 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4318 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4319 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4320 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4321 &cleanssldatabase
();
4324 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4325 &deletebackupcert
();
4328 # Create the pkcs12 file
4329 # The system call is safe, because all arguments are passed as an array.
4330 system('/usr/bin/openssl', 'pkcs12', '-export',
4331 '-inkey', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem",
4332 '-in', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4333 '-name', $cgiparams{'NAME'},
4334 '-passout', "pass:$cgiparams{'CERT_PASS1'}",
4335 '-certfile', "${General::swroot}/ovpn/ca/cacert.pem",
4336 '-caname', "$vpnsettings{'ROOTCERT_ORGANIZATION'} CA",
4337 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12");
4339 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4340 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4341 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4342 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12");
4345 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4347 } elsif ($cgiparams{'AUTH'} eq 'cert') {
4348 ;# Nothing, just editing
4350 $errormessage = $Lang::tr
{'invalid input for authentication method'};
4355 my $key = $cgiparams{'KEY'};
4358 $key = &General
::findhasharraykey
(\
%confighash);
4359 foreach my $i (0 .. 43) { $confighash{$key}[$i] = "";}
4361 $confighash{$key}[0] = $cgiparams{'ENABLED'};
4362 $confighash{$key}[1] = $cgiparams{'NAME'};
4363 if ((! $cgiparams{'KEY'}) && $cgiparams{'AUTH'} ne 'psk') {
4364 $confighash{$key}[2] = $cgiparams{'CERT_NAME'};
4367 $confighash{$key}[3] = $cgiparams{'TYPE'};
4368 if ($cgiparams{'AUTH'} eq 'psk') {
4369 $confighash{$key}[4] = 'psk';
4370 $confighash{$key}[5] = $cgiparams{'PSK'};
4372 $confighash{$key}[4] = 'cert';
4374 if ($cgiparams{'TYPE'} eq 'net') {
4375 $confighash{$key}[6] = $cgiparams{'SIDE'};
4376 $confighash{$key}[11] = $cgiparams{'REMOTE_SUBNET'};
4378 $confighash{$key}[8] = $cgiparams{'LOCAL_SUBNET'};
4379 $confighash{$key}[10] = $cgiparams{'REMOTE'};
4380 if ($cgiparams{'OVPN_MGMT'} eq '') {
4381 $confighash{$key}[22] = $confighash{$key}[29];
4383 $confighash{$key}[22] = $cgiparams{'OVPN_MGMT'};
4385 $confighash{$key}[23] = $cgiparams{'MSSFIX'};
4386 $confighash{$key}[24] = $cgiparams{'FRAGMENT'};
4387 $confighash{$key}[25] = $cgiparams{'REMARK'};
4388 $confighash{$key}[26] = $cgiparams{'INTERFACE'};
4390 $confighash{$key}[27] = $cgiparams{'OVPN_SUBNET'};
4391 $confighash{$key}[28] = $cgiparams{'PROTOCOL'};
4392 $confighash{$key}[29] = $cgiparams{'DEST_PORT'};
4393 $confighash{$key}[30] = $cgiparams{'COMPLZO'};
4394 $confighash{$key}[31] = $cgiparams{'MTU'};
4395 $confighash{$key}[32] = $cgiparams{'CHECK1'};
4396 $name=$cgiparams{'CHECK1'};
4397 $confighash{$key}[33] = $cgiparams{$name};
4398 $confighash{$key}[34] = $cgiparams{'RG'};
4399 $confighash{$key}[35] = $cgiparams{'CCD_DNS1'};
4400 $confighash{$key}[36] = $cgiparams{'CCD_DNS2'};
4401 $confighash{$key}[37] = $cgiparams{'CCD_WINS'};
4402 $confighash{$key}[39] = $cgiparams{'DAUTH'};
4403 $confighash{$key}[40] = $cgiparams{'DCIPHER'};
4405 if ($confighash{$key}[41] eq "") {
4406 if (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} eq "")) {
4407 $confighash{$key}[41] = "no-pass";
4408 } elsif (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} ne "")) {
4409 $confighash{$key}[41] = "pass";
4410 } elsif ($cgiparams{'TYPE'} eq 'net') {
4411 $confighash{$key}[41] = "no-pass";
4415 $confighash{$key}[42] = 'HOTP/T30/6';
4416 $confighash{$key}[43] = $cgiparams{'OTP_STATE'};
4417 if (($confighash{$key}[43] eq 'on') && ($confighash{$key}[44] eq '')) {
4418 my @otp_secret = &General
::system_output
("/usr/bin/openssl", "rand", "-hex", "20");
4419 chomp($otp_secret[0]);
4420 $confighash{$key}[44] = $otp_secret[0];
4421 } elsif ($confighash{$key}[43] eq '') {
4422 $confighash{$key}[44] = '';
4425 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4427 # Rewrite the server configuration
4430 if ($cgiparams{'TYPE'} eq 'net') {
4432 if (-e
"/var/run/$confighash{$key}[1]n2n.pid") {
4433 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
4435 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4436 my $key = $cgiparams{'KEY'};
4438 $key = &General
::findhasharraykey
(\
%confighash);
4439 foreach my $i (0 .. 31) {
4440 $confighash{$key}[$i] = "";
4444 $confighash{$key}[0] = 'on';
4445 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4447 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "start", "$confighash{$cgiparams{'KEY'}}[1]");
4453 $cgiparams{'ENABLED'} = 'on';
4454 $cgiparams{'MSSFIX'} = 'on';
4455 $cgiparams{'FRAGMENT'} = '1300';
4456 $cgiparams{'DAUTH'} = 'SHA512';
4457 $cgiparams{'SIDE'} = 'left';
4458 if ( ! -f
"${General::swroot}/ovpn/ca/cakey.pem" ) {
4459 $cgiparams{'AUTH'} = 'psk';
4460 } elsif ( ! -f
"${General::swroot}/ovpn/ca/cacert.pem") {
4461 $cgiparams{'AUTH'} = 'certfile';
4463 $cgiparams{'AUTH'} = 'certgen';
4465 $cgiparams{'LOCAL_SUBNET'} ="$Network::ethernet{'GREEN_NETADDRESS'}/$Network::ethernet{'GREEN_NETMASK'}";
4466 $cgiparams{'CERT_ORGANIZATION'} = $vpnsettings{'ROOTCERT_ORGANIZATION'};
4467 $cgiparams{'CERT_CITY'} = $vpnsettings{'ROOTCERT_CITY'};
4468 $cgiparams{'CERT_STATE'} = $vpnsettings{'ROOTCERT_STATE'};
4469 $cgiparams{'CERT_COUNTRY'} = $vpnsettings{'ROOTCERT_COUNTRY'};
4470 $cgiparams{'DAYS_VALID'} = $vpnsettings{'DAYS_VALID'} = '730';
4474 $checked{'ENABLED'}{'off'} = '';
4475 $checked{'ENABLED'}{'on'} = '';
4476 $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = 'CHECKED';
4478 $checked{'OTP_STATE'}{$cgiparams{'OTP_STATE'}} = 'CHECKED';
4480 $selected{'SIDE'}{'server'} = '';
4481 $selected{'SIDE'}{'client'} = '';
4482 $selected{'SIDE'}{$cgiparams{'SIDE'}} = 'SELECTED';
4484 $selected{'PROTOCOL'}{'udp'} = '';
4485 $selected{'PROTOCOL'}{'tcp'} = '';
4486 $selected{'PROTOCOL'}{$cgiparams{'PROTOCOL'}} = 'SELECTED';
4489 $checked{'AUTH'}{'psk'} = '';
4490 $checked{'AUTH'}{'certreq'} = '';
4491 $checked{'AUTH'}{'certgen'} = '';
4492 $checked{'AUTH'}{'certfile'} = '';
4493 $checked{'AUTH'}{$cgiparams{'AUTH'}} = 'CHECKED';
4495 $selected{'INTERFACE'}{$cgiparams{'INTERFACE'}} = 'SELECTED';
4497 $checked{'COMPLZO'}{'off'} = '';
4498 $checked{'COMPLZO'}{'on'} = '';
4499 $checked{'COMPLZO'}{$cgiparams{'COMPLZO'}} = 'CHECKED';
4501 $checked{'MSSFIX'}{'off'} = '';
4502 $checked{'MSSFIX'}{'on'} = '';
4503 $checked{'MSSFIX'}{$cgiparams{'MSSFIX'}} = 'CHECKED';
4505 $selected{'DCIPHER'}{'AES-256-GCM'} = '';
4506 $selected{'DCIPHER'}{'AES-192-GCM'} = '';
4507 $selected{'DCIPHER'}{'AES-128-GCM'} = '';
4508 $selected{'DCIPHER'}{'CAMELLIA-256-CBC'} = '';
4509 $selected{'DCIPHER'}{'CAMELLIA-192-CBC'} = '';
4510 $selected{'DCIPHER'}{'CAMELLIA-128-CBC'} = '';
4511 $selected{'DCIPHER'}{'AES-256-CBC'} = '';
4512 $selected{'DCIPHER'}{'AES-192-CBC'} = '';
4513 $selected{'DCIPHER'}{'AES-128-CBC'} = '';
4514 $selected{'DCIPHER'}{'DESX-CBC'} = '';
4515 $selected{'DCIPHER'}{'SEED-CBC'} = '';
4516 $selected{'DCIPHER'}{'DES-EDE3-CBC'} = '';
4517 $selected{'DCIPHER'}{'DES-EDE-CBC'} = '';
4518 $selected{'DCIPHER'}{'CAST5-CBC'} = '';
4519 $selected{'DCIPHER'}{'BF-CBC'} = '';
4520 $selected{'DCIPHER'}{'DES-CBC'} = '';
4521 $selected{'DCIPHER'}{$cgiparams{'DCIPHER'}} = 'SELECTED';
4522 $selected{'DAUTH'}{'whirlpool'} = '';
4523 $selected{'DAUTH'}{'SHA512'} = '';
4524 $selected{'DAUTH'}{'SHA384'} = '';
4525 $selected{'DAUTH'}{'SHA256'} = '';
4526 $selected{'DAUTH'}{'SHA1'} = '';
4527 $selected{'DAUTH'}{$cgiparams{'DAUTH'}} = 'SELECTED';
4528 $checked{'TLSAUTH'}{'off'} = '';
4529 $checked{'TLSAUTH'}{'on'} = '';
4530 $checked{'TLSAUTH'}{$cgiparams{'TLSAUTH'}} = 'CHECKED';
4533 &Header
::showhttpheaders
();
4534 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
4535 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
4538 &Header
::errorbox
($errormessage);
4541 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'warning messages'}:");
4542 print "<class name='base'>$warnmessage";
4543 print " </class>";
4544 &Header
::closebox
();
4547 print "<form method='post' enctype='multipart/form-data'>";
4548 print "<input type='hidden' name='TYPE' value='$cgiparams{'TYPE'}' />";
4550 if ($cgiparams{'KEY'}) {
4551 print "<input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />";
4552 print "<input type='hidden' name='AUTH' value='$cgiparams{'AUTH'}' />";
4555 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'connection'}:");
4557 my $readonly = ($cgiparams{'KEY'}) ? "readonly" : "";
4560 <table class="form">
4566 <input type="text" name="NAME" value="$cgiparams{'NAME'}" $readonly/>
4572 $Lang::tr{'remark title'}
4575 <input type="text" name="REMARK" value="$cgiparams{'REMARK'}" />
4580 if ($cgiparams{'TYPE'} eq 'host') {
4584 $Lang::tr{'enabled'}
4587 <input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} />
4593 $Lang::tr{'enable otp'}
4596 <input type='checkbox' name='OTP_STATE' $checked{'OTP_STATE'}{'on'} />
4602 if ($cgiparams{'TYPE'} eq 'net') {
4603 # If GCM ciphers are in usage, HMAC menu is disabled
4605 if (($confighash{$cgiparams{'KEY'}}[40] eq 'AES-256-GCM') ||
4606 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-192-GCM') ||
4607 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-128-GCM')) {
4608 $hmacdisabled = "disabled='disabled'";
4613 <td>$Lang::tr{'Act as'}</td>
4615 <select name='SIDE'>
4616 <option value='server' $selected{'SIDE'}{'server'}>$Lang::tr{'openvpn server'}</option>
4617 <option value='client' $selected{'SIDE'}{'client'}>$Lang::tr{'openvpn client'}</option>
4623 <td>$Lang::tr{'remote host/ip'}:</td>
4625 <input type='TEXT' name='REMOTE' value='$cgiparams{'REMOTE'}' />
4630 <td>$Lang::tr{'local subnet'} <img src='/blob.gif' alt='*' /></td>
4632 <input type='TEXT' name='LOCAL_SUBNET' value='$cgiparams{'LOCAL_SUBNET'}' />
4637 <td>$Lang::tr{'remote subnet'} <img src='/blob.gif' alt='*' /></td>
4639 <input type='text' name='REMOTE_SUBNET' value='$cgiparams{'REMOTE_SUBNET'}' />
4644 <td>$Lang::tr{'ovpn subnet'} <img src='/blob.gif' alt='*' /></td>
4646 <input type='TEXT' name='OVPN_SUBNET' value='$cgiparams{'OVPN_SUBNET'}' />
4651 <td>$Lang::tr{'protocol'}</td>
4653 <select name='PROTOCOL'>
4654 <option value='udp' $selected{'PROTOCOL'}{'udp'}>UDP</option>
4655 <option value='tcp' $selected{'PROTOCOL'}{'tcp'}>TCP</option>
4661 <td>$Lang::tr{'destination port'}: <img src='/blob.gif' alt='*' /></td>
4663 <input type='TEXT' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' size='5' />
4668 <td>Management Port ($Lang::tr{'openvpn default'}: <span class="base">$Lang::tr{'destination port'}):</td>
4670 <input type='TEXT' name='OVPN_MGMT' VALUE='$cgiparams{'OVPN_MGMT'}'size='5' />
4676 $Lang::tr{'MTU settings'}
4679 <table class="form">
4681 <td>$Lang::tr{'MTU'}</td>
4683 <input type='TEXT' name='MTU' VALUE='$cgiparams{'MTU'}'size='5' />
4690 <input type='TEXT' name='FRAGMENT' VALUE='$cgiparams{'FRAGMENT'}'size='5' />
4697 <input type='checkbox' name='MSSFIX' $checked{'MSSFIX'}{'on'} />
4702 <td>$Lang::tr{'comp-lzo'}</td>
4704 <input type='checkbox' name='COMPLZO' $checked{'COMPLZO'}{'on'} />
4710 $Lang::tr{'ovpn crypto settings'}:
4713 <table class="form">
4715 <td>$Lang::tr{'cipher'}</td>
4717 <select name='DCIPHER' id="n2ncipher" required>
4718 <option value='AES-256-GCM' $selected{'DCIPHER'}{'AES-256-GCM'}>AES-GCM (256 $Lang::tr{'bit'})</option>
4719 <option value='AES-192-GCM' $selected{'DCIPHER'}{'AES-192-GCM'}>AES-GCM (192 $Lang::tr{'bit'})</option>
4720 <option value='AES-128-GCM' $selected{'DCIPHER'}{'AES-128-GCM'}>AES-GCM (128 $Lang::tr{'bit'})</option>
4721 <option value='CAMELLIA-256-CBC' $selected{'DCIPHER'}{'CAMELLIA-256-CBC'}>CAMELLIA-CBC (256 $Lang::tr{'bit'})</option>
4722 <option value='CAMELLIA-192-CBC' $selected{'DCIPHER'}{'CAMELLIA-192-CBC'}>CAMELLIA-CBC (192 $Lang::tr{'bit'})</option>
4723 <option value='CAMELLIA-128-CBC' $selected{'DCIPHER'}{'CAMELLIA-128-CBC'}>CAMELLIA-CBC (128 $Lang::tr{'bit'})</option>
4724 <option value='AES-256-CBC' $selected{'DCIPHER'}{'AES-256-CBC'}>AES-CBC (256 $Lang::tr{'bit'}, $Lang::tr{'default'})</option>
4725 <option value='AES-192-CBC' $selected{'DCIPHER'}{'AES-192-CBC'}>AES-CBC (192 $Lang::tr{'bit'})</option>
4726 <option value='AES-128-CBC' $selected{'DCIPHER'}{'AES-128-CBC'}>AES-CBC (128 $Lang::tr{'bit'})</option>
4727 <option value='SEED-CBC' $selected{'DCIPHER'}{'SEED-CBC'}>SEED-CBC (128 $Lang::tr{'bit'})</option>
4728 <option value='DES-EDE3-CBC' $selected{'DCIPHER'}{'DES-EDE3-CBC'}>DES-EDE3-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4729 <option value='DESX-CBC' $selected{'DCIPHER'}{'DESX-CBC'}>DESX-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4730 <option value='DES-EDE-CBC' $selected{'DCIPHER'}{'DES-EDE-CBC'}>DES-EDE-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4731 <option value='BF-CBC' $selected{'DCIPHER'}{'BF-CBC'}>BF-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4732 <option value='CAST5-CBC' $selected{'DCIPHER'}{'CAST5-CBC'}>CAST5-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4738 <td>$Lang::tr{'ovpn ha'}:</td>
4740 <select name='DAUTH' id="n2nhmac" $hmacdisabled>
4741 <option value='whirlpool' $selected{'DAUTH'}{'whirlpool'}>Whirlpool (512 $Lang::tr{'bit'})</option>
4742 <option value='SHA512' $selected{'DAUTH'}{'SHA512'}>SHA2 (512 $Lang::tr{'bit'})</option>
4743 <option value='SHA384' $selected{'DAUTH'}{'SHA384'}>SHA2 (384 $Lang::tr{'bit'})</option>
4744 <option value='SHA256' $selected{'DAUTH'}{'SHA256'}>SHA2 (256 $Lang::tr{'bit'})</option>
4745 <option value='SHA1' $selected{'DAUTH'}{'SHA1'}>SHA1 (160 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4753 #### JAVA SCRIPT ####
4754 # Validate N2N cipher. If GCM will be used, HMAC menu will be disabled onchange
4757 var disable_options = false;
4758 document.getElementById('n2ncipher').onchange = function () {
4759 if((this.value == "AES-256-GCM"||this.value == "AES-192-GCM"||this.value == "AES-128-GCM")) {
4760 document.getElementById('n2nhmac').setAttribute('disabled', true);
4762 document.getElementById('n2nhmac').removeAttribute('disabled');
4769 if ($cgiparams{'TYPE'} eq 'host') {
4770 print "<table border='0' width='100%' cellspacing='1' cellpadding='0'><tr><td colspan='3'><hr><br><b>$Lang::tr{'ccd choose net'}</td></tr><tr><td height='20' colspan='3'></td></tr>";
4773 &General
::readhash
("${General::swroot}/ovpn/settings", \
%vpnnet);
4774 $vpnip=$vpnnet{'DOVPN_SUBNET'};
4775 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
4779 $checked{'check1'}{'off'} = '';
4780 $checked{'check1'}{'on'} = '';
4781 $checked{'check1'}{$cgiparams{'CHECK1'}} = 'CHECKED';
4782 print"<tr><td align='center' width='1%' valign='top'><input type='radio' name='CHECK1' value='dynamic' checked /></td><td align='left' valign='top' width='35%'>$Lang::tr{'ccd dynrange'} ($vpnip)</td><td width='30%'>";
4783 print"</td></tr></table><br><br>";
4784 my $name=$cgiparams{'CHECK1'};
4785 $checked{'RG'}{$cgiparams{'RG'}} = 'CHECKED';
4787 if (! -z
"${General::swroot}/ovpn/ccd.conf"){
4788 print"<table border='0' width='100%' cellspacing='1' cellpadding='0'><tr><td width='1%'></td><td width='30%' class='boldbase' align='center'><b>$Lang::tr{'ccd name'}</td><td width='15%' class='boldbase' align='center'><b>$Lang::tr{'network'}</td><td class='boldbase' align='center' width='18%'><b>$Lang::tr{'ccd clientip'}</td></tr>";
4789 foreach my $key (sort { uc($ccdconfhash{$a}[0]) cmp uc($ccdconfhash{$b}[0]) } keys %ccdconfhash) {
4791 @ccdconf=($ccdconfhash{$key}[0],$ccdconfhash{$key}[1]);
4792 if ($count % 2){print"<tr bgcolor='$Header::color{'color22'}'>";}else{print"<tr bgcolor='$Header::color{'color20'}'>";}
4793 print"<td align='center' width='1%'><input type='radio' name='CHECK1' value='$ccdconf[0]' $checked{'check1'}{$ccdconf[0]}/></td><td>$ccdconf[0]</td><td width='40%' align='center'>$ccdconf[1]</td><td align='left' width='10%'>";
4794 &fillselectbox
($ccdconf[0], $ccdconf[1], &convert_top30_ccd_allocation
($cgiparams{$name}));
4797 print "</table><br><br><hr><br><br>";
4801 &Header
::closebox
();
4802 if ($cgiparams{'KEY'} && $cgiparams{'AUTH'} eq 'psk') {
4804 } elsif (! $cgiparams{'KEY'}) {
4808 my $cakeydisabled='';
4809 my $cacrtdisabled='';
4810 if ( ! -f
"${General::swroot}/ovpn/ca/cakey.pem" ) { $cakeydisabled = "disabled='disabled'" } else { $cakeydisabled = "" };
4811 if ( ! -f
"${General::swroot}/ovpn/ca/cacert.pem" ) { $cacrtdisabled = "disabled='disabled'" } else { $cacrtdisabled = "" };
4813 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'authentication'});
4816 if ($cgiparams{'TYPE'} eq 'host') {
4819 <table width='100%' cellpadding='0' cellspacing='5' border='0'>
4821 <tr><td><input type='radio' name='AUTH' value='certreq' $checked{'AUTH'}{'certreq'} $cakeydisabled /></td><td class='base'>$Lang::tr{'upload a certificate request'}</td><td class='base' rowspan='2'><input type='file' name='FH' size='30' $cacrtdisabled></td></tr>
4822 <tr><td><input type='radio' name='AUTH' value='certfile' $checked{'AUTH'}{'certfile'} $cacrtdisabled /></td><td class='base'>$Lang::tr{'upload a certificate'}</td></tr>
4823 <tr><td colspan='3'> </td></tr>
4824 <tr><td colspan='3'><hr /></td></tr>
4825 <tr><td colspan='3'> </td></tr>
4826 <tr><td><input type='radio' name='AUTH' value='certgen' $checked{'AUTH'}{'certgen'} $cakeydisabled /></td><td class='base'>$Lang::tr{'generate a certificate'}</td><td> </td></tr>
4827 <tr><td> </td><td class='base'>$Lang::tr{'users fullname or system hostname'}: <img src='/blob.gif' alt='*' /></td><td class='base' nowrap='nowrap'><input type='text' name='CERT_NAME' value='$cgiparams{'CERT_NAME'}' SIZE='32' $cakeydisabled /></td></tr>
4828 <tr><td> </td><td class='base'>$Lang::tr{'users email'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_EMAIL' value='$cgiparams{'CERT_EMAIL'}' SIZE='32' $cakeydisabled /></td></tr>
4829 <tr><td> </td><td class='base'>$Lang::tr{'users department'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_OU' value='$cgiparams{'CERT_OU'}' SIZE='32' $cakeydisabled /></td></tr>
4830 <tr><td> </td><td class='base'>$Lang::tr{'organization name'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_ORGANIZATION' value='$cgiparams{'CERT_ORGANIZATION'}' SIZE='32' $cakeydisabled /></td></tr>
4831 <tr><td> </td><td class='base'>$Lang::tr{'city'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_CITY' value='$cgiparams{'CERT_CITY'}' SIZE='32' $cakeydisabled /></td></tr>
4832 <tr><td> </td><td class='base'>$Lang::tr{'state or province'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_STATE' value='$cgiparams{'CERT_STATE'}' SIZE='32' $cakeydisabled /></td></tr>
4833 <tr><td> </td><td class='base'>$Lang::tr{'country'}:</td><td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
4840 <table width='100%' cellpadding='0' cellspacing='5' border='0'>
4842 <tr><td><input type='radio' name='AUTH' value='certgen' $checked{'AUTH'}{'certgen'} $cakeydisabled /></td><td class='base'>$Lang::tr{'generate a certificate'}</td><td> </td></tr>
4843 <tr><td> </td><td class='base'>$Lang::tr{'users fullname or system hostname'}: <img src='/blob.gif' alt='*' /></td><td class='base' nowrap='nowrap'><input type='text' name='CERT_NAME' value='$cgiparams{'CERT_NAME'}' SIZE='32' $cakeydisabled /></td></tr>
4844 <tr><td> </td><td class='base'>$Lang::tr{'users email'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_EMAIL' value='$cgiparams{'CERT_EMAIL'}' SIZE='32' $cakeydisabled /></td></tr>
4845 <tr><td> </td><td class='base'>$Lang::tr{'users department'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_OU' value='$cgiparams{'CERT_OU'}' SIZE='32' $cakeydisabled /></td></tr>
4846 <tr><td> </td><td class='base'>$Lang::tr{'organization name'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_ORGANIZATION' value='$cgiparams{'CERT_ORGANIZATION'}' SIZE='32' $cakeydisabled /></td></tr>
4847 <tr><td> </td><td class='base'>$Lang::tr{'city'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_CITY' value='$cgiparams{'CERT_CITY'}' SIZE='32' $cakeydisabled /></td></tr>
4848 <tr><td> </td><td class='base'>$Lang::tr{'state or province'}:</td><td class='base' nowrap='nowrap'><input type='text' name='CERT_STATE' value='$cgiparams{'CERT_STATE'}' SIZE='32' $cakeydisabled /></td></tr>
4849 <tr><td> </td><td class='base'>$Lang::tr{'country'}:</td><td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
4857 foreach my $country (sort keys %{Countries
::countries
}) {
4858 print "<option value='$Countries::countries{$country}'";
4859 if ( $Countries::countries
{$country} eq $cgiparams{'CERT_COUNTRY'} ) {
4860 print " selected='selected'";
4862 print ">$country</option>";
4865 if ($cgiparams{'TYPE'} eq 'host') {
4868 <td> </td><td class='base'>$Lang::tr{'valid till'} (days): <img src='/blob.gif' alt='*' /</td>
4869 <td class='base' nowrap='nowrap'><input type='text' name='DAYS_VALID' value='$cgiparams{'DAYS_VALID'}' size='32' $cakeydisabled /></td></tr>
4871 <td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
4872 <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS1' value='$cgiparams{'CERT_PASS1'}' size='32' $cakeydisabled /></td></tr>
4873 <tr><td> </td><td class='base'>$Lang::tr{'pkcs12 file password'}:<br>($Lang::tr{'confirmation'})</td>
4874 <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS2' value='$cgiparams{'CERT_PASS2'}' size='32' $cakeydisabled /></td></tr>
4875 <tr><td colspan='3'> </td></tr>
4876 <tr><td colspan='3'><hr /></td></tr>
4877 <tr><td class='base' colspan='3' align='left'><img src='/blob.gif' alt='*' /> $Lang::tr{'required field'}</td></tr>
4883 <td> </td><td class='base'>$Lang::tr{'valid till'} (days): <img src='/blob.gif' alt='*' /</td>
4884 <td class='base' nowrap='nowrap'><input type='text' name='DAYS_VALID' value='$cgiparams{'DAYS_VALID'}' size='32' $cakeydisabled /></td></tr>
4885 <tr><td> </td><td> </td><td> </td></tr>
4886 <tr><td> </td><td> </td><td> </td></tr>
4887 <tr><td colspan='3'><hr /></td></tr>
4888 <tr><td class='base' colspan='3' align='left'><img src='/blob.gif' alt='*' /> $Lang::tr{'required field'}</td></tr>
4894 &Header
::closebox
();
4898 if ($cgiparams{'TYPE'} eq 'host') {
4900 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ccd client options'}:");
4904 <table border='0' width='100%'>
4905 <tr><td width='20%'>Redirect Gateway:</td><td colspan='3'><input type='checkbox' name='RG' $checked{'RG'}{'on'} /></td></tr>
4906 <tr><td colspan='4'><b><br>$Lang::tr{'ccd routes'}</b></td></tr>
4907 <tr><td colspan='4'> </td></tr>
4908 <tr><td valign='top'>$Lang::tr{'ccd iroute'}</td><td align='left' width='30%'><textarea name='IR' cols='26' rows='6' wrap='off'>
4911 if ($cgiparams{'IR'} ne ''){
4912 print $cgiparams{'IR'};
4914 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
4915 foreach my $key (keys %ccdroutehash) {
4916 if( $cgiparams{'NAME'} eq $ccdroutehash{$key}[0]){
4917 foreach my $i (1 .. $#{$ccdroutehash{$key}}) {
4918 if ($ccdroutehash{$key}[$i] ne ''){
4919 print $ccdroutehash{$key}[$i]."\n";
4921 $cgiparams{'IR'} .= $ccdroutehash{$key}[$i];
4928 </textarea></td><td valign='top' colspan='2'></td></tr>
4929 <tr><td colspan='4'><br></td></tr>
4930 <tr><td valign='top' rowspan='3'>$Lang::tr{'ccd iroute2'}</td><td align='left' valign='top' rowspan='3'><select name='IFROUTE' style="width: 205px"; size='6' multiple>
4944 open(FILE
, "${General::swroot}/main/routing") ;
4947 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
4949 foreach my $key (keys %ccdroute2hash) {
4950 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
4951 if ($ccdroute2hash{$key}[1] eq ''){
4958 print"<option>$Lang::tr{'ccd none'}</option>";
4960 print"<option selected>$Lang::tr{'ccd none'}</option>";
4962 #check if static routes are defined for client
4963 foreach my $line (@current) {
4965 $line=~s/\s*$//g; # remove newline
4966 @temp=split(/\,/,$line);
4967 $temp[1] = '' unless defined $temp[1]; # not always populated
4968 my ($a,$b) = split(/\//,$temp[1]);
4969 $temp[1] = $a."/".&General
::iporsubtocidr
($b);
4970 foreach my $key (keys %ccdroute2hash) {
4971 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
4972 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
4973 if($ccdroute2hash{$key}[$i] eq $a."/".&General
::iporsubtodec
($b)){
4979 if ($set == '1' && $#temp != -1){ print"<option selected>$temp[1]</option>";$set=0;}elsif($set == '0' && $#temp != -1){print"<option>$temp[1]</option>";}
4983 &General
::readhasharray
("${General::swroot}/vpn/config", \
%vpnconfig);
4984 foreach my $vpn (keys %vpnconfig) {
4985 # Skip all disabled VPN connections
4986 my $enabled = $vpnconfig{$vpn}[0];
4987 next unless ($enabled eq "on");
4989 my $name = $vpnconfig{$vpn}[1];
4992 my @networks = split(/\|/, $vpnconfig{$vpn}[11]);
4993 foreach my $network (@networks) {
4996 foreach my $key (keys %ccdroute2hash) {
4997 if ($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}) {
4998 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
4999 if ($ccdroute2hash{$key}[$i] eq $network) {
5000 $selected = "selected";
5006 print "<option value=\"$network\" $selected>$name ($network)</option>\n";
5010 #check if green,blue,orange are defined for client
5011 foreach my $key (keys %ccdroute2hash) {
5012 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
5014 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
5015 if ($ccdroute2hash{$key}[$i] eq $Network::ethernet
{'GREEN_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'GREEN_NETMASK'})){
5018 if (&Header
::blue_used
()){
5019 if( $ccdroute2hash{$key}[$i] eq $Network::ethernet
{'BLUE_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'BLUE_NETMASK'})) {
5023 if (&Header
::orange_used
()){
5024 if( $ccdroute2hash{$key}[$i] eq $Network::ethernet
{'ORANGE_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'ORANGE_NETMASK'}) ) {
5031 if (&Header
::blue_used
() && $selblue == '1'){ print"<option selected>$Lang::tr{'blue'}</option>";$selblue=0;}elsif(&Header
::blue_used
() && $selblue == '0'){print"<option>$Lang::tr{'blue'}</option>";}
5032 if (&Header
::orange_used
() && $selorange == '1'){ print"<option selected>$Lang::tr{'orange'}</option>";$selorange=0;}elsif(&Header
::orange_used
() && $selorange == '0'){print"<option>$Lang::tr{'orange'}</option>";}
5033 if ($selgreen == '1' || $other == '0'){ print"<option selected>$Lang::tr{'green'}</option>";$set=0;}else{print"<option>$Lang::tr{'green'}</option>";};
5036 </select></td><td valign='top'>DNS1:</td><td valign='top'><input type='TEXT' name='CCD_DNS1' value='$cgiparams{'CCD_DNS1'}' size='30' /></td></tr>
5037 <tr valign='top'><td>DNS2:</td><td><input type='TEXT' name='CCD_DNS2' value='$cgiparams{'CCD_DNS2'}' size='30' /></td></tr>
5038 <tr valign='top'><td valign='top'>WINS:</td><td><input type='TEXT' name='CCD_WINS' value='$cgiparams{'CCD_WINS'}' size='30' /></td></tr></table><br><hr>
5042 &Header
::closebox
();
5044 print "<div align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' />";
5045 print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
5046 &Header
::closebigbox
();
5047 &Header
::closepage
();
5055 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
5056 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
5060 # Only load status when the RW server is enabled
5061 if ($vpnsettings{'ENABLED'} eq 'on') {
5062 open(FILE
, "/usr/local/bin/openvpnctrl rw log |");
5067 $checked{'ENABLED'}{'off'} = '';
5068 $checked{'ENABLED'}{'on'} = '';
5069 $checked{'ENABLED'}{$vpnsettings{'ENABLED'}} = 'CHECKED';
5071 &Header
::showhttpheaders
();
5072 &Header
::openpage
($Lang::tr
{'status ovpn'}, 1, '');
5073 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
5075 # Show any errors and warnings
5076 &Header
::errorbox
($errormessage);
5079 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'warning messages'});
5080 print "$warnmessage<br>";
5081 print "$Lang::tr{'fwdfw warn1'}<br>";
5082 &Header
::closebox
();
5083 print"<center><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'ok'}' style='width: 5em;'></form>";
5084 &Header
::closepage
();
5088 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'ovpn roadwarrior settings'});
5090 # Show the service status
5091 &Header
::ServiceStatus
({
5092 $Lang::tr
{'ovpn roadwarrior server'} => {
5093 "process" => "openvpn",
5094 "pidfile" => "/var/run/openvpn-rw.pid",
5099 <form method='POST'>
5100 <table class="form">
5102 <td class='boldbase'>
5103 $Lang::tr{'enabled'}
5106 <input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} />
5111 <td colspan='2'></td>
5116 $Lang::tr{'ovpn fqdn'}
5119 <input type='text' name='VPN_IP' value='$vpnsettings{'VPN_IP'}' />
5125 $Lang::tr{'ovpn dynamic client subnet'}
5128 <input type='TEXT' name='DOVPN_SUBNET' value='$vpnsettings{'DOVPN_SUBNET'}' />
5134 <input type='submit' name='ACTION' value='$Lang::tr{'save'}' />
5135 <input type='submit' name='ACTION' value='$Lang::tr{'ccd net'}' />
5136 <input type='submit' name='ACTION' value='$Lang::tr{'advanced server'}' />
5143 &Header
::closebox
();
5145 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'connection status and controlc' });
5161 <th width='5%' colspan='8'>
5169 foreach my $key (sort { ncmp
($confighash{$a}[1],$confighash{$b}[1]) } keys %confighash) {
5170 my $status = $confighash{$key}[0];
5171 my $name = $confighash{$key}[1];
5172 my $type = $confighash{$key}[3];
5174 # Create some simple booleans to check the status
5176 my $expiresSoon = 0;
5178 # Fetch information about the certificate for non-N2N connections only
5179 if ($confighash{$key}[3] ne 'net') {
5180 my @cavalid = &General
::system_output
("/usr/bin/openssl", "x509", "-text",
5181 "-in", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
5185 # Parse the certificate information
5186 foreach my $line (@cavalid) {
5187 if ($line =~ /Not After : (.*)[\n]/) {
5188 $expiryDate = &Date
::Parse
::str2time
($1);
5193 # Calculate the remaining time
5194 my $remainingTime = $expiryDate - time();
5196 # Determine whether the certificate has already expired, or will so soon
5197 $hasExpired = ($remainingTime <= 0);
5198 $expiresSoon = ($remainingTime <= 30 * 24 * 3600);
5203 # Highlight the row if the certificate has expired/will expire soon
5204 if ($hasExpired || $expiresSoon) {
5205 push(@classes, "is-warning");
5209 print "<tr class='@classes'>";
5211 # Show the name of the connection
5212 print " <th scope='row'>$name";
5214 print " ($Lang::tr{'openvpn cert has expired'})";
5215 } elsif ($expiresSoon) {
5216 print " ($Lang::tr{'openvpn cert expires soon'})";
5221 print "<td class='text-center'>$Lang::tr{$type}</td>";
5224 print "<td>$confighash{$key}[25]</td>";
5226 my $connstatus = "DISCONNECTED";
5228 # Disabled Connections
5229 if ($status eq "off") {
5230 $connstatus = "DISABLED";
5233 } elsif ($type eq "net") {
5234 if (-e
"/var/run/${name}n2n.pid") {
5235 my $port = $confighash{$key}[22];
5238 $connstatus = &openvpn_status
($confighash{$key}[22]);
5243 } elsif ($type eq "host") {
5246 foreach my $line (@status) {
5249 if ($line =~ /^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/) {
5250 my @match = split(m/^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/, $line);
5252 if ($match[1] ne "Common Name") {
5256 if ($cn eq "$confighash{$key}[2]") {
5257 $connstatus = "CONNECTED";
5263 if ($connstatus eq "DISABLED") {
5264 print "<td class='status is-disabled'>$Lang::tr{'capsclosed'}</td>";
5265 } elsif ($connstatus eq "CONNECTED") {
5266 print "<td class='status is-connected'>$Lang::tr{'capsopen'}</td>";
5267 } elsif ($connstatus eq "DISCONNECTED") {
5268 print "<td class='status is-disconnected'>$Lang::tr{'capsclosed'}</td>";
5270 print "<td class='status is-unknown'>$connstatus</td>";
5273 # Download Configuration
5275 <td class="text-center">
5276 <form method='post' name='frm${key}a'>
5277 <input type='image' name='$Lang::tr{'dl client arch'}' src='/images/openvpn.png'
5278 alt='$Lang::tr{'dl client arch'}' title='$Lang::tr{'dl client arch'}' />
5279 <input type='hidden' name='ACTION' value='$Lang::tr{'dl client arch'}' />
5280 <input type='hidden' name='KEY' value='$key' />
5286 if ($confighash{$key}[4] eq 'cert') {
5288 <td class="text-center">
5289 <form method='post' name='frm${key}b'>
5290 <input type='image' name='$Lang::tr{'show certificate'}' src='/images/info.gif'
5291 alt='$Lang::tr{'show certificate'}' title='$Lang::tr{'show certificate'}' />
5292 <input type='hidden' name='ACTION' value='$Lang::tr{'show certificate'}' />
5293 <input type='hidden' name='KEY' value='$key' />
5303 if ($confighash{$key}[43] eq 'on') {
5305 <td class="text-center">
5306 <form method='post' name='frm${key}o'>
5307 <input type='image' name='$Lang::tr{'show otp qrcode'}' src='/images/qr-code.png'
5308 alt='$Lang::tr{'show otp qrcode'}' title='$Lang::tr{'show otp qrcode'}' />
5309 <input type='hidden' name='ACTION' value='$Lang::tr{'show otp qrcode'}' />
5310 <input type='hidden' name='KEY' value='$key' />
5318 # Download Certificate
5319 if ($confighash{$key}[4] eq 'cert' && -f
"${General::swroot}/ovpn/certs/$confighash{$key}[1].p12") {
5321 <td class="text-center">
5322 <form method='post' name='frm${key}c'>
5323 <input type='image' name='$Lang::tr{'download pkcs12 file'}' src='/images/media-floppy.png'
5324 alt='$Lang::tr{'download pkcs12 file'}' title='$Lang::tr{'download pkcs12 file'}' />
5325 <input type='hidden' name='ACTION' value='$Lang::tr{'download pkcs12 file'}' />
5326 <input type='hidden' name='KEY' value='$key' />
5331 } elsif ($confighash{$key}[4] eq 'cert') {
5333 <td class="text-center">
5334 <form method='post' name='frm${key}c'>
5335 <input type='image' name='$Lang::tr{'download certificate'}' src='/images/media-floppy.png'
5336 alt='$Lang::tr{'download certificate'}' title='$Lang::tr{'download certificate'}' />
5337 <input type='hidden' name='ACTION' value='$Lang::tr{'download certificate'}' />
5338 <input type='hidden' name='KEY' value='$key' />
5346 if ($status eq 'on') {
5353 <td class="text-center">
5354 <form method='post' name='frm${key}d'>
5355 <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif'
5356 alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />
5357 <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
5358 <input type='hidden' name='KEY' value='$key' />
5362 <td class="text-center">
5363 <form method='post' name='frm${key}e'>
5364 <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
5365 <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif'
5366 alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
5367 <input type='hidden' name='KEY' value='$key' />
5371 <td class="text-center">
5372 <form method='post' name='frm${key}f'>
5373 <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
5374 <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif'
5375 alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
5376 <input type='hidden' name='KEY' value='$key' />
5387 <table class="form">
5390 <form method='post'>
5391 <input type='submit' name='ACTION' value='$Lang::tr{'add'}' />
5392 <input type='submit' name='ACTION' value='$Lang::tr{'ovpn con stat'}' />
5399 &Header
::closebox
();
5402 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'certificate authorities'}");
5404 <table width='100%' cellspacing='1' cellpadding='0' class='tbl'>
5406 <th width='25%' class='boldbase' align='center'><b>$Lang::tr{'name'}</b></th>
5407 <th width='65%' class='boldbase' align='center'><b>$Lang::tr{'subject'}</b></th>
5408 <th width='10%' class='boldbase' colspan='3' align='center'><b>$Lang::tr{'action'}</b></th>
5412 my $col1="bgcolor='$Header::color{'color22'}'";
5413 my $col2="bgcolor='$Header::color{'color20'}'";
5415 my $col3="bgcolor='$Header::color{'color22'}'";
5417 my $col4="bgcolor='$Header::color{'color20'}'";
5419 if (-f
"${General::swroot}/ovpn/ca/cacert.pem") {
5420 my @casubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
5423 foreach my $line (@casubject) {
5424 if ($line =~ /Subject: (.*)[\n]/) {
5426 $casubject =~ s
+/Email
+, E
+;
5427 $casubject =~ s/ ST=/ S=/;
5435 <td class='base' $col1>$Lang::tr{'root certificate'}</td>
5436 <td class='base' $col1>$casubject</td>
5437 <form method='post' name='frmrootcrta'><td width='3%' align='center' $col1>
5438 <input type='hidden' name='ACTION' value='$Lang::tr{'show root certificate'}' />
5439 <input type='image' name='$Lang::tr{'edit'}' src='/images/info.gif' alt='$Lang::tr{'show root certificate'}' title='$Lang::tr{'show root certificate'}' width='20' height='20' border='0' />
5441 <form method='post' name='frmrootcrtb'><td width='3%' align='center' $col1>
5442 <input type='image' name='$Lang::tr{'download root certificate'}' src='/images/media-floppy.png' alt='$Lang::tr{'download root certificate'}' title='$Lang::tr{'download root certificate'}' border='0' />
5443 <input type='hidden' name='ACTION' value='$Lang::tr{'download root certificate'}' />
5445 <td width='4%' $col1> </td>
5450 # display rootcert generation buttons
5453 <td class='base' $col1>$Lang::tr{'root certificate'}:</td>
5454 <td class='base' $col1>$Lang::tr{'not present'}</td>
5455 <td colspan='3' $col1> </td>
5461 if (-f
"${General::swroot}/ovpn/certs/servercert.pem") {
5462 my @hostsubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
5465 foreach my $line (@hostsubject) {
5466 if ($line =~ /Subject: (.*)[\n]/) {
5468 $hostsubject =~ s
+/Email
+, E
+;
5469 $hostsubject =~ s/ ST=/ S=/;
5477 <td class='base' $col2>$Lang::tr{'host certificate'}</td>
5478 <td class='base' $col2>$hostsubject</td>
5479 <form method='post' name='frmhostcrta'><td width='3%' align='center' $col2>
5480 <input type='hidden' name='ACTION' value='$Lang::tr{'show host certificate'}' />
5481 <input type='image' name='$Lang::tr{'show host certificate'}' src='/images/info.gif' alt='$Lang::tr{'show host certificate'}' title='$Lang::tr{'show host certificate'}' width='20' height='20' border='0' />
5483 <form method='post' name='frmhostcrtb'><td width='3%' align='center' $col2>
5484 <input type='image' name="$Lang::tr{'download host certificate'}" src='/images/media-floppy.png' alt="$Lang::tr{'download host certificate'}" title="$Lang::tr{'download host certificate'}" border='0' />
5485 <input type='hidden' name='ACTION' value="$Lang::tr{'download host certificate'}" />
5487 <td width='4%' $col2> </td>
5495 <td width='25%' class='base' $col2>$Lang::tr{'host certificate'}:</td>
5496 <td class='base' $col2>$Lang::tr{'not present'}</td>
5497 </td><td colspan='3' $col2> </td>
5503 # Adding ta.key to chart
5504 if (-f
"${General::swroot}/ovpn/certs/ta.key") {
5505 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
5506 my @tasubject = <FILE
>;
5510 foreach my $line (@tasubject) {
5511 if($line =~ /# (.*)[\n]/) {
5521 <td class='base' $col4>$Lang::tr{'ta key'}</td>
5522 <td class='base' $col4>$tasubject</td>
5523 <form method='post' name='frmtakey'><td width='3%' align='center' $col4>
5524 <input type='hidden' name='ACTION' value='$Lang::tr{'show tls-auth key'}' />
5525 <input type='image' name='$Lang::tr{'edit'}' src='/images/info.gif' alt='$Lang::tr{'show tls-auth key'}' title='$Lang::tr{'show tls-auth key'}' width='20' height='20' border='0' />
5527 <form method='post' name='frmtakey'><td width='3%' align='center' $col4>
5528 <input type='image' name='$Lang::tr{'download tls-auth key'}' src='/images/media-floppy.png' alt='$Lang::tr{'download tls-auth key'}' title='$Lang::tr{'download tls-auth key'}' border='0' />
5529 <input type='hidden' name='ACTION' value='$Lang::tr{'download tls-auth key'}' />
5531 <td width='4%' $col4> </td>
5539 <td width='25%' class='base' $col4>$Lang::tr{'ta key'}:</td>
5540 <td class='base' $col4>$Lang::tr{'not present'}</td>
5541 <td colspan='3' $col4> </td>
5547 if (! -f
"${General::swroot}/ovpn/ca/cacert.pem") {
5548 print "<tr><td colspan='5' align='center'><form method='post'>";
5549 print "<input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' />";
5550 print "</form></td></tr>\n";
5553 if (keys %cahash > 0) {
5554 foreach my $key (keys %cahash) {
5555 if (($key + 1) % 2) {
5556 print "<tr bgcolor='$Header::color{'color20'}'>\n";
5558 print "<tr bgcolor='$Header::color{'color22'}'>\n";
5560 print "<td class='base'>$cahash{$key}[0]</td>\n";
5561 print "<td class='base'>$cahash{$key}[1]</td>\n";
5563 <form method='post' name='cafrm${key}a'><td align='center'>
5564 <input type='image' name='$Lang::tr{'show ca certificate'}' src='/images/info.gif' alt='$Lang::tr{'show ca certificate'}' title='$Lang::tr{'show ca certificate'}' border='0' />
5565 <input type='hidden' name='ACTION' value='$Lang::tr{'show ca certificate'}' />
5566 <input type='hidden' name='KEY' value='$key' />
5568 <form method='post' name='cafrm${key}b'><td align='center'>
5569 <input type='image' name='$Lang::tr{'download ca certificate'}' src='/images/media-floppy.png' alt='$Lang::tr{'download ca certificate'}' title='$Lang::tr{'download ca certificate'}' border='0' />
5570 <input type='hidden' name='ACTION' value='$Lang::tr{'download ca certificate'}' />
5571 <input type='hidden' name='KEY' value='$key' />
5573 <form method='post' name='cafrm${key}c'><td align='center'>
5574 <input type='hidden' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
5575 <input type='image' name='$Lang::tr{'remove ca certificate'}' src='/images/delete.gif' alt='$Lang::tr{'remove ca certificate'}' title='$Lang::tr{'remove ca certificate'}' width='20' height='20' border='0' />
5576 <input type='hidden' name='KEY' value='$key' />
5585 # If the file contains entries, print Key to action icons
5586 if ( -f
"${General::swroot}/ovpn/ca/cacert.pem") {
5590 <td class='boldbase'> <b>$Lang::tr{'legend'}:</b></td>
5591 <td> <img src='/images/info.gif' alt='$Lang::tr{'show certificate'}' /></td>
5592 <td class='base'>$Lang::tr{'show certificate'}</td>
5593 <td> <img src='/images/media-floppy.png' alt='$Lang::tr{'download certificate'}' /></td>
5594 <td class='base'>$Lang::tr{'download certificate'}</td>
5605 <form method='post' enctype='multipart/form-data'>
5606 <table border='0' width='100%'>
5608 <td colspan='4'><b>$Lang::tr{'upload ca certificate'}</b></td>
5612 <td width='10%'>$Lang::tr{'ca name'}:</td>
5613 <td width='30%'><input type='text' name='CA_NAME' value='$cgiparams{'CA_NAME'}' size='15' align='left'></td>
5614 <td width='30%'><input type='file' name='FH' size='25'>
5615 <td width='30%'align='right'><input type='submit' name='ACTION' value='$Lang::tr{'upload ca certificate'}'></td>
5619 <td colspan='3'> </td>
5620 <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'show crl'}' /></td>
5629 if ($vpnsettings{'ENABLED'} eq "yes") {
5630 print "<div align='center'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' disabled='disabled' /></div></form>\n";
5632 print "<div align='center'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' /></div></form>\n";
5634 &Header
::closebox
();
5638 &Header
::closepage
();