update 2026-05-13 01:55:45

This commit is contained in:
action committed 2026-05-13 01:55:45 +08:00
1 parent 1b6001bfed
commit 6f4a0231c5
1857 files changed
+749084 -99

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
# Copyright (C) 2018-2021 Lienol <lawlienol@gmail.com>
#
# This is free software, licensed under the Apache License, Version 2.0 .
#
include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for PPTP VPN Server
LUCI_DEPENDS:=+pptpd +kmod-mppe +ppp +luci-lib-jsonc
LUCI_PKGARCH:=all
PKG_VERSION:=20211223
PKG_RELEASE:=3
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
@@ -0,0 +1,21 @@
-- Copyright 2018-2020 Lienol <lawlienol@gmail.com>
module("luci.controller.pptpd", package.seeall)
function index()
if not nixio.fs.access("/etc/config/luci-app-pptp-server") then return end
entry({"admin", "vpn"}, firstchild(), "VPN", 45).dependent = false
entry({"admin", "vpn", "pptpd"}, alias("admin", "vpn", "pptpd", "settings"), _("PPTP VPN Server"), 48)
entry({"admin", "vpn", "pptpd", "settings"}, cbi("pptpd/settings"), _("General Settings"), 10).leaf = true
entry({"admin", "vpn", "pptpd", "users"}, cbi("pptpd/users"), _("Users Manager"), 20).leaf = true
entry({"admin", "vpn", "pptpd", "user"}, cbi("pptpd/user")).leaf = true
entry({"admin", "vpn", "pptpd", "online"}, cbi("pptpd/online"), _("Online Users"), 30).leaf = true
entry({"admin", "vpn", "pptpd", "status"}, call("status")).leaf = true
end
function status()
local e = {}
e.status = luci.sys.call("pidof %s >/dev/null" % "pptpd") == 0
luci.http.prepare_content("application/json")
luci.http.write_json(e)
end
@@ -0,0 +1,84 @@
local o = require "luci.dispatcher"
local fs = require "nixio.fs"
local jsonc = require "luci.jsonc"
local sessions = {}
local session_path = "/var/etc/pptpd/session"
if fs.access(session_path) then
for filename in fs.dir(session_path) do
local session_file = session_path .. "/" .. filename
local file = io.open(session_file, "r")
local t = jsonc.parse(file:read("*a"))
if t then
t.session_file = session_file
sessions[#sessions + 1] = t
end
file:close()
end
end
local blacklist = {}
local firewall_user_path = "/etc/firewall.user"
if fs.access(firewall_user_path) then
for line in io.lines(firewall_user_path) do
local m = line:match('pptpd%-blacklist%-([^\n]+)')
if m then
local t = {}
t.ip = m
blacklist[#blacklist + 1] = t
end
end
end
f = SimpleForm("processes", translate("PPTP VPN Server"))
f.reset = false
f.submit = false
f.description = translate("Simple, quick and convenient PPTP VPN, universal across the platform")
t = f:section(Table, sessions, translate("Online Users"))
t:option(DummyValue, "username", translate("Username"))
t:option(DummyValue, "interface", translate("Interface"))
t:option(DummyValue, "ip", translate("Client IP"))
t:option(DummyValue, "remote_ip", translate("IP address"))
t:option(DummyValue, "login_time", translate("Login Time"))
_blacklist = t:option(Button, "_blacklist", translate("Blacklist"))
function _blacklist.render(e, t, a)
e.title = translate("Add to Blacklist")
e.inputstyle = "remove"
Button.render(e, t, a)
end
function _blacklist.write(t, s)
local e = t.map:get(s, "remote_ip")
luci.util.execi("echo 'iptables -I INPUT -s %s -p tcp --dport 1723 -j DROP ## pptpd-blacklist-%s' >> /etc/firewall.user" % {e, e})
luci.util.execi("iptables -I INPUT -s %s -p tcp --dport 1723 -j DROP" % {e})
luci.util.execi("rm -f " .. t.map:get(s, "session_file"))
null, t.tag_error[s] = luci.sys.process.signal(t.map:get(s, "pid"), 9)
luci.http.redirect(o.build_url("admin/vpn/pptpd/online"))
end
_kill = t:option(Button, "_kill", translate("Forced offline"))
_kill.inputstyle = "reset"
function _kill.write(t, s)
luci.util.execi("rm -f " .. t.map:get(s, "session_file"))
null, t.tag_error[t] = luci.sys.process.signal(t.map:get(s, "pid"), 9)
luci.http.redirect(o.build_url("admin/vpn/pptpd/online"))
end
t = f:section(Table, blacklist, translate("Blacklist"))
t:option(DummyValue, "ip", translate("IP address"))
_blacklist2 = t:option(Button, "_blacklist2", translate("Blacklist"))
function _blacklist2.render(e, t, a)
e.title = translate("Remove from Blacklist")
e.inputstyle = "apply"
Button.render(e, t, a)
end
function _blacklist2.write(t, s)
local e = t.map:get(s, "ip")
luci.util.execi("sed -i -e '/## pptpd-blacklist-%s/d' /etc/firewall.user" % {e})
luci.util.execi("iptables -D INPUT -s %s -p tcp --dport 1723 -j DROP" % {e})
luci.http.redirect(o.build_url("admin/vpn/pptpd/online"))
end
return f
@@ -0,0 +1,40 @@
local s = require "luci.sys"
local net = require"luci.model.network".init()
local ifaces = s.net:devices()
local m, s, o
m = Map("luci-app-pptp-server", translate("PPTP VPN Server"))
m.description = translate("Simple, quick and convenient PPTP VPN, universal across the platform")
m.template = "pptpd/index"
s = m:section(TypedSection, "service")
s.anonymous = true
o = s:option(DummyValue, "pptpd_status", translate("Current Condition"))
o.template = "pptpd/status"
o.value = translate("Collecting data...")
o = s:option(Flag, "enabled", translate("Enabled"))
o.rmempty = false
o = s:option(Value, "localip", translate("Server IP"), translate("VPN Server IP address, it not required."))
o.datatype = "ipaddr"
o.placeholder = translate("192.168.1.2")
o.rmempty = true
o.default = "192.168.1.2"
o = s:option(Value, "remoteip", translate("Client IP"), translate("VPN Client IP address, it not required."))
o.placeholder = translate("192.168.1.10-20")
o.rmempty = true
o.default = "192.168.1.10-20"
--[[
o = s:option(Value, "dns", translate("DNS IP address"), translate("This will be sent to the client, it not required."))
o.placeholder = translate("192.168.1.1")
o.datatype = "ipaddr"
o.rmempty = true
o.default = "192.168.1.1"
]]--
o = s:option(Flag, "mppe", translate("Enable MPPE Encryption"), translate("Allows 128-bit encrypted connection."))
o.rmempty = false
return m
@@ -0,0 +1,32 @@
local d = require "luci.dispatcher"
m = Map("luci-app-pptp-server", translate("Users Manager"))
m.redirect = d.build_url("admin", "vpn", "pptpd", "users")
s = m:section(NamedSection, arg[1], "users", "")
s.addremove = false
s.anonymous = true
o = s:option(Flag, "enabled", translate("Enabled"))
o.default = 1
o.rmempty = false
o = s:option(Value, "username", translate("Username"))
o.placeholder = translate("Username")
o.rmempty = false
o = s:option(Value, "password", translate("Password"))
o.placeholder = translate("Password")
o.rmempty = false
o = s:option(Value, "ipaddress", translate("IP address"))
o.placeholder = translate("Automatically")
o.datatype = "ip4addr"
o.rmempty = true
o = s:option(DynamicList, "routes", translate("Static Routes"))
o.placeholder = "192.168.10.0/24"
o.datatype = "ipmask4"
o.rmempty = true
return m
@@ -0,0 +1,33 @@
local d = require "luci.dispatcher"
m = Map("luci-app-pptp-server", translate("PPTP VPN Server"))
m.description = translate("Simple, quick and convenient PPTP VPN, universal across the platform")
s = m:section(TypedSection, "users", translate("Users Manager"))
s.addremove = true
s.anonymous = true
s.template = "cbi/tblsection"
s.extedit = d.build_url("admin", "vpn", "pptpd", "user", "%s")
function s.create(e, t)
t = TypedSection.create(e, t)
luci.http.redirect(e.extedit:format(t))
end
o = s:option(Flag, "enabled", translate("Enabled"))
o.default = 1
o.rmempty = false
o = s:option(Value, "username", translate("Username"))
o.placeholder = translate("Username")
o.rmempty = false
o = s:option(Value, "password", translate("Password"))
o.placeholder = translate("Password")
o.rmempty = false
o = s:option(Value, "ipaddress", translate("IP address"))
o.placeholder = translate("Automatically")
o.datatype = "ip4addr"
o.rmempty = true
return m
@@ -0,0 +1,13 @@
<% include("cbi/map") %>
<script type="text/javascript">//<![CDATA[
XHR.poll(2, '<%=luci.dispatcher.build_url("admin", "vpn", "pptpd", "status")%>', null,
function(x, result)
{
var status = document.getElementsByClassName('pptpd_status')[0];
status.setAttribute("style","font-weight:bold;");
status.setAttribute("color",result.status ? "green":"red");
status.innerHTML = result.status?'<%=translate("RUNNING")%>':'<%=translate("NOT RUNNING")%>';
}
)
//]]>
</script>
@@ -0,0 +1,3 @@
<%+cbi/valueheader%>
<font class="pptpd_status"><%=pcdata(self:cfgvalue(section) or self.default or "")%></font>
<%+cbi/valuefooter%>
@@ -0,0 +1,71 @@
msgid "PPTP VPN Server"
msgstr "PPTP VPN 服务器"
msgid "Simple, quick and convenient PPTP VPN, universal across the platform"
msgstr "简单快捷方便的PPTP VPN,全平台通用。"
msgid "Current Condition"
msgstr "当前状态"
msgid "General settings"
msgstr "基本设置"
msgid "Enabled"
msgstr "启用"
msgid "Server IP"
msgstr "服务器 IP 地址"
msgid "VPN Server IP address, it not required."
msgstr "VPN 服务器远程地址,留空将自动设置。"
msgid "Client IP"
msgstr "客户端 IP 地址"
msgid "VPN Client IP address, it not required."
msgstr "分配给客户端的 IP 地址范围,留空将自动设置。"
msgid "Enable MPPE Encryption"
msgstr "启用MPPE 加密"
msgid "Allows 128-bit encrypted connection."
msgstr "允许使用 128 位加密连接。"
msgid "Users Manager"
msgstr "用户管理"
msgid "Username"
msgstr "用户名"
msgid "Password"
msgstr "密码"
msgid "IP address"
msgstr "IP 地址"
msgid "Automatically"
msgstr "自动分配"
msgid "Online Users"
msgstr "在线用户"
msgid "Login Time"
msgstr "登录时间"
msgid "Blacklist"
msgstr "黑名单"
msgid "Add to Blacklist"
msgstr "加入黑名单"
msgid "Remove from Blacklist"
msgstr "移出黑名单"
msgid "Forced offline"
msgstr "强制下线"
msgid "NOT RUNNING"
msgstr "未运行"
msgid "RUNNING"
msgstr "运行中"
+1
View File
@@ -0,0 +1 @@
zh-cn
@@ -0,0 +1,7 @@
config service 'pptpd'
option mppe '1'
option localip '192.168.2.1'
option remoteip '192.168.2.10-20'
option enabled '0'
@@ -0,0 +1,125 @@
#!/bin/sh /etc/rc.common
START=99
CONFIG="luci-app-pptp-server"
PPTP_PATH=/var/etc/pptpd
PPTP_CONFIG_FILE=${PPTP_PATH}/pptpd.conf
PPTP_OPTIONS_FILE=${PPTP_PATH}/options.pptpd
CHAP_SECRETS=/etc/ppp/chap-secrets
localip=$(uci -q get ${CONFIG}.@service[0].localip)
[ -z "${localip}" ] && localip="172.16.100.1"
ipt_flag="PPTP VPN Server"
get_enabled_anonymous_secs() {
uci -q show "${CONFIG}" | grep "${1}\[.*\.enabled='1'" | cut -d '.' -sf2
}
ipt_rule() {
if [ "$1" = "add" ]; then
iptables -t nat -I postrouting_rule -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j MASQUERADE 2>/dev/null
iptables -I forwarding_rule -s ${localip%.*}.0/24 -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
iptables -I input_rule -p tcp --dport 1723 -m comment --comment "${ipt_flag}" -j ACCEPT 2>/dev/null
iptables -t mangle -I OUTPUT -p tcp --sport 1723 -m comment --comment "${ipt_flag}" -j RETURN 2>/dev/null
else
ipt_del() {
for i in $(seq 1 $($1 -nL $2 | grep -c "${ipt_flag}")); do
local index=$($1 --line-number -nL $2 | grep "${ipt_flag}" | head -1 | awk '{print $1}')
$1 -w -D $2 $index 2>/dev/null
done
}
ipt_del "iptables" "forwarding_rule"
ipt_del "iptables" "input_rule"
ipt_del "iptables -t nat" "postrouting_rule"
ipt_del "iptables -t mangle" "OUTPUT"
fi
}
gen_include() {
echo '#!/bin/sh' > /var/etc/${CONFIG}.include
extract_rules() {
echo "*$1"
iptables-save -t $1 | grep "${ipt_flag}" | \
sed -e "s/^-A \(INPUT\)/-I \1 1/"
echo 'COMMIT'
}
cat <<-EOF >> /var/etc/${CONFIG}.include
iptables-save -c | grep -v "${ipt_flag}" | iptables-restore -c
iptables-restore -n <<-EOT
$(extract_rules filter)
$(extract_rules nat)
EOT
EOF
return 0
}
start() {
local enabled=$(uci -q get ${CONFIG}.@service[0].enabled)
[ "${enabled}" -eq 1 ] || return 1
touch ${CHAP_SECRETS}
mkdir -p ${PPTP_PATH}
cp /etc/ppp/options.pptpd ${PPTP_OPTIONS_FILE}
sed -i '/mppe/d' ${PPTP_OPTIONS_FILE} 2>/dev/null
sed -i '/ms-dns/d' ${PPTP_OPTIONS_FILE} 2>/dev/null
sed -i '/name/d' ${PPTP_OPTIONS_FILE} 2>/dev/null
echo "name pptp-server">> ${PPTP_OPTIONS_FILE}
local mppe=$(uci -q get ${CONFIG}.@service[0].mppe)
[ -n "${mppe}" ] && [ "${mppe}" -eq 1 ] && echo "mppe required,no40,no56,stateless" >> ${PPTP_OPTIONS_FILE}
echo "ms-dns ${localip}">> ${PPTP_OPTIONS_FILE}
cp /etc/pptpd.conf ${PPTP_CONFIG_FILE}
sed -i '/localip/d' ${PPTP_CONFIG_FILE} 2>/dev/null
sed -i '/remoteip/d' ${PPTP_CONFIG_FILE} 2>/dev/null
sed -i '/option/d' ${PPTP_CONFIG_FILE} 2>/dev/null
sed -i '/name/d' ${PPTP_CONFIG_FILE} 2>/dev/null
echo "name pptp-server">> ${PPTP_CONFIG_FILE}
local remoteip=$(uci -q get ${CONFIG}.@service[0].remoteip)
[ -z "${remoteip}" ] && remoteip="172.16.100.10-20"
echo "localip ${localip}" >> ${PPTP_CONFIG_FILE}
echo "remoteip ${remoteip}" >> ${PPTP_CONFIG_FILE}
echo "option ${PPTP_OPTIONS_FILE}" >> ${PPTP_CONFIG_FILE}
local _users=$(get_enabled_anonymous_secs "@users")
[ -n "${_users}" ] && {
for _user in ${_users}; do
local u_enabled=$(uci -q get ${CONFIG}.${_user}.enabled)
[ "${u_enabled}" -eq 1 ] || continue
local u_username=$(uci -q get ${CONFIG}.${_user}.username)
[ -n "${u_username}" ] || continue
local u_password=$(uci -q get ${CONFIG}.${_user}.password)
[ -n "${u_password}" ] || continue
local u_ipaddress=$(uci -q get ${CONFIG}.${_user}.ipaddress)
[ -n "${u_ipaddress}" ] || u_ipaddress="*"
echo "${u_username} pptp-server ${u_password} ${u_ipaddress}" >> ${CHAP_SECRETS}
done
}
echo "ip-up-script /usr/share/pptpd/ip-up" >> ${PPTP_OPTIONS_FILE}
echo "ip-down-script /usr/share/pptpd/ip-down" >> ${PPTP_OPTIONS_FILE}
for m in arc4 sha1_generic slhc crc-ccitt ppp_generic ppp_async ppp_mppe; do
insmod ${m} >/dev/null 2>&1
done
/usr/sbin/pptpd -c ${PPTP_CONFIG_FILE}
ipt_rule add
gen_include
}
stop() {
sed -i '/pptp-server/d' ${CHAP_SECRETS} 2>/dev/null
top -bn1 | grep "${PPTP_PATH}" | grep -v "grep" | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
ipt_rule del
rm -rf /var/etc/${CONFIG}.include
rm -rf ${PPTP_PATH}
}
@@ -0,0 +1,21 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete firewall.luci_app_pptp_server
set firewall.luci_app_pptp_server=include
set firewall.luci_app_pptp_server.type=script
set firewall.luci_app_pptp_server.path=/var/etc/pptpd.include
set firewall.luci_app_pptp_server.reload=1
EOF
uci -q batch <<-EOF >/dev/null
delete ucitrack.@luci-app-pptp-server[-1]
add ucitrack luci-app-pptp-server
set ucitrack.@luci-app-pptp-server[-1].init=luci-app-pptp-server
commit ucitrack
EOF
/etc/init.d/pptpd disable 2>/dev/null
/etc/init.d/pptpd stop 2>/dev/null
rm -rf /tmp/luci-*cache
exit 0
+27
View File
@@ -0,0 +1,27 @@
#!/bin/sh
_LOGOUT_TIME="$(date "+%Y-%m-%d %H:%M:%S")"
CONFIG="luci-app-pptp-server"
PPTP_PATH=/var/etc/pptpd
PPTP_SESSION_PATH=${PPTP_PATH}/session
_USERNAME=${PEERNAME}
_IFACE=${1}
_TTY=${2}
_SPEED=${3}
_LOCALIP=${4}
_PEERIP=${5}
_REMOTEIP=${6}
_BYTES_SENT=${BYTES_SENT}
_BYTES_RCVD=${BYTES_RCVD}
_CONNECT_TIME=${CONNECT_TIME}
rm -f ${PPTP_SESSION_PATH}/${_USERNAME}.${_IFACE}
rm -f /var/run/${_IFACE}.pid
#可根据退出的账号自定义脚本,如静态路由表,组网等。
SCRIPT="/usr/share/pptpd/ip-down.d/${_USERNAME}"
[ -s "$SCRIPT" ] && {
[ ! -x "$SCRIPT" ] && chmod 0755 "$SCRIPT"
"$SCRIPT" "$@"
}
+58
View File
@@ -0,0 +1,58 @@
#!/bin/sh
_LOGIN_TIME="$(date "+%Y-%m-%d %H:%M:%S")"
CONFIG="luci-app-pptp-server"
PPTP_PATH=/var/etc/pptpd
PPTP_SESSION_PATH=${PPTP_PATH}/session
_USERNAME=${PEERNAME}
_IFACE=${1}
_TTY=${2}
_SPEED=${3}
_LOCALIP=${4}
_PEERIP=${5}
_REMOTEIP=${6}
_PID="$(cat /var/run/${_IFACE}.pid 2>/dev/null)"
mkdir -p ${PPTP_SESSION_PATH}
cat <<-EOF > ${PPTP_SESSION_PATH}/${_USERNAME}.${_IFACE}
{
"username": "${_USERNAME}",
"interface": "${_IFACE}",
"tty": "${_TTY}",
"speed": "${_SPEED}",
"ip": "${_PEERIP}",
"remote_ip": "${_REMOTEIP}",
"pid": "${_PID}",
"login_time": "${_LOGIN_TIME}"
}
EOF
#只能单用户使用
cfgid=$(uci show ${CONFIG} | grep "@users" | grep "\.username='${_USERNAME}'" | cut -d '.' -sf 2)
[ -n "$cfgid" ] && {
HAS_LOGIN=$(ls ${PPTP_SESSION_PATH} | grep "^${_USERNAME}\.ppp" | grep -v "${_IFACE}")
[ -n "$HAS_LOGIN" ] && {
#踢出之前的用户
KO_IFACE=$(echo $HAS_LOGIN | awk -F '.' '{print $2}')
KO_PID=$(cat /var/run/${KO_IFACE}.pid 2>/dev/null)
[ -n "$KO_PID" ] && kill -9 ${KO_PID} >/dev/null 2>&1
rm -f ${PPTP_SESSION_PATH}/${HAS_LOGIN}
rm -f /var/run/${KO_IFACE}.pid
}
routes=$(uci -q get ${CONFIG}.${cfgid}.routes)
[ -n "$routes" ] && {
for router in ${routes}; do
route add -net ${router} dev ${_IFACE} >/dev/null 2>&1
done
}
}
#可根据登录的账号自定义脚本,如组网、日志、限速、权限等特殊待遇。
SCRIPT="/usr/share/pptpd/ip-up.d/${_USERNAME}"
[ -s "$SCRIPT" ] && {
[ ! -x "$SCRIPT" ] && chmod 0755 "$SCRIPT"
"$SCRIPT" "$@"
}
@@ -0,0 +1,11 @@
{
"luci-app-pptp-server": {
"description": "Grant UCI access for luci-app-pptp-server",
"read": {
"uci": [ "luci-app-pptp-server" ]
},
"write": {
"uci": [ "luci-app-pptp-server" ]
}
}
}
@@ -0,0 +1,4 @@
{
"config": "luci-app-pptp-server",
"init": "luci-app-pptp-server"
}