Go编写流量代理工具

这是一个演示

代理本地HTTP服务
在这里插入图片描述
代理局域网SSH服务
在这里插入图片描述
在这里插入图片描述
其他的TCP服务没测试了


主要分为俩包:

main -》 主函数,包含Server、Client函数和goroutine函数
utils -》 工具函数,包含发包和读包函数,现在使用的是json序列化没有加密(内置AES256加密,可以把粘包问题处理后进行使用)


流程:

返回数据呈现给用户:

本地Conn -》服务器中转Conn -》 服务器代理Conn

用户发送请求到本地:

服务器代理Conn -》 本地中转Conn -》 本地Conn


逻辑:(端口随意,本地ssh为例)

  • Server (对外IP 1.2.3.4)
    1. 先监听0.0.0.0:2222(中转代理服务)
      • 有连接 -》进行②
      • 无连接 -》 继续听(每隔5秒)
    2. 再监听0.0.0.0:3333(代理出来的端口)

  • Client
    1. 先连接127.0.0.1:22(本地服务)(这两个先后顺序无所谓)
      • 成功 -》进行②
      • 失败-》 继续连(每隔5秒)
    2. 再连接1.2.3.4:2222(中转代理服务)

用法:

使用方法:
服务器模式:
  程序名 -s R1地址:端口 Up地址:端口
  例子:程序名 -s x.x.x.x:2222 x.x.x.x:3333
客户端模式:
  程序名 -c 本地地址:端口 R1地址:端口
  例子:程序名 -c 127.0.0.1:22 x.x.x.x:2222
显示帮助信息:
  程序名 -h

文件地址:

Github地址:https://github.com/jumppppp/go/tree/master/htools/pangolin

代码如下:

package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"net"
	"pangolin/utils"
	"time"
)

type Client_t struct{
	ConnLocal net.Conn
	BufR1 [1024]byte
	ConnR1 net.Conn
	ConnectedR1 bool
}
type Server_t struct{
	LnR1 net.Listener
	ConnR1 net.Conn
	ConnectedUp bool
	LnUp net.Listener
	ConnUp net.Conn
	BufR1 [1024]byte
}

func printUsage() {
	fmt.Println("使用方法:")
	fmt.Println("服务器模式:")
	fmt.Println("  程序名 -s R1地址:端口 Up地址:端口")
	fmt.Println("  例子:程序名 -s x.x.x.x:2222 x.x.x.x:3333")
	fmt.Println("客户端模式:")
	fmt.Println("  程序名 -c 本地地址:端口 R1地址:端口")
	fmt.Println("  例子:程序名 -c 127.0.0.1:22 x.x.x.x:2222")
	fmt.Println("显示帮助信息:")
	fmt.Println("  程序名 -h")
}
func main() {
	var (
		helpFlag   bool
		serverFlag bool
		clientFlag bool
	)

	// 设置命令行参数
	flag.BoolVar(&helpFlag, "h", false, "显示帮助信息")
	flag.BoolVar(&serverFlag, "s", false, "使用服务器模式")
	flag.BoolVar(&clientFlag, "c", false, "使用客户端模式")

	flag.Parse()

	if helpFlag {
		printUsage()
		return
	}

	args := flag.Args()

	if serverFlag {
		if len(args) != 2 {
			fmt.Println("错误:请提供R1地址和Up地址")
			printUsage()
			return
		}

		HpR1 := args[0]
		HpUp := args[1]

		Server(HpR1, HpUp)
	} else if clientFlag {
		if len(args) != 2 {
			fmt.Println("错误:请提供本地地址和R1地址")
			printUsage()
			return
		}

		HpLocal := args[0]
		HpR1 := args[1]

		Client(HpR1, HpLocal)
	} else {
		fmt.Println("错误:请提供-s或-c选项")
		printUsage()
	}
}
func Server(HpR1 string,HpUp string)(){
	ms:=&Server_t{}
	var err error
	ms.LnR1,err = net.Listen("tcp",HpR1)
	if err!=nil{
		fmt.Println("远程服务R1 No=",err)
	}
	fmt.Println("远程服务R1...")

	ms.LnUp,err = net.Listen("tcp",HpUp)
	if err!=nil{
		fmt.Println("远程服务Up No=",err)
	}
	fmt.Println("远程服务Up...")

	go ms.handleServerR1()
	ms.handleServerUp()


}
func (this * Server_t)handleServerR1()(){
	var err error
	for{

		this.ConnR1,err  = this.LnR1.Accept()
		if err != nil {
			fmt.Println("Accept error:", err)
			continue // 继续等待下一个连接请求
		}
		fmt.Println(this.ConnR1.RemoteAddr().String()," Connect ",this.ConnR1.LocalAddr().String())
		for{
			tf := &utils.Transfer{Conn: this.ConnR1,}
			data,err,offset,data2:=tf.ReadPkgNo()

			if err!=nil{
				fmt.Println("R R1 No=",err)
				if err == io.EOF { // 远程主机已经关闭连接
					fmt.Println("Connection closed by remote host")

				}
				break
			}

			switch data.Type{
			case utils.BackType:
				// fmt.Println(data)
				for {
					if this.ConnectedUp{
						this.ConnUp.Write(data.Data)
						if offset!=0{
							this.ConnUp.Write(data2.Data)
						}
						break
					}else{
						fmt.Println("未检测到Up连接 等待5秒")
						time.Sleep(5*time.Second)
					}
				}

			case utils.GoType:
				fmt.Println(data)
			default:
				fmt.Println(data)
			}
	
		}
		this.ConnR1.Close() // 关闭连接
	}

	
}
func (this * Server_t)handleServerUp()(){
	var err error
	for {
		this.ConnUp, err = this.LnUp.Accept()
		if err != nil {
			fmt.Println("Accept error:", err)
			continue // 继续等待下一个连接请求
		}
		fmt.Println(this.ConnUp.RemoteAddr().String(), " Connect ", this.ConnUp.LocalAddr().String())
		this.ConnectedUp = true
		for {
			n, err := this.ConnUp.Read(this.BufR1[:])
			if err != nil {
				fmt.Println("R Up No", err)
				if err == io.EOF { // 远程主机已经关闭连接
					fmt.Println("Connection closed by remote host")
				}
				this.ConnectedUp = false
				break // 退出当前循环并关闭连接
			}
			tf:=&utils.Transfer{Conn: this.ConnR1,}
			//发送返回包
			var GoMsg utils.Message
			GoMsg.Type = utils.GoType
			GoMsg.Data = this.BufR1[:n]
			GoMsgM,err:=json.Marshal(GoMsg)
			if err!=nil{
				fmt.Println("No=",err)
			}
			
			err = tf.WritePkgNo(GoMsgM)
			if err!=nil{
				fmt.Println("WNo=",err)
			}
			for i := range this.BufR1 {
				this.BufR1[i] = 0
			}

		}
	
		this.ConnUp.Close() // 关闭连接
	}
	
}
func Client(HpR1 string,HpLocal string)(){
	mc:=&Client_t{}

	go mc.handleR1(HpR1)
	mc.handleLocal(HpLocal)


}
func (this * Client_t)handleLocal(hp string){
	//做最大次数尝试
	var err error
	for{
		this.ConnLocal,err = net.Dial("tcp",hp)
		if err!=nil{
			fmt.Println("本地服务连接No=",err)
		}
		fmt.Println("本地服务已连接")
		for{
			n,err := this.ConnLocal.Read(this.BufR1[:])
			if err!=nil{
				fmt.Println("R Local No=",err)
				if err == io.EOF { // 远程主机已经关闭连接
					fmt.Println("Connection closed by remote host")
				}
				break
			}
	
			if this.ConnectedR1{
				tf:=&utils.Transfer{Conn: this.ConnR1,}
				//发送返回包
				var BackMsg utils.Message
				BackMsg.Type = utils.BackType
				BackMsg.Data = this.BufR1[:n]
				BackMsgM,err:=json.Marshal(BackMsg)
				if err!=nil{
					fmt.Println("No=",err)
				}
				fmt.Println("读到",n,"发送",len(BackMsgM))
				err = tf.WritePkgNo(BackMsgM)
				if err!=nil{
					fmt.Println("WNo=",err)
				}
				for i := range this.BufR1 {
					this.BufR1[i] = 0
				}
			}else{
				fmt.Println("未检测到R1连接 等待5秒")
				time.Sleep(5*time.Second)
			}

			
		}
		this.ConnLocal.Close()
	}
	
}
func (this * Client_t)handleR1(hp string){
	// defer HR.Done()
	var err error
	for{
		this.ConnR1,err = net.Dial("tcp",hp)
		if err!=nil{
			fmt.Println("远程服务R1 等待5秒 No=",err)
			time.Sleep(5*time.Second)
			continue
		}
		fmt.Println("远程服务已连接")
		this.ConnectedR1 = true
		for{
			
			tf := &utils.Transfer{Conn: this.ConnR1,}
			data,err,offset,data2:=tf.ReadPkgNo()
			if err!=nil{
				fmt.Println("R R1 No=",err)
				if err == io.EOF { // 远程主机已经关闭连接
					fmt.Println("Connection closed by remote host")
				}
				this.ConnectedR1 = false
				break

			}
			switch data.Type{
			case utils.BackType:
				fmt.Println(data)
			case utils.GoType:
				// fmt.Println(data)
				this.ConnLocal.Write(data.Data)
				if offset!=0{
					this.ConnLocal.Write(data2.Data)
				}
			default:
				fmt.Println(data)
			}
			
		}
		this.ConnR1.Close()
	}
	
}


package utils

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/binary"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"net"
)
var (
	GoType string ="Go"
	BackType string = "Back"
)

type Message struct{
	Type string `json:"type"`
	Data []byte	`json:"data"`
}
type Transfer struct{
	Conn net.Conn	//文件描述符
	Buf [4096]byte //缓冲
}
func (this *Transfer)WritePkgNo(data []byte) (err error) {
    pkgLen := uint32(len(data))
    binary.BigEndian.PutUint32(this.Buf[:4], pkgLen)
    n := copy(this.Buf[4:], data)
	if n!=int(pkgLen){
		fmt.Println("Copy No=",n,"!=",int(pkgLen))
		return
	}
    lastLen :=int(pkgLen)+4
    // fmt.Println("W=",this.Buf[:4],string(this.Buf[4:lastLen]),int(pkgLen),string(data))
    fmt.Println("W=",int(pkgLen))
    n,err=this.Conn.Write(this.Buf[:lastLen])
    if err!=nil || int(lastLen)!=n{
        fmt.Println(err,int(lastLen),"!=",n)
        return
    }
    return
}

func (this *Transfer)ReadPkgNo()(msg Message,err error,offset int,msg2 Message){
    n,err:=this.Conn.Read(this.Buf[:])
    if err!=nil{
        fmt.Println("R No=",err)
        return
    }
    var pkgLen uint32
	pkgLen = binary.BigEndian.Uint32(this.Buf[:4])
    lastLen:=int(pkgLen)+4
    // fmt.Println("R=",this.Buf[:4],string(this.Buf[4:lastLen]),int(pkgLen),string(this.Buf[4:n]))
    fmt.Println("W=",int(pkgLen))
    if n!=lastLen{
        fmt.Println("[1]",int(lastLen),"!=",n)
        offset = lastLen
        var pkgLen2 uint32
	    pkgLen2 = binary.BigEndian.Uint32(this.Buf[offset:offset+4])
        if n!= offset+4+int(pkgLen2){
            fmt.Println("[2]",int(offset+4+int(pkgLen2)),"!=",n)
        }
        err = json.Unmarshal(this.Buf[offset+4:offset+4+int(pkgLen2)],&msg2)
        if err!=nil{
            fmt.Println("Unmarshal No=",err)
            return
        }
        fmt.Println("第二个包",msg2)
    }else{
        offset = 0
    }

    err = json.Unmarshal(this.Buf[4:lastLen],&msg)
    if err!=nil{
        fmt.Println("Unmarshal No=",err)
        return
    }
	return 
}

func (this *Transfer)WritePkg(data []byte) (err error) {
	//加密流程,长度+原始内容 -》 替换过的密钥(32)+长度(4)+加密内容
	pkgLen := uint32(len(data))
    fmt.Println("write n=",int(pkgLen))
	var BufTemp [4096]byte
	binary.BigEndian.PutUint32(BufTemp[:4], pkgLen)
	n := copy(BufTemp[4:], data)
	if n!=int(pkgLen){
		fmt.Println("WNo=",n,"!=",int(pkgLen))
		return
	}
	lastLenTemp := 4+n
	// fmt.Println(string(BufTemp[:]))
	//加密程序
	oldKey,newKey:= OutKey()
	// fmt.Println(string(oldKey),len(oldKey),string(newKey),len(newKey))
	ciphertext, err := EncryptAES(BufTemp[:lastLenTemp],[]byte(oldKey))
    if err != nil {
        fmt.Println("EncodeNo=",err)
		return
    }
	EnpkgLen := uint32(len(ciphertext))
	binary.BigEndian.PutUint32(this.Buf[32:36], EnpkgLen)
	copy(this.Buf[:32], newKey)
	n =copy(this.Buf[36:],ciphertext)
	lastLen := 36+n
	// fmt.Println(string(this.Buf[:32]),this.Buf[32:36],this.Buf[36:lastLen])
	//发包
	n, err = this.Conn.Write(this.Buf[:lastLen])
	if err != nil || n!=int(lastLen) {
		fmt.Println("WNo=", err,n,"!=",int(lastLen))
		return
	}

	//调试
	// fmt.Println("W=",this.Buf[:4],string(this.Buf[4:lastLen]),"n=",n)
	return
}
func (this *Transfer)ReadPkg()(msg Message,err error){
	//解密流程,替换过的密钥(32)+长度(4)+加密内容 -》  长度+原始内容 
	//fmt.Println("Reading client send message...")
	n,err:=this.Conn.Read(this.Buf[:])
	if err!=nil{
		return
	}
	if n<=32{
		err  = fmt.Errorf("The Readpkg is Null %v %v %v %v",string(this.Buf[:n]),this.Buf[:n],this.Conn.RemoteAddr().String(),this.Conn.LocalAddr().String())
		return
	}
	var EnpkgLen uint32
	EnpkgLen = binary.BigEndian.Uint32(this.Buf[32:36])
	newKey := string(this.Buf[:32])
	oldKey := KeyOut(newKey)
	// fmt.Println(newKey,oldKey,EnpkgLen)
	EncodeData := this.Buf[36:36+EnpkgLen]
	// fmt.Println(EncodeData)
	// decrypt ciphertext with AES-256-CBC
	decryptedPlaintext, err := DecryptAES(EncodeData, []byte(oldKey))
	if err != nil {
		fmt.Println("DecodeNo=",err)
		return
	}
	n = copy(this.Buf[:],decryptedPlaintext)
	// fmt.Println(string(decryptedPlaintext),n)
	//调试
	var pkgLen uint32
	pkgLen = binary.BigEndian.Uint32(this.Buf[:4])
	//调试
    fmt.Println("read n=",int(pkgLen))
	// fmt.Println("R=",this.Buf[:4],string(this.Buf[4:n]),"n=",n)
	if err!=nil||(n-4)!=int(pkgLen){
		fmt.Println("RNo=",err,(n-4),"!=",int(pkgLen))
		return
	}
	//调试
    err = json.Unmarshal(this.Buf[4:n],&msg)
    if err!=nil{
        fmt.Println("No=",err)
    }
	return 
}


func OutKey() (oldKey string, newKey string) {
    // 生成32字节的随机密钥
    key := make([]byte, 16)
    if _, err := rand.Read(key); err != nil {
        panic(err)
    }
    oldKey = hex.EncodeToString(key)

    // 转换为16进制字符串并替换字符
    replacementMap := map[rune]rune{
        '0': 'f',
        '1': 'e',
        '2': 'd',
        '3': 'c',
        '4': 'b',
        '5': 'a',
        '6': '9',
        '7': '8',
        '8': '7',
        '9': '6',
        'a': '5',
        'b': '4',
        'c': '3',
        'd': '2',
        'e': '1',
        'f': '0',
    }
    var buffer bytes.Buffer
    for _, r := range oldKey {
        if original, ok := replacementMap[r]; ok {
            buffer.WriteRune(original)
        } else {
            buffer.WriteRune(r)
        }
    }
    newKey = buffer.String()


    return
}

func KeyOut(hexKey string) string {
    // 构造字符替换表
    replacementMap := map[rune]rune{
        'f': '0',
        'e': '1',
        'd': '2',
        'c': '3',
        'b': '4',
        'a': '5',
        '9': '6',
        '8': '7',
        '7': '8',
        '6': '9',
        '5': 'a',
        '4': 'b',
        '3': 'c',
        '2': 'd',
        '1': 'e',
        '0': 'f',
    }

    // 转换为字节数组并替换字符
    keyBytes, err := hex.DecodeString(hexKey)
    if err != nil {
        panic(err)
    }
    var buffer bytes.Buffer
    for _, b := range keyBytes {
        hexStr := hex.EncodeToString([]byte{b})
        rune1 := rune(hexStr[0])
        rune2 := rune(hexStr[1])
        if original1, ok := replacementMap[rune1]; ok {
            buffer.WriteRune(original1)
        } else {
            buffer.WriteRune(rune1)
        }
        if original2, ok := replacementMap[rune2]; ok {
            buffer.WriteRune(original2)
        } else {
            buffer.WriteRune(rune2)
        }
    }
    replacedHexKey := buffer.String()

    return replacedHexKey
}
// EncryptAES encrypts plaintext using AES-256-CBC with the given key
func EncryptAES(plaintext []byte, key []byte) ([]byte, error) {
    // create AES cipher block
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }

    // pad plaintext with PKCS#7 padding
    paddedPlaintext := pkcs7Pad(plaintext, aes.BlockSize)

    // generate random IV
    iv := make([]byte, aes.BlockSize)
    if _, err := rand.Read(iv); err != nil {
        return nil, err
    }

    // create CBC mode encrypter
    cbc := cipher.NewCBCEncrypter(block, iv)

    // encrypt plaintext
    ciphertext := make([]byte, len(paddedPlaintext))
    cbc.CryptBlocks(ciphertext, paddedPlaintext)

    // append IV to the beginning of the ciphertext
    ciphertext = append(iv, ciphertext...)

    return ciphertext, nil
}

// DecryptAES decrypts ciphertext using AES-256-CBC with the given key
func DecryptAES(ciphertext []byte, key []byte) ([]byte, error) {
    if len(ciphertext) < aes.BlockSize*2 {
        return nil, errors.New("invalid ciphertext")
    }

    // extract IV from the beginning of the ciphertext
    iv := ciphertext[:aes.BlockSize]
    ciphertext = ciphertext[aes.BlockSize:]

    // create AES cipher block
    block, err := aes.NewCipher(key)
    if err != nil {
        return nil, err
    }

    // create CBC mode decrypter
    cbc := cipher.NewCBCDecrypter(block, iv)

    // decrypt ciphertext
    decryptedPlaintext := make([]byte, len(ciphertext))
    cbc.CryptBlocks(decryptedPlaintext, ciphertext)

    // unpad plaintext by removing PKCS#7 padding
    plaintext, err := pkcs7Unpad(decryptedPlaintext, aes.BlockSize)
    if err != nil {
        return nil, err
    }

    return plaintext, nil
}

func pkcs7Pad(data []byte, blockSize int) []byte {
    padding := blockSize - len(data)%blockSize
    padText := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(data, padText...)
}

func pkcs7Unpad(data []byte, blockSize int) ([]byte, error) {
    length := len(data)
    if length == 0 {
        return nil, errors.New("empty data")
    }
    if length%blockSize != 0 {
        return nil, errors.New("invalid data length")
    }
    padding := int(data[length-1])
    if padding > blockSize || padding == 0 {
        return nil, errors.New("invalid padding")
    }
    for i := 1; i <= padding; i++ {
        if data[length-i] != byte(padding) {
            return nil, errors.New("invalid padding")
        }
    }
    return data[:length-padding], nil
}


代码还会出现一些问题,粘包问题,不能多个连接等问题

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我重来不说话

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值