原始套接字SOCK_RAW

转载 2015年11月18日 11:54:28

实际上,我们常用的网络编程都是在应用层的报文的收发操作,也就是大多数程序员接触到的流式套接字(SOCK_STREAM)和数据包式套接字(SOCK_DGRAM)。而这些数据包都是由系统提供的协议栈实现,用户只需要填充应用层报文即可,由系统完成底层报文头的填充并发送。然而在某些情况下需要执行更底层的操作,比如修改报文头、避开系统协议栈等。这个时候就需要使用其他的方式来实现。

 

一 原始套接字

原始套接字(SOCK_RAW)是一种不同于SOCK_STREAMSOCK_DGRAM的套接字,它实现于系统核心。然而,原始套接字能做什么呢?首先来说,普通的套接字无法处理ICMPIGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。总体来说,SOCK_RAW可以处理普通的网络报文之外,还可以处理一些特殊协议报文以及操作IP层及其以上的数据。

既然SOCK_RAW有以上特性,所以在某些处理流程上它区别于普通套接字。

·  若设置IP_HDRINCL选项,SOCK_RAW可以操作IP头数据(也就是用户需用填充IP头及其以上的payload);否则SOCK_RAW无法操作IP头数据

·  端口对于SOCK_RAW而言没有任何意义

·  如果使用bind函数绑定本地IP,那么如果IP_HDRINCL未设置,则用此IP填充源IP地址;若不调用bind则将源IP地址设置为外出接口的主IP地址

·  如果使用connect函数设置目标IP,则可以使用send或者write函数发送报文,而不需要使用sendto函数

·  内核处理流程:

·  接收到的TCPUDP分组不会传递给任何SOCK_RAW

· ICMPIGMP报文分组传递给SOCK_RAW

· 内核不识别的IP报文传递给SOCK_RAW

·  SOCK_RAW是否接收报文:

·     Protocol指定类型需要匹配,否则不传递给该SOCK_RAW

·       如果使用bind函数绑定了源IP,则报文目的IP必须和绑定的IP匹配,否则不传递给该SOCK_RAW

·       如果使用connect函数绑定了目的IP,则报文源IP必须和指定的IP匹配,否则不传递给该SOCK_RAW 


综上所述,原始套接字处理的只是IP层及其以上的数据,比如实现SYN FLOOD攻击、处理PING报文等。当需要操作更底层的数据的时候,就需要采用其他的方式。

二 链路层处理报文

如果需要从链路层处理报文,那么就需要采用更加底层的套接字。还是先看下套接字函数的原型吧:

#include <sys/socket.h>

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

这个函数中,domain表示协议簇,type表示套接字类型,而protocol表示的是处理的协议类型。在Linux下提供了多种底层套接字。下面分别进行简单介绍。

1 PF_INET协议簇

通过PF_INET可以构造原始套接字,如下所示:

int fd = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);

正如前面所讲的,它工作在IP层及其以上各层协议上(当然是在使用IP_HDRINCL选项之后才能操作IP层数据啦),但是这种套接字无法接收从本地发送出去的报文。而使用SOCK_PACKET类型的套接字,则可以操作链路层数据了:

int fd = socket (PF_INET, SOCK_PACKET, IPPROTO_TCP);

不过据说这种方式存在一定的缺陷,而且也不能保证后续版本的系统上一定支持这种方式,因此不推荐使用

2 PF_PACKET协议簇

PF_PACKET协议簇是用来取代SOCK_PACKET的一种编程接口。作为一种协议簇,它可以对应两种不同的套接字类型:SOCK_RAWSOCK_DGRAM。当使用SOCK_RAW时,用户操作链路层数据,但是如果使用后者,则由系统处理链路层协议头。这种套接字支持四种协议(ETH_P_IPETH_P_ARPETH_P_RARPETH_P_ALL)(未确认)

int fd = socket (PF_PACKET, SOCK_RAW, IPPROTO_TCP);

int fd = socket (PF_PACKET, SOCK_DGRAM, IPPROTO_TCP);

3 NETLINK协议簇

这种方式是用户模式和kernelIP网络配置之间的推荐接口


 

综上所述,真正能够实现操作链路层数据的只有三种方式:

int fd = socket (PF_INET, SOCK_PACKET, IPPROTO_TCP);

int fd = socket (PF_PACKET, SOCK_RAW, IPPROTO_TCP);

int fd = socket (PF_PACKET, SOCK_DGRAM, IPPROTO_TCP);

Linux下使用原始套接字实现ping命令

客户端程通过透明代理访问远程服务器,代理需要以SNAT去修改源地址源端口,一般写法是Add SNAT、Connect、Del SNAT; 那么问题来了,加SNAT规则时需要 -s $ip --spor...
  • stayneckwind2
  • stayneckwind2
  • 2016年11月09日 23:16
  • 771

浅谈原始套接字 SOCK_RAW 的内幕及其应用(port scan, packet sniffer, syn flood, icmp flood)

一、SOCK_RAW 内幕 首先在讲SOCK_RAW 之前,先来看创建socket 的函数: int socket(int domain, int type, int protocol); doma...
  • Simba888888
  • Simba888888
  • 2013年10月07日 16:30
  • 15978

linux sock_raw原始套接字编程 (转)和Linux下Libpcap源码分析和包过滤机制

sock_raw原始套接字编程可以接收到本机网卡上的数据帧或者数据包,对与监听网络的流量和分析是很有作用的.一共可以有3种方式创建这种 socket 1.socket(AF_INET, SOCK_...
  • seven407
  • seven407
  • 2010年10月25日 14:50
  • 1000

Linux C raw_socket (原始套接字)

我们平常所用到的网络编程都是在应用层收发数据,每个程序只能收到发给自己的数据,即每个程序只能收到来自该程序绑定的端口的数据。收到的数据往往只包括应用层数据。某些情况下我们需要执行更底层的操作,比如监听...
  • zgrjkflmkyc
  • zgrjkflmkyc
  • 2014年09月11日 15:46
  • 8738

[LWIP学习]--原始套接字(SOCK_RAW)

...
  • Ivan804638781
  • Ivan804638781
  • 2017年08月31日 14:49
  • 204

原始套接字SOCK_RAW

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

网络编程原始套接字SOCKET_RAW

SOCKET_STREAM 流式套接字      SOCKET_DGRAM        SOCKET_RAW 原始套接字    IPPROTO_IP IP协议    IPPR...
  • Beyond_cn
  • Beyond_cn
  • 2015年03月30日 20:44
  • 2628

Linux原始套接字实现分析

本文从IPV4协议栈原始套接字的分类入手,详细介绍了链路层和网络层原始套接字的特点及其内核实现细节。并结合原始套接字的实际应用,说明各类型原始套接字的适应范围,以及在实际使用时需要注意的问题。 一...
  • gold0523
  • gold0523
  • 2014年05月02日 12:57
  • 3260

原始套接字(SOCK_RAW)概述[转载]

大多数程序员所接触到的套接字(Socket)为两类:   (1)流式套接字(SOCK_STREAM):一种面向连接的Socket,针对于面向连接的TCP服务应用;   (2)数据报式套接字...
  • tjcwt2011
  • tjcwt2011
  • 2017年08月16日 16:52
  • 63

利用原始套接字(SOCK_RAW)对ip数据进行监听

  • Suprman
  • Suprman
  • 2006年07月27日 10:27
  • 1988
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:原始套接字SOCK_RAW
举报原因:
原因补充:

(最多只允许输入30个字)