🌴 Sync 2026-03-05 23:51:42

This commit is contained in:
github-actions[bot]
2026-03-05 23:51:42 +08:00
parent 0d155c70be
commit 32600acc60
14258 changed files with 3954570 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-proto-tinc
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/luci-proto-tinc
SECTION:=net
CATEGORY:=protocols
TITLE:=Protocol for TincVPN
PKGARCH:=all
DEPENDS:=+tinc
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./files/* $(PKG_BUILD_DIR)/
endef
define Package/luci-proto-tinc/install
$(INSTALL_DIR) $(1)/lib/netifd/proto
$(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/netifd/proto/tinc.sh $(1)/lib/netifd/proto
$(INSTALL_BIN) $(PKG_BUILD_DIR)/lib/netifd/tinc.script $(1)/lib/netifd
$(INSTALL_DIR) $(1)/www/luci-static/resources/protocol
$(INSTALL_DATA) $(PKG_BUILD_DIR)/www/luci-static/resources/protocol/tinc.js $(1)/www/luci-static/resources/protocol
endef
$(eval $(call BuildPackage,luci-proto-tinc))
+2
View File
@@ -0,0 +1,2 @@
.PHONY: all
all:
@@ -0,0 +1,118 @@
#!/bin/sh
[ -x /usr/sbin/tincd ] || exit 0
[ -n "$INCLUDE_ONLY" ] || {
. /lib/functions.sh
. ../netifd-proto.sh
init_proto "$@"
}
proto_tinc_append() {
append "$3" "$1"
}
proto_tinc_init_config() {
no_device=1
available=1
renew_handler=1
proto_config_add_string ipaddr
proto_config_add_string ip6addr
proto_config_add_string name
proto_config_add_string bindtoaddr
proto_config_add_string 'mode:or("router","switch","hub")'
proto_config_add_string 'priority:or("low","normal","high")'
proto_config_add_string 'strict_subnets:or("no","yes")'
proto_config_add_array 'connect:list(string)'
proto_config_add_array 'option:list(string)'
proto_config_add_array 'subnet:list(string)'
proto_config_add_array 'route:list(string)'
proto_config_add_int mtu
}
proto_tinc_setup() {
local config="$1"
local ipaddr ip6addr name bindtoaddr connect connects mode priority strict_subnets option options subnet subnets route routes mtu
json_get_vars ipaddr ip6addr name bindtoaddr mode priority strict_subnets mtu
json_for_each_item proto_tinc_append connect connects
json_for_each_item proto_tinc_append option options
json_for_each_item proto_tinc_append subnet subnets
json_for_each_item proto_tinc_append route routes
proto_export CONFIG="$config"
proto_export IPADDR="$ipaddr"
proto_export IP6ADDR="$ip6addr"
proto_export ROUTES="$routes"
proto_export MTU="$mtu"
config_dir="/etc/tinc/$config"
tmp_config_dir="/tmp/tinc/$config"
tmp_config_file="$tmp_config_dir/tinc.conf"
rm -rf $tmp_config_dir
cp -rf $config_dir $tmp_config_dir
cp -f /lib/netifd/tinc.script $tmp_config_dir/tinc-up
chmod 755 $tmp_config_dir/tinc-up
mkdir -p $config_dir/hosts $tmp_config_dir/hosts
{
echo "Name=$name"
echo "Interface=tinc-$config"
echo "Mode=$mode"
[ -z "$bindtoaddr" ] || echo "BindToAddress=$bindtoaddr"
[ -z "$priority" ] || echo "ProcessPriority=$priority"
[ -z "$strict_subnets" ] || echo "StrictSubnets=$strict_subnets"
for host in $connects; do
echo "ConnectTo=$host"
done
for option in $options; do
echo "$option"
done
} > $tmp_config_file
if [ ! -f $tmp_config_dir/hosts/$name ]; then
tincd -c $tmp_config_dir -K
cp -f $tmp_config_dir/*.priv $config_dir
cp -rf $tmp_config_dir/hosts $config_dir
fi
{
if [ -n "$ipaddr" ]; then
echo "Subnet=${ipaddr%%/*}/32"
fi
if [ -n "$ip6addr" ]; then
echo "Subnet=${ip6addr%%/*}/128"
fi
for subnet in $subnets; do
echo "Subnet=$subnet"
done
cat $config_dir/hosts/$name
} > $tmp_config_dir/hosts/$name
proto_run_command "$config" /usr/sbin/tincd \
-c $tmp_config_dir \
--no-detach \
--pidfile=/var/run/tinc.${config}.pid \
--logfile=/tmp/log/tinc.${config}.log
}
proto_tinc_teardown() {
local config="$1"
logger -t tinc "stopping..."
proto_kill_command "$config" 9
}
proto_tinc_renew() {
local iface="$1"
logger -t tinc "renew $iface ..."
}
[ -n "$INCLUDE_ONLY" ] || {
add_protocol tinc
}
@@ -0,0 +1,55 @@
#!/bin/sh
. /lib/netifd/netifd-proto.sh
add_route() {
local route="$1"
local next version target mask gw metric
version="${route%%,*}"
next="${route#*,}"
target="${next%%/*}"
next="${route#*/}"
mask="${next%%,*}"
next="${next#*,}"
if [ "$next" != "$mask" ]; then
gw="${next%%,*}"
next="${next#*,}"
if [ "$next" == "$gw" ]; then
metric="$gw"
gw=""
else
metric="${next#*,}"
fi
fi
if [ "$version" == "4" ]; then
echo proto_add_ipv4_route \"$target\" \"$mask\" \"$gw\" \"\" \"$metric\"
else
echo proto_add_ipv6_route \"$target\" \"$mask\" \"$gw\" \"$metric\"
fi
}
proto_init_update "$INTERFACE" 1
if [ -n "$IPADDR" ]; then
proto_add_ipv4_address "${IPADDR%%/*}" "${IPADDR##*/}"
fi
if [ -n "$IP6ADDR" ]; then
proto_add_ipv6_address "${IP6ADDR%%/*}" "${IP6ADDR##*/}"
fi
# version,target/mask,gw,metric
# version,target/mask,metric
# version,target/mask
for route in $ROUTES; do
eval $(add_route $route)
done
echo "MTU:$MTU">>/tmp/debug.txt
if [ -n "$MTU" ]; then
ip link set $INTERFACE mtu $MTU
fi
proto_send_update "$CONFIG"
@@ -0,0 +1 @@
/etc/tinc/
@@ -0,0 +1,157 @@
'use strict';
'require uci';
'require form';
'require network';
'require fs';
'require ui';
network.registerPatternVirtual(/^tinc-.+$/);
function getHosts(section_id) {
return fs.list('/etc/tinc/' + section_id + '/hosts').then(function (lines) {
return lines.map(function (file) {
if (file.type === 'file') {
return file.name;
}
});
}).then(L.bind(function (names) {
this.names = names;
return this.super('load', section_id);
}, this));
}
return network.registerProtocol('tinc', {
IPAddr: form.Value.extend({
validate: function (section_id, value) {
var str = this.formvalue(section_id);
if (str.length > 0) {
var m = str.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,3}$/);
if (!m) {
return _('Expecting: valid IPv4 CIDR');
}
}
return true;
}
}),
IP6Addr: form.Value.extend({
validate: function (section_id, value) {
var str = this.formvalue(section_id);
if (str.length > 0) {
var m = str.match(/^([\da-fA-F]{1,4}:){6}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^::([\da-fA-F]{1,4}:){0,4}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:):([\da-fA-F]{1,4}:){0,3}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){2}:([\da-fA-F]{1,4}:){0,2}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){3}:([\da-fA-F]{1,4}:){0,1}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){4}:((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^:((:[\da-fA-F]{1,4}){1,6}|:)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^[\da-fA-F]{1,4}:((:[\da-fA-F]{1,4}){1,5}|:)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){2}((:[\da-fA-F]{1,4}){1,4}|:)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){3}((:[\da-fA-F]{1,4}){1,3}|:)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){4}((:[\da-fA-F]{1,4}){1,2}|:)(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){5}:([\da-fA-F]{1,4})?(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$|^([\da-fA-F]{1,4}:){6}:(\/([1-9]?\d|(1([0-1]\d|2[0-8]))))?$/);
if (!m) {
return _('Expecting: valid IPv6 CIDR');
}
}
return true;
}
}),
Name: form.Value.extend({
validate: function (section_id, value) {
var str = this.formvalue(section_id);
if (str.length > 16 || !str.match(/^[a-zA-Z0-9_\-.]+$/)) {
return _('valid node name');
}
return true;
}
}),
BindToAddress: form.Value.extend({
validate: function (section_id, value) {
var str = this.formvalue(section_id);
if (str.length > 0 && !str.match(/^\*\ \d+$/)) {
return _('Format: <address> [<port>]');
}
return true;
}
}),
DropDownList: form.ListValue.extend({
renderWidget: function (section_id, option_index, cfgvalue) {
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default);
var widget = new ui.Dropdown(values, this.choices, {
id: this.cbid(section_id),
sort: this.sort,
multiple: this.multiple,
optional: this.optional,
select_placeholder: E('em', _(this.placeholder || 'unspecified')),
optional: this.optional || this.rmempty,
});
return widget.render();
}
}),
ConnectTo: form.ListValue.extend({
load: getHosts,
filter: function (section_id, value) {
return true;
},
renderWidget: function (section_id, option_index, cfgvalue) {
var values = L.toArray((cfgvalue != null) ? cfgvalue : this.default)
, choices = {};
for (var i = 0; i < this.names.length; i++) {
choices[this.names[i]] = E('span', {
'class': 'zonebadge',
}, E('label', _(this.names[i])));
}
var widget = new ui.Dropdown(values, choices, {
id: this.cbid(section_id),
sort: true,
multiple: true,
select_placeholder: E('em', _(this.placeholder || 'unspecified')),
});
return widget.render();
}
}),
Option: form.DynamicList.extend({
validate: function (section_id, value) {
var val = this.formvalue(section_id),
i;
for (i = 0; i < val.length; i++) {
if (val[i].length > 0 && !val[i].match(/^[a-zA-Z0-9_\-]+=[a-zA-Z0-9_\-]+$/)) {
return _('Expecting: valid option');
}
}
return true;
}
}),
Route: form.DynamicList.extend({
validate: function (section_id, value) {
var val = this.formvalue(section_id),
i;
return true;
}
}),
getI18n: function () {
return _('TincVPN');
},
getIfname: function () {
return this._ubus('l3_device') || 'tinc-%s'.format(this.sid);
},
getOpkgPackage: function () {
return 'tinc';
},
containsDevice: function (ifname) {
return (network.getIfnameOf(ifname) == this.getIfname());
},
renderFormOptions: function (s) {
var dev = this.getL3Device() || this.getDevice(),
o;
o = s.taboption('general', this.IPAddr, 'ipaddr', _('IPv4 Address'));
o.datatype = 'cidr';
o = s.taboption('general', this.IP6Addr, 'ip6addr', _('IPv6 Address'));
o.datatype = 'cidr6';
o.optional = true
o = s.taboption('general', this.Name, 'name', _('Name'));
s.taboption('general', this.BindToAddress, 'bindtoaddr', _('BindToAddress'));
s.taboption('general', this.ConnectTo, 'connect', _('ConnectTo'));
o = s.taboption('general', this.DropDownList, 'mode', _('Mode'));
o.choices = { 'router': 'router', 'switch': 'switch', 'hub': 'hub' };
o = s.taboption('general', this.DropDownList, 'priority', _('ProcessPriority'));
o.choices = { 'low': 'low', 'normal': 'normal', 'high': 'high' };
o = s.taboption('general', this.DropDownList, 'strict_subnets', _('StrictSubnets'));
o.choices = { 'yes': 'yes', 'no': 'no' };
s.taboption('general', this.Option, 'option', _('Extra option'));
o = s.taboption('general', form.DynamicList, 'subnet', _('Subnet'));
o.datatype = 'cidr';
s.taboption('general', this.Route, 'route', _('Route'));
o = s.taboption('general', form.Value, 'mtu', _('Override MTU'));
o.placeholder = dev ? (dev.getMTU() || '1400') : '1400';
o.datatype = 'range(68, 9200)';
}
});