[Feature Request] implement healthcheck or extend urltest with HTTP/2 ping
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 38.2k
- Forks
- 4.6k
- Avg merge
- 19d 15h
- Merged PRs (30d)
- 1
Description
It seems that currently sing-box is doing full http(s) requests for urltest by default:
We both know non-HTTPS captive portal endpoints are unreliable, but the full HTTPS requests impact performance and they're not 1-rtt.
With HTTP/2 ping, we can measure 1-rtt with ~100 bytes' read and write.
With simple tests:
Source code
package main
import (
"context"
"crypto/tls"
"flag"
"fmt"
"net"
"time"
"golang.org/x/net/http2"
)
type Stats struct {
conn net.Conn
BytesRead int64
BytesWritten int64
}
func (t *Stats) Read(b []byte) (n int, err error) {
n, err = t.conn.Read(b)
t.BytesRead += int64(n)
return
}
func (t *Stats) Write(b []byte) (n int, err error) {
n, err = t.conn.Write(b)
t.BytesWritten += int64(n)
return
}
func (t *Stats) Close() error {
return t.conn.Close()
}
func (t *Stats) LocalAddr() net.Addr {
return t.conn.LocalAddr()
}
func (t *Stats) RemoteAddr() net.Addr {
return t.conn.RemoteAddr()
}
func (t *Stats) SetDeadline(time time.Time) error {
return t.conn.SetDeadline(time)
}
func (t *Stats) SetReadDeadline(time time.Time) error {
return t.conn.SetReadDeadline(time)
}
func (t *Stats) SetWriteDeadline(time time.Time) error {
return t.conn.SetWriteDeadline(time)
}
func NewStatsConn(conn net.Conn) *Stats {
return &Stats{
conn: conn,
}
}
func main() {
resolve := flag.String("resolve", "1.1.1.1", "")
server := flag.String("server", "cloudflare.com", "ServerName is used to verify the hostname on the returned certificates unless InsecureSkipVerify is given. It is also included in the client's handshake to support virtual hosting unless it is an IP address.")
port := flag.Uint("port", 443, "")
flag.Parse()
var address string
if *resolve == "" {
address = fmt.Sprintf("%s:%d", *server, *port)
} else {
address = fmt.Sprintf("%s:%d", *resolve, *port)
}
tcpConn, err := net.Dial("tcp", address)
if err != nil {
panic(err)
}
defer tcpConn.Close()
statsConn := NewStatsConn(tcpConn)
tlsConn := tls.Client(statsConn, &tls.Config{
ServerName: *server,
NextProtos: []string{"h2"},
})
tr := http2.Transport{}
http2Conn, err := tr.NewClientConn(tlsConn)
if err != nil {
panic(err)
}
defer http2Conn.Close()
for http2Conn.State().MaxConcurrentStreams == 0 {
time.Sleep(time.Millisecond * 100)
}
fmt.Println("init", statsConn.BytesRead, statsConn.BytesWritten)
r, w := statsConn.BytesRead, statsConn.BytesWritten
for i := 0; i < 3; i++ {
// https://github.com/zckevin/Clash.Meta/tree/b349b464acf0984553597cc95b0092d7866cbbc0/adapter/outboundgroup/http2ping
start := time.Now()
err = http2Conn.Ping(context.Background())
rtt := time.Since(start)
fmt.Println(*server, "index", i,
"read", statsConn.BytesRead-r, "written", statsConn.BytesWritten-w,
"rtt(ms)", uint(rtt.Milliseconds()))
r, w = statsConn.BytesRead, statsConn.BytesWritten
if err != nil {
panic(err)
}
time.Sleep(time.Second)
}
}
$ go run ./http2ping -server dns.pub -resolve 1.12.12.12
init 2712 525
dns.pub index 0 read 46 written 46 rtt(ms) 11
dns.pub index 1 read 46 written 46 rtt(ms) 11
dns.pub index 2 read 46 written 46 rtt(ms) 11
$ go run ./http2ping -server cloudflare.com -resolve 1.1.1.1
init 3033 456
cloudflare.com index 0 read 39 written 39 rtt(ms) 221
cloudflare.com index 1 read 39 written 39 rtt(ms) 219
cloudflare.com index 2 read 39 written 39 rtt(ms) 219
$ go run ./http2ping -server 8.8.8.8 -resolve 8.8.8.8
init 4913 433
8.8.8.8 index 0 read 39 written 39 rtt(ms) 220
8.8.8.8 index 1 read 39 written 39 rtt(ms) 221
8.8.8.8 index 2 read 39 written 39 rtt(ms) 220
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with common/urltest/urltest.go at the linked request and response handling, then review the provided golang.org/x/net/http2 example and its Ping API. Determine whether the work belongs in urltest or as a separate healthcheck, and verify that the selected approach measures HTTP/2 round-trip latency with the intended small read and write.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- networking
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100