原始套接字实现TCP SYN扫描,自己构造的IP包发出去时系统还是自动添了个IP头,实在不知道原因

aucusaga 2013-12-04 12:01:11
话说是第一次在这发帖子的说= =,小女安全扫描要写课程设计,用的是TCP SYN扫描,参考的是李瑞民那本书,用原始套接字该设的都设置了,IP_HDRINCL确实设置过了,自己构造包之后用sendto发送的,但抓包显示系统又自动在我构造的包前面加了个IP头,校验和检查了没错,实在不知道什么原因,我是新手啊,望各位大神解答+_+
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib,"WS2_32.lib")
#define MAXDATASIZE 1024 //缓冲区大小
#include "WS2TCPIP.H"

#define SEQ 0x28376839 //ip数据包的首部数据结构
struct sockaddr_in target,source;
int rawsock;

typedef struct _iphdr {
unsigned char h_lenver; //4位首部长度+4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议 (TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;

typedef struct _tcphdr //定义TCP首部
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
unsigned int th_seq; //32位序列号
unsigned int th_ack; //32位确认号
unsigned char th_lenres; //4位首部长度/6位保留字
unsigned char th_flag; //6位标志位
USHORT th_win; //16位窗口大小
USHORT th_sum; //16位校验和
USHORT th_urp; //16位紧急数据偏移量
}TCP_HEADER;

struct //定义TCP伪首部
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz; char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}psd_header;

//SOCK错误处理程序
void CheckSockError(int iErrorCode, char *pErrorMsg)
{
if(iErrorCode==SOCKET_ERROR) {
printf("%s Error:%d\n", pErrorMsg, GetLastError());
closesocket(rawsock);
ExitProcess(-1);
}
}

//计算检验和
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
unsigned short answer=0;
while (size > 1) {
cksum += *buffer++;
size -= sizeof(USHORT);
}
if (size==1) {
*(char *)&answer=*(char *)buffer;
cksum += answer;
}
while(cksum >> 16)
cksum = (cksum >> 16) + (cksum & 0xffff);
return (USHORT)(~cksum);
}

//IP解包程序
int DecodeIPHeader(char *recvbuf, int bytes)
{
IP_HEADER *iphdr;
TCP_HEADER *tcphdr;
unsigned short iphdrlen;
iphdr = (IP_HEADER *)recvbuf;
iphdrlen = sizeof(unsigned long) * (iphdr->h_lenver & 0xf);
iphdrlen=sizeof(IP_HEADER);
tcphdr = (TCP_HEADER*)(recvbuf + iphdrlen);

//是否来自目标IP
if(iphdr->sourceIP != target.sin_addr.s_addr) {
printf("不来自目标IP\n");
return 0;
}

//序列号是否正确
if(ntohl(tcphdr->th_ack) != (SEQ+1)) {
printf("序列号错误\n");
return 0;
}

//RST/ACK - 无服务
if(tcphdr->th_flag == 20) {
printf("RST+ACK 无服务.\n");
return 1;
}

//SYN/ACK - 扫描到一个端口
if(tcphdr ->th_flag == 18) {
printf("%d\n",ntohs(tcphdr->th_sport));
return 2;
}
printf("未知\n");
return 1;
}





int main()
{



int datasize;
IP_HEADER ip_header;
TCP_HEADER tcp_header;
char ip_data[MAXDATASIZE]={0};
char RecvBuf[65535]={0};

WSAData data;
struct sockaddr_in target,source;
WORD w = MAKEWORD(2,2); //版本号
WSAStartup(w,&data); //初始化
if((rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_IP))== INVALID_SOCKET)
{
printf("socket error!\n");
printf("%d\n",GetLastError());
exit(1);
}

bool bOpt=true;
DWORD dwBufferLen[10] ;
DWORD dwBufferInLen = 1 ;
DWORD dwBytesReturned = 0 ;
WSAIoctl(rawsock, _WSAIOW(IOC_VENDOR,1),&dwBufferInLen, sizeof(dwBufferInLen), &dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );


setsockopt(rawsock,IPPROTO_IP,IP_HDRINCL,(char *)&bOpt,sizeof(bOpt));
source.sin_family=AF_INET;
source.sin_addr.S_un.S_addr=inet_addr("192.168.1.203");
source.sin_port=htons(1234);
bind(rawsock,(struct sockaddr *)&source,sizeof(source));

target.sin_family=AF_INET;
target.sin_addr.S_un.S_addr=inet_addr("192.168.1.202");
target.sin_port=htons(80);


ip_header.h_lenver=(4<<4 | sizeof(ip_header)/sizeof(unsigned long)); //高四位IP版本号,低四位首部长度
ip_header.tos=0;
ip_header.total_len=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)); //16位总长度(字节)
ip_header.ident=0; //16位标识
ip_header.frag_and_flags=0; //3位标志位
ip_header.ttl=128; //8位生存时间TTL
ip_header.proto=IPPROTO_TCP; //8位协议
ip_header.checksum=0; //16位IP首部校验和
ip_header.sourceIP=source.sin_addr.s_addr; //32位源IP地址
ip_header.destIP=target.sin_addr.s_addr; //32位目的IP地址 //填充TCP首部

tcp_header.th_sport=source.sin_port; //源端口号
tcp_header.th_dport=target.sin_port; //目的端口号
tcp_header.th_seq=htonl(SEQ); //SYN序列号
tcp_header.th_ack=0; //ACK序列号置为0
tcp_header.th_lenres=(sizeof(TCP_HEADER)/4<<4|0); //TCP长度和保留位
tcp_header.th_flag=2; //SYN 标志
tcp_header.th_win=htons(16384); //窗口大小
tcp_header.th_urp=0; //偏移
tcp_header.th_sum=0; //校验和


//填充TCP伪首部(用于计算校验和,并不真正发送)
psd_header.saddr=ip_header.sourceIP;
psd_header.daddr=ip_header.destIP;
psd_header.mbz=0;
psd_header.ptcl=IPPROTO_TCP;
psd_header.tcpl=htons(sizeof(tcp_header)); //计算TCP校验和,计算校验和时需要包括TCP pseudo header


memcpy(ip_data,&psd_header,sizeof(psd_header));
memcpy(ip_data+sizeof(psd_header),&tcp_header,sizeof(tcp_header));
tcp_header.th_sum=checksum((USHORT *)ip_data,sizeof(psd_header)+sizeof(tcp_header)); //计算IP校验和
memcpy(ip_data,&ip_header,sizeof(ip_header));
memcpy(ip_data+sizeof(ip_header),&tcp_header,sizeof(tcp_header));
memset(ip_data+sizeof(ip_header)+sizeof(tcp_header),0,4);
datasize=sizeof(ip_header)+sizeof(tcp_header);
ip_header.checksum=checksum((USHORT *)ip_data,datasize); //填充发送缓冲区
memcpy(ip_data,&ip_header,sizeof(ip_header));

datasize=sizeof(ip_header)+sizeof(tcp_header);

if ((sendto(rawsock,ip_data,datasize,0,(struct sockaddr *)&target,sizeof(target)))<0)
{
printf("sendto error!\n");
printf("%d\n",GetLastError());
}


//接收数据
DWORD timeout = 200000;//2000
DWORD start = GetTickCount();
int sizedest=sizeof(target);
while(true) { //计时,2s超时
if((GetTickCount() - start) >= timeout) break;
memset(RecvBuf, 0, sizeof(RecvBuf));

int iErrorCode = recv(rawsock, RecvBuf, sizeof(RecvBuf), 0);
CheckSockError(iErrorCode, "recv");

if(int i = DecodeIPHeader(RecvBuf,iErrorCode)) {
if(i == 1) break;
tcp_header.th_flag=4; //RST 标志
//计算TCP校验和,计算校验和时需要包括TCP pseudo header
memcpy(ip_data,&psd_header,sizeof(psd_header));
memcpy(ip_data+sizeof(psd_header),&tcp_header,sizeof(tcp_header));
tcp_header.th_sum=checksum((USHORT *)ip_data,sizeof(psd_header)+sizeof(tcp_header)); //计算IP校验和
memcpy(ip_data,&ip_header,sizeof(ip_header));
memcpy(ip_data+sizeof(ip_header),&tcp_header,sizeof(tcp_header));
memset(ip_data+sizeof(ip_header)+sizeof(tcp_header),0,4);
datasize=sizeof(ip_header)+sizeof(tcp_header);
ip_header.checksum=checksum((USHORT *)ip_data,datasize); //填充发送缓冲区
memcpy(ip_data,&ip_header,sizeof(ip_header)); //发送TCP报文
iErrorCode=sendto(rawsock,ip_data,datasize,0,(struct sockaddr*) &target, sizeof(target));
CheckSockError(iErrorCode, "sendto2()");
break;
}
} //退出前清理 */

return 0;
if(rawsock != INVALID_SOCKET) closesocket(rawsock);
WSACleanup();
return 0;
}
...全文
512 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
max_min_ 2013-12-04
  • 打赏
  • 举报
回复
引用 3 楼 truelance 的回复:
如果你不想系统自动加IP头,就不应该用AF_INET, 而使用AF_PACKET
问题关键!楼主可以看下tcp/ip协议
aucusaga 2013-12-04
  • 打赏
  • 举报
回复
引用
看你想干什么, 如果你是研究网络的, 想在IP协议内做增强进行仿真, 那就要自己用AF_PACKET; 如果你只是在IP协议之上开发一些应用, 那就不要自己定义IP头, 使用系统自带的.
我想扫对方端口开没开,又想用原始套接字,想自己构包发过去三次握手握两次,要用AF_PACKET吗?
熊熊大叔 2013-12-04
  • 打赏
  • 举报
回复
引用 5 楼 aucusaga 的回复:
[quote=引用 2 楼 truelance 的回复:] rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_IP) 你选的IP协议,当然会给你加IP头 bind(rawsock,(struct sockaddr *)&source,sizeof(source)); IP头里的数据是要填到source里的
要是用AF_PACKET,不是要MAC地址吗,扫描的话能用吗?我就想构造一个SYN=1的tcp发出去啊[/quote] 看你想干什么, 如果你是研究网络的, 想在IP协议内做增强进行仿真, 那就要自己用AF_PACKET; 如果你只是在IP协议之上开发一些应用, 那就不要自己定义IP头, 使用系统自带的.
aucusaga 2013-12-04
  • 打赏
  • 举报
回复
引用 2 楼 truelance 的回复:
rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_IP) 你选的IP协议,当然会给你加IP头 bind(rawsock,(struct sockaddr *)&source,sizeof(source)); IP头里的数据是要填到source里的
要是用AF_PACKET,不是要MAC地址吗,扫描的话能用吗?我就想构造一个SYN=1的tcp发出去啊
  • 打赏
  • 举报
回复
楼上正解。 你用了INET域,发出去的是数据,当然会帮你把包头给打上
熊熊大叔 2013-12-04
  • 打赏
  • 举报
回复
如果你不想系统自动加IP头,就不应该用AF_INET, 而使用AF_PACKET
熊熊大叔 2013-12-04
  • 打赏
  • 举报
回复
rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_IP) 你选的IP协议,当然会给你加IP头 bind(rawsock,(struct sockaddr *)&source,sizeof(source)); IP头里的数据是要填到source里的
xlrtx 2013-12-04
  • 打赏
  • 举报
回复
代码太长了没仔细看..不知道你的意思是神马.. 是系统又给你添加了个ip头么?一共有两个ip头么? 还有这些实在没看出你是什么意图啊..改了涂涂了改啊..

    memcpy(ip_data,&psd_header,sizeof(psd_header)); 
    memcpy(ip_data+sizeof(psd_header),&tcp_header,sizeof(tcp_header)); 
    tcp_header.th_sum=checksum((USHORT *)ip_data,sizeof(psd_header)+sizeof(tcp_header)); //计算IP校验和 
    memcpy(ip_data,&ip_header,sizeof(ip_header)); 
    memcpy(ip_data+sizeof(ip_header),&tcp_header,sizeof(tcp_header)); 
    memset(ip_data+sizeof(ip_header)+sizeof(tcp_header),0,4); 
    datasize=sizeof(ip_header)+sizeof(tcp_header); 
    ip_header.checksum=checksum((USHORT *)ip_data,datasize); //填充发送缓冲区 
    memcpy(ip_data,&ip_header,sizeof(ip_header)); 

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧