feat: bind socket to a particular device

This commit is contained in:
hellodword 2022-05-23 18:13:24 +08:00
parent 31d34e5269
commit 32f35894cc
7 changed files with 93 additions and 2 deletions

View File

@ -63,6 +63,10 @@ type serverConfig struct {
User string `json:"user"` User string `json:"user"`
Password string `json:"password"` Password string `json:"password"`
} `json:"socks5_outbound"` } `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) { func (c *serverConfig) Speed() (uint64, uint64, error) {

View File

@ -15,6 +15,7 @@ import (
"github.com/tobyxdd/hysteria/pkg/core" "github.com/tobyxdd/hysteria/pkg/core"
"github.com/tobyxdd/hysteria/pkg/obfs" "github.com/tobyxdd/hysteria/pkg/obfs"
"github.com/tobyxdd/hysteria/pkg/pmtud_fix" "github.com/tobyxdd/hysteria/pkg/pmtud_fix"
"github.com/tobyxdd/hysteria/pkg/sockopt"
"github.com/tobyxdd/hysteria/pkg/transport" "github.com/tobyxdd/hysteria/pkg/transport"
"github.com/yosuke-furukawa/json5/encoding/json5" "github.com/yosuke-furukawa/json5/encoding/json5"
"io" "io"
@ -163,6 +164,33 @@ func server(config *serverConfig) {
} }
transport.DefaultServerTransport.SOCKS5Client = ob 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 // ACL
var aclEngine *acl.Engine var aclEngine *acl.Engine
if len(config.ACL) > 0 { if len(config.ACL) > 0 {

2
go.mod
View File

@ -22,6 +22,7 @@ require (
github.com/spf13/viper v1.11.0 github.com/spf13/viper v1.11.0
github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a github.com/txthinking/socks5 v0.0.0-20220212043548-414499347d4a
github.com/yosuke-furukawa/json5 v0.1.1 github.com/yosuke-furukawa/json5 v0.1.1
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
) )
require ( require (
@ -66,7 +67,6 @@ require (
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
golang.org/x/mod v0.5.0 // indirect golang.org/x/mod v0.5.0 // indirect
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // 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/text v0.3.7 // indirect
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect

23
pkg/sockopt/sockopt.go Normal file
View 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)
}

View 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)
}
})
}

View 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 }

View File

@ -8,6 +8,7 @@ import (
"github.com/tobyxdd/hysteria/pkg/conns/udp" "github.com/tobyxdd/hysteria/pkg/conns/udp"
"github.com/tobyxdd/hysteria/pkg/conns/wechat" "github.com/tobyxdd/hysteria/pkg/conns/wechat"
"github.com/tobyxdd/hysteria/pkg/obfs" "github.com/tobyxdd/hysteria/pkg/obfs"
"github.com/tobyxdd/hysteria/pkg/sockopt"
"github.com/tobyxdd/hysteria/pkg/utils" "github.com/tobyxdd/hysteria/pkg/utils"
"net" "net"
"strconv" "strconv"
@ -20,6 +21,8 @@ type ServerTransport struct {
PrefEnabled bool PrefEnabled bool
PrefIPv6 bool PrefIPv6 bool
PrefExclusive bool PrefExclusive bool
LocalAddrUDP *net.UDPAddr
Intf *net.Interface
} }
// AddrEx is like net.TCPAddr or net.UDPAddr, but with additional domain information for SOCKS5. // 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 { if st.SOCKS5Client != nil {
return st.SOCKS5Client.ListenUDP() return st.SOCKS5Client.ListenUDP()
} else { } else {
conn, err := net.ListenUDP("udp", nil) conn, err := net.ListenUDP("udp", st.LocalAddrUDP)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if st.Intf != nil {
err = sockopt.BindUDPConn("udp", conn, st.Intf)
if err != nil {
conn.Close()
return nil, err
}
}
return &udpConnPUDPConn{ return &udpConnPUDPConn{
Conn: conn, Conn: conn,
}, nil }, nil