Skip to content

Commit

Permalink
Merge pull request #3 from dollarkillerx/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
dollarkillerx authored Oct 31, 2020
2 parents 5bd3c80 + 7a0be2a commit 782af6d
Show file tree
Hide file tree
Showing 12 changed files with 986 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@

# Dependency directories (remove the comment below to include it)
# vendor/
.idea
.vscode
ip2region.db

plumber
pct.md
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Generate:
@echo 'Build GRPC'
protoc -I rpc/proto/ rpc/proto/*.proto --go_out=plugins=grpc:rpc/proto/.

generate_test:
@echo 'generate_test'
protoc -I test_simple/proto/ test_simple/proto/*.proto --go_out=plugins=grpc:test_simple/proto/.
protoc -I test_stream/proto/ test_stream/proto/*.proto --go_out=plugins=grpc:test_stream/proto/.


SSLKey:
@echo 'SSLKey'
openssl genrsa -out cert/server.key 2048
openssl ecparam -genkey -name secp384r1 -out cert/serveryek
openssl req -new -x509 -sha256 -key cert/serveryek -out cert/servermpe -days 3650 # plumber
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
# plumber
walk in the darkness and worship the light.

### 测试
Cloudflase
1. simple
2. stream

推荐使用Stream
`CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w" -tags=tcp `
272 changes: 272 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
package main

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"io"
"log"
"net"
"os"
"plumber/utils"
"strconv"

"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"plumber/rpc"
)

const pem = `
-----BEGIN CERTIFICATE-----
MIICYzCCAeqgAwIBAgIUTShO8REvwRrDoBdRq9ZzzcEMP6swCgYIKoZIzj0EAwIw
aTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu
dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEQMA4GA1UECwwHcGx1bWJlcjEQMA4GA1UE
AwwHcGx1bWJlcjAeFw0yMDEwMjcxMTU1MDZaFw0zMDEwMjUxMTU1MDZaMGkxCzAJ
BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l
dCBXaWRnaXRzIFB0eSBMdGQxEDAOBgNVBAsMB3BsdW1iZXIxEDAOBgNVBAMMB3Bs
dW1iZXIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATvf5qn0hKp56iFULTyXfTNRVMf
8mBgQR8GiJlhMNs8SE/128T2lD0UFDMrAVxKxo/rHsP5ORiP/uc9NnK721dVlmcH
40XGXtW2BbThJeCFdNO1ife81fuqzxWx4oSIGWajUzBRMB0GA1UdDgQWBBQoI4sE
Nx8JzONu9VixAeN1Kr5GdzAfBgNVHSMEGDAWgBQoI4sENx8JzONu9VixAeN1Kr5G
dzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA2cAMGQCMEa8IP5y+EzZOzrm
O9yFZkNqkBkFl00M0GAR5wvO1W6pyC7tJfvgxd8C3mClltakOgIwXzDvpKz9eG4h
59r69pUhx2Jc5ffDO/SbNEx51o3zOvdR77OxaJvNS/cyC2TENO8C
-----END CERTIFICATE-----
`

// ./client addr socketAddr user passwd
func main() {
//log.SetFlags(log.LstdFlags | log.Llongfile)
if len(os.Args) < 5 {
log.Fatalln("what fuck???")
}
addr, err := net.ResolveTCPAddr("tcp", os.Args[2])
if err != nil {
log.Fatalln(err)
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
log.Fatalln(err)
}
log.Println("Socket Addr: ", os.Args[2])
s := New(os.Args[1])
if len(os.Args) > 5 {
s.pac = true
log.Println("Pac Model")
}

for {
client, err := l.Accept()
if err != nil {
log.Println(err)
continue
}

go s.handleClientRequest(client)
}
}

type server struct {
client rpc.PlumberClient
pac bool
}

func New(addr string) *server {
creds, err := NewClientTLSFromFile(pem, "plumber")
if err != nil {
log.Fatalln(err)
}

conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(creds), grpc.WithPerRPCCredentials(&loginCreds{
Username: os.Args[3],
Password: os.Args[4],
}))

client := rpc.NewPlumberClient(conn)
return &server{client: client}
}

func (s *server) handleClientRequest(client net.Conn) {
defer func() {
if err := recover(); err != nil {
fmt.Printf("%s\n", err)
return
}
}()

if client == nil {
return
}
defer client.Close()
var b [1024]byte
n, err := client.Read(b[:])
if err != nil {
//log.Println(err)
return
}
var pac bool
if b[0] == 0x05 { //只处理Socket5协议
//客户端回应:Socket服务端不需要验证方式
client.Write([]byte{0x05, 0x00})
n, err = client.Read(b[:])
var host, port string
switch b[3] {
case 0x01: //IP V4
host = net.IPv4(b[4], b[5], b[6], b[7]).String()
pac, err = s.isPac(host, "")
if err != nil {
//log.Println(err)
return
}
case 0x03: //域名
host = string(b[5 : n-2]) //b[4]表示域名的长度
pac, err = s.isPac("", host)
if err != nil {
//log.Println(err)
return
}
case 0x04: //IP V6
//host = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
return
}
port = strconv.Itoa(int(b[n-2])<<8 | int(b[n-1]))

addr := net.JoinHostPort(host, port)

if _, err := client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); err != nil { //响应客户端连接成功
//log.Println(err)
return
}

if pac {
simple(client, addr)
return
}

//进行转发
stream, err := s.client.Plumber(context.TODO())
if err != nil {
//log.Println(err)
return
}


if err := stream.Send(&rpc.PlumberRequest{
Addr: addr,
}); err != nil {
//log.Println(err)
return
}

go copy1(stream, client)
copy2(client, stream)
}
}

func copy1(server rpc.Plumber_PlumberClient, client io.Reader) {
for {
var b [1024]byte
read, err := client.Read(b[:])
if err != nil {
if err == io.EOF {
server.Send(&rpc.PlumberRequest{Over: true})
break
}
break
}

if err := server.Send(&rpc.PlumberRequest{Data: b[:read]}); err != nil {
//log.Println(err)
break
}
}
}

func copy2(client io.Writer, server rpc.Plumber_PlumberClient) {
for {
recv, err := server.Recv()
if err != nil {
//log.Println(err)
break
}
if _, err := client.Write(recv.Data); err != nil {
//log.Println(err)
break
}
}
}

func (s *server) isPac(ip string, domain string) (bool, error) {
if s.pac {
if ip != "" {
search, err := utils.IP2.MemorySearch(ip)
if err != nil {
return false, err
}
if search.Country == "中国" {
return true, nil
}
}
if domain != "" {
lookupIP, err := net.LookupIP(domain)
if err != nil {
return false, err
}
if len(lookupIP) >= 1 {
search, err := utils.IP2.MemorySearch(lookupIP[0].String())
if err != nil {
return false, err
}
if search.Country == "中国" {
return true, nil
}
}
}
}
return false, nil
}

func simple(client net.Conn, addr string) {
//log.Println("Simple ", addr)
addrs, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
return
}
server, err := net.DialTCP("tcp", nil, addrs)
if err != nil {
return
}

if err := server.SetLinger(0); err != nil {
return
}

defer server.Close()
//进行转发
go io.Copy(server, client)
io.Copy(client, server)
}

type loginCreds struct {
Username, Password string
}

func (c *loginCreds) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
return map[string]string{
"username": c.Username,
"password": c.Password,
}, nil
}

func (c *loginCreds) RequireTransportSecurity() bool {
return true
}

func NewClientTLSFromFile(certFile, serverNameOverride string) (credentials.TransportCredentials, error) {
cp := x509.NewCertPool()
if !cp.AppendCertsFromPEM([]byte(certFile)) {
return nil, fmt.Errorf("credentials: failed to append certificates")
}
return credentials.NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp}), nil
}
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module plumber

go 1.13

require (
github.com/golang/protobuf v1.4.1
github.com/lionsoul2014/ip2region v2.2.0-release+incompatible
google.golang.org/grpc v1.33.1
google.golang.org/protobuf v1.25.0
)
Loading

0 comments on commit 782af6d

Please sign in to comment.