2 princeguangchao princeguangchao 于 2014.10.22 16:48 提问

udp原始套接字绑定0.0.0.0

我在服务器端用原始套接字发包给客户端程序。出现了以下问题:
1. 如果客户端和服务端都绑定ip地址为0.0.0.0,虽然包能在客户端的机器上被wireshark抓到,但是不能被客户端程序收到。
2. 如果客户端绑定真实的ip地址,服务器端绑定0.0.0.0, 在有些无线网络环境下,包能够被客户端的wireshark抓到,但是不能客户端程序收到
3. 如果服务器端绑定真实ip地址,无论客户端绑定是0.0.0.0还是真实ip地址,都能正常收到包。

我的代码如下`
客户端:

   int _tmain(int argc, _TCHAR* argv[])
{
    SOCKET  udpSock;
    WSADATA wsa;
    if(WSAStartup(MAKEWORD(2,2),&wsa)){
        return 0;
    }
    udpSock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
    if(udpSock == INVALID_SOCKET){
        return 0;
    }
    SOCKADDR_IN  localAddr;
    localAddr.sin_family = AF_INET;
    localAddr.sin_port = htons(8622);
    //localAddr.sin_addr.s_addr = INADDR_ANY;
    //localAddr.sin_addr.s_addr = inet_addr("192.168.191.5");

    localAddr.sin_addr.s_addr = inet_addr("10.6.192.112");
int opt = 1;
::setsockopt( udpSock, IPPROTO_UDP, 19,(char*) &opt, sizeof ( opt ) );
int aa = 8192;
::setsockopt(udpSock,SOL_SOCKET,SO_SNDBUF,(char*)&aa,sizeof(aa));

if(bind(udpSock,(sockaddr*)&localAddr,sizeof(localAddr)) != 0){
    return 0;
}
sockaddr_in RecvAddr;
RecvAddr.sin_family = AF_INET;
RecvAddr.sin_port = htons(8821);
RecvAddr.sin_addr.s_addr = inet_addr("10.6.192.111");
char sendBuf[2048]; 
strcpy(sendBuf,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\0");

BYTE         recvBuf[4096];
int          recvLen = 0;
SOCKADDR_IN  tmpAddr;
int          tmpRecvLen;
tmpRecvLen = sizeof(tmpAddr);
int i = 0;
while(true)
{   
    int len2 = sendto(udpSock, sendBuf, strlen(sendBuf), 0, (SOCKADDR *) &RecvAddr, sizeof(RecvAddr));
    printf("start recv");
    Sleep(100);
    ZeroMemory(recvBuf,4096);
    recvLen = recvfrom(udpSock,(char *)recvBuf,4096,0,(SOCKADDR *)&tmpAddr,&tmpRecvLen);
    printf("recvLen = %d\n",recvLen);
    if(recvLen > 0)
    {   
        recvLen = 0;
        printf("%s ",recvBuf);
        printf("\n");
    }
}
closesocket(udpSock);
return 0;
}

服务器代码:

#include<stdio.h> //for printf
#include<string.h> //memset
#include<sys/socket.h>    //for socket ofcourse
#include<stdlib.h> //for exit(0);
#include<errno.h> //For errno - the error number
#include<netinet/udp.h>   //Provides declarations for udp header
#include<netinet/ip.h>    //Provides declarations for ip header
#include <unistd.h>
#include <arpa/inet.h>
/* 
    96 bit (12 bytes) pseudo header needed for udp header checksum calculation 
*/
struct pseudo_header
{
    u_int32_t source_address;
    u_int32_t dest_address;
    u_int8_t placeholder;
    u_int8_t protocol;
    u_int16_t udp_length;
};

/*
    Generic checksum calculation function
*/
unsigned short csum(unsigned short *ptr,int nbytes)
{
    register long sum;
    unsigned short oddbyte;
    register short answer;

    sum=0;
    while(nbytes>1) {
        sum+=*ptr++;
        nbytes-=2;
    }
    if(nbytes==1) {
        oddbyte=0;
        *((u_char*)&oddbyte)=*(u_char*)ptr;
        sum+=oddbyte;
    }

    sum = (sum>>16)+(sum & 0xffff);
    sum = sum + (sum>>16);
    answer=(short)~sum;

    return(answer);
}

int main (void)
{
    int  RcvSock = socket(AF_INET, SOCK_DGRAM, 0);

    struct sockaddr_in localAddr;
memset(&localAddr, 0, sizeof(struct sockaddr_in));
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
localAddr.sin_port = htons(8821);

if (bind(RcvSock, (struct sockaddr *)&localAddr, sizeof(struct sockaddr_in)) < 0)
{
    printf("bind failed: %d\n", errno);
    return -1;
}

char buf[2048]={0};
struct sockaddr_in  remoteAddr;
memset(buf,0,sizeof(buf));
int srclen = sizeof(remoteAddr);
int len = recvfrom(RcvSock,buf,sizeof(buf),0,(sockaddr*)&remoteAddr,( socklen_t* )&srclen);
char * remoteIp = inet_ntoa(remoteAddr.sin_addr);
unsigned int  remotePort = ntohl(remoteAddr.sin_port);
printf(" recv %s, remote ip %s, remote port %u\n",buf,remoteIp, remotePort);

char sBuf[2048]={0};
snprintf(sBuf,sizeof(sBuf),"iddddddhello\n");
sendto(RcvSock,sBuf,strlen(sBuf),0,(struct sockaddr*)&remoteAddr,sizeof(remoteAddr));
//Create a raw socket of type IPPROTO
int s = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);

int on = 1;


 if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
               printf(" can not set the IP_HDR_INCL option\n");
        return -1;
    }
if(s == -1)
{
    //socket creation failed, may be because of non-root privileges
    perror("Failed to create raw socket");
    exit(1);
}

//Datagram to represent the packet
char datagram[4096] , source_ip[32] , *data , *pseudogram;

//zero out the packet buffer
memset (datagram, 0, 4096);

//IP header
struct iphdr *iph = (struct iphdr *) datagram;

//UDP header
struct udphdr *udph = (struct udphdr *) (datagram + sizeof (struct ip));

struct sockaddr_in *sin = &remoteAddr;
struct pseudo_header psh;

    //Data part
  data = datagram + sizeof(struct iphdr) + sizeof(struct udphdr);
    strcpy(data , "ABCDEFGHIJKLMNOPQRSTUVWXYZ");

    //some address resolution
   strcpy(source_ip , "10.6.192.111");
 //     strcpy(source_ip , "0.0.0.0");
  int tot_len =  sizeof (struct iphdr) + sizeof (struct udphdr) + strlen(data);
     //Fill in the IP Header
    iph->ihl = 5;
    iph->version = 4;
    iph->tos = 0;
    iph->tot_len = htonl(tot_len);
    iph->id = htonl (54321); //Id of this packet
    iph->frag_off = 0;
    iph->ttl = 255;
    iph->protocol = IPPROTO_UDP;
    iph->check = 0;      //Set to 0 before calculating checksum
    iph->saddr = inet_addr ( source_ip );    //Spoof the source ip address
    iph->daddr = remoteAddr.sin_addr.s_addr;

    //Ip checksum
   iph->check = csum ((unsigned short *) datagram, iph->tot_len);
//UDP header
udph->source = htons (8821);
udph->dest = remoteAddr.sin_port;
udph->len = htons(8 + strlen(data)); //tcp header size
udph->check = 0; //leave checksum 0 now, filled later by pseudo header

//Now the UDP checksum using the pseudo header
psh.source_address = inet_addr( source_ip );
psh.dest_address = remoteAddr.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) + strlen(data) );

int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + strlen(data);
pseudogram = (char*)malloc(psize);

memcpy(pseudogram , (char*) &psh , sizeof (struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header) , udph , sizeof(struct udphdr) + strlen(data));

udph->check = csum( (unsigned short*) pseudogram , psize);

//loop if you want to flood :)
while (1)
{
  printf("start send\n");
    //Send the packet
    if (sendto (s, datagram, tot_len ,  0, (struct sockaddr *) &remoteAddr, sizeof (remoteAddr)) < 0)
    {
        perror("sendto failed");
    }
      sleep(1);
}

return 0;
}

1个回答

princeguangchao
princeguangchao   2014.11.27 14:40

最后没有解决。我都改成了普通套接字

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!