raw socket编写自定义Ip数据包,无发包

好人阿萨德飞 2013-07-20 01:10:03

#include "Winsock2.h"
#include "stdio.h"
#include "Ws2tcpip.h"

#pragma comment(lib,"ws2_32.lib")

typedef struct //定义IP报头
{
unsigned short ip_verlen; //4位首部长度+4位版本号
unsigned short ip_tos; //8位服务类型
unsigned short ip_totallength;///16位总长度(字节)
unsigned short ip_id; //16位标识
unsigned short ip_offset; //3位标志位
unsigned short ip_ttl; //8位生存时间 TTL
unsigned short ip_protocol; //8位协议 (TCP, UDP 或其他)
unsigned short ip_checksum; //16位IP首部校验和
unsigned long ip_srcaddr; //32位源IP地址
unsigned long ip_destaddr; //32位目的IP地址
}IP_HDR;

typedef struct //定义UDP报头
{
unsigned short src_portno;//16位源端口
unsigned short dst_portno;//16位目的端口
unsigned short udp_length;//16位长度
unsigned short udp_checksum;//16位校验和
}UDP_HDR;
int main()
{
WSADATA wsd;
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("WSAStartup() failed: %d ", GetLastError());
return -1;
}
SOCKET s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_IP, NULL, 0,WSA_FLAG_OVERLAPPED); // Create a raw socket
if (s == INVALID_SOCKET)
{
printf("WSASocket() failed: %d ", WSAGetLastError());
return -1;
}
DWORD bOpt = TRUE;
int ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char*) &bOpt, sizeof(bOpt)); // 使用IP_HDRINCL
if (ret == SOCKET_ERROR)
{
printf("setsockopt(IP_HDRINCL) failed: %d ", WSAGetLastError());
return -1;
}
const int BUFFER_SIZE = 80;
char buffer[BUFFER_SIZE];
const char *strMessage = "treat demo"; // Message to send
// Set IP header
   const u_short uToPort = 8000;
udpHdr.dst_portno = htons(uToPort); // 接收方端口
const u_short uFromPort = 1000;
udpHdr.src_portno = htons(uFromPort); // 发送伪造的端口
const unsigned short iUdpSize = sizeof(udpHdr) + strlen(strMessage);
udpHdr.udp_length = htons(iUdpSize);
udpHdr.udp_checksum = 0;
// 组建待发送的UDP报文
ZeroMemory(buffer, BUFFER_SIZE);
char *ptr = buffer;
memcpy(ptr, &ipHdr, sizeof(ipHdr));
ptr += sizeof(ipHdr);
memcpy(ptr, &udpHdr, sizeof(udpHdr));
ptr += sizeof(udpHdr);
memcpy(ptr, strMessage, strlen(strMessage));
// Apparently, this SOCKADDR_IN structure makes no difference.
// Whatever we put as the destination IP addr in the IP header is what goes.
// Specifying a different destination in remote will be ignored.
sockaddr_in remote;
remote.sin_family = AF_INET;
remote.sin_port = htons(8000);
remote.sin_addr.s_addr = inet_addr("192.168.0.6");
printf("TO %s:%d ", target_ip_address, uToPort);
ret = sendto(s, buffer, iTotalSize, 0, (SOCKADDR*) &remote, sizeof(remote)); // 发送伪造的报文
if (ret == SOCKET_ERROR)
{
printf("sendto() failed: %d ", WSAGetLastError());
}
else
printf("sent %d bytes ", ret);
closesocket(s);
WSACleanup();
return 1;
}

运行没错误,但是用wireshark抓包发现并无发包,请各路大神指教
...全文
686 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
weilin.jiang 2015-12-10
  • 打赏
  • 举报
回复
[quote=引用 5 楼 zhao4zhong1 的回复:] 搜“Win7 SOCK_RAW”
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <mmsystem.h>
#pragma comment(lib, "ws2_32")
#pragma comment(lib, "winmm")
#define ICMP_ECHOREPLY 0 //ICMP回应答复
#define ICMP_ECHOREQ 8 //ICMP回应请求
#define REQ_DATASIZE 32 //请求数据报大小
#include <iostream>
using namespace std;

//定义IP首部格式
typedef struct _IPHeader {
    u_char VIHL; //版本和首部长度
    u_char ToS; //服务类型
    u_short TotalLen; //总长度
    u_short ID; //标识号
    u_short Frag_Flags; //片偏移量
    u_char TTL; //生存时间
    u_char Protocol; //协议
    u_short Checksum; //首部校验和
    struct in_addr SrcIP; //源IP地址
    struct in_addr DestIP; //目的地址
}
IPHDR, *PIPHDR;

//定义ICMP首部格式
typedef struct _ICMPHeader {
    u_char Type; //类型
    u_char Code; //代码
    u_short Checksum; //首部校验和
    u_short ID; //标识
    u_short Seq; //序列号
    char Data; //数据
}
ICMPHDR, *PICMPHDR;

//定义ICMP回应请求
typedef struct _ECHOREQUEST {
    ICMPHDR icmpHdr;
    DWORD dwTime;
    char cData[REQ_DATASIZE];
}
ECHOREQUEST, *PECHOREQUEST;

//定义ICMP回应答复
typedef struct _ECHOREPLY {
    IPHDR ipHdr;
    ECHOREQUEST echoRequest;
    char cFiller[256];
}
ECHOREPLY, *PECHOREPLY;

//计算校验和
u_short checksum(u_short *buffer, int len) {
    register int nleft = len;
    register u_short *w = buffer;
    register u_short answer;
    register int sum = 0;
    //使用32位累加器,进行16位的反馈计算
    while ( nleft > 1 ) {
        sum += *w++;
        nleft -= 2;
    }
    //补全奇数位
    if ( nleft == 1 ) {
        u_short u = 0;
        *(u_char *)(&u) = *(u_char*)w;
        sum += u;
    }
    //将反馈的16位从高位移到低位
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return (answer);
}

//发送回应请求函数
int SendEchoRequest(SOCKET s, struct sockaddr_in *lpstToAddr) {
    static ECHOREQUEST echoReq;
    static int nId = 1;
    static int nSeq = 1;
    int nRet;
    //填充回应请求消息
    echoReq.icmpHdr.Type = ICMP_ECHOREQ;
    echoReq.icmpHdr.Code = 0;
    echoReq.icmpHdr.Checksum = 0;
    echoReq.icmpHdr.ID = nId++;
    echoReq.icmpHdr.Seq = nSeq++;
    //填充要发送的数据
    for (nRet = 0; nRet < REQ_DATASIZE; nRet++) {
        echoReq.cData[nRet] = '1' + nRet;
    }
    //存储发送的时间
    echoReq.dwTime = timeGetTime();
    //计算回应请求的校验和
    echoReq.icmpHdr.Checksum = checksum((u_short*)&echoReq, sizeof(ECHOREQUEST));
    //发送回应请求
    nRet = sendto(s,(LPSTR)&echoReq,sizeof(ECHOREQUEST),
                  0,(struct sockaddr*)lpstToAddr,sizeof(SOCKADDR_IN));
    if (nRet == SOCKET_ERROR) {
        printf("send to() error:%d\n", WSAGetLastError());
    }
    return (nRet);
}

//接收应答回复并进行解析
DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL) {
    ECHOREPLY echoReply;
    int nRet;
    int nAddrLen = sizeof(struct sockaddr_in);
    //接收应答回复
    nRet = recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY),
                    0,(LPSOCKADDR)lpsaFrom,&nAddrLen);
    //检验接收结果

    if (nRet == SOCKET_ERROR) {
        printf("recvfrom() error:%d\n",WSAGetLastError());
    }
    //记录返回的TTL
    *pTTL = echoReply.ipHdr.TTL;
    //返回应答时间
    return(echoReply.echoRequest.dwTime);
}

//等待回应答复,使用select模型
int WaitForEchoReply(SOCKET s) {
    struct timeval timeout;
    fd_set readfds;
    readfds.fd_count = 1;
    readfds.fd_array[0] = s;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    return(select(1, &readfds, NULL, NULL, &timeout));
}

//PING功能实现
void Ping(char *pstrHost,bool logic) {
    SOCKET rawSocket;
    LPHOSTENT lpHost;
    struct sockaddr_in destIP;
    struct sockaddr_in srcIP;
    DWORD dwTimeSent;
    DWORD dwElapsed;
    u_char cTTL;
    int nLoop,k=4;
    int nRet,minimum=100000,maximum=0,average=0;
    int sent=4,reveived=0,lost=0;
    //创建原始套接字,ICMP类型
    rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (rawSocket == SOCKET_ERROR) {
        printf("socket() error:%d\n", WSAGetLastError());
        return;
    }
    //检测目标主机
    lpHost = gethostbyname(pstrHost);
    if (lpHost==NULL) {
        printf("Host not found:%s\n", pstrHost);
        return;
    }
    //设置目标机地址
    destIP.sin_addr.s_addr = *((u_long FAR*)(lpHost->h_addr)); //设置目标IP
    destIP.sin_family = AF_INET;  //地址规格
    destIP.sin_port = 0;
    //提示开始进行PING
    printf("\nPinging %s [%s] with %d bytes of data:\n",pstrHost,inet_ntoa(destIP.sin_addr),REQ_DATASIZE);
    //发起多次PING测试
    for (nLoop=0; nLoop<k; nLoop++) {
        if (logic)k=k+1;
        //发送ICMP回应请求
        SendEchoRequest(rawSocket, &destIP);
        //等待回复的数据
        nRet = WaitForEchoReply(rawSocket);
        if (nRet == SOCKET_ERROR) {
            printf("select() error:%d\n", WSAGetLastError());
            break;
        }
        if (!nRet) {
            lost++;
            printf("\nRequest time out.");
            continue;
        }
        //接收回复
        dwTimeSent = RecvEchoReply(rawSocket, &srcIP, &cTTL);
        reveived++;
        //计算花费的时间
        dwElapsed = timeGetTime() - dwTimeSent;
        if(dwElapsed>maximum)maximum=dwElapsed;
        if(dwElapsed<minimum)minimum=dwElapsed;
        average+=dwElapsed;
        printf("\nReply from %s: bytes = %d time = %ldms TTL = %d",
               inet_ntoa(srcIP.sin_addr),REQ_DATASIZE,dwElapsed,cTTL);
    }
    printf("\n\n");
    printf("Ping statistics for %s:\n",inet_ntoa(srcIP.sin_addr));
    printf("    Packets: Sent = %d, Received = %d, Lost = %d (%.f%% loss),\n",
           sent,reveived,lost,(float)(lost*1.0/sent)*100);
    if(lost==0) {
        printf("Approximate round trip times in milli-seconds:\n");
        printf("    Minimum = %dms, Maximum = %dms, Average = %dms\n",minimum,maximum,average/sent);
    }
    printf("\n\n");
    nRet = closesocket(rawSocket);
    if (nRet == SOCKET_ERROR) {
        printf("closesocket() error:%d\n", WSAGetLastError());
    }
}

void main() {
    printf("Welcome to the Ping Test\n");
    while(1) {
        WSADATA wsd;//检测输入的参数
        //初始化Winsock
        if (WSAStartup(MAKEWORD(1, 1), &wsd) != 0) {
            printf("加载 Winsock 失败!\n");
        }
        char opt1[100];
        char *ptr=opt1;
        bool log=false;
        printf("Ping ");
        cin.getline(opt1,100,'\n');
        if ((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) {
            log=true;
            ptr=opt1+3;
        }
        //开始PING
        Ping(ptr,log);
        //程序释放 Winsock 资源
        WSACleanup();
    }
}
[/quot] 赵4老师啊,我最近在用多线程做一个局域网ip嗅探器。按照你的思路,我发现只要sock变为可读,select就会返回,那其他非局域网的ip发送的回应ping也会激发select的返回,在调用select之前有什么办法可以过滤掉这些多余的icmp回应么??
derekrose 2014-02-13
  • 打赏
  • 举报
回复
你发给谁的包啊 经过网卡吗
赵4老师 2014-02-13
  • 打赏
  • 举报
回复
搜“Win7 SOCK_RAW”
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <mmsystem.h>
#pragma comment(lib, "ws2_32")
#pragma comment(lib, "winmm")
#define ICMP_ECHOREPLY 0 //ICMP回应答复
#define ICMP_ECHOREQ 8 //ICMP回应请求
#define REQ_DATASIZE 32 //请求数据报大小
#include <iostream>
using namespace std;

//定义IP首部格式
typedef struct _IPHeader {
    u_char VIHL; //版本和首部长度
    u_char ToS; //服务类型
    u_short TotalLen; //总长度
    u_short ID; //标识号
    u_short Frag_Flags; //片偏移量
    u_char TTL; //生存时间
    u_char Protocol; //协议
    u_short Checksum; //首部校验和
    struct in_addr SrcIP; //源IP地址
    struct in_addr DestIP; //目的地址
}
IPHDR, *PIPHDR;

//定义ICMP首部格式
typedef struct _ICMPHeader {
    u_char Type; //类型
    u_char Code; //代码
    u_short Checksum; //首部校验和
    u_short ID; //标识
    u_short Seq; //序列号
    char Data; //数据
}
ICMPHDR, *PICMPHDR;

//定义ICMP回应请求
typedef struct _ECHOREQUEST {
    ICMPHDR icmpHdr;
    DWORD dwTime;
    char cData[REQ_DATASIZE];
}
ECHOREQUEST, *PECHOREQUEST;

//定义ICMP回应答复
typedef struct _ECHOREPLY {
    IPHDR ipHdr;
    ECHOREQUEST echoRequest;
    char cFiller[256];
}
ECHOREPLY, *PECHOREPLY;

//计算校验和
u_short checksum(u_short *buffer, int len) {
    register int nleft = len;
    register u_short *w = buffer;
    register u_short answer;
    register int sum = 0;
    //使用32位累加器,进行16位的反馈计算
    while ( nleft > 1 ) {
        sum += *w++;
        nleft -= 2;
    }
    //补全奇数位
    if ( nleft == 1 ) {
        u_short u = 0;
        *(u_char *)(&u) = *(u_char*)w;
        sum += u;
    }
    //将反馈的16位从高位移到低位
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return (answer);
}

//发送回应请求函数
int SendEchoRequest(SOCKET s, struct sockaddr_in *lpstToAddr) {
    static ECHOREQUEST echoReq;
    static int nId = 1;
    static int nSeq = 1;
    int nRet;
    //填充回应请求消息
    echoReq.icmpHdr.Type = ICMP_ECHOREQ;
    echoReq.icmpHdr.Code = 0;
    echoReq.icmpHdr.Checksum = 0;
    echoReq.icmpHdr.ID = nId++;
    echoReq.icmpHdr.Seq = nSeq++;
    //填充要发送的数据
    for (nRet = 0; nRet < REQ_DATASIZE; nRet++) {
        echoReq.cData[nRet] = '1' + nRet;
    }
    //存储发送的时间
    echoReq.dwTime = timeGetTime();
    //计算回应请求的校验和
    echoReq.icmpHdr.Checksum = checksum((u_short*)&echoReq, sizeof(ECHOREQUEST));
    //发送回应请求
    nRet = sendto(s,(LPSTR)&echoReq,sizeof(ECHOREQUEST),
                  0,(struct sockaddr*)lpstToAddr,sizeof(SOCKADDR_IN));
    if (nRet == SOCKET_ERROR) {
        printf("send to() error:%d\n", WSAGetLastError());
    }
    return (nRet);
}

//接收应答回复并进行解析
DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL) {
    ECHOREPLY echoReply;
    int nRet;
    int nAddrLen = sizeof(struct sockaddr_in);
    //接收应答回复
    nRet = recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY),
                    0,(LPSOCKADDR)lpsaFrom,&nAddrLen);
    //检验接收结果

    if (nRet == SOCKET_ERROR) {
        printf("recvfrom() error:%d\n",WSAGetLastError());
    }
    //记录返回的TTL
    *pTTL = echoReply.ipHdr.TTL;
    //返回应答时间
    return(echoReply.echoRequest.dwTime);
}

//等待回应答复,使用select模型
int WaitForEchoReply(SOCKET s) {
    struct timeval timeout;
    fd_set readfds;
    readfds.fd_count = 1;
    readfds.fd_array[0] = s;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    return(select(1, &readfds, NULL, NULL, &timeout));
}

//PING功能实现
void Ping(char *pstrHost,bool logic) {
    SOCKET rawSocket;
    LPHOSTENT lpHost;
    struct sockaddr_in destIP;
    struct sockaddr_in srcIP;
    DWORD dwTimeSent;
    DWORD dwElapsed;
    u_char cTTL;
    int nLoop,k=4;
    int nRet,minimum=100000,maximum=0,average=0;
    int sent=4,reveived=0,lost=0;
    //创建原始套接字,ICMP类型
    rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (rawSocket == SOCKET_ERROR) {
        printf("socket() error:%d\n", WSAGetLastError());
        return;
    }
    //检测目标主机
    lpHost = gethostbyname(pstrHost);
    if (lpHost==NULL) {
        printf("Host not found:%s\n", pstrHost);
        return;
    }
    //设置目标机地址
    destIP.sin_addr.s_addr = *((u_long FAR*)(lpHost->h_addr)); //设置目标IP
    destIP.sin_family = AF_INET;  //地址规格
    destIP.sin_port = 0;
    //提示开始进行PING
    printf("\nPinging %s [%s] with %d bytes of data:\n",pstrHost,inet_ntoa(destIP.sin_addr),REQ_DATASIZE);
    //发起多次PING测试
    for (nLoop=0; nLoop<k; nLoop++) {
        if (logic)k=k+1;
        //发送ICMP回应请求
        SendEchoRequest(rawSocket, &destIP);
        //等待回复的数据
        nRet = WaitForEchoReply(rawSocket);
        if (nRet == SOCKET_ERROR) {
            printf("select() error:%d\n", WSAGetLastError());
            break;
        }
        if (!nRet) {
            lost++;
            printf("\nRequest time out.");
            continue;
        }
        //接收回复
        dwTimeSent = RecvEchoReply(rawSocket, &srcIP, &cTTL);
        reveived++;
        //计算花费的时间
        dwElapsed = timeGetTime() - dwTimeSent;
        if(dwElapsed>maximum)maximum=dwElapsed;
        if(dwElapsed<minimum)minimum=dwElapsed;
        average+=dwElapsed;
        printf("\nReply from %s: bytes = %d time = %ldms TTL = %d",
               inet_ntoa(srcIP.sin_addr),REQ_DATASIZE,dwElapsed,cTTL);
    }
    printf("\n\n");
    printf("Ping statistics for %s:\n",inet_ntoa(srcIP.sin_addr));
    printf("    Packets: Sent = %d, Received = %d, Lost = %d (%.f%% loss),\n",
           sent,reveived,lost,(float)(lost*1.0/sent)*100);
    if(lost==0) {
        printf("Approximate round trip times in milli-seconds:\n");
        printf("    Minimum = %dms, Maximum = %dms, Average = %dms\n",minimum,maximum,average/sent);
    }
    printf("\n\n");
    nRet = closesocket(rawSocket);
    if (nRet == SOCKET_ERROR) {
        printf("closesocket() error:%d\n", WSAGetLastError());
    }
}

void main() {
    printf("Welcome to the Ping Test\n");
    while(1) {
        WSADATA wsd;//检测输入的参数
        //初始化Winsock
        if (WSAStartup(MAKEWORD(1, 1), &wsd) != 0) {
            printf("加载 Winsock 失败!\n");
        }
        char opt1[100];
        char *ptr=opt1;
        bool log=false;
        printf("Ping ");
        cin.getline(opt1,100,'\n');
        if ((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) {
            log=true;
            ptr=opt1+3;
        }
        //开始PING
        Ping(ptr,log);
        //程序释放 Winsock 资源
        WSACleanup();
    }
}
u010053164 2014-02-13
  • 打赏
  • 举报
回复
ip 头没定义
好人阿萨德飞 2013-07-21
  • 打赏
  • 举报
回复
谁能告诉我直接原因吗?
AnYidan 2013-07-20
  • 打赏
  • 举报
回复
google "ping"代码看看
Geoff08Zhang 2013-07-20
  • 打赏
  • 举报
回复
这有可以正确运行的raw socket例子,你参考一下: http://download.csdn.net/detail/geoff08zhang/4571358

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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