您的位置:首页 > 编程语言 > C语言/C++

计网_C语言编程获取本机的mac地址以及mac下pcap编程报错Undefined symbols for architecture x86_64-"_pcap_*****"...的解决办法

2017-10-16 12:43 465 查看
本文包含以下两部分:

## C语言编程获取本机的mac地址

## mac下pcap编程报错Undefined symbols for architecture x86_64:”__pcap_*****”, referenced from: _main in…的解决方法

关键词:计算机网络; pcap; libpcap; mac; mac地址;

本学期计网lab老师要求我实现用C语言获取本机的mac地址。但像我这么懒的人眼珠一转就想直接调shell,但问过了老师,直接调shell的命令不行,也就意味着system(“ipconfig”)这样的代码不允许出现。不让用就算了吧,那就自己搞。当然,老师明确说了不会就问度娘,那我就问问。。。

上网查了一下,网上相关的实现有很多,比如有调用API的、通过访问网卡获取的,等等。但我这么懒,肯定不想访问网卡什么的(其实也挺容易的),那么应该怎么办呢?

受到ping命令的启发,我的想法是通过一次网络连接请求,获取本机mac地址。在构思结束后我上网查相关资料,才发现我的想法对应的是一个叫ARP协议的东西。好高兴自己居然独立想出来了一个高级的东西~(并不,只是你的思路别人已经造好了轮子而已。。)

ARP的C语言实现网络上有:传送门,但这个太长,我感觉很多功能并不需要。

我利用ARP协议获取本机的mac地址的思路是:模拟接收到一个数据包,并且发送数据包回应(此部分类似ping命令),然后捕获我们回应的数据包进行解析,得到本机的mac地址并不是完全基于ARP,更正为抓取ping命令发送的ICMP包

既然是捕获数据包,那就要用到我们”大名鼎鼎“的数据包捕获函数库PCAP了。

要使用PCAP可能你需要在自己的电脑上安装libpcap这个函数库(是叫函数库嘛?问号脸。。。。)

mac我并没有安装libpcap,好像是自带pcap库了?(便利性赞一个)。其他系统要安装可以百度一下

好了废话不多说,直接上代码:

/**************************myMacAddress.c*************************************
* Copyright (C) 2017 by guoayng (Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)*
* 实现了C语言获取本机的mac地址
* 备注:
* 网上相关的实现有很多,比如有调用API的、通过访问网卡获取的,等等。并且问过了老师,直接调shell的命令不行,也就意味着system(“ipconfig”)这样的代码不允许出现
* 但我不想访问网卡什么的,那么应该怎么办呢?
* 受到ping命令的启发,我的想法是通过一次网络连接请求,获取本机mac地址
* 在构思结束后我上网查相关资料,才发现我的想法对应的是一个叫ARP协议的东西
* ARP的C语言实现网络上有:http://blog.csdn.net/wangpengqi/article/details/46240505,但这个太长,我感觉很多功能并不需要
* 我利用ARP协议获取本机的mac地址的思路是:模拟接收到一个数据包,并且发送数据包回应(此部分类似ping命令),然后截取我们回应的数据包进行解析,得到本机的mac地址
* 参考了http://blog.csdn.net/wypblog/article/details/7456829 的资料后,我写出了以下代码。
****************************************************************************/

#include <stdio.h>
#include <pcap/pcap.h>
#include <netinet/if_ether.h>

int main(){
pcap_t *sniffer_des;
char errbuf[PCAP_ERRBUF_SIZE];// PCAP_ERRBUF_SIZE is in {/usr/include/pcap/pcap.h}
// the Defination is {#define PCAP_ERRBUF_SIZE 256}
char *net_dev;
bpf_u_int32 net, mask;
struct bpf_program fp;          // 可理解为结构体实例化(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
const u_char *packet;
struct pcap_pkthdr hdr;         // 可理解为结构体实例化
struct ether_header *eth_header;// 可理解为结构体实例化
u_char *ptr;

net_dev = "en7";//此处为我的网卡编号,一般的机子此处应为eth0
if(pcap_lookupnet(net_dev, &net, &mask, errbuf) == -1){
printf("get net error:%s\n", errbuf);
return 1;
}

sniffer_des = pcap_open_live(net_dev, 1024, 1, 5000, errbuf);// 调用PCAP_API中的pcap_open_live
// sniffer_des = pcap_open_live(net_dev, 65535, 1, 5000, errbuf);// 调用PCAP_API中的pcap_open_live
// 参考http://blog.csdn.net/cheng_fangang/article/details/8608126 :发现在pcap_t* handle = pcap_open_live(sDevice, 65535, 1, 0, errbuf);这个函数时有问题了,当设置到1024的时候一点都不丢包,但是65535的时候就丢包了,(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
// 看了pcap的pcap_open_live函数也没有看明白什么原因,我怀疑时内部处理分配内存的时候,每一个包分配65535大小肯定比分配处理1024包大小的内存耗时,所以导致丢包。
// 请各位用pcap的时候牢记这个东东吧,我可吃过苦了。。。。
if(sniffer_des == NULL){
printf("pcap_open_live%s\n", errbuf);
return 1;
}

if(pcap_setfilter(sniffer_des, &fp) == -1){
printf("pcap_setfilter() error\n");
return 1;
}

packet = pcap_next(sniffer_des, &hdr);
if(packet == NULL){
printf("pacap_next() failed\n");
return 1;
}

eth_header = (struct ether_header*)packet;
if(ntohs(eth_header->ether_type) != ETHERTYPE_IP){// ETHERTYPE_IP is in {/usr/include/net/ethernet.h},
// the Defination is {#define ETHERTYPE_IP 0x0800}==>IP数据报的以太网帧类型也是0x0800(IPv4: 0x0800)
printf("not ethernet packet\n");              // 若ether_type(类型)不是ip数据报,则报错(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
return 1;
}

ptr = eth_header->ether_shost;
int i = 0;
printf("\nMy Physical Adress(MAC):");
while(i < ETHER_ADDR_LEN){                          // The number of bytes in an ethernet (MAC) address.
// #define  ETHER_ADDR_LEN      6
printf(" %x:", *ptr++);
i++;
}

printf("\n");
return 0;

}


好了进入下一部分,gcc编译时报错如下信息:(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)

Undefined symbols for architecture x86_64:
"_pcap_lookupnet", referenced from:
_main in xxxx.o


以上错误是由于没有告诉gcc要链接造成的。是的,不要以为include了pcap.h就够了,在编译的时候还需要:(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)

~$ gcc myMacAddress.c -l pcap -o sgyMac


看到
-l pcap
了吗,这是告诉gcc还要动态链接pcap库

然后,成功编译。(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)

调用

调用很简单,另一个终端ping本机地址如192.168.1.10,然后新开一个终端,输入:

note:有时候会由于权限不够,需要
sudo


~$ sudo ./sgyMac


回车,等待一会儿,得到完美输出:

~$ sudo ./sgyMac
Password:

My Physical Adress(MAC): xx: xx: xx: xx: xx: xx://我的mac地址不在这里贴出来了


与终端命令
ifconfig
的结果对比后,完全正确。

文中所用C代码运行时并没有返回mac地址,而是报“not ethernet packet”

因为代码基于抓包,所以我自己在测试的时候也发生过这种情况,没有返回MAC地址。经过测试我发现,在有线连接和手机热点下的无线连接,程序都可以正常运行,但大局域网(比如商场的公共Wi-Fi)下很小几率会报这个错,我猜测是丢包?不是很清楚为什么。我可以确定的是只要是固定连接(网线那种或者开手机热点只给自己用那种),程序都可以获得MAC地址,但其他情况下就很迷。这个如果各位有想法可以在评论里与我交流。

至此本文结束!

References

[1] https://ubuntuforums.org/showthread.php?t=125444

[2] https://stackoverflow.com/questions/25583379/libpcap-not-linking-netbeans

[3] http://blog.csdn.net/wypblog/article/details/7456829

[4] http://blog.csdn.net/cheng_fangang/article/details/8608126

(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)

visitor tracker

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐