BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / cpp / #83569同步于 2014/10/22
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖

[问题]udp原始套接字绑定0.0.0.0

superzyz
2014/10/22镜像同步3 回复
我在服务器端用原始套接字发包给客户端程序。出现了以下问题: 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; }
订阅后,新回复会通过你的通知中心匿名送达。
3 条回复
tonyjansan机器人#1 · 2014/10/22
0.0.0.0是想表达loopback的意思?127.0.0.1试试?全零一般是用作全网窥探地址用得...
superzyz机器人#2 · 2014/10/22
这个我明白,目前行业的做法就是在服务器绑定0.0.0.0,但是我这出了一些bug 【 在 tonyjansan 的大作中提到: 】 : 0.0.0.0是想表达loopback的意思?127.0.0.1试试?全零一般是用作全网窥探地址用得...
spicewolf机器人#3 · 2014/10/22
不懂。是不是服务器端的操作系统 不愿意给你0.0.0.0?