Linux 网络编程——原始套接字实例:MAC 地址扫描器
如果 A (192.168.1.1 )向 B (192.168.1.2 )发送一个数据包,那么需要的条件有 ip、port、使用的协议(TCP/UDP)之外还需要 MAC 地址,因为在以太网数据包中 MAC 地址是必须要有的。那么怎样才能知道对方的 MAC 地址?答案是:它通过 ARP 协议来获取对方的 MAC 地址。
ARP(Address Resolution Protocol,地址解析协议),是 TCP/IP 协议族中的一个,主要用于查询指定 ip 所对应的的 MAC(通过 ip 找 MAC)。
请求方使用广播来发送请求,应答方使用单播来回送数据。收到返回消息后将该 IP 地址和物理地址存入本机 ARP 缓存中并保留一定时间,下次请求时直接查询 ARP 缓存以节约资源。
以机器 A 获取机器 B 的 MAC 为例,A 广播发送一个 ARP 请求包,和 A 同在一个局域网的主机都会收到这个请求包,每个机器都会比较自己的 ip 和请求包的目的 ip 是不是一样的,如果不一样,就丢弃这个请求包,结果,只有 B 机器符合条件,B 机器单独给 A 发送 ARP 应答包,应答包带上了 B 的 ip 所对应的 MAC 地址,当 A 收到这个应答包后,就把 B 的 ip 以及其对应的 MAC 地址存入本机 ARP 缓存中。
在 Linux 查看 ARP 缓存表:arp
在 Windows 查看 ARP 缓存表:arp -a
ARP头部
1、Dest MAC:目的 MAC 地址
2、Src MAC:源 MAC 地址
3、帧类型:0x0806
4、硬件类型:1(以太网)
5、协议类型:0x0800(IP地址)
6、硬件地址长度:6
7、协议地址长度:4
8、OP:1(ARP请求),2(ARP应答),3(RARP请求),4(RARP应答)
接下来这个例子为,虚拟机(ubuntu)获取 PC 机的 MAC 地址:
先查看 ubuntu 的 ip 和 MAC 地址:
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h> //struct ifreq
#include <sys/ioctl.h> //ioctl、SIOCGIFADDR
#include <sys/socket.h>
#include <netinet/ether.h> //ETH_P_ALL
#include <netpacket/packet.h> //struct sockaddr_ll
#include <netinet/in.h>int main(int argc,char *argv[])
{//1.创建通信用的原始套接字int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));//2. 根据各种协议首部格式构建发送数据报unsigned char send_msg[1024] = {//--------------组MAC--------14------0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //dst_mac: FF:FF:FF:FF:FF:FF0x00, 0x0c, 0x29, 0x97, 0xc7,0xc1, //src_mac: 00:0c:29:97:c7:c10x08, 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, 0x97, 0xc7,0xc1, //发送端的MAC地址10, 221, 0, 11, //发送端的IP地址0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //目的MAC地址(由于要获取对方的MAC,所以目的MAC置零)10, 221, 20, 10 //目的IP地址};//3.数据初始化struct sockaddr_ll sll; //原始套接字地址结构struct ifreq req; //网络接口地址strncpy(req.ifr_name, "eth0", IFNAMSIZ); //指定网卡名称//4.将网络接口赋值给原始套接字地址结构ioctl(sock_raw_fd, SIOCGIFINDEX, &req);bzero(&sll, sizeof(sll));sll.sll_ifindex = req.ifr_ifindex;//5. 发送 ARP 请求包int len = sendto(sock_raw_fd, send_msg, 42, 0 , (struct sockaddr *)&sll, sizeof(sll));if(len == -1){perror("sendto");}//6.接收对方的ARP应答unsigned char recv_msg[1024] = {0};recvfrom(sock_raw_fd, recv_msg, sizeof(recv_msg), 0, NULL, NULL);if(recv_msg[21] == 2) //ARP应答{char resp_mac[18] = ""; //arp响应的MACchar resp_ip[16] = ""; //arp响应的IPsprintf(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;
}
程序运行结果如下:
查看 PC 的网卡信息:
下面的例子能够获取指定网段所有机器的 MAC 地址:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h> //struct ifreq
#include <sys/ioctl.h> //ioctl、SIOCGIFADDR
#include <sys/socket.h>
#include <netinet/ether.h> //ETH_P_ALL
#include <netpacket/packet.h> //struct sockaddr_ll
#include <pthread.h>
#include <netinet/in.h>
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响应的MACchar resp_ip[16] = ""; //arp响应的IPsprintf(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:FF0x00, 0x0c, 0x29, 0x75, 0xa6, 0x51, //src_mac: 00:0c:29:75:a6:510x08, 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 req; //网络接口地址strncpy(req.ifr_name, "eth0", IFNAMSIZ); //指定网卡名称//3.将网络接口赋值给原始套接字地址结构ioctl(sock_raw_fd, SIOCGIFINDEX, &req);bzero(&sll, sizeof(sll));sll.sll_ifindex = req.ifr_ifindex;//4.本地机的IPif(!(ioctl(sock_raw_fd, SIOCGIFADDR, &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)的MACif (!(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) req.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);}return;
}
程序运行结果如下:
源代码下载请点此次。
Linux 网络编程——原始套接字实例:MAC 地址扫描器相关推荐
- Linux网络编程——原始套接字编程
Linux网络编程--原始套接字编程 转自:http://blog.csdn.net/tennysonsky/article/details/44676377 原始套接字编程和之前的 UDP 编程差不 ...
- linux串口编程实例_Linux 网络编程——原始套接字实例:发送 UDP 数据包
以太网报文格式: IP 报文格式: UDP 报文格式: 校验和函数: /*******************************************************功能:校验和函数参 ...
- Linux网络编程——原始套接字能干什么?
一.知识回顾: 通常情况下程序员接所接触到的套接字(Socket)为两类: (1)流式套接字(SOCK_STREAM):一种面向连接的 Socket,针对于面向连接的TCP 服务应用: (2)数据报式 ...
- Linux原始网络编程,Linux操作系统网络编程 原始套接字 (1)
Linux操作系统网络编程--原始套接字 (1) http://soft.zdnet.com.cn/software_zone/2007/1020/568223.shtml 我们在前面已经学习过了网络 ...
- Linux网络编程之套接字基础
Linux网络编程之套接字基础 1.套接字的基本结构 struct sockaddr 这个结构用来存储套接字地址. 数据定义: struct sockaddr { unsigned short sa_ ...
- 【Linux网络编程】套接字简介
00. 目录 文章目录 00. 目录 01. 概述 02. 套接字属性 03. socket函数 04. 套接字地址结构 05. 附录 01. 概述 Socket套接字由远景研究规划局(Advance ...
- 【Linux网络编程】套接字的介绍
套接字是一种通信机制(通信的两方的一种约定),凭借这种机制,不同主机之间的进程可以进行通信.我们可以用套接字中的相关函数来完成通信过程. 套接字的特性有三个属性确定,它们是:域(domain),类型( ...
- Linux网络编程 之 套接字(四)
目录 1. 套接字的定义 2. 套接字的创建方法 3. 套接字的地址 本地套接字 网络套接字 1. 套接字的定义 套接字是一种通信机制(通信的两方的一种约定),凭借这种机制,不同主机之间的进程可以进行 ...
- linux网络编程 华清,Linux网络编程之套接字
一 :套接字属性 套接字由域(domain),类型(type)和协议(protocol)三个属性确定其特性. 1)套接字的域 域指定套接字通信中使用的网络 介质,常见的套接字域是AF_INET,它指的 ...
最新文章
- 三星超过台积电 成为全球市值最高半导体公司
- myNote app debug - page render
- 如何使用Chrome开发者工具调试web socket应用
- 异步日志系统设计demo
- 四、mysql数据常用命令
- cocos2d(粒子效果编辑器)
- 协同过滤算法_《推荐系统实践》3.基于物品的协同过滤算法
- Python开源机器学习项目实战
- 吸烟 打电话 行为 图片 数据集
- 计算机内存不足黑屏怎么办,win10内存不足会黑屏怎么办
- TF-IDF算法总结
- Java文件操作——简单文件搜索
- (问题)双击页面时,会出现蓝色背景,选中文字,css 样式解决问题
- OSChina 周三乱弹 ——发福利的日子到了!来领妹子!
- tensorflow2.0 dqn 深度强化学习 AI自动玩游戏,有详细注解
- LeetCode 387、字符串中的第一个唯一字符
- 10行代码DIY一个类USB Rubber Ducky来遥控自己电脑
- 2016全域大数据应用论坛11位嘉宾核心观点
- 基于QT实现的多媒体播放器
- HYKSVCAO2V4F3电液伺服阀控制器
热门文章
- REVISITING DYNAMIC CONVOLUTION VIA MATRIXDECOMPOSITION 官方代码解析心得
- css wangeditor 修改_HTML富文本编辑器wangEditor的使用
- 史上最牛逼的音乐播放器—仿网易云音乐(已开源)
- Gatsby中怎么使用emotion?
- 一起背英语单词(一):新概念英语I - 长度1到3的英语单词
- 【转载】林萧教会你--如何做到招聘要求中的“要有扎实的Java基础”。
- mysql批量添加卡号_mysql数据库卡号卡密批量生成写入验证附易辅助模块
- 【CAD开发】gltf文件格式的转换工具汇总(js、python、c++)
- 六、T100库存管理之定期盘点
- BZOJ3039-玉蟾宫