Linux下PF_PACKET的使用

  • Post author:
  • Post category:linux


原文地址::

http://blog.sina.com.cn/s/blog_82f2fc28010132og.html

相关文章

1、


AF_INET和AF_PACKET区别—-

https://blog.csdn.net/an_zhenwei/article/details/16861805



2、


TCP/IP协议(一)网络基础知识

—-

https://www.cnblogs.com/imyalost/p/6086808.html




sock_raw(注意一定要在root下使用)原始套接字编程可以接收到本机网卡上的数据帧或者数据包,对于监听网络的流量和分析是很有作用的.一共可以有3种方式创建这种socket

1.socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收ip数据包,不能用IPPROTO_IP,因为如果是用了IPPROTO_IP,系统根本就不知道该用什么协议。

2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧

3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))过时了,不要用啊

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 <sys/types.h>

#include <sys/time.h>

#include <time.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/if_ether.h>

#include <net/if_arp.h>

#include <netinet/in.h>

#include <stdio.h>

#include <string.h>

#include <unistd.h>

#include <errno.h>

#include <netinet/if_ether.h>

#include <net/if_arp.h>

#include <net/if.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <sys/ioctl.h>

#include <netpacket/packet.h>

}

#include <cstdlib>

struct arpMsg {


struct ethhdr ethhdr;

u_short htype;

u_short ptype;

u_char  hlen;

u_char  plen;

u_short operation;

u_char  sHaddr[6];

u_char  sInaddr[4];

u_char  tHaddr[6];

u_char  tInaddr[4];

u_char  pad[18];

};

#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(“X”, 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;

int rv = 1;

struct sockaddr_ll addr;

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”);