免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1662 | 回复: 0
打印 上一主题 下一主题

Linux下PF_PACKET的使用,RARP的server和client程序 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-03 17:05 |只看该作者 |倒序浏览
网上看到这个,写的很具体,转过来存着。

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 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  0)
{
  parp = (struct arpMsg*)szBuffer;
  printf("The request is from ");
  print_ip(parp->sInaddr);
  
  for (int i = 0; i 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.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))

//////////////////////////////////////////////////////////
//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
void print_ip(unsigned char * ip_addr)
{
for (int i =0; i
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)) 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
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)
{
  FD_ZERO(&fdset);
  FD_SET(s, &fdset);
  tm.tv_sec = timeout;
  if (select(s + 1, &fdset, (fd_set *) NULL, (fd_set *) NULL, &tm)
本文来自CSDN博客,转载请标明出处:
http://blog.csdn.net/tqyou85/archive/2008/10/21/3115664.aspx


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/70579/showart_1985151.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP