GO 的 socks5代理 编写

这里学习一下 socks5 代理的编写

网上有很多 学习一下

go 语言实战入门案例之实现Socks5 - 知乎

滑动验证页面

socks5协议原理学习-腾讯云开发者社区-腾讯云 (tencent.com)

首先我们要了解一下socks5的代理方式

socks5 是基于

  • 认证
  • 建立连接
  • 转发数据

所形成的代理 我们只需要按照这三个写出代码即可 

首先就是socks5的认证

Socks5Atuth

这里首先要认证 那么我们首先要确定是不是socks5代理

 在socks5中 前两个字节 分别是 socks版本号 和 支持的认证方式

前面两个 1

所以这里我们开始读取前面的 版本号 ver socks5是固定值 0x05

这里开始编写一下监听

package mainimport ("bufio""fmt""log""net"
)const socks5Ver = 0x05
const cmdVer = 0x01
const aytpVerIpv4 = 0x01
const aytpVerUrl = 0x03   //这里是下面的常量 不需要理会即可 当作值即可func main() {server, err := net.Listen("tcp", "127.0.0.1:1080")if err != nil {panic(err)}for {client, err := server.Accept()if err != nil {log.Printf("Accpet error :", err)continue}//确定ip端口 进行链接后 开始进程fmt.Println("开始监听", client, client.RemoteAddr())}
}

 然后开始处理数据

首先我们需要开启一个协程 处理

func process(conn net.Conn) {defer conn.Close()readio := bufio.NewReader(conn)err := auth(readio, conn)
}

这里我们首先处理一下认证的信息

	// +----+----------+----------+// |VER | NMETHODS | METHODS  |// +----+----------+----------+// | 1  |    1     | 1 to 255 |// +----+----------+----------+// VER: 协议版本,socks5为0x05// NMETHODS: 支持认证的方法数量// METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:// X’00’ NO AUTHENTICATION REQUIRED// X’02’ USERNAME/PASSWORD// 版本和NMETHODS值都是单字节的,所以ReadByte读一个字节就好了

这里需要认证的东西就是这些 我们首先进行认证 ver

func auth(readio *bufio.Reader, conn net.Conn) (err error) {ver, err := readio.ReadByte()fmt.Println(ver)return nil
}

这里是通过 readbyte 读取一个字节 我们输出一下就知道是多少了

发现我们通过浏览器进行代理 第一个byte是 5 对应 socks5

如果将代理设置为 socks4 那么这里就是对应4

 然后这里进行匹配 如果不是就输出错误 这样 ver认证就结束了

认证的ver

func auth(readio *bufio.Reader, conn net.Conn) (err error) {ver, err := readio.ReadByte()if err != nil {return fmt.Errorf("ver error:", err)}if ver != socks5Ver {return fmt.Errorf("ver num error: ", err)}}

认证method        

这里是socks5的认证,是否需要认证

	methodSize, err := readio.ReadByte()fmt.Println(methodSize)return

其实这里就是读取一个字节的大小

func auth(readio *bufio.Reader, conn net.Conn) (err error) {ver, err := readio.ReadByte()if err != nil {return fmt.Errorf("ver error:", err)}if ver != socks5Ver {return fmt.Errorf("ver num error: ", err)}methodSize, err := readio.ReadByte() //确定切片大小 为 1字节method := make([]byte, methodSize)   //创建一个大小的切片_, err = io.ReadFull(readio, method) // 这里是判断是否读了if err != nil {return fmt.Errorf("read method error :", err)}_, err = conn.Write([]byte{socks5Ver, 0x00}) // 这里是握手的回复 说明我们不需要认证if err != nil {return fmt.Errorf("write error:", err)}return nil
}

这里注意

_, err = conn.Write([]byte{socks5Ver, 0x00}) 

这里其实是监听后告诉 不需要进行 认证

当我们认证完后开始处理浏览器的报文

Socks5Connect

	// 读取浏览器发送的报文// +----+-----+-------+------+----------+----------+// |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |// +----+-----+-------+------+----------+----------+// | 1  |  1  | X'00' |  1   | Variable |    2     |// +----+-----+-------+------+----------+----------+// VER 版本号,socks5的值为0x05// CMD 0x01表示CONNECT请求// RSV 保留字段,值为0x00// ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。//   0x01表示IPv4地址,DST.ADDR为4个字节//   0x03表示域名,DST.ADDR是一个可变长度的域名// DST.ADDR 一个可变长度的值// DST.PORT 目标端口,固定2个字节这里是浏览器发送的报文 我们依旧先进行鉴定
func connnect(readio *bufio.Reader, conn net.Conn) (err error) {buf := make([]byte, 4)_, err = io.ReadFull(readio, buf) // 这里是读取字节数 读取前面4个作为一个切片if err != nil {return fmt.Errorf("read header error :", err)}var ver, cmd, atyp = buf[0], buf[1], buf[3] // 这里对应报文的字节认证的位置fmt.Println(ver, cmd, atyp)return
}

这里就很明显了 5 对应 socks5 1 对应 链接的请求 3 对应 url 是一个域名

+----+--------+-------------------+--------------+---------------+
|VER |  CMD   |       ATYP        |   HOST SIZE  |      HOST     |
+----+--------+-------------------+--------------+---------------+
| 05 |  01    |       03          |      11      | www.exa.com   |
+----+--------+-------------------+--------------+---------------+首先之前的都已经被读了ver cmdatyp然后再读 就是 host size 这里是 后面 host 的地址长度

这里开源发现 cn.bing.com的长度是11 因为url是可变的 所以后面的host也是可变的

我们首先读取字节长度 然后作为 值传递给切片 读取该长度的值 这样我们就开源获取到url地址

	_, err = io.ReadFull(readio, buf[:2]) //再向后读取两个字节 是portif err != nil {return fmt.Errorf("port error:", err)}port := binary.BigEndian.Uint16(buf[:2])  //这里是大端序监听端口fmt.Println(port)fmt.Println(addr)return

这里的原理是这样的

首先我们读取两个字节

443 [1 187]

然后进行大端序排序 0 在高 80 在低

这个时候就是

[1 187]

然后我们进uint16处理

[1 187]将高位字节(1)左移 8 位,使其占据 uint16 的高 8 位,得到结果 00000001 00000000将低位字节(187)放在 uint16 的低 8 位,得到结果 00000001 1011101100000001 10111011443

这样我们就获取到了端口

然后我们就可以进行拼接url

	dest := fmt.Sprintf("%v:%v", addr, port)  fmt.Println(dest)

 然后我们开始建立tcp请求

	dest, err := net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port)) //建立tcp协议if err != nil {return fmt.Errorf("dial error:", err)}defer dest.Close()log.Println("访问:", addr, port)

完整代码

package mainimport ("bufio""context""encoding/binary""fmt""io""log""net"
)const socks5Ver = 0x05
const cmdVer = 0x01
const aytpVerIpv4 = 0x01
const aytpVerUrl = 0x03func main() {server, err := net.Listen("tcp", "127.0.0.1:1080")if err != nil {panic(err)}for {client, err := server.Accept()if err != nil {log.Printf("Accpet error :", err)continue}//确定ip端口 进行链接后 开始进程fmt.Println("开始监听")go process(client)}
}
func process(conn net.Conn) {defer conn.Close()readio := bufio.NewReader(conn)err := auth(readio, conn)if err != nil {fmt.Errorf("ip: %v,auth error :", conn.RemoteAddr().String(), err)}err = connnect(readio, conn)
}func auth(readio *bufio.Reader, conn net.Conn) (err error) {ver, err := readio.ReadByte()if err != nil {return fmt.Errorf("ver error:", err)}if ver != socks5Ver {return fmt.Errorf("ver num error: ", err)}methodSize, err := readio.ReadByte() //确定切片大小 为 1字节method := make([]byte, methodSize)   //创建一个大小的切片_, err = io.ReadFull(readio, method) // 这里是判断是否读了if err != nil {return fmt.Errorf("read method error :", err)}_, err = conn.Write([]byte{socks5Ver, 0x00}) // 这里是握手的回复 说明我们不需要认证if err != nil {return fmt.Errorf("write error:", err)}return nil
}func connnect(readio *bufio.Reader, conn net.Conn) (err error) {buf := make([]byte, 4)_, err = io.ReadFull(readio, buf) // 这里是读取字节数 读取前面4个作为一个切片if err != nil {return fmt.Errorf("read header error :", err)}var ver, cmd, atyp = buf[0], buf[1], buf[3] // 这里对应报文的字节认证的位置if ver != socks5Ver {return fmt.Errorf("connect ver error:", err)}if cmd != cmdVer {return fmt.Errorf("connect cmd	 error:", err)}addr := ""switch atyp {case aytpVerIpv4:_, err = io.ReadFull(readio, buf)if err != nil {return fmt.Errorf("ipv4 error:", err)}addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]) //读取ip地址case aytpVerUrl: //这里解析的是urlhostSize, err := readio.ReadByte() //获取url的字节长度if err != nil {return fmt.Errorf("read hostSize failed:%w", err)}host := make([]byte, hostSize) //获取url字符的字节_, err = io.ReadFull(readio, host)if err != nil {return fmt.Errorf("read host failed:%w", err)}addr = string(host)default:return fmt.Errorf("not yet", atyp)}_, err = io.ReadFull(readio, buf[:2]) //再向后读取两个字节 是portif err != nil {return fmt.Errorf("port error:", err)}port := binary.BigEndian.Uint16(buf[:2])                       //这里是大端序监听端口dest, err := net.Dial("tcp", fmt.Sprintf("%v:%v", addr, port)) //建立tcp协议if err != nil {return fmt.Errorf("dial error:", err)}defer dest.Close()log.Println("访问:", addr, port)_, err = conn.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})if err != nil {return fmt.Errorf("写入错误:", err)}ctx, cancel := context.WithCancel(context.Background()) //启动一个可以取消的上下文功能defer cancel()go func() {_, _ = io.Copy(dest, readio) //这里是从我们的请求中读取出来 写入请求中cancel()}()go func() {_, _ = io.Copy(conn, dest) //这里从请求中写入返回报文中cancel()}()<-ctx.Done() // 这里是 只要管道输出内容了就停止 所以上面两个协程 只要有一个输出 就取消return nil
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/233279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Wireshark统计和可视化

第一章&#xff1a;Wireshark基础及捕获技巧 1.1 Wireshark基础知识回顾 1.2 高级捕获技巧&#xff1a;过滤器和捕获选项 1.3 Wireshark与其他抓包工具的比较 第二章&#xff1a;网络协议分析 2.1 网络协议分析&#xff1a;TCP、UDP、ICMP等 2.2 高级协议分析&#xff1a;HTTP…

LLMs推理框架总结

总结一下这些框架的特点&#xff0c;如下表所示&#xff1a; LLM推理有很多框架&#xff0c;各有其特点&#xff0c;下面分别介绍一下表中七个框架的关键点&#xff1a; vLLM&#xff1a;适用于大批量Prompt输入&#xff0c;并对推理速度要求高的场景&#xff1b;Text generat…

P1011 [NOIP1998 提高组] 车站 ---Java

主打一个枚举找规律... 站台123456...上车ababa2b2a3b3a5b下车bbaba2b2a3b人数aa2a2ab3a2b4a4b 上车这一行: 观察a的系数&#xff08;假设是dx[i]&#xff09;可知: dx[i] dx[i-1] dx[i-2] b的系数&#xff08;假设是dy[i]&#xff09;可知: dy[i] dy[i-1] dy[i-2] 人数…

黑豹程序员-vue3获取拖动div后的坐标

<script lang"ts" setup> import {ref, reactive, onMounted} from vuelet startclientX ref(0) // 元素拖拽前距离浏览器的X轴位置 let startclientY ref(0) //元素拖拽前距离浏览器的Y轴位置 let elLeft ref(770) // 元素的左偏移量 let elTop ref(220) …

android的bundle的常用函数(ChatGPT)

在 Android 中&#xff0c;Bundle 是一个用于保存和传递数据的容器类&#xff0c;它被广泛用于在不同组件&#xff08;如 Activity、Fragment&#xff09;之间传递数据。以下是一些 Bundle 中常用的函数&#xff1a; putXXX 系列方法&#xff1a; 用于将各种类型的数据放入 Bun…

C语言-> 文件操作(函数满屏)

系列文章目录 前言 ✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;橘橙黄又青_C语言,数据结构,函数-CSDN博客 目的&#xff1a;学习文件操作&#xff0c;即…

林杰:程序员依然是草根跨越阶级的最佳途径之一 | 程客有话说

《程客有话说》是我们最新推出的一个访谈栏目&#xff0c;邀请一些国内外有趣的程序员来分享他们的经验、观点与成长故事&#xff0c;尝试建立一个程序员交流与学习的平台&#xff0c;也欢迎大家推荐朋友或自己来参加我们的节目&#xff0c;一起加油。 本期我们邀请的程序员林…

2023-12-19 二叉搜索树的最小绝对差和二叉搜索树的众数和二叉树的最近公共祖先

二叉搜索树的最小绝对差 关键信息&#xff1a;二叉搜索树表明了树有序的&#xff01;遇到在二叉搜索树上求什么最值啊&#xff0c;差值之类的&#xff0c;就把它想成在一个有序数组上求最值&#xff0c;求差值 # Definition for a binary tree node. # class TreeNode: # …

微信私域管理工具如何帮助企业提升销售业绩?

现如今&#xff0c;微信已经从社交通讯软件&#xff0c;慢慢被默认为常规办公软件&#xff0c;工作沟通、业务洽谈、网络会议等都在微信上进行&#xff0c;完全变成职场首选的社交工具。 但受限于微信平台&#xff0c;许多公司在微信私域营销方面面临诸多挑战。 微信私域管理工…

调用第三方http接口 hutool工具类

1、引入依赖 <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.0.M2</version> </dependency>2、请求组装 String params"<BSXml>" " <MsgHeader>&…

Leetcode—16.最接近的三数之和【中等】

2023每日刷题&#xff08;六十四&#xff09; Leetcode—16.最接近的三数之和 实现代码 class Solution { public:int threeSumClosest(vector<int>& nums, int target) {sort(nums.begin(), nums.end());int s 0;int diff INT_MAX / 2;int n nums.size();int a…

四级作文考前积累(个人蒟蒻向)

观点类 With the giant leap of the economy,nowdays the youngsters have different opinions upon gratuation Some think that....,while others think that.... Personally ,i perfer the former,the letter. The following reasons can account for my preference. Fi…

计算机试题

选择题 在计算机中&#xff0c;RAM代表什么&#xff1f; A) Random Access MemoryB) Read-Only MemoryC) Real-time Access MemoryD) Remote Access Memory答案&#xff1a;A) Random Access Memory TCP和UDP之间的主要区别是什么&#xff1f; A) TCP是面向连接的&#xff0c;U…

光伏收益计算工具:助力可再生能源发展的关键

随着全球对可再生能源需求的不断增加&#xff0c;光伏发电作为清洁、可再生的能源形式&#xff0c;越来越受到人们的关注。然而&#xff0c;要评估光伏系统的经济效益和投资回报&#xff0c;需要一个准确的光伏收益计算工具。 光伏收益计算工具是一种专门用于计算光伏系统发电量…

Ridge Lasso Regression解决线性回归的过拟合(Overfitting)(基于波士顿房价预测)

目录 介绍&#xff1a; 1、过拟合 2、Lasso regression 3、 Ridge regression 4、 Lasso regression 和 Ridge regression一定优于LinearRegression吗 一、 Linear Regression 二、Ridge Regression 三、Lasso Regression 四、Ridge Regression和Lasso Regression 五、…

Linux常用命令详解

文章目录 Linux常用命令详解一、Shell&#xff08;执行的任务—翻译&#xff09;二、Linux命令1、Linux命令的分类内部命令与外部命令的区别命令执行过程 2、Linux命令行的格式通用的命令行使用格式 3、编辑Linux命令行的辅助操作4、获得命令帮助的办法内部命令help命令的“--h…

100GPTS计划-AI写作VersatileWriter

地址 https://chat.openai.com/g/g-zHErU9z9m-versatile-writer https://poe.com/VersatileWriterGPT 测试 翻译:要求将给定的英语语句翻译成中文。 总结:给出一段文本,要求进行概括和总结。 问答:根据给定段落,提出相关问题并给出答案。 推理:给出前提,进行多步推理并得…

2024吃透软件测试面试最全八股文攻略,一周学完让你面试少走99%的弯路

1. 请自我介绍一下(需简单清楚的表述自已的基本情况&#xff0c;在这过程中要展现出自信&#xff0c;对工作有激情&#xff0c;上进&#xff0c;好学) 面试官您好&#xff0c;我叫###&#xff0c;今年26岁&#xff0c;来自江西九江&#xff0c;就读专业是电子商务&#xff0c;…

文件包含的提升刷题

上一篇文章&#xff1a;一篇文章带你入门文件包含-CSDN博客 已经开始入门了文件包含&#xff0c;那现在开始拔高提升刷题&#xff01; 1. 拿到题目后啥也没有&#xff0c;所以也不知道要读取啥文件&#xff0c;那就查看源代码。 直接看if的条件就可以知道一定要设置cookie&a…

【linux】(ubuntu)下 QT 出现的问题

错误一&#xff1a;Make 运行QT程序以后出现这样的错误。 【解决方法】 我的ubuntu版本是18.04.4&#xff0c; 原因1&#xff1a;没有更换软件源 原因2&#xff1a;没安装相关 软件包 注意&#xff1a;这一步很有可能卡死这一步&#xff0c;所以如果一直卡在这并且进度…