读取linux下的网络设备的mac地址与发送原始数据包

转自:http://blog.csdn.net/crazyleen/article/details/7014978

一:linux下的网络设备

linux的网络设备信息都在/proc/net/dev,从这里我们可以得到所有网卡的名字,如eth0, eth1等等

 
  1. [html]  view plain  copy
    1. root@dlrc-desktop:/home/dlrc/dlsp-ep9302/work/mystar-v0.4# cat /proc/net/dev  
    2.   
    3. Inter-| Receive | Transmit  
    4.   
    5.  face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop   
    6.   
    7.     lo: 472252 1696 0 0 0 0 0 0 472252 1696 0 0 0 0 0 0  
    8.   
    9.   eth1:20826443 20156 0 0 0 0 0 0 926357 14613 0 0 0 0 0 0  

上面的lo和eth1便是我的网卡名字。ifconfig就是读取/proc/net/dev这个文件来取得设备名列表的。

 

二:读取网卡mac地址

可以通过ioctl(sock, SIOCGIFHWADDR, &ifr)读取mac地址,对任意类型的socket都适用,只需指定第三参数struct ifreq ifr的ifr.ifr_name, 这个ifr_name就是网络设备的名字,如eth0, eth1, lo等,在/proc/net/dev可找到。ioctl通过ifr_name获取设备信息。

[cpp]  view plain  copy
  1. struct ifreq ifr;  
  2. strncpy(ifr.ifr_name, name, 6);  
  3.  if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0){  
  4.    perror("get_hwaddr ioctl:");  
  5.    close(sock);  
  6.    return -1;  
  7.  }  

以下是一个实现:

[cpp]  view plain  copy
  1. /** 
  2.  * get_hwaddr - get netdevice mac addr  
  3.  * @name: device name, e.g: eth0 
  4.  * @hwaddr: where to save mac, 6 byte hwaddr[6] 
  5.  * @return: 0 on success, -1 on failure 
  6.  */  
  7. int get_hwaddr(char *name, unsigned char *hwaddr)  
  8. {  
  9.     struct ifreq ifr;  
  10.     unsigned char memzero[6];  
  11.     int sock;  
  12.   
  13.     if(name == NULL || hwaddr == NULL){  
  14.         printf("get_hwaddr: NULL para\n");  
  15.         return -1;  
  16.     }  
  17.   
  18.  sock = socket(AF_INET, SOCK_STREAM, 0);  
  19.     if(sock < 0){  
  20.         printf("get_hwaddr: socket error\n");  
  21.         //return -1;  
  22.     }  
  23.   
  24.     //get eth1 mac addr  
  25.     memset(hwaddr, 0, 6);  
  26.     memset(&ifr, 0, sizeof(ifr));  
  27.     strncpy(ifr.ifr_name, name, 6);  
  28.     if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0){  
  29.             perror("get_hwaddr ioctl:");  
  30.             close(sock);  
  31.             return -1;  
  32.     } else {  
  33.             memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);  
  34.             //printf("hwaddr: %2x : %2x : %2x : %2x : %2x : %2x\n", hwaddr[0], hwaddr[1],hwaddr[2], hwaddr[3],hwaddr[4], hwaddr[5]);  
  35.     }  
  36.   
  37.     memset(memzero, 0, 6);  
  38.     if(memcmp(memzero, hwaddr, 6) == 0){  
  39.         printf("no mac\n");  
  40.         return -1;  
  41.     }  
  42.   
  43.     close(sock);  
  44.     return 0;  
  45. }  


 

三:发送底层网络数据包

绕过TCP,UDP等传输协议,自己维护协议首部,发送原始数据包,在自定义的协议方面很方便。

SOCK_RAW提供了一个数据包接口直接访问底层网络。使用这个socket需要root权限。

创建 socket,用于发送自定义数据报:

[cpp]  view plain  copy
  1. int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));  
  2.  if(sock < 0){  
  3.   perror("sock");  
  4.   return -1;  
  5.  }  


 

第三个参数htons(ETH_P_ALL)只对recvfrom有意义。用这个socket发送的数据,都需要自己维护数据包协议首部,包括网络数据包中的mac地址。

发送数据包:

[cpp]  view plain  copy
  1. struct sockaddr_ll sll;  
  2. memset(&sll, 0, sizeof(sll));  
  3. sll.sll_ifindex = 2; // 指定网卡  
  4. if (sendto(sock, packet_start, sizeof packet_start, 0, &sll, sizeof(sll)) < 0){  
  5.     perror("sendto");  
  6.     return 1;  
  7. }  


 

sendto发送原始数据包,只需用struct sockaddr_ll的sll_ifindex指定网卡。

接收这类的数据包:

[cpp]  view plain  copy
  1. ret = recvfrom(sock, buf, 1024, 0, NULL, NULL);  


 

以下是一个简单的实现,运行两个实例,一个带参数,用于发送数据包。一个不带参数,用于接收数据包。完整的源码在最下面:

 在wireshark可以看到,发送的数据包就是原始的网络数据包。

完整的源码:

[cpp]  view plain  copy
  1. /* 
  2.  * socket.c 
  3.  * 
  4.  * Copyright (C) 2011 crazyleen <ruishenglin@126.com> 
  5.  *  
  6.  */  
  7.   
  8. #include <sys/socket.h>  
  9. #include <string.h>  
  10. #include <sys/types.h>  
  11. #include <arpa/inet.h>  
  12. #include <features.h>    /* for the glibc version number */  
  13. #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1  
  14. #include <netpacket/packet.h>  
  15. #include <net/ethernet.h>     /* the L2 protocols */  
  16. #else  
  17. #include <asm/types.h>  
  18. #include <linux/if_packet.h>  
  19. #include <linux/if_ether.h>   /* The L2 protocols */  
  20. #endif  
  21. #include <stdio.h>  
  22. #include <netinet/in.h>  
  23. #include <net/if.h>  
  24. #include <sys/ioctl.h>  
  25. #include <errno.h>  
  26.   
  27. #define _PATH_PROCNET_DEV               "/proc/net/dev"  
  28.   
  29. static char *get_name(char *name, char *p)  
  30. {  
  31.     while (isspace(*p))  
  32.             p++;  
  33.   
  34.     while (*p) {  
  35.             if (isspace(*p))  
  36.         break;  
  37.             if (*p == ':') {    /* could be an alias */  
  38.         char *dot = p, *dotname = name;  
  39.         *name++ = *p++;  
  40.         while (isdigit(*p))  
  41.         *name++ = *p++;  
  42.         if (*p != ':') {    /* it wasn't, backup */  
  43.         p = dot;  
  44.         name = dotname;  
  45.         }  
  46.         if (*p == '\0')  
  47.         return NULL;  
  48.         p++;  
  49.         break;  
  50.     }  
  51.     *name++ = *p++;  
  52.     }  
  53.     *name++ = '\0';  
  54.     return p;  
  55. }  
  56.   
  57. /** 
  58.  * read_netdev_proc - read net dev names form proc/net/dev 
  59.  * @devname: where to store dev names, devname[num][len] 
  60.  */  
  61. static int read_netdev_proc(void *devname, const int num, const int len)  
  62. {  
  63.     FILE *fh;  
  64.     char buf[512];  
  65.         int cnt = 0;  
  66.         char *dev = (char *)devname;  
  67.   
  68.         if(devname == NULL || num < 1 || len < 4){  
  69.             printf("read_netdev_proc: para error\n");  
  70.             return -1;  
  71.         }  
  72.   
  73.         memset(devname, 0, len * num);  
  74.   
  75.     fh = fopen(_PATH_PROCNET_DEV, "r");  
  76.     if (!fh) {  
  77.         fprintf(stderr, "Warning: cannot open %s (%s). Limited output.\n",  
  78.             _PATH_PROCNET_DEV, strerror(errno));   
  79.         return -1;  
  80.       }  
  81.   
  82.     fgets(buf, sizeof buf, fh); /* eat two line */  
  83.     fgets(buf, sizeof buf, fh);  
  84.   
  85.         cnt = 0;  
  86.     while (fgets(buf, sizeof buf, fh) && cnt < num) {  
  87.             char *s, name[IFNAMSIZ];  
  88.             s = get_name(name, buf);      
  89.   
  90.             strncpy(devname, name, len);  
  91.             devname += len;  
  92.             printf("get_name: %s\n", name);  
  93.     }  
  94.   
  95.     if (ferror(fh)) {  
  96.             perror(_PATH_PROCNET_DEV);  
  97.     }  
  98.   
  99.     fclose(fh);  
  100.     return 0;  
  101. }  
  102.   
  103. /** 
  104.  * get_hwaddr - get netdevice mac addr  
  105.  * @name: device name, e.g: eth0 
  106.  * @hwaddr: where to save mac, 6 byte hwaddr[6] 
  107.  * @return: 0 on success, -1 on failure 
  108.  */  
  109. int get_hwaddr(char *name, unsigned char *hwaddr)  
  110. {  
  111.     struct ifreq ifr;  
  112.     unsigned char memzero[6];  
  113.     int sock;  
  114.   
  115.     if(name == NULL || hwaddr == NULL){  
  116.         printf("get_hwaddr: NULL para\n");  
  117.         return -1;  
  118.     }  
  119.   
  120.  sock = socket(AF_INET, SOCK_STREAM, 0);  
  121.     if(sock < 0){  
  122.         printf("get_hwaddr: socket error\n");  
  123.         //return -1;  
  124.     }  
  125.   
  126.     //get eth1 mac addr  
  127.     memset(hwaddr, 0, 6);  
  128.     memset(&ifr, 0, sizeof(ifr));  
  129.     strncpy(ifr.ifr_name, name, 6);  
  130.     if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0){  
  131.             perror("get_hwaddr ioctl:");  
  132.             close(sock);  
  133.             return -1;  
  134.     } else {  
  135.             memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);  
  136.             //printf("hwaddr: %2x : %2x : %2x : %2x : %2x : %2x\n", hwaddr[0], hwaddr[1],hwaddr[2], hwaddr[3],hwaddr[4], hwaddr[5]);  
  137.     }  
  138.   
  139.     memset(memzero, 0, 6);  
  140.     if(memcmp(memzero, hwaddr, 6) == 0){  
  141.         printf("no mac\n");  
  142.         return -1;  
  143.     }  
  144.   
  145.     close(sock);  
  146.     return 0;  
  147. }  
  148.   
  149. unsigned char packet_start[]={  
  150.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff,//dst mac  
  151.     0x00, 0x23, 0x54, 0x0e, 0xe5, 0xd8,//src mac  
  152.     0x88, 0x8e, //Type: 802.1x authentication  
  153.         0x01, //Version:v1  
  154.         0x01, //Type:  Start (1)  
  155.         0x00, 0x00//Length 0  
  156. };  
  157.   
  158. void printhex(void *hex, int len, char *tag)  
  159. {  
  160.     int i;  
  161.     unsigned char *p = (unsigned char *)hex;  
  162.   
  163.     if(len < 1)  
  164.         return;  
  165.   
  166.     for(i = 0; i < len - 1; i++){  
  167.         if(*p < 0x10)  
  168.             printf("0%x%s", *p++, tag);  
  169.         else  
  170.             printf("%2x%s", *p++, tag);  
  171.     }  
  172.   
  173.     if(*p < 0x10)  
  174.         printf("0%x\n", *p++);  
  175.     else  
  176.         printf("%2x\n", *p++);  
  177. }  
  178.   
  179. int main(int argc, char **argv)  
  180. {  
  181.         int i;  
  182.         unsigned char hwaddr[6];  
  183.         char devname[3][7];  
  184.          unsigned char buf[1024]; // for revevied packet  
  185.         int ret;  
  186.   
  187.     read_netdev_proc(devname, 3, 7);  
  188.   
  189.     for(i = 0; i < 3 && get_hwaddr(devname[i], hwaddr) != 0; i++){     
  190.         //empty  
  191.     }  
  192.   
  193.     printf("devname: [ %s ]\t", devname[i]);  
  194.     printhex(hwaddr, 6, ":");  
  195.   
  196.  int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));  
  197.     if(sock < 0){  
  198.         perror("sock");  
  199.         return -1;  
  200.     }  
  201.   
  202.     struct sockaddr_ll sll;  
  203.     memset(&sll, 0, sizeof(sll));  
  204.     sll.sll_ifindex = 2; // It seems only need this to specify which NIC to use  
  205.   
  206.     memcpy(packet_start + 6, hwaddr, 6);  
  207.     //memcpy(packet_start, hwaddr, 6);  
  208.     while(argc == 1){  
  209.         if (sendto(sock, packet_start, sizeof packet_start, 0, &sll, sizeof(sll)) < 0){  
  210.             perror("sendto");  
  211.             return 1;  
  212.         }  
  213.         printf("Sendto Success!\n");  
  214.         sleep(1);  
  215.     }  
  216.   
  217.     while(argc == 2){  
  218.         ret = recvfrom(sock, buf, 1024, 0, NULL, NULL);  
  219.         printf("recv: ");  
  220.         printhex(buf, ret, " ");  
  221.     }  
  222.   
  223.     return 0;  
  224. }  
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值