From a8d6a7eaf2b09bf2e92c584e03b9149adac2f0e1 Mon Sep 17 00:00:00 2001 From: Mr Chen Date: Mon, 22 Jul 2019 16:43:40 +0800 Subject: [PATCH] l2tp --- plugins/l2tp/LICENSE | 21 + plugins/l2tp/README.md | 17 + plugins/l2tp/ico.png | Bin 0 -> 2459 bytes plugins/l2tp/index.html | 18 + plugins/l2tp/index.py | 233 +++++++++ plugins/l2tp/info.json | 14 + plugins/l2tp/install.sh | 46 ++ plugins/l2tp/js/l2tp.js | 150 ++++++ plugins/l2tp/screenshot/ss1.png | Bin 0 -> 89462 bytes plugins/l2tp/scripts/l2tp.sh | 820 ++++++++++++++++++++++++++++++++ plugins/l2tp/tmp/chap-secrets | 3 + plugins/l2tp/tmp/ipsec.secrets | 1 + 12 files changed, 1323 insertions(+) create mode 100644 plugins/l2tp/LICENSE create mode 100644 plugins/l2tp/README.md create mode 100644 plugins/l2tp/ico.png create mode 100755 plugins/l2tp/index.html create mode 100755 plugins/l2tp/index.py create mode 100755 plugins/l2tp/info.json create mode 100755 plugins/l2tp/install.sh create mode 100755 plugins/l2tp/js/l2tp.js create mode 100644 plugins/l2tp/screenshot/ss1.png create mode 100644 plugins/l2tp/scripts/l2tp.sh create mode 100644 plugins/l2tp/tmp/chap-secrets create mode 100644 plugins/l2tp/tmp/ipsec.secrets diff --git a/plugins/l2tp/LICENSE b/plugins/l2tp/LICENSE new file mode 100644 index 000000000..b89fade39 --- /dev/null +++ b/plugins/l2tp/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Mr Chen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/l2tp/README.md b/plugins/l2tp/README.md new file mode 100644 index 000000000..7119b07cb --- /dev/null +++ b/plugins/l2tp/README.md @@ -0,0 +1,17 @@ +# mw-l2tp + +``` +mdserver-web项目的中用于管理vpn的插件 +``` + +### 安装过程 + +``` +* 先进行压缩 `cd mw-l2tp && zip l2tp.zip -r ./* ` +* 在mdserver-web点击`添加插件` +``` + +### 截图 + +[![截图1](/screenshot/ss1.png)](/screenshot/ss1.png) + diff --git a/plugins/l2tp/ico.png b/plugins/l2tp/ico.png new file mode 100644 index 0000000000000000000000000000000000000000..ddfd2f89b51407ed7c18f3f8b5ba840ad3aabbac GIT binary patch literal 2459 zcmV;M31s$(P)UT5yyW$7tlb0gp?2{&1Gf)p&$mr1;ubXyOe;u43eaZM<5ENl!B57F;t;}@KAyv z4-t^!jnM)OAc=y4-p*bUgFpd-$ZKXV355s*f`JIh-L&=1-tNxq?(Oa+DXaLZQmNao zzyA8)udlmD_?R#Gn9I+$0nno(=qOG`B?tN?;80+flya1Hz)FNd{IA=73Xy@WRp8bE z=qVn6rQZN%)d}2MvUh-AV{r@J&aUbpA%;w=cLHfE@6z`6mV`|;dY@WbB%In;;IVg*WERUSMDs`q19D~X-lwXl`O3GON)@TMcoC7)!WT(12lx2AK@y)VT za{zv@806%7#`-X$IEgOzy~q;Unjc&Pat@Z{=(h6}n&oTupuhi4 zgfBNZcNd;BdnhXm4Z!$3+|ocR3&=W`)cx)U%TXDNXYW6x#*90z3!erVLB`&vF5~#Y z=_tR9<0rNB3_SO?Mj#pkSP^#8&kMi~sY9Z3$+*|lG0KPC@#BO}$8+y*8hnM~@u)t4 zFq4d9;w8OeSK|SY?GhUsiDW-=c3&-dV*vS}7ZLNCCYCP3bI)%mTt0jlp_7cgU&}mh z-Vr~14y2!~(>NXH!RaNzY6>=rWd`K0n1nmI&=oAmkmBvB@Oljhhj-DD)Y(OS2VffaD+c4l)8x> zM~?a-Z;n z`0WsD4>A)>VOL#+zTMI2bzmc&vtzuG4_`!h3D23<;-0&axaTOZEAbptM?$Mc7`zF8Xv(;Dvm_9BZt4HJ{Tcx6GB1P&qnK<|ULl_2)&K}LrJir;*pE!7 zDJQnwshh0U8yPd&JF6P_FQCCM0Qua#4M4R!2Rb@~=rzz?1RncNnxK{reS zFddVXKxzDceH}Bg`pDRK#J?AUMW_s&L0U^I6-wPcUKHkJ=Jy`A{^9Xw}jZ4A5&vR9R;jUfJi z0WiY^bhI}IQoE=8!84Z?THIM;8v1@sk^QfDU2O)DqCwH*ue2FDV~(rOH| zl&oW3{ZtT}F3Y^ErKS2CvTl7lnMBmg0+CK3=RO&e_XJ&7@pYqU z&{O;*5^YHJqmdj)&VFV{1kGch^4#Nx7XX)Tkp+5#y@}+dglF`l)@X9}hiL%jui7|( z#duD#21(1%Du_+TWo?#p0M@{0WdT1lDZ4tA(5nB}11JR3QAsq~x*2Q4K6H1QG6QuI&M0%jGb(G zhxowZho%cVGIdy~A87TiK8UEl(%!X_wQgVK^;pxjD_>lI=)#)&A0_LUOqs^i@Y3F3 zJQ2@>j83@H1}y2`nvW4}0W?Y(=+7fEDt$Nm)9tQl4}hVn3+Q;du#S$7gDXLuABL%b??wY`zQ)5a~m(L~Z+@1Qp zH=IO-DgGAVIrTZ;B#1&-K;-~*)VN9oYM7Lg$6261PHR5iycW+*%aFLZ)p*@B)MgTA z<~HeN+B)IP_?tj^`Na!CFGBbx87Dm$_5-5~GfF=-&S2%0?>hvEZUR2v;Ep@+oYR|) zD_eiyFkJoO{8&4wej&b2Q62;9MznJ&Sq3N+&BJpVa4T4sm4;UXmmzW#Fb~hUlAbq5 zA@84z=-D8R>VGrfx&Y6;yj9$^2Oy4#qDQ3nAnewdss0CKRjGH?ljF}yY2SMewH`zC zi=YRk=1*z5H;I@|&RyP0c(dO=07Jbh+>H;p1K}&}FdsIJ@(9~SvzfZ*o9&(*9)OD9 zhTn=m3yJL6?nO=MR9{8pay;kO;qu!u097F7!^Uis6A? +
+
+

服务

+

用户配置

+

PSK配置

+

用户列表

+
+
+
+
+
+ + \ No newline at end of file diff --git a/plugins/l2tp/index.py b/plugins/l2tp/index.py new file mode 100755 index 000000000..e0b1eb576 --- /dev/null +++ b/plugins/l2tp/index.py @@ -0,0 +1,233 @@ +# coding:utf-8 + +import sys +import io +import os +import time +import shutil + +sys.path.append(os.getcwd() + "/class/core") +import public + +app_debug = False +if public.isAppleSystem(): + app_debug = True + + +def getPluginName(): + return 'l2tp' + + +def getPluginDir(): + return public.getPluginDir() + '/' + getPluginName() + + +def getServerDir(): + return public.getServerDir() + '/' + getPluginName() + + +def getArgs(): + args = sys.argv[2:] + tmp = {} + args_len = len(args) + + if args_len == 1: + t = args[0].strip('{').strip('}') + t = t.split(':') + tmp[t[0]] = t[1] + elif args_len > 1: + for i in range(len(args)): + t = args[i].split(':') + tmp[t[0]] = t[1] + + return tmp + + +def checkArgs(data, ck=[]): + for i in range(len(ck)): + if not ck[i] in data: + return (False, public.returnJson(False, '参数:(' + ck[i] + ')没有!')) + return (True, public.returnJson(True, 'ok')) + + +def status(): + cmd = "ps -ef|grep xl2tpd |grep -v grep | grep -v python | awk '{print $2}'" + data = public.execShell(cmd) + if data[0] == '': + return 'stop' + return 'start' + + +def initConf(): + l2tp_cs = getServerDir() + '/chap-secrets' + if not os.path.exists(l2tp_cs): + public.execShell('cp -rf ' + getPluginDir() + + '/tmp/chap-secrets' + ' ' + getServerDir()) + + l2tp_is = getServerDir() + '/ipsec.secrets' + if not os.path.exists(l2tp_is): + public.execShell('cp -rf ' + getPluginDir() + + '/tmp/ipsec.secrets' + ' ' + getServerDir()) + + +def start(): + initConf() + + if public.isAppleSystem(): + return "Apple Computer does not support" + + data = public.execShell('service xl2tpd start') + if data[0] == '': + return 'ok' + return data[1] + + +def stop(): + if public.isAppleSystem(): + return "Apple Computer does not support" + + data = public.execShell('service xl2tpd stop') + if data[0] == '': + return 'ok' + return data[1] + + +def restart(): + if public.isAppleSystem(): + return "Apple Computer does not support" + + data = public.execShell('service xl2tpd restart') + if data[0] == '': + return 'ok' + return data[1] + + +def reload(): + data = public.execShell('service xl2tpd reload') + if data[0] == '': + return 'ok' + return data[1] + + +def getPathFile(): + if public.isAppleSystem(): + return getServerDir() + '/chap-secrets' + return '/etc/ppp/chap-secrets' + + +def getPathFilePsk(): + if public.isAppleSystem(): + return getServerDir() + '/ipsec.secrets' + return '/etc/ipsec.secrets' + + +def getUserList(): + import re + path = getPathFile() + if not os.path.exists(path): + return public.returnJson(False, '密码配置文件不存在!') + conf = public.readFile(path) + + conf = re.sub('#(.*)\n', '', conf) + + if conf.strip() == '': + return public.returnJson(True, 'ok', []) + + ulist = conf.strip().split('\n') + + user = [] + for line in ulist: + line_info = {} + line = re.match(r'(\w*)\s*(\w*)\s*(\w*)\s*(.*)', + line.strip(), re.M | re.I).groups() + line_info['user'] = line[0] + line_info['pwd'] = line[2] + line_info['type'] = line[1] + line_info['ip'] = line[3] + user.append(line_info) + + return public.returnJson(True, 'ok', user) + + +def addUser(): + if public.isAppleSystem(): + return public.returnJson(False, "Apple Computer does not support") + + args = getArgs() + data = checkArgs(args, ['username']) + if not data[0]: + return data[1] + ret = public.execShell('echo ' + args['username'] + '|l2tp -a') + if ret[1] == '': + return public.returnJson(True, '添加成功!:' + ret[0]) + return public.returnJson(False, '添加失败:' + ret[0]) + + +def delUser(): + if public.isAppleSystem(): + return public.returnJson(False, "Apple Computer does not support") + + args = getArgs() + data = checkArgs(args, ['username']) + if not data[0]: + return data[1] + + ret = public.execShell('echo ' + args['username'] + '|l2tp -d') + if ret[1] == '': + return public.returnJson(True, '删除成功!:' + ret[0]) + return public.returnJson(False, '删除失败:' + ret[0]) + + +def modUser(): + + args = getArgs() + data = checkArgs(args, ['username', 'password']) + if not data[0]: + return data[1] + + path = getPathFile() + username = args['username'] + password = args['password'] + + # sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets + # echo "${user} l2tpd ${pass} *" >> /etc/ppp/chap-secrets + + if public.isAppleSystem(): + public.execShell("sed -i .bak '/^\(" + username + "\)/d' " + path) + else: + public.execShell("sed -i '/^\(" + username + "\)/d' " + path) + # print 'echo "' + username + " l2tpd " + password + " *\" >>" + # + path + ret = public.execShell("echo \"" + username + + " l2tpd " + password + " *\" >>" + path) + if ret[1] == '': + return public.returnJson(True, '修改成功!') + return public.returnJson(False, '修改失败') + + +if __name__ == "__main__": + func = sys.argv[1] + if func == 'status': + print status() + elif func == 'start': + print start() + elif func == 'stop': + print stop() + elif func == 'restart': + print restart() + elif func == 'reload': + print reload() + elif func == 'conf': + print getPathFile() + elif func == 'conf_psk': + print getPathFilePsk() + elif func == 'user_list': + print getUserList() + elif func == 'add_user': + print addUser() + elif func == 'del_user': + print delUser() + elif func == 'mod_user': + print modUser() + else: + print 'error' diff --git a/plugins/l2tp/info.json b/plugins/l2tp/info.json new file mode 100755 index 000000000..8d3ab2fb1 --- /dev/null +++ b/plugins/l2tp/info.json @@ -0,0 +1,14 @@ +{ + "title":"L2TP", + "tip":"soft", + "name":"l2tp", + "type":"运行环境", + "ps":"VPN网关", + "versions":"1.0", + "shell":"install.sh", + "checks":"server/l2tp", + "author":"teddysun", + "home":"https://github.com/teddysun/across/blob/master/l2tp.sh", + "date":"2019-02-27", + "pid": "4" +} \ No newline at end of file diff --git a/plugins/l2tp/install.sh b/plugins/l2tp/install.sh new file mode 100755 index 000000000..2d7b767bb --- /dev/null +++ b/plugins/l2tp/install.sh @@ -0,0 +1,46 @@ +#!/bin/bash +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin +export PATH + + +curPath=`pwd` +rootPath=$(dirname "$curPath") +rootPath=$(dirname "$rootPath") +serverPath=$(dirname "$rootPath") + + +install_tmp=${rootPath}/tmp/mw_install.pl +SYSOS=`uname` + +Install_l2tp() +{ + isStart="" + echo '正在安装脚本文件...' > $install_tmp + mkdir -p $serverPath/l2tp + echo '1.0' > $serverPath/l2tp/version.pl + + cp -rf scripts/l2tp.sh $serverPath/l2tp + chmod +x $serverPath/l2tp/l2tp.sh + + if [ "Darwin" == "$SYSOS" ];then + echo 'macosx unavailable' > $install_tmp + exit 0 + fi + + /bin/sh $serverPath/l2tp/l2tp.sh + + echo 'install complete' > $install_tmp +} + +Uninstall_l2tp() +{ + rm -rf $serverPath/l2tp + echo "Uninstall completed" > $install_tmp +} + +action=$1 +if [ "${1}" == 'install' ];then + Install_l2tp +else + Uninstall_l2tp +fi diff --git a/plugins/l2tp/js/l2tp.js b/plugins/l2tp/js/l2tp.js new file mode 100755 index 000000000..12b0c4fc4 --- /dev/null +++ b/plugins/l2tp/js/l2tp.js @@ -0,0 +1,150 @@ +function str2Obj(str){ + var data = {}; + kv = str.split('&'); + for(i in kv){ + v = kv[i].split('='); + data[v[0]] = v[1]; + } + return data; +} + +function lpPost(method,args,callback, title){ + + var _args = null; + if (typeof(args) == 'string'){ + _args = JSON.stringify(str2Obj(args)); + } else { + _args = JSON.stringify(args); + } + + var _title = '正在获取...'; + if (typeof(title) != 'undefined'){ + _title = title; + } + + var loadT = layer.msg(_title, { icon: 16, time: 0, shade: 0.3 }); + $.post('/plugins/run', {name:'l2tp', func:method, args:_args}, function(data) { + layer.close(loadT); + if (!data.status){ + layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + + if(typeof(callback) == 'function'){ + callback(data); + } + },'json'); +} + +function lpAsyncPost(method,args){ + var _args = null; + if (typeof(args) == 'string'){ + _args = JSON.stringify(str2Obj(args)); + } else { + _args = JSON.stringify(args); + } + + var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); + return syncPost('/plugins/run', {name:'l2tp', func:method, args:_args}); +} + +function userList(){ + lpPost('user_list', '' ,function(data){ + var rdata = $.parseJSON(data['data']); + + if (!rdata['status']){ + layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']}); + return; + } + var list = rdata['data']; + + var con = ''; + con += '
'; + con += ''; + con += ''; + con += ''; + con += ''; + con += ''; + + con += ''; + + for (var i = 0; i < list.length; i++) { + con += ''+ + '' + + '' + + ''; + } + + con += ''; + con += '
用户密码操作(添加)
' + list[i]['user']+'' + list[i]['pwd']+'改密|删除
'; + + $(".soft-man-con").html(con); + }); +} + + +function addUser(){ + var loadOpen = layer.open({ + type: 1, + title: '添加用户', + area: '240px', + content:"
\ +
\ +
\ +
\ +
\ + \ +
\ +
" + }); + + $('#add_ok').click(function(){ + _data = {}; + _data['username'] = $('#username').val(); + var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); + lpPost('add_user', _data, function(data){ + var rdata = $.parseJSON(data.data); + layer.close(loadOpen); + layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); + setTimeout(function(){userList();},2000); + }); + }); +} + +function delUser(username){ + lpPost('del_user', {username:username}, function(data){ + var rdata = $.parseJSON(data.data); + layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); + setTimeout(function(){userList();},2000); + }); +} + +function modUser(username){ + var loadOpen = layer.open({ + type: 1, + title: '修改密码', + area: '240px', + content:"
\ +
\ +
\ +
\ +
\ + \ +
\ +
" + }); + + $('#mod_ok').click(function(){ + _data = {}; + _data['username'] = username; + _data['password'] = $('#password').val(); + var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 }); + lpPost('mod_user', _data, function(data){ + var rdata = $.parseJSON(data.data); + layer.close(loadOpen); + layer.msg(rdata.msg,{icon:rdata.status?1:2,time:2000,shade: [0.3, '#000']}); + setTimeout(function(){userList();},2000); + }); + }); +} + diff --git a/plugins/l2tp/screenshot/ss1.png b/plugins/l2tp/screenshot/ss1.png new file mode 100644 index 0000000000000000000000000000000000000000..f9e270f3cd9dbff8016b49bf5ba23886f40fe744 GIT binary patch literal 89462 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 # +# Intro: https://teddysun.com/448.html # +#=======================================================================# +cur_dir=`pwd` + +libreswan_filename="libreswan-3.27" +download_root_url="https://dl.lamp.sh/files" + +rootness(){ + if [[ $EUID -ne 0 ]]; then + echo "Error:This script must be run as root!" 1>&2 + exit 1 + fi +} + +tunavailable(){ + if [[ ! -e /dev/net/tun ]]; then + echo "Error:TUN/TAP is not available!" 1>&2 + exit 1 + fi +} + +disable_selinux(){ +if [ -s /etc/selinux/config ] && grep 'SELINUX=enforcing' /etc/selinux/config; then + sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config + setenforce 0 +fi +} + +get_opsy(){ + [ -f /etc/redhat-release ] && awk '{print ($1,$3~/^[0-9]/?$3:$4)}' /etc/redhat-release && return + [ -f /etc/os-release ] && awk -F'[= "]' '/PRETTY_NAME/{print $3,$4,$5}' /etc/os-release && return + [ -f /etc/lsb-release ] && awk -F'[="]+' '/DESCRIPTION/{print $2}' /etc/lsb-release && return +} + +get_os_info(){ + IP=$( ip addr | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | egrep -v "^192\.168|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-2]\.|^10\.|^127\.|^255\.|^0\." | head -n 1 ) + [ -z ${IP} ] && IP=$( wget -qO- -t1 -T2 ipv4.icanhazip.com ) + + local cname=$( awk -F: '/model name/ {name=$2} END {print name}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' ) + local cores=$( awk -F: '/model name/ {core++} END {print core}' /proc/cpuinfo ) + local freq=$( awk -F: '/cpu MHz/ {freq=$2} END {print freq}' /proc/cpuinfo | sed 's/^[ \t]*//;s/[ \t]*$//' ) + local tram=$( free -m | awk '/Mem/ {print $2}' ) + local swap=$( free -m | awk '/Swap/ {print $2}' ) + local up=$( awk '{a=$1/86400;b=($1%86400)/3600;c=($1%3600)/60;d=$1%60} {printf("%ddays, %d:%d:%d\n",a,b,c,d)}' /proc/uptime ) + local load=$( w | head -1 | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//;s/[ \t]*$//' ) + local opsy=$( get_opsy ) + local arch=$( uname -m ) + local lbit=$( getconf LONG_BIT ) + local host=$( hostname ) + local kern=$( uname -r ) + + echo "########## System Information ##########" + echo + echo "CPU model : ${cname}" + echo "Number of cores : ${cores}" + echo "CPU frequency : ${freq} MHz" + echo "Total amount of ram : ${tram} MB" + echo "Total amount of swap : ${swap} MB" + echo "System uptime : ${up}" + echo "Load average : ${load}" + echo "OS : ${opsy}" + echo "Arch : ${arch} (${lbit} Bit)" + echo "Kernel : ${kern}" + echo "Hostname : ${host}" + echo "IPv4 address : ${IP}" + echo + echo "########################################" +} + +check_sys(){ + local checkType=$1 + local value=$2 + + local release='' + local systemPackage='' + + if [[ -f /etc/redhat-release ]]; then + release="centos" + systemPackage="yum" + elif cat /etc/issue | grep -Eqi "debian"; then + release="debian" + systemPackage="apt" + elif cat /etc/issue | grep -Eqi "ubuntu"; then + release="ubuntu" + systemPackage="apt" + elif cat /etc/issue | grep -Eqi "centos|red hat|redhat"; then + release="centos" + systemPackage="yum" + elif cat /proc/version | grep -Eqi "debian"; then + release="debian" + systemPackage="apt" + elif cat /proc/version | grep -Eqi "ubuntu"; then + release="ubuntu" + systemPackage="apt" + elif cat /proc/version | grep -Eqi "centos|red hat|redhat"; then + release="centos" + systemPackage="yum" + fi + + if [[ ${checkType} == "sysRelease" ]]; then + if [ "$value" == "$release" ];then + return 0 + else + return 1 + fi + elif [[ ${checkType} == "packageManager" ]]; then + if [ "$value" == "$systemPackage" ];then + return 0 + else + return 1 + fi + fi +} + +rand(){ + index=0 + str="" + for i in {a..z}; do arr[index]=${i}; index=`expr ${index} + 1`; done + for i in {A..Z}; do arr[index]=${i}; index=`expr ${index} + 1`; done + for i in {0..9}; do arr[index]=${i}; index=`expr ${index} + 1`; done + for i in {1..10}; do str="$str${arr[$RANDOM%$index]}"; done + echo ${str} +} + +is_64bit(){ + if [ `getconf WORD_BIT` = '32' ] && [ `getconf LONG_BIT` = '64' ] ; then + return 0 + else + return 1 + fi +} + +download_file(){ + if [ -s ${1} ]; then + echo "$1 [found]" + else + echo "$1 not found!!!download now..." + if ! wget -c -t3 -T60 ${download_root_url}/${1}; then + echo "Failed to download $1, please download it to ${cur_dir} directory manually and try again." + exit 1 + fi + fi +} + +versionget(){ + if [[ -s /etc/redhat-release ]];then + grep -oE "[0-9.]+" /etc/redhat-release + else + grep -oE "[0-9.]+" /etc/issue + fi +} + +centosversion(){ + if check_sys sysRelease centos;then + local code=${1} + local version="`versionget`" + local main_ver=${version%%.*} + if [ "${main_ver}" == "${code}" ];then + return 0 + else + return 1 + fi + else + return 1 + fi +} + +debianversion(){ + if check_sys sysRelease debian;then + local version=$( get_opsy ) + local code=${1} + local main_ver=$( echo ${version} | sed 's/[^0-9]//g') + if [ "${main_ver}" == "${code}" ];then + return 0 + else + return 1 + fi + else + return 1 + fi +} + +version_check(){ + if check_sys packageManager yum; then + if centosversion 5; then + echo "Error: CentOS 5 is not supported, Please re-install OS and try again." + exit 1 + fi + fi +} + +get_char(){ + SAVEDSTTY=`stty -g` + stty -echo + stty cbreak + dd if=/dev/tty bs=1 count=1 2> /dev/null + stty -raw + stty echo + stty $SAVEDSTTY +} + +preinstall_l2tp(){ + + echo + if [ -d "/proc/vz" ]; then + echo -e "\033[41;37m WARNING: \033[0m Your VPS is based on OpenVZ, and IPSec might not be supported by the kernel." + echo "Continue installation? (y/n)" + read -p "(Default: n)" agree + [ -z ${agree} ] && agree="n" + if [ "${agree}" == "n" ]; then + echo + echo "L2TP installation cancelled." + echo + exit 0 + fi + fi + echo + echo "Please enter IP-Range:" + # read -p "(Default Range: 192.168.18):" iprange + # [ -z ${iprange} ] && iprange="192.168.18" + iprange="192.168.18" + echo ${iprange} + + echo "Please enter PSK:" + # read -p "(Default PSK: teddysun.com):" mypsk + # [ -z ${mypsk} ] && mypsk="teddysun.com" + mypsk="midoks" + echo ${mypsk} + + echo "Please enter Username:" + # read -p "(Default Username: teddysun):" username + # [ -z ${username} ] && username="teddysun" + username="midoks" + echo ${username} + + # password=`rand` + echo "Please enter ${username}'s password:" + # read -p "(Default Password: ${password}):" tmppassword + # [ ! -z ${tmppassword} ] && password=${tmppassword} + password=midoks + echo ${password} + + echo + echo "ServerIP:${IP}" + echo "Server Local IP:${iprange}.1" + echo "Client Remote IP Range:${iprange}.2-${iprange}.254" + echo "PSK:${mypsk}" + echo + echo "Press any key to start... or press Ctrl + C to cancel." + char=`get_char` + +} + +install_l2tp(){ + + mknod /dev/random c 1 9 + + if check_sys packageManager apt; then + apt-get -y update + + if debianversion 7; then + if is_64bit; then + local libnspr4_filename1="libnspr4_4.10.7-1_amd64.deb" + local libnspr4_filename2="libnspr4-0d_4.10.7-1_amd64.deb" + local libnspr4_filename3="libnspr4-dev_4.10.7-1_amd64.deb" + local libnspr4_filename4="libnspr4-dbg_4.10.7-1_amd64.deb" + local libnss3_filename1="libnss3_3.17.2-1.1_amd64.deb" + local libnss3_filename2="libnss3-1d_3.17.2-1.1_amd64.deb" + local libnss3_filename3="libnss3-tools_3.17.2-1.1_amd64.deb" + local libnss3_filename4="libnss3-dev_3.17.2-1.1_amd64.deb" + local libnss3_filename5="libnss3-dbg_3.17.2-1.1_amd64.deb" + else + local libnspr4_filename1="libnspr4_4.10.7-1_i386.deb" + local libnspr4_filename2="libnspr4-0d_4.10.7-1_i386.deb" + local libnspr4_filename3="libnspr4-dev_4.10.7-1_i386.deb" + local libnspr4_filename4="libnspr4-dbg_4.10.7-1_i386.deb" + local libnss3_filename1="libnss3_3.17.2-1.1_i386.deb" + local libnss3_filename2="libnss3-1d_3.17.2-1.1_i386.deb" + local libnss3_filename3="libnss3-tools_3.17.2-1.1_i386.deb" + local libnss3_filename4="libnss3-dev_3.17.2-1.1_i386.deb" + local libnss3_filename5="libnss3-dbg_3.17.2-1.1_i386.deb" + fi + rm -rf ${cur_dir}/l2tp + mkdir -p ${cur_dir}/l2tp + cd ${cur_dir}/l2tp + download_file "${libnspr4_filename1}" + download_file "${libnspr4_filename2}" + download_file "${libnspr4_filename3}" + download_file "${libnspr4_filename4}" + download_file "${libnss3_filename1}" + download_file "${libnss3_filename2}" + download_file "${libnss3_filename3}" + download_file "${libnss3_filename4}" + download_file "${libnss3_filename5}" + dpkg -i ${libnspr4_filename1} ${libnspr4_filename2} ${libnspr4_filename3} ${libnspr4_filename4} + dpkg -i ${libnss3_filename1} ${libnss3_filename2} ${libnss3_filename3} ${libnss3_filename4} ${libnss3_filename5} + + apt-get -y install wget gcc ppp flex bison make pkg-config libpam0g-dev libcap-ng-dev iptables \ + libcap-ng-utils libunbound-dev libevent-dev libcurl4-nss-dev libsystemd-daemon-dev + else + apt-get -y install wget gcc ppp flex bison make python libnss3-dev libnss3-tools libselinux-dev iptables \ + libnspr4-dev pkg-config libpam0g-dev libcap-ng-dev libcap-ng-utils libunbound-dev \ + libevent-dev libcurl4-nss-dev libsystemd-dev + fi + apt-get -y --no-install-recommends install xmlto + apt-get -y install xl2tpd + + compile_install + elif check_sys packageManager yum; then + echo "Adding the EPEL repository..." + yum -y install epel-release yum-utils + [ ! -f /etc/yum.repos.d/epel.repo ] && echo "Install EPEL repository failed, please check it." && exit 1 + yum-config-manager --enable epel + echo "Adding the EPEL repository complete..." + + if centosversion 7; then + yum -y install ppp libreswan xl2tpd firewalld + yum_install + elif centosversion 6; then + yum -y remove libevent-devel + yum -y install libevent2-devel + yum -y install nss-devel nspr-devel pkgconfig pam-devel \ + libcap-ng-devel libselinux-devel lsof \ + curl-devel flex bison gcc ppp make iptables gmp-devel \ + fipscheck-devel unbound-devel xmlto libpcap-devel xl2tpd + + compile_install + fi + fi + +} + +config_install(){ + + cat > /etc/ipsec.conf< /etc/ipsec.secrets< /etc/xl2tpd/xl2tpd.conf< /etc/ppp/options.xl2tpd< /etc/ppp/chap-secrets< Makefile.inc.local <<'EOF' +WERROR_CFLAGS = +USE_DNSSEC = false +USE_DH31 = false +USE_GLIBC_KERN_FLIP_HEADERS = true +EOF + make programs && make install + + /usr/local/sbin/ipsec --version >/dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "${libreswan_filename} install failed." + exit 1 + fi + + config_install + + cp -pf /etc/sysctl.conf /etc/sysctl.conf.bak + + sed -i 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/g' /etc/sysctl.conf + + for each in `ls /proc/sys/net/ipv4/conf/`; do + echo "net.ipv4.conf.${each}.accept_source_route=0" >> /etc/sysctl.conf + echo "net.ipv4.conf.${each}.accept_redirects=0" >> /etc/sysctl.conf + echo "net.ipv4.conf.${each}.send_redirects=0" >> /etc/sysctl.conf + echo "net.ipv4.conf.${each}.rp_filter=0" >> /etc/sysctl.conf + done + sysctl -p + + if centosversion 6; then + [ -f /etc/sysconfig/iptables ] && cp -pf /etc/sysconfig/iptables /etc/sysconfig/iptables.old.`date +%Y%m%d` + + if [ "`iptables -L -n | grep -c '\-\-'`" == "0" ]; then + cat > /etc/sysconfig/iptables < /var/tmp/libreswan-nss-pwd + certutil -N -f /var/tmp/libreswan-nss-pwd -d /etc/ipsec.d + rm -f /var/tmp/libreswan-nss-pwd + fi + + chkconfig --add iptables + chkconfig iptables on + chkconfig --add ipsec + chkconfig ipsec on + chkconfig --add xl2tpd + chkconfig xl2tpd on + + /etc/init.d/iptables restart + /etc/init.d/ipsec start + /etc/init.d/xl2tpd start + + else + [ -f /etc/iptables.rules ] && cp -pf /etc/iptables.rules /etc/iptables.rules.old.`date +%Y%m%d` + + if [ "`iptables -L -n | grep -c '\-\-'`" == "0" ]; then + cat > /etc/iptables.rules < /etc/iptables.rules + fi + + cat > /etc/network/if-up.d/iptables < /var/tmp/libreswan-nss-pwd + certutil -N -f /var/tmp/libreswan-nss-pwd -d /etc/ipsec.d + rm -f /var/tmp/libreswan-nss-pwd + fi + + update-rc.d -f xl2tpd defaults + + cp -f /etc/rc.local /etc/rc.local.old.`date +%Y%m%d` + sed --follow-symlinks -i -e '/^exit 0/d' /etc/rc.local + cat >> /etc/rc.local < /proc/sys/net/ipv4/ip_forward +/usr/sbin/service ipsec start +exit 0 +EOF + chmod +x /etc/rc.local + echo 1 > /proc/sys/net/ipv4/ip_forward + + /sbin/iptables-restore < /etc/iptables.rules + /usr/sbin/service ipsec start + /usr/sbin/service xl2tpd restart + + fi + +} + +yum_install(){ + + config_install + + cp -pf /etc/sysctl.conf /etc/sysctl.conf.bak + + echo "# Added by L2TP VPN" >> /etc/sysctl.conf + echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf + echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf + echo "net.ipv4.icmp_echo_ignore_broadcasts=1" >> /etc/sysctl.conf + echo "net.ipv4.icmp_ignore_bogus_error_responses=1" >> /etc/sysctl.conf + + for each in `ls /proc/sys/net/ipv4/conf/`; do + echo "net.ipv4.conf.${each}.accept_source_route=0" >> /etc/sysctl.conf + echo "net.ipv4.conf.${each}.accept_redirects=0" >> /etc/sysctl.conf + echo "net.ipv4.conf.${each}.send_redirects=0" >> /etc/sysctl.conf + echo "net.ipv4.conf.${each}.rp_filter=0" >> /etc/sysctl.conf + done + sysctl -p + + cat > /etc/firewalld/services/xl2tpd.xml< + + xl2tpd + L2TP IPSec + + + +EOF + chmod 640 /etc/firewalld/services/xl2tpd.xml + + systemctl enable ipsec + systemctl enable xl2tpd + systemctl enable firewalld + + systemctl status firewalld > /dev/null 2>&1 + if [ $? -eq 0 ]; then + firewall-cmd --reload + echo "Checking firewalld status..." + firewall-cmd --list-all + echo "add firewalld rules..." + firewall-cmd --permanent --add-service=ipsec + firewall-cmd --permanent --add-service=xl2tpd + firewall-cmd --permanent --add-masquerade + firewall-cmd --reload + else + echo "Firewalld looks like not running, trying to start..." + systemctl start firewalld + if [ $? -eq 0 ]; then + echo "Firewalld start successfully..." + firewall-cmd --reload + echo "Checking firewalld status..." + firewall-cmd --list-all + echo "adding firewalld rules..." + firewall-cmd --permanent --add-service=ipsec + firewall-cmd --permanent --add-service=xl2tpd + firewall-cmd --permanent --add-masquerade + firewall-cmd --reload + else + echo "Failed to start firewalld. please enable udp port 500 4500 1701 manually if necessary." + fi + fi + + systemctl restart ipsec + systemctl restart xl2tpd + echo "Checking ipsec status..." + systemctl -a | grep ipsec + echo "Checking xl2tpd status..." + systemctl -a | grep xl2tpd + echo "Checking firewalld status..." + firewall-cmd --list-all + +} + +finally(){ + + cd ${cur_dir} + rm -fr ${cur_dir}/l2tp + # create l2tp command + cp -f ${cur_dir}/`basename $0` /usr/bin/l2tp + + echo "Please wait a moment..." + sleep 5 + ipsec verify + echo + echo "###############################################################" + echo "# L2TP VPN Auto Installer #" + echo "# System Supported: CentOS 6+ / Debian 7+ / Ubuntu 12+ #" + echo "# Intro: https://teddysun.com/448.html #" + echo "# Author: Teddysun #" + echo "###############################################################" + echo "If there is no [FAILED] above, you can connect to your L2TP " + echo "VPN Server with the default Username/Password is below:" + echo + echo "Server IP: ${IP}" + echo "PSK : ${mypsk}" + echo "Username : ${username}" + echo "Password : ${password}" + echo + echo "If you want to modify user settings, please use below command(s):" + echo "l2tp -a (Add a user)" + echo "l2tp -d (Delete a user)" + echo "l2tp -l (List all users)" + echo "l2tp -m (Modify a user password)" + echo + echo "Welcome to visit our website: https://teddysun.com/448.html" + echo "Enjoy it!" + echo +} + + +l2tp(){ + clear + echo + echo "###############################################################" + echo "# L2TP VPN Auto Installer #" + echo "# System Supported: CentOS 6+ / Debian 7+ / Ubuntu 12+ #" + echo "# Intro: https://teddysun.com/448.html #" + echo "# Author: Teddysun #" + echo "###############################################################" + echo + rootness + tunavailable + disable_selinux + version_check + get_os_info + preinstall_l2tp + install_l2tp + finally +} + +list_users(){ + if [ ! -f /etc/ppp/chap-secrets ];then + echo "Error: /etc/ppp/chap-secrets file not found." + exit 1 + fi + local line="+-------------------------------------------+\n" + local string=%20s + printf "${line}|${string} |${string} |\n${line}" Username Password + grep -v "^#" /etc/ppp/chap-secrets | awk '{printf "|'${string}' |'${string}' |\n", $1,$3}' + printf ${line} +} + +add_user(){ + while : + do + read -p "Please input your Username:" user + if [ -z ${user} ]; then + echo "Username can not be empty" + else + grep -w "${user}" /etc/ppp/chap-secrets > /dev/null 2>&1 + if [ $? -eq 0 ];then + echo "Username (${user}) already exists. Please re-enter your username." + else + break + fi + fi + done + pass=`rand` + echo "Please input ${user}'s password:" + read -p "(Default Password: ${pass}):" tmppass + [ ! -z ${tmppass} ] && pass=${tmppass} + echo "${user} l2tpd ${pass} *" >> /etc/ppp/chap-secrets + echo "Username (${user}) add completed." +} + +del_user(){ + while : + do + read -p "Please input Username you want to delete it:" user + if [ -z ${user} ]; then + echo "Username can not be empty" + else + grep -w "${user}" /etc/ppp/chap-secrets >/dev/null 2>&1 + if [ $? -eq 0 ];then + break + else + echo "Username (${user}) is not exists. Please re-enter your username." + fi + fi + done + sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets + echo "Username (${user}) delete completed." +} + +mod_user(){ + while : + do + read -p "Please input Username you want to change password:" user + if [ -z ${user} ]; then + echo "Username can not be empty" + else + grep -w "${user}" /etc/ppp/chap-secrets >/dev/null 2>&1 + if [ $? -eq 0 ];then + break + else + echo "Username (${user}) is not exists. Please re-enter your username." + fi + fi + done + pass=`rand` + echo "Please input ${user}'s new password:" + read -p "(Default Password: ${pass}):" tmppass + [ ! -z ${tmppass} ] && pass=${tmppass} + sed -i "/^\<${user}\>/d" /etc/ppp/chap-secrets + echo "${user} l2tpd ${pass} *" >> /etc/ppp/chap-secrets + echo "Username ${user}'s password has been changed." +} + + + +# Main process +action=$1 +if [ -z ${action} ] && [ "`basename $0`" != "l2tp" ]; then + action=install +fi + +case ${action} in + install) + l2tp 2>&1 | tee ${cur_dir}/l2tp.log + ;; + -l|--list) + list_users + ;; + -a|--add) + add_user + ;; + -d|--del) + del_user + ;; + -m|--mod) + mod_user + ;; + -h|--help) + echo "Usage: `basename $0` -l,--list List all users" + echo " `basename $0` -a,--add Add a user" + echo " `basename $0` -d,--del Delete a user" + echo " `basename $0` -m,--mod Modify a user password" + echo " `basename $0` -h,--help Print this help information" + ;; + *) + echo "Usage: `basename $0` [-l,--list|-a,--add|-d,--del|-m,--mod|-h,--help]" && exit + ;; +esac diff --git a/plugins/l2tp/tmp/chap-secrets b/plugins/l2tp/tmp/chap-secrets new file mode 100644 index 000000000..20721096a --- /dev/null +++ b/plugins/l2tp/tmp/chap-secrets @@ -0,0 +1,3 @@ +# Secrets for authentication using CHAP +# client server secret IP addresses +demo demo demo * diff --git a/plugins/l2tp/tmp/ipsec.secrets b/plugins/l2tp/tmp/ipsec.secrets new file mode 100644 index 000000000..e186ee087 --- /dev/null +++ b/plugins/l2tp/tmp/ipsec.secrets @@ -0,0 +1 @@ +%any %any : PSK "midoks"