aw socket,即原始套接字,可以接收本机网卡上的数据帧或者数据包,对与监听网络的流量和分析是很有作用的,一共可以有3种方式创建这种socket。
中文名
原始套接字
外文名
RAW SOCKET
作    用
网卡对该数据帧进行硬过滤
类    型
3种方式
 

目录

  1. 简介
  2. 总结

简介编辑

1.socket(AF_INETSOCK_RAWIPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收ip数据包
2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧
3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))过时了,不要用啊
理解一下SOCK_RAW的原理, 比如网卡收到了一个 14+20+8+100+4 的udp的以太网数据帧.
首先,网卡对该数据帧进行硬过滤(根据网卡的模式不同会有不同的动作,如果设置了promisc混杂模式的话,则不做任何过滤直接交给下一层输入例程,否则非本机mac或者广播mac会被直接丢弃).按照上面的例子,如果成功的话,会进入ip输入例程.但是在进入ip输入例程之前,系统会检查系统中是否有通过socket(AF_PACKET, SOCK_RAW, ..)创建的套接字.如果有的话并且协议相符,在这个例子中就是需要ETH_P_IP或者ETH_P_ALL类型.系统就给每个这样的socket接收缓冲区发送一个数据帧拷贝.然后进入下一步.
其次,进入了ip输入例程(ip层会对该数据包进行软过滤,就是检查校验或者丢弃非本机ip或者广播ip的数据包等,具体要参考源代码),例子中就是如果成功的话会进入udp输入例程.但是在交给udp输入例程之前,系统会检查系统中是否有通过socket(AF_INET,SOCK_RAW, ..)创建的套接字.如果有的话并且协议相符,在这个例子中就是需要IPPROTO_UDP类型.系统就给每个这样的socket接收缓冲区发送一个数据帧拷贝.然后进入下一步.
最后,进入udp输入例程 ...
ps:如果校验和出错的话,内核会直接丢弃该数据包的.而不会拷贝给sock_raw的套接字,因为校验和都出错了,数据肯定有问题的包括所有信息都没有意义了.
进一步分析他们的能力.
1. socket(AF_INETSOCK_RAW, IPPROTO_UDP);
能:该套接字可以接收协议类型为(tcp udp icmp等)发往本机的ip数据包,从上面看的就是20+8+100.
不能:不能收到非发往本地ip的数据包(ip软过滤会丢弃这些不是发往本机ip的数据包).
不能:不能收到从本机发送出去的数据包.
发送的话需要自己组织tcp udp icmp等头部.可以setsockopt来自己包装ip头部
这种套接字用来写个ping程序比较适合
2. socket(PF_PACKET, SOCK_RAW, htons(x));
这个套接字比较强大,创建这种套接字可以监听网卡上的所有数据帧.从上面看就是20+20+8+100.最后一个以太网crc从来都不算进来的,因为内核已经判断过了,对程序来说没有任何意义了.
能: 接收发往本地mac的数据帧
能: 接收从本机发送出去的数据帧(第3个参数需要设置为ETH_P_ALL)
能: 接收非发往本地mac的数据帧(网卡需要设置为promisc混杂模式)
协议类型一共有四个
ETH_P_IP 0x800 只接收发往本机mac的ip类型的数据帧
ETH_P_ARP 0x806 只接受发往本机mac的arp类型的数据帧
ETH_P_RARP 0x8035 只接受发往本机mac的rarp类型的数据帧
ETH_P_ALL 0x3 接收发往本机mac的所有类型ip arp rarp的数据帧, 接收从本机发出的所有类型的数据帧.(混杂模式打开的情况下,会接收到非发往本地mac的数据帧)
3. socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL)),这个一般用于抓包程序。

总结编辑

1.只想收到发往本机某种协议的ip数据包的话用第一种就足够了
2. 更多的详细的内容请使用第二种.包括ETH_P_ALL参数和混杂模式都可以使它的能力不断的加强.
 

1.1 原始套接字工作原理与规则
         原始套接字是一个特殊的套接字类型,它的创建方式跟TCP/UDP创建方法几乎是
一摸一样,例如,通过

       int sockfd;
       sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP);

这两句程序你就可以创建一个原始套接字.然而这种类型套接字的功能却与TCP或者UDP类型套接字的功能有很大的不同:TCP/UDP类型的套接字只能够访问传输层以及传输层以上的数据,因为当IP层把数据传递给传输层时,下层的数据包头已经被丢掉了.而原始套接字却可以访问传输层以下的数据,,所以使用 raw套接字你可以实现上至应用层的数据操作,也可以实现下至链路层的数据操作.
         比如:通过

sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))

方式创建的raw socket就能直接读取链路层的数据.

1)使用原始套接字时应该注意的问题(参考<<unix网络编程>>以及网上的优秀文档)

(1):对于UDP/TCP产生的IP数据包,内核不将它传递给任何原始套接字,而只是将这些数据交给对应的UDP/TCP数据处理句柄(所以,如果你想要通过原始套接字来访问TCP/UDP或者其它类型的数据,调用socket函数创建原始套接字第三个参数应该指定为htons(ETH_P_IP),也就是通过直接访问数据链路层来实现.(我们后面的密码窃取器就是基于这种类型的).

(2):对于ICMP和EGP等使用IP数据包承载数据但又在传输层之下的协议类型的IP数据包,内核不管是否已经有注册了的句柄来处理这些数据,都会将这些IP数据包复制一份传递给协议类型匹配的原始套接字.

(3):对于不能识别协议类型的数据包,内核进行必要的校验,然后会查看是否有类型匹配的原始套接字负责处理这些数据,如果有的话,就会将这些IP数据包复制一份传递给匹配的原始套接字,否则,内核将会丢弃这个IP数据包,并返回一个ICMP主机不可达的消息给源主机.

(4): 如果原始套接字bind绑定了一个地址,核心只将目的地址为本机IP地址的数包传递给原始套接字,如果某个原始套接字没有bind地址,核心就会把收到的所有IP数据包发给这个原始套接字.

(5): 如果原始套接字调用了connect函数,则核心只将源地址为connect连接的IP地址的IP数据包传递给这个原始套接字.

(6):如果原始套接字没有调用bind和connect函数,则核心会将所有协议匹配的IP数据包传递给这个原始套接字.

2).编程选项
     原始套接字是直接使用IP协议的非面向连接的套接字,在这个套接字上可以调用bind和connect函数进行地址绑定.说明如下:

(1)bind函数:调用bind函数后,发送数据包的源IP地址将是bind函数指定的地址。如是不调用bind,则内核将以发送接口的主IP地址填充 IP头. 如果使用setsockopt设置了IP_HDRINCL(header including)选项,就必须手工填充每个要发送的数据包的源IP地址,否则,内核将自动创建IP首部.

(2)connetc函数:调用connect函数后,就可以使用write和send函数来发送数据包,而且内核将会用这个绑定的地址填充IP数据包的目的IP地址,否则的话,则应使用sendto或sendmsg函数来发送数据包,并且要在函数参数中指定对方的IP地址。

综合以上种种功能和特点,我们可以使用原始套接字来实现很多功能,比如最基本的数据包分析,主机嗅探等.其实也可以使用原始套接字作一个自定义的传输层协议.

 
直接上代码
 
 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net;

using System.Net.Sockets;

using log4net;
namespace test.test
{
public class RawSocket
{
private Socket _socket;
private IPAddress _address;
public Action<TcpPacket> OnTcpPacketCapture;
public Action<byte[], int> OnRawDataCapure;
ILog log = LogManager.GetLogger("ErrorLog");
public RawSocket(IPAddress address)
{
_address = address;
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);
_socket.Bind(new IPEndPoint(address, ));
} public bool Capture()
{
bool isOk = true;
try
{
_socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, );
byte[] inBytes = new byte[] { , , , };
byte[] outBytes = new byte[] { , , , };
_socket.IOControl(IOControlCode.ReceiveAll, inBytes, outBytes);
if ( != outBytes[] + outBytes[] + outBytes[] + outBytes[]) { isOk = false; }
}
catch (SocketException)
{
isOk = false;
} if (isOk)
{
while (true)
{
//以太网MTU 最大为1500 似乎1500会有错误
byte[] buffer = new byte[]; int count = _socket.Receive(buffer, SocketFlags.None); //if (OnRawDataCapure != null)
// OnRawDataCapure(buffer, count); //if (OnTcpPacketCapture != null)
{
IPPacket ip = new IPPacket(buffer, , count); if (ip.Protocol == IPProtocolType.UDP)
{
log.ErrorFormat(ip.ToString());
log.ErrorFormat(System.Text.Encoding.ASCII.GetString(ip.Data.Data));
//TcpPacket tcp = new TcpPacket(ip); // OnTcpPacketCapture(tcp);
}
}
}
} return isOk;
} public void Stop()
{
if (_socket != null)
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
}
} class SocketData
{
public Socket Socket { get; set; }
public Byte[] Data { get; set; }
} public class DataBuffer
{
public byte[] RawBuffer;
public int RawStart;
public int RawCount; private byte[] buffer;
private int start;
private int end;
public int Length { get { return end - start; } }
public byte this[int index] { get { return buffer[start + index]; } } public DataBuffer(byte[] data)
: this(data, , data.Length) { } public DataBuffer(byte[] data, int start, int count)
{
this.RawBuffer = this.buffer = data;
this.RawStart = this.start = start;
this.RawCount = count;
this.end = start + count;
} public void SetPosition(int position)
{
this.start += position;
} public byte[] Data
{
get
{
byte[] data = new byte[this.Length];
Array.Copy(this.buffer, this.start, data, , data.Length);
return data;
}
}
} public class IPPacket
{
public int Version; //版本号
public int HeadLen; //头长度
public int DiffServices; //区分服务
public int DataLen;//数据长度
public int Identification; //标志
public int Flag; //标识 3bit
public int Excursion;//片偏移 13bit
public byte TTL;//生存周期
public IPProtocolType Protocol; //协议
public int CheckSum; //校验和
public IPAddress SrcAddr; //源地址
public IPAddress DestAddr; //目标地址
public byte[] option; //选项
public DataBuffer Data; //IP Payload public IPPacket(byte[] data) : this(new DataBuffer(data)) { }
public IPPacket(byte[] data, int start, int count) : this(new DataBuffer(data, start, count)) { } public IPPacket(DataBuffer data)
{
Version = (data[] & 0xF0) >> ;
HeadLen = (int)(data[] & 0x0F) * ;
DiffServices = (int)data[];
DataLen = ((int)data[] << ) + (int)data[];
Identification = ((int)data[] << ) + (int)data[];
Flag = data[] >> ;
Excursion = (((int)data[] & 0x1F) << ) + (int)data[];
TTL = data[];
Protocol = (IPProtocolType)data[];
CheckSum = ((int)data[] << ) + (int)data[]; byte[] addr = new byte[];
for (int i = ; i < ; i++)
addr[i] = data[ + i];
SrcAddr = new IPAddress(addr); addr = new byte[];
for (int i = ; i < ; i++)
addr[i] = data[ + i];
DestAddr = new IPAddress(addr); //option
if (HeadLen > )
{
option = new byte[HeadLen - ];
for (int i = ; i < option.Length; i++)
option[i] = data[ + i]; //会包括填充部分
} data.SetPosition(HeadLen);
Data = data;
} public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("SrcAddr:{0} DestAddr={1}\r\n", SrcAddr.ToString(), DestAddr.ToString());
sb.AppendFormat("CheckSum: {0} Protocol:{1}\r\n", CheckSum, Protocol.ToString());
sb.AppendFormat("Version: {0} HeadLen:{1}\r\n", Version, HeadLen);
sb.AppendFormat("DataLen: {0} DiffServices:{1}\r\n", DataLen, DiffServices);
return sb.ToString();
}
} public class TcpPacket
{
public int SrcPort = ;//源端口
public int DestPort = ;//目标端口
public uint SequenceNo = ;//序号
public uint NextSeqNo = ;//确认号
public int HeadLen = ;//头长度
public int Flag = ;//控制位
public int WindowSize = ;//窗口
public int CheckSum = ;//校验和
public int UrgPtr = ;//紧急指针
public byte[] option;//选项
public IPPacket IPPacket;
public DataBuffer Data;
public byte[] Body { get { return Data.Data; } } public TcpPacket(byte[] data) : this(new IPPacket(new DataBuffer(data))) { }
public TcpPacket(byte[] data, int start, int count) : this(new IPPacket(new DataBuffer(data, start, count))) { } public TcpPacket(IPPacket packet)
{
if (packet.Protocol != IPProtocolType.TCP)
throw new NotSupportedException(string.Format("TcpPacket not support {0}", packet.Protocol));
this.IPPacket = packet; DataBuffer data = packet.Data;
SrcPort = ((int)data[] << ) + (int)data[];
DestPort = ((int)data[] << ) + (int)data[]; SequenceNo = ((uint)data[] << ) + ((uint)data[] << ) + ((uint)data[] << ) + ((uint)data[]);
NextSeqNo = ((uint)data[] << ) + ((uint)data[] << ) + ((uint)data[] << ) + ((uint)data[]); HeadLen = ((data[] & 0xF0) >> ) * ;
//6bit保留位
Flag = (data[] & 0x3F);
WindowSize = ((int)data[] << ) + (int)data[];
CheckSum = ((int)data[] << ) + (int)data[];
UrgPtr = ((int)data[] << ) + (int)data[];
//option
if (HeadLen > )
{
option = new byte[HeadLen - ];
for (int i = ; i < option.Length; i++)
option[i] = data[ + i]; //会包括填充部分
} data.SetPosition(this.HeadLen);
Data = data;
} public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("SrcPort:{0} DestPort={1}\r\n", SrcPort, DestPort);
sb.AppendFormat("SequenceNo:{0} NextSeqNo={1}\r\n", SequenceNo, NextSeqNo);
sb.AppendFormat("HeadLen:{0} Flag={1}\r\n", HeadLen, Flag);
sb.AppendFormat("WindowSize:{0} CheckSum={1}\r\n", WindowSize, CheckSum);
return sb.ToString();
}
} public enum IPProtocolType : byte
{
/// <summary> Dummy protocol for TCP. </summary>
IP = ,
/// <summary> IPv6 Hop-by-Hop options. </summary>
HOPOPTS = ,
/// <summary> Internet Control Message Protocol. </summary>
ICMP = ,
/// <summary> Internet Group Management Protocol.</summary>
IGMP = ,
/// <summary> IPIP tunnels (older KA9Q tunnels use 94). </summary>
IPIP = ,
/// <summary> Transmission Control Protocol. </summary>
TCP = ,
/// <summary> Exterior Gateway Protocol. </summary>
EGP = ,
/// <summary> PUP protocol. </summary>
PUP = ,
/// <summary> User Datagram Protocol. </summary>
UDP = ,
/// <summary> XNS IDP protocol. </summary>
IDP = ,
/// <summary> SO Transport Protocol Class 4. </summary>
TP = ,
/// <summary> IPv6 header. </summary>
IPV6 = ,
/// <summary> IPv6 routing header. </summary>
ROUTING = ,
/// <summary> IPv6 fragmentation header. </summary>
FRAGMENT = ,
/// <summary> Reservation Protocol. </summary>
RSVP = ,
/// <summary> General Routing Encapsulation. </summary>
GRE = ,
/// <summary> encapsulating security payload. </summary>
ESP = ,
/// <summary> authentication header. </summary>
AH = ,
/// <summary> ICMPv6. </summary>
ICMPV6 = ,
/// <summary> IPv6 no next header. </summary>
NONE = ,
/// <summary> IPv6 destination options. </summary>
DSTOPTS = ,
/// <summary> Multicast Transport Protocol. </summary>
MTP = ,
/// <summary> Encapsulation Header. </summary>
ENCAP = ,
/// <summary> Protocol Independent Multicast. </summary>
PIM = ,
/// <summary> Compression Header Protocol. </summary>
COMP = ,
/// <summary> Raw IP packets. </summary>
RAW = ,
/// <summary> IP protocol mask.</summary>
MASK = 0xff
}
}

使用RawSocket进行网络抓包的更多相关文章

  1. CatchPacket网络抓包软件

    CatchPacket网络抓包软件  qq  22945088431.技术特点:基于WinPcap库,c# winform2.实现获取机器所有网卡,可任意选择监听3.可以捕获常见网络协议arp dns ...

  2. 网络抓包wireshark(转)

    转自 网络抓包wireshark   抓包应该是每个技术人员掌握的基础知识,无论是技术支持运维人员或者是研发,多少都会遇到要抓包的情况,用过的抓包工具有fiddle.wireshark,作为一个不是经 ...

  3. 跨平台网络抓包工具-Microsoft Message Analyzer

    Microsoft Message Analyzer (MMA 2013)是微软最受欢迎的Netmon的最新版本. 在Netmon网络跟踪和排除故障功能的基础上提供了更强大的跨平台网络分析追踪能力.园 ...

  4. Microsoft Message Analyzer (微软消息分析器,“网络抓包工具 - Network Monitor”的替代品)官方正式版现已发布

    来自官方日志的喜悦 被誉为全新开始的消息分析器时代,由MMA为您开启,博客原文写的很激动,大家可以点击这里浏览:http://blogs.technet.com/b/messageanalyzer/a ...

  5. 网络抓包工具-Wireshark学习资料

    wireshark一个非常牛逼的网络抓包工具.转载一系列博文 一站式学习Wireshark(一):Wireshark基本用法 一站式学习Wireshark(二):应用Wireshark观察基本网络协议 ...

  6. 三种经典iPhone上网络抓包方法详解

    此文章来自:听云博客 很多时候需要网络抓包分析,在iPhone上抓包稍有不同,下面介绍三种常用的方式.分析工具以wireshark为例. 一.最简单的方式:用PC作为热点,在PC上抓包 优点:简单 缺 ...

  7. HttpWatch网络抓包工具的使用

    HttpWatch网络抓包工具是专为IE浏览器集成的一款网络拽包工具.   是一款强大的网页数据分析软件,是最好用的抓包工具,httpwatch可以抓到上传视屏图片的包,一般的抓包软件是抓不到的.打开 ...

  8. 网络抓包--Wireshark

    Wireshark 是一款非常棒的Unix和Windows上的开源网络协议分析器.它可以实时检测网络通讯数据,也可以检测其抓取的网络通讯数据快照文件.可以通过图形界面浏览这些数据,可以查看网络通讯数据 ...

  9. Android 下使用tcpdump网络抓包方法

    Android 下使用tcpdump网络抓包方法 抓包需要tcpdump以及Root权限,tcpdump在本文后有下载. 首先把tcpdump传进手机,用adb命令(放SD卡有时会有问题,我一次可以用 ...

随机推荐

  1. android中的屏幕单位介绍

    1.px (pixels)(像素):是屏幕的物理像素点,与密度相关,密度大了,单位面积上的px 会比较多.通常不推荐使用这个. 2.dip 或dp(与密度无关的像素):一个基于density(密度)的 ...

  2. 自定义CoordinatorLayout Behavior 隐藏Footer View

    在用新的控件中,我们可以用Toolbar与CoordinatorLayout实现 向上滚动隐藏的效果,可是官方并没有找到向上隐藏底部导航的功能,有一些第三方的框架实现了. 在Android M,Coo ...

  3. mybatis和ibatis控制台打印sql语句方法

    #将ibatis log4j运行级别调到DEBUG可以在控制台打印出ibatis运行的sql语句 log4j.rootLogger=debug,stdout,logfile### 把日志信息输出到控制 ...

  4. [转]使用Sencha Ext JS 6打造通用应用程序

    原文地址:http://www.uedsc.com/using-sencha-ext-js-6-to-build-universal-apps.html 在Sencha和整个Ext JS团队的支持下, ...

  5. [转]servlet中的service, doGet, doPost方法的区别和联系

    原文地址:http://m.blog.csdn.net/blog/ghyg525/22928567 大家都知道在javax.servlet.Servlet接口中只有init, service, des ...

  6. Web的结构组件

    HTTP代理服务器的作用 Web安全,应用集成,性能优化 1. 代理 In computer networks, a proxy server is a server (a computer syst ...

  7. Linux_rsylogd日志轮替(三)

    一.轮替规则及配置文件:vi /etc/logrotate.conf 1.如果配置文件中拥有" dateext"参数,那么日志会用日期来作为日志文件的后缀,例如" sec ...

  8. nutch-2.1导入eclipse+mysql运行

    初次接触nutch,记录下来 首先数据库 CREATE DATABASE nutch DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_c ...

  9. AS技巧合集「编码技巧篇」

    转载:http://www.apkbus.com/forum.php?mod=viewthread&tid=254725&extra=page%3D2%26filter%3Dautho ...

  10. Angular实现注册系统

    Angular是Google开发的前端技术框架,下载地址:https://code.angularjs.org/1.5.0/angular.js 通过对angular的简单理解后发现,angular通 ...