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";
245 # Enable multihoming when running in UDP mode to send reply packets
246 # from the same IP address that the client was talking to.
247 if ($vpnsettings{'DPROTOCOL'} eq 'udp') {
248 print CONF
"multihome\n";
251 print CONF
"script-security 3\n";
252 print CONF
"ifconfig-pool-persist /var/ipfire/ovpn/ovpn-leases.db 3600\n";
253 print CONF
"client-config-dir /var/ipfire/ovpn/ccd\n";
254 print CONF
"tls-server\n";
255 print CONF
"ca ${General::swroot}/ovpn/ca/cacert.pem\n";
256 print CONF
"cert ${General::swroot}/ovpn/certs/servercert.pem\n";
257 print CONF
"key ${General::swroot}/ovpn/certs/serverkey.pem\n";
258 print CONF
"dh $DHPARAM\n";
260 # Enable subnet topology
261 print CONF
"# Topology\n";
262 print CONF
"topology subnet\n\n";
264 my $netaddress = &Network
::get_netaddress
($vpnsettings{'DOVPN_SUBNET'});
265 my $subnetmask = &Network
::get_netmask
($vpnsettings{'DOVPN_SUBNET'});
267 print CONF
"server $netaddress $subnetmask\n";
268 print CONF
"tun-mtu $vpnsettings{'DMTU'}\n";
270 # Write custom routes
271 if ($vpnsettings{'ROUTES_PUSH'} ne '') {
272 my @routes = split(/\|/, $vpnsettings{'ROUTES_PUSH'});
274 foreach my $route (@routes) {
275 my $netaddr = &Network
::get_netaddress
($route);
276 my $netmask = &Network
::get_netmask
($route);
278 if (defined($netaddr) && defined($netmask)) {
279 print CONF
"push \"route ${netaddr} ${netmask}\"\n";
285 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
286 foreach my $key (keys %ccdconfhash) {
287 my $a=$ccdconfhash{$key}[1];
288 my ($b,$c) = split (/\//, $a);
289 print CONF
"route $b ".&General
::cidrtosub
($c)."\n";
292 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
293 foreach my $key (keys %ccdroutehash) {
294 foreach my $i ( 1 .. $#{$ccdroutehash{$key}}){
295 my ($a,$b)=split (/\//,$ccdroutehash{$key}[$i]);
296 print CONF
"route $a $b\n";
300 if ($vpnsettings{MSSFIX
} eq 'on') {
301 print CONF
"mssfix\n";
303 print CONF
"mssfix 0\n";
305 if ($vpnsettings{FRAGMENT
} ne '' && $vpnsettings{'DPROTOCOL'} ne 'tcp') {
306 print CONF
"fragment $vpnsettings{'FRAGMENT'}\n";
309 # Regularly send keep-alive packets
310 print CONF
"keepalive 10 60\n";
312 print CONF
"status-version 1\n";
313 print CONF
"status $RW_STATUS 30\n";
316 if ($vpnsettings{'DATACIPHERS'} ne '') {
317 print CONF
"data-ciphers " . $vpnsettings{'DATACIPHERS'} =~ s/\|/:/gr . "\n";
320 # Enable fallback cipher?
321 if ($vpnsettings{'DCIPHER'} ne '') {
322 if (&is_legacy_cipher
($vpnsettings{'DCIPHER'})) {
323 $requires_legacy_provider++;
326 print CONF
"data-ciphers-fallback $vpnsettings{'DCIPHER'}\n";
329 print CONF
"auth $vpnsettings{'DAUTH'}\n";
331 if (&is_legacy_auth
($vpnsettings{'DAUTH'})) {
332 $requires_legacy_provider++;
335 # Set TLSv2 as minimum
336 print CONF
"tls-version-min 1.2\n";
338 if ($vpnsettings{'TLSAUTH'} eq 'on') {
339 print CONF
"tls-auth ${General::swroot}/ovpn/certs/ta.key\n";
343 # Use migration to support clients that have compression enabled, but disable
344 # compression for everybody else.
345 print CONF
"compress migrate\n";
347 if ($vpnsettings{REDIRECT_GW_DEF1
} eq 'on') {
348 print CONF
"push \"redirect-gateway def1\"\n";
350 if ($vpnsettings{DHCP_DOMAIN
} ne '') {
351 print CONF
"push \"dhcp-option DOMAIN $vpnsettings{DHCP_DOMAIN}\"\n";
354 my @dns_servers = split(/\|/, $vpnsettings{'DHCP_DNS'});
357 foreach my $dns_server (@dns_servers) {
358 print CONF
"push \"dhcp-option DNS $dns_server\"\n";
361 my @wins_servers = split(/\|/, $vpnsettings{'DHCP_WINS'});
364 foreach my $wins_server (@wins_servers) {
365 print CONF
"push \"dhcp-option WINS $wins_server\"\n";
368 if ($vpnsettings{MAX_CLIENTS
} eq '') {
369 print CONF
"max-clients 100\n";
371 if ($vpnsettings{MAX_CLIENTS
} ne '') {
372 print CONF
"max-clients $vpnsettings{MAX_CLIENTS}\n";
374 print CONF
"tls-verify /usr/lib/openvpn/verify\n";
375 print CONF
"crl-verify /var/ipfire/ovpn/crls/cacrl.pem\n";
376 print CONF
"auth-user-pass-optional\n";
377 print CONF
"reneg-sec 86400\n";
378 print CONF
"user nobody\n";
379 print CONF
"group nobody\n";
380 print CONF
"persist-key\n";
381 print CONF
"persist-tun\n";
382 print CONF
"verb 3\n";
384 print CONF
"# Log clients connecting/disconnecting\n";
385 print CONF
"client-connect \"/usr/sbin/openvpn-metrics client-connect\"\n";
386 print CONF
"client-disconnect \"/usr/sbin/openvpn-metrics client-disconnect\"\n";
389 print CONF
"# Enable Management Socket\n";
390 print CONF
"management /var/run/openvpn.sock unix\n";
391 print CONF
"management-client-auth\n";
393 # Enable the legacy provider
394 if ($requires_legacy_provider > 0) {
395 print CONF
"providers legacy default\n";
398 # Send clients a message when the server is being shut down
399 print CONF
"explicit-exit-notify\n";
403 # Rewrite all CCD configurations
404 &write_ccd_configs
();
411 # Checks a ccdname for letters, numbers and spaces
412 sub validccdname
($) {
415 # name should be at least one character in length
416 # but no more than 63 characters
417 if (length ($name) < 1 || length ($name) > 63) {
421 # Only valid characters are a-z, A-Z, 0-9, space and -
422 if ($name !~ /^[a-zA-Z0-9 -]*$/) {
435 # Load all connections
436 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
438 # Check if the subnet is in use
439 foreach my $key (keys %conns) {
440 if ($conns{$key}[32] eq $name) {
441 return $Lang::tr
{'ccd err hostinnet'};
446 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
449 foreach my $key (keys %subnets) {
450 if ($subnets{$key}[0] eq $name){
451 delete $subnets{$key};
455 # Write the subnets back
456 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
458 # Update the server configuration to remove routes
462 # Returns the network with the matching name
463 sub get_cdd_network
($) {
468 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%subnets);
470 # Find the matching subnet
471 foreach my $key (keys %subnets) {
472 if ($subnets{$key}[0] eq $name) {
473 return $subnets{$key}[1];
484 my %ccdconfhash = ();
486 # Check if the name is valid
487 unless (&validccdname
($name)) {
488 return $Lang::tr
{'ccd err invalidname'};
491 # Fetch the network address & prefix
492 my $address = &Network
::get_netaddress
($network);
493 my $prefix = &Network
::get_prefix
($network);
495 # If we could not decode the subnet, it must be invalid
496 if (!defined $address || !defined $prefix) {
497 return $Lang::tr
{'ccd err invalidnet'};
499 # If the network is smaller than /30, there is no point in using it
500 } elsif ($prefix > 30) {
501 return $Lang::tr
{'ccd err invalidnet'};
504 # Read the configuration
505 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
508 my $key = &General
::findhasharraykey
(\
%ccdconfhash);
511 $ccdconfhash{$key}[0] = $name;
512 $ccdconfhash{$key}[1] = "$address/$prefix";
514 # Write the hash back
515 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
517 # Update the server configuration to add routes
529 # Check if the new name is valid
530 unless (&validccdname
($newname)) {
531 $errormessage = $Lang::tr
{'ccd err invalidname'};
536 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
538 # Check if the name already exists
539 foreach my $key (keys %ccdconfhash) {
540 if ($ccdconfhash{$key}[0] eq $newname) {
541 return $Lang::tr
{'ccd err netadrexist'};
546 foreach my $key (keys %ccdconfhash) {
547 if ($ccdconfhash{$key}[1] eq $subnet) {
548 $oldname = $ccdconfhash{$key}[0];
549 $ccdconfhash{$key}[0] = $newname;
554 # Load all configurations
555 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
557 # Update all matching connections
558 foreach my $key (keys %conns) {
559 if ($conns{$key}[32] eq $oldname) {
560 $conns{$key}[32] = $newname;
564 # Write back the configuration
565 &General
::writehasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
566 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
569 sub get_ccd_client_routes
($) {
572 my %client_routes = ();
575 # Load all client routes
576 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%client_routes);
578 foreach my $key (keys %client_routes) {
579 if ($client_routes{$key}[0] eq $name) {
580 push(@routes, @{$client_routes{$key}}[1 .. $#{$client_routes{$key}}]);
587 sub get_ccd_server_routes
($) {
590 my %server_routes = ();
593 # Load all server routes
594 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%server_routes);
596 foreach my $key (keys %server_routes) {
597 if ($server_routes{$key}[0] eq $name) {
598 push(@routes, @{$server_routes{$key}}[1 .. $#{$server_routes{$key}}]);
605 # This function rewrites all CCD configuration files upon change
606 sub write_ccd_configs
() {
609 # Load all configurations
610 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
612 foreach my $key (keys %conns) {
613 my $name = $conns{$key}[1];
614 my $type = $conns{$key}[3];
616 # Skip anything that isn't a host connection
617 next unless ($type eq "host");
619 my $filename = "${General::swroot}/ovpn/ccd/$conns{$key}[2]";
621 # Open the configuration file
622 open(CONF
, ">${filename}") or die "Unable to open ${filename} for writing: $!";
625 print CONF
"# OpenVPN Client Configuration File\n\n";
627 # Fetch the allocated IP address (if any)
628 my $pool = $conns{$key}[32];
629 my $address = $conns{$key}[33];
631 # If the client has a dynamically allocated IP address, there is nothing to do
632 if ($pool eq "dynamic") {
633 print CONF
"# This client uses the dynamic pool\n\n";
635 # Otherwise we need to push the selected IP address
637 $address = &convert_top30_ccd_allocation
($address);
639 # Fetch the network of the pool
640 my $network = &get_cdd_network
($pool);
641 my $netaddr = &Network
::get_netaddress
($network);
642 my $netmask = &Network
::get_netmask
($network);
644 # The gateway is always the first address in the network
645 # (this is needed to push any routes below)
646 my $gateway = &Network
::find_next_ip_address
($netaddr, 1);
648 if (defined $address && defined $network && defined $netmask) {
649 print CONF
"# Allocated IP address from $pool\n";
650 print CONF
"ifconfig-push ${address} ${netmask}\n";
653 # Push the first address of the static pool as the gateway.
654 # Withtout this pushed, the client will receive the first IP address
655 # of the dynamic pool which will cause problems later on:
656 # Any additional routes won't be able to reach the dynamic gateway
657 # but pushing a host route is not possible, because the OpenVPN client
658 # does not seem to understand how a layer 3 VPN works.
659 if (defined $gateway) {
660 print CONF
"push \"route-gateway ${gateway}\"\n";
663 # Add a host route for the dynamic pool gateway so that
664 # the firewall can reach the client without needing to assign
665 # the gateway IP address of the static pool to the tun interface.
666 $netaddr = &Network
::get_netaddress
($vpnsettings{'DOVPN_SUBNET'});
667 $gateway = &Network
::find_next_ip_address
($netaddr, 1);
668 if (defined $gateway) {
669 print CONF
"push \"route ${gateway} 255.255.255.255\"\n";
677 my $redirect = $conns{$key}[34];
679 if ($redirect eq "on") {
680 print CONF
"# Redirect all traffic to us\n";
681 print CONF
"push redirect-gateway\n\n";
696 print CONF
"# DHCP Options\n";
698 foreach my $option (keys %options) {
699 foreach my $address (@{ $options{$option} }) {
700 # Skip empty addresses
701 next if ($address eq "");
703 print CONF
"push \"dhcp-option $option $address\"\n";
710 # Networks routed to client
711 my @client_routes = &get_ccd_client_routes
($name);
713 if (scalar @client_routes) {
714 print CONF
"# Networks routed to the client\n";
716 foreach my $route (@client_routes) {
717 my $netaddress = &Network
::get_netaddress
($route);
718 my $netmask = &Network
::get_netmask
($route);
720 if (!defined $netaddress || !defined $netmask) {
724 print CONF
"iroute $netaddress $netmask\n";
731 # Networks routed to server
732 my @server_routes = &get_ccd_server_routes
($name);
734 if (scalar @server_routes) {
735 print CONF
"# Networks routed to the server\n";
737 foreach my $route (@server_routes) {
738 my $netaddress = &Network
::get_netaddress
($route);
739 my $netmask = &Network
::get_netmask
($route);
741 if (!defined $netaddress || !defined $netmask) {
745 print CONF
"push \"route $netaddress $netmask\"\n";
756 sub ccdmaxclients
($) {
760 my $prefix = &Network
::get_prefix
($network);
762 # Return undef on invalid input
763 if (!defined $prefix) {
767 # We take three addresses away: the network base address, the gateway, and broadcast
768 return (1 << (32 - $prefix)) - 3;
771 # Lists all selectable CCD addresses for the given network
772 sub getccdadresses
($) {
775 # Collect all available addresses
778 # Convert the network into binary
779 my ($start, $netmask) = &Network
::network2bin
($network);
781 # Fetch the broadcast address
782 my $broadcast = &Network
::get_broadcast
($network);
783 $broadcast = &Network
::ip2bin
($broadcast);
785 # Fail if we could not parse the network
786 if (!defined $start || !defined $netmask || !defined $broadcast) {
790 # Skip the base address and gateway
793 while ($start < $broadcast) {
794 push(@addresses, &Network
::bin2ip
($start++));
800 sub convert_top30_ccd_allocation
($) {
803 # Do nothing if the address does not end on /30
804 return $address unless ($address =~ m/\/30$/);
806 # Fetch the network base address
807 my $netaddress = &Network
::get_netaddress
($address);
809 # Break on invalid input
810 return undef if (!defined $netaddress);
812 # The client IP address was the second address of the subnet
813 return &Network
::find_next_ip_address
($netaddress, 2);
816 sub get_addresses_in_use
($) {
821 # Load all connections
822 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%conns);
826 # Check if the address is in use
827 foreach my $key (keys %conns) {
828 my $address = &convert_top30_ccd_allocation
($conns{$key}[33]);
830 # Skip on invalid inputs
831 next if (!defined $address);
833 # If the first address is part of the network, we have a match
834 if (&Network
::ip_address_in_network
($address, $network)) {
835 push(@addresses, $address);
842 sub fillselectbox
($$) {
845 my @selected = shift;
847 # Fetch all available addresses for this network
848 my @addresses = &getccdadresses
($network);
850 # Fetch all addresses in use
851 my @addresses_in_use = &get_addresses_in_use
($network);
853 print "<select name='$boxname'>";
855 foreach my $address (@addresses) {
856 print "<option value='$address'";
858 # Select any requested addresses
859 foreach (@selected) {
860 if ($address eq $_) {
866 # Disable any addresses that are not free
867 foreach (@addresses_in_use) {
868 if ($address eq $_) {
875 print ">$address</option>";
881 # XXX THIS WILL NO LONGER WORK
882 sub check_routes_push
885 my ($ip,$cidr) = split (/\//, $val);
886 ##check for existing routes in routes_push
887 if (-e
"${General::swroot}/ovpn/routes_push") {
888 open(FILE
,"${General::swroot}/ovpn/routes_push");
892 my ($ip2,$cidr2) = split (/\//,"$_");
893 my $val2=$ip2."/".&General
::iporsubtodec
($cidr2);
899 if (&General
::IpInSubnet
($ip,$ip2,&General
::iporsubtodec
($cidr2))){
912 my ($ip,$cidr) = split (/\//, $val);
913 #check for existing routes in ccdroute
914 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
915 foreach my $key (keys %ccdroutehash) {
916 foreach my $i (1 .. $#{$ccdroutehash{$key}}) {
917 if (&General
::iporsubtodec
($val) eq $ccdroutehash{$key}[$i] && $ccdroutehash{$key}[0] ne $cgiparams{'NAME'}){
920 my ($ip2,$cidr2) = split (/\//,$ccdroutehash{$key}[$i]);
922 if (&General
::IpInSubnet
($ip,$ip2,$cidr2)&& $ccdroutehash{$key}[0] ne $cgiparams{'NAME'} ){
933 my ($ip,$cidr) = split (/\//, $val);
934 #check for existing routes in ccdroute
935 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
936 foreach my $key (keys %ccdconfhash) {
937 if (&General
::iporsubtocidr
($val) eq $ccdconfhash{$key}[1]){
940 my ($ip2,$cidr2) = split (/\//,$ccdconfhash{$key}[1]);
942 if (&General
::IpInSubnet
($ip,$ip2,&General
::cidrtosub
($cidr2))){
950 # -------------------------------------------------------------------
952 sub read_routepushfile
($) {
955 # This is some legacy code that reads the routes file if it is still present
956 if (-e
"$routes_push_file") {
959 open(FILE
,"$routes_push_file");
966 $hash->{'ROUTES_PUSH'} = join("|", @routes);
971 # Unlink the legacy file
972 unlink($routes_push_file);
976 sub writecollectdconf
{
980 open(COLLECTDVPN
, ">${General::swroot}/ovpn/collectd.vpn") or die "Unable to open collectd.vpn: $!";
981 print COLLECTDVPN
"Loadplugin openvpn\n";
982 print COLLECTDVPN
"\n";
983 print COLLECTDVPN
"<Plugin openvpn>\n";
984 print COLLECTDVPN
"Statusfile \"${RW_STATUS}\"\n";
986 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%ccdhash);
987 foreach my $key (keys %ccdhash) {
988 if ($ccdhash{$key}[0] eq 'on' && $ccdhash{$key}[3] eq 'net') {
989 print COLLECTDVPN
"Statusfile \"/var/run/openvpn/$ccdhash{$key}[1]-n2n\"\n";
993 print COLLECTDVPN
"</Plugin>\n";
996 # Reload collectd afterwards
997 &General
::system("/usr/local/bin/collectdctrl", "restart");
1000 sub openvpn_status
($) {
1003 # Create a new Telnet session
1004 my $telnet = new Net
::Telnet
(
1007 Errmode
=> "return",
1011 $telnet->open("127.0.0.1");
1014 my @output = $telnet->cmd(
1016 Prompt
=> "/(END.*\n|ERROR:.*\n)/"
1019 my ($time, $status) = split(/\,/, $output[1]);
1022 #CONNECTING -- OpenVPN's initial state.
1023 #WAIT -- (Client only) Waiting for initial response from server.
1024 #AUTH -- (Client only) Authenticating with server.
1025 #GET_CONFIG -- (Client only) Downloading configuration options from server.
1026 #ASSIGN_IP -- Assigning IP address to virtual network interface.
1027 #ADD_ROUTES -- Adding routes to system.
1028 #CONNECTED -- Initialization Sequence Completed.
1029 #RECONNECTING -- A restart has occurred.
1030 #EXITING -- A graceful exit is in progress.
1033 if ($status eq "CONNECTING") {
1034 return "DISCONNECTED";
1035 } elsif ($status eq "WAIT") {
1036 return "DISCONNECTED";
1037 } elsif ($status eq "AUTH") {
1038 return "DISCONNECTED";
1039 } elsif ($status eq "GET_CONFIG") {
1040 return "DISCONNECTED";
1041 } elsif ($status eq "ASSIGN_IP") {
1042 return "DISCONNECTED";
1043 } elsif ($status eq "ADD_ROUTES") {
1044 return "DISCONNECTED";
1045 } elsif ($status eq "RECONNECTING") {
1047 } elsif ($status eq "EXITING") {
1048 return "DISCONNECTED";
1054 # Hook to regenerate the configuration files
1055 if ($ENV{"REMOTE_ADDR"} eq "") {
1061 ### Save Advanced options
1064 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save-adv-options'}) {
1065 $vpnsettings{'DPROTOCOL'} = $cgiparams{'DPROTOCOL'};
1066 $vpnsettings{'DDEST_PORT'} = $cgiparams{'DDEST_PORT'};
1067 $vpnsettings{'DMTU'} = $cgiparams{'DMTU'};
1068 $vpnsettings{'MAX_CLIENTS'} = $cgiparams{'MAX_CLIENTS'};
1069 $vpnsettings{'REDIRECT_GW_DEF1'} = $cgiparams{'REDIRECT_GW_DEF1'};
1070 $vpnsettings{'DHCP_DOMAIN'} = $cgiparams{'DHCP_DOMAIN'};
1071 $vpnsettings{'DHCP_DNS'} = $cgiparams{'DHCP_DNS'};
1072 $vpnsettings{'DHCP_WINS'} = $cgiparams{'DHCP_WINS'};
1073 $vpnsettings{'ROUTES_PUSH'} = $cgiparams{'ROUTES_PUSH'};
1074 $vpnsettings{'DATACIPHERS'} = $cgiparams{'DATACIPHERS'};
1075 $vpnsettings{'DCIPHER'} = $cgiparams{'DCIPHER'};
1076 $vpnsettings{'DAUTH'} = $cgiparams{'DAUTH'};
1077 $vpnsettings{'TLSAUTH'} = $cgiparams{'TLSAUTH'};
1079 # We must have at least one cipher selected
1080 if ($cgiparams{'DATACIPHERS'} eq '') {
1081 $errormessage = $Lang::tr
{'ovpn no cipher selected'};
1085 # Split data ciphers
1086 my @dataciphers = split(/\|/, $cgiparams{'DATACIPHERS'});
1088 # Check if all ciphers are supported
1089 foreach my $cipher (@dataciphers) {
1090 if (!grep(/^$cipher$/, @SUPPORTED_CIPHERS)) {
1091 $errormessage = $Lang::tr
{'ovpn unsupported cipher selected'};
1097 unless (&General
::validport
($cgiparams{'DDEST_PORT'})) {
1098 $errormessage = $Lang::tr
{'invalid port'};
1103 if (($cgiparams{'DMTU'} eq "") || (($cgiparams{'DMTU'}) < 1280 )) {
1104 $errormessage = $Lang::tr
{'invalid mtu input'};
1108 if ($cgiparams{'FRAGMENT'} eq '') {
1109 delete $vpnsettings{'FRAGMENT'};
1111 if ($cgiparams{'FRAGMENT'} !~ /^[0-9]+$/) {
1112 $errormessage = "Incorrect value, please insert only numbers.";
1115 $vpnsettings{'FRAGMENT'} = $cgiparams{'FRAGMENT'};
1119 if ($cgiparams{'MSSFIX'} ne 'on') {
1120 $vpnsettings{'MSSFIX'} = "off";
1122 $vpnsettings{'MSSFIX'} = $cgiparams{'MSSFIX'};
1125 if ($cgiparams{'DHCP_DOMAIN'} ne ''){
1126 unless (&General
::validdomainname
($cgiparams{'DHCP_DOMAIN'}) || &General
::validip
($cgiparams{'DHCP_DOMAIN'})) {
1127 $errormessage = $Lang::tr
{'invalid input for dhcp domain'};
1132 my @dns_servers = split(/[,\s]+/, $cgiparams{'DHCP_DNS'});
1134 # Check if all DNS servers are valid
1135 foreach my $dns_server (@dns_servers) {
1136 unless (&General
::validfqdn
($dns_server) || &General
::validip
($dns_server)) {
1137 $errormessage = $Lang::tr
{'invalid input for dhcp dns'} . ": ${dns_server}";
1142 # Store the DNS servers
1143 $vpnsettings{'DHCP_DNS'} = join("|", @dns_servers);
1145 my @wins_servers = split(/[,\s]+/, $cgiparams{'DHCP_WINS'});
1147 # Check if all WINS servers are valid
1148 foreach my $wins_server (@wins_servers) {
1149 unless (&General
::validfqdn
($wins_server) || &General
::validip
($wins_server)) {
1150 $errormessage = $Lang::tr
{'invalid input for dhcp wins'} . ": ${wins_server}";
1155 # Store the WINS servers
1156 $vpnsettings{'DHCP_WINS'} = join("|", @wins_servers);
1158 # Validate pushed routes
1159 if ($cgiparams{'ROUTES_PUSH'} ne ''){
1160 my @temp = split(/\n/, $cgiparams{'ROUTES_PUSH'});
1164 foreach my $route (@temp) {
1167 # Remove any excess whitespace
1168 $route =~ s/^\s+//g;
1169 $route =~ s/\s+$//g;
1172 next if ($route eq "");
1174 unless (&Network
::check_subnet
($route)) {
1175 $errormessage = "$Lang::tr{'ovpn errmsg invalid route'}: $route";
1179 push(@routes, $route);
1182 $vpnsettings{'ROUTES_PUSH'} = join("|", @routes);
1185 if ((length($cgiparams{'MAX_CLIENTS'}) == 0) || (($cgiparams{'MAX_CLIENTS'}) < 1 ) || (($cgiparams{'MAX_CLIENTS'}) > 1024 )) {
1186 $errormessage = $Lang::tr
{'invalid input for max clients'};
1190 # Store our configuration
1193 # Write the server configuration
1196 # Restart the server if it is enabled
1197 if ($vpnsettings{'ENABLED'} eq "on") {
1198 &General
::system("/usr/local/bin/openvpnctrl", "rw", "restart");
1202 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq 'net' && $cgiparams{'SIDE'} eq 'server')
1205 my @remsubnet = split(/\//,$cgiparams{'REMOTE_SUBNET'});
1206 my @ovsubnettemp = split(/\./,$cgiparams{'OVPN_SUBNET'});
1207 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
1210 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
1211 unless(-d
"${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}"){mkdir "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}", 0770 or die "Unable to create dir $!";}
1213 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: $!";
1215 flock SERVERCONF
, 2;
1216 print SERVERCONF
"# IPFire n2n Open VPN Server Config by ummeegge und m.a.d\n";
1217 print SERVERCONF
"\n";
1218 print SERVERCONF
"# User Security\n";
1219 print SERVERCONF
"user nobody\n";
1220 print SERVERCONF
"group nobody\n";
1221 print SERVERCONF
"persist-tun\n";
1222 print SERVERCONF
"persist-key\n";
1223 print SERVERCONF
"script-security 2\n";
1224 print SERVERCONF
"# IP/DNS for remote Server Gateway\n";
1226 if ($cgiparams{'REMOTE'} ne '') {
1227 print SERVERCONF
"remote $cgiparams{'REMOTE'}\n";
1230 print SERVERCONF
"float\n";
1231 print SERVERCONF
"# IP adresses of the VPN Subnet\n";
1232 print SERVERCONF
"ifconfig $ovsubnet.1 $ovsubnet.2\n";
1233 print SERVERCONF
"# Client Gateway Network\n";
1234 print SERVERCONF
"route $remsubnet[0] $remsubnet[1]\n";
1235 print SERVERCONF
"up \"/etc/init.d/static-routes start\"\n";
1236 print SERVERCONF
"# tun Device\n";
1237 print SERVERCONF
"dev tun\n";
1238 print SERVERCONF
"#Logfile for statistics\n";
1239 print SERVERCONF
"status-version 1\n";
1240 print SERVERCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
1241 print SERVERCONF
"# Port and Protokol\n";
1242 print SERVERCONF
"port $cgiparams{'DEST_PORT'}\n";
1244 if ($cgiparams{'PROTOCOL'} eq 'tcp') {
1245 print SERVERCONF
"proto tcp4-server\n";
1246 print SERVERCONF
"# Packet size\n";
1247 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1400'} else {$tunmtu = $cgiparams{'MTU'}};
1248 print SERVERCONF
"tun-mtu $tunmtu\n";
1251 if ($cgiparams{'PROTOCOL'} eq 'udp') {
1252 print SERVERCONF
"proto udp4\n";
1253 print SERVERCONF
"# Paketsize\n";
1254 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1500'} else {$tunmtu = $cgiparams{'MTU'}};
1255 print SERVERCONF
"tun-mtu $tunmtu\n";
1256 if ($cgiparams{'FRAGMENT'} ne '') {print SERVERCONF
"fragment $cgiparams{'FRAGMENT'}\n";}
1257 if ($cgiparams{'MSSFIX'} eq 'on') {print SERVERCONF
"mssfix\n"; } else { print SERVERCONF
"mssfix 0\n" };
1260 print SERVERCONF
"# Auth. Server\n";
1261 print SERVERCONF
"tls-server\n";
1262 print SERVERCONF
"ca ${General::swroot}/ovpn/ca/cacert.pem\n";
1263 print SERVERCONF
"cert ${General::swroot}/ovpn/certs/servercert.pem\n";
1264 print SERVERCONF
"key ${General::swroot}/ovpn/certs/serverkey.pem\n";
1265 print SERVERCONF
"dh $DHPARAM\n";
1266 print SERVERCONF
"# Cipher\n";
1267 print SERVERCONF
"cipher $cgiparams{'DCIPHER'}\n";
1269 # If GCM cipher is used, do not use --auth
1270 if (($cgiparams{'DCIPHER'} eq 'AES-256-GCM') ||
1271 ($cgiparams{'DCIPHER'} eq 'AES-192-GCM') ||
1272 ($cgiparams{'DCIPHER'} eq 'AES-128-GCM')) {
1273 print SERVERCONF
unless "# HMAC algorithm\n";
1274 print SERVERCONF
unless "auth $cgiparams{'DAUTH'}\n";
1276 print SERVERCONF
"# HMAC algorithm\n";
1277 print SERVERCONF
"auth $cgiparams{'DAUTH'}\n";
1280 # Set TLSv1.2 as minimum
1281 print SERVERCONF
"tls-version-min 1.2\n";
1283 if ($cgiparams{'COMPLZO'} eq 'on') {
1284 print SERVERCONF
"# Enable Compression\n";
1285 print SERVERCONF
"comp-lzo\n";
1287 print SERVERCONF
"# Debug Level\n";
1288 print SERVERCONF
"verb 3\n";
1289 print SERVERCONF
"# Tunnel check\n";
1290 print SERVERCONF
"keepalive 10 60\n";
1291 print SERVERCONF
"# Start as daemon\n";
1292 print SERVERCONF
"daemon $cgiparams{'NAME'}n2n\n";
1293 print SERVERCONF
"writepid /var/run/$cgiparams{'NAME'}n2n.pid\n";
1294 print SERVERCONF
"# Activate Management Interface and Port\n";
1295 if ($cgiparams{'OVPN_MGMT'} eq '') {print SERVERCONF
"management localhost $cgiparams{'DEST_PORT'}\n"}
1296 else {print SERVERCONF
"management localhost $cgiparams{'OVPN_MGMT'}\n"};
1301 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq 'net' && $cgiparams{'SIDE'} eq 'client')
1304 my @ovsubnettemp = split(/\./,$cgiparams{'OVPN_SUBNET'});
1305 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
1306 my @remsubnet = split(/\//,$cgiparams{'REMOTE_SUBNET'});
1309 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
1310 unless(-d
"${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}"){mkdir "${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}", 0770 or die "Unable to create dir $!";}
1312 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: $!";
1314 flock CLIENTCONF
, 2;
1315 print CLIENTCONF
"# IPFire rewritten n2n Open VPN Client Config by ummeegge und m.a.d\n";
1316 print CLIENTCONF
"#\n";
1317 print CLIENTCONF
"# User Security\n";
1318 print CLIENTCONF
"user nobody\n";
1319 print CLIENTCONF
"group nobody\n";
1320 print CLIENTCONF
"persist-tun\n";
1321 print CLIENTCONF
"persist-key\n";
1322 print CLIENTCONF
"script-security 2\n";
1323 print CLIENTCONF
"# IP/DNS for remote Server Gateway\n";
1324 print CLIENTCONF
"remote $cgiparams{'REMOTE'}\n";
1325 print CLIENTCONF
"float\n";
1326 print CLIENTCONF
"# IP adresses of the VPN Subnet\n";
1327 print CLIENTCONF
"ifconfig $ovsubnet.2 $ovsubnet.1\n";
1328 print CLIENTCONF
"# Server Gateway Network\n";
1329 print CLIENTCONF
"route $remsubnet[0] $remsubnet[1]\n";
1330 print CLIENTCONF
"up \"/etc/init.d/static-routes start\"\n";
1331 print CLIENTCONF
"# tun Device\n";
1332 print CLIENTCONF
"dev tun\n";
1333 print CLIENTCONF
"#Logfile for statistics\n";
1334 print CLIENTCONF
"status-version 1\n";
1335 print CLIENTCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
1336 print CLIENTCONF
"# Port and Protokol\n";
1337 print CLIENTCONF
"port $cgiparams{'DEST_PORT'}\n";
1339 if ($cgiparams{'PROTOCOL'} eq 'tcp') {
1340 print CLIENTCONF
"proto tcp4-client\n";
1341 print CLIENTCONF
"# Packet size\n";
1342 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1400'} else {$tunmtu = $cgiparams{'MTU'}};
1343 print CLIENTCONF
"tun-mtu $tunmtu\n";
1346 if ($cgiparams{'PROTOCOL'} eq 'udp') {
1347 print CLIENTCONF
"proto udp4\n";
1348 print CLIENTCONF
"# Paketsize\n";
1349 if ($cgiparams{'MTU'} eq '') {$tunmtu = '1500'} else {$tunmtu = $cgiparams{'MTU'}};
1350 print CLIENTCONF
"tun-mtu $tunmtu\n";
1351 if ($cgiparams{'FRAGMENT'} ne '') {print CLIENTCONF
"fragment $cgiparams{'FRAGMENT'}\n";}
1352 if ($cgiparams{'MSSFIX'} eq 'on') {print CLIENTCONF
"mssfix\n"; } else { print CLIENTCONF
"mssfix 0\n" };
1355 # Check host certificate if X509 is RFC3280 compliant.
1356 # If not, old --ns-cert-type directive will be used.
1357 # If appropriate key usage extension exists, new --remote-cert-tls directive will be used.
1358 my @hostcert = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1359 if ( ! grep(/TLS Web Server Authentication/, @hostcert)) {
1360 print CLIENTCONF
"ns-cert-type server\n";
1362 print CLIENTCONF
"remote-cert-tls server\n";
1364 print CLIENTCONF
"# Auth. Client\n";
1365 print CLIENTCONF
"tls-client\n";
1366 print CLIENTCONF
"# Cipher\n";
1367 print CLIENTCONF
"cipher $cgiparams{'DCIPHER'}\n";
1368 print CLIENTCONF
"pkcs12 ${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12\r\n";
1370 # If GCM cipher is used, do not use --auth
1371 if (($cgiparams{'DCIPHER'} eq 'AES-256-GCM') ||
1372 ($cgiparams{'DCIPHER'} eq 'AES-192-GCM') ||
1373 ($cgiparams{'DCIPHER'} eq 'AES-128-GCM')) {
1374 print CLIENTCONF
unless "# HMAC algorithm\n";
1375 print CLIENTCONF
unless "auth $cgiparams{'DAUTH'}\n";
1377 print CLIENTCONF
"# HMAC algorithm\n";
1378 print CLIENTCONF
"auth $cgiparams{'DAUTH'}\n";
1381 # Set TLSv1.2 as minimum
1382 print CLIENTCONF
"tls-version-min 1.2\n";
1384 if ($cgiparams{'COMPLZO'} eq 'on') {
1385 print CLIENTCONF
"# Enable Compression\n";
1386 print CLIENTCONF
"comp-lzo\n";
1388 print CLIENTCONF
"# Debug Level\n";
1389 print CLIENTCONF
"verb 3\n";
1390 print CLIENTCONF
"# Tunnel check\n";
1391 print CLIENTCONF
"keepalive 10 60\n";
1392 print CLIENTCONF
"# Start as daemon\n";
1393 print CLIENTCONF
"daemon $cgiparams{'NAME'}n2n\n";
1394 print CLIENTCONF
"writepid /var/run/$cgiparams{'NAME'}n2n.pid\n";
1395 print CLIENTCONF
"# Activate Management Interface and Port\n";
1396 if ($cgiparams{'OVPN_MGMT'} eq '') {print CLIENTCONF
"management localhost $cgiparams{'DEST_PORT'}\n"}
1397 else {print CLIENTCONF
"management localhost $cgiparams{'OVPN_MGMT'}\n"};
1398 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}")) {
1399 print CLIENTCONF
"providers legacy default\n";
1406 ### Save main settings
1409 if ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'TYPE'} eq '' && $cgiparams{'KEY'} eq '') {
1410 #DAN do we really need (to to check) this value? Besides if we listen on blue and orange too,
1411 #DAN this value has to leave.
1412 if ($cgiparams{'ENABLED'} eq 'on'){
1413 unless (&General
::validfqdn
($cgiparams{'VPN_IP'}) || &General
::validip
($cgiparams{'VPN_IP'})) {
1414 $errormessage = $Lang::tr
{'invalid input for hostname'};
1415 goto SETTINGS_ERROR
;
1419 if (! &General
::validipandmask
($cgiparams{'DOVPN_SUBNET'})) {
1420 $errormessage = $Lang::tr
{'ovpn subnet is invalid'};
1421 goto SETTINGS_ERROR
;
1423 my @tmpovpnsubnet = split("\/",$cgiparams{'DOVPN_SUBNET'});
1425 if (&General
::IpInSubnet
( $Network::ethernet
{'RED_ADDRESS'},
1426 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1427 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire RED Network $Network::ethernet{'RED_ADDRESS'}";
1428 goto SETTINGS_ERROR
;
1431 if (&General
::IpInSubnet
( $Network::ethernet
{'GREEN_ADDRESS'},
1432 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1433 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Green Network $Network::ethernet{'GREEN_ADDRESS'}";
1434 goto SETTINGS_ERROR
;
1437 if (&General
::IpInSubnet
( $Network::ethernet
{'BLUE_ADDRESS'},
1438 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1439 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Blue Network $Network::ethernet{'BLUE_ADDRESS'}";
1440 goto SETTINGS_ERROR
;
1443 if (&General
::IpInSubnet
( $Network::ethernet
{'ORANGE_ADDRESS'},
1444 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1445 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire Orange Network $Network::ethernet{'ORANGE_ADDRESS'}";
1446 goto SETTINGS_ERROR
;
1448 open(ALIASES
, "${General::swroot}/ethernet/aliases") or die 'Unable to open aliases file.';
1452 my @tempalias = split(/\,/,$_);
1453 if ($tempalias[1] eq 'on') {
1454 if (&General
::IpInSubnet
($tempalias[0] ,
1455 $tmpovpnsubnet[0], $tmpovpnsubnet[1])) {
1456 $errormessage = "$Lang::tr{'ovpn subnet overlap'} IPFire alias entry $tempalias[0]";
1461 if ($errormessage ne ''){
1462 goto SETTINGS_ERROR
;
1464 if ($cgiparams{'ENABLED'} !~ /^(on|off|)$/) {
1465 $errormessage = $Lang::tr
{'invalid input'};
1466 goto SETTINGS_ERROR
;
1469 # Create ta.key for tls-auth if not presant
1470 if ($cgiparams{'TLSAUTH'} eq 'on') {
1471 if ( ! -e
"${General::swroot}/ovpn/certs/ta.key") {
1472 # This system call is safe, because all arguements are passed as an array.
1473 system("/usr/sbin/openvpn", "--genkey", "secret", "${General::swroot}/ovpn/certs/ta.key");
1475 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1476 goto SETTINGS_ERROR
;
1481 $vpnsettings{'ENABLED'} = $cgiparams{'ENABLED'};
1482 $vpnsettings{'VPN_IP'} = $cgiparams{'VPN_IP'};
1483 $vpnsettings{'DOVPN_SUBNET'} = $cgiparams{'DOVPN_SUBNET'};
1485 # Store our configuration
1488 # Write the OpenVPN server configuration
1491 # Start/Stop the server
1492 if ($vpnsettings{'ENABLED'} eq "on") {
1493 &General
::system("/usr/local/bin/openvpnctrl", "rw", "restart");
1495 &General
::system("/usr/local/bin/openvpnctrl", "rw", "stop");
1500 ### Reset all step 2
1502 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove x509'} && $cgiparams{'AREUSURE'} eq 'yes') {
1504 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1506 # Stop all N2N connections
1507 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop");
1509 foreach my $key (keys %confighash) {
1510 my $name = $confighash{$cgiparams{'$key'}}[1];
1512 if ($confighash{$key}[4] eq 'cert') {
1513 delete $confighash{$cgiparams{'$key'}};
1516 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "delete", "$name");
1518 while ($file = glob("${General::swroot}/ovpn/ca/*")) {
1521 while ($file = glob("${General::swroot}/ovpn/certs/*")) {
1524 while ($file = glob("${General::swroot}/ovpn/crls/*")) {
1527 &cleanssldatabase
();
1528 if (open(FILE
, ">${General::swroot}/ovpn/caconfig")) {
1532 if (open(FILE
, ">${General::swroot}/ovpn/ccdroute")) {
1536 if (open(FILE
, ">${General::swroot}/ovpn/ccdroute2")) {
1540 while ($file = glob("${General::swroot}/ovpn/ccd/*")) {
1543 while ($file = glob("${General::swroot}/ovpn/ccd/*")) {
1546 if (open(FILE
, ">${General::swroot}/ovpn/ovpn-leases.db")) {
1550 if (open(FILE
, ">${General::swroot}/ovpn/ovpnconfig")) {
1554 while ($file = glob("${General::swroot}/ovpn/n2nconf/*")) {
1558 # Remove everything from the collectd configuration
1559 &writecollectdconf
();
1561 #&writeserverconf();
1563 ### Reset all step 1
1565 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove x509'}) {
1566 &Header
::showhttpheaders
();
1567 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1568 &Header
::openbigbox
('100%', 'left', '', '');
1569 &Header
::openbox
('100%', 'left', $Lang::tr
{'are you sure'});
1571 <form method='post'>
1572 <table width='100%'>
1575 <input type='hidden' name='AREUSURE' value='yes' />
1576 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>:
1577 $Lang::tr{'resetting the vpn configuration will remove the root ca, the host certificate and all certificate based connections'}</td>
1580 <td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' />
1581 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td>
1587 &Header
::closebox
();
1588 &Header
::closebigbox
();
1589 &Header
::closepage
();
1593 ### Upload CA Certificate
1595 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'upload ca certificate'}) {
1596 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1598 if ($cgiparams{'CA_NAME'} !~ /^[a-zA-Z0-9]+$/) {
1599 $errormessage = $Lang::tr
{'name must only contain characters'};
1600 goto UPLOADCA_ERROR
;
1603 if (length($cgiparams{'CA_NAME'}) >60) {
1604 $errormessage = $Lang::tr
{'name too long'};
1608 if ($cgiparams{'CA_NAME'} eq 'ca') {
1609 $errormessage = $Lang::tr
{'name is invalid'};
1610 goto UPLOADCA_ERROR
;
1613 # Check if there is no other entry with this name
1614 foreach my $key (keys %cahash) {
1615 if ($cahash{$key}[0] eq $cgiparams{'CA_NAME'}) {
1616 $errormessage = $Lang::tr
{'a ca certificate with this name already exists'};
1617 goto UPLOADCA_ERROR
;
1621 unless (ref ($cgiparams{'FH'})) {
1622 $errormessage = $Lang::tr
{'there was no file upload'};
1623 goto UPLOADCA_ERROR
;
1625 # Move uploaded ca to a temporary file
1626 (my $fh, my $filename) = tempfile
( );
1627 if (copy
($cgiparams{'FH'}, $fh) != 1) {
1629 goto UPLOADCA_ERROR
;
1631 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "$filename");
1632 if ( ! grep(/CA:TRUE/i, @temp )) {
1633 $errormessage = $Lang::tr
{'not a valid ca certificate'};
1635 goto UPLOADCA_ERROR
;
1637 unless(move
($filename, "${General::swroot}/ovpn/ca/$cgiparams{'CA_NAME'}cert.pem")) {
1638 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1640 goto UPLOADCA_ERROR
;
1644 my @casubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/$cgiparams{'CA_NAME'}cert.pem");
1647 foreach my $line (@casubject) {
1648 if ($line =~ /Subject: (.*)[\n]/) {
1650 $casubject =~ s
+/Email
+, E
+;
1651 $casubject =~ s/ ST=/ S=/;
1657 $casubject = &Header
::cleanhtml
($casubject);
1659 my $key = &General
::findhasharraykey
(\
%cahash);
1660 $cahash{$key}[0] = $cgiparams{'CA_NAME'};
1661 $cahash{$key}[1] = $casubject;
1662 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1667 ### Display ca certificate
1669 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show ca certificate'}) {
1670 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1672 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem") {
1673 &Header
::showhttpheaders
();
1674 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1675 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
1676 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ca certificate'}:");
1677 my @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1678 my $output = &Header
::cleanhtml
(join("", @output),"y");
1679 print "<pre>$output</pre>\n";
1680 &Header
::closebox
();
1681 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1682 &Header
::closebigbox
();
1683 &Header
::closepage
();
1686 $errormessage = $Lang::tr
{'invalid key'};
1690 ### Download ca certificate
1692 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download ca certificate'}) {
1693 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1695 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1696 print "Content-Type: application/octet-stream\r\n";
1697 print "Content-Disposition: filename=$cahash{$cgiparams{'KEY'}}[0]cert.pem\r\n\r\n";
1699 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1704 $errormessage = $Lang::tr
{'invalid key'};
1708 ### Remove ca certificate (step 2)
1710 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove ca certificate'} && $cgiparams{'AREUSURE'} eq 'yes') {
1711 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1712 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1714 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1715 foreach my $key (keys %confighash) {
1716 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");
1717 if (grep(/: OK/, @test)) {
1718 unlink ("${General::swroot}/ovpn//certs/$confighash{$key}[1]cert.pem");
1719 unlink ("${General::swroot}/ovpn/certs/$confighash{$key}[1].p12");
1720 delete $confighash{$key};
1721 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1724 unlink ("${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1725 delete $cahash{$cgiparams{'KEY'}};
1726 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1728 $errormessage = $Lang::tr
{'invalid key'};
1731 ### Remove ca certificate (step 1)
1733 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove ca certificate'}) {
1734 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
1735 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1737 my $assignedcerts = 0;
1738 if ( -f
"${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem" ) {
1739 foreach my $key (keys %confighash) {
1740 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");
1741 if (grep(/: OK/, @test)) {
1745 if ($assignedcerts) {
1746 &Header
::showhttpheaders
();
1747 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1748 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
1749 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'are you sure'});
1751 <table><form method='post'><input type='hidden' name='AREUSURE' value='yes' />
1752 <input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />
1753 <tr><td align='center'>
1754 <b><font color='${Header::colourred}'>$Lang::tr{'capswarning'}</font></b>: $assignedcerts
1755 $Lang::tr{'connections are associated with this ca. deleting the ca will delete these connections as well.'}
1756 <tr><td align='center'><input type='submit' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
1757 <input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></td></tr>
1761 &Header
::closebox
();
1762 &Header
::closebigbox
();
1763 &Header
::closepage
();
1766 unlink ("${General::swroot}/ovpn/ca/$cahash{$cgiparams{'KEY'}}[0]cert.pem");
1767 delete $cahash{$cgiparams{'KEY'}};
1768 &General
::writehasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
1771 $errormessage = $Lang::tr
{'invalid key'};
1775 ### Display root certificate
1777 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show root certificate'} ||
1778 $cgiparams{'ACTION'} eq $Lang::tr
{'show host certificate'}) {
1780 &Header
::showhttpheaders
();
1781 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
1782 &Header
::openbigbox
('100%', 'LEFT', '', '');
1783 if ($cgiparams{'ACTION'} eq $Lang::tr
{'show root certificate'}) {
1784 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'root certificate'}:");
1785 @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
1787 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'host certificate'}:");
1788 @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1790 my $output = &Header
::cleanhtml
(join("", @output), "y");
1791 print "<pre>$output</pre>\n";
1792 &Header
::closebox
();
1793 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
1794 &Header
::closebigbox
();
1795 &Header
::closepage
();
1799 ### Download root certificate
1801 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download root certificate'}) {
1802 if ( -f
"${General::swroot}/ovpn/ca/cacert.pem" ) {
1803 print "Content-Type: application/octet-stream\r\n";
1804 print "Content-Disposition: filename=cacert.pem\r\n\r\n";
1806 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
1813 ### Download host certificate
1815 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download host certificate'}) {
1816 if ( -f
"${General::swroot}/ovpn/certs/servercert.pem" ) {
1817 print "Content-Type: application/octet-stream\r\n";
1818 print "Content-Disposition: filename=servercert.pem\r\n\r\n";
1820 my @tmp = &General
::system_output
("/usr/bin/openssl", "x509", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
1827 ### Download tls-auth key
1829 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download tls-auth key'}) {
1830 if ( -f
"${General::swroot}/ovpn/certs/ta.key" ) {
1831 print "Content-Type: application/octet-stream\r\n";
1832 print "Content-Disposition: filename=ta.key\r\n\r\n";
1834 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
1844 ### Form for generating a root certificate
1846 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'generate root/host certificates'} ||
1847 $cgiparams{'ACTION'} eq $Lang::tr
{'upload p12 file'}) {
1849 if (-f
"${General::swroot}/ovpn/ca/cacert.pem") {
1850 $errormessage = $Lang::tr
{'valid root certificate already exists'};
1851 $cgiparams{'ACTION'} = '';
1852 goto ROOTCERT_ERROR
;
1855 if (($cgiparams{'ROOTCERT_HOSTNAME'} eq '') && -e
"${General::swroot}/red/active") {
1856 if (open(IPADDR
, "${General::swroot}/red/local-ipaddress")) {
1857 my $ipaddr = <IPADDR
>;
1860 $cgiparams{'ROOTCERT_HOSTNAME'} = (gethostbyaddr(pack("C4", split(/\./, $ipaddr)), 2))[0];
1861 if ($cgiparams{'ROOTCERT_HOSTNAME'} eq '') {
1862 $cgiparams{'ROOTCERT_HOSTNAME'} = $ipaddr;
1865 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'upload p12 file'}) {
1866 unless (ref ($cgiparams{'FH'})) {
1867 $errormessage = $Lang::tr
{'there was no file upload'};
1868 goto ROOTCERT_ERROR
;
1871 # Move uploaded certificate request to a temporary file
1872 (my $fh, my $filename) = tempfile
( );
1873 if (copy
($cgiparams{'FH'}, $fh) != 1) {
1875 goto ROOTCERT_ERROR
;
1878 # Create a temporary dirctory
1879 my $tempdir = tempdir
( CLEANUP
=> 1 );
1881 # Extract the CA certificate from the file
1882 my $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', '-cacerts', '-nokeys',
1897 '-out', "$tempdir/cacert.pem")) {
1898 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1900 goto ROOTCERT_ERROR
;
1904 # Extract the Host certificate 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', '-clcerts', '-nokeys',
1920 '-out', "$tempdir/hostcert.pem")) {
1921 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1923 goto ROOTCERT_ERROR
;
1927 # Extract the Host key from the file
1928 $pid = open(OPENSSL
, "|-");
1929 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
1930 if ($pid) { # parent
1931 if ($cgiparams{'P12_PASS'} ne '') {
1932 print OPENSSL
"$cgiparams{'P12_PASS'}\n";
1936 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
1938 goto ROOTCERT_ERROR
;
1941 unless (exec ('/usr/bin/openssl', 'pkcs12', '-nocerts',
1944 '-out', "$tempdir/serverkey.pem")) {
1945 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
1947 goto ROOTCERT_ERROR
;
1951 unless(move
("$tempdir/cacert.pem", "${General::swroot}/ovpn/ca/cacert.pem")) {
1952 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1954 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1955 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1956 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1957 goto ROOTCERT_ERROR
;
1960 unless(move
("$tempdir/hostcert.pem", "${General::swroot}/ovpn/certs/servercert.pem")) {
1961 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1963 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1964 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1965 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1966 goto ROOTCERT_ERROR
;
1969 unless(move
("$tempdir/serverkey.pem", "${General::swroot}/ovpn/certs/serverkey.pem")) {
1970 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
1972 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
1973 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
1974 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
1975 goto ROOTCERT_ERROR
;
1978 goto ROOTCERT_SUCCESS
;
1980 } elsif ($cgiparams{'ROOTCERT_COUNTRY'} ne '') {
1982 # Validate input since the form was submitted
1983 if ($cgiparams{'ROOTCERT_ORGANIZATION'} eq ''){
1984 $errormessage = $Lang::tr
{'organization cant be empty'};
1985 goto ROOTCERT_ERROR
;
1987 if (length($cgiparams{'ROOTCERT_ORGANIZATION'}) >60) {
1988 $errormessage = $Lang::tr
{'organization too long'};
1989 goto ROOTCERT_ERROR
;
1991 if ($cgiparams{'ROOTCERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
1992 $errormessage = $Lang::tr
{'invalid input for organization'};
1993 goto ROOTCERT_ERROR
;
1995 if ($cgiparams{'ROOTCERT_HOSTNAME'} eq ''){
1996 $errormessage = $Lang::tr
{'hostname cant be empty'};
1997 goto ROOTCERT_ERROR
;
1999 unless (&General
::validfqdn
($cgiparams{'ROOTCERT_HOSTNAME'}) || &General
::validip
($cgiparams{'ROOTCERT_HOSTNAME'})) {
2000 $errormessage = $Lang::tr
{'invalid input for hostname'};
2001 goto ROOTCERT_ERROR
;
2003 if ($cgiparams{'ROOTCERT_EMAIL'} ne '' && (! &General
::validemail
($cgiparams{'ROOTCERT_EMAIL'}))) {
2004 $errormessage = $Lang::tr
{'invalid input for e-mail address'};
2005 goto ROOTCERT_ERROR
;
2007 if (length($cgiparams{'ROOTCERT_EMAIL'}) > 40) {
2008 $errormessage = $Lang::tr
{'e-mail address too long'};
2009 goto ROOTCERT_ERROR
;
2011 if ($cgiparams{'ROOTCERT_OU'} ne '' && $cgiparams{'ROOTCERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
2012 $errormessage = $Lang::tr
{'invalid input for department'};
2013 goto ROOTCERT_ERROR
;
2015 if ($cgiparams{'ROOTCERT_CITY'} ne '' && $cgiparams{'ROOTCERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
2016 $errormessage = $Lang::tr
{'invalid input for city'};
2017 goto ROOTCERT_ERROR
;
2019 if ($cgiparams{'ROOTCERT_STATE'} ne '' && $cgiparams{'ROOTCERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
2020 $errormessage = $Lang::tr
{'invalid input for state or province'};
2021 goto ROOTCERT_ERROR
;
2023 if ($cgiparams{'ROOTCERT_COUNTRY'} !~ /^[A-Z]*$/) {
2024 $errormessage = $Lang::tr
{'invalid input for country'};
2025 goto ROOTCERT_ERROR
;
2028 # Copy the cgisettings to vpnsettings and save the configfile
2029 $vpnsettings{'ROOTCERT_ORGANIZATION'} = $cgiparams{'ROOTCERT_ORGANIZATION'};
2030 $vpnsettings{'ROOTCERT_HOSTNAME'} = $cgiparams{'ROOTCERT_HOSTNAME'};
2031 $vpnsettings{'ROOTCERT_EMAIL'} = $cgiparams{'ROOTCERT_EMAIL'};
2032 $vpnsettings{'ROOTCERT_OU'} = $cgiparams{'ROOTCERT_OU'};
2033 $vpnsettings{'ROOTCERT_CITY'} = $cgiparams{'ROOTCERT_CITY'};
2034 $vpnsettings{'ROOTCERT_STATE'} = $cgiparams{'ROOTCERT_STATE'};
2035 $vpnsettings{'ROOTCERT_COUNTRY'} = $cgiparams{'ROOTCERT_COUNTRY'};
2038 # Replace empty strings with a .
2039 (my $ou = $cgiparams{'ROOTCERT_OU'}) =~ s/^\s*$/\./;
2040 (my $city = $cgiparams{'ROOTCERT_CITY'}) =~ s/^\s*$/\./;
2041 (my $state = $cgiparams{'ROOTCERT_STATE'}) =~ s/^\s*$/\./;
2043 # Create the CA certificate
2044 my $pid = open(OPENSSL
, "|-");
2045 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
2046 if ($pid) { # parent
2047 print OPENSSL
"$cgiparams{'ROOTCERT_COUNTRY'}\n";
2048 print OPENSSL
"$state\n";
2049 print OPENSSL
"$city\n";
2050 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
2051 print OPENSSL
"$ou\n";
2052 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'} CA\n";
2053 print OPENSSL
"$cgiparams{'ROOTCERT_EMAIL'}\n";
2056 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2057 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2058 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2059 goto ROOTCERT_ERROR
;
2062 unless (exec ('/usr/bin/openssl', 'req', '-x509', '-nodes',
2063 '-days', '999999', '-newkey', 'rsa:4096', '-sha512',
2064 '-keyout', "${General::swroot}/ovpn/ca/cakey.pem",
2065 '-out', "${General::swroot}/ovpn/ca/cacert.pem",
2066 '-config', "/usr/share/openvpn/ovpn.cnf")) {
2067 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
2068 goto ROOTCERT_ERROR
;
2072 # Create the Host certificate request
2073 $pid = open(OPENSSL
, "|-");
2074 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto ROOTCERT_ERROR
;};
2075 if ($pid) { # parent
2076 print OPENSSL
"$cgiparams{'ROOTCERT_COUNTRY'}\n";
2077 print OPENSSL
"$state\n";
2078 print OPENSSL
"$city\n";
2079 print OPENSSL
"$cgiparams{'ROOTCERT_ORGANIZATION'}\n";
2080 print OPENSSL
"$ou\n";
2081 print OPENSSL
"$cgiparams{'ROOTCERT_HOSTNAME'}\n";
2082 print OPENSSL
"$cgiparams{'ROOTCERT_EMAIL'}\n";
2083 print OPENSSL
".\n";
2084 print OPENSSL
".\n";
2087 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2088 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2089 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2090 goto ROOTCERT_ERROR
;
2093 unless (exec ('/usr/bin/openssl', 'req', '-nodes',
2094 '-newkey', 'rsa:4096',
2095 '-keyout', "${General::swroot}/ovpn/certs/serverkey.pem",
2096 '-out', "${General::swroot}/ovpn/certs/serverreq.pem",
2097 '-extensions', 'server',
2098 '-config', "/usr/share/openvpn/ovpn.cnf" )) {
2099 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
2100 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2101 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2102 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2103 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2104 goto ROOTCERT_ERROR
;
2108 # Sign the host certificate request
2109 # This system call is safe, because all argeuments are passed as an array.
2110 system('/usr/bin/openssl', 'ca', '-days', '999999',
2111 '-batch', '-notext',
2112 '-in', "${General::swroot}/ovpn/certs/serverreq.pem",
2113 '-out', "${General::swroot}/ovpn/certs/servercert.pem",
2114 '-extensions', 'server',
2115 '-config', "/usr/share/openvpn/ovpn.cnf");
2117 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2118 unlink ("${General::swroot}/ovpn/ca/cakey.pem");
2119 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2120 unlink ("${General::swroot}/ovpn/serverkey.pem");
2121 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2122 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
2123 &cleanssldatabase
();
2124 goto ROOTCERT_ERROR
;
2126 unlink ("${General::swroot}/ovpn/certs/serverreq.pem");
2127 &deletebackupcert
();
2130 # Create an empty CRL
2131 # System call is safe, because all arguments are passed as array.
2132 system('/usr/bin/openssl', 'ca', '-gencrl',
2133 '-out', "${General::swroot}/ovpn/crls/cacrl.pem",
2134 '-config', "/usr/share/openvpn/ovpn.cnf" );
2136 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2137 unlink ("${General::swroot}/ovpn/certs/serverkey.pem");
2138 unlink ("${General::swroot}/ovpn/certs/servercert.pem");
2139 unlink ("${General::swroot}/ovpn/ca/cacert.pem");
2140 unlink ("${General::swroot}/ovpn/crls/cacrl.pem");
2141 &cleanssldatabase
();
2142 goto ROOTCERT_ERROR
;
2144 # &cleanssldatabase();
2146 # Create ta.key for tls-auth
2147 # This system call is safe, because all arguments are passed as an array.
2148 system('/usr/sbin/openvpn', '--genkey', 'secret', "${General::swroot}/ovpn/certs/ta.key");
2150 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
2151 &cleanssldatabase
();
2152 goto ROOTCERT_ERROR
;
2154 goto ROOTCERT_SUCCESS
;
2157 if ($cgiparams{'ACTION'} ne '') {
2158 &Header
::showhttpheaders
();
2159 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2160 &Header
::openbigbox
('100%', 'LEFT', '', '');
2163 &Header
::errorbox
($errormessage);
2165 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'generate root/host certificates'}:");
2167 <form method='post' enctype='multipart/form-data'>
2168 <table width='100%' border='0' cellspacing='1' cellpadding='0'>
2169 <tr><td width='30%' class='base'>$Lang::tr{'organization name'}: <img src='/blob.gif' alt='*' /></td>
2170 <td width='35%' class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_ORGANIZATION' value='$cgiparams{'ROOTCERT_ORGANIZATION'}' size='32' /></td>
2171 <td width='35%' colspan='2'> </td></tr>
2172 <tr><td class='base'>$Lang::tr{'ipfires hostname'}: <img src='/blob.gif' alt='*' /></td>
2173 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_HOSTNAME' value='$cgiparams{'ROOTCERT_HOSTNAME'}' size='32' /></td>
2174 <td colspan='2'> </td></tr>
2175 <tr><td class='base'>$Lang::tr{'your e-mail'}:</td>
2176 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_EMAIL' value='$cgiparams{'ROOTCERT_EMAIL'}' size='32' /></td>
2177 <td colspan='2'> </td></tr>
2178 <tr><td class='base'>$Lang::tr{'your department'}:</td>
2179 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_OU' value='$cgiparams{'ROOTCERT_OU'}' size='32' /></td>
2180 <td colspan='2'> </td></tr>
2181 <tr><td class='base'>$Lang::tr{'city'}:</td>
2182 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_CITY' value='$cgiparams{'ROOTCERT_CITY'}' size='32' /></td>
2183 <td colspan='2'> </td></tr>
2184 <tr><td class='base'>$Lang::tr{'state or province'}:</td>
2185 <td class='base' nowrap='nowrap'><input type='text' name='ROOTCERT_STATE' value='$cgiparams{'ROOTCERT_STATE'}' size='32' /></td>
2186 <td colspan='2'> </td></tr>
2187 <tr><td class='base'>$Lang::tr{'country'}:</td>
2188 <td class='base'><select name='ROOTCERT_COUNTRY'>
2192 foreach my $country (sort keys %{Countries
::countries
}) {
2193 print "<option value='$Countries::countries{$country}'";
2194 if ( $Countries::countries
{$country} eq $cgiparams{'ROOTCERT_COUNTRY'} ) {
2195 print " selected='selected'";
2197 print ">$country</option>";
2203 <td><input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' /></td>
2204 <td> </td><td> </td></tr>
2205 <tr><td class='base' colspan='4' align='left'>
2206 <img src='/blob.gif' valign='top' alt='*' /> $Lang::tr{'required field'}</td></tr>
2207 <tr><td colspan='2'><br></td></tr>
2210 <table width='100%'>
2211 <tr><td colspan='4'><hr></td></tr>
2212 <tr><td class='base' nowrap='nowrap'>$Lang::tr{'upload p12 file'}: <img src='/blob.gif' alt='*' /></td>
2213 <td nowrap='nowrap'><input type='file' name='FH' size='32'></td>
2214 <td colspan='2'> </td></tr>
2215 <tr><td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
2216 <td class='base' nowrap='nowrap'><input type='password' name='P12_PASS' value='$cgiparams{'P12_PASS'}' size='32' /></td>
2217 <td colspan='2'> </td></tr>
2219 <td><input type='submit' name='ACTION' value='$Lang::tr{'upload p12 file'}' /></td>
2220 <td colspan='2'> </td></tr>
2221 <tr><td class='base' colspan='4' align='left'>
2222 <img src='/blob.gif' valign='top' alt='*' > $Lang::tr{'required field'}</td>
2227 &Header
::closebox
();
2228 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2229 &Header
::closebigbox
();
2230 &Header
::closepage
();
2235 &General
::system("chmod", "600", "${General::swroot}/ovpn/certs/serverkey.pem");
2238 ### Enable/Disable connection
2241 }elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'toggle enable disable'}) {
2242 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2244 my @ps = &General
::system_output
("/bin/ps", "ax");
2246 if(grep(/$confighash{$cgiparams{'KEY'}}[1]/, @ps)) {
2250 if ($confighash{$cgiparams{'KEY'}}) {
2251 if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
2252 $confighash{$cgiparams{'KEY'}}[0] = 'on';
2253 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2255 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2256 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "start", "$confighash{$cgiparams{'KEY'}}[1]");
2257 &writecollectdconf
();
2261 $confighash{$cgiparams{'KEY'}}[0] = 'off';
2262 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2264 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2265 if ($n2nactive ne '') {
2266 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
2267 &writecollectdconf
();
2274 ### Download OpenVPN client package
2277 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'dl client arch'}) {
2278 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2280 my $clientovpn = '';
2282 my $tempdir = tempdir
( CLEANUP
=> 1 );
2283 my $zippath = "$tempdir/";
2286 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net'){
2287 my $zipname = "$confighash{$cgiparams{'KEY'}}[1]-Client.zip";
2288 my $zippathname = "$zippath$zipname";
2289 $clientovpn = "$confighash{$cgiparams{'KEY'}}[1].conf";
2290 my @ovsubnettemp = split(/\./,$confighash{$cgiparams{'KEY'}}[27]);
2291 my $ovsubnet = "$ovsubnettemp[0].$ovsubnettemp[1].$ovsubnettemp[2]";
2293 my @remsubnet = split(/\//,$confighash{$cgiparams{'KEY'}}[8]);
2294 my $n2nfragment = '';
2296 open(CLIENTCONF
, ">$tempdir/$clientovpn") or die "Unable to open tempfile: $!";
2297 flock CLIENTCONF
, 2;
2299 my $zip = Archive
::Zip-
>new();
2300 print CLIENTCONF
"# IPFire n2n Open VPN Client Config by ummeegge und m.a.d\n";
2301 print CLIENTCONF
"# \n";
2302 print CLIENTCONF
"# User Security\n";
2303 print CLIENTCONF
"user nobody\n";
2304 print CLIENTCONF
"group nobody\n";
2305 print CLIENTCONF
"persist-tun\n";
2306 print CLIENTCONF
"persist-key\n";
2307 print CLIENTCONF
"script-security 2\n";
2308 print CLIENTCONF
"# IP/DNS for remote Server Gateway\n";
2309 print CLIENTCONF
"remote $vpnsettings{'VPN_IP'}\n";
2310 print CLIENTCONF
"float\n";
2311 print CLIENTCONF
"# IP adresses of the VPN Subnet\n";
2312 print CLIENTCONF
"ifconfig $ovsubnet.2 $ovsubnet.1\n";
2313 print CLIENTCONF
"# Server Gateway Network\n";
2314 print CLIENTCONF
"route $remsubnet[0] $remsubnet[1]\n";
2315 print CLIENTCONF
"# tun Device\n";
2316 print CLIENTCONF
"dev tun\n";
2317 print CLIENTCONF
"#Logfile for statistics\n";
2318 print CLIENTCONF
"status-version 1\n";
2319 print CLIENTCONF
"status /var/run/openvpn/$cgiparams{'NAME'}-n2n 10\n";
2320 print CLIENTCONF
"# Port and Protokoll\n";
2321 print CLIENTCONF
"port $confighash{$cgiparams{'KEY'}}[29]\n";
2323 if ($confighash{$cgiparams{'KEY'}}[28] eq 'tcp') {
2324 print CLIENTCONF
"proto tcp4-client\n";
2325 print CLIENTCONF
"# Packet size\n";
2326 if ($confighash{$cgiparams{'KEY'}}[31] eq '') {
2329 $tunmtu = $confighash{$cgiparams{'KEY'}}[31];
2331 print CLIENTCONF
"tun-mtu $tunmtu\n";
2334 if ($confighash{$cgiparams{'KEY'}}[28] eq 'udp') {
2335 print CLIENTCONF
"proto udp4\n";
2336 print CLIENTCONF
"# Paketsize\n";
2337 if ($confighash{$cgiparams{'KEY'}}[31] eq '') {
2340 $tunmtu = $confighash{$cgiparams{'KEY'}}[31];
2342 print CLIENTCONF
"tun-mtu $tunmtu\n";
2343 if ($confighash{$cgiparams{'KEY'}}[24] ne '') {
2344 print CLIENTCONF
"fragment $confighash{$cgiparams{'KEY'}}[24]\n";
2346 if ($confighash{$cgiparams{'KEY'}}[23] eq 'on') {
2347 print CLIENTCONF
"mssfix\n";
2349 print CLIENTCONF
"mssfix 0\n";
2353 # Check host certificate if X509 is RFC3280 compliant.
2354 # If not, old --ns-cert-type directive will be used.
2355 # If appropriate key usage extension exists, new --remote-cert-tls directive will be used.
2356 my @hostcert = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
2357 if (! grep(/TLS Web Server Authentication/, @hostcert)) {
2358 print CLIENTCONF
"ns-cert-type server\n";
2360 print CLIENTCONF
"remote-cert-tls server\n";
2362 print CLIENTCONF
"# Auth. Client\n";
2363 print CLIENTCONF
"tls-client\n";
2364 print CLIENTCONF
"# Cipher\n";
2365 print CLIENTCONF
"cipher $confighash{$cgiparams{'KEY'}}[40]\n";
2367 if ($confighash{$cgiparams{'KEY'}}[4] eq 'cert' && -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12") {
2368 print CLIENTCONF
"pkcs12 ${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12\r\n";
2369 $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";
2372 # If GCM cipher is used, do not use --auth
2373 if (($confighash{$cgiparams{'KEY'}}[40] eq 'AES-256-GCM') ||
2374 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-192-GCM') ||
2375 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-128-GCM')) {
2376 print CLIENTCONF
unless "# HMAC algorithm\n";
2377 print CLIENTCONF
unless "auth $confighash{$cgiparams{'KEY'}}[39]\n";
2379 print CLIENTCONF
"# HMAC algorithm\n";
2380 print CLIENTCONF
"auth $confighash{$cgiparams{'KEY'}}[39]\n";
2383 if ($confighash{$cgiparams{'KEY'}}[30] eq 'on') {
2384 print CLIENTCONF
"# Enable Compression\n";
2385 print CLIENTCONF
"comp-lzo\n";
2387 print CLIENTCONF
"# Debug Level\n";
2388 print CLIENTCONF
"verb 3\n";
2389 print CLIENTCONF
"# Tunnel check\n";
2390 print CLIENTCONF
"keepalive 10 60\n";
2391 print CLIENTCONF
"# Start as daemon\n";
2392 print CLIENTCONF
"daemon $confighash{$cgiparams{'KEY'}}[1]n2n\n";
2393 print CLIENTCONF
"writepid /var/run/$confighash{$cgiparams{'KEY'}}[1]n2n.pid\n";
2394 print CLIENTCONF
"# Activate Management Interface and Port\n";
2395 if ($confighash{$cgiparams{'KEY'}}[22] eq '') {
2396 print CLIENTCONF
"management localhost $confighash{$cgiparams{'KEY'}}[29]\n"
2398 print CLIENTCONF
"management localhost $confighash{$cgiparams{'KEY'}}[22]\n"
2400 print CLIENTCONF
"# remsub $confighash{$cgiparams{'KEY'}}[11]\n";
2401 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
2402 print CLIENTCONF
"providers legacy default\n";
2406 $zip->addFile( "$tempdir/$clientovpn", $clientovpn) or die "Can't add file $clientovpn\n";
2407 my $status = $zip->writeToFileNamed($zippathname);
2409 open(DLFILE
, "<$zippathname") or die "Unable to open $zippathname: $!";
2410 @fileholder = <DLFILE
>;
2411 print "Content-Type:application/x-download\n";
2412 print "Content-Disposition:attachment;filename=$zipname\n\n";
2417 my $name = $confighash{$cgiparams{'KEY'}}[1];
2420 &Header
::showhttpheaders
({
2421 "Content-Type" => "application/x-openvpn-profile",
2422 "Content-Disposition" => "attachment; filename=${name}.ovpn",
2425 print "########################################################################\n";
2426 print "# IPFire OpenVPN Client Configuration for \"${name}\"\n";
2427 print "########################################################################\n";
2432 # This is a layer 3 VPN
2435 # Point the client to this server
2436 print "remote $vpnsettings{'VPN_IP'} $vpnsettings{'DDEST_PORT'}\n";
2437 print "proto $vpnsettings{'DPROTOCOL'}\n";
2439 # Configure the MTU of the tunnel interface
2440 print "tun-mtu $vpnsettings{'DMTU'}\n";
2442 # Ask the client to verify the server certificate
2443 if (&is_cert_rfc3280_compliant
("${General::swroot}/ovpn/certs/servercert.pem")) {
2444 print "remote-cert-tls server\n";
2446 print "verify-x509-name $vpnsettings{'ROOTCERT_HOSTNAME'} name\n";
2448 if ($vpnsettings{'MSSFIX'} eq 'on') {
2453 if ($vpnsettings{'FRAGMENT'} ne '' && $vpnsettings{'DPROTOCOL'} ne 'tcp' ) {
2454 print "fragment $vpnsettings{'FRAGMENT'}\n";
2457 # We no longer send any cryptographic configuration since 2.6.
2458 # That way, we will be able to push this from the server.
2459 # Therefore we always mandate NCP for new clients.
2461 if ($vpnsettings{'DAUTH'} ne "") {
2462 print "auth $vpnsettings{'DAUTH'}\n";
2465 # Set a fake user name for authentication
2466 print "auth-user-pass\n";
2467 print "auth-token-user USER\n";
2468 print "auth-token TOTP\n";
2470 # If the server is asking for TOTP this needs to happen interactively
2471 print "auth-retry interact\n";
2473 # Add provider line if certificate is legacy type
2474 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]")) {
2475 print "providers legacy default\n";
2479 open(FILE
, "<${General::swroot}/ovpn/ca/cacert.pem");
2489 open(FILE
, "<${General::swroot}/ovpn/certs/${name}.p12");
2490 print "\n<pkcs12>\n";
2491 print &MIME
::Base64
::encode_base64
(do { local $/; <FILE
> });
2492 print "</pkcs12>\n";
2496 if ($vpnsettings{'TLSAUTH'} eq 'on') {
2497 open(FILE
, "<${General::swroot}/ovpn/certs/ta.key");
2498 print "\n<tls-auth>\n";
2503 print "</tls-auth>\n";
2510 ### Remove connection
2514 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'remove'}) {
2515 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2517 if ($confighash{$cgiparams{'KEY'}}) {
2518 # Revoke certificate if certificate was deleted and rewrite the CRL
2519 &General
::system("/usr/bin/openssl", "ca", "-revoke", "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2520 &General
::system("/usr/bin/openssl", "ca", "-gencrl", "-out", "${General::swroot}/ovpn/crls/cacrl.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2522 if ($confighash{$cgiparams{'KEY'}}[3] eq 'net') {
2523 # Stop the N2N connection before it is removed
2524 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
2526 my $conffile = glob("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]/$confighash{$cgiparams{'KEY'}}[1].conf");
2527 my $certfile = glob("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2531 if (-e
"${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") {
2532 rmdir ("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") || die "Kann Verzeichnis nicht loeschen: $!";
2536 unlink ("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
2537 unlink ("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2539 # Delete CCD files and routes
2541 if (-f
"${General::swroot}/ovpn/ccd/$confighash{$cgiparams{'KEY'}}[2]")
2543 unlink "${General::swroot}/ovpn/ccd/$confighash{$cgiparams{'KEY'}}[2]";
2546 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
2547 foreach my $key (keys %ccdroutehash) {
2548 if ($ccdroutehash{$key}[0] eq $confighash{$cgiparams{'KEY'}}[1]){
2549 delete $ccdroutehash{$key};
2552 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
2554 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
2555 foreach my $key (keys %ccdroute2hash) {
2556 if ($ccdroute2hash{$key}[0] eq $confighash{$cgiparams{'KEY'}}[1]){
2557 delete $ccdroute2hash{$key};
2560 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
2563 # Update collectd configuration and delete all RRD files of the removed connection
2564 &writecollectdconf
();
2565 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "delete", "$confighash{$cgiparams{'KEY'}}[1]");
2567 delete $confighash{$cgiparams{'KEY'}};
2568 &General
::system("/usr/bin/openssl", "ca", "-gencrl", "-out", "${General::swroot}/ovpn/crls/cacrl.pem", "-config", "/usr/share/openvpn/ovpn.cnf");
2569 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2572 $errormessage = $Lang::tr
{'invalid key'};
2574 &General
::firewall_reload
();
2577 ### Download PKCS12 file
2579 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download pkcs12 file'}) {
2580 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2582 print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . ".p12\r\n";
2583 print "Content-Type: application/octet-stream\r\n\r\n";
2585 open(FILE
, "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
2593 ### Display certificate
2595 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show certificate'}) {
2596 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2598 if ( -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
2599 &Header
::showhttpheaders
();
2600 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2601 &Header
::openbigbox
('100%', 'LEFT', '', '');
2602 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'certificate'}:");
2603 my @output = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
2604 my $output = &Header
::cleanhtml
(join("", @output), "y");
2605 print "<pre>$output</pre>\n";
2606 &Header
::closebox
();
2607 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2608 &Header
::closebigbox
();
2609 &Header
::closepage
();
2614 ### Display OTP QRCode
2616 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show otp qrcode'}) {
2617 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
2619 my $qrcode = Imager
::QRCode-
>new(
2626 lightcolor
=> Imager
::Color-
>new(255, 255, 255),
2627 darkcolor
=> Imager
::Color-
>new(0, 0, 0),
2629 my $cn = uri_encode
($confighash{$cgiparams{'KEY'}}[2]);
2630 my $secret = encode_base32
(pack('H*', $confighash{$cgiparams{'KEY'}}[44]));
2631 my $issuer = uri_encode
("$mainsettings{'HOSTNAME'}.$mainsettings{'DOMAINNAME'}");
2632 my $qrcodeimg = $qrcode->plot("otpauth://totp/$cn?secret=$secret&issuer=$issuer");
2634 $qrcodeimg->write(data
=> \
$qrcodeimgdata, type
=> 'png')
2635 or die $qrcodeimg->errstr;
2636 $qrcodeimgdata = encode_base64
($qrcodeimgdata, '');
2638 &Header
::showhttpheaders
();
2639 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2640 &Header
::openbigbox
('100%', 'LEFT', '', '');
2641 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'otp qrcode'}:");
2643 $Lang::tr{'secret'}: $secret</br></br>
2644 <img alt="$Lang::tr{'otp qrcode'}" src="data:image/png;base64,$qrcodeimgdata">
2646 &Header
::closebox
();
2647 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2648 &Header
::closebigbox
();
2649 &Header
::closepage
();
2653 ### Display tls-auth key
2655 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show tls-auth key'}) {
2657 if (! -e
"${General::swroot}/ovpn/certs/ta.key") {
2658 $errormessage = $Lang::tr
{'not present'};
2660 &Header
::showhttpheaders
();
2661 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2662 &Header
::openbigbox
('100%', 'LEFT', '', '');
2663 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ta key'}:");
2665 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
2666 my @output = <FILE
>;
2669 my $output = &Header
::cleanhtml
(join("", @output),"y");
2670 print "<pre>$output</pre>\n";
2671 &Header
::closebox
();
2672 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2673 &Header
::closebigbox
();
2674 &Header
::closepage
();
2679 ### Display Certificate Revoke List
2681 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'show crl'}) {
2682 # &General::readhasharray("${General::swroot}/ovpn/ovpnconfig", \%confighash);
2684 if (! -e
"${General::swroot}/ovpn/crls/cacrl.pem") {
2685 $errormessage = $Lang::tr
{'not present'};
2687 &Header
::showhttpheaders
();
2688 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
2689 &Header
::openbigbox
('100%', 'LEFT', '', '');
2690 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'crl'}:");
2691 my @output = &General
::system_output
("/usr/bin/openssl", "crl", "-text", "-noout", "-in", "${General::swroot}/ovpn/crls/cacrl.pem");
2692 my $output = &Header
::cleanhtml
(join("", @output), "y");
2693 print "<pre>$output</pre>\n";
2694 &Header
::closebox
();
2695 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
2696 &Header
::closebigbox
();
2697 &Header
::closepage
();
2702 ### Advanced Server Settings
2705 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'advanced server'}) {
2707 $selected{'DPROTOCOL'}{'udp'} = '';
2708 $selected{'DPROTOCOL'}{'tcp'} = '';
2709 $selected{'DPROTOCOL'}{$vpnsettings{'DPROTOCOL'}} = 'SELECTED';
2711 $checked{'REDIRECT_GW_DEF1'}{'off'} = '';
2712 $checked{'REDIRECT_GW_DEF1'}{'on'} = '';
2713 $checked{'REDIRECT_GW_DEF1'}{$vpnsettings{'REDIRECT_GW_DEF1'}} = 'CHECKED';
2714 $checked{'MSSFIX'}{'off'} = '';
2715 $checked{'MSSFIX'}{'on'} = '';
2716 $checked{'MSSFIX'}{$vpnsettings{'MSSFIX'}} = 'CHECKED';
2718 # Split data ciphers
2719 my @data_ciphers = split(/\|/, $vpnsettings{'DATACIPHERS'});
2721 # Select the correct ones
2722 $selected{'DATACIPHERS'} = ();
2723 foreach my $cipher (@SUPPORTED_CIPHERS) {
2724 $selected{'DATACIPHERS'}{$cipher} = grep(/^$cipher$/, @data_ciphers) ? "selected" : "";
2728 $vpnsettings{'ROUTES_PUSH'} =~ s/\|/\n/g;
2730 $selected{'DCIPHER'}{'AES-256-GCM'} = '';
2731 $selected{'DCIPHER'}{'AES-192-GCM'} = '';
2732 $selected{'DCIPHER'}{'AES-128-GCM'} = '';
2733 $selected{'DCIPHER'}{'CAMELLIA-256-CBC'} = '';
2734 $selected{'DCIPHER'}{'CAMELLIA-192-CBC'} = '';
2735 $selected{'DCIPHER'}{'CAMELLIA-128-CBC'} = '';
2736 $selected{'DCIPHER'}{'AES-256-CBC'} = '';
2737 $selected{'DCIPHER'}{'AES-192-CBC'} = '';
2738 $selected{'DCIPHER'}{'AES-128-CBC'} = '';
2739 $selected{'DCIPHER'}{'DES-EDE3-CBC'} = '';
2740 $selected{'DCIPHER'}{'DESX-CBC'} = '';
2741 $selected{'DCIPHER'}{'SEED-CBC'} = '';
2742 $selected{'DCIPHER'}{'DES-EDE-CBC'} = '';
2743 $selected{'DCIPHER'}{'CAST5-CBC'} = '';
2744 $selected{'DCIPHER'}{'BF-CBC'} = '';
2745 $selected{'DCIPHER'}{'DES-CBC'} = '';
2746 $selected{'DCIPHER'}{$vpnsettings{'DCIPHER'}} = 'SELECTED';
2748 $selected{'DAUTH'}{'whirlpool'} = '';
2749 $selected{'DAUTH'}{'SHA512'} = '';
2750 $selected{'DAUTH'}{'SHA384'} = '';
2751 $selected{'DAUTH'}{'SHA256'} = '';
2752 $selected{'DAUTH'}{'SHA1'} = '';
2753 $selected{'DAUTH'}{$vpnsettings{'DAUTH'}} = 'SELECTED';
2755 $checked{'TLSAUTH'}{'off'} = '';
2756 $checked{'TLSAUTH'}{'on'} = '';
2757 $checked{'TLSAUTH'}{$vpnsettings{'TLSAUTH'}} = 'CHECKED';
2759 &Header
::showhttpheaders
();
2760 &Header
::openpage
($Lang::tr
{'status ovpn'}, 1, '');
2761 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
2764 &Header
::errorbox
($errormessage);
2766 &Header
::opensection
();
2769 <form method='POST' enctype='multipart/form-data'>
2770 <h6>$Lang::tr{'ovpn protocol settings'}</h6>
2772 <table class="form">
2774 <td>$Lang::tr{'ovpn transport protocol'}</td>
2776 <select name='DPROTOCOL'>
2777 <option value='udp' $selected{'DPROTOCOL'}{'udp'}>UDP</option>
2778 <option value='tcp' $selected{'DPROTOCOL'}{'tcp'}>TCP</option>
2784 <td>$Lang::tr{'destination port'}</td>
2786 <input type='number' name='DDEST_PORT' value='$vpnsettings{'DDEST_PORT'}' />
2791 <td>$Lang::tr{'mtu'}</td>
2793 <input type='number' name='DMTU' value='$vpnsettings{'DMTU'}' min="1280" max="9000" />
2800 <input type='checkbox' name='MSSFIX' $checked{'MSSFIX'}{'on'} />
2807 <input type='TEXT' name='FRAGMENT' value='$vpnsettings{'FRAGMENT'}' />
2812 <h6>$Lang::tr{'ovpn crypto settings'}</h6>
2814 <table class="form">
2817 $Lang::tr{'ovpn ciphers'}
2821 <select name='DATACIPHERS' multiple required>
2824 foreach my $cipher (@SUPPORTED_CIPHERS) {
2825 my $name = $CIPHERS{$cipher} // $cipher;
2828 <option value='$cipher' $selected{'DATACIPHERS'}{$cipher}>
2834 # Format DNS and WINS servers as comma-separated
2835 my $dns_servers = join(", ", split(/\|/, $vpnsettings{'DHCP_DNS'}));
2836 my $wins_servers = join(", ", split(/\|/, $vpnsettings{'DHCP_WINS'}));
2845 $Lang::tr{'ovpn ha'}
2849 <select name='DAUTH'>
2850 <option value='whirlpool' $selected{'DAUTH'}{'whirlpool'}>Whirlpool (512 $Lang::tr{'bit'}, $Lang::tr{'vpn deprecated'})</option>
2851 <option value='SHA512' $selected{'DAUTH'}{'SHA512'}>SHA2 (512 $Lang::tr{'bit'})</option>
2852 <option value='SHA384' $selected{'DAUTH'}{'SHA384'}>SHA2 (384 $Lang::tr{'bit'})</option>
2853 <option value='SHA256' $selected{'DAUTH'}{'SHA256'}>SHA2 (256 $Lang::tr{'bit'})</option>
2854 <option value='SHA1' $selected{'DAUTH'}{'SHA1'}>SHA1 (160 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
2861 $Lang::tr{'ovpn tls auth'}
2865 <input type='checkbox' name='TLSAUTH' $checked{'TLSAUTH'}{'on'} />
2871 $Lang::tr{'ovpn fallback cipher'}
2875 <select name='DCIPHER'>
2876 <option value='' $selected{'DCIPHER'}{''}>- $Lang::tr{'Disabled'} -</option>
2877 <option value='AES-256-GCM' $selected{'DCIPHER'}{'AES-256-GCM'}>AES-GCM (256 $Lang::tr{'bit'})</option>
2878 <option value='AES-192-GCM' $selected{'DCIPHER'}{'AES-192-GCM'}>AES-GCM (192 $Lang::tr{'bit'})</option>
2879 <option value='AES-128-GCM' $selected{'DCIPHER'}{'AES-128-GCM'}>AES-GCM (128 $Lang::tr{'bit'})</option>
2880 <option value='CAMELLIA-256-CBC' $selected{'DCIPHER'}{'CAMELLIA-256-CBC'}>CAMELLIA-CBC (256 $Lang::tr{'bit'})</option>
2881 <option value='CAMELLIA-192-CBC' $selected{'DCIPHER'}{'CAMELLIA-192-CBC'}>CAMELLIA-CBC (192 $Lang::tr{'bit'})</option>
2882 <option value='CAMELLIA-128-CBC' $selected{'DCIPHER'}{'CAMELLIA-128-CBC'}>CAMELLIA-CBC (128 $Lang::tr{'bit'})</option>
2883 <option value='AES-256-CBC' $selected{'DCIPHER'}{'AES-256-CBC'}>AES-CBC (256 $Lang::tr{'bit'})</option>
2884 <option value='AES-192-CBC' $selected{'DCIPHER'}{'AES-192-CBC'}>AES-CBC (192 $Lang::tr{'bit'})</option>
2885 <option value='AES-128-CBC' $selected{'DCIPHER'}{'AES-128-CBC'}>AES-CBC (128 $Lang::tr{'bit'})</option>
2886 <option value='SEED-CBC' $selected{'DCIPHER'}{'SEED-CBC'}>SEED-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn deprecated'})</option>
2887 <option value='DES-EDE3-CBC' $selected{'DCIPHER'}{'DES-EDE3-CBC'}>DES-EDE3-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn deprecated'})</option>
2888 <option value='DESX-CBC' $selected{'DCIPHER'}{'DESX-CBC'}>DESX-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn deprecated'})</option>
2889 <option value='DES-EDE-CBC' $selected{'DCIPHER'}{'DES-EDE-CBC'}>DES-EDE-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn deprecated'})</option>
2890 <option value='BF-CBC' $selected{'DCIPHER'}{'BF-CBC'}>BF-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn deprecated'})</option>
2891 <option value='CAST5-CBC' $selected{'DCIPHER'}{'CAST5-CBC'}>CAST5-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn deprecated'})</option>
2899 $Lang::tr{'ovpn fallback cipher help'}
2904 <h6>$Lang::tr{'ovpn dhcp settings'}</h6>
2906 <table class="form">
2910 <input type='TEXT' name='DHCP_DOMAIN' value='$vpnsettings{'DHCP_DOMAIN'}' size='30' />
2916 <input type='TEXT' name='DHCP_DNS' value='$dns_servers' size='30' />
2922 <input type='TEXT' name='DHCP_WINS' value='$wins_servers' size='30' />
2927 <h6>$Lang::tr{'ovpn routing settings'}</h6>
2929 <table class="form">
2931 <td>$Lang::tr{'ovpn push default route'}</td>
2933 <input type='checkbox' name='REDIRECT_GW_DEF1' $checked{'REDIRECT_GW_DEF1'}{'on'} />
2938 <td>$Lang::tr{'ovpn routes push'}</td>
2940 <textarea name='ROUTES_PUSH' cols='26' rows='6' wrap='off'>$vpnsettings{'ROUTES_PUSH'}</textarea>
2945 <h6>$Lang::tr{'ovpn misc settings'}</h6>
2947 <table class="form">
2949 <td>Max-Clients</td>
2951 <input type='text' name='MAX_CLIENTS' value='$vpnsettings{'MAX_CLIENTS'}' />
2957 <input type='submit' name='ACTION' value='$Lang::tr{'save-adv-options'}' />
2958 <input type='submit' name='ACTION' value='$Lang::tr{'cancel-adv-options'}' />
2964 &Header
::closesection
();
2965 &Header
::closebigbox
();
2967 &Header
::closepage
();
2971 # Add, delete or edit CCD net
2973 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'ccd net'} ||
2974 $cgiparams{'ACTION'} eq "ccd-add" ||
2975 $cgiparams{'ACTION'} eq "ccd-delete" ||
2976 $cgiparams{'ACTION'} eq "ccd-edit" ||
2977 $cgiparams{'ACTION'} eq 'ccd-edit-save'){
2978 &Header
::showhttpheaders
();
2980 &Header
::openpage
($Lang::tr
{'ccd net'}, 1, '');
2982 &Header
::openbigbox
('100%', 'LEFT', '', '');
2985 if ($cgiparams{'ACTION'} eq "ccd-delete") {
2986 $errormessage = &delccdnet
($cgiparams{'name'});
2989 } elsif ($cgiparams{'ACTION'} eq 'ccd-edit-save') {
2990 $errormessage = &modccdnet
($cgiparams{'subnet'}, $cgiparams{'name'});
2993 if ($errormessage eq "") {
2994 $cgiparams{"name"} = "";
2995 $cgiparams{"subnet"} = "";
2999 } elsif ($cgiparams{'ACTION'} eq "ccd-add") {
3000 $errormessage = &addccdnet
($cgiparams{'name'}, $cgiparams{'subnet'});
3003 if ($errormessage eq "") {
3004 $cgiparams{"name"} = "";
3005 $cgiparams{"subnet"} = "";
3009 &Header
::errorbox
($errormessage);
3011 my %ccdconfhash = ();
3012 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
3014 &Header
::opensection
();
3019 $Lang::tr{'ccd name'}
3023 $Lang::tr{'network'}
3027 $Lang::tr{'ccd used'}
3030 <th colspan="2"></th>
3034 foreach my $key (sort { uc($ccdconfhash{$a}[0]) cmp uc($ccdconfhash{$b}[0]) } keys %ccdconfhash) {
3035 my $name = $ccdconfhash{$key}[0];
3036 my $subnet = $ccdconfhash{$key}[1];
3038 my $ccdhosts = scalar &get_addresses_in_use
($subnet);
3039 my $maxhosts = &ccdmaxclients
($subnet);
3047 <td class="text-center">
3051 <td class="text-center">
3052 ${ccdhosts}/${maxhosts}
3055 <td class="text-center">
3056 <form method='post' />
3057 <input type='image' src='/images/edit.gif' align='middle'
3058 alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
3059 <input type='hidden' name='ACTION' value='ccd-edit'/>
3060 <input type='hidden' name='name' value='$name' />
3061 <input type='hidden' name='subnet' value='$subnet' />
3065 <td class="text-center">
3066 <form method='post' />
3067 <input type='hidden' name='ACTION' value='ccd-delete'/>
3068 <input type='hidden' name='name' value='$name' />
3069 <input type='image' src='/images/delete.gif' align='middle'
3070 alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
3077 &Header
::closesection
();
3079 &Header
::openbox
('100%', 'LEFT',
3080 ($cgiparams{'ACTION'} eq "ccd-edit") ? $Lang::tr
{'ccd modify'} : $Lang::tr
{'ccd add'});
3082 # The subnet cannot be edited
3083 my $readonly = ($cgiparams{'ACTION'} eq "ccd-edit") ? "readonly" : "";
3084 my $action = ($cgiparams{'ACTION'} eq "ccd-edit") ? "ccd-edit-save" : "ccd-add";
3087 <form method='post'>
3088 <table class="form">
3090 <td>$Lang::tr{'ccd name'}</td>
3092 <input type='TEXT' name='name' value='$cgiparams{'name'}' />
3097 <td>$Lang::tr{'ccd subnet'}</td>
3099 <input type='TEXT' name='subnet' value='$cgiparams{'subnet'}'
3106 <input type='hidden' name='ACTION' value='$action' />
3107 <input type='submit' value='$Lang::tr{'save'}' />
3113 &Header
::closebox
();
3116 <div class="text-center">
3117 <a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a>
3121 &Header
::closebigbox
();
3122 &Header
::closepage
();
3127 ### Openvpn Connections Statistics
3129 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'ovpn con stat'}) {
3130 &Header
::showhttpheaders
();
3131 &Header
::openpage
($Lang::tr
{'ovpn con stat'}, 1, '');
3132 &Header
::openbigbox
('100%', 'LEFT', '', '');
3134 &Header
::opensection
();
3139 <th>$Lang::tr{'common name'}</th>
3140 <th>$Lang::tr{'real address'}</th>
3141 <th>$Lang::tr{'country'}</th>
3142 <th>$Lang::tr{'virtual address'}</th>
3143 <th>$Lang::tr{'loged in at'}</th>
3144 <th>$Lang::tr{'bytes sent'}</th>
3145 <th>$Lang::tr{'bytes received'}</th>
3146 <th>$Lang::tr{'last activity'}</th>
3150 open(FILE
, "/usr/local/bin/openvpnctrl rw log |") or die "Unable to open $RW_STATUS: $!";
3151 my @current = <FILE
>;
3158 my %userlookup = ();
3160 foreach my $line (@current) {
3163 if ($line =~ /^Updated,(.+)/) {
3164 @match = split(/^Updated,(.+)/, $line);
3165 $status = $match[1];
3167 } elsif ( $line =~ /^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/) {
3168 @match = split(m/^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/, $line);
3171 next if ($match[1] eq "Common Name");
3173 $userlookup{$match[2]} = $uid;
3174 $users[$uid]{'CommonName'} = $match[1];
3175 $users[$uid]{'RealAddress'} = $match[2];
3176 $users[$uid]{'BytesReceived'} = &General
::formatBytes
($match[3]);
3177 $users[$uid]{'BytesSent'} = &General
::formatBytes
($match[4]);
3178 $users[$uid]{'Since'} = $match[5];
3180 my $address = (split ':', $users[$uid]{'RealAddress'})[0];
3181 $users[$uid]{'Country'} = &Location
::Functions
::lookup_country_code
($address);
3184 } elsif ($line =~ /^(\d+\.\d+\.\d+\.\d+),(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(.+)/) {
3185 @match = split(m/^(\d+\.\d+\.\d+\.\d+),(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(.+)/, $line);
3188 next if ($match[1] eq "Virtual Address");
3190 my $address = $match[3];
3191 #find the uid in the lookup table
3192 $uid = $userlookup{$address};
3193 $users[$uid]{'VirtualAddress'} = $match[1];
3194 $users[$uid]{'LastRef'} = $match[4];
3198 foreach my $id (keys @users) {
3199 my $user = $users[$id];
3201 my $flag_icon = &Location
::Functions
::get_flag_icon
($user->{"Country"});
3206 $user->{"CommonName"}
3209 <td class="text-center">
3210 $user->{"RealAddress"}
3213 <td class="text-center">
3214 <a href="country.cgi#$user->{"Country"}">
3215 <img src="$flag_icon" border='0' align='absmiddle'
3216 alt='$user->{"Country"}' title='$user->{"Country"}' />
3220 <td class="text-center">
3221 $user->{"VirtualAddress"}
3224 <td class="text-center">
3228 <td class="text-right">
3229 $user->{"BytesSent"}
3232 <td class="text-right">
3233 $user->{"BytesReceived"}
3236 <td class="text-right">
3246 <p class="text-center">
3247 $Lang::tr{'the statistics were last updated at'} <b>$status</b>
3252 &Header
::closesection
();
3255 <p class="text-center">
3256 <a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a>
3260 &Header
::closebigbox
();
3261 &Header
::closepage
();
3266 ### Download Certificate
3268 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'download certificate'}) {
3269 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3271 if ( -f
"${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem") {
3272 print "Content-Disposition: filename=" . $confighash{$cgiparams{'KEY'}}[1] . "cert.pem\r\n";
3273 print "Content-Type: application/octet-stream\r\n\r\n";
3275 open(FILE
, "${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1]cert.pem");
3284 ### Enable/Disable connection
3287 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'toggle enable disable'}) {
3288 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3290 if ($confighash{$cgiparams{'KEY'}}) {
3291 if ($confighash{$cgiparams{'KEY'}}[0] eq 'off') {
3292 $confighash{$cgiparams{'KEY'}}[0] = 'on';
3293 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3295 $confighash{$cgiparams{'KEY'}}[0] = 'off';
3296 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3299 $errormessage = $Lang::tr
{'invalid key'};
3302 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'add'} && $cgiparams{'TYPE'} eq '') {
3303 &Header
::showhttpheaders
();
3304 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
3305 &Header
::openbigbox
('100%', 'LEFT', '', '');
3306 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'connection type'});
3308 if ( -s
"${General::swroot}/ovpn/settings") {
3311 <b>$Lang::tr{'connection type'}:</b><br />
3312 <table border='0' width='100%'><form method='post' ENCTYPE="multipart/form-data">
3313 <tr><td><input type='radio' name='TYPE' value='host' checked /></td>
3314 <td class='base'>$Lang::tr{'host to net vpn'}</td></tr>
3315 <tr><td><input type='radio' name='TYPE' value='net' /></td>
3316 <td class='base'>$Lang::tr{'net to net vpn'}</td></tr>
3317 <tr><td><input type='radio' name='TYPE' value='net2net' /></td>
3318 <td class='base'>$Lang::tr{'net to net vpn'} (Upload Client Package)</td></tr>
3319 <tr><td> </td><td class='base'><input type='file' name='FH' size='30'></td></tr>
3320 <tr><td> </td><td>Import Connection Name</td></tr>
3321 <tr><td> </td><td class='base'><input type='text' name='n2nname' size='30'>$Lang::tr{'openvpn default'}: Client Packagename</td></tr>
3322 <tr><td colspan='3'><hr /></td></tr>
3323 <tr><td align='right' colspan='3'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td></tr>
3331 <b>$Lang::tr{'connection type'}:</b><br />
3332 <table border='0' width='100%'><form method='post' ENCTYPE="multipart/form-data">
3333 <tr><td><input type='radio' name='TYPE' value='host' checked /></td> <td class='base'>$Lang::tr{'host to net vpn'}</td></tr>
3334 <tr><td align='right' colspan'3'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' /></td></tr>
3341 &Header
::closebox
();
3342 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
3343 &Header
::closebigbox
();
3344 &Header
::closepage
();
3347 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) && ($cgiparams{'TYPE'} eq 'net2net')){
3351 my $uplconffilename ='';
3352 my $uplconffilename2 ='';
3353 my $uplp12name = '';
3354 my $uplp12name2 = '';
3361 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3363 # Check if a file is uploaded
3364 unless (ref ($cgiparams{'FH'})) {
3365 $errormessage = $Lang::tr
{'there was no file upload'};
3369 # Move uploaded IPfire n2n package to temporary file
3371 (my $fh, my $filename) = tempfile
( );
3372 if (copy
($cgiparams{'FH'}, $fh) != 1) {
3377 my $zip = Archive
::Zip-
>new();
3378 my $zipName = $filename;
3379 my $status = $zip->read( $zipName );
3380 if ($status != AZ_OK
) {
3381 $errormessage = "Read of $zipName failed\n";
3385 my $tempdir = tempdir
( CLEANUP
=> 1 );
3386 my @files = $zip->memberNames();
3388 $zip->extractMemberWithoutPaths($_,"$tempdir/$_");
3390 my $countfiles = @files;
3392 # Check if we have not more then 2 files
3394 if ( $countfiles == 2){
3396 if ( $_ =~ /.conf$/){
3397 $uplconffilename = $_;
3399 if ( $_ =~ /.p12$/){
3403 if (($uplconffilename eq '') || ($uplp12name eq '')){
3404 $errormessage = "Either no *.conf or no *.p12 file found\n";
3408 open(FILE
, "$tempdir/$uplconffilename") or die 'Unable to open*.conf file';
3409 @firen2nconf = <FILE
>;
3411 chomp(@firen2nconf);
3414 $errormessage = "Filecount does not match only 2 files are allowed\n";
3418 if ($cgiparams{'n2nname'} ne ''){
3420 $uplconffilename2 = "$cgiparams{'n2nname'}.conf";
3421 $uplp12name2 = "$cgiparams{'n2nname'}.p12";
3422 $n2nname[0] = $cgiparams{'n2nname'};
3423 my @n2nname2 = split(/\./,$uplconffilename);
3424 $n2nname2[0] =~ s/\n|\r//g;
3425 my $input1 = "${General::swroot}/ovpn/certs/$uplp12name";
3426 my $output1 = "${General::swroot}/ovpn/certs/$uplp12name2";
3427 my $input2 = "$n2nname2[0]n2n";
3428 my $output2 = "$n2nname[0]n2n";
3429 my $filename = "$tempdir/$uplconffilename";
3430 open(FILE
, "< $filename") or die 'Unable to open config file.';
3431 my @current = <FILE
>;
3433 foreach (@current) {s/$input1/$output1/g;}
3434 foreach (@current) {s/$input2/$output2/g;}
3435 open (OUT
, "> $filename") || die 'Unable to open config file.';
3440 $uplconffilename2 = $uplconffilename;
3441 $uplp12name2 = $uplp12name;
3442 @n2nname = split(/\./,$uplconffilename);
3443 $n2nname[0] =~ s/\n|\r//g;
3445 unless(-d
"${General::swroot}/ovpn/n2nconf/"){mkdir "${General::swroot}/ovpn/n2nconf", 0755 or die "Unable to create dir $!";}
3446 unless(-d
"${General::swroot}/ovpn/n2nconf/$n2nname[0]"){mkdir "${General::swroot}/ovpn/n2nconf/$n2nname[0]", 0770 or die "Unable to create dir $!";}
3448 #Add collectd settings to configfile
3449 open(FILE
, ">> $tempdir/$uplconffilename") or die 'Unable to open config file.';
3450 print FILE
"# Logfile\n";
3451 print FILE
"status-version 1\n";
3452 print FILE
"status /var/run/openvpn/$n2nname[0]-n2n 10\n";
3453 if (&iscertlegacy
("${General::swroot}/ovpn/certs/$cgiparams{'n2nname'}")) {
3454 print CLIENTCONF
"providers legacy default\n";
3459 unless(move
("$tempdir/$uplconffilename", "${General::swroot}/ovpn/n2nconf/$n2nname[0]/$uplconffilename2")) {
3460 $errormessage = "*.conf move failed: $!";
3465 unless(move
("$tempdir/$uplp12name", "${General::swroot}/ovpn/certs/$uplp12name2")) {
3466 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
3471 chmod 0600, "${General::swroot}/ovpn/certs/$uplp12name";
3477 my @n2nproto2 = split(/ /, (grep { /^proto/ } @firen2nconf)[0]);
3478 my @n2nproto = split(/-/, $n2nproto2[1]);
3479 my @n2nport = split(/ /, (grep { /^port/ } @firen2nconf)[0]);
3480 my @n2ntunmtu = split(/ /, (grep { /^tun-mtu/ } @firen2nconf)[0]);
3481 my @n2ncomplzo = grep { /^comp-lzo/ } @firen2nconf;
3482 if ($n2ncomplzo[0] =~ /comp-lzo/){$complzoactive = "on";} else {$complzoactive = "off";}
3483 my @n2nmssfix = grep { /^mssfix/ } @firen2nconf;
3484 if ($n2nmssfix[0] =~ /mssfix/){$mssfixactive = "on";} else {$mssfixactive = "off";}
3485 #my @n2nmssfix = split(/ /, (grep { /^mssfix/ } @firen2nconf)[0]);
3486 my @n2nfragment = split(/ /, (grep { /^fragment/ } @firen2nconf)[0]);
3487 my @n2nremote = split(/ /, (grep { /^remote/ } @firen2nconf)[0]);
3488 my @n2novpnsuball = split(/ /, (grep { /^ifconfig/ } @firen2nconf)[0]);
3489 my @n2novpnsub = split(/\./,$n2novpnsuball[1]);
3490 my @n2nremsub = split(/ /, (grep { /^route/ } @firen2nconf)[0]);
3491 my @n2nmgmt = split(/ /, (grep { /^management/ } @firen2nconf)[0]);
3492 my @n2nlocalsub = split(/ /, (grep { /^# remsub/ } @firen2nconf)[0]);
3493 my @n2ncipher = split(/ /, (grep { /^cipher/ } @firen2nconf)[0]);
3494 my @n2nauth = split(/ /, (grep { /^auth/ } @firen2nconf)[0]);;
3497 # m.a.d delete CR and LF from arrays for this chomp doesnt work
3500 $n2nremote[1] =~ s/\n|\r//g;
3501 $n2novpnsub[0] =~ s/\n|\r//g;
3502 $n2novpnsub[1] =~ s/\n|\r//g;
3503 $n2novpnsub[2] =~ s/\n|\r//g;
3504 $n2nproto[0] =~ s/\n|\r//g;
3505 $n2nport[1] =~ s/\n|\r//g;
3506 $n2ntunmtu[1] =~ s/\n|\r//g;
3507 $n2nremsub[1] =~ s/\n|\r//g;
3508 $n2nremsub[2] =~ s/\n|\r//g;
3509 $n2nlocalsub[2] =~ s/\n|\r//g;
3510 $n2nfragment[1] =~ s/\n|\r//g;
3511 $n2nmgmt[2] =~ s/\n|\r//g;
3512 $n2ncipher[1] =~ s/\n|\r//g;
3513 $n2nauth[1] =~ s/\n|\r//g;
3514 chomp ($complzoactive);
3515 chomp ($mssfixactive);
3518 # Check if there is no other entry with this name
3521 foreach my $dkey (keys %confighash) {
3522 if ($confighash{$dkey}[1] eq $n2nname[0]) {
3523 $errormessage = $Lang::tr
{'a connection with this name already exists'};
3524 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3525 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3526 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3532 # Check if OpenVPN Subnet is valid
3535 foreach my $dkey (keys %confighash) {
3536 if ($confighash{$dkey}[27] eq "$n2novpnsub[0].$n2novpnsub[1].$n2novpnsub[2].0/255.255.255.0") {
3537 $errormessage = 'The OpenVPN Subnet is already in use';
3538 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3539 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3540 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3546 # Check if Dest Port is vaild
3549 foreach my $dkey (keys %confighash) {
3550 if ($confighash{$dkey}[29] eq $n2nport[1] ) {
3551 $errormessage = 'The OpenVPN Port is already in use';
3552 unlink ("${General::swroot}/ovpn/n2nconf/$n2nname[0]/$n2nname[0].conf") or die "Removing Configfile fail: $!";
3553 unlink ("${General::swroot}/ovpn/certs/$n2nname[0].p12") or die "Removing Certfile fail: $!";
3554 rmdir ("${General::swroot}/ovpn/n2nconf/$n2nname[0]") || die "Removing Directory fail: $!";
3561 $key = &General
::findhasharraykey
(\
%confighash);
3563 foreach my $i (0 .. 42) { $confighash{$key}[$i] = "";}
3565 $confighash{$key}[0] = 'off';
3566 $confighash{$key}[1] = $n2nname[0];
3567 $confighash{$key}[2] = $n2nname[0];
3568 $confighash{$key}[3] = 'net';
3569 $confighash{$key}[4] = 'cert';
3570 $confighash{$key}[6] = 'client';
3571 $confighash{$key}[8] = $n2nlocalsub[2];
3572 $confighash{$key}[10] = $n2nremote[1];
3573 $confighash{$key}[11] = "$n2nremsub[1]/$n2nremsub[2]";
3574 $confighash{$key}[22] = $n2nmgmt[2];
3575 $confighash{$key}[23] = $mssfixactive;
3576 $confighash{$key}[24] = $n2nfragment[1];
3577 $confighash{$key}[25] = 'IPFire n2n Client';
3578 $confighash{$key}[26] = 'red';
3579 $confighash{$key}[27] = "$n2novpnsub[0].$n2novpnsub[1].$n2novpnsub[2].0/255.255.255.0";
3580 $confighash{$key}[28] = $n2nproto[0];
3581 $confighash{$key}[29] = $n2nport[1];
3582 $confighash{$key}[30] = $complzoactive;
3583 $confighash{$key}[31] = $n2ntunmtu[1];
3584 $confighash{$key}[39] = $n2nauth[1];
3585 $confighash{$key}[40] = $n2ncipher[1];
3586 $confighash{$key}[41] = 'no-pass';
3588 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3592 &Header
::showhttpheaders
();
3593 &Header
::openpage
('Validate imported configuration', 1, '');
3594 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
3595 if ($errormessage) {
3596 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'error messages'});
3597 print "<class name='base'>$errormessage";
3598 print " </class>";
3599 &Header
::closebox
();
3603 &Header
::openbox
('100%', 'LEFT', 'import ipfire net2net config');
3605 if ($errormessage eq ''){
3607 <!-- ipfire net2net config gui -->
3608 <table width='100%'>
3609 <tr><td width='25%'> </td><td width='25%'> </td></tr>
3610 <tr><td class='boldbase'>$Lang::tr{'name'}:</td><td><b>$n2nname[0]</b></td></tr>
3611 <tr><td> </td><td> </td></tr>
3612 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'Act as'}</td><td><b>$confighash{$key}[6]</b></td></tr>
3613 <tr><td class='boldbase' nowrap='nowrap'>Remote Host </td><td><b>$confighash{$key}[10]</b></td></tr>
3614 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'local subnet'}</td><td><b>$confighash{$key}[8]</b></td></tr>
3615 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'remote subnet'}:</td><td><b>$confighash{$key}[11]</b></td></tr>
3616 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'ovpn subnet'}</td><td><b>$confighash{$key}[27]</b></td></tr>
3617 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'protocol'}</td><td><b>$confighash{$key}[28]</b></td></tr>
3618 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'destination port'}:</td><td><b>$confighash{$key}[29]</b></td></tr>
3619 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'comp-lzo'}</td><td><b>$confighash{$key}[30]</b></td></tr>
3620 <tr><td class='boldbase' nowrap='nowrap'>MSSFIX:</td><td><b>$confighash{$key}[23]</b></td></tr>
3621 <tr><td class='boldbase' nowrap='nowrap'>Fragment:</td><td><b>$confighash{$key}[24]</b></td></tr>
3622 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'MTU'}</td><td><b>$confighash{$key}[31]</b></td></tr>
3623 <tr><td class='boldbase' nowrap='nowrap'>Management Port </td><td><b>$confighash{$key}[22]</b></td></tr>
3624 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'ovpn tls auth'}:</td><td><b>$confighash{$key}[39]</b></td></tr>
3625 <tr><td class='boldbase' nowrap='nowrap'>$Lang::tr{'cipher'}</td><td><b>$confighash{$key}[40]</b></td></tr>
3626 <tr><td> </td><td> </td></tr>
3630 &Header
::closebox
();
3633 if ($errormessage) {
3634 print "<div align='center'><a href='/cgi-bin/ovpnmain.cgi'>$Lang::tr{'back'}</a></div>";
3636 print "<div align='center'><form method='post' ENCTYPE='multipart/form-data'><input type='submit' name='ACTION' value='$Lang::tr{'add'}' />";
3637 print "<input type='hidden' name='TYPE' value='net2netakn' />";
3638 print "<input type='hidden' name='KEY' value='$key' />";
3639 print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
3641 &Header
::closebigbox
();
3642 &Header
::closepage
();
3647 ### Accept IPFire n2n Package Settings
3650 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) && ($cgiparams{'TYPE'} eq 'net2netakn')){
3653 ### Discard and Rollback IPFire n2n Package Settings
3656 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'cancel'}) && ($cgiparams{'TYPE'} eq 'net2netakn')){
3658 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3660 if ($confighash{$cgiparams{'KEY'}}) {
3662 my $conffile = glob("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]/$confighash{$cgiparams{'KEY'}}[1].conf");
3663 my $certfile = glob("${General::swroot}/ovpn/certs/$confighash{$cgiparams{'KEY'}}[1].p12");
3664 unlink ($certfile) or die "Removing $certfile fail: $!";
3665 unlink ($conffile) or die "Removing $conffile fail: $!";
3666 rmdir ("${General::swroot}/ovpn/n2nconf/$confighash{$cgiparams{'KEY'}}[1]") || die "Kann Verzeichnis nicht loeschen: $!";
3667 delete $confighash{$cgiparams{'KEY'}};
3668 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3671 $errormessage = $Lang::tr
{'invalid key'};
3675 ### Adding a new connection
3677 } elsif (($cgiparams{'ACTION'} eq $Lang::tr
{'add'}) ||
3678 ($cgiparams{'ACTION'} eq $Lang::tr
{'edit'}) ||
3679 ($cgiparams{'ACTION'} eq $Lang::tr
{'save'} && $cgiparams{'ADVANCED'} eq '')) {
3680 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
3681 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
3683 if ($cgiparams{'ACTION'} eq $Lang::tr
{'edit'}) {
3684 if (! $confighash{$cgiparams{'KEY'}}[0]) {
3685 $errormessage = $Lang::tr
{'invalid key'};
3688 $cgiparams{'ENABLED'} = $confighash{$cgiparams{'KEY'}}[0];
3689 $cgiparams{'NAME'} = $confighash{$cgiparams{'KEY'}}[1];
3690 $cgiparams{'TYPE'} = $confighash{$cgiparams{'KEY'}}[3];
3691 $cgiparams{'AUTH'} = $confighash{$cgiparams{'KEY'}}[4];
3692 $cgiparams{'PSK'} = $confighash{$cgiparams{'KEY'}}[5];
3693 $cgiparams{'SIDE'} = $confighash{$cgiparams{'KEY'}}[6];
3694 $cgiparams{'LOCAL_SUBNET'} = $confighash{$cgiparams{'KEY'}}[8];
3695 $cgiparams{'REMOTE'} = $confighash{$cgiparams{'KEY'}}[10];
3696 $cgiparams{'REMOTE_SUBNET'} = $confighash{$cgiparams{'KEY'}}[11];
3697 $cgiparams{'OVPN_MGMT'} = $confighash{$cgiparams{'KEY'}}[22];
3698 $cgiparams{'MSSFIX'} = $confighash{$cgiparams{'KEY'}}[23];
3699 $cgiparams{'FRAGMENT'} = $confighash{$cgiparams{'KEY'}}[24];
3700 $cgiparams{'REMARK'} = $confighash{$cgiparams{'KEY'}}[25];
3701 $cgiparams{'INTERFACE'} = $confighash{$cgiparams{'KEY'}}[26];
3702 $cgiparams{'OVPN_SUBNET'} = $confighash{$cgiparams{'KEY'}}[27];
3703 $cgiparams{'PROTOCOL'} = $confighash{$cgiparams{'KEY'}}[28];
3704 $cgiparams{'DEST_PORT'} = $confighash{$cgiparams{'KEY'}}[29];
3705 $cgiparams{'COMPLZO'} = $confighash{$cgiparams{'KEY'}}[30];
3706 $cgiparams{'MTU'} = $confighash{$cgiparams{'KEY'}}[31];
3707 $cgiparams{'CHECK1'} = $confighash{$cgiparams{'KEY'}}[32];
3708 $name=$cgiparams{'CHECK1'} ;
3709 $cgiparams{$name} = $confighash{$cgiparams{'KEY'}}[33];
3710 $cgiparams{'RG'} = $confighash{$cgiparams{'KEY'}}[34];
3711 $cgiparams{'CCD_DNS1'} = $confighash{$cgiparams{'KEY'}}[35];
3712 $cgiparams{'CCD_DNS2'} = $confighash{$cgiparams{'KEY'}}[36];
3713 $cgiparams{'CCD_WINS'} = $confighash{$cgiparams{'KEY'}}[37];
3714 $cgiparams{'DAUTH'} = $confighash{$cgiparams{'KEY'}}[39];
3715 $cgiparams{'DCIPHER'} = $confighash{$cgiparams{'KEY'}}[40];
3716 $cgiparams{'TLSAUTH'} = $confighash{$cgiparams{'KEY'}}[41];
3717 $cgiparams{'OTP_STATE'} = $confighash{$cgiparams{'KEY'}}[43];
3718 } elsif ($cgiparams{'ACTION'} eq $Lang::tr
{'save'}) {
3719 $cgiparams{'REMARK'} = &Header
::cleanhtml
($cgiparams{'REMARK'});
3721 # CCD check iroute field and convert it to decimal
3722 if ($cgiparams{'TYPE'} eq 'host') {
3724 my %ccdroutehash=();
3728 if ($cgiparams{'IR'} ne ''){
3729 @temp = split("\n",$cgiparams{'IR'});
3730 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3732 foreach my $key (keys %ccdroutehash) {
3733 if ($ccdroutehash{$key}[0] eq $cgiparams{'NAME'}) {
3735 delete $ccdroutehash{$key};
3737 $keypoint = &General
::findhasharraykey
(\
%ccdroutehash);
3740 $ccdroutehash{$keypoint}[0]=$cgiparams{'NAME'};
3743 foreach $val (@temp){
3746 #check if iroute exists in ccdroute or if new iroute is part of an existing one
3747 foreach my $key (keys %ccdroutehash) {
3748 foreach my $oldiroute ( 1 .. $#{$ccdroutehash{$key}}){
3749 if ($ccdroutehash{$key}[$oldiroute] eq "$val") {
3750 $errormessage=$errormessage.$Lang::tr
{'ccd err irouteexist'};
3753 my ($ip1,$cidr1) = split (/\//, $val);
3754 $ip1 = &General
::getnetworkip
($ip1,&General
::iporsubtocidr
($cidr1));
3755 my ($ip2,$cidr2) = split (/\//, $ccdroutehash{$key}[$oldiroute]);
3756 if (&General
::IpInSubnet
($ip1,$ip2,$cidr2)){
3757 $errormessage=$errormessage.$Lang::tr
{'ccd err irouteexist'};
3763 if (!&General
::validipandmask
($val)){
3764 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($val)";
3767 ($ip,$cidr) = split(/\//,$val);
3768 $ip=&General
::getnetworkip
($ip,&General
::iporsubtocidr
($cidr));
3769 $cidr=&General
::iporsubtodec
($cidr);
3770 $ccdroutehash{$keypoint}[$i] = $ip."/".$cidr;
3774 #check for existing network IP's
3775 if (&General
::IpInSubnet
($ip,$Network::ethernet
{GREEN_NETADDRESS
},$Network::ethernet
{GREEN_NETMASK
}) && $Network::ethernet
{GREEN_NETADDRESS
} ne '0.0.0.0')
3777 $errormessage=$Lang::tr
{'ccd err green'};
3779 }elsif(&General
::IpInSubnet
($ip,$Network::ethernet
{RED_NETADDRESS
},$Network::ethernet
{RED_NETMASK
}) && $Network::ethernet
{RED_NETADDRESS
} ne '0.0.0.0')
3781 $errormessage=$Lang::tr
{'ccd err red'};
3783 }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 '')
3785 $errormessage=$Lang::tr
{'ccd err blue'};
3787 }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 '' )
3789 $errormessage=$Lang::tr
{'ccd err orange'};
3793 if (&General
::validipandmask
($val)){
3794 $ccdroutehash{$keypoint}[$i] = $ip."/".$cidr;
3796 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($ip/$cidr)";
3801 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3804 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3805 foreach my $key (keys %ccdroutehash) {
3806 if ($ccdroutehash{$key}[0] eq $cgiparams{'NAME'}) {
3807 delete $ccdroutehash{$key};
3808 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3814 #check route field and convert it to decimal
3817 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
3819 foreach my $key (keys %ccdroute2hash) {
3820 if ($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}) {
3822 delete $ccdroute2hash{$key};
3824 $keypoint = &General
::findhasharraykey
(\
%ccdroute2hash);
3825 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
3829 $ccdroute2hash{$keypoint}[0]=$cgiparams{'NAME'};
3830 if ($cgiparams{'IFROUTE'} eq ''){$cgiparams{'IFROUTE'} = $Lang::tr
{'ccd none'};}
3831 @temp = split(/\|/,$cgiparams{'IFROUTE'});
3832 foreach $val (@temp){
3835 if ($val eq $Lang::tr
{'green'})
3837 $val=$Network::ethernet
{GREEN_NETADDRESS
}."/".$Network::ethernet
{GREEN_NETMASK
};
3839 if ($val eq $Lang::tr
{'blue'})
3841 $val=$Network::ethernet
{BLUE_NETADDRESS
}."/".$Network::ethernet
{BLUE_NETMASK
};
3843 if ($val eq $Lang::tr
{'orange'})
3845 $val=$Network::ethernet
{ORANGE_NETADDRESS
}."/".$Network::ethernet
{ORANGE_NETMASK
};
3847 my ($ip,$cidr) = split (/\//, $val);
3849 if ($val ne $Lang::tr
{'ccd none'})
3851 if (! &check_routes_push
($val)){$errormessage=$errormessage."Route $val ".$Lang::tr
{'ccd err routeovpn2'}." ($val)";goto VPNCONF_ERROR
;}
3852 if (! &check_ccdroute
($val)){$errormessage=$errormessage."<br>Route $val ".$Lang::tr
{'ccd err inuse'}." ($val)" ;goto VPNCONF_ERROR
;}
3853 if (! &check_ccdconf
($val)){$errormessage=$errormessage."<br>Route $val ".$Lang::tr
{'ccd err routeovpn'}." ($val)";goto VPNCONF_ERROR
;}
3854 if (&General
::validipandmask
($val)){
3855 $val=$ip."/".&General
::iporsubtodec
($cidr);
3856 $ccdroute2hash{$keypoint}[$i] = $val;
3858 $errormessage=$errormessage."Route ".$Lang::tr
{'ccd invalid'}." ($val)";
3862 $ccdroute2hash{$keypoint}[$i]='';
3866 &General
::writehasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
3869 if ($cgiparams{'CCD_DNS1'} ne '' && ! &General
::validip
($cgiparams{'CCD_DNS1'})) {
3870 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp dns'}." 1";
3874 if ($cgiparams{'CCD_DNS2'} ne '' && ! &General
::validip
($cgiparams{'CCD_DNS2'})) {
3875 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp dns'}." 2";
3879 if ($cgiparams{'CCD_WINS'} ne '' && ! &General
::validip
($cgiparams{'CCD_WINS'})) {
3880 $errormessage=$errormessage."<br>".$Lang::tr
{'invalid input for dhcp wins'};
3885 if ($cgiparams{'TYPE'} !~ /^(host|net)$/) {
3886 $errormessage = $Lang::tr
{'connection type is invalid'};
3887 if ($cgiparams{'TYPE'} eq 'net') {
3888 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3889 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3895 if ($cgiparams{'NAME'} !~ /^[a-zA-Z0-9]+$/) {
3896 $errormessage = $Lang::tr
{'name must only contain characters'};
3897 if ($cgiparams{'TYPE'} eq 'net') {
3903 if ($cgiparams{'NAME'} =~ /^(host|01|block|private|clear|packetdefault)$/) {
3904 $errormessage = $Lang::tr
{'name is invalid'};
3905 if ($cgiparams{'TYPE'} eq 'net') {
3906 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3907 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3913 if (length($cgiparams{'NAME'}) >60) {
3914 $errormessage = $Lang::tr
{'name too long'};
3915 if ($cgiparams{'TYPE'} eq 'net') {
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: $!";
3923 if ($cgiparams{'TYPE'} eq 'net') {
3924 if ($cgiparams{'DEST_PORT'} eq $vpnsettings{'DDEST_PORT'}) {
3925 $errormessage = $Lang::tr
{'openvpn destination port used'};
3926 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3927 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3931 foreach my $key (sort keys %confighash){
3932 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])){
3933 $errormessage = $Lang::tr
{'openvpn destination port used'};
3934 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3935 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3939 if ($cgiparams{'DEST_PORT'} eq '') {
3940 $errormessage = $Lang::tr
{'invalid port'};
3941 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3942 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3946 # Check if the input for the transfer net is valid.
3947 if (!&General
::validipandmask
($cgiparams{'OVPN_SUBNET'})){
3948 $errormessage = $Lang::tr
{'ccd err invalidnet'};
3949 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3950 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3954 if ($cgiparams{'OVPN_SUBNET'} eq $vpnsettings{'DOVPN_SUBNET'}) {
3955 $errormessage = $Lang::tr
{'openvpn subnet is used'};
3956 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3957 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3961 if (($cgiparams{'PROTOCOL'} eq 'tcp') && ($cgiparams{'MSSFIX'} eq 'on')) {
3962 $errormessage = $Lang::tr
{'openvpn mssfix allowed with udp'};
3963 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3964 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3968 if (($cgiparams{'PROTOCOL'} eq 'tcp') && ($cgiparams{'FRAGMENT'} ne '')) {
3969 $errormessage = $Lang::tr
{'openvpn fragment allowed with udp'};
3970 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3971 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3975 if (!&Network
::check_subnet
($cgiparams{'LOCAL_SUBNET'})) {
3976 $errormessage = $Lang::tr
{'openvpn prefix local subnet'};
3977 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3978 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3982 if (!&Network
::check_subnet
($cgiparams{'OVPN_SUBNET'})) {
3983 $errormessage = $Lang::tr
{'openvpn prefix openvpn subnet'};
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: $!";
3989 if (!&Network
::check_subnet
($cgiparams{'REMOTE_SUBNET'})) {
3990 $errormessage = $Lang::tr
{'openvpn prefix remote subnet'};
3991 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3992 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
3996 if ($cgiparams{'DEST_PORT'} <= 1023) {
3997 $errormessage = $Lang::tr
{'ovpn port in root range'};
3998 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
3999 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4003 if ($cgiparams{'OVPN_MGMT'} eq '') {
4004 $cgiparams{'OVPN_MGMT'} = $cgiparams{'DEST_PORT'};
4007 if ($cgiparams{'OVPN_MGMT'} <= 1023) {
4008 $errormessage = $Lang::tr
{'ovpn mgmt in root range'};
4009 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4010 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4013 #Check if remote subnet is used elsewhere
4014 my ($n2nip,$n2nsub)=split("/",$cgiparams{'REMOTE_SUBNET'});
4015 $warnmessage=&General
::checksubnets
('',$n2nip,'ovpn');
4017 $warnmessage=$Lang::tr
{'remote subnet'}." ($cgiparams{'REMOTE_SUBNET'}) <br>".$warnmessage;
4021 # Check if there is no other entry with this name
4022 if (! $cgiparams{'KEY'}) {
4023 foreach my $key (keys %confighash) {
4024 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
4025 $errormessage = $Lang::tr
{'a connection with this name already exists'};
4026 if ($cgiparams{'TYPE'} eq 'net') {
4027 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4028 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4035 # Check if a remote host/IP has been set for the client.
4036 if ($cgiparams{'TYPE'} eq 'net') {
4037 if ($cgiparams{'SIDE'} ne 'server' && $cgiparams{'REMOTE'} eq '') {
4038 $errormessage = $Lang::tr
{'invalid input for remote host/ip'};
4040 # Check if this is a N2N connection and drop temporary config.
4041 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4042 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4047 # Check if a remote host/IP has been configured - the field can be empty on the server side.
4048 if ($cgiparams{'REMOTE'} ne '') {
4049 # Check if the given IP is valid - otherwise check if it is a valid domain.
4050 if (! &General
::validip
($cgiparams{'REMOTE'})) {
4051 # Check for a valid domain.
4052 if (! &General
::validfqdn
($cgiparams{'REMOTE'})) {
4053 $errormessage = $Lang::tr
{'invalid input for remote host/ip'};
4055 # Check if this is a N2N connection and drop temporary config.
4056 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4057 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4065 if ($cgiparams{'TYPE'} ne 'host') {
4066 unless (&General
::validipandmask
($cgiparams{'LOCAL_SUBNET'})) {
4067 $errormessage = $Lang::tr
{'local subnet is invalid'};
4068 if ($cgiparams{'TYPE'} eq 'net') {
4069 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4070 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4072 goto VPNCONF_ERROR
;}
4074 # Check if there is no other entry without IP-address and PSK
4075 if ($cgiparams{'REMOTE'} eq '') {
4076 foreach my $key (keys %confighash) {
4077 if(($cgiparams{'KEY'} ne $key) &&
4078 ($confighash{$key}[4] eq 'psk' || $cgiparams{'AUTH'} eq 'psk') &&
4079 $confighash{$key}[10] eq '') {
4080 $errormessage = $Lang::tr
{'you can only define one roadwarrior connection when using pre-shared key authentication'};
4085 if (($cgiparams{'TYPE'} eq 'net') && (! &General
::validipandmask
($cgiparams{'REMOTE_SUBNET'}))) {
4086 $errormessage = $Lang::tr
{'remote subnet is invalid'};
4087 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4088 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4092 # Check for N2N that OpenSSL maximum of valid days will not be exceeded
4093 if ($cgiparams{'TYPE'} eq 'net') {
4094 if ($cgiparams{'DAYS_VALID'} >= '999999') {
4095 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4096 unlink ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}/$cgiparams{'NAME'}.conf") or die "Removing Configfile fail: $!";
4097 rmdir ("${General::swroot}/ovpn/n2nconf/$cgiparams{'NAME'}") || die "Removing Directory fail: $!";
4102 if ($cgiparams{'ENABLED'} !~ /^(on|off|)$/) {
4103 $errormessage = $Lang::tr
{'invalid input'};
4107 if ($cgiparams{'AUTH'} eq 'certreq') {
4108 if ($cgiparams{'KEY'}) {
4109 $errormessage = $Lang::tr
{'cant change certificates'};
4112 unless (ref ($cgiparams{'FH'})) {
4113 $errormessage = $Lang::tr
{'there was no file upload'};
4117 # Move uploaded certificate request to a temporary file
4118 (my $fh, my $filename) = tempfile
( );
4119 if (copy
($cgiparams{'FH'}, $fh) != 1) {
4124 # Sign the certificate request and move it
4125 # Sign the host certificate request
4126 # The system call is safe, because all arguments are passed as an array.
4127 system('/usr/bin/openssl', 'ca', '-days', "$cgiparams{'DAYS_VALID'}",
4128 '-batch', '-notext',
4130 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4131 '-config', "/usr/share/openvpn/ovpn.cnf");
4133 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4135 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4136 &cleanssldatabase
();
4140 &deletebackupcert
();
4143 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4146 foreach my $line (@temp) {
4147 if ($line =~ /Subject:.*CN\s?=\s?(.*)[\n]/) {
4149 $temp =~ s
+/Email
+, E
+;
4150 $temp =~ s/ ST=/ S=/;
4156 $cgiparams{'CERT_NAME'} = $temp;
4157 $cgiparams{'CERT_NAME'} =~ s/,//g;
4158 $cgiparams{'CERT_NAME'} =~ s/\'//g;
4159 if ($cgiparams{'CERT_NAME'} eq '') {
4160 $errormessage = $Lang::tr
{'could not retrieve common name from certificate'};
4163 } elsif ($cgiparams{'AUTH'} eq 'certfile') {
4164 if ($cgiparams{'KEY'}) {
4165 $errormessage = $Lang::tr
{'cant change certificates'};
4168 unless (ref ($cgiparams{'FH'})) {
4169 $errormessage = $Lang::tr
{'there was no file upload'};
4172 # Move uploaded certificate to a temporary file
4173 (my $fh, my $filename) = tempfile
( );
4174 if (copy
($cgiparams{'FH'}, $fh) != 1) {
4179 # Verify the certificate has a valid CA and move it
4181 my @test = &General
::system_output
("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/cacert.pem", "$filename");
4182 if (grep(/: OK/, @test)) {
4185 foreach my $key (keys %cahash) {
4186 @test = &General
::system_output
("/usr/bin/openssl", "verify", "-CAfile", "${General::swroot}/ovpn/ca/$cahash{$key}[0]cert.pem", "$filename");
4187 if (grep(/: OK/, @test)) {
4193 $errormessage = $Lang::tr
{'certificate does not have a valid ca associated with it'};
4197 unless(move
($filename, "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem")) {
4198 $errormessage = "$Lang::tr{'certificate file move failed'}: $!";
4204 my @temp = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4207 foreach my $line (@temp) {
4208 if ($line =~ /Subject:.*CN\s?=\s?(.*)[\n]/) {
4210 $temp =~ s
+/Email
+, E
+;
4211 $temp =~ s/ ST=/ S=/;
4217 $cgiparams{'CERT_NAME'} = $temp;
4218 $cgiparams{'CERT_NAME'} =~ s/,//g;
4219 $cgiparams{'CERT_NAME'} =~ s/\'//g;
4220 if ($cgiparams{'CERT_NAME'} eq '') {
4221 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4222 $errormessage = $Lang::tr
{'could not retrieve common name from certificate'};
4225 } elsif ($cgiparams{'AUTH'} eq 'certgen') {
4226 if ($cgiparams{'KEY'}) {
4227 $errormessage = $Lang::tr
{'cant change certificates'};
4230 # Validate input since the form was submitted
4231 if (length($cgiparams{'CERT_NAME'}) >60) {
4232 $errormessage = $Lang::tr
{'name too long'};
4235 if ($cgiparams{'CERT_NAME'} eq '' || $cgiparams{'CERT_NAME'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
4236 $errormessage = $Lang::tr
{'invalid input for name'};
4239 if ($cgiparams{'CERT_EMAIL'} ne '' && (! &General
::validemail
($cgiparams{'CERT_EMAIL'}))) {
4240 $errormessage = $Lang::tr
{'invalid input for e-mail address'};
4243 if (length($cgiparams{'CERT_EMAIL'}) > 40) {
4244 $errormessage = $Lang::tr
{'e-mail address too long'};
4247 if ($cgiparams{'CERT_OU'} ne '' && $cgiparams{'CERT_OU'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4248 $errormessage = $Lang::tr
{'invalid input for department'};
4251 if (length($cgiparams{'CERT_ORGANIZATION'}) >60) {
4252 $errormessage = $Lang::tr
{'organization too long'};
4255 if ($cgiparams{'CERT_ORGANIZATION'} !~ /^[a-zA-Z0-9 ,\.\-_]+$/) {
4256 $errormessage = $Lang::tr
{'invalid input for organization'};
4259 if ($cgiparams{'CERT_CITY'} ne '' && $cgiparams{'CERT_CITY'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4260 $errormessage = $Lang::tr
{'invalid input for city'};
4263 if ($cgiparams{'CERT_STATE'} ne '' && $cgiparams{'CERT_STATE'} !~ /^[a-zA-Z0-9 ,\.\-_]*$/) {
4264 $errormessage = $Lang::tr
{'invalid input for state or province'};
4267 if ($cgiparams{'CERT_COUNTRY'} !~ /^[A-Z]*$/) {
4268 $errormessage = $Lang::tr
{'invalid input for country'};
4271 if ($cgiparams{'CERT_PASS1'} ne '' && $cgiparams{'CERT_PASS2'} ne ''){
4272 if (length($cgiparams{'CERT_PASS1'}) < 5) {
4273 $errormessage = $Lang::tr
{'password too short'};
4277 if ($cgiparams{'CERT_PASS1'} ne $cgiparams{'CERT_PASS2'}) {
4278 $errormessage = $Lang::tr
{'passwords do not match'};
4281 if ($cgiparams{'DAYS_VALID'} eq '' && $cgiparams{'DAYS_VALID'} !~ /^[0-9]+$/) {
4282 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4286 # Check for RW that OpenSSL maximum of valid days will not be exceeded
4287 if ($cgiparams{'TYPE'} eq 'host') {
4288 if ($cgiparams{'DAYS_VALID'} >= '999999') {
4289 $errormessage = $Lang::tr
{'invalid input for valid till days'};
4294 # Check for RW if client name is already set
4295 if ($cgiparams{'TYPE'} eq 'host') {
4296 foreach my $key (keys %confighash) {
4297 if ($confighash{$key}[1] eq $cgiparams{'NAME'}) {
4298 $errormessage = $Lang::tr
{'a connection with this name already exists'};
4304 # Check if there is no other entry with this common name
4305 if ((! $cgiparams{'KEY'}) && ($cgiparams{'AUTH'} ne 'psk')) {
4306 foreach my $key (keys %confighash) {
4307 if ($confighash{$key}[2] eq $cgiparams{'CERT_NAME'}) {
4308 $errormessage = $Lang::tr
{'a connection with this common name already exists'};
4314 # Replace empty strings with a .
4315 (my $ou = $cgiparams{'CERT_OU'}) =~ s/^\s*$/\./;
4316 (my $city = $cgiparams{'CERT_CITY'}) =~ s/^\s*$/\./;
4317 (my $state = $cgiparams{'CERT_STATE'}) =~ s/^\s*$/\./;
4319 # Create the Host certificate request client
4320 my $pid = open(OPENSSL
, "|-");
4321 $SIG{ALRM
} = sub { $errormessage = $Lang::tr
{'broken pipe'}; goto VPNCONF_ERROR
;};
4322 if ($pid) { # parent
4323 print OPENSSL
"$cgiparams{'CERT_COUNTRY'}\n";
4324 print OPENSSL
"$state\n";
4325 print OPENSSL
"$city\n";
4326 print OPENSSL
"$cgiparams{'CERT_ORGANIZATION'}\n";
4327 print OPENSSL
"$ou\n";
4328 print OPENSSL
"$cgiparams{'CERT_NAME'}\n";
4329 print OPENSSL
"$cgiparams{'CERT_EMAIL'}\n";
4330 print OPENSSL
".\n";
4331 print OPENSSL
".\n";
4334 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4335 unlink ("${General::swroot}ovpn/certs/$cgiparams{'NAME'}key.pem");
4336 unlink ("${General::swroot}ovpn/certs/$cgiparams{'NAME'}req.pem");
4340 unless (exec ('/usr/bin/openssl', 'req', '-nodes',
4341 '-newkey', 'rsa:4096',
4342 '-keyout', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem",
4343 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem",
4344 '-config', "/usr/share/openvpn/ovpn.cnf")) {
4345 $errormessage = "$Lang::tr{'cant start openssl'}: $!";
4346 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4347 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4352 # Sign the host certificate request
4353 # The system call is safe, because all arguments are passed as an array.
4354 system('/usr/bin/openssl', 'ca', '-days', "$cgiparams{'DAYS_VALID'}",
4355 '-batch', '-notext',
4356 '-in', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem",
4357 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4358 '-config', "/usr/share/openvpn/ovpn.cnf");
4360 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4361 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4362 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4363 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4364 &cleanssldatabase
();
4367 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}req.pem");
4368 &deletebackupcert
();
4371 # Create the pkcs12 file
4372 # The system call is safe, because all arguments are passed as an array.
4373 system('/usr/bin/openssl', 'pkcs12', '-export',
4374 '-inkey', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem",
4375 '-in', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem",
4376 '-name', $cgiparams{'NAME'},
4377 '-passout', "pass:$cgiparams{'CERT_PASS1'}",
4378 '-certfile', "${General::swroot}/ovpn/ca/cacert.pem",
4379 '-caname', "$vpnsettings{'ROOTCERT_ORGANIZATION'} CA",
4380 '-out', "${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12");
4382 $errormessage = "$Lang::tr{'openssl produced an error'}: $?";
4383 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4384 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}cert.pem");
4385 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}.p12");
4388 unlink ("${General::swroot}/ovpn/certs/$cgiparams{'NAME'}key.pem");
4390 } elsif ($cgiparams{'AUTH'} eq 'cert') {
4391 ;# Nothing, just editing
4393 $errormessage = $Lang::tr
{'invalid input for authentication method'};
4398 my $key = $cgiparams{'KEY'};
4401 $key = &General
::findhasharraykey
(\
%confighash);
4402 foreach my $i (0 .. 43) { $confighash{$key}[$i] = "";}
4404 $confighash{$key}[0] = $cgiparams{'ENABLED'};
4405 $confighash{$key}[1] = $cgiparams{'NAME'};
4406 if ((! $cgiparams{'KEY'}) && $cgiparams{'AUTH'} ne 'psk') {
4407 $confighash{$key}[2] = $cgiparams{'CERT_NAME'};
4410 $confighash{$key}[3] = $cgiparams{'TYPE'};
4411 if ($cgiparams{'AUTH'} eq 'psk') {
4412 $confighash{$key}[4] = 'psk';
4413 $confighash{$key}[5] = $cgiparams{'PSK'};
4415 $confighash{$key}[4] = 'cert';
4417 if ($cgiparams{'TYPE'} eq 'net') {
4418 $confighash{$key}[6] = $cgiparams{'SIDE'};
4419 $confighash{$key}[11] = $cgiparams{'REMOTE_SUBNET'};
4421 $confighash{$key}[8] = $cgiparams{'LOCAL_SUBNET'};
4422 $confighash{$key}[10] = $cgiparams{'REMOTE'};
4423 if ($cgiparams{'OVPN_MGMT'} eq '') {
4424 $confighash{$key}[22] = $confighash{$key}[29];
4426 $confighash{$key}[22] = $cgiparams{'OVPN_MGMT'};
4428 $confighash{$key}[23] = $cgiparams{'MSSFIX'};
4429 $confighash{$key}[24] = $cgiparams{'FRAGMENT'};
4430 $confighash{$key}[25] = $cgiparams{'REMARK'};
4431 $confighash{$key}[26] = $cgiparams{'INTERFACE'};
4433 $confighash{$key}[27] = $cgiparams{'OVPN_SUBNET'};
4434 $confighash{$key}[28] = $cgiparams{'PROTOCOL'};
4435 $confighash{$key}[29] = $cgiparams{'DEST_PORT'};
4436 $confighash{$key}[30] = $cgiparams{'COMPLZO'};
4437 $confighash{$key}[31] = $cgiparams{'MTU'};
4438 $confighash{$key}[32] = $cgiparams{'CHECK1'};
4439 $name=$cgiparams{'CHECK1'};
4440 $confighash{$key}[33] = $cgiparams{$name};
4441 $confighash{$key}[34] = $cgiparams{'RG'};
4442 $confighash{$key}[35] = $cgiparams{'CCD_DNS1'};
4443 $confighash{$key}[36] = $cgiparams{'CCD_DNS2'};
4444 $confighash{$key}[37] = $cgiparams{'CCD_WINS'};
4445 $confighash{$key}[39] = $cgiparams{'DAUTH'};
4446 $confighash{$key}[40] = $cgiparams{'DCIPHER'};
4448 if ($confighash{$key}[41] eq "") {
4449 if (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} eq "")) {
4450 $confighash{$key}[41] = "no-pass";
4451 } elsif (($cgiparams{'TYPE'} eq 'host') && ($cgiparams{'CERT_PASS1'} ne "")) {
4452 $confighash{$key}[41] = "pass";
4453 } elsif ($cgiparams{'TYPE'} eq 'net') {
4454 $confighash{$key}[41] = "no-pass";
4458 $confighash{$key}[42] = 'HOTP/T30/6';
4459 $confighash{$key}[43] = $cgiparams{'OTP_STATE'};
4460 if (($confighash{$key}[43] eq 'on') && ($confighash{$key}[44] eq '')) {
4461 my @otp_secret = &General
::system_output
("/usr/bin/openssl", "rand", "-hex", "20");
4462 chomp($otp_secret[0]);
4463 $confighash{$key}[44] = $otp_secret[0];
4464 } elsif ($confighash{$key}[43] eq '') {
4465 $confighash{$key}[44] = '';
4468 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4470 # Rewrite the server configuration
4473 if ($cgiparams{'TYPE'} eq 'net') {
4475 if (-e
"/var/run/$confighash{$key}[1]n2n.pid") {
4476 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "stop", "$confighash{$cgiparams{'KEY'}}[1]");
4478 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4479 my $key = $cgiparams{'KEY'};
4481 $key = &General
::findhasharraykey
(\
%confighash);
4482 foreach my $i (0 .. 31) {
4483 $confighash{$key}[$i] = "";
4487 $confighash{$key}[0] = 'on';
4488 &General
::writehasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
4490 &General
::system("/usr/local/bin/openvpnctrl", "n2n", "start", "$confighash{$cgiparams{'KEY'}}[1]");
4496 $cgiparams{'ENABLED'} = 'on';
4497 $cgiparams{'MSSFIX'} = 'on';
4498 $cgiparams{'FRAGMENT'} = '1300';
4499 $cgiparams{'DAUTH'} = 'SHA512';
4500 $cgiparams{'SIDE'} = 'left';
4501 if ( ! -f
"${General::swroot}/ovpn/ca/cakey.pem" ) {
4502 $cgiparams{'AUTH'} = 'psk';
4503 } elsif ( ! -f
"${General::swroot}/ovpn/ca/cacert.pem") {
4504 $cgiparams{'AUTH'} = 'certfile';
4506 $cgiparams{'AUTH'} = 'certgen';
4508 $cgiparams{'LOCAL_SUBNET'} ="$Network::ethernet{'GREEN_NETADDRESS'}/$Network::ethernet{'GREEN_NETMASK'}";
4509 $cgiparams{'CERT_ORGANIZATION'} = $vpnsettings{'ROOTCERT_ORGANIZATION'};
4510 $cgiparams{'CERT_CITY'} = $vpnsettings{'ROOTCERT_CITY'};
4511 $cgiparams{'CERT_STATE'} = $vpnsettings{'ROOTCERT_STATE'};
4512 $cgiparams{'CERT_COUNTRY'} = $vpnsettings{'ROOTCERT_COUNTRY'};
4513 $cgiparams{'DAYS_VALID'} = $vpnsettings{'DAYS_VALID'} = '730';
4517 $checked{'ENABLED'}{'off'} = '';
4518 $checked{'ENABLED'}{'on'} = '';
4519 $checked{'ENABLED'}{$cgiparams{'ENABLED'}} = 'CHECKED';
4521 $checked{'OTP_STATE'}{$cgiparams{'OTP_STATE'}} = 'CHECKED';
4523 $selected{'SIDE'}{'server'} = '';
4524 $selected{'SIDE'}{'client'} = '';
4525 $selected{'SIDE'}{$cgiparams{'SIDE'}} = 'SELECTED';
4527 $selected{'PROTOCOL'}{'udp'} = '';
4528 $selected{'PROTOCOL'}{'tcp'} = '';
4529 $selected{'PROTOCOL'}{$cgiparams{'PROTOCOL'}} = 'SELECTED';
4532 $checked{'AUTH'}{'psk'} = '';
4533 $checked{'AUTH'}{'certreq'} = '';
4534 $checked{'AUTH'}{'certgen'} = '';
4535 $checked{'AUTH'}{'certfile'} = '';
4536 $checked{'AUTH'}{$cgiparams{'AUTH'}} = 'CHECKED';
4538 $selected{'INTERFACE'}{$cgiparams{'INTERFACE'}} = 'SELECTED';
4540 $checked{'COMPLZO'}{'off'} = '';
4541 $checked{'COMPLZO'}{'on'} = '';
4542 $checked{'COMPLZO'}{$cgiparams{'COMPLZO'}} = 'CHECKED';
4544 $checked{'MSSFIX'}{'off'} = '';
4545 $checked{'MSSFIX'}{'on'} = '';
4546 $checked{'MSSFIX'}{$cgiparams{'MSSFIX'}} = 'CHECKED';
4548 $selected{'DCIPHER'}{'AES-256-GCM'} = '';
4549 $selected{'DCIPHER'}{'AES-192-GCM'} = '';
4550 $selected{'DCIPHER'}{'AES-128-GCM'} = '';
4551 $selected{'DCIPHER'}{'CAMELLIA-256-CBC'} = '';
4552 $selected{'DCIPHER'}{'CAMELLIA-192-CBC'} = '';
4553 $selected{'DCIPHER'}{'CAMELLIA-128-CBC'} = '';
4554 $selected{'DCIPHER'}{'AES-256-CBC'} = '';
4555 $selected{'DCIPHER'}{'AES-192-CBC'} = '';
4556 $selected{'DCIPHER'}{'AES-128-CBC'} = '';
4557 $selected{'DCIPHER'}{'DESX-CBC'} = '';
4558 $selected{'DCIPHER'}{'SEED-CBC'} = '';
4559 $selected{'DCIPHER'}{'DES-EDE3-CBC'} = '';
4560 $selected{'DCIPHER'}{'DES-EDE-CBC'} = '';
4561 $selected{'DCIPHER'}{'CAST5-CBC'} = '';
4562 $selected{'DCIPHER'}{'BF-CBC'} = '';
4563 $selected{'DCIPHER'}{'DES-CBC'} = '';
4564 $selected{'DCIPHER'}{$cgiparams{'DCIPHER'}} = 'SELECTED';
4565 $selected{'DAUTH'}{'whirlpool'} = '';
4566 $selected{'DAUTH'}{'SHA512'} = '';
4567 $selected{'DAUTH'}{'SHA384'} = '';
4568 $selected{'DAUTH'}{'SHA256'} = '';
4569 $selected{'DAUTH'}{'SHA1'} = '';
4570 $selected{'DAUTH'}{$cgiparams{'DAUTH'}} = 'SELECTED';
4571 $checked{'TLSAUTH'}{'off'} = '';
4572 $checked{'TLSAUTH'}{'on'} = '';
4573 $checked{'TLSAUTH'}{$cgiparams{'TLSAUTH'}} = 'CHECKED';
4576 &Header
::showhttpheaders
();
4577 &Header
::openpage
($Lang::tr
{'ovpn'}, 1, '');
4578 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
4581 &Header
::errorbox
($errormessage);
4584 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'warning messages'}:");
4585 print "<class name='base'>$warnmessage";
4586 print " </class>";
4587 &Header
::closebox
();
4590 print "<form method='post' enctype='multipart/form-data'>";
4591 print "<input type='hidden' name='TYPE' value='$cgiparams{'TYPE'}' />";
4593 if ($cgiparams{'KEY'}) {
4594 print "<input type='hidden' name='KEY' value='$cgiparams{'KEY'}' />";
4595 print "<input type='hidden' name='AUTH' value='$cgiparams{'AUTH'}' />";
4598 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'connection'}:");
4600 my $readonly = ($cgiparams{'KEY'}) ? "readonly" : "";
4603 <table class="form">
4609 <input type="text" name="NAME" value="$cgiparams{'NAME'}" $readonly/>
4615 $Lang::tr{'remark title'}
4618 <input type="text" name="REMARK" value="$cgiparams{'REMARK'}" />
4623 if ($cgiparams{'TYPE'} eq 'host') {
4627 $Lang::tr{'enabled'}
4630 <input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} />
4636 $Lang::tr{'enable otp'}
4639 <input type='checkbox' name='OTP_STATE' $checked{'OTP_STATE'}{'on'} />
4645 if ($cgiparams{'TYPE'} eq 'net') {
4646 # If GCM ciphers are in usage, HMAC menu is disabled
4648 if (($confighash{$cgiparams{'KEY'}}[40] eq 'AES-256-GCM') ||
4649 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-192-GCM') ||
4650 ($confighash{$cgiparams{'KEY'}}[40] eq 'AES-128-GCM')) {
4651 $hmacdisabled = "disabled='disabled'";
4656 <td>$Lang::tr{'Act as'}</td>
4658 <select name='SIDE'>
4659 <option value='server' $selected{'SIDE'}{'server'}>$Lang::tr{'openvpn server'}</option>
4660 <option value='client' $selected{'SIDE'}{'client'}>$Lang::tr{'openvpn client'}</option>
4666 <td>$Lang::tr{'remote host/ip'}:</td>
4668 <input type='TEXT' name='REMOTE' value='$cgiparams{'REMOTE'}' />
4673 <td>$Lang::tr{'local subnet'} <img src='/blob.gif' alt='*' /></td>
4675 <input type='TEXT' name='LOCAL_SUBNET' value='$cgiparams{'LOCAL_SUBNET'}' />
4680 <td>$Lang::tr{'remote subnet'} <img src='/blob.gif' alt='*' /></td>
4682 <input type='text' name='REMOTE_SUBNET' value='$cgiparams{'REMOTE_SUBNET'}' />
4687 <td>$Lang::tr{'ovpn subnet'} <img src='/blob.gif' alt='*' /></td>
4689 <input type='TEXT' name='OVPN_SUBNET' value='$cgiparams{'OVPN_SUBNET'}' />
4694 <td>$Lang::tr{'protocol'}</td>
4696 <select name='PROTOCOL'>
4697 <option value='udp' $selected{'PROTOCOL'}{'udp'}>UDP</option>
4698 <option value='tcp' $selected{'PROTOCOL'}{'tcp'}>TCP</option>
4704 <td>$Lang::tr{'destination port'}: <img src='/blob.gif' alt='*' /></td>
4706 <input type='TEXT' name='DEST_PORT' value='$cgiparams{'DEST_PORT'}' size='5' />
4711 <td>Management Port ($Lang::tr{'openvpn default'}: <span class="base">$Lang::tr{'destination port'}):</td>
4713 <input type='TEXT' name='OVPN_MGMT' VALUE='$cgiparams{'OVPN_MGMT'}'size='5' />
4719 $Lang::tr{'MTU settings'}
4722 <table class="form">
4724 <td>$Lang::tr{'MTU'}</td>
4726 <input type='TEXT' name='MTU' VALUE='$cgiparams{'MTU'}'size='5' />
4733 <input type='TEXT' name='FRAGMENT' VALUE='$cgiparams{'FRAGMENT'}'size='5' />
4740 <input type='checkbox' name='MSSFIX' $checked{'MSSFIX'}{'on'} />
4745 <td>$Lang::tr{'comp-lzo'}</td>
4747 <input type='checkbox' name='COMPLZO' $checked{'COMPLZO'}{'on'} />
4753 $Lang::tr{'ovpn crypto settings'}:
4756 <table class="form">
4758 <td>$Lang::tr{'cipher'}</td>
4760 <select name='DCIPHER' id="n2ncipher" required>
4761 <option value='AES-256-GCM' $selected{'DCIPHER'}{'AES-256-GCM'}>AES-GCM (256 $Lang::tr{'bit'})</option>
4762 <option value='AES-192-GCM' $selected{'DCIPHER'}{'AES-192-GCM'}>AES-GCM (192 $Lang::tr{'bit'})</option>
4763 <option value='AES-128-GCM' $selected{'DCIPHER'}{'AES-128-GCM'}>AES-GCM (128 $Lang::tr{'bit'})</option>
4764 <option value='CAMELLIA-256-CBC' $selected{'DCIPHER'}{'CAMELLIA-256-CBC'}>CAMELLIA-CBC (256 $Lang::tr{'bit'})</option>
4765 <option value='CAMELLIA-192-CBC' $selected{'DCIPHER'}{'CAMELLIA-192-CBC'}>CAMELLIA-CBC (192 $Lang::tr{'bit'})</option>
4766 <option value='CAMELLIA-128-CBC' $selected{'DCIPHER'}{'CAMELLIA-128-CBC'}>CAMELLIA-CBC (128 $Lang::tr{'bit'})</option>
4767 <option value='AES-256-CBC' $selected{'DCIPHER'}{'AES-256-CBC'}>AES-CBC (256 $Lang::tr{'bit'}, $Lang::tr{'default'})</option>
4768 <option value='AES-192-CBC' $selected{'DCIPHER'}{'AES-192-CBC'}>AES-CBC (192 $Lang::tr{'bit'})</option>
4769 <option value='AES-128-CBC' $selected{'DCIPHER'}{'AES-128-CBC'}>AES-CBC (128 $Lang::tr{'bit'})</option>
4770 <option value='SEED-CBC' $selected{'DCIPHER'}{'SEED-CBC'}>SEED-CBC (128 $Lang::tr{'bit'})</option>
4771 <option value='DES-EDE3-CBC' $selected{'DCIPHER'}{'DES-EDE3-CBC'}>DES-EDE3-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4772 <option value='DESX-CBC' $selected{'DCIPHER'}{'DESX-CBC'}>DESX-CBC (192 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4773 <option value='DES-EDE-CBC' $selected{'DCIPHER'}{'DES-EDE-CBC'}>DES-EDE-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4774 <option value='BF-CBC' $selected{'DCIPHER'}{'BF-CBC'}>BF-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4775 <option value='CAST5-CBC' $selected{'DCIPHER'}{'CAST5-CBC'}>CAST5-CBC (128 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4781 <td>$Lang::tr{'ovpn ha'}:</td>
4783 <select name='DAUTH' id="n2nhmac" $hmacdisabled>
4784 <option value='whirlpool' $selected{'DAUTH'}{'whirlpool'}>Whirlpool (512 $Lang::tr{'bit'})</option>
4785 <option value='SHA512' $selected{'DAUTH'}{'SHA512'}>SHA2 (512 $Lang::tr{'bit'})</option>
4786 <option value='SHA384' $selected{'DAUTH'}{'SHA384'}>SHA2 (384 $Lang::tr{'bit'})</option>
4787 <option value='SHA256' $selected{'DAUTH'}{'SHA256'}>SHA2 (256 $Lang::tr{'bit'})</option>
4788 <option value='SHA1' $selected{'DAUTH'}{'SHA1'}>SHA1 (160 $Lang::tr{'bit'}, $Lang::tr{'vpn weak'})</option>
4796 #### JAVA SCRIPT ####
4797 # Validate N2N cipher. If GCM will be used, HMAC menu will be disabled onchange
4800 var disable_options = false;
4801 document.getElementById('n2ncipher').onchange = function () {
4802 if((this.value == "AES-256-GCM"||this.value == "AES-192-GCM"||this.value == "AES-128-GCM")) {
4803 document.getElementById('n2nhmac').setAttribute('disabled', true);
4805 document.getElementById('n2nhmac').removeAttribute('disabled');
4812 if ($cgiparams{'TYPE'} eq 'host') {
4813 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>";
4816 &General
::readhash
("${General::swroot}/ovpn/settings", \
%vpnnet);
4817 $vpnip=$vpnnet{'DOVPN_SUBNET'};
4818 &General
::readhasharray
("${General::swroot}/ovpn/ccd.conf", \
%ccdconfhash);
4822 $checked{'check1'}{'off'} = '';
4823 $checked{'check1'}{'on'} = '';
4824 $checked{'check1'}{$cgiparams{'CHECK1'}} = 'CHECKED';
4825 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%'>";
4826 print"</td></tr></table><br><br>";
4827 my $name=$cgiparams{'CHECK1'};
4828 $checked{'RG'}{$cgiparams{'RG'}} = 'CHECKED';
4830 if (! -z
"${General::swroot}/ovpn/ccd.conf"){
4831 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>";
4832 foreach my $key (sort { uc($ccdconfhash{$a}[0]) cmp uc($ccdconfhash{$b}[0]) } keys %ccdconfhash) {
4834 @ccdconf=($ccdconfhash{$key}[0],$ccdconfhash{$key}[1]);
4835 if ($count % 2){print"<tr bgcolor='$Header::color{'color22'}'>";}else{print"<tr bgcolor='$Header::color{'color20'}'>";}
4836 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%'>";
4837 &fillselectbox
($ccdconf[0], $ccdconf[1], &convert_top30_ccd_allocation
($cgiparams{$name}));
4840 print "</table><br><br><hr><br><br>";
4844 &Header
::closebox
();
4845 if ($cgiparams{'KEY'} && $cgiparams{'AUTH'} eq 'psk') {
4847 } elsif (! $cgiparams{'KEY'}) {
4851 my $cakeydisabled='';
4852 my $cacrtdisabled='';
4853 if ( ! -f
"${General::swroot}/ovpn/ca/cakey.pem" ) { $cakeydisabled = "disabled='disabled'" } else { $cakeydisabled = "" };
4854 if ( ! -f
"${General::swroot}/ovpn/ca/cacert.pem" ) { $cacrtdisabled = "disabled='disabled'" } else { $cacrtdisabled = "" };
4856 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'authentication'});
4859 if ($cgiparams{'TYPE'} eq 'host') {
4862 <table width='100%' cellpadding='0' cellspacing='5' border='0'>
4864 <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>
4865 <tr><td><input type='radio' name='AUTH' value='certfile' $checked{'AUTH'}{'certfile'} $cacrtdisabled /></td><td class='base'>$Lang::tr{'upload a certificate'}</td></tr>
4866 <tr><td colspan='3'> </td></tr>
4867 <tr><td colspan='3'><hr /></td></tr>
4868 <tr><td colspan='3'> </td></tr>
4869 <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>
4870 <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>
4871 <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>
4872 <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>
4873 <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>
4874 <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>
4875 <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>
4876 <tr><td> </td><td class='base'>$Lang::tr{'country'}:</td><td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
4883 <table width='100%' cellpadding='0' cellspacing='5' border='0'>
4885 <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>
4886 <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>
4887 <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>
4888 <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>
4889 <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>
4890 <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>
4891 <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>
4892 <tr><td> </td><td class='base'>$Lang::tr{'country'}:</td><td class='base'><select name='CERT_COUNTRY' $cakeydisabled>
4900 foreach my $country (sort keys %{Countries
::countries
}) {
4901 print "<option value='$Countries::countries{$country}'";
4902 if ( $Countries::countries
{$country} eq $cgiparams{'CERT_COUNTRY'} ) {
4903 print " selected='selected'";
4905 print ">$country</option>";
4908 if ($cgiparams{'TYPE'} eq 'host') {
4911 <td> </td><td class='base'>$Lang::tr{'valid till'} (days): <img src='/blob.gif' alt='*' /</td>
4912 <td class='base' nowrap='nowrap'><input type='text' name='DAYS_VALID' value='$cgiparams{'DAYS_VALID'}' size='32' $cakeydisabled /></td></tr>
4914 <td class='base'>$Lang::tr{'pkcs12 file password'}:</td>
4915 <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS1' value='$cgiparams{'CERT_PASS1'}' size='32' $cakeydisabled /></td></tr>
4916 <tr><td> </td><td class='base'>$Lang::tr{'pkcs12 file password'}:<br>($Lang::tr{'confirmation'})</td>
4917 <td class='base' nowrap='nowrap'><input type='password' name='CERT_PASS2' value='$cgiparams{'CERT_PASS2'}' size='32' $cakeydisabled /></td></tr>
4918 <tr><td colspan='3'> </td></tr>
4919 <tr><td colspan='3'><hr /></td></tr>
4920 <tr><td class='base' colspan='3' align='left'><img src='/blob.gif' alt='*' /> $Lang::tr{'required field'}</td></tr>
4926 <td> </td><td class='base'>$Lang::tr{'valid till'} (days): <img src='/blob.gif' alt='*' /</td>
4927 <td class='base' nowrap='nowrap'><input type='text' name='DAYS_VALID' value='$cgiparams{'DAYS_VALID'}' size='32' $cakeydisabled /></td></tr>
4928 <tr><td> </td><td> </td><td> </td></tr>
4929 <tr><td> </td><td> </td><td> </td></tr>
4930 <tr><td colspan='3'><hr /></td></tr>
4931 <tr><td class='base' colspan='3' align='left'><img src='/blob.gif' alt='*' /> $Lang::tr{'required field'}</td></tr>
4937 &Header
::closebox
();
4941 if ($cgiparams{'TYPE'} eq 'host') {
4943 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'ccd client options'}:");
4947 <table border='0' width='100%'>
4948 <tr><td width='20%'>Redirect Gateway:</td><td colspan='3'><input type='checkbox' name='RG' $checked{'RG'}{'on'} /></td></tr>
4949 <tr><td colspan='4'><b><br>$Lang::tr{'ccd routes'}</b></td></tr>
4950 <tr><td colspan='4'> </td></tr>
4951 <tr><td valign='top'>$Lang::tr{'ccd iroute'}</td><td align='left' width='30%'><textarea name='IR' cols='26' rows='6' wrap='off'>
4954 if ($cgiparams{'IR'} ne ''){
4955 print $cgiparams{'IR'};
4957 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute", \
%ccdroutehash);
4958 foreach my $key (keys %ccdroutehash) {
4959 if( $cgiparams{'NAME'} eq $ccdroutehash{$key}[0]){
4960 foreach my $i (1 .. $#{$ccdroutehash{$key}}) {
4961 if ($ccdroutehash{$key}[$i] ne ''){
4962 print $ccdroutehash{$key}[$i]."\n";
4964 $cgiparams{'IR'} .= $ccdroutehash{$key}[$i];
4971 </textarea></td><td valign='top' colspan='2'></td></tr>
4972 <tr><td colspan='4'><br></td></tr>
4973 <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>
4987 open(FILE
, "${General::swroot}/main/routing") ;
4990 &General
::readhasharray
("${General::swroot}/ovpn/ccdroute2", \
%ccdroute2hash);
4992 foreach my $key (keys %ccdroute2hash) {
4993 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
4994 if ($ccdroute2hash{$key}[1] eq ''){
5001 print"<option>$Lang::tr{'ccd none'}</option>";
5003 print"<option selected>$Lang::tr{'ccd none'}</option>";
5005 #check if static routes are defined for client
5006 foreach my $line (@current) {
5008 $line=~s/\s*$//g; # remove newline
5009 @temp=split(/\,/,$line);
5010 $temp[1] = '' unless defined $temp[1]; # not always populated
5011 my ($a,$b) = split(/\//,$temp[1]);
5012 $temp[1] = $a."/".&General
::iporsubtocidr
($b);
5013 foreach my $key (keys %ccdroute2hash) {
5014 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
5015 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
5016 if($ccdroute2hash{$key}[$i] eq $a."/".&General
::iporsubtodec
($b)){
5022 if ($set == '1' && $#temp != -1){ print"<option selected>$temp[1]</option>";$set=0;}elsif($set == '0' && $#temp != -1){print"<option>$temp[1]</option>";}
5026 &General
::readhasharray
("${General::swroot}/vpn/config", \
%vpnconfig);
5027 foreach my $vpn (keys %vpnconfig) {
5028 # Skip all disabled VPN connections
5029 my $enabled = $vpnconfig{$vpn}[0];
5030 next unless ($enabled eq "on");
5032 my $name = $vpnconfig{$vpn}[1];
5035 my @networks = split(/\|/, $vpnconfig{$vpn}[11]);
5036 foreach my $network (@networks) {
5039 foreach my $key (keys %ccdroute2hash) {
5040 if ($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}) {
5041 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
5042 if ($ccdroute2hash{$key}[$i] eq $network) {
5043 $selected = "selected";
5049 print "<option value=\"$network\" $selected>$name ($network)</option>\n";
5053 #check if green,blue,orange are defined for client
5054 foreach my $key (keys %ccdroute2hash) {
5055 if($ccdroute2hash{$key}[0] eq $cgiparams{'NAME'}){
5057 foreach my $i (1 .. $#{$ccdroute2hash{$key}}) {
5058 if ($ccdroute2hash{$key}[$i] eq $Network::ethernet
{'GREEN_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'GREEN_NETMASK'})){
5061 if (&Header
::blue_used
()){
5062 if( $ccdroute2hash{$key}[$i] eq $Network::ethernet
{'BLUE_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'BLUE_NETMASK'})) {
5066 if (&Header
::orange_used
()){
5067 if( $ccdroute2hash{$key}[$i] eq $Network::ethernet
{'ORANGE_NETADDRESS'}."/".&General
::iporsubtodec
($Network::ethernet
{'ORANGE_NETMASK'}) ) {
5074 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>";}
5075 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>";}
5076 if ($selgreen == '1' || $other == '0'){ print"<option selected>$Lang::tr{'green'}</option>";$set=0;}else{print"<option>$Lang::tr{'green'}</option>";};
5079 </select></td><td valign='top'>DNS1:</td><td valign='top'><input type='TEXT' name='CCD_DNS1' value='$cgiparams{'CCD_DNS1'}' size='30' /></td></tr>
5080 <tr valign='top'><td>DNS2:</td><td><input type='TEXT' name='CCD_DNS2' value='$cgiparams{'CCD_DNS2'}' size='30' /></td></tr>
5081 <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>
5085 &Header
::closebox
();
5087 print "<div align='center'><input type='submit' name='ACTION' value='$Lang::tr{'save'}' />";
5088 print "<input type='submit' name='ACTION' value='$Lang::tr{'cancel'}' /></div></form>";
5089 &Header
::closebigbox
();
5090 &Header
::closepage
();
5098 &General
::readhasharray
("${General::swroot}/ovpn/caconfig", \
%cahash);
5099 &General
::readhasharray
("${General::swroot}/ovpn/ovpnconfig", \
%confighash);
5103 # Only load status when the RW server is enabled
5104 if ($vpnsettings{'ENABLED'} eq 'on') {
5105 open(FILE
, "/usr/local/bin/openvpnctrl rw log |");
5110 $checked{'ENABLED'}{'off'} = '';
5111 $checked{'ENABLED'}{'on'} = '';
5112 $checked{'ENABLED'}{$vpnsettings{'ENABLED'}} = 'CHECKED';
5114 &Header
::showhttpheaders
();
5115 &Header
::openpage
($Lang::tr
{'status ovpn'}, 1, '');
5116 &Header
::openbigbox
('100%', 'LEFT', '', $errormessage);
5120 # Check if a legacy cipher is being used
5121 if (&is_legacy_cipher
($vpnsettings{'DCIPHER'})) {
5122 push(@warnings, $Lang::tr
{'ovpn legacy cipher used'});
5125 # Check if a legacy auth algorithm is being used
5126 if (&is_legacy_auth
($vpnsettings{'DAUTH'})) {
5127 push(@warnings, $Lang::tr
{'ovpn legacy auth used'});
5130 # Show any errors and warnings
5131 &Header
::errorbox
($errormessage);
5134 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'warning messages'});
5135 print "$warnmessage<br>";
5136 print "$Lang::tr{'fwdfw warn1'}<br>";
5137 &Header
::closebox
();
5138 print"<center><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'ok'}' style='width: 5em;'></form>";
5139 &Header
::closepage
();
5143 &Header
::warningbox
(@warnings);
5145 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'ovpn roadwarrior settings'});
5147 # Show the service status
5148 &Header
::ServiceStatus
({
5149 $Lang::tr
{'ovpn roadwarrior server'} => {
5150 "process" => "openvpn",
5151 "pidfile" => "/var/run/openvpn-rw.pid",
5156 <form method='POST'>
5157 <table class="form">
5159 <td class='boldbase'>
5160 $Lang::tr{'enabled'}
5163 <input type='checkbox' name='ENABLED' $checked{'ENABLED'}{'on'} />
5168 <td colspan='2'></td>
5173 $Lang::tr{'ovpn fqdn'}
5176 <input type='text' name='VPN_IP' value='$vpnsettings{'VPN_IP'}' />
5182 $Lang::tr{'ovpn dynamic client subnet'}
5185 <input type='TEXT' name='DOVPN_SUBNET' value='$vpnsettings{'DOVPN_SUBNET'}' />
5191 <input type='submit' name='ACTION' value='$Lang::tr{'save'}' />
5192 <input type='submit' name='ACTION' value='$Lang::tr{'ccd net'}' />
5193 <input type='submit' name='ACTION' value='$Lang::tr{'advanced server'}' />
5200 &Header
::closebox
();
5202 &Header
::openbox
('100%', 'LEFT', $Lang::tr
{'connection status and controlc' });
5218 <th width='5%' colspan='8'>
5226 foreach my $key (sort { ncmp
($confighash{$a}[1],$confighash{$b}[1]) } keys %confighash) {
5227 my $status = $confighash{$key}[0];
5228 my $name = $confighash{$key}[1];
5229 my $type = $confighash{$key}[3];
5231 # Create some simple booleans to check the status
5233 my $expiresSoon = 0;
5235 # Fetch information about the certificate for non-N2N connections only
5236 if ($confighash{$key}[3] ne 'net') {
5237 my @cavalid = &General
::system_output
("/usr/bin/openssl", "x509", "-text",
5238 "-in", "${General::swroot}/ovpn/certs/$confighash{$key}[1]cert.pem");
5242 # Parse the certificate information
5243 foreach my $line (@cavalid) {
5244 if ($line =~ /Not After : (.*)[\n]/) {
5245 $expiryDate = &Date
::Parse
::str2time
($1);
5250 # Calculate the remaining time
5251 my $remainingTime = $expiryDate - time();
5253 # Determine whether the certificate has already expired, or will so soon
5254 $hasExpired = ($remainingTime <= 0);
5255 $expiresSoon = ($remainingTime <= 30 * 24 * 3600);
5260 # Highlight the row if the certificate has expired/will expire soon
5261 if ($hasExpired || $expiresSoon) {
5262 push(@classes, "is-warning");
5266 print "<tr class='@classes'>";
5268 # Show the name of the connection
5269 print " <th scope='row'>$name";
5271 print " ($Lang::tr{'openvpn cert has expired'})";
5272 } elsif ($expiresSoon) {
5273 print " ($Lang::tr{'openvpn cert expires soon'})";
5278 print "<td class='text-center'>$Lang::tr{$type}</td>";
5281 print "<td>$confighash{$key}[25]</td>";
5283 my $connstatus = "DISCONNECTED";
5285 # Disabled Connections
5286 if ($status eq "off") {
5287 $connstatus = "DISABLED";
5290 } elsif ($type eq "net") {
5291 if (-e
"/var/run/${name}n2n.pid") {
5292 my $port = $confighash{$key}[22];
5295 $connstatus = &openvpn_status
($confighash{$key}[22]);
5300 } elsif ($type eq "host") {
5303 foreach my $line (@status) {
5306 if ($line =~ /^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/) {
5307 my @match = split(m/^(.+),(\d+\.\d+\.\d+\.\d+\:\d+),(\d+),(\d+),(.+)/, $line);
5309 if ($match[1] ne "Common Name") {
5313 if ($cn eq "$confighash{$key}[2]") {
5314 $connstatus = "CONNECTED";
5320 if ($connstatus eq "DISABLED") {
5321 print "<td class='status is-disabled'>$Lang::tr{'capsclosed'}</td>";
5322 } elsif ($connstatus eq "CONNECTED") {
5323 print "<td class='status is-connected'>$Lang::tr{'capsopen'}</td>";
5324 } elsif ($connstatus eq "DISCONNECTED") {
5325 print "<td class='status is-disconnected'>$Lang::tr{'capsclosed'}</td>";
5327 print "<td class='status is-unknown'>$connstatus</td>";
5330 # Download Configuration
5332 <td class="text-center">
5333 <form method='post' name='frm${key}a'>
5334 <input type='image' name='$Lang::tr{'dl client arch'}' src='/images/openvpn.png'
5335 alt='$Lang::tr{'dl client arch'}' title='$Lang::tr{'dl client arch'}' />
5336 <input type='hidden' name='ACTION' value='$Lang::tr{'dl client arch'}' />
5337 <input type='hidden' name='KEY' value='$key' />
5343 if ($confighash{$key}[4] eq 'cert') {
5345 <td class="text-center">
5346 <form method='post' name='frm${key}b'>
5347 <input type='image' name='$Lang::tr{'show certificate'}' src='/images/info.gif'
5348 alt='$Lang::tr{'show certificate'}' title='$Lang::tr{'show certificate'}' />
5349 <input type='hidden' name='ACTION' value='$Lang::tr{'show certificate'}' />
5350 <input type='hidden' name='KEY' value='$key' />
5360 if ($confighash{$key}[43] eq 'on') {
5362 <td class="text-center">
5363 <form method='post' name='frm${key}o'>
5364 <input type='image' name='$Lang::tr{'show otp qrcode'}' src='/images/qr-code.png'
5365 alt='$Lang::tr{'show otp qrcode'}' title='$Lang::tr{'show otp qrcode'}' />
5366 <input type='hidden' name='ACTION' value='$Lang::tr{'show otp qrcode'}' />
5367 <input type='hidden' name='KEY' value='$key' />
5375 # Download Certificate
5376 if ($confighash{$key}[4] eq 'cert' && -f
"${General::swroot}/ovpn/certs/$confighash{$key}[1].p12") {
5378 <td class="text-center">
5379 <form method='post' name='frm${key}c'>
5380 <input type='image' name='$Lang::tr{'download pkcs12 file'}' src='/images/media-floppy.png'
5381 alt='$Lang::tr{'download pkcs12 file'}' title='$Lang::tr{'download pkcs12 file'}' />
5382 <input type='hidden' name='ACTION' value='$Lang::tr{'download pkcs12 file'}' />
5383 <input type='hidden' name='KEY' value='$key' />
5388 } elsif ($confighash{$key}[4] eq 'cert') {
5390 <td class="text-center">
5391 <form method='post' name='frm${key}c'>
5392 <input type='image' name='$Lang::tr{'download certificate'}' src='/images/media-floppy.png'
5393 alt='$Lang::tr{'download certificate'}' title='$Lang::tr{'download certificate'}' />
5394 <input type='hidden' name='ACTION' value='$Lang::tr{'download certificate'}' />
5395 <input type='hidden' name='KEY' value='$key' />
5403 if ($status eq 'on') {
5410 <td class="text-center">
5411 <form method='post' name='frm${key}d'>
5412 <input type='image' name='$Lang::tr{'toggle enable disable'}' src='/images/$gif'
5413 alt='$Lang::tr{'toggle enable disable'}' title='$Lang::tr{'toggle enable disable'}' />
5414 <input type='hidden' name='ACTION' value='$Lang::tr{'toggle enable disable'}' />
5415 <input type='hidden' name='KEY' value='$key' />
5419 <td class="text-center">
5420 <form method='post' name='frm${key}e'>
5421 <input type='hidden' name='ACTION' value='$Lang::tr{'edit'}' />
5422 <input type='image' name='$Lang::tr{'edit'}' src='/images/edit.gif'
5423 alt='$Lang::tr{'edit'}' title='$Lang::tr{'edit'}' />
5424 <input type='hidden' name='KEY' value='$key' />
5428 <td class="text-center">
5429 <form method='post' name='frm${key}f'>
5430 <input type='hidden' name='ACTION' value='$Lang::tr{'remove'}' />
5431 <input type='image' name='$Lang::tr{'remove'}' src='/images/delete.gif'
5432 alt='$Lang::tr{'remove'}' title='$Lang::tr{'remove'}' />
5433 <input type='hidden' name='KEY' value='$key' />
5444 <table class="form">
5447 <form method='post'>
5448 <input type='submit' name='ACTION' value='$Lang::tr{'add'}' />
5449 <input type='submit' name='ACTION' value='$Lang::tr{'ovpn con stat'}' />
5456 &Header
::closebox
();
5459 &Header
::openbox
('100%', 'LEFT', "$Lang::tr{'certificate authorities'}");
5461 <table width='100%' cellspacing='1' cellpadding='0' class='tbl'>
5463 <th width='25%' class='boldbase' align='center'><b>$Lang::tr{'name'}</b></th>
5464 <th width='65%' class='boldbase' align='center'><b>$Lang::tr{'subject'}</b></th>
5465 <th width='10%' class='boldbase' colspan='3' align='center'><b>$Lang::tr{'action'}</b></th>
5469 my $col1="bgcolor='$Header::color{'color22'}'";
5470 my $col2="bgcolor='$Header::color{'color20'}'";
5472 my $col3="bgcolor='$Header::color{'color22'}'";
5474 my $col4="bgcolor='$Header::color{'color20'}'";
5476 if (-f
"${General::swroot}/ovpn/ca/cacert.pem") {
5477 my @casubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/ca/cacert.pem");
5480 foreach my $line (@casubject) {
5481 if ($line =~ /Subject: (.*)[\n]/) {
5483 $casubject =~ s
+/Email
+, E
+;
5484 $casubject =~ s/ ST=/ S=/;
5492 <td class='base' $col1>$Lang::tr{'root certificate'}</td>
5493 <td class='base' $col1>$casubject</td>
5494 <form method='post' name='frmrootcrta'><td width='3%' align='center' $col1>
5495 <input type='hidden' name='ACTION' value='$Lang::tr{'show root certificate'}' />
5496 <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' />
5498 <form method='post' name='frmrootcrtb'><td width='3%' align='center' $col1>
5499 <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' />
5500 <input type='hidden' name='ACTION' value='$Lang::tr{'download root certificate'}' />
5502 <td width='4%' $col1> </td>
5507 # display rootcert generation buttons
5510 <td class='base' $col1>$Lang::tr{'root certificate'}:</td>
5511 <td class='base' $col1>$Lang::tr{'not present'}</td>
5512 <td colspan='3' $col1> </td>
5518 if (-f
"${General::swroot}/ovpn/certs/servercert.pem") {
5519 my @hostsubject = &General
::system_output
("/usr/bin/openssl", "x509", "-text", "-in", "${General::swroot}/ovpn/certs/servercert.pem");
5522 foreach my $line (@hostsubject) {
5523 if ($line =~ /Subject: (.*)[\n]/) {
5525 $hostsubject =~ s
+/Email
+, E
+;
5526 $hostsubject =~ s/ ST=/ S=/;
5534 <td class='base' $col2>$Lang::tr{'host certificate'}</td>
5535 <td class='base' $col2>$hostsubject</td>
5536 <form method='post' name='frmhostcrta'><td width='3%' align='center' $col2>
5537 <input type='hidden' name='ACTION' value='$Lang::tr{'show host certificate'}' />
5538 <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' />
5540 <form method='post' name='frmhostcrtb'><td width='3%' align='center' $col2>
5541 <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' />
5542 <input type='hidden' name='ACTION' value="$Lang::tr{'download host certificate'}" />
5544 <td width='4%' $col2> </td>
5552 <td width='25%' class='base' $col2>$Lang::tr{'host certificate'}:</td>
5553 <td class='base' $col2>$Lang::tr{'not present'}</td>
5554 </td><td colspan='3' $col2> </td>
5560 # Adding ta.key to chart
5561 if (-f
"${General::swroot}/ovpn/certs/ta.key") {
5562 open(FILE
, "${General::swroot}/ovpn/certs/ta.key");
5563 my @tasubject = <FILE
>;
5567 foreach my $line (@tasubject) {
5568 if($line =~ /# (.*)[\n]/) {
5578 <td class='base' $col4>$Lang::tr{'ta key'}</td>
5579 <td class='base' $col4>$tasubject</td>
5580 <form method='post' name='frmtakey'><td width='3%' align='center' $col4>
5581 <input type='hidden' name='ACTION' value='$Lang::tr{'show tls-auth key'}' />
5582 <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' />
5584 <form method='post' name='frmtakey'><td width='3%' align='center' $col4>
5585 <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' />
5586 <input type='hidden' name='ACTION' value='$Lang::tr{'download tls-auth key'}' />
5588 <td width='4%' $col4> </td>
5596 <td width='25%' class='base' $col4>$Lang::tr{'ta key'}:</td>
5597 <td class='base' $col4>$Lang::tr{'not present'}</td>
5598 <td colspan='3' $col4> </td>
5604 if (! -f
"${General::swroot}/ovpn/ca/cacert.pem") {
5605 print "<tr><td colspan='5' align='center'><form method='post'>";
5606 print "<input type='submit' name='ACTION' value='$Lang::tr{'generate root/host certificates'}' />";
5607 print "</form></td></tr>\n";
5610 if (keys %cahash > 0) {
5611 foreach my $key (keys %cahash) {
5612 if (($key + 1) % 2) {
5613 print "<tr bgcolor='$Header::color{'color20'}'>\n";
5615 print "<tr bgcolor='$Header::color{'color22'}'>\n";
5617 print "<td class='base'>$cahash{$key}[0]</td>\n";
5618 print "<td class='base'>$cahash{$key}[1]</td>\n";
5620 <form method='post' name='cafrm${key}a'><td align='center'>
5621 <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' />
5622 <input type='hidden' name='ACTION' value='$Lang::tr{'show ca certificate'}' />
5623 <input type='hidden' name='KEY' value='$key' />
5625 <form method='post' name='cafrm${key}b'><td align='center'>
5626 <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' />
5627 <input type='hidden' name='ACTION' value='$Lang::tr{'download ca certificate'}' />
5628 <input type='hidden' name='KEY' value='$key' />
5630 <form method='post' name='cafrm${key}c'><td align='center'>
5631 <input type='hidden' name='ACTION' value='$Lang::tr{'remove ca certificate'}' />
5632 <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' />
5633 <input type='hidden' name='KEY' value='$key' />
5642 # If the file contains entries, print Key to action icons
5643 if ( -f
"${General::swroot}/ovpn/ca/cacert.pem") {
5647 <td class='boldbase'> <b>$Lang::tr{'legend'}:</b></td>
5648 <td> <img src='/images/info.gif' alt='$Lang::tr{'show certificate'}' /></td>
5649 <td class='base'>$Lang::tr{'show certificate'}</td>
5650 <td> <img src='/images/media-floppy.png' alt='$Lang::tr{'download certificate'}' /></td>
5651 <td class='base'>$Lang::tr{'download certificate'}</td>
5662 <form method='post' enctype='multipart/form-data'>
5663 <table border='0' width='100%'>
5665 <td colspan='4'><b>$Lang::tr{'upload ca certificate'}</b></td>
5669 <td width='10%'>$Lang::tr{'ca name'}:</td>
5670 <td width='30%'><input type='text' name='CA_NAME' value='$cgiparams{'CA_NAME'}' size='15' align='left'></td>
5671 <td width='30%'><input type='file' name='FH' size='25'>
5672 <td width='30%'align='right'><input type='submit' name='ACTION' value='$Lang::tr{'upload ca certificate'}'></td>
5676 <td colspan='3'> </td>
5677 <td align='right'><input type='submit' name='ACTION' value='$Lang::tr{'show crl'}' /></td>
5686 if ($vpnsettings{'ENABLED'} eq "yes") {
5687 print "<div align='center'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' disabled='disabled' /></div></form>\n";
5689 print "<div align='center'><form method='post'><input type='submit' name='ACTION' value='$Lang::tr{'remove x509'}' /></div></form>\n";
5691 &Header
::closebox
();
5695 &Header
::closepage
();