【问题标题】:Problem with IP_HDRINCL?IP_HDRINCL 有问题吗?
【发布时间】:2009-03-04 12:38:04
【问题描述】:

我已经问过这个关于原始 IP 数据包实现的问题。但我没有得到任何解决方案。

我的代码:

if((s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_TCP, 0, 0, 0))==SOCKET_ERROR) // Socket 
    {
        printf("Creation of raw socket failed.");
        return 0;
    }
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval))==SOCKET_ERROR)
    {
        printf("failed to set socket in raw mode.");
        return 0;
    }
if((sendto(s ,(char *) buf , sizeof(IPV4_HDR)+sizeof(TCP_HDR) + payload, 0,(SOCKADDR *)&dest, sizeof(dest)))==SOCKET_ERROR)
    {
    printf("Error sending Packet : %d",WSAGetLastError());
    break;
    }

错误:

WSAGetLastError() 返回 10022:

说明:

向 setsockopt (Wsapiref_94aa.asp) 函数提供了无效参数(例如,指定无效级别的参数)。有时,它也指套接字的当前状态,例如,在未侦听的套接字上调用accept (Wsapiref_13aq.asp)。

评论:

但是我已经设置了正确的选项值和大小。

我做错了什么?我正在使用 Windows XP (SP3)。在 setsocketopt 中,我为该程序尝试了 IP_OPTIONS,它工作正常,并且它也发送 IP 数据包。但是对于每个 IP 数据包,它都会从目的地生成 ICMP 数据包。

我该如何解决这个问题?

源代码

//原始tcp数据包制作器

#include "stdio.h"
#include "winsock2.h"
#include "ws2tcpip.h"  //IP_HDRINCL is here
#include "conio.h"

typedef struct ip_hdr
{
    unsigned char  ip_header_len:4;  // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes may be 24 also)
    unsigned char  ip_version   :4;  // 4-bit IPv4 version
    unsigned char  ip_tos;           // IP type of service
    unsigned short ip_total_length;  // Total length
    unsigned short ip_id;            // Unique identifier 

    unsigned char  ip_frag_offset   :5;        // Fragment offset field

    unsigned char  ip_more_fragment :1;
    unsigned char  ip_dont_fragment :1;
    unsigned char  ip_reserved_zero :1;

    unsigned char  ip_frag_offset1;    //fragment offset

    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;      // Source address
}   IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR;

// TCP header
typedef struct tcp_header 
{ 
    unsigned short source_port;  // source port 
    unsigned short dest_port;    // destination port 
    unsigned int   sequence;     // sequence number - 32 bits 
    unsigned int   acknowledge;  // acknowledgement number - 32 bits 

    unsigned char  ns   :1;          //Nonce Sum Flag Added in RFC 3540.
    unsigned char  reserved_part1:3; //according to rfc
    unsigned char  data_offset:4;    /*The number of 32-bit words in the TCP header. 
                                       This indicates where the data begins. 
                                       The length of the TCP header is always a multiple 
                                       of 32 bits.*/

    unsigned char  fin  :1;      //Finish Flag
    unsigned char  syn  :1;      //Synchronise Flag
    unsigned char  rst  :1;      //Reset Flag
    unsigned char  psh  :1;      //Push Flag 
    unsigned char  ack  :1;      //Acknowledgement Flag 
    unsigned char  urg  :1;      //Urgent Flag

    unsigned char  ecn  :1;      //ECN-Echo Flag
    unsigned char  cwr  :1;      //Congestion Window Reduced Flag

    ////////////////////////////////

    unsigned short window;  // window 
    unsigned short checksum;  // checksum 
    unsigned short urgent_pointer;  // urgent pointer 
}   TCP_HDR , *PTCP_HDR , FAR * LPTCP_HDR , TCPHeader , TCP_HEADER;

int main()
{
    char host[100],buf[1000],*data=NULL,source_ip[20]; //buf is the complete packet
    SOCKET s;
    int k=1;

    IPV4_HDR *v4hdr=NULL;
    TCP_HDR  *tcphdr=NULL;

    int payload=512 ;
    int optval= 1;
    SOCKADDR_IN dest;
    hostent *server;

    //Initialise Winsock
    WSADATA wsock;
    printf("\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2),&wsock) != 0)
    {
        fprintf(stderr,"WSAStartup() failed");
        exit(EXIT_FAILURE); 
    } 
    printf("Initialised successfully.");
    ////////////////////////////////////////////////

    //Create Raw TCP Packet
    printf("\nCreating Raw TCP Socket...");
    if((s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_TCP, 0, 0, 0))==SOCKET_ERROR)
    {
        printf("Creation of raw socket failed.");
        return 0;
    }
    printf("Raw TCP Socket Created successfully.");
    ////////////////////////////////////////////////

    //Put Socket in RAW Mode.
    printf("\nSetting the socket in RAW mode...");
    if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval))==SOCKET_ERROR)
    {
        printf("failed to set socket in raw mode.");
        return 0;
    }
    printf("Successful.");
    ////////////////////////////////////////////////
    //Target Hostname
    printf("\nEnter hostname : ");
    gets(host);
    printf("\nResolving Hostname...");
    if((server=gethostbyname(host))==0)
    {
        printf("Unable to resolve.");
        return 0;
    }
    dest.sin_family = AF_INET;
    dest.sin_port   = htons(8888);  //your destination port
    memcpy(&dest.sin_addr.s_addr,server->h_addr,server->h_length);
    printf("Resolved.");
    /////////////////////////////////////////////////

    printf("\nEnter Source IP : ");
    gets(source_ip);


    v4hdr = (IPV4_HDR *)buf;  //lets point to the ip header portion
    v4hdr->ip_version=4;
    v4hdr->ip_header_len=5;
    v4hdr->ip_tos    = 0;
    v4hdr->ip_total_length = htons ( sizeof(IPV4_HDR) + sizeof(TCP_HDR) + payload );
    v4hdr->ip_id     = htons(2);
    v4hdr->ip_frag_offset = 0;
    v4hdr->ip_frag_offset1 = 0;
    v4hdr->ip_reserved_zero = 0;
    v4hdr->ip_dont_fragment = 1;
    v4hdr->ip_more_fragment = 0;
    v4hdr->ip_ttl    = 8;
    v4hdr->ip_protocol = IPPROTO_TCP;
    v4hdr->ip_srcaddr  = inet_addr(source_ip);
    v4hdr->ip_destaddr = inet_addr(inet_ntoa(dest.sin_addr));
    v4hdr->ip_checksum = 0;

    tcphdr = (TCP_HDR *)&buf[sizeof(IPV4_HDR)]; //get the pointer to the tcp header in the packet

    tcphdr->source_port = htons(1234);
    tcphdr->dest_port = htons(8888);

    tcphdr->cwr=0;
    tcphdr->ecn=1;
    tcphdr->urg=0;
    tcphdr->ack=0;
    tcphdr->psh=0;
    tcphdr->rst=1;
    tcphdr->syn=0;
    tcphdr->fin=0;
    tcphdr->ns=1;

    tcphdr->checksum = 0;


    // Initialize the TCP payload to some rubbish
    data = &buf[sizeof(IPV4_HDR) + sizeof(TCP_HDR)];
    memset(data, '^', payload);


    printf("\nSending packet...\n");

    while(!_kbhit())
    {
        printf("  %d  packets send\r",k++);
        if((sendto(s ,(char *) buf , sizeof(IPV4_HDR)+sizeof(TCP_HDR) + payload, 0,(SOCKADDR *)&dest, sizeof(dest)))==SOCKET_ERROR)
        {
        printf("Error sending Packet : %d",WSAGetLastError());
        break;
        }
    }
    return 0;
}

【问题讨论】:

  • 如果您还显示了选项值“optval”的定义,将会有所帮助。
  • int optval=1 ;它实际上是 int 类型还是 boolean 类型?
  • 让我发送完整的代码

标签: c++ c sockets network-programming


【解决方案1】:

您不能在 windows 中的原始 tcp 套接字上发送数据。

来自here

"原始套接字的限制

在 Windows 7、Windows Vista、带有 Service Pack 2 (SP2) 的 Windows XP 和带有 Service Pack 3 (SP3) 的 Windows XP 上,通过原始套接字发送流量的能力受到以下几个方面的限制:

  • 无法通过原始套接字发送 TCP 数据。

  • 具有无效源地址的 UDP 数据报不能通过原始套接字发送。任何传出 UDP 数据报的 IP 源地址必须存在于网络接口上,否则数据报将被丢弃。进行此更改是为了限制恶意代码创建分布式拒绝服务攻击的能力,并限制发送欺骗数据包(具有伪造源 IP 地址的 TCP/IP 数据包)的能力。

  • 不允许使用 IPPROTO_TCP 协议的原始套接字调用绑定函数。 "

【讨论】:

    【解决方案2】:

    好吧,看来您没有要发送的交易对手。

    您已经创建了套接字并设置了它的选项,但是您需要侦听传入连接 (bind() + accept()) 或 connect() 到另一方。

    错误描述:Sometimes, it also refers to the current state of the sockets - 我猜是你的情况。您的套接字未处于连接状态,因此sendto() 无效。

    【讨论】:

    • 使用 IPPROTO_TCP 绑定原始套接字不起作用。它适用于 IPPROTO_UDP、IPPROTO_IP、IPPROTO_ICMP、IPPROTO_IGMP
    • 我建议买一本关于网络编程的书——Richard Stevens 的 Unix Network Programming 是最好的。原始套接字上应该有一些东西。
    【解决方案3】:

    顺便说一句,作为参考,有一个关于 'optval' 的讨论,它是 bool 还是 int。显然 'int' 是更好的选择,但我已经看到了很多使用 bool 的示例。

    Set IP_HDRINCL to setsockopt function in win32

    我使用了“bool”,我的程序在 Windows XP 上运行良好。现在它在 Win 7 上不起作用,错误代码为 10022。

    【讨论】:

      猜你喜欢
      • 2018-09-14
      • 2012-03-03
      • 2011-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-12
      相关资源
      最近更新 更多