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,
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 # Writes the OpenVPN RW server settings and ensures that some values are set
215 sub writesettings
() {
217 if ($vpnsettings{"TLSAUTH"} eq "") {
218 $vpnsettings{"TLSAUTH"} = "off";
222 if ($vpnsettings{"MSSFIX"} eq "") {
223 $vpnsettings{"MSSFIX"} = "off";
226 &General
::writehash
("${General::swroot}/ovpn/settings", \
%vpnsettings);
229 sub writeserverconf
{
230 # Do we require the OpenSSL Legacy Provider?
231 my $requires_legacy_provider = 0;
233 open(CONF
, ">${General::swroot}/ovpn/server.conf") or die "Unable to open ${General::swroot}/ovpn/server.conf: $!";
235 print CONF
"#OpenVPN Server conf\n";
237 print CONF
"daemon openvpnserver\n";
238 print CONF
"writepid $RW_PID\n";
239 print CONF
"#DAN prepare OpenVPN for listening on blue and orange\n";
240 print CONF
";local $vpnsettings{'VPN_IP'}\n";
241 print CONF
"dev tun\n";
242 print CONF
"proto $vpnsettings{'DPROTOCOL'}\n";
243 print CONF
"port $vpnsettings{'DDEST_PORT'}\n";
244 print CONF
"script-security 3\n";
245 print CONF
"ifconfig-pool-persist /var/ipfire/ovpn/ovpn-leases.db 3600\n";
246 print CONF
"client-config-dir /var/ipfire/ovpn/ccd\n";
247 print CONF
"tls-server\n";
248 print CONF
"ca ${General::swroot}/ovpn/ca/cacert.pem\n";
249 print CONF
"cert ${General::swroot}/ovpn/certs/servercert.pem\n";
250 print CONF
"key ${General::swroot}/ovpn/certs/serverkey.pem\n";
251 print CONF
"dh $DHPARAM\n";
253 # Enable subnet topology
254 print CONF
"# Topology\n";
255 print CONF
"topology subnet\n\n";
257 my $netaddress = &Network
::get_netaddress
($vpnsettings{'DOVPN_SUBNET'});
258 my $subnetmask = &Network
::get_netmask
($vpnsettings{'DOVPN_SUBNET'});
260 print CONF
"server $netaddress $subnetmask\n";
261 print CONF
"tun-mtu $vpnsettings{'DMTU'}\n";
263 # Write custom routes
264 if ($vpnsettings{'ROUTES_PUSH'} ne '') {
265 my @routes = split(/\|/, $vpnsettings{'ROUTES_PUSH'});
267 foreach my $route (@routes) {
268 my $netaddr = &Network
::get_netaddress
($route);
269 my $netmask = &Network
::get_netmask
($route);
271 if (defined($netaddr) && defined($netmask)) {
272 print CONF
"push \"route ${netaddr} ${netmask}\"\n";
278 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
279 foreach my $key (keys %ccdconfhash) {
280 my $a=$ccdconfhash{$key}[1];
281 my ($b,$c) = split (/\//, $a);
282 print CONF
"route $b ".&General
::cidrtosub
($c)."\n";
285 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
286 foreach my $key (keys %ccdroutehash) {
287 foreach my $i ( 1 .. $#{$ccdroutehash{$key}}){
288 my ($a,$b)=split (/\//,$ccdroutehash{$key}[$i]);
289 print CONF
"route $a $b\n";
293 if ($vpnsettings{MSSFIX
} eq 'on') {
294 print CONF
"mssfix\n";
296 print CONF
"mssfix 0\n";
298 if ($vpnsettings{FRAGMENT
} ne '' && $vpnsettings{'DPROTOCOL'} ne 'tcp') {
299 print CONF
"fragment $vpnsettings{'FRAGMENT'}\n";
302 # Regularly send keep-alive packets
303 print CONF
"keepalive 10 60\n";
305 print CONF
"status-version 1\n";
306 print CONF
"status $RW_STATUS 30\n";
309 if ($vpnsettings{'DATACIPHERS'} ne '') {
310 print CONF
"data-ciphers " . $vpnsettings{'DATACIPHERS'} =~ s/\|/:/gr . "\n";
313 # Enable fallback cipher?
314 if ($vpnsettings{'DCIPHER'} ne '') {
315 if (&is_legacy_cipher
($vpnsettings{'DCIPHER'})) {
316 $requires_legacy_provider++;
319 print CONF
"data-ciphers-fallback $vpnsettings{'DCIPHER'}\n";
322 print CONF
"auth $vpnsettings{'DAUTH'}\n";
324 if (&is_legacy_auth
($vpnsettings{'DAUTH'})) {
325 $requires_legacy_provider++;
328 # Set TLSv2 as minimum
329 print CONF
"tls-version-min 1.2\n";
331 if ($vpnsettings{'TLSAUTH'} eq 'on') {
332 print CONF
"tls-auth ${General::swroot}/ovpn/certs/ta.key\n";
336 # Use migration to support clients that have compression enabled, but disable
337 # compression for everybody else.
338 print CONF
"compress migrate\n";
340 if ($vpnsettings{REDIRECT_GW_DEF1
} eq 'on') {
341 print CONF
"push \"redirect-gateway def1\"\n";
343 if ($vpnsettings{DHCP_DOMAIN
} ne '') {
344 print CONF
"push \"dhcp-option DOMAIN $vpnsettings{DHCP_DOMAIN}\"\n";
347 if ($vpnsettings{DHCP_DNS
} ne '') {
348 print CONF
"push \"dhcp-option DNS $vpnsettings{DHCP_DNS}\"\n";
351 if ($vpnsettings{DHCP_WINS
} ne '') {
352 print CONF
"push \"dhcp-option WINS $vpnsettings{DHCP_WINS}\"\n";
355 if ($vpnsettings{MAX_CLIENTS
} eq '') {
356 print CONF
"max-clients 100\n";
358 if ($vpnsettings{MAX_CLIENTS
} ne '') {
359 print CONF
"max-clients $vpnsettings{MAX_CLIENTS}\n";
361 print CONF
"tls-verify /usr/lib/openvpn/verify\n";
362 print CONF
"crl-verify /var/ipfire/ovpn/crls/cacrl.pem\n";
363 print CONF
"auth-user-pass-optional\n";
364 print CONF
"reneg-sec 86400\n";
365 print CONF
"user nobody\n";
366 print CONF
"group nobody\n";
367 print CONF
"persist-key\n";
368 print CONF
"persist-tun\n";
369 print CONF
"verb 3\n";
371 print CONF
"# Log clients connecting/disconnecting\n";
372 print CONF
"client-connect \"/usr/sbin/openvpn-metrics client-connect\"\n";
373 print CONF
"client-disconnect \"/usr/sbin/openvpn-metrics client-disconnect\"\n";
376 print CONF
"# Enable Management Socket\n";
377 print CONF
"management /var/run/openvpn.sock unix\n";
378 print CONF
"management-client-auth\n";
380 # Enable the legacy provider
381 if ($requires_legacy_provider > 0) {
382 print CONF
"providers legacy default\n";
385 # Send clients a message when the server is being shut down
386 print CONF
"explicit-exit-notify\n";
390 # Rewrite all CCD configurations
391 &write_ccd_configs
();
398 # Checks a ccdname for letters, numbers and spaces
399 sub validccdname
($) {
402 # name should be at least one character in length
403 # but no more than 63 characters
404 if (length ($name) < 1 || length ($name) > 63) {
408 # Only valid characters are a-z, A-Z, 0-9, space and -
409 if ($name !~ /^[a-zA-Z0-9 -]*$/) {
422 # Load all connections
423 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
425 # Check if the subnet is in use
426 foreach my $key (keys %conns) {
427 if ($conns{$key}[32] eq $name) {
428 return $Lang::tr
{'ccd err hostinnet'};
433 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
436 foreach my $key (keys %subnets) {
437 if ($subnets{$key}[0] eq $name){
438 delete $subnets{$key};
442 # Write the subnets back
443 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
445 # Update the server configuration to remove routes
449 # Returns the network with the matching name
450 sub get_cdd_network
($) {
455 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
457 # Find the matching subnet
458 foreach my $key (keys %subnets) {
459 if ($subnets{$key}[0] eq $name) {
460 return $subnets{$key}[1];
471 my %ccdconfhash = ();
473 # Check if the name is valid
474 unless (&validccdname
($name)) {
475 return $Lang::tr
{'ccd err invalidname'};
478 # Fetch the network address & prefix
479 my $address = &Network
::get_netaddress
($network);
480 my $prefix = &Network
::get_prefix
($network);
482 # If we could not decode the subnet, it must be invalid
483 if (!defined $address || !defined $prefix) {
484 return $Lang::tr
{'ccd err invalidnet'};
486 # If the network is smaller than /30, there is no point in using it
487 } elsif ($prefix > 30) {
488 return $Lang::tr
{'ccd err invalidnet'};
491 # Read the configuration
492 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
495 my $key = &General
::findhasharraykey
(\
%ccdconfhash);
498 $ccdconfhash{$key}[0] = $name;
499 $ccdconfhash{$key}[1] = "$address/$prefix";
501 # Write the hash back
502 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
504 # Update the server configuration to add routes
516 # Check if the new name is valid
517 unless (&validccdname
($newname)) {
518 $errormessage = $Lang::tr
{'ccd err invalidname'};
523 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
525 # Check if the name already exists
526 foreach my $key (keys %ccdconfhash) {
527 if ($ccdconfhash{$key}[0] eq $newname) {
528 return $Lang::tr
{'ccd err netadrexist'};
533 foreach my $key (keys %ccdconfhash) {
534 if ($ccdconfhash{$key}[1] eq $subnet) {
535 $oldname = $ccdconfhash{$key}[0];
536 $ccdconfhash{$key}[0] = $newname;
541 # Load all configurations
542 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
544 # Update all matching connections
545 foreach my $key (keys %conns) {
546 if ($conns{$key}[32] eq $oldname) {
547 $conns{$key}[32] = $newname;
551 # Write back the configuration
552 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
553 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
556 sub get_ccd_client_routes
($) {
559 my %client_routes = ();
562 # Load all client routes
563 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%client_routes);
565 foreach my $key (keys %client_routes) {
566 if ($client_routes{$key}[0] eq $name) {
567 push(@routes, $client_routes{$key}[1]);
574 sub get_ccd_server_routes
($) {
577 my %server_routes = ();
580 # Load all server routes
581 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%server_routes);
583 foreach my $key (keys %server_routes) {
584 if ($server_routes{$key}[0] eq $name) {
587 while (my $route = $server_routes{$key}[$i++]) {
588 push(@routes, $route);
596 # This function rewrites all CCD configuration files upon change
597 sub write_ccd_configs
() {
600 # Load all configurations
601 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
603 foreach my $key (keys %conns) {
604 my $name = $conns{$key}[1];
605 my $type = $conns{$key}[3];
607 # Skip anything that isn't a host connection
608 next unless ($type eq "host");
610 my $filename = "${General::swroot}/ovpn/ccd/$conns{$key}[2]";
612 # Open the configuration file
613 open(CONF
, ">${filename}") or die "Unable to open ${filename} for writing: $!";
616 print CONF
"# OpenVPN Client Configuration File\n\n";
618 # Fetch the allocated IP address (if any)
619 my $pool = $conns{$key}[32];
620 my $address = $conns{$key}[33];
622 # If the client has a dynamically allocated IP address, there is nothing to do
623 if ($pool eq "dynamic") {
624 print CONF
"# This client uses the dynamic pool\n\n";
626 # Otherwise we need to push the selected IP address
628 $address = &convert_top30_ccd_allocation
($address);
630 # Fetch the network of the pool
631 my $network = &get_cdd_network
($pool);
632 my $netaddr = &Network
::get_netaddress
($network);
633 my $netmask = &Network
::get_netmask
($network);
635 # The gateway is always the first address in the network
636 # (this is needed to push any routes below)
637 my $gateway = &Network
::find_next_ip_address
($netaddr, 1);
639 if (defined $address && defined $network && defined $netmask) {
640 print CONF
"# Allocated IP address from $pool\n";
641 print CONF
"ifconfig-push ${address} ${netmask}\n";
644 # Push the first address of the static pool as the gateway.
645 # Withtout this pushed, the client will receive the first IP address
646 # of the dynamic pool which will cause problems later on:
647 # Any additional routes won't be able to reach the dynamic gateway
648 # but pushing a host route is not possible, because the OpenVPN client
649 # does not seem to understand how a layer 3 VPN works.
650 if (defined $gateway) {
651 print CONF
"push \"route-gateway ${gateway}\"\n";
654 # Add a host route for the dynamic pool gateway so that
655 # the firewall can reach the client without needing to assign
656 # the gateway IP address of the static pool to the tun interface.
657 $netaddr = &Network
::get_netaddress
($vpnsettings{'DOVPN_SUBNET'});
658 $gateway = &Network
::find_next_ip_address
($netaddr, 1);
659 if (defined $gateway) {
660 print CONF
"push \"route ${gateway} 255.255.255.255\"\n";
668 my $redirect = $conns{$key}[34];
670 if ($redirect eq "on") {
671 print CONF
"# Redirect all traffic to us\n";
672 print CONF
"push redirect-gateway\n\n";
687 print CONF
"# DHCP Options";
689 foreach my $option (keys %options) {
690 foreach (@options{$option}) {
694 print CONF
"push \"dhcp-option $option $_\"\n";
701 # Networks routed to client
702 my @client_routes = &get_ccd_client_routes
($name);
704 if (scalar @client_routes) {
705 print CONF
"# Networks routed to the client\n";
707 foreach my $route (@client_routes) {
708 my $netaddress = &Network
::get_netaddress
($route);
709 my $netmask = &Network
::get_netmask
($route);
711 if (!defined $netaddress || !defined $netmask) {
715 print CONF
"iroute $netaddress $netmask\n";
722 # Networks routed to server
723 my @server_routes = &get_ccd_server_routes
($name);
725 if (scalar @server_routes) {
726 print CONF
"# Networks routed to the server\n";
728 foreach my $route (@server_routes) {
729 my $netaddress = &Network
::get_netaddress
($route);
730 my $netmask = &Network
::get_netmask
($route);
732 if (!defined $netaddress || !defined $netmask) {
736 print CONF
"push \"route $netaddress $netmask\"\n";
747 sub ccdmaxclients
($) {
751 my $prefix = &Network
::get_prefix
($network);
753 # Return undef on invalid input
754 if (!defined $prefix) {
758 # We take three addresses away: the network base address, the gateway, and broadcast
759 return (1 << (32 - $prefix)) - 3;
762 # Lists all selectable CCD addresses for the given network
763 sub getccdadresses
($) {
766 # Collect all available addresses
769 # Convert the network into binary
770 my ($start, $netmask) = &Network
::network2bin
($network);
772 # Fetch the broadcast address
773 my $broadcast = &Network
::get_broadcast
($network);
774 $broadcast = &Network
::ip2bin
($broadcast);
776 # Fail if we could not parse the network
777 if (!defined $start || !defined $netmask || !defined $broadcast) {
781 # Skip the base address and gateway
784 while ($start < $broadcast) {
785 push(@addresses, &Network
::bin2ip
($start++));
791 sub convert_top30_ccd_allocation
($) {
794 # Do nothing if the address does not end on /30
795 return $address unless ($address =~ m/\/30$/);
797 # Fetch the network base address
798 my $netaddress = &Network
::get_netaddress
($address);
800 # Break on invalid input
801 return undef if (!defined $netaddress);
803 # The client IP address was the second address of the subnet
804 return &Network
::find_next_ip_address
($netaddress, 2);
807 sub get_addresses_in_use
($) {
812 # Load all connections
813 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
817 # Check if the address is in use
818 foreach my $key (keys %conns) {
819 my $address = &convert_top30_ccd_allocation
($conns{$key}[33]);
821 # Skip on invalid inputs
822 next if (!defined $address);
824 # If the first address is part of the network, we have a match
825 if (&Network
::ip_address_in_network
($address, $network)) {
826 push(@addresses, $address);
833 sub fillselectbox
($$) {
836 my @selected = shift;
838 # Fetch all available addresses for this network
839 my @addresses = &getccdadresses
($network);
841 # Fetch all addresses in use
842 my @addresses_in_use = &get_addresses_in_use
($network);
844 print "<select name='$boxname'>";
846 foreach my $address (@addresses) {
847 print "<option value='$address'";
849 # Select any requested addresses
850 foreach (@selected) {
851 if ($address eq $_) {
857 # Disable any addresses that are not free
858 foreach (@addresses_in_use) {
859 if ($address eq $_) {
866 print ">$address</option>";
872 # XXX THIS WILL NO LONGER WORK
873 sub check_routes_push
876 my ($ip,$cidr) = split (/\//, $val);
877 ##check for existing routes in routes_push
878 if (-e
"${General::swroot}/ovpn/routes_push") {
879 open(FILE
,"${General::swroot}/ovpn/routes_push");
883 my ($ip2,$cidr2) = split (/\//,"$_");
884 my $val2=$ip2."/".&General
::iporsubtodec
($cidr2);
890 if (&General
::IpInSubnet
($ip,$ip2,&General
::iporsubtodec
($cidr2))){
903 my ($ip,$cidr) = split (/\//, $val);
904 #check for existing routes in ccdroute
905 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
906 foreach my $key (keys %ccdroutehash) {
907 foreach my $i (1 .. $#{$ccdroutehash{$key}}) {
908 if (&General
::iporsubtodec
($val) eq $ccdroutehash{$key}[$i] && $ccdroutehash{$key}[0] ne $cgiparams{'NAME'}){
911 my ($ip2,$cidr2) = split (/\//,$ccdroutehash{$key}[$i]);
913 if (&General
::IpInSubnet
($ip,$ip2,$cidr2)&& $ccdroutehash{$key}[0] ne $cgiparams{'NAME'} ){
924 my ($ip,$cidr) = split (/\//, $val);
925 #check for existing routes in ccdroute
926 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
927 foreach my $key (keys %ccdconfhash) {
928 if (&General
::iporsubtocidr
($val) eq $ccdconfhash{$key}[1]){
931 my ($ip2,$cidr2) = split (/\//,$ccdconfhash{$key}[1]);
933 if (&General
::IpInSubnet
($ip,$ip2,&General
::cidrtosub
($cidr2))){
941 # -------------------------------------------------------------------
943 sub read_routepushfile
($) {
946 # This is some legacy code that reads the routes file if it is still present
947 if (-e
"$routes_push_file") {
950 open(FILE
,"$routes_push_file");
957 $hash->{'ROUTES_PUSH'} = join("|", @routes);
962 # Unlink the legacy file
963 unlink($routes_push_file);
967 sub writecollectdconf
{
971 open(COLLECTDVPN
, ">${General::swroot}/ovpn/collectd.vpn") or die "Unable to open collectd.vpn: $!";
972 print COLLECTDVPN
"Loadplugin openvpn\n";
973 print COLLECTDVPN
"\n";
974 print COLLECTDVPN
"<Plugin openvpn>\n";
975 print COLLECTDVPN
"Statusfile \"${RW_STATUS}\"\n";
977 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%ccdhash);
978 foreach my $key (keys %ccdhash) {
979 if ($ccdhash{$key}[0] eq 'on' && $ccdhash{$key}[3] eq 'net') {
980 print COLLECTDVPN
"Statusfile \"/var/run/openvpn/$ccdhash{$key}[1]-n2n\"\n";
984 print COLLECTDVPN
"</Plugin>\n";
987 # Reload collectd afterwards
988 &General
::system("/usr/local/bin/collectdctrl", "restart");
991 sub openvpn_status
($) {
994 # Create a new Telnet session
995 my $telnet = new Net
::Telnet
(
1002 $telnet->open("127.0.0.1");
1005 my @output = $telnet->cmd(
1007 Prompt
=> "/(END.*\n|ERROR:.*\n)/"
1010 my ($time, $status) = split(/\,/, $output[1]);
1013 #CONNECTING -- OpenVPN's initial state.
1014 #WAIT -- (Client only) Waiting for initial response from server.
1015 #AUTH -- (Client only) Authenticating with server.
1016 #GET_CONFIG -- (Client only) Downloading configuration options from server.
1017 #ASSIGN_IP -- Assigning IP address to virtual network interface.
1018 #ADD_ROUTES -- Adding routes to system.
1019 #CONNECTED -- Initialization Sequence Completed.
1020 #RECONNECTING -- A restart has occurred.
1021 #EXITING -- A graceful exit is in progress.
1024 if ($status eq "CONNECTING") {
1025 return "DISCONNECTED";
1026 } elsif ($status eq "WAIT") {
1027 return "DISCONNECTED";
1028 } elsif ($status eq "AUTH") {
1029 return "DISCONNECTED";
1030 } elsif ($status eq "GET_CONFIG") {
1031 return "DISCONNECTED";
1032 } elsif ($status eq "ASSIGN_IP") {
1033 return "DISCONNECTED";
1034 } elsif ($status eq "ADD_ROUTES") {
1035 return "DISCONNECTED";
1036 } elsif ($status eq "RECONNECTING") {
1038 } elsif ($status eq "EXITING") {
1039 return "DISCONNECTED";
1045 # Hook to regenerate the configuration files
1046 if ($ENV{"REMOTE_ADDR"} eq "") {
1052 ### Save Advanced options
1055 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save-adv-options'}) {
1056 $vpnsettings{'DPROTOCOL'} = $cgiparams{'DPROTOCOL'};
1057 $vpnsettings{'DDEST_PORT'} = $cgiparams{'DDEST_PORT'};
1058 $vpnsettings{'DMTU'} = $cgiparams{'DMTU'};
1059 $vpnsettings{'MAX_CLIENTS'} = $cgiparams{'MAX_CLIENTS'};
1060 $vpnsettings{'REDIRECT_GW_DEF1'} = $cgiparams{'REDIRECT_GW_DEF1'};
1061 $vpnsettings{'DHCP_DOMAIN'} = $cgiparams{'DHCP_DOMAIN'};
1062 $vpnsettings{'DHCP_DNS'} = $cgiparams{'DHCP_DNS'};
1063 $vpnsettings{'DHCP_WINS'} = $cgiparams{'DHCP_WINS'};
1064 $vpnsettings{'ROUTES_PUSH'} = $cgiparams{'ROUTES_PUSH'};
1065 $vpnsettings{'DATACIPHERS'} = $cgiparams{'DATACIPHERS'};
1066 $vpnsettings{'DCIPHER'} = $cgiparams{'DCIPHER'};
1067 $vpnsettings{'DAUTH'} = $cgiparams{'DAUTH'};
1068 $vpnsettings{'TLSAUTH'} = $cgiparams{'TLSAUTH'};
1070 # We must have at least one cipher selected
1071 if ($cgiparams{'DATACIPHERS'} eq '') {
1072 $errormessage = $Lang::tr
{'ovpn no cipher selected'};
1076 # Split data ciphers
1077 my @dataciphers = split(/\|/, $cgiparams{'DATACIPHERS'});
1079 # Check if all ciphers are supported
1080 foreach my $cipher (@dataciphers) {
1081 if (!grep(/^$cipher$/, @SUPPORTED_CIPHERS)) {
1082 $errormessage = $Lang::tr
{'ovpn unsupported cipher selected'};
1088 unless (&General
::validport
($cgiparams{'DDEST_PORT'})) {
1089 $errormessage = $Lang::tr
{'invalid port'};
1094 if (($cgiparams{'DMTU'} eq "") || (($cgiparams{'DMTU'}) < 1280 )) {
1095 $errormessage = $Lang::tr
{'invalid mtu input'};
1099 if ($cgiparams{'FRAGMENT'} eq '') {
1100 delete $vpnsettings{'FRAGMENT'};
1102 if ($cgiparams{'FRAGMENT'} !~ /^[0-9]+$/) {
1103 $errormessage = "Incorrect value, please insert only numbers.";
1106 $vpnsettings{'FRAGMENT'} = $cgiparams{'FRAGMENT'};
1110 if ($cgiparams{'MSSFIX'} ne 'on') {
1111 $vpnsettings{'MSSFIX'} = "off";
1113 $vpnsettings{'MSSFIX'} = $cgiparams{'MSSFIX'};
1116 if ($cgiparams{'DHCP_DOMAIN'} ne ''){
1117 unless (&General
::validdomainname
($cgiparams{'DHCP_DOMAIN'}) || &General
::validip
($cgiparams{'DHCP_DOMAIN'})) {
1118 $errormessage = $Lang::tr
{'invalid input for dhcp domain'};
1122 if ($cgiparams{'DHCP_DNS'} ne ''){
1123 unless (&General
::validfqdn
($cgiparams{'DHCP_DNS'}) || &General
::validip
($cgiparams{'DHCP_DNS'})) {
1124 $errormessage = $Lang::tr
{'invalid input for dhcp dns'};
1128 if ($cgiparams{'DHCP_WINS'} ne ''){
1129 unless (&General
::validfqdn
($cgiparams{'DHCP_WINS'}) || &General
::validip
($cgiparams{'DHCP_WINS'})) {
1130 $errormessage = $Lang::tr
{'invalid input for dhcp wins'};
1135 # Validate pushed routes
1136 if ($cgiparams{'ROUTES_PUSH'} ne ''){
1137 my @temp = split(/\n/, $cgiparams{'ROUTES_PUSH'});
1141 foreach my $route (@temp) {
1144 # Remove any excess whitespace
1145 $route =~ s/^\s+//g;
1146 $route =~ s/\s+$//g;
1149 next if ($route eq "");
1151 unless (&Network
::check_subnet
($route)) {
1152 $errormessage = "$Lang::tr{'ovpn errmsg invalid route'}: $route";
1156 push(@routes, $route);
1159 $vpnsettings{'ROUTES_PUSH'} = join("|", @routes);
1162 if ((length($cgiparams{'MAX_CLIENTS'}) == 0) || (($cgiparams{'MAX_CLIENTS'}) < 1 ) || (($cgiparams{'MAX_CLIENTS'}) > 1024 )) {
1163 $errormessage = $Lang::tr
{'invalid input for max clients'};
1167 # Store our configuration
1170 # Write the server configuration
1173 # Restart the server if it is enabled
1174 if ($vpnsettings{'ENABLED'} eq "on") {
1175 &General
::system("/usr/local/bin/openvpnctrl", "rw", "restart");
1179 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq 'net' && $cgiparams{'SIDE'} eq 'server')
1182 my @remsubnet = split(/\//,$cgiparams{'REMOTE_SUBNET'});
1183 my @ovsubnettemp = split(/\./,$cgiparams{'OVPN_SUBNET'});
1184 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
1187 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
1188 unless(-d
"${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}"){mkdir "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}", 0770 or die "Unable to create dir $!";}
1190 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: $!";
1192 flock SERVERCONF
, 2;
1193 print SERVERCONF
"# IPFire n2n Open VPN Server Config by ummeegge und m.a.d\n";
1194 print SERVERCONF
"\n";
1195 print SERVERCONF
"# User Security\n";
1196 print SERVERCONF
"user nobody\n";
1197 print SERVERCONF
"group nobody\n";
1198 print SERVERCONF
"persist-tun\n";
1199 print SERVERCONF
"persist-key\n";
1200 print SERVERCONF
"script-security 2\n";
1201 print SERVERCONF
"# IP/DNS for remote Server Gateway\n";
1203 if ($cgiparams{'REMOTE'} ne '') {
1204 print SERVERCONF
"remote $cgiparams{'REMOTE'}\n";
1207 print SERVERCONF
"float\n";
1208 print SERVERCONF
"# IP adresses of the VPN Subnet\n";
1209 print SERVERCONF
"ifconfig $ovsubnet.1 $ovsubnet.2\n";
1210 print SERVERCONF
"# Client Gateway Network\n";
1211 print SERVERCONF
"route $remsubnet[0] $remsubnet[1]\n";
1212 print SERVERCONF
"up \"/etc/init.d/static-routes start\"\n";
1213 print SERVERCONF
"# tun Device\n";
1214 print SERVERCONF
"dev tun\n";
1215 print SERVERCONF
"#Logfile for statistics\n";
1216 print SERVERCONF
"status-version 1\n";
1217 print SERVERCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
1218 print SERVERCONF
"# Port and Protokol\n";
1219 print SERVERCONF
"port $cgiparams{'DEST_PORT'}\n";
1221 if ($cgiparams{'PROTOCOL'} eq 'tcp') {
1222 print SERVERCONF
"proto tcp4-server\n";
1223 print SERVERCONF
"# Packet size\n";
1224 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1400'} else {$tunmtu = $cgiparams{'MTU'}};
1225 print SERVERCONF
"tun-mtu $tunmtu\n";
1228 if ($cgiparams{'PROTOCOL'} eq 'udp') {
1229 print SERVERCONF
"proto udp4\n";
1230 print SERVERCONF
"# Paketsize\n";
1231 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1500'} else {$tunmtu = $cgiparams{'MTU'}};
1232 print SERVERCONF
"tun-mtu $tunmtu\n";
1233 if ($cgiparams{'FRAGMENT'} ne '') {print SERVERCONF
"fragment $cgiparams{'FRAGMENT'}\n";}
1234 if ($cgiparams{'MSSFIX'} eq 'on') {print SERVERCONF
"mssfix\n"; } else { print SERVERCONF
"mssfix 0\n" };
1237 print SERVERCONF
"# Auth. Server\n";
1238 print SERVERCONF
"tls-server\n";
1239 print SERVERCONF
"ca ${General::swroot}/ovpn/ca/cacert.pem\n";
1240 print SERVERCONF
"cert ${General::swroot}/ovpn/certs/servercert.pem\n";
1241 print SERVERCONF
"key ${General::swroot}/ovpn/certs/serverkey.pem\n";
1242 print SERVERCONF
"dh $DHPARAM\n";
1243 print SERVERCONF
"# Cipher\n";
1244 print SERVERCONF
"cipher $cgiparams{'DCIPHER'}\n";
1246 # If GCM cipher is used, do not use --auth
1247 if (($cgiparams{'DCIPHER'} eq 'AES-256-GCM') ||
1248 ($cgiparams{'DCIPHER'} eq 'AES-192-GCM') ||
1249 ($cgiparams{'DCIPHER'} eq 'AES-128-GCM')) {
1250 print SERVERCONF
unless "# HMAC algorithm\n";
1251 print SERVERCONF
unless "auth $cgiparams{'DAUTH'}\n";
1253 print SERVERCONF
"# HMAC algorithm\n";
1254 print SERVERCONF
"auth $cgiparams{'DAUTH'}\n";
1257 # Set TLSv1.2 as minimum
1258 print SERVERCONF
"tls-version-min 1.2\n";
1260 if ($cgiparams{'COMPLZO'} eq 'on') {
1261 print SERVERCONF
"# Enable Compression\n";
1262 print SERVERCONF
"comp-lzo\n";
1264 print SERVERCONF
"# Debug Level\n";
1265 print SERVERCONF
"verb 3\n";
1266 print SERVERCONF
"# Tunnel check\n";
1267 print SERVERCONF
"keepalive 10 60\n";
1268 print SERVERCONF
"# Start as daemon\n";
1269 print SERVERCONF
"daemon $cgiparams{'NAME'}n2n\n";
1270 print SERVERCONF
"writepid /var/run/$cgiparams{'NAME'}n2n.pid\n";
1271 print SERVERCONF
"# Activate Management Interface and Port\n";
1272 if ($cgiparams{'OVPN_MGMT'} eq '') {print SERVERCONF
"management localhost $cgiparams{'DEST_PORT'}\n"}
1273 else {print SERVERCONF
"management localhost $cgiparams{'OVPN_MGMT'}\n"};
1278 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq 'net' && $cgiparams{'SIDE'} eq 'client')
1281 my @ovsubnettemp = split(/\./,$cgiparams{'OVPN_SUBNET'});
1282 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
1283 my @remsubnet = split(/\//,$cgiparams{'REMOTE_SUBNET'});
1286 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
1287 unless(-d
"${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}"){mkdir "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}", 0770 or die "Unable to create dir $!";}
1289 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: $!";
1291 flock CLIENTCONF
, 2;
1292 print CLIENTCONF
"# IPFire rewritten n2n Open VPN Client Config by ummeegge und m.a.d\n";
1293 print CLIENTCONF
"#\n";
1294 print CLIENTCONF
"# User Security\n";
1295 print CLIENTCONF
"user nobody\n";
1296 print CLIENTCONF
"group nobody\n";
1297 print CLIENTCONF
"persist-tun\n";
1298 print CLIENTCONF
"persist-key\n";
1299 print CLIENTCONF
"script-security 2\n";
1300 print CLIENTCONF
"# IP/DNS for remote Server Gateway\n";
1301 print CLIENTCONF
"remote $cgiparams{'REMOTE'}\n";
1302 print CLIENTCONF
"float\n";
1303 print CLIENTCONF
"# IP adresses of the VPN Subnet\n";
1304 print CLIENTCONF
"ifconfig $ovsubnet.2 $ovsubnet.1\n";
1305 print CLIENTCONF
"# Server Gateway Network\n";
1306 print CLIENTCONF
"route $remsubnet[0] $remsubnet[1]\n";
1307 print CLIENTCONF
"up \"/etc/init.d/static-routes start\"\n";
1308 print CLIENTCONF
"# tun Device\n";
1309 print CLIENTCONF
"dev tun\n";
1310 print CLIENTCONF
"#Logfile for statistics\n";
1311 print CLIENTCONF
"status-version 1\n";
1312 print CLIENTCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
1313 print CLIENTCONF
"# Port and Protokol\n";
1314 print CLIENTCONF
"port $cgiparams{'DEST_PORT'}\n";
1316 if ($cgiparams{'PROTOCOL'} eq 'tcp') {
1317 print CLIENTCONF
"proto tcp4-client\n";
1318 print CLIENTCONF
"# Packet size\n";
1319 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1400'} else {$tunmtu = $cgiparams{'MTU'}};
1320 print CLIENTCONF
"tun-mtu $tunmtu\n";
1323 if ($cgiparams{'PROTOCOL'} eq 'udp') {
1324 print CLIENTCONF
"proto udp4\n";
1325 print CLIENTCONF
"# Paketsize\n";
1326 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1500'} else {$tunmtu = $cgiparams{'MTU'}};
1327 print CLIENTCONF
"tun-mtu $tunmtu\n";
1328 if ($cgiparams{'FRAGMENT'} ne '') {print CLIENTCONF
"fragment $cgiparams{'FRAGMENT'}\n";}
1329 if ($cgiparams{'MSSFIX'} eq 'on') {print CLIENTCONF
"mssfix\n"; } else { print CLIENTCONF
"mssfix 0\n" };
1332 # Check host certificate if X509 is RFC3280 compliant.
1333 # If not, old --ns-cert-type directive will be used.
1334 # If appropriate key usage extension exists, new --remote-cert-tls directive will be used.
1335 my @hostcert = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1336 if ( ! grep(/TLS Web Server Authentication/, @hostcert)) {
1337 print CLIENTCONF
"ns-cert-type server\n";
1339 print CLIENTCONF
"remote-cert-tls server\n";
1341 print CLIENTCONF
"# Auth. Client\n";
1342 print CLIENTCONF
"tls-client\n";
1343 print CLIENTCONF
"# Cipher\n";
1344 print CLIENTCONF
"cipher $cgiparams{'DCIPHER'}\n";
1345 print CLIENTCONF
"pkcs12 ${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12\r\n";
1347 # If GCM cipher is used, do not use --auth
1348 if (($cgiparams{'DCIPHER'} eq 'AES-256-GCM') ||
1349 ($cgiparams{'DCIPHER'} eq 'AES-192-GCM') ||
1350 ($cgiparams{'DCIPHER'} eq 'AES-128-GCM')) {
1351 print CLIENTCONF
unless "# HMAC algorithm\n";
1352 print CLIENTCONF
unless "auth $cgiparams{'DAUTH'}\n";
1354 print CLIENTCONF
"# HMAC algorithm\n";
1355 print CLIENTCONF
"auth $cgiparams{'DAUTH'}\n";
1358 # Set TLSv1.2 as minimum
1359 print CLIENTCONF
"tls-version-min 1.2\n";
1361 if ($cgiparams{'COMPLZO'} eq 'on') {
1362 print CLIENTCONF
"# Enable Compression\n";
1363 print CLIENTCONF
"comp-lzo\n";
1365 print CLIENTCONF
"# Debug Level\n";
1366 print CLIENTCONF
"verb 3\n";
1367 print CLIENTCONF
"# Tunnel check\n";
1368 print CLIENTCONF
"keepalive 10 60\n";
1369 print CLIENTCONF
"# Start as daemon\n";
1370 print CLIENTCONF
"daemon $cgiparams{'NAME'}n2n\n";
1371 print CLIENTCONF
"writepid /var/run/$cgiparams{'NAME'}n2n.pid\n";
1372 print CLIENTCONF
"# Activate Management Interface and Port\n";
1373 if ($cgiparams{'OVPN_MGMT'} eq '') {print CLIENTCONF
"management localhost $cgiparams{'DEST_PORT'}\n"}
1374 else {print CLIENTCONF
"management localhost $cgiparams{'OVPN_MGMT'}\n"};
1375 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}")) {
1376 print CLIENTCONF
"providers legacy default\n";
1383 ### Save main settings
1386 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq '' && $cgiparams{'KEY'} eq '') {
1387 #DAN do we really need (to to check) this value? Besides if we listen on blue and orange too,
1388 #DAN this value has to leave.
1389 if ($cgiparams{'ENABLED'} eq 'on'){
1390 unless (&General
::validfqdn
($cgiparams{'VPN_IP'}) || &General
::validip
($cgiparams{'VPN_IP'})) {
1391 $errormessage = $Lang::tr
{'invalid input for hostname'};
1392 goto SETTINGS_ERROR
;
1396 if (! &General
::validipandmask
($cgiparams{'DOVPN_SUBNET'})) {
1397 $errormessage = $Lang::tr
{'ovpn subnet is invalid'};
1398 goto SETTINGS_ERROR
;
1400 my @tmpovpnsubnet = split("\/",$cgiparams{'DOVPN_SUBNET'});
1402 if (&General
::IpInSubnet
( $Network::ethernet
{'RED_ADDRESS'},
1403 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1404 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire RED Network $Network::ethernet{'RED_ADDRESS'}";
1405 goto SETTINGS_ERROR
;
1408 if (&General
::IpInSubnet
( $Network::ethernet
{'GREEN_ADDRESS'},
1409 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1410 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Green Network $Network::ethernet{'GREEN_ADDRESS'}";
1411 goto SETTINGS_ERROR
;
1414 if (&General
::IpInSubnet
( $Network::ethernet
{'BLUE_ADDRESS'},
1415 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1416 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Blue Network $Network::ethernet{'BLUE_ADDRESS'}";
1417 goto SETTINGS_ERROR
;
1420 if (&General
::IpInSubnet
( $Network::ethernet
{'ORANGE_ADDRESS'},
1421 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1422 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Orange Network $Network::ethernet{'ORANGE_ADDRESS'}";
1423 goto SETTINGS_ERROR
;
1425 open(ALIASES
, "${General::swroot}/ethernet/aliases") or die 'Unable to open aliases file.';
1429 my @tempalias = split(/\,/,$_);
1430 if ($tempalias[1] eq 'on') {
1431 if (&General
::IpInSubnet
($tempalias[0] ,
1432 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1433 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire alias entry $tempalias[0]";
1438 if ($errormessage ne ''){
1439 goto SETTINGS_ERROR
;
1441 if ($cgiparams{'ENABLED'} !~ /^(on|off|)$/) {
1442 $errormessage = $Lang::tr
{'invalid input'};
1443 goto SETTINGS_ERROR
;
1446 # Create ta.key for tls-auth if not presant
1447 if ($cgiparams{'TLSAUTH'} eq 'on') {
1448 if ( ! -e
"${General::swroot}/ovpn/certs/ta.key") {
1449 # This system call is safe, because all arguements are passed as an array.
1450 system("/usr/sbin/openvpn", "--genkey", "secret", "${General::swroot}/ovpn/certs/ta.key");
1452 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1453 goto SETTINGS_ERROR
;
1458 $vpnsettings{'ENABLED'} = $cgiparams{'ENABLED'};
1459 $vpnsettings{'VPN_IP'} = $cgiparams{'VPN_IP'};
1460 $vpnsettings{'DOVPN_SUBNET'} = $cgiparams{'DOVPN_SUBNET'};
1462 # Store our configuration
1465 # Write the OpenVPN server configuration
1468 # Start/Stop the server
1469 if ($vpnsettings{'ENABLED'} eq "on") {
1470 &General
::system("/usr/local/bin/openvpnctrl", "rw", "restart");
1472 &General
::system("/usr/local/bin/openvpnctrl", "rw", "stop");
1477 ### Reset all step 2
1479 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove x509'} && $cgiparams{'AREUSURE'} eq 'yes') {
1481 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1483 # Stop all N2N connections
1484 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop");
1486 foreach my $key (keys %confighash) {
1487 my $name = $confighash{$cgiparams{'$key'}}[1];
1489 if ($confighash{$key}[4] eq 'cert') {
1490 delete $confighash{$cgiparams{'$key'}};
1493 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "delete", "$name");
1495 while ($file = glob("${General::swroot}/ovpn/ca/*")) {
1498 while ($file = glob("${General::swroot}/ovpn/certs/*")) {
1501 while ($file = glob("${General::swroot}/ovpn/crls/*")) {
1504 &cleanssldatabase
();
1505 if (open(FILE
, ">${General::swroot}/ovpn/caconfig")) {
1509 if (open(FILE
, ">${General::swroot}/ovpn/ccdroute")) {
1513 if (open(FILE
, ">${General::swroot}/ovpn/ccdroute2")) {
1517 while ($file = glob("${General::swroot}/ovpn/ccd/*")) {
1520 while ($file = glob("${General::swroot}/ovpn/ccd/*")) {
1523 if (open(FILE
, ">${General::swroot}/ovpn/ovpn-leases.db")) {
1527 if (open(FILE
, ">${General::swroot}/ovpn/ovpnconfig")) {
1531 while ($file = glob("${General::swroot}/ovpn/n2nconf/*")) {
1535 # Remove everything from the collectd configuration
1536 &writecollectdconf
();
1538 #&writeserverconf();
1540 ### Reset all step 1
1542 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove x509'}) {
1543 &Header
::showhttpheaders
();
1544 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1545 &Header
::openbigbox
('100%', 'left', '', '');
1546 &Header
::openbox
('100%', 'left', $Lang::tr
{'are you sure'});
1548 <form method='post'>
1549 <table width='100%'>
1552 <input type='hidden' name='AREUSURE' value='yes' />
1553 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>:
1554 $Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'}</td>
1557 <td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' />
1558 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td>
1564 &Header
::closebox
();
1565 &Header
::closebigbox
();
1566 &Header
::closepage
();
1570 ### Upload CA Certificate
1572 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'upload ca certificate'}) {
1573 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1575 if ($cgiparams{'CA_NAME'} !~ /^[a-zA-Z0-9]+$/) {
1576 $errormessage = $Lang::tr
{'name must only contain characters'};
1577 goto UPLOADCA_ERROR
;
1580 if (length($cgiparams{'CA_NAME'}) >60) {
1581 $errormessage = $Lang::tr
{'name too long'};
1585 if ($cgiparams{'CA_NAME'} eq 'ca') {
1586 $errormessage = $Lang::tr
{'name is invalid'};
1587 goto UPLOADCA_ERROR
;
1590 # Check if there is no other entry with this name
1591 foreach my $key (keys %cahash) {
1592 if ($cahash{$key}[0] eq $cgiparams{'CA_NAME'}) {
1593 $errormessage = $Lang::tr
{'a ca certificate with this name already exists'};
1594 goto UPLOADCA_ERROR
;
1598 unless (ref ($cgiparams{'FH'})) {
1599 $errormessage = $Lang::tr
{'there was no file upload'};
1600 goto UPLOADCA_ERROR
;
1602 # Move uploaded ca to a temporary file
1603 (my $fh, my $filename) = tempfile
( );
1604 if (copy
($cgiparams{'FH'}, $fh) != 1) {
1606 goto UPLOADCA_ERROR
;
1608 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "$filename");
1609 if ( ! grep(/CA:TRUE/i, @temp )) {
1610 $errormessage = $Lang::tr
{'not a valid ca certificate'};
1612 goto UPLOADCA_ERROR
;
1614 unless(move
($filename, "${General::swroot}/ovpn/ca/$cgiparams{'CA_NAME'}cert.pem")) {
1615 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1617 goto UPLOADCA_ERROR
;
1621 my @casubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/$cgiparams{'CA_NAME'}cert.pem");
1624 foreach my $line (@casubject) {
1625 if ($line =~ /Subject: (.*)[\n]/) {
1627 $casubject =~ s
+/Email
+, E
+;
1628 $casubject =~ s/ ST=/ S=/;
1634 $casubject = &Header
::cleanhtml
($casubject);
1636 my $key = &General
::findhasharraykey
(\
%cahash);
1637 $cahash{$key}[0] = $cgiparams{'CA_NAME'};
1638 $cahash{$key}[1] = $casubject;
1639 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1644 ### Display ca certificate
1646 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show ca certificate'}) {
1647 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1649 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem") {
1650 &Header
::showhttpheaders
();
1651 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1652 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
1653 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ca certificate'}:");
1654 my @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1655 my $output = &Header
::cleanhtml
(join("", @output),"y");
1656 print "<pre>$output</pre>\n";
1657 &Header
::closebox
();
1658 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1659 &Header
::closebigbox
();
1660 &Header
::closepage
();
1663 $errormessage = $Lang::tr
{'invalid key'};
1667 ### Download ca certificate
1669 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download ca certificate'}) {
1670 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1672 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1673 print "Content-Type: application/octet-stream\r\n";
1674 print "Content-Disposition: filename=$cahash{$cgiparams{'KEY'}}[0]cert.pem\r\n\r\n";
1676 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1681 $errormessage = $Lang::tr
{'invalid key'};
1685 ### Remove ca certificate (step 2)
1687 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove ca certificate'} && $cgiparams{'AREUSURE'} eq 'yes') {
1688 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1689 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1691 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1692 foreach my $key (keys %confighash) {
1693 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");
1694 if (grep(/: OK/, @test)) {
1695 unlink ("${General::swroot}/ovpn//certs/$confighash{$key}[1]cert.pem");
1696 unlink ("${General::swroot}/ovpn/certs/$confighash{$key}[1].p12");
1697 delete $confighash{$key};
1698 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1701 unlink ("${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1702 delete $cahash{$cgiparams{'KEY'}};
1703 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1705 $errormessage = $Lang::tr
{'invalid key'};
1708 ### Remove ca certificate (step 1)
1710 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove ca certificate'}) {
1711 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1712 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1714 my $assignedcerts = 0;
1715 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1716 foreach my $key (keys %confighash) {
1717 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");
1718 if (grep(/: OK/, @test)) {
1722 if ($assignedcerts) {
1723 &Header
::showhttpheaders
();
1724 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1725 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
1726 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'are you sure'});
1728 <table><form method='post'><input type='hidden' name='AREUSURE' value='yes' />
1729 <input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />
1730 <tr><td align='center'>
1731 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>: $assignedcerts
1732 $Lang::tr{'connections are associated with this ca. deleting the ca will delete these connections as well.'}
1733 <tr><td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
1734 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td></tr>
1738 &Header
::closebox
();
1739 &Header
::closebigbox
();
1740 &Header
::closepage
();
1743 unlink ("${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1744 delete $cahash{$cgiparams{'KEY'}};
1745 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1748 $errormessage = $Lang::tr
{'invalid key'};
1752 ### Display root certificate
1754 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show root certificate'} ||
1755 $cgiparams{'ACTION'} eq $Lang::tr
{'show host certificate'}) {
1757 &Header
::showhttpheaders
();
1758 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1759 &Header
::openbigbox
('100%', 'LEFT', '', '');
1760 if ($cgiparams{'ACTION'} eq $Lang::tr
{'show root certificate'}) {
1761 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'root certificate'}:");
1762 @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
1764 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'host certificate'}:");
1765 @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1767 my $output = &Header
::cleanhtml
(join("", @output), "y");
1768 print "<pre>$output</pre>\n";
1769 &Header
::closebox
();
1770 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1771 &Header
::closebigbox
();
1772 &Header
::closepage
();
1776 ### Download root certificate
1778 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download root certificate'}) {
1779 if ( -f
"${General::swroot}/ovpn/ca/cacert.pem" ) {
1780 print "Content-Type: application/octet-stream\r\n";
1781 print "Content-Disposition: filename=cacert.pem\r\n\r\n";
1783 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
1790 ### Download host certificate
1792 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download host certificate'}) {
1793 if ( -f
"${General::swroot}/ovpn/certs/servercert.pem" ) {
1794 print "Content-Type: application/octet-stream\r\n";
1795 print "Content-Disposition: filename=servercert.pem\r\n\r\n";
1797 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1804 ### Download tls-auth key
1806 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download tls-auth key'}) {
1807 if ( -f
"${General::swroot}/ovpn/certs/ta.key" ) {
1808 print "Content-Type: application/octet-stream\r\n";
1809 print "Content-Disposition: filename=ta.key\r\n\r\n";
1811 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
1821 ### Form for generating a root certificate
1823 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'generate root/host certificates'} ||
1824 $cgiparams{'ACTION'} eq $Lang::tr
{'upload p12 file'}) {
1826 if (-f
"${General::swroot}/ovpn/ca/cacert.pem") {
1827 $errormessage = $Lang::tr
{'valid root certificate already exists'};
1828 $cgiparams{'ACTION'} = '';
1829 goto ROOTCERT_ERROR
;
1832 if (($cgiparams{'ROOTCERT_HOSTNAME'} eq '') && -e
"${General::swroot}/red/active") {
1833 if (open(IPADDR
, "${General::swroot}/red/local-ipaddress")) {
1834 my $ipaddr = <IPADDR
>;
1837 $cgiparams{'ROOTCERT_HOSTNAME'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0];
1838 if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') {
1839 $cgiparams{'ROOTCERT_HOSTNAME'} = $ipaddr;
1842 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'upload p12 file'}) {
1843 unless (ref ($cgiparams{'FH'})) {
1844 $errormessage = $Lang::tr
{'there was no file upload'};
1845 goto ROOTCERT_ERROR
;
1848 # Move uploaded certificate request to a temporary file
1849 (my $fh, my $filename) = tempfile
( );
1850 if (copy
($cgiparams{'FH'}, $fh) != 1) {
1852 goto ROOTCERT_ERROR
;
1855 # Create a temporary dirctory
1856 my $tempdir = tempdir
( CLEANUP
=> 1 );
1858 # Extract the CA certificate from the file
1859 my $pid = open(OPENSSL
, "|-");
1860 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
1861 if ($pid) { # parent
1862 if ($cgiparams{'P12_PASS'} ne '') {
1863 print OPENSSL
"$cgiparams{'P12_PASS'}\n";
1867 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1869 goto ROOTCERT_ERROR
;
1872 unless (exec ('/usr/bin/openssl', 'pkcs12', '-cacerts', '-nokeys',
1874 '-out', "$tempdir/cacert.pem")) {
1875 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1877 goto ROOTCERT_ERROR
;
1881 # Extract the Host certificate from the file
1882 $pid = open(OPENSSL
, "|-");
1883 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
1884 if ($pid) { # parent
1885 if ($cgiparams{'P12_PASS'} ne '') {
1886 print OPENSSL
"$cgiparams{'P12_PASS'}\n";
1890 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1892 goto ROOTCERT_ERROR
;
1895 unless (exec ('/usr/bin/openssl', 'pkcs12', '-clcerts', '-nokeys',
1897 '-out', "$tempdir/hostcert.pem")) {
1898 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1900 goto ROOTCERT_ERROR
;
1904 # Extract the Host key from the file
1905 $pid = open(OPENSSL
, "|-");
1906 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
1907 if ($pid) { # parent
1908 if ($cgiparams{'P12_PASS'} ne '') {
1909 print OPENSSL
"$cgiparams{'P12_PASS'}\n";
1913 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1915 goto ROOTCERT_ERROR
;
1918 unless (exec ('/usr/bin/openssl', 'pkcs12', '-nocerts',
1921 '-out', "$tempdir/serverkey.pem")) {
1922 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1924 goto ROOTCERT_ERROR
;
1928 unless(move
("$tempdir/cacert.pem", "${General::swroot}/ovpn/ca/cacert.pem")) {
1929 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1931 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1932 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1933 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1934 goto ROOTCERT_ERROR
;
1937 unless(move
("$tempdir/hostcert.pem", "${General::swroot}/ovpn/certs/servercert.pem")) {
1938 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1940 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1941 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1942 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1943 goto ROOTCERT_ERROR
;
1946 unless(move
("$tempdir/serverkey.pem", "${General::swroot}/ovpn/certs/serverkey.pem")) {
1947 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1949 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1950 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1951 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1952 goto ROOTCERT_ERROR
;
1955 goto ROOTCERT_SUCCESS
;
1957 } elsif ($cgiparams{'ROOTCERT_COUNTRY'} ne '') {
1959 # Validate input since the form was submitted
1960 if ($cgiparams{'ROOTCERT_ORGANIZATION'} eq ''){
1961 $errormessage = $Lang::tr
{'organization cant be empty'};
1962 goto ROOTCERT_ERROR
;
1964 if (length($cgiparams{'ROOTCERT_ORGANIZATION'}) >60) {
1965 $errormessage = $Lang::tr
{'organization too long'};
1966 goto ROOTCERT_ERROR
;
1968 if ($cgiparams{'ROOTCERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1969 $errormessage = $Lang::tr
{'invalid input for organization'};
1970 goto ROOTCERT_ERROR
;
1972 if ($cgiparams{'ROOTCERT_HOSTNAME'} eq ''){
1973 $errormessage = $Lang::tr
{'hostname cant be empty'};
1974 goto ROOTCERT_ERROR
;
1976 unless (&General
::validfqdn
($cgiparams{'ROOTCERT_HOSTNAME'}) || &General
::validip
($cgiparams{'ROOTCERT_HOSTNAME'})) {
1977 $errormessage = $Lang::tr
{'invalid input for hostname'};
1978 goto ROOTCERT_ERROR
;
1980 if ($cgiparams{'ROOTCERT_EMAIL'} ne '' && (! &General
::validemail
($cgiparams{'ROOTCERT_EMAIL'}))) {
1981 $errormessage = $Lang::tr
{'invalid input for e-mail address'};
1982 goto ROOTCERT_ERROR
;
1984 if (length($cgiparams{'ROOTCERT_EMAIL'}) > 40) {
1985 $errormessage = $Lang::tr
{'e-mail address too long'};
1986 goto ROOTCERT_ERROR
;
1988 if ($cgiparams{'ROOTCERT_OU'} ne '' && $cgiparams{'ROOTCERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1989 $errormessage = $Lang::tr
{'invalid input for department'};
1990 goto ROOTCERT_ERROR
;
1992 if ($cgiparams{'ROOTCERT_CITY'} ne '' && $cgiparams{'ROOTCERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1993 $errormessage = $Lang::tr
{'invalid input for city'};
1994 goto ROOTCERT_ERROR
;
1996 if ($cgiparams{'ROOTCERT_STATE'} ne '' && $cgiparams{'ROOTCERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1997 $errormessage = $Lang::tr
{'invalid input for state or province'};
1998 goto ROOTCERT_ERROR
;
2000 if ($cgiparams{'ROOTCERT_COUNTRY'} !~ /^[A-Z]*$/) {
2001 $errormessage = $Lang::tr
{'invalid input for country'};
2002 goto ROOTCERT_ERROR
;
2005 # Copy the cgisettings to vpnsettings and save the configfile
2006 $vpnsettings{'ROOTCERT_ORGANIZATION'} = $cgiparams{'ROOTCERT_ORGANIZATION'};
2007 $vpnsettings{'ROOTCERT_HOSTNAME'} = $cgiparams{'ROOTCERT_HOSTNAME'};
2008 $vpnsettings{'ROOTCERT_EMAIL'} = $cgiparams{'ROOTCERT_EMAIL'};
2009 $vpnsettings{'ROOTCERT_OU'} = $cgiparams{'ROOTCERT_OU'};
2010 $vpnsettings{'ROOTCERT_CITY'} = $cgiparams{'ROOTCERT_CITY'};
2011 $vpnsettings{'ROOTCERT_STATE'} = $cgiparams{'ROOTCERT_STATE'};
2012 $vpnsettings{'ROOTCERT_COUNTRY'} = $cgiparams{'ROOTCERT_COUNTRY'};
2015 # Replace empty strings with a .
2016 (my $ou = $cgiparams{'ROOTCERT_OU'}) =~ s/^\s*$/\./;
2017 (my $city = $cgiparams{'ROOTCERT_CITY'}) =~ s/^\s*$/\./;
2018 (my $state = $cgiparams{'ROOTCERT_STATE'}) =~ s/^\s*$/\./;
2020 # Create the CA certificate
2021 my $pid = open(OPENSSL
, "|-");
2022 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
2023 if ($pid) { # parent
2024 print OPENSSL
"$cgiparams{'ROOTCERT_COUNTRY'}\n";
2025 print OPENSSL
"$state\n";
2026 print OPENSSL
"$city\n";
2027 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
2028 print OPENSSL
"$ou\n";
2029 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'} CA\n";
2030 print OPENSSL
"$cgiparams{'ROOTCERT_EMAIL'}\n";
2033 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2034 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2035 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2036 goto ROOTCERT_ERROR
;
2039 unless (exec ('/usr/bin/openssl', 'req', '-x509', '-nodes',
2040 '-days', '999999', '-newkey', 'rsa:4096', '-sha512',
2041 '-keyout', "${General::swroot}/ovpn/ca/cakey.pem",
2042 '-out', "${General::swroot}/ovpn/ca/cacert.pem",
2043 '-config', "/usr/share/openvpn/ovpn.cnf")) {
2044 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
2045 goto ROOTCERT_ERROR
;
2049 # Create the Host certificate request
2050 $pid = open(OPENSSL
, "|-");
2051 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
2052 if ($pid) { # parent
2053 print OPENSSL
"$cgiparams{'ROOTCERT_COUNTRY'}\n";
2054 print OPENSSL
"$state\n";
2055 print OPENSSL
"$city\n";
2056 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
2057 print OPENSSL
"$ou\n";
2058 print OPENSSL
"$cgiparams{'ROOTCERT_HOSTNAME'}\n";
2059 print OPENSSL
"$cgiparams{'ROOTCERT_EMAIL'}\n";
2060 print OPENSSL
".\n";
2061 print OPENSSL
".\n";
2064 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2065 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2066 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2067 goto ROOTCERT_ERROR
;
2070 unless (exec ('/usr/bin/openssl', 'req', '-nodes',
2071 '-newkey', 'rsa:4096',
2072 '-keyout', "${General::swroot}/ovpn/certs/serverkey.pem",
2073 '-out', "${General::swroot}/ovpn/certs/serverreq.pem",
2074 '-extensions', 'server',
2075 '-config', "/usr/share/openvpn/ovpn.cnf" )) {
2076 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
2077 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2078 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2079 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2080 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2081 goto ROOTCERT_ERROR
;
2085 # Sign the host certificate request
2086 # This system call is safe, because all argeuments are passed as an array.
2087 system('/usr/bin/openssl', 'ca', '-days', '999999',
2088 '-batch', '-notext',
2089 '-in', "${General::swroot}/ovpn/certs/serverreq.pem",
2090 '-out', "${General::swroot}/ovpn/certs/servercert.pem",
2091 '-extensions', 'server',
2092 '-config', "/usr/share/openvpn/ovpn.cnf");
2094 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2095 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2096 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2097 unlink ("${General::swroot}/ovpn/serverkey.pem");
2098 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2099 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
2100 &cleanssldatabase
();
2101 goto ROOTCERT_ERROR
;
2103 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2104 &deletebackupcert
();
2107 # Create an empty CRL
2108 # System call is safe, because all arguments are passed as array.
2109 system('/usr/bin/openssl', 'ca', '-gencrl',
2110 '-out', "${General::swroot}/ovpn/crls/cacrl.pem",
2111 '-config', "/usr/share/openvpn/ovpn.cnf" );
2113 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2114 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2115 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
2116 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2117 unlink ("${General::swroot}/ovpn/crls/cacrl.pem");
2118 &cleanssldatabase
();
2119 goto ROOTCERT_ERROR
;
2121 # &cleanssldatabase();
2123 # Create ta.key for tls-auth
2124 # This system call is safe, because all arguments are passed as an array.
2125 system('/usr/sbin/openvpn', '--genkey', 'secret', "${General::swroot}/ovpn/certs/ta.key");
2127 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2128 &cleanssldatabase
();
2129 goto ROOTCERT_ERROR
;
2131 goto ROOTCERT_SUCCESS
;
2134 if ($cgiparams{'ACTION'} ne '') {
2135 &Header
::showhttpheaders
();
2136 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2137 &Header
::openbigbox
('100%', 'LEFT', '', '');
2140 &Header
::errorbox
($errormessage);
2142 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'generate root/host certificates'}:");
2144 <form method='post' enctype='multipart/form-data'>
2145 <table width='100%' border='0' cellspacing='1' cellpadding='0'>
2146 <tr><td width='30%' class='base'>$Lang::tr{'organization name'}: <img src='/blob.gif' alt='*' /></td>
2147 <td width='35%' class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_ORGANIZATION' value='$cgiparams{'ROOTCERT_ORGANIZATION'}' size='32' /></td>
2148 <td width='35%' colspan='2'> </td></tr>
2149 <tr><td class='base'>$Lang::tr{'ipfires hostname'}: <img src='/blob.gif' alt='*' /></td>
2150 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_HOSTNAME' value='$cgiparams{'ROOTCERT_HOSTNAME'}' size='32' /></td>
2151 <td colspan='2'> </td></tr>
2152 <tr><td class='base'>$Lang::tr{'your e-mail'}:</td>
2153 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_EMAIL' value='$cgiparams{'ROOTCERT_EMAIL'}' size='32' /></td>
2154 <td colspan='2'> </td></tr>
2155 <tr><td class='base'>$Lang::tr{'your department'}:</td>
2156 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_OU' value='$cgiparams{'ROOTCERT_OU'}' size='32' /></td>
2157 <td colspan='2'> </td></tr>
2158 <tr><td class='base'>$Lang::tr{'city'}:</td>
2159 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_CITY' value='$cgiparams{'ROOTCERT_CITY'}' size='32' /></td>
2160 <td colspan='2'> </td></tr>
2161 <tr><td class='base'>$Lang::tr{'state or province'}:</td>
2162 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_STATE' value='$cgiparams{'ROOTCERT_STATE'}' size='32' /></td>
2163 <td colspan='2'> </td></tr>
2164 <tr><td class='base'>$Lang::tr{'country'}:</td>
2165 <td class='base'><select name='ROOTCERT_COUNTRY'>
2169 foreach my $country (sort keys %{Countries
::countries
}) {
2170 print "<option value='$Countries::countries{$country}'";
2171 if ( $Countries::countries
{$country} eq $cgiparams{'ROOTCERT_COUNTRY'} ) {
2172 print " selected='selected'";
2174 print ">$country</option>";
2180 <td><input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' /></td>
2181 <td> </td><td> </td></tr>
2182 <tr><td class='base' colspan='4' align='left'>
2183 <img src='/blob.gif' valign='top' alt='*' /> $Lang::tr{'required field'}</td></tr>
2184 <tr><td colspan='2'><br></td></tr>
2187 <table width='100%'>
2188 <tr><td colspan='4'><hr></td></tr>
2189 <tr><td class='base' nowrap='nowrap'>$Lang::tr{'upload p12 file'}: <img src='/blob.gif' alt='*' /></td>
2190 <td nowrap='nowrap'><input type='file' name='FH' size='32'></td>
2191 <td colspan='2'> </td></tr>
2192 <tr><td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
2193 <td class='base' nowrap='nowrap'><input type='password' name='P12_PASS' value='$cgiparams{'P12_PASS'}' size='32' /></td>
2194 <td colspan='2'> </td></tr>
2196 <td><input type='submit' name='ACTION' value='$Lang::tr{'upload p12 file'}' /></td>
2197 <td colspan='2'> </td></tr>
2198 <tr><td class='base' colspan='4' align='left'>
2199 <img src='/blob.gif' valign='top' alt='*' > $Lang::tr{'required field'}</td>
2204 &Header
::closebox
();
2205 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2206 &Header
::closebigbox
();
2207 &Header
::closepage
();
2212 &General
::system("chmod", "600", "${General::swroot}/ovpn/certs/serverkey.pem");
2215 ### Enable/Disable connection
2218 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'toggle enable disable'}) {
2219 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2221 my @ps = &General
::system_output
("/bin/ps", "ax");
2223 if(grep(/$confighash{$cgiparams{'KEY'}}[1]/, @ps)) {
2227 if ($confighash{$cgiparams{'KEY'}}) {
2228 if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
2229 $confighash{$cgiparams{'KEY'}}[0] = 'on';
2230 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2232 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2233 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "start", "$confighash{$cgiparams{'KEY'}}[1]");
2234 &writecollectdconf
();
2238 $confighash{$cgiparams{'KEY'}}[0] = 'off';
2239 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2241 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2242 if ($n2nactive ne '') {
2243 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
2244 &writecollectdconf
();
2251 ### Download OpenVPN client package
2254 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'dl client arch'}) {
2255 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2257 my $clientovpn = '';
2259 my $tempdir = tempdir
( CLEANUP
=> 1 );
2260 my $zippath = "$tempdir/";
2263 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2264 my $zipname = "$confighash{$cgiparams{'KEY'}}[1]-Client.zip";
2265 my $zippathname = "$zippath$zipname";
2266 $clientovpn = "$confighash{$cgiparams{'KEY'}}[1].conf";
2267 my @ovsubnettemp = split(/\./,$confighash{$cgiparams{'KEY'}}[27]);
2268 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
2270 my @remsubnet = split(/\//,$confighash{$cgiparams{'KEY'}}[8]);
2271 my $n2nfragment = '';
2273 open(CLIENTCONF
, ">$tempdir/$clientovpn") or die "Unable to open tempfile: $!";
2274 flock CLIENTCONF
, 2;
2276 my $zip = Archive
::Zip-
>new();
2277 print CLIENTCONF
"# IPFire n2n Open VPN Client Config by ummeegge und m.a.d\n";
2278 print CLIENTCONF
"# \n";
2279 print CLIENTCONF
"# User Security\n";
2280 print CLIENTCONF
"user nobody\n";
2281 print CLIENTCONF
"group nobody\n";
2282 print CLIENTCONF
"persist-tun\n";
2283 print CLIENTCONF
"persist-key\n";
2284 print CLIENTCONF
"script-security 2\n";
2285 print CLIENTCONF
"# IP/DNS for remote Server Gateway\n";
2286 print CLIENTCONF
"remote $vpnsettings{'VPN_IP'}\n";
2287 print CLIENTCONF
"float\n";
2288 print CLIENTCONF
"# IP adresses of the VPN Subnet\n";
2289 print CLIENTCONF
"ifconfig $ovsubnet.2 $ovsubnet.1\n";
2290 print CLIENTCONF
"# Server Gateway Network\n";
2291 print CLIENTCONF
"route $remsubnet[0] $remsubnet[1]\n";
2292 print CLIENTCONF
"# tun Device\n";
2293 print CLIENTCONF
"dev tun\n";
2294 print CLIENTCONF
"#Logfile for statistics\n";
2295 print CLIENTCONF
"status-version 1\n";
2296 print CLIENTCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
2297 print CLIENTCONF
"# Port and Protokoll\n";
2298 print CLIENTCONF
"port $confighash{$cgiparams{'KEY'}}[29]\n";
2300 if ($confighash{$cgiparams{'KEY'}}[28] eq 'tcp') {
2301 print CLIENTCONF
"proto tcp4-client\n";
2302 print CLIENTCONF
"# Packet size\n";
2303 if ($confighash{$cgiparams{'KEY'}}[31] eq '') {
2306 $tunmtu = $confighash{$cgiparams{'KEY'}}[31];
2308 print CLIENTCONF
"tun-mtu $tunmtu\n";
2311 if ($confighash{$cgiparams{'KEY'}}[28] eq 'udp') {
2312 print CLIENTCONF
"proto udp4\n";
2313 print CLIENTCONF
"# Paketsize\n";
2314 if ($confighash{$cgiparams{'KEY'}}[31] eq '') {
2317 $tunmtu = $confighash{$cgiparams{'KEY'}}[31];
2319 print CLIENTCONF
"tun-mtu $tunmtu\n";
2320 if ($confighash{$cgiparams{'KEY'}}[24] ne '') {
2321 print CLIENTCONF
"fragment $confighash{$cgiparams{'KEY'}}[24]\n";
2323 if ($confighash{$cgiparams{'KEY'}}[23] eq 'on') {
2324 print CLIENTCONF
"mssfix\n";
2326 print CLIENTCONF
"mssfix 0\n";
2330 # Check host certificate if X509 is RFC3280 compliant.
2331 # If not, old --ns-cert-type directive will be used.
2332 # If appropriate key usage extension exists, new --remote-cert-tls directive will be used.
2333 my @hostcert = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
2334 if (! grep(/TLS Web Server Authentication/, @hostcert)) {
2335 print CLIENTCONF
"ns-cert-type server\n";
2337 print CLIENTCONF
"remote-cert-tls server\n";
2339 print CLIENTCONF
"# Auth. Client\n";
2340 print CLIENTCONF
"tls-client\n";
2341 print CLIENTCONF
"# Cipher\n";
2342 print CLIENTCONF
"cipher $confighash{$cgiparams{'KEY'}}[40]\n";
2344 if ($confighash{$cgiparams{'KEY'}}[4] eq 'cert' && -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12") {
2345 print CLIENTCONF
"pkcs12 ${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12\r\n";
2346 $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";
2349 # If GCM cipher is used, do not use --auth
2350 if (($confighash{$cgiparams{'KEY'}}[40] eq 'AES-256-GCM') ||
2351 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-192-GCM') ||
2352 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-128-GCM')) {
2353 print CLIENTCONF
unless "# HMAC algorithm\n";
2354 print CLIENTCONF
unless "auth $confighash{$cgiparams{'KEY'}}[39]\n";
2356 print CLIENTCONF
"# HMAC algorithm\n";
2357 print CLIENTCONF
"auth $confighash{$cgiparams{'KEY'}}[39]\n";
2360 if ($confighash{$cgiparams{'KEY'}}[30] eq 'on') {
2361 print CLIENTCONF
"# Enable Compression\n";
2362 print CLIENTCONF
"comp-lzo\n";
2364 print CLIENTCONF
"# Debug Level\n";
2365 print CLIENTCONF
"verb 3\n";
2366 print CLIENTCONF
"# Tunnel check\n";
2367 print CLIENTCONF
"keepalive 10 60\n";
2368 print CLIENTCONF
"# Start as daemon\n";
2369 print CLIENTCONF
"daemon $confighash{$cgiparams{'KEY'}}[1]n2n\n";
2370 print CLIENTCONF
"writepid /var/run/$confighash{$cgiparams{'KEY'}}[1]n2n.pid\n";
2371 print CLIENTCONF
"# Activate Management Interface and Port\n";
2372 if ($confighash{$cgiparams{'KEY'}}[22] eq '') {
2373 print CLIENTCONF
"management localhost $confighash{$cgiparams{'KEY'}}[29]\n"
2375 print CLIENTCONF
"management localhost $confighash{$cgiparams{'KEY'}}[22]\n"
2377 print CLIENTCONF
"# remsub $confighash{$cgiparams{'KEY'}}[11]\n";
2378 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
2379 print CLIENTCONF
"providers legacy default\n";
2383 $zip->addFile( "$tempdir/$clientovpn", $clientovpn) or die "Can't add file $clientovpn\n";
2384 my $status = $zip->writeToFileNamed($zippathname);
2386 open(DLFILE
, "<$zippathname") or die "Unable to open $zippathname: $!";
2387 @fileholder = <DLFILE
>;
2388 print "Content-Type:application/x-download\n";
2389 print "Content-Disposition:attachment;filename=$zipname\n\n";
2394 my $name = $confighash{$cgiparams{'KEY'}}[1];
2397 &Header
::showhttpheaders
({
2398 "Content-Type" => "application/x-openvpn-profile",
2399 "Content-Disposition" => "attachment; filename=${name}.ovpn",
2402 print "########################################################################\n";
2403 print "# IPFire OpenVPN Client Configuration for \"${name}\"\n";
2404 print "########################################################################\n";
2409 # This is a layer 3 VPN
2412 # Point the client to this server
2413 print "remote $vpnsettings{'VPN_IP'} $vpnsettings{'DDEST_PORT'}\n";
2414 print "proto $vpnsettings{'DPROTOCOL'}\n";
2416 # Configure the MTU of the tunnel interface
2417 print "tun-mtu $vpnsettings{'DMTU'}\n";
2419 # Ask the client to verify the server certificate
2420 if (&is_cert_rfc3280_compliant
("${General::swroot}/ovpn/certs/servercert.pem")) {
2421 print "remote-cert-tls server\n";
2423 print "verify-x509-name $vpnsettings{'ROOTCERT_HOSTNAME'} name\n";
2425 if ($vpnsettings{'MSSFIX'} eq 'on') {
2430 if ($vpnsettings{'FRAGMENT'} ne '' && $vpnsettings{'DPROTOCOL'} ne 'tcp' ) {
2431 print "fragment $vpnsettings{'FRAGMENT'}\n";
2434 # We no longer send any cryptographic configuration since 2.6.
2435 # That way, we will be able to push this from the server.
2436 # Therefore we always mandate NCP for new clients.
2438 if ($vpnsettings{'DAUTH'} ne "") {
2439 print "auth $vpnsettings{'DAUTH'}\n";
2442 # Disable storing any credentials in memory
2443 print "auth-nocache\n";
2445 # Set a fake user name for authentication
2446 print "auth-token-user USER\n";
2447 print "auth-token TOTP\n";
2449 # If the server is asking for TOTP this needs to happen interactively
2450 print "auth-retry interact\n";
2452 # Add provider line if certificate is legacy type
2453 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
2454 print "providers legacy default\n";
2458 open(FILE
, "<${General::swroot}/ovpn/ca/cacert.pem");
2468 open(FILE
, "<${General::swroot}/ovpn/certs/${name}.p12");
2469 print "\n<pkcs12>\n";
2470 print &MIME
::Base64
::encode_base64
(do { local $/; <FILE
> });
2471 print "</pkcs12>\n";
2475 if ($vpnsettings{'TLSAUTH'} eq 'on') {
2476 open(FILE
, "<${General::swroot}/ovpn/certs/ta.key");
2477 print "\n<tls-auth>\n";
2482 print "</tls-auth>\n";
2489 ### Remove connection
2493 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove'}) {
2494 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2496 if ($confighash{$cgiparams{'KEY'}}) {
2497 # Revoke certificate if certificate was deleted and rewrite the CRL
2498 &General
::system("/usr/bin/openssl", "ca", "-revoke", "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2499 &General
::system("/usr/bin/openssl", "ca", "-gencrl", "-out", "${General::swroot}/ovpn/crls/cacrl.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2501 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net') {
2502 # Stop the N2N connection before it is removed
2503 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
2505 my $conffile = glob("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]/$confighash{$cgiparams{'KEY'}}[1].conf");
2506 my $certfile = glob("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2510 if (-e
"${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") {
2511 rmdir ("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") || die "Kann Verzeichnis nicht loeschen: $!";
2515 unlink ("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
2516 unlink ("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2518 # Delete CCD files and routes
2520 if (-f
"${General::swroot}/ovpn/ccd/$confighash{$cgiparams{'KEY'}}[2]")
2522 unlink "${General::swroot}/ovpn/ccd/$confighash{$cgiparams{'KEY'}}[2]";
2525 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
2526 foreach my $key (keys %ccdroutehash) {
2527 if ($ccdroutehash{$key}[0] eq $confighash{$cgiparams{'KEY'}}[1]){
2528 delete $ccdroutehash{$key};
2531 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
2533 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
2534 foreach my $key (keys %ccdroute2hash) {
2535 if ($ccdroute2hash{$key}[0] eq $confighash{$cgiparams{'KEY'}}[1]){
2536 delete $ccdroute2hash{$key};
2539 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
2542 # Update collectd configuration and delete all RRD files of the removed connection
2543 &writecollectdconf
();
2544 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "delete", "$confighash{$cgiparams{'KEY'}}[1]");
2546 delete $confighash{$cgiparams{'KEY'}};
2547 &General
::system("/usr/bin/openssl", "ca", "-gencrl", "-out", "${General::swroot}/ovpn/crls/cacrl.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2548 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2551 $errormessage = $Lang::tr
{'invalid key'};
2553 &General
::firewall_reload
();
2556 ### Download PKCS12 file
2558 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download pkcs12 file'}) {
2559 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2561 print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . ".p12\r\n";
2562 print "Content-Type: application/octet-stream\r\n\r\n";
2564 open(FILE
, "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2572 ### Display certificate
2574 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show certificate'}) {
2575 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2577 if ( -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
2578 &Header
::showhttpheaders
();
2579 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2580 &Header
::openbigbox
('100%', 'LEFT', '', '');
2581 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'certificate'}:");
2582 my @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
2583 my $output = &Header
::cleanhtml
(join("", @output), "y");
2584 print "<pre>$output</pre>\n";
2585 &Header
::closebox
();
2586 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2587 &Header
::closebigbox
();
2588 &Header
::closepage
();
2593 ### Display OTP QRCode
2595 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show otp qrcode'}) {
2596 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2598 my $qrcode = Imager
::QRCode-
>new(
2605 lightcolor
=> Imager
::Color-
>new(255, 255, 255),
2606 darkcolor
=> Imager
::Color-
>new(0, 0, 0),
2608 my $cn = uri_encode
($confighash{$cgiparams{'KEY'}}[2]);
2609 my $secret = encode_base32
(pack('H*', $confighash{$cgiparams{'KEY'}}[44]));
2610 my $issuer = uri_encode
("$mainsettings{'HOSTNAME'}.$mainsettings{'DOMAINNAME'}");
2611 my $qrcodeimg = $qrcode->plot("otpauth://totp/$cn?secret=$secret&issuer=$issuer");
2613 $qrcodeimg->write(data
=> \
$qrcodeimgdata, type
=> 'png')
2614 or die $qrcodeimg->errstr;
2615 $qrcodeimgdata = encode_base64
($qrcodeimgdata, '');
2617 &Header
::showhttpheaders
();
2618 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2619 &Header
::openbigbox
('100%', 'LEFT', '', '');
2620 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'otp qrcode'}:");
2622 $Lang::tr{'secret'}: $secret</br></br>
2623 <img alt="$Lang::tr{'otp qrcode'}" src="data:image/png;base64,$qrcodeimgdata">
2625 &Header
::closebox
();
2626 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2627 &Header
::closebigbox
();
2628 &Header
::closepage
();
2632 ### Display tls-auth key
2634 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show tls-auth key'}) {
2636 if (! -e
"${General::swroot}/ovpn/certs/ta.key") {
2637 $errormessage = $Lang::tr
{'not present'};
2639 &Header
::showhttpheaders
();
2640 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2641 &Header
::openbigbox
('100%', 'LEFT', '', '');
2642 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ta key'}:");
2644 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
2645 my @output = <FILE
>;
2648 my $output = &Header
::cleanhtml
(join("", @output),"y");
2649 print "<pre>$output</pre>\n";
2650 &Header
::closebox
();
2651 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2652 &Header
::closebigbox
();
2653 &Header
::closepage
();
2658 ### Display Certificate Revoke List
2660 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show crl'}) {
2661 # &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2663 if (! -e
"${General::swroot}/ovpn/crls/cacrl.pem") {
2664 $errormessage = $Lang::tr
{'not present'};
2666 &Header
::showhttpheaders
();
2667 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2668 &Header
::openbigbox
('100%', 'LEFT', '', '');
2669 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'crl'}:");
2670 my @output = &General
::system_output
("/usr/bin/openssl", "crl", "-text", "-noout", "-in", "${General::swroot}/ovpn/crls/cacrl.pem");
2671 my $output = &Header
::cleanhtml
(join("", @output), "y");
2672 print "<pre>$output</pre>\n";
2673 &Header
::closebox
();
2674 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2675 &Header
::closebigbox
();
2676 &Header
::closepage
();
2681 ### Advanced Server Settings
2684 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'advanced server'}) {
2686 $selected{'DPROTOCOL'}{'udp'} = '';
2687 $selected{'DPROTOCOL'}{'tcp'} = '';
2688 $selected{'DPROTOCOL'}{$vpnsettings{'DPROTOCOL'}} = 'SELECTED';
2690 $checked{'REDIRECT_GW_DEF1'}{'off'} = '';
2691 $checked{'REDIRECT_GW_DEF1'}{'on'} = '';
2692 $checked{'REDIRECT_GW_DEF1'}{$vpnsettings{'REDIRECT_GW_DEF1'}} = 'CHECKED';
2693 $checked{'MSSFIX'}{'off'} = '';
2694 $checked{'MSSFIX'}{'on'} = '';
2695 $checked{'MSSFIX'}{$vpnsettings{'MSSFIX'}} = 'CHECKED';
2697 # Split data ciphers
2698 my @data_ciphers = split(/\|/, $vpnsettings{'DATACIPHERS'});
2700 # Select the correct ones
2701 $selected{'DATACIPHERS'} = ();
2702 foreach my $cipher (@SUPPORTED_CIPHERS) {
2703 $selected{'DATACIPHERS'}{$cipher} = grep(/^$cipher$/, @data_ciphers) ? "selected" : "";
2707 $vpnsettings{'ROUTES_PUSH'} =~ s/\|/\n/g;
2709 $selected{'DCIPHER'}{'AES-256-GCM'} = '';
2710 $selected{'DCIPHER'}{'AES-192-GCM'} = '';
2711 $selected{'DCIPHER'}{'AES-128-GCM'} = '';
2712 $selected{'DCIPHER'}{'CAMELLIA-256-CBC'} = '';
2713 $selected{'DCIPHER'}{'CAMELLIA-192-CBC'} = '';
2714 $selected{'DCIPHER'}{'CAMELLIA-128-CBC'} = '';
2715 $selected{'DCIPHER'}{'AES-256-CBC'} = '';
2716 $selected{'DCIPHER'}{'AES-192-CBC'} = '';
2717 $selected{'DCIPHER'}{'AES-128-CBC'} = '';
2718 $selected{'DCIPHER'}{'DES-EDE3-CBC'} = '';
2719 $selected{'DCIPHER'}{'DESX-CBC'} = '';
2720 $selected{'DCIPHER'}{'SEED-CBC'} = '';
2721 $selected{'DCIPHER'}{'DES-EDE-CBC'} = '';
2722 $selected{'DCIPHER'}{'CAST5-CBC'} = '';
2723 $selected{'DCIPHER'}{'BF-CBC'} = '';
2724 $selected{'DCIPHER'}{'DES-CBC'} = '';
2725 $selected{'DCIPHER'}{$vpnsettings{'DCIPHER'}} = 'SELECTED';
2727 $selected{'DAUTH'}{'whirlpool'} = '';
2728 $selected{'DAUTH'}{'SHA512'} = '';
2729 $selected{'DAUTH'}{'SHA384'} = '';
2730 $selected{'DAUTH'}{'SHA256'} = '';
2731 $selected{'DAUTH'}{'SHA1'} = '';
2732 $selected{'DAUTH'}{$vpnsettings{'DAUTH'}} = 'SELECTED';
2734 $checked{'TLSAUTH'}{'off'} = '';
2735 $checked{'TLSAUTH'}{'on'} = '';
2736 $checked{'TLSAUTH'}{$vpnsettings{'TLSAUTH'}} = 'CHECKED';
2738 &Header
::showhttpheaders
();
2739 &Header
::openpage
($Lang::tr
{'status ovpn'}, 1, '');
2740 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
2743 &Header
::errorbox
($errormessage);
2745 &Header
::opensection
();
2748 <form method='POST' enctype='multipart/form-data'>
2749 <h6>$Lang::tr{'ovpn protocol settings'}</h6>
2751 <table class="form">
2753 <td>$Lang::tr{'ovpn transport protocol'}</td>
2755 <select name='DPROTOCOL'>
2756 <option value='udp' $selected{'DPROTOCOL'}{'udp'}>UDP</option>
2757 <option value='tcp' $selected{'DPROTOCOL'}{'tcp'}>TCP</option>
2763 <td>$Lang::tr{'destination port'}</td>
2765 <input type='number' name='DDEST_PORT' value='$vpnsettings{'DDEST_PORT'}' />
2770 <td>$Lang::tr{'mtu'}</td>
2772 <input type='number' name='DMTU' value='$vpnsettings{'DMTU'}' min="1280" max="9000" />
2779 <input type='checkbox' name='MSSFIX' $checked{'MSSFIX'}{'on'} />
2786 <input type='TEXT' name='FRAGMENT' value='$vpnsettings{'FRAGMENT'}' />
2791 <h6>$Lang::tr{'ovpn crypto settings'}</h6>
2793 <table class="form">
2796 $Lang::tr{'ovpn ciphers'}
2800 <select name='DATACIPHERS' multiple required>
2803 foreach my $cipher (@SUPPORTED_CIPHERS) {
2804 my $name = $CIPHERS{$cipher} // $cipher;
2807 <option value='$cipher' $selected{'DATACIPHERS'}{$cipher}>
2820 $Lang::tr{'ovpn ha'}
2824 <select name='DAUTH'>
2825 <option value='whirlpool' $selected{'DAUTH'}{'whirlpool'}>Whirlpool (512 $Lang::tr{'bit'})</option>
2826 <option value='SHA512' $selected{'DAUTH'}{'SHA512'}>SHA2 (512 $Lang::tr{'bit'})</option>
2827 <option value='SHA384' $selected{'DAUTH'}{'SHA384'}>SHA2 (384 $Lang::tr{'bit'})</option>
2828 <option value='SHA256' $selected{'DAUTH'}{'SHA256'}>SHA2 (256 $Lang::tr{'bit'})</option>
2829 <option value='SHA1' $selected{'DAUTH'}{'SHA1'}>SHA1 (160 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2836 $Lang::tr{'ovpn tls auth'}
2840 <input type='checkbox' name='TLSAUTH' $checked{'TLSAUTH'}{'on'} />
2846 $Lang::tr{'ovpn fallback cipher'}
2850 <select name='DCIPHER'>
2851 <option value='' $selected{'DCIPHER'}{''}>- $Lang::tr{'Disabled'} -</option>
2852 <option value='AES-256-GCM' $selected{'DCIPHER'}{'AES-256-GCM'}>AES-GCM (256 $Lang::tr{'bit'})</option>
2853 <option value='AES-192-GCM' $selected{'DCIPHER'}{'AES-192-GCM'}>AES-GCM (192 $Lang::tr{'bit'})</option>
2854 <option value='AES-128-GCM' $selected{'DCIPHER'}{'AES-128-GCM'}>AES-GCM (128 $Lang::tr{'bit'})</option>
2855 <option value='CAMELLIA-256-CBC' $selected{'DCIPHER'}{'CAMELLIA-256-CBC'}>CAMELLIA-CBC (256 $Lang::tr{'bit'})</option>
2856 <option value='CAMELLIA-192-CBC' $selected{'DCIPHER'}{'CAMELLIA-192-CBC'}>CAMELLIA-CBC (192 $Lang::tr{'bit'})</option>
2857 <option value='CAMELLIA-128-CBC' $selected{'DCIPHER'}{'CAMELLIA-128-CBC'}>CAMELLIA-CBC (128 $Lang::tr{'bit'})</option>
2858 <option value='AES-256-CBC' $selected{'DCIPHER'}{'AES-256-CBC'}>AES-CBC (256 $Lang::tr{'bit'})</option>
2859 <option value='AES-192-CBC' $selected{'DCIPHER'}{'AES-192-CBC'}>AES-CBC (192 $Lang::tr{'bit'})</option>
2860 <option value='AES-128-CBC' $selected{'DCIPHER'}{'AES-128-CBC'}>AES-CBC (128 $Lang::tr{'bit'})</option>
2861 <option value='SEED-CBC' $selected{'DCIPHER'}{'SEED-CBC'}>SEED-CBC (128 $Lang::tr{'bit'})</option>
2862 <option value='DES-EDE3-CBC' $selected{'DCIPHER'}{'DES-EDE3-CBC'}>DES-EDE3-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2863 <option value='DESX-CBC' $selected{'DCIPHER'}{'DESX-CBC'}>DESX-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2864 <option value='DES-EDE-CBC' $selected{'DCIPHER'}{'DES-EDE-CBC'}>DES-EDE-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2865 <option value='BF-CBC' $selected{'DCIPHER'}{'BF-CBC'}>BF-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2866 <option value='CAST5-CBC' $selected{'DCIPHER'}{'CAST5-CBC'}>CAST5-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2874 $Lang::tr{'ovpn fallback cipher help'}
2879 <h6>$Lang::tr{'ovpn dhcp settings'}</h6>
2881 <table class="form">
2885 <input type='TEXT' name='DHCP_DOMAIN' value='$vpnsettings{'DHCP_DOMAIN'}' size='30' />
2891 <input type='TEXT' name='DHCP_DNS' value='$vpnsettings{'DHCP_DNS'}' size='30' />
2897 <input type='TEXT' name='DHCP_WINS' value='$vpnsettings{'DHCP_WINS'}' size='30' />
2902 <h6>$Lang::tr{'ovpn routing settings'}</h6>
2904 <table class="form">
2906 <td>$Lang::tr{'ovpn push default route'}</td>
2908 <input type='checkbox' name='REDIRECT_GW_DEF1' $checked{'REDIRECT_GW_DEF1'}{'on'} />
2913 <td>$Lang::tr{'ovpn routes push'}</td>
2915 <textarea name='ROUTES_PUSH' cols='26' rows='6' wrap='off'>$vpnsettings{'ROUTES_PUSH'}</textarea>
2920 <h6>$Lang::tr{'ovpn misc settings'}</h6>
2922 <table class="form">
2924 <td>Max-Clients</td>
2926 <input type='text' name='MAX_CLIENTS' value='$vpnsettings{'MAX_CLIENTS'}' />
2932 <input type='submit' name='ACTION' value='$Lang::tr{'save-adv-options'}' />
2933 <input type='submit' name='ACTION' value='$Lang::tr{'cancel-adv-options'}' />
2939 &Header
::closesection
();
2940 &Header
::closebigbox
();
2942 &Header
::closepage
();
2946 # Add, delete or edit CCD net
2948 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'ccd net'} ||
2949 $cgiparams{'ACTION'} eq "ccd-add" ||
2950 $cgiparams{'ACTION'} eq "ccd-delete" ||
2951 $cgiparams{'ACTION'} eq "ccd-edit" ||
2952 $cgiparams{'ACTION'} eq 'ccd-edit-save'){
2953 &Header
::showhttpheaders
();
2955 &Header
::openpage
($Lang::tr
{'ccd net'}, 1, '');
2957 &Header
::openbigbox
('100%', 'LEFT', '', '');
2960 if ($cgiparams{'ACTION'} eq "ccd-delete") {
2961 $errormessage = &delccdnet
($cgiparams{'name'});
2964 } elsif ($cgiparams{'ACTION'} eq 'ccd-edit-save') {
2965 $errormessage = &modccdnet
($cgiparams{'subnet'}, $cgiparams{'name'});
2968 if ($errormessage eq "") {
2969 $cgiparams{"name"} = "";
2970 $cgiparams{"subnet"} = "";
2974 } elsif ($cgiparams{'ACTION'} eq "ccd-add") {
2975 $errormessage = &addccdnet
($cgiparams{'name'}, $cgiparams{'subnet'});
2978 if ($errormessage eq "") {
2979 $cgiparams{"name"} = "";
2980 $cgiparams{"subnet"} = "";
2984 &Header
::errorbox
($errormessage);
2986 my %ccdconfhash = ();
2987 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
2989 &Header
::opensection
();
2994 $Lang::tr{'ccd name'}
2998 $Lang::tr{'network'}
3002 $Lang::tr{'ccd used'}
3005 <th colspan="2"></th>
3009 foreach my $key (sort { uc($ccdconfhash{$a}[0]) cmp uc($ccdconfhash{$b}[0]) } keys %ccdconfhash) {
3010 my $name = $ccdconfhash{$key}[0];
3011 my $subnet = $ccdconfhash{$key}[1];
3013 my $ccdhosts = scalar &get_addresses_in_use
($subnet);
3014 my $maxhosts = &ccdmaxclients
($subnet);
3022 <td class="text-center">
3026 <td class="text-center">
3027 ${ccdhosts}/${maxhosts}
3030 <td class="text-center">
3031 <form method='post' />
3032 <input type='image' src='/images/edit.gif' align='middle'
3033 alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
3034 <input type='hidden' name='ACTION' value='ccd-edit'/>
3035 <input type='hidden' name='name' value='$name' />
3036 <input type='hidden' name='subnet' value='$subnet' />
3040 <td class="text-center">
3041 <form method='post' />
3042 <input type='hidden' name='ACTION' value='ccd-delete'/>
3043 <input type='hidden' name='name' value='$name' />
3044 <input type='image' src='/images/delete.gif' align='middle'
3045 alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
3052 &Header
::closesection
();
3054 &Header
::openbox
('100%', 'LEFT',
3055 ($cgiparams{'ACTION'} eq "ccd-edit") ? $Lang::tr
{'ccd modify'} : $Lang::tr
{'ccd add'});
3057 # The subnet cannot be edited
3058 my $readonly = ($cgiparams{'ACTION'} eq "ccd-edit") ? "readonly" : "";
3059 my $action = ($cgiparams{'ACTION'} eq "ccd-edit") ? "ccd-edit-save" : "ccd-add";
3062 <form method='post'>
3063 <table class="form">
3065 <td>$Lang::tr{'ccd name'}</td>
3067 <input type='TEXT' name='name' value='$cgiparams{'name'}' />
3072 <td>$Lang::tr{'ccd subnet'}</td>
3074 <input type='TEXT' name='subnet' value='$cgiparams{'subnet'}'
3081 <input type='hidden' name='ACTION' value='$action' />
3082 <input type='submit' value='$Lang::tr{'save'}' />
3088 &Header
::closebox
();
3091 <div class="text-center">
3092 <a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a>
3096 &Header
::closebigbox
();
3097 &Header
::closepage
();
3102 ### Openvpn Connections Statistics
3104 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'ovpn con stat'}) {
3105 &Header
::showhttpheaders
();
3106 &Header
::openpage
($Lang::tr
{'ovpn con stat'}, 1, '');
3107 &Header
::openbigbox
('100%', 'LEFT', '', '');
3109 &Header
::opensection
();
3114 <th>$Lang::tr{'common name'}</th>
3115 <th>$Lang::tr{'real address'}</th>
3116 <th>$Lang::tr{'country'}</th>
3117 <th>$Lang::tr{'virtual address'}</th>
3118 <th>$Lang::tr{'loged in at'}</th>
3119 <th>$Lang::tr{'bytes sent'}</th>
3120 <th>$Lang::tr{'bytes received'}</th>
3121 <th>$Lang::tr{'last activity'}</th>
3125 open(FILE
, "/usr/local/bin/openvpnctrl rw log |") or die "Unable to open $RW_STATUS: $!";
3126 my @current = <FILE
>;
3133 my %userlookup = ();
3135 foreach my $line (@current) {
3138 if ($line =~ /^Updated,(.+)/) {
3139 @match = split(/^Updated,(.+)/, $line);
3140 $status = $match[1];
3142 } elsif ( $line =~ /^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/) {
3143 @match = split(m/^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/, $line);
3146 next if ($match[1] eq "Common Name");
3148 $userlookup{$match[2]} = $uid;
3149 $users[$uid]{'CommonName'} = $match[1];
3150 $users[$uid]{'RealAddress'} = $match[2];
3151 $users[$uid]{'BytesReceived'} = &General
::formatBytes
($match[3]);
3152 $users[$uid]{'BytesSent'} = &General
::formatBytes
($match[4]);
3153 $users[$uid]{'Since'} = $match[5];
3155 my $address = (split ':', $users[$uid]{'RealAddress'})[0];
3156 $users[$uid]{'Country'} = &Location
::Functions
::lookup_country_code
($address);
3159 } elsif ($line =~ /^(\d+\.\d+\.\d+\.\d+),(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(.+)/) {
3160 @match = split(m/^(\d+\.\d+\.\d+\.\d+),(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(.+)/, $line);
3163 next if ($match[1] eq "Virtual Address");
3165 my $address = $match[3];
3166 #find the uid in the lookup table
3167 $uid = $userlookup{$address};
3168 $users[$uid]{'VirtualAddress'} = $match[1];
3169 $users[$uid]{'LastRef'} = $match[4];
3173 foreach my $id (keys @users) {
3174 my $user = $users[$id];
3176 my $flag_icon = &Location
::Functions
::get_flag_icon
($user->{"Country"});
3181 $user->{"CommonName"}
3184 <td class="text-center">
3185 $user->{"RealAddress"}
3188 <td class="text-center">
3189 <a href="country.cgi#$user->{"Country"}">
3190 <img src="$flag_icon" border='0' align='absmiddle'
3191 alt='$user->{"Country"}' title='$user->{"Country"}' />
3195 <td class="text-center">
3196 $user->{"VirtualAddress"}
3199 <td class="text-center">
3203 <td class="text-right">
3204 $user->{"BytesSent"}
3207 <td class="text-right">
3208 $user->{"BytesReceived"}
3211 <td class="text-right">
3221 <p class="text-center">
3222 $Lang::tr{'the statistics were last updated at'} <b>$status</b>
3227 &Header
::closesection
();
3230 <p class="text-center">
3231 <a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a>
3235 &Header
::closebigbox
();
3236 &Header
::closepage
();
3241 ### Download Certificate
3243 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download certificate'}) {
3244 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3246 if ( -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
3247 print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . "cert.pem\r\n";
3248 print "Content-Type: application/octet-stream\r\n\r\n";
3250 open(FILE
, "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
3259 ### Enable/Disable connection
3262 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'toggle enable disable'}) {
3263 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3265 if ($confighash{$cgiparams{'KEY'}}) {
3266 if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
3267 $confighash{$cgiparams{'KEY'}}[0] = 'on';
3268 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3270 $confighash{$cgiparams{'KEY'}}[0] = 'off';
3271 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3274 $errormessage = $Lang::tr
{'invalid key'};
3277 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'add'} && $cgiparams{'TYPE'} eq '') {
3278 &Header
::showhttpheaders
();
3279 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
3280 &Header
::openbigbox
('100%', 'LEFT', '', '');
3281 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'connection type'});
3283 if ( -s
"${General::swroot}/ovpn/settings") {
3286 <b>$Lang::tr{'connection type'}:</b><br />
3287 <table border='0' width='100%'><form method='post' ENCTYPE="multipart/form-data">
3288 <tr><td><input type='radio' name='TYPE' value='host' checked /></td>
3289 <td class='base'>$Lang::tr{'host to net vpn'}</td></tr>
3290 <tr><td><input type='radio' name='TYPE' value='net' /></td>
3291 <td class='base'>$Lang::tr{'net to net vpn'}</td></tr>
3292 <tr><td><input type='radio' name='TYPE' value='net2net' /></td>
3293 <td class='base'>$Lang::tr{'net to net vpn'} (Upload Client Package)</td></tr>
3294 <tr><td> </td><td class='base'><input type='file' name='FH' size='30'></td></tr>
3295 <tr><td> </td><td>Import Connection Name</td></tr>
3296 <tr><td> </td><td class='base'><input type='text' name='n2nname' size='30'>$Lang::tr{'openvpn default'}: Client Packagename</td></tr>
3297 <tr><td colspan='3'><hr /></td></tr>
3298 <tr><td align='right' colspan='3'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td></tr>
3306 <b>$Lang::tr{'connection type'}:</b><br />
3307 <table border='0' width='100%'><form method='post' ENCTYPE="multipart/form-data">
3308 <tr><td><input type='radio' name='TYPE' value='host' checked /></td> <td class='base'>$Lang::tr{'host to net vpn'}</td></tr>
3309 <tr><td align='right' colspan'3'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td></tr>
3316 &Header
::closebox
();
3317 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
3318 &Header
::closebigbox
();
3319 &Header
::closepage
();
3322 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) && ($cgiparams{'TYPE'} eq 'net2net')){
3326 my $uplconffilename ='';
3327 my $uplconffilename2 ='';
3328 my $uplp12name = '';
3329 my $uplp12name2 = '';
3336 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3338 # Check if a file is uploaded
3339 unless (ref ($cgiparams{'FH'})) {
3340 $errormessage = $Lang::tr
{'there was no file upload'};
3344 # Move uploaded IPfire n2n package to temporary file
3346 (my $fh, my $filename) = tempfile
( );
3347 if (copy
($cgiparams{'FH'}, $fh) != 1) {
3352 my $zip = Archive
::Zip-
>new();
3353 my $zipName = $filename;
3354 my $status = $zip->read( $zipName );
3355 if ($status != AZ_OK
) {
3356 $errormessage = "Read of $zipName failed\n";
3360 my $tempdir = tempdir
( CLEANUP
=> 1 );
3361 my @files = $zip->memberNames();
3363 $zip->extractMemberWithoutPaths($_,"$tempdir/$_");
3365 my $countfiles = @files;
3367 # Check if we have not more then 2 files
3369 if ( $countfiles == 2){
3371 if ( $_ =~ /.conf$/){
3372 $uplconffilename = $_;
3374 if ( $_ =~ /.p12$/){
3378 if (($uplconffilename eq '') || ($uplp12name eq '')){
3379 $errormessage = "Either no *.conf or no *.p12 file found\n";
3383 open(FILE
, "$tempdir/$uplconffilename") or die 'Unable to open*.conf file';
3384 @firen2nconf = <FILE
>;
3386 chomp(@firen2nconf);
3389 $errormessage = "Filecount does not match only 2 files are allowed\n";
3393 if ($cgiparams{'n2nname'} ne ''){
3395 $uplconffilename2 = "$cgiparams{'n2nname'}.conf";
3396 $uplp12name2 = "$cgiparams{'n2nname'}.p12";
3397 $n2nname[0] = $cgiparams{'n2nname'};
3398 my @n2nname2 = split(/\./,$uplconffilename);
3399 $n2nname2[0] =~ s/\n|\r//g;
3400 my $input1 = "${General::swroot}/ovpn/certs/$uplp12name";
3401 my $output1 = "${General::swroot}/ovpn/certs/$uplp12name2";
3402 my $input2 = "$n2nname2[0]n2n";
3403 my $output2 = "$n2nname[0]n2n";
3404 my $filename = "$tempdir/$uplconffilename";
3405 open(FILE
, "< $filename") or die 'Unable to open config file.';
3406 my @current = <FILE
>;
3408 foreach (@current) {s/$input1/$output1/g;}
3409 foreach (@current) {s/$input2/$output2/g;}
3410 open (OUT
, "> $filename") || die 'Unable to open config file.';
3415 $uplconffilename2 = $uplconffilename;
3416 $uplp12name2 = $uplp12name;
3417 @n2nname = split(/\./,$uplconffilename);
3418 $n2nname[0] =~ s/\n|\r//g;
3420 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
3421 unless(-d
"${General::swroot}/ovpn/n2nconf/$n2nname[0]"){mkdir "${General::swroot}/ovpn/n2nconf/$n2nname[0]", 0770 or die "Unable to create dir $!";}
3423 #Add collectd settings to configfile
3424 open(FILE
, ">> $tempdir/$uplconffilename") or die 'Unable to open config file.';
3425 print FILE
"# Logfile\n";
3426 print FILE
"status-version 1\n";
3427 print FILE
"status /var/run/openvpn/$n2nname[0]-n2n 10\n";
3428 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$cgiparams{'n2nname'}")) {
3429 print CLIENTCONF
"providers legacy default\n";
3434 unless(move
("$tempdir/$uplconffilename", "${General::swroot}/ovpn/n2nconf/$n2nname[0]/$uplconffilename2")) {
3435 $errormessage = "*.conf move failed: $!";
3440 unless(move
("$tempdir/$uplp12name", "${General::swroot}/ovpn/certs/$uplp12name2")) {
3441 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
3446 chmod 0600, "${General::swroot}/ovpn/certs/$uplp12name";
3452 my @n2nproto2 = split(/ /, (grep { /^proto/ } @firen2nconf)[0]);
3453 my @n2nproto = split(/-/, $n2nproto2[1]);
3454 my @n2nport = split(/ /, (grep { /^port/ } @firen2nconf)[0]);
3455 my @n2ntunmtu = split(/ /, (grep { /^tun-mtu/ } @firen2nconf)[0]);
3456 my @n2ncomplzo = grep { /^comp-lzo/ } @firen2nconf;
3457 if ($n2ncomplzo[0] =~ /comp-lzo/){$complzoactive = "on";} else {$complzoactive = "off";}
3458 my @n2nmssfix = grep { /^mssfix/ } @firen2nconf;
3459 if ($n2nmssfix[0] =~ /mssfix/){$mssfixactive = "on";} else {$mssfixactive = "off";}
3460 #my @n2nmssfix = split(/ /, (grep { /^mssfix/ } @firen2nconf)[0]);
3461 my @n2nfragment = split(/ /, (grep { /^fragment/ } @firen2nconf)[0]);
3462 my @n2nremote = split(/ /, (grep { /^remote/ } @firen2nconf)[0]);
3463 my @n2novpnsuball = split(/ /, (grep { /^ifconfig/ } @firen2nconf)[0]);
3464 my @n2novpnsub = split(/\./,$n2novpnsuball[1]);
3465 my @n2nremsub = split(/ /, (grep { /^route/ } @firen2nconf)[0]);
3466 my @n2nmgmt = split(/ /, (grep { /^management/ } @firen2nconf)[0]);
3467 my @n2nlocalsub = split(/ /, (grep { /^# remsub/ } @firen2nconf)[0]);
3468 my @n2ncipher = split(/ /, (grep { /^cipher/ } @firen2nconf)[0]);
3469 my @n2nauth = split(/ /, (grep { /^auth/ } @firen2nconf)[0]);;
3472 # m.a.d delete CR and LF from arrays for this chomp doesnt work
3475 $n2nremote[1] =~ s/\n|\r//g;
3476 $n2novpnsub[0] =~ s/\n|\r//g;
3477 $n2novpnsub[1] =~ s/\n|\r//g;
3478 $n2novpnsub[2] =~ s/\n|\r//g;
3479 $n2nproto[0] =~ s/\n|\r//g;
3480 $n2nport[1] =~ s/\n|\r//g;
3481 $n2ntunmtu[1] =~ s/\n|\r//g;
3482 $n2nremsub[1] =~ s/\n|\r//g;
3483 $n2nremsub[2] =~ s/\n|\r//g;
3484 $n2nlocalsub[2] =~ s/\n|\r//g;
3485 $n2nfragment[1] =~ s/\n|\r//g;
3486 $n2nmgmt[2] =~ s/\n|\r//g;
3487 $n2ncipher[1] =~ s/\n|\r//g;
3488 $n2nauth[1] =~ s/\n|\r//g;
3489 chomp ($complzoactive);
3490 chomp ($mssfixactive);
3493 # Check if there is no other entry with this name
3496 foreach my $dkey (keys %confighash) {
3497 if ($confighash{$dkey}[1] eq $n2nname[0]) {
3498 $errormessage = $Lang::tr
{'a connection with this name already exists'};
3499 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3500 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3501 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3507 # Check if OpenVPN Subnet is valid
3510 foreach my $dkey (keys %confighash) {
3511 if ($confighash{$dkey}[27] eq "$n2novpnsub[0].$n2novpnsub[1].$n2novpnsub[2].0/255.255.255.0") {
3512 $errormessage = 'The OpenVPN Subnet is already in use';
3513 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3514 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3515 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3521 # Check if Dest Port is vaild
3524 foreach my $dkey (keys %confighash) {
3525 if ($confighash{$dkey}[29] eq $n2nport[1] ) {
3526 $errormessage = 'The OpenVPN Port is already in use';
3527 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3528 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3529 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3536 $key = &General
::findhasharraykey
(\
%confighash);
3538 foreach my $i (0 .. 42) { $confighash{$key}[$i] = "";}
3540 $confighash{$key}[0] = 'off';
3541 $confighash{$key}[1] = $n2nname[0];
3542 $confighash{$key}[2] = $n2nname[0];
3543 $confighash{$key}[3] = 'net';
3544 $confighash{$key}[4] = 'cert';
3545 $confighash{$key}[6] = 'client';
3546 $confighash{$key}[8] = $n2nlocalsub[2];
3547 $confighash{$key}[10] = $n2nremote[1];
3548 $confighash{$key}[11] = "$n2nremsub[1]/$n2nremsub[2]";
3549 $confighash{$key}[22] = $n2nmgmt[2];
3550 $confighash{$key}[23] = $mssfixactive;
3551 $confighash{$key}[24] = $n2nfragment[1];
3552 $confighash{$key}[25] = 'IPFire n2n Client';
3553 $confighash{$key}[26] = 'red';
3554 $confighash{$key}[27] = "$n2novpnsub[0].$n2novpnsub[1].$n2novpnsub[2].0/255.255.255.0";
3555 $confighash{$key}[28] = $n2nproto[0];
3556 $confighash{$key}[29] = $n2nport[1];
3557 $confighash{$key}[30] = $complzoactive;
3558 $confighash{$key}[31] = $n2ntunmtu[1];
3559 $confighash{$key}[39] = $n2nauth[1];
3560 $confighash{$key}[40] = $n2ncipher[1];
3561 $confighash{$key}[41] = 'no-pass';
3563 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3567 &Header
::showhttpheaders
();
3568 &Header
::openpage
('Validate imported configuration', 1, '');
3569 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
3570 if ($errormessage) {
3571 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'error messages'});
3572 print "<class name='base'>$errormessage";
3573 print " </class>";
3574 &Header
::closebox
();
3578 &Header
::openbox
('100%', 'LEFT', 'import ipfire net2net config');
3580 if ($errormessage eq ''){
3582 <!-- ipfire net2net config gui -->
3583 <table width='100%'>
3584 <tr><td width='25%'> </td><td width='25%'> </td></tr>
3585 <tr><td class='boldbase'>$Lang::tr{'name'}:</td><td><b>$n2nname[0]</b></td></tr>
3586 <tr><td> </td><td> </td></tr>
3587 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'Act as'}</td><td><b>$confighash{$key}[6]</b></td></tr>
3588 <tr><td class='boldbase' nowrap='nowrap'>Remote Host </td><td><b>$confighash{$key}[10]</b></td></tr>
3589 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'local subnet'}</td><td><b>$confighash{$key}[8]</b></td></tr>
3590 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'remote subnet'}:</td><td><b>$confighash{$key}[11]</b></td></tr>
3591 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'ovpn subnet'}</td><td><b>$confighash{$key}[27]</b></td></tr>
3592 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'protocol'}</td><td><b>$confighash{$key}[28]</b></td></tr>
3593 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'destination port'}:</td><td><b>$confighash{$key}[29]</b></td></tr>
3594 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'comp-lzo'}</td><td><b>$confighash{$key}[30]</b></td></tr>
3595 <tr><td class='boldbase' nowrap='nowrap'>MSSFIX:</td><td><b>$confighash{$key}[23]</b></td></tr>
3596 <tr><td class='boldbase' nowrap='nowrap'>Fragment:</td><td><b>$confighash{$key}[24]</b></td></tr>
3597 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'MTU'}</td><td><b>$confighash{$key}[31]</b></td></tr>
3598 <tr><td class='boldbase' nowrap='nowrap'>Management Port </td><td><b>$confighash{$key}[22]</b></td></tr>
3599 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'ovpn tls auth'}:</td><td><b>$confighash{$key}[39]</b></td></tr>
3600 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'cipher'}</td><td><b>$confighash{$key}[40]</b></td></tr>
3601 <tr><td> </td><td> </td></tr>
3605 &Header
::closebox
();
3608 if ($errormessage) {
3609 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
3611 print "<div align='center'><form method='post' ENCTYPE='multipart/form-data'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' />";
3612 print "<input type='hidden' name='TYPE' value='net2netakn' />";
3613 print "<input type='hidden' name='KEY' value='$key' />";
3614 print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
3616 &Header
::closebigbox
();
3617 &Header
::closepage
();
3622 ### Accept IPFire n2n Package Settings
3625 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) && ($cgiparams{'TYPE'} eq 'net2netakn')){
3628 ### Discard and Rollback IPFire n2n Package Settings
3631 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'cancel'}) && ($cgiparams{'TYPE'} eq 'net2netakn')){
3633 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3635 if ($confighash{$cgiparams{'KEY'}}) {
3637 my $conffile = glob("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]/$confighash{$cgiparams{'KEY'}}[1].conf");
3638 my $certfile = glob("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
3639 unlink ($certfile) or die "Removing $certfile fail: $!";
3640 unlink ($conffile) or die "Removing $conffile fail: $!";
3641 rmdir ("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") || die "Kann Verzeichnis nicht loeschen: $!";
3642 delete $confighash{$cgiparams{'KEY'}};
3643 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3646 $errormessage = $Lang::tr
{'invalid key'};
3650 ### Adding a new connection
3652 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) ||
3653 ($cgiparams{'ACTION'} eq $Lang::tr
{'edit'}) ||
3654 ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'ADVANCED'} eq '')) {
3655 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
3656 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3658 if ($cgiparams{'ACTION'} eq $Lang::tr
{'edit'}) {
3659 if (! $confighash{$cgiparams{'KEY'}}[0]) {
3660 $errormessage = $Lang::tr
{'invalid key'};
3663 $cgiparams{'ENABLED'} = $confighash{$cgiparams{'KEY'}}[0];
3664 $cgiparams{'NAME'} = $confighash{$cgiparams{'KEY'}}[1];
3665 $cgiparams{'TYPE'} = $confighash{$cgiparams{'KEY'}}[3];
3666 $cgiparams{'AUTH'} = $confighash{$cgiparams{'KEY'}}[4];
3667 $cgiparams{'PSK'} = $confighash{$cgiparams{'KEY'}}[5];
3668 $cgiparams{'SIDE'} = $confighash{$cgiparams{'KEY'}}[6];
3669 $cgiparams{'LOCAL_SUBNET'} = $confighash{$cgiparams{'KEY'}}[8];
3670 $cgiparams{'REMOTE'} = $confighash{$cgiparams{'KEY'}}[10];
3671 $cgiparams{'REMOTE_SUBNET'} = $confighash{$cgiparams{'KEY'}}[11];
3672 $cgiparams{'OVPN_MGMT'} = $confighash{$cgiparams{'KEY'}}[22];
3673 $cgiparams{'MSSFIX'} = $confighash{$cgiparams{'KEY'}}[23];
3674 $cgiparams{'FRAGMENT'} = $confighash{$cgiparams{'KEY'}}[24];
3675 $cgiparams{'REMARK'} = $confighash{$cgiparams{'KEY'}}[25];
3676 $cgiparams{'INTERFACE'} = $confighash{$cgiparams{'KEY'}}[26];
3677 $cgiparams{'OVPN_SUBNET'} = $confighash{$cgiparams{'KEY'}}[27];
3678 $cgiparams{'PROTOCOL'} = $confighash{$cgiparams{'KEY'}}[28];
3679 $cgiparams{'DEST_PORT'} = $confighash{$cgiparams{'KEY'}}[29];
3680 $cgiparams{'COMPLZO'} = $confighash{$cgiparams{'KEY'}}[30];
3681 $cgiparams{'MTU'} = $confighash{$cgiparams{'KEY'}}[31];
3682 $cgiparams{'CHECK1'} = $confighash{$cgiparams{'KEY'}}[32];
3683 $name=$cgiparams{'CHECK1'} ;
3684 $cgiparams{$name} = $confighash{$cgiparams{'KEY'}}[33];
3685 $cgiparams{'RG'} = $confighash{$cgiparams{'KEY'}}[34];
3686 $cgiparams{'CCD_DNS1'} = $confighash{$cgiparams{'KEY'}}[35];
3687 $cgiparams{'CCD_DNS2'} = $confighash{$cgiparams{'KEY'}}[36];
3688 $cgiparams{'CCD_WINS'} = $confighash{$cgiparams{'KEY'}}[37];
3689 $cgiparams{'DAUTH'} = $confighash{$cgiparams{'KEY'}}[39];
3690 $cgiparams{'DCIPHER'} = $confighash{$cgiparams{'KEY'}}[40];
3691 $cgiparams{'TLSAUTH'} = $confighash{$cgiparams{'KEY'}}[41];
3692 $cgiparams{'OTP_STATE'} = $confighash{$cgiparams{'KEY'}}[43];
3693 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'save'}) {
3694 $cgiparams{'REMARK'} = &Header
::cleanhtml
($cgiparams{'REMARK'});
3696 # CCD check iroute field and convert it to decimal
3697 if ($cgiparams{'TYPE'} eq 'host') {
3699 my %ccdroutehash=();
3703 if ($cgiparams{'IR'} ne ''){
3704 @temp = split("\n",$cgiparams{'IR'});
3705 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3707 foreach my $key (keys %ccdroutehash) {
3708 if ($ccdroutehash{$key}[0] eq $cgiparams{'NAME'}) {
3710 delete $ccdroutehash{$key};
3712 $keypoint = &General
::findhasharraykey
(\
%ccdroutehash);
3715 $ccdroutehash{$keypoint}[0]=$cgiparams{'NAME'};
3718 foreach $val (@temp){
3721 #check if iroute exists in ccdroute or if new iroute is part of an existing one
3722 foreach my $key (keys %ccdroutehash) {
3723 foreach my $oldiroute ( 1 .. $#{$ccdroutehash{$key}}){
3724 if ($ccdroutehash{$key}[$oldiroute] eq "$val") {
3725 $errormessage=$errormessage.$Lang::tr
{'ccd err irouteexist'};
3728 my ($ip1,$cidr1) = split (/\//, $val);
3729 $ip1 = &General
::getnetworkip
($ip1,&General
::iporsubtocidr
($cidr1));
3730 my ($ip2,$cidr2) = split (/\//, $ccdroutehash{$key}[$oldiroute]);
3731 if (&General
::IpInSubnet
($ip1,$ip2,$cidr2)){
3732 $errormessage=$errormessage.$Lang::tr
{'ccd err irouteexist'};
3738 if (!&General
::validipandmask
($val)){
3739 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($val)";
3742 ($ip,$cidr) = split(/\//,$val);
3743 $ip=&General
::getnetworkip
($ip,&General
::iporsubtocidr
($cidr));
3744 $cidr=&General
::iporsubtodec
($cidr);
3745 $ccdroutehash{$keypoint}[$i] = $ip."/".$cidr;
3749 #check for existing network IP's
3750 if (&General
::IpInSubnet
($ip,$Network::ethernet
{GREEN_NETADDRESS
},$Network::ethernet
{GREEN_NETMASK
}) && $Network::ethernet
{GREEN_NETADDRESS
} ne '0.0.0.0')
3752 $errormessage=$Lang::tr
{'ccd err green'};
3754 }elsif(&General
::IpInSubnet
($ip,$Network::ethernet
{RED_NETADDRESS
},$Network::ethernet
{RED_NETMASK
}) && $Network::ethernet
{RED_NETADDRESS
} ne '0.0.0.0')
3756 $errormessage=$Lang::tr
{'ccd err red'};
3758 }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 '')
3760 $errormessage=$Lang::tr
{'ccd err blue'};
3762 }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 '' )
3764 $errormessage=$Lang::tr
{'ccd err orange'};
3768 if (&General
::validipandmask
($val)){
3769 $ccdroutehash{$keypoint}[$i] = $ip."/".$cidr;
3771 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($ip/$cidr)";
3776 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3779 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3780 foreach my $key (keys %ccdroutehash) {
3781 if ($ccdroutehash{$key}[0] eq $cgiparams{'NAME'}) {
3782 delete $ccdroutehash{$key};
3783 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3789 #check route field and convert it to decimal
3792 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
3794 foreach my $key (keys %ccdroute2hash) {
3795 if ($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}) {
3797 delete $ccdroute2hash{$key};
3799 $keypoint = &General
::findhasharraykey
(\
%ccdroute2hash);
3800 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3804 $ccdroute2hash{$keypoint}[0]=$cgiparams{'NAME'};
3805 if ($cgiparams{'IFROUTE'} eq ''){$cgiparams{'IFROUTE'} = $Lang::tr
{'ccd none'};}
3806 @temp = split(/\|/,$cgiparams{'IFROUTE'});
3807 foreach $val (@temp){
3810 if ($val eq $Lang::tr
{'green'})
3812 $val=$Network::ethernet
{GREEN_NETADDRESS
}."/".$Network::ethernet
{GREEN_NETMASK
};
3814 if ($val eq $Lang::tr
{'blue'})
3816 $val=$Network::ethernet
{BLUE_NETADDRESS
}."/".$Network::ethernet
{BLUE_NETMASK
};
3818 if ($val eq $Lang::tr
{'orange'})
3820 $val=$Network::ethernet
{ORANGE_NETADDRESS
}."/".$Network::ethernet
{ORANGE_NETMASK
};
3822 my ($ip,$cidr) = split (/\//, $val);
3824 if ($val ne $Lang::tr
{'ccd none'})
3826 if (! &check_routes_push
($val)){$errormessage=$errormessage."Route $val ".$Lang::tr
{'ccd err routeovpn2'}." ($val)";goto VPNCONF_ERROR
;}
3827 if (! &check_ccdroute
($val)){$errormessage=$errormessage."<br>Route $val ".$Lang::tr
{'ccd err inuse'}." ($val)" ;goto VPNCONF_ERROR
;}
3828 if (! &check_ccdconf
($val)){$errormessage=$errormessage."<br>Route $val ".$Lang::tr
{'ccd err routeovpn'}." ($val)";goto VPNCONF_ERROR
;}
3829 if (&General
::validipandmask
($val)){
3830 $val=$ip."/".&General
::iporsubtodec
($cidr);
3831 $ccdroute2hash{$keypoint}[$i] = $val;
3833 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($val)";
3837 $ccdroute2hash{$keypoint}[$i]='';
3841 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
3844 if ($cgiparams{'CCD_DNS1'} ne '' && ! &General
::validip
($cgiparams{'CCD_DNS1'})) {
3845 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp dns'}." 1";
3849 if ($cgiparams{'CCD_DNS2'} ne '' && ! &General
::validip
($cgiparams{'CCD_DNS2'})) {
3850 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp dns'}." 2";
3854 if ($cgiparams{'CCD_WINS'} ne '' && ! &General
::validip
($cgiparams{'CCD_WINS'})) {
3855 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp wins'};
3860 if ($cgiparams{'TYPE'} !~ /^(host|net)$/) {
3861 $errormessage = $Lang::tr
{'connection type 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 ($cgiparams{'NAME'} !~ /^[a-zA-Z0-9]+$/) {
3871 $errormessage = $Lang::tr
{'name must only contain characters'};
3872 if ($cgiparams{'TYPE'} eq 'net') {
3878 if ($cgiparams{'NAME'} =~ /^(host|01|block|private|clear|packetdefault)$/) {
3879 $errormessage = $Lang::tr
{'name is invalid'};
3880 if ($cgiparams{'TYPE'} eq 'net') {
3881 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3882 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3888 if (length($cgiparams{'NAME'}) >60) {
3889 $errormessage = $Lang::tr
{'name too long'};
3890 if ($cgiparams{'TYPE'} eq 'net') {
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: $!";
3898 if ($cgiparams{'TYPE'} eq 'net') {
3899 if ($cgiparams{'DEST_PORT'} eq $vpnsettings{'DDEST_PORT'}) {
3900 $errormessage = $Lang::tr
{'openvpn destination port used'};
3901 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3902 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3906 foreach my $key (sort keys %confighash){
3907 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])){
3908 $errormessage = $Lang::tr
{'openvpn destination port used'};
3909 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3910 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3914 if ($cgiparams{'DEST_PORT'} eq '') {
3915 $errormessage = $Lang::tr
{'invalid port'};
3916 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3917 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3921 # Check if the input for the transfer net is valid.
3922 if (!&General
::validipandmask
($cgiparams{'OVPN_SUBNET'})){
3923 $errormessage = $Lang::tr
{'ccd err invalidnet'};
3924 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3925 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3929 if ($cgiparams{'OVPN_SUBNET'} eq $vpnsettings{'DOVPN_SUBNET'}) {
3930 $errormessage = $Lang::tr
{'openvpn subnet is used'};
3931 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3932 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3936 if (($cgiparams{'PROTOCOL'} eq 'tcp') && ($cgiparams{'MSSFIX'} eq 'on')) {
3937 $errormessage = $Lang::tr
{'openvpn mssfix allowed with udp'};
3938 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3939 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3943 if (($cgiparams{'PROTOCOL'} eq 'tcp') && ($cgiparams{'FRAGMENT'} ne '')) {
3944 $errormessage = $Lang::tr
{'openvpn fragment allowed with udp'};
3945 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3946 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3950 if (!&Network
::check_subnet
($cgiparams{'LOCAL_SUBNET'})) {
3951 $errormessage = $Lang::tr
{'openvpn prefix local subnet'};
3952 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3953 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3957 if (!&Network
::check_subnet
($cgiparams{'OVPN_SUBNET'})) {
3958 $errormessage = $Lang::tr
{'openvpn prefix openvpn subnet'};
3959 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3960 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3964 if (!&Network
::check_subnet
($cgiparams{'REMOTE_SUBNET'})) {
3965 $errormessage = $Lang::tr
{'openvpn prefix remote subnet'};
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: $!";
3971 if ($cgiparams{'DEST_PORT'} <= 1023) {
3972 $errormessage = $Lang::tr
{'ovpn port in root range'};
3973 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3974 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3978 if ($cgiparams{'OVPN_MGMT'} eq '') {
3979 $cgiparams{'OVPN_MGMT'} = $cgiparams{'DEST_PORT'};
3982 if ($cgiparams{'OVPN_MGMT'} <= 1023) {
3983 $errormessage = $Lang::tr
{'ovpn mgmt in root range'};
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: $!";
3988 #Check if remote subnet is used elsewhere
3989 my ($n2nip,$n2nsub)=split("/",$cgiparams{'REMOTE_SUBNET'});
3990 $warnmessage=&General
::checksubnets
('',$n2nip,'ovpn');
3992 $warnmessage=$Lang::tr
{'remote subnet'}." ($cgiparams{'REMOTE_SUBNET'}) <br>".$warnmessage;
3996 # Check if there is no other entry with this name
3997 if (! $cgiparams{'KEY'}) {
3998 foreach my $key (keys %confighash) {
3999 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
4000 $errormessage = $Lang::tr
{'a connection with this name already exists'};
4001 if ($cgiparams{'TYPE'} eq 'net') {
4002 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4003 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4010 # Check if a remote host/IP has been set for the client.
4011 if ($cgiparams{'TYPE'} eq 'net') {
4012 if ($cgiparams{'SIDE'} ne 'server' && $cgiparams{'REMOTE'} eq '') {
4013 $errormessage = $Lang::tr
{'invalid input for remote host/ip'};
4015 # Check if this is a N2N connection and drop temporary config.
4016 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4017 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4022 # Check if a remote host/IP has been configured - the field can be empty on the server side.
4023 if ($cgiparams{'REMOTE'} ne '') {
4024 # Check if the given IP is valid - otherwise check if it is a valid domain.
4025 if (! &General
::validip
($cgiparams{'REMOTE'})) {
4026 # Check for a valid domain.
4027 if (! &General
::validfqdn
($cgiparams{'REMOTE'})) {
4028 $errormessage = $Lang::tr
{'invalid input for remote host/ip'};
4030 # Check if this is a N2N connection and drop temporary config.
4031 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4032 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4040 if ($cgiparams{'TYPE'} ne 'host') {
4041 unless (&General
::validipandmask
($cgiparams{'LOCAL_SUBNET'})) {
4042 $errormessage = $Lang::tr
{'local subnet is invalid'};
4043 if ($cgiparams{'TYPE'} eq 'net') {
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: $!";
4047 goto VPNCONF_ERROR
;}
4049 # Check if there is no other entry without IP-address and PSK
4050 if ($cgiparams{'REMOTE'} eq '') {
4051 foreach my $key (keys %confighash) {
4052 if(($cgiparams{'KEY'} ne $key) &&
4053 ($confighash{$key}[4] eq 'psk' || $cgiparams{'AUTH'} eq 'psk') &&
4054 $confighash{$key}[10] eq '') {
4055 $errormessage = $Lang::tr
{'you can only define one roadwarrior connection when using pre-shared key authentication'};
4060 if (($cgiparams{'TYPE'} eq 'net') && (! &General
::validipandmask
($cgiparams{'REMOTE_SUBNET'}))) {
4061 $errormessage = $Lang::tr
{'remote subnet is invalid'};
4062 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4063 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4067 # Check for N2N that OpenSSL maximum of valid days will not be exceeded
4068 if ($cgiparams{'TYPE'} eq 'net') {
4069 if ($cgiparams{'DAYS_VALID'} >= '999999') {
4070 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4071 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4072 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4077 if ($cgiparams{'ENABLED'} !~ /^(on|off|)$/) {
4078 $errormessage = $Lang::tr
{'invalid input'};
4082 if ($cgiparams{'AUTH'} eq 'certreq') {
4083 if ($cgiparams{'KEY'}) {
4084 $errormessage = $Lang::tr
{'cant change certificates'};
4087 unless (ref ($cgiparams{'FH'})) {
4088 $errormessage = $Lang::tr
{'there was no file upload'};
4092 # Move uploaded certificate request to a temporary file
4093 (my $fh, my $filename) = tempfile
( );
4094 if (copy
($cgiparams{'FH'}, $fh) != 1) {
4099 # Sign the certificate request and move it
4100 # Sign the host certificate request
4101 # The system call is safe, because all arguments are passed as an array.
4102 system('/usr/bin/openssl', 'ca', '-days', "$cgiparams{'DAYS_VALID'}",
4103 '-batch', '-notext',
4105 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4106 '-config', "/usr/share/openvpn/ovpn.cnf");
4108 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4110 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4111 &cleanssldatabase
();
4115 &deletebackupcert
();
4118 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4121 foreach my $line (@temp) {
4122 if ($line =~ /Subject:.*CN\s?=\s?(.*)[\n]/) {
4124 $temp =~ s
+/Email
+, E
+;
4125 $temp =~ s/ ST=/ S=/;
4131 $cgiparams{'CERT_NAME'} = $temp;
4132 $cgiparams{'CERT_NAME'} =~ s/,//g;
4133 $cgiparams{'CERT_NAME'} =~ s/\'//g;
4134 if ($cgiparams{'CERT_NAME'} eq '') {
4135 $errormessage = $Lang::tr
{'could not retrieve common name from certificate'};
4138 } elsif ($cgiparams{'AUTH'} eq 'certfile') {
4139 if ($cgiparams{'KEY'}) {
4140 $errormessage = $Lang::tr
{'cant change certificates'};
4143 unless (ref ($cgiparams{'FH'})) {
4144 $errormessage = $Lang::tr
{'there was no file upload'};
4147 # Move uploaded certificate to a temporary file
4148 (my $fh, my $filename) = tempfile
( );
4149 if (copy
($cgiparams{'FH'}, $fh) != 1) {
4154 # Verify the certificate has a valid CA and move it
4156 my @test = &General
::system_output
("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/cacert.pem", "$filename");
4157 if (grep(/: OK/, @test)) {
4160 foreach my $key (keys %cahash) {
4161 @test = &General
::system_output
("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/$cahash{$key}[0]cert.pem", "$filename");
4162 if (grep(/: OK/, @test)) {
4168 $errormessage = $Lang::tr
{'certificate does not have a valid ca associated with it'};
4172 unless(move
($filename, "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem")) {
4173 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
4179 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4182 foreach my $line (@temp) {
4183 if ($line =~ /Subject:.*CN\s?=\s?(.*)[\n]/) {
4185 $temp =~ s
+/Email
+, E
+;
4186 $temp =~ s/ ST=/ S=/;
4192 $cgiparams{'CERT_NAME'} = $temp;
4193 $cgiparams{'CERT_NAME'} =~ s/,//g;
4194 $cgiparams{'CERT_NAME'} =~ s/\'//g;
4195 if ($cgiparams{'CERT_NAME'} eq '') {
4196 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4197 $errormessage = $Lang::tr
{'could not retrieve common name from certificate'};
4200 } elsif ($cgiparams{'AUTH'} eq 'certgen') {
4201 if ($cgiparams{'KEY'}) {
4202 $errormessage = $Lang::tr
{'cant change certificates'};
4205 # Validate input since the form was submitted
4206 if (length($cgiparams{'CERT_NAME'}) >60) {
4207 $errormessage = $Lang::tr
{'name too long'};
4210 if ($cgiparams{'CERT_NAME'} eq '' || $cgiparams{'CERT_NAME'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
4211 $errormessage = $Lang::tr
{'invalid input for name'};
4214 if ($cgiparams{'CERT_EMAIL'} ne '' && (! &General
::validemail
($cgiparams{'CERT_EMAIL'}))) {
4215 $errormessage = $Lang::tr
{'invalid input for e-mail address'};
4218 if (length($cgiparams{'CERT_EMAIL'}) > 40) {
4219 $errormessage = $Lang::tr
{'e-mail address too long'};
4222 if ($cgiparams{'CERT_OU'} ne '' && $cgiparams{'CERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4223 $errormessage = $Lang::tr
{'invalid input for department'};
4226 if (length($cgiparams{'CERT_ORGANIZATION'}) >60) {
4227 $errormessage = $Lang::tr
{'organization too long'};
4230 if ($cgiparams{'CERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
4231 $errormessage = $Lang::tr
{'invalid input for organization'};
4234 if ($cgiparams{'CERT_CITY'} ne '' && $cgiparams{'CERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4235 $errormessage = $Lang::tr
{'invalid input for city'};
4238 if ($cgiparams{'CERT_STATE'} ne '' && $cgiparams{'CERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4239 $errormessage = $Lang::tr
{'invalid input for state or province'};
4242 if ($cgiparams{'CERT_COUNTRY'} !~ /^[A-Z]*$/) {
4243 $errormessage = $Lang::tr
{'invalid input for country'};
4246 if ($cgiparams{'CERT_PASS1'} ne '' && $cgiparams{'CERT_PASS2'} ne ''){
4247 if (length($cgiparams{'CERT_PASS1'}) < 5) {
4248 $errormessage = $Lang::tr
{'password too short'};
4252 if ($cgiparams{'CERT_PASS1'} ne $cgiparams{'CERT_PASS2'}) {
4253 $errormessage = $Lang::tr
{'passwords do not match'};
4256 if ($cgiparams{'DAYS_VALID'} eq '' && $cgiparams{'DAYS_VALID'} !~ /^[0-9]+$/) {
4257 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4261 # Check for RW that OpenSSL maximum of valid days will not be exceeded
4262 if ($cgiparams{'TYPE'} eq 'host') {
4263 if ($cgiparams{'DAYS_VALID'} >= '999999') {
4264 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4269 # Check for RW if client name is already set
4270 if ($cgiparams{'TYPE'} eq 'host') {
4271 foreach my $key (keys %confighash) {
4272 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
4273 $errormessage = $Lang::tr
{'a connection with this name already exists'};
4279 # Check if there is no other entry with this common name
4280 if ((! $cgiparams{'KEY'}) && ($cgiparams{'AUTH'} ne 'psk')) {
4281 foreach my $key (keys %confighash) {
4282 if ($confighash{$key}[2] eq $cgiparams{'CERT_NAME'}) {
4283 $errormessage = $Lang::tr
{'a connection with this common name already exists'};
4289 # Replace empty strings with a .
4290 (my $ou = $cgiparams{'CERT_OU'}) =~ s/^\s*$/\./;
4291 (my $city = $cgiparams{'CERT_CITY'}) =~ s/^\s*$/\./;
4292 (my $state = $cgiparams{'CERT_STATE'}) =~ s/^\s*$/\./;
4294 # Create the Host certificate request client
4295 my $pid = open(OPENSSL
, "|-");
4296 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto VPNCONF_ERROR
;};
4297 if ($pid) { # parent
4298 print OPENSSL
"$cgiparams{'CERT_COUNTRY'}\n";
4299 print OPENSSL
"$state\n";
4300 print OPENSSL
"$city\n";
4301 print OPENSSL
"$cgiparams{'CERT_ORGANIZATION'}\n";
4302 print OPENSSL
"$ou\n";
4303 print OPENSSL
"$cgiparams{'CERT_NAME'}\n";
4304 print OPENSSL
"$cgiparams{'CERT_EMAIL'}\n";
4305 print OPENSSL
".\n";
4306 print OPENSSL
".\n";
4309 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4310 unlink ("${General::swroot}ovpn/certs/$cgiparams{'NAME'}key.pem");
4311 unlink ("${General::swroot}ovpn/certs/$cgiparams{'NAME'}req.pem");
4315 unless (exec ('/usr/bin/openssl', 'req', '-nodes',
4316 '-newkey', 'rsa:4096',
4317 '-keyout', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem",
4318 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem",
4319 '-config', "/usr/share/openvpn/ovpn.cnf")) {
4320 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
4321 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4322 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4327 # Sign the host certificate request
4328 # The system call is safe, because all arguments are passed as an array.
4329 system('/usr/bin/openssl', 'ca', '-days', "$cgiparams{'DAYS_VALID'}",
4330 '-batch', '-notext',
4331 '-in', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem",
4332 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4333 '-config', "/usr/share/openvpn/ovpn.cnf");
4335 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4336 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4337 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4338 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4339 &cleanssldatabase
();
4342 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4343 &deletebackupcert
();
4346 # Create the pkcs12 file
4347 # The system call is safe, because all arguments are passed as an array.
4348 system('/usr/bin/openssl', 'pkcs12', '-export',
4349 '-inkey', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem",
4350 '-in', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4351 '-name', $cgiparams{'NAME'},
4352 '-passout', "pass:$cgiparams{'CERT_PASS1'}",
4353 '-certfile', "${General::swroot}/ovpn/ca/cacert.pem",
4354 '-caname', "$vpnsettings{'ROOTCERT_ORGANIZATION'} CA",
4355 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12");
4357 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4358 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4359 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4360 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12");
4363 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4365 } elsif ($cgiparams{'AUTH'} eq 'cert') {
4366 ;# Nothing, just editing
4368 $errormessage = $Lang::tr
{'invalid input for authentication method'};
4373 my $key = $cgiparams{'KEY'};
4376 $key = &General
::findhasharraykey
(\
%confighash);
4377 foreach my $i (0 .. 43) { $confighash{$key}[$i] = "";}
4379 $confighash{$key}[0] = $cgiparams{'ENABLED'};
4380 $confighash{$key}[1] = $cgiparams{'NAME'};
4381 if ((! $cgiparams{'KEY'}) && $cgiparams{'AUTH'} ne 'psk') {
4382 $confighash{$key}[2] = $cgiparams{'CERT_NAME'};
4385 $confighash{$key}[3] = $cgiparams{'TYPE'};
4386 if ($cgiparams{'AUTH'} eq 'psk') {
4387 $confighash{$key}[4] = 'psk';
4388 $confighash{$key}[5] = $cgiparams{'PSK'};
4390 $confighash{$key}[4] = 'cert';
4392 if ($cgiparams{'TYPE'} eq 'net') {
4393 $confighash{$key}[6] = $cgiparams{'SIDE'};
4394 $confighash{$key}[11] = $cgiparams{'REMOTE_SUBNET'};
4396 $confighash{$key}[8] = $cgiparams{'LOCAL_SUBNET'};
4397 $confighash{$key}[10] = $cgiparams{'REMOTE'};
4398 if ($cgiparams{'OVPN_MGMT'} eq '') {
4399 $confighash{$key}[22] = $confighash{$key}[29];
4401 $confighash{$key}[22] = $cgiparams{'OVPN_MGMT'};
4403 $confighash{$key}[23] = $cgiparams{'MSSFIX'};
4404 $confighash{$key}[24] = $cgiparams{'FRAGMENT'};
4405 $confighash{$key}[25] = $cgiparams{'REMARK'};
4406 $confighash{$key}[26] = $cgiparams{'INTERFACE'};
4408 $confighash{$key}[27] = $cgiparams{'OVPN_SUBNET'};
4409 $confighash{$key}[28] = $cgiparams{'PROTOCOL'};
4410 $confighash{$key}[29] = $cgiparams{'DEST_PORT'};
4411 $confighash{$key}[30] = $cgiparams{'COMPLZO'};
4412 $confighash{$key}[31] = $cgiparams{'MTU'};
4413 $confighash{$key}[32] = $cgiparams{'CHECK1'};
4414 $name=$cgiparams{'CHECK1'};
4415 $confighash{$key}[33] = $cgiparams{$name};
4416 $confighash{$key}[34] = $cgiparams{'RG'};
4417 $confighash{$key}[35] = $cgiparams{'CCD_DNS1'};
4418 $confighash{$key}[36] = $cgiparams{'CCD_DNS2'};
4419 $confighash{$key}[37] = $cgiparams{'CCD_WINS'};
4420 $confighash{$key}[39] = $cgiparams{'DAUTH'};
4421 $confighash{$key}[40] = $cgiparams{'DCIPHER'};
4423 if ($confighash{$key}[41] eq "") {
4424 if (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} eq "")) {
4425 $confighash{$key}[41] = "no-pass";
4426 } elsif (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} ne "")) {
4427 $confighash{$key}[41] = "pass";
4428 } elsif ($cgiparams{'TYPE'} eq 'net') {
4429 $confighash{$key}[41] = "no-pass";
4433 $confighash{$key}[42] = 'HOTP/T30/6';
4434 $confighash{$key}[43] = $cgiparams{'OTP_STATE'};
4435 if (($confighash{$key}[43] eq 'on') && ($confighash{$key}[44] eq '')) {
4436 my @otp_secret = &General
::system_output
("/usr/bin/openssl", "rand", "-hex", "20");
4437 chomp($otp_secret[0]);
4438 $confighash{$key}[44] = $otp_secret[0];
4439 } elsif ($confighash{$key}[43] eq '') {
4440 $confighash{$key}[44] = '';
4443 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4445 # Rewrite the server configuration
4448 if ($cgiparams{'TYPE'} eq 'net') {
4450 if (-e
"/var/run/$confighash{$key}[1]n2n.pid") {
4451 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
4453 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4454 my $key = $cgiparams{'KEY'};
4456 $key = &General
::findhasharraykey
(\
%confighash);
4457 foreach my $i (0 .. 31) {
4458 $confighash{$key}[$i] = "";
4462 $confighash{$key}[0] = 'on';
4463 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4465 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "start", "$confighash{$cgiparams{'KEY'}}[1]");
4471 $cgiparams{'ENABLED'} = 'on';
4472 $cgiparams{'MSSFIX'} = 'on';
4473 $cgiparams{'FRAGMENT'} = '1300';
4474 $cgiparams{'DAUTH'} = 'SHA512';
4475 $cgiparams{'SIDE'} = 'left';
4476 if ( ! -f
"${General::swroot}/ovpn/ca/cakey.pem" ) {
4477 $cgiparams{'AUTH'} = 'psk';
4478 } elsif ( ! -f
"${General::swroot}/ovpn/ca/cacert.pem") {
4479 $cgiparams{'AUTH'} = 'certfile';
4481 $cgiparams{'AUTH'} = 'certgen';
4483 $cgiparams{'LOCAL_SUBNET'} ="$Network::ethernet{'GREEN_NETADDRESS'}/$Network::ethernet{'GREEN_NETMASK'}";
4484 $cgiparams{'CERT_ORGANIZATION'} = $vpnsettings{'ROOTCERT_ORGANIZATION'};
4485 $cgiparams{'CERT_CITY'} = $vpnsettings{'ROOTCERT_CITY'};
4486 $cgiparams{'CERT_STATE'} = $vpnsettings{'ROOTCERT_STATE'};
4487 $cgiparams{'CERT_COUNTRY'} = $vpnsettings{'ROOTCERT_COUNTRY'};
4488 $cgiparams{'DAYS_VALID'} = $vpnsettings{'DAYS_VALID'} = '730';
4492 $checked{'ENABLED'}{'off'} = '';
4493 $checked{'ENABLED'}{'on'} = '';
4494 $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = 'CHECKED';
4496 $checked{'OTP_STATE'}{$cgiparams{'OTP_STATE'}} = 'CHECKED';
4498 $selected{'SIDE'}{'server'} = '';
4499 $selected{'SIDE'}{'client'} = '';
4500 $selected{'SIDE'}{$cgiparams{'SIDE'}} = 'SELECTED';
4502 $selected{'PROTOCOL'}{'udp'} = '';
4503 $selected{'PROTOCOL'}{'tcp'} = '';
4504 $selected{'PROTOCOL'}{$cgiparams{'PROTOCOL'}} = 'SELECTED';
4507 $checked{'AUTH'}{'psk'} = '';
4508 $checked{'AUTH'}{'certreq'} = '';
4509 $checked{'AUTH'}{'certgen'} = '';
4510 $checked{'AUTH'}{'certfile'} = '';
4511 $checked{'AUTH'}{$cgiparams{'AUTH'}} = 'CHECKED';
4513 $selected{'INTERFACE'}{$cgiparams{'INTERFACE'}} = 'SELECTED';
4515 $checked{'COMPLZO'}{'off'} = '';
4516 $checked{'COMPLZO'}{'on'} = '';
4517 $checked{'COMPLZO'}{$cgiparams{'COMPLZO'}} = 'CHECKED';
4519 $checked{'MSSFIX'}{'off'} = '';
4520 $checked{'MSSFIX'}{'on'} = '';
4521 $checked{'MSSFIX'}{$cgiparams{'MSSFIX'}} = 'CHECKED';
4523 $selected{'DCIPHER'}{'AES-256-GCM'} = '';
4524 $selected{'DCIPHER'}{'AES-192-GCM'} = '';
4525 $selected{'DCIPHER'}{'AES-128-GCM'} = '';
4526 $selected{'DCIPHER'}{'CAMELLIA-256-CBC'} = '';
4527 $selected{'DCIPHER'}{'CAMELLIA-192-CBC'} = '';
4528 $selected{'DCIPHER'}{'CAMELLIA-128-CBC'} = '';
4529 $selected{'DCIPHER'}{'AES-256-CBC'} = '';
4530 $selected{'DCIPHER'}{'AES-192-CBC'} = '';
4531 $selected{'DCIPHER'}{'AES-128-CBC'} = '';
4532 $selected{'DCIPHER'}{'DESX-CBC'} = '';
4533 $selected{'DCIPHER'}{'SEED-CBC'} = '';
4534 $selected{'DCIPHER'}{'DES-EDE3-CBC'} = '';
4535 $selected{'DCIPHER'}{'DES-EDE-CBC'} = '';
4536 $selected{'DCIPHER'}{'CAST5-CBC'} = '';
4537 $selected{'DCIPHER'}{'BF-CBC'} = '';
4538 $selected{'DCIPHER'}{'DES-CBC'} = '';
4539 $selected{'DCIPHER'}{$cgiparams{'DCIPHER'}} = 'SELECTED';
4540 $selected{'DAUTH'}{'whirlpool'} = '';
4541 $selected{'DAUTH'}{'SHA512'} = '';
4542 $selected{'DAUTH'}{'SHA384'} = '';
4543 $selected{'DAUTH'}{'SHA256'} = '';
4544 $selected{'DAUTH'}{'SHA1'} = '';
4545 $selected{'DAUTH'}{$cgiparams{'DAUTH'}} = 'SELECTED';
4546 $checked{'TLSAUTH'}{'off'} = '';
4547 $checked{'TLSAUTH'}{'on'} = '';
4548 $checked{'TLSAUTH'}{$cgiparams{'TLSAUTH'}} = 'CHECKED';
4551 &Header
::showhttpheaders
();
4552 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
4553 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
4556 &Header
::errorbox
($errormessage);
4559 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'warning messages'}:");
4560 print "<class name='base'>$warnmessage";
4561 print " </class>";
4562 &Header
::closebox
();
4565 print "<form method='post' enctype='multipart/form-data'>";
4566 print "<input type='hidden' name='TYPE' value='$cgiparams{'TYPE'}' />";
4568 if ($cgiparams{'KEY'}) {
4569 print "<input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />";
4570 print "<input type='hidden' name='AUTH' value='$cgiparams{'AUTH'}' />";
4573 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'connection'}:");
4575 my $readonly = ($cgiparams{'KEY'}) ? "readonly" : "";
4578 <table class="form">
4584 <input type="text" name="NAME" value="$cgiparams{'NAME'}" $readonly/>
4590 $Lang::tr{'remark title'}
4593 <input type="text" name="REMARK" value="$cgiparams{'REMARK'}" />
4598 if ($cgiparams{'TYPE'} eq 'host') {
4602 $Lang::tr{'enabled'}
4605 <input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} />
4611 $Lang::tr{'enable otp'}
4614 <input type='checkbox' name='OTP_STATE' $checked{'OTP_STATE'}{'on'} />
4620 if ($cgiparams{'TYPE'} eq 'net') {
4621 # If GCM ciphers are in usage, HMAC menu is disabled
4623 if (($confighash{$cgiparams{'KEY'}}[40] eq 'AES-256-GCM') ||
4624 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-192-GCM') ||
4625 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-128-GCM')) {
4626 $hmacdisabled = "disabled='disabled'";
4631 <td>$Lang::tr{'Act as'}</td>
4633 <select name='SIDE'>
4634 <option value='server' $selected{'SIDE'}{'server'}>$Lang::tr{'openvpn server'}</option>
4635 <option value='client' $selected{'SIDE'}{'client'}>$Lang::tr{'openvpn client'}</option>
4641 <td>$Lang::tr{'remote host/ip'}:</td>
4643 <input type='TEXT' name='REMOTE' value='$cgiparams{'REMOTE'}' />
4648 <td>$Lang::tr{'local subnet'} <img src='/blob.gif' alt='*' /></td>
4650 <input type='TEXT' name='LOCAL_SUBNET' value='$cgiparams{'LOCAL_SUBNET'}' />
4655 <td>$Lang::tr{'remote subnet'} <img src='/blob.gif' alt='*' /></td>
4657 <input type='text' name='REMOTE_SUBNET' value='$cgiparams{'REMOTE_SUBNET'}' />
4662 <td>$Lang::tr{'ovpn subnet'} <img src='/blob.gif' alt='*' /></td>
4664 <input type='TEXT' name='OVPN_SUBNET' value='$cgiparams{'OVPN_SUBNET'}' />
4669 <td>$Lang::tr{'protocol'}</td>
4671 <select name='PROTOCOL'>
4672 <option value='udp' $selected{'PROTOCOL'}{'udp'}>UDP</option>
4673 <option value='tcp' $selected{'PROTOCOL'}{'tcp'}>TCP</option>
4679 <td>$Lang::tr{'destination port'}: <img src='/blob.gif' alt='*' /></td>
4681 <input type='TEXT' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' size='5' />
4686 <td>Management Port ($Lang::tr{'openvpn default'}: <span class="base">$Lang::tr{'destination port'}):</td>
4688 <input type='TEXT' name='OVPN_MGMT' VALUE='$cgiparams{'OVPN_MGMT'}'size='5' />
4694 $Lang::tr{'MTU settings'}
4697 <table class="form">
4699 <td>$Lang::tr{'MTU'}</td>
4701 <input type='TEXT' name='MTU' VALUE='$cgiparams{'MTU'}'size='5' />
4708 <input type='TEXT' name='FRAGMENT' VALUE='$cgiparams{'FRAGMENT'}'size='5' />
4715 <input type='checkbox' name='MSSFIX' $checked{'MSSFIX'}{'on'} />
4720 <td>$Lang::tr{'comp-lzo'}</td>
4722 <input type='checkbox' name='COMPLZO' $checked{'COMPLZO'}{'on'} />
4728 $Lang::tr{'ovpn crypto settings'}:
4731 <table class="form">
4733 <td>$Lang::tr{'cipher'}</td>
4735 <select name='DCIPHER' id="n2ncipher" required>
4736 <option value='AES-256-GCM' $selected{'DCIPHER'}{'AES-256-GCM'}>AES-GCM (256 $Lang::tr{'bit'})</option>
4737 <option value='AES-192-GCM' $selected{'DCIPHER'}{'AES-192-GCM'}>AES-GCM (192 $Lang::tr{'bit'})</option>
4738 <option value='AES-128-GCM' $selected{'DCIPHER'}{'AES-128-GCM'}>AES-GCM (128 $Lang::tr{'bit'})</option>
4739 <option value='CAMELLIA-256-CBC' $selected{'DCIPHER'}{'CAMELLIA-256-CBC'}>CAMELLIA-CBC (256 $Lang::tr{'bit'})</option>
4740 <option value='CAMELLIA-192-CBC' $selected{'DCIPHER'}{'CAMELLIA-192-CBC'}>CAMELLIA-CBC (192 $Lang::tr{'bit'})</option>
4741 <option value='CAMELLIA-128-CBC' $selected{'DCIPHER'}{'CAMELLIA-128-CBC'}>CAMELLIA-CBC (128 $Lang::tr{'bit'})</option>
4742 <option value='AES-256-CBC' $selected{'DCIPHER'}{'AES-256-CBC'}>AES-CBC (256 $Lang::tr{'bit'}, $Lang::tr{'default'})</option>
4743 <option value='AES-192-CBC' $selected{'DCIPHER'}{'AES-192-CBC'}>AES-CBC (192 $Lang::tr{'bit'})</option>
4744 <option value='AES-128-CBC' $selected{'DCIPHER'}{'AES-128-CBC'}>AES-CBC (128 $Lang::tr{'bit'})</option>
4745 <option value='SEED-CBC' $selected{'DCIPHER'}{'SEED-CBC'}>SEED-CBC (128 $Lang::tr{'bit'})</option>
4746 <option value='DES-EDE3-CBC' $selected{'DCIPHER'}{'DES-EDE3-CBC'}>DES-EDE3-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4747 <option value='DESX-CBC' $selected{'DCIPHER'}{'DESX-CBC'}>DESX-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4748 <option value='DES-EDE-CBC' $selected{'DCIPHER'}{'DES-EDE-CBC'}>DES-EDE-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4749 <option value='BF-CBC' $selected{'DCIPHER'}{'BF-CBC'}>BF-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4750 <option value='CAST5-CBC' $selected{'DCIPHER'}{'CAST5-CBC'}>CAST5-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4756 <td>$Lang::tr{'ovpn ha'}:</td>
4758 <select name='DAUTH' id="n2nhmac" $hmacdisabled>
4759 <option value='whirlpool' $selected{'DAUTH'}{'whirlpool'}>Whirlpool (512 $Lang::tr{'bit'})</option>
4760 <option value='SHA512' $selected{'DAUTH'}{'SHA512'}>SHA2 (512 $Lang::tr{'bit'})</option>
4761 <option value='SHA384' $selected{'DAUTH'}{'SHA384'}>SHA2 (384 $Lang::tr{'bit'})</option>
4762 <option value='SHA256' $selected{'DAUTH'}{'SHA256'}>SHA2 (256 $Lang::tr{'bit'})</option>
4763 <option value='SHA1' $selected{'DAUTH'}{'SHA1'}>SHA1 (160 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4771 #### JAVA SCRIPT ####
4772 # Validate N2N cipher. If GCM will be used, HMAC menu will be disabled onchange
4775 var disable_options = false;
4776 document.getElementById('n2ncipher').onchange = function () {
4777 if((this.value == "AES-256-GCM"||this.value == "AES-192-GCM"||this.value == "AES-128-GCM")) {
4778 document.getElementById('n2nhmac').setAttribute('disabled', true);
4780 document.getElementById('n2nhmac').removeAttribute('disabled');
4787 if ($cgiparams{'TYPE'} eq 'host') {
4788 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>";
4791 &General
::readhash
("${General::swroot}/ovpn/settings", \
%vpnnet);
4792 $vpnip=$vpnnet{'DOVPN_SUBNET'};
4793 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
4797 $checked{'check1'}{'off'} = '';
4798 $checked{'check1'}{'on'} = '';
4799 $checked{'check1'}{$cgiparams{'CHECK1'}} = 'CHECKED';
4800 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%'>";
4801 print"</td></tr></table><br><br>";
4802 my $name=$cgiparams{'CHECK1'};
4803 $checked{'RG'}{$cgiparams{'RG'}} = 'CHECKED';
4805 if (! -z
"${General::swroot}/ovpn/ccd.conf"){
4806 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>";
4807 foreach my $key (sort { uc($ccdconfhash{$a}[0]) cmp uc($ccdconfhash{$b}[0]) } keys %ccdconfhash) {
4809 @ccdconf=($ccdconfhash{$key}[0],$ccdconfhash{$key}[1]);
4810 if ($count % 2){print"<tr bgcolor='$Header::color{'color22'}'>";}else{print"<tr bgcolor='$Header::color{'color20'}'>";}
4811 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%'>";
4812 &fillselectbox
($ccdconf[0], $ccdconf[1], &convert_top30_ccd_allocation
($cgiparams{$name}));
4815 print "</table><br><br><hr><br><br>";
4819 &Header
::closebox
();
4820 if ($cgiparams{'KEY'} && $cgiparams{'AUTH'} eq 'psk') {
4822 } elsif (! $cgiparams{'KEY'}) {
4826 my $cakeydisabled='';
4827 my $cacrtdisabled='';
4828 if ( ! -f
"${General::swroot}/ovpn/ca/cakey.pem" ) { $cakeydisabled = "disabled='disabled'" } else { $cakeydisabled = "" };
4829 if ( ! -f
"${General::swroot}/ovpn/ca/cacert.pem" ) { $cacrtdisabled = "disabled='disabled'" } else { $cacrtdisabled = "" };
4831 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'authentication'});
4834 if ($cgiparams{'TYPE'} eq 'host') {
4837 <table width='100%' cellpadding='0' cellspacing='5' border='0'>
4839 <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>
4840 <tr><td><input type='radio' name='AUTH' value='certfile' $checked{'AUTH'}{'certfile'} $cacrtdisabled /></td><td class='base'>$Lang::tr{'upload a certificate'}</td></tr>
4841 <tr><td colspan='3'> </td></tr>
4842 <tr><td colspan='3'><hr /></td></tr>
4843 <tr><td colspan='3'> </td></tr>
4844 <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>
4845 <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>
4846 <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>
4847 <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>
4848 <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>
4849 <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>
4850 <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>
4851 <tr><td> </td><td class='base'>$Lang::tr{'country'}:</td><td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
4858 <table width='100%' cellpadding='0' cellspacing='5' border='0'>
4860 <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>
4861 <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>
4862 <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>
4863 <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>
4864 <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>
4865 <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>
4866 <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>
4867 <tr><td> </td><td class='base'>$Lang::tr{'country'}:</td><td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
4875 foreach my $country (sort keys %{Countries
::countries
}) {
4876 print "<option value='$Countries::countries{$country}'";
4877 if ( $Countries::countries
{$country} eq $cgiparams{'CERT_COUNTRY'} ) {
4878 print " selected='selected'";
4880 print ">$country</option>";
4883 if ($cgiparams{'TYPE'} eq 'host') {
4886 <td> </td><td class='base'>$Lang::tr{'valid till'} (days): <img src='/blob.gif' alt='*' /</td>
4887 <td class='base' nowrap='nowrap'><input type='text' name='DAYS_VALID' value='$cgiparams{'DAYS_VALID'}' size='32' $cakeydisabled /></td></tr>
4889 <td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
4890 <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS1' value='$cgiparams{'CERT_PASS1'}' size='32' $cakeydisabled /></td></tr>
4891 <tr><td> </td><td class='base'>$Lang::tr{'pkcs12 file password'}:<br>($Lang::tr{'confirmation'})</td>
4892 <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS2' value='$cgiparams{'CERT_PASS2'}' size='32' $cakeydisabled /></td></tr>
4893 <tr><td colspan='3'> </td></tr>
4894 <tr><td colspan='3'><hr /></td></tr>
4895 <tr><td class='base' colspan='3' align='left'><img src='/blob.gif' alt='*' /> $Lang::tr{'required field'}</td></tr>
4901 <td> </td><td class='base'>$Lang::tr{'valid till'} (days): <img src='/blob.gif' alt='*' /</td>
4902 <td class='base' nowrap='nowrap'><input type='text' name='DAYS_VALID' value='$cgiparams{'DAYS_VALID'}' size='32' $cakeydisabled /></td></tr>
4903 <tr><td> </td><td> </td><td> </td></tr>
4904 <tr><td> </td><td> </td><td> </td></tr>
4905 <tr><td colspan='3'><hr /></td></tr>
4906 <tr><td class='base' colspan='3' align='left'><img src='/blob.gif' alt='*' /> $Lang::tr{'required field'}</td></tr>
4912 &Header
::closebox
();
4916 if ($cgiparams{'TYPE'} eq 'host') {
4918 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ccd client options'}:");
4922 <table border='0' width='100%'>
4923 <tr><td width='20%'>Redirect Gateway:</td><td colspan='3'><input type='checkbox' name='RG' $checked{'RG'}{'on'} /></td></tr>
4924 <tr><td colspan='4'><b><br>$Lang::tr{'ccd routes'}</b></td></tr>
4925 <tr><td colspan='4'> </td></tr>
4926 <tr><td valign='top'>$Lang::tr{'ccd iroute'}</td><td align='left' width='30%'><textarea name='IR' cols='26' rows='6' wrap='off'>
4929 if ($cgiparams{'IR'} ne ''){
4930 print $cgiparams{'IR'};
4932 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
4933 foreach my $key (keys %ccdroutehash) {
4934 if( $cgiparams{'NAME'} eq $ccdroutehash{$key}[0]){
4935 foreach my $i (1 .. $#{$ccdroutehash{$key}}) {
4936 if ($ccdroutehash{$key}[$i] ne ''){
4937 print $ccdroutehash{$key}[$i]."\n";
4939 $cgiparams{'IR'} .= $ccdroutehash{$key}[$i];
4946 </textarea></td><td valign='top' colspan='2'></td></tr>
4947 <tr><td colspan='4'><br></td></tr>
4948 <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>
4962 open(FILE
, "${General::swroot}/main/routing") ;
4965 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
4967 foreach my $key (keys %ccdroute2hash) {
4968 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
4969 if ($ccdroute2hash{$key}[1] eq ''){
4976 print"<option>$Lang::tr{'ccd none'}</option>";
4978 print"<option selected>$Lang::tr{'ccd none'}</option>";
4980 #check if static routes are defined for client
4981 foreach my $line (@current) {
4983 $line=~s/\s*$//g; # remove newline
4984 @temp=split(/\,/,$line);
4985 $temp[1] = '' unless defined $temp[1]; # not always populated
4986 my ($a,$b) = split(/\//,$temp[1]);
4987 $temp[1] = $a."/".&General
::iporsubtocidr
($b);
4988 foreach my $key (keys %ccdroute2hash) {
4989 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
4990 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
4991 if($ccdroute2hash{$key}[$i] eq $a."/".&General
::iporsubtodec
($b)){
4997 if ($set == '1' && $#temp != -1){ print"<option selected>$temp[1]</option>";$set=0;}elsif($set == '0' && $#temp != -1){print"<option>$temp[1]</option>";}
5001 &General
::readhasharray
("${General::swroot}/vpn/config", \
%vpnconfig);
5002 foreach my $vpn (keys %vpnconfig) {
5003 # Skip all disabled VPN connections
5004 my $enabled = $vpnconfig{$vpn}[0];
5005 next unless ($enabled eq "on");
5007 my $name = $vpnconfig{$vpn}[1];
5010 my @networks = split(/\|/, $vpnconfig{$vpn}[11]);
5011 foreach my $network (@networks) {
5014 foreach my $key (keys %ccdroute2hash) {
5015 if ($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}) {
5016 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
5017 if ($ccdroute2hash{$key}[$i] eq $network) {
5018 $selected = "selected";
5024 print "<option value=\"$network\" $selected>$name ($network)</option>\n";
5028 #check if green,blue,orange are defined for client
5029 foreach my $key (keys %ccdroute2hash) {
5030 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
5032 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
5033 if ($ccdroute2hash{$key}[$i] eq $Network::ethernet
{'GREEN_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'GREEN_NETMASK'})){
5036 if (&Header
::blue_used
()){
5037 if( $ccdroute2hash{$key}[$i] eq $Network::ethernet
{'BLUE_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'BLUE_NETMASK'})) {
5041 if (&Header
::orange_used
()){
5042 if( $ccdroute2hash{$key}[$i] eq $Network::ethernet
{'ORANGE_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'ORANGE_NETMASK'}) ) {
5049 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>";}
5050 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>";}
5051 if ($selgreen == '1' || $other == '0'){ print"<option selected>$Lang::tr{'green'}</option>";$set=0;}else{print"<option>$Lang::tr{'green'}</option>";};
5054 </select></td><td valign='top'>DNS1:</td><td valign='top'><input type='TEXT' name='CCD_DNS1' value='$cgiparams{'CCD_DNS1'}' size='30' /></td></tr>
5055 <tr valign='top'><td>DNS2:</td><td><input type='TEXT' name='CCD_DNS2' value='$cgiparams{'CCD_DNS2'}' size='30' /></td></tr>
5056 <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>
5060 &Header
::closebox
();
5062 print "<div align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' />";
5063 print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
5064 &Header
::closebigbox
();
5065 &Header
::closepage
();
5073 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
5074 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
5078 # Only load status when the RW server is enabled
5079 if ($vpnsettings{'ENABLED'} eq 'on') {
5080 open(FILE
, "/usr/local/bin/openvpnctrl rw log |");
5085 $checked{'ENABLED'}{'off'} = '';
5086 $checked{'ENABLED'}{'on'} = '';
5087 $checked{'ENABLED'}{$vpnsettings{'ENABLED'}} = 'CHECKED';
5089 &Header
::showhttpheaders
();
5090 &Header
::openpage
($Lang::tr
{'status ovpn'}, 1, '');
5091 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
5093 # Show any errors and warnings
5094 &Header
::errorbox
($errormessage);
5097 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'warning messages'});
5098 print "$warnmessage<br>";
5099 print "$Lang::tr{'fwdfw warn1'}<br>";
5100 &Header
::closebox
();
5101 print"<center><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'ok'}' style='width: 5em;'></form>";
5102 &Header
::closepage
();
5106 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'ovpn roadwarrior settings'});
5108 # Show the service status
5109 &Header
::ServiceStatus
({
5110 $Lang::tr
{'ovpn roadwarrior server'} => {
5111 "process" => "openvpn",
5112 "pidfile" => "/var/run/openvpn-rw.pid",
5117 <form method='POST'>
5118 <table class="form">
5120 <td class='boldbase'>
5121 $Lang::tr{'enabled'}
5124 <input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} />
5129 <td colspan='2'></td>
5134 $Lang::tr{'ovpn fqdn'}
5137 <input type='text' name='VPN_IP' value='$vpnsettings{'VPN_IP'}' />
5143 $Lang::tr{'ovpn dynamic client subnet'}
5146 <input type='TEXT' name='DOVPN_SUBNET' value='$vpnsettings{'DOVPN_SUBNET'}' />
5152 <input type='submit' name='ACTION' value='$Lang::tr{'save'}' />
5153 <input type='submit' name='ACTION' value='$Lang::tr{'ccd net'}' />
5154 <input type='submit' name='ACTION' value='$Lang::tr{'advanced server'}' />
5161 &Header
::closebox
();
5163 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'connection status and controlc' });
5179 <th width='5%' colspan='8'>
5187 foreach my $key (sort { ncmp
($confighash{$a}[1],$confighash{$b}[1]) } keys %confighash) {
5188 my $status = $confighash{$key}[0];
5189 my $name = $confighash{$key}[1];
5190 my $type = $confighash{$key}[3];
5192 # Create some simple booleans to check the status
5194 my $expiresSoon = 0;
5196 # Fetch information about the certificate for non-N2N connections only
5197 if ($confighash{$key}[3] ne 'net') {
5198 my @cavalid = &General
::system_output
("/usr/bin/openssl", "x509", "-text",
5199 "-in", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
5203 # Parse the certificate information
5204 foreach my $line (@cavalid) {
5205 if ($line =~ /Not After : (.*)[\n]/) {
5206 $expiryDate = &Date
::Parse
::str2time
($1);
5211 # Calculate the remaining time
5212 my $remainingTime = $expiryDate - time();
5214 # Determine whether the certificate has already expired, or will so soon
5215 $hasExpired = ($remainingTime <= 0);
5216 $expiresSoon = ($remainingTime <= 30 * 24 * 3600);
5221 # Highlight the row if the certificate has expired/will expire soon
5222 if ($hasExpired || $expiresSoon) {
5223 push(@classes, "is-warning");
5227 print "<tr class='@classes'>";
5229 # Show the name of the connection
5230 print " <th scope='row'>$name";
5232 print " ($Lang::tr{'openvpn cert has expired'})";
5233 } elsif ($expiresSoon) {
5234 print " ($Lang::tr{'openvpn cert expires soon'})";
5239 print "<td class='text-center'>$Lang::tr{$type}</td>";
5242 print "<td>$confighash{$key}[25]</td>";
5244 my $connstatus = "DISCONNECTED";
5246 # Disabled Connections
5247 if ($status eq "off") {
5248 $connstatus = "DISABLED";
5251 } elsif ($type eq "net") {
5252 if (-e
"/var/run/${name}n2n.pid") {
5253 my $port = $confighash{$key}[22];
5256 $connstatus = &openvpn_status
($confighash{$key}[22]);
5261 } elsif ($type eq "host") {
5264 foreach my $line (@status) {
5267 if ($line =~ /^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/) {
5268 my @match = split(m/^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/, $line);
5270 if ($match[1] ne "Common Name") {
5274 if ($cn eq "$confighash{$key}[2]") {
5275 $connstatus = "CONNECTED";
5281 if ($connstatus eq "DISABLED") {
5282 print "<td class='status is-disabled'>$Lang::tr{'capsclosed'}</td>";
5283 } elsif ($connstatus eq "CONNECTED") {
5284 print "<td class='status is-connected'>$Lang::tr{'capsopen'}</td>";
5285 } elsif ($connstatus eq "DISCONNECTED") {
5286 print "<td class='status is-disconnected'>$Lang::tr{'capsclosed'}</td>";
5288 print "<td class='status is-unknown'>$connstatus</td>";
5291 # Download Configuration
5293 <td class="text-center">
5294 <form method='post' name='frm${key}a'>
5295 <input type='image' name='$Lang::tr{'dl client arch'}' src='/images/openvpn.png'
5296 alt='$Lang::tr{'dl client arch'}' title='$Lang::tr{'dl client arch'}' />
5297 <input type='hidden' name='ACTION' value='$Lang::tr{'dl client arch'}' />
5298 <input type='hidden' name='KEY' value='$key' />
5304 if ($confighash{$key}[4] eq 'cert') {
5306 <td class="text-center">
5307 <form method='post' name='frm${key}b'>
5308 <input type='image' name='$Lang::tr{'show certificate'}' src='/images/info.gif'
5309 alt='$Lang::tr{'show certificate'}' title='$Lang::tr{'show certificate'}' />
5310 <input type='hidden' name='ACTION' value='$Lang::tr{'show certificate'}' />
5311 <input type='hidden' name='KEY' value='$key' />
5321 if ($confighash{$key}[43] eq 'on') {
5323 <td class="text-center">
5324 <form method='post' name='frm${key}o'>
5325 <input type='image' name='$Lang::tr{'show otp qrcode'}' src='/images/qr-code.png'
5326 alt='$Lang::tr{'show otp qrcode'}' title='$Lang::tr{'show otp qrcode'}' />
5327 <input type='hidden' name='ACTION' value='$Lang::tr{'show otp qrcode'}' />
5328 <input type='hidden' name='KEY' value='$key' />
5336 # Download Certificate
5337 if ($confighash{$key}[4] eq 'cert' && -f
"${General::swroot}/ovpn/certs/$confighash{$key}[1].p12") {
5339 <td class="text-center">
5340 <form method='post' name='frm${key}c'>
5341 <input type='image' name='$Lang::tr{'download pkcs12 file'}' src='/images/media-floppy.png'
5342 alt='$Lang::tr{'download pkcs12 file'}' title='$Lang::tr{'download pkcs12 file'}' />
5343 <input type='hidden' name='ACTION' value='$Lang::tr{'download pkcs12 file'}' />
5344 <input type='hidden' name='KEY' value='$key' />
5349 } elsif ($confighash{$key}[4] eq 'cert') {
5351 <td class="text-center">
5352 <form method='post' name='frm${key}c'>
5353 <input type='image' name='$Lang::tr{'download certificate'}' src='/images/media-floppy.png'
5354 alt='$Lang::tr{'download certificate'}' title='$Lang::tr{'download certificate'}' />
5355 <input type='hidden' name='ACTION' value='$Lang::tr{'download certificate'}' />
5356 <input type='hidden' name='KEY' value='$key' />
5364 if ($status eq 'on') {
5371 <td class="text-center">
5372 <form method='post' name='frm${key}d'>
5373 <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif'
5374 alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />
5375 <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
5376 <input type='hidden' name='KEY' value='$key' />
5380 <td class="text-center">
5381 <form method='post' name='frm${key}e'>
5382 <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
5383 <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif'
5384 alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
5385 <input type='hidden' name='KEY' value='$key' />
5389 <td class="text-center">
5390 <form method='post' name='frm${key}f'>
5391 <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
5392 <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif'
5393 alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
5394 <input type='hidden' name='KEY' value='$key' />
5405 <table class="form">
5408 <form method='post'>
5409 <input type='submit' name='ACTION' value='$Lang::tr{'add'}' />
5410 <input type='submit' name='ACTION' value='$Lang::tr{'ovpn con stat'}' />
5417 &Header
::closebox
();
5420 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'certificate authorities'}");
5422 <table width='100%' cellspacing='1' cellpadding='0' class='tbl'>
5424 <th width='25%' class='boldbase' align='center'><b>$Lang::tr{'name'}</b></th>
5425 <th width='65%' class='boldbase' align='center'><b>$Lang::tr{'subject'}</b></th>
5426 <th width='10%' class='boldbase' colspan='3' align='center'><b>$Lang::tr{'action'}</b></th>
5430 my $col1="bgcolor='$Header::color{'color22'}'";
5431 my $col2="bgcolor='$Header::color{'color20'}'";
5433 my $col3="bgcolor='$Header::color{'color22'}'";
5435 my $col4="bgcolor='$Header::color{'color20'}'";
5437 if (-f
"${General::swroot}/ovpn/ca/cacert.pem") {
5438 my @casubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
5441 foreach my $line (@casubject) {
5442 if ($line =~ /Subject: (.*)[\n]/) {
5444 $casubject =~ s
+/Email
+, E
+;
5445 $casubject =~ s/ ST=/ S=/;
5453 <td class='base' $col1>$Lang::tr{'root certificate'}</td>
5454 <td class='base' $col1>$casubject</td>
5455 <form method='post' name='frmrootcrta'><td width='3%' align='center' $col1>
5456 <input type='hidden' name='ACTION' value='$Lang::tr{'show root certificate'}' />
5457 <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' />
5459 <form method='post' name='frmrootcrtb'><td width='3%' align='center' $col1>
5460 <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' />
5461 <input type='hidden' name='ACTION' value='$Lang::tr{'download root certificate'}' />
5463 <td width='4%' $col1> </td>
5468 # display rootcert generation buttons
5471 <td class='base' $col1>$Lang::tr{'root certificate'}:</td>
5472 <td class='base' $col1>$Lang::tr{'not present'}</td>
5473 <td colspan='3' $col1> </td>
5479 if (-f
"${General::swroot}/ovpn/certs/servercert.pem") {
5480 my @hostsubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
5483 foreach my $line (@hostsubject) {
5484 if ($line =~ /Subject: (.*)[\n]/) {
5486 $hostsubject =~ s
+/Email
+, E
+;
5487 $hostsubject =~ s/ ST=/ S=/;
5495 <td class='base' $col2>$Lang::tr{'host certificate'}</td>
5496 <td class='base' $col2>$hostsubject</td>
5497 <form method='post' name='frmhostcrta'><td width='3%' align='center' $col2>
5498 <input type='hidden' name='ACTION' value='$Lang::tr{'show host certificate'}' />
5499 <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' />
5501 <form method='post' name='frmhostcrtb'><td width='3%' align='center' $col2>
5502 <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' />
5503 <input type='hidden' name='ACTION' value="$Lang::tr{'download host certificate'}" />
5505 <td width='4%' $col2> </td>
5513 <td width='25%' class='base' $col2>$Lang::tr{'host certificate'}:</td>
5514 <td class='base' $col2>$Lang::tr{'not present'}</td>
5515 </td><td colspan='3' $col2> </td>
5521 # Adding ta.key to chart
5522 if (-f
"${General::swroot}/ovpn/certs/ta.key") {
5523 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
5524 my @tasubject = <FILE
>;
5528 foreach my $line (@tasubject) {
5529 if($line =~ /# (.*)[\n]/) {
5539 <td class='base' $col4>$Lang::tr{'ta key'}</td>
5540 <td class='base' $col4>$tasubject</td>
5541 <form method='post' name='frmtakey'><td width='3%' align='center' $col4>
5542 <input type='hidden' name='ACTION' value='$Lang::tr{'show tls-auth key'}' />
5543 <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' />
5545 <form method='post' name='frmtakey'><td width='3%' align='center' $col4>
5546 <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' />
5547 <input type='hidden' name='ACTION' value='$Lang::tr{'download tls-auth key'}' />
5549 <td width='4%' $col4> </td>
5557 <td width='25%' class='base' $col4>$Lang::tr{'ta key'}:</td>
5558 <td class='base' $col4>$Lang::tr{'not present'}</td>
5559 <td colspan='3' $col4> </td>
5565 if (! -f
"${General::swroot}/ovpn/ca/cacert.pem") {
5566 print "<tr><td colspan='5' align='center'><form method='post'>";
5567 print "<input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' />";
5568 print "</form></td></tr>\n";
5571 if (keys %cahash > 0) {
5572 foreach my $key (keys %cahash) {
5573 if (($key + 1) % 2) {
5574 print "<tr bgcolor='$Header::color{'color20'}'>\n";
5576 print "<tr bgcolor='$Header::color{'color22'}'>\n";
5578 print "<td class='base'>$cahash{$key}[0]</td>\n";
5579 print "<td class='base'>$cahash{$key}[1]</td>\n";
5581 <form method='post' name='cafrm${key}a'><td align='center'>
5582 <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' />
5583 <input type='hidden' name='ACTION' value='$Lang::tr{'show ca certificate'}' />
5584 <input type='hidden' name='KEY' value='$key' />
5586 <form method='post' name='cafrm${key}b'><td align='center'>
5587 <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' />
5588 <input type='hidden' name='ACTION' value='$Lang::tr{'download ca certificate'}' />
5589 <input type='hidden' name='KEY' value='$key' />
5591 <form method='post' name='cafrm${key}c'><td align='center'>
5592 <input type='hidden' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
5593 <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' />
5594 <input type='hidden' name='KEY' value='$key' />
5603 # If the file contains entries, print Key to action icons
5604 if ( -f
"${General::swroot}/ovpn/ca/cacert.pem") {
5608 <td class='boldbase'> <b>$Lang::tr{'legend'}:</b></td>
5609 <td> <img src='/images/info.gif' alt='$Lang::tr{'show certificate'}' /></td>
5610 <td class='base'>$Lang::tr{'show certificate'}</td>
5611 <td> <img src='/images/media-floppy.png' alt='$Lang::tr{'download certificate'}' /></td>
5612 <td class='base'>$Lang::tr{'download certificate'}</td>
5623 <form method='post' enctype='multipart/form-data'>
5624 <table border='0' width='100%'>
5626 <td colspan='4'><b>$Lang::tr{'upload ca certificate'}</b></td>
5630 <td width='10%'>$Lang::tr{'ca name'}:</td>
5631 <td width='30%'><input type='text' name='CA_NAME' value='$cgiparams{'CA_NAME'}' size='15' align='left'></td>
5632 <td width='30%'><input type='file' name='FH' size='25'>
5633 <td width='30%'align='right'><input type='submit' name='ACTION' value='$Lang::tr{'upload ca certificate'}'></td>
5637 <td colspan='3'> </td>
5638 <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'show crl'}' /></td>
5647 if ($vpnsettings{'ENABLED'} eq "yes") {
5648 print "<div align='center'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' disabled='disabled' /></div></form>\n";
5650 print "<div align='center'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' /></div></form>\n";
5652 &Header
::closebox
();
5656 &Header
::closepage
();