Linux下PF_PACKET的使用

原文地址::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");

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值