Add Fortinet hostcheck support
This commit is contained in:
@@ -58,6 +58,10 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"fortinet_host_check": {
|
||||
"hostcheck": "",
|
||||
"check_virtual_desktop": ""
|
||||
},
|
||||
"no_udp": false,
|
||||
"dtls_local_port": 0,
|
||||
"compression_disabled": false,
|
||||
@@ -342,6 +346,30 @@ TNCC machine certificate path in PEM format.
|
||||
|
||||
Conflict with `tncc.certificates.certificate`.
|
||||
|
||||
### fortinet_host_check
|
||||
|
||||
Fortinet hostcheck result override.
|
||||
|
||||
Hostcheck is disabled by default. It is enabled only when `fortinet_host_check.hostcheck` is non-empty. No operating system, security product, or network interface information is collected automatically.
|
||||
|
||||
When enabled and a successful Fortinet login response requests hostcheck, both configured values are submitted to the server before the VPN session is used. The values are sent unchanged as `application/x-www-form-urlencoded` fields.
|
||||
|
||||
Some Fortinet servers only request hostcheck from recognized FortiClient user agents. Configure `user_agent` when required by the server policy.
|
||||
|
||||
### fortinet_host_check.hostcheck
|
||||
|
||||
Fortinet hostcheck result string.
|
||||
|
||||
The conventional format is `<security-status>,<os-version>`, for example `0100,10.0.19042`. `security-status` contains four `0` or `1` characters representing, in order, third-party firewall, third-party antivirus, FortiClient firewall, and FortiClient antivirus.
|
||||
|
||||
An empty value disables Fortinet hostcheck, even if `fortinet_host_check.check_virtual_desktop` is configured.
|
||||
|
||||
### fortinet_host_check.check_virtual_desktop
|
||||
|
||||
Fortinet virtual desktop check result string.
|
||||
|
||||
FortiClient conventionally sends colon-separated MAC addresses joined by `|`, for example `74:78:27:4d:81:93|84:1b:77:3a:95:84`. An empty value is submitted as an empty field when hostcheck is enabled.
|
||||
|
||||
### no_udp
|
||||
|
||||
Disable the DTLS or ESP secondary data channel and use the TLS data channel only.
|
||||
|
||||
@@ -58,6 +58,10 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"fortinet_host_check": {
|
||||
"hostcheck": "",
|
||||
"check_virtual_desktop": ""
|
||||
},
|
||||
"no_udp": false,
|
||||
"dtls_local_port": 0,
|
||||
"compression_disabled": false,
|
||||
@@ -342,6 +346,30 @@ PEM 格式的 TNCC 机器证书路径。
|
||||
|
||||
与 `tncc.certificates.certificate` 冲突。
|
||||
|
||||
### fortinet_host_check
|
||||
|
||||
Fortinet hostcheck 结果覆盖选项。
|
||||
|
||||
默认禁用 hostcheck。仅当 `fortinet_host_check.hostcheck` 非空时启用。不会自动收集操作系统、安全产品或网络接口信息。
|
||||
|
||||
启用后,如果成功的 Fortinet 登录响应要求 hostcheck,将在使用 VPN 会话前向服务器提交两个配置值。这些值不经修改,作为 `application/x-www-form-urlencoded` 字段发送。
|
||||
|
||||
部分 Fortinet 服务器只会要求可识别的 FortiClient User-Agent 执行 hostcheck。服务器策略有要求时请配置 `user_agent`。
|
||||
|
||||
### fortinet_host_check.hostcheck
|
||||
|
||||
Fortinet hostcheck 结果字符串。
|
||||
|
||||
通常格式为 `<security-status>,<os-version>`,例如 `0100,10.0.19042`。`security-status` 包含四个 `0` 或 `1` 字符,依次表示第三方防火墙、第三方杀毒软件、FortiClient 防火墙和 FortiClient 杀毒软件。
|
||||
|
||||
空值会禁用 Fortinet hostcheck,即使配置了 `fortinet_host_check.check_virtual_desktop`。
|
||||
|
||||
### fortinet_host_check.check_virtual_desktop
|
||||
|
||||
Fortinet virtual desktop 检查结果字符串。
|
||||
|
||||
FortiClient 通常发送以冒号分隔的 MAC 地址,多个地址使用 `|` 连接,例如 `74:78:27:4d:81:93|84:1b:77:3a:95:84`。启用 hostcheck 时,空值会作为空字段提交。
|
||||
|
||||
### no_udp
|
||||
|
||||
禁用 DTLS 或 ESP 辅助数据通道,仅使用 TLS 数据通道。
|
||||
|
||||
@@ -46,7 +46,7 @@ require (
|
||||
github.com/sagernet/sing v0.8.12-0.20260721063414-596db5dd6ef4
|
||||
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3
|
||||
github.com/sagernet/sing-mux v0.3.5
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260721013312-6c25fa7e089a
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260721123934-0d945d43288f
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260721005523-64b754d1c277
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
|
||||
@@ -190,8 +190,6 @@ github.com/mdlayher/netlink v1.9.0 h1:G8+GLq2x3v4D4MVIqDdNUhTUC7TKiCy/6MDkmItfKc
|
||||
github.com/mdlayher/netlink v1.9.0/go.mod h1:YBnl5BXsCoRuwBjKKlZ+aYmEoq0r12FDA/3JC+94KDg=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg=
|
||||
github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/metacubex/utls v1.8.7 h1:Cp+yWkNTFkSihETgGWq34hlVFds5HpYWVOR1xovUVTs=
|
||||
github.com/metacubex/utls v1.8.7/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/mholt/acmez/v3 v3.1.6 h1:eGVQNObP0pBN4sxqrXeg7MYqTOWyoiYpQqITVWlrevk=
|
||||
@@ -319,8 +317,8 @@ github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 h1:3y6
|
||||
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg=
|
||||
github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONfhI=
|
||||
github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260721013312-6c25fa7e089a h1:DafepSfytV5uShjQctZ0Cnw+Q9cOBIMT88p8jU2DSck=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260721013312-6c25fa7e089a/go.mod h1:4AKZLVcvY3r54UaK2Gbnm7aN8pOwdLz+y4EP0QFZ5Eg=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260721123934-0d945d43288f h1:FKT5eCVyNiRNpa5jov6Fl9aQpAgKuCmkuhqVXvBK8b4=
|
||||
github.com/sagernet/sing-openconnect v0.0.0-20260721123934-0d945d43288f/go.mod h1:4AKZLVcvY3r54UaK2Gbnm7aN8pOwdLz+y4EP0QFZ5Eg=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260721005523-64b754d1c277 h1:4H38L3OxOx1fGEuH4n9lh/5O7XtZTgQ/1V/gdQ+b+Es=
|
||||
github.com/sagernet/sing-openvpn v0.0.0-20260721005523-64b754d1c277/go.mod h1:PWX7WygD8jpwfqfaGNySXpJYTn0SOwjBI1BKHHC2+Bw=
|
||||
github.com/sagernet/sing-quic v0.6.4-0.20260720125339-63fa6a7ebc31 h1:FuiTs45PaA1/f2Kj6E2QlctFBrJUUFB8QAHnV5im9c8=
|
||||
|
||||
+47
-41
@@ -4,47 +4,48 @@ import "github.com/sagernet/sing/common/json/badoption"
|
||||
|
||||
type OpenConnectEndpointOptions struct {
|
||||
DialerOptions
|
||||
System bool `json:"system,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
UDPTimeout badoption.Duration `json:"udp_timeout,omitempty"`
|
||||
UDPMapping UDPNATBehavior `json:"udp_mapping,omitempty"`
|
||||
UDPFiltering UDPNATBehavior `json:"udp_filtering,omitempty"`
|
||||
UDPNATMax uint32 `json:"udp_nat_max,omitempty"`
|
||||
Server string `json:"server"`
|
||||
Flavor string `json:"flavor,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
AuthGroup string `json:"auth_group,omitempty"`
|
||||
Cookie string `json:"cookie,omitempty"`
|
||||
Token *OpenConnectTokenOptions `json:"token,omitempty"`
|
||||
ReportedOS string `json:"reported_os,omitempty"`
|
||||
UserAgent string `json:"user_agent,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
LocalHostname string `json:"local_hostname,omitempty"`
|
||||
Mobile *OpenConnectMobileOptions `json:"mobile,omitempty"`
|
||||
CSD *OpenConnectCSDOptions `json:"csd,omitempty"`
|
||||
HIP *OpenConnectHIPOptions `json:"hip,omitempty"`
|
||||
TNCC *OpenConnectTNCCOptions `json:"tncc,omitempty"`
|
||||
NoUDP bool `json:"no_udp,omitempty"`
|
||||
DTLSLocalPort uint16 `json:"dtls_local_port,omitempty"`
|
||||
CompressionDisabled bool `json:"compression_disabled,omitempty"`
|
||||
CompressionMode string `json:"compression_mode,omitempty"`
|
||||
IPv6Disabled bool `json:"ipv6_disabled,omitempty"`
|
||||
HTTPKeepAliveDisabled bool `json:"http_keepalive_disabled,omitempty"`
|
||||
XMLPostDisabled bool `json:"xml_post_disabled,omitempty"`
|
||||
ExternalAuthDisabled bool `json:"external_auth_disabled,omitempty"`
|
||||
PasswordAuthenticationDisabled bool `json:"password_authentication_disabled,omitempty"`
|
||||
TCPKeepAliveEnabled bool `json:"tcp_keep_alive_enabled,omitempty"`
|
||||
PFS bool `json:"pfs,omitempty"`
|
||||
MTU uint32 `json:"mtu,omitempty"`
|
||||
BaseMTU uint32 `json:"base_mtu,omitempty"`
|
||||
DPDInterval badoption.Duration `json:"dpd_interval,omitempty"`
|
||||
ReconnectTimeout badoption.Duration `json:"reconnect_timeout,omitempty"`
|
||||
TrojanInterval badoption.Duration `json:"trojan_interval,omitempty"`
|
||||
QueueLength uint32 `json:"queue_length,omitempty"`
|
||||
AllowInsecureCrypto bool `json:"allow_insecure_crypto,omitempty"`
|
||||
TLS OpenConnectTLSOptions `json:"tls,omitempty"`
|
||||
FormEntries []OpenConnectFormEntryOptions `json:"form_entries,omitempty"`
|
||||
System bool `json:"system,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
UDPTimeout badoption.Duration `json:"udp_timeout,omitempty"`
|
||||
UDPMapping UDPNATBehavior `json:"udp_mapping,omitempty"`
|
||||
UDPFiltering UDPNATBehavior `json:"udp_filtering,omitempty"`
|
||||
UDPNATMax uint32 `json:"udp_nat_max,omitempty"`
|
||||
Server string `json:"server"`
|
||||
Flavor string `json:"flavor,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
AuthGroup string `json:"auth_group,omitempty"`
|
||||
Cookie string `json:"cookie,omitempty"`
|
||||
Token *OpenConnectTokenOptions `json:"token,omitempty"`
|
||||
ReportedOS string `json:"reported_os,omitempty"`
|
||||
UserAgent string `json:"user_agent,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
LocalHostname string `json:"local_hostname,omitempty"`
|
||||
Mobile *OpenConnectMobileOptions `json:"mobile,omitempty"`
|
||||
CSD *OpenConnectCSDOptions `json:"csd,omitempty"`
|
||||
HIP *OpenConnectHIPOptions `json:"hip,omitempty"`
|
||||
TNCC *OpenConnectTNCCOptions `json:"tncc,omitempty"`
|
||||
FortinetHostCheck *OpenConnectFortinetHostCheckOptions `json:"fortinet_host_check,omitempty"`
|
||||
NoUDP bool `json:"no_udp,omitempty"`
|
||||
DTLSLocalPort uint16 `json:"dtls_local_port,omitempty"`
|
||||
CompressionDisabled bool `json:"compression_disabled,omitempty"`
|
||||
CompressionMode string `json:"compression_mode,omitempty"`
|
||||
IPv6Disabled bool `json:"ipv6_disabled,omitempty"`
|
||||
HTTPKeepAliveDisabled bool `json:"http_keepalive_disabled,omitempty"`
|
||||
XMLPostDisabled bool `json:"xml_post_disabled,omitempty"`
|
||||
ExternalAuthDisabled bool `json:"external_auth_disabled,omitempty"`
|
||||
PasswordAuthenticationDisabled bool `json:"password_authentication_disabled,omitempty"`
|
||||
TCPKeepAliveEnabled bool `json:"tcp_keep_alive_enabled,omitempty"`
|
||||
PFS bool `json:"pfs,omitempty"`
|
||||
MTU uint32 `json:"mtu,omitempty"`
|
||||
BaseMTU uint32 `json:"base_mtu,omitempty"`
|
||||
DPDInterval badoption.Duration `json:"dpd_interval,omitempty"`
|
||||
ReconnectTimeout badoption.Duration `json:"reconnect_timeout,omitempty"`
|
||||
TrojanInterval badoption.Duration `json:"trojan_interval,omitempty"`
|
||||
QueueLength uint32 `json:"queue_length,omitempty"`
|
||||
AllowInsecureCrypto bool `json:"allow_insecure_crypto,omitempty"`
|
||||
TLS OpenConnectTLSOptions `json:"tls,omitempty"`
|
||||
FormEntries []OpenConnectFormEntryOptions `json:"form_entries,omitempty"`
|
||||
}
|
||||
|
||||
type OpenConnectTokenOptions struct {
|
||||
@@ -79,6 +80,11 @@ type OpenConnectTNCCOptions struct {
|
||||
Certificates []OpenConnectTNCCCertificateOptions `json:"certificates,omitempty"`
|
||||
}
|
||||
|
||||
type OpenConnectFortinetHostCheckOptions struct {
|
||||
HostCheck string `json:"hostcheck,omitempty"`
|
||||
CheckVirtualDesktop string `json:"check_virtual_desktop,omitempty"`
|
||||
}
|
||||
|
||||
type OpenConnectTNCCCertificateOptions struct {
|
||||
Certificate badoption.Listable[string] `json:"certificate,omitempty"`
|
||||
CertificatePath string `json:"certificate_path,omitempty"`
|
||||
|
||||
@@ -254,6 +254,13 @@ func (e *Endpoint) buildClientOptions(options option.OpenConnectEndpointOptions,
|
||||
Certificates: tnccCertificates,
|
||||
}
|
||||
}
|
||||
var fortinetHostCheckOptions *openconnect.FortinetHostCheckOptions
|
||||
if options.FortinetHostCheck != nil {
|
||||
fortinetHostCheckOptions = &openconnect.FortinetHostCheckOptions{
|
||||
HostCheck: options.FortinetHostCheck.HostCheck,
|
||||
CheckVirtualDesktop: options.FortinetHostCheck.CheckVirtualDesktop,
|
||||
}
|
||||
}
|
||||
formEntries := common.Map(options.FormEntries, func(entry option.OpenConnectFormEntryOptions) openconnect.FormEntry {
|
||||
return openconnect.FormEntry{
|
||||
FormID: entry.FormID,
|
||||
@@ -280,6 +287,7 @@ func (e *Endpoint) buildClientOptions(options option.OpenConnectEndpointOptions,
|
||||
CSD: csdOptions,
|
||||
HIP: hipOptions,
|
||||
TNCC: tnccOptions,
|
||||
FortinetHostCheck: fortinetHostCheckOptions,
|
||||
NoUDP: options.NoUDP,
|
||||
DTLSLocalPort: options.DTLSLocalPort,
|
||||
CompressionDisabled: options.CompressionDisabled,
|
||||
|
||||
Reference in New Issue
Block a user