原始套接字编程和之前的 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. 从数据库中生成XML文件

    前台页面<%@ page language="java" contentType="text/html; charset=utf-8" pageEncod ...

  2. ecshop微信接口基础认识

    ecshop微信接口基础认识,当你要学习ecshop和微信整合的时候,你就必须研究ecshop的数据结构对接以及微信数据接口的基本知识.我们知道微信其实就是通过有效的消息推送,用JSON格式的数据或者 ...

  3. 对象的序列化与反序列化---IO学习笔记(四)

    对象的序列化,反序列化 对象的序列化: 就是将Object转换成byte序列 对象的反序列化: 将byte序列转换成Object 序列化流.反序列化流 序列化流(ObjectOutputStream) ...

  4. bootstrap课程8 bootstrap导航条在不同设备上的显示效果如何

    bootstrap课程8 bootstrap导航条在不同设备上的显示效果如何(多去看参考手册) 一.总结 一句话总结:在手机端或者平板端或者显示不够的话就缩起来了.(多去看参考手册) 二.bootst ...

  5. docker网络访问

    一 docker网络访问 描述: 在启动容器的时候,如果不指定对应的参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的.当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-P或者-p ...

  6. socket TCP简单通讯

    socket 服务器 // // main.m // socket_server // // Created by lujunjie on 2016/11/23. // Copyright © 201 ...

  7. JQuery 各节点获取函数:父节点,子节点,兄弟节点

    jQuery.parent(expr)           //找父元素 jQuery.parents(expr)          //找到所有祖先元素,不限于父元素 jQuery.children ...

  8. 软件——protel 的pcb电路图制作

    近期一直在学习PCB板的绘制.

  9. 学习笔记:Vue——动态组件&异步组件

    动态组件 01.在动态组件上使用keep-alive,保持组件的状态,以避免反复重渲染导致的性能问题. <!-- 失活的组件将会被缓存!--> <keep-alive> < ...

  10. postman--基本使用1

    本文转自:http://blog.csdn.net/five3/article/details/53021084 HTTP的接口测试工具有很多,可以进行http请求的方式也有很多,但是可以直接拿来就用 ...