使用PF_PACKET和SOCK_RAW发送自定义type以太网数据包

本文介绍使用PF_PACKET和SOCK_RAW发送自定义type以太网数据包,使用wireshare抓包可以获取到数据包,为Linux内核增加网络协议做铺垫。

先上码:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>           // close()

#include <string.h>           // strcpy, memset(), and memcpy()

#include <netdb.h>            // struct addrinfo

#include <sys/types.h>        // needed for socket(), uint8_t, uint16_t, uint32_t

#include <sys/socket.h>       // needed for socket()

#include <netinet/in.h>       // IPPROTO_ICMP, INET_ADDRSTRLEN

#include <netinet/ip.h>       // struct ip and IP_MAXPACKET (which is 65535)

#include <netinet/ip_icmp.h>  // struct icmp, ICMP_ECHO

#include <arpa/inet.h>        // inet_pton() and inet_ntop()

#include <sys/ioctl.h>        // macro ioctl is defined

#include <bits/ioctls.h>      // defines values for argument "request" of ioctl.

#include <net/if.h>           // struct ifreq

#include <linux/if_ether.h>   // ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD

#include <linux/if_packet.h>  // struct sockaddr_ll (see man 7 packet)

#include <net/ethernet.h>

#include <errno.h>            // errno, perror()

#define ETH_P_DEAN 0x8874 //自定义的以太网协议type

int main (int argc, char **argv)

{

int i, datalen,frame_length, sd, bytes;

char *interface="eth1";;

uint8_t data[IP_MAXPACKET];

uint8_t src_mac[6];

uint8_t dst_mac[6];;

uint8_t ether_frame[IP_MAXPACKET];

struct sockaddr_ll device;

struct ifreq ifr;

// Submit request for a socket descriptor to look up interface.

if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {//第一次创建socket是为了获取本地网卡信息

perror ("socket() failed to get socket descriptor for using ioctl() ");

exit (EXIT_FAILURE);

}

// Use ioctl() to look up interface name and get its MAC address.

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

snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);

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

perror ("ioctl() failed to get source MAC address ");

return (EXIT_FAILURE);

}

close (sd);

// Copy source MAC address.

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

// Report source MAC address to stdout.

printf ("MAC address for interface %s is ", interface);

for (i=0; i<5; i++) {

printf ("%02x:", src_mac[i]);

}

printf ("%02x\n", src_mac[5]);

// Find interface index from interface name and store index in

// struct sockaddr_ll device, which will be used as an argument of sendto().

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

if ((device.sll_ifindex = if_nametoindex (interface)) == 0) {

perror ("if_nametoindex() failed to obtain interface index ");

exit (EXIT_FAILURE);

}

printf ("Index for interface %s is %i\n", interface, device.sll_ifindex);

// Set destination MAC address: you need to fill these out

dst_mac[0] = 0x10;//设置目的网卡地址

dst_mac[1] = 0x78;

dst_mac[2] = 0xd2;

dst_mac[3] = 0xc6;

dst_mac[4] = 0x2f;

dst_mac[5] = 0x89;

// Fill out sockaddr_ll.

device.sll_family = AF_PACKET;

memcpy (device.sll_addr, src_mac, 6);

device.sll_halen = htons (6);

// 发送的data,长度可以任意,但是抓包时看到最小数据长度为46,这是以太网协议规定以太网帧数据域部分最小为46字节,不足的自动补零处理

datalen = 12;

data[0] = ‘h‘;

data[1] = ‘e‘;

data[2] = ‘l‘;

data[3] = ‘l‘;

data[4] = ‘o‘;

data[5] = ‘ ‘;

data[6] = ‘w‘;

data[7] = ‘o‘;

data[8] = ‘r‘;

data[9] = ‘l‘;

data[10] = ‘d‘;

data[11] = ‘!‘;

// Fill out ethernet frame header.

frame_length = 6 + 6 + 2   + datalen;

// Destination and Source MAC addresses

memcpy (ether_frame, dst_mac, 6);

memcpy (ether_frame + 6, src_mac, 6);

ether_frame[12] = ETH_P_DEAN / 256;

ether_frame[13] = ETH_P_DEAN % 256;

// data

memcpy (ether_frame + 14 , data, datalen);

// Submit request for a raw socket descriptor.

if ((sd = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {//创建正真发送的socket

perror ("socket() failed ");

exit (EXIT_FAILURE);

}

// Send ethernet frame to socket.

if ((bytes = sendto (sd, ether_frame, frame_length, 0, (struct sockaddr *) &device, sizeof (device))) <= 0) {

perror ("sendto() failed");

exit (EXIT_FAILURE);

}

printf ("send num=%d,read num=%d\n",frame_length,bytes);

// Close socket descriptor.

close (sd);

return (EXIT_SUCCESS);

}

抓包获取:

下一章我们在Linux使用dev_add_pack添加此type的协议探测。

感谢David Buchan的网页提供的参考代码:

http://www.pdbuchan.com/rawsock/rawsock.html

使用PF_PACKET和SOCK_RAW发送自定义type以太网数据包,布布扣,bubuko.com

时间: 2024-08-11 07:48:33

使用PF_PACKET和SOCK_RAW发送自定义type以太网数据包的相关文章

使用PF_PACKET和SOCK_RAW发送自己定义type以太网数据包

本文介绍使用PF_PACKET和SOCK_RAW发送自己定义type以太网数据包,使用wireshare抓包能够获取到数据包,为Linux内核添加网络协议做铺垫. 先上码: #include <stdio.h> #include <stdlib.h> #include <unistd.h>           // close() #include <string.h>           // strcpy, memset(), and memcpy()

以太网数据包、IP包、TCP/UDP 包的结构(转)

源:以太网数据包.IP包.TCP/UDP 包的结构 版本号(Version):长度4比特.标识目前采用的IP协议的版本号.一般的值为0100(IPv4),0110(IPv6). IP包头长度(Header Length):长度4比特.这个字段的作用是为了描述IP包头的长度,因为在IP包头中有变长的可选部分.该部分占4个bit位,单位为32bit(4个字节),即本区域值 = IP头部长度(单位为bit)/ (8*4),因此,一个IP包头的长度最长为“1111”,即15*4=60个字节.IP包头最小

以太网 数据包速率计算方法

我们知道1个千兆端口的线速包转发率是1.4881MPPS, 百兆端口的线速包转发率是0.14881MPPS,这是国际标准,但是如何得来的呢? 具体的数据包在传输过程中会在每个包的前面加上64个(前导符)preamble也就是一个64个字节的数据包,原本只有512个bit,但在传输过程中实际上会有512+64+96=672bit,也就是这时一个数据包的长度实际上是有672bit的千兆端口线速包转发率=1000Mbps/672=1.488095Mpps,约等于1.4881Mpps,百兆除于10 为0

以太网,IP,TCP,UDP数据包分析

http://www.cnblogs.com/feitian629/archive/2012/11/16/2774065.html 1.ISO开放系统有以下几层: 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 2.TCP/IP 网络协议栈分为应用层(Application).传输层(Transport).网络层(Network)和链路层(Link)四层. 通信过程中,每层协议都要加上一个数据首部(header),称为封装(Encapsulation),如

Linux网络之设备接口层:发送数据包流程dev_queue_xmit

转自:http://blog.csdn.net/wdscq1234/article/details/51926808 写在前面 本文主要是分析kernel-3.8的源代码,主要集中在Network的netdevice层面,来贯穿interface传输数据包的流程,kernel 博大精深,这也仅仅是一点个人愚见,作为一个笔记形式的文章,如有错误或者表述不当之处,还请大家留言批评指正,非常感谢! 主要涉及的file:kernel-3.18/net/core/dev.c kernel-3.18/net

第四十四课、发送自定义事件(下)

一.自定义事件对象 1.Qt可以自定义新的事件类 (1).自定义的事件类必须继承自QEvent (2).自定义的事件类必须拥有全局唯一的Type值(event->type()可以获得事件的类型) (3).程序中必须提供处理自定义事件的方法 2.自定义事件类 (1).将QEvent作为父类继承 (2).指定全局唯一的Type值 3.Qt事件的Type值 (1).每个事件类都拥有全局唯一的Type值(类似于唯一的ID号) (2).自定义事件类的Type值也需要自定义 (3).自定义事件类使用QEve

第44课 发送自定义事件(下)

1. 自定义事件对象 (1)自定义事件类必须继承自QEvent (2)自定义的事件类必须拥有全局唯一的Type值 (3)程序中必须提供处理自定义事件对象的方法 2. 自定义事件类 (1)将QEvent作为父类继承 (2)指定全局唯一的Type值 class StringEvent: public QEvent { public: //提供全局唯一的Type值 static const Type TYPE = static_cast<Type>(QEvent::User + 0xFF); //.

第43课 发送自定义事件(上)

1. Qt中发送自定义事件 (1)阻塞型事件发送:事件发送后需要等待事件处理完成 (2)非阻塞型事件发送 ①事件发送后立即返回 ②事件被发送到事件队列中等待处理 2. QApplication类提供了支持事件发送的静态成员函数 (1)阻塞型发送函数 bool sendEvent(QObject* receiver, QEvent* event); (2)非阻塞型发送函数 void postEvent(QObject* receiver, QEvent* event); (3)注意事项 ①send

python利用企业微信api来进行发送自定义报警的类实现

python利用企业微信api来进行发送自定义报警的类实现 企业微信注册 打开http://work.weixin.qq.com/企业微信主页: 点击企业注册: 填写相关信息,营业执照和注册号可以不用填,直接下一步,按照提示操作即可: 注册完成后,登陆,就显示如下界面: 点击我的企业标签: 看到如上界面,复制CorpID对应的值: 点击企业应用: 点击 创建应用: 填写对应内容,点击创建应用即可: 然后再点击企业应用,就可以在自建应用里看到自己创建的应用: 点击应用图标,看到如下图 复制Agen