mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-05 09:54:06 +08:00
567 lines
22 KiB
JavaScript
567 lines
22 KiB
JavaScript
/*
|
|
* SPDX-License-Identifier: GPL-2.0-only
|
|
*
|
|
* Copyright (C) 2022-2025 ImmortalWrt.org
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
'require baseclass';
|
|
'require form';
|
|
'require uci';
|
|
|
|
'require homeproxy-pro as hp';
|
|
|
|
/* Build the shared body of a routing/dns rule section. The two sections
|
|
* differ in their tab/option names, the sniffed-protocol value list, the
|
|
* order of the protocol/network/query-type triplet, a handful of
|
|
* descriptions and their action-specific field sets; everything else is
|
|
* emitted identically. */
|
|
function renderRuleSection(s, kind, self) {
|
|
let o, ss, so;
|
|
let is_dns = (kind === 'dns');
|
|
let uci_type = is_dns ? 'dns_rule' : 'routing_rule';
|
|
|
|
s.tab(uci_type, is_dns ? _('DNS Rules') : _('Routing Rules'));
|
|
o = s.taboption(uci_type, form.SectionValue, '_' + uci_type, form.GridSection, uci_type);
|
|
o.depends('routing_mode', 'custom');
|
|
|
|
ss = o.subsection;
|
|
ss.addremove = true;
|
|
ss.rowcolors = true;
|
|
ss.sortable = true;
|
|
ss.nodescriptions = true;
|
|
ss.modaltitle = L.bind(hp.loadModalTitle, hp, is_dns ? _('DNS rule') : _('Routing rule'),
|
|
is_dns ? _('Add a DNS rule') : _('Add a routing rule'), 'homeproxy-pro');
|
|
ss.sectiontitle = L.bind(hp.loadDefaultLabel, self, 'homeproxy-pro');
|
|
/* Plain wrapper, not L.bind(): see hp.renderSectionAdd() for why the bound
|
|
* form hands a call site's button factory to the wrong argument. */
|
|
ss.renderSectionAdd = function(extra_class) {
|
|
return hp.renderSectionAdd(ss, extra_class);
|
|
};
|
|
|
|
ss.tab('field_other', _('Other fields'));
|
|
ss.tab('field_host', _('Host/IP fields'));
|
|
ss.tab('field_port', _('Port fields'));
|
|
ss.tab('fields_process', _('Process fields'));
|
|
|
|
so = ss.taboption('field_other', form.Value, 'label', _('Label'));
|
|
so.load = L.bind(hp.loadDefaultLabel, self, 'homeproxy-pro');
|
|
so.validate = L.bind(hp.validateUniqueValue, self, 'homeproxy-pro', uci_type, 'label');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'enabled', _('Enable'));
|
|
so.default = so.enabled;
|
|
so.rmempty = false;
|
|
so.editable = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'mode', _('Mode'),
|
|
is_dns ? _('The default rule uses the following matching logic:<br/>' +
|
|
'<code>(domain || domain_suffix || domain_keyword || domain_regex)</code> &&<br/>' +
|
|
'<code>(port || port_range)</code> &&<br/>' +
|
|
'<code>(source_ip_cidr || source_ip_is_private)</code> &&<br/>' +
|
|
'<code>(source_port || source_port_range)</code> &&<br/>' +
|
|
'<code>other fields</code>.<br/>' +
|
|
'Additionally, included rule sets can be considered merged rather than as a single rule sub-item.') :
|
|
_('The default rule uses the following matching logic:<br/>' +
|
|
'<code>(domain || domain_suffix || domain_keyword || domain_regex || ip_cidr || ip_is_private)</code> &&<br/>' +
|
|
'<code>(port || port_range)</code> &&<br/>' +
|
|
'<code>(source_ip_cidr || source_ip_is_private)</code> &&<br/>' +
|
|
'<code>(source_port || source_port_range)</code> &&<br/>' +
|
|
'<code>other fields</code>.<br/>' +
|
|
'Additionally, included rule sets can be considered merged rather than as a single rule sub-item.'));
|
|
so.value('default', _('Default'));
|
|
so.default = 'default';
|
|
so.rmempty = false;
|
|
so.readonly = true;
|
|
if (is_dns)
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'ip_version', _('IP version'),
|
|
is_dns ? null : _('4 or 6. Not limited if empty.'));
|
|
so.value('4', _('IPv4'));
|
|
so.value('6', _('IPv6'));
|
|
so.value('', _('Both'));
|
|
so.modalonly = true;
|
|
|
|
function addSniffedProtocol() {
|
|
let opt = ss.taboption('field_other', form.MultiValue, 'protocol', _('Protocol'),
|
|
_('Sniffed protocol, see <a target="_blank" href="https://sing-box.sagernet.org/configuration/route/sniff/">Sniff</a> for details.'));
|
|
opt.value('bittorrent', _('BitTorrent'));
|
|
if (!is_dns)
|
|
opt.value('dns', _('DNS'));
|
|
opt.value('dtls', _('DTLS'));
|
|
opt.value('http', _('HTTP'));
|
|
opt.value('quic', _('QUIC'));
|
|
opt.value('rdp', _('RDP'));
|
|
opt.value('ssh', _('SSH'));
|
|
opt.value('stun', _('STUN'));
|
|
opt.value('tls', _('TLS'));
|
|
|
|
return opt;
|
|
}
|
|
|
|
function addNetwork() {
|
|
let opt = ss.taboption('field_other', form.ListValue, 'network', _('Network'));
|
|
opt.value('tcp', _('TCP'));
|
|
opt.value('udp', _('UDP'));
|
|
opt.value('', _('Both'));
|
|
|
|
return opt;
|
|
}
|
|
|
|
if (is_dns) {
|
|
so = ss.taboption('field_other', form.DynamicList, 'query_type', _('Query type'),
|
|
_('Match query type.'));
|
|
so.modalonly = true;
|
|
|
|
so = addNetwork();
|
|
so = addSniffedProtocol();
|
|
} else {
|
|
so = addSniffedProtocol();
|
|
|
|
so = ss.taboption('field_other', form.Value, 'client', _('Client'),
|
|
_('Sniffed client type (QUIC client type or SSH client name).'));
|
|
so.value('chromium', _('Chromium / Cronet'));
|
|
so.value('firefox', _('Firefox / uquic firefox'));
|
|
so.value('quic-go', _('quic-go / uquic chrome'));
|
|
so.value('safari', _('Safari / Apple Network API'));
|
|
so.depends('protocol', 'quic');
|
|
so.depends('protocol', 'ssh');
|
|
so.modalonly = true;
|
|
|
|
so = addNetwork();
|
|
}
|
|
|
|
so = ss.taboption('field_other', form.DynamicList, 'user', _('User'),
|
|
_('Match user name.'));
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', hp.CBIStaticList, 'rule_set', _('Rule set'),
|
|
is_dns ? _('Match rule set. DNS: rules referencing rule-sets that contain query_type are incompatible with legacy address filters (ip_cidr / ip_is_private) — use match_response instead (1.14).') :
|
|
_('Match rule set. Since 1.14: a rule-set holding a single default rule is merged into this rule; any other rule-set matches as an OR collection.'));
|
|
so.load = function(section_id) {
|
|
delete this.keylist;
|
|
delete this.vallist;
|
|
|
|
uci.sections('homeproxy-pro', 'ruleset', (res) => {
|
|
if (res.enabled === '1')
|
|
this.value(res['.name'], res.label);
|
|
});
|
|
|
|
return this.super('load', section_id);
|
|
}
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'rule_set_ip_cidr_match_source', _('Rule set IP CIDR as source IP'),
|
|
is_dns ? _('Make IP CIDR in rule sets match the source IP.') : _('Make IP CIDR in rule set used to match the source IP.'));
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'invert', _('Invert'),
|
|
_('Invert match result.'));
|
|
so.modalonly = true;
|
|
|
|
/* Action options are split by which schema they belong to:
|
|
* dns_rule actions: route, reject, predefined, evaluate (1.14 only)
|
|
* routing_rule actions: route, route-options, reject, resolve, hijack/sniff
|
|
* (sniff/hijack are emitted by the proxy-mode builder,
|
|
* not exposed in the form).
|
|
*
|
|
* `route-options` is a routing_rule-only action: sing-box 1.14's dns_rule
|
|
* schema has no such action, and emitting it would make the whole dns block
|
|
* fail with "unknown action". Earlier code added it to both branches and
|
|
* the depends() guards for dns_disable_cache / rewrite_ttl / client_subnet
|
|
* pinned a stale 'route-options' in the UCI that resurfaced as "unknown
|
|
* field" the next time the user flipped back to 'route'. */
|
|
so = ss.taboption('field_other', form.ListValue, 'action', _('Action'));
|
|
so.value('route', _('Route'));
|
|
so.value('reject', _('Reject'));
|
|
if (is_dns) {
|
|
so.value('predefined', _('Predefined'));
|
|
so.value('evaluate', _('Evaluate (1.14)'));
|
|
} else {
|
|
so.value('route-options', _('Route options'));
|
|
so.value('resolve', _('Resolve'));
|
|
}
|
|
so.default = 'route';
|
|
so.rmempty = false;
|
|
so.editable = true;
|
|
|
|
if (is_dns) {
|
|
so = ss.taboption('field_other', form.ListValue, 'server', _('Server'),
|
|
_('Tag of the target dns server.'));
|
|
so.load = function(section_id) {
|
|
delete this.keylist;
|
|
delete this.vallist;
|
|
|
|
this.value('default-dns', _('Default DNS (issued by WAN)'));
|
|
this.value('system-dns', _('System DNS'));
|
|
uci.sections('homeproxy-pro', 'dns_server', (res) => {
|
|
if (res.enabled === '1')
|
|
this.value(res['.name'], res.label);
|
|
});
|
|
|
|
return this.super('load', section_id);
|
|
}
|
|
so.rmempty = false;
|
|
so.editable = true;
|
|
so.depends('action', 'route');
|
|
so.depends('action', 'evaluate');
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'dns_disable_cache', _('Disable dns cache'),
|
|
_('Disable cache and save cache in this query.'));
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'rewrite_ttl', _('Rewrite TTL'),
|
|
_('Rewrite TTL in DNS responses.'));
|
|
so.datatype = 'uinteger';
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'client_subnet', _('EDNS Client subnet'),
|
|
_('Append a <code>edns0-subnet</code> OPT extra record with the specified IP prefix to every query by default.<br/>' +
|
|
'If value is an IP address instead of prefix, <code>/32</code> or <code>/128</code> will be appended automatically.'));
|
|
so.datatype = 'or(cidr, ipaddr)';
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'match_response', _('Match response'),
|
|
_('1 matches the latest untagged evaluate result; other values match an evaluate tag (1.14).'));
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'evaluate_tag', _('Evaluate tag'),
|
|
_('Optional tag for this evaluate result.'));
|
|
so.depends('action', 'evaluate');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'race', _('Race'),
|
|
_('Judge this response-dependent rule in parallel; first match wins (1.14).'));
|
|
so.depends({'action': 'route', 'match_response': /[\s\S]/});
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'speculative', _('Speculative'),
|
|
_('Send the query before pending race rules are judged (1.14).'));
|
|
so.depends('action', 'route');
|
|
so.depends('action', 'evaluate');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'disable_optimistic_cache', _('Disable optimistic cache'),
|
|
_('Disable optimistic DNS caching for this query.'));
|
|
so.depends('action', 'route');
|
|
so.depends('action', 'evaluate');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'dns_timeout', _('Query timeout'),
|
|
_('Override dns.timeout for this query, in seconds.'));
|
|
so.datatype = 'uinteger';
|
|
so.depends('action', 'route');
|
|
so.depends('action', 'evaluate');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'remove_client_subnet', _('Remove EDNS client subnet'),
|
|
_('Remove the edns0-subnet record from the query (1.14).'));
|
|
so.depends('action', 'route');
|
|
so.depends('action', 'evaluate');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'response_rcode', _('Response RCode'),
|
|
_('Match the evaluated response code (requires match_response).'));
|
|
for (let rc of [ 'NOERROR', 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMP', 'REFUSED' ])
|
|
so.value(rc);
|
|
so.depends({'action': 'route', 'match_response': /[\s\S]/});
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.DynamicList, 'response_answer', _('Response answer'),
|
|
_('Text DNS records to match in the evaluated answer.'));
|
|
so.depends({'action': 'route', 'match_response': /[\s\S]/});
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.DynamicList, 'response_ns', _('Response NS'));
|
|
so.depends({'action': 'route', 'match_response': /[\s\S]/});
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.DynamicList, 'response_extra', _('Response extra'));
|
|
so.depends({'action': 'route', 'match_response': /[\s\S]/});
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'reject_method', _('Method'));
|
|
so.value('default', _('Reply with REFUSED'));
|
|
so.value('drop', _('Drop requests'));
|
|
so.default = 'default';
|
|
so.depends('action', 'reject');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'reject_no_drop', _('Don\'t drop requests'),
|
|
_('<code>%s</code> will be temporarily overwritten to <code>%s</code> after 50 triggers in 30s if not enabled.').format(
|
|
_('Method'), _('Drop requests')));
|
|
so.depends('reject_method', 'default');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'predefined_rcode', _('RCode'),
|
|
_('The response code.'));
|
|
so.value('NOERROR');
|
|
so.value('FORMERR');
|
|
so.value('SERVFAIL');
|
|
so.value('NXDOMAIN');
|
|
so.value('NOTIMP');
|
|
so.value('REFUSED');
|
|
so.default = 'NOERROR';
|
|
so.depends('action', 'predefined');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.DynamicList, 'predefined_answer', _('Answer'),
|
|
_('List of text DNS record to respond as answers.'));
|
|
so.depends('action', 'predefined');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.DynamicList, 'predefined_ns', _('NS'),
|
|
_('List of text DNS record to respond as name servers.'));
|
|
so.depends('action', 'predefined');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.DynamicList, 'predefined_extra', _('Extra records'),
|
|
_('List of text DNS record to respond as extra records.'));
|
|
so.depends('action', 'predefined');
|
|
so.modalonly = true;
|
|
} else {
|
|
so = ss.taboption('field_other', form.ListValue, 'outbound', _('Outbound'),
|
|
_('Tag of the target outbound.'));
|
|
so.load = function(section_id) {
|
|
delete this.keylist;
|
|
delete this.vallist;
|
|
|
|
this.value('direct-out', _('Direct'));
|
|
uci.sections('homeproxy-pro', 'routing_node', (res) => {
|
|
if (res.enabled === '1')
|
|
this.value(res['.name'], res.label);
|
|
});
|
|
|
|
return this.super('load', section_id);
|
|
}
|
|
so.rmempty = false;
|
|
so.depends('action', 'route');
|
|
so.editable = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'override_address', _('Override address'),
|
|
_('Override the connection destination address.'));
|
|
so.datatype = 'ipaddr';
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'override_port', _('Override port'),
|
|
_('Override the connection destination port.'));
|
|
so.datatype = 'port';
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'udp_disable_domain_unmapping', _('Disable UDP domain unmapping'),
|
|
_('If enabled, for UDP proxy requests addressed to a domain, the original packet address will be sent in the response instead of the mapped domain.'));
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'udp_connect', _('connect UDP connections'),
|
|
_('If enabled, attempts to connect UDP connection to the destination instead of listen.'));
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'udp_timeout', _('UDP timeout'),
|
|
_('Timeout for UDP connections.<br/>Setting a larger value than the UDP timeout in inbounds will have no effect.'));
|
|
so.datatype = 'uinteger';
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'tls_record_fragment', _('TLS record fragment'),
|
|
_('Fragment TLS handshake into multiple TLS records.'));
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'tls_fragment', _('TLS fragment'),
|
|
_('Fragment TLS handshakes. Due to poor performance, try <code>%s</code> first.').format(
|
|
_('TLS record fragment')));
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'tls_fragment_fallback_delay', _('Fragment fallback delay'),
|
|
_('The fallback value in milliseconds used when TLS segmentation cannot automatically determine the wait time.'));
|
|
so.datatype = 'uinteger';
|
|
so.placeholder = '500';
|
|
so.depends('tls_fragment', '1');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'tls_spoof', _('TLS spoof SNI (1.14)'),
|
|
_('Inject a forged TLS ClientHello carrying this SNI before the real one to fool SNI-filtering middleboxes. Requires elevated privileges.'));
|
|
so.datatype = 'hostname';
|
|
so.depends('action', 'route');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'tls_spoof_method', _('TLS spoof method (1.14)'),
|
|
_('How the forged segment is rejected by the real server.'));
|
|
so.value('', _('wrong-sequence (default)'));
|
|
so.value('wrong-checksum', _('wrong-checksum'));
|
|
so.value('wrong-ack', _('wrong-ack'));
|
|
so.value('wrong-md5', _('wrong-md5'));
|
|
so.value('wrong-timestamp', _('wrong-timestamp'));
|
|
so.depends('action', 'route');
|
|
so.depends('tls_spoof', /[\s\S]/);
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'resolve_server', _('DNS server'),
|
|
_('Specifies DNS server tag to use instead of selecting through DNS routing.'));
|
|
so.load = function(section_id) {
|
|
delete this.keylist;
|
|
delete this.vallist;
|
|
|
|
this.value('', _('Default'));
|
|
this.value('default-dns', _('Default DNS (issued by WAN)'));
|
|
this.value('system-dns', _('System DNS'));
|
|
uci.sections('homeproxy-pro', 'dns_server', (res) => {
|
|
if (res.enabled === '1')
|
|
this.value(res['.name'], res.label);
|
|
});
|
|
|
|
return this.super('load', section_id);
|
|
}
|
|
so.depends('action', 'resolve');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'reject_method', _('Method'));
|
|
so.value('default', _('Reply with TCP RST / ICMP port unreachable'));
|
|
so.value('drop', _('Drop packets'));
|
|
so.depends('action', 'reject');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'reject_no_drop', _('Don\'t drop packets'),
|
|
_('<code>%s</code> will be temporarily overwritten to <code>%s</code> after 50 triggers in 30s if not enabled.').format(
|
|
_('Method'), _('Drop packets')));
|
|
so.depends('reject_method', 'default');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.ListValue, 'resolve_strategy', _('Resolve strategy'),
|
|
_('Domain strategy for resolving the domain names.'));
|
|
for (let i in hp.dns_strategy)
|
|
so.value(i, hp.dns_strategy[i]);
|
|
so.depends('action', 'resolve');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'resolve_disable_cache', _('Disable DNS cache'),
|
|
_('Disable DNS cache in this query.'));
|
|
so.depends('action', 'resolve');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'resolve_rewrite_ttl', _('Rewrite TTL'),
|
|
_('Rewrite TTL in DNS responses.'));
|
|
so.datatype = 'uinteger';
|
|
so.depends('action', 'resolve');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'resolve_client_subnet', _('EDNS Client subnet'),
|
|
_('Append a <code>edns0-subnet</code> OPT extra record with the specified IP prefix to every query by default.<br/>' +
|
|
'If value is an IP address instead of prefix, <code>/32</code> or <code>/128</code> will be appended automatically.'));
|
|
so.datatype = 'or(cidr, ipaddr)';
|
|
so.depends('action', 'resolve');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Flag, 'resolve_disable_optimistic_cache', _('Disable optimistic cache'),
|
|
_('Disable optimistic DNS caching in this lookup (1.14).'));
|
|
so.depends('action', 'resolve');
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_other', form.Value, 'resolve_timeout', _('Query timeout'),
|
|
_('Override dns.timeout for this lookup, in seconds (1.14).'));
|
|
so.datatype = 'uinteger';
|
|
so.depends('action', 'resolve');
|
|
so.modalonly = true;
|
|
}
|
|
|
|
so = ss.taboption('field_host', form.DynamicList, 'domain', _('Domain name'),
|
|
_('Match full domain.'));
|
|
so.datatype = 'hostname';
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.DynamicList, 'domain_suffix', _('Domain suffix'),
|
|
_('Match domain suffix.'));
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.DynamicList, 'domain_keyword', _('Domain keyword'),
|
|
_('Match domain using keyword.'));
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.DynamicList, 'domain_regex', _('Domain regex'),
|
|
_('Match domain using regular expression.'));
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.DynamicList, 'source_ip_cidr', _('Source IP CIDR'),
|
|
_('Match source IP CIDR.'));
|
|
so.datatype = 'or(cidr, ipaddr)';
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.Flag, 'source_ip_is_private', _('Match private source IP'));
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.DynamicList, 'ip_cidr', _('IP CIDR'),
|
|
is_dns ? _('Match IP CIDR with the evaluated response (needs match_response; old rules are auto-wrapped in 1.14).') :
|
|
_('Match IP CIDR.'));
|
|
so.datatype = 'or(cidr, ipaddr)';
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.Flag, 'ip_is_private', _('Match private IP'),
|
|
is_dns ? _('Match private IP with the evaluated response (needs match_response).') : null);
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.DynamicList, 'source_mac_address', _('Source MAC address'),
|
|
_('Match LAN device by MAC address.'));
|
|
so.datatype = 'macaddr';
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.DynamicList, 'source_hostname', _('Source hostname'),
|
|
_('Match LAN device hostname via neighbor resolution; enable find_neighbor.'));
|
|
so.modalonly = true;
|
|
|
|
if (is_dns) {
|
|
so = ss.taboption('field_host', form.Value, 'query_client_subnet', _('Query EDNS client subnet'),
|
|
_('Match the EDNS Client Subnet in the query (1.14).'));
|
|
so.datatype = 'or(cidr, ipaddr)';
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_host', form.Flag, 'query_dnssec', _('Match DNSSEC OK'),
|
|
_('Match queries with the DNSSEC OK bit set (1.14).'));
|
|
so.modalonly = true;
|
|
}
|
|
|
|
so = ss.taboption('field_port', form.DynamicList, 'source_port', _('Source port'),
|
|
_('Match source port.'));
|
|
so.datatype = 'port';
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_port', form.DynamicList, 'source_port_range', _('Source port range'),
|
|
_('Match source port range. Format as START:/:END/START:END.'));
|
|
so.validate = hp.validatePortRange;
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_port', form.DynamicList, 'port', _('Port'),
|
|
_('Match port.'));
|
|
so.datatype = 'port';
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('field_port', form.DynamicList, 'port_range', _('Port range'),
|
|
_('Match port range. Format as START:/:END/START:END.'));
|
|
so.validate = hp.validatePortRange;
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('fields_process', form.DynamicList, 'process_name', _('Process name'),
|
|
_('Match process name.'));
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('fields_process', form.DynamicList, 'process_path', _('Process path'),
|
|
_('Match process path.'));
|
|
so.modalonly = true;
|
|
|
|
so = ss.taboption('fields_process', form.DynamicList, 'process_path_regex', _('Process path (regex)'),
|
|
_('Match process path using regular expression.'));
|
|
so.modalonly = true;
|
|
}
|
|
|
|
return baseclass.extend({ renderRuleSection });
|