Chinaunix首页 | 论坛 | 博客
  • 博客访问: 149415
  • 博文数量: 31
  • 博客积分: 1911
  • 博客等级: 上尉
  • 技术积分: 327
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-29 09:48
文章分类

全部博文(31)

文章存档

2011年(22)

2010年(9)

我的朋友

分类: BSD

2011-03-27 21:02:36

Linux下PF_PACKET的使用,RARP的server和client程序
网上看到这个,写的很具体,转过来存着。
 
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
#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;
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tqyou85/archive/2008/10/21/3115664.aspx
阅读(2212) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~