initial commit of file from CVS for smeserver-openvpn-s2s on Sat Sep 7 19:57:57 AEST 2024
This commit is contained in:
16
root/usr/lib/systemd/system/openvpn-s2s.service
Normal file
16
root/usr/lib/systemd/system/openvpn-s2s.service
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=OpenVPN Server to Server
|
||||
After=network.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
GuessMainPID=no
|
||||
|
||||
ExecStart=/usr/sbin/systemd/openvpn-s2s start
|
||||
ExecStop=/usr/sbin/systemd/openvpn-s2s stop
|
||||
ExecReload=/usr/sbin/systemd/openvpn-s2s reopen
|
||||
|
||||
[Install]
|
||||
WantedBy=sme-server.target
|
||||
|
269
root/usr/sbin/systemd/openvpn-s2s
Normal file
269
root/usr/sbin/systemd/openvpn-s2s
Normal file
@@ -0,0 +1,269 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# openvpn This shell script takes care of starting and stopping
|
||||
# openvpn on RedHat or other chkconfig-based system.
|
||||
#
|
||||
# chkconfig: - 24 76
|
||||
#
|
||||
# processname: openvpn
|
||||
# description: OpenVPN is a robust and highly flexible tunneling \
|
||||
# application that uses all of the encryption, \
|
||||
# authentication, and certification features of the OpenSSL \
|
||||
# library to securely tunnel IP networks over a single UDP \
|
||||
# port.
|
||||
#
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: openvpn
|
||||
# Required-Start: $network
|
||||
# Required-Stop: $network
|
||||
# Short-Description: start and stop openvpn
|
||||
# Description: OpenVPN is a robust and highly flexible tunneling \
|
||||
# application that uses all of the encryption, \
|
||||
# authentication, and certification features of the OpenSSL \
|
||||
# library to securely tunnel IP networks over a single UDP \
|
||||
# port.
|
||||
### END INIT INFO
|
||||
|
||||
|
||||
# Contributed to the OpenVPN project by
|
||||
# Douglas Keller <doug@voidstar.dyndns.org>
|
||||
# 2002.05.15
|
||||
|
||||
# To install:
|
||||
# copy this file to /etc/rc.d/init.d/openvpn
|
||||
# shell> chkconfig --add openvpn
|
||||
# shell> mkdir /etc/openvpn
|
||||
# make .conf or .sh files in /etc/openvpn (see below)
|
||||
|
||||
# To uninstall:
|
||||
# run: chkconfig --del openvpn
|
||||
|
||||
# Author's Notes:
|
||||
#
|
||||
# I have created an /etc/init.d init script and enhanced openvpn.spec to
|
||||
# automatically register the init script. Once the RPM is installed you
|
||||
# can start and stop OpenVPN with "service openvpn start" and "service
|
||||
# openvpn stop".
|
||||
#
|
||||
# The init script does the following:
|
||||
#
|
||||
# - Starts an openvpn process for each .conf file it finds in
|
||||
# /etc/openvpn.
|
||||
#
|
||||
# - If /etc/openvpn/xxx.sh exists for a xxx.conf file then it executes
|
||||
# it before starting openvpn (useful for doing openvpn --mktun...).
|
||||
#
|
||||
# - In addition to start/stop you can do:
|
||||
#
|
||||
# service openvpn reload - SIGHUP
|
||||
# service openvpn reopen - SIGUSR1
|
||||
# service openvpn status - SIGUSR2
|
||||
#
|
||||
# Modifications:
|
||||
#
|
||||
# 2003.05.02
|
||||
# * Changed == to = for sh compliance (Bishop Clark).
|
||||
# * If condrestart|reload|reopen|status, check that we were
|
||||
# actually started (James Yonan).
|
||||
# * Added lock, piddir, and work variables (James Yonan).
|
||||
# * If start is attempted twice, without an intervening stop, or
|
||||
# if start is attempted when previous start was not properly
|
||||
# shut down, then kill any previously started processes, before
|
||||
# commencing new start operation (James Yonan).
|
||||
# * Do a better job of flagging errors on start, and properly
|
||||
# returning success or failure status to caller (James Yonan).
|
||||
#
|
||||
# 2005.04.04
|
||||
# * Added openvpn-startup and openvpn-shutdown script calls
|
||||
# (James Yonan).
|
||||
#
|
||||
|
||||
# Location of openvpn binary
|
||||
openvpn=""
|
||||
openvpn_locations="/usr/sbin/openvpn /usr/local/sbin/openvpn"
|
||||
for location in $openvpn_locations
|
||||
do
|
||||
if [ -f "$location" ]
|
||||
then
|
||||
openvpn=$location
|
||||
fi
|
||||
done
|
||||
|
||||
#ncp
|
||||
ncp=" --ncp-ciphers AES-256-GCM:AES-128-GCM:AES-256-CBC:AES-128-CBC:BF-CBC "
|
||||
|
||||
# Lockfile
|
||||
lock="/var/lock/subsys/openvpn-s2s"
|
||||
|
||||
# PID directory
|
||||
piddir="/var/run/openvpn-s2s"
|
||||
|
||||
# Our working directory
|
||||
work=/etc/openvpn/s2s
|
||||
|
||||
# Source function library.
|
||||
. /etc/rc.d/init.d/functions
|
||||
|
||||
# Source networking configuration.
|
||||
. /etc/sysconfig/network
|
||||
|
||||
# Check that networking is up.
|
||||
if [ ${NETWORKING} = "no" ]
|
||||
then
|
||||
echo "Networking is down"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check that binary exists
|
||||
if ! [ -f $openvpn ]
|
||||
then
|
||||
echo "openvpn binary not found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n $"Starting openvpn-s2s: "
|
||||
|
||||
/sbin/modprobe tun >/dev/null 2>&1
|
||||
|
||||
# From a security perspective, I think it makes
|
||||
# sense to remove this, and have users who need
|
||||
# it explictly enable in their --up scripts or
|
||||
# firewall setups.
|
||||
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
# Run startup script, if defined
|
||||
if [ -f $work/openvpn-startup ]; then
|
||||
$work/openvpn-startup
|
||||
fi
|
||||
|
||||
if [ ! -d $piddir ]; then
|
||||
mkdir $piddir
|
||||
fi
|
||||
|
||||
if [ -f $lock ]; then
|
||||
# we were not shut down correctly
|
||||
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
|
||||
if [ -s $pidf ]; then
|
||||
kill `cat $pidf` >/dev/null 2>&1
|
||||
fi
|
||||
rm -f $pidf
|
||||
done
|
||||
rm -f $lock
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
rm -f $piddir/*.pid
|
||||
cd $work
|
||||
|
||||
# Start every .conf in $work and run .sh if exists
|
||||
errors=0
|
||||
successes=0
|
||||
for c in `/bin/ls *.conf 2>/dev/null`; do
|
||||
bn=${c%%.conf}
|
||||
if [ -f "$bn.sh" ]; then
|
||||
. ./$bn.sh
|
||||
fi
|
||||
rm -f $piddir/$bn.pid
|
||||
# Handle backward compatibility, see Red Hat Bugzilla ID #458594
|
||||
script_security=''
|
||||
if [ -z "$( grep '^[[:space:]]*script-security[[:space:]]' $c )" ]; then
|
||||
script_security="--script-security 2"
|
||||
fi
|
||||
$openvpn --daemon --writepid $piddir/$bn.pid --config $c --cd $work $script_security
|
||||
if [ $? = 0 ]; then
|
||||
successes=1
|
||||
else
|
||||
errors=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $errors = 1 ]; then
|
||||
failure; echo
|
||||
else
|
||||
success; echo
|
||||
fi
|
||||
|
||||
if [ $successes = 1 ]; then
|
||||
touch $lock
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
echo -n $"Shutting down openvpn: "
|
||||
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
|
||||
if [ -s $pidf ]; then
|
||||
kill `cat $pidf` >/dev/null 2>&1
|
||||
fi
|
||||
rm -f $pidf
|
||||
done
|
||||
|
||||
# Run shutdown script, if defined
|
||||
if [ -f $work/openvpn-shutdown ]; then
|
||||
$work/openvpn-shutdown
|
||||
fi
|
||||
|
||||
success; echo
|
||||
rm -f $lock
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
sleep 2
|
||||
$0 start
|
||||
;;
|
||||
reload)
|
||||
if [ -f $lock ]; then
|
||||
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
|
||||
if [ -s $pidf ]; then
|
||||
kill -HUP `cat $pidf` >/dev/null 2>&1
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
else
|
||||
echo "openvpn: service not started"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
reopen)
|
||||
if [ -f $lock ]; then
|
||||
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
|
||||
if [ -s $pidf ]; then
|
||||
kill -USR1 `cat $pidf` >/dev/null 2>&1
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
else
|
||||
echo "openvpn: service not started"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
condrestart)
|
||||
if [ -f $lock ]; then
|
||||
$0 stop
|
||||
# avoid race
|
||||
sleep 2
|
||||
$0 start
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
if [ -f $lock ]; then
|
||||
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
|
||||
if [ -s $pidf ]; then
|
||||
kill -USR2 `cat $pidf` >/dev/null 2>&1
|
||||
fi
|
||||
done
|
||||
echo "Status written to /var/log/messages"
|
||||
else
|
||||
echo "openvpn: service not started"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart|condrestart|reload|reopen|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit 0
|
@@ -0,0 +1,783 @@
|
||||
#!/usr/bin/perl
|
||||
package esmith::FormMagick::Panel::openvpns2s;
|
||||
|
||||
# Imports
|
||||
use strict;
|
||||
use warnings;
|
||||
use esmith::ConfigDB;
|
||||
use esmith::NetworksDB;
|
||||
use esmith::FormMagick;
|
||||
use esmith::cgi;
|
||||
use esmith::util;
|
||||
use Net::IP;
|
||||
use CGI::Carp qw ( fatalsToBrowser );
|
||||
use File::Basename;
|
||||
|
||||
our @ISA = qw(esmith::FormMagick Exporter);
|
||||
|
||||
# TODO: update sub list
|
||||
our @EXPORT = qw(
|
||||
print_custom_button
|
||||
print_section_bar
|
||||
write_db_conf
|
||||
update_ports
|
||||
print_conf_table
|
||||
print_conf_name_field
|
||||
remove_conf
|
||||
print_conf_to_remove
|
||||
read_file
|
||||
reload
|
||||
);
|
||||
|
||||
our $pubdir = '/etc/openvpn/s2s/pub';
|
||||
our $privdir = '/etc/openvpn/s2s/priv';
|
||||
our $ovpn_db = esmith::ConfigDB->open('openvpn-s2s') || esmith::ConfigDB->create('openvpn-s2s');
|
||||
our $conf_db = esmith::ConfigDB->open || die "Error opening configuration DB\n";
|
||||
our $net_db = esmith::NetworksDB->open_ro || die "Error opening netwoks DB\n";
|
||||
our $base_url = "?page=0&page_stack=&Next=Next&wherenext=";
|
||||
|
||||
*wherenext = \&CGI::FormMagick::wherenext;
|
||||
|
||||
sub new {
|
||||
shift;
|
||||
my $fm = esmith::FormMagick->new();
|
||||
$fm->{calling_package} = (caller)[0];
|
||||
bless $fm;
|
||||
return $fm;
|
||||
}
|
||||
|
||||
sub print_custom_button{
|
||||
my ($fm,$desc,$url) = @_;
|
||||
my $q = $fm->{cgi};
|
||||
$url="openvpns2s?page=0&page_stack=&Next=Next&wherenext=".$url;
|
||||
print " <tr>\n <td colspan='2'>\n";
|
||||
print $q->p($q->a({href => $url, -class => "button-like"},$fm->localise($desc)));
|
||||
print qq(</tr>\n);
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub print_section_bar{
|
||||
my ($fm) = @_;
|
||||
print " <tr>\n <td colspan='2'>\n";
|
||||
print "<hr class=\"sectionbar\"/>\n";
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub write_db_conf{
|
||||
my ($fm,$type) = @_;
|
||||
my $q = $fm->{cgi};
|
||||
my $conf = $q->param('conf_name');
|
||||
|
||||
if ($q->param('action') ne 'modify'){
|
||||
if ($ovpn_db->get($conf)){
|
||||
return $fm->error('CONF_CONFLICT','FIRST_PAGE');
|
||||
}
|
||||
my $msg = $fm->validate_conf_name($conf);
|
||||
unless ($msg eq "OK"){
|
||||
return $fm->error($msg,'FIRST_PAGE');
|
||||
}
|
||||
}
|
||||
|
||||
# Write DB values
|
||||
$ovpn_db->new_record($conf, {type => $type});
|
||||
if ($type eq 'client'){
|
||||
$ovpn_db->set_prop($conf, 'RemoteHost', $q->param("remote_host"));
|
||||
}
|
||||
|
||||
$ovpn_db->set_prop($conf, 'status', $q->param("status"));
|
||||
$ovpn_db->set_prop($conf, 'Authentication', $q->param("auth"));
|
||||
$ovpn_db->set_prop($conf, 'LocalIP', $q->param("local_ip"));
|
||||
$ovpn_db->set_prop($conf, 'RemoteIP', $q->param("remote_ip"));
|
||||
$ovpn_db->set_prop($conf, 'Port', $q->param("port"));
|
||||
$ovpn_db->set_prop($conf, 'status', $q->param("status"));
|
||||
$ovpn_db->set_prop($conf, 'Comment', $q->param("comment"));
|
||||
$ovpn_db->set_prop($conf, 'RemoteNetworks', $q->param("remote_net"));
|
||||
$ovpn_db->set_prop($conf, 'SnatOutbound', $q->param("SnatOutbound"));
|
||||
if ($q->param("hmac") eq 'SHA1') {
|
||||
my $tmpk = $ovpn_db->get($conf);
|
||||
$tmpk->delete_prop('HMAC');
|
||||
}
|
||||
else {
|
||||
$ovpn_db->set_prop($conf, 'HMAC' , $q->param("hmac"));
|
||||
}
|
||||
if ($q->param("cipher") eq 'BF-CBC') {
|
||||
my $tmpk = $ovpn_db->get($conf);
|
||||
$tmpk->delete_prop('Cipher');
|
||||
}
|
||||
else {
|
||||
$ovpn_db->set_prop($conf, 'Cipher', $q->param("cipher"));
|
||||
}
|
||||
|
||||
# Now, update the main configuration entry
|
||||
update_ports();
|
||||
|
||||
$fm->success('SUCCESS','CONFIG_CERT_PAGE');
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub write_pem{
|
||||
my ($fm) = @_;
|
||||
my $q = $fm->{cgi};
|
||||
my $conf = $q->param('conf_name');
|
||||
my $type = $ovpn_db->get_prop($conf, 'type') || 'server';
|
||||
my $auth = $ovpn_db->get_prop($conf, 'Authentication') || 'TLS';
|
||||
|
||||
# Run validation routines
|
||||
my $msg = $fm->is_url_or_empty( $q->param("crl_url"));
|
||||
unless ($msg eq "OK"){
|
||||
return $fm->error($msg,'CONFIG_CERT_PAGE');
|
||||
}
|
||||
|
||||
my @pems = ();
|
||||
|
||||
if ($auth eq 'TLS'){
|
||||
push @pems, qw/cacert_pem cert_pem key_pem/;
|
||||
push @pems, 'dh_pem' if $type eq 'server';
|
||||
}
|
||||
else{
|
||||
push @pems, 'shared_key' if $auth eq 'SharedKey';
|
||||
}
|
||||
|
||||
foreach my $pem (@pems){
|
||||
$msg = $fm->is_valid_key( $q->param("$pem") );
|
||||
unless ($msg eq "OK"){
|
||||
return $fm->error($msg,'CONFIG_CERT_PAGE');
|
||||
}
|
||||
}
|
||||
|
||||
# Untaint $conf
|
||||
$conf =~ m/(.*)/;
|
||||
$conf = $1;
|
||||
|
||||
if (! open (CA, ">$pubdir/$conf". "_cacert.pem")){
|
||||
$fm->error('ERROR_OPEN_CA','FIRST_PAGE');
|
||||
return;
|
||||
}
|
||||
print CA $q->param('cacert_pem');
|
||||
close CA;
|
||||
|
||||
if (! open (CRT, ">$pubdir/$conf" . "_cert.pem")){
|
||||
$fm->error('ERROR_OPEN_CRT','FIRST_PAGE');
|
||||
return;
|
||||
}
|
||||
print CRT $q->param('cert_pem');
|
||||
close CRT;
|
||||
|
||||
if (! open (KEY, ">$privdir/$conf" . "_key.pem")){
|
||||
$fm->error('ERROR_OPEN_KEY','FIRST_PAGE');
|
||||
return;
|
||||
}
|
||||
print KEY $q->param('key_pem');
|
||||
close KEY;
|
||||
chmod(0600, "$privdir/${conf}_key.pem" );
|
||||
esmith::util::chownFile("root", "root","$privdir/${conf}_key.pem" );
|
||||
|
||||
|
||||
if (! open (DH, ">$pubdir/$conf" . "_dh.pem")){
|
||||
$fm->error('ERROR_OPEN_DH','FIRST_PAGE');
|
||||
return;
|
||||
}
|
||||
print DH $q->param('dh_pem');
|
||||
close DH;
|
||||
|
||||
if (! open (TA, ">$privdir/$conf" . "_sharedkey.pem")){
|
||||
$fm->error('ERROR_OPEN_TA','FIRST_PAGE');
|
||||
return;
|
||||
}
|
||||
print TA $q->param('shared_key');
|
||||
close TA;
|
||||
chmod(0600, "$privdir/${conf}_sharedkey.pem" );
|
||||
esmith::util::chownFile("root", "root","$privdir/${conf}_sharedkey.pem" );
|
||||
|
||||
esmith::util::chownFile("root", "root", "$privdir");
|
||||
esmith::util::chownFile("root", "root", "$pubdir");
|
||||
chmod 0600, "$privdir";
|
||||
chmod 0644, "$pubdir";
|
||||
|
||||
$ovpn_db->set_prop($conf, 'CrlUrl', $q->param("crl_url"));
|
||||
|
||||
unless ( system ("/sbin/e-smith/signal-event", "openvpn-s2s-update") == 0 ){
|
||||
return $fm->error("ERROR_OCCURED", 'FIRST_PAGE');
|
||||
}
|
||||
|
||||
$fm->success('SUCCESS','FIRST_PAGE');
|
||||
return undef;
|
||||
|
||||
}
|
||||
|
||||
# Update ports used in the configuration DB
|
||||
sub update_ports{
|
||||
my @tcp_ports = ();
|
||||
my @udp_ports = ();
|
||||
foreach my $vpn ($ovpn_db->get_all_by_prop(type=>'server')){
|
||||
my $port = $vpn->prop('Port') || next;
|
||||
my $proto = ($vpn->prop('Protocol') || 'udp');
|
||||
my $status = ($vpn->prop('status') || 'disabled');
|
||||
if ( $proto eq 'udp' && $status eq 'enabled' ){
|
||||
push @udp_ports, $port;
|
||||
}
|
||||
elsif ( $proto eq 'tcp' && $status eq 'enabled' ){
|
||||
push @tcp_ports, $port;
|
||||
}
|
||||
}
|
||||
$conf_db->set_prop('openvpn-s2s', 'UDPPorts', join(',',@udp_ports));
|
||||
$conf_db->set_prop('openvpn-s2s', 'TCPPorts', join(',',@tcp_ports));
|
||||
}
|
||||
|
||||
sub print_cert_fields{
|
||||
my $fm = shift;
|
||||
my $q = $fm->{cgi};
|
||||
my $conf = $q->param('conf_name');
|
||||
my $rec = $ovpn_db->get("$conf");
|
||||
my $type = $rec->prop('type') || 'server';
|
||||
my $auth = $rec->prop('Authentication') || 'TLS';
|
||||
my $crlurl = $rec->prop('CrlUrl') || '';
|
||||
|
||||
# Untaint $conf
|
||||
$conf =~ m/(.*)/;
|
||||
$conf = $1;
|
||||
|
||||
if ($auth eq 'TLS'){
|
||||
print esmith::cgi::genTextRow($q,$fm->localise('DESC_CRL_URL'));
|
||||
print $q->Tr (
|
||||
$q->td ({-class => "sme-noborders-label"},
|
||||
$fm->localise('LABEL_CRL_URL')),"\n",
|
||||
$q->td ({-class => "sme-noborders-content"},
|
||||
$q->textfield (
|
||||
-name => 'crl_url',
|
||||
-override => 1,
|
||||
-default => $crlurl,
|
||||
-size => 62))),"\n";
|
||||
print esmith::cgi::genTextRow($q,$fm->localise('DESC_CA_PEM'));
|
||||
print $q->Tr (
|
||||
$q->td ({-class => "sme-noborders-label"},
|
||||
$fm->localise('LABEL_CA_PEM')),"\n",
|
||||
$q->td ({-class => "sme-noborders-content"},
|
||||
$q->textarea (
|
||||
-name => 'cacert_pem',
|
||||
-override => 1,
|
||||
-default => read_file("$pubdir/$conf"."_cacert.pem"),
|
||||
-rows => 15,
|
||||
-columns => 70))),"\n";
|
||||
print esmith::cgi::genTextRow($q,$fm->localise('DESC_CRT_PEM'));
|
||||
print $q->Tr (
|
||||
$q->td ({-class => "sme-noborders-label"},
|
||||
$fm->localise('LABEL_CRT_PEM')),"\n",
|
||||
$q->td ({-class => "sme-noborders-content"},
|
||||
$q->textarea (
|
||||
-name => 'cert_pem',
|
||||
-override => 1,
|
||||
-default => read_file("$pubdir/$conf"."_cert.pem"),
|
||||
-rows => 15,
|
||||
-columns => 70))),"\n";
|
||||
print esmith::cgi::genTextRow($q,$fm->localise('DESC_KEY_PEM'));
|
||||
print $q->Tr (
|
||||
$q->td ({-class => "sme-noborders-label"},
|
||||
$fm->localise('LABEL_KEY_PEM')),"\n",
|
||||
$q->td ({-class => "sme-noborders-content"},
|
||||
$q->textarea (
|
||||
-name => 'key_pem',
|
||||
-override => 1,
|
||||
-default => read_file("$privdir/$conf"."_key.pem"),
|
||||
-rows => 15,
|
||||
-columns => 70))),"\n";
|
||||
if ($type eq 'server'){
|
||||
print esmith::cgi::genTextRow($q,$fm->localise('DESC_DH_PEM'));
|
||||
print $q->Tr (
|
||||
$q->td ({-class => "sme-noborders-label"},
|
||||
$fm->localise('LABEL_DH_PEM')),"\n",
|
||||
$q->td ({-class => "sme-noborders-content"},
|
||||
$q->textarea (
|
||||
-name => 'dh_pem',
|
||||
-override => 1,
|
||||
-default => read_file("$pubdir/$conf"."_dh.pem"),
|
||||
-rows => 8,
|
||||
-columns => 70))),"\n";
|
||||
}
|
||||
print esmith::cgi::genTextRow($q,$fm->localise('DESC_SHARED_KEY_TLS'));
|
||||
}
|
||||
else{
|
||||
print esmith::cgi::genTextRow($q,$fm->localise('DESC_SHARED_KEY'));
|
||||
}
|
||||
|
||||
print $q->Tr (
|
||||
$q->td ({-class => "sme-noborders-label"},
|
||||
$fm->localise('LABEL_SHARED_KEY')),"\n",
|
||||
$q->td ({-class => "sme-noborders-content"},
|
||||
$q->textarea (
|
||||
-name => 'shared_key',
|
||||
-override => 1,
|
||||
-default => read_file("$privdir/$conf"."_sharedkey.pem"),
|
||||
-rows => 5,
|
||||
-columns => 70))),"\n";
|
||||
return undef;
|
||||
}
|
||||
|
||||
|
||||
# Print clients or servers table
|
||||
sub reload{
|
||||
my ($fm) = @_;
|
||||
my $q = $fm->{cgi};
|
||||
my $conf = $q->param('conf_name');
|
||||
#$conf = $conf=~ m/^([a-zA-Z\-\_0-9]+)$/;
|
||||
unless (system ("/sbin/e-smith/signal-event", "openvpn-s2s-update-one", $conf) == 0 ){
|
||||
$fm->error('ERROR_OCCURED1','FIRST_PAGE');
|
||||
return undef;
|
||||
}
|
||||
$fm->success( $fm->localise('SUCCESS_RELOAD') . " $conf" ,'FIRST_PAGE');
|
||||
return undef;
|
||||
|
||||
|
||||
}
|
||||
|
||||
# Print clients or servers table
|
||||
sub print_conf_table{
|
||||
my $fm = shift;
|
||||
my $type = shift;
|
||||
my $q = $fm->{cgi};
|
||||
my $conf_name = $fm->localise('CONF_NAME');
|
||||
my $modify = $fm->localise('MODIFY');
|
||||
|
||||
my @conf = $ovpn_db->get_all_by_prop(type=>$type);
|
||||
|
||||
unless ( scalar @conf ){
|
||||
print $q->Tr($q->td($fm->localise('NO_CONF')));
|
||||
return "";
|
||||
}
|
||||
print $q->start_table({-CLASS => "sme-border"}),"\n";
|
||||
print $q->Tr (
|
||||
esmith::cgi::genSmallCell($q, $fm->localise('CONF_NAME'),"header"),
|
||||
esmith::cgi::genSmallCell($q, $fm->localise('STATUS'),"header"),
|
||||
esmith::cgi::genSmallCell($q, $fm->localise('CIPHER'),"header"),
|
||||
esmith::cgi::genSmallCell($q, 'HMAC',"header"),
|
||||
esmith::cgi::genSmallCell($q, $fm->localise('LABEL_AUTH'),"header"),
|
||||
esmith::cgi::genSmallCell($q, $fm->localise('LINK'),"header"),
|
||||
esmith::cgi::genSmallCell($q, $fm->localise('ACTION'),"header", 3),
|
||||
),
|
||||
"\n";
|
||||
|
||||
|
||||
foreach my $config (@conf){
|
||||
my $key = $config->key;
|
||||
|
||||
my $status = $config->prop('status') || 'enabled';
|
||||
my $linkup = "<span style='color:red'>". $fm->localise('DOWN')."</span>" ;
|
||||
use Net::Ping;
|
||||
my $p = Net::Ping->new('icmp');
|
||||
$linkup = "<span style='color:green'>". $fm->localise('UP') . "</span>" if (($status eq "enabled" ) && ( $p->ping($config->prop('RemoteIP'),1) ) );
|
||||
$linkup = " " if ($status eq "disabled" );
|
||||
|
||||
if ($status eq 'enabled'){
|
||||
$status = $fm->localise('ENABLED');
|
||||
}
|
||||
elsif ($status eq 'disabled'){
|
||||
$status = $fm->localise('DISABLED');
|
||||
}
|
||||
my $cipher = $config->prop('Cipher') || 'BF-CBC';
|
||||
$cipher = "<span style='color:red'>". $fm->localise('INSECURE'). " $cipher</span> " unless ($cipher =~ /(128|192|256|512|SEED)/ );
|
||||
my $hmac = $config->prop('HMAC') || 'SHA1';
|
||||
$hmac= "<span style='color:red'>". $fm->localise('INSECURE'). " $hmac</span> " unless ($hmac eq "whirlpool" || $hmac =~ /(512|256|384|224)$/);
|
||||
my $authe = $config->prop('Authentication') || '';
|
||||
|
||||
print $q->Tr (esmith::cgi::genSmallCell($q,"$key"),
|
||||
esmith::cgi::genSmallCell($q,"$status"),
|
||||
esmith::cgi::genSmallCell($q,"$cipher"),
|
||||
esmith::cgi::genSmallCell($q,"$hmac"),
|
||||
esmith::cgi::genSmallCell($q,"$authe"),
|
||||
esmith::cgi::genSmallCell($q,"$linkup"),
|
||||
esmith::cgi::genSmallCell ($q, $q->a ({href => $q->url (-absolute => 1).
|
||||
$base_url."RELOAD_PAGE&action=reload&conf_name=".
|
||||
$key}, $fm->localise('RELOAD'))),
|
||||
esmith::cgi::genSmallCell ($q, $q->a ({href => $q->url (-absolute => 1).
|
||||
$base_url."CREATE_OR_MODIFY_".uc($type)."_CONF_PAGE&action=modify&conf_name=".
|
||||
$key}, $fm->localise('MODIFY'))),
|
||||
esmith::cgi::genSmallCell ($q, $q->a ({href => $q->url (-absolute => 1).
|
||||
$base_url."REMOVE_CONF_PAGE&conf_name=".
|
||||
$key}, $fm->localise('REMOVE'))));
|
||||
}
|
||||
print $q->end_table,"\n";
|
||||
return "";
|
||||
}
|
||||
|
||||
# Print conf_name field
|
||||
sub print_conf_name_field{
|
||||
my $fm = shift;
|
||||
my $q = $fm->{cgi};
|
||||
my $name = $q->param('conf_name') || '';
|
||||
my $action = $q->param('action') || '';
|
||||
print qq(<tr><td colspan="2">) . $fm->localise('DESC_CONF_NAME').qq(</td></tr>);
|
||||
print qq(<tr><td class="sme-noborders-label">) .
|
||||
$fm->localise('CONF_NAME') . qq(</td>\n);
|
||||
if ($action eq 'modify' and $name) {
|
||||
print qq(
|
||||
<td class="sme-noborders-content">$name
|
||||
<input type="hidden" name="name" value="$name">
|
||||
<input type="hidden" name="action" value="modify">
|
||||
</td>
|
||||
);
|
||||
|
||||
# If action is modify, we need to read the DB
|
||||
# And set CGI parameters
|
||||
|
||||
my $rec = $ovpn_db->get($name);
|
||||
if ($rec){
|
||||
if ($rec->prop('type') eq 'client'){
|
||||
$q->param(-name=>'remote_host',-value=>
|
||||
$rec->prop('RemoteHost'));
|
||||
}
|
||||
$q->param(-name=>'auth',-value=>
|
||||
$rec->prop('Authentication'));
|
||||
$q->param(-name=>'local_ip',-value=>
|
||||
$rec->prop('LocalIP'));
|
||||
$q->param(-name=>'remote_ip',-value=>
|
||||
$rec->prop('RemoteIP'));
|
||||
$q->param(-name=>'port',-value=>
|
||||
$rec->prop('Port'));
|
||||
$q->param(-name=>'comment',-value=>
|
||||
$rec->prop('Comment'));
|
||||
$q->param(-name=>'status',-value=>
|
||||
$rec->prop('status'));
|
||||
$q->param(-name=>'remote_net',-value=>
|
||||
$rec->prop('RemoteNetworks'));
|
||||
$q->param(-name=>'hmac',-value=>
|
||||
get_current_hmac($fm));
|
||||
$q->param(-name=>'cipher',-value=>
|
||||
get_current_cipher($fm));
|
||||
$q->param(-name=>'SnatOutbound',-value=>
|
||||
$rec->prop('SnatOutbound'));
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
print qq(
|
||||
<td><input type="text" name="conf_name" value="$name">
|
||||
<input type="hidden" name="action" value="create">
|
||||
</td>
|
||||
);
|
||||
$q->param(-name=>'status',-value=>
|
||||
'enabled')
|
||||
}
|
||||
|
||||
print qq(</tr>\n);
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub remove_conf{
|
||||
my ($fm) = @_;
|
||||
my $q = $fm->{cgi};
|
||||
my $conf = $q->param('conf_name');
|
||||
unless($q->param("cancel")){
|
||||
unless ($ovpn_db->get($conf)->delete()){
|
||||
$fm->error('ERROR_OCCURED','FIRST_PAGE');
|
||||
return undef;
|
||||
}
|
||||
unless (system ("/sbin/e-smith/signal-event", "openvpn-s2s-update") == 0 ){
|
||||
$fm->error('ERROR_OCCURED','FIRST_PAGE');
|
||||
return undef;
|
||||
}
|
||||
update_ports();
|
||||
$fm->success('SUCCESS','FIRST_PAGE');
|
||||
return undef;
|
||||
}
|
||||
$fm->error('CANCELED','FIRST_PAGE');
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub print_conf_to_remove{
|
||||
my ($fm) = @_;
|
||||
my $q = $fm->{cgi};
|
||||
my $conf = $q->param('conf_name');
|
||||
my $rec = $ovpn_db->get($conf);
|
||||
my $comment = $rec->prop('Comment') || '';
|
||||
|
||||
print $q->Tr(
|
||||
$q->td(
|
||||
{ -class => 'sme-noborders-label' },
|
||||
$fm->localise('CONF_NAME')
|
||||
),
|
||||
$q->td( { -class => 'sme-noborders-content' }, $conf )
|
||||
),
|
||||
"\n";
|
||||
print $q->Tr(
|
||||
$q->td(
|
||||
{ -class => 'sme-noborders-label' },
|
||||
$fm->localise('COMMENT')
|
||||
),
|
||||
$q->td( { -class => 'sme-noborders-content' }, $comment )
|
||||
),
|
||||
"\n";
|
||||
|
||||
print $q->table(
|
||||
{ -width => '100%' },
|
||||
$q->Tr(
|
||||
$q->th(
|
||||
{ -class => 'sme-layout' },
|
||||
$q->submit(
|
||||
-name => 'cancel',
|
||||
-value => $fm->localise('CANCEL')
|
||||
),
|
||||
' ',
|
||||
$q->submit(
|
||||
-name => 'remove',
|
||||
-value => $fm->localise('REMOVE')
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
"\n";
|
||||
|
||||
# Clear these values to prevent collisions when the page reloads.
|
||||
$q->delete("cancel");
|
||||
$q->delete("remove");
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub read_file{
|
||||
my $file = shift;
|
||||
my $ret = '';
|
||||
|
||||
if (open (PEM, "<$file")){
|
||||
$ret .= $_ while (<PEM>);
|
||||
close PEM;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
# Validation routines
|
||||
sub is_valid_key{
|
||||
my ($fm, $string) = @_;
|
||||
my $ret = 'OK';
|
||||
# Just check if the string is empty
|
||||
$ret = $fm->localise('INVALID_SHARED_KEY') if ($string eq '');
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub is_url_or_empty{
|
||||
my ($fm, $url) = @_;
|
||||
my $ret = 'OK';
|
||||
if (defined $url && ($url !~ /^(http:\/\/)|(https:\/\/)/) && ($url ne '')){
|
||||
$ret = $fm->localise('NOT_A_VALID_URL',{string => $url});
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub is_valid_net_or_empty{
|
||||
my ($fm, $nets) = @_;
|
||||
my $ret = 'OK';
|
||||
my $conf = $fm->{cgi}->param('conf_name') || '';
|
||||
|
||||
foreach my $net (split (/[;,]/, $nets)){
|
||||
$ret = $fm->localise('INVALID_NET') unless $net =~ m/([\d\.]+)\/([\d\.]+)/;
|
||||
my $netaddr = $1;
|
||||
my $mask = $2;
|
||||
$ret = $fm->localise('NET_IS_LOCAL') if
|
||||
($net_db->get("$netaddr") &&
|
||||
($net_db->get("$netaddr")->prop('VPN') || '') ne $conf);
|
||||
$ret = $fm->localise('INVALID_NET') unless
|
||||
(CGI::FormMagick::Validator::ip_number($fm,$netaddr) eq 'OK' &&
|
||||
CGI::FormMagick::Validator::ip_number($fm,$mask) eq 'OK');
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub is_hostname_or_ip{
|
||||
my ($fm,$host) = @_;
|
||||
return "OK" if ( CGI::FormMagick::Validator::ip_number( $fm, $host ) eq "OK" );
|
||||
return "OK" if ( $host =~ m/^([a-zA-Z0-9][\_\.\-a-zA-Z0-9]*)$/);
|
||||
return $fm->localise('NOT_A_VALID_HOSTNAME_OR_IP');
|
||||
}
|
||||
|
||||
sub validate_conf_name{
|
||||
my ($fm, $conf_name) = @_;
|
||||
|
||||
unless ($conf_name =~ /^([a-zA-Z0-9][\_\.\-a-zA-Z0-9]{0,9})$/){
|
||||
return $fm->localise('INVALID_CHARS',{string => $conf_name});
|
||||
}
|
||||
return "OK";
|
||||
}
|
||||
|
||||
sub is_valid_port{
|
||||
my ($fm, $port) = @_;
|
||||
my $ret = $fm->localise('NOT_A_VALID_PORT',{string => $port});
|
||||
|
||||
if (($port =~ /^\d+$/) &&
|
||||
($port > 0) &&
|
||||
($port < 65536)){
|
||||
$ret = "OK";
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub is_valid_vpn_ip{
|
||||
my ($fm,$ip) = @_;
|
||||
my $ret = 'OK';
|
||||
my $conf = $fm->{cgi}->param('conf_name') || '';
|
||||
|
||||
# Check it's a valid IP number
|
||||
return $fm->localise('NOT_A_VALID_IP_NUMBER') unless
|
||||
( CGI::FormMagick::Validator::ip_number( $fm, $ip ) eq "OK" );
|
||||
|
||||
# Check it's not already used by another daemon
|
||||
foreach my $vpn ($ovpn_db->get_all_by_prop(type=>'client'),
|
||||
$ovpn_db->get_all_by_prop(type=>'server')){
|
||||
next if ($vpn->key eq $conf);
|
||||
$ret = $fm->localise('IP_ALREADY_IN_USED')
|
||||
if ((($vpn->prop('LocalIP') || '') eq $ip) ||
|
||||
(($vpn->prop('RemoteIP') || '') eq $ip));
|
||||
}
|
||||
|
||||
# 127 is a reserved network
|
||||
return $fm->localise('RESERVED_NET') if ($ip =~ m/^127\./);
|
||||
|
||||
# Check if it's not part of a local network
|
||||
foreach my $net ($net_db->networks){
|
||||
# Skip VPN networks
|
||||
next if (($net->prop('VPN') || '') ne '');
|
||||
my $mask = $net->prop('Mask');
|
||||
$net = $net->key . '/' . $mask;
|
||||
$ret = $fm->localise('IP_IN_LOCAL_NET') if (eval{Net::IPv4Addr::ipv4_in_network($net,$ip)});
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
sub is_valid_and_available_port{
|
||||
my ($fm, $port) = @_;
|
||||
my $ret = is_valid_port($fm,$port);
|
||||
|
||||
my $conf = $fm->{cgi}->param('conf_name');
|
||||
my $oldport = $ovpn_db->get_prop($conf,'Port') || '';
|
||||
|
||||
# If the port is valid
|
||||
# Check if it's not used by another service
|
||||
if ($ret eq 'OK'){
|
||||
my @used = ();
|
||||
foreach my $srv ($conf_db->get_all_by_prop(type=>'service')){
|
||||
push @used, $srv->prop('UDPPort') if $srv->prop('UDPPort');
|
||||
push @used, $srv->prop('TCPPort') if $srv->prop('TCPPort');
|
||||
push @used, split( /[;,]/, $srv->prop('UDPPorts')) if $srv->prop('UDPPorts');
|
||||
push @used, split( /[;,]/, $srv->prop('TCPPorts')) if $srv->prop('TCPPorts');
|
||||
}
|
||||
# Remove the old port number from the list
|
||||
# So it won't be marked as already used
|
||||
# if we just modify an existing VPN server
|
||||
foreach my $i (0..$#used){
|
||||
splice(@used,$i,1) if ($used[$i] eq $oldport);
|
||||
}
|
||||
|
||||
$ret = $fm->localise('PORT_ALREAY_USED',{string => $port})
|
||||
if (grep { $_ eq $port } @used);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
###### those are copy paste for bridge and s2s
|
||||
#
|
||||
=head2 get_current_hmac
|
||||
|
||||
=cut
|
||||
sub get_current_hmac{
|
||||
my ($self) = @_;
|
||||
my $name = $self->cgi->param('conf_name') or return "SHA256";
|
||||
my $cvpn= $ovpn_db->get($name);
|
||||
return "SHA1" unless defined $cvpn->prop('HMAC');
|
||||
return $cvpn->prop('HMAC') ;
|
||||
}
|
||||
|
||||
|
||||
=head2 get_digests_options
|
||||
|
||||
=cut
|
||||
sub get_digests_options{
|
||||
my ($self) = @_;
|
||||
my $translate = $self->localise('DEFAULT');
|
||||
my $suggested = $self->localise('SUGGESTED');
|
||||
my %options= (
|
||||
'whirlpool' => 'whirlpool (512)',
|
||||
'SHA512' => 'SHA512',
|
||||
'SHA384' => 'SHA384',
|
||||
'SHA256' => 'SHA256' . ": $suggested",
|
||||
'SHA224' => 'SHA224',
|
||||
'SHA1' => 'SHA1 (160)' . ": $translate",
|
||||
'SHA' => 'SHA (160)',
|
||||
'ecdsa-with-SHA1' => 'ecdsa-with-SHA1 (160)',
|
||||
'RIPEMD160' => 'RIPEMD160',
|
||||
'MD5' => 'MD5 (128)',
|
||||
'MD4' => 'MD4 (128)',
|
||||
);
|
||||
return \%options;
|
||||
}
|
||||
|
||||
|
||||
=head2 get_current_cipher
|
||||
list obtained using
|
||||
openvpn --show-digests | egrep 'digest size' | awk {'print "'\''" $1 "'\'' => '\''" $1 "'\''," '}
|
||||
=cut
|
||||
sub get_current_cipher{
|
||||
my ($self) = @_;
|
||||
my $name = $self->cgi->param('conf_name') or return "AES-128-CBC";
|
||||
my $cvpn= $ovpn_db->get($name);
|
||||
return "BF-CBC" unless defined $cvpn->prop('Cipher');
|
||||
return $cvpn->prop('Cipher') ;
|
||||
}
|
||||
|
||||
=head2 get_ciphers_options
|
||||
list obtained using
|
||||
openvpn --show-ciphers | egrep '^[A-Z]{2}' | sed 's/ by//; s/ default//; s/block,/block/; s/)// ' | awk {'print " '\''" $1 "'\'' => '\''" $1 $2 " " $4 " " $5 " " $7")'\''," '}
|
||||
then reduced to remove most of insecure ciphers
|
||||
Using a CBC or GCM mode is recommended.
|
||||
In static key mode only CBC mode is allowed.
|
||||
|
||||
=cut
|
||||
sub get_ciphers_options{
|
||||
my ($self) = @_;
|
||||
my $translate = $self->localise('DEFAULT');
|
||||
my $suggested = $self->localise('SUGGESTED');
|
||||
my %options= (
|
||||
'AES-128-CBC' => 'AES-128-CBC (128 key, 128 block)'.": $suggested",
|
||||
'AES-128-CFB' => 'AES-128-CFB (128 key, 128 block)',
|
||||
'AES-128-CFB1' => 'AES-128-CFB1 (128 key, 128 block)',
|
||||
'AES-128-CFB8' => 'AES-128-CFB8 (128 key, 128 block)',
|
||||
'AES-128-GCM' => 'AES-128-GCM (128 key, 128 block)',
|
||||
'AES-128-OFB' => 'AES-128-OFB (128 key, 128 block)',
|
||||
'AES-192-CBC' => 'AES-192-CBC (192 key, 128 block)',
|
||||
'AES-192-CFB' => 'AES-192-CFB (192 key, 128 block)',
|
||||
'AES-192-CFB1' => 'AES-192-CFB1 (192 key, 128 block)',
|
||||
'AES-192-CFB8' => 'AES-192-CFB8 (192 key, 128 block)',
|
||||
'AES-192-GCM' => 'AES-192-GCM (192 key, 128 block)',
|
||||
'AES-192-OFB' => 'AES-192-OFB (192 key, 128 block)',
|
||||
'AES-256-CBC' => 'AES-256-CBC (256 key, 128 block)',
|
||||
'AES-256-CFB' => 'AES-256-CFB (256 key, 128 block)',
|
||||
'AES-256-CFB1' => 'AES-256-CFB1 (256 key, 128 block)',
|
||||
'AES-256-CFB8' => 'AES-256-CFB8 (256 key, 128 block)',
|
||||
'AES-256-GCM' => 'AES-256-GCM (256 key, 128 block)',
|
||||
'AES-256-OFB' => 'AES-256-OFB (256 key, 128 block)',
|
||||
'CAMELLIA-128-CBC' => 'CAMELLIA-128-CBC (128 key, 128 block)',
|
||||
'CAMELLIA-128-CFB' => 'CAMELLIA-128-CFB (128 key, 128 block)',
|
||||
'CAMELLIA-128-CFB1' => 'CAMELLIA-128-CFB1 (128 key, 128 block)',
|
||||
'CAMELLIA-128-CFB8' => 'CAMELLIA-128-CFB8 (128 key, 128 block)',
|
||||
'CAMELLIA-128-OFB' => 'CAMELLIA-128-OFB (128 key, 128 block)',
|
||||
'CAMELLIA-192-CBC' => 'CAMELLIA-192-CBC (192 key, 128 block)',
|
||||
'CAMELLIA-192-CFB' => 'CAMELLIA-192-CFB (192 key, 128 block)',
|
||||
'CAMELLIA-192-CFB1' => 'CAMELLIA-192-CFB1 (192 key, 128 block)',
|
||||
'CAMELLIA-192-CFB8' => 'CAMELLIA-192-CFB8 (192 key, 128 block)',
|
||||
'CAMELLIA-192-OFB' => 'CAMELLIA-192-OFB (192 key, 128 block)',
|
||||
'CAMELLIA-256-CBC' => 'CAMELLIA-256-CBC (256 key, 128 block)',
|
||||
'CAMELLIA-256-CFB' => 'CAMELLIA-256-CFB (256 key, 128 block)',
|
||||
'CAMELLIA-256-CFB1' => 'CAMELLIA-256-CFB1 (256 key, 128 block)',
|
||||
'CAMELLIA-256-CFB8' => 'CAMELLIA-256-CFB8 (256 key, 128 block)',
|
||||
'CAMELLIA-256-OFB' => 'CAMELLIA-256-OFB (256 key, 128 block)',
|
||||
'SEED-CBC' => 'SEED-CBC (128 key, 128 block)',
|
||||
'SEED-CFB' => 'SEED-CFB (128 key, 128 block)',
|
||||
'SEED-OFB' => 'SEED-OFB (128 key, 128 block)',
|
||||
'BF-CBC' => 'BF-CBC(128 key, 64 block)'. ": $translate ",
|
||||
);
|
||||
return \%options;
|
||||
}
|
||||
|
||||
1;
|
Reference in New Issue
Block a user