在Linux系统中,使用非原始的socket,可以收发TCP或者UDP等网络层数据包。如果要处理网络层以下的数据包,比如ICMP、ARP等,或者更底层,比如链路层数据包,就得使用原始socket了。

创建socket

创建socket要使用socket函数,socket函数的原型为:

#include <sys/types.h>  
#include <sys/socket.h>  int socket(int domain, int type, int protocol);

其中,domain比较常用的值有:

  • AF_UNIX Unix本地通讯
  • AF_INET IPv4网络协议
  • AF_INET6 IPv6网络协议
  • AF_NETLINK 内核用户界面设备
  • AF_PACKET 底层包设备

我们要处理网络层以下的数据包,就得使用AF_PACKET

type比较常用的值有:

  • SOCK_STREAM 用于面向字节流的协议,如TCP
  • SOCK_DGRAM 用于面向数据报的协议,如UDP
  • SOCK_RAW 用于非处理的原始数据包

我们这里要使用SOCK_RAW

protocol是要使用的网络协议。

如下代码,创建一个原始socket:

#include <sys/types.h>
#include <sys/socket.h>int raw_socket_new () {int fd;fd = socket (PF_PACKET, SOCK_RAW, IPPROTO_RAW);if (fd < 0){fprintf (stderr, "socket error: %s\n", strerror (errno));}return fd;

绑定网口

如果我们处理非原始的数据包,可以使用网络层绑定IP,或者连接IP(其实socket也会自动绑定IP),协议栈会自动根据IP把数据包发往特定的网络接口,不需要绑定网口。

我们通过原始socket发送底层数据包,就需要绑定网口了。

绑定网口的方法很简单,先使用if_nametoindex函数,找到对应网口名的编号,之后设置到struct sockaddr_ll结构中,调用bind函数就行了。

`if_nametoindex`的原型为:

#include <net/if.h>unsigned int if_nametoindex(const char *ifname);

struct sockaddr_ll的定义为:

#include <linux/if_packet.h>struct sockaddr_ll {  unsigned short  sll_family;  __be16          sll_protocol;  int             sll_ifindex;  unsigned short  sll_hatype;  unsigned char   sll_pkttype;  unsigned char   sll_halen;  unsigned char   sll_addr[8];  
};

以下函数,就把给定的网络接口,绑定到了给定的socket上:

#include <net/if.h>
#include <linux/if_packet.h>int raw_socket_bind(int fd, const char *eth) {struct sockaddr_ll sa;memset (&sa, 0, sizeof (struct sockaddr_ll));// 原始数据包sa.sll_family = AF_PACKET;// 自定义二层协议sa.sll_protocol = htons (CUSTOM_TYPE);sa.sll_ifindex = if_nametoindex (eth);if (bind (jdpdk->fd, (struct sockaddr *)&sa, sizeof (struct sockaddr_ll))!= 0){fprintf (stderr, "bind error: %s\n", strerror (errno));return -1;}return 0;
}

二层包结构

socket创建成功,绑定了网口,就可以发送自定义的二层数据包了。

根据TCP/IP标准,二层的数据包包头为14个字节,即6字节的目标MAC地址、6字节的源MAC地址再加2字节的包类型。

net/ethernet.h中,结构定义为:

struct ether_header  
{uint8_t  ether_dhost[ETH_ALEN]; uint8_t  ether_shost[ETH_ALEN];uint16_t ether_type;
} __attribute__ ((__packed__));

在我们使用网口发送的时候,源MAC地址可以设成全0,但是目标MAC地址,必须设置。

我们可以实现一个组包函数,把给定的数据,设上预订的目标地址:

int raw_encode (const char *dst_mac, unsigned short type, const char *data, size_t data_len, char *packet, size_t packet_len) {assert (14 + data_len <= packet_len);memcpy (packet, dst_mac, 6);memset (packet + 6, 0, 6);* (unsigned short *) (packet + 12) = htons (type);memcpy (packet + 14, data, data_len);return 14 + data_len;
}

发送

发送函数就比较简单,跟网络层的发送没有区别。

int raw_send (int fd, const char *data, int data_len) {int ret;ret = send (fd, data, data_len, 0);  if (ret != data_len)  {  fprintf (stderr, "send error: %s\n", strerror (errno));       }return ret;
}

接收

接收函数也同样,只是记得接收成功以后,偏移14字节(即二层包头以后)才是我们的应用层数据:

int raw_recv (int fd, char *packet, size_t packet_len) {int ret;ret = recv (fd, packet, packet_len, 0);return ret;
}

原始socket示例:arp组包

根据TCP/IP协议,当我们网络层使用TCP、UDP或者ICMP等使用IP地址作为目标的数据包时,协议栈要查询本机的arp表,找到IP地址对应的MAC地址。

如果查询失败,就会发送arp请求,通过arp响应来得到目标MAC地址。

所以,arp协议有两种数据包:一种是arp请求,一种是arp响应。对应到arp结构中,就是操作码的值为1或者2。

linux/if_arp.h中,有arp包的包头结构:

struct arphdr {  __be16          ar_hrd;__be16          ar_pro;unsigned char   ar_hln;unsigned char   ar_pln;__be16          ar_op;  
};

在arp的包体中,分别是发送MAC、发送IP、目标MAC与目标IP。

  • 当arp请求的时候,设置arp包头中的操作码为1,另外设置发送MAC(即本机MAC)与目标IP,发送IP与目标MAC置空。

当arp响应的时候,设置arp包头中的操作码为2,另外设置发送MAC(即本机MAC)、发送IP(即本机IP)、目标MAC(即请求时的发送MAC),目标IP置空。

我们写一个组包函数:

#include <net/ethernet.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <memory.h>void
buf_encode_arp (uint8_t *buf, uint16_t opcode, const uint8_t *source_mac,  const uint8_t *dst_mac, unsigned long sip, unsigned long dip)  
{struct ether_header *hdr;  hdr = (struct ether_header *)buf;  if (source_mac)  {  memcpy (hdr->ether_shost, source_mac, sizeof hdr->ether_shost);}// arp请求的时候,二层目标MAC地址填全0xFF,否则填全0memset (hdr->ether_dhost, opcode == 1 ? 0xFF : 0, sizeof hdr->ether_dhost);if (dst_mac)  {  memcpy (hdr->ether_dhost, dst_mac, sizeof hdr->ether_dhost);}hdr->ether_type = htons (ETHERTYPE_ARP);struct ether_arp *arp = (struct ether_arp *)(hdr + 1);// 设置arp包头arp->ea_hdr.ar_hrd = htons (1);arp->ea_hdr.ar_pro = htons (0x800);arp->ea_hdr.ar_hln = 6;arp->ea_hdr.ar_pln = sizeof (uint32_t);arp->ea_hdr.ar_op = htons (opcode);// 根据输入参数,设置arp包体memset (arp->arp_sha, 0, sizeof arp->arp_sha);if (source_mac)  {  memcpy (arp->arp_sha, source_mac, sizeof arp->arp_sha);}  memset (arp->arp_tha, 0, sizeof arp->arp_tha);if (dst_mac)  {  memcpy (arp->arp_tha, dst_mac, sizeof arp->arp_tha);}memcpy (&arp->arp_spa, &sip, 4);memcpy (&arp->arp_tpa, &dip, 4);
}

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

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

相关文章

暑期自学嵌入式——Day05补充(C语言阶段)

接续上文&#xff1a;暑期自学嵌入式——Day05&#xff08;C语言阶段&#xff09;-CSDN博客 主页点关注不迷路哟。你的点赞、收藏&#xff0c;一键三连&#xff0c;是我持续更新的动力哟&#xff01;&#xff01;&#xff01; 主页&#xff1a; 一位搞嵌入式的 genius-CSDN博…

.NET Core EFCore零基础快速入门简单使用

一、什么是 Entity Framework (EF) Core Entity Framework (EF) Core 是轻量化、可扩展和跨平台版的对象关系映射程序 (O/RM)数据访问技术&#xff0c;。 它将开发人员从编写大量 SQL 语句中解放出来。 二、EF的相关程序包 Microsoft.EntityFrameworkCore 核心程序包&#x…

AAC音频格式

目录 AAC音频格式介绍 主要特点 技术优势 常见文件扩展名 应用领域 AAC与PCM的区别与优势对比 基本概念差异 主要技术区别 各自优势 PCM的优势 AAC的优势 应用场景选择 AAC音频数据格式解析 1. AAC 文件格式 (1) ADIF (Audio Data Interchange Format) (2) ADT…

pom.xml文件中的${}变量从哪里传值

在 Maven 的 pom.xml 文件中&#xff0c;${} 格式的变量&#xff08;称为属性占位符&#xff09;的值来源主要有以下几种途径&#xff1a; 1. ​内置属性&#xff08;Maven 预定义&#xff09;​​ ${project.basedir}&#xff1a;项目根目录${project.version}&#xff1a;项…

【人工智能】项目案例分析:使用TensorFlow进行大规模对象检测

🏆🏆欢迎大家来到我们的天空🏆🏆 🏆 作者简介:我们的天空 🏆《头衔》:大厂高级软件测试工程师,阿里云开发者社区专家博主,CSDN人工智能领域新星创作者。 🏆《博客》:人工智能,深度学习,机器学习,python,自然语言处理,AIGC等分享。 所属的专栏:TensorF…

C++---cout、cerr、clog

在C编程里&#xff0c;cout、cerr和clog是标准库提供的重要输出流对象&#xff0c;在数据输出方面发挥着关键作用。 一、cout&#xff1a;标准输出流 cout 是 std::ostream 类的对象&#xff0c;其作用是向标准输出设备&#xff08;一般是控制台&#xff09;输出数据。它和 C 语…

脉冲神经网络(Spiking Neural Network, SNN)与知识蒸馏(Knowledge Distillation, KD)

目录 脉冲神经网络&#xff08;Spiking Neural Network, SNN&#xff09; 知识蒸馏&#xff08;Knowledge Distillation, KD&#xff09; 三种类别 三种变体 脉冲神经网络&#xff08;Spiking Neural Network, SNN&#xff09; 收到生物神经系统的启发&#xff0c;设计的&a…

使用Java完成下面项目

第一题&#xff1a;从控制台输入十个学生的成绩&#xff0c;使用list集合来保存数据&#xff0c; 遍历并打印其中成绩不及格的成绩&#xff0c;打印最高成绩&#xff0c;最低成绩&#xff0c;并计算及格率代码如下public class Home1 {public static void main(String[] args) …

龙虎榜——20250718

上证指数今天上涨收阳线&#xff0c;继续在5天均线保持强势上涨&#xff0c;个股下跌稍多&#xff0c;大盘股上涨为主。深证指数收小阳线&#xff0c;继续在5天均线上&#xff0c;总体保持强势&#xff0c;调整更多是小票。2025年7月18日龙虎榜行业方向分析1. 医药医疗• 代表标…

2025年华为认证之HCIE-云计算方向的报考流程

一、先搞明白&#xff1a;HCIE - 云计算认证到底是啥&#xff1f; HCIE - 云计算&#xff08;华为认证 ICT 专家 - 云计算&#xff09;是华为体系里云计算领域的顶级认证&#xff0c;说白了&#xff0c;就是证明你有能力搞定大型企业的云平台设计、部署和运维。现在政企、金融…

什么是私有化部署企业即时通讯?吱吱企业即时通讯安全吗?

在企业数字化转型加速的今天&#xff0c;沟通工具的选择已经从满足简单沟通&#xff0c;升级为“安全、高效、可控”。其中&#xff0c;“私有化部署企业即时通讯”成为许多中小型企业、跨国企业以及数据敏感型企业的核心需求。 那么&#xff0c;究竟什么是私有化部署&#xff…

Vue3 中使用 Element Plus 实现自定义按钮的 ElNotification 提示框

在 Vue3 项目中&#xff0c;我们经常会用到 ElNotification 作为消息提醒组件&#xff0c;尤其是在异步操作、任务完成或用户需要交互确认时。然而&#xff0c;Element Plus 默认的 Notification 是非交互式的&#xff0c;不能直接嵌入按钮或事件。 今天我们来实现一个带自定义…

下载webrtc M114版本源码只能使用外网googlesource源-命令版

声网、国内源都不行&#xff0c;只能外网googlesource源&#xff01;&#xff01;&#xff01; 二、创建 Ubuntu 容器&#xff08;带目录挂载&#xff09; 拉取Ubuntu镜像 docker pull ubuntu:22.04创建并启动容器&#xff08;挂载Windows目录到容器&#xff09; docker run -i…

Linux运维新手的修炼手扎之第21天

Nginx服务和Tomcat服务1 负载均衡语法格式&#xff1a;upstream[一个或多个]rootubuntu24-13:~# vim /etc/nginx/conf.d/vhost.confupstream group1 {server 10.0.0.16;}upstream group2 {server 10.0.0.14;}server {listen 80;server_name sswang1.magedu.com;location / {pro…

TrOCR: 基于Transformer的光学字符识别方法,使用预训练模型

温馨提示&#xff1a; 本篇文章已同步至"AI专题精讲" TrOCR: 基于Transformer的光学字符识别方法&#xff0c;使用预训练模型 摘要 文本识别是文档数字化中的一个长期研究问题。现有方法通常基于CNN进行图像理解&#xff0c;基于RNN进行字符级文本生成。此外&#…

西门子工业软件全球高级副总裁兼大中华区董事总经理梁乃明先生一行到访庭田科技

概要2025年6月&#xff0c;西门子工业软件全球高级副总裁兼大中华区董事总经理梁乃明先生一行到访我司。庭田科技总经理聂春文携销售团队对西门子代表团表示热烈欢迎&#xff0c;并就当前业务发展方向及未来行业聚焦领域与代表团展开深入交流。 聂春文总经理及销售团队陪同西门…

在 Jenkins 中使用 SSH 部署密钥

本文档介绍了如何在 Jenkins 中配置 SSH 部署密钥&#xff0c;以便更稳定地拉取 Git 仓库代码&#xff0c;避免常见的 RPC 错误。 1. 背景 在使用 Jenkins 进行持续集成时&#xff0c;常常需要从 Git 仓库拉取代码。如果使用 HTTP/HTTPS 协议&#xff0c;有时会遇到 RPC 错误&…

小红书采集工具:无水印图片一键获取,同步采集笔记与评论

我用python语言开发了一款名为“爬xhs图片软件”的工具&#xff0c;该工具不仅能采集图片&#xff0c;还可获取笔记数据、评论数据等内容。 软件界面长这个样子&#xff1a; 采集到的图片&#xff1a;演示视频&#xff1a;https://live.csdn.net/v/485813介绍文章、想你所想&am…

Java行为型模式---命令模式

命令模式基础概念命令模式&#xff08;Command Pattern&#xff09;是一种行为型设计模式&#xff0c;其核心思想是将请求封装为一个对象&#xff0c;从而使你可以用不同的请求对客户进行参数化&#xff0c;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。命令模式…

Android性能优化之包体积优化

一、包体积组成与瓶颈分析 1. 典型 APK 结构占比 #mermaid-svg-KEUQMlEifvHlk1CV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-KEUQMlEifvHlk1CV .error-icon{fill:#552222;}#mermaid-svg-KEUQMlEifvHlk1CV .erro…