mirror of
https://github.com/net-byte/vtun
synced 2024-03-14 10:50:03 +08:00
123 lines
3.1 KiB
Go
123 lines
3.1 KiB
Go
package grpc
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/golang/snappy"
|
|
"github.com/net-byte/vtun/grpc/proto"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
|
|
"github.com/net-byte/vtun/common/cache"
|
|
"github.com/net-byte/vtun/common/cipher"
|
|
"github.com/net-byte/vtun/common/config"
|
|
"github.com/net-byte/vtun/common/counter"
|
|
"github.com/net-byte/vtun/common/netutil"
|
|
"github.com/net-byte/water"
|
|
)
|
|
|
|
// The StreamService is the implementation of the StreamServer interface
|
|
type StreamService struct {
|
|
proto.UnimplementedGrpcServeServer
|
|
config config.Config
|
|
iface *water.Interface
|
|
}
|
|
|
|
// Tunnel implements the StreamServer interface
|
|
func (s *StreamService) Tunnel(srv proto.GrpcServe_TunnelServer) error {
|
|
toServer(srv, s.config, s.iface)
|
|
return nil
|
|
}
|
|
|
|
// GetHTTPServeMux common HTTP Server
|
|
func GetHTTPServeMux() *http.ServeMux {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("follow"))
|
|
})
|
|
return mux
|
|
}
|
|
|
|
// StartServer starts the grpc server
|
|
func StartServer(iface *water.Interface, config config.Config) {
|
|
log.Printf("vtun grpc server started on %v", config.LocalAddr)
|
|
creds, err := credentials.NewServerTLSFromFile(config.TLSCertificateFilePath, config.TLSCertificateKeyFilePath)
|
|
if err != nil {
|
|
log.Panic(err)
|
|
}
|
|
mux := GetHTTPServeMux()
|
|
grpcServer := grpc.NewServer(grpc.Creds(creds))
|
|
proto.RegisterGrpcServeServer(grpcServer, &StreamService{config: config, iface: iface})
|
|
go toClient(config, iface)
|
|
err = http.ListenAndServeTLS(config.LocalAddr, config.TLSCertificateFilePath, config.TLSCertificateKeyFilePath, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
|
|
grpcServer.ServeHTTP(w, r)
|
|
} else {
|
|
mux.ServeHTTP(w, r)
|
|
}
|
|
return
|
|
}))
|
|
if err != nil {
|
|
log.Fatalf("grpc server error: %v", err)
|
|
}
|
|
}
|
|
|
|
// toClient sends packets from tun to grpc
|
|
func toClient(config config.Config, iface *water.Interface) {
|
|
packet := make([]byte, config.BufferSize)
|
|
for {
|
|
n, err := iface.Read(packet)
|
|
if err != nil {
|
|
netutil.PrintErr(err, config.Verbose)
|
|
break
|
|
}
|
|
b := packet[:n]
|
|
if key := netutil.GetDstKey(b); key != "" {
|
|
if v, ok := cache.GetCache().Get(key); ok {
|
|
if config.Obfs {
|
|
b = cipher.XOR(b)
|
|
}
|
|
if config.Compress {
|
|
b = snappy.Encode(nil, b)
|
|
}
|
|
err := v.(proto.GrpcServe_TunnelServer).Send(&proto.PacketData{Data: b})
|
|
if err != nil {
|
|
cache.GetCache().Delete(key)
|
|
continue
|
|
}
|
|
counter.IncrWrittenBytes(n)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// toServer sends packets from grpc to tun
|
|
func toServer(srv proto.GrpcServe_TunnelServer, config config.Config, iface *water.Interface) {
|
|
for {
|
|
packet, err := srv.Recv()
|
|
if err != nil {
|
|
netutil.PrintErr(err, config.Verbose)
|
|
break
|
|
}
|
|
b := packet.Data[:]
|
|
if config.Compress {
|
|
b, err = snappy.Decode(nil, b)
|
|
if err != nil {
|
|
netutil.PrintErr(err, config.Verbose)
|
|
break
|
|
}
|
|
}
|
|
if config.Obfs {
|
|
b = cipher.XOR(b)
|
|
}
|
|
if key := netutil.GetSrcKey(b); key != "" {
|
|
cache.GetCache().Set(key, srv, 24*time.Hour)
|
|
iface.Write(b)
|
|
counter.IncrReadBytes(len(b))
|
|
}
|
|
}
|
|
}
|