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>
/* 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 <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 <cstdlib>


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;
}
 

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐