原始套接字编程和之前的 UDP 编程差不多,无非就是创建一个套接字后,通过这个套接字接收数据或者发送数据。区别在于,原始套接字可以自行组装数据包(伪装本地 IP,本地 MAC),可以接收本机网卡上所有的数据帧(数据包)。另外,必须在管理员权限下才能使用原始套接字。

 
原始套接字的创建:

int socket ( int family, int type, int protocol );

参数:
  family:协议族 这里写 PF_PACKET
  type:  套接字类,这里写 SOCK_RAW
  protocol:协议类别,指定可以接收或发送的数据包类型,不能写 “0”,取值如下,注意,传参时需要用 htons() 进行字节序转换。

  ETH_P_IP:IPV4数据包
  ETH_P_ARP:ARP数据包
  ETH_P_ALL:任何协议类型的数据包

返回值:
  成功( >0 ):套接字,这里为链路层的套接字
  失败( <0 ):出错

实例如下:

 // 所需头文件
#include <sys/socket.h>
#include <netinet/ether.h>
#include <stdio.h> // perror int main(int argc,char *argv[])
{
int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) ); if(sock_raw_fd < ){
perror("socket");
return -;
} return ;
}

获取链路层的数据包:

ssize_t recvfrom( int sockfd,
          void *buf,
          size_t nbytes,
          int flags,
          struct sockaddr *from,
          socklen_t *addrlen );

参数:

  sockfd: 原始套接字
  buf: 接收数据缓冲区
  nbytes: 接收数据缓冲区的大小

  flags: 套接字标志(常为0)

  from: 这里没有用,写 NULL

  addrlen:这里没有用,写 NULL

返回值:
  成功:接收到的字符数
  失败:-1

实例如下:

 #include <stdio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/ether.h> int main(int argc,char *argv[])
{
unsigned char buf[] = {};
int sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); //获取链路层的数据包
int len = recvfrom(sock_raw_fd, buf, sizeof(buf), , NULL, NULL);
printf("len = %d\n", len); return ;
}

混杂模式

  默认的情况下,我们接收数据,目的地址是本地地址,才会接收。有时候我们想接收所有经过网卡的所有数据流,而不论其目的地址是否是它,这时候我们需要设置网卡为混杂模式

  网卡的混杂模式一般在网络管理员分析网络数据作为网络故障诊断手段时用到,同时这个模式也被网络黑客利用来作为网络数据窃听的入口。在 Linux 操作系统中设置网卡混杂模式时需要管理员权限。在 Windows 操作系统和 Linux 操作系统中都有使用混杂模式的抓包工具,比如著名的开源软件 Wireshark。

通过命令给 Linux 网卡设置混杂模式(需要管理员权限)

设置混杂模式:ifconfig eth0 promisc

取消混杂模式:ifconfig eth0 -promisc

通过代码给 Linux 网卡设置混杂模式

代码如下:

 struct ifreq ethreq;    //网络接口地址

 strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);            //指定网卡名称
if(- == ioctl(sock_raw_fd, SIOCGIFINDEX, &ethreq)) //获取网络接口
{
perror("ioctl");
close(sock_raw_fd);
exit(-);
} ethreq.ifr_flags |= IFF_PROMISC;
if(- == ioctl(sock_raw_fd, SIOCSIFINDEX, &ethreq)) //网卡设置混杂模式
{
perror("ioctl");
close(sock_raw_fd);
exit(-);
}

发送自定义的数据包:

ssize_t sendto( int sockfd,
        const void *buf,
        size_t nbytes,int flags,
        const struct sockaddr *to,
        socklen_t addrlen );

参数:

  sockfd: 原始套接字
  buf: 发送数据缓冲区
  nbytes: 发送数据缓冲区的大小

  flags: 一般为 0
  to: 本机网络接口,指发送的数据应该从本机的哪个网卡出去,而不是以前的目的地址
  addrlen:to 所指向内容的长度

返回值:
  成功:发送数据的字符数
  失败: -1

本机网络接口的定义

发送完整代码如下:

 struct sockaddr_ll sll;                    //原始套接字地址结构
struct ifreq ethreq; //网络接口地址 strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ); //指定网卡名称
if(- == ioctl(sock_raw_fd, SIOCGIFINDEX, ðreq)) //获取网络接口
{
perror("ioctl");
close(sock_raw_fd);
exit(-);
} /*将网络接口赋值给原始套接字地址结构*/
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex; // 发送数据
// send_msg, msg_len 这里还没有定义,模拟一下
int len = sendto(sock_raw_fd, send_msg, msg_len, , (struct sockaddr *)&sll, sizeof(sll));
if(len == -)
{
perror("sendto");
}

这里头文件情况如下:

 #include <net/if.h>// struct ifreq
#include <sys/ioctl.h> // ioctl、SIOCGIFADDR
#include <sys/socket.h> // socket
#include <netinet/ether.h> // ETH_P_ALL
#include <netpacket/packet.h> // struct sockaddr_ll

转自:http://blog.csdn.net/tennysonsky/article/details/44676377

Linux网络编程——原始套接字编程的更多相关文章

  1. Linux网络编程——原始套接字实例:MAC 头部报文分析

    通过<Linux网络编程——原始套接字编程>得知,我们可以通过原始套接字以及 recvfrom( ) 可以获取链路层的数据包,那我们接收的链路层数据包到底长什么样的呢? 链路层封包格式 M ...

  2. Linux Socket 原始套接字编程

    对于linux网络编程来说,可以简单的分为标准套接字编程和原始套接字编程,标准套接字主要就是应用层数据的传输,原始套接字则是可以获得不止是应用层的其他层不同协议的数据.与标准套接字相区别的主要是要开发 ...

  3. UNIX网络编程——原始套接字(dos攻击)

    原始套接字(SOCK_RAW).应用原始套接字,我们可以编写出由TCP和UDP套接字不能够实现的功能. 注意原始套接字只能够由有 root权限的人创建. 可以参考前面的博客<<UNIX网络 ...

  4. UNIX网络编程——原始套接字的魔力【续】

    如何从链路层直接发送数据帧 上一篇里面提到的是从链路层"收发"数据,该篇是从链路层发送数据帧. 上一节我们主要研究了如何从链路层直接接收数据帧,可以通过bind函数来将原始套接字绑 ...

  5. UNIX网络编程——原始套接字的魔力【上】

    基于原始套接字编程 在开发面向连接的TCP和面向无连接的UDP程序时,我们所关心的核心问题在于数据收发层面,数据的传输特性由TCP或UDP来保证: 也就是说,对于TCP或UDP的程序开发,焦点在Dat ...

  6. Linux网络编程——原始套接字能干什么?

    通常情况下程序员接所接触到的套接字(Socket)为两类: (1)流式套接字(SOCK_STREAM):一种面向连接的 Socket,针对于面向连接的TCP 服务应用: (2)数据报式套接字(SOCK ...

  7. LINUX 网络编程 原始套接字

    一 原始套接字 原始套接字(SOCK_RAW)是一种不同于SOCK_STREAM.SOCK_DGRAM的套接字,它实现于系统核心.然而,原始套接字能做什么呢?首先来说,普通的套接字无法处理ICMP.I ...

  8. 关于linux 原始套接字编程

    关于linux 网络编程最权威的书是<<unix网络编程>>,但是看这本书时有些内容你可能理解的不是很深刻,或者说只知其然而不知其所以然,那么如果你想搞懂的话那么我建议你可以看 ...

  9. UNIX网络编程——原始套接字SOCK_RAW

    实际上,我们常用的网络编程都是在应用层的报文的收发操作,也就是大多数程序员接触到的流式套接字(SOCK_STREAM)和数据包式套接字(SOCK_DGRAM).而这些数据包都是由系统提供的协议栈实现, ...

随机推荐

  1. BZOJ2434: [Noi2011]阿狸的打字机(fail树+dfs序)

    Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的 ...

  2. yarn的安装和使用

    yarn的简介: Yarn是facebook发布的一款取代npm的包管理工具. yarn的特点: 速度超快. Yarn 缓存了每个下载过的包,所以再次使用时无需重复下载. 同时利用并行下载以最大化资源 ...

  3. PatentTips - Interrupt redirection for virtual partitioning

    BACKGROUND The present disclosure relates to the handling of interrupts in a environment that utiliz ...

  4. Redmine安装

    http://www.itnpc.com/news/web/146433249372595.html http://www.cnblogs.com/iluzhiyong/p/redmine.html ...

  5. C# 依据KeyEventArgs与组合键字符串相互转换

    /// 快捷键相关的类 /// </summary> public static class HotKeyInfo { /// <summary> /// 依据KeyEvent ...

  6. curl如何发起DELETE/PUT请求

    curl如何发起DELETE/PUT请求 DELETE: curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); PUT: curl_setopt($ch ...

  7. metabase实施文档

    安装提前:需要安装JDK1.8以上 软件下载地址: https://metabase.com 还需要下载 ojdbc7.jar,以支持Oracle驱动 下载地址:http://www.oracle.c ...

  8. HTTP请求报文、响应报文

    HTTP请求报文 HTTP请求报文由3部分组成(请求行+请求头+请求体): 请求行:①是请求方法,GET和POST是最常见的HTTP方法,除此以外还包括DELETE.HEAD.OPTIONS.PUT. ...

  9. nodeJS+socket.io传递消息

    服务器端 安装express,socket.io npm install express --save-dev npm install socket.io --save app.js const ex ...

  10. input表单验证(全面)

    1.英文字母 1 <script type="text/javascript"> 2 //验证只能是字母 3 function checkZm(zm){ 4 var z ...