Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[http2]代理一个只支持http2的server, frp返回502错误码 #4217

Closed
3 of 11 tasks
shuguang101 opened this issue May 13, 2024 · 9 comments · Fixed by #4230
Closed
3 of 11 tasks

[http2]代理一个只支持http2的server, frp返回502错误码 #4217

shuguang101 opened this issue May 13, 2024 · 9 comments · Fixed by #4230
Labels

Comments

@shuguang101
Copy link

shuguang101 commented May 13, 2024

Bug Description

使用frp代理一个只支持http2的server时, frp总是返回502错误码
HTTP 178 HTTP/1.1 502 Bad Gateway

使用curl连接frp vhost端口
强制curl使用http2连接,但最终http协议还是failback到http1.1了(frp not agree on a protocol), 返回502错误码

curl -4 -vsk --http2 --request POST  ${frp_addr:frp_port} 命令行输出信息

* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
* using HTTP/1.x

使用curl直接连接原始端口
强制curl使用http2,能够协商成功,最终使用http2,返回200 服务能正常访问

curl -4 -vsk --http2  raw_ip:raw_port 命令行输出

* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
* using HTTP/2

由于被代理的服务只支持http2, 如果强制使用http1.1访问会失败

curl -4 -vsk --http1.1 raw_ip:raw_port

* ALPN: offers http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
* using HTTP/1.x
* old SSL session ID is stale, removing
*** Received HTTP/0.9 when not allowed**
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):

frpc Version

0.57.0

frps Version

0.57.0

System Architecture

linux/amd64

Configurations

frpc

user = "xx"
auth.method = "token"
auth.token = "xx"
udpPacketSize = 1400

loginFailExit = false
serverAddr = "xxxx"
serverPort = xx

transport.poolCount = 0
transport.tcpMux = false
transport.protocol = "tcp"
transport.connectServerLocalIP = "0.0.0.0"

[[proxies]]
name = "https_xxx"
type = "https"
customDomains = ["xxxxx.com"]
transport.proxyProtocolVersion = ""
[proxies.plugin]
type = "https2https"
localAddr = "127.0.0.1:12345"
crtPath = "/xxx/fullchain.pem"
keyPath = "/xxx/privkey.pem"

frps

bindAddr = "xxx"
bindPort = xx

transport.maxPoolCount = 1000
transport.tcpMux = false

vhostHTTPSPort = 443
vhostHTTPTimeout = 120
userConnTimeout = 15
tcpmuxHTTPConnectPort = 0
tcpmuxPassthrough = false

auth.method = "token"
auth.token = "xx"
udpPacketSize = 1400

Logs

No response

Steps to reproduce

  1. 创建一个只支持http2的https服务
  2. 使用https2https代理这个服务
  3. 访问frp会返回502
    ...

Affected area

  • Docs
  • Installation
  • Performance and Scalability
  • Security
  • User Experience
  • Test and Release
  • Developer Infrastructure
  • Client Plugin
  • Server Plugin
  • Extensions
  • Others
@xqzr
Copy link

xqzr commented May 13, 2024

看起来是 https2https 插件,返回的 alpn 列表中 不含 h2
建议在 监听 127.0.0.1:12345 的程序 正确配置证书

@shuguang101
Copy link
Author

建议在 监听 127.0.0.1:12345 的程序 正确配置证书

证书配置是正确的,因为不通过frp代理直接访问原始端口的情况下能正常访问,并且没有证书错误。

@xqzr
Copy link

xqzr commented May 13, 2024

建议在 监听 127.0.0.1:12345 的程序 正确配置证书

证书配置是正确的,因为不通过frp代理直接访问原始端口的情况下能正常访问,并且没有证书错误。

可以尝试 注释掉 [proxies.plugin] 及以下的行
并添加 localPort = 12345

@xqzr
Copy link

xqzr commented May 13, 2024

并且没有证书错误。

那是因为,给 curl 传递了 -k

@shuguang101
Copy link
Author

刚试了一下不带k也没有证书错误

curl -4 -vs --http2 --request POST
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  SSL certificate verify ok.
* using HTTP/2
* h2h3 [:method: POST]
* h2h3 [:path: /xxxxx]
* h2h3 [:scheme: https]
* h2h3 [:authority: xxxxx]
* h2h3 [user-agent: curl/7.88.1]
* Using Stream ID: 1 (easy handle 0x562d1b103070)
* * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* We are completely uploaded and fine
< HTTP/2 200 

@shuguang101
Copy link
Author

shuguang101 commented May 13, 2024

https2https 插件和Port 12345 服务用的都是Let's Encrypt的证书(同一个证书)

@xqzr
Copy link

xqzr commented May 13, 2024

https2https 插件和Port 12345 服务用的都是Let's Encrypt的证书(同一个证书)

既然是 同一个证书,那么 不需要使用插件

@shuguang101
Copy link
Author

用插件设置了一下http header。现在能确定是什么原因吗?

不知道是否和这个有关:
https://www.cnblogs.com/embedded-linux/p/12585854.html
Golang默认支持HTTP/2协议,只要使用TLS则默认启动HTTP/2特性,但对http Client做一些定制化配置后,会覆盖掉http库的默认行为,导致开启HTTP/1.1。

@shuguang101
Copy link
Author

shuguang101 commented May 15, 2024

nginx在配置proxy_pass时可以指定http版本

location / {
  proxy_pass http://1.2.3.0;
  proxy_http_version 1.1;
}

如果无法准确判断http version,是否可以考虑像nginx一样,在插件配置项里添加一个proxy_http_version用于指定http版本。仅仅是个建议哈,我对nginx和http也不是十分熟悉,只是刚刚看到nginx里有这个配置项。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants