您的位置:首页 > 游戏 > 游戏 > 证券公司客户经理怎么拉客户_中建二局官网_四川百度推广和seo优化_正规推广平台

证券公司客户经理怎么拉客户_中建二局官网_四川百度推广和seo优化_正规推广平台

2024/12/23 15:08:08 来源:https://blog.csdn.net/weixin_47763623/article/details/144282078  浏览:    关键词:证券公司客户经理怎么拉客户_中建二局官网_四川百度推广和seo优化_正规推广平台
证券公司客户经理怎么拉客户_中建二局官网_四川百度推广和seo优化_正规推广平台

Go语言玩转原始套接字通信:从入门到飞起

1. 概述:从协议小白到网络老手

想象一下,你就是个网络魔法师,可以操控每一个数据包,直接给它们安排源头、目的地,甚至在中途变个花样。这就是原始套接字的魅力所在!在本教程中,我们将通过Go语言实现一个简单的原始套接字通信系统,玩转数据包的发送和接收。


2. 初识原始套接字

原始套接字是个有趣的家伙。它能让你绕过传输层,直接操控 IP 层,甚至更底层的协议栈。一般来说,这种能力常用于:

  • 网络嗅探:捕获并分析网络数据包,进行安全审计。
  • 自定义协议:实现自定义的网络协议。
  • 网络诊断:直接发送和接收特定的数据包,检测网络状态。

注意:使用原始套接字需要管理员权限,因为它太强大了,容易玩脱。


3. 深入浅出 IP 协议头

3.1 IP 头部结构

每个 IP 数据包的头部包含了各种重要信息,就像寄快递时的包裹单。下面是一个典型的 IPv4 头部结构:

    0                   1                   2                   30 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|Version|  IHL  |Type of Service|          Total Length         |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|         Identification        |Flags|      Fragment Offset    |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|  Time to Live |    Protocol   |         Header Checksum       |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                       Source Address                          |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                    Destination Address                        |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|                    Options                    |    Padding    |+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
字段长度(位)描述
版本号4表示 IPv4。
头部长度4头部长度,单位为 32 位字。
服务类型8数据包的优先级等。
总长度16数据包的总长度。
标识符16数据包的唯一标识。
标志3分片控制位。
片偏移13数据分片的偏移量。
TTL8数据包生存时间。
协议8指示上层协议类型。
校验和16检查 IP 头部错误。
源 IP 地址32数据包的来源。
目标 IP 地址32数据包的目的地。

3.2 校验和计算

校验和是 IP 头部的一种自我检查机制,用于检测传输中的错误。计算方法很简单:

  1. 把头部按 16 位为一组分割,逐组相加。
  2. 如果有进位,加到结果里。
  3. 对结果取反。

4. 项目结构与实现思路

4.1 客户端

  • 构建自定义 IP 头部和数据:客户端首先需要构建一个符合 IP 协议格式的自定义 IP 头部,并将其与要发送的消息内容组合成一个完整的 IP 数据包。这个过程包括构造源 IP 地址、目标 IP 地址以及必要的校验和等字段。
  • 发送数据包到服务器:客户端将构建好的数据包通过原始套接字发送到目标服务器。此时,客户端的任务是确保数据包格式符合 IP 协议规范,并能够成功地将数据发送到指定的服务器地址。
  • 接收服务器的返回数据:客户端发送数据包后,需要等待服务器的响应。客户端会监听原始套接字,接收从服务器返回的响应数据包,并对接收到的数据包进行解析,提取有效信息,最终将响应内容展示给用户。

4.2 服务器

  • 监听原始套接字,接收数据包:服务器使用原始套接字监听网络接口,等待客户端发送的数据包。当服务器接收到数据包时,它会对数据包进行初步的处理和验证,确保数据包符合预期。
  • 解析 IP 头部,提取源 IP 和目标 IP:在接收到数据包后,服务器需要解析 IP 头部,从中提取源 IP 地址和目标 IP 地址。这一步非常重要,因为服务器需要知道数据包的来源和目标,以便进行后续的处理。
  • 把数据再发回客户端:服务器在接收到数据包并解析出相关信息后,会将数据包内容原封不动地返回给客户端。服务器通过原始套接字将数据包发送回客户端,确保客户端可以接收到并处理响应数据。

4.2 目录结构

project/
│
├── client.go        # 客户端代码
├── server.go        # 服务器端代码
├── rawutil.go       # 公共工具代码 (IP头部处理、校验和计算等)
  1. client.go:客户端的核心逻辑,包括构建 IP 头部、发送数据包和接收服务器响应数据。
  2. server.go:服务器的核心逻辑,包括监听数据包、解析 IP 头部并响应客户端数据包。
  3. rawutil.go:公用工具函数,包括 IP 头部构造、校验和计算、数据包解析等。

5. 代码实现

5.1 代码结构说明

  • rawutil.go: 封装了与 IP 头部相关的功能,包括创建 IP 头部、计算校验和、解析 IP 头部等函数,这些功能在客户端和服务器端都可以重用。

  • server.go: 服务器监听原始套接字,接收数据包,解析 IP 头部,提取源 IP 和目标 IP,并将数据包返回给客户端。

  • client.go: 客户端构建自定义 IP 头部,发送数据包到服务器,并接收服务器的回包。

5.2 测试地址说明

为了方便测试, 这里服务器, 客户端都在同一台电脑上

  • 服务器, 绑定本地的127.0.0.1地址
  • 客户端, 绑定本地的127.0.0.2地址(没错,这个地址也是发送到本地的, 实际上127开头的地址都是发送到本地的)

5.3 server.go - 服务器端实现

package mainimport ("log""syscall""rawutil"
)func main() {// 创建原始套接字,监听所有 IP 数据包sock, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)if err != nil {log.Fatalf("Error creating raw socket: %v", err)}defer syscall.Close(sock)// 绑定原始套接字到127.0.0.1if err := rawutil.BindToAddress(sock, "127.0.0.1"); err != nil {log.Fatalf("Error binding raw socket: %v", err)}// 缓冲区用来接收数据buffer := make([]byte, 1500)for {// 接收数据包n, from, err := syscall.Recvfrom(sock, buffer, 0)if err != nil {log.Printf("Error reading packet: %v", err)break}log.Printf("Received %d bytes from %v", n, from)// 解析接收到的 IP 头部srcIP, dstIP, err := rawutil.ParseIPHeader(buffer[:n])if err != nil {log.Printf("Error parsing IP header: %v", err)continue}msgRecv := string(buffer[rawutil.IPHeaderLength:])log.Printf("Received packet ip.src: %s ip.dst: %s [%s]", srcIP, dstIP, msgRecv)// 发送数据包log.Printf("Replying to %s", srcIP)err = rawutil.SendRawPacket(sock, dstIP, srcIP, []byte(msgRecv), syscall.IPPROTO_RAW)if err != nil {log.Printf("Error sending packet: %v", err)}}
}

5.4 client.go - 客户端实现

package mainimport ("fmt""log""syscall""rawutil"
)func main() {srcIP := "127.0.0.2"dstIP := "127.0.0.1"message := "Hello, world!"// 创建原始套接字sock, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)if err != nil {fmt.Printf("Error creating raw socket: %v\n", err)return}defer syscall.Close(sock)// 绑定原始套接字到本地地址if err := rawutil.BindToAddress(sock, srcIP); err != nil {log.Fatalf("Error binding raw socket: %v", err)}fmt.Printf("Bind raw socket to %s\n", srcIP)// 发送数据包err = rawutil.SendRawPacket(sock, srcIP, dstIP, []byte(message), syscall.IPPROTO_RAW)if err != nil {log.Fatalf("Error sending raw packet: %v\n", err)}fmt.Printf("Sent message [%s] to %s\n", message, dstIP)// 接收数据包var packet [1500]byten, _, err := syscall.Recvfrom(sock, packet[:], 0)if err != nil {fmt.Printf("Error receiving raw packet: %v\n", err)return}// 解析 IP 头部rcv_srcIP, rcv_dstIP, err := rawutil.ParseIPHeader(packet[:n])if err != nil {fmt.Printf("Error parsing IP header: %v\n", err)return}recv_msg := string(packet[rawutil.IPHeaderLength:])// 打印接收到的消息fmt.Printf("Received message ip.src %s ip.dst %s: [%s]\n", rcv_srcIP, rcv_dstIP, recv_msg)
}

5.5 rawutil.go - 公用工具函数

package rawutilimport ("encoding/binary""fmt""net""syscall"
)// 定义 IP 头部结构
const (IPHeaderLength = 20 // IP 头部长度
)// IPHeader 用于构造和解析 IP 头部
type IPHeader struct {VersionIhl      uint8  // 版本 + 头部长度TypeOfService   uint8  // 服务类型TotalLength     uint16 // 总长度Identification  uint16 // 标识符FlagsFragOffset uint16 // 标志 + 片偏移TTL             uint8  // TTLProtocol        uint8  // 协议类型Checksum        uint16 // 校验和SrcAddr         uint32 // 源 IP 地址DstAddr         uint32 // 目标 IP 地址
}// 校验和计算
func checksum(data []byte) uint16 {var sum uint32// 每 2 字节为一个单位进行加和for i := 0; i < len(data); i += 2 {word := uint16(data[i])<<8 + uint16(data[i+1])sum += uint32(word)}// 加上高 16 位和低 16 位的进位for sum>>16 > 0 {sum = (sum & 0xFFFF) + (sum >> 16)}return ^uint16(sum)
}// 解析 IP 头部,提取源 IP 和目标 IP
func ParseIPHeader(packet []byte) (srcIP, dstIP string, err error) {if len(packet) < IPHeaderLength {return "", "", fmt.Errorf("packet too short to be an IP packet")}ipHeader := IPHeader{VersionIhl:      packet[0],TypeOfService:   packet[1],TotalLength:     binary.BigEndian.Uint16(packet[2:4]),Identification:  binary.BigEndian.Uint16(packet[4:6]),FlagsFragOffset: binary.BigEndian.Uint16(packet[6:8]),TTL:             packet[8],Protocol:        packet[9],Checksum:        binary.BigEndian.Uint16(packet[10:12]),SrcAddr:         binary.BigEndian.Uint32(packet[12:16]),DstAddr:         binary.BigEndian.Uint32(packet[16:20]),}// 将二进制地址转换为点分十进制的字符串形式srcIP = fmt.Sprintf("%d.%d.%d.%d", byte(ipHeader.SrcAddr>>24), byte(ipHeader.SrcAddr>>16&0xFF), byte(ipHeader.SrcAddr>>8&0xFF), byte(ipHeader.SrcAddr&0xFF))dstIP = fmt.Sprintf("%d.%d.%d.%d", byte(ipHeader.DstAddr>>24), byte(ipHeader.DstAddr>>16&0xFF), byte(ipHeader.DstAddr>>8&0xFF), byte(ipHeader.DstAddr&0xFF))return srcIP, dstIP, nil
}// 构造 IP 头部
func createIPHeader(srcIP, dstIP string, protocol uint8, msg_len uint16) ([]byte, error) {srcAddr := net.ParseIP(srcIP).To4()if srcAddr == nil {return nil, fmt.Errorf("invalid source IP address")}dstAddr := net.ParseIP(dstIP).To4()if dstAddr == nil {return nil, fmt.Errorf("invalid destination IP address")}// 设置 IP 头部ipHeader := IPHeader{VersionIhl:      (4 << 4) | 5, // IPv4 + 头部长度 5TypeOfService:   0,TotalLength:     IPHeaderLength + msg_len, // IP 头部 + 数据部分Identification:  0,FlagsFragOffset: 0,TTL:             64,Protocol:        protocol,SrcAddr:         binary.BigEndian.Uint32(srcAddr),DstAddr:         binary.BigEndian.Uint32(dstAddr),}// 构造 IP 头部header := make([]byte, IPHeaderLength)header[0] = ipHeader.VersionIhlheader[1] = ipHeader.TypeOfServicebinary.BigEndian.PutUint16(header[2:4], ipHeader.TotalLength)binary.BigEndian.PutUint16(header[4:6], ipHeader.Identification)binary.BigEndian.PutUint16(header[6:8], ipHeader.FlagsFragOffset)header[8] = ipHeader.TTLheader[9] = ipHeader.Protocolbinary.BigEndian.PutUint16(header[10:12], ipHeader.Checksum)binary.BigEndian.PutUint32(header[12:16], ipHeader.SrcAddr)binary.BigEndian.PutUint32(header[16:20], ipHeader.DstAddr)// 计算校验和checksumValue := checksum(header)binary.BigEndian.PutUint16(header[10:12], checksumValue)return header, nil
}// 发送原始数据包
func SendRawPacket(sock int, srcIP, dstIP string, message []byte, protocol uint8) error {ipHeader, err := createIPHeader(srcIP, dstIP, protocol, uint16(len(message)))if err != nil {return fmt.Errorf("failed to create IP header: %v", err)}// 构造完整的数据包:IP 头部 + 数据packet := append(ipHeader, message...)// 设置目标地址addr := &syscall.SockaddrInet4{}copy(addr.Addr[:], net.ParseIP(dstIP).To4())// 发送数据包err = syscall.Sendto(sock, packet, 0, addr)return err
}// 绑定到指定地址
func BindToAddress(sock int, ip string) error {sa := &syscall.SockaddrInet4{Port: 0, // raw socket 不使用端口,所以设置为0}ipAddr := net.ParseIP(ip)if ipAddr == nil {return fmt.Errorf("failed to Parse IP: %v", ip)}copy(sa.Addr[:], ipAddr.To4())if err := syscall.Bind(sock, sa); err != nil {return fmt.Errorf("failed to bind to address: %v  err=%v", sa, err)}return nil
}

5.6 运行与测试

  1. 启动服务器

    sudo go run server.go
    
  2. 启动客户端

    sudo go run client.go  
    
  3. 观察输出:客户端将发送一个数据包,服务器收到数据包后会返回数据包,客户端会接收到服务器的回应,并打印响应的源和目标 IP 地址。

6. 总结与下一步探索

恭喜你!现在你已经掌握了使用 Go 语言实现原始套接字通信的基本技能。通过本教程,你学会了如何构造和解析 IP 数据包,使用原始套接字发送和接收数据,并实现了一个简易的客户端-服务器通信系统。你已经打下了扎实的网络编程基础,接下来有很多更深层次的知识等待你去探索。

6.1 下一步,你可以尝试:

  • 构建更复杂的协议:在本教程中,我们主要讨论了 IP 协议,但网络通信不仅仅限于此。你可以尝试设计和实现自己的应用层协议,甚至是自定义的传输协议。通过研究 TCP、UDP 或其他协议栈的实现原理,进一步扩展你的网络编程知识。

  • 实现数据包嗅探工具:数据包嗅探是网络分析中重要的一环。你可以编写一个简单的数据包嗅探工具,捕获并分析网络上的流量。通过这个项目,你将进一步理解协议栈的工作原理,甚至可能发现一些有趣的网络安全漏洞。

  • 深入研究网络安全:你已经了解了原始套接字的基础,接下来可以尝试探索更高级的网络安全技术。例如,如何利用网络嗅探技术进行攻击与防御,或者深入了解如何通过操控数据包进行渗透测试。这不仅能提高你的网络安全意识,还能帮助你更好地理解如何保护网络免受潜在威胁。

6.2 动手实验吧,网络魔法师!

理论知识的积累固然重要,但最重要的是通过实践来加深理解。去试试更多的网络编程项目,挑战自己,解决新的问题,甚至和其他网络编程爱好者一起分享你的经验。无论你选择深入哪个领域,记住:网络世界充满了未知与挑战,只有不断探索,才能成为真正的网络专家。

祝你在未来的探索旅程中,始终保持好奇心和创造力!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com