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

一: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

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

structifreq ifr;

strncpy(ifr.ifr_name, name, 6);

if(ioctl(sock, SIOCGIFHWADDR, &ifr) 

perror("get_hwaddr ioctl:");

close(sock);

return-1;

}

struct ifreq ifr;

strncpy(ifr.ifr_name, name, 6);

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

perror("get_hwaddr ioctl:");

close(sock);

return -1;

}

以下是一个实现:

intget_hwaddr(char*name, unsignedchar*hwaddr)

{

structifreq ifr;

unsignedcharmemzero[6];

intsock;

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

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

return-1;

}

sock = socket(AF_INET, SOCK_STREAM, 0);

if(sock 

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) 

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

return0;

}

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,用于发送自定义数据报:

intsock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

if(sock 

perror("sock");

return-1;

}

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地址。

发送数据包:

structsockaddr_ll sll;

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

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

if(sendto(sock, packet_start,sizeofpacket_start, 0, &sll,sizeof(sll)) 

perror("sendto");

return1;

}

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

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

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

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

完整的源码:

#include 

#include 

#include 

#include 

#include 

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

#include 

#include 

#else

#include 

#include 

#include 

#endif

#include 

#include 

#include 

#include 

#include 

#define _PATH_PROCNET_DEV "/proc/net/dev"

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

{

while(isspace(*p))

p++;

while(*p) {

if(isspace(*p))

break;

if(*p ==':') {

char*dot = p, *dotname = name;

*name++ = *p++;

while(isdigit(*p))

*name++ = *p++;

if(*p !=':') {

p = dot;

name = dotname;

}

if(*p =='\0')

returnNULL;

p++;

break;

}

*name++ = *p++;

}

*name++ ='\0';

returnp;

}

staticintread_netdev_proc(void*devname,constintnum,constintlen)

{

FILE*fh;

charbuf[512];

intcnt = 0;

char*dev = (char*)devname;

if(devname == NULL || num 

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,sizeofbuf, fh);

fgets(buf,sizeofbuf, fh);

cnt = 0;

while(fgets(buf,sizeofbuf, fh) && cnt 

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

return0;

}

intget_hwaddr(char*name, unsignedchar*hwaddr)

{

structifreq ifr;

unsignedcharmemzero[6];

intsock;

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

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

return-1;

}

sock = socket(AF_INET, SOCK_STREAM, 0);

if(sock 

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) 

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

return0;

}

unsignedcharpacket_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

};

voidprinthex(void*hex,intlen,char*tag)

{

inti;

unsignedchar*p = (unsignedchar*)hex;

if(len 

return;

for(i = 0; i 

if(*p 

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

else

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

}

if(*p 

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

else

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

}

intmain(intargc,char**argv)

{

inti;

unsignedcharhwaddr[6];

chardevname[3][7];

unsignedcharbuf[1024];// for revevied packet

intret;

read_netdev_proc(devname, 3, 7);

for(i = 0; i 

//empty

}

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

printhex(hwaddr, 6,":");

intsock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

if(sock 

perror("sock");

return-1;

}

structsockaddr_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,sizeofpacket_start, 0, &sll,sizeof(sll)) 

perror("sendto");

return1;

}

printf("Sendto Success!\n");

sleep(1);

}

while(argc == 2){

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

printf("recv: ");

printhex(buf, ret," ");

}

return0;

}

#include

#include

#include

#include

#include

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

#include

#include

#else

#include

#include

#include

#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 == ':') {

char *dot = p, *dotname = name;

*name++ = *p++;

while (isdigit(*p))

*name++ = *p++;

if (*p != ':') {

p = dot;

name = dotname;

}

if (*p == '\0')

return NULL;

p++;

break;

}

*name++ = *p++;

}

*name++ = '\0';

return p;

}

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

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;

}

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;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值