热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

关于原始套接字

<pre>数据报式套接字(SOCK_DGRAM),仅限于UDP;<p><p><p>流式套接字(SOCK_STREAM),仅限于TCP;<p&

数据报式套接字(SOCK_DGRAM),仅限于UDP;

流式套接字(SOCK_STREAM),仅限于TCP;

TCP与UDP各自有独立的port互不影响,没一个进程可以使用多个port;

原始套接字(SOCK_RAW),它实现于系统核心.可以接收本机网卡上所有的数据帧(数据包),对于监听网络流量和分析网络数据很有作用.开发人员可发送自己组装的数据包到网络上.原始套接字可以收发内核没有处理的数据包  因此,要访问其他协议发送的数据需要使用原始套接字(SOCK_RAW);

int socket(PF_PACKET, SOCK_RAW, protocol)功能:创建链路层的原始套接字

protocol:指定可以接收或发送的数据包类型

ETH_P_IP:IPV4数据包ETH_P_ARP:ARP数据包ETH_P_ALL:任何协议类型的数据包;

例如:

成功返回套接字;

sock_raw_fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL));

头文件:

#include #include

使用原始套接字进行编程开发时,首先要对不同协议的数据包进行学习,需要手动对IP、TCP、UDP、ICMP等包头进行组装或者拆解。

组装/拆解udp数据包流程:port来标记给哪个进程

*
* =====================================================================================
*
* Filename:
*
* Description:
*
* Version: 1.0
* Created:
* Revision: none
* Compiler: gcc
*
* Author: Dr. moshui (no_water), 276908080@qq.com
* Organization:
*
* =====================================================================================
*/

#include
#include
#include
#include
#include
#include
#include

int main(int argc,char *argv[])
{
int i = 0;
unsigned char buf[1024] = "";
unsigned char type[10] = {1, 6, 17};//ICMP->1、TCP->6、UDP->17
char name[10][128] = {"ICMP", "TCP", "UDP"};
int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
while(1)
{
unsigned char src_mac[18] = "";
unsigned char dst_mac[18] = "";
unsigned char dst_ip[16] = "";
unsigned char src_ip[16] = "";
//获取链路层的数据帧
recvfrom(sock_raw_fd, buf, sizeof(buf),0,NULL,NULL);
//从buf里提取目的mac、源mac
sprintf(dst_mac,"%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
sprintf(src_mac,"%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
//判断是否为IP数据包
if(buf[12]==0x08 && buf[13]==0x00)
{
printf("______________IP数据报_______________\n");
printf("MAC:%s >> %s\n",src_mac,dst_mac);
//获取源IP、目的IP
sprintf(src_ip,"%d:%d:%d:%d", buf[26], buf[27], buf[28], buf[29]);
sprintf(dst_ip,"%d:%d:%d:%d", buf[30], buf[31], buf[32], buf[33]);
printf("IP:%s >> %s\n",src_ip,dst_ip);
for(i=0;i<10;i++)
{
if(buf[23] == type[i])
{
printf("协议类别:%s\n",name[i]);
}
}
}//判断是否为ARP数据包
else if(buf[12]==0x08 && buf[13]==0x06)
{
printf("______________ARP数据报_______________\n");
printf("MAC:%s >> %s\n",src_mac,dst_mac);
//获取源IP、目的IP
sprintf(src_ip,"%d:%d:%d:%d", buf[28], buf[29], buf[30], buf[31]);
sprintf(dst_ip,"%d:%d:%d:%d", buf[38], buf[39], buf[40], buf[41]);
printf("IP:%s >> %s\n",src_ip,dst_ip);
}//判断是否为RARP数据包
else if(buf[12]==0x80 && buf[13]==0x35)
{
printf("______________RARP数据报_______________\n");
printf("MAC:%s>>%s\n",src_mac,dst_mac);
//获取源IP、目的IP(RARP报文格式与ARP报文格式一样)
sprintf(src_ip,"%d:%d:%d:%d", buf[28], buf[29], buf[30], buf[31]);
sprintf(dst_ip,"%d:%d:%d:%d", buf[38], buf[39], buf[40], buf[41]);
printf("IP:%s>>%s\n",src_ip,dst_ip);
}
}
return 0;
}


混杂模式

设置混杂模式:ifconfig eth0 promisc

取消混杂模式:ifconfig eth0 -promisc


用sendto发送原始套接字数据:

sendto(sock_raw_fd, msg, msg_len, 0,(struct sockaddr*)&sll, sizeof(sll));

sock_raw_fd:原始套接字
msg:发送的消息(封装好的协议数据)
sll:本机网络接口,指发送的数据应该从本机的哪个网卡出去,而不是以前的目的地址


本机网络接口
struct sockaddr_ll sll;
#include


通过ioctl来获取网络接口地址
int ioctl(int fd, int request,void *)
#include




获取到当前网段中所有机器的MAC地址:

#include 
#include
#include
#include //struct ifreq
#include //ioctl、SIOCGIFADDR
#include
#include //ETH_P_ALL
#include //struct sockaddr_ll
#include
#include
void *send_arp_ask(void *arg);
int main(int argc,char *argv[])
{
//1.创建通信用的原始套接字
int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

//2.创建发送线程
pthread_t tid;
pthread_create(&tid, NULL, (void *)send_arp_ask, (void *)sock_raw_fd);

while(1)
{
//3.接收对方的ARP应答
unsigned char recv_msg[1024] = "";
recvfrom(sock_raw_fd, recv_msg, sizeof(recv_msg), 0, NULL, NULL);
if(recv_msg[21] == 2)//ARP应答
{
char resp_mac[18] = "";//arp响应的MAC
char resp_ip[16] = "";//arp响应的IP

sprintf(resp_mac, "%02x:%02x:%02x:%02x:%02x:%02x", \
recv_msg[22],recv_msg[23],recv_msg[24],recv_msg[25],recv_msg[26],recv_msg[27]);
sprintf(resp_ip, "%d.%d.%d.%d", recv_msg[28], recv_msg[29], recv_msg[30], recv_msg[31]);
printf("IP:%s - MAC:%s\n",resp_ip, resp_mac);
}
}

return 0;
}

void *send_arp_ask(void *arg)
{
int i = 0;
int sock_raw_fd = (int)arg;
//1.根据各种协议首部格式构建发送数据报
unsigned char send_msg[1024] = {
//--------------组MAC--------14------
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //dst_mac: FF:FF:FF:FF:FF:FF
0x00, 0x0c, 0x29, 0x75, 0xa6, 0x51, //src_mac: 00:0c:29:75:a6:51
0x08, 0x06,//类型:0x0806 ARP协议

//--------------组ARP--------28-----
0x00, 0x01, 0x08, 0x00,//硬件类型1(以太网地址),协议类型0x0800(IP)
0x06, 0x04, 0x00, 0x01,//硬件、协议地址分别是6、4,op:(1:arp请求,2:arp应答)
0x00, 0x0c, 0x29, 0x75, 0xa6, 0x51,//发送端的MAC地址
172, 20, 226, 12, //发送端的IP地址
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//目的MAC地址(由于要获取对方的MAC,所以目的MAC置零)
172, 20, 226, 11//目的IP地址
};

//2.数据初始化
struct sockaddr_ll sll;//原始套接字地址结构
struct ifreq ethreq;//网络接口地址
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);//指定网卡名称

//3.将网络接口赋值给原始套接字地址结构
ioctl(sock_raw_fd, SIOCGIFINDEX, (char *)ðreq);
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;

//4.本地机的IP
if(!(ioctl(sock_raw_fd, SIOCGIFADDR, (char *)ðreq)))
{
int num = ntohl(((struct sockaddr_in*) (ðreq.ifr_addr))->sin_addr.s_addr);
for(i=0; i<4; i++)
{
send_msg[31-i] = num>>8*i & 0xff;//将发送端的IP地址组包
}
}

//5.获取本地机(eth0)的MAC
if (!(ioctl(sock_raw_fd, SIOCGIFHWADDR, (char *) ðreq)))
{
for(i=0; i<6; i++)
{
//将src_mac、发送端的MAC地址组包
send_msg[22+i] = send_msg[6+i] = (unsigned char) ethreq.ifr_hwaddr.sa_data[i];
}
}

while(1)
{
int i = 0;
int num[4] = {0};
unsigned char input_buf[1024] = "";

//6.获取所要扫描的网段(172.20.226.0)
printf("input_dst_Network:172.20.226.0\n");
fgets(input_buf, sizeof(input_buf), stdin);
sscanf(input_buf, "%d.%d.%d.", &num[0], &num[1], &num[2]//目的IP地址
);

//7.将键盘输入的信息组包
for(i=0;i<4;i++)
send_msg[38+i] = num[i];//将目的IP地址组包

//8.给1~254的IP发送ARP请求
for(i=1; i<255; i++)
{
send_msg[41] = i;
int len = sendto(sock_raw_fd, send_msg, 42, 0 , (struct sockaddr *)&sll, sizeof(sll));
if(len == -1)
{
perror("sendto");
}
}
sleep(1);
}





推荐阅读
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 本文介绍了最长上升子序列问题的一个变种解法,通过记录拐点的位置,将问题拆分为左右两个LIS问题。详细讲解了算法的实现过程,并给出了相应的代码。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有