热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

linuxsocket发送ARP数据包

linuxsocket发送ARP数据包--Linux通用技术-Linux编程与内核信息,下面是详情阅读。
Linux 中获得本机网卡MAC地址很简单,ioctl()就OK。可如何获得局域网其他主机的MAC地址呢…链路层广播ARP请求,然后接收ARP响应。实现介个功能其实已有现成三方库可用,如libnet。不过想加深对协议的理解和Linux网络编程API的理解,jiayi 还是决定用Linux的PF_PACKET自己实现,改啊改,终于成功~以下是大体思路
1. 为数据报分配空间,创建相应的结构体 req,arp 数据报

2. 创建 PF_PACKET 原始套接字,发送套接字为 reqfd,接收套接字为 recvfd
3. 填写链路层通用结构体 reqsa
3. get_ifi()获取本机网络接口数据,填写要发送的ARP数据报 req 结构体,sendto()发送
4. 循环recvfrom()接收ARP响应,滤掉经由本地接口的其他ARP数据报
发送ARP请求能做的事不仅仅获取MAC地址吧…其他“有意义”的事也可以尝试一下下……下面是代码
C code

/**
* @send_arp.c
* @This software is intended to be used as a example to show how to send and receive arp request with Linux * PF_PACKET interface
* @Author:jiayi,http://www.jiayii.com
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /* 需要里面的 glibc 版本号 */
#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
#include
#include /* 链路层(L2)协议 */
#else
#include
#include
#include /* 链路层协议 */
#endif
#include
#define INLEN 4
#define MAC_BCAST_ADDR (uint8_t *) "\xff\xff\xff\xff\xff\xff"
void usage_quit(char *arg0);
int get_ifi(char *dev, char *mac, int macln, struct in_addr *lc_addr, int ipln);
void prmac(u_char *ptr);
int main(int argc, char **argv)
{
if(argc != 2)
usage_quit(argv[0]);
int reqfd, recvfd, salen, n;
u_char *mac;
char recv_buf[120], rep_addr[16];
struct in_addr lc_addr, req_addr;
struct sockaddr_ll reqsa, repsa;
struct arp_pkt {
struct ether_header eh;
struct ether_arp ea;
u_char padding[18];
} req;

bzero(&reqsa, sizeof(reqsa));
reqsa.sll_family = PF_PACKET;
reqsa.sll_ifindex = if_nametoindex("eth0");
if((reqfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_RARP))) <0) {
perror("Socket error");
exit(1);
}
mac = (char *)malloc(ETH_ALEN);
bzero(&req, sizeof(req));
if(get_ifi("eth0", mac, ETH_ALEN, &lc_addr, INLEN)) {
fprintf(stderr, "Error: Get host’s information failed\n");
exit(0);
}
/* 填写以太网头部*/
memcpy(req.eh.ether_dhost, MAC_BCAST_ADDR, ETH_ALEN);
memcpy(req.eh.ether_shost, mac, ETH_ALEN);
req.eh.ether_type = htons(ETHERTYPE_ARP);
/* 填写arp数据 */
req.ea.arp_hrd = htons(ARPHRD_ETHER);
req.ea.arp_pro = htons(ETHERTYPE_IP);
req.ea.arp_hln = ETH_ALEN;
req.ea.arp_pln = INLEN;
req.ea.arp_op = htons(ARPOP_REQUEST);
memcpy(req.ea.arp_sha, mac, ETH_ALEN);
memcpy(req.ea.arp_spa, &lc_addr, INLEN);
inet_aton(argv[1], req.ea.arp_tpa);
if((n = sendto(reqfd, &req, sizeof(req), 0, (struct sockaddr *)&reqsa, sizeof(reqsa))) <= 0) {
perror("Sendto error");
exit(1);
}
printf("Broadcast arp request of %s, %d bytes be sent\n\n", argv[1], n);
recvfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
bzero(recv_buf, sizeof(recv_buf));
bzero(&repsa, sizeof(repsa));
salen = sizeof(struct sockaddr_ll);
while(1) {
if((n = recvfrom(recvfd, recv_buf, sizeof(req), 0, (struct sockaddr *)&repsa, &salen)) <= 0) {
perror("Recvfrom error");
exit(1);
}
if( ntohs(*(__be16 *)(recv_buf + 20))==2 && !memcmp(req.ea.arp_tpa, recv_buf + 28, 4) ) {
printf("Response from %s, %d bytes received\n", argv[1], n);
printf(" Peer IP is: %s\n", inet_ntop(AF_INET, (struct in_addr *)(recv_buf + 28), rep_addr, 1024));
prmac( (u_char *)(recv_buf + 22) ); //prmac( (u_char *)(recv_buf + 6) );
break;
}
}
free(mac);
}
int get_ifi(char *dev, char * mac, int macln, struct in_addr *lc_addr, int ipln)
{
int reqfd, n;
struct ifreq macreq;
reqfd = socket(AF_INET, SOCK_DGRAM, 0);
strcpy(macreq.ifr_name, dev);
/* 获取本地接口MAC地址*/
if(ioctl(reqfd, SIOCGIFHWADDR, ¯eq) != 0)
return 1;
memcpy(mac, macreq.ifr_hwaddr.sa_data, macln);
/* 获取本地接口IP地址*/
if(ioctl(reqfd, SIOCGIFADDR, ¯eq) != 0)
return 1;
memcpy(lc_addr, &((struct sockaddr_in *)(¯eq.ifr_addr))->sin_addr, ipln);
return 0;
}
void prmac(u_char *ptr)
{
printf(" Peer MAC is: %02x:%02x:%02x:%02x:%02x:%02x\n",*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));
}
void usage_quit(char *arg0)
{
fprintf(stderr, "Usage: %s \n", arg0);
exit(1);
}
此程序需要root权限运行,或者设置suid。
此程序用到的结构体和宏,在/usr/include/linux/if_ether.h /usr/include/linux/if_arp.h /usr/include/net/ethernet.h /usr/include/netinet/if_ether.h 中有相应的声明。
其他参考: man packet,《TCP/IP 详解 卷一》第四章
如果想偷偷的实验此程序,tcpdump 能够帮你找到接入局域网的其他主机(额,阴暗心理又暴露了…)。
程序运行如下

另一终端 tcpdump 探嗅
推荐阅读
  • 本文比较了eBPF和WebAssembly作为云原生VM的特点和应用领域。eBPF作为运行在Linux内核中的轻量级代码执行沙箱,适用于网络或安全相关的任务;而WebAssembly作为图灵完备的语言,在商业应用中具有优势。同时,介绍了WebAssembly在Linux内核中运行的尝试以及基于LLVM的云原生WebAssembly编译器WasmEdge Runtime的案例,展示了WebAssembly作为原生应用程序的潜力。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 近年来,大数据成为互联网世界的新宠儿,被列入阿里巴巴、谷歌等公司的战略规划中,也在政府报告中频繁提及。据《大数据人才报告》显示,目前全国大数据人才仅46万,未来3-5年将出现高达150万的人才缺口。根据领英报告,数据剖析人才供应指数最低,且跳槽速度最快。中国商业结合会数据剖析专业委员会统计显示,未来中国基础性数据剖析人才缺口将高达1400万。目前BAT企业中,60%以上的招聘职位都是针对大数据人才的。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文主要讨论了在xps15上安装双系统win10和MacOS后,win10无法正常更新的问题。分析了可能的引导问题,并提供了解决方法。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 树莓派Linux基础(一):查看文件系统的命令行操作
    本文介绍了在树莓派上通过SSH服务使用命令行查看文件系统的操作,包括cd命令用于变更目录、pwd命令用于显示当前目录位置、ls命令用于显示文件和目录列表。详细讲解了这些命令的使用方法和注意事项。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
author-avatar
Belief
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有