原始套接字编程和之前的 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. 前端项目中常用es6知识总结 -- Async、Await让异步美如画

    项目开发中一些常用的es6知识,主要是为以后分享小程序开发.node+koa项目开发以及vueSSR(vue服务端渲染)做个前置铺垫. 项目开发常用es6介绍 1.块级作用域 let const 2. ...

  2. Spring RootBeanDefinition,ChildBeanDefinition,GenericBeanDefinition

    转自:https://blog.csdn.net/joenqc/article/details/68942972 RootBeanDefinition,ChildBeanDefinition,Gene ...

  3. 前端切图|点击按钮div变色

    <!DOCTYPE html> <html> <head> <title>点击按钮div变色.html</title> <meta c ...

  4. js进阶 13-5 jquery队列动画如何实现

    js进阶 13-5 jquery队列动画如何实现 一.总结 一句话总结:同一个jquery对象,直接写多个animate()就好. 1.什么是队列动画? 比如说先左再下,而不是左下一起走 2.怎么实现 ...

  5. Flask项目之手机端租房网站的实战开发(二)

    说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! 接着上一篇博客继续往下写 :https://blog.csdn.net/qq_41782425/article/details/8 ...

  6. PythonAdvanced

    PythonAdvanced function 函数 (要多使用函数,方便,少变量,好改错) 函数是可以重复执行的语句块,可以重复使用 作用: 1.用于封装语句块,提高代码的重用性 2.定义用户级别的 ...

  7. DC针对pipeline的优化

    set_optimize_register    true compile  -ultra 调整pipleline各级的组合逻辑,使得各级组合逻辑的延迟跟接近 对非pipeline进行优化: regi ...

  8. FTP 访问的形式

    主要是扼要的列举一下访问的方式,不涉及太具体的内容.大家可以在百度上搜索一下具体的操作方法. 主要有: 1. 网页浏览器中输入 ftp://192.168.0.111的形式. 2. 资源管理器中输入f ...

  9. 第三方插件将数据转成json

    1.需要使用第三方jar commons-beanutils-1.7.0.jar /commons-collections-3.1.jar/commons-lang-2.5jar /commons-l ...

  10. vue指令概览

    原文 简书原文:https://www.jianshu.com/p/5fd47b7422fd 大纲 1.什么是vue指令 2.向指令中传入参数 3.指令中带入修饰符 4.指令的缩写 5.常见的vue指 ...