Compare commits

...

2 Commits

Author SHA1 Message Date
github-actions[bot]
e5346defb9 🎉 Sync 2026-07-01 00:17:42 2026-07-01 00:17:42 +08:00
github-actions[bot]
9c5c48e5f2 🌈 Sync 2026-06-30 20:43:37 2026-06-30 20:43:37 +08:00
17 changed files with 627 additions and 138 deletions

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=BitSrunLoginGo
PKG_VERSION:=1.6.7
PKG_RELEASE:=5
PKG_RELEASE:=6
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/Mmx233/BitSrunLoginGo/tar.gz/v$(PKG_VERSION)?

View File

@ -27,6 +27,9 @@ config bitsrunlogin-go 'config'
# Interface name in regex, e.g. "eth0\.[2-3]"
# Multi-interfaces mode will be enabled if not empty
option interfaces ''
option interfaces_interval ''
# Custom DNS server. System DNS will be used if empty
option dns_server ''
# Enable debug log
option debug '0'

View File

@ -69,6 +69,8 @@ start_service() {
uci_json_add_boolean "skip_cert_verify" "skip_cert_verify"
uci_json_add_int "timeout" "timeout" "5"
uci_json_add_string "interfaces" "interfaces"
uci_json_add_int "interfaces_interval" "interfaces_interval"
uci_json_add_string "dns_server" "dns_server"
json_close_object
json_add_object "guardian"
json_add_boolean "enable" "1"

View File

@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=daed
PKG_VERSION:=2026.06.14
PKG_RELEASE:=15
PKG_RELEASE:=16
PKG_SOURCE:=daed-src-2026.06.14-4e215048068a.tar.gz
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-daede/releases/download/daed-src

View File

@ -0,0 +1,19 @@
From: kenzok8 <kenzok8@noreply>
Date: 2026-06-30
Subject: [PATCH] daed: raise manual latency probe concurrency to 16
Raise concurrent probes 8->16 so manual latency tests finish faster
when many nodes (incl. dead/timeout ones) are present.
Reported: https://github.com/kenzok8/openwrt-daede/issues/20
---
--- a/graphql/service/node/latency_mutation_utils.go
+++ b/graphql/service/node/latency_mutation_utils.go
@@ -19,7 +19,7 @@
"github.com/sirupsen/logrus"
)
-const latencyProbeConcurrency = 8
+const latencyProbeConcurrency = 16
func TestLatencies(ctx context.Context, ids *[]graphql.ID) ([]*LatencyResolver, error) {
option, err := latencyProbeOption(ctx)

View File

@ -2,6 +2,7 @@
'require baseclass';
'require form';
'require fs';
'require dom';
'require rpc';
'require uci';
'require ui';
@ -495,6 +496,31 @@ const CBIDynamicList = form.DynamicList.extend({ // @less_25_12
}
});
const CBIMultiValue = form.MultiValue.extend({ // @pr8758_merged
__name__: 'CBI.MultiValue',
renderWidget(section_id, option_index, cfgvalue) {
const value = (cfgvalue != null) ? cfgvalue : this.default;
const choices = this.transformChoices();
const widget = new UIDropdown(L.toArray(value), choices, {
id: this.cbid(section_id),
sort: this.keylist,
multiple: true,
keep_order: this.keep_order,
optional: this.optional || this.rmempty,
select_placeholder: this.placeholder,
create: this.create,
display_items: this.display_size ?? this.size ?? 3,
dropdown_items: this.dropdown_size ?? this.size ?? -1,
validate: this.getValidator(section_id),
disabled: (this.readonly != null) ? this.readonly : this.map.readonly
});
return widget.render();
}
});
const CBIStaticList = form.DynamicList.extend({
__name__: 'CBI.StaticList',
@ -786,6 +812,360 @@ const UIDynamicList = ui.DynamicList.extend({ // @less_25_12
}
});
// keep selected order for multiple selection
const UIDropdown = ui.Dropdown.extend({ // @pr8758_merged
__init__(value, choices, options) {
if (typeof(choices) != 'object')
choices = {};
if (!Array.isArray(value))
this.values = (value != null && value != '') ? [ value ] : [];
else
this.values = value;
this.orderCounter = this.values.length;
this.choices = choices;
this.options = Object.assign({
sort: true,
multiple: Array.isArray(value),
keep_order: false,
optional: true,
select_placeholder: _('-- Please choose --'),
custom_placeholder: _('-- custom --'),
display_items: 3,
dropdown_items: -1,
create: false,
create_query: '.create-item-input',
create_template: 'script[type="item-template"]'
}, options);
},
render() {
const sb = E('div', {
'id': this.options.id,
'class': 'cbi-dropdown',
'multiple': this.options.multiple ? '' : null,
'keep_order': this.options.keep_order ? '' : null,
'optional': this.options.optional ? '' : null,
'disabled': this.options.disabled ? '' : null,
'tabindex': -1
}, E('ul'));
let keys = Object.keys(this.choices);
if (this.options.sort === true)
keys.sort(L.naturalCompare);
else if (Array.isArray(this.options.sort))
keys = this.options.sort;
if (this.options.create)
for (let i = 0; i < this.values.length; i++)
if (!this.choices.hasOwnProperty(this.values[i]))
keys.push(this.values[i]);
for (let i = 0; i < keys.length; i++) {
let label = this.choices[keys[i]];
if (dom.elem(label))
label = label.cloneNode(true);
sb.lastElementChild.appendChild(E('li', {
'data-value': keys[i],
'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null
}, [ label ?? keys[i] ]));
}
if (this.options.create) {
const createEl = E('input', {
'type': 'text',
'class': 'create-item-input',
'readonly': this.options.readonly ? '' : null,
'maxlength': this.options.maxlength,
'placeholder': this.options.custom_placeholder ?? this.options.placeholder,
'inputmode': 'text',
'enterkeyhint': 'done'
});
if (this.options.datatype || this.options.validate)
UI.prototype.addValidator(createEl, this.options.datatype ?? 'string',
true, this.options.validate, 'blur', 'keyup');
sb.lastElementChild.appendChild(E('li', { 'data-value': '-' }, createEl));
}
if (this.options.create_markup)
sb.appendChild(E('script', { type: 'item-template' },
this.options.create_markup));
return this.bind(sb);
},
bind(sb) {
const o = this.options;
o.multiple = sb.hasAttribute('multiple');
o.keep_order = sb.hasAttribute('keep_order');
o.optional = sb.hasAttribute('optional');
o.placeholder = sb.getAttribute('placeholder') ?? o.placeholder;
o.display_items = parseInt(sb.getAttribute('display-items') ?? o.display_items);
o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') ?? o.dropdown_items);
o.create_query = sb.getAttribute('item-create') ?? o.create_query;
o.create_template = sb.getAttribute('item-template') ?? o.create_template;
const ul = sb.querySelector('ul');
const more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···'));
sb.appendChild(E('span', { class: 'open', tabindex: -1 }, '▾'));
const canary = sb.appendChild(E('div'));
const create = sb.querySelector(this.options.create_query);
let ndisplay = this.options.display_items;
let n = 0;
if (this.options.multiple) {
let items = ul.querySelectorAll('li');
for (let i = 0; i < items.length; i++) {
this.transformItem(sb, items[i]);
if (items[i].hasAttribute('selected')) {
if (ndisplay-- > 0)
items[i].setAttribute('display', n++);
if (this.options.keep_order) {
const value = items[i].getAttribute('data-value');
if (this.values.includes(value))
items[i].setAttribute('data-order', this.values.indexOf(value) + 1);
}
}
}
}
else {
if (this.options.optional && !ul.querySelector('li[data-value=""]')) {
const placeholder = E('li', { placeholder: '' },
this.options.select_placeholder ?? this.options.placeholder);
ul.firstChild
? ul.insertBefore(placeholder, ul.firstChild)
: ul.appendChild(placeholder);
}
let items = ul.querySelectorAll('li');
const sel = sb.querySelectorAll('[selected]');
sel.forEach(s => {
s.removeAttribute('selected');
});
const s = sel[0] ?? items[0];
if (s) {
s.setAttribute('selected', '');
s.setAttribute('display', n++);
}
ndisplay--;
}
this.saveValues(sb, ul);
ul.setAttribute('tabindex', -1);
sb.setAttribute('tabindex', 0);
if (ndisplay < 0)
sb.setAttribute('more', '')
else
sb.removeAttribute('more');
if (ndisplay == this.options.display_items)
sb.setAttribute('empty', '')
else
sb.removeAttribute('empty');
dom.content(more, (ndisplay == this.options.display_items)
? (this.options.select_placeholder ?? this.options.placeholder) : '···');
sb.addEventListener('click', this.handleClick.bind(this));
sb.addEventListener('keydown', this.handleKeydown.bind(this));
sb.addEventListener('cbi-dropdown-close', this.handleDropdownClose.bind(this));
sb.addEventListener('cbi-dropdown-select', this.handleDropdownSelect.bind(this));
if ('ontouchstart' in window) {
sb.addEventListener('touchstart', ev => ev.stopPropagation());
window.addEventListener('touchstart', this.closeAllDropdowns);
}
else {
sb.addEventListener('focus', this.handleFocus.bind(this));
canary.addEventListener('focus', this.handleCanaryFocus.bind(this));
window.addEventListener('click', this.closeAllDropdowns);
}
if (create) {
create.addEventListener('keydown', this.handleCreateKeydown.bind(this));
create.addEventListener('focus', this.handleCreateFocus.bind(this));
create.addEventListener('blur', this.handleCreateBlur.bind(this));
const li = findParent(create, 'li');
li.setAttribute('unselectable', '');
li.addEventListener('click', this.handleCreateClick.bind(this));
}
this.node = sb;
this.setUpdateEvents(sb, 'cbi-dropdown-open', 'cbi-dropdown-close');
this.setChangeEvents(sb, 'cbi-dropdown-change', 'cbi-dropdown-close');
dom.bindClassInstance(sb, this);
return sb;
},
toggleItem(sb, li, force_state) {
const ul = li.parentNode;
if (li.hasAttribute('unselectable'))
return;
if (this.options.multiple) {
const cbox = li.querySelector('input[type="checkbox"]');
const items = li.parentNode.querySelectorAll('li');
const label = sb.querySelector('ul.preview');
let sel = li.parentNode.querySelectorAll('[selected]').length;
const more = sb.querySelector('.more');
let ndisplay = this.options.display_items;
let n = 0;
if (li.hasAttribute('selected')) {
if (force_state !== true) {
if (sel > 1 || this.options.optional) {
li.removeAttribute('selected');
cbox.checked = cbox.disabled = false;
sel--;
if (this.options.keep_order)
li.removeAttribute('data-order');
}
else {
cbox.disabled = true;
}
}
}
else {
if (force_state !== false) {
li.setAttribute('selected', '');
cbox.checked = true;
cbox.disabled = false;
sel++;
if (this.options.keep_order)
li.setAttribute('data-order', ++this.orderCounter);
}
}
while (label && label.firstElementChild)
label.removeChild(label.firstElementChild);
for (let i = 0; i < items.length; i++) {
items[i].removeAttribute('display');
if (items[i].hasAttribute('selected')) {
if (ndisplay-- > 0) {
items[i].setAttribute('display', n++);
if (label)
label.appendChild(items[i].cloneNode(true));
}
const c = items[i].querySelector('input[type="checkbox"]');
if (c)
c.disabled = (sel == 1 && !this.options.optional);
}
}
if (ndisplay < 0)
sb.setAttribute('more', '');
else
sb.removeAttribute('more');
if (ndisplay === this.options.display_items)
sb.setAttribute('empty', '');
else
sb.removeAttribute('empty');
dom.content(more, (ndisplay === this.options.display_items)
? (this.options.select_placeholder ?? this.options.placeholder) : '···');
}
else {
let sel = li.parentNode.querySelector('[selected]');
if (sel) {
sel.removeAttribute('display');
sel.removeAttribute('selected');
}
li.setAttribute('display', 0);
li.setAttribute('selected', '');
this.closeDropdown(sb);
}
this.saveValues(sb, ul);
},
saveValues(sb, ul) {
const sel = Array.from(ul.querySelectorAll('li[selected]'));
const div = sb.lastElementChild;
const name = this.options.name;
let strval = '';
const values = [];
if (this.options.keep_order) {
sel.sort((a, b) =>
(+a.getAttribute('data-order') || 0) -
(+b.getAttribute('data-order') || 0)
);
}
while (div.lastElementChild)
div.removeChild(div.lastElementChild);
sel.forEach(s => {
if (s.hasAttribute('placeholder'))
return;
const v = {
text: s.innerText,
value: s.hasAttribute('data-value') ? s.getAttribute('data-value') : s.innerText,
element: s
};
div.appendChild(E('input', {
type: 'hidden',
name: name,
value: v.value
}));
values.push(v);
strval += strval.length ? ` ${v.value}` : v.value;
});
const detail = {
instance: this,
element: sb
};
if (this.options.multiple)
detail.values = values;
else
detail.value = values.length ? values[0] : null;
sb.value = strval;
sb.dispatchEvent(new CustomEvent('cbi-dropdown-change', {
bubbles: true,
detail: detail
}));
}
});
/* Method */
/* thanks to homeproxy */
function calcStringMD5(e) {
@ -1114,109 +1494,80 @@ function loadModalTitle(title, addtitle, section_id) {
return label ? title + ' » ' + label : addtitle;
}
function loadProxyGroupLabel(preadds, section_id) {
function loadLabel(preadds, section_id) {
delete this.keylist;
delete this.vallist;
preadds?.forEach((arr) => {
this.value.apply(this, arr);
});
uci.sections(this.config, 'proxy_group', (res) => {
if (res.enabled !== '0')
this.value(res['.name'], res.label);
});
for (const arr of preadds || [])
this.value(...arr);
return this.super('load', section_id);
}
function loadNodeLabel(preadds, section_id) {
delete this.keylist;
delete this.vallist;
function loadLabelValues(uciconfig, sectiontype, options = {}) {
const values = [];
preadds?.forEach((arr) => {
this.value.apply(this, arr);
});
uci.sections(this.config, 'node', (res) => {
if (res.enabled !== '0')
this.value(res['.name'], res.label);
});
switch (sectiontype) {
case 'proxy_group':
case 'node':
case 'provider':
uci.sections(uciconfig, sectiontype, (res) => {
if (res.enabled !== '0')
values.push([res['.name'], res.label]);
});
break;
case 'ruleset':
uci.sections(uciconfig, sectiontype, (res) => {
if (
res.enabled !== '0' &&
(!options.behaviors ||
options.behaviors.includes(res.behavior))
) {
values.push([res['.name'], res.label]);
}
});
break;
case 'subrule-group': {
const groups = new Set();
return this.super('load', section_id);
}
uci.sections(uciconfig, 'subrules', (res) => {
if (res.enabled !== '0')
groups.add(res.group);
});
function loadProviderLabel(preadds, section_id) {
delete this.keylist;
delete this.vallist;
for (const group of groups)
values.push([group, group]);
break;
}
case 'rematch-name': {
const names = new Set();
preadds?.forEach((arr) => {
this.value.apply(this, arr);
});
uci.sections(this.config, 'provider', (res) => {
if (res.enabled !== '0')
this.value(res['.name'], res.label);
});
for (const type of ['rules', 'subrules']) {
uci.sections(uciconfig, type, (res) => {
if (res.enabled === '0')
return;
return this.super('load', section_id);
}
try {
const payload =
JSON.parse(res?.entry?.trim() || '{}').payload || [];
function loadRulesetLabel(preadds, behaviors, section_id) {
delete this.keylist;
delete this.vallist;
for (const p of payload)
if (p.type === 'REMATCH-NAME')
names.add(p.factor);
} catch {}
});
}
preadds?.forEach((arr) => {
this.value.apply(this, arr);
});
uci.sections(this.config, 'ruleset', (res) => {
if (res.enabled !== '0')
if (behaviors ? behaviors.includes(res.behavior) : true)
this.value(res['.name'], res.label);
});
for (const name of names)
values.push([name, name]);
return this.super('load', section_id);
}
break;
}
default:
break;
}
function loadSubRuleGroup(preadds, section_id) {
delete this.keylist;
delete this.vallist;
preadds?.forEach((arr) => {
this.value.apply(this, arr);
});
let groups = {};
uci.sections(this.config, 'subrules', (res) => {
if (res.enabled !== '0')
groups[res.group] = res.group;
});
Object.keys(groups).forEach((group) => {
this.value(group, group);
});
return this.super('load', section_id);
}
function loadRematchName(preadds, section_id) {
delete this.keylist;
delete this.vallist;
preadds?.forEach((arr) => {
this.value.apply(this, arr);
});
let names = {};
for (const section_type of ['rules', 'subrules'])
uci.sections(this.config, section_type, (res) => {
if (res.enabled !== '0')
try {
const obj = JSON.parse(res?.entry?.trim() || '{}');
for (const p of obj.payload || [])
if (p.type === 'REMATCH-NAME')
names[p.factor] = p.factor;
} catch {}
});
Object.keys(names).forEach((name) => {
this.value(name, name);
});
return this.super('load', section_id);
return values;
}
function renderStatus(ElId, isRunning, instance, noGlobal) {
@ -1790,6 +2141,7 @@ return baseclass.extend({
/* Prototype */
GridSection: CBIGridSection,
DynamicList: CBIDynamicList,
MultiValue: CBIMultiValue,
StaticList: CBIStaticList,
ListValue: CBIListValue,
RichValue: CBIRichValue,
@ -1819,12 +2171,8 @@ return baseclass.extend({
// load
loadDefaultLabel,
loadModalTitle,
loadProxyGroupLabel,
loadNodeLabel,
loadProviderLabel,
loadRulesetLabel,
loadSubRuleGroup,
loadRematchName,
loadLabel,
loadLabelValues,
// render
renderStatus,
updateStatus,

View File

@ -609,7 +609,12 @@ function renderListeners(s, uciconfig, isClient) {
o = s.taboption('field_general', hm.ListValue, 'rule', _('Sub rule'),
_('Name of the Sub rule used for inbound matching.'));
o.value.apply(o, ['', _('null')]);
o.load = L.bind(hm.loadSubRuleGroup, o, [['', _('null')]]);
o.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('null')],
...hm.loadLabelValues(this.config, 'subrule-group')
], section_id);
}
o.editable = true;
o = s.taboption('field_general', hm.ListValue, 'proxy', _('Proxy group'),
@ -618,7 +623,12 @@ function renderListeners(s, uciconfig, isClient) {
hm.preset_outbound.direct.forEach((res) => {
o.value.apply(o, res);
})
o.load = L.bind(hm.loadProxyGroupLabel, o, hm.preset_outbound.direct);
o.load = function(section_id) {
return hm.loadLabel.call(this, [
...hm.preset_outbound.direct,
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
}
o.editable = true;
}

View File

@ -18,12 +18,12 @@ const parseProxyGroupYaml = hm.parseYaml.extend({
id: this.id,
label: this.label,
type: cfg.type,
groups: cfg.proxies ? cfg.proxies.map((grop) => hm.preset_outbound.full.map(([key, label]) => key).includes(grop) ? grop : this.calcID(hm.glossary["proxy_group"].field, grop)) : null, // array
groups: cfg.proxies ? cfg.proxies.map((grop) => hm.preset_outbound.proxy.map(([key, label]) => key).includes(grop) ? grop : this.calcID(hm.glossary["proxy_group"].field, grop)) : null, // array
use: cfg.use ? cfg.use.map((prov) => this.calcID(hm.glossary["provider"].field, prov)) : null, // array
include_all: this.bool2str(cfg["include-all"]), // bool
include_all_proxies: this.bool2str(cfg["include-all-proxies"]), // bool
include_all_providers: this.bool2str(cfg["include-all-providers"]), // bool
empty_fallback: cfg["empty-fallback"] ? hm.preset_outbound.full.map(([key, label]) => key).includes(cfg["empty-fallback"]) ? cfg["empty-fallback"] : this.calcID(hm.glossary["proxy_group"].field, cfg["empty-fallback"]) : null, // string
empty_fallback: cfg["empty-fallback"] ? hm.preset_outbound.proxy.map(([key, label]) => key).includes(cfg["empty-fallback"]) ? cfg["empty-fallback"] : this.calcID(hm.glossary["proxy_group"].field, cfg["empty-fallback"]) : null, // string
// Url-test fields
tolerance: cfg.tolerance,
// Load-balance fields
@ -255,7 +255,7 @@ const parseDNSYaml = hm.parseYaml.extend({
let detour = addr.parseParam('detour');
if (detour)
addr.setParam('detour', hm.preset_outbound.full.map(([key, label]) => key).includes(detour) ? detour : this.calcID(hm.glossary["proxy_group"].field, detour));
addr.setParam('detour', hm.preset_outbound.dns.map(([key, label]) => key).includes(detour) ? detour : detour === 'RULES' ? '' : this.calcID(hm.glossary["proxy_group"].field, detour));
// key mapping // 2026/01/17
let config = {
@ -614,7 +614,7 @@ function renderPayload(s, total, uciconfig) {
o.depends(prefix + 'type', 'RULE-SET');
initPayload(o, n, 'factor', uciconfig);
o.load = L.bind(function(n, key, uciconfig, section_id) {
hm.loadRulesetLabel.call(this, [], null, section_id);
hm.loadLabel.call(this, hm.loadLabelValues(this.config, 'ruleset'), section_id);
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayload(n)[key];
}, o, n, 'factor', uciconfig)
@ -688,8 +688,11 @@ function renderPayload(s, total, uciconfig) {
['tcp', _('TCP')],
['RULESET', '-- RULE-SET --']
];
hm.loadRulesetLabel.call(this, fusedval, null, section_id);
this.super('load', section_id);
hm.loadLabel.call(this, [
...fusedval,
...hm.loadLabelValues(this.config, 'ruleset')
], section_id);
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).getPayloads().slice(n).map(e => e[key] ?? '');
}, o, n, 'factor', uciconfig)
@ -791,7 +794,10 @@ function renderRules(s, uciconfig) {
o = s.option(hm.ListValue, 'detour', _('Proxy group'));
o.load = function(section_id) {
hm.loadProxyGroupLabel.call(this, hm.preset_outbound.full, section_id);
hm.loadLabel.call(this, [
...hm.preset_outbound.full,
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
return new RulesEntry(uci.get(uciconfig, section_id, 'entry')).detour;
}
@ -867,7 +873,12 @@ function renderPolicies(s, uciconfig) {
o = s.option(form.MultiValue, 'rule_set', _('Rule set'),
_('Match rule set.'));
o.value('', _('-- Please choose --'));
o.load = L.bind(hm.loadRulesetLabel, o, [['', _('-- Please choose --')]], ['domain', 'classical']);
o.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'ruleset', {behaviors: ['domain', 'classical']})
], section_id);
}
o.depends('type', 'rule_set');
o.modalonly = true;
@ -893,7 +904,12 @@ function renderPolicies(s, uciconfig) {
hm.preset_outbound.direct.forEach((res) => {
o.value.apply(o, res);
})
o.load = L.bind(hm.loadProxyGroupLabel, o, hm.preset_outbound.direct);
o.load = function(section_id) {
return hm.loadLabel.call(this, [
...hm.preset_outbound.direct,
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
}
o.editable = true;
}
@ -1041,16 +1057,28 @@ return view.extend({
so.value.apply(so, res);
})
so = ss.taboption('field_general', form.MultiValue, 'groups', _('Group'));
hm.preset_outbound.full.forEach((res) => {
so = ss.taboption('field_general', hm.MultiValue, 'groups', _('Group')); // @pr8758_merged
hm.preset_outbound.proxy.forEach((res) => {
so.value.apply(so, res);
})
so.load = L.bind(hm.loadProxyGroupLabel, so, hm.preset_outbound.full);
so.keep_order = true;
so.load = function(section_id) {
return hm.loadLabel.call(this, [
...hm.preset_outbound.proxy,
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
}
so.editable = true;
so = ss.taboption('field_general', form.MultiValue, 'proxies', _('Node'));
so = ss.taboption('field_general', hm.MultiValue, 'proxies', _('Node')); // @pr8758_merged
so.value('', _('-- Please choose --'));
so.load = L.bind(hm.loadNodeLabel, so, [['', _('-- Please choose --')]]);
so.keep_order = true;
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'node')
], section_id);
}
so.validate = function(section_id, value) {
if (this.section.getOption('include_all').formvalue(section_id) === '1' ||
this.section.getOption('include_all_proxies').formvalue(section_id) === '1')
@ -1062,9 +1090,15 @@ return view.extend({
}
so.editable = true;
so = ss.taboption('field_general', form.MultiValue, 'use', _('Provider'));
so = ss.taboption('field_general', hm.MultiValue, 'use', _('Provider')); // @pr8758_merged
so.value('', _('-- Please choose --'));
so.load = L.bind(hm.loadProviderLabel, so, [['', _('-- Please choose --')]]);
so.keep_order = true;
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'provider')
], section_id);
}
so.validate = function(section_id, value) {
if (this.section.getOption('include_all').formvalue(section_id) === '1' ||
this.section.getOption('include_all_providers').formvalue(section_id) === '1')
@ -1096,8 +1130,13 @@ return view.extend({
hm.preset_outbound.proxy.forEach((res) => {
so.value.apply(so, res);
})
so.load = L.bind(hm.loadNodeLabel, so, hm.preset_outbound.proxy);
so.modalonly = true;
so.load = function(section_id) {
return hm.loadLabel.call(this, [
...hm.preset_outbound.proxy,
...hm.loadLabelValues(this.config, 'node')
], section_id);
}
so.textvalue = hm.textvalue2Value;
/* Override fields */
so = ss.taboption('field_override', form.Flag, 'disable_udp', _('Disable UDP'));
@ -1293,7 +1332,10 @@ return view.extend({
so = ss.option(form.ListValue, 'SUB-RULE', _('SUB-RULE'));
so.load = function(section_id) {
hm.loadSubRuleGroup.call(this, [['', _('-- Please choose --')]], section_id);
hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'subrule-group')
], section_id);
return new RulesEntry(uci.get(data[0], section_id, 'entry')).subrule || '';
}
@ -1563,7 +1605,10 @@ return view.extend({
so = ss.option(hm.ListValue, 'detour', _('Proxy group'));
so.load = function(section_id) {
hm.loadProxyGroupLabel.call(this, hm.preset_outbound.dns, section_id);
hm.loadLabel.call(this, [
...hm.preset_outbound.dns,
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
return new DNSAddress(uci.get(data[0], section_id, 'address')).parseParam('detour');
}

View File

@ -28,7 +28,7 @@ const CBIBubblesValue = form.DummyValue.extend({
__name__: 'CBI.BubblesValue',
load(section_id) {
const uciconfig = this.config || this.section.configthis.config || this.map.config;
const uciconfig = this.config || this.section.config || this.map.config;
const type = uci.get(uciconfig, section_id, 'type');
const detour = uci.get(uciconfig, section_id, 'chain_tail_group') || uci.get(uciconfig, section_id, 'chain_tail');
@ -116,7 +116,7 @@ const parseProviderYaml = hm.parseYaml.extend({
url: cfg.url,
size_limit: cfg["size-limit"],
interval: cfg.interval,
proxy: cfg.proxy ? hm.preset_outbound.full.map(([key, label]) => key).includes(cfg.proxy) ? cfg.proxy : this.calcID(hm.glossary["proxy_group"].field, cfg.proxy) : null,
proxy: cfg.proxy ? hm.preset_outbound.direct.map(([key, label]) => key).includes(cfg.proxy) ? cfg.proxy : this.calcID(hm.glossary["proxy_group"].field, cfg.proxy) : null,
age_private_key: cfg["age-secret-key"],
header: cfg.header ? JSON.stringify(cfg.header, null, 2) : null, // string: object
/* Health fields */
@ -265,13 +265,23 @@ return view.extend({
/* Rematch fields */
so = ss.taboption('field_general', form.ListValue, 'target_rematch_name', _('REMATCH-NAME marking'));
so.load = L.bind(hm.loadRematchName, so, [['', _('-- Please choose --')]]);
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'rematch-name')
], section_id);
}
so.rmempty = false;
so.depends('type', 'rematch');
so.modalonly = true;
so = ss.taboption('field_general', form.ListValue, 'target_sub_rule', _('Use sub rule'));
so.load = L.bind(hm.loadSubRuleGroup, so, [['', _('-- Please choose --')]]);
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'subrule-group')
], section_id);
}
so.depends('type', 'rematch');
so.modalonly = true;
@ -1750,7 +1760,12 @@ return view.extend({
hm.preset_outbound.direct.forEach((res) => {
so.value.apply(so, res);
})
so.load = L.bind(hm.loadProxyGroupLabel, so, hm.preset_outbound.direct);
so.load = function(section_id) {
return hm.loadLabel.call(this, [
...hm.preset_outbound.direct,
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
}
so.textvalue = hm.textvalue2Value;
//so.editable = true;
so.depends('type', 'http');
@ -2032,13 +2047,23 @@ return view.extend({
so.modalonly = false;
so = ss.option(form.ListValue, 'chain_head_sub', _('Destination provider'));
so.load = L.bind(hm.loadProviderLabel, so, [['', _('-- Please choose --')]]);
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'provider')
], section_id);
}
so.rmempty = false;
so.depends('type', 'provider');
so.modalonly = true;
so = ss.option(form.ListValue, 'chain_head', _('Destination proxy node'));
so.load = L.bind(hm.loadNodeLabel, so, [['', _('-- Please choose --')]]);
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'node')
], section_id);
}
so.rmempty = false;
so.validate = function(section_id, value) {
const chain_tail = this.section.getUIElement(section_id, 'chain_tail').getValue();
@ -2052,13 +2077,23 @@ return view.extend({
so.modalonly = true;
so = ss.option(form.ListValue, 'chain_tail_group', _('Transit proxy group'));
so.load = L.bind(hm.loadProxyGroupLabel, so, [['', _('-- Please choose --')]]);
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
}
so.rmempty = false;
so.depends({chain_tail: /.+/, '!reverse': true});
so.modalonly = true;
so = ss.option(form.ListValue, 'chain_tail', _('Transit proxy node'));
so.load = L.bind(hm.loadNodeLabel, so, [['', _('-- Please choose --')]]);
so.load = function(section_id) {
return hm.loadLabel.call(this, [
['', _('-- Please choose --')],
...hm.loadLabelValues(this.config, 'node')
], section_id);
}
so.rmempty = false;
so.validate = function(section_id, value) {
const chain_head = this.section.getUIElement(section_id, 'chain_head').getValue();

View File

@ -25,7 +25,7 @@ const parseRulesetYaml = hm.parseYaml.extend({
path_in_bundle: cfg["path-in-bundle"],
size_limit: cfg["size-limit"],
interval: cfg.interval,
proxy: cfg.proxy ? hm.preset_outbound.full.map(([key, label]) => key).includes(cfg.proxy) ? cfg.proxy : this.calcID(hm.glossary["proxy_group"].field, cfg.proxy) : null,
proxy: cfg.proxy ? hm.preset_outbound.direct.map(([key, label]) => key).includes(cfg.proxy) ? cfg.proxy : this.calcID(hm.glossary["proxy_group"].field, cfg.proxy) : null,
header: cfg.header ? JSON.stringify(cfg.header, null, 2) : null, // string: object
})
});
@ -406,7 +406,12 @@ return view.extend({
hm.preset_outbound.direct.forEach((res) => {
o.value.apply(o, res);
})
o.load = L.bind(hm.loadProxyGroupLabel, o, hm.preset_outbound.direct);
o.load = function(section_id) {
return hm.loadLabel.call(this, [
...hm.preset_outbound.direct,
...hm.loadLabelValues(this.config, 'proxy_group')
], section_id);
}
o.textvalue = hm.textvalue2Value;
//o.editable = true;
o.depends('type', 'http');

View File

@ -7,8 +7,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall
PKG_VERSION:=26.6.2
PKG_RELEASE:=170
PKG_VERSION:=26.7.1
PKG_RELEASE:=171
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \

View File

@ -829,8 +829,19 @@ update_wan_sets() {
}
}
set_tproxy_sysctl() {
# Disable IPv4 rp_filter for TPROXY compatibility.
sysctl -w net.ipv4.conf.all.rp_filter=0 >/dev/null 2>&1
sysctl -w net.ipv4.conf.default.rp_filter=0 >/dev/null 2>&1
local f
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
echo 0 > "$f" 2>/dev/null
done
}
add_firewall_rule() {
echolog "开始加载 iptables 防火墙规则..."
set_tproxy_sysctl
ipset -! create $IPSET_LOCAL nethash maxelem 1048576
ipset -! create $IPSET_WAN nethash maxelem 1048576
ipset -! create $IPSET_LAN nethash maxelem 1048576

View File

@ -891,11 +891,22 @@ update_wan_sets() {
}
}
set_tproxy_sysctl() {
# Disable IPv4 rp_filter for TPROXY compatibility.
sysctl -w net.ipv4.conf.all.rp_filter=0 >/dev/null 2>&1
sysctl -w net.ipv4.conf.default.rp_filter=0 >/dev/null 2>&1
local f
for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
echo 0 > "$f" 2>/dev/null
done
}
add_firewall_rule() {
echolog "开始加载 nftables 防火墙规则..."
gen_nft_tables
add_script_mwan3
mwan3_start
set_tproxy_sysctl
gen_nftset $NFTSET_WAN ipv4_addr 0 "-1"
gen_nftset $NFTSET_VPS ipv4_addr 0 "-1"
gen_nftset $NFTSET_GFW ipv4_addr "2d" 0

View File

@ -4,7 +4,7 @@ LUCI_TITLE:=luci-app-ssr-plus
LUCI_PKGARCH:=all
PKG_NAME:=luci-app-ssr-plus
PKG_VERSION:=196
PKG_RELEASE:=35
PKG_RELEASE:=36
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \

View File

@ -840,7 +840,6 @@ local function build_v2ray_mihomo_proxy(sid)
proxy.down = string_or_nil(get_server_field(sid, "downlink_capacity", "")) and (get_server_field(sid, "downlink_capacity", "") .. " Mbps") or nil
proxy.sni = string_or_nil(get_server_field(sid, "tls_host", ""))
proxy.fingerprint = string_or_nil(get_server_field(sid, "tls_CertSha", ""))
proxy["cert-name"] = string_or_nil(get_server_field(sid, "tls_CertByName", ""))
proxy["skip-cert-verify"] = bool_enabled(get_server_field(sid, "insecure", "0"))
local alpn = split_alpn(get_server_field(sid, "tls_alpn", ""))
if #alpn > 0 then

View File

@ -5,8 +5,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=smartdns
PKG_VERSION:=48
PKG_RELEASE:=3
PKG_VERSION:=48.2
PKG_RELEASE:=4
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/pymumu/smartdns/tar.gz/Release$(PKG_VERSION)?
@ -29,7 +29,7 @@ include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/rust/rust-package.mk
MAKE_PATH:=src
MAKE_VARS+= VER=$(PKG_VERSION)
MAKE_VARS+= VER=$(PKG_VERSION) WITH_ZLIB=0
define Package/smartdns/Default
SECTION:=net
@ -104,6 +104,7 @@ ifneq ($(CONFIG_PACKAGE_smartdns-ui),)
pushd plugin/smartdns-ui ; \
$(CARGO_PKG_CONFIG_VARS) \
MAKEFLAGS="$(PKG_JOBS)" \
WITH_ZLIB=0 \
TARGET_CFLAGS="$(filter-out -O%,$(TARGET_CFLAGS)) $(RUSTC_CFLAGS)" \
BINDGEN_EXTRA_CLANG_ARGS="--sysroot=$(TOOLCHAIN_ROOT_DIR)" \
cargo build -v --profile $(CARGO_PKG_PROFILE) \

View File

@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=torrserver
PKG_VERSION:=MatriX.141.9
PKG_RELEASE:=10
PKG_VERSION:=MatriX.141.10
PKG_RELEASE:=11
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://github.com/YouROK/TorrServer.git
PKG_SOURCE_VERSION:=9ba8f2a8a37869eda85eb2f1deaac71e89a183af
PKG_SOURCE_VERSION:=394c915bfc64c8448a7da166e909da074420172e
PKG_MIRROR_HASH:=skip
PKG_MAINTAINER:=Konstantine Shevlakov <shevlakov@132lan.ru>