一:linux下的网络设备

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

root@dlrc-desktop:/home/dlrc/dlsp-ep9302/work/mystar-v0.4# cat /proc/net/dev

Inter-| Receive | Transmit

face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop

lo: 472252 1696 0 0 0 0 0 0 472252 1696 0 0 0 0 0 0

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获取设备信息。

struct ifreq ifr;

strncpy(ifr.ifr_name, name, 6);

if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0){

perror("get_hwaddr ioctl:");

close(sock);

return -1;

}

以下是一个实现:

/**

* get_hwaddr - get netdevice mac addr

* @name: device name, e.g: eth0

* @hwaddr: where to save mac, 6 byte hwaddr[6]

* @return: 0 on success, -1 on failure

*/

int get_hwaddr(char *name, unsigned char *hwaddr)

{

struct ifreq ifr;

unsigned char memzero[6];

int sock;

if(name == NULL || hwaddr == NULL){

printf("get_hwaddr: NULL para\n");

return -1;

}

sock = socket(AF_INET, SOCK_STREAM, 0);

if(sock < 0){

printf("get_hwaddr: socket error\n");

//return -1;

}

//get eth1 mac addr

memset(hwaddr, 0, 6);

memset(&ifr, 0, sizeof(ifr));

strncpy(ifr.ifr_name, name, 6);

if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0){

perror("get_hwaddr ioctl:");

close(sock);

return -1;

} else {

memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);

//printf("hwaddr: %2x : %2x : %2x : %2x : %2x : %2x\n", hwaddr[0], hwaddr[1],hwaddr[2], hwaddr[3],hwaddr[4], hwaddr[5]);

}

memset(memzero, 0, 6);

if(memcmp(memzero, hwaddr, 6) == 0){

printf("no mac\n");

return -1;

}

close(sock);

return 0;

}

三:发送底层网络数据包

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

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

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

int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

if(sock < 0){

perror("sock");

return -1;

}

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

发送数据包:

struct sockaddr_ll sll;

memset(&sll, 0, sizeof(sll));

sll.sll_ifindex = 2; // 指定网卡

if (sendto(sock, packet_start, sizeof packet_start, 0, &sll, sizeof(sll)) < 0){

perror("sendto");

return 1;

}

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

接收这类的数据包:

ret = recvfrom(sock, buf, 1024, 0, NULL, NULL);

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

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

完整的源码:

/*

* socket.c

*

* Copyright (C) 2011 crazyleen

*

*/

#include

#include

#include

#include

#include /* for the glibc version number */

#if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1

#include

#include /* the L2 protocols */

#else

#include

#include

#include /* The L2 protocols */

#endif

#include

#include

#include

#include

#include

#define _PATH_PROCNET_DEV "/proc/net/dev"

static char *get_name(char *name, char *p)

{

while (isspace(*p))

p++;

while (*p) {

if (isspace(*p))

break;

if (*p == ':') {/* could be an alias */

char *dot = p, *dotname = name;

*name++ = *p++;

while (isdigit(*p))

*name++ = *p++;

if (*p != ':') {/* it wasn't, backup */

p = dot;

name = dotname;

}

if (*p == '\0')

return NULL;

p++;

break;

}

*name++ = *p++;

}

*name++ = '\0';

return p;

}

/**

* read_netdev_proc - read net dev names form proc/net/dev

* @devname: where to store dev names, devname[num][len]

*/

static int read_netdev_proc(void *devname, const int num, const int len)

{

FILE *fh;

char buf[512];

int cnt = 0;

char *dev = (char *)devname;

if(devname == NULL || num < 1 || len < 4){

printf("read_netdev_proc: para error\n");

return -1;

}

memset(devname, 0, len * num);

fh = fopen(_PATH_PROCNET_DEV, "r");

if (!fh) {

fprintf(stderr, "Warning: cannot open %s (%s). Limited output.\n",

_PATH_PROCNET_DEV, strerror(errno));

return -1;

}

fgets(buf, sizeof buf, fh);/* eat two line */

fgets(buf, sizeof buf, fh);

cnt = 0;

while (fgets(buf, sizeof buf, fh) && cnt < num) {

char *s, name[IFNAMSIZ];

s = get_name(name, buf);

strncpy(devname, name, len);

devname += len;

printf("get_name: %s\n", name);

}

if (ferror(fh)) {

perror(_PATH_PROCNET_DEV);

}

fclose(fh);

return 0;

}

/**

* get_hwaddr - get netdevice mac addr

* @name: device name, e.g: eth0

* @hwaddr: where to save mac, 6 byte hwaddr[6]

* @return: 0 on success, -1 on failure

*/

int get_hwaddr(char *name, unsigned char *hwaddr)

{

struct ifreq ifr;

unsigned char memzero[6];

int sock;

if(name == NULL || hwaddr == NULL){

printf("get_hwaddr: NULL para\n");

return -1;

}

sock = socket(AF_INET, SOCK_STREAM, 0);

if(sock < 0){

printf("get_hwaddr: socket error\n");

//return -1;

}

//get eth1 mac addr

memset(hwaddr, 0, 6);

memset(&ifr, 0, sizeof(ifr));

strncpy(ifr.ifr_name, name, 6);

if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0){

perror("get_hwaddr ioctl:");

close(sock);

return -1;

} else {

memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);

//printf("hwaddr: %2x : %2x : %2x : %2x : %2x : %2x\n", hwaddr[0], hwaddr[1],hwaddr[2], hwaddr[3],hwaddr[4], hwaddr[5]);

}

memset(memzero, 0, 6);

if(memcmp(memzero, hwaddr, 6) == 0){

printf("no mac\n");

return -1;

}

close(sock);

return 0;

}

unsigned char packet_start[]={

0xff, 0xff, 0xff, 0xff, 0xff, 0xff,//dst mac

0x00, 0x23, 0x54, 0x0e, 0xe5, 0xd8,//src mac

0x88, 0x8e, //Type: 802.1x authentication

0x01, //Version:v1

0x01, //Type: Start (1)

0x00, 0x00//Length 0

};

void printhex(void *hex, int len, char *tag)

{

int i;

unsigned char *p = (unsigned char *)hex;

if(len < 1)

return;

for(i = 0; i < len - 1; i++){

if(*p < 0x10)

printf("0%x%s", *p++, tag);

else

printf("%2x%s", *p++, tag);

}

if(*p < 0x10)

printf("0%x\n", *p++);

else

printf("%2x\n", *p++);

}

int main(int argc, char **argv)

{

int i;

unsigned char hwaddr[6];

char devname[3][7];

unsigned char buf[1024]; // for revevied packet

int ret;

read_netdev_proc(devname, 3, 7);

for(i = 0; i < 3 && get_hwaddr(devname[i], hwaddr) != 0; i++){

//empty

}

printf("devname: [ %s ]\t", devname[i]);

printhex(hwaddr, 6, ":");

int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

if(sock < 0){

perror("sock");

return -1;

}

struct sockaddr_ll sll;

memset(&sll, 0, sizeof(sll));

sll.sll_ifindex = 2; // It seems only need this to specify which NIC to use

memcpy(packet_start + 6, hwaddr, 6);

//memcpy(packet_start, hwaddr, 6);

while(argc == 1){

if (sendto(sock, packet_start, sizeof packet_start, 0, &sll, sizeof(sll)) < 0){

perror("sendto");

return 1;

}

printf("Sendto Success!\n");

sleep(1);

}

while(argc == 2){

ret = recvfrom(sock, buf, 1024, 0, NULL, NULL);

printf("recv: ");

printhex(buf, ret, " ");

}

return 0;

}

linux获取网卡协议地址,读取linux下的网络设备的mac地址与发送原始数据包 (2011-11-23 20:11)...相关推荐

  1. linux临时配置mac地址,Linux获取网卡型号、mac地址、修改IP地址的几种方法

    1.获取所有有(无)网卡型号 方法一.ifconfig 用法:ifconfig | grep | cut -d ':' -f 1 ubuntu root@ubuntu:~# ifconfig | gr ...

  2. linux下c语言使用mac地址进行socket通信

    linux下c语言使用mac地址进行socket通信 server端: #include <unistd.h> #include <stdio.h> #include < ...

  3. linux 获取网卡接口信息

    linux 获取网卡接口信息 获取本机所有网卡名称 struct ifreq ioctl 头文件 获取网卡信息 获取本机所有网卡名称 // /usr/include/net/if.h, 头文件 < ...

  4. VMWarevSphere Client 克隆虚拟机、变更IP地址、变更主机名、修改MAC地址

    VMWarevSphere Client 克隆虚拟机.变更IP地址.变更主机名.修改MAC地址 vSphere 是VMware公司推出一套服务器虚拟化解决方案 一.VMWarevSphere Clie ...

  5. [H3C]配置命令之MAC地址表项应用:封禁MAC地址

    MAC(Media Access Control,媒体访问控制)地址表记录了 MAC 地址与接口的对应关系,以及接口所属的 VLAN 等信息.设备在转发报文时,根据报文的目的 MAC 地址查询 MAC ...

  6. 2022-09-07 网工进阶(三十)以太网交换安全-端口隔离、MAC地址表安全、端口安全、MAC地址漂移防止与检测、链路层安全、流量抑制、风暴控制、IPSG(IP Source Guard)

    概述 目前网络中以太网技术的应用非常广泛.然而,各种网络攻击的存在,不仅造成了网络合法用户无法正常访问网络资源,而且对网络信息安全构成严重威胁,因此以太网交换的安全性越来越重要. 端口隔离 大型网络中 ...

  7. sql server2008如何修改mac地址_如何查看本机的MAC地址和IP地址?

    MAC地址是每台电脑或是手机设备中唯一进行识别的编码,IP地址则是路由器分配给电脑或是手机设备联网使用的一个编码.当我们电脑或无法上网,都需要查看IP地址是否正确.那如何查看MAC地址和IP地址呢? ...

  8. linux c 获取mac地址吗,Linux系统下用C语言获取MAC地址

    最近在做一个小程序,需要用到在linux系统里编写C程序从而获取MAC地址,从网上搜了一遍,想总结一下.如果你就只需要单个功能的程序,可以采用方法一,见代码1,一般最好能够封装起来,写成获取MAC地址 ...

  9. Linux多网卡不通网段,[转载]linux环境下,双网卡配置不同网段后,路由问题

    最近,新上线了10几台服务器,系统是centos 6.0 按照以前的惯例,配置服务器生产网络和维护网络.每台服务器的eth0 配置ip为生产网络,eth3配置为维护网络,生产网络和维护网络,物理上隔离 ...

最新文章

  1. 【Spring boot 实战】使用Maven插件构建Docker镜像
  2. .classpath文件
  3. “ yield”关键字有什么作用?
  4. CTFshow php特性 web93
  5. 不小心关闭了explorer.exe进程,桌面变白解决办法
  6. 深度技术揭秘 | 大促狂欢背后,如何有效评估并规划数据库计算资源?
  7. Object category automatic search
  8. Spring MVC研究之MVC pure string response debug
  9. Cent OS yum 安装 Adobe flash player
  10. [数据结构]Map和Set
  11. python3输入输出_Python3 输入和输出
  12. JavaScript重难点解析5(对象高级、浏览器内核与事件循环模型(js异步机制))
  13. 怎样填充潘通颜色_怎样判定润滑脂,锂基脂的好坏?
  14. vue day13 网易云项目(歌词)
  15. AWVS扫描器使用入门
  16. snownlp 原理_使用snownlp进行情感分析
  17. java上传文件服务器_java 实现文件上传到另一台服务器
  18. 微信公众号第三方平台授权流程
  19. 手把手教你DIY一款属于自己的万能红外遥控器!
  20. 亚马逊将为语音助手研发AI芯片 欲追赶苹果

热门文章

  1. 实验2:MIPS指令系统和MIPS体系结构
  2. python代码实现进制转换
  3. tar tar.gz
  4. React Reconciler
  5. Java 深入掌握JMS:JSM基础
  6. python中redis incr的使用
  7. CPNTools入门
  8. 计算机执行管理任务时,管理Active Directory用户和计算机
  9. Java-File文件操作
  10. 使用Git向Github上传项目(包含大文件>25mb)