diff --git a/cmd/gost/register.go b/cmd/gost/register.go index 6c0d667..ed353ad 100644 --- a/cmd/gost/register.go +++ b/cmd/gost/register.go @@ -15,6 +15,7 @@ import ( // Register dialers _ "github.com/go-gost/gost/pkg/dialer/ftcp" + _ "github.com/go-gost/gost/pkg/dialer/grpc" _ "github.com/go-gost/gost/pkg/dialer/http2" _ "github.com/go-gost/gost/pkg/dialer/http2/h2" _ "github.com/go-gost/gost/pkg/dialer/http3" @@ -53,6 +54,7 @@ import ( // Register listeners _ "github.com/go-gost/gost/pkg/listener/dns" _ "github.com/go-gost/gost/pkg/listener/ftcp" + _ "github.com/go-gost/gost/pkg/listener/grpc" _ "github.com/go-gost/gost/pkg/listener/http2" _ "github.com/go-gost/gost/pkg/listener/http2/h2" _ "github.com/go-gost/gost/pkg/listener/http3" diff --git a/go.mod b/go.mod index 766fd76..91b6b12 100644 --- a/go.mod +++ b/go.mod @@ -54,14 +54,20 @@ require ( github.com/xtaci/tcpraw v1.2.25 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 golang.org/x/mod v0.4.2 // indirect - golang.org/x/net v0.0.0-20211209124913-491a49abca63 - golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect - golang.org/x/text v0.3.6 // indirect + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd + golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect + golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/grpc v1.44.0 gopkg.in/ini.v1 v1.63.2 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 ) -require github.com/marten-seemann/qpack v0.2.1 // indirect +require ( + github.com/golang/protobuf v1.5.2 // indirect + github.com/marten-seemann/qpack v0.2.1 // indirect + google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 // indirect + google.golang.org/protobuf v1.27.1 // indirect +) diff --git a/go.sum b/go.sum index 4d7f0ef..8f1227e 100644 --- a/go.sum +++ b/go.sum @@ -70,6 +70,7 @@ github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBT github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -79,7 +80,11 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-iptables v0.5.0 h1:mw6SAibtHKZcNzAsOxjoHIG0gy5YFHhypWSSNc6EjbQ= github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -98,6 +103,7 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= @@ -176,6 +182,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -538,6 +545,8 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -633,9 +642,12 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -645,6 +657,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -809,7 +823,10 @@ google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKr google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71 h1:z+ErRPu0+KS02Td3fOAgdX+lnPDh/VyaABEJPD4JRQs= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350 h1:YxHp5zqIcAShDEvRr5/0rVESVS+njYF68PSdazrNLJo= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= @@ -837,7 +854,10 @@ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= diff --git a/pkg/chain/transport.go b/pkg/chain/transport.go index 2d3c12b..c7938b9 100644 --- a/pkg/chain/transport.go +++ b/pkg/chain/transport.go @@ -36,7 +36,9 @@ func (tr *Transport) Dial(ctx context.Context, addr string) (net.Conn, error) { } func (tr *Transport) dialOptions() []dialer.DialOption { - var opts []dialer.DialOption + opts := []dialer.DialOption{ + dialer.HostDialOption(tr.addr), + } if !tr.route.IsEmpty() { opts = append(opts, dialer.DialFuncDialOption( diff --git a/pkg/common/util/grpc/proto/gost.pb.go b/pkg/common/util/grpc/proto/gost.pb.go new file mode 100644 index 0000000..90847bc --- /dev/null +++ b/pkg/common/util/grpc/proto/gost.pb.go @@ -0,0 +1,148 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.12.4 +// source: gost.proto + +package proto + +import ( + 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) +) + +type Chunk struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *Chunk) Reset() { + *x = Chunk{} + if protoimpl.UnsafeEnabled { + mi := &file_gost_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Chunk) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Chunk) ProtoMessage() {} + +func (x *Chunk) ProtoReflect() protoreflect.Message { + mi := &file_gost_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 Chunk.ProtoReflect.Descriptor instead. +func (*Chunk) Descriptor() ([]byte, []int) { + return file_gost_proto_rawDescGZIP(), []int{0} +} + +func (x *Chunk) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +var File_gost_proto protoreflect.FileDescriptor + +var file_gost_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x67, 0x6f, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x1b, 0x0a, 0x05, + 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x32, 0x29, 0x0a, 0x09, 0x47, 0x6f, 0x73, + 0x74, 0x54, 0x75, 0x6e, 0x65, 0x6c, 0x12, 0x1c, 0x0a, 0x06, 0x54, 0x75, 0x6e, 0x6e, 0x65, 0x6c, + 0x12, 0x06, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x1a, 0x06, 0x2e, 0x43, 0x68, 0x75, 0x6e, 0x6b, + 0x28, 0x01, 0x30, 0x01, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x67, 0x6f, 0x73, 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x74, 0x2f, + 0x70, 0x6b, 0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x75, 0x74, 0x69, 0x6c, 0x2f, + 0x67, 0x72, 0x70, 0x63, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_gost_proto_rawDescOnce sync.Once + file_gost_proto_rawDescData = file_gost_proto_rawDesc +) + +func file_gost_proto_rawDescGZIP() []byte { + file_gost_proto_rawDescOnce.Do(func() { + file_gost_proto_rawDescData = protoimpl.X.CompressGZIP(file_gost_proto_rawDescData) + }) + return file_gost_proto_rawDescData +} + +var file_gost_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_gost_proto_goTypes = []interface{}{ + (*Chunk)(nil), // 0: Chunk +} +var file_gost_proto_depIdxs = []int32{ + 0, // 0: GostTunel.Tunnel:input_type -> Chunk + 0, // 1: GostTunel.Tunnel:output_type -> Chunk + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_gost_proto_init() } +func file_gost_proto_init() { + if File_gost_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_gost_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Chunk); 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_gost_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_gost_proto_goTypes, + DependencyIndexes: file_gost_proto_depIdxs, + MessageInfos: file_gost_proto_msgTypes, + }.Build() + File_gost_proto = out.File + file_gost_proto_rawDesc = nil + file_gost_proto_goTypes = nil + file_gost_proto_depIdxs = nil +} diff --git a/pkg/common/util/grpc/proto/gost.proto b/pkg/common/util/grpc/proto/gost.proto new file mode 100644 index 0000000..228b8a5 --- /dev/null +++ b/pkg/common/util/grpc/proto/gost.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +option go_package = "github.com/go-gost/gost/pkg/common/util/grpc/proto"; + +message Chunk { + bytes data = 1; +} + +service GostTunel { + rpc Tunnel (stream Chunk) returns (stream Chunk); +} \ No newline at end of file diff --git a/pkg/common/util/grpc/proto/gost_grpc.pb.go b/pkg/common/util/grpc/proto/gost_grpc.pb.go new file mode 100644 index 0000000..2cf63d2 --- /dev/null +++ b/pkg/common/util/grpc/proto/gost_grpc.pb.go @@ -0,0 +1,133 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +// GostTunelClient is the client API for GostTunel service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type GostTunelClient interface { + Tunnel(ctx context.Context, opts ...grpc.CallOption) (GostTunel_TunnelClient, error) +} + +type gostTunelClient struct { + cc grpc.ClientConnInterface +} + +func NewGostTunelClient(cc grpc.ClientConnInterface) GostTunelClient { + return &gostTunelClient{cc} +} + +func (c *gostTunelClient) Tunnel(ctx context.Context, opts ...grpc.CallOption) (GostTunel_TunnelClient, error) { + stream, err := c.cc.NewStream(ctx, &GostTunel_ServiceDesc.Streams[0], "/GostTunel/Tunnel", opts...) + if err != nil { + return nil, err + } + x := &gostTunelTunnelClient{stream} + return x, nil +} + +type GostTunel_TunnelClient interface { + Send(*Chunk) error + Recv() (*Chunk, error) + grpc.ClientStream +} + +type gostTunelTunnelClient struct { + grpc.ClientStream +} + +func (x *gostTunelTunnelClient) Send(m *Chunk) error { + return x.ClientStream.SendMsg(m) +} + +func (x *gostTunelTunnelClient) Recv() (*Chunk, error) { + m := new(Chunk) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// GostTunelServer is the server API for GostTunel service. +// All implementations must embed UnimplementedGostTunelServer +// for forward compatibility +type GostTunelServer interface { + Tunnel(GostTunel_TunnelServer) error + mustEmbedUnimplementedGostTunelServer() +} + +// UnimplementedGostTunelServer must be embedded to have forward compatible implementations. +type UnimplementedGostTunelServer struct { +} + +func (UnimplementedGostTunelServer) Tunnel(GostTunel_TunnelServer) error { + return status.Errorf(codes.Unimplemented, "method Tunnel not implemented") +} +func (UnimplementedGostTunelServer) mustEmbedUnimplementedGostTunelServer() {} + +// UnsafeGostTunelServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to GostTunelServer will +// result in compilation errors. +type UnsafeGostTunelServer interface { + mustEmbedUnimplementedGostTunelServer() +} + +func RegisterGostTunelServer(s grpc.ServiceRegistrar, srv GostTunelServer) { + s.RegisterService(&GostTunel_ServiceDesc, srv) +} + +func _GostTunel_Tunnel_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(GostTunelServer).Tunnel(&gostTunelTunnelServer{stream}) +} + +type GostTunel_TunnelServer interface { + Send(*Chunk) error + Recv() (*Chunk, error) + grpc.ServerStream +} + +type gostTunelTunnelServer struct { + grpc.ServerStream +} + +func (x *gostTunelTunnelServer) Send(m *Chunk) error { + return x.ServerStream.SendMsg(m) +} + +func (x *gostTunelTunnelServer) Recv() (*Chunk, error) { + m := new(Chunk) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// GostTunel_ServiceDesc is the grpc.ServiceDesc for GostTunel service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var GostTunel_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "GostTunel", + HandlerType: (*GostTunelServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Tunnel", + Handler: _GostTunel_Tunnel_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "gost.proto", +} diff --git a/pkg/common/util/grpc/proto/protoc.sh b/pkg/common/util/grpc/proto/protoc.sh new file mode 100755 index 0000000..4e33305 --- /dev/null +++ b/pkg/common/util/grpc/proto/protoc.sh @@ -0,0 +1,3 @@ +protoc --go_out=. --go_opt=paths=source_relative \ + --go-grpc_out=. --go-grpc_opt=paths=source_relative \ + gost.proto \ No newline at end of file diff --git a/pkg/dialer/grpc/conn.go b/pkg/dialer/grpc/conn.go new file mode 100644 index 0000000..dceb1a6 --- /dev/null +++ b/pkg/dialer/grpc/conn.go @@ -0,0 +1,92 @@ +package grpc + +import ( + "errors" + "io" + "net" + "time" + + pb "github.com/go-gost/gost/pkg/common/util/grpc/proto" +) + +type conn struct { + c pb.GostTunel_TunnelClient + rb []byte + localAddr net.Addr + remoteAddr net.Addr + closed chan struct{} +} + +func (c *conn) Read(b []byte) (n int, err error) { + select { + case <-c.c.Context().Done(): + err = c.c.Context().Err() + return + case <-c.closed: + err = io.ErrClosedPipe + return + default: + } + + if len(c.rb) == 0 { + chunk, err := c.c.Recv() + if err != nil { + return 0, err + } + c.rb = chunk.Data + } + + n = copy(b, c.rb) + c.rb = c.rb[n:] + return +} + +func (c *conn) Write(b []byte) (n int, err error) { + select { + case <-c.c.Context().Done(): + err = c.c.Context().Err() + return + case <-c.closed: + err = io.ErrClosedPipe + return + default: + } + + if err = c.c.Send(&pb.Chunk{ + Data: b, + }); err != nil { + return + } + n = len(b) + return +} + +func (c *conn) Close() error { + select { + case <-c.closed: + default: + close(c.closed) + } + + return nil +} + +func (c *conn) LocalAddr() net.Addr { + return c.localAddr +} + +func (c *conn) RemoteAddr() net.Addr { + return c.remoteAddr +} + +func (c *conn) SetDeadline(t time.Time) error { + return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} +} + +func (c *conn) SetReadDeadline(t time.Time) error { + return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} +} + +func (c *conn) SetWriteDeadline(t time.Time) error { + return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} +} diff --git a/pkg/dialer/grpc/dialer.go b/pkg/dialer/grpc/dialer.go new file mode 100644 index 0000000..4b46583 --- /dev/null +++ b/pkg/dialer/grpc/dialer.go @@ -0,0 +1,140 @@ +package grpc + +import ( + "context" + "net" + "sync" + "time" + + pb "github.com/go-gost/gost/pkg/common/util/grpc/proto" + "github.com/go-gost/gost/pkg/dialer" + "github.com/go-gost/gost/pkg/logger" + md "github.com/go-gost/gost/pkg/metadata" + "github.com/go-gost/gost/pkg/registry" + "google.golang.org/grpc" + "google.golang.org/grpc/backoff" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" +) + +func init() { + registry.RegisterDialer("grpc", NewDialer) +} + +type grpcDialer struct { + clients map[string]pb.GostTunelClient + clientMutex sync.Mutex + logger logger.Logger + md metadata + options dialer.Options +} + +func NewDialer(opts ...dialer.Option) dialer.Dialer { + options := dialer.Options{} + for _, opt := range opts { + opt(&options) + } + + return &grpcDialer{ + clients: make(map[string]pb.GostTunelClient), + logger: options.Logger, + options: options, + } +} + +func (d *grpcDialer) Init(md md.Metadata) (err error) { + return d.parseMetadata(md) +} + +// Multiplex implements dialer.Multiplexer interface. +func (d *grpcDialer) Multiplex() bool { + return true +} + +func (d *grpcDialer) Dial(ctx context.Context, addr string, opts ...dialer.DialOption) (net.Conn, error) { + remoteAddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return nil, err + } + + d.clientMutex.Lock() + defer d.clientMutex.Unlock() + + client, ok := d.clients[addr] + if !ok { + var options dialer.DialOptions + for _, opt := range opts { + opt(&options) + } + + host := d.md.host + if host == "" { + host = options.Host + } + + grpcOpts := []grpc.DialOption{ + grpc.WithBlock(), + grpc.WithContextDialer(func(c context.Context, s string) (net.Conn, error) { + return d.dial(ctx, "tcp", s, &options) + }), + grpc.WithAuthority(host), + grpc.WithConnectParams(grpc.ConnectParams{ + Backoff: backoff.DefaultConfig, + MinConnectTimeout: 10 * time.Second, + }), + } + if !d.md.insecure { + grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(credentials.NewTLS(d.options.TLSConfig))) + } else { + grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } + + cc, err := grpc.DialContext(ctx, addr, grpcOpts...) + if err != nil { + d.logger.Error(err) + return nil, err + } + client = pb.NewGostTunelClient(cc) + d.clients[addr] = client + } + + cli, err := client.Tunnel(ctx) + if err != nil { + return nil, err + } + + return &conn{ + c: cli, + localAddr: &net.TCPAddr{}, + remoteAddr: remoteAddr, + closed: make(chan struct{}), + }, nil +} + +func (d *grpcDialer) dial(ctx context.Context, network, addr string, opts *dialer.DialOptions) (net.Conn, error) { + dial := opts.DialFunc + if dial != nil { + conn, err := dial(ctx, addr) + if err != nil { + d.logger.Error(err) + } else { + d.logger.WithFields(map[string]interface{}{ + "src": conn.LocalAddr().String(), + "dst": addr, + }).Debug("dial with dial func") + } + return conn, err + } + + var netd net.Dialer + conn, err := netd.DialContext(ctx, network, addr) + if err != nil { + d.logger.Error(err) + } else { + d.logger.WithFields(map[string]interface{}{ + "src": conn.LocalAddr().String(), + "dst": addr, + }).Debugf("dial direct %s/%s", addr, network) + } + return conn, err +} diff --git a/pkg/dialer/grpc/metadata.go b/pkg/dialer/grpc/metadata.go new file mode 100644 index 0000000..d3beb20 --- /dev/null +++ b/pkg/dialer/grpc/metadata.go @@ -0,0 +1,22 @@ +package grpc + +import ( + mdata "github.com/go-gost/gost/pkg/metadata" +) + +type metadata struct { + insecure bool + host string +} + +func (d *grpcDialer) parseMetadata(md mdata.Metadata) (err error) { + const ( + insecure = "grpcInsecure" + host = "host" + ) + + d.md.insecure = mdata.GetBool(md, insecure) + d.md.host = mdata.GetString(md, host) + + return +} diff --git a/pkg/dialer/http2/dialer.go b/pkg/dialer/http2/dialer.go index 2790948..42f82d1 100644 --- a/pkg/dialer/http2/dialer.go +++ b/pkg/dialer/http2/dialer.go @@ -53,11 +53,6 @@ func (d *http2Dialer) Multiplex() bool { } func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.DialOption) (net.Conn, error) { - options := &dialer.DialOptions{} - for _, opt := range opts { - opt(options) - } - raddr, err := net.ResolveTCPAddr("tcp", address) if err != nil { d.logger.Error(err) @@ -69,11 +64,16 @@ func (d *http2Dialer) Dial(ctx context.Context, address string, opts ...dialer.D client, ok := d.clients[address] if !ok { + options := dialer.DialOptions{} + for _, opt := range opts { + opt(&options) + } + client = &http.Client{ Transport: &http.Transport{ TLSClientConfig: d.options.TLSConfig, DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return d.dial(ctx, network, addr, options) + return d.dial(ctx, network, addr, &options) }, ForceAttemptHTTP2: true, MaxIdleConns: 100, diff --git a/pkg/dialer/option.go b/pkg/dialer/option.go index ab92635..061dce8 100644 --- a/pkg/dialer/option.go +++ b/pkg/dialer/option.go @@ -36,11 +36,18 @@ func LoggerOption(logger logger.Logger) Option { } type DialOptions struct { + Host string DialFunc func(ctx context.Context, addr string) (net.Conn, error) } type DialOption func(opts *DialOptions) +func HostDialOption(host string) DialOption { + return func(opts *DialOptions) { + opts.Host = host + } +} + func DialFuncDialOption(dialf func(ctx context.Context, addr string) (net.Conn, error)) DialOption { return func(opts *DialOptions) { opts.DialFunc = dialf diff --git a/pkg/listener/grpc/listener.go b/pkg/listener/grpc/listener.go new file mode 100644 index 0000000..d9560d7 --- /dev/null +++ b/pkg/listener/grpc/listener.go @@ -0,0 +1,101 @@ +package grpc + +import ( + "net" + + pb "github.com/go-gost/gost/pkg/common/util/grpc/proto" + "github.com/go-gost/gost/pkg/listener" + "github.com/go-gost/gost/pkg/logger" + md "github.com/go-gost/gost/pkg/metadata" + "github.com/go-gost/gost/pkg/registry" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + +func init() { + registry.RegisterListener("grpc", NewListener) +} + +type grpcListener struct { + addr net.Addr + server *grpc.Server + cqueue chan net.Conn + errChan chan error + md metadata + logger logger.Logger + options listener.Options +} + +func NewListener(opts ...listener.Option) listener.Listener { + options := listener.Options{} + for _, opt := range opts { + opt(&options) + } + return &grpcListener{ + logger: options.Logger, + options: options, + } +} + +func (l *grpcListener) Init(md md.Metadata) (err error) { + if err = l.parseMetadata(md); err != nil { + return + } + + laddr, err := net.ResolveTCPAddr("tcp", l.options.Addr) + if err != nil { + return + } + + ln, err := net.ListenTCP("tcp", laddr) + if err != nil { + return + } + + var opts []grpc.ServerOption + if !l.md.insecure { + opts = append(opts, grpc.Creds(credentials.NewTLS(l.options.TLSConfig))) + } + + l.server = grpc.NewServer(opts...) + l.addr = ln.Addr() + l.cqueue = make(chan net.Conn, l.md.backlog) + l.errChan = make(chan error, 1) + + pb.RegisterGostTunelServer(l.server, &server{ + cqueue: l.cqueue, + localAddr: l.addr, + logger: l.options.Logger, + }) + + go func() { + err := l.server.Serve(ln) + if err != nil { + l.errChan <- err + } + close(l.errChan) + }() + + return +} + +func (l *grpcListener) Accept() (conn net.Conn, err error) { + var ok bool + select { + case conn = <-l.cqueue: + case err, ok = <-l.errChan: + if !ok { + err = listener.ErrClosed + } + } + return +} + +func (l *grpcListener) Close() error { + l.server.Stop() + return nil +} + +func (l *grpcListener) Addr() net.Addr { + return l.addr +} diff --git a/pkg/listener/grpc/metadata.go b/pkg/listener/grpc/metadata.go new file mode 100644 index 0000000..14f15a3 --- /dev/null +++ b/pkg/listener/grpc/metadata.go @@ -0,0 +1,29 @@ +package grpc + +import ( + mdata "github.com/go-gost/gost/pkg/metadata" +) + +const ( + defaultBacklog = 128 +) + +type metadata struct { + backlog int + insecure bool +} + +func (l *grpcListener) parseMetadata(md mdata.Metadata) (err error) { + const ( + backlog = "backlog" + insecure = "grpcInsecure" + ) + + l.md.backlog = mdata.GetInt(md, backlog) + if l.md.backlog <= 0 { + l.md.backlog = defaultBacklog + } + + l.md.insecure = mdata.GetBool(md, insecure) + return +} diff --git a/pkg/listener/grpc/server.go b/pkg/listener/grpc/server.go new file mode 100644 index 0000000..c46a833 --- /dev/null +++ b/pkg/listener/grpc/server.go @@ -0,0 +1,120 @@ +package grpc + +import ( + "errors" + "io" + "net" + "time" + + pb "github.com/go-gost/gost/pkg/common/util/grpc/proto" + "github.com/go-gost/gost/pkg/logger" +) + +type server struct { + cqueue chan net.Conn + localAddr net.Addr + pb.UnimplementedGostTunelServer + logger logger.Logger +} + +func (s *server) Tunnel(srv pb.GostTunel_TunnelServer) error { + c := &conn{ + s: srv, + localAddr: s.localAddr, + remoteAddr: &net.TCPAddr{}, + closed: make(chan struct{}), + } + + select { + case s.cqueue <- c: + default: + c.Close() + s.logger.Warnf("connection queue is full, client discarded") + } + + <-c.closed + + return nil +} + +type conn struct { + s pb.GostTunel_TunnelServer + rb []byte + localAddr net.Addr + remoteAddr net.Addr + closed chan struct{} +} + +func (c *conn) Read(b []byte) (n int, err error) { + select { + case <-c.s.Context().Done(): + err = c.s.Context().Err() + return + case <-c.closed: + err = io.ErrClosedPipe + return + default: + } + + if len(c.rb) == 0 { + chunk, err := c.s.Recv() + if err != nil { + return 0, err + } + c.rb = chunk.Data + } + + n = copy(b, c.rb) + c.rb = c.rb[n:] + return +} + +func (c *conn) Write(b []byte) (n int, err error) { + select { + case <-c.s.Context().Done(): + err = c.s.Context().Err() + return + case <-c.closed: + err = io.ErrClosedPipe + return + default: + } + + if err = c.s.Send(&pb.Chunk{ + Data: b, + }); err != nil { + return + } + n = len(b) + return +} + +func (c *conn) Close() error { + select { + case <-c.closed: + default: + close(c.closed) + } + + return nil +} + +func (c *conn) LocalAddr() net.Addr { + return c.localAddr +} + +func (c *conn) RemoteAddr() net.Addr { + return c.remoteAddr +} + +func (c *conn) SetDeadline(t time.Time) error { + return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} +} + +func (c *conn) SetReadDeadline(t time.Time) error { + return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} +} + +func (c *conn) SetWriteDeadline(t time.Time) error { + return &net.OpError{Op: "set", Net: "grpc", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} +} diff --git a/pkg/listener/tcp/listener.go b/pkg/listener/tcp/listener.go index 0af1139..7b3d7a7 100644 --- a/pkg/listener/tcp/listener.go +++ b/pkg/listener/tcp/listener.go @@ -14,20 +14,20 @@ func init() { } type tcpListener struct { - addr string - md metadata net.Listener - logger logger.Logger + logger logger.Logger + md metadata + options listener.Options } func NewListener(opts ...listener.Option) listener.Listener { - options := &listener.Options{} + options := listener.Options{} for _, opt := range opts { - opt(options) + opt(&options) } return &tcpListener{ - addr: options.Addr, - logger: options.Logger, + logger: options.Logger, + options: options, } } @@ -36,7 +36,7 @@ func (l *tcpListener) Init(md md.Metadata) (err error) { return } - laddr, err := net.ResolveTCPAddr("tcp", l.addr) + laddr, err := net.ResolveTCPAddr("tcp", l.options.Addr) if err != nil { return }