使用RawSocket进行网络抓包
简介编辑
总结编辑
1.1 原始套接字工作原理与规则
原始套接字是一个特殊的套接字类型,它的创建方式跟TCP/UDP创建方法几乎是
一摸一样,例如,通过
sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP);
这两句程序你就可以创建一个原始套接字.然而这种类型套接字的功能却与TCP或者UDP类型套接字的功能有很大的不同:TCP/UDP类型的套接字只能够访问传输层以及传输层以上的数据,因为当IP层把数据传递给传输层时,下层的数据包头已经被丢掉了.而原始套接字却可以访问传输层以下的数据,,所以使用 raw套接字你可以实现上至应用层的数据操作,也可以实现下至链路层的数据操作.
比如:通过
方式创建的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地址。
综合以上种种功能和特点,我们可以使用原始套接字来实现很多功能,比如最基本的数据包分析,主机嗅探等.其实也可以使用原始套接字作一个自定义的传输层协议.
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进行网络抓包的更多相关文章
- CatchPacket网络抓包软件
CatchPacket网络抓包软件 qq 22945088431.技术特点:基于WinPcap库,c# winform2.实现获取机器所有网卡,可任意选择监听3.可以捕获常见网络协议arp dns ...
- 网络抓包wireshark(转)
转自 网络抓包wireshark 抓包应该是每个技术人员掌握的基础知识,无论是技术支持运维人员或者是研发,多少都会遇到要抓包的情况,用过的抓包工具有fiddle.wireshark,作为一个不是经 ...
- 跨平台网络抓包工具-Microsoft Message Analyzer
Microsoft Message Analyzer (MMA 2013)是微软最受欢迎的Netmon的最新版本. 在Netmon网络跟踪和排除故障功能的基础上提供了更强大的跨平台网络分析追踪能力.园 ...
- Microsoft Message Analyzer (微软消息分析器,“网络抓包工具 - Network Monitor”的替代品)官方正式版现已发布
来自官方日志的喜悦 被誉为全新开始的消息分析器时代,由MMA为您开启,博客原文写的很激动,大家可以点击这里浏览:http://blogs.technet.com/b/messageanalyzer/a ...
- 网络抓包工具-Wireshark学习资料
wireshark一个非常牛逼的网络抓包工具.转载一系列博文 一站式学习Wireshark(一):Wireshark基本用法 一站式学习Wireshark(二):应用Wireshark观察基本网络协议 ...
- 三种经典iPhone上网络抓包方法详解
此文章来自:听云博客 很多时候需要网络抓包分析,在iPhone上抓包稍有不同,下面介绍三种常用的方式.分析工具以wireshark为例. 一.最简单的方式:用PC作为热点,在PC上抓包 优点:简单 缺 ...
- HttpWatch网络抓包工具的使用
HttpWatch网络抓包工具是专为IE浏览器集成的一款网络拽包工具. 是一款强大的网页数据分析软件,是最好用的抓包工具,httpwatch可以抓到上传视屏图片的包,一般的抓包软件是抓不到的.打开 ...
- 网络抓包--Wireshark
Wireshark 是一款非常棒的Unix和Windows上的开源网络协议分析器.它可以实时检测网络通讯数据,也可以检测其抓取的网络通讯数据快照文件.可以通过图形界面浏览这些数据,可以查看网络通讯数据 ...
- Android 下使用tcpdump网络抓包方法
Android 下使用tcpdump网络抓包方法 抓包需要tcpdump以及Root权限,tcpdump在本文后有下载. 首先把tcpdump传进手机,用adb命令(放SD卡有时会有问题,我一次可以用 ...
随机推荐
- linux基础-第十六单元 yum管理RPM包
第十六单元 yum管理RPM包 yum的功能 本地yum配置 光盘挂载和镜像挂载 本地yum配置 网络yum配置 网络yum配置 Yum命令的使用 使用yum安装软件 使用yum删除软件 安装组件 删 ...
- windows server2008 r2 下启用 sqlserver 2008的远程连接
首先说明,本文转自互联网. TMD 花了二天,终于找到怎么开启这个远程连接了.....娘的,累死了,写下来,希望能帮助同胞们... 用win server 2008 r2 和sql server 20 ...
- SpringMVC对日期类型的转换
在做web开发的时候,页面传入的都是String类型,SpringMVC可以对一些基本的类型进行转换,但是对于日期类的转换可能就需要我们配置. 1.如果查询类使我们自己写,那么在属性前面加上@Date ...
- PHP中CURL方法curl_setopt()函数的参数
PHP CURL curl_setopt 参数 bool curl_setopt (int ch, string option, mixed value)curl_setopt()函数将为一个CURL ...
- Entity Framework Code First (八)迁移 Migrations
创建初始模型和数据库 在开始使用迁移(Migrations)之前,我们需要一个 Project 和一个 Code First Model, 对于本文将使用典型的 Blog 和 Post 模型 创建一个 ...
- bzoj3224
学习了下treap #include<iostream> #include<cstdio> #include<cstdlib> using namespace st ...
- 100735D
排序+搜索 为什么这是对的呢?其实我不是很清楚 大概是这个样子的:我们希望构成三角形的三个数尽可能集中,因此在搜索中贪心地选取从最小依次往上,选取三条边,但是总感觉有反例,先挖个坑... #inclu ...
- eclipse-debug时直接进入/不进入/提示进入调试页面修改
eclipse使用debug调试程序时 默认设置每次程序走到断点位置时提示是否进入调试页面(如图) 而个人习惯有些系统直接进入调试页面.也有些人系统不进入调试页面调试 在这里勾选Remember my ...
- UIScrollView 实践经验(转)
转载自:http://tech.glowing.com/cn/practice-in-uiscrollview/ UIScrollView(包括它的子类 UITableView 和 UICollect ...
- Android Studio 连接提交Git
转载:http://www.jianshu.com/p/061d24a6b798 之前一直在使用SVN的时候,就听说Git是个很强大的版本控制工具,最近比较闲,又赶上在痛苦的学习着使用Android ...