#!/usr/bin/env perl # for linux use #!/usr/bin/perl # for freebsd use #!/usr/local/bin/perl # vpn : create delete and connect to openvpn pptp l2tp # this just manages proiles it doesn't setup pptp openvpn or l2tp # l2tp requires start and stop scripts - at the end of this file # this script creates an ovpn file which uses tcp, most openvpn uses udp # modify the ovpn file to work for each router running openvpn server $ver = "0.20"; #print "$ENV{'USER'}\n"; #exit; @d = localtime(); $d[4]++; if ($d[5] < 1900) { $d[5]+=1900; } printf("$d[5]-%02i-%02i %02i:%02i:%02i\n",$d[4],$d[3],$d[2],$d[1],$d[0]); $home = $ENV{'HOME'}; $osname = $^O; $osver = ''; if ($osname =~ /freebsd/i) { $freebsd = 1; # pkg install strongswan mpd5 # /etc/rc.conf: strongswan_interface="stroke" # to disable vici # /boot/loader/conf: ipsec_load="YES" } elsif ($osname =~ /linux/i) { $linux = 1; } if (-e "/etc/os-release" && open(FILE,"/etc/os-release")) { while() { if ($_ =~ /freebsd/i) { $freebsd = 1; } elsif ($_ =~ /linux|debian|ubuntu/i) { $linux = 1; } if ($_ =~ /VERSION[^\"]+\"([\d\.]+)/i) { $osver = $1; } } close(FILE); } if (!$freebsd && !$linux) { die "Error, can't detect FreeBSD or Linux OS\n"; } if (-e "/usr/local/sbin/openvpn") { $opath = "/usr/local/sbin"; } elsif (-e "/usr/sbin/openvpn") { $opath = "/usr/sbin"; } if (-e "/usr/local/sbin/pptp") { $ppath = "/usr/local/sbin"; } elsif (-e "/usr/sbin/pppd") { $ppath = "/usr/sbin"; } if (-e "/usr/local/sbin/xl2tpd") { $lpath = "/usr/local/sbin"; } elsif (-e "/usr/sbin/xl2tpd") { $lpath = "/usr/sbin"; } # FreeBSD Paths if (-e "/usr/local/sbin/mpd5") { $mpath = "/usr/local/sbin"; } if (-e "/usr/local/sbin/ipsec") { $ipath = "/usr/local/sbin"; } if (!$opath && !$ppath && !$lpath) { die "Unable to find location of openvpn pppd or xl2tpd binaries\n"; } if ($ARGV[0] =~ /^\-+h/) { &vpnhelp; exit(0); } elsif ($ARGV[0] =~ /\-reset/ && $freebsd) { print "FreeBSD network reset.\n"; system("service netif restart"); system("service routing restart"); exit(0); } elsif ($ARGV[0] =~ /\-l\b/) { $str = $ARGV[1]; &vpnlist($str); exit(0); } elsif ($ARGV[0] =~ /^\-s|stop|kill|close/i) { &vpnstop; exit(0); } elsif ($ARGV[0] =~ /\-oset|\-oadd/i) { $str = $ARGV[1]; &addopenvpn($str); exit(0); } elsif ($ARGV[0] =~ /\-odel|\-orem/ && $ARGV[1]) { $str = $ARGV[1]; &removeovpn($str); } elsif ($ARGV[0] =~ /\-pset|\-padd/) { $str = $ARGV[1]; &addpptp($str); exit(0); } elsif ($ARGV[0] =~ /\-pdel|\-prem/ && $ARGV[1]) { # if ($freebsd) { die "Command only works with Debian.\n"; } $str = $ARGV[1]; &removepptp($str); } elsif ($ARGV[0] =~ /\-lset|\-ladd/) { $str = $ARGV[1]; &addl2tp($str); } elsif ($ARGV[0] =~ /\-ldel|\-lrem/ && $ARGV[1]) { $str = $ARGV[1]; if ($freebsd) { &bsd_removel2tp($str); } else { &deb_removel2tp($str); } } elsif ($ARGV[0] =~ /start/ && $ARGV[1]) { $str = $ARGV[1]; } elsif ($ARGV[0] =~ /\-p/ && $ARGV[1]) { $str = $ARGV[1]; $pptp = 1; } elsif ($ARGV[0] =~ /\-l2/ && $ARGV[1]) { $str = $ARGV[1]; $l2tp = 1; } elsif ($ARGV[0] && $ARGV[0] !~ /help/) { $str = $ARGV[0]; } else { &vpnhelp; &vpnlist(''); exit(0); } if ($str =~ /^stop/i) { die "Error, profile $str matches reserved word stop.\n"; } # OpenVPN simple if (!$l2tp && !$pptp && -e "$home/OpenVPN/config/$str") { # openvpn &ovpn($str); exit(0); } # debian pptp simple if (!$l2tp && -e "/etc/ppp/peers/$str") { # debian pptp print "$ppath/pppd call $str\n"; system("$ppath/pppd call $str"); exit(0); } # debian l2tp simple # this works - see code at end of this file if (!$pptp && -e "/etc/ppp/l2tp/$str") { print "$home/bin/start-l2tp $str\n"; system("$home/bin/start-l2tp $str"); exit(0); } #route 192.168.0.0 255.255.0.0 #route 172.16.20.0 255.255.224.0 # route 10.0.0.0 255.0.0.0 # the next 4 avoid 10.200 and some other nets #route 10.0.0.0 255.128.0.0 #route 10.128.0.0 255.192.0.0 #route 10.208.0.0 255.240.0.0 #route 10.224.0.0 255.224.0.0 # freebsd pptp simple and store matches $profile = ''; $match = ''; if (!$l2tp && $freebsd && -e "/etc/ppp/ppp.conf" && open(FILE,"/etc/ppp/ppp.conf")) { print "searching /etc/ppp/ppp.conf\n"; while() { if ($_ =~ /^$str:/) { $profile = $str; } elsif ($_ =~ /^($str\S+):/i && length($str) >= 3 && !$match) { $match = $1; } elsif ($_ =~ /^$str\S+:/i && length($str) >= 3) { print "Warning: More than one match to $str in /etc/ppp/ppp.conf\n"; } elsif ($profile && $_ =~ /^\s+#\s*WAN\s*(\S+)\s*$/) { $ip = $1; last; } elsif ($match && !$addr{$match} && $_ =~ /^\s+#\s*WAN\s*(\S+)\s*$/) { $addr{$match} = $1; } } closedir(FILE); if ($profile && $ip) { print "$ppath/pptp $ip $profile\n"; system("$ppath/pptp $ip $profile &"); exit(0); } } if (length($str) < 3) { die "Error, no 'exact' match to $str, use at least 3 characters for matching.\n"; } # openvpn match $profile = ''; if (!$l2tp && !$pptp && opendir(DIR,"$home/OpenVPN/config")) { $profile = ''; while($file = readdir(DIR)) { if ($file =~ /^\.{1,2}$/) { next; } if ($file =~ /^$str/i) { if ($profile) { die "Error, more than one OpenVPN profile matches $str.\n"; } else { $profile = $file; } } } closedir(DIR); if ($profile) { &ovpn($profile); exit(0); } } # freebsd pptp match if (!$l2tp && freebsd && $match && $addr{$match}) { print "$ppath/pptp $addr{$match} $match\n"; system("$ppath/pptp $addr{$match} $match &"); exit(0); } # debian pptp match if (!$l2tp && $linux && -e "/etc/ppp/peers" && opendir(DIR,"/etc/ppp/peers")) { $profile = ''; while($file = readdir(DIR)) { if ($file =~ /^\.{1,2}$|^provider$|^failed$/) { next; } if ($file =~ /^$str/i) { if (!$profile) { $profile = $file; } else { print "Warning: More than one match to $str in /etc/ppp/peers\n"; } } } closedir(DIR); if ($profile) { print "$ppath/pppd call $profile\n"; system("$ppath/pppd call $profile"); exit(0); } } # debian l2tp match if (!$pptp && $linux && -e "/etc/ppp/l2tp" && opendir(DIR,"/etc/ppp/l2tp")) { $profile = ''; while($file = readdir(DIR)) { if ($file =~ /^\.{1,2}$|^provider$|^failed$|\.conf$/) { next; } if ($file =~ /^$str/i) { if (!$profile) { $profile = $file; } else { print "Warning: More than one match to $str in /etc/ppp/l2tp\n"; } } } closedir(DIR); if ($profile) { # this works print "$home/bin/start-l2tp $profile\n"; system("$home/bin/start-l2tp $profile"); exit(0); } # freebsd l2tp match } elsif (!$pptp && $freebsd && -e "/usr/local/sbin/mpd5" && -e "/usr/local/sbin/ipsec" && -e "/usr/local/etc/ipsec.secrets" && -e "/usr/local/etc/mpd5/mpd.conf") { my $dol2tp=0; # check ipsec for matches if (open(FILE,"/usr/local/etc/ipsec.conf")) { while() { if ($_ =~ /^conn\s+($str\S*)/i) { if (!$profile) { $profile = $1; } else { print "Warning: More than one match to $str in /usr/local/etc/ipsec.conf\n"; } } } close(FILE); } # check mpd for profile if ($profile && open(FILE,"/usr/local/etc/mpd5/mpd.conf")) { while() { if ($_ =~ /^$profile:/) { $dol2tp=1; last; } } close(FILE); } if ($profile && $dol2tp==1) { &vpnstop; sleep(1); my $failed = 0; if (system("$ipath/ipsec up $profile")==0) { print "Success: $ipath/ipsec up $profile\n"; if (system("/usr/local/sbin/mpd5 -b $profile")==0) { print "Success: /usr/local/sbin/mpd5 -b $profile\n"; } else { print "Failed: /usr/local/sbin/mpd5 -b $profile\n"; $failed = 1; } } else { print "Failed: $ipath/ipsec up $profile\n"; $failed = 1; } if ($failed) { &vpnstop; } exit(0); } } die "Error, no VPN profile matches $str.\n"; sub vpnhelp { print "This is an OpenVPN wrapper. Note Microtik uses TCP not UDP. OPVN config files are in $home/OpenVPN/config/\[profilename\] List: vpn -l [filter] Start: vpn [profile] Stop: vpn -s PPTP Force: vpn -p [profile] L2TP Force: vpn -l2 [profile] OVPN Setup: vpn -oadd [profile] [IP_ADDRESS] PPTP Setup: vpn -padd [profile] L2TP Setup: vpn -ladd [profile] OVPN Delete: vpn -odel [profile] PPTP Delete: vpn -pdel [profile] L2TP Delete: vpn -ldel [profile]\n"; } sub ovpn { my($profile) = @_; print "ovpn:$home/OpenVPN/config/$profile\n"; opendir(DIR,"$home/OpenVPN/config/$profile"); while($file = readdir(DIR)) { if ($file =~ /^\.{1,2}$/) { next; } if ($file =~ /\.ovpn$/i) { if ($configfile) { die "Error, more than one \.ovpn in $home/OpenVPN/config/$profile\n"; } else { $configfile = $file; } } elsif ($file =~ /auto|auth/i) { # like autologin.pass $authfile = $file; } elsif ($file =~ /ta\.key|hmac|tls/i) { # like autologin.pass $tlsfile = $file; } } closedir(DIR); if (!$configfile) { die "Error, could not find an \.ovpn file in $home/OpenVPN/config/$profile\n"; } elsif (!$authfile && !$tlsfile) { die "Error, could not find $home/OpenVPN/config/$profile/\[auto|auth] file\nFile $profile.auth should contain a login and password one per line.\n"; } # lets check if tls is really enabled in config file # actually you can do both so always use user and password # leave tls what is in the config file if (0 && $tlsfile && open(FILE,"$home/OpenVPN/config/$profile/$configfile")) { # this is for tls authentication without username and password only while() { if ($_ =~ /^\W/) { next; } if ($_ =~ /^tls-auth\s+.*$tlsfile.*\s+1/i) { $tls = 1; last; } } close(FILE); if ($tls) { # Use TLS ta.key to connect print "$opath/openvpn --cd $home/OpenVPN/config/$profile --config $configfile\n"; system("$opath/openvpn --cd $home/OpenVPN/config/$profile --config $configfile &"); return; } } if (!$authfile) { die "Error, tls ta.key and $home/OpenVPN/config/$profile/\[auto|auth] file not found.\nFile $profile.auth should contain a login and password one per line.\n"; } # Use authfile username password and tls if so configured print "$opath/openvpn --cd $home/OpenVPN/config/$profile --auth-user-pass $authfile --config $configfile\n"; system("$opath/openvpn --cd $home/OpenVPN/config/$profile --auth-user-pass $authfile --config $configfile &"); } # subroutines sub vpnlist { my($search) = @_; my($file); opendir(DIR,"$home/OpenVPN/config"); while($file = readdir(DIR)) { if ($file =~ /^\.{1,2}$/) { next; } push(@olist, $file); $vlist{"$file.o"} .= "ovpn: $file\n"; } closedir(DIR); if ($freebsd) { if (-e "/etc/ppp/ppp.conf" && open(FILE,"/etc/ppp/ppp.conf")) { my $lastpeer; while() { if ($_ =~ /^(\S+):/) { $lastpeer = $1; } elsif ($_ =~ /^\s+#\s*WAN\s*(\S+)\s*$/) { if ($lastpeer) { #print "pptp: $lastpeer\n"; $vlist{"$lastpeer.p"} .= "pptp: $lastpeer\n"; } $lastpeer = ''; } elsif ($_ !~ /\w/) { $lastpeer = ''; } } close(FILE); } if (-e "/usr/local/etc/mpd5/mpd.conf" && -e "/usr/local/etc/ipsec.conf" && open(FILE,"/usr/local/etc/ipsec.conf")) { while() { if ($_ !~ /conn\s+\%default/ && $_ =~ /^conn\s+(\S+)/) { my $lhost = $1; $vlist{"$lhost.l"} .= "l2tp: $lhost\n"; } } close (FILE); } } else { # debian opendir(DIR,"/etc/ppp/peers"); while($file = readdir(DIR)) { if ($file =~ /^\.{1,2}$|^provider$|^failed$/) { next; } $vlist{"$file.p"} .= "pptp: $file\n"; } closedir(DIR); opendir(DIR,"/etc/ppp/l2tp"); while($file = readdir(DIR)) { if ($file =~ /^\.{1,2}$|^failed$|\.ipsec$|\.conf$/) { next; } $vlist{"$file.l"} .= "l2tp: $file\n"; } closedir(DIR); } print "------------------ list --------------------\n"; foreach $i (sort {$a cmp $b} keys %vlist) { if (!$search || $i =~ /$search/i) { print $vlist{$i}; } } print "--------------------------------------------\n"; } sub vpnstop { if ($freebsd) { open(PS,"$ipath/ipsec status|"); while() { if ($_ =~ /ESTABLISHED|INSTALLED/ && $_ =~ /^\s*([^\[\]\{\}\:\s]+)/) { my $profile = $1; system("$ipath/ipsec down $profile"); } } close(PS); system("$ipath/ipsec stop"); system("$ipath/ipsec start"); } # kill all mpd ppp openvpn processes my $x = 0; open(PS,"ps -agxw|"); while() { if ($_ =~ /openvpn|\/sbin\/ppp\b|\/pppd call|sbin\/mpd/ && $_ =~ /^\s*(\d+)/) { my $pid = $1; if ($pid == $$) { next; } kill(1,$pid); # SIGHUP $x++; } } close(PS); # some types do not close with a SIGHUP sleep(1); open(PS,"ps -agxw|"); while() { if ($_ =~ /openvpn|\/sbin\/ppp\b|\/pppd call|sbin\/mpd/ && $_ =~ /^\s*(\d+)/) { my $pid = $1; if ($pid == $$) { next; } kill(2,$pid); # SIGINT $x++; } } close(PS); if (-e "/var/run/xl2tpd/l2tp-control") { system("$home/bin/stop-l2tp"); print "L2TP: Found /var/run/xl2pd-control so ran stop-l2tp.\n"; if ($x == 0) { return; } } if ($x > 1) { print "Killed $x processes matching openvpn or ppp\n"; } elsif ($x && $pid) { print "Killed $x process pid=$pid\n"; } else { print "Killed $x processes.\n"; } } sub removeovpn { my($profile) = @_; if (-d "$ENV{'HOME'}/OpenVPN/config/$profile") { while($inp !~ /^y|^n/i) { print "Are you sure [y/n]? "; $inp = ; } if ($inp =~ /^y/) { system("rm -r $ENV{'HOME'}/OpenVPN/config/$profile"); die "OVPN: Deleted $profile\n"; } else { die "OVPN: Skipped delete $profile\n"; } } } sub bsd_removel2tp { my($profile) = @_; my %ipsec_secrets = (); # remove ipsec.conf if (open(FILE,"/usr/local/etc/ipsec.conf")) { my @new_file = (); while() { if ($_ =~ /^config\s+setup|conn\s+\%default\b/) { $match = 0; } elsif ($_ =~ /^conn\s+$profile\b/) { $match = 1; } elsif ($_ =~ /^conn\s+\S+/) { $match = 0; } if (!$match) { push(@new_file, $_); } elsif ($match && $_ =~ /^\s*right=\s*(\S+)/) { $ipsec_secrets{$1} = 1; } } close(FILE); if (@new_file && open(FILE,">/usr/local/etc/ipsec.conf")) { print FILE (@new_file); close(FILE); } else { print "Error Write: /usr/local/etc/ipsec.conf\n"; } } else { print "Error Read: /usr/local/etc/ipsec.conf\n"; } # remove mpd5.conf if (open(FILE,"/usr/local/etc/mpd5/mpd.conf")) { print "Opening /usr/local/etc/mpd5/mpd.conf\n"; my @new_file = (); while() { if ($_ =~ /^startup:|^log\s+\S|^default:/) { $match = 0; } elsif ($_ =~ /^$profile:/) { $match = 1; } elsif ($_ =~ /^[^\s\:]+\:/) { $match = 0; } if (!$match) { push(@new_file, $_); } elsif ($match && $_ =~ /^\s*set\s+l2tp\s+peer\s+(\S+)/) { $ipsec_secrets{$1} = 1; } } close(FILE); print "Writing /usr/local/etc/mpd5/mpd.conf\n"; if (@new_file && open(FILE,">/usr/local/etc/mpd5/mpd.conf")) { print FILE (@new_file); close(FILE); } else { print "Error Write: /usr/local/etc/mpd5/mpd.conf\n"; } } else { print "Error Read: /usr/local/etc/mpd5/mpd.conf\n"; } if (%ipsec_secrets) { print "Secrets may be use by more than one profile, delete with caution.\n"; if (open(FILE,"/usr/local/etc/ipsec.secrets")) { my @new_file = (); while() { if ($_ =~ /^(\S+) \: PSK \"([^\"]+)\"/ && $ipsec_secrets{$1}) { my $secrethost = $1; my $secret = $2; my $removesecrets = ""; while($removesecrets !~ /^y|^n/i) { print "Remove PSK \"$secret\" for host '$secrethost' (y|n)? "; $removesecrets = ; if ($removesecrets =~ /^y/) { last; } elsif ($removesecrets =~ /^n/) { push(@new_file,$_); } } } else { push(@new_file,$_); } } close(FILE); if (@new_file && open(FILE,">/usr/local/etc/ipsec.secrets")) { print FILE (@new_file); close(FILE); } else { die "Error Write: /usr/local/etc/ipsec.secrets\n"; } } else { die "Error Read: /usr/local/etc/ipsec.secrets\n"; } } exit(0); } sub deb_removel2tp { my($profile) = @_; $found = 0; $match = 0; @new_file = (); if (open(FILE,"/etc/xl2tpd/xl2tpd.conf")) { while() { if ($_ =~ /^\[lac\s+$profile\]/) { $match = 1; $found = 1; } elsif ($_ =~ /^\[lac\s+\S+\]/) { $match = 0; } if (!$match) { push(@new_file, $_); } } close(FILE); } if ($found && -e "/etc/ppp/l2tp/$profile" && -e "/etc/ppp/l2tp/$profile.conf") { if (@new_file && open(FILE,">/etc/xl2tpd/xl2tpd.conf")) { print FILE (@new_file); close(FILE); } else { return; } unlink("/etc/ppp/l2tp/$profile"); unlink("/etc/ppp/l2tp/$profile.conf"); print "L2TP: Profile $profile removed. Preshared keys may be use in multiple profiles.\n"; print "L2TP: Edit /etc/ipsec.secrets manually to remove presharedkey.\n"; } else { print "Error, $profile files not found, use exact profile name\n"; } exit(0); } sub addl2tp { # Do not forget your includes in /etc/ipsec.conf my($profile) = @_; my $username = ''; my $ipaddr = ''; my $password = ''; my $presharedkey = ''; my $meraki = ''; print "New L2TP profile setup.\n"; while($profile !~ /^\w{3}\w*$/) { print "L2TP: Enter a 3 or more character unique client name.\n"; print "L2TP Profile: "; $profile = ; chomp($profile); $profile =~ s/\W+//g; } if ($profile && -e "/etc/ppp/l2tp/$profile") { print "Alert, existing profile '$profile' will be replaced.\n"; } while($meraki !~ /^y|^n/) { if ($freebsd && $osver >= 13) { print "########################################################\n"; print "# Meraki l2tp only seems to support 3DES #\n"; print "# FreeBSD 13+ kernel does not support 3DES ipsec fails #\n"; print "# Ctl-C to abort or continue to add resonable? config #\n"; print "########################################################\n"; } print "L2TP: Meraki may use a hostname and IPADDRESS or they may both be the same hostname or same IPADDRESS.\n"; print "L2TP: Is the remote device a Meraki (y|n)? "; $meraki = ; if ($meraki =~ /^y/i) { print "L2TP: Using Meraki profile.\n"; $meraki = "y"; } elsif ($meraki =~ /^n/i) { print "L2TP: Not using Meraki profile.\n"; $meraki = "n"; } else { $meraki = ""; } } my $mhost = ""; if ($meraki eq "y") { if ($freebsd && $osver >= 13) { print "########################################################\n"; print "# Meraki l2tp only seems to support 3DES #\n"; print "# FreeBSD 13+ kernel does not support 3DES #\n"; print "# Ctl-C to abort or continue to add resonable config #\n"; print "#######################################################\n"; } print "L2TP: Enter the Meraki (dynamic?) hostname, use IP if not known? "; while($mhost !~ /^[\w\-\.]+\.\w\w+$/) { $mhost = ; chomp($mhost); $mhost =~ s/_//g; $mhost =~ s/[^\w\-\.]//g; } } # while($ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { while($ipaddr !~ /^[\w\-\.]+\.\w\w+$/) { print "L2TP IP Address (suggested) or hostname: "; $ipaddr = ; chomp($ipaddr); $ipaddr =~ s/_//g; $ipaddr =~ s/[^\w\-\.]//g; while ($ipgood !~ /^y|n/i) { print "L2TP: ipaddr=$ipaddr (y|n)?"; $ipgood = ; if ($ipgood =~ /^y/i) { ; } else { $ipaddr = ""; } } } if ($mhost eq "") { $mhost = $ipaddr; } while($presharedkey !~ /\S{2}\S*$/) { print "L2TP: Enter a 2 or more word character presharedkey.\n"; print "L2TP: Preshared Key: "; $presharedkey = ; chomp($presharedkey); $presharedkey =~ s/\s+//g; } while($username !~ /^[\w\@\.\-]{2}[\w\@\.\-]*$/) { print "L2TP: Enter a 2 or more word character username.\n"; print "L2TP: Username: "; $username = ; chomp($username); $username =~ s/\s+//g; $username =~ s/[^\w\@\.\-]+//g; } while($password !~ /^\S{2}\S*$/) { print "L2TP: Enter a 2 or more nonspace character password.\n"; print "L2TP Password: "; $password = ; chomp($password); $password =~ s/\s+//g; } if ($freebsd && -e "$ipath/ipsec" && -e "$mpath/mpd5") { # create defaults ipsec.conf if (!(-e "/usr/local/etc/ipsec.conf") && open(FILE,">/usr/local/etc/ipsec.conf")) { print FILE "# ipsec.conf - strongSwan IPsec configuration file # basic configuration config setup # strictcrlpolicy=yes uniqueids = yes charondebug=\"ike 1, knl 1, cfg 4\" conn %default ikelifetime=60m keylife=20m rekeymargin=3m keyingtries=1 keyexchange=ikev1 authby=secret ike=3des-sha1-modp1024,aes128-sha1-modp2048,aes128-sha1-modp1024! esp=3des-sha1-modp1024,aes128-sha1-modp2048,aes128-sha1-modp1024! # Add connections here.\n"; close(FILE); } # create default ipsec.secrets if (!(-e "/usr/local/etc/ipsec.secrets") && open(FILE,">/usr/local/etc/ipsec.secrets")) { print FILE "# ipsec.secrets - strongSwan IPsec secrets file\n# 10.10.10.10 : PSK \"SamplePreSharedKey\"\n"; close(FILE); } # create default mpd.conf if (!(-e "/usr/local/etc/mpd5/mpd.conf") && open(FILE,">/usr/local/etc/mpd5/mpd.conf")) { print FILE "################################################################# # # MPD configuration file # # This file defines the configuration for mpd: what the # bundles are, what the links are in those bundles, how # the interface should be configured, various PPP parameters, # etc. It contains commands just as you would type them # in at the console. Lines without padding are labels. Lines # starting with a \"#\" are comments. # # $Id: mpd.conf.sample 2204 2015-06-02 08:30:35Z dmitryluhtionov $ # ################################################################# startup: ## configure mpd users # set user foo bar admin # set user foo1 bar1 ## configure the console # set console self 127.0.0.1 5005 # set console open ## configure the web server # set web self 0.0.0.0 5006 # set web open log +ALL +EVENTS -FRAME -ECHO default: load $profile \n"; close(FILE); } # add ipsec.conf @new_file = (); if (open(FILE,"/usr/local/etc/ipsec.conf")) { while() { if ($_ =~ /^config\s+setup|conn\s+\%default\b/) { $match = 0; } elsif ($_ =~ /^conn\s+$profile\b/) { $match = 1; } elsif ($_ =~ /^conn\s+\S+/) { $match = 0; } if (!$match) { push(@new_file, $_); } } close(FILE); if (@new_file) { # leftprotoport=17/1701 if ($meraki) { push(@new_file," conn $profile keyexchange=ikev1 type=transport authby=secret # Meraki / No kernel support for 3DES in FreeBSD 13+ ike=3des-sha1-modp1024! esp=3des-sha1! left=%defaultroute leftprotoport=17/%any rightid=%any rightprotoport=17/1701 right=$ipaddr auto=add\n"); } else { push(@new_file," conn $profile keyexchange=ikev1 type=transport leftauth=psk left=%defaultroute leftprotoport=17/%any rightauth=psk rightid=%any rightprotoport=17/1701 right=$ipaddr auto=add\n"); } } } else { die "Error Read: /usr/local/etc/ipsec.conf\n"; } if (@new_file && open(FILE,">/usr/local/etc/ipsec.conf")) { print FILE (@new_file); close(FILE); } else { die "Error Write: /usr/local/etc/ipsec.conf\n"; } # add mpd5.conf @new_file = (); if (open(FILE,"/usr/local/etc/mpd5/mpd.conf")) { while() { if ($_ =~ /^startup:\b|^log\s+|^default:\b/) { $match = 0; } elsif ($_ =~ /^$profile:\b/) { $match = 1; } elsif ($_ =~ /^\S+:\b/) { $match = 0; } if (!$match) { push(@new_file, $_); } } close(FILE); if (@new_file) { push(@new_file," $profile: create bundle static B1 set bundle enable compression set iface route 10.0.0.0/8 set iface route 172.16.0.0/12 set iface route 192.168.0.0/16 set iface enable tcpmssfix set ipcp yes vjcomp set ipcp dns 8.8.8.8 set ccp yes mppc set mppc yes e128 set mppc yes stateless create link static L1 l2tp set link action bundle B1 set link max-redial 0 set link mtu 1460 set link keep-alive 0 0#20 75 set link accept chap-msv2 set l2tp peer $mhost set auth authname $username set auth password $password open\n"); } } else { die "Error Read: /usr/local/etc/mpd5/mpd.conf\n"; } if (@new_file && open(FILE,">/usr/local/etc/mpd5/mpd.conf")) { print FILE (@new_file); close(FILE); } else { die "Error Write: /usr/local/etc/mpd5/mpd.conf\n"; } # end FreeBSD mpd5 } else { # Debian system("mkdir -p /etc/ppp/l2tp"); if (open(FILE,">/etc/ppp/l2tp/$profile")) { if ($meraki eq "y") { print FILE "ipcp-accept-local ipcp-accept-remote refuse-eap require-pap noccp noauth idle 1800 mtu 1410 mru 1410 defaultroute usepeerdns debug connect-delay 5000 name $username password $password\n"; } else { #mtu 1280 #mru 1280 print FILE "ipcp-accept-local ipcp-accept-remote refuse-eap require-chap noccp noauth mtu 1410 mru 1410 noipdefault defaultroute usepeerdns connect-delay 5000 name $username password $password\n"; } close(FILE); } else { die "Error Write: /etc/ppp/l2tp/$profile\n"; } # Do not forget your includes in /etc/ipsec.conf if (open(FILE,">/etc/ppp/l2tp/$profile.conf")) { if ($meraki eq "y") { print FILE "conn $profile keyexchange=ikev 1 left=%defaultroute auto=add ike=3des-sha1-modp1024! esp=3des-sha1! authby=secret type=transport leftprotoport=17/1701 rightprotoport=17/1701 #right=$mhost right=$ipaddr\n"; } else { print FILE "conn $profile keyexchange=ikev1 left=%defaultroute auto=add ike=\"aes128-sha1-modp2048,3des-sha1-modp1536\" esp=\"aes128-sha1,3des-sha1\" authby=secret type=transport leftprotoport=17/1701 rightprotoport=17/1701 right=$ipaddr\n"; } close(FILE); } else { die "Error Write: /etc/ppp/l2tp/$profile,conf\n"; } # check xl2tpd.conf @new_file = (); if (open(FILE,"/etc/xl2tpd/xl2tpd.conf")) { while() { if ($_ =~ /^\[lac\s+$profile\]/) { $match = 1; } elsif ($_ =~ /^\[lac\s+\S+\]/) { $match = 0; } if (!$match) { push(@new_file, $_); } } close(FILE); if (@new_file) { push(@new_file," \[lac $profile\] lns = $mhost ppp debug = yes pppoptfile = /etc/ppp/l2tp/$profile length bit = yes\n"); } } else { die "Error Read: /etc/xl2tpd/xl2tpd.conf\n"; } if (@new_file && open(FILE,">/etc/xl2tpd/xl2tpd.conf")) { print FILE (@new_file); close(FILE); } else { die "Error Write: /etc/xl2tpd/xl2tpd.conf\n"; } } # Debian and FreeBSD check ipsec.secrets my $secretsfile = "/etc/ipsec.secrets"; if ($freebsd && -e "/usr/local/etc/ipsec.secrets") { $secretsfile = "/usr/local/etc/ipsec.secrets"; } elsif (-e "/etc/ipsec.secrets") { $secretsfile = "/etc/ipsec.secrets"; } @new_file = (); if (open(FILE,"$secretsfile")) { while() { if ($_ !~ /^$ipaddr\s*\:\s+PSK|^$mhost\s*\:\s+PSK/) { push(@new_file,$_); } } close(FILE); if (@new_file) { push(@new_file,"$ipaddr : PSK \"$presharedkey\"\n"); if ($mhost ne $ipaddr) { push(@new_file,"$mhost : PSK \"$presharedkey\"\n"); } } } else { die "Error Read: $secretsfile\n"; } if (@new_file && open(FILE,">$secretsfile")) { print FILE (@new_file); close(FILE); } else { die "Error Write: $secretsfile\n"; } if ($freebsd) { print "L2TP: Successfull added profile $profile\n"; # This doesn't ipsec down [conn] or close mpd5 ... use 'vpn stop' instead # Ensures ipsec is running and reloaded use auto=load in ipsec.conf system("$ipath/ipsec stop"); system("$ipath/ipsec start"); } else { print "L2TP: Successfull added profile $profile\n"; print "systemctl restart strongswan-starter\n"; system("systemctl restart strongswan-starter"); print "systemctl restart xl2tpd\n"; system("systemctl restart xl2tpd"); } exit(0); } sub removepptp { my($profile) = @_; if ($freebsd) { @new_file = (); $match = 0; if ($profile =~ /\w/ && open(FILE,"/etc/ppp/ppp.conf")) { while() { if ($_ =~ /^$profile\:/) { $match=1; #} elsif ($_ =~ /^\w+\:/ || $_ !~ /\w/) { } elsif ($_ =~ /^\w+\:/) { $match=0; } if (!$match) { push(@new_file,$_); } } close(FILE); } else { return; } $inp = ''; while($inp !~ /^y|^n/i) { print "Remove profile $profile, are you sure [y/n]? "; $inp = ; } if ($inp =~ /^n/) { die "PPTP: Skipped delete $profile\n"; } if (@new_file && open(FILE,">/etc/ppp/ppp.conf")) { print FILE (@new_file); close(FILE); print "PPTP: Removed profile '$profile' from /etc/ppp/ppp.conf.\n"; } exit(0); } # FreeBSD removepptp end # Debian or Linux removepptp if (-e "/etc/ppp/peers/$profile") { $inp = ''; while($inp !~ /^y|^n/i) { print "Remove profile $profile, are you sure [y/n]? "; $inp = ; } if ($inp =~ /^n/) { die "PPTP: Skipped delete $profile\n"; } unlink("/etc/ppp/peers/$profile"); print "PPTP: Remove /etc/ppp/peers/$profile\n"; print "PPTP: Manually edit /etc/ppp/chap-secrets to completely delete.\n"; } else { print "PPTP: Profile $profile not found, use exact profile name to delete.\n"; } exit(0); } sub addpptp { my($profile) = @_; my $username = ''; my $ipaddr = ''; my $password = ''; print "New PPTP profile setup.\n"; while($profile !~ /^\w{3}\w*$/) { print "PPTP: Enter a 3 or more character unique client name.\n"; print "PPTP Profile: "; $profile = ; chomp($profile); $profile =~ s/\W+//g; } if ($profile && -e "/etc/ppp/peers/$profile") { print "Alert, existing profile '$profile' will be replaced.\n"; } $sure = ''; while($ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ && $sure !~ /^y/) { print "PPTP: Enter the server IP address for $profile.\n"; print "PPTP: IP Address: "; $ipaddr = ; chomp($ipaddr); while ($ipaddr !~ /^[\d\.]+$/ && $sure !~ /^y|^n/) { print "ADDR=$ipaddr is not an IP address are you sure [y|n]: "; $sure = ; chomp($sure); } if ($sure !~ /^y/) { $ipaddr =~ s/[^\d\.]//g; } print "PPTP: ipaddr=$ipaddr\n"; } while($username !~ /^\w{3}\w*$/) { print "Enter a 3 or more word character username.\n"; print "Username: "; $username = ; chomp($username); $username =~ s/\W+//g; } while($password !~ /^\S{3}\S*$/) { print "PPTP: Enter a 3 or more nonspace character password.\n"; print "PPTP: Password: "; $password = ; chomp($password); $password =~ s/\s+//g; } # FreeBSD addpptp if ($freebsd) { while($snet !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2}$|^def/) { print "PPTP: Enter LAN Route as CIDR or type 'default' for $profile.\n"; print "PPTP: LAN Route CIDR: "; $snet = ; chomp($snet); if ($snet !~ /^def/) { $snet =~ s/[^\d\.\/]//g; } } if ($snet =~ /^def/) { $snet = " add 192.168.0.0/16 HISADDR add 172.16.0.0/12 HISADDR add 10.0.0.0/8 HISADDR"; } else { $snet = " add $snet HISADDR"; } print "PPTP: LAN Route CIDR\n $snet\n"; @new_file = (); $match = 0; if ($profile =~ /\w/ && open(FILE,"/etc/ppp/ppp.conf")) { while() { if ($_ =~ /^$profile\:/) { $match=1; #} elsif ($_ =~ /^\w+\:/ || $_ !~ /\w/) { } elsif ($_ =~ /^\w+\:/) { $match=0; } if (!$match) { push(@new_file,$_); } } close(FILE); if (@new_file) { push(@new_file," $profile: # WAN $ipaddr set authname $username set authkey $password set timeout 0 set ifaddr 0 0 $snet disable ipv6cp\n"); } } else { return; } if (@new_file && open(FILE,">/etc/ppp/ppp.conf")) { print FILE (@new_file); close(FILE); print "PPTP: Added to /etc/ppp/ppp.conf...\n$profile:\n # WAN $ipaddr\n set authname $username\n set authkey $password\n$snet\n"; } exit(0); } # FreeBSD addpptp end # Debian or Linux if (open(FILE,">/etc/ppp/peers/$profile")) { print FILE "pty \"pptp $ipaddr --nolaunchpppd\"\n"; print FILE "name $username\n"; print FILE "remotename $profile\n"; print FILE "require-mppe-128\n"; print FILE "file /etc/ppp/options.pptp\n"; print FILE "ipparam $profile\n"; close(FILE); $name = $username; $remotename = $profile; print "PPTP: Created /etc/ppp/peers/$profile\n"; } else { return; } @new_file = (); if (open(FILE,"/etc/ppp/chap-secrets")) { while() { if ($_ !~ /^$username\s+$profile\s/) { push(@new_file,$_); } } close(FILE); if (@new_file) { push(@new_file,"$username\t$profile\t$password\t$ipaddr\n"); } } else { return; } if (@new_file && open(FILE,">/etc/ppp/chap-secrets")) { print FILE (@new_file); close(FILE); print "PPTP: Added $name\t$profile\t$password\t$ipaddr\n"; } } sub addopenvpn { my($profile) = @_; my $ipaddr = ''; my $username = ''; my $password = ''; print "New OpenVPN profile setup.\n"; while($profile !~ /^\w{3}\w*$/) { print "OVPN: Enter a 3 or more character unique profile name.\n"; print "OVPN Profile: "; $profile = ; chomp($profile); $profile =~ s/\W+//g; } my $caid = '-1'; while($caid !~ /^\w{3}\w*$|^$/) { print "OVPN: Enter a 3+ char CA ID to add before ca and server or [n].\n"; print "OVPN: This may be to avoid duplicate ca names with OVPN clients.\n"; print "CA & Server CA ID: "; $caid = ; chomp($caid); $caid =~ s/\W+//g; } print "OVPN: 1 CA ID set to '${caid}'.\n"; $sure = ''; while($ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ && $sure !~ /^y/) { print "OVPN: Enter the server IP address for $profile.\n"; print "OVPN: IP Address: "; $ipaddr = ; chomp($ipaddr); while ($ipaddr !~ /^[\d\.]+$/ && $sure !~ /^y|^n/) { print "ADDR=$ipaddr is not an IP address are you sure [y|n]: "; $sure = ; chomp($sure); } if ($sure !~ /^y/) { $ipaddr =~ s/[^\d\.]//g; } print "OVPN: ipaddr=$ipaddr\n"; } while($username !~ /^\w{3}\w*$/) { print "OVPN: Enter a 3 or more character username like $profile.\n"; print "OVPN Username: "; $username = ; chomp($username); $username =~ s/\W+//g; } while($password !~ /^\S{3}\S*$/) { print "OVPN: Enter a 3 or more nonspace character password.\n"; print "OVPN: Password: "; $password = ; chomp($password); $password =~ s/\s+//g; } # $epass = "123445678"; while($epass !~ /^\w{8}\w*$/) { print "Enter an export passphrase like 12345678.\n"; print "Export PassPhrase: "; $epass = ; chomp($epass); $epass =~ s/\W+//g; } print "OVPN: Writing $ENV{'HOME'}/OpenVPN/config/$profile\n"; system("mkdir -p $ENV{'HOME'}/OpenVPN/config/$profile"); if (open(FILE,">$ENV{'HOME'}/OpenVPN/config/$profile/$username.pass")) { print FILE "$epass\n"; close(FILE); print "Created $ENV{'HOME'}/OpenVPN/config/$profile/$username.pass.\n"; print "Used '$epass' for export passphrase.\n"; } else { return; } print "OVPN: Writing $ENV{'HOME'}/OpenVPN/config/$profile/$username.auth"; if (open(FILE,">$ENV{'HOME'}/OpenVPN/config/$profile/$username.auth")) { print FILE "$username\n$password\n"; close(FILE); print "Created $ENV{'HOME'}/OpenVPN/config/$profile/$username.auth\n"; } else { return; } print "OVPN: Check settings, press enter to approve ----------------------- profile=$profile ip=$ipaddr prefix=${caid} username=$username password=$password epass=$epass ca=${caid}ca server=${caid}server -----------------------\n"; my $junk = ; print "OVPN: Writing $ENV{'HOME'}/OpenVPN/config/$profile/$username.ovpn\n"; if (open(FILE,">$ENV{'HOME'}/OpenVPN/config/$profile/$username.ovpn")) { print FILE "client dev tun proto tcp remote $ipaddr 1194 resolv-retry infinite nobind persist-tun persist-key tls-client # tls-auth ${caid}ta.key 1 #remote-cert-tls server ca ${caid}ca.crt cert $username.crt key $username.key askpass $username.pass data-ciphers AES-256-GCM:AES-256-CBC data-ciphers-fallback AES-256-CBC auth SHA1 verify-x509-name \"${caid}server\" name auth-user-pass $username.auth pull # explicit-exit-notify # only works with udp verb 3 # modify these routes, route works better on *nix route 192.168.0.0 255.255.0.0 # route 172.16.0.0 255.240.0.0 # route 10.0.0.0 255.0.0.0 # the next 4 avoid 10.200 and some other nets # route 10.0.0.0 255.128.0.0 # route 10.128.0.0 255.192.0.0 # route 10.208.0.0 255.240.0.0 # route 10.224.0.0 255.224.0.0 # sometimes redirect breaks connections but may be needed on Windows # redirect-gateway local def1 # redirect-gateway def1\n"; print "Created $ENV{'HOME'}/OpenVPN/config/$profile/$username.ovpn\n"; } else { return; } # make a tls-authkey if needed system("$opath/openvpn --genkey secret $ENV{'HOME'}/OpenVPN/config/$profile/${caid}ta.key"); print "OVPN: Changing mod on $ENV{'HOME'}/OpenVPN/config/$profile\n"; system("chmod 750 $ENV{'HOME'}/OpenVPN/config/$profile"); print "OVPN: Changing mod on $ENV{'HOME'}/OpenVPN/config/$profile/*\n"; system("chmod 640 $ENV{'HOME'}/OpenVPN/config/$profile/*"); print "# Microtik Instructions, hit any key to display."; print "# If ${caid}ca.crt is already created just use the lines starting with # a hash '#' mark and remove the hash while pasting commands.\n"; my $junk = ; print " Microtik Howto\n------------------ # Make sure you change \"profile\" to something unique to identify the connection. # Make sure to change the IP address, username, and supersecretpassword # You can subsitite anything in place of client for multiple users. # ssh into the router ssh admin@$ipaddr # # OLD / SKIP # add name=${caid}ca-template common-name=$ipaddr days-valid=3650 key-usage=key-cert-sign,crl-sign # [admin@MikroTik] > /certificate [admin@MikroTik] /certificate> add name=${caid}ca-template common-name=${caid}ca days-valid=3650 key-usage=key-cert-sign,crl-sign add name=${caid}server-template days-valid=3650 common-name=${caid}server # add name=$username-template days-valid=3650 common-name=$username sign ${caid}ca-template ca-crl-host=$ipaddr name=${caid}ca sign ${caid}server-template ca=${caid}ca name=${caid}server # sign $username-template ca=${caid}ca name=$username [admin@MikroTik] /certificate> set ${caid}ca trusted=yes set ${caid}server trusted=yes [admin@MikroTik] /certificate> export-certificate ${caid}ca # export-certificate $username export-passphrase=$epass / quit # The following 3 steps are handled by this script and can be skipped # 1) On client machine create client configuration directory # mkdir -p ~/OpenVPN/config/$profile # 2) You need a passphrase or it won't export a client cert # and 12345678 is just an example but works well enough. # echo '$epass' > ~/OpenVPN/config/$profile/$username.pass # 3) This program asks you to enter a username and password and writes the # files in $ENV{'HOME'}/OpenVPN/config/$profile # echo '$username' > ~/OpenVPN/config/$profile/$username.auth # echo '$password' >> ~/OpenVPN/config/$profile/$username.auth # Download the Files / Go to Files -> # Download cert_export_${caid}ca.crt and save to $ENV{'HOME'}/OpenVPN/config/$profile # Download cert_export_$username.crt save to $ENV{'HOME'}/OpenVPN/config/$profile # Download cert_export_$username.key save to $ENV{'HOME'}/OpenVPN/config/$profile # Change directory to where you saved the files. cd $ENV{'HOME'}/OpenVPN/config/$profile # Put these files in $ENV{'HOME'}/OpenVPN/config/$profile mv ./cert_export_${caid}ca.crt $ENV{'HOME'}/OpenVPN/config/$profile/${caid}ca.crt mv ./cert_export_$username.crt $ENV{'HOME'}/OpenVPN/config/$profile/$username.crt mv ./cert_export_$username.key $ENV{'HOME'}/OpenVPN/config/$profile/$username.key # Update: these files should already be created. # client configuration file modify remote and route tcp for Microtik only # Create ~/OpenVPN/config/$profile/$username.ovpn --------------------------------------------- client dev tun proto tcp remote $ipaddr 1194 resolv-retry infinite nobind persist-tun persist-key tls-client # tls-auth ${caid}ta.key 1 #remote-cert-tls server ca ca.crt cert $username.crt key $username.key askpass $username.pass data-ciphers AES-256-GCM:AES-256-CBC data-ciphers-fallback AES-256-CBC auth SHA1 verify-x509-name \"server\" name auth-user-pass $username.auth pull # explicit-exit-notify # only works with udp verb 3 # modify these routes, route works better on *nix # route 10.50.50.0 255.255.255.0 route 192.168.0.0 255.255.0.0 route 172.16.20.0 255.255.224.0 # route 10.0.0.0 255.0.0.0 # the next 4 avoid 10.200 and some other nets route 10.0.0.0 255.128.0.0 route 10.128.0.0 255.192.0.0 route 10.208.0.0 255.240.0.0 route 10.224.0.0 255.224.0.0 # sometimes redirect breaks connections but may be needed on Windows # redirect-gateway local def1 --------------------------------------------- # make more secure chmod 750 ~/OpenVPN/config/$profile chmod 640 ~/OpenVPN/config/$profile/* # Update: This should already be done. # Part 2 # Make an OpenVPN Pool ovpn-pool 192.168.99.100-192.168.99.200 # Create OpenVPN Profile Go to PPP > Profiles > Add New Profile ovpn-profile Local Address 192.168.99.1 Remote Address ovpn-pool Set Change TCP-MSS=yes Use Encryption=yes Limit Only One=no #Go to PPP - Secrets - Add New Secret user: $username password: $password Service ovpn Profile ovpn-profile # Now enable the openvpn server # Go to PPP > Interface > OVPN Server Click Enabled Port 1194 Mode ip Netmask 24 # not needed Check Require Client Certificate check sha1 aes256 Default Profile : ovpn-profile Certificate : server # Again!!!! Certificate : server # And Again!!! # Remember to set the Server Certificate back to \"server\" if # you deleted the previous ca and certs but not the configurations. # It always seems to default back to ca Apply and OK # Open the Firewall to TCP 1194 # IP -> Firewall input tcp dst port 1194 interface ether1 Apply OK # drag up to before deny rules # The following does not seem necessary on some router configurations # but can be used with default configuration or use as needed. # To identify this as a LAN interface for firewall # PPP -> Interface -> Add OpenVPN Server Binding OpenVPN server binding add ovpn but make user [username] Namelike: ovpn-in1 User: $username Interfaces -> Interface List Add LAN to interface ovpn-in1 # FIREWALL Can't access the web interface # This is if using default firewall where not LAN is denied input LAN ovpn-in1 ether1 allow # # Usually the firewall default is to allow certain connections then # the first block is to block everything that is NOT LAN so... # Go to Interfaces -> ADD LAN ovpn-in1 user $username allow Apply OK # Create OVPN configuration file as above if you haven't already # This program reads ~/OpenVPN/config directory to get profiles.\n"; } sub otherscripts { print " # start script #!/usr/bin/bash profile=$1 (service strongswan-starter start ; sleep 2 ; service xl2tpd start) && ( ipsec up $profile echo \"c $profile\" > /var/run/xl2tpd/l2tp-control sleep 5 #ip route add 10.0.0.0/24 dev ppp0 ) # stop script #!/usr/bin/bash (echo \"d myvpn\" > /var/run/xl2tpd/l2tp-control ipsec down myvpn) && ( service xl2tpd stop ; service strongswan-starter stop) "; }