diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..94baf35 --- /dev/null +++ b/api/api.go @@ -0,0 +1,24 @@ +package api + +import ( + "context" + "github.com/p4gefau1t/trojan-go/log" + "github.com/p4gefau1t/trojan-go/statistic" +) + +type Handler func(ctx context.Context, auth statistic.Authenticator) error + +var handlers = map[string]Handler{} + +func RegisterHandler(name string, handler Handler) { + handlers[name] = handler +} + +func RunService(ctx context.Context, name string, auth statistic.Authenticator) error { + if h, ok := handlers[name]; ok { + log.Debug("api handler found", name) + return h(ctx, auth) + } + log.Debug("api handler not found", name) + return nil +} diff --git a/api/service/api.pb.go b/api/service/api.pb.go new file mode 100644 index 0000000..9e07af7 --- /dev/null +++ b/api/service/api.pb.go @@ -0,0 +1,1457 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.11.4 +// source: api.proto + +package service + +import ( + context "context" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type SetUsersRequest_Operation int32 + +const ( + SetUsersRequest_Add SetUsersRequest_Operation = 0 + SetUsersRequest_Delete SetUsersRequest_Operation = 1 + SetUsersRequest_Modify SetUsersRequest_Operation = 2 +) + +// Enum value maps for SetUsersRequest_Operation. +var ( + SetUsersRequest_Operation_name = map[int32]string{ + 0: "Add", + 1: "Delete", + 2: "Modify", + } + SetUsersRequest_Operation_value = map[string]int32{ + "Add": 0, + "Delete": 1, + "Modify": 2, + } +) + +func (x SetUsersRequest_Operation) Enum() *SetUsersRequest_Operation { + p := new(SetUsersRequest_Operation) + *p = x + return p +} + +func (x SetUsersRequest_Operation) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SetUsersRequest_Operation) Descriptor() protoreflect.EnumDescriptor { + return file_api_proto_enumTypes[0].Descriptor() +} + +func (SetUsersRequest_Operation) Type() protoreflect.EnumType { + return &file_api_proto_enumTypes[0] +} + +func (x SetUsersRequest_Operation) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SetUsersRequest_Operation.Descriptor instead. +func (SetUsersRequest_Operation) EnumDescriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{10, 0} +} + +type Traffic struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UploadTraffic uint64 `protobuf:"varint,1,opt,name=upload_traffic,json=uploadTraffic,proto3" json:"upload_traffic,omitempty"` + DownloadTraffic uint64 `protobuf:"varint,2,opt,name=download_traffic,json=downloadTraffic,proto3" json:"download_traffic,omitempty"` +} + +func (x *Traffic) Reset() { + *x = Traffic{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Traffic) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Traffic) ProtoMessage() {} + +func (x *Traffic) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Traffic.ProtoReflect.Descriptor instead. +func (*Traffic) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{0} +} + +func (x *Traffic) GetUploadTraffic() uint64 { + if x != nil { + return x.UploadTraffic + } + return 0 +} + +func (x *Traffic) GetDownloadTraffic() uint64 { + if x != nil { + return x.DownloadTraffic + } + return 0 +} + +type Speed struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UploadSpeed uint64 `protobuf:"varint,1,opt,name=upload_speed,json=uploadSpeed,proto3" json:"upload_speed,omitempty"` + DownloadSpeed uint64 `protobuf:"varint,2,opt,name=download_speed,json=downloadSpeed,proto3" json:"download_speed,omitempty"` +} + +func (x *Speed) Reset() { + *x = Speed{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Speed) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Speed) ProtoMessage() {} + +func (x *Speed) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Speed.ProtoReflect.Descriptor instead. +func (*Speed) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{1} +} + +func (x *Speed) GetUploadSpeed() uint64 { + if x != nil { + return x.UploadSpeed + } + return 0 +} + +func (x *Speed) GetDownloadSpeed() uint64 { + if x != nil { + return x.DownloadSpeed + } + return 0 +} + +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` + Hash string `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` //optional +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{2} +} + +func (x *User) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *User) GetHash() string { + if x != nil { + return x.Hash + } + return "" +} + +type UserStatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + TrafficTotal *Traffic `protobuf:"bytes,2,opt,name=traffic_total,json=trafficTotal,proto3" json:"traffic_total,omitempty"` + SpeedCurrent *Speed `protobuf:"bytes,3,opt,name=speed_current,json=speedCurrent,proto3" json:"speed_current,omitempty"` + SpeedLimit *Speed `protobuf:"bytes,4,opt,name=speed_limit,json=speedLimit,proto3" json:"speed_limit,omitempty"` + IpCurrent int32 `protobuf:"varint,5,opt,name=ip_current,json=ipCurrent,proto3" json:"ip_current,omitempty"` + IpLimit int32 `protobuf:"varint,6,opt,name=ip_limit,json=ipLimit,proto3" json:"ip_limit,omitempty"` +} + +func (x *UserStatus) Reset() { + *x = UserStatus{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserStatus) ProtoMessage() {} + +func (x *UserStatus) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserStatus.ProtoReflect.Descriptor instead. +func (*UserStatus) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{3} +} + +func (x *UserStatus) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +func (x *UserStatus) GetTrafficTotal() *Traffic { + if x != nil { + return x.TrafficTotal + } + return nil +} + +func (x *UserStatus) GetSpeedCurrent() *Speed { + if x != nil { + return x.SpeedCurrent + } + return nil +} + +func (x *UserStatus) GetSpeedLimit() *Speed { + if x != nil { + return x.SpeedLimit + } + return nil +} + +func (x *UserStatus) GetIpCurrent() int32 { + if x != nil { + return x.IpCurrent + } + return 0 +} + +func (x *UserStatus) GetIpLimit() int32 { + if x != nil { + return x.IpLimit + } + return 0 +} + +type GetTrafficRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` +} + +func (x *GetTrafficRequest) Reset() { + *x = GetTrafficRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTrafficRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTrafficRequest) ProtoMessage() {} + +func (x *GetTrafficRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTrafficRequest.ProtoReflect.Descriptor instead. +func (*GetTrafficRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{4} +} + +func (x *GetTrafficRequest) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +type GetTrafficResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + Info string `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + TrafficTotal *Traffic `protobuf:"bytes,3,opt,name=traffic_total,json=trafficTotal,proto3" json:"traffic_total,omitempty"` + SpeedCurrent *Speed `protobuf:"bytes,4,opt,name=speed_current,json=speedCurrent,proto3" json:"speed_current,omitempty"` +} + +func (x *GetTrafficResponse) Reset() { + *x = GetTrafficResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetTrafficResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetTrafficResponse) ProtoMessage() {} + +func (x *GetTrafficResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetTrafficResponse.ProtoReflect.Descriptor instead. +func (*GetTrafficResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{5} +} + +func (x *GetTrafficResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *GetTrafficResponse) GetInfo() string { + if x != nil { + return x.Info + } + return "" +} + +func (x *GetTrafficResponse) GetTrafficTotal() *Traffic { + if x != nil { + return x.TrafficTotal + } + return nil +} + +func (x *GetTrafficResponse) GetSpeedCurrent() *Speed { + if x != nil { + return x.SpeedCurrent + } + return nil +} + +type ListUsersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ListUsersRequest) Reset() { + *x = ListUsersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListUsersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUsersRequest) ProtoMessage() {} + +func (x *ListUsersRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListUsersRequest.ProtoReflect.Descriptor instead. +func (*ListUsersRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{6} +} + +type ListUsersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Status *UserStatus `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *ListUsersResponse) Reset() { + *x = ListUsersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListUsersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListUsersResponse) ProtoMessage() {} + +func (x *ListUsersResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListUsersResponse.ProtoReflect.Descriptor instead. +func (*ListUsersResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{7} +} + +func (x *ListUsersResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +func (x *ListUsersResponse) GetStatus() *UserStatus { + if x != nil { + return x.Status + } + return nil +} + +type GetUsersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` +} + +func (x *GetUsersRequest) Reset() { + *x = GetUsersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUsersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUsersRequest) ProtoMessage() {} + +func (x *GetUsersRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUsersRequest.ProtoReflect.Descriptor instead. +func (*GetUsersRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{8} +} + +func (x *GetUsersRequest) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +type GetUsersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + Info string `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + User *User `protobuf:"bytes,3,opt,name=user,proto3" json:"user,omitempty"` + Status *UserStatus `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` +} + +func (x *GetUsersResponse) Reset() { + *x = GetUsersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetUsersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetUsersResponse) ProtoMessage() {} + +func (x *GetUsersResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetUsersResponse.ProtoReflect.Descriptor instead. +func (*GetUsersResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{9} +} + +func (x *GetUsersResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *GetUsersResponse) GetInfo() string { + if x != nil { + return x.Info + } + return "" +} + +func (x *GetUsersResponse) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +func (x *GetUsersResponse) GetStatus() *UserStatus { + if x != nil { + return x.Status + } + return nil +} + +type SetUsersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Operation SetUsersRequest_Operation `protobuf:"varint,2,opt,name=operation,proto3,enum=trojan.api.SetUsersRequest_Operation" json:"operation,omitempty"` + SpeedLimit *Speed `protobuf:"bytes,3,opt,name=speed_limit,json=speedLimit,proto3" json:"speed_limit,omitempty"` + IpLimit int32 `protobuf:"varint,4,opt,name=ip_limit,json=ipLimit,proto3" json:"ip_limit,omitempty"` +} + +func (x *SetUsersRequest) Reset() { + *x = SetUsersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetUsersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetUsersRequest) ProtoMessage() {} + +func (x *SetUsersRequest) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetUsersRequest.ProtoReflect.Descriptor instead. +func (*SetUsersRequest) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{10} +} + +func (x *SetUsersRequest) GetUser() *User { + if x != nil { + return x.User + } + return nil +} + +func (x *SetUsersRequest) GetOperation() SetUsersRequest_Operation { + if x != nil { + return x.Operation + } + return SetUsersRequest_Add +} + +func (x *SetUsersRequest) GetSpeedLimit() *Speed { + if x != nil { + return x.SpeedLimit + } + return nil +} + +func (x *SetUsersRequest) GetIpLimit() int32 { + if x != nil { + return x.IpLimit + } + return 0 +} + +type SetUsersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"` + Info string `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` +} + +func (x *SetUsersResponse) Reset() { + *x = SetUsersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_api_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SetUsersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SetUsersResponse) ProtoMessage() {} + +func (x *SetUsersResponse) ProtoReflect() protoreflect.Message { + mi := &file_api_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SetUsersResponse.ProtoReflect.Descriptor instead. +func (*SetUsersResponse) Descriptor() ([]byte, []int) { + return file_api_proto_rawDescGZIP(), []int{11} +} + +func (x *SetUsersResponse) GetSuccess() bool { + if x != nil { + return x.Success + } + return false +} + +func (x *SetUsersResponse) GetInfo() string { + if x != nil { + return x.Info + } + return "" +} + +var File_api_proto protoreflect.FileDescriptor + +var file_api_proto_rawDesc = []byte{ + 0x0a, 0x09, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x74, 0x72, 0x6f, + 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x22, 0x5b, 0x0a, 0x07, 0x54, 0x72, 0x61, 0x66, 0x66, + 0x69, 0x63, 0x12, 0x25, 0x0a, 0x0e, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x72, 0x61, + 0x66, 0x66, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x75, 0x70, 0x6c, 0x6f, + 0x61, 0x64, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x72, 0x61, + 0x66, 0x66, 0x69, 0x63, 0x22, 0x51, 0x0a, 0x05, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x21, 0x0a, + 0x0c, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0b, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x53, 0x70, 0x65, 0x65, 0x64, + 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x73, 0x70, 0x65, + 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, + 0x61, 0x64, 0x53, 0x70, 0x65, 0x65, 0x64, 0x22, 0x36, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, + 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x68, + 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, + 0x92, 0x02, 0x0a, 0x0a, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, + 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, + 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, + 0x75, 0x73, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, + 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, + 0x52, 0x0c, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x36, + 0x0a, 0x0d, 0x73, 0x70, 0x65, 0x65, 0x64, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x53, 0x70, 0x65, 0x65, 0x64, 0x52, 0x0c, 0x73, 0x70, 0x65, 0x65, 0x64, 0x43, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x65, 0x64, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x72, + 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x70, 0x65, 0x65, 0x64, 0x52, 0x0a, + 0x73, 0x70, 0x65, 0x65, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x70, + 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, + 0x69, 0x70, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x70, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x69, 0x70, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x22, 0x39, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x66, 0x66, + 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, + 0xb4, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x69, 0x6e, 0x66, 0x6f, 0x12, 0x38, 0x0a, 0x0d, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x5f, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, + 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, + 0x52, 0x0c, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x36, + 0x0a, 0x0d, 0x73, 0x70, 0x65, 0x65, 0x64, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x53, 0x70, 0x65, 0x65, 0x64, 0x52, 0x0c, 0x73, 0x70, 0x65, 0x65, 0x64, 0x43, + 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x69, 0x0a, 0x11, 0x4c, 0x69, + 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x37, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x96, + 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, + 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x6e, 0x66, + 0x6f, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x10, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xf9, 0x01, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x75, + 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x72, 0x6f, 0x6a, + 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, + 0x72, 0x12, 0x43, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x0b, 0x73, 0x70, 0x65, 0x65, 0x64, 0x5f, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x72, + 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x70, 0x65, 0x65, 0x64, 0x52, 0x0a, + 0x73, 0x70, 0x65, 0x65, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x70, + 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x69, 0x70, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x2c, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x69, 0x66, + 0x79, 0x10, 0x02, 0x22, 0x40, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x69, 0x6e, 0x66, 0x6f, 0x32, 0x64, 0x0a, 0x13, 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x0a, + 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x12, 0x1d, 0x2e, 0x74, 0x72, 0x6f, + 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x66, 0x66, + 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x74, 0x72, 0x6f, 0x6a, + 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, + 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x32, 0xfd, 0x01, 0x0a, 0x13, + 0x54, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x12, 0x1c, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, + 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, + 0x01, 0x12, 0x4b, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, + 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x72, 0x6f, + 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x4b, + 0x0a, 0x08, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x74, 0x72, 0x6f, + 0x6a, 0x61, 0x6e, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x74, 0x72, 0x6f, 0x6a, 0x61, 0x6e, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x0b, 0x5a, 0x09, 0x2e, + 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_api_proto_rawDescOnce sync.Once + file_api_proto_rawDescData = file_api_proto_rawDesc +) + +func file_api_proto_rawDescGZIP() []byte { + file_api_proto_rawDescOnce.Do(func() { + file_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_proto_rawDescData) + }) + return file_api_proto_rawDescData +} + +var file_api_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_api_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_api_proto_goTypes = []interface{}{ + (SetUsersRequest_Operation)(0), // 0: trojan.api.SetUsersRequest.Operation + (*Traffic)(nil), // 1: trojan.api.Traffic + (*Speed)(nil), // 2: trojan.api.Speed + (*User)(nil), // 3: trojan.api.User + (*UserStatus)(nil), // 4: trojan.api.UserStatus + (*GetTrafficRequest)(nil), // 5: trojan.api.GetTrafficRequest + (*GetTrafficResponse)(nil), // 6: trojan.api.GetTrafficResponse + (*ListUsersRequest)(nil), // 7: trojan.api.ListUsersRequest + (*ListUsersResponse)(nil), // 8: trojan.api.ListUsersResponse + (*GetUsersRequest)(nil), // 9: trojan.api.GetUsersRequest + (*GetUsersResponse)(nil), // 10: trojan.api.GetUsersResponse + (*SetUsersRequest)(nil), // 11: trojan.api.SetUsersRequest + (*SetUsersResponse)(nil), // 12: trojan.api.SetUsersResponse +} +var file_api_proto_depIdxs = []int32{ + 3, // 0: trojan.api.UserStatus.user:type_name -> trojan.api.User + 1, // 1: trojan.api.UserStatus.traffic_total:type_name -> trojan.api.Traffic + 2, // 2: trojan.api.UserStatus.speed_current:type_name -> trojan.api.Speed + 2, // 3: trojan.api.UserStatus.speed_limit:type_name -> trojan.api.Speed + 3, // 4: trojan.api.GetTrafficRequest.user:type_name -> trojan.api.User + 1, // 5: trojan.api.GetTrafficResponse.traffic_total:type_name -> trojan.api.Traffic + 2, // 6: trojan.api.GetTrafficResponse.speed_current:type_name -> trojan.api.Speed + 3, // 7: trojan.api.ListUsersResponse.user:type_name -> trojan.api.User + 4, // 8: trojan.api.ListUsersResponse.status:type_name -> trojan.api.UserStatus + 3, // 9: trojan.api.GetUsersRequest.user:type_name -> trojan.api.User + 3, // 10: trojan.api.GetUsersResponse.user:type_name -> trojan.api.User + 4, // 11: trojan.api.GetUsersResponse.status:type_name -> trojan.api.UserStatus + 3, // 12: trojan.api.SetUsersRequest.user:type_name -> trojan.api.User + 0, // 13: trojan.api.SetUsersRequest.operation:type_name -> trojan.api.SetUsersRequest.Operation + 2, // 14: trojan.api.SetUsersRequest.speed_limit:type_name -> trojan.api.Speed + 5, // 15: trojan.api.TrojanClientService.GetTraffic:input_type -> trojan.api.GetTrafficRequest + 7, // 16: trojan.api.TrojanServerService.ListUsers:input_type -> trojan.api.ListUsersRequest + 9, // 17: trojan.api.TrojanServerService.GetUsers:input_type -> trojan.api.GetUsersRequest + 11, // 18: trojan.api.TrojanServerService.SetUsers:input_type -> trojan.api.SetUsersRequest + 6, // 19: trojan.api.TrojanClientService.GetTraffic:output_type -> trojan.api.GetTrafficResponse + 8, // 20: trojan.api.TrojanServerService.ListUsers:output_type -> trojan.api.ListUsersResponse + 10, // 21: trojan.api.TrojanServerService.GetUsers:output_type -> trojan.api.GetUsersResponse + 12, // 22: trojan.api.TrojanServerService.SetUsers:output_type -> trojan.api.SetUsersResponse + 19, // [19:23] is the sub-list for method output_type + 15, // [15:19] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name +} + +func init() { file_api_proto_init() } +func file_api_proto_init() { + if File_api_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Traffic); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Speed); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserStatus); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTrafficRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetTrafficResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListUsersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListUsersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUsersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUsersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetUsersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_api_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SetUsersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_api_proto_rawDesc, + NumEnums: 1, + NumMessages: 12, + NumExtensions: 0, + NumServices: 2, + }, + GoTypes: file_api_proto_goTypes, + DependencyIndexes: file_api_proto_depIdxs, + EnumInfos: file_api_proto_enumTypes, + MessageInfos: file_api_proto_msgTypes, + }.Build() + File_api_proto = out.File + file_api_proto_rawDesc = nil + file_api_proto_goTypes = nil + file_api_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// TrojanClientServiceClient is the client API for TrojanClientService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type TrojanClientServiceClient interface { + GetTraffic(ctx context.Context, in *GetTrafficRequest, opts ...grpc.CallOption) (*GetTrafficResponse, error) +} + +type trojanClientServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewTrojanClientServiceClient(cc grpc.ClientConnInterface) TrojanClientServiceClient { + return &trojanClientServiceClient{cc} +} + +func (c *trojanClientServiceClient) GetTraffic(ctx context.Context, in *GetTrafficRequest, opts ...grpc.CallOption) (*GetTrafficResponse, error) { + out := new(GetTrafficResponse) + err := c.cc.Invoke(ctx, "/trojan.api.TrojanClientService/GetTraffic", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// TrojanClientServiceServer is the server API for TrojanClientService service. +type TrojanClientServiceServer interface { + GetTraffic(context.Context, *GetTrafficRequest) (*GetTrafficResponse, error) +} + +// UnimplementedTrojanClientServiceServer can be embedded to have forward compatible implementations. +type UnimplementedTrojanClientServiceServer struct { +} + +func (*UnimplementedTrojanClientServiceServer) GetTraffic(context.Context, *GetTrafficRequest) (*GetTrafficResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTraffic not implemented") +} + +func RegisterTrojanClientServiceServer(s *grpc.Server, srv TrojanClientServiceServer) { + s.RegisterService(&_TrojanClientService_serviceDesc, srv) +} + +func _TrojanClientService_GetTraffic_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetTrafficRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TrojanClientServiceServer).GetTraffic(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/trojan.api.TrojanClientService/GetTraffic", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TrojanClientServiceServer).GetTraffic(ctx, req.(*GetTrafficRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _TrojanClientService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "trojan.api.TrojanClientService", + HandlerType: (*TrojanClientServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetTraffic", + Handler: _TrojanClientService_GetTraffic_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "api.proto", +} + +// TrojanServerServiceClient is the client API for TrojanServerService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type TrojanServerServiceClient interface { + // list all users + ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (TrojanServerService_ListUsersClient, error) + // obtain specified user's info + GetUsers(ctx context.Context, opts ...grpc.CallOption) (TrojanServerService_GetUsersClient, error) + // setup exsisting users' config + SetUsers(ctx context.Context, opts ...grpc.CallOption) (TrojanServerService_SetUsersClient, error) +} + +type trojanServerServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewTrojanServerServiceClient(cc grpc.ClientConnInterface) TrojanServerServiceClient { + return &trojanServerServiceClient{cc} +} + +func (c *trojanServerServiceClient) ListUsers(ctx context.Context, in *ListUsersRequest, opts ...grpc.CallOption) (TrojanServerService_ListUsersClient, error) { + stream, err := c.cc.NewStream(ctx, &_TrojanServerService_serviceDesc.Streams[0], "/trojan.api.TrojanServerService/ListUsers", opts...) + if err != nil { + return nil, err + } + x := &trojanServerServiceListUsersClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type TrojanServerService_ListUsersClient interface { + Recv() (*ListUsersResponse, error) + grpc.ClientStream +} + +type trojanServerServiceListUsersClient struct { + grpc.ClientStream +} + +func (x *trojanServerServiceListUsersClient) Recv() (*ListUsersResponse, error) { + m := new(ListUsersResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *trojanServerServiceClient) GetUsers(ctx context.Context, opts ...grpc.CallOption) (TrojanServerService_GetUsersClient, error) { + stream, err := c.cc.NewStream(ctx, &_TrojanServerService_serviceDesc.Streams[1], "/trojan.api.TrojanServerService/GetUsers", opts...) + if err != nil { + return nil, err + } + x := &trojanServerServiceGetUsersClient{stream} + return x, nil +} + +type TrojanServerService_GetUsersClient interface { + Send(*GetUsersRequest) error + Recv() (*GetUsersResponse, error) + grpc.ClientStream +} + +type trojanServerServiceGetUsersClient struct { + grpc.ClientStream +} + +func (x *trojanServerServiceGetUsersClient) Send(m *GetUsersRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *trojanServerServiceGetUsersClient) Recv() (*GetUsersResponse, error) { + m := new(GetUsersResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *trojanServerServiceClient) SetUsers(ctx context.Context, opts ...grpc.CallOption) (TrojanServerService_SetUsersClient, error) { + stream, err := c.cc.NewStream(ctx, &_TrojanServerService_serviceDesc.Streams[2], "/trojan.api.TrojanServerService/SetUsers", opts...) + if err != nil { + return nil, err + } + x := &trojanServerServiceSetUsersClient{stream} + return x, nil +} + +type TrojanServerService_SetUsersClient interface { + Send(*SetUsersRequest) error + Recv() (*SetUsersResponse, error) + grpc.ClientStream +} + +type trojanServerServiceSetUsersClient struct { + grpc.ClientStream +} + +func (x *trojanServerServiceSetUsersClient) Send(m *SetUsersRequest) error { + return x.ClientStream.SendMsg(m) +} + +func (x *trojanServerServiceSetUsersClient) Recv() (*SetUsersResponse, error) { + m := new(SetUsersResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// TrojanServerServiceServer is the server API for TrojanServerService service. +type TrojanServerServiceServer interface { + // list all users + ListUsers(*ListUsersRequest, TrojanServerService_ListUsersServer) error + // obtain specified user's info + GetUsers(TrojanServerService_GetUsersServer) error + // setup exsisting users' config + SetUsers(TrojanServerService_SetUsersServer) error +} + +// UnimplementedTrojanServerServiceServer can be embedded to have forward compatible implementations. +type UnimplementedTrojanServerServiceServer struct { +} + +func (*UnimplementedTrojanServerServiceServer) ListUsers(*ListUsersRequest, TrojanServerService_ListUsersServer) error { + return status.Errorf(codes.Unimplemented, "method ListUsers not implemented") +} +func (*UnimplementedTrojanServerServiceServer) GetUsers(TrojanServerService_GetUsersServer) error { + return status.Errorf(codes.Unimplemented, "method GetUsers not implemented") +} +func (*UnimplementedTrojanServerServiceServer) SetUsers(TrojanServerService_SetUsersServer) error { + return status.Errorf(codes.Unimplemented, "method SetUsers not implemented") +} + +func RegisterTrojanServerServiceServer(s *grpc.Server, srv TrojanServerServiceServer) { + s.RegisterService(&_TrojanServerService_serviceDesc, srv) +} + +func _TrojanServerService_ListUsers_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(ListUsersRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(TrojanServerServiceServer).ListUsers(m, &trojanServerServiceListUsersServer{stream}) +} + +type TrojanServerService_ListUsersServer interface { + Send(*ListUsersResponse) error + grpc.ServerStream +} + +type trojanServerServiceListUsersServer struct { + grpc.ServerStream +} + +func (x *trojanServerServiceListUsersServer) Send(m *ListUsersResponse) error { + return x.ServerStream.SendMsg(m) +} + +func _TrojanServerService_GetUsers_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(TrojanServerServiceServer).GetUsers(&trojanServerServiceGetUsersServer{stream}) +} + +type TrojanServerService_GetUsersServer interface { + Send(*GetUsersResponse) error + Recv() (*GetUsersRequest, error) + grpc.ServerStream +} + +type trojanServerServiceGetUsersServer struct { + grpc.ServerStream +} + +func (x *trojanServerServiceGetUsersServer) Send(m *GetUsersResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *trojanServerServiceGetUsersServer) Recv() (*GetUsersRequest, error) { + m := new(GetUsersRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _TrojanServerService_SetUsers_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(TrojanServerServiceServer).SetUsers(&trojanServerServiceSetUsersServer{stream}) +} + +type TrojanServerService_SetUsersServer interface { + Send(*SetUsersResponse) error + Recv() (*SetUsersRequest, error) + grpc.ServerStream +} + +type trojanServerServiceSetUsersServer struct { + grpc.ServerStream +} + +func (x *trojanServerServiceSetUsersServer) Send(m *SetUsersResponse) error { + return x.ServerStream.SendMsg(m) +} + +func (x *trojanServerServiceSetUsersServer) Recv() (*SetUsersRequest, error) { + m := new(SetUsersRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _TrojanServerService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "trojan.api.TrojanServerService", + HandlerType: (*TrojanServerServiceServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "ListUsers", + Handler: _TrojanServerService_ListUsers_Handler, + ServerStreams: true, + }, + { + StreamName: "GetUsers", + Handler: _TrojanServerService_GetUsers_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "SetUsers", + Handler: _TrojanServerService_SetUsers_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "api.proto", +} diff --git a/api/service/api.proto b/api/service/api.proto new file mode 100644 index 0000000..6fc00bb --- /dev/null +++ b/api/service/api.proto @@ -0,0 +1,88 @@ +syntax = "proto3"; +package trojan.api; +option go_package = ".;service"; + +message Traffic { + uint64 upload_traffic = 1; + uint64 download_traffic = 2; +} + +message Speed { + uint64 upload_speed = 1; + uint64 download_speed = 2; +} + +message User { + string password = 1; + string hash = 2; //optional +} + +message UserStatus { + User user = 1; + Traffic traffic_total = 2; + Speed speed_current = 3; + Speed speed_limit = 4; + int32 ip_current = 5; + int32 ip_limit = 6; +} + +message GetTrafficRequest { + User user = 1; +} + +message GetTrafficResponse { + bool success = 1; + string info = 2; + Traffic traffic_total = 3; + Speed speed_current = 4; +} + +message ListUsersRequest { + +} + +message ListUsersResponse { + User user = 1; + UserStatus status = 2; +} + +message GetUsersRequest { + User user = 1; +} + +message GetUsersResponse { + bool success = 1; + string info = 2; + User user = 3; + UserStatus status = 4; +} + +message SetUsersRequest { + User user = 1; + enum Operation { + Add = 0; + Delete = 1; + Modify = 2; + } + Operation operation = 2; + Speed speed_limit = 3; + int32 ip_limit = 4; +} + +message SetUsersResponse { + bool success = 1; + string info = 2; +} + +service TrojanClientService { + rpc GetTraffic(GetTrafficRequest) returns(GetTrafficResponse){} +} + +service TrojanServerService { + // list all users + rpc ListUsers(ListUsersRequest) returns(stream ListUsersResponse){} + // obtain specified user's info + rpc GetUsers(stream GetUsersRequest) returns(stream GetUsersResponse){} + // setup exsisting users' config + rpc SetUsers(stream SetUsersRequest) returns(stream SetUsersResponse){} +} \ No newline at end of file diff --git a/api/service/client.go b/api/service/client.go new file mode 100644 index 0000000..6252e64 --- /dev/null +++ b/api/service/client.go @@ -0,0 +1,83 @@ +package service + +import ( + "context" + "fmt" + "github.com/p4gefau1t/trojan-go/api" + "github.com/p4gefau1t/trojan-go/common" + "github.com/p4gefau1t/trojan-go/config" + "github.com/p4gefau1t/trojan-go/log" + "github.com/p4gefau1t/trojan-go/statistic" + "github.com/p4gefau1t/trojan-go/tunnel/trojan" + "google.golang.org/grpc" + "net" +) + +type ClientAPI struct { + TrojanClientServiceServer + + auth statistic.Authenticator + ctx context.Context + uploadSpeed uint64 + downloadSpeed uint64 + lastSent uint64 + lastRecv uint64 +} + +func (s *ClientAPI) GetTraffic(ctx context.Context, req *GetTrafficRequest) (*GetTrafficResponse, error) { + log.Debug("API: GetTraffic") + if req.User == nil { + return nil, common.NewError("User is unspecified") + } + if req.User.Hash == "" { + req.User.Hash = common.SHA224String(req.User.Password) + } + valid, user := s.auth.AuthUser(req.User.Hash) + if !valid { + return nil, common.NewError("User " + req.User.Hash + " not found") + } + sent, recv := user.GetTraffic() + sentSpeed, recvSpeed := user.GetSpeed() + resp := &GetTrafficResponse{ + Success: true, + TrafficTotal: &Traffic{ + UploadTraffic: sent, + DownloadTraffic: recv, + }, + SpeedCurrent: &Speed{ + UploadSpeed: sentSpeed, + DownloadSpeed: recvSpeed, + }, + } + return resp, nil +} + +func RunClientAPI(ctx context.Context, auth statistic.Authenticator) error { + server := grpc.NewServer() + service := &ClientAPI{ + ctx: ctx, + auth: auth, + } + RegisterTrojanClientServiceServer(server, service) + cfg := config.FromContext(ctx, Name).(*Config) + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", cfg.APIHost, cfg.APIPort)) + if err != nil { + return err + } + log.Info("client-side api service is listening on", listener.Addr().String()) + errChan := make(chan error, 1) + go func() { + errChan <- server.Serve(listener) + }() + select { + case err := <-errChan: + return err + case <-ctx.Done(): + server.Stop() + return nil + } +} + +func init() { + api.RegisterHandler(trojan.Name+"_CLIENT", RunClientAPI) +} diff --git a/api/service/client_test.go b/api/service/client_test.go new file mode 100644 index 0000000..7d7c8f3 --- /dev/null +++ b/api/service/client_test.go @@ -0,0 +1,53 @@ +package service + +import ( + "context" + "fmt" + "github.com/p4gefau1t/trojan-go/common" + "github.com/p4gefau1t/trojan-go/config" + "github.com/p4gefau1t/trojan-go/statistic/memory" + "google.golang.org/grpc" + "testing" + "time" +) + +func TestClientAPI(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + ctx = config.WithConfig(ctx, memory.Name, + &memory.Config{ + Passwords: []string{"useless"}, + }) + port := common.PickPort("tcp", "127.0.0.1") + ctx = config.WithConfig(ctx, Name, &Config{ + APIConfig{ + Enabled: true, + APIHost: "127.0.0.1", + APIPort: port, + }, + }) + auth, err := memory.NewAuthenticator(ctx) + common.Must(err) + go RunClientAPI(ctx, auth) + common.Must(auth.AddUser("hash1234")) + valid, user := auth.AuthUser("hash1234") + if !valid { + t.Fail() + } + user.AddTraffic(1234, 5678) + time.Sleep(time.Second) + conn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", port), grpc.WithInsecure()) + common.Must(err) + client := NewTrojanClientServiceClient(conn) + resp, err := client.GetTraffic(ctx, &GetTrafficRequest{User: &User{ + Hash: "hash1234", + }}) + common.Must(err) + if resp.TrafficTotal.DownloadTraffic != 5678 || resp.TrafficTotal.UploadTraffic != 1234 { + t.Fail() + } + resp, err = client.GetTraffic(ctx, &GetTrafficRequest{}) + if err == nil { + t.Fail() + } + cancel() +} diff --git a/api/service/config.go b/api/service/config.go new file mode 100644 index 0000000..e8ce2ed --- /dev/null +++ b/api/service/config.go @@ -0,0 +1,21 @@ +package service + +import "github.com/p4gefau1t/trojan-go/config" + +const Name = "API_SERVICE" + +type APIConfig struct { + Enabled bool `json:"enabled" yaml:"enabled"` + APIHost string `json:"api_addr" yaml:"api-addr"` + APIPort int `json:"api_port" yaml:"api-port"` +} + +type Config struct { + APIConfig `json,yaml:"api"` +} + +func init() { + config.RegisterConfigCreator(Name, func() interface{} { + return new(Config) + }) +} diff --git a/api/service/gen.sh b/api/service/gen.sh new file mode 100755 index 0000000..a2ac96e --- /dev/null +++ b/api/service/gen.sh @@ -0,0 +1 @@ +protoc ./api.proto --go_out=plugins=grpc:. diff --git a/api/service/server.go b/api/service/server.go new file mode 100644 index 0000000..f6faa04 --- /dev/null +++ b/api/service/server.go @@ -0,0 +1,195 @@ +package service + +import ( + "context" + "fmt" + "github.com/p4gefau1t/trojan-go/api" + "github.com/p4gefau1t/trojan-go/common" + "github.com/p4gefau1t/trojan-go/config" + "github.com/p4gefau1t/trojan-go/log" + "github.com/p4gefau1t/trojan-go/statistic" + "github.com/p4gefau1t/trojan-go/tunnel/trojan" + "google.golang.org/grpc" + "io" + "net" +) + +type ServerAPI struct { + TrojanServerServiceServer + auth statistic.Authenticator +} + +func (s *ServerAPI) GetUsers(stream TrojanServerService_GetUsersServer) error { + log.Debug("API: GetUsers") + for { + req, err := stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + if req.User == nil { + return common.NewError("User is unspecified") + } + if req.User.Hash == "" { + req.User.Hash = common.SHA224String(req.User.Password) + } + valid, user := s.auth.AuthUser(req.User.Hash) + if !valid { + stream.Send(&GetUsersResponse{ + Success: false, + Info: "Invalid user: " + req.User.Hash, + }) + continue + } + downloadTraffic, uploadTraffic := user.GetTraffic() + downloadSpeed, uploadSpeed := user.GetSpeed() + downloadSpeedLimit, uploadSpeedLimit := user.GetSpeedLimit() + ipLimit := user.GetIPLimit() + ipCurrent := user.GetIP() + err = stream.Send(&GetUsersResponse{ + Success: true, + Status: &UserStatus{ + User: req.User, + TrafficTotal: &Traffic{ + UploadTraffic: uploadTraffic, + DownloadTraffic: downloadTraffic, + }, + SpeedCurrent: &Speed{ + DownloadSpeed: downloadSpeed, + UploadSpeed: uploadSpeed, + }, + SpeedLimit: &Speed{ + DownloadSpeed: uint64(downloadSpeedLimit), + UploadSpeed: uint64(uploadSpeedLimit), + }, + IpCurrent: int32(ipCurrent), + IpLimit: int32(ipLimit), + }, + }) + if err != nil { + return err + } + } +} + +func (s *ServerAPI) SetUsers(stream TrojanServerService_SetUsersServer) error { + log.Debug("API: SetUsers") + for { + req, err := stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + if req.User == nil { + return common.NewError("User is unspecified") + } + if req.User.Hash == "" { + req.User.Hash = common.SHA224String(req.User.Password) + } + switch req.Operation { + case SetUsersRequest_Add: + err = s.auth.AddUser(req.User.Hash) + if req.SpeedLimit != nil { + valid, user := s.auth.AuthUser(req.User.Hash) + if !valid { + return common.NewError("Failed to add new user") + } + user.SetSpeedLimit(int(req.SpeedLimit.DownloadSpeed), int(req.SpeedLimit.UploadSpeed)) + } + case SetUsersRequest_Delete: + err = s.auth.DelUser(req.User.Hash) + case SetUsersRequest_Modify: + valid, user := s.auth.AuthUser(req.User.Hash) + if !valid { + err = common.NewError("Invalid user " + req.User.Hash) + } else { + if req.SpeedLimit.DownloadSpeed > 0 || req.SpeedLimit.UploadSpeed > 0 { + user.SetSpeedLimit(int(req.SpeedLimit.DownloadSpeed), int(req.SpeedLimit.UploadSpeed)) + } + if req.IpLimit > 0 { + user.SetIPLimit(int(req.IpLimit)) + } + } + } + if err != nil { + stream.Send(&SetUsersResponse{ + Success: false, + Info: err.Error(), + }) + continue + } + stream.Send(&SetUsersResponse{ + Success: true, + }) + } +} + +func (s *ServerAPI) ListUsers(req *ListUsersRequest, stream TrojanServerService_ListUsersServer) error { + log.Debug("API: ListUsers") + users := s.auth.ListUsers() + for _, user := range users { + downloadTraffic, uploadTraffic := user.GetTraffic() + downloadSpeed, uploadSpeed := user.GetSpeed() + downloadSpeedLimit, uploadSpeedLimit := user.GetSpeedLimit() + ipLimit := user.GetIPLimit() + ipCurrent := user.GetIP() + err := stream.Send(&ListUsersResponse{ + User: &User{ + Hash: user.Hash(), + }, + Status: &UserStatus{ + TrafficTotal: &Traffic{ + DownloadTraffic: downloadTraffic, + UploadTraffic: uploadTraffic, + }, + SpeedCurrent: &Speed{ + DownloadSpeed: downloadSpeed, + UploadSpeed: uploadSpeed, + }, + SpeedLimit: &Speed{ + DownloadSpeed: uint64(downloadSpeedLimit), + UploadSpeed: uint64(uploadSpeedLimit), + }, + IpLimit: int32(ipLimit), + IpCurrent: int32(ipCurrent), + }, + }) + if err != nil { + return err + } + } + return nil +} + +func RunServerAPI(ctx context.Context, auth statistic.Authenticator) error { + server := grpc.NewServer() + service := &ServerAPI{ + auth: auth, + } + RegisterTrojanServerServiceServer(server, service) + cfg := config.FromContext(ctx, Name).(*Config) + listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", cfg.APIHost, cfg.APIPort)) + if err != nil { + return err + } + log.Info("server-side api service is listening on", listener.Addr().String()) + errChan := make(chan error, 1) + go func() { + errChan <- server.Serve(listener) + }() + select { + case err := <-errChan: + return err + case <-ctx.Done(): + server.Stop() + return nil + } +} + +func init() { + api.RegisterHandler(trojan.Name+"_SERVER", RunServerAPI) +} diff --git a/api/service/server_test.go b/api/service/server_test.go new file mode 100644 index 0000000..7240da0 --- /dev/null +++ b/api/service/server_test.go @@ -0,0 +1,132 @@ +package service + +import ( + "context" + "fmt" + "github.com/p4gefau1t/trojan-go/common" + "github.com/p4gefau1t/trojan-go/config" + "github.com/p4gefau1t/trojan-go/statistic/memory" + "google.golang.org/grpc" + "testing" + "time" +) + +func TestServerAPI(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + ctx = config.WithConfig(ctx, memory.Name, + &memory.Config{ + Passwords: []string{}, + }) + port := common.PickPort("tcp", "127.0.0.1") + ctx = config.WithConfig(ctx, Name, &Config{ + APIConfig{ + Enabled: true, + APIHost: "127.0.0.1", + APIPort: port, + }, + }) + auth, err := memory.NewAuthenticator(ctx) + common.Must(err) + go RunServerAPI(ctx, auth) + common.Must(auth.AddUser("hash1234")) + _, user := auth.AuthUser("hash1234") + conn, err := grpc.Dial(fmt.Sprintf("127.0.0.1:%d", port), grpc.WithInsecure()) + common.Must(err) + server := NewTrojanServerServiceClient(conn) + stream1, err := server.ListUsers(ctx, &ListUsersRequest{}) + common.Must(err) + for { + resp, err := stream1.Recv() + if err != nil { + break + } + fmt.Println(resp.User.Hash) + if resp.User.Hash != "hash1234" { + t.Fail() + } + fmt.Println(resp.Status.SpeedCurrent) + fmt.Println(resp.Status.SpeedLimit) + } + stream1.CloseSend() + user.AddTraffic(1234, 5678) + time.Sleep(time.Millisecond * 1000) + stream2, err := server.GetUsers(ctx) + common.Must(err) + stream2.Send(&GetUsersRequest{ + User: &User{ + Hash: "hash1234", + }, + }) + resp2, err := stream2.Recv() + common.Must(err) + if resp2.Status.TrafficTotal.DownloadTraffic != 1234 || resp2.Status.TrafficTotal.UploadTraffic != 5678 { + t.Fail() + } + if resp2.Status.SpeedCurrent.DownloadSpeed != 1234 || resp2.Status.TrafficTotal.UploadTraffic != 5678 { + t.Fail() + } + + stream3, err := server.SetUsers(ctx) + stream3.Send(&SetUsersRequest{ + User: &User{ + Hash: "hash1234", + }, + Operation: SetUsersRequest_Delete, + }) + resp3, err := stream3.Recv() + if err != nil || !resp3.Success { + t.Fail() + } + valid, _ := auth.AuthUser("hash1234") + if valid { + t.Fail() + } + stream3.Send(&SetUsersRequest{ + User: &User{ + Hash: "newhash", + }, + Operation: SetUsersRequest_Add, + }) + resp3, err = stream3.Recv() + if err != nil || !resp3.Success { + t.Fail() + } + valid, user = auth.AuthUser("newhash") + if !valid { + t.Fail() + } + stream3.Send(&SetUsersRequest{ + User: &User{ + Hash: "newhash", + }, + Operation: SetUsersRequest_Modify, + SpeedLimit: &Speed{ + DownloadSpeed: 5000, + UploadSpeed: 3000, + }, + }) + go func() { + for { + user.AddTraffic(200, 0) + } + }() + go func() { + for { + user.AddTraffic(0, 300) + } + }() + time.Sleep(time.Second * 3) + for i := 0; i < 3; i++ { + stream2.Send(&GetUsersRequest{ + User: &User{ + Hash: "newhash", + }, + }) + resp2, err = stream2.Recv() + fmt.Println(resp2.Status.SpeedCurrent) + fmt.Println(resp2.Status.SpeedLimit) + time.Sleep(time.Second) + } + stream2.CloseSend() + cancel() +} diff --git a/go.mod b/go.mod index 0eec3b5..a720266 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed github.com/go-sql-driver/mysql v1.5.0 - github.com/golang/protobuf v1.3.2 + github.com/golang/protobuf v1.4.1 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/refraction-networking/utls v0.0.0-20200601200209-ada0bb9b38a0 github.com/shadowsocks/go-shadowsocks2 v0.1.0 @@ -15,6 +15,8 @@ require ( golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 + google.golang.org/grpc v1.27.0 + google.golang.org/protobuf v1.24.0 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v2 v2.3.0 v2ray.com/core v0.0.0-00010101000000-000000000000 diff --git a/go.sum b/go.sum index 8ac5e7f..a04cb20 100644 --- a/go.sum +++ b/go.sum @@ -4,7 +4,10 @@ github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed h1:eqa6queie github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed/go.mod h1:rA52xkgZwql9LRZXWb2arHEFP6qSR48KY2xOfWzEciQ= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= @@ -12,10 +15,22 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1 h1:ZFgWrT+bLgsYPirOnRfKLYJLvssAegOj/hgyMFdJZe0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= @@ -29,6 +44,7 @@ github.com/miekg/dns v1.1.4 h1:rCMZsU2ScVSYcAsOXgmC6+AKOK+6pmQTOcw03nfwYV0= github.com/miekg/dns v1.1.4/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/refraction-networking/utls v0.0.0-20190909200633-43c36d3c1f57/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0= github.com/refraction-networking/utls v0.0.0-20200601200209-ada0bb9b38a0 h1:vIkvetWOJZSADSKCF9MLTsQNW2httdBmYz47dQQteP8= github.com/refraction-networking/utls v0.0.0-20200601200209-ada0bb9b38a0/go.mod h1:tz9gX959MEFfFN5whTIocCLUG57WiILqtdVxI8c6Wj0= @@ -49,13 +65,22 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed h1:g4KENRiCMEx58Q7/ecwfT0N2o8z35Fnbsjig/Alf2T4= golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y= @@ -64,19 +89,41 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= h12.io/socks v1.0.0/go.mod h1:MdYbo5/eB9ka7u5dzW2Qh0iSyJENwB3KI5H5ngenFGA= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/proxy/proxy.go b/proxy/proxy.go index e862e65..f881a09 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -3,6 +3,7 @@ package proxy import ( "context" "io" + "math/rand" "net" "strings" @@ -153,7 +154,8 @@ func RegisterProxyCreator(name string, creator Creator) { } func NewProxyFromConfigData(data []byte, isJSON bool) (*Proxy, error) { - ctx := context.Background() + // create a unique context for each proxy instance to avoid duplicated authenticator + ctx := context.WithValue(context.Background(), Name+"_ID", rand.Int()) var err error if isJSON { ctx, err = config.WithJSONConfig(context.Background(), data) diff --git a/statistic/statistics.go b/statistic/statistics.go index 632063f..1d3e65a 100644 --- a/statistic/statistics.go +++ b/statistic/statistics.go @@ -8,11 +8,6 @@ import ( "github.com/p4gefau1t/trojan-go/common" ) -const ( - TrafficMeterKey = "TRAFFIC_METER" - AuthenticatorKey = "AUTHENTICATOR" -) - type TrafficMeter interface { io.Closer Hash() string @@ -49,15 +44,25 @@ type Authenticator interface { type Creator func(ctx context.Context) (Authenticator, error) var authCreators = map[string]Creator{} +var createdAuth = map[context.Context]Authenticator{} func RegisterAuthenticatorCreator(name string, creator Creator) { authCreators[name] = creator } func NewAuthenticator(ctx context.Context, name string) (Authenticator, error) { + // one authenticator for each context + if auth, found := createdAuth[ctx]; found { + return auth, nil + } creator, found := authCreators[strings.ToUpper(name)] if !found { - return nil, common.NewError("Auth driver name " + name + " not found") + return nil, common.NewError("auth driver name " + name + " not found") } - return creator(ctx) + auth, err := creator(ctx) + if err != nil { + return nil, err + } + createdAuth[ctx] = auth + return auth, err } diff --git a/tunnel/raw/config.go b/tunnel/raw/config.go index 87488e5..dc09629 100644 --- a/tunnel/raw/config.go +++ b/tunnel/raw/config.go @@ -4,7 +4,7 @@ import "github.com/p4gefau1t/trojan-go/config" type Config struct { LocalHost string `json:"local_addr" yaml:"local-addr"` - LocalPort int `json:"local_port" yaml:"local-addr"` + LocalPort int `json:"local_port" yaml:"local-port"` DNS []string `json:"dns" yaml:"dns"` TCP TCPConfig `json:"tcp" yaml:"tcp"` } diff --git a/tunnel/router/client.go b/tunnel/router/client.go index 5794122..c4b5194 100644 --- a/tunnel/router/client.go +++ b/tunnel/router/client.go @@ -11,6 +11,7 @@ import ( "io/ioutil" "net" "regexp" + "strconv" "strings" v2router "v2ray.com/core/app/router" ) @@ -359,6 +360,26 @@ func NewClient(ctx context.Context, underlay tunnel.Client) (*Client, error) { }) } + cidrInfo := loadCode(cfg, "cidr:") + for _, info := range cidrInfo { + tmp := strings.Split(info.code, "/") + if len(tmp) != 2 { + return nil, common.NewError("invalid cidr:" + info.code) + } + ip := net.ParseIP(tmp[0]) + if ip == nil { + return nil, common.NewError("invalid cidr ip:" + info.code) + } + prefix, err := strconv.ParseInt(tmp[1], 10, 32) + if err != nil { + return nil, common.NewError("invalid prefix").Base(err) + } + client.cidrs[info.strategy] = append(client.cidrs[info.strategy], &v2router.CIDR{ + Ip: ip, + Prefix: uint32(prefix), + }) + } + log.Info("router client created") return client, nil } diff --git a/tunnel/router/config.go b/tunnel/router/config.go index 209a0de..c297fac 100644 --- a/tunnel/router/config.go +++ b/tunnel/router/config.go @@ -2,6 +2,7 @@ package router import ( "github.com/p4gefau1t/trojan-go/config" + "os" ) type Config struct { @@ -21,7 +22,7 @@ type RouterConfig struct { func init() { config.RegisterConfigCreator(Name, func() interface{} { - return &Config{ + cfg := &Config{ Router: RouterConfig{ DefaultPolicy: "proxy", DomainStrategy: "as_is", @@ -29,5 +30,10 @@ func init() { GeoSiteFilename: "geosite.dat", }, } + if path := os.Getenv("TROJAN_GO_LOCATION_ASSET"); path != "" { + cfg.Router.GeoIPFilename = path + "geoip.dat" + cfg.Router.GeoSiteFilename = path + "geosite.dat" + } + return cfg }) } diff --git a/tunnel/router/router_test.go b/tunnel/router/router_test.go index eceb6aa..d6bc5c5 100644 --- a/tunnel/router/router_test.go +++ b/tunnel/router/router_test.go @@ -84,6 +84,7 @@ router: - "regex:proxyreg(.*)" - "full:proxyfull" - "domain:proxy.com" + - "cidr:192.168.1.1/16" ` ctx, err := config.WithYAMLConfig(context.Background(), []byte(data)) common.Must(err) @@ -114,6 +115,15 @@ router: t.Fail() } + _, err = client.DialConn(&tunnel.Address{ + AddressType: tunnel.IPv4, + IP: net.ParseIP("192.168.123.123"), + Port: 80, + }, nil) + if err.Error() != "mockproxy" { + t.Fail() + } + _, err = client.DialConn(&tunnel.Address{ AddressType: tunnel.DomainName, DomainName: "block.com", diff --git a/tunnel/trojan/client.go b/tunnel/trojan/client.go index 90c8b93..f5bb17f 100644 --- a/tunnel/trojan/client.go +++ b/tunnel/trojan/client.go @@ -3,6 +3,8 @@ package trojan import ( "bytes" "context" + "github.com/p4gefau1t/trojan-go/api" + "github.com/p4gefau1t/trojan-go/statistic/memory" "github.com/p4gefau1t/trojan-go/tunnel/mux" "net" "time" @@ -146,10 +148,13 @@ func (c *Client) DialPacket(tunnel.Tunnel) (tunnel.PacketConn, error) { } func NewClient(ctx context.Context, client tunnel.Client) (*Client, error) { - auth, err := statistic.NewAuthenticator(ctx, "memory") + auth, err := statistic.NewAuthenticator(ctx, memory.Name) if err != nil { return nil, err } + + go api.RunService(ctx, Name+"_CLIENT", auth) + log.Debug("trojan client created") return &Client{ underlay: client, diff --git a/tunnel/trojan/server.go b/tunnel/trojan/server.go index 23faf46..7da9169 100644 --- a/tunnel/trojan/server.go +++ b/tunnel/trojan/server.go @@ -3,6 +3,7 @@ package trojan import ( "context" "fmt" + "github.com/p4gefau1t/trojan-go/api" "github.com/p4gefau1t/trojan-go/statistic/memory" "github.com/p4gefau1t/trojan-go/statistic/mysql" "io" @@ -194,6 +195,8 @@ func NewServer(ctx context.Context, underlay tunnel.Server) (tunnel.Server, erro if cfg.MySQL.Enabled { auth, err = statistic.NewAuthenticator(ctx, mysql.Name) } + go api.RunService(ctx, Name+"_SERVER", auth) + if err != nil { return nil, common.NewError("failed to create authenticator").Base(err) }