当前位置: 首页 > news >正文

Linux下PF_PACKET的使用,RARP的server和client程序

1.介绍
在linux中提供了PF_PACKET接口可以操作链路层的数据。
2.使用方法
定义一个pf_packet = socket(PF_SOCKET, SOCK_RAW, htons(ETH_P_RARP));
就可以利用函数sendto和recefrom来读取和发送链路层的数据包了(当然,发送ARP包,上面第三个参数要变为htons(ETH_P_ARP),或者IP的包为ETH_P_IP,可查看文件/usr/include/linux/if_ether.h文件看到所有支持的协议)。
3.在使用SOCK_RAW, SOCK_DGRAM和SOCK_PACKET的区别
在socket的第一个参数使用PF_PACKET的时候,上述三种socket的类型都可以使用。但是有区别。
(1)使用SOCK_RAW发送的数据必须包含链路层的协议头,接受得到的数据包,包含链路层协议头。而使用SOCK_DGRAM则都不含链路层的协议头。
(2)SOCK_PACKET也是可以使用的,但是已经废弃,以后不保证还能支持,不推荐使用。
(3)在使用SOCK_RAW或SOCK_DGRAM和SOCK_PACKET时,在sendto和recvfrom中使用的地址类型不同,前两者使用sockaddr_ll类型的地址,而后者使用sockaddr类型的地址。
(4)如socket的第一个参数使用PF_INET,第二个参数使用SOCK_RAW,则可以得到原始的IP包。
4.下面的例子是一个简单的rarp协议的server程序和client程序
server程序一开始获得除lo接口以外接口的mac地址,等待rarp request请求的到来,如果请求的是自己的mac地址,则向客户端发送rarp reply,回送自己的ip地址。应我使用的地方,一台机器的ip地址每次dhcp以后都会变。所以该程序还是有一些用处。
注意:本程序只为演示packet socket的工作原理,所以没有进行任何的错误处理,并假设工作的机器上只有ethernet接口。但是本程序有个缺点,就是两个程序工作在同一台机器上的时候,server无法接收到client的rarp request。请知道的朋友赐教,谢谢!
//File Name : rarp_server.cpp
extern "C"
{ 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include 
#include 
#include 
#include 
#include 
#include
#include 
}
#include
/* args: yiaddr - what IP to ping
* ip - our ip
* mac - our arp address
* interface - interface to use
* retn: 1 addr free
* 0 addr used
* -1 error 
*/
/* FIXME: match response against chaddr */
struct arpMsg {
struct ethhdr ethhdr; /* Ethernet header */
u_short htype; /* hardware type (must be ARPHRD_ETHER) */
u_short ptype; /* protocol type (must be ETH_P_IP) */
u_char hlen; /* hardware address length (must be 6) */
u_char plen; /* protocol address length (must be 4) */
u_short operation; /* ARP opcode */
u_char sHaddr[6]; /* sender's hardware address */
u_char sInaddr[4]; /* sender's IP address */
u_char tHaddr[6]; /* target's hardware address */
u_char tInaddr[4]; /* target's IP address */
u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */
};
/* miscellaneous defines */
#define MAC_BCAST_ADDR (uint8_t *) "\xff\xff\xff\xff\xff\xff"
#define OPT_CODE 0
#define OPT_LEN 1
#define OPT_DATA 2
struct interface_info
{
char ifname[64];
unsigned char ip[4];
unsigned char mac[6]; 
};
struct interface_info if_info[10];
int eth_num = 0;
void print_mac(unsigned char * mac_addr)
{
for (int i =0; i < 6; ++i)
{
printf("%02X", mac_addr[i]);
if (i != 5) printf(":");
} 
printf("\n");
}
void print_ip(unsigned char * ip_addr)
{
for (int i =0; i < 4; ++i)
{
printf("%d", ip_addr[i]);
if (i != 3) printf(".");
} 
printf("\n");
}
int get_iface_index(int fd, const char* interface_name)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strcpy (ifr.ifr_name, interface_name);
if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1)
{
return (-1);
}
return ifr.ifr_ifindex;
}
int get_interfaces()
{
int sock;
int len = 64;
int last_len = 0;
char *pBuff = NULL;
int interface_num = 0;

struct ifconf interface_conf;
struct ifreq ifreq1;
struct sockaddr_in *psockaddr_in = NULL;


if ( (sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Could not create socket for geting interface info");
exit(1);
}

while(1)
{
pBuff = (char*)malloc(len);
interface_conf.ifc_len = len;
interface_conf.ifc_buf = pBuff;
if (ioctl(sock, SIOCGIFCONF, &interface_conf) < 0)
{
perror("ioctl error");
}
else
{
if (interface_conf.ifc_len == last_len)
{
break;
}
else
{
last_len = interface_conf.ifc_len; 
} 
}
len += 2*sizeof(struct ifreq);
free(pBuff); 
}

interface_num = last_len / sizeof(struct ifreq);

for (int i =0; i < interface_num; ++i)
{
strcpy(ifreq1.ifr_name, interface_conf.ifc_ifcu.ifcu_req[i].ifr_name);
if (strcmp(ifreq1.ifr_name, "lo") == 0)
{
continue;
} 
if (ioctl(sock, SIOCGIFHWADDR, &ifreq1) < 0)
{
continue; 
} 
memcpy(if_info[eth_num].mac, ifreq1.ifr_hwaddr.sa_data, 6); 
strcpy(if_info[eth_num].ifname, ifreq1.ifr_name);
psockaddr_in = (struct sockaddr_in*)&interface_conf.ifc_req[i].ifr_addr;
memcpy(if_info[eth_num].ip, &(psockaddr_in->sin_addr.s_addr), 4);
printf("Interface name: %s", if_info[eth_num].ifname);
printf(" ip address: ");
print_ip(if_info[eth_num].ip);
printf(" mac address:");
print_mac(if_info[eth_num].mac); 
eth_num++;
} 

free(pBuff); 
close(sock); 
}
int equal_mac(unsigned char* mac1, unsigned char* mac2)
{
for (int i =0; i < 6; ++i)
{
if (mac1[i] != mac2[i]) return 0;
}
return 1; 
} 

int main()
{
int timeout = 2;
int optval = 1;
int s; /* socket */
int rv = 1; /* return value */
struct sockaddr_ll addr; /* for interface name */
struct arpMsg arp;
struct arpMsg *parp;

fd_set fdset;
struct timeval tm;
time_t prevTime;
u_int32_t ip;
u_int32_t yiaddr;
struct in_addr my_ip;
struct in_addr dst_ip;
char buff[2000];
int nLen;
char szBuffer[4096];

if ((s = socket (PF_PACKET, SOCK_RAW, htons(ETH_P_RARP))) == -1) 
{
printf("Could not open raw socket\n");
return -1;
}

if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) 
{
printf("Could not setsocketopt on raw socket\n");
close(s);
return -1;
} 

memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_ifindex = get_iface_index(s, "eth0");
addr.sll_protocol = htons(ETH_P_ARP);

get_interfaces();

memset(szBuffer, 0, sizeof(szBuffer)); 
while ((nLen = recvfrom(s, szBuffer, sizeof(szBuffer), MSG_TRUNC, NULL, NULL)) > 0)
{
parp = (struct arpMsg*)szBuffer;
printf("The request is from ");
print_ip(parp->sInaddr);

for (int i = 0; i < eth_num; ++i)
{
if (equal_mac(if_info[i].mac, parp->tHaddr))
{
/* send arp request */
memset(&arp, 0, sizeof(arp));
memcpy(arp.ethhdr.h_dest, parp->sHaddr, 6); // MAC DA
memcpy(arp.ethhdr.h_source, parp->tHaddr, 6); // MAC SA
arp.ethhdr.h_proto = htons(ETH_P_RARP); // protocol type (Ethernet)
arp.htype = htons(ARPHRD_ETHER); // hardware type
arp.ptype = htons(ETH_P_IP); // protocol type (ARP message)
arp.hlen = 6; // hardware address length
arp.plen = 4; // protocol address length
arp.operation = htons(4); // RARP reply code
memcpy(arp.sInaddr, if_info[i].ip, 4); // source IP address 
memcpy(arp.sHaddr, parp->tHaddr, 6); // source hardware address
memcpy(arp.tInaddr, parp->sInaddr, 4); // target IP address
memcpy(arp.tHaddr, parp->sHaddr, 6);

if (sendto(s, &arp, sizeof(arp), 0, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
perror("Unabele to send arp request");
return 0; 
}
else
printf("send reply\n"); 

} 
} 
}
close(s);
return 0;
}
//
//File Name : get_ip_by_mac.cpp
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include 
#include 
#include 
#include 
#include 
#include
#include

struct arpMsg {
struct ethhdr ethhdr; /* Ethernet header */
u_short htype; /* hardware type (must be ARPHRD_ETHER) */
u_short ptype; /* protocol type (must be ETH_P_IP) */
u_char hlen; /* hardware address length (must be 6) */
u_char plen; /* protocol address length (must be 4) */
u_short operation; /* ARP opcode */
u_char sHaddr[6]; /* sender's hardware address */
u_char sInaddr[4]; /* sender's IP address */
u_char tHaddr[6]; /* target's hardware address */
u_char tInaddr[4]; /* target's IP address */
u_char pad[18]; /* pad for min. Ethernet payload (60 bytes) */
};
/* miscellaneous defines */
#define MAC_BCAST_ADDR (uint8_t *) "\xff\xff\xff\xff\xff\xff"
#define OPT_CODE 0
#define OPT_LEN 1
#define OPT_DATA 2

void print_mac(unsigned char * mac_addr)
{
for (int i =0; i < 6; ++i)
{
printf("%02X", mac_addr[i]);
if (i != 5) printf(":");
} 
printf("\n");
}
void print_ip(unsigned char * ip_addr)
{
for (int i =0; i < 4; ++i)
{
printf("%d", ip_addr[i]);
if (i != 3) printf(".");
} 
printf("\n");
}
void get_local_addr(unsigned char* mac, u_int32_t &ip)
{
struct ifconf interface_conf;
struct ifreq ifreq1;
int sock;
struct sockaddr_in* psockaddr_in = NULL;


if ( (sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("Unable to create socket for geting the mac address");
exit(1);
} 
strcpy(ifreq1.ifr_name, "eth0");

if (ioctl(sock, SIOCGIFHWADDR, &ifreq1) < 0)
{
perror("Unable to get the mac address");
exit(1); 
} 
memcpy(mac, ifreq1.ifr_hwaddr.sa_data, 6); 
if (ioctl(sock, SIOCGIFADDR, &ifreq1) < 0)
{
perror("Unable to get the ip address");
exit(1); 
} 

psockaddr_in = (struct sockaddr_in*)&ifreq1.ifr_addr; 
ip = psockaddr_in->sin_addr.s_addr;
//print_ip((unsigned char*)ip);
} 
int main(int argc, char* argv[])
{
int timeout = 2;
int optval = 1;
int s; /* socket */
int rv = 1; /* return value */
struct sockaddr addr; /* for interface name */
struct arpMsg arp;
fd_set fdset;
struct timeval tm;
time_t prevTime;
u_int32_t ip;
struct in_addr my_ip;
struct in_addr dst_ip;
char buff[2000];

unsigned char mac[6];
unsigned char dmac[6];

char interface[] = "eth0";

if (argc != 2)
{
printf("Usage: get_ip_by_mac dst_mac\n");
printf("For example: get_ip_by_mac 00:0F:EA:40:0D:04\n");
return 0; 
}
get_local_addr(mac, ip);

for (int i = 0; i < 6; ++i)
{
strncpy(buff, argv[1]+3*i, 2);
buff[3] = '\0';
dmac[i] = strtol(buff, (char**)NULL, 16);
}
if ((s = socket (PF_PACKET, SOCK_PACKET, htons(ETH_P_RARP))) == -1) 
{
printf("Could not open raw socket\n");
return -1;
}

if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) 
{
printf("Could not setsocketopt on raw socket\n");
close(s);
return -1;
}

memset(&addr, 0, sizeof(addr));
strcpy(addr.sa_data, interface);

/* send rarp request */
memset(&arp, 0, sizeof(arp));
memcpy(arp.ethhdr.h_dest, MAC_BCAST_ADDR, 6); /* MAC DA */
memcpy(arp.ethhdr.h_source, mac, 6); /* MAC SA */
arp.ethhdr.h_proto = htons(ETH_P_RARP); /* protocol type (Ethernet) */
arp.htype = htons(ARPHRD_ETHER); /* hardware type */
arp.ptype = htons(ETH_P_IP); /* protocol type (ARP message) */
arp.hlen = 6; /* hardware address length */
arp.plen = 4; /* protocol address length */
arp.operation = htons(3); /* RARP request code */
*((u_int *) arp.sInaddr) = ip; /* source IP address */
memcpy(arp.sHaddr, mac, 6); /* source hardware address */ 
memcpy(arp.tHaddr, dmac, 6);
if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0)
{
perror("Unabele to send arp request");
return 0; 
}
rv = 0;

/* wait arp reply, and check it */
tm.tv_usec = 0;
time(&prevTime);
while (timeout > 0) 
{
FD_ZERO(&fdset);
FD_SET(s, &fdset);
tm.tv_sec = timeout;
if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm) < 0) 
{
printf("Error on ARPING request:");
if (errno != EINTR) rv = 0;
} 
else if (FD_ISSET(s, &fdset)) 
{
if (recv(s, &arp, sizeof(arp), 0) < 0 ) 
{
perror("Unable get valid rarp response");
rv = 0;
} 
if (arp.operation == htons(4) && 
bcmp(arp.tHaddr, mac, 6) == 0 ) 
{
printf("Valid rarp reply receved for this address\n");
//print_mac(arp.sHaddr);
print_ip(arp.sInaddr);
rv = 0;
break;
}
}
timeout -= time(NULL) - prevTime;
time(&prevTime);
}
close(s);
return 0;
}

转载自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=686647&id=1745799

相关文章:

  • 面试官:不会真有人不知道什么是线程池吧?
  • 从零搭建基于SpringBoot的秒杀系统(一):项目准备
  • 【总结】oracle恢复误删除数据,解除锁定的等sql语句
  • 从零搭建基于SpringBoot的秒杀系统(二):快速搭建一个SpringBoot项目
  • 重拾cgi——cgi dispatcher
  • 从零搭建基于SpringBoot的秒杀系统(三):首页、详情页编写
  • 从零搭建基于SpringBoot的秒杀系统(四):雪花算法生成订单号以及抢购功能实现
  • 操作系统实验一 命令解释程序的编写
  • 从零搭建基于SpringBoot的秒杀系统(五):基于Shiro的人员登陆认证
  • 从零搭建基于SpringBoot的秒杀系统(六):使用RabbitMQ让订单指定时间后失效
  • 从零搭建基于SpringBoot的秒杀系统(七):高并发导致超卖问题分析处理
  • 从零搭建基于SpringBoot的秒杀系统(八):通过分布式锁解决多线程导致的问题
  • 读《世界是数字的》有感
  • 面试官问我:什么是静态代理?什么是动态代理?注解、反射你会吗?
  • redis入门到精通系列(十):springboot集成redis及redis工具类的编写
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • 2017年终总结、随想
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Babel配置的不完全指南
  • canvas 绘制双线技巧
  • HashMap ConcurrentHashMap
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • mysql 数据库四种事务隔离级别
  • ReactNative开发常用的三方模块
  • React系列之 Redux 架构模式
  • Sublime Text 2/3 绑定Eclipse快捷键
  • 百度小程序遇到的问题
  • 聊聊hikari连接池的leakDetectionThreshold
  • 如何优雅地使用 Sublime Text
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • PostgreSQL之连接数修改
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 正则表达式-基础知识Review
  • #include
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (003)SlickEdit Unity的补全
  • (14)学习笔记:动手深度学习(Pytorch神经网络基础)
  • (22)C#传智:复习,多态虚方法抽象类接口,静态类,String与StringBuilder,集合泛型List与Dictionary,文件类,结构与类的区别
  • (4)(4.6) Triducer
  • (a /b)*c的值
  • (C)一些题4
  • (delphi11最新学习资料) Object Pascal 学习笔记---第7章第3节(封装和窗体)
  • (力扣)循环队列的实现与详解(C语言)
  • (六)软件测试分工
  • (七)Knockout 创建自定义绑定
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)C#开发微信门户及应用(1)--开始使用微信接口
  • (转)程序员疫苗:代码注入
  • .bashrc在哪里,alias妙用
  • .FileZilla的使用和主动模式被动模式介绍
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .Net 知识杂记