原始套接字实现

来源:互联网 发布:video.js怎么播放flv 编辑:程序博客网 时间:2024/04/30 09:48
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <stdlib.h>  
  4. #include <errno.h>  
  5.   
  6. #ifdef WIN32  
  7. #include <Winsock2.h>  
  8. #include <ws2ipdef.h>  
  9. #include <WS2tcpip.h>  
  10. #else  
  11. #include <sys/types.h>  
  12. #include <sys/socket.h>  
  13. #include <netinet/in.h>  
  14. #include <unistd.h>  
  15. #include <arpa/inet.h>  
  16. #endif  
  17.   
  18. #ifdef WIN32  
  19. #pragma comment(lib,"ws2_32.lib")  
  20. #else  
  21. #define SOCKET_ERROR -1  
  22. typedef int BOOL;  
  23. #endif  
  24.   
  25.   
  26.   
  27. #define  DEFAULT_PORT 10089  
  28.   
  29.   
  30. typedef struct ip_head  
  31. {   
  32.     union   
  33.     {    
  34.         unsigned char Version;    
  35.         unsigned char HeadLen;   
  36.     };  
  37.     unsigned char ServiceType;   
  38.     unsigned short TotalLen;   
  39.     unsigned short Identifier;   
  40.     union   
  41.     {    
  42.         unsigned short Flags;   
  43.         unsigned short FragOffset;   
  44.     };   
  45.     unsigned char TimeToLive;   
  46.     unsigned char Protocol;   
  47.     unsigned short HeadChecksum;   
  48.     unsigned int SourceAddr;   
  49.     unsigned int DestinAddr;   
  50. }IP_HEADER;  
  51.   
  52.   
  53. /* 
  54.  * TCP header. 
  55.  * Per RFC 793, September, 1981. 
  56.  */  
  57. typedef struct tcp_head {  
  58.     u_short th_sport;               /* source port */  
  59.     u_short th_dport;               /* destination port */  
  60.     unsigned int th_seq;                 /* sequence number */  
  61.     unsigned int th_ack;                 /* acknowledgement number */  
  62.     unsigned char th_lenres;  
  63.     u_char  th_flags;  
  64.     u_short th_win;                 /* window */  
  65.     u_short th_sum;                 /* checksum */  
  66.     u_short th_urp;                 /* urgent pointer */  
  67. }TCP_HEADER;  
  68.   
  69. //tcp伪报头  
  70. typedef struct psd_hdr  
  71. {  
  72.     unsigned long saddr;  
  73.     unsigned long daddr;  
  74.     char mbz;  
  75.     char ptcl; //协议类型  
  76.     unsigned short tcpl;  //tcp长度  
  77. }PSD_HEADER;  
  78.   
  79. typedef struct udp_head  
  80. {  
  81.     unsigned short uh_sport;  
  82.     unsigned short uh_dport;  
  83.     unsigned short uh_len;  
  84.     unsigned short uh_sum;  
  85. }UDP_HEADER;  
  86.   
  87. struct tcpiphdr  
  88. {  
  89.     ip_head ipHead;  
  90.     tcp_head tcpHead;  
  91. };  
  92.   
  93. void InitSocket()  
  94. {  
  95. #ifdef WIN32  
  96.     WSADATA wsaData;   
  97.     WORD wVersionRequested = MAKEWORD(2, 2);   
  98.     int err = WSAStartup(wVersionRequested, &wsaData);   
  99.     if(err != 0)  
  100.     {  
  101.         printf("windows socket DLL initiates faild\n");  
  102.         exit(-1);  
  103.     }  
  104. #endif  
  105. }  
  106.   
  107.   
  108. int GetErrNo()  
  109. {  
  110. #ifdef WIN32  
  111.     return WSAGetLastError();  
  112. #else  
  113.     return errno;  
  114. #endif  
  115. }  
  116.   
  117. const char* GetErrStr(int errnum)  
  118. {  
  119.     #ifdef WIN32  
  120.     return "请查看msdn帮助文档或定义winerror.h";  
  121. #else  
  122.     return strerror(errnum);  
  123. #endif  
  124. }  
  125. //设置虚拟IP地址  
  126. void SetVirtualIp(int fd, const char* userIp)  
  127. {  
  128.     bool flag = true;  
  129.     if(setsockopt(fd,IPPROTO_IP,IP_HDRINCL,(char *) &flag,sizeof(flag))==SOCKET_ERROR)  
  130.     {  
  131.         printf("windows socket DLL initiates faild\n");  
  132.         exit(-1);  
  133.     }  
  134. }  
  135.   
  136. unsigned short CheckSum(unsigned short *buffer, int size)  
  137. {  
  138.     unsigned long cksum = 0;  
  139.     while(size > 0)  
  140.     {  
  141.         cksum += *buffer;  
  142.         size -= sizeof(unsigned short );  
  143.     }  
  144.     if (size)  
  145.     {  
  146.         cksum += *(unsigned short*)buffer;  
  147.     }  
  148.     cksum = (cksum >> 16) + (cksum & 0xffff);  
  149.     cksum += (cksum >> 16);  
  150.     return (unsigned short )(~cksum);  
  151. }  
  152.   
  153. void WriteTcpPkg(const char* sourceIp, const char* destIp, unsigned int destPort,  char* szBuffer )  
  154. {  
  155.     int iTotalSize = sizeof(ip_head) + sizeof(tcp_head);  
  156.     int iIpVersion = 4;  
  157.     int iIpSize = sizeof(ip_head)/sizeof(unsigned long);  
  158.     ip_head ipHead;  
  159.     tcp_head tcpHead;  
  160.     psd_hdr psdHead;  
  161.   
  162.     ipHead.Version = (iIpVersion << 4) | iIpSize;  
  163.     //ipHead.ServiceType = 0;  
  164.     ipHead.TotalLen = htons(iTotalSize);  
  165.     ipHead.Identifier = 1;  
  166.     ipHead.FragOffset = 0;  
  167.     ipHead.TimeToLive = 128;  
  168.     ipHead.Protocol = IPPROTO_TCP;  
  169.     ipHead.HeadChecksum = 0;  
  170.     ipHead.SourceAddr = inet_addr(sourceIp);  
  171.     ipHead.DestinAddr = inet_addr(destIp);  
  172.   
  173.     tcpHead.th_sport = htons(DEFAULT_PORT);  
  174.     tcpHead.th_dport = htons(destPort);  
  175.     tcpHead.th_seq = htonl(0x12345678);  
  176.     tcpHead.th_ack = 0;  
  177.     tcpHead.th_lenres = (sizeof(tcp_head)/4 << 4 | 0);  
  178.     tcpHead.th_flags = 2;  //标志位探测  2是syn  
  179.     tcpHead.th_win = htons(512);  
  180.     tcpHead.th_urp = 0;  
  181.     tcpHead.th_sum = 0;  
  182.   
  183.     psdHead.saddr = ipHead.SourceAddr;  
  184.     psdHead.daddr = ipHead.DestinAddr;  
  185.     psdHead.mbz = 0;  
  186.     psdHead.ptcl = IPPROTO_TCP;  
  187.     psdHead.tcpl = htons(sizeof(tcp_head));  
  188.   
  189.     //计算校验和  
  190.     memcpy(szBuffer, &psdHead, sizeof(psdHead));   
  191.     memcpy(szBuffer + sizeof(psdHead), &tcpHead, sizeof(tcpHead));   
  192.     tcpHead.th_sum = CheckSum( (unsigned short*)szBuffer, sizeof(psdHead) + sizeof(tcpHead));  
  193.   
  194.   
  195.     memcpy(szBuffer, &ipHead, sizeof(ipHead));  
  196.     memcpy(szBuffer + sizeof(ipHead), &tcpHead, sizeof(tcpHead));  
  197.     memset(szBuffer + sizeof(ipHead) + sizeof(tcpHead), 0, sizeof(int));   
  198.     ipHead.HeadChecksum = CheckSum((unsigned short*)szBuffer, sizeof(ipHead) + sizeof(tcpHead));  
  199.   
  200.     memcpy(szBuffer, &ipHead, sizeof(ipHead));  
  201. }  
  202.   
  203.   
  204.   
  205. void MyConnectTcp(sockaddr_in &servaddr)  
  206. {  
  207.     int fd = socket(AF_INET, SOCK_DGRAM, 0);  
  208.     int r = connect(fd, (struct sockaddr*)&servaddr, sizeof(servaddr));  
  209.     int ret = sendto(fd, "hello", 5, 0, (struct sockaddr*)&servaddr, sizeof(servaddr));  
  210.     struct sockaddr_in clientaddr;  
  211.     socklen_t size = sizeof(clientaddr);  
  212.     char szBuf[1024];  
  213.     ret = recvfrom(fd, szBuf, 1024, 0,(struct sockaddr*)&clientaddr, &size);  
  214. }  
  215.   
  216. int main(int argc, char** argv)  
  217. {  
  218.     if(argc < 5)  
  219.     {  
  220.         printf("usage : tm_client servIp servPort data userIp\n");  
  221.         exit(-1);  
  222.     }  
  223.     char    servIp[64], userIp[64], workfId[16];  
  224.     int port = atoi(argv[2]);  
  225.     strcpy(servIp, argv[1]);  
  226.     strcpy(workfId, argv[3]);  
  227.     strcpy(userIp, argv[4]);  
  228.     struct sockaddr_in servaddr;  
  229.   
  230.     InitSocket();  
  231.   
  232.     //创建原始套接字,需要有超级用户的权限  
  233.     int fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);  
  234.     if( fd == SOCKET_ERROR)  
  235.     {  
  236.         printf("%s\n", GetErrStr(GetErrNo()));  
  237.         printf("socket函数执行失败\n");  
  238.         return 1;  
  239.     }  
  240.       
  241.     //Header is included with data. 报文将由自己组装,以数据的形式进行发送  
  242.     BOOL flag = true;  
  243.     if(setsockopt(fd,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)  
  244.     {  
  245.         printf("%d", GetErrNo());  
  246.         printf("set socket IP_HDRINCL faild\n");  
  247.         exit(-1);  
  248.     }  
  249.   
  250.     //设置超时  
  251.     int nTimeOver = 1000;  
  252.     if(setsockopt(fd,SOL_SOCKET,SO_SNDTIMEO,(char *)&nTimeOver,sizeof(nTimeOver))==SOCKET_ERROR)  
  253.     {  
  254.         printf("%d", GetErrNo());  
  255.         printf("set socket SO_SNDTIMEO faild\n");  
  256.         exit(-1);  
  257.     }  
  258.   
  259.     servaddr.sin_family = AF_INET;  
  260.     servaddr.sin_addr.s_addr = inet_addr(servIp);  
  261.     servaddr.sin_port = htons(port);  
  262.   
  263.   
  264.     char szDataBuf[1024];  
  265.       
  266.     memset(szDataBuf, 0, sizeof(szDataBuf));  
  267.   
  268.     int ipsize = sizeof(ip_head), tcpsize = sizeof(tcp_head);  
  269.     int iTotalSize = sizeof(ip_head) + sizeof(tcp_head);  
  270.     WriteTcpPkg(userIp, servIp, port, szDataBuf);  
  271.   
  272.     //此处在XP系统下会返回错误码WSAEINTR,表示通过WSACancelBlockingCall函数中断了,xp sp2及以上版本都会遇到这个问题  
  273.     if(sendto(fd, szDataBuf, iTotalSize, 0, (struct sockaddr*)&servaddr, sizeof(servaddr)) == SOCKET_ERROR)  
  274.     {  
  275.         printf("sendto message faild, errno = %d\n", GetErrNo());  
  276.         exit(-1);  
  277.     }  
  278.   
  279.   
  280.     struct sockaddr_in cliaddr;  
  281.     socklen_t cliLen = sizeof(cliaddr);  
  282.   
  283.     if( recvfrom(fd,szDataBuf, sizeof(iTotalSize), 0, (struct sockaddr*)&cliaddr, &cliLen) < 0)  
  284.     {  
  285.         printf("recvfrom message faild\n");  
  286.         exit(-1);  
  287.     }  
  288.   
  289. #ifdef WIN32  
  290.     closesocket(fd);  
  291.     WSACleanup();  
  292. #else  
  293.   close(fd);  
  294. #endif  
  295.     return 0;  
原创粉丝点击