mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-11-16 11:42:43 +08:00
feat: add ssh outbound (#1087)
* feat: add ssh outbound * fix: Modify the way to get dstAddr --------- Co-authored-by: trevid <trevidmy@gmail.com>
This commit is contained in:
parent
37b02b18f7
commit
0bb5568de9
98
adapter/outbound/ssh.go
Normal file
98
adapter/outbound/ssh.go
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
package outbound
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
CN "github.com/metacubex/mihomo/common/net"
|
||||||
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
|
C "github.com/metacubex/mihomo/constant"
|
||||||
|
"golang.org/x/crypto/ssh"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Ssh struct {
|
||||||
|
*Base
|
||||||
|
|
||||||
|
option *SshOption
|
||||||
|
client *ssh.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type SshOption struct {
|
||||||
|
BasicOption
|
||||||
|
Name string `proxy:"name"`
|
||||||
|
Server string `proxy:"server"`
|
||||||
|
Port int `proxy:"port"`
|
||||||
|
UserName string `proxy:"username"`
|
||||||
|
Password string `proxy:"password,omitempty"`
|
||||||
|
PrivateKey string `proxy:"privateKey,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Ssh) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
|
||||||
|
c, err := h.client.Dial("tcp", metadata.RemoteAddress())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewConn(CN.NewRefConn(c, h), h), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeSsh(h *Ssh) {
|
||||||
|
if h.client != nil {
|
||||||
|
_ = h.client.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSsh(option SshOption) (*Ssh, error) {
|
||||||
|
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
||||||
|
|
||||||
|
config := ssh.ClientConfig{
|
||||||
|
User: option.UserName,
|
||||||
|
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if option.Password == "" {
|
||||||
|
|
||||||
|
b, err := os.ReadFile(option.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pKey, err := ssh.ParsePrivateKey(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Auth = []ssh.AuthMethod{
|
||||||
|
ssh.PublicKeys(pKey),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config.Auth = []ssh.AuthMethod{
|
||||||
|
ssh.Password(option.Password),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := ssh.Dial("tcp", addr, &config)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
outbound := &Ssh{
|
||||||
|
Base: &Base{
|
||||||
|
name: option.Name,
|
||||||
|
addr: addr,
|
||||||
|
tp: C.Ssh,
|
||||||
|
udp: true,
|
||||||
|
iface: option.Interface,
|
||||||
|
rmark: option.RoutingMark,
|
||||||
|
prefer: C.NewDNSPrefer(option.IPVersion),
|
||||||
|
},
|
||||||
|
option: &option,
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
runtime.SetFinalizer(outbound, closeSsh)
|
||||||
|
|
||||||
|
return outbound, nil
|
||||||
|
}
|
|
@ -134,6 +134,13 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
proxy = outbound.NewRejectWithOption(*rejectOption)
|
proxy = outbound.NewRejectWithOption(*rejectOption)
|
||||||
|
case "ssh":
|
||||||
|
sshOption := &outbound.SshOption{}
|
||||||
|
err = decoder.Decode(mapping, sshOption)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
proxy, err = outbound.NewSsh(*sshOption)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupport proxy type: %s", proxyType)
|
return nil, fmt.Errorf("unsupport proxy type: %s", proxyType)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ const (
|
||||||
Hysteria2
|
Hysteria2
|
||||||
WireGuard
|
WireGuard
|
||||||
Tuic
|
Tuic
|
||||||
|
Ssh
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -222,7 +223,8 @@ func (at AdapterType) String() string {
|
||||||
return "URLTest"
|
return "URLTest"
|
||||||
case LoadBalance:
|
case LoadBalance:
|
||||||
return "LoadBalance"
|
return "LoadBalance"
|
||||||
|
case Ssh:
|
||||||
|
return "Ssh"
|
||||||
default:
|
default:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user