使用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卡有时会有问题,我一次可以用 ...
随机推荐
- android中的屏幕单位介绍
1.px (pixels)(像素):是屏幕的物理像素点,与密度相关,密度大了,单位面积上的px 会比较多.通常不推荐使用这个. 2.dip 或dp(与密度无关的像素):一个基于density(密度)的 ...
- 自定义CoordinatorLayout Behavior 隐藏Footer View
在用新的控件中,我们可以用Toolbar与CoordinatorLayout实现 向上滚动隐藏的效果,可是官方并没有找到向上隐藏底部导航的功能,有一些第三方的框架实现了. 在Android M,Coo ...
- mybatis和ibatis控制台打印sql语句方法
#将ibatis log4j运行级别调到DEBUG可以在控制台打印出ibatis运行的sql语句 log4j.rootLogger=debug,stdout,logfile### 把日志信息输出到控制 ...
- [转]使用Sencha Ext JS 6打造通用应用程序
原文地址:http://www.uedsc.com/using-sencha-ext-js-6-to-build-universal-apps.html 在Sencha和整个Ext JS团队的支持下, ...
- [转]servlet中的service, doGet, doPost方法的区别和联系
原文地址:http://m.blog.csdn.net/blog/ghyg525/22928567 大家都知道在javax.servlet.Servlet接口中只有init, service, des ...
- Web的结构组件
HTTP代理服务器的作用 Web安全,应用集成,性能优化 1. 代理 In computer networks, a proxy server is a server (a computer syst ...
- Linux_rsylogd日志轮替(三)
一.轮替规则及配置文件:vi /etc/logrotate.conf 1.如果配置文件中拥有" dateext"参数,那么日志会用日期来作为日志文件的后缀,例如" sec ...
- nutch-2.1导入eclipse+mysql运行
初次接触nutch,记录下来 首先数据库 CREATE DATABASE nutch DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_c ...
- AS技巧合集「编码技巧篇」
转载:http://www.apkbus.com/forum.php?mod=viewthread&tid=254725&extra=page%3D2%26filter%3Dautho ...
- Angular实现注册系统
Angular是Google开发的前端技术框架,下载地址:https://code.angularjs.org/1.5.0/angular.js 通过对angular的简单理解后发现,angular通 ...