Skip to content

Commit

Permalink
refactor(view): improve tuic support
Browse files Browse the repository at this point in the history
Signed-off-by: Tianling Shen <[email protected]>
  • Loading branch information
1715173329 committed Aug 19, 2023
1 parent cbc7ec2 commit b5edb2c
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 88 deletions.
2 changes: 1 addition & 1 deletion htdocs/luci-static/resources/view/homeproxy/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ return view.extend({
so = ss.option(form.ListValue, 'tcpip_stack', _('TCP/IP stack'),
_('TCP/IP stack.'));
if (features.with_gvisor) {
so.value('mixed', _('Mixed'))
so.value('mixed', _('Mixed'));
so.value('gvisor', _('gVisor'));
}
if (features.with_lwip)
Expand Down
107 changes: 68 additions & 39 deletions htdocs/luci-static/resources/view/homeproxy/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,30 @@ function parseShareLink(uri, features) {
break;
}

break;
case 'tuic':
/* https://github.com/daeuniverse/dae/discussions/182 */
var url = new URL('http://' + uri[1]);
var params = url.searchParams;

/* Check if uuid exists */
if (!url.username)
return null;

config = {
label: url.hash ? decodeURIComponent(url.hash.slice(1)) : null,
type: 'tuic',
address: url.hostname,
port: url.port || '80',
uuid: url.username,
password: url.password ? decodeURIComponent(url.password) : null,
tuic_congestion_control: params.get('congestion_control'),
tuic_udp_relay_mode: params.get('udp_relay_mode'),
tls: '1',
tls_sni: params.get('sni'),
tls_alpn: params.get('alpn') ? decodeURIComponent(params.get('alpn')).split(',') : null
};

break;
case 'vless':
/* https://github.com/XTLS/Xray-core/discussions/716 */
Expand Down Expand Up @@ -490,13 +514,14 @@ return view.extend({
so.value('http', _('HTTP'));
if (features.with_quic)
so.value('hysteria', _('Hysteria'));
so.value('tuic', _('Tuic'));
so.value('shadowsocks', _('Shadowsocks'));
if (features.with_shadowsocksr)
so.value('shadowsocksr', _('ShadowsocksR'));
so.value('shadowtls', _('ShadowTLS'));
so.value('socks', _('Socks'));
so.value('trojan', _('Trojan'));
if (features.with_quic)
so.value('tuic', _('Tuic'));
if (features.with_wireguard)
so.value('wireguard', _('WireGuard'));
so.value('vless', _('VLESS'));
Expand Down Expand Up @@ -524,14 +549,14 @@ return view.extend({
so.depends('type', 'shadowsocks');
so.depends('type', 'shadowsocksr');
so.depends('type', 'trojan');
so.depends('type', 'tuic');
so.depends({'type': 'shadowtls', 'shadowtls_version': '2'});
so.depends({'type': 'shadowtls', 'shadowtls_version': '3'});
so.depends({'type': 'socks', 'socks_version': '5'});
so.depends('type', 'tuic');
so.validate = function(section_id, value) {
if (section_id) {
var type = this.map.lookupOption('type', section_id)[0].formvalue(section_id);
var required_type = [ 'shadowsocks', 'shadowsocksr', 'shadowtls', 'trojan', 'tuic' ];
var required_type = [ 'shadowsocks', 'shadowsocksr', 'shadowtls', 'trojan' ];

if (required_type.includes(type)) {
if (type === 'shadowsocks') {
Expand Down Expand Up @@ -749,14 +774,49 @@ return view.extend({
so.rmempty = false;
so.modalonly = true;

/* VMess / VLESS config start */
/* TUIC config start */
so = ss.option(form.Value, 'uuid', _('UUID'));
so.depends('type', 'tuic');
so.depends('type', 'vless');
so.depends('type', 'vmess');
so.depends('type', 'tuic');
so.validate = hp.validateUUID;
so.modalonly = true;

so = ss.option(form.ListValue, 'tuic_congestion_control', _('Congestion control algorithm'),
_('QUIC congestion control algorithm.'));
so.value('cubic', _('CUBIC'));
so.value('new_reno', _('New Reno'));
so.value('bbr', _('BBR'));
so.default = 'cubic';
so.depends('type', 'tuic');
so.rmempty = false;
so.modalonly = true;

so = ss.option(form.ListValue, 'tuic_udp_relay_mode', _('UDP relay mode'),
_('UDP packet relay mode.'));
so.value('native', _('Native'));
so.value('quic', _('QUIC'));
so.default = 'native';
so.depends('type', 'tuic');
so.rmempty = false;
so.modalonly = true;

so = ss.option(form.Flag, 'tuic_enable_zero_rtt', _('Enable 0-RTT handshake'),
_('Enable 0-RTT QUIC connection handshake on the client side. This is not impacting much on the performance, as the protocol is fully multiplexed.<br/>' +
'Disabling this is highly recommended, as it is vulnerable to replay attacks.'));
so.default = so.disabled;
so.depends('type', 'tuic');
so.modalonly = true;

so = ss.option(form.Value, 'tuic_heartbeat', _('Heartbeat'),
_('Interval for sending heartbeat packets for keeping the connection alive (in seconds).'));
so.datatype = 'uinteger';
so.default = '10';
so.depends('type', 'tuic');
so.modalonly = true;
/* Tuic config end */

/* VMess / VLESS config start */
so = ss.option(form.ListValue, 'vless_flow', _('Flow'));
so.value('', _('None'));
so.value('xtls-rprx-vision');
Expand Down Expand Up @@ -794,37 +854,6 @@ return view.extend({
so.modalonly = true;
/* VMess config end */

/* Tuic config start */
so = ss.option(form.ListValue, 'tuic_congestion_control', _('Congestion control'),
_('QUIC congestion control algorithm.'));
so.value('cubic');
so.value('new_reno');
so.value('bbr');
so.default = 'cubic';
so.depends('type', 'tuic');
so.modalonly = true;

so = ss.option(form.ListValue, 'tuic_udp_relay_mode', _('UDP relay mode'),
_('UDP packet relay mode.'));
so.value('native');
so.value('quic');
so.default = 'native';
so.depends('type', 'tuic');
so.modalonly = true;

so = ss.option(form.Flag, 'tuic_zero_rtt_handshake', _('Zero RTT handshake'),
_('Enable 0-RTT QUIC connection handshake on the client side. This is not impacting much on the performance, as the protocol is fully multiplexed. Disabling this is highly recommended, as it is vulnerable to replay attacks.'));
so.default = so.disabled;
so.depends('type', 'tuic');
so.modalonly = true;

so = ss.option(form.Value, 'tuic_heartbeat', _('Heartbeat'),
_('Interval for sending heartbeat packets for keeping the connection alive.'));
so.default = '10s';
so.depends('type', 'tuic');
so.modalonly = true;
/* Tuic config end */

/* Transport config start */
so = ss.option(form.ListValue, 'transport', _('Transport'),
_('No TCP transport, plain HTTP is merged into the HTTP transport.'));
Expand Down Expand Up @@ -895,15 +924,15 @@ return view.extend({
so.modalonly = true;

so = ss.option(form.Value, 'http_idle_timeout', _('Idle timeout'),
_('Specifies the period of time after which a health check will be performed using a ping frame if no frames have been received on the connection.<br/>' +
_('Specifies the period of time (in seconds) after which a health check will be performed using a ping frame if no frames have been received on the connection.<br/>' +
'Please note that a ping response is considered a received frame, so if there is no other traffic on the connection, the health check will be executed every interval.'));
so.datatype = 'uinteger';
so.depends('transport', 'grpc');
so.depends({'transport': 'http', 'tls': '1'});
so.modalonly = true;

so = ss.option(form.Value, 'http_ping_timeout', _('Ping timeout'),
_('Specifies the timeout duration after sending a PING frame, within which a response must be received.<br/>' +
_('Specifies the timeout (in seconds) duration after sending a PING frame, within which a response must be received.<br/>' +
'If a response to the PING frame is not received within the specified timeout duration, the connection will be closed.'));
so.datatype = 'uinteger';
so.depends('transport', 'grpc');
Expand Down Expand Up @@ -1033,9 +1062,9 @@ return view.extend({
so.depends('type', 'hysteria');
so.depends('type', 'shadowtls');
so.depends('type', 'trojan');
so.depends('type', 'tuic');
so.depends('type', 'vless');
so.depends('type', 'vmess');
so.depends('type', 'tuic');
so.validate = function(section_id, value) {
if (section_id) {
var type = this.map.lookupOption('type', section_id)[0].formvalue(section_id);
Expand Down
72 changes: 38 additions & 34 deletions htdocs/luci-static/resources/view/homeproxy/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,12 @@ return view.extend({
if (features.with_quic) {
o.value('hysteria', _('Hysteria'));
o.value('naive', _('NaïveProxy'));
o.value('tuic', _('Tuic'));
}
o.value('shadowsocks', _('Shadowsocks'));
o.value('socks', _('Socks'));
o.value('trojan', _('Trojan'));
if (features.with_quic)
o.value('tuic', _('Tuic'));
o.value('vless', _('VLESS'));
o.value('vmess', _('VMess'));
o.rmempty = false;
Expand Down Expand Up @@ -232,14 +233,46 @@ return view.extend({
o.depends('type', 'shadowsocks');
o.modalonly = true;

/* VLESS / VMess config start */
/* Tuic config start */
o = s.option(form.Value, 'uuid', _('UUID'));
o.depends('type', 'tuic');
o.depends('type', 'vless');
o.depends('type', 'vmess');
o.depends('type', 'tuic');
o.validate = hp.validateUUID;
o.modalonly = true;

o = s.option(form.ListValue, 'tuic_congestion_control', _('Congestion control algorithm'),
_('QUIC congestion control algorithm.'));
o.value('cubic');
o.value('new_reno');
o.value('bbr');
o.default = 'cubic';
o.depends('type', 'tuic');
o.modalonly = true;

o = s.option(form.ListValue, 'tuic_auth_timeout', _('Auth timeout'),
_('How long the server should wait for the client to send the authentication command (in seconds).'));
o.datatype = 'uinteger';
o.default = '3';
o.depends('type', 'tuic');
o.modalonly = true;

o = s.option(form.Flag, 'tuic_enable_zero_rtt', _('Enable 0-RTT handshake'),
_('Enable 0-RTT QUIC connection handshake on the client side. This is not impacting much on the performance, as the protocol is fully multiplexed.<br/>' +
'Disabling this is highly recommended, as it is vulnerable to replay attacks.'));
o.default = o.disabled;
o.depends('type', 'tuic');
o.modalonly = true;

o = s.option(form.Value, 'tuic_heartbeat', _('Heartbeat'),
_('Interval for sending heartbeat packets for keeping the connection alive (in seconds).'));
o.datatype = 'uinteger';
o.default = '10';
o.depends('type', 'tuic');
o.modalonly = true;
/* Tuic config end */

/* VLESS / VMess config start */
o = s.option(form.ListValue, 'vless_flow', _('Flow'));
o.value('', _('None'));
o.value('xtls-rprx-vision');
Expand All @@ -253,35 +286,6 @@ return view.extend({
o.modalonly = true;
/* VMess config end */

/* Tuic config start */
so = ss.option(form.ListValue, 'tuic_congestion_control', _('Congestion control'),
_('QUIC congestion control algorithm.'));
so.value('cubic');
so.value('new_reno');
so.value('bbr');
so.default = 'cubic';
so.depends('type', 'tuic');
so.modalonly = true;

so = ss.option(form.ListValue, 'tuic_auth_timeout', _('Auth timeout'),
_('How long the server should wait for the client to send the authentication command.'));
so.default = '3s';
so.depends('type', 'tuic');
so.modalonly = true;

so = ss.option(form.Flag, 'tuic_zero_rtt_handshake', _('Zero RTT handshake'),
_('Enable 0-RTT QUIC connection handshake on the client side. This is not impacting much on the performance, as the protocol is fully multiplexed. Disabling this is highly recommended, as it is vulnerable to replay attacks.'));
so.default = so.disabled;
so.depends('type', 'tuic');
so.modalonly = true;

so = ss.option(form.Value, 'tuic_heartbeat', _('Heartbeat'),
_('Interval for sending heartbeat packets for keeping the connection alive.'));
so.default = '10s';
so.depends('type', 'tuic');
so.modalonly = true;
/* Tuic config end */

/* Transport config start */
o = s.option(form.ListValue, 'transport', _('Transport'),
_('No TCP transport, plain HTTP is merged into the HTTP transport.'));
Expand Down Expand Up @@ -334,15 +338,15 @@ return view.extend({
o.modalonly = true;

o = s.option(form.Value, 'http_idle_timeout', _('Idle timeout'),
_('Specifies the time until idle clients should be closed with a GOAWAY frame. PING frames are not considered as activity.'));
_('Specifies the time (in seconds) until idle clients should be closed with a GOAWAY frame. PING frames are not considered as activity.'));
o.datatype = 'uinteger';
o.depends('transport', 'grpc');
o.depends({'transport': 'http', 'tls': '1'});
o.modalonly = true;

if (features.with_grpc) {
o = s.option(form.Value, 'http_ping_timeout', _('Ping timeout'),
_('The timeout that after performing a keepalive check, the client will wait for activity. If no activity is detected, the connection will be closed.'));
_('The timeout (in seconds) that after performing a keepalive check, the client will wait for activity. If no activity is detected, the connection will be closed.'));
o.datatype = 'uinteger';
o.depends('transport', 'grpc');
o.modalonly = true;
Expand Down
12 changes: 6 additions & 6 deletions root/etc/homeproxy/scripts/generate_client.uc
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,13 @@ function generate_outbound(node) {
obfs_param: node.shadowsocksr_obfs_param,
/* ShadowTLS / Socks */
version: (node.type === 'shadowtls') ? strToInt(node.shadowtls_version) : ((node.type === 'socks') ? node.socks_version : null),
/* VLESS / VMess / Tuic */
/* Tuic */
uuid: node.uuid,
congestion_control: node.tuic_congestion_control,
udp_relay_mode: node.tuic_udp_relay_mode,
zero_rtt_handshake: (node.tuic_enable_zero_rtt === '1') || null,
heartbeat: node.tuic_heartbeat ? (node.tuic_heartbeat + 's') : null,
/* VLESS / VMess */
flow: node.vless_flow,
alter_id: strToInt(node.vmess_alterid),
security: node.vmess_encrypt,
Expand All @@ -170,11 +175,6 @@ function generate_outbound(node) {
pre_shared_key: node.wireguard_pre_shared_key,
reserved: parse_port(node.wireguard_reserved),
mtu: node.wireguard_mtu,
/* Tuic */
congestion_control: node.tuic_congestion_control,
udp_relay_mode: node.tuic_udp_relay_mode,
zero_rtt_handshake: (node.tuic_zero_rtt_handshake === '1') || null,
heartbeat: node.tuic_heartbeat,

multiplex: (node.multiplex === '1') ? {
enabled: true,
Expand Down
18 changes: 10 additions & 8 deletions root/etc/homeproxy/scripts/generate_server.uc
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,17 @@ uci.foreach(uciconfig, uciserver, (cfg) => {
max_conn_client: strToInt(cfg.hysteria_max_conn_client),
disable_mtu_discovery: (cfg.hysteria_disable_mtu_discovery === '1') || null,

/* Tuic */
congestion_control: cfg.tuic_congestion_control,
auth_timeout: cfg.tuic_auth_timeout,
zero_rtt_handshake: (cfg.tuic_zero_rtt_handshake === '1') || null,
heartbeat: cfg.tuic_heartbeat,

/* Shadowsocks */
method: (cfg.type === 'shadowsocks') ? cfg.shadowsocks_encrypt_method : null,
password: (cfg.type in ['shadowsocks', 'shadowtls']) ? cfg.password : null,

/* HTTP / Hysteria / Socks / Trojan / VLESS / VMess / Tuic */
/* Tuic */
congestion_control: cfg.tuic_congestion_control,
auth_timeout: cfg.tuic_auth_timeout ? (cfg.tuic_auth_timeout + 's') : null,
zero_rtt_handshake: (cfg.tuic_enable_zero_rtt === '1') || null,
heartbeat: cfg.tuic_heartbeat ? (cfg.tuic_heartbeat + 's') : null,

/* HTTP / Hysteria / Socks / Trojan / Tuic / VLESS / VMess */
users: (cfg.type !== 'shadowsocks') ? [
{
name: !(cfg.type in ['http', 'socks']) ? 'cfg-' + cfg['.name'] + '-server' : null,
Expand All @@ -85,8 +85,10 @@ uci.foreach(uciconfig, uciserver, (cfg) => {
auth: (cfg.hysteria_auth_type === 'base64') ? cfg.hysteria_auth_payload : null,
auth_str: (cfg.hysteria_auth_type === 'string') ? cfg.hysteria_auth_payload : null,

/* VLESS / VMess / Tuic */
/* Tuic */
uuid: cfg.uuid,

/* VLESS / VMess */
flow: cfg.vless_flow,
alterId: strToInt(cfg.vmess_alterid)
}
Expand Down
Loading

0 comments on commit b5edb2c

Please sign in to comment.