yggdrasil-go/src/core/link_wss.go
2024-11-17 21:29:26 +00:00

70 lines
1.6 KiB
Go

package core
import (
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"net/url"
"github.com/Arceliar/phony"
"github.com/coder/websocket"
)
type linkWSS struct {
phony.Inbox
*links
tlsconfig *tls.Config
}
type linkWSSConn struct {
net.Conn
}
func (l *links) newLinkWSS() *linkWSS {
lwss := &linkWSS{
links: l,
tlsconfig: l.core.config.tls.Clone(),
}
return lwss
}
func (l *linkWSS) dial(ctx context.Context, url *url.URL, info linkInfo, options linkOptions) (net.Conn, error) {
tlsconfig := l.tlsconfig.Clone()
return l.links.findSuitableIP(url, func(hostname string, ip net.IP, port int) (net.Conn, error) {
tlsconfig.ServerName = hostname
u := *url
u.Host = net.JoinHostPort(ip.String(), fmt.Sprintf("%d", port))
addr := &net.TCPAddr{
IP: ip,
Port: port,
}
dialer, err := l.tcp.dialerFor(addr, info.sintf)
if err != nil {
return nil, err
}
wsconn, _, err := websocket.Dial(ctx, u.String(), &websocket.DialOptions{
HTTPClient: &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: dialer.Dial,
DialContext: dialer.DialContext,
TLSClientConfig: tlsconfig,
},
},
Subprotocols: []string{"ygg-ws"},
Host: hostname,
})
if err != nil {
return nil, err
}
return &linkWSSConn{
Conn: websocket.NetConn(ctx, wsconn, websocket.MessageBinary),
}, nil
})
}
func (l *linkWSS) listen(ctx context.Context, url *url.URL, _ string) (net.Listener, error) {
return nil, fmt.Errorf("WSS listener not supported, use WS listener behind reverse proxy instead")
}