最近由于项目需要,研究了一下ICMP和ROW SOCKET协议,顺便在这里记下,一是方便给自已
留个笔记,也方便和朋友们一起学习和进步。
昨天在修改公司一个wince的程序时,偶然发现其中一个ping主机的模块代码有内存泄露问题,但我也有几年没有去看过ICMP的东东,因此,把以前项目用过的ICMP和row socket协议代码拿出来再翻翻,把BUG给修正了,顺道也把row socet实现IP欺骗的代码也贴出来。(PING的代码就不贴了,网上很多例子,简单的就几个ICMP的api就可实现,也有用socket来实现的,代码量多一点而已。)
我对协议的理解是在每层加上一个包头而已,IP层位于网络层,socket提供的函数只能修改网络层的东东,因此,平常我们用的socket函数一般只能使用在网络层以后面的像HTTP层上,Http这些应该属于应用层,只是在网络层上再加一个Http包头而已。
下面的代码是在三年前一个用于做自动网络拓朴发现中用到的IP欺骗的一个模块,说起Auto拓朴发现,就是通过一个网管程序,采用SNMP+ICMP+socket+TD等各设备厂家提供的自有协议的前提下,能够自动把企业内的网络图画出来,刚好那时候公司安排我做的这个模块,因此也研究过阿尔卡特/北电/华为/思科等的路由器和交换机,对他们的公有、私有mib库都有一些了解,二层和三层的拓朴图还是画得比较完善的,只是在交换机到普通的PC服务器之间的线画得不全,后来才通过采用IP欺骗才得到进一点提高。
简单的讲一下IP欺骗,目的是向A设备发送ICMP包,在包里面把本应该是填自已的IP地址改为B设备的IP地址,让A设备误以为是B设备向他发的包,因此,A就会把回应的包发到B设备去。而这样,原A和B设备之间也许没有通信,通过IP欺骗主动使他们交流一下,这样就方便我在A设备的mib库中找到关于更多B的信息。
说不多说了,下面是代码,是用C++写的,但因为主项目是用python写的,因为下面的代码中,会有一些关于生成python可以调用的dll的东东,如果你编译时报错可以直接去掉即可。因为你不需要生成python能调的dll,呵呵。
//#define WIN32_LEAN_AND_MEAN
#include "include/Python.h"
#include <winsock2.h>
//#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
//
// Set up some default values
//
#define DEFAULT_COUNT 4
#define DEFAULT_MESSAGE "This is a test"
#define ICMP_FLOOD 0
#define IP_HDRINCL 2
#define IP_TTL 255
typedef struct ip_hdr
{
//BYTE h_len:4; // Length of the header in dwords
//BYTE version:4; // Version of IP
unsigned char ip_verlen; // IP version & length
unsigned char ip_tos; // IP type of service
unsigned short ip_totallength; // Total length
unsigned short ip_id; // Unique identifier
unsigned short ip_offset; // Fragment offset field
unsigned char ip_ttl; // Time to live
unsigned char ip_protocol; // Protocol(TCP, UDP, etc.)
unsigned short ip_checksum; // IP checksum
unsigned int ip_srcaddr; // Source address
unsigned int ip_destaddr; // Destination address
} ;
typedef struct icmp_hdr {
BYTE type; // ICMP packet type
BYTE code; // Type sub code
USHORT checksum;
USHORT id;
USHORT seq;
//ULONG timestamp; // not part of ICMP, but we need it
};
struct pkt
{
struct ip_hdr ip;
struct icmp_hdr icmp;
}pack;
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while (size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
static PyObject* icmpsend(PyObject *self, PyObject *args);
static PyObject* icmpsend(PyObject* self, PyObject* args)
{
char *src_ip,*dest_ip;
WSADATA wsd;
SOCKET s;
int bOpt;
struct sockaddr_in remote; // IP addressing structures
struct ip_hdr ipHdr;
int ret;
unsigned short iIPVersion,
iIPSize;
IN_ADDR addr;
unsigned short chk;
int ttl;
DWORD i;
if (! PyArg_ParseTuple(args, "s|s", &src_ip, &dest_ip))
return Py_BuildValue("i", -1);
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
ret =GetLastError();
return Py_BuildValue("i", ret);
}
s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0, 0, 0);
if (s == INVALID_SOCKET)
{
ret =WSAGetLastError();
return Py_BuildValue("i", ret);
}
bOpt = 1;
ttl = 30;
ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&bOpt, sizeof(bOpt));
//ret = setsockopt(s, IPPROTO_IP, IP_TTL, (const char*)&ttl,sizeof(ttl));
if (ret == SOCKET_ERROR)
{
ret = WSAGetLastError();
return Py_BuildValue("i", ret);
}
// Initalize the IP header
//
iIPVersion = 4;
iIPSize = sizeof(ipHdr) / sizeof(unsigned long);
//
// IP version goes in the high-order 4 bits of ip_verlen. The
// IP header length (in 32-bit words) goes in the lower 4 bits.
//
//pack.ip.ihl=5;
pack.ip.ip_verlen=(iIPVersion << 4) | iIPSize;
pack.ip.ip_tos=0;
pack.ip.ip_totallength = htons(28);
pack.ip.ip_id=0;
pack.ip.ip_offset=0;
pack.ip.ip_ttl=255;
pack.ip.ip_protocol=1;
pack.ip.ip_checksum=0;
//pack.ip.ip_checksum = chk;
pack.ip.ip_srcaddr = inet_addr(src_ip);
pack.ip.ip_destaddr = inet_addr(dest_ip);
pack.icmp.type = 8;
pack.icmp.code = 0;
pack.icmp.checksum = 0;
chk=checksum((unsigned short *)&pack.icmp, 8);
pack.icmp.checksum=chk;
chk=checksum((unsigned short *)&pack, 28);
pack.ip.ip_checksum=chk;
remote.sin_family = AF_INET;
remote.sin_addr.s_addr = pack.ip.ip_destaddr;
for(i = 0; i < DEFAULT_COUNT; i++)
{
ret = sendto(s, (char *)&pack, sizeof(pack), 0, (SOCKADDR *)&remote,sizeof(remote));
if (ret == SOCKET_ERROR)
{
ret = WSAGetLastError();
break;
}
}
closesocket(s);
WSACleanup();
return Py_BuildValue("i", ret);
}
static PyMethodDef addMethods[] =
{
{"icmpsend", icmpsend, METH_VARARGS, "Execute a shell command."},
{NULL, NULL, 0, NULL}
};
#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
#define PyMODINIT_FUNC _declspec(dllexport) void
#endif
PyMODINIT_FUNC initipspoof()
{
Py_InitModule("ipspoof", addMethods);
}
忘了说一点了,只有用Row Socket才可以使icmp_hdr和IP_hdr修改生效。才能做到IP欺骗。
刚起床,把昨天做的东东记下来,一会找朋友打几局星际,我的周未就这样子过了。写程序这么些年来我一直不会交际,不喜欢出去玩,周未在家就是一个人,习惯了寂寞,习惯了一个人呆在房子里的日子...