mirror of
https://github.com/cedar2025/hysteria.git
synced 2025-06-23 04:59:50 +00:00
feat: bind socket to a particular device
This commit is contained in:
parent
31d34e5269
commit
32f35894cc
@ -63,6 +63,10 @@ type serverConfig struct {
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
} `json:"socks5_outbound"`
|
||||
SocketConfig struct {
|
||||
BindAddress string `json:"bind_address"`
|
||||
BindToDevice string `json:"bind_to_device"`
|
||||
} `json:"socket_config"`
|
||||
}
|
||||
|
||||
func (c *serverConfig) Speed() (uint64, uint64, error) {
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"github.com/tobyxdd/hysteria/pkg/core"
|
||||
"github.com/tobyxdd/hysteria/pkg/obfs"
|
||||
"github.com/tobyxdd/hysteria/pkg/pmtud_fix"
|
||||
"github.com/tobyxdd/hysteria/pkg/sockopt"
|
||||
"github.com/tobyxdd/hysteria/pkg/transport"
|
||||
"github.com/yosuke-furukawa/json5/encoding/json5"
|
||||
"io"
|
||||
@ -163,6 +164,33 @@ func server(config *serverConfig) {
|
||||
}
|
||||
transport.DefaultServerTransport.SOCKS5Client = ob
|
||||
}
|
||||
// socket settings
|
||||
if config.SocketConfig.BindToDevice != "" {
|
||||
iface, err := net.InterfaceByName(config.SocketConfig.BindToDevice)
|
||||
if err != nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("Failed to get bind_to_device")
|
||||
}
|
||||
transport.DefaultServerTransport.Intf = iface
|
||||
sockopt.BindDialer(transport.DefaultServerTransport.Dialer, iface)
|
||||
}
|
||||
if config.SocketConfig.BindAddress != "" {
|
||||
ip := net.ParseIP(config.SocketConfig.BindAddress)
|
||||
if ip == nil {
|
||||
logrus.WithFields(logrus.Fields{
|
||||
"error": err,
|
||||
}).Fatal("Failed to parse bind_address")
|
||||
}
|
||||
transport.DefaultServerTransport.Dialer.LocalAddr = &net.TCPAddr{
|
||||
IP: ip,
|
||||
Port: 0,
|
||||
}
|
||||
transport.DefaultServerTransport.LocalAddrUDP = &net.UDPAddr{
|
||||
IP: ip,
|
||||
Port: 0,
|
||||
}
|
||||
}
|
||||
// ACL
|
||||
var aclEngine *acl.Engine
|
||||
if len(config.ACL) > 0 {
|
||||
|
2
go.mod
2
go.mod
@ -22,6 +22,7 @@ require (
|
||||
github.com/spf13/viper v1.11.0
|
||||
github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a
|
||||
github.com/yosuke-furukawa/json5 v0.1.1
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
|
||||
)
|
||||
|
||||
require (
|
||||
@ -66,7 +67,6 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||
golang.org/x/mod v0.5.0 // indirect
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
|
23
pkg/sockopt/sockopt.go
Normal file
23
pkg/sockopt/sockopt.go
Normal file
@ -0,0 +1,23 @@
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
//https://github.com/v2fly/v2ray-core/blob/4e247840821f3dd326722d4db02ee3c237074fc2/transport/internet/config.pb.go#L420-L426
|
||||
|
||||
func BindDialer(d *net.Dialer, intf *net.Interface) {
|
||||
d.Control = func(network, address string, c syscall.RawConn) error {
|
||||
return bindRawConn(network, c, intf)
|
||||
}
|
||||
}
|
||||
|
||||
func BindUDPConn(network string, conn *net.UDPConn, intf *net.Interface) error {
|
||||
c, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bindRawConn(network, c, intf)
|
||||
}
|
16
pkg/sockopt/sockopt_linux.go
Normal file
16
pkg/sockopt/sockopt_linux.go
Normal file
@ -0,0 +1,16 @@
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func bindRawConn(network string, c syscall.RawConn, bindIface *net.Interface) error {
|
||||
return c.Control(func(fd uintptr) {
|
||||
if bindIface != nil {
|
||||
unix.BindToDevice(int(fd), bindIface.Name)
|
||||
}
|
||||
})
|
||||
}
|
10
pkg/sockopt/sockopt_others.go
Normal file
10
pkg/sockopt/sockopt_others.go
Normal file
@ -0,0 +1,10 @@
|
||||
//go:build !linux
|
||||
|
||||
package sockopt
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func bindRawConn(network string, c syscall.RawConn, bindIface *net.Interface) error { return nil }
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/tobyxdd/hysteria/pkg/conns/udp"
|
||||
"github.com/tobyxdd/hysteria/pkg/conns/wechat"
|
||||
"github.com/tobyxdd/hysteria/pkg/obfs"
|
||||
"github.com/tobyxdd/hysteria/pkg/sockopt"
|
||||
"github.com/tobyxdd/hysteria/pkg/utils"
|
||||
"net"
|
||||
"strconv"
|
||||
@ -20,6 +21,8 @@ type ServerTransport struct {
|
||||
PrefEnabled bool
|
||||
PrefIPv6 bool
|
||||
PrefExclusive bool
|
||||
LocalAddrUDP *net.UDPAddr
|
||||
Intf *net.Interface
|
||||
}
|
||||
|
||||
// AddrEx is like net.TCPAddr or net.UDPAddr, but with additional domain information for SOCKS5.
|
||||
@ -164,10 +167,17 @@ func (st *ServerTransport) ListenUDP() (PUDPConn, error) {
|
||||
if st.SOCKS5Client != nil {
|
||||
return st.SOCKS5Client.ListenUDP()
|
||||
} else {
|
||||
conn, err := net.ListenUDP("udp", nil)
|
||||
conn, err := net.ListenUDP("udp", st.LocalAddrUDP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if st.Intf != nil {
|
||||
err = sockopt.BindUDPConn("udp", conn, st.Intf)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &udpConnPUDPConn{
|
||||
Conn: conn,
|
||||
}, nil
|
||||
|
Loading…
x
Reference in New Issue
Block a user