mirror of
https://github.com/apernet/hysteria.git
synced 2025-04-03 20:47:38 +03:00
fix: ipv{4,6}-only listen on wildcard address
fix: #797 when listening on a wildcard address like "0.0.0.0" or "[::]", hysteria actually listened on both IPv4 and IPv6. this is a well-known bug of the golang net package. this commit introduces a fix for that, the intended behavior will be: 0.0.0.0:443 => listen on IPv4 only [::]:443 => listen on IPv6 only :443 => listen on both IPv4 and IPv6
This commit is contained in:
parent
f48a5edd39
commit
e70838cd98
4 changed files with 108 additions and 8 deletions
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/apernet/hysteria/extras/correctnet"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -504,7 +505,7 @@ func clientSOCKS5(config socks5Config, c client.Client) error {
|
||||||
if config.Listen == "" {
|
if config.Listen == "" {
|
||||||
return configError{Field: "listen", Err: errors.New("listen address is empty")}
|
return configError{Field: "listen", Err: errors.New("listen address is empty")}
|
||||||
}
|
}
|
||||||
l, err := net.Listen("tcp", config.Listen)
|
l, err := correctnet.Listen("tcp", config.Listen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return configError{Field: "listen", Err: err}
|
return configError{Field: "listen", Err: err}
|
||||||
}
|
}
|
||||||
|
@ -529,7 +530,7 @@ func clientHTTP(config httpConfig, c client.Client) error {
|
||||||
if config.Listen == "" {
|
if config.Listen == "" {
|
||||||
return configError{Field: "listen", Err: errors.New("listen address is empty")}
|
return configError{Field: "listen", Err: errors.New("listen address is empty")}
|
||||||
}
|
}
|
||||||
l, err := net.Listen("tcp", config.Listen)
|
l, err := correctnet.Listen("tcp", config.Listen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return configError{Field: "listen", Err: err}
|
return configError{Field: "listen", Err: err}
|
||||||
}
|
}
|
||||||
|
@ -562,7 +563,7 @@ func clientTCPForwarding(entries []tcpForwardingEntry, c client.Client) error {
|
||||||
if e.Remote == "" {
|
if e.Remote == "" {
|
||||||
return configError{Field: "remote", Err: errors.New("remote address is empty")}
|
return configError{Field: "remote", Err: errors.New("remote address is empty")}
|
||||||
}
|
}
|
||||||
l, err := net.Listen("tcp", e.Listen)
|
l, err := correctnet.Listen("tcp", e.Listen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return configError{Field: "listen", Err: err}
|
return configError{Field: "listen", Err: err}
|
||||||
}
|
}
|
||||||
|
@ -589,7 +590,7 @@ func clientUDPForwarding(entries []udpForwardingEntry, c client.Client) error {
|
||||||
if e.Remote == "" {
|
if e.Remote == "" {
|
||||||
return configError{Field: "remote", Err: errors.New("remote address is empty")}
|
return configError{Field: "remote", Err: errors.New("remote address is empty")}
|
||||||
}
|
}
|
||||||
l, err := net.ListenPacket("udp", e.Listen)
|
l, err := correctnet.ListenPacket("udp", e.Listen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return configError{Field: "listen", Err: err}
|
return configError{Field: "listen", Err: err}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/apernet/hysteria/extras/correctnet"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
|
@ -219,7 +220,7 @@ func (c *serverConfig) fillConn(hyConfig *server.Config) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return configError{Field: "listen", Err: err}
|
return configError{Field: "listen", Err: err}
|
||||||
}
|
}
|
||||||
conn, err := net.ListenUDP("udp", uAddr)
|
conn, err := correctnet.ListenUDP("udp", uAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return configError{Field: "listen", Err: err}
|
return configError{Field: "listen", Err: err}
|
||||||
}
|
}
|
||||||
|
@ -752,7 +753,7 @@ func runServer(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
func runTrafficStatsServer(listen string, handler http.Handler) {
|
func runTrafficStatsServer(listen string, handler http.Handler) {
|
||||||
logger.Info("traffic stats server up and running", zap.String("listen", listen))
|
logger.Info("traffic stats server up and running", zap.String("listen", listen))
|
||||||
if err := http.ListenAndServe(listen, handler); err != nil {
|
if err := correctnet.HTTPListenAndServe(listen, handler); err != nil {
|
||||||
logger.Fatal("failed to serve traffic stats", zap.Error(err))
|
logger.Fatal("failed to serve traffic stats", zap.Error(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
92
extras/correctnet/correctnet.go
Normal file
92
extras/correctnet/correctnet.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package correctnet
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func extractIPFamily(ip net.IP) (family string) {
|
||||||
|
if len(ip) == 0 {
|
||||||
|
// real family independent wildcard address, such as ":443"
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if p4 := ip.To4(); len(p4) == net.IPv4len {
|
||||||
|
return "4"
|
||||||
|
}
|
||||||
|
return "6"
|
||||||
|
}
|
||||||
|
|
||||||
|
func tcpAddrNetwork(addr *net.TCPAddr) (network string) {
|
||||||
|
if addr == nil {
|
||||||
|
return "tcp"
|
||||||
|
}
|
||||||
|
return "tcp" + extractIPFamily(addr.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func udpAddrNetwork(addr *net.UDPAddr) (network string) {
|
||||||
|
if addr == nil {
|
||||||
|
return "udp"
|
||||||
|
}
|
||||||
|
return "udp" + extractIPFamily(addr.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipAddrNetwork(addr *net.IPAddr) (network string) {
|
||||||
|
if addr == nil {
|
||||||
|
return "ip"
|
||||||
|
}
|
||||||
|
return "ip" + extractIPFamily(addr.IP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Listen(network string, address string) (net.Listener, error) {
|
||||||
|
if network == "tcp" {
|
||||||
|
tcpAddr, err := net.ResolveTCPAddr(network, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ListenTCP(network, tcpAddr)
|
||||||
|
}
|
||||||
|
return net.Listen(network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListenTCP(network string, laddr *net.TCPAddr) (*net.TCPListener, error) {
|
||||||
|
if network == "tcp" {
|
||||||
|
return net.ListenTCP(tcpAddrNetwork(laddr), laddr)
|
||||||
|
}
|
||||||
|
return net.ListenTCP(network, laddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListenPacket(network string, address string) (listener net.PacketConn, err error) {
|
||||||
|
if network == "udp" {
|
||||||
|
udpAddr, err := net.ResolveUDPAddr(network, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ListenUDP(network, udpAddr)
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(network, "ip:") {
|
||||||
|
proto := network[3:]
|
||||||
|
ipAddr, err := net.ResolveIPAddr(proto, address)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return net.ListenIP(ipAddrNetwork(ipAddr)+":"+proto, ipAddr)
|
||||||
|
}
|
||||||
|
return net.ListenPacket(network, address)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListenUDP(network string, laddr *net.UDPAddr) (*net.UDPConn, error) {
|
||||||
|
if network == "udp" {
|
||||||
|
return net.ListenUDP(udpAddrNetwork(laddr), laddr)
|
||||||
|
}
|
||||||
|
return net.ListenUDP(network, laddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func HTTPListenAndServe(address string, handler http.Handler) (err error) {
|
||||||
|
listener, err := Listen("tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
return http.Serve(listener, handler)
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/apernet/hysteria/extras/correctnet"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
@ -20,7 +21,7 @@ type MasqTCPServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MasqTCPServer) ListenAndServeHTTP(addr string) error {
|
func (s *MasqTCPServer) ListenAndServeHTTP(addr string) error {
|
||||||
return http.ListenAndServe(addr, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return correctnet.HTTPListenAndServe(addr, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if s.ForceHTTPS {
|
if s.ForceHTTPS {
|
||||||
if s.HTTPSPort == 0 || s.HTTPSPort == 443 {
|
if s.HTTPSPort == 0 || s.HTTPSPort == 443 {
|
||||||
// Omit port if it's the default
|
// Omit port if it's the default
|
||||||
|
@ -42,7 +43,12 @@ func (s *MasqTCPServer) ListenAndServeHTTPS(addr string) error {
|
||||||
}),
|
}),
|
||||||
TLSConfig: s.TLSConfig,
|
TLSConfig: s.TLSConfig,
|
||||||
}
|
}
|
||||||
return server.ListenAndServeTLS("", "")
|
listener, err := correctnet.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer listener.Close()
|
||||||
|
return server.ServeTLS(listener, "", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ http.ResponseWriter = (*altSvcHijackResponseWriter)(nil)
|
var _ http.ResponseWriter = (*altSvcHijackResponseWriter)(nil)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue