mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-06-03 21:01:12 +08:00
daemon: Add Tailssh
This commit is contained in:
parent
72ce97f7c8
commit
3488377cf3
@ -7,4 +7,5 @@ type PlatformHandler interface {
|
||||
SetSystemProxyEnabled(enabled bool) error
|
||||
TriggerNativeCrash() error
|
||||
WriteDebugMessage(message string)
|
||||
ConnectSSHAgent() (int32, error)
|
||||
}
|
||||
|
||||
@ -1151,6 +1151,18 @@ func resolveOutbound(instance *Instance, tag string) (adapter.Outbound, error) {
|
||||
return outbound, nil
|
||||
}
|
||||
|
||||
func resolveTailscaleEndpoint(instance *Instance, tag string) (adapter.Endpoint, error) {
|
||||
endpointManager := service.FromContext[adapter.EndpointManager](instance.ctx)
|
||||
endpoint, loaded := endpointManager.Get(tag)
|
||||
if !loaded {
|
||||
return nil, E.New("endpoint not found: ", tag)
|
||||
}
|
||||
if endpoint.Type() != C.TypeTailscale {
|
||||
return nil, E.New("endpoint is not Tailscale: ", tag)
|
||||
}
|
||||
return endpoint, nil
|
||||
}
|
||||
|
||||
func (s *StartedService) StartNetworkQualityTest(
|
||||
request *NetworkQualityTestRequest,
|
||||
server grpc.ServerStreamingServer[NetworkQualityTestProgress],
|
||||
@ -1423,19 +1435,11 @@ func (s *StartedService) StartTailscalePing(
|
||||
boxService := s.instance
|
||||
s.serviceAccess.RUnlock()
|
||||
|
||||
endpointManager := service.FromContext[adapter.EndpointManager](boxService.ctx)
|
||||
if endpointManager == nil {
|
||||
return status.Error(codes.FailedPrecondition, "endpoint manager not available")
|
||||
}
|
||||
|
||||
var provider adapter.TailscaleEndpoint
|
||||
if request.EndpointTag != "" {
|
||||
endpoint, loaded := endpointManager.Get(request.EndpointTag)
|
||||
if !loaded {
|
||||
return status.Error(codes.NotFound, "endpoint not found: "+request.EndpointTag)
|
||||
}
|
||||
if endpoint.Type() != C.TypeTailscale {
|
||||
return status.Error(codes.InvalidArgument, "endpoint is not Tailscale: "+request.EndpointTag)
|
||||
endpoint, err := resolveTailscaleEndpoint(boxService, request.EndpointTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pingProvider, loaded := endpoint.(adapter.TailscaleEndpoint)
|
||||
if !loaded {
|
||||
@ -1443,6 +1447,10 @@ func (s *StartedService) StartTailscalePing(
|
||||
}
|
||||
provider = pingProvider
|
||||
} else {
|
||||
endpointManager := service.FromContext[adapter.EndpointManager](boxService.ctx)
|
||||
if endpointManager == nil {
|
||||
return status.Error(codes.FailedPrecondition, "endpoint manager not available")
|
||||
}
|
||||
for _, endpoint := range endpointManager.Endpoints() {
|
||||
if endpoint.Type() != C.TypeTailscale {
|
||||
continue
|
||||
@ -1479,19 +1487,9 @@ func (s *StartedService) SetTailscaleExitNode(ctx context.Context, request *SetT
|
||||
boxService := s.instance
|
||||
s.serviceAccess.RUnlock()
|
||||
|
||||
endpointManager := service.FromContext[adapter.EndpointManager](boxService.ctx)
|
||||
if endpointManager == nil {
|
||||
return nil, status.Error(codes.FailedPrecondition, "endpoint manager not available")
|
||||
}
|
||||
if request.EndpointTag == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "endpoint tag is required")
|
||||
}
|
||||
endpoint, loaded := endpointManager.Get(request.EndpointTag)
|
||||
if !loaded {
|
||||
return nil, status.Error(codes.NotFound, "endpoint not found: "+request.EndpointTag)
|
||||
}
|
||||
if endpoint.Type() != C.TypeTailscale {
|
||||
return nil, status.Error(codes.InvalidArgument, "endpoint is not Tailscale: "+request.EndpointTag)
|
||||
endpoint, err := resolveTailscaleEndpoint(boxService, request.EndpointTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tsEndpoint, loaded := endpoint.(adapter.TailscaleEndpoint)
|
||||
if !loaded {
|
||||
|
||||
@ -2820,6 +2820,690 @@ func (x *SetTailscaleExitNodeRequest) GetStableID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type TailscaleSSHClientMessage struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Types that are valid to be assigned to Message:
|
||||
//
|
||||
// *TailscaleSSHClientMessage_Start
|
||||
// *TailscaleSSHClientMessage_Input
|
||||
// *TailscaleSSHClientMessage_Resize
|
||||
Message isTailscaleSSHClientMessage_Message `protobuf_oneof:"message"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHClientMessage) Reset() {
|
||||
*x = TailscaleSSHClientMessage{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[38]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHClientMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHClientMessage) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHClientMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[38]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHClientMessage.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHClientMessage) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{38}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHClientMessage) GetMessage() isTailscaleSSHClientMessage_Message {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHClientMessage) GetStart() *TailscaleSSHStart {
|
||||
if x != nil {
|
||||
if x, ok := x.Message.(*TailscaleSSHClientMessage_Start); ok {
|
||||
return x.Start
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHClientMessage) GetInput() *TailscaleSSHInput {
|
||||
if x != nil {
|
||||
if x, ok := x.Message.(*TailscaleSSHClientMessage_Input); ok {
|
||||
return x.Input
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHClientMessage) GetResize() *TailscaleSSHResize {
|
||||
if x != nil {
|
||||
if x, ok := x.Message.(*TailscaleSSHClientMessage_Resize); ok {
|
||||
return x.Resize
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isTailscaleSSHClientMessage_Message interface {
|
||||
isTailscaleSSHClientMessage_Message()
|
||||
}
|
||||
|
||||
type TailscaleSSHClientMessage_Start struct {
|
||||
Start *TailscaleSSHStart `protobuf:"bytes,1,opt,name=start,proto3,oneof"`
|
||||
}
|
||||
|
||||
type TailscaleSSHClientMessage_Input struct {
|
||||
Input *TailscaleSSHInput `protobuf:"bytes,2,opt,name=input,proto3,oneof"`
|
||||
}
|
||||
|
||||
type TailscaleSSHClientMessage_Resize struct {
|
||||
Resize *TailscaleSSHResize `protobuf:"bytes,3,opt,name=resize,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*TailscaleSSHClientMessage_Start) isTailscaleSSHClientMessage_Message() {}
|
||||
|
||||
func (*TailscaleSSHClientMessage_Input) isTailscaleSSHClientMessage_Message() {}
|
||||
|
||||
func (*TailscaleSSHClientMessage_Resize) isTailscaleSSHClientMessage_Message() {}
|
||||
|
||||
type TailscaleSSHStart struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
EndpointTag string `protobuf:"bytes,1,opt,name=endpointTag,proto3" json:"endpointTag,omitempty"`
|
||||
PeerAddress string `protobuf:"bytes,2,opt,name=peerAddress,proto3" json:"peerAddress,omitempty"`
|
||||
Username string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"`
|
||||
TerminalType string `protobuf:"bytes,4,opt,name=terminalType,proto3" json:"terminalType,omitempty"`
|
||||
Columns int32 `protobuf:"varint,5,opt,name=columns,proto3" json:"columns,omitempty"`
|
||||
Rows int32 `protobuf:"varint,6,opt,name=rows,proto3" json:"rows,omitempty"`
|
||||
WidthPixels int32 `protobuf:"varint,7,opt,name=widthPixels,proto3" json:"widthPixels,omitempty"`
|
||||
HeightPixels int32 `protobuf:"varint,8,opt,name=heightPixels,proto3" json:"heightPixels,omitempty"`
|
||||
HostKeys []string `protobuf:"bytes,9,rep,name=hostKeys,proto3" json:"hostKeys,omitempty"`
|
||||
ForwardAgent bool `protobuf:"varint,10,opt,name=forward_agent,json=forwardAgent,proto3" json:"forward_agent,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) Reset() {
|
||||
*x = TailscaleSSHStart{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[39]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHStart) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHStart) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[39]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHStart.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHStart) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{39}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetEndpointTag() string {
|
||||
if x != nil {
|
||||
return x.EndpointTag
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetPeerAddress() string {
|
||||
if x != nil {
|
||||
return x.PeerAddress
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetUsername() string {
|
||||
if x != nil {
|
||||
return x.Username
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetTerminalType() string {
|
||||
if x != nil {
|
||||
return x.TerminalType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetColumns() int32 {
|
||||
if x != nil {
|
||||
return x.Columns
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetRows() int32 {
|
||||
if x != nil {
|
||||
return x.Rows
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetWidthPixels() int32 {
|
||||
if x != nil {
|
||||
return x.WidthPixels
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetHeightPixels() int32 {
|
||||
if x != nil {
|
||||
return x.HeightPixels
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetHostKeys() []string {
|
||||
if x != nil {
|
||||
return x.HostKeys
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHStart) GetForwardAgent() bool {
|
||||
if x != nil {
|
||||
return x.ForwardAgent
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type TailscaleSSHInput struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHInput) Reset() {
|
||||
*x = TailscaleSSHInput{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[40]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHInput) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHInput) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHInput) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[40]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHInput.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHInput) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{40}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHInput) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TailscaleSSHResize struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Columns int32 `protobuf:"varint,1,opt,name=columns,proto3" json:"columns,omitempty"`
|
||||
Rows int32 `protobuf:"varint,2,opt,name=rows,proto3" json:"rows,omitempty"`
|
||||
WidthPixels int32 `protobuf:"varint,3,opt,name=widthPixels,proto3" json:"widthPixels,omitempty"`
|
||||
HeightPixels int32 `protobuf:"varint,4,opt,name=heightPixels,proto3" json:"heightPixels,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHResize) Reset() {
|
||||
*x = TailscaleSSHResize{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[41]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHResize) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHResize) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHResize) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[41]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHResize.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHResize) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{41}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHResize) GetColumns() int32 {
|
||||
if x != nil {
|
||||
return x.Columns
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHResize) GetRows() int32 {
|
||||
if x != nil {
|
||||
return x.Rows
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHResize) GetWidthPixels() int32 {
|
||||
if x != nil {
|
||||
return x.WidthPixels
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHResize) GetHeightPixels() int32 {
|
||||
if x != nil {
|
||||
return x.HeightPixels
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type TailscaleSSHServerMessage struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Types that are valid to be assigned to Message:
|
||||
//
|
||||
// *TailscaleSSHServerMessage_AuthBanner
|
||||
// *TailscaleSSHServerMessage_Ready
|
||||
// *TailscaleSSHServerMessage_Output
|
||||
// *TailscaleSSHServerMessage_Exit
|
||||
// *TailscaleSSHServerMessage_Error
|
||||
Message isTailscaleSSHServerMessage_Message `protobuf_oneof:"message"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) Reset() {
|
||||
*x = TailscaleSSHServerMessage{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[42]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHServerMessage) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[42]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHServerMessage.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHServerMessage) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{42}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) GetMessage() isTailscaleSSHServerMessage_Message {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) GetAuthBanner() *TailscaleSSHAuthBanner {
|
||||
if x != nil {
|
||||
if x, ok := x.Message.(*TailscaleSSHServerMessage_AuthBanner); ok {
|
||||
return x.AuthBanner
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) GetReady() *TailscaleSSHReady {
|
||||
if x != nil {
|
||||
if x, ok := x.Message.(*TailscaleSSHServerMessage_Ready); ok {
|
||||
return x.Ready
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) GetOutput() *TailscaleSSHOutput {
|
||||
if x != nil {
|
||||
if x, ok := x.Message.(*TailscaleSSHServerMessage_Output); ok {
|
||||
return x.Output
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) GetExit() *TailscaleSSHExit {
|
||||
if x != nil {
|
||||
if x, ok := x.Message.(*TailscaleSSHServerMessage_Exit); ok {
|
||||
return x.Exit
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHServerMessage) GetError() *TailscaleSSHError {
|
||||
if x != nil {
|
||||
if x, ok := x.Message.(*TailscaleSSHServerMessage_Error); ok {
|
||||
return x.Error
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isTailscaleSSHServerMessage_Message interface {
|
||||
isTailscaleSSHServerMessage_Message()
|
||||
}
|
||||
|
||||
type TailscaleSSHServerMessage_AuthBanner struct {
|
||||
AuthBanner *TailscaleSSHAuthBanner `protobuf:"bytes,1,opt,name=authBanner,proto3,oneof"`
|
||||
}
|
||||
|
||||
type TailscaleSSHServerMessage_Ready struct {
|
||||
Ready *TailscaleSSHReady `protobuf:"bytes,2,opt,name=ready,proto3,oneof"`
|
||||
}
|
||||
|
||||
type TailscaleSSHServerMessage_Output struct {
|
||||
Output *TailscaleSSHOutput `protobuf:"bytes,3,opt,name=output,proto3,oneof"`
|
||||
}
|
||||
|
||||
type TailscaleSSHServerMessage_Exit struct {
|
||||
Exit *TailscaleSSHExit `protobuf:"bytes,4,opt,name=exit,proto3,oneof"`
|
||||
}
|
||||
|
||||
type TailscaleSSHServerMessage_Error struct {
|
||||
Error *TailscaleSSHError `protobuf:"bytes,5,opt,name=error,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*TailscaleSSHServerMessage_AuthBanner) isTailscaleSSHServerMessage_Message() {}
|
||||
|
||||
func (*TailscaleSSHServerMessage_Ready) isTailscaleSSHServerMessage_Message() {}
|
||||
|
||||
func (*TailscaleSSHServerMessage_Output) isTailscaleSSHServerMessage_Message() {}
|
||||
|
||||
func (*TailscaleSSHServerMessage_Exit) isTailscaleSSHServerMessage_Message() {}
|
||||
|
||||
func (*TailscaleSSHServerMessage_Error) isTailscaleSSHServerMessage_Message() {}
|
||||
|
||||
type TailscaleSSHAuthBanner struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHAuthBanner) Reset() {
|
||||
*x = TailscaleSSHAuthBanner{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[43]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHAuthBanner) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHAuthBanner) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHAuthBanner) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[43]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHAuthBanner.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHAuthBanner) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{43}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHAuthBanner) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type TailscaleSSHReady struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHReady) Reset() {
|
||||
*x = TailscaleSSHReady{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[44]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHReady) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHReady) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHReady) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[44]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHReady.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHReady) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{44}
|
||||
}
|
||||
|
||||
type TailscaleSSHOutput struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHOutput) Reset() {
|
||||
*x = TailscaleSSHOutput{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[45]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHOutput) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHOutput) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHOutput) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[45]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHOutput.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHOutput) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{45}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHOutput) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type TailscaleSSHExit struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ExitCode int32 `protobuf:"varint,1,opt,name=exitCode,proto3" json:"exitCode,omitempty"`
|
||||
Signal string `protobuf:"bytes,2,opt,name=signal,proto3" json:"signal,omitempty"`
|
||||
ErrorMessage string `protobuf:"bytes,3,opt,name=errorMessage,proto3" json:"errorMessage,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHExit) Reset() {
|
||||
*x = TailscaleSSHExit{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[46]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHExit) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHExit) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHExit) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[46]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHExit.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHExit) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{46}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHExit) GetExitCode() int32 {
|
||||
if x != nil {
|
||||
return x.ExitCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHExit) GetSignal() string {
|
||||
if x != nil {
|
||||
return x.Signal
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHExit) GetErrorMessage() string {
|
||||
if x != nil {
|
||||
return x.ErrorMessage
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type TailscaleSSHError struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHError) Reset() {
|
||||
*x = TailscaleSSHError{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[47]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHError) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TailscaleSSHError) ProtoMessage() {}
|
||||
|
||||
func (x *TailscaleSSHError) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[47]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TailscaleSSHError.ProtoReflect.Descriptor instead.
|
||||
func (*TailscaleSSHError) Descriptor() ([]byte, []int) {
|
||||
return file_daemon_started_service_proto_rawDescGZIP(), []int{47}
|
||||
}
|
||||
|
||||
func (x *TailscaleSSHError) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Log_Message struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Level LogLevel `protobuf:"varint,1,opt,name=level,proto3,enum=daemon.LogLevel" json:"level,omitempty"`
|
||||
@ -2830,7 +3514,7 @@ type Log_Message struct {
|
||||
|
||||
func (x *Log_Message) Reset() {
|
||||
*x = Log_Message{}
|
||||
mi := &file_daemon_started_service_proto_msgTypes[38]
|
||||
mi := &file_daemon_started_service_proto_msgTypes[48]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -2842,7 +3526,7 @@ func (x *Log_Message) String() string {
|
||||
func (*Log_Message) ProtoMessage() {}
|
||||
|
||||
func (x *Log_Message) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_daemon_started_service_proto_msgTypes[38]
|
||||
mi := &file_daemon_started_service_proto_msgTypes[48]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -3096,7 +3780,51 @@ const file_daemon_started_service_proto_rawDesc = "" +
|
||||
"\x05error\x18\x06 \x01(\tR\x05error\"[\n" +
|
||||
"\x1bSetTailscaleExitNodeRequest\x12 \n" +
|
||||
"\vendpointTag\x18\x01 \x01(\tR\vendpointTag\x12\x1a\n" +
|
||||
"\bstableID\x18\x02 \x01(\tR\bstableID*U\n" +
|
||||
"\bstableID\x18\x02 \x01(\tR\bstableID\"\xc2\x01\n" +
|
||||
"\x19TailscaleSSHClientMessage\x121\n" +
|
||||
"\x05start\x18\x01 \x01(\v2\x19.daemon.TailscaleSSHStartH\x00R\x05start\x121\n" +
|
||||
"\x05input\x18\x02 \x01(\v2\x19.daemon.TailscaleSSHInputH\x00R\x05input\x124\n" +
|
||||
"\x06resize\x18\x03 \x01(\v2\x1a.daemon.TailscaleSSHResizeH\x00R\x06resizeB\t\n" +
|
||||
"\amessage\"\xcc\x02\n" +
|
||||
"\x11TailscaleSSHStart\x12 \n" +
|
||||
"\vendpointTag\x18\x01 \x01(\tR\vendpointTag\x12 \n" +
|
||||
"\vpeerAddress\x18\x02 \x01(\tR\vpeerAddress\x12\x1a\n" +
|
||||
"\busername\x18\x03 \x01(\tR\busername\x12\"\n" +
|
||||
"\fterminalType\x18\x04 \x01(\tR\fterminalType\x12\x18\n" +
|
||||
"\acolumns\x18\x05 \x01(\x05R\acolumns\x12\x12\n" +
|
||||
"\x04rows\x18\x06 \x01(\x05R\x04rows\x12 \n" +
|
||||
"\vwidthPixels\x18\a \x01(\x05R\vwidthPixels\x12\"\n" +
|
||||
"\fheightPixels\x18\b \x01(\x05R\fheightPixels\x12\x1a\n" +
|
||||
"\bhostKeys\x18\t \x03(\tR\bhostKeys\x12#\n" +
|
||||
"\rforward_agent\x18\n" +
|
||||
" \x01(\bR\fforwardAgent\"'\n" +
|
||||
"\x11TailscaleSSHInput\x12\x12\n" +
|
||||
"\x04data\x18\x01 \x01(\fR\x04data\"\x88\x01\n" +
|
||||
"\x12TailscaleSSHResize\x12\x18\n" +
|
||||
"\acolumns\x18\x01 \x01(\x05R\acolumns\x12\x12\n" +
|
||||
"\x04rows\x18\x02 \x01(\x05R\x04rows\x12 \n" +
|
||||
"\vwidthPixels\x18\x03 \x01(\x05R\vwidthPixels\x12\"\n" +
|
||||
"\fheightPixels\x18\x04 \x01(\x05R\fheightPixels\"\xb4\x02\n" +
|
||||
"\x19TailscaleSSHServerMessage\x12@\n" +
|
||||
"\n" +
|
||||
"authBanner\x18\x01 \x01(\v2\x1e.daemon.TailscaleSSHAuthBannerH\x00R\n" +
|
||||
"authBanner\x121\n" +
|
||||
"\x05ready\x18\x02 \x01(\v2\x19.daemon.TailscaleSSHReadyH\x00R\x05ready\x124\n" +
|
||||
"\x06output\x18\x03 \x01(\v2\x1a.daemon.TailscaleSSHOutputH\x00R\x06output\x12.\n" +
|
||||
"\x04exit\x18\x04 \x01(\v2\x18.daemon.TailscaleSSHExitH\x00R\x04exit\x121\n" +
|
||||
"\x05error\x18\x05 \x01(\v2\x19.daemon.TailscaleSSHErrorH\x00R\x05errorB\t\n" +
|
||||
"\amessage\"2\n" +
|
||||
"\x16TailscaleSSHAuthBanner\x12\x18\n" +
|
||||
"\amessage\x18\x01 \x01(\tR\amessage\"\x13\n" +
|
||||
"\x11TailscaleSSHReady\"(\n" +
|
||||
"\x12TailscaleSSHOutput\x12\x12\n" +
|
||||
"\x04data\x18\x01 \x01(\fR\x04data\"j\n" +
|
||||
"\x10TailscaleSSHExit\x12\x1a\n" +
|
||||
"\bexitCode\x18\x01 \x01(\x05R\bexitCode\x12\x16\n" +
|
||||
"\x06signal\x18\x02 \x01(\tR\x06signal\x12\"\n" +
|
||||
"\ferrorMessage\x18\x03 \x01(\tR\ferrorMessage\"-\n" +
|
||||
"\x11TailscaleSSHError\x12\x18\n" +
|
||||
"\amessage\x18\x01 \x01(\tR\amessage*U\n" +
|
||||
"\bLogLevel\x12\t\n" +
|
||||
"\x05PANIC\x10\x00\x12\t\n" +
|
||||
"\x05FATAL\x10\x01\x12\t\n" +
|
||||
@ -3108,7 +3836,7 @@ const file_daemon_started_service_proto_rawDesc = "" +
|
||||
"\x13ConnectionEventType\x12\x18\n" +
|
||||
"\x14CONNECTION_EVENT_NEW\x10\x00\x12\x1b\n" +
|
||||
"\x17CONNECTION_EVENT_UPDATE\x10\x01\x12\x1b\n" +
|
||||
"\x17CONNECTION_EVENT_CLOSED\x10\x022\xf0\x10\n" +
|
||||
"\x17CONNECTION_EVENT_CLOSED\x10\x022\xd8\x11\n" +
|
||||
"\x0eStartedService\x12=\n" +
|
||||
"\vStopService\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12?\n" +
|
||||
"\rReloadService\x12\x16.google.protobuf.Empty\x1a\x16.google.protobuf.Empty\x12K\n" +
|
||||
@ -3138,7 +3866,8 @@ const file_daemon_started_service_proto_rawDesc = "" +
|
||||
"\rStartSTUNTest\x12\x17.daemon.STUNTestRequest\x1a\x18.daemon.STUNTestProgress\"\x000\x01\x12U\n" +
|
||||
"\x18SubscribeTailscaleStatus\x12\x16.google.protobuf.Empty\x1a\x1d.daemon.TailscaleStatusUpdate\"\x000\x01\x12U\n" +
|
||||
"\x12StartTailscalePing\x12\x1c.daemon.TailscalePingRequest\x1a\x1d.daemon.TailscalePingResponse\"\x000\x01\x12U\n" +
|
||||
"\x14SetTailscaleExitNode\x12#.daemon.SetTailscaleExitNodeRequest\x1a\x16.google.protobuf.Empty\"\x00B%Z#github.com/sagernet/sing-box/daemonb\x06proto3"
|
||||
"\x14SetTailscaleExitNode\x12#.daemon.SetTailscaleExitNodeRequest\x1a\x16.google.protobuf.Empty\"\x00\x12f\n" +
|
||||
"\x18StartTailscaleSSHSession\x12!.daemon.TailscaleSSHClientMessage\x1a!.daemon.TailscaleSSHServerMessage\"\x00(\x010\x01B%Z#github.com/sagernet/sing-box/daemonb\x06proto3"
|
||||
|
||||
var (
|
||||
file_daemon_started_service_proto_rawDescOnce sync.Once
|
||||
@ -3154,7 +3883,7 @@ func file_daemon_started_service_proto_rawDescGZIP() []byte {
|
||||
|
||||
var (
|
||||
file_daemon_started_service_proto_enumTypes = make([]protoimpl.EnumInfo, 4)
|
||||
file_daemon_started_service_proto_msgTypes = make([]protoimpl.MessageInfo, 39)
|
||||
file_daemon_started_service_proto_msgTypes = make([]protoimpl.MessageInfo, 49)
|
||||
file_daemon_started_service_proto_goTypes = []any{
|
||||
(LogLevel)(0), // 0: daemon.LogLevel
|
||||
(ConnectionEventType)(0), // 1: daemon.ConnectionEventType
|
||||
@ -3198,14 +3927,24 @@ var (
|
||||
(*TailscalePingRequest)(nil), // 39: daemon.TailscalePingRequest
|
||||
(*TailscalePingResponse)(nil), // 40: daemon.TailscalePingResponse
|
||||
(*SetTailscaleExitNodeRequest)(nil), // 41: daemon.SetTailscaleExitNodeRequest
|
||||
(*Log_Message)(nil), // 42: daemon.Log.Message
|
||||
(*emptypb.Empty)(nil), // 43: google.protobuf.Empty
|
||||
(*TailscaleSSHClientMessage)(nil), // 42: daemon.TailscaleSSHClientMessage
|
||||
(*TailscaleSSHStart)(nil), // 43: daemon.TailscaleSSHStart
|
||||
(*TailscaleSSHInput)(nil), // 44: daemon.TailscaleSSHInput
|
||||
(*TailscaleSSHResize)(nil), // 45: daemon.TailscaleSSHResize
|
||||
(*TailscaleSSHServerMessage)(nil), // 46: daemon.TailscaleSSHServerMessage
|
||||
(*TailscaleSSHAuthBanner)(nil), // 47: daemon.TailscaleSSHAuthBanner
|
||||
(*TailscaleSSHReady)(nil), // 48: daemon.TailscaleSSHReady
|
||||
(*TailscaleSSHOutput)(nil), // 49: daemon.TailscaleSSHOutput
|
||||
(*TailscaleSSHExit)(nil), // 50: daemon.TailscaleSSHExit
|
||||
(*TailscaleSSHError)(nil), // 51: daemon.TailscaleSSHError
|
||||
(*Log_Message)(nil), // 52: daemon.Log.Message
|
||||
(*emptypb.Empty)(nil), // 53: google.protobuf.Empty
|
||||
}
|
||||
)
|
||||
|
||||
var file_daemon_started_service_proto_depIdxs = []int32{
|
||||
2, // 0: daemon.ServiceStatus.status:type_name -> daemon.ServiceStatus.Type
|
||||
42, // 1: daemon.Log.messages:type_name -> daemon.Log.Message
|
||||
52, // 1: daemon.Log.messages:type_name -> daemon.Log.Message
|
||||
0, // 2: daemon.DefaultLogLevel.level:type_name -> daemon.LogLevel
|
||||
11, // 3: daemon.Groups.group:type_name -> daemon.Group
|
||||
12, // 4: daemon.Group.items:type_name -> daemon.GroupItem
|
||||
@ -3221,70 +3960,80 @@ var file_daemon_started_service_proto_depIdxs = []int32{
|
||||
37, // 14: daemon.TailscaleEndpointStatus.userGroups:type_name -> daemon.TailscaleUserGroup
|
||||
38, // 15: daemon.TailscaleEndpointStatus.exitNode:type_name -> daemon.TailscalePeer
|
||||
38, // 16: daemon.TailscaleUserGroup.peers:type_name -> daemon.TailscalePeer
|
||||
0, // 17: daemon.Log.Message.level:type_name -> daemon.LogLevel
|
||||
43, // 18: daemon.StartedService.StopService:input_type -> google.protobuf.Empty
|
||||
43, // 19: daemon.StartedService.ReloadService:input_type -> google.protobuf.Empty
|
||||
43, // 20: daemon.StartedService.SubscribeServiceStatus:input_type -> google.protobuf.Empty
|
||||
43, // 21: daemon.StartedService.SubscribeLog:input_type -> google.protobuf.Empty
|
||||
43, // 22: daemon.StartedService.GetDefaultLogLevel:input_type -> google.protobuf.Empty
|
||||
43, // 23: daemon.StartedService.ClearLogs:input_type -> google.protobuf.Empty
|
||||
6, // 24: daemon.StartedService.SubscribeStatus:input_type -> daemon.SubscribeStatusRequest
|
||||
43, // 25: daemon.StartedService.SubscribeGroups:input_type -> google.protobuf.Empty
|
||||
43, // 26: daemon.StartedService.GetClashModeStatus:input_type -> google.protobuf.Empty
|
||||
43, // 27: daemon.StartedService.SubscribeClashMode:input_type -> google.protobuf.Empty
|
||||
16, // 28: daemon.StartedService.SetClashMode:input_type -> daemon.ClashMode
|
||||
13, // 29: daemon.StartedService.URLTest:input_type -> daemon.URLTestRequest
|
||||
14, // 30: daemon.StartedService.SelectOutbound:input_type -> daemon.SelectOutboundRequest
|
||||
15, // 31: daemon.StartedService.SetGroupExpand:input_type -> daemon.SetGroupExpandRequest
|
||||
43, // 32: daemon.StartedService.GetSystemProxyStatus:input_type -> google.protobuf.Empty
|
||||
19, // 33: daemon.StartedService.SetSystemProxyEnabled:input_type -> daemon.SetSystemProxyEnabledRequest
|
||||
20, // 34: daemon.StartedService.TriggerDebugCrash:input_type -> daemon.DebugCrashRequest
|
||||
43, // 35: daemon.StartedService.TriggerOOMReport:input_type -> google.protobuf.Empty
|
||||
21, // 36: daemon.StartedService.SubscribeConnections:input_type -> daemon.SubscribeConnectionsRequest
|
||||
26, // 37: daemon.StartedService.CloseConnection:input_type -> daemon.CloseConnectionRequest
|
||||
43, // 38: daemon.StartedService.CloseAllConnections:input_type -> google.protobuf.Empty
|
||||
43, // 39: daemon.StartedService.GetDeprecatedWarnings:input_type -> google.protobuf.Empty
|
||||
43, // 40: daemon.StartedService.GetStartedAt:input_type -> google.protobuf.Empty
|
||||
43, // 41: daemon.StartedService.SubscribeOutbounds:input_type -> google.protobuf.Empty
|
||||
31, // 42: daemon.StartedService.StartNetworkQualityTest:input_type -> daemon.NetworkQualityTestRequest
|
||||
33, // 43: daemon.StartedService.StartSTUNTest:input_type -> daemon.STUNTestRequest
|
||||
43, // 44: daemon.StartedService.SubscribeTailscaleStatus:input_type -> google.protobuf.Empty
|
||||
39, // 45: daemon.StartedService.StartTailscalePing:input_type -> daemon.TailscalePingRequest
|
||||
41, // 46: daemon.StartedService.SetTailscaleExitNode:input_type -> daemon.SetTailscaleExitNodeRequest
|
||||
43, // 47: daemon.StartedService.StopService:output_type -> google.protobuf.Empty
|
||||
43, // 48: daemon.StartedService.ReloadService:output_type -> google.protobuf.Empty
|
||||
4, // 49: daemon.StartedService.SubscribeServiceStatus:output_type -> daemon.ServiceStatus
|
||||
7, // 50: daemon.StartedService.SubscribeLog:output_type -> daemon.Log
|
||||
8, // 51: daemon.StartedService.GetDefaultLogLevel:output_type -> daemon.DefaultLogLevel
|
||||
43, // 52: daemon.StartedService.ClearLogs:output_type -> google.protobuf.Empty
|
||||
9, // 53: daemon.StartedService.SubscribeStatus:output_type -> daemon.Status
|
||||
10, // 54: daemon.StartedService.SubscribeGroups:output_type -> daemon.Groups
|
||||
17, // 55: daemon.StartedService.GetClashModeStatus:output_type -> daemon.ClashModeStatus
|
||||
16, // 56: daemon.StartedService.SubscribeClashMode:output_type -> daemon.ClashMode
|
||||
43, // 57: daemon.StartedService.SetClashMode:output_type -> google.protobuf.Empty
|
||||
43, // 58: daemon.StartedService.URLTest:output_type -> google.protobuf.Empty
|
||||
43, // 59: daemon.StartedService.SelectOutbound:output_type -> google.protobuf.Empty
|
||||
43, // 60: daemon.StartedService.SetGroupExpand:output_type -> google.protobuf.Empty
|
||||
18, // 61: daemon.StartedService.GetSystemProxyStatus:output_type -> daemon.SystemProxyStatus
|
||||
43, // 62: daemon.StartedService.SetSystemProxyEnabled:output_type -> google.protobuf.Empty
|
||||
43, // 63: daemon.StartedService.TriggerDebugCrash:output_type -> google.protobuf.Empty
|
||||
43, // 64: daemon.StartedService.TriggerOOMReport:output_type -> google.protobuf.Empty
|
||||
23, // 65: daemon.StartedService.SubscribeConnections:output_type -> daemon.ConnectionEvents
|
||||
43, // 66: daemon.StartedService.CloseConnection:output_type -> google.protobuf.Empty
|
||||
43, // 67: daemon.StartedService.CloseAllConnections:output_type -> google.protobuf.Empty
|
||||
27, // 68: daemon.StartedService.GetDeprecatedWarnings:output_type -> daemon.DeprecatedWarnings
|
||||
29, // 69: daemon.StartedService.GetStartedAt:output_type -> daemon.StartedAt
|
||||
30, // 70: daemon.StartedService.SubscribeOutbounds:output_type -> daemon.OutboundList
|
||||
32, // 71: daemon.StartedService.StartNetworkQualityTest:output_type -> daemon.NetworkQualityTestProgress
|
||||
34, // 72: daemon.StartedService.StartSTUNTest:output_type -> daemon.STUNTestProgress
|
||||
35, // 73: daemon.StartedService.SubscribeTailscaleStatus:output_type -> daemon.TailscaleStatusUpdate
|
||||
40, // 74: daemon.StartedService.StartTailscalePing:output_type -> daemon.TailscalePingResponse
|
||||
43, // 75: daemon.StartedService.SetTailscaleExitNode:output_type -> google.protobuf.Empty
|
||||
47, // [47:76] is the sub-list for method output_type
|
||||
18, // [18:47] is the sub-list for method input_type
|
||||
18, // [18:18] is the sub-list for extension type_name
|
||||
18, // [18:18] is the sub-list for extension extendee
|
||||
0, // [0:18] is the sub-list for field type_name
|
||||
43, // 17: daemon.TailscaleSSHClientMessage.start:type_name -> daemon.TailscaleSSHStart
|
||||
44, // 18: daemon.TailscaleSSHClientMessage.input:type_name -> daemon.TailscaleSSHInput
|
||||
45, // 19: daemon.TailscaleSSHClientMessage.resize:type_name -> daemon.TailscaleSSHResize
|
||||
47, // 20: daemon.TailscaleSSHServerMessage.authBanner:type_name -> daemon.TailscaleSSHAuthBanner
|
||||
48, // 21: daemon.TailscaleSSHServerMessage.ready:type_name -> daemon.TailscaleSSHReady
|
||||
49, // 22: daemon.TailscaleSSHServerMessage.output:type_name -> daemon.TailscaleSSHOutput
|
||||
50, // 23: daemon.TailscaleSSHServerMessage.exit:type_name -> daemon.TailscaleSSHExit
|
||||
51, // 24: daemon.TailscaleSSHServerMessage.error:type_name -> daemon.TailscaleSSHError
|
||||
0, // 25: daemon.Log.Message.level:type_name -> daemon.LogLevel
|
||||
53, // 26: daemon.StartedService.StopService:input_type -> google.protobuf.Empty
|
||||
53, // 27: daemon.StartedService.ReloadService:input_type -> google.protobuf.Empty
|
||||
53, // 28: daemon.StartedService.SubscribeServiceStatus:input_type -> google.protobuf.Empty
|
||||
53, // 29: daemon.StartedService.SubscribeLog:input_type -> google.protobuf.Empty
|
||||
53, // 30: daemon.StartedService.GetDefaultLogLevel:input_type -> google.protobuf.Empty
|
||||
53, // 31: daemon.StartedService.ClearLogs:input_type -> google.protobuf.Empty
|
||||
6, // 32: daemon.StartedService.SubscribeStatus:input_type -> daemon.SubscribeStatusRequest
|
||||
53, // 33: daemon.StartedService.SubscribeGroups:input_type -> google.protobuf.Empty
|
||||
53, // 34: daemon.StartedService.GetClashModeStatus:input_type -> google.protobuf.Empty
|
||||
53, // 35: daemon.StartedService.SubscribeClashMode:input_type -> google.protobuf.Empty
|
||||
16, // 36: daemon.StartedService.SetClashMode:input_type -> daemon.ClashMode
|
||||
13, // 37: daemon.StartedService.URLTest:input_type -> daemon.URLTestRequest
|
||||
14, // 38: daemon.StartedService.SelectOutbound:input_type -> daemon.SelectOutboundRequest
|
||||
15, // 39: daemon.StartedService.SetGroupExpand:input_type -> daemon.SetGroupExpandRequest
|
||||
53, // 40: daemon.StartedService.GetSystemProxyStatus:input_type -> google.protobuf.Empty
|
||||
19, // 41: daemon.StartedService.SetSystemProxyEnabled:input_type -> daemon.SetSystemProxyEnabledRequest
|
||||
20, // 42: daemon.StartedService.TriggerDebugCrash:input_type -> daemon.DebugCrashRequest
|
||||
53, // 43: daemon.StartedService.TriggerOOMReport:input_type -> google.protobuf.Empty
|
||||
21, // 44: daemon.StartedService.SubscribeConnections:input_type -> daemon.SubscribeConnectionsRequest
|
||||
26, // 45: daemon.StartedService.CloseConnection:input_type -> daemon.CloseConnectionRequest
|
||||
53, // 46: daemon.StartedService.CloseAllConnections:input_type -> google.protobuf.Empty
|
||||
53, // 47: daemon.StartedService.GetDeprecatedWarnings:input_type -> google.protobuf.Empty
|
||||
53, // 48: daemon.StartedService.GetStartedAt:input_type -> google.protobuf.Empty
|
||||
53, // 49: daemon.StartedService.SubscribeOutbounds:input_type -> google.protobuf.Empty
|
||||
31, // 50: daemon.StartedService.StartNetworkQualityTest:input_type -> daemon.NetworkQualityTestRequest
|
||||
33, // 51: daemon.StartedService.StartSTUNTest:input_type -> daemon.STUNTestRequest
|
||||
53, // 52: daemon.StartedService.SubscribeTailscaleStatus:input_type -> google.protobuf.Empty
|
||||
39, // 53: daemon.StartedService.StartTailscalePing:input_type -> daemon.TailscalePingRequest
|
||||
41, // 54: daemon.StartedService.SetTailscaleExitNode:input_type -> daemon.SetTailscaleExitNodeRequest
|
||||
42, // 55: daemon.StartedService.StartTailscaleSSHSession:input_type -> daemon.TailscaleSSHClientMessage
|
||||
53, // 56: daemon.StartedService.StopService:output_type -> google.protobuf.Empty
|
||||
53, // 57: daemon.StartedService.ReloadService:output_type -> google.protobuf.Empty
|
||||
4, // 58: daemon.StartedService.SubscribeServiceStatus:output_type -> daemon.ServiceStatus
|
||||
7, // 59: daemon.StartedService.SubscribeLog:output_type -> daemon.Log
|
||||
8, // 60: daemon.StartedService.GetDefaultLogLevel:output_type -> daemon.DefaultLogLevel
|
||||
53, // 61: daemon.StartedService.ClearLogs:output_type -> google.protobuf.Empty
|
||||
9, // 62: daemon.StartedService.SubscribeStatus:output_type -> daemon.Status
|
||||
10, // 63: daemon.StartedService.SubscribeGroups:output_type -> daemon.Groups
|
||||
17, // 64: daemon.StartedService.GetClashModeStatus:output_type -> daemon.ClashModeStatus
|
||||
16, // 65: daemon.StartedService.SubscribeClashMode:output_type -> daemon.ClashMode
|
||||
53, // 66: daemon.StartedService.SetClashMode:output_type -> google.protobuf.Empty
|
||||
53, // 67: daemon.StartedService.URLTest:output_type -> google.protobuf.Empty
|
||||
53, // 68: daemon.StartedService.SelectOutbound:output_type -> google.protobuf.Empty
|
||||
53, // 69: daemon.StartedService.SetGroupExpand:output_type -> google.protobuf.Empty
|
||||
18, // 70: daemon.StartedService.GetSystemProxyStatus:output_type -> daemon.SystemProxyStatus
|
||||
53, // 71: daemon.StartedService.SetSystemProxyEnabled:output_type -> google.protobuf.Empty
|
||||
53, // 72: daemon.StartedService.TriggerDebugCrash:output_type -> google.protobuf.Empty
|
||||
53, // 73: daemon.StartedService.TriggerOOMReport:output_type -> google.protobuf.Empty
|
||||
23, // 74: daemon.StartedService.SubscribeConnections:output_type -> daemon.ConnectionEvents
|
||||
53, // 75: daemon.StartedService.CloseConnection:output_type -> google.protobuf.Empty
|
||||
53, // 76: daemon.StartedService.CloseAllConnections:output_type -> google.protobuf.Empty
|
||||
27, // 77: daemon.StartedService.GetDeprecatedWarnings:output_type -> daemon.DeprecatedWarnings
|
||||
29, // 78: daemon.StartedService.GetStartedAt:output_type -> daemon.StartedAt
|
||||
30, // 79: daemon.StartedService.SubscribeOutbounds:output_type -> daemon.OutboundList
|
||||
32, // 80: daemon.StartedService.StartNetworkQualityTest:output_type -> daemon.NetworkQualityTestProgress
|
||||
34, // 81: daemon.StartedService.StartSTUNTest:output_type -> daemon.STUNTestProgress
|
||||
35, // 82: daemon.StartedService.SubscribeTailscaleStatus:output_type -> daemon.TailscaleStatusUpdate
|
||||
40, // 83: daemon.StartedService.StartTailscalePing:output_type -> daemon.TailscalePingResponse
|
||||
53, // 84: daemon.StartedService.SetTailscaleExitNode:output_type -> google.protobuf.Empty
|
||||
46, // 85: daemon.StartedService.StartTailscaleSSHSession:output_type -> daemon.TailscaleSSHServerMessage
|
||||
56, // [56:86] is the sub-list for method output_type
|
||||
26, // [26:56] is the sub-list for method input_type
|
||||
26, // [26:26] is the sub-list for extension type_name
|
||||
26, // [26:26] is the sub-list for extension extendee
|
||||
0, // [0:26] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_daemon_started_service_proto_init() }
|
||||
@ -3292,13 +4041,25 @@ func file_daemon_started_service_proto_init() {
|
||||
if File_daemon_started_service_proto != nil {
|
||||
return
|
||||
}
|
||||
file_daemon_started_service_proto_msgTypes[38].OneofWrappers = []any{
|
||||
(*TailscaleSSHClientMessage_Start)(nil),
|
||||
(*TailscaleSSHClientMessage_Input)(nil),
|
||||
(*TailscaleSSHClientMessage_Resize)(nil),
|
||||
}
|
||||
file_daemon_started_service_proto_msgTypes[42].OneofWrappers = []any{
|
||||
(*TailscaleSSHServerMessage_AuthBanner)(nil),
|
||||
(*TailscaleSSHServerMessage_Ready)(nil),
|
||||
(*TailscaleSSHServerMessage_Output)(nil),
|
||||
(*TailscaleSSHServerMessage_Exit)(nil),
|
||||
(*TailscaleSSHServerMessage_Error)(nil),
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_daemon_started_service_proto_rawDesc), len(file_daemon_started_service_proto_rawDesc)),
|
||||
NumEnums: 4,
|
||||
NumMessages: 39,
|
||||
NumMessages: 49,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@ -41,6 +41,7 @@ service StartedService {
|
||||
rpc SubscribeTailscaleStatus(google.protobuf.Empty) returns (stream TailscaleStatusUpdate) {}
|
||||
rpc StartTailscalePing(TailscalePingRequest) returns (stream TailscalePingResponse) {}
|
||||
rpc SetTailscaleExitNode(SetTailscaleExitNodeRequest) returns (google.protobuf.Empty) {}
|
||||
rpc StartTailscaleSSHSession(stream TailscaleSSHClientMessage) returns (stream TailscaleSSHServerMessage) {}
|
||||
}
|
||||
|
||||
message ServiceStatus {
|
||||
@ -341,3 +342,66 @@ message SetTailscaleExitNodeRequest {
|
||||
string endpointTag = 1;
|
||||
string stableID = 2;
|
||||
}
|
||||
|
||||
message TailscaleSSHClientMessage {
|
||||
oneof message {
|
||||
TailscaleSSHStart start = 1;
|
||||
TailscaleSSHInput input = 2;
|
||||
TailscaleSSHResize resize = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message TailscaleSSHStart {
|
||||
string endpointTag = 1;
|
||||
string peerAddress = 2;
|
||||
string username = 3;
|
||||
string terminalType = 4;
|
||||
int32 columns = 5;
|
||||
int32 rows = 6;
|
||||
int32 widthPixels = 7;
|
||||
int32 heightPixels = 8;
|
||||
repeated string hostKeys = 9;
|
||||
bool forward_agent = 10;
|
||||
}
|
||||
|
||||
message TailscaleSSHInput {
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
message TailscaleSSHResize {
|
||||
int32 columns = 1;
|
||||
int32 rows = 2;
|
||||
int32 widthPixels = 3;
|
||||
int32 heightPixels = 4;
|
||||
}
|
||||
|
||||
message TailscaleSSHServerMessage {
|
||||
oneof message {
|
||||
TailscaleSSHAuthBanner authBanner = 1;
|
||||
TailscaleSSHReady ready = 2;
|
||||
TailscaleSSHOutput output = 3;
|
||||
TailscaleSSHExit exit = 4;
|
||||
TailscaleSSHError error = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message TailscaleSSHAuthBanner {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
message TailscaleSSHReady {
|
||||
}
|
||||
|
||||
message TailscaleSSHOutput {
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
message TailscaleSSHExit {
|
||||
int32 exitCode = 1;
|
||||
string signal = 2;
|
||||
string errorMessage = 3;
|
||||
}
|
||||
|
||||
message TailscaleSSHError {
|
||||
string message = 1;
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ const (
|
||||
StartedService_SubscribeTailscaleStatus_FullMethodName = "/daemon.StartedService/SubscribeTailscaleStatus"
|
||||
StartedService_StartTailscalePing_FullMethodName = "/daemon.StartedService/StartTailscalePing"
|
||||
StartedService_SetTailscaleExitNode_FullMethodName = "/daemon.StartedService/SetTailscaleExitNode"
|
||||
StartedService_StartTailscaleSSHSession_FullMethodName = "/daemon.StartedService/StartTailscaleSSHSession"
|
||||
)
|
||||
|
||||
// StartedServiceClient is the client API for StartedService service.
|
||||
@ -79,6 +80,7 @@ type StartedServiceClient interface {
|
||||
SubscribeTailscaleStatus(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (grpc.ServerStreamingClient[TailscaleStatusUpdate], error)
|
||||
StartTailscalePing(ctx context.Context, in *TailscalePingRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[TailscalePingResponse], error)
|
||||
SetTailscaleExitNode(ctx context.Context, in *SetTailscaleExitNodeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
StartTailscaleSSHSession(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[TailscaleSSHClientMessage, TailscaleSSHServerMessage], error)
|
||||
}
|
||||
|
||||
type startedServiceClient struct {
|
||||
@ -478,6 +480,19 @@ func (c *startedServiceClient) SetTailscaleExitNode(ctx context.Context, in *Set
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *startedServiceClient) StartTailscaleSSHSession(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[TailscaleSSHClientMessage, TailscaleSSHServerMessage], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &StartedService_ServiceDesc.Streams[11], StartedService_StartTailscaleSSHSession_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[TailscaleSSHClientMessage, TailscaleSSHServerMessage]{ClientStream: stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type StartedService_StartTailscaleSSHSessionClient = grpc.BidiStreamingClient[TailscaleSSHClientMessage, TailscaleSSHServerMessage]
|
||||
|
||||
// StartedServiceServer is the server API for StartedService service.
|
||||
// All implementations must embed UnimplementedStartedServiceServer
|
||||
// for forward compatibility.
|
||||
@ -511,6 +526,7 @@ type StartedServiceServer interface {
|
||||
SubscribeTailscaleStatus(*emptypb.Empty, grpc.ServerStreamingServer[TailscaleStatusUpdate]) error
|
||||
StartTailscalePing(*TailscalePingRequest, grpc.ServerStreamingServer[TailscalePingResponse]) error
|
||||
SetTailscaleExitNode(context.Context, *SetTailscaleExitNodeRequest) (*emptypb.Empty, error)
|
||||
StartTailscaleSSHSession(grpc.BidiStreamingServer[TailscaleSSHClientMessage, TailscaleSSHServerMessage]) error
|
||||
mustEmbedUnimplementedStartedServiceServer()
|
||||
}
|
||||
|
||||
@ -636,6 +652,10 @@ func (UnimplementedStartedServiceServer) StartTailscalePing(*TailscalePingReques
|
||||
func (UnimplementedStartedServiceServer) SetTailscaleExitNode(context.Context, *SetTailscaleExitNodeRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SetTailscaleExitNode not implemented")
|
||||
}
|
||||
|
||||
func (UnimplementedStartedServiceServer) StartTailscaleSSHSession(grpc.BidiStreamingServer[TailscaleSSHClientMessage, TailscaleSSHServerMessage]) error {
|
||||
return status.Error(codes.Unimplemented, "method StartTailscaleSSHSession not implemented")
|
||||
}
|
||||
func (UnimplementedStartedServiceServer) mustEmbedUnimplementedStartedServiceServer() {}
|
||||
func (UnimplementedStartedServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
@ -1102,6 +1122,13 @@ func _StartedService_SetTailscaleExitNode_Handler(srv interface{}, ctx context.C
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _StartedService_StartTailscaleSSHSession_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(StartedServiceServer).StartTailscaleSSHSession(&grpc.GenericServerStream[TailscaleSSHClientMessage, TailscaleSSHServerMessage]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type StartedService_StartTailscaleSSHSessionServer = grpc.BidiStreamingServer[TailscaleSSHClientMessage, TailscaleSSHServerMessage]
|
||||
|
||||
// StartedService_ServiceDesc is the grpc.ServiceDesc for StartedService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@ -1238,6 +1265,12 @@ var StartedService_ServiceDesc = grpc.ServiceDesc{
|
||||
Handler: _StartedService_StartTailscalePing_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "StartTailscaleSSHSession",
|
||||
Handler: _StartedService_StartTailscaleSSHSession_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "daemon/started_service.proto",
|
||||
}
|
||||
|
||||
340
daemon/started_service_tailscale_ssh.go
Normal file
340
daemon/started_service_tailscale_ssh.go
Normal file
@ -0,0 +1,340 @@
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/agent"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type windowChangeRequest struct {
|
||||
Columns uint32
|
||||
Rows uint32
|
||||
WidthPixels uint32
|
||||
HeightPixels uint32
|
||||
}
|
||||
|
||||
func (s *StartedService) StartTailscaleSSHSession(
|
||||
server grpc.BidiStreamingServer[TailscaleSSHClientMessage, TailscaleSSHServerMessage],
|
||||
) error {
|
||||
ctx := server.Context()
|
||||
err := s.waitForStarted(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.serviceAccess.RLock()
|
||||
boxService := s.instance
|
||||
s.serviceAccess.RUnlock()
|
||||
|
||||
firstMessage, err := server.Recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
start := firstMessage.GetStart()
|
||||
|
||||
hostKeys := make([]ssh.PublicKey, 0, len(start.HostKeys))
|
||||
for _, line := range start.HostKeys {
|
||||
key, _, _, _, parseErr := ssh.ParseAuthorizedKey([]byte(line))
|
||||
if parseErr != nil {
|
||||
return E.Cause(parseErr, "parse host key")
|
||||
}
|
||||
hostKeys = append(hostKeys, key)
|
||||
}
|
||||
|
||||
endpoint, err := resolveTailscaleEndpoint(boxService, start.EndpointTag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
peerAddr := M.ParseSocksaddrHostPort(start.PeerAddress, 22)
|
||||
|
||||
sessionCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
var sendAccess sync.Mutex
|
||||
sendMessage := func(msg *TailscaleSSHServerMessage) {
|
||||
sendAccess.Lock()
|
||||
defer sendAccess.Unlock()
|
||||
sendErr := server.Send(msg)
|
||||
if sendErr != nil {
|
||||
cancel()
|
||||
}
|
||||
}
|
||||
|
||||
finishWithError := func(message string) error {
|
||||
sendMessage(&TailscaleSSHServerMessage{
|
||||
Message: &TailscaleSSHServerMessage_Error{Error: &TailscaleSSHError{Message: message}},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
peerConn, err := endpoint.DialContext(ctx, N.NetworkTCP, peerAddr)
|
||||
if err != nil {
|
||||
return finishWithError(E.Cause(err, "dial peer").Error())
|
||||
}
|
||||
|
||||
var lastBanner string
|
||||
config := &ssh.ClientConfig{
|
||||
User: start.Username,
|
||||
Auth: nil,
|
||||
BannerCallback: func(message string) error {
|
||||
lastBanner = message
|
||||
sendMessage(&TailscaleSSHServerMessage{
|
||||
Message: &TailscaleSSHServerMessage_AuthBanner{
|
||||
AuthBanner: &TailscaleSSHAuthBanner{Message: message},
|
||||
},
|
||||
})
|
||||
return nil
|
||||
},
|
||||
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
|
||||
serverKey := key.Marshal()
|
||||
for _, hostKey := range hostKeys {
|
||||
if bytes.Equal(serverKey, hostKey.Marshal()) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return E.New("untrusted host key: ", key.Type())
|
||||
},
|
||||
}
|
||||
sshConn, chans, reqs, err := ssh.NewClientConn(peerConn, peerAddr.String(), config)
|
||||
if err != nil {
|
||||
common.Close(peerConn)
|
||||
banner := strings.TrimSpace(lastBanner)
|
||||
if banner != "" {
|
||||
return finishWithError(banner)
|
||||
}
|
||||
return finishWithError(E.Cause(err, "ssh handshake").Error())
|
||||
}
|
||||
sshClient := ssh.NewClient(sshConn, chans, reqs)
|
||||
|
||||
if start.ForwardAgent {
|
||||
agentChannels := sshClient.HandleChannelOpen("auth-agent@openssh.com")
|
||||
if agentChannels != nil {
|
||||
go func() {
|
||||
for newChannel := range agentChannels {
|
||||
channel, reqs, acceptErr := newChannel.Accept()
|
||||
if acceptErr != nil {
|
||||
continue
|
||||
}
|
||||
go ssh.DiscardRequests(reqs)
|
||||
go s.forwardSSHAgentChannel(channel)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
sshSession, err := sshClient.NewSession()
|
||||
if err != nil {
|
||||
common.Close(sshClient)
|
||||
return finishWithError(E.Cause(err, "open ssh session").Error())
|
||||
}
|
||||
|
||||
cols := int(start.Columns)
|
||||
rows := int(start.Rows)
|
||||
err = sshSession.RequestPty(start.TerminalType, rows, cols, ssh.TerminalModes{
|
||||
ssh.ECHO: 1,
|
||||
ssh.ECHOE: 1,
|
||||
ssh.ECHOK: 1,
|
||||
ssh.ECHOKE: 1,
|
||||
ssh.ECHOCTL: 1,
|
||||
ssh.ICANON: 1,
|
||||
ssh.ISIG: 1,
|
||||
ssh.IEXTEN: 1,
|
||||
ssh.ICRNL: 1,
|
||||
ssh.IXON: 1,
|
||||
ssh.IXANY: 1,
|
||||
ssh.IMAXBEL: 1,
|
||||
ssh.OPOST: 1,
|
||||
ssh.ONLCR: 1,
|
||||
ssh.TTY_OP_ISPEED: 14400,
|
||||
ssh.TTY_OP_OSPEED: 14400,
|
||||
})
|
||||
if err != nil {
|
||||
common.Close(sshSession, sshClient)
|
||||
return finishWithError(E.Cause(err, "request pty").Error())
|
||||
}
|
||||
if start.WidthPixels > 0 || start.HeightPixels > 0 {
|
||||
_, _ = sshSession.SendRequest("window-change", false, ssh.Marshal(&windowChangeRequest{
|
||||
Columns: uint32(start.Columns),
|
||||
Rows: uint32(start.Rows),
|
||||
WidthPixels: uint32(start.WidthPixels),
|
||||
HeightPixels: uint32(start.HeightPixels),
|
||||
}))
|
||||
}
|
||||
|
||||
if start.ForwardAgent {
|
||||
err = agent.RequestAgentForwarding(sshSession)
|
||||
if err != nil {
|
||||
common.Close(sshSession, sshClient)
|
||||
return finishWithError(E.Cause(err, "request agent forwarding").Error())
|
||||
}
|
||||
}
|
||||
|
||||
stdin, err := sshSession.StdinPipe()
|
||||
if err != nil {
|
||||
common.Close(sshSession, sshClient)
|
||||
return finishWithError(E.Cause(err, "stdin pipe").Error())
|
||||
}
|
||||
stdout, err := sshSession.StdoutPipe()
|
||||
if err != nil {
|
||||
common.Close(sshSession, sshClient)
|
||||
return finishWithError(E.Cause(err, "stdout pipe").Error())
|
||||
}
|
||||
stderr, err := sshSession.StderrPipe()
|
||||
if err != nil {
|
||||
common.Close(sshSession, sshClient)
|
||||
return finishWithError(E.Cause(err, "stderr pipe").Error())
|
||||
}
|
||||
err = sshSession.Shell()
|
||||
if err != nil {
|
||||
common.Close(sshSession, sshClient)
|
||||
return finishWithError(E.Cause(err, "start shell").Error())
|
||||
}
|
||||
|
||||
var workersWg sync.WaitGroup
|
||||
|
||||
sendMessage(&TailscaleSSHServerMessage{
|
||||
Message: &TailscaleSSHServerMessage_Ready{Ready: &TailscaleSSHReady{}},
|
||||
})
|
||||
|
||||
workersWg.Add(1)
|
||||
go func() {
|
||||
defer workersWg.Done()
|
||||
for {
|
||||
msg, recvErr := server.Recv()
|
||||
if recvErr == io.EOF {
|
||||
stdin.Close()
|
||||
return
|
||||
}
|
||||
if recvErr != nil {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
switch m := msg.GetMessage().(type) {
|
||||
case *TailscaleSSHClientMessage_Input:
|
||||
if len(m.Input.Data) == 0 {
|
||||
continue
|
||||
}
|
||||
_, writeErr := stdin.Write(m.Input.Data)
|
||||
if writeErr != nil {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
case *TailscaleSSHClientMessage_Resize:
|
||||
_, _ = sshSession.SendRequest("window-change", false, ssh.Marshal(&windowChangeRequest{
|
||||
Columns: uint32(m.Resize.Columns),
|
||||
Rows: uint32(m.Resize.Rows),
|
||||
WidthPixels: uint32(m.Resize.WidthPixels),
|
||||
HeightPixels: uint32(m.Resize.HeightPixels),
|
||||
}))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
pumpReader := func(reader io.Reader) {
|
||||
defer workersWg.Done()
|
||||
buffer := buf.Get(buf.BufferSize)
|
||||
defer buf.Put(buffer)
|
||||
for {
|
||||
n, readErr := reader.Read(buffer)
|
||||
if n > 0 {
|
||||
sendMessage(&TailscaleSSHServerMessage{
|
||||
Message: &TailscaleSSHServerMessage_Output{Output: &TailscaleSSHOutput{Data: bytes.Clone(buffer[:n])}},
|
||||
})
|
||||
}
|
||||
if readErr != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
workersWg.Add(1)
|
||||
go pumpReader(stdout)
|
||||
workersWg.Add(1)
|
||||
go pumpReader(stderr)
|
||||
|
||||
workersWg.Add(1)
|
||||
go func() {
|
||||
defer workersWg.Done()
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-sessionCtx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
_, _, keepAliveErr := sshConn.SendRequest("keepalive@openssh.com", true, nil)
|
||||
if keepAliveErr != nil {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
workersWg.Add(1)
|
||||
go func() {
|
||||
defer workersWg.Done()
|
||||
waitErr := sshSession.Wait()
|
||||
exitMessage := &TailscaleSSHExit{}
|
||||
switch waitErrTyped := waitErr.(type) {
|
||||
case nil:
|
||||
case *ssh.ExitError:
|
||||
exitMessage.ExitCode = int32(waitErrTyped.ExitStatus())
|
||||
exitMessage.Signal = waitErrTyped.Signal()
|
||||
default:
|
||||
exitMessage.ErrorMessage = waitErrTyped.Error()
|
||||
}
|
||||
sendMessage(&TailscaleSSHServerMessage{
|
||||
Message: &TailscaleSSHServerMessage_Exit{Exit: exitMessage},
|
||||
})
|
||||
cancel()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
<-sessionCtx.Done()
|
||||
common.Close(peerConn, sshSession, sshClient)
|
||||
}()
|
||||
|
||||
workersWg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StartedService) forwardSSHAgentChannel(channel ssh.Channel) {
|
||||
defer channel.Close()
|
||||
fd, err := s.handler.ConnectSSHAgent()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
file := os.NewFile(uintptr(fd), "ssh-agent")
|
||||
conn, err := net.FileConn(file)
|
||||
file.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
io.Copy(conn, channel)
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
io.Copy(channel, conn)
|
||||
}()
|
||||
wg.Wait()
|
||||
}
|
||||
@ -2,6 +2,7 @@ package libbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -818,3 +819,125 @@ func (c *CommandClient) StartTailscalePing(endpointTag string, peerIP string, ha
|
||||
handler.OnPingResult(tailscalePingResultFromGRPC(event))
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CommandClient) StartTailscaleSSHSession(opts *TailscaleSSHOptions, handler TailscaleSSHHandler) (*TailscaleSSHSession, error) {
|
||||
client, err := c.getClientForCall()
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "start tailscale ssh session")
|
||||
}
|
||||
|
||||
streamCtx, cancel := context.WithCancel(context.Background())
|
||||
failStart := func(cause error, message string) (*TailscaleSSHSession, error) {
|
||||
cancel()
|
||||
if c.standalone {
|
||||
c.closeConnection()
|
||||
}
|
||||
return nil, E.Cause(cause, message)
|
||||
}
|
||||
|
||||
stream, err := client.StartTailscaleSSHSession(streamCtx)
|
||||
if err != nil {
|
||||
return failStart(err, "start tailscale ssh session")
|
||||
}
|
||||
|
||||
sendErr := stream.Send(&daemon.TailscaleSSHClientMessage{
|
||||
Message: &daemon.TailscaleSSHClientMessage_Start{Start: &daemon.TailscaleSSHStart{
|
||||
EndpointTag: opts.EndpointTag,
|
||||
PeerAddress: opts.PeerAddress,
|
||||
Username: opts.Username,
|
||||
TerminalType: opts.TerminalType,
|
||||
Columns: opts.Columns,
|
||||
Rows: opts.Rows,
|
||||
WidthPixels: opts.WidthPixels,
|
||||
HeightPixels: opts.HeightPixels,
|
||||
HostKeys: iteratorToArray[string](opts.HostKeys),
|
||||
ForwardAgent: opts.ForwardAgent,
|
||||
}},
|
||||
})
|
||||
if sendErr != nil {
|
||||
return failStart(sendErr, "send tailscale ssh start")
|
||||
}
|
||||
|
||||
session := &TailscaleSSHSession{
|
||||
stream: stream,
|
||||
inputCh: make(chan []byte, 8),
|
||||
resizeCh: make(chan tailscaleSSHResize, 1),
|
||||
ctx: streamCtx,
|
||||
cancel: cancel,
|
||||
closeDone: make(chan struct{}),
|
||||
}
|
||||
|
||||
session.wg.Add(1)
|
||||
go func() {
|
||||
defer session.wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-streamCtx.Done():
|
||||
return
|
||||
case data := <-session.inputCh:
|
||||
sendErr := stream.Send(&daemon.TailscaleSSHClientMessage{
|
||||
Message: &daemon.TailscaleSSHClientMessage_Input{Input: &daemon.TailscaleSSHInput{Data: data}},
|
||||
})
|
||||
if sendErr != nil {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
case resize := <-session.resizeCh:
|
||||
sendErr := stream.Send(&daemon.TailscaleSSHClientMessage{
|
||||
Message: &daemon.TailscaleSSHClientMessage_Resize{Resize: &daemon.TailscaleSSHResize{
|
||||
Columns: resize.columns,
|
||||
Rows: resize.rows,
|
||||
WidthPixels: resize.widthPixels,
|
||||
HeightPixels: resize.heightPixels,
|
||||
}},
|
||||
})
|
||||
if sendErr != nil {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
session.wg.Add(1)
|
||||
go func() {
|
||||
defer session.wg.Done()
|
||||
for {
|
||||
msg, recvErr := stream.Recv()
|
||||
if recvErr == io.EOF {
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
if recvErr != nil {
|
||||
handler.OnError(E.Cause(recvErr, "tailscale ssh recv").Error())
|
||||
cancel()
|
||||
return
|
||||
}
|
||||
switch payload := msg.GetMessage().(type) {
|
||||
case *daemon.TailscaleSSHServerMessage_AuthBanner:
|
||||
handler.OnAuthBanner(payload.AuthBanner.Message)
|
||||
case *daemon.TailscaleSSHServerMessage_Ready:
|
||||
handler.OnReady()
|
||||
case *daemon.TailscaleSSHServerMessage_Output:
|
||||
handler.OnOutput(payload.Output.Data)
|
||||
case *daemon.TailscaleSSHServerMessage_Exit:
|
||||
handler.OnExit(payload.Exit.ExitCode, payload.Exit.Signal, payload.Exit.ErrorMessage)
|
||||
cancel()
|
||||
return
|
||||
case *daemon.TailscaleSSHServerMessage_Error:
|
||||
handler.OnError(payload.Error.Message)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
standalone := c.standalone
|
||||
go func() {
|
||||
session.wg.Wait()
|
||||
close(session.closeDone)
|
||||
if standalone {
|
||||
c.closeConnection()
|
||||
}
|
||||
}()
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
@ -41,6 +41,7 @@ type CommandServerHandler interface {
|
||||
SetSystemProxyEnabled(enabled bool) error
|
||||
TriggerNativeCrash() error
|
||||
WriteDebugMessage(message string)
|
||||
ConnectSSHAgent() (int32, error)
|
||||
}
|
||||
|
||||
func NewCommandServer(handler CommandServerHandler, platformInterface PlatformInterface) (*CommandServer, error) {
|
||||
@ -286,3 +287,7 @@ func (h *platformHandler) TriggerNativeCrash() error {
|
||||
func (h *platformHandler) WriteDebugMessage(message string) {
|
||||
(*CommandServer)(h).handler.WriteDebugMessage(message)
|
||||
}
|
||||
|
||||
func (h *platformHandler) ConnectSSHAgent() (int32, error) {
|
||||
return (*CommandServer)(h).handler.ConnectSSHAgent()
|
||||
}
|
||||
|
||||
82
experimental/libbox/command_types_tailscale_ssh.go
Normal file
82
experimental/libbox/command_types_tailscale_ssh.go
Normal file
@ -0,0 +1,82 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/daemon"
|
||||
)
|
||||
|
||||
type TailscaleSSHOptions struct {
|
||||
EndpointTag string
|
||||
PeerAddress string
|
||||
Username string
|
||||
TerminalType string
|
||||
Columns int32
|
||||
Rows int32
|
||||
WidthPixels int32
|
||||
HeightPixels int32
|
||||
HostKeys StringIterator
|
||||
ForwardAgent bool
|
||||
}
|
||||
|
||||
type TailscaleSSHHandler interface {
|
||||
OnReady()
|
||||
OnOutput(data []byte)
|
||||
OnAuthBanner(message string)
|
||||
OnExit(exitCode int32, signal string, errorMessage string)
|
||||
OnError(message string)
|
||||
}
|
||||
|
||||
type tailscaleSSHResize struct {
|
||||
columns int32
|
||||
rows int32
|
||||
widthPixels int32
|
||||
heightPixels int32
|
||||
}
|
||||
|
||||
type TailscaleSSHSession struct {
|
||||
stream daemon.StartedService_StartTailscaleSSHSessionClient
|
||||
inputCh chan []byte
|
||||
resizeCh chan tailscaleSSHResize
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
wg sync.WaitGroup
|
||||
closeOnce sync.Once
|
||||
closeDone chan struct{}
|
||||
}
|
||||
|
||||
func (s *TailscaleSSHSession) SendInput(data []byte) error {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
return os.ErrClosed
|
||||
case s.inputCh <- bytes.Clone(data):
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TailscaleSSHSession) SendResize(columns int32, rows int32, widthPixels int32, heightPixels int32) error {
|
||||
resize := tailscaleSSHResize{
|
||||
columns: columns,
|
||||
rows: rows,
|
||||
widthPixels: widthPixels,
|
||||
heightPixels: heightPixels,
|
||||
}
|
||||
select {
|
||||
case s.resizeCh <- resize:
|
||||
return nil
|
||||
case <-s.ctx.Done():
|
||||
return os.ErrClosed
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TailscaleSSHSession) Close() error {
|
||||
s.closeOnce.Do(func() {
|
||||
s.cancel()
|
||||
_ = s.stream.CloseSend()
|
||||
})
|
||||
<-s.closeDone
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user